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