Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.22 266 lines 6.0 kB view raw
1/* Miro PCM20 radio driver for Linux radio support 2 * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> 3 * Thanks to Norberto Pellici for the ACI device interface specification 4 * The API part is based on the radiotrack driver by M. Kirkwood 5 * This driver relies on the aci mixer (drivers/sound/aci.c) 6 * Look there for further info... 7 */ 8 9/* Revision history: 10 * 11 * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> 12 * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de> 13 * removed unfinished volume control (maybe adding it later again) 14 * use OSS-mixer; added stereo control 15 */ 16 17/* What ever you think about the ACI, version 0x07 is not very well! 18 * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono 19 * conditions... Robert 20 */ 21 22#include <linux/module.h> 23#include <linux/init.h> 24#include <linux/videodev.h> 25#include <media/v4l2-common.h> 26#include "oss/aci.h" 27#include "miropcm20-rds-core.h" 28 29static int radio_nr = -1; 30module_param(radio_nr, int, 0); 31 32struct pcm20_device { 33 unsigned long freq; 34 int muted; 35 int stereo; 36}; 37 38 39static int pcm20_mute(struct pcm20_device *dev, unsigned char mute) 40{ 41 dev->muted = mute; 42 return aci_write_cmd(ACI_SET_TUNERMUTE, mute); 43} 44 45static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo) 46{ 47 dev->stereo = stereo; 48 return aci_write_cmd(ACI_SET_TUNERMONO, !stereo); 49} 50 51static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) 52{ 53 unsigned char freql; 54 unsigned char freqh; 55 56 dev->freq=freq; 57 58 freq /= 160; 59 if (!(aci_version==0x07 || aci_version>=0xb0)) 60 freq /= 10; /* I don't know exactly which version 61 * needs this hack */ 62 freql = freq & 0xff; 63 freqh = freq >> 8; 64 65 aci_rds_cmd(RDS_RESET, NULL, 0); 66 pcm20_stereo(dev, 1); 67 68 return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh); 69} 70 71static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal) 72{ 73 /* okay, check for signal, stereo and rds here... */ 74 int i; 75 unsigned char buf; 76 77 if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0) 78 return i; 79 pr_debug("check_sig: 0x%x\n", i); 80 if (i & 0x80) { 81 /* no signal from tuner */ 82 *flags=0; 83 *signal=0; 84 return 0; 85 } else 86 *signal=0xffff; 87 88 if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0) 89 return i; 90 if (i & 0x40) { 91 *flags=0; 92 } else { 93 /* stereo */ 94 *flags=VIDEO_TUNER_STEREO_ON; 95 /* I can't see stereo, when forced to mono */ 96 dev->stereo=1; 97 } 98 99 if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0) 100 return i; 101 if (buf & 1) 102 /* RDS available */ 103 *flags|=VIDEO_TUNER_RDS_ON; 104 else 105 return 0; 106 107 if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) 108 return i; 109 pr_debug("rds-signal: %d\n", buf); 110 if (buf > 15) { 111 printk("miropcm20-radio: RX strengths unexpected high...\n"); 112 buf=15; 113 } 114 /* refine signal */ 115 if ((*signal=SCALE(15, 0xffff, buf))==0) 116 *signal = 1; 117 118 return 0; 119} 120 121static int pcm20_do_ioctl(struct inode *inode, struct file *file, 122 unsigned int cmd, void *arg) 123{ 124 struct video_device *dev = video_devdata(file); 125 struct pcm20_device *pcm20 = dev->priv; 126 int i; 127 128 switch(cmd) 129 { 130 case VIDIOCGCAP: 131 { 132 struct video_capability *v = arg; 133 memset(v,0,sizeof(*v)); 134 v->type=VID_TYPE_TUNER; 135 strcpy(v->name, "Miro PCM20"); 136 v->channels=1; 137 v->audios=1; 138 return 0; 139 } 140 case VIDIOCGTUNER: 141 { 142 struct video_tuner *v = arg; 143 if(v->tuner) /* Only 1 tuner */ 144 return -EINVAL; 145 v->rangelow=87*16000; 146 v->rangehigh=108*16000; 147 pcm20_getflags(pcm20, &v->flags, &v->signal); 148 v->flags|=VIDEO_TUNER_LOW; 149 v->mode=VIDEO_MODE_AUTO; 150 strcpy(v->name, "FM"); 151 return 0; 152 } 153 case VIDIOCSTUNER: 154 { 155 struct video_tuner *v = arg; 156 if(v->tuner!=0) 157 return -EINVAL; 158 /* Only 1 tuner so no setting needed ! */ 159 return 0; 160 } 161 case VIDIOCGFREQ: 162 { 163 unsigned long *freq = arg; 164 *freq = pcm20->freq; 165 return 0; 166 } 167 case VIDIOCSFREQ: 168 { 169 unsigned long *freq = arg; 170 pcm20->freq = *freq; 171 i=pcm20_setfreq(pcm20, pcm20->freq); 172 pr_debug("First view (setfreq): 0x%x\n", i); 173 return i; 174 } 175 case VIDIOCGAUDIO: 176 { 177 struct video_audio *v = arg; 178 memset(v,0, sizeof(*v)); 179 v->flags=VIDEO_AUDIO_MUTABLE; 180 if (pcm20->muted) 181 v->flags|=VIDEO_AUDIO_MUTE; 182 v->mode=VIDEO_SOUND_STEREO; 183 if (pcm20->stereo) 184 v->mode|=VIDEO_SOUND_MONO; 185 /* v->step=2048; */ 186 strcpy(v->name, "Radio"); 187 return 0; 188 } 189 case VIDIOCSAUDIO: 190 { 191 struct video_audio *v = arg; 192 if(v->audio) 193 return -EINVAL; 194 195 pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE)); 196 if(v->flags&VIDEO_SOUND_MONO) 197 pcm20_stereo(pcm20, 0); 198 if(v->flags&VIDEO_SOUND_STEREO) 199 pcm20_stereo(pcm20, 1); 200 201 return 0; 202 } 203 default: 204 return -ENOIOCTLCMD; 205 } 206} 207 208static int pcm20_ioctl(struct inode *inode, struct file *file, 209 unsigned int cmd, unsigned long arg) 210{ 211 return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl); 212} 213 214static struct pcm20_device pcm20_unit = { 215 .freq = 87*16000, 216 .muted = 1, 217}; 218 219static const struct file_operations pcm20_fops = { 220 .owner = THIS_MODULE, 221 .open = video_exclusive_open, 222 .release = video_exclusive_release, 223 .ioctl = pcm20_ioctl, 224 .compat_ioctl = v4l_compat_ioctl32, 225 .llseek = no_llseek, 226}; 227 228static struct video_device pcm20_radio = { 229 .owner = THIS_MODULE, 230 .name = "Miro PCM 20 radio", 231 .type = VID_TYPE_TUNER, 232 .hardware = VID_HARDWARE_RTRACK, 233 .fops = &pcm20_fops, 234 .priv = &pcm20_unit 235}; 236 237static int __init pcm20_init(void) 238{ 239 if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1) 240 goto video_register_device; 241 242 if(attach_aci_rds()<0) 243 goto attach_aci_rds; 244 245 printk(KERN_INFO "Miro PCM20 radio card driver.\n"); 246 247 return 0; 248 249 attach_aci_rds: 250 video_unregister_device(&pcm20_radio); 251 video_register_device: 252 return -EINVAL; 253} 254 255MODULE_AUTHOR("Ruurd Reitsma"); 256MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); 257MODULE_LICENSE("GPL"); 258 259static void __exit pcm20_cleanup(void) 260{ 261 unload_aci_rds(); 262 video_unregister_device(&pcm20_radio); 263} 264 265module_init(pcm20_init); 266module_exit(pcm20_cleanup);