]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/radio/radio-mr800.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
[linux-2.6-omap-h63xx.git] / drivers / media / radio / radio-mr800.c
1 /*
2  * A driver for the AverMedia MR 800 USB FM radio. This device plugs
3  * into both the USB and an analog audio input, so this thing
4  * only deals with initialization and frequency setting, the
5  * audio data has to be handled by a sound driver.
6  *
7  * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24 /*
25  * Big thanks to authors of dsbr100.c and radio-si470x.c
26  *
27  * When work was looked pretty good, i discover this:
28  * http://av-usbradio.sourceforge.net/index.php
29  * http://sourceforge.net/projects/av-usbradio/
30  * Latest release of theirs project was in 2005.
31  * Probably, this driver could be improved trough using their
32  * achievements (specifications given).
33  * So, we have smth to begin with.
34  *
35  * History:
36  * Version 0.01:        First working version.
37  *                      It's required to blacklist AverMedia USB Radio
38  *                      in usbhid/hid-quirks.c
39  *
40  * Many things to do:
41  *      - Correct power managment of device (suspend & resume)
42  *      - Make x86 independance (little-endian and big-endian stuff)
43  *      - Add code for scanning and smooth tuning
44  *      - Checked and add stereo&mono stuff
45  *      - Add code for sensitivity value
46  *      - Correct mistakes
47  *      - In Japan another FREQ_MIN and FREQ_MAX
48  */
49
50 /* kernel includes */
51 #include <linux/kernel.h>
52 #include <linux/module.h>
53 #include <linux/init.h>
54 #include <linux/slab.h>
55 #include <linux/input.h>
56 #include <linux/videodev2.h>
57 #include <media/v4l2-common.h>
58 #include <media/v4l2-ioctl.h>
59 #include <linux/usb.h>
60 #include <linux/version.h>      /* for KERNEL_VERSION MACRO */
61
62 /* driver and module definitions */
63 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
64 #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
65 #define DRIVER_VERSION "0.01"
66 #define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
67
68 MODULE_AUTHOR(DRIVER_AUTHOR);
69 MODULE_DESCRIPTION(DRIVER_DESC);
70 MODULE_LICENSE("GPL");
71
72 #define USB_AMRADIO_VENDOR 0x07ca
73 #define USB_AMRADIO_PRODUCT 0xb800
74
75 /* Probably USB_TIMEOUT should be modified in module parameter */
76 #define BUFFER_LENGTH 8
77 #define USB_TIMEOUT 500
78
79 /* Frequency limits in MHz -- these are European values.  For Japanese
80 devices, that would be 76 and 91.  */
81 #define FREQ_MIN  87.5
82 #define FREQ_MAX 108.0
83 #define FREQ_MUL 16000
84
85 /* module parameter */
86 static int radio_nr = -1;
87 module_param(radio_nr, int, 0);
88 MODULE_PARM_DESC(radio_nr, "Radio Nr");
89
90 static struct v4l2_queryctrl radio_qctrl[] = {
91         {
92                 .id            = V4L2_CID_AUDIO_MUTE,
93                 .name          = "Mute",
94                 .minimum       = 0,
95                 .maximum       = 1,
96                 .step          = 1,
97                 .default_value = 1,
98                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
99         },
100 /* HINT: the disabled controls are only here to satify kradio and such apps */
101         {       .id             = V4L2_CID_AUDIO_VOLUME,
102                 .flags          = V4L2_CTRL_FLAG_DISABLED,
103         },
104         {
105                 .id             = V4L2_CID_AUDIO_BALANCE,
106                 .flags          = V4L2_CTRL_FLAG_DISABLED,
107         },
108         {
109                 .id             = V4L2_CID_AUDIO_BASS,
110                 .flags          = V4L2_CTRL_FLAG_DISABLED,
111         },
112         {
113                 .id             = V4L2_CID_AUDIO_TREBLE,
114                 .flags          = V4L2_CTRL_FLAG_DISABLED,
115         },
116         {
117                 .id             = V4L2_CID_AUDIO_LOUDNESS,
118                 .flags          = V4L2_CTRL_FLAG_DISABLED,
119         },
120 };
121
122 static int usb_amradio_probe(struct usb_interface *intf,
123                              const struct usb_device_id *id);
124 static void usb_amradio_disconnect(struct usb_interface *intf);
125 static int usb_amradio_open(struct inode *inode, struct file *file);
126 static int usb_amradio_close(struct inode *inode, struct file *file);
127 static int usb_amradio_suspend(struct usb_interface *intf,
128                                 pm_message_t message);
129 static int usb_amradio_resume(struct usb_interface *intf);
130
131 /* Data for one (physical) device */
132 struct amradio_device {
133         /* reference to USB and video device */
134         struct usb_device *usbdev;
135         struct video_device *videodev;
136
137         unsigned char *buffer;
138         struct mutex lock;      /* buffer locking */
139         int curfreq;
140         int stereo;
141         int users;
142         int removed;
143         int muted;
144 };
145
146 /* USB Device ID List */
147 static struct usb_device_id usb_amradio_device_table[] = {
148         {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
149                                                         USB_CLASS_HID, 0, 0) },
150         { }                                             /* Terminating entry */
151 };
152
153 MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
154
155 /* USB subsystem interface */
156 static struct usb_driver usb_amradio_driver = {
157         .name                   = "radio-mr800",
158         .probe                  = usb_amradio_probe,
159         .disconnect             = usb_amradio_disconnect,
160         .suspend                = usb_amradio_suspend,
161         .resume                 = usb_amradio_resume,
162         .reset_resume           = usb_amradio_resume,
163         .id_table               = usb_amradio_device_table,
164         .supports_autosuspend   = 1,
165 };
166
167 /* switch on radio. Send 8 bytes to device. */
168 static int amradio_start(struct amradio_device *radio)
169 {
170         int retval;
171         int size;
172
173         mutex_lock(&radio->lock);
174
175         radio->buffer[0] = 0x00;
176         radio->buffer[1] = 0x55;
177         radio->buffer[2] = 0xaa;
178         radio->buffer[3] = 0x00;
179         radio->buffer[4] = 0xab;
180         radio->buffer[5] = 0x00;
181         radio->buffer[6] = 0x00;
182         radio->buffer[7] = 0x00;
183
184         retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
185                 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
186
187         if (retval) {
188                 mutex_unlock(&radio->lock);
189                 return retval;
190         }
191
192         mutex_unlock(&radio->lock);
193
194         radio->muted = 0;
195
196         return retval;
197 }
198
199 /* switch off radio */
200 static int amradio_stop(struct amradio_device *radio)
201 {
202         int retval;
203         int size;
204
205         mutex_lock(&radio->lock);
206
207         radio->buffer[0] = 0x00;
208         radio->buffer[1] = 0x55;
209         radio->buffer[2] = 0xaa;
210         radio->buffer[3] = 0x00;
211         radio->buffer[4] = 0xab;
212         radio->buffer[5] = 0x01;
213         radio->buffer[6] = 0x00;
214         radio->buffer[7] = 0x00;
215
216         retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
217                 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
218
219         if (retval) {
220                 mutex_unlock(&radio->lock);
221                 return retval;
222         }
223
224         mutex_unlock(&radio->lock);
225
226         radio->muted = 1;
227
228         return retval;
229 }
230
231 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
232 static int amradio_setfreq(struct amradio_device *radio, int freq)
233 {
234         int retval;
235         int size;
236         unsigned short freq_send = 0x13 + (freq >> 3) / 25;
237
238         mutex_lock(&radio->lock);
239
240         radio->buffer[0] = 0x00;
241         radio->buffer[1] = 0x55;
242         radio->buffer[2] = 0xaa;
243         radio->buffer[3] = 0x03;
244         radio->buffer[4] = 0xa4;
245         radio->buffer[5] = 0x00;
246         radio->buffer[6] = 0x00;
247         radio->buffer[7] = 0x08;
248
249         retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
250                 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
251
252         if (retval) {
253                 mutex_unlock(&radio->lock);
254                 return retval;
255         }
256
257         /* frequency is calculated from freq_send and placed in first 2 bytes */
258         radio->buffer[0] = (freq_send >> 8) & 0xff;
259         radio->buffer[1] = freq_send & 0xff;
260         radio->buffer[2] = 0x01;
261         radio->buffer[3] = 0x00;
262         radio->buffer[4] = 0x00;
263         /* 5 and 6 bytes of buffer already = 0x00 */
264         radio->buffer[7] = 0x00;
265
266         retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
267                 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
268
269         if (retval) {
270                 mutex_unlock(&radio->lock);
271                 return retval;
272         }
273
274         mutex_unlock(&radio->lock);
275
276         radio->stereo = 0;
277
278         return retval;
279 }
280
281 /* USB subsystem interface begins here */
282
283 /* handle unplugging of the device, release data structures
284 if nothing keeps us from doing it.  If something is still
285 keeping us busy, the release callback of v4l will take care
286 of releasing it. */
287 static void usb_amradio_disconnect(struct usb_interface *intf)
288 {
289         struct amradio_device *radio = usb_get_intfdata(intf);
290
291         usb_set_intfdata(intf, NULL);
292
293         if (radio) {
294                 video_unregister_device(radio->videodev);
295                 radio->videodev = NULL;
296                 if (radio->users) {
297                         kfree(radio->buffer);
298                         kfree(radio);
299                 } else {
300                         radio->removed = 1;
301                 }
302         }
303 }
304
305 /* vidioc_querycap - query device capabilities */
306 static int vidioc_querycap(struct file *file, void *priv,
307                                         struct v4l2_capability *v)
308 {
309         strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
310         strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
311         sprintf(v->bus_info, "USB");
312         v->version = RADIO_VERSION;
313         v->capabilities = V4L2_CAP_TUNER;
314         return 0;
315 }
316
317 /* vidioc_g_tuner - get tuner attributes */
318 static int vidioc_g_tuner(struct file *file, void *priv,
319                                 struct v4l2_tuner *v)
320 {
321         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
322
323         if (v->index > 0)
324                 return -EINVAL;
325
326 /* TODO: Add function which look is signal stereo or not
327  *      amradio_getstat(radio);
328  */
329         radio->stereo = -1;
330         strcpy(v->name, "FM");
331         v->type = V4L2_TUNER_RADIO;
332         v->rangelow = FREQ_MIN * FREQ_MUL;
333         v->rangehigh = FREQ_MAX * FREQ_MUL;
334         v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
335         v->capability = V4L2_TUNER_CAP_LOW;
336         if (radio->stereo)
337                 v->audmode = V4L2_TUNER_MODE_STEREO;
338         else
339                 v->audmode = V4L2_TUNER_MODE_MONO;
340         v->signal = 0xffff;     /* Can't get the signal strength, sad.. */
341         v->afc = 0; /* Don't know what is this */
342         return 0;
343 }
344
345 /* vidioc_s_tuner - set tuner attributes */
346 static int vidioc_s_tuner(struct file *file, void *priv,
347                                 struct v4l2_tuner *v)
348 {
349         if (v->index > 0)
350                 return -EINVAL;
351         return 0;
352 }
353
354 /* vidioc_s_frequency - set tuner radio frequency */
355 static int vidioc_s_frequency(struct file *file, void *priv,
356                                 struct v4l2_frequency *f)
357 {
358         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
359
360         radio->curfreq = f->frequency;
361         if (amradio_setfreq(radio, radio->curfreq) < 0)
362                 warn("Set frequency failed");
363         return 0;
364 }
365
366 /* vidioc_g_frequency - get tuner radio frequency */
367 static int vidioc_g_frequency(struct file *file, void *priv,
368                                 struct v4l2_frequency *f)
369 {
370         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
371
372         f->type = V4L2_TUNER_RADIO;
373         f->frequency = radio->curfreq;
374         return 0;
375 }
376
377 /* vidioc_queryctrl - enumerate control items */
378 static int vidioc_queryctrl(struct file *file, void *priv,
379                                 struct v4l2_queryctrl *qc)
380 {
381         int i;
382
383         for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
384                 if (qc->id && qc->id == radio_qctrl[i].id) {
385                         memcpy(qc, &(radio_qctrl[i]),
386                                                 sizeof(*qc));
387                         return 0;
388                 }
389         }
390         return -EINVAL;
391 }
392
393 /* vidioc_g_ctrl - get the value of a control */
394 static int vidioc_g_ctrl(struct file *file, void *priv,
395                                 struct v4l2_control *ctrl)
396 {
397         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
398
399         switch (ctrl->id) {
400         case V4L2_CID_AUDIO_MUTE:
401                 ctrl->value = radio->muted;
402                 return 0;
403         }
404         return -EINVAL;
405 }
406
407 /* vidioc_s_ctrl - set the value of a control */
408 static int vidioc_s_ctrl(struct file *file, void *priv,
409                                 struct v4l2_control *ctrl)
410 {
411         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
412
413         switch (ctrl->id) {
414         case V4L2_CID_AUDIO_MUTE:
415                 if (ctrl->value) {
416                         if (amradio_stop(radio) < 0) {
417                                 warn("amradio_stop() failed");
418                                 return -1;
419                         }
420                 } else {
421                         if (amradio_start(radio) < 0) {
422                                 warn("amradio_start() failed");
423                                 return -1;
424                         }
425                 }
426                 return 0;
427         }
428         return -EINVAL;
429 }
430
431 /* vidioc_g_audio - get audio attributes */
432 static int vidioc_g_audio(struct file *file, void *priv,
433                                 struct v4l2_audio *a)
434 {
435         if (a->index > 1)
436                 return -EINVAL;
437
438         strcpy(a->name, "Radio");
439         a->capability = V4L2_AUDCAP_STEREO;
440         return 0;
441 }
442
443 /* vidioc_s_audio - set audio attributes  */
444 static int vidioc_s_audio(struct file *file, void *priv,
445                                         struct v4l2_audio *a)
446 {
447         if (a->index != 0)
448                 return -EINVAL;
449         return 0;
450 }
451
452 /* vidioc_g_input - get input */
453 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
454 {
455         *i = 0;
456         return 0;
457 }
458
459 /* vidioc_s_input - set input */
460 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
461 {
462         if (i != 0)
463                 return -EINVAL;
464         return 0;
465 }
466
467 /* open device - amradio_start() and amradio_setfreq() */
468 static int usb_amradio_open(struct inode *inode, struct file *file)
469 {
470         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
471
472         lock_kernel();
473
474         radio->users = 1;
475         radio->muted = 1;
476
477         if (amradio_start(radio) < 0) {
478                 warn("Radio did not start up properly");
479                 radio->users = 0;
480                 unlock_kernel();
481                 return -EIO;
482         }
483         if (amradio_setfreq(radio, radio->curfreq) < 0)
484                 warn("Set frequency failed");
485
486         unlock_kernel();
487         return 0;
488 }
489
490 /*close device - free driver structures */
491 static int usb_amradio_close(struct inode *inode, struct file *file)
492 {
493         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
494
495         if (!radio)
496                 return -ENODEV;
497         radio->users = 0;
498         if (radio->removed) {
499                 kfree(radio->buffer);
500                 kfree(radio);
501         }
502         return 0;
503 }
504
505 /* Suspend device - stop device. Need to be checked and fixed */
506 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
507 {
508         struct amradio_device *radio = usb_get_intfdata(intf);
509
510         if (amradio_stop(radio) < 0)
511                 warn("amradio_stop() failed");
512
513         info("radio-mr800: Going into suspend..");
514
515         return 0;
516 }
517
518 /* Resume device - start device. Need to be checked and fixed */
519 static int usb_amradio_resume(struct usb_interface *intf)
520 {
521         struct amradio_device *radio = usb_get_intfdata(intf);
522
523         if (amradio_start(radio) < 0)
524                 warn("amradio_start() failed");
525
526         info("radio-mr800: Coming out of suspend..");
527
528         return 0;
529 }
530
531 /* File system interface */
532 static const struct file_operations usb_amradio_fops = {
533         .owner          = THIS_MODULE,
534         .open           = usb_amradio_open,
535         .release        = usb_amradio_close,
536         .ioctl          = video_ioctl2,
537 #ifdef CONFIG_COMPAT
538         .compat_ioctl   = v4l_compat_ioctl32,
539 #endif
540         .llseek         = no_llseek,
541 };
542
543 static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
544         .vidioc_querycap    = vidioc_querycap,
545         .vidioc_g_tuner     = vidioc_g_tuner,
546         .vidioc_s_tuner     = vidioc_s_tuner,
547         .vidioc_g_frequency = vidioc_g_frequency,
548         .vidioc_s_frequency = vidioc_s_frequency,
549         .vidioc_queryctrl   = vidioc_queryctrl,
550         .vidioc_g_ctrl      = vidioc_g_ctrl,
551         .vidioc_s_ctrl      = vidioc_s_ctrl,
552         .vidioc_g_audio     = vidioc_g_audio,
553         .vidioc_s_audio     = vidioc_s_audio,
554         .vidioc_g_input     = vidioc_g_input,
555         .vidioc_s_input     = vidioc_s_input,
556 };
557
558 /* V4L2 interface */
559 static struct video_device amradio_videodev_template = {
560         .name           = "AverMedia MR 800 USB FM Radio",
561         .fops           = &usb_amradio_fops,
562         .ioctl_ops      = &usb_amradio_ioctl_ops,
563         .release        = video_device_release,
564 };
565
566 /* check if the device is present and register with v4l and
567 usb if it is */
568 static int usb_amradio_probe(struct usb_interface *intf,
569                                 const struct usb_device_id *id)
570 {
571         struct amradio_device *radio;
572
573         radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
574
575         if (!(radio))
576                 return -ENOMEM;
577
578         radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
579
580         if (!(radio->buffer)) {
581                 kfree(radio);
582                 return -ENOMEM;
583         }
584
585         radio->videodev = video_device_alloc();
586
587         if (!(radio->videodev)) {
588                 kfree(radio->buffer);
589                 kfree(radio);
590                 return -ENOMEM;
591         }
592
593         memcpy(radio->videodev, &amradio_videodev_template,
594                 sizeof(amradio_videodev_template));
595
596         radio->removed = 0;
597         radio->users = 0;
598         radio->usbdev = interface_to_usbdev(intf);
599         radio->curfreq = 95.16 * FREQ_MUL;
600
601         mutex_init(&radio->lock);
602
603         video_set_drvdata(radio->videodev, radio);
604         if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
605                 warn("Could not register video device");
606                 video_device_release(radio->videodev);
607                 kfree(radio->buffer);
608                 kfree(radio);
609                 return -EIO;
610         }
611
612         usb_set_intfdata(intf, radio);
613         return 0;
614 }
615
616 static int __init amradio_init(void)
617 {
618         int retval = usb_register(&usb_amradio_driver);
619
620         info(DRIVER_VERSION " " DRIVER_DESC);
621         if (retval)
622                 err("usb_register failed. Error number %d", retval);
623         return retval;
624 }
625
626 static void __exit amradio_exit(void)
627 {
628         usb_deregister(&usb_amradio_driver);
629 }
630
631 module_init(amradio_init);
632 module_exit(amradio_exit);
633