]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/media/radio/dsbr100.c
e6485cfe121899ef0ae891606c4a6ad41d5d1072
[mv-sheeva.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 <media/v4l2-ioctl.h>
89 #include <linux/usb.h>
90
91 /*
92  * Version Information
93  */
94 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
95
96 #define DRIVER_VERSION "v0.41"
97 #define RADIO_VERSION KERNEL_VERSION(0,4,1)
98
99 static struct v4l2_queryctrl radio_qctrl[] = {
100         {
101                 .id            = V4L2_CID_AUDIO_MUTE,
102                 .name          = "Mute",
103                 .minimum       = 0,
104                 .maximum       = 1,
105                 .default_value = 1,
106                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
107         }
108 };
109
110 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
111 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
112
113 #define DSB100_VENDOR 0x04b4
114 #define DSB100_PRODUCT 0x1002
115
116 /* Commands the device appears to understand */
117 #define DSB100_TUNE 1
118 #define DSB100_ONOFF 2
119
120 #define TB_LEN 16
121
122 /* Frequency limits in MHz -- these are European values.  For Japanese
123 devices, that would be 76 and 91.  */
124 #define FREQ_MIN  87.5
125 #define FREQ_MAX 108.0
126 #define FREQ_MUL 16000
127
128
129 static int usb_dsbr100_probe(struct usb_interface *intf,
130                              const struct usb_device_id *id);
131 static void usb_dsbr100_disconnect(struct usb_interface *intf);
132 static int usb_dsbr100_open(struct inode *inode, struct file *file);
133 static int usb_dsbr100_close(struct inode *inode, struct file *file);
134 static int usb_dsbr100_suspend(struct usb_interface *intf,
135                                                 pm_message_t message);
136 static int usb_dsbr100_resume(struct usb_interface *intf);
137
138 static int radio_nr = -1;
139 module_param(radio_nr, int, 0);
140
141 /* Data for one (physical) device */
142 struct dsbr100_device {
143         struct usb_device *usbdev;
144         struct video_device *videodev;
145         u8 *transfer_buffer;
146         int curfreq;
147         int stereo;
148         int users;
149         int removed;
150         int muted;
151 };
152
153
154 static struct usb_device_id usb_dsbr100_device_table [] = {
155         { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
156         { }                                             /* Terminating entry */
157 };
158
159 MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
160
161 /* USB subsystem interface */
162 static struct usb_driver usb_dsbr100_driver = {
163         .name                   = "dsbr100",
164         .probe                  = usb_dsbr100_probe,
165         .disconnect             = usb_dsbr100_disconnect,
166         .id_table               = usb_dsbr100_device_table,
167         .suspend                = usb_dsbr100_suspend,
168         .resume                 = usb_dsbr100_resume,
169         .reset_resume           = usb_dsbr100_resume,
170         .supports_autosuspend   = 0,
171 };
172
173 /* Low-level device interface begins here */
174
175 /* switch on radio */
176 static int dsbr100_start(struct dsbr100_device *radio)
177 {
178         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
179                         USB_REQ_GET_STATUS,
180                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
181                         0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 ||
182         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
183                         DSB100_ONOFF,
184                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
185                         0x01, 0x00, radio->transfer_buffer, 8, 300) < 0)
186                 return -1;
187         radio->muted=0;
188         return (radio->transfer_buffer)[0];
189 }
190
191
192 /* switch off radio */
193 static int dsbr100_stop(struct dsbr100_device *radio)
194 {
195         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
196                         USB_REQ_GET_STATUS,
197                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
198                         0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 ||
199         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
200                         DSB100_ONOFF,
201                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
202                         0x00, 0x00, radio->transfer_buffer, 8, 300) < 0)
203                 return -1;
204         radio->muted=1;
205         return (radio->transfer_buffer)[0];
206 }
207
208 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
209 static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
210 {
211         freq = (freq / 16 * 80) / 1000 + 856;
212         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
213                         DSB100_TUNE,
214                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
215                         (freq >> 8) & 0x00ff, freq & 0xff,
216                         radio->transfer_buffer, 8, 300) < 0 ||
217            usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
218                         USB_REQ_GET_STATUS,
219                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
220                         0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 ||
221         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
222                         USB_REQ_GET_STATUS,
223                         USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
224                         0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
225                 radio->stereo = -1;
226                 return -1;
227         }
228         radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
229         return (radio->transfer_buffer)[0];
230 }
231
232 /* return the device status.  This is, in effect, just whether it
233 sees a stereo signal or not.  Pity. */
234 static void dsbr100_getstat(struct dsbr100_device *radio)
235 {
236         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
237                 USB_REQ_GET_STATUS,
238                 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
239                 0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0)
240                 radio->stereo = -1;
241         else
242                 radio->stereo = !(radio->transfer_buffer[0] & 0x01);
243 }
244
245
246 /* USB subsystem interface begins here */
247
248 /* handle unplugging of the device, release data structures
249 if nothing keeps us from doing it.  If something is still
250 keeping us busy, the release callback of v4l will take care
251 of releasing it. */
252 static void usb_dsbr100_disconnect(struct usb_interface *intf)
253 {
254         struct dsbr100_device *radio = usb_get_intfdata(intf);
255
256         usb_set_intfdata (intf, NULL);
257         if (radio) {
258                 video_unregister_device(radio->videodev);
259                 radio->videodev = NULL;
260                 if (radio->users) {
261                         kfree(radio->transfer_buffer);
262                         kfree(radio);
263                 } else {
264                         radio->removed = 1;
265                 }
266         }
267 }
268
269
270 static int vidioc_querycap(struct file *file, void *priv,
271                                         struct v4l2_capability *v)
272 {
273         strlcpy(v->driver, "dsbr100", sizeof(v->driver));
274         strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
275         sprintf(v->bus_info, "USB");
276         v->version = RADIO_VERSION;
277         v->capabilities = V4L2_CAP_TUNER;
278         return 0;
279 }
280
281 static int vidioc_g_tuner(struct file *file, void *priv,
282                                 struct v4l2_tuner *v)
283 {
284         struct dsbr100_device *radio = video_drvdata(file);
285
286         if (v->index > 0)
287                 return -EINVAL;
288
289         dsbr100_getstat(radio);
290         strcpy(v->name, "FM");
291         v->type = V4L2_TUNER_RADIO;
292         v->rangelow = FREQ_MIN * FREQ_MUL;
293         v->rangehigh = FREQ_MAX * FREQ_MUL;
294         v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
295         v->capability = V4L2_TUNER_CAP_LOW;
296         if(radio->stereo)
297                 v->audmode = V4L2_TUNER_MODE_STEREO;
298         else
299                 v->audmode = V4L2_TUNER_MODE_MONO;
300         v->signal = 0xffff;     /* We can't get the signal strength */
301         return 0;
302 }
303
304 static int vidioc_s_tuner(struct file *file, void *priv,
305                                 struct v4l2_tuner *v)
306 {
307         if (v->index > 0)
308                 return -EINVAL;
309
310         return 0;
311 }
312
313 static int vidioc_s_frequency(struct file *file, void *priv,
314                                 struct v4l2_frequency *f)
315 {
316         struct dsbr100_device *radio = video_drvdata(file);
317
318         radio->curfreq = f->frequency;
319         if (dsbr100_setfreq(radio, radio->curfreq) == -1)
320                 dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
321         return 0;
322 }
323
324 static int vidioc_g_frequency(struct file *file, void *priv,
325                                 struct v4l2_frequency *f)
326 {
327         struct dsbr100_device *radio = video_drvdata(file);
328
329         f->type = V4L2_TUNER_RADIO;
330         f->frequency = radio->curfreq;
331         return 0;
332 }
333
334 static int vidioc_queryctrl(struct file *file, void *priv,
335                                 struct v4l2_queryctrl *qc)
336 {
337         int i;
338
339         for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
340                 if (qc->id && qc->id == radio_qctrl[i].id) {
341                         memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
342                         return 0;
343                 }
344         }
345         return -EINVAL;
346 }
347
348 static int vidioc_g_ctrl(struct file *file, void *priv,
349                                 struct v4l2_control *ctrl)
350 {
351         struct dsbr100_device *radio = video_drvdata(file);
352
353         switch (ctrl->id) {
354         case V4L2_CID_AUDIO_MUTE:
355                 ctrl->value = radio->muted;
356                 return 0;
357         }
358         return -EINVAL;
359 }
360
361 static int vidioc_s_ctrl(struct file *file, void *priv,
362                                 struct v4l2_control *ctrl)
363 {
364         struct dsbr100_device *radio = video_drvdata(file);
365
366         switch (ctrl->id) {
367         case V4L2_CID_AUDIO_MUTE:
368                 if (ctrl->value) {
369                         if (dsbr100_stop(radio) == -1) {
370                                 dev_warn(&radio->usbdev->dev,
371                                          "Radio did not respond properly\n");
372                                 return -EBUSY;
373                         }
374                 } else {
375                         if (dsbr100_start(radio) == -1) {
376                                 dev_warn(&radio->usbdev->dev,
377                                          "Radio did not respond properly\n");
378                                 return -EBUSY;
379                         }
380                 }
381                 return 0;
382         }
383         return -EINVAL;
384 }
385
386 static int vidioc_g_audio(struct file *file, void *priv,
387                                 struct v4l2_audio *a)
388 {
389         if (a->index > 1)
390                 return -EINVAL;
391
392         strcpy(a->name, "Radio");
393         a->capability = V4L2_AUDCAP_STEREO;
394         return 0;
395 }
396
397 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
398 {
399         *i = 0;
400         return 0;
401 }
402
403 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
404 {
405         if (i != 0)
406                 return -EINVAL;
407         return 0;
408 }
409
410 static int vidioc_s_audio(struct file *file, void *priv,
411                                         struct v4l2_audio *a)
412 {
413         if (a->index != 0)
414                 return -EINVAL;
415         return 0;
416 }
417
418 static int usb_dsbr100_open(struct inode *inode, struct file *file)
419 {
420         struct dsbr100_device *radio = video_drvdata(file);
421         int retval;
422
423         lock_kernel();
424         radio->users = 1;
425         radio->muted = 1;
426
427         if (dsbr100_start(radio) < 0) {
428                 dev_warn(&radio->usbdev->dev,
429                          "Radio did not start up properly\n");
430                 radio->users = 0;
431                 unlock_kernel();
432                 return -EIO;
433         }
434
435         retval = dsbr100_setfreq(radio, radio->curfreq);
436
437         if (retval == -1)
438                 printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n");
439
440         unlock_kernel();
441         return 0;
442 }
443
444 static int usb_dsbr100_close(struct inode *inode, struct file *file)
445 {
446         struct dsbr100_device *radio = video_drvdata(file);
447
448         if (!radio)
449                 return -ENODEV;
450         radio->users = 0;
451         if (radio->removed) {
452                 kfree(radio->transfer_buffer);
453                 kfree(radio);
454         }
455         return 0;
456 }
457
458 /* Suspend device - stop device. */
459 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
460 {
461         struct dsbr100_device *radio = usb_get_intfdata(intf);
462         int retval;
463
464         retval = dsbr100_stop(radio);
465         if (retval == -1)
466                 dev_warn(&intf->dev, "dsbr100_stop failed\n");
467
468         dev_info(&intf->dev, "going into suspend..\n");
469
470         return 0;
471 }
472
473 /* Resume device - start device. */
474 static int usb_dsbr100_resume(struct usb_interface *intf)
475 {
476         struct dsbr100_device *radio = usb_get_intfdata(intf);
477         int retval;
478
479         retval = dsbr100_start(radio);
480         if (retval == -1)
481                 dev_warn(&intf->dev, "dsbr100_start failed\n");
482
483         dev_info(&intf->dev, "coming out of suspend..\n");
484
485         return 0;
486 }
487
488 /* File system interface */
489 static const struct file_operations usb_dsbr100_fops = {
490         .owner          = THIS_MODULE,
491         .open           = usb_dsbr100_open,
492         .release        = usb_dsbr100_close,
493         .ioctl          = video_ioctl2,
494 #ifdef CONFIG_COMPAT
495         .compat_ioctl   = v4l_compat_ioctl32,
496 #endif
497         .llseek         = no_llseek,
498 };
499
500 static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
501         .vidioc_querycap    = vidioc_querycap,
502         .vidioc_g_tuner     = vidioc_g_tuner,
503         .vidioc_s_tuner     = vidioc_s_tuner,
504         .vidioc_g_frequency = vidioc_g_frequency,
505         .vidioc_s_frequency = vidioc_s_frequency,
506         .vidioc_queryctrl   = vidioc_queryctrl,
507         .vidioc_g_ctrl      = vidioc_g_ctrl,
508         .vidioc_s_ctrl      = vidioc_s_ctrl,
509         .vidioc_g_audio     = vidioc_g_audio,
510         .vidioc_s_audio     = vidioc_s_audio,
511         .vidioc_g_input     = vidioc_g_input,
512         .vidioc_s_input     = vidioc_s_input,
513 };
514
515 /* V4L2 interface */
516 static struct video_device dsbr100_videodev_template = {
517         .name           = "D-Link DSB-R 100",
518         .fops           = &usb_dsbr100_fops,
519         .ioctl_ops      = &usb_dsbr100_ioctl_ops,
520         .release        = video_device_release,
521 };
522
523 /* check if the device is present and register with v4l and
524 usb if it is */
525 static int usb_dsbr100_probe(struct usb_interface *intf,
526                                 const struct usb_device_id *id)
527 {
528         struct dsbr100_device *radio;
529
530         radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
531
532         if (!radio)
533                 return -ENOMEM;
534
535         radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL);
536
537         if (!(radio->transfer_buffer)) {
538                 kfree(radio);
539                 return -ENOMEM;
540         }
541         radio->videodev = video_device_alloc();
542
543         if (!(radio->videodev)) {
544                 kfree(radio->transfer_buffer);
545                 kfree(radio);
546                 return -ENOMEM;
547         }
548         memcpy(radio->videodev, &dsbr100_videodev_template,
549                 sizeof(dsbr100_videodev_template));
550         radio->removed = 0;
551         radio->users = 0;
552         radio->usbdev = interface_to_usbdev(intf);
553         radio->curfreq = FREQ_MIN * FREQ_MUL;
554         video_set_drvdata(radio->videodev, radio);
555         if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
556                 dev_warn(&intf->dev, "Could not register video device\n");
557                 video_device_release(radio->videodev);
558                 kfree(radio->transfer_buffer);
559                 kfree(radio);
560                 return -EIO;
561         }
562         usb_set_intfdata(intf, radio);
563         return 0;
564 }
565
566 static int __init dsbr100_init(void)
567 {
568         int retval = usb_register(&usb_dsbr100_driver);
569         printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
570                DRIVER_DESC "\n");
571         return retval;
572 }
573
574 static void __exit dsbr100_exit(void)
575 {
576         usb_deregister(&usb_dsbr100_driver);
577 }
578
579 module_init (dsbr100_init);
580 module_exit (dsbr100_exit);
581
582 MODULE_AUTHOR( DRIVER_AUTHOR );
583 MODULE_DESCRIPTION( DRIVER_DESC );
584 MODULE_LICENSE("GPL");