Diff markup
1 /* radio-cadet.c - A video4linux driver for th 1 /* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card
2 * 2 *
3 * by Fred Gleason <fredg@wava.com> 3 * by Fred Gleason <fredg@wava.com>
4 * Version 0.3.3 4 * Version 0.3.3
5 * 5 *
6 * (Loosely) based on code for the Aztech radi 6 * (Loosely) based on code for the Aztech radio card by
7 * 7 *
8 * Russell Kroll (rkroll@exploits.org) 8 * Russell Kroll (rkroll@exploits.org)
9 * Quay Ly 9 * Quay Ly
10 * Donald Song 10 * Donald Song
11 * Jason Lewis (jlewis@twilight.vtc.vsc.e 11 * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
12 * Scott McGrath (smcgrath@twilight.vtc.vsc 12 * Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
13 * William McGrath (wmcgrath@twilight.vtc.vsc 13 * William McGrath (wmcgrath@twilight.vtc.vsc.edu)
14 * 14 *
15 * History: 15 * History:
16 * 2000-04-29 Russell Kroll <rkroll@exploits 16 * 2000-04-29 Russell Kroll <rkroll@exploits.org>
17 * Added ISAPnP detection for Lin 17 * Added ISAPnP detection for Linux 2.3/2.4
18 * 18 *
19 * 2001-01-10 Russell Kroll <rkroll@exploits 19 * 2001-01-10 Russell Kroll <rkroll@exploits.org>
20 * Removed dead CONFIG_RADIO_CADE 20 * Removed dead CONFIG_RADIO_CADET_PORT code
21 * PnP detection on load is now d 21 * PnP detection on load is now default (no args necessary)
22 * 22 *
23 * 2002-01-17 Adam Belay <ambx1@neo.rr.com> 23 * 2002-01-17 Adam Belay <ambx1@neo.rr.com>
24 * Updated to latest pnp code 24 * Updated to latest pnp code
25 * 25 *
26 * 2003-01-31 Alan Cox <alan@lxorguk.ukuu.or !! 26 * 2003-01-31 Alan Cox <alan@redhat.com>
27 * Cleaned up locking, delay code 27 * Cleaned up locking, delay code, general odds and ends
28 * 28 *
29 * 2006-07-30 Hans J. Koch <koch@hjk-az.de> 29 * 2006-07-30 Hans J. Koch <koch@hjk-az.de>
30 * Changed API to V4L2 30 * Changed API to V4L2
31 */ 31 */
32 32
33 #include <linux/version.h> 33 #include <linux/version.h>
34 #include <linux/module.h> /* Modules 34 #include <linux/module.h> /* Modules */
35 #include <linux/init.h> /* Initdata 35 #include <linux/init.h> /* Initdata */
36 #include <linux/ioport.h> /* request_reg 36 #include <linux/ioport.h> /* request_region */
37 #include <linux/delay.h> /* udelay 37 #include <linux/delay.h> /* udelay */
>> 38 #include <asm/io.h> /* outb, outb_p */
>> 39 #include <asm/uaccess.h> /* copy to/from user */
38 #include <linux/videodev2.h> /* V4L2 API de 40 #include <linux/videodev2.h> /* V4L2 API defs */
>> 41 #include <media/v4l2-common.h>
39 #include <linux/param.h> 42 #include <linux/param.h>
40 #include <linux/pnp.h> 43 #include <linux/pnp.h>
41 #include <linux/io.h> /* outb, outb_ <<
42 #include <media/v4l2-device.h> <<
43 #include <media/v4l2-ioctl.h> <<
44 <<
45 MODULE_AUTHOR("Fred Gleason, Russell Kroll, Qu <<
46 MODULE_DESCRIPTION("A driver for the ADS Cadet <<
47 MODULE_LICENSE("GPL"); <<
48 <<
49 static int io = -1; /* default to <<
50 static int radio_nr = -1; <<
51 <<
52 module_param(io, int, 0); <<
53 MODULE_PARM_DESC(io, "I/O address of Cadet car <<
54 module_param(radio_nr, int, 0); <<
55 <<
56 #define CADET_VERSION KERNEL_VERSION(0, 3, 3) <<
57 44
58 #define RDS_BUFFER 256 45 #define RDS_BUFFER 256
59 #define RDS_RX_FLAG 1 46 #define RDS_RX_FLAG 1
60 #define MBS_RX_FLAG 2 47 #define MBS_RX_FLAG 2
61 48
62 struct cadet { !! 49 #define CADET_VERSION KERNEL_VERSION(0,3,3)
63 struct v4l2_device v4l2_dev; !! 50
64 struct video_device vdev; !! 51 static struct v4l2_queryctrl radio_qctrl[] = {
65 int io; !! 52 {
66 int users; !! 53 .id = V4L2_CID_AUDIO_MUTE,
67 int curtuner; !! 54 .name = "Mute",
68 int tunestat; !! 55 .minimum = 0,
69 int sigstrength; !! 56 .maximum = 1,
70 wait_queue_head_t read_queue; !! 57 .default_value = 1,
71 struct timer_list readtimer; !! 58 .type = V4L2_CTRL_TYPE_BOOLEAN,
72 __u8 rdsin, rdsout, rdsstat; !! 59 },{
73 unsigned char rdsbuf[RDS_BUFFER]; !! 60 .id = V4L2_CID_AUDIO_VOLUME,
74 struct mutex lock; !! 61 .name = "Volume",
75 int reading; !! 62 .minimum = 0,
>> 63 .maximum = 0xff,
>> 64 .step = 1,
>> 65 .default_value = 0xff,
>> 66 .type = V4L2_CTRL_TYPE_INTEGER,
>> 67 }
76 }; 68 };
77 69
78 static struct cadet cadet_card; !! 70 static int io=-1; /* default to isapnp activation */
>> 71 static int radio_nr = -1;
>> 72 static int users=0;
>> 73 static int curtuner=0;
>> 74 static int tunestat=0;
>> 75 static int sigstrength=0;
>> 76 static wait_queue_head_t read_queue;
>> 77 static struct timer_list readtimer;
>> 78 static __u8 rdsin=0,rdsout=0,rdsstat=0;
>> 79 static unsigned char rdsbuf[RDS_BUFFER];
>> 80 static spinlock_t cadet_io_lock;
>> 81
>> 82 static int cadet_probe(void);
79 83
80 /* 84 /*
81 * Signal Strength Threshold Values 85 * Signal Strength Threshold Values
82 * The V4L API spec does not define any partic 86 * The V4L API spec does not define any particular unit for the signal
83 * strength value. These values are in microv 87 * strength value. These values are in microvolts of RF at the tuner's input.
84 */ 88 */
85 static __u16 sigtable[2][4] = { !! 89 static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
86 { 5, 10, 30, 150 }, <<
87 { 28, 40, 63, 1000 } <<
88 }; <<
89 90
90 91
91 static int cadet_getstereo(struct cadet *dev) !! 92 static int
>> 93 cadet_getstereo(void)
92 { 94 {
93 int ret = V4L2_TUNER_SUB_MONO; 95 int ret = V4L2_TUNER_SUB_MONO;
94 !! 96 if(curtuner != 0) /* Only FM has stereo capability! */
95 if (dev->curtuner != 0) /* Only FM has <<
96 return V4L2_TUNER_SUB_MONO; 97 return V4L2_TUNER_SUB_MONO;
97 98
98 mutex_lock(&dev->lock); !! 99 spin_lock(&cadet_io_lock);
99 outb(7, dev->io); /* Select t !! 100 outb(7,io); /* Select tuner control */
100 if ((inb(dev->io + 1) & 0x40) == 0) !! 101 if( (inb(io+1) & 0x40) == 0)
101 ret = V4L2_TUNER_SUB_STEREO; 102 ret = V4L2_TUNER_SUB_STEREO;
102 mutex_unlock(&dev->lock); !! 103 spin_unlock(&cadet_io_lock);
103 return ret; 104 return ret;
104 } 105 }
105 106
106 static unsigned cadet_gettune(struct cadet *de !! 107 static unsigned
>> 108 cadet_gettune(void)
107 { 109 {
108 int curvol, i; !! 110 int curvol,i;
109 unsigned fifo = 0; !! 111 unsigned fifo=0;
110 112
111 /* 113 /*
112 * Prepare for read 114 * Prepare for read
113 */ 115 */
114 116
115 mutex_lock(&dev->lock); !! 117 spin_lock(&cadet_io_lock);
116 118
117 outb(7, dev->io); /* Select tune !! 119 outb(7,io); /* Select tuner control */
118 curvol = inb(dev->io + 1); /* Save cur !! 120 curvol=inb(io+1); /* Save current volume/mute setting */
119 outb(0x00, dev->io + 1); /* Ensure WR !! 121 outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
120 dev->tunestat = 0xffff; !! 122 tunestat=0xffff;
121 123
122 /* 124 /*
123 * Read the shift register 125 * Read the shift register
124 */ 126 */
125 for (i = 0; i < 25; i++) { !! 127 for(i=0;i<25;i++) {
126 fifo = (fifo << 1) | ((inb(dev !! 128 fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
127 if (i < 24) { !! 129 if(i<24) {
128 outb(0x01, dev->io + 1 !! 130 outb(0x01,io+1);
129 dev->tunestat &= inb(d !! 131 tunestat&=inb(io+1);
130 outb(0x00, dev->io + 1 !! 132 outb(0x00,io+1);
131 } 133 }
132 } 134 }
133 135
134 /* 136 /*
135 * Restore volume/mute setting 137 * Restore volume/mute setting
136 */ 138 */
137 outb(curvol, dev->io + 1); !! 139 outb(curvol,io+1);
138 mutex_unlock(&dev->lock); !! 140 spin_unlock(&cadet_io_lock);
139 141
140 return fifo; 142 return fifo;
141 } 143 }
142 144
143 static unsigned cadet_getfreq(struct cadet *de !! 145 static unsigned
>> 146 cadet_getfreq(void)
144 { 147 {
145 int i; 148 int i;
146 unsigned freq = 0, test, fifo = 0; !! 149 unsigned freq=0,test,fifo=0;
147 150
148 /* 151 /*
149 * Read current tuning 152 * Read current tuning
150 */ 153 */
151 fifo = cadet_gettune(dev); !! 154 fifo=cadet_gettune();
152 155
153 /* 156 /*
154 * Convert to actual frequency 157 * Convert to actual frequency
155 */ 158 */
156 if (dev->curtuner == 0) { /* FM */ !! 159 if(curtuner==0) { /* FM */
157 test = 12500; !! 160 test=12500;
158 for (i = 0; i < 14; i++) { !! 161 for(i=0;i<14;i++) {
159 if ((fifo & 0x01) != 0 !! 162 if((fifo&0x01)!=0) {
160 freq += test; !! 163 freq+=test;
161 test = test << 1; !! 164 }
162 fifo = fifo >> 1; !! 165 test=test<<1;
>> 166 fifo=fifo>>1;
163 } 167 }
164 freq -= 10700000; /* !! 168 freq-=10700000; /* IF frequency is 10.7 MHz */
165 freq = (freq * 16) / 1000000; !! 169 freq=(freq*16)/1000000; /* Make it 1/16 MHz */
>> 170 }
>> 171 if(curtuner==1) { /* AM */
>> 172 freq=((fifo&0x7fff)-2010)*16;
166 } 173 }
167 if (dev->curtuner == 1) /* AM */ <<
168 freq = ((fifo & 0x7fff) - 2010 <<
169 174
170 return freq; 175 return freq;
171 } 176 }
172 177
173 static void cadet_settune(struct cadet *dev, u !! 178 static void
>> 179 cadet_settune(unsigned fifo)
174 { 180 {
175 int i; 181 int i;
176 unsigned test; 182 unsigned test;
177 183
178 mutex_lock(&dev->lock); !! 184 spin_lock(&cadet_io_lock);
179 185
180 outb(7, dev->io); /* Se !! 186 outb(7,io); /* Select tuner control */
181 /* 187 /*
182 * Write the shift register 188 * Write the shift register
183 */ 189 */
184 test = 0; !! 190 test=0;
185 test = (fifo >> 23) & 0x02; /* Al !! 191 test=(fifo>>23)&0x02; /* Align data for SDO */
186 test |= 0x1c; /* SDM=1, !! 192 test|=0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */
187 outb(7, dev->io); /* Se !! 193 outb(7,io); /* Select tuner control */
188 outb(test, dev->io + 1); /* !! 194 outb(test,io+1); /* Initialize for write */
189 for (i = 0; i < 25; i++) { !! 195 for(i=0;i<25;i++) {
190 test |= 0x01; /* !! 196 test|=0x01; /* Toggle SCK High */
191 outb(test, dev->io + 1); !! 197 outb(test,io+1);
192 test &= 0xfe; /* !! 198 test&=0xfe; /* Toggle SCK Low */
193 outb(test, dev->io + 1); !! 199 outb(test,io+1);
194 fifo = fifo << 1; / !! 200 fifo=fifo<<1; /* Prepare the next bit */
195 test = 0x1c | ((fifo >> 23) & !! 201 test=0x1c|((fifo>>23)&0x02);
196 outb(test, dev->io + 1); !! 202 outb(test,io+1);
197 } 203 }
198 mutex_unlock(&dev->lock); !! 204 spin_unlock(&cadet_io_lock);
199 } 205 }
200 206
201 static void cadet_setfreq(struct cadet *dev, u !! 207 static void
>> 208 cadet_setfreq(unsigned freq)
202 { 209 {
203 unsigned fifo; 210 unsigned fifo;
204 int i, j, test; !! 211 int i,j,test;
205 int curvol; 212 int curvol;
206 213
207 /* 214 /*
208 * Formulate a fifo command 215 * Formulate a fifo command
209 */ 216 */
210 fifo = 0; !! 217 fifo=0;
211 if (dev->curtuner == 0) { /* FM */ !! 218 if(curtuner==0) { /* FM */
212 test = 102400; !! 219 test=102400;
213 freq = (freq * 1000) / 16; !! 220 freq=(freq*1000)/16; /* Make it kHz */
214 freq += 10700; / !! 221 freq+=10700; /* IF is 10700 kHz */
215 for (i = 0; i < 14; i++) { !! 222 for(i=0;i<14;i++) {
216 fifo = fifo << 1; !! 223 fifo=fifo<<1;
217 if (freq >= test) { !! 224 if(freq>=test) {
218 fifo |= 0x01; !! 225 fifo|=0x01;
219 freq -= test; !! 226 freq-=test;
220 } 227 }
221 test = test >> 1; !! 228 test=test>>1;
222 } 229 }
223 } 230 }
224 if (dev->curtuner == 1) { /* AM */ !! 231 if(curtuner==1) { /* AM */
225 fifo = (freq / 16) + 2010; !! 232 fifo=(freq/16)+2010; /* Make it kHz */
226 fifo |= 0x100000; / !! 233 fifo|=0x100000; /* Select AM Band */
227 } 234 }
228 235
229 /* 236 /*
230 * Save current volume/mute setting 237 * Save current volume/mute setting
231 */ 238 */
232 239
233 mutex_lock(&dev->lock); !! 240 spin_lock(&cadet_io_lock);
234 outb(7, dev->io); /* Se !! 241 outb(7,io); /* Select tuner control */
235 curvol = inb(dev->io + 1); !! 242 curvol=inb(io+1);
236 mutex_unlock(&dev->lock); !! 243 spin_unlock(&cadet_io_lock);
237 244
238 /* 245 /*
239 * Tune the card 246 * Tune the card
240 */ 247 */
241 for (j = 3; j > -1; j--) { !! 248 for(j=3;j>-1;j--) {
242 cadet_settune(dev, fifo | (j < !! 249 cadet_settune(fifo|(j<<16));
243 250
244 mutex_lock(&dev->lock); !! 251 spin_lock(&cadet_io_lock);
245 outb(7, dev->io); /* S !! 252 outb(7,io); /* Select tuner control */
246 outb(curvol, dev->io + 1); !! 253 outb(curvol,io+1);
247 mutex_unlock(&dev->lock); !! 254 spin_unlock(&cadet_io_lock);
248 255
249 msleep(100); 256 msleep(100);
250 257
251 cadet_gettune(dev); !! 258 cadet_gettune();
252 if ((dev->tunestat & 0x40) == !! 259 if((tunestat & 0x40) == 0) { /* Tuned */
253 dev->sigstrength = sig !! 260 sigstrength=sigtable[curtuner][j];
254 return; 261 return;
255 } 262 }
256 } 263 }
257 dev->sigstrength = 0; !! 264 sigstrength=0;
258 } 265 }
259 266
260 267
261 static int cadet_getvol(struct cadet *dev) !! 268 static int
>> 269 cadet_getvol(void)
262 { 270 {
263 int ret = 0; 271 int ret = 0;
264 272
265 mutex_lock(&dev->lock); !! 273 spin_lock(&cadet_io_lock);
266 274
267 outb(7, dev->io); /* Se !! 275 outb(7,io); /* Select tuner control */
268 if ((inb(dev->io + 1) & 0x20) != 0) !! 276 if((inb(io + 1) & 0x20) != 0)
269 ret = 0xffff; 277 ret = 0xffff;
270 278
271 mutex_unlock(&dev->lock); !! 279 spin_unlock(&cadet_io_lock);
272 return ret; 280 return ret;
273 } 281 }
274 282
275 283
276 static void cadet_setvol(struct cadet *dev, in !! 284 static void
>> 285 cadet_setvol(int vol)
277 { 286 {
278 mutex_lock(&dev->lock); !! 287 spin_lock(&cadet_io_lock);
279 outb(7, dev->io); /* Se !! 288 outb(7,io); /* Select tuner control */
280 if (vol > 0) !! 289 if(vol>0)
281 outb(0x20, dev->io + 1); !! 290 outb(0x20,io+1);
282 else 291 else
283 outb(0x00, dev->io + 1); !! 292 outb(0x00,io+1);
284 mutex_unlock(&dev->lock); !! 293 spin_unlock(&cadet_io_lock);
285 } 294 }
286 295
287 static void cadet_handler(unsigned long data) !! 296 static void
>> 297 cadet_handler(unsigned long data)
288 { 298 {
289 struct cadet *dev = (void *)data; !! 299 /*
>> 300 * Service the RDS fifo
>> 301 */
290 302
291 /* Service the RDS fifo */ !! 303 if(spin_trylock(&cadet_io_lock))
292 if (mutex_trylock(&dev->lock)) { !! 304 {
293 outb(0x3, dev->io); /* S !! 305 outb(0x3,io); /* Select RDS Decoder Control */
294 if ((inb(dev->io + 1) & 0x20) !! 306 if((inb(io+1)&0x20)!=0) {
295 printk(KERN_CRIT "cade 307 printk(KERN_CRIT "cadet: RDS fifo overflow\n");
296 outb(0x80, dev->io); /* S !! 308 }
297 while ((inb(dev->io) & 0x80) ! !! 309 outb(0x80,io); /* Select RDS fifo */
298 dev->rdsbuf[dev->rdsin !! 310 while((inb(io)&0x80)!=0) {
299 if (dev->rdsin == dev- !! 311 rdsbuf[rdsin]=inb(io+1);
>> 312 if(rdsin==rdsout)
300 printk(KERN_WA 313 printk(KERN_WARNING "cadet: RDS buffer overflow\n");
301 else 314 else
302 dev->rdsin++; !! 315 rdsin++;
303 } 316 }
304 mutex_unlock(&dev->lock); !! 317 spin_unlock(&cadet_io_lock);
305 } 318 }
306 319
307 /* 320 /*
308 * Service pending read 321 * Service pending read
309 */ 322 */
310 if (dev->rdsin != dev->rdsout) !! 323 if( rdsin!=rdsout)
311 wake_up_interruptible(&dev->re !! 324 wake_up_interruptible(&read_queue);
312 325
313 /* 326 /*
314 * Clean up and exit 327 * Clean up and exit
315 */ 328 */
316 init_timer(&dev->readtimer); !! 329 init_timer(&readtimer);
317 dev->readtimer.function = cadet_handle !! 330 readtimer.function=cadet_handler;
318 dev->readtimer.data = (unsigned long)0 !! 331 readtimer.data=(unsigned long)0;
319 dev->readtimer.expires = jiffies + mse !! 332 readtimer.expires=jiffies+msecs_to_jiffies(50);
320 add_timer(&dev->readtimer); !! 333 add_timer(&readtimer);
321 } 334 }
322 335
323 336
324 static ssize_t cadet_read(struct file *file, c !! 337
>> 338 static ssize_t
>> 339 cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
325 { 340 {
326 struct cadet *dev = video_drvdata(file !! 341 int i=0;
327 unsigned char readbuf[RDS_BUFFER]; 342 unsigned char readbuf[RDS_BUFFER];
328 int i = 0; <<
329 343
330 if (dev->rdsstat == 0) { !! 344 if(rdsstat==0) {
331 mutex_lock(&dev->lock); !! 345 spin_lock(&cadet_io_lock);
332 dev->rdsstat = 1; !! 346 rdsstat=1;
333 outb(0x80, dev->io); /* !! 347 outb(0x80,io); /* Select RDS fifo */
334 mutex_unlock(&dev->lock); !! 348 spin_unlock(&cadet_io_lock);
335 init_timer(&dev->readtimer); !! 349 init_timer(&readtimer);
336 dev->readtimer.function = cade !! 350 readtimer.function=cadet_handler;
337 dev->readtimer.data = (unsigne !! 351 readtimer.data=(unsigned long)0;
338 dev->readtimer.expires = jiffi !! 352 readtimer.expires=jiffies+msecs_to_jiffies(50);
339 add_timer(&dev->readtimer); !! 353 add_timer(&readtimer);
340 } 354 }
341 if (dev->rdsin == dev->rdsout) { !! 355 if(rdsin==rdsout) {
342 if (file->f_flags & O_NONBLOCK 356 if (file->f_flags & O_NONBLOCK)
343 return -EWOULDBLOCK; 357 return -EWOULDBLOCK;
344 interruptible_sleep_on(&dev->r !! 358 interruptible_sleep_on(&read_queue);
345 } 359 }
346 while (i < count && dev->rdsin != dev- !! 360 while( i<count && rdsin!=rdsout)
347 readbuf[i++] = dev->rdsbuf[dev !! 361 readbuf[i++]=rdsbuf[rdsout++];
348 362
349 if (copy_to_user(data, readbuf, i)) !! 363 if (copy_to_user(data,readbuf,i))
350 return -EFAULT; 364 return -EFAULT;
351 return i; 365 return i;
352 } 366 }
353 367
354 368
355 static int vidioc_querycap(struct file *file, 369 static int vidioc_querycap(struct file *file, void *priv,
356 struct v4l2_ca 370 struct v4l2_capability *v)
357 { 371 {
358 strlcpy(v->driver, "ADS Cadet", sizeof !! 372 v->capabilities =
359 strlcpy(v->card, "ADS Cadet", sizeof(v !! 373 V4L2_CAP_TUNER |
360 strlcpy(v->bus_info, "ISA", sizeof(v-> !! 374 V4L2_CAP_READWRITE;
361 v->version = CADET_VERSION; 375 v->version = CADET_VERSION;
362 v->capabilities = V4L2_CAP_TUNER | V4L !! 376 strcpy(v->driver, "ADS Cadet");
>> 377 strcpy(v->card, "ADS Cadet");
363 return 0; 378 return 0;
364 } 379 }
365 380
366 static int vidioc_g_tuner(struct file *file, v 381 static int vidioc_g_tuner(struct file *file, void *priv,
367 struct v4l2_tu 382 struct v4l2_tuner *v)
368 { 383 {
369 struct cadet *dev = video_drvdata(file <<
370 <<
371 v->type = V4L2_TUNER_RADIO; 384 v->type = V4L2_TUNER_RADIO;
372 switch (v->index) { 385 switch (v->index) {
373 case 0: 386 case 0:
374 strlcpy(v->name, "FM", sizeof( !! 387 strcpy(v->name, "FM");
375 v->capability = V4L2_TUNER_CAP 388 v->capability = V4L2_TUNER_CAP_STEREO;
376 v->rangelow = 1400; /* 87. 389 v->rangelow = 1400; /* 87.5 MHz */
377 v->rangehigh = 1728; /* 108 390 v->rangehigh = 1728; /* 108.0 MHz */
378 v->rxsubchans = cadet_getstere !! 391 v->rxsubchans=cadet_getstereo();
379 switch (v->rxsubchans) { !! 392 switch (v->rxsubchans){
380 case V4L2_TUNER_SUB_MONO: 393 case V4L2_TUNER_SUB_MONO:
381 v->audmode = V4L2_TUNE 394 v->audmode = V4L2_TUNER_MODE_MONO;
382 break; 395 break;
383 case V4L2_TUNER_SUB_STEREO: 396 case V4L2_TUNER_SUB_STEREO:
384 v->audmode = V4L2_TUNE 397 v->audmode = V4L2_TUNER_MODE_STEREO;
385 break; 398 break;
386 default: !! 399 default: ;
387 break; <<
388 } 400 }
389 break; 401 break;
390 case 1: 402 case 1:
391 strlcpy(v->name, "AM", sizeof( !! 403 strcpy(v->name, "AM");
392 v->capability = V4L2_TUNER_CAP 404 v->capability = V4L2_TUNER_CAP_LOW;
393 v->rangelow = 8320; /* 52 405 v->rangelow = 8320; /* 520 kHz */
394 v->rangehigh = 26400; /* 16 406 v->rangehigh = 26400; /* 1650 kHz */
395 v->rxsubchans = V4L2_TUNER_SUB 407 v->rxsubchans = V4L2_TUNER_SUB_MONO;
396 v->audmode = V4L2_TUNER_MODE_M 408 v->audmode = V4L2_TUNER_MODE_MONO;
397 break; 409 break;
398 default: 410 default:
399 return -EINVAL; 411 return -EINVAL;
400 } 412 }
401 v->signal = dev->sigstrength; /* We mi !! 413 v->signal = sigstrength; /* We might need to modify scaling of this */
402 return 0; 414 return 0;
403 } 415 }
404 416
405 static int vidioc_s_tuner(struct file *file, v 417 static int vidioc_s_tuner(struct file *file, void *priv,
406 struct v4l2_tu 418 struct v4l2_tuner *v)
407 { 419 {
408 struct cadet *dev = video_drvdata(file !! 420 if((v->index != 0)&&(v->index != 1))
409 <<
410 if (v->index != 0 && v->index != 1) <<
411 return -EINVAL; 421 return -EINVAL;
412 dev->curtuner = v->index; !! 422 curtuner = v->index;
413 return 0; 423 return 0;
414 } 424 }
415 425
416 static int vidioc_g_frequency(struct file *fil 426 static int vidioc_g_frequency(struct file *file, void *priv,
417 struct v4l2_fr 427 struct v4l2_frequency *f)
418 { 428 {
419 struct cadet *dev = video_drvdata(file !! 429 f->tuner = curtuner;
420 <<
421 f->tuner = dev->curtuner; <<
422 f->type = V4L2_TUNER_RADIO; 430 f->type = V4L2_TUNER_RADIO;
423 f->frequency = cadet_getfreq(dev); !! 431 f->frequency = cadet_getfreq();
424 return 0; 432 return 0;
425 } 433 }
426 434
427 435
428 static int vidioc_s_frequency(struct file *fil 436 static int vidioc_s_frequency(struct file *file, void *priv,
429 struct v4l2_fr 437 struct v4l2_frequency *f)
430 { 438 {
431 struct cadet *dev = video_drvdata(file <<
432 <<
433 if (f->type != V4L2_TUNER_RADIO) 439 if (f->type != V4L2_TUNER_RADIO)
434 return -EINVAL; 440 return -EINVAL;
435 if (dev->curtuner == 0 && (f->frequenc !! 441 if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728)))
436 return -EINVAL; 442 return -EINVAL;
437 if (dev->curtuner == 1 && (f->frequenc !! 443 if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400)))
438 return -EINVAL; 444 return -EINVAL;
439 cadet_setfreq(dev, f->frequency); !! 445 cadet_setfreq(f->frequency);
440 return 0; 446 return 0;
441 } 447 }
442 448
443 static int vidioc_queryctrl(struct file *file, 449 static int vidioc_queryctrl(struct file *file, void *priv,
444 struct v4l2_qu 450 struct v4l2_queryctrl *qc)
445 { 451 {
446 switch (qc->id) { !! 452 int i;
447 case V4L2_CID_AUDIO_MUTE: !! 453
448 return v4l2_ctrl_query_fill(qc !! 454 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
449 case V4L2_CID_AUDIO_VOLUME: !! 455 if (qc->id && qc->id == radio_qctrl[i].id) {
450 return v4l2_ctrl_query_fill(qc !! 456 memcpy(qc, &(radio_qctrl[i]),
>> 457 sizeof(*qc));
>> 458 return 0;
>> 459 }
451 } 460 }
452 return -EINVAL; 461 return -EINVAL;
453 } 462 }
454 463
455 static int vidioc_g_ctrl(struct file *file, vo 464 static int vidioc_g_ctrl(struct file *file, void *priv,
456 struct v4l2_co 465 struct v4l2_control *ctrl)
457 { 466 {
458 struct cadet *dev = video_drvdata(file !! 467 switch (ctrl->id){
459 <<
460 switch (ctrl->id) { <<
461 case V4L2_CID_AUDIO_MUTE: /* TODO: Han 468 case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
462 ctrl->value = (cadet_getvol(de !! 469 ctrl->value = (cadet_getvol() == 0);
463 break; 470 break;
464 case V4L2_CID_AUDIO_VOLUME: 471 case V4L2_CID_AUDIO_VOLUME:
465 ctrl->value = cadet_getvol(dev !! 472 ctrl->value = cadet_getvol();
466 break; 473 break;
467 default: 474 default:
468 return -EINVAL; 475 return -EINVAL;
469 } 476 }
470 return 0; 477 return 0;
471 } 478 }
472 479
473 static int vidioc_s_ctrl(struct file *file, vo 480 static int vidioc_s_ctrl(struct file *file, void *priv,
474 struct v4l2_co 481 struct v4l2_control *ctrl)
475 { 482 {
476 struct cadet *dev = video_drvdata(file <<
477 <<
478 switch (ctrl->id){ 483 switch (ctrl->id){
479 case V4L2_CID_AUDIO_MUTE: /* TODO: Han 484 case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
480 if (ctrl->value) 485 if (ctrl->value)
481 cadet_setvol(dev, 0); !! 486 cadet_setvol(0);
482 else 487 else
483 cadet_setvol(dev, 0xff !! 488 cadet_setvol(0xffff);
484 break; 489 break;
485 case V4L2_CID_AUDIO_VOLUME: 490 case V4L2_CID_AUDIO_VOLUME:
486 cadet_setvol(dev, ctrl->value) !! 491 cadet_setvol(ctrl->value);
487 break; 492 break;
488 default: 493 default:
489 return -EINVAL; 494 return -EINVAL;
490 } 495 }
491 return 0; 496 return 0;
492 } 497 }
493 498
494 static int vidioc_g_input(struct file *filp, v !! 499 static int vidioc_g_audio(struct file *file, void *priv,
>> 500 struct v4l2_audio *a)
495 { 501 {
496 *i = 0; !! 502 if (a->index > 1)
>> 503 return -EINVAL;
>> 504 strcpy(a->name, "Radio");
>> 505 a->capability = V4L2_AUDCAP_STEREO;
497 return 0; 506 return 0;
498 } 507 }
499 508
500 static int vidioc_s_input(struct file *filp, v !! 509 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
501 { 510 {
502 return i ? -EINVAL : 0; !! 511 *i = 0;
>> 512 return 0;
503 } 513 }
504 514
505 static int vidioc_g_audio(struct file *file, v !! 515 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
506 struct v4l2_au <<
507 { 516 {
508 a->index = 0; !! 517 if (i != 0)
509 strlcpy(a->name, "Radio", sizeof(a->na !! 518 return -EINVAL;
510 a->capability = V4L2_AUDCAP_STEREO; <<
511 return 0; 519 return 0;
512 } 520 }
513 521
514 static int vidioc_s_audio(struct file *file, v 522 static int vidioc_s_audio(struct file *file, void *priv,
515 struct v4l2_au 523 struct v4l2_audio *a)
516 { 524 {
517 return a->index ? -EINVAL : 0; !! 525 if (a->index != 0)
>> 526 return -EINVAL;
>> 527 return 0;
518 } 528 }
519 529
520 static int cadet_open(struct file *file) !! 530 static int
>> 531 cadet_open(struct inode *inode, struct file *file)
521 { 532 {
522 struct cadet *dev = video_drvdata(file !! 533 users++;
523 !! 534 if (1 == users) init_waitqueue_head(&read_queue);
524 dev->users++; <<
525 if (1 == dev->users) <<
526 init_waitqueue_head(&dev->read <<
527 return 0; 535 return 0;
528 } 536 }
529 537
530 static int cadet_release(struct file *file) !! 538 static int
>> 539 cadet_release(struct inode *inode, struct file *file)
531 { 540 {
532 struct cadet *dev = video_drvdata(file !! 541 users--;
533 !! 542 if (0 == users){
534 dev->users--; !! 543 del_timer_sync(&readtimer);
535 if (0 == dev->users) { !! 544 rdsstat=0;
536 del_timer_sync(&dev->readtimer <<
537 dev->rdsstat = 0; <<
538 } 545 }
539 return 0; 546 return 0;
540 } 547 }
541 548
542 static unsigned int cadet_poll(struct file *fi !! 549 static unsigned int
>> 550 cadet_poll(struct file *file, struct poll_table_struct *wait)
543 { 551 {
544 struct cadet *dev = video_drvdata(file !! 552 poll_wait(file,&read_queue,wait);
545 !! 553 if(rdsin != rdsout)
546 poll_wait(file, &dev->read_queue, wait <<
547 if (dev->rdsin != dev->rdsout) <<
548 return POLLIN | POLLRDNORM; 554 return POLLIN | POLLRDNORM;
549 return 0; 555 return 0;
550 } 556 }
551 557
552 558
553 static const struct v4l2_file_operations cadet !! 559 static const struct file_operations cadet_fops = {
554 .owner = THIS_MODULE, 560 .owner = THIS_MODULE,
555 .open = cadet_open, 561 .open = cadet_open,
556 .release = cadet_release, 562 .release = cadet_release,
557 .read = cadet_read, 563 .read = cadet_read,
558 .ioctl = video_ioctl2, 564 .ioctl = video_ioctl2,
559 .poll = cadet_poll, 565 .poll = cadet_poll,
>> 566 .compat_ioctl = v4l_compat_ioctl32,
>> 567 .llseek = no_llseek,
560 }; 568 };
561 569
562 static const struct v4l2_ioctl_ops cadet_ioctl !! 570 static struct video_device cadet_radio=
>> 571 {
>> 572 .owner = THIS_MODULE,
>> 573 .name = "Cadet radio",
>> 574 .type = VID_TYPE_TUNER,
>> 575 .fops = &cadet_fops,
563 .vidioc_querycap = vidioc_querycap, 576 .vidioc_querycap = vidioc_querycap,
564 .vidioc_g_tuner = vidioc_g_tuner, 577 .vidioc_g_tuner = vidioc_g_tuner,
565 .vidioc_s_tuner = vidioc_s_tuner, 578 .vidioc_s_tuner = vidioc_s_tuner,
566 .vidioc_g_frequency = vidioc_g_frequen 579 .vidioc_g_frequency = vidioc_g_frequency,
567 .vidioc_s_frequency = vidioc_s_frequen 580 .vidioc_s_frequency = vidioc_s_frequency,
568 .vidioc_queryctrl = vidioc_queryctrl 581 .vidioc_queryctrl = vidioc_queryctrl,
569 .vidioc_g_ctrl = vidioc_g_ctrl, 582 .vidioc_g_ctrl = vidioc_g_ctrl,
570 .vidioc_s_ctrl = vidioc_s_ctrl, 583 .vidioc_s_ctrl = vidioc_s_ctrl,
571 .vidioc_g_audio = vidioc_g_audio, 584 .vidioc_g_audio = vidioc_g_audio,
572 .vidioc_s_audio = vidioc_s_audio, 585 .vidioc_s_audio = vidioc_s_audio,
573 .vidioc_g_input = vidioc_g_input, 586 .vidioc_g_input = vidioc_g_input,
574 .vidioc_s_input = vidioc_s_input, 587 .vidioc_s_input = vidioc_s_input,
575 }; 588 };
576 589
577 #ifdef CONFIG_PNP 590 #ifdef CONFIG_PNP
578 591
579 static struct pnp_device_id cadet_pnp_devices[ 592 static struct pnp_device_id cadet_pnp_devices[] = {
580 /* ADS Cadet AM/FM Radio Card */ 593 /* ADS Cadet AM/FM Radio Card */
581 {.id = "MSM0c24", .driver_data = 0}, 594 {.id = "MSM0c24", .driver_data = 0},
582 {.id = ""} 595 {.id = ""}
583 }; 596 };
584 597
585 MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices); 598 MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices);
586 599
587 static int cadet_pnp_probe(struct pnp_dev *dev !! 600 static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
588 { 601 {
589 if (!dev) 602 if (!dev)
590 return -ENODEV; 603 return -ENODEV;
591 /* only support one device */ 604 /* only support one device */
592 if (io > 0) 605 if (io > 0)
593 return -EBUSY; 606 return -EBUSY;
594 607
595 if (!pnp_port_valid(dev, 0)) !! 608 if (!pnp_port_valid(dev, 0)) {
596 return -ENODEV; 609 return -ENODEV;
>> 610 }
597 611
598 io = pnp_port_start(dev, 0); 612 io = pnp_port_start(dev, 0);
599 613
600 printk(KERN_INFO "radio-cadet: PnP rep !! 614 printk ("radio-cadet: PnP reports device at %#x\n", io);
601 615
602 return io; 616 return io;
603 } 617 }
604 618
605 static struct pnp_driver cadet_pnp_driver = { 619 static struct pnp_driver cadet_pnp_driver = {
606 .name = "radio-cadet", 620 .name = "radio-cadet",
607 .id_table = cadet_pnp_devices, 621 .id_table = cadet_pnp_devices,
608 .probe = cadet_pnp_probe, 622 .probe = cadet_pnp_probe,
609 .remove = NULL, 623 .remove = NULL,
610 }; 624 };
611 625
612 #else 626 #else
613 static struct pnp_driver cadet_pnp_driver; 627 static struct pnp_driver cadet_pnp_driver;
614 #endif 628 #endif
615 629
616 static void cadet_probe(struct cadet *dev) !! 630 static int cadet_probe(void)
617 { 631 {
618 static int iovals[8] = { 0x330, 0x332, !! 632 static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
619 int i; 633 int i;
620 634
621 for (i = 0; i < 8; i++) { !! 635 for(i=0;i<8;i++) {
622 dev->io = iovals[i]; !! 636 io=iovals[i];
623 if (request_region(dev->io, 2, !! 637 if (request_region(io, 2, "cadet-probe")) {
624 cadet_setfreq(dev, 141 !! 638 cadet_setfreq(1410);
625 if (cadet_getfreq(dev) !! 639 if(cadet_getfreq()==1410) {
626 release_region !! 640 release_region(io, 2);
627 return; !! 641 return io;
628 } 642 }
629 release_region(dev->io !! 643 release_region(io, 2);
630 } 644 }
631 } 645 }
632 dev->io = -1; !! 646 return -1;
633 } 647 }
634 648
635 /* 649 /*
636 * io should only be set if the user has used 650 * io should only be set if the user has used something like
637 * isapnp (the userspace program) to initializ 651 * isapnp (the userspace program) to initialize this card for us
638 */ 652 */
639 653
640 static int __init cadet_init(void) 654 static int __init cadet_init(void)
641 { 655 {
642 struct cadet *dev = &cadet_card; !! 656 spin_lock_init(&cadet_io_lock);
643 struct v4l2_device *v4l2_dev = &dev->v <<
644 int res; <<
645 657
646 strlcpy(v4l2_dev->name, "cadet", sizeo !! 658 /*
647 mutex_init(&dev->lock); !! 659 * If a probe was requested then probe ISAPnP first (safest)
648 !! 660 */
649 /* If a probe was requested then probe <<
650 if (io < 0) 661 if (io < 0)
651 pnp_register_driver(&cadet_pnp 662 pnp_register_driver(&cadet_pnp_driver);
652 dev->io = io; !! 663 /*
>> 664 * If that fails then probe unsafely if probe is requested
>> 665 */
>> 666 if(io < 0)
>> 667 io = cadet_probe ();
653 668
654 /* If that fails then probe unsafely i !! 669 /*
655 if (dev->io < 0) !! 670 * Else we bail out
656 cadet_probe(dev); !! 671 */
657 672
658 /* Else we bail out */ !! 673 if(io < 0) {
659 if (dev->io < 0) { <<
660 #ifdef MODULE 674 #ifdef MODULE
661 v4l2_err(v4l2_dev, "you must s !! 675 printk(KERN_ERR "You must set an I/O address with io=0x???\n");
662 v4l2_err(v4l2_dev, "0x336, 0x3 <<
663 #endif 676 #endif
664 goto fail; 677 goto fail;
665 } 678 }
666 if (!request_region(dev->io, 2, "cadet !! 679 if (!request_region(io,2,"cadet"))
667 goto fail; 680 goto fail;
668 !! 681 if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) {
669 res = v4l2_device_register(NULL, v4l2_ !! 682 release_region(io,2);
670 if (res < 0) { <<
671 release_region(dev->io, 2); <<
672 v4l2_err(v4l2_dev, "could not <<
673 goto fail; 683 goto fail;
674 } 684 }
675 !! 685 printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
676 strlcpy(dev->vdev.name, v4l2_dev->name <<
677 dev->vdev.v4l2_dev = v4l2_dev; <<
678 dev->vdev.fops = &cadet_fops; <<
679 dev->vdev.ioctl_ops = &cadet_ioctl_ops <<
680 dev->vdev.release = video_device_relea <<
681 video_set_drvdata(&dev->vdev, dev); <<
682 <<
683 if (video_register_device(&dev->vdev, <<
684 v4l2_device_unregister(v4l2_de <<
685 release_region(dev->io, 2); <<
686 goto fail; <<
687 } <<
688 v4l2_info(v4l2_dev, "ADS Cadet Radio C <<
689 return 0; 686 return 0;
690 fail: 687 fail:
691 pnp_unregister_driver(&cadet_pnp_drive 688 pnp_unregister_driver(&cadet_pnp_driver);
692 return -ENODEV; !! 689 return -1;
693 } 690 }
694 691
695 static void __exit cadet_exit(void) <<
696 { <<
697 struct cadet *dev = &cadet_card; <<
698 692
699 video_unregister_device(&dev->vdev); !! 693
700 v4l2_device_unregister(&dev->v4l2_dev) !! 694 MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
701 release_region(dev->io, 2); !! 695 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
>> 696 MODULE_LICENSE("GPL");
>> 697
>> 698 module_param(io, int, 0);
>> 699 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
>> 700 module_param(radio_nr, int, 0);
>> 701
>> 702 static void __exit cadet_cleanup_module(void)
>> 703 {
>> 704 video_unregister_device(&cadet_radio);
>> 705 release_region(io,2);
702 pnp_unregister_driver(&cadet_pnp_drive 706 pnp_unregister_driver(&cadet_pnp_driver);
703 } 707 }
704 708
705 module_init(cadet_init); 709 module_init(cadet_init);
706 module_exit(cadet_exit); !! 710 module_exit(cadet_cleanup_module);
707 711
708 712
|
This page was automatically generated by the
LXR engine.
|