V4L/DVB (7402): add macro validation for v4l_compat_ioctl32
[linux-2.6.git] / drivers / media / radio / dsbr100.c
1 /* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
2  into both the USB and an analog audio input, so this thing
3  only deals with initialisation and frequency setting, the
4  audio data has to be handled by a sound driver.
5
6  Major issue: I can't find out where the device reports the signal
7  strength, and indeed the windows software appearantly just looks
8  at the stereo indicator as well.  So, scanning will only find
9  stereo stations.  Sad, but I can't help it.
10
11  Also, the windows program sends oodles of messages over to the
12  device, and I couldn't figure out their meaning.  My suspicion
13  is that they don't have any:-)
14
15  You might find some interesting stuff about this module at
16  http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
17
18  Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
19
20  This program is free software; you can redistribute it and/or modify
21  it under the terms of the GNU General Public License as published by
22  the Free Software Foundation; either version 2 of the License, or
23  (at your option) any later version.
24
25  This program is distributed in the hope that it will be useful,
26  but WITHOUT ANY WARRANTY; without even the implied warranty of
27  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  GNU General Public License for more details.
29
30  You should have received a copy of the GNU General Public License
31  along with this program; if not, write to the Free Software
32  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33
34  History:
35
36  Version 0.43:
37         Oliver Neukum: avoided DMA coherency issue
38
39  Version 0.42:
40         Converted dsbr100 to use video_ioctl2
41         by Douglas Landgraf <dougsland@gmail.com>
42
43  Version 0.41-ac1:
44         Alan Cox: Some cleanups and fixes
45
46  Version 0.41:
47         Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
48
49  Version 0.40:
50         Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
51
52  Version 0.30:
53         Markus: Updates for 2.5.x kernel and more ISO compliant source
54
55  Version 0.25:
56         PSL and Markus: Cleanup, radio now doesn't stop on device close
57
58  Version 0.24:
59         Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
60         right.  Some minor cleanup, improved standalone compilation
61
62  Version 0.23:
63         Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
64
65  Version 0.22:
66         Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
67         thanks to Mike Cox for pointing the problem out.
68
69  Version 0.21:
70         Markus: Minor cleanup, warnings if something goes wrong, lame attempt
71         to adhere to Documentation/CodingStyle
72
73  Version 0.2:
74         Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
75         Markus: Copyright clarification
76
77  Version 0.01: Markus: initial release
78
79 */
80
81 #include <linux/kernel.h>
82 #include <linux/module.h>
83 #include <linux/init.h>
84 #include <linux/slab.h>
85 #include <linux/input.h>
86 #include <linux/videodev2.h>
87 #include <media/v4l2-common.h>
88 #include <linux/usb.h>
89
90 /*
91  * Version Information
92  */
93 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
94
95 #define DRIVER_VERSION "v0.41"
96 #define RADIO_VERSION KERNEL_VERSION(0,4,1)
97
98 static struct v4l2_queryctrl radio_qctrl[] = {
99         {
100                 .id            = V4L2_CID_AUDIO_MUTE,
101                 .name          = "Mute",
102                 .minimum       = 0,
103                 .maximum       = 1,
104                 .default_value = 1,
105                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
106         }
107 };
108
109 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
110 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
111
112 #define DSB100_VENDOR 0x04b4
113 #define DSB100_PRODUCT 0x1002
114
115 /* Commands the device appears to understand */
116 #define DSB100_TUNE 1
117 #define DSB100_ONOFF 2
118
119 #define TB_LEN 16
120
121 /* Frequency limits in MHz -- these are European values.  For Japanese
122 devices, that would be 76 and 91.  */
123 #define FREQ_MIN  87.5
124 #define FREQ_MAX 108.0
125 #define FREQ_MUL 16000
126
127
128 static int usb_dsbr100_probe(struct usb_interface *intf,
129                              const struct usb_device_id *id);
130 static void usb_dsbr100_disconnect(struct usb_interface *intf);
131 static int usb_dsbr100_open(struct inode *inode, struct file *file);
132 static int usb_dsbr100_close(struct inode *inode, struct file *file);
133
134 static int radio_nr = -1;
135 module_param(radio_nr, int, 0);
136
137 /* Data for one (physical) device */
138 struct dsbr100_device {
139         struct usb_device *usbdev;
140         struct video_device *videodev;
141         u8 *transfer_buffer;
142         int curfreq;
143         int stereo;
144         int users;
145         int removed;
146         int muted;
147 };
148
149
150 static struct usb_device_id usb_dsbr100_device_table [] = {
151         { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
152         { }                                             /* Terminating entry */
153 };
154
155 MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
156
157 /* USB subsystem interface */
158 static struct usb_driver usb_dsbr100_driver = {
159         .name =         "dsbr100",
160         .probe =        usb_dsbr100_probe,
161         .disconnect =   usb_dsbr100_disconnect,
162         .id_table =     usb_dsbr100_device_table,
163 };
164
165 /* Low-level device interface begins here */
166
167 /* switch on radio */
168 static int dsbr100_start(struct dsbr100_device *radio)
169 {
170         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
171                         USB_REQ_GET_STATUS,
172                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
173                         0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
174         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
175                         DSB100_ONOFF,
176                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
177                         0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
178                 return -1;
179         radio->muted=0;
180         return (radio->transfer_buffer)[0];
181 }
182
183
184 /* switch off radio */
185 static int dsbr100_stop(struct dsbr100_device *radio)
186 {
187         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
188                         USB_REQ_GET_STATUS,
189                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
190                         0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
191         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
192                         DSB100_ONOFF,
193                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
194                         0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
195                 return -1;
196         radio->muted=1;
197         return (radio->transfer_buffer)[0];
198 }
199
200 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
201 static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
202 {
203         freq = (freq/16*80)/1000+856;
204         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
205                         DSB100_TUNE,
206                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
207                         (freq>>8)&0x00ff, freq&0xff,
208                         radio->transfer_buffer, 8, 300)<0 ||
209            usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
210                         USB_REQ_GET_STATUS,
211                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
212                         0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
213         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
214                         USB_REQ_GET_STATUS,
215                         USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
216                         0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
217                 radio->stereo = -1;
218                 return -1;
219         }
220         radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
221         return (radio->transfer_buffer)[0];
222 }
223
224 /* return the device status.  This is, in effect, just whether it
225 sees a stereo signal or not.  Pity. */
226 static void dsbr100_getstat(struct dsbr100_device *radio)
227 {
228         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
229                 USB_REQ_GET_STATUS,
230                 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
231                 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
232                 radio->stereo = -1;
233         else
234                 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
235 }
236
237
238 /* USB subsystem interface begins here */
239
240 /* handle unplugging of the device, release data structures
241 if nothing keeps us from doing it.  If something is still
242 keeping us busy, the release callback of v4l will take care
243 of releasing it. */
244 static void usb_dsbr100_disconnect(struct usb_interface *intf)
245 {
246         struct dsbr100_device *radio = usb_get_intfdata(intf);
247
248         usb_set_intfdata (intf, NULL);
249         if (radio) {
250                 video_unregister_device(radio->videodev);
251                 radio->videodev = NULL;
252                 if (radio->users) {
253                         kfree(radio->transfer_buffer);
254                         kfree(radio);
255                 } else {
256                         radio->removed = 1;
257                 }
258         }
259 }
260
261
262 static int vidioc_querycap(struct file *file, void *priv,
263                                         struct v4l2_capability *v)
264 {
265         strlcpy(v->driver, "dsbr100", sizeof(v->driver));
266         strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
267         sprintf(v->bus_info, "ISA");
268         v->version = RADIO_VERSION;
269         v->capabilities = V4L2_CAP_TUNER;
270         return 0;
271 }
272
273 static int vidioc_g_tuner(struct file *file, void *priv,
274                                 struct v4l2_tuner *v)
275 {
276         struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
277
278         if (v->index > 0)
279                 return -EINVAL;
280
281         dsbr100_getstat(radio);
282         strcpy(v->name, "FM");
283         v->type = V4L2_TUNER_RADIO;
284         v->rangelow = FREQ_MIN*FREQ_MUL;
285         v->rangehigh = FREQ_MAX*FREQ_MUL;
286         v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
287         v->capability = V4L2_TUNER_CAP_LOW;
288         if(radio->stereo)
289                 v->audmode = V4L2_TUNER_MODE_STEREO;
290         else
291                 v->audmode = V4L2_TUNER_MODE_MONO;
292         v->signal = 0xffff;     /* We can't get the signal strength */
293         return 0;
294 }
295
296 static int vidioc_s_tuner(struct file *file, void *priv,
297                                 struct v4l2_tuner *v)
298 {
299         if (v->index > 0)
300                 return -EINVAL;
301
302         return 0;
303 }
304
305 static int vidioc_s_frequency(struct file *file, void *priv,
306                                 struct v4l2_frequency *f)
307 {
308         struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
309
310         radio->curfreq = f->frequency;
311         if (dsbr100_setfreq(radio, radio->curfreq)==-1)
312                 warn("Set frequency failed");
313         return 0;
314 }
315
316 static int vidioc_g_frequency(struct file *file, void *priv,
317                                 struct v4l2_frequency *f)
318 {
319         struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
320
321         f->type = V4L2_TUNER_RADIO;
322         f->frequency = radio->curfreq;
323         return 0;
324 }
325
326 static int vidioc_queryctrl(struct file *file, void *priv,
327                                 struct v4l2_queryctrl *qc)
328 {
329         int i;
330
331         for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
332                 if (qc->id && qc->id == radio_qctrl[i].id) {
333                         memcpy(qc, &(radio_qctrl[i]),
334                                                 sizeof(*qc));
335                         return 0;
336                 }
337         }
338         return -EINVAL;
339 }
340
341 static int vidioc_g_ctrl(struct file *file, void *priv,
342                                 struct v4l2_control *ctrl)
343 {
344         struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
345
346         switch (ctrl->id) {
347         case V4L2_CID_AUDIO_MUTE:
348                 ctrl->value = radio->muted;
349                 return 0;
350         }
351         return -EINVAL;
352 }
353
354 static int vidioc_s_ctrl(struct file *file, void *priv,
355                                 struct v4l2_control *ctrl)
356 {
357         struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
358
359         switch (ctrl->id) {
360         case V4L2_CID_AUDIO_MUTE:
361                 if (ctrl->value) {
362                         if (dsbr100_stop(radio)==-1)
363                                 warn("Radio did not respond properly");
364                 } else {
365                         if (dsbr100_start(radio)==-1)
366                                 warn("Radio did not respond properly");
367                 }
368                 return 0;
369         }
370         return -EINVAL;
371 }
372
373 static int vidioc_g_audio(struct file *file, void *priv,
374                                 struct v4l2_audio *a)
375 {
376         if (a->index > 1)
377                 return -EINVAL;
378
379         strcpy(a->name, "Radio");
380         a->capability = V4L2_AUDCAP_STEREO;
381         return 0;
382 }
383
384 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
385 {
386         *i = 0;
387         return 0;
388 }
389
390 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
391 {
392         if (i != 0)
393                 return -EINVAL;
394         return 0;
395 }
396
397 static int vidioc_s_audio(struct file *file, void *priv,
398                                         struct v4l2_audio *a)
399 {
400         if (a->index != 0)
401                 return -EINVAL;
402         return 0;
403 }
404
405 static int usb_dsbr100_open(struct inode *inode, struct file *file)
406 {
407         struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
408
409         radio->users = 1;
410         radio->muted = 1;
411
412         if (dsbr100_start(radio)<0) {
413                 warn("Radio did not start up properly");
414                 radio->users = 0;
415                 return -EIO;
416         }
417         dsbr100_setfreq(radio, radio->curfreq);
418         return 0;
419 }
420
421 static int usb_dsbr100_close(struct inode *inode, struct file *file)
422 {
423         struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
424
425         if (!radio)
426                 return -ENODEV;
427         radio->users = 0;
428         if (radio->removed) {
429                 kfree(radio->transfer_buffer);
430                 kfree(radio);
431         }
432         return 0;
433 }
434
435 /* File system interface */
436 static const struct file_operations usb_dsbr100_fops = {
437         .owner          = THIS_MODULE,
438         .open           = usb_dsbr100_open,
439         .release        = usb_dsbr100_close,
440         .ioctl          = video_ioctl2,
441 #ifdef CONFIG_COMPAT
442         .compat_ioctl   = v4l_compat_ioctl32,
443 #endif
444         .llseek         = no_llseek,
445 };
446
447 /* V4L2 interface */
448 static struct video_device dsbr100_videodev_template =
449 {
450         .owner          = THIS_MODULE,
451         .name           = "D-Link DSB-R 100",
452         .type           = VID_TYPE_TUNER,
453         .fops           = &usb_dsbr100_fops,
454         .release        = video_device_release,
455         .vidioc_querycap    = vidioc_querycap,
456         .vidioc_g_tuner     = vidioc_g_tuner,
457         .vidioc_s_tuner     = vidioc_s_tuner,
458         .vidioc_g_frequency = vidioc_g_frequency,
459         .vidioc_s_frequency = vidioc_s_frequency,
460         .vidioc_queryctrl   = vidioc_queryctrl,
461         .vidioc_g_ctrl      = vidioc_g_ctrl,
462         .vidioc_s_ctrl      = vidioc_s_ctrl,
463         .vidioc_g_audio     = vidioc_g_audio,
464         .vidioc_s_audio     = vidioc_s_audio,
465         .vidioc_g_input     = vidioc_g_input,
466         .vidioc_s_input     = vidioc_s_input,
467 };
468
469 /* check if the device is present and register with v4l and
470 usb if it is */
471 static int usb_dsbr100_probe(struct usb_interface *intf,
472                                 const struct usb_device_id *id)
473 {
474         struct dsbr100_device *radio;
475
476         if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
477                 return -ENOMEM;
478         if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
479                 kfree(radio);
480                 return -ENOMEM;
481         }
482         if (!(radio->videodev = video_device_alloc())) {
483                 kfree(radio->transfer_buffer);
484                 kfree(radio);
485                 return -ENOMEM;
486         }
487         memcpy(radio->videodev, &dsbr100_videodev_template,
488                 sizeof(dsbr100_videodev_template));
489         radio->removed = 0;
490         radio->users = 0;
491         radio->usbdev = interface_to_usbdev(intf);
492         radio->curfreq = FREQ_MIN*FREQ_MUL;
493         video_set_drvdata(radio->videodev, radio);
494         if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
495                 warn("Could not register video device");
496                 video_device_release(radio->videodev);
497                 kfree(radio->transfer_buffer);
498                 kfree(radio);
499                 return -EIO;
500         }
501         usb_set_intfdata(intf, radio);
502         return 0;
503 }
504
505 static int __init dsbr100_init(void)
506 {
507         int retval = usb_register(&usb_dsbr100_driver);
508         info(DRIVER_VERSION ":" DRIVER_DESC);
509         return retval;
510 }
511
512 static void __exit dsbr100_exit(void)
513 {
514         usb_deregister(&usb_dsbr100_driver);
515 }
516
517 module_init (dsbr100_init);
518 module_exit (dsbr100_exit);
519
520 MODULE_AUTHOR( DRIVER_AUTHOR );
521 MODULE_DESCRIPTION( DRIVER_DESC );
522 MODULE_LICENSE("GPL");