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.
7 * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com>
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.
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.
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
25 * Big thanks to authors of dsbr100.c and radio-si470x.c
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.
36 * Version 0.01: First working version.
37 * It's required to blacklist AverMedia USB Radio
38 * in usbhid/hid-quirks.c
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
47 * - In Japan another FREQ_MIN and FREQ_MAX
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 */
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)
68 MODULE_AUTHOR(DRIVER_AUTHOR);
69 MODULE_DESCRIPTION(DRIVER_DESC);
70 MODULE_LICENSE("GPL");
72 #define USB_AMRADIO_VENDOR 0x07ca
73 #define USB_AMRADIO_PRODUCT 0xb800
75 /* dev_warn macro with driver name */
76 #define MR800_DRIVER_NAME "radio-mr800"
77 #define amradio_dev_warn(dev, fmt, arg...) \
78 dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
80 /* Probably USB_TIMEOUT should be modified in module parameter */
81 #define BUFFER_LENGTH 8
82 #define USB_TIMEOUT 500
84 /* Frequency limits in MHz -- these are European values. For Japanese
85 devices, that would be 76 and 91. */
87 #define FREQ_MAX 108.0
88 #define FREQ_MUL 16000
91 * Commands that device should understand
92 * List isnt full and will be updated with implementation of new functions
94 #define AMRADIO_SET_FREQ 0xa4
95 #define AMRADIO_SET_MUTE 0xab
96 #define AMRADIO_SET_MONO 0xae
98 /* Comfortable defines for amradio_set_mute */
99 #define AMRADIO_START 0x00
100 #define AMRADIO_STOP 0x01
102 /* Comfortable defines for amradio_set_stereo */
103 #define WANT_STEREO 0x00
104 #define WANT_MONO 0x01
106 /* module parameter */
107 static int radio_nr = -1;
108 module_param(radio_nr, int, 0);
109 MODULE_PARM_DESC(radio_nr, "Radio Nr");
111 static struct v4l2_queryctrl radio_qctrl[] = {
113 .id = V4L2_CID_AUDIO_MUTE,
119 .type = V4L2_CTRL_TYPE_BOOLEAN,
121 /* HINT: the disabled controls are only here to satify kradio and such apps */
122 { .id = V4L2_CID_AUDIO_VOLUME,
123 .flags = V4L2_CTRL_FLAG_DISABLED,
126 .id = V4L2_CID_AUDIO_BALANCE,
127 .flags = V4L2_CTRL_FLAG_DISABLED,
130 .id = V4L2_CID_AUDIO_BASS,
131 .flags = V4L2_CTRL_FLAG_DISABLED,
134 .id = V4L2_CID_AUDIO_TREBLE,
135 .flags = V4L2_CTRL_FLAG_DISABLED,
138 .id = V4L2_CID_AUDIO_LOUDNESS,
139 .flags = V4L2_CTRL_FLAG_DISABLED,
143 static int usb_amradio_probe(struct usb_interface *intf,
144 const struct usb_device_id *id);
145 static void usb_amradio_disconnect(struct usb_interface *intf);
146 static int usb_amradio_open(struct file *file);
147 static int usb_amradio_close(struct file *file);
148 static int usb_amradio_suspend(struct usb_interface *intf,
149 pm_message_t message);
150 static int usb_amradio_resume(struct usb_interface *intf);
152 /* Data for one (physical) device */
153 struct amradio_device {
154 /* reference to USB and video device */
155 struct usb_device *usbdev;
156 struct video_device *videodev;
158 unsigned char *buffer;
159 struct mutex lock; /* buffer locking */
167 /* USB Device ID List */
168 static struct usb_device_id usb_amradio_device_table[] = {
169 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
170 USB_CLASS_HID, 0, 0) },
171 { } /* Terminating entry */
174 MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
176 /* USB subsystem interface */
177 static struct usb_driver usb_amradio_driver = {
178 .name = MR800_DRIVER_NAME,
179 .probe = usb_amradio_probe,
180 .disconnect = usb_amradio_disconnect,
181 .suspend = usb_amradio_suspend,
182 .resume = usb_amradio_resume,
183 .reset_resume = usb_amradio_resume,
184 .id_table = usb_amradio_device_table,
185 .supports_autosuspend = 0,
188 /* switch on/off the radio. Send 8 bytes to device */
189 static int amradio_set_mute(struct amradio_device *radio, char argument)
198 mutex_lock(&radio->lock);
200 radio->buffer[0] = 0x00;
201 radio->buffer[1] = 0x55;
202 radio->buffer[2] = 0xaa;
203 radio->buffer[3] = 0x00;
204 radio->buffer[4] = AMRADIO_SET_MUTE;
205 radio->buffer[5] = argument;
206 radio->buffer[6] = 0x00;
207 radio->buffer[7] = 0x00;
209 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
210 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
213 mutex_unlock(&radio->lock);
217 radio->muted = argument;
219 mutex_unlock(&radio->lock);
224 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
225 static int amradio_setfreq(struct amradio_device *radio, int freq)
229 unsigned short freq_send = 0x10 + (freq >> 3) / 25;
235 mutex_lock(&radio->lock);
237 radio->buffer[0] = 0x00;
238 radio->buffer[1] = 0x55;
239 radio->buffer[2] = 0xaa;
240 radio->buffer[3] = 0x03;
241 radio->buffer[4] = AMRADIO_SET_FREQ;
242 radio->buffer[5] = 0x00;
243 radio->buffer[6] = 0x00;
244 radio->buffer[7] = 0x08;
246 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
247 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
250 mutex_unlock(&radio->lock);
254 /* frequency is calculated from freq_send and placed in first 2 bytes */
255 radio->buffer[0] = (freq_send >> 8) & 0xff;
256 radio->buffer[1] = freq_send & 0xff;
257 radio->buffer[2] = 0x01;
258 radio->buffer[3] = 0x00;
259 radio->buffer[4] = 0x00;
260 /* 5 and 6 bytes of buffer already = 0x00 */
261 radio->buffer[7] = 0x00;
263 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
264 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
267 mutex_unlock(&radio->lock);
271 mutex_unlock(&radio->lock);
276 static int amradio_set_stereo(struct amradio_device *radio, char argument)
285 mutex_lock(&radio->lock);
287 radio->buffer[0] = 0x00;
288 radio->buffer[1] = 0x55;
289 radio->buffer[2] = 0xaa;
290 radio->buffer[3] = 0x00;
291 radio->buffer[4] = AMRADIO_SET_MONO;
292 radio->buffer[5] = argument;
293 radio->buffer[6] = 0x00;
294 radio->buffer[7] = 0x00;
296 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
297 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
299 if (retval < 0 || size != BUFFER_LENGTH) {
301 mutex_unlock(&radio->lock);
307 mutex_unlock(&radio->lock);
314 /* USB subsystem interface begins here */
316 /* handle unplugging of the device, release data structures
317 if nothing keeps us from doing it. If something is still
318 keeping us busy, the release callback of v4l will take care
320 static void usb_amradio_disconnect(struct usb_interface *intf)
322 struct amradio_device *radio = usb_get_intfdata(intf);
324 mutex_lock(&radio->lock);
326 mutex_unlock(&radio->lock);
328 usb_set_intfdata(intf, NULL);
329 video_unregister_device(radio->videodev);
332 /* vidioc_querycap - query device capabilities */
333 static int vidioc_querycap(struct file *file, void *priv,
334 struct v4l2_capability *v)
336 struct amradio_device *radio = video_drvdata(file);
338 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
339 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
340 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
341 v->version = RADIO_VERSION;
342 v->capabilities = V4L2_CAP_TUNER;
346 /* vidioc_g_tuner - get tuner attributes */
347 static int vidioc_g_tuner(struct file *file, void *priv,
348 struct v4l2_tuner *v)
350 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
360 /* TODO: Add function which look is signal stereo or not
361 * amradio_getstat(radio);
364 /* we call amradio_set_stereo to set radio->stereo
365 * Honestly, amradio_getstat should cover this in future and
366 * amradio_set_stereo shouldn't be here
368 retval = amradio_set_stereo(radio, WANT_STEREO);
370 amradio_dev_warn(&radio->videodev->dev,
371 "set stereo failed\n");
373 strcpy(v->name, "FM");
374 v->type = V4L2_TUNER_RADIO;
375 v->rangelow = FREQ_MIN * FREQ_MUL;
376 v->rangehigh = FREQ_MAX * FREQ_MUL;
377 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
378 v->capability = V4L2_TUNER_CAP_LOW;
380 v->audmode = V4L2_TUNER_MODE_STEREO;
382 v->audmode = V4L2_TUNER_MODE_MONO;
383 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
384 v->afc = 0; /* Don't know what is this */
388 /* vidioc_s_tuner - set tuner attributes */
389 static int vidioc_s_tuner(struct file *file, void *priv,
390 struct v4l2_tuner *v)
392 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
402 /* mono/stereo selector */
403 switch (v->audmode) {
404 case V4L2_TUNER_MODE_MONO:
405 retval = amradio_set_stereo(radio, WANT_MONO);
407 amradio_dev_warn(&radio->videodev->dev,
408 "set mono failed\n");
410 case V4L2_TUNER_MODE_STEREO:
411 retval = amradio_set_stereo(radio, WANT_STEREO);
413 amradio_dev_warn(&radio->videodev->dev,
414 "set stereo failed\n");
423 /* vidioc_s_frequency - set tuner radio frequency */
424 static int vidioc_s_frequency(struct file *file, void *priv,
425 struct v4l2_frequency *f)
427 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
434 mutex_lock(&radio->lock);
435 radio->curfreq = f->frequency;
436 mutex_unlock(&radio->lock);
438 retval = amradio_setfreq(radio, radio->curfreq);
440 amradio_dev_warn(&radio->videodev->dev,
441 "set frequency failed\n");
445 /* vidioc_g_frequency - get tuner radio frequency */
446 static int vidioc_g_frequency(struct file *file, void *priv,
447 struct v4l2_frequency *f)
449 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
455 f->type = V4L2_TUNER_RADIO;
456 f->frequency = radio->curfreq;
460 /* vidioc_queryctrl - enumerate control items */
461 static int vidioc_queryctrl(struct file *file, void *priv,
462 struct v4l2_queryctrl *qc)
466 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
467 if (qc->id && qc->id == radio_qctrl[i].id) {
468 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
475 /* vidioc_g_ctrl - get the value of a control */
476 static int vidioc_g_ctrl(struct file *file, void *priv,
477 struct v4l2_control *ctrl)
479 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
486 case V4L2_CID_AUDIO_MUTE:
487 ctrl->value = radio->muted;
493 /* vidioc_s_ctrl - set the value of a control */
494 static int vidioc_s_ctrl(struct file *file, void *priv,
495 struct v4l2_control *ctrl)
497 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
505 case V4L2_CID_AUDIO_MUTE:
507 retval = amradio_set_mute(radio, AMRADIO_STOP);
509 amradio_dev_warn(&radio->videodev->dev,
510 "amradio_stop failed\n");
514 retval = amradio_set_mute(radio, AMRADIO_START);
516 amradio_dev_warn(&radio->videodev->dev,
517 "amradio_start failed\n");
526 /* vidioc_g_audio - get audio attributes */
527 static int vidioc_g_audio(struct file *file, void *priv,
528 struct v4l2_audio *a)
533 strcpy(a->name, "Radio");
534 a->capability = V4L2_AUDCAP_STEREO;
538 /* vidioc_s_audio - set audio attributes */
539 static int vidioc_s_audio(struct file *file, void *priv,
540 struct v4l2_audio *a)
547 /* vidioc_g_input - get input */
548 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
554 /* vidioc_s_input - set input */
555 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
562 /* open device - amradio_start() and amradio_setfreq() */
563 static int usb_amradio_open(struct file *file)
565 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
573 retval = amradio_set_mute(radio, AMRADIO_START);
575 amradio_dev_warn(&radio->videodev->dev,
576 "radio did not start up properly\n");
582 retval = amradio_set_stereo(radio, WANT_STEREO);
584 amradio_dev_warn(&radio->videodev->dev,
585 "set stereo failed\n");
587 retval = amradio_setfreq(radio, radio->curfreq);
589 amradio_dev_warn(&radio->videodev->dev,
590 "set frequency failed\n");
597 static int usb_amradio_close(struct file *file)
599 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
605 mutex_lock(&radio->lock);
607 mutex_unlock(&radio->lock);
609 if (!radio->removed) {
610 retval = amradio_set_mute(radio, AMRADIO_STOP);
612 amradio_dev_warn(&radio->videodev->dev,
613 "amradio_stop failed\n");
619 /* Suspend device - stop device. Need to be checked and fixed */
620 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
622 struct amradio_device *radio = usb_get_intfdata(intf);
625 retval = amradio_set_mute(radio, AMRADIO_STOP);
627 dev_warn(&intf->dev, "amradio_stop failed\n");
629 dev_info(&intf->dev, "going into suspend..\n");
634 /* Resume device - start device. Need to be checked and fixed */
635 static int usb_amradio_resume(struct usb_interface *intf)
637 struct amradio_device *radio = usb_get_intfdata(intf);
640 retval = amradio_set_mute(radio, AMRADIO_START);
642 dev_warn(&intf->dev, "amradio_start failed\n");
644 dev_info(&intf->dev, "coming out of suspend..\n");
649 /* File system interface */
650 static const struct v4l2_file_operations usb_amradio_fops = {
651 .owner = THIS_MODULE,
652 .open = usb_amradio_open,
653 .release = usb_amradio_close,
654 .ioctl = video_ioctl2,
657 static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
658 .vidioc_querycap = vidioc_querycap,
659 .vidioc_g_tuner = vidioc_g_tuner,
660 .vidioc_s_tuner = vidioc_s_tuner,
661 .vidioc_g_frequency = vidioc_g_frequency,
662 .vidioc_s_frequency = vidioc_s_frequency,
663 .vidioc_queryctrl = vidioc_queryctrl,
664 .vidioc_g_ctrl = vidioc_g_ctrl,
665 .vidioc_s_ctrl = vidioc_s_ctrl,
666 .vidioc_g_audio = vidioc_g_audio,
667 .vidioc_s_audio = vidioc_s_audio,
668 .vidioc_g_input = vidioc_g_input,
669 .vidioc_s_input = vidioc_s_input,
672 static void usb_amradio_device_release(struct video_device *videodev)
674 struct amradio_device *radio = video_get_drvdata(videodev);
676 /* we call v4l to free radio->videodev */
677 video_device_release(videodev);
679 /* free rest memory */
680 kfree(radio->buffer);
685 static struct video_device amradio_videodev_template = {
686 .name = "AverMedia MR 800 USB FM Radio",
687 .fops = &usb_amradio_fops,
688 .ioctl_ops = &usb_amradio_ioctl_ops,
689 .release = usb_amradio_device_release,
692 /* check if the device is present and register with v4l and usb if it is */
693 static int usb_amradio_probe(struct usb_interface *intf,
694 const struct usb_device_id *id)
696 struct amradio_device *radio;
699 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
702 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
706 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
708 if (!radio->buffer) {
709 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
714 radio->videodev = video_device_alloc();
716 if (!radio->videodev) {
717 dev_err(&intf->dev, "video_device_alloc failed\n");
718 kfree(radio->buffer);
723 memcpy(radio->videodev, &amradio_videodev_template,
724 sizeof(amradio_videodev_template));
728 radio->usbdev = interface_to_usbdev(intf);
729 radio->curfreq = 95.16 * FREQ_MUL;
732 mutex_init(&radio->lock);
734 video_set_drvdata(radio->videodev, radio);
735 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
737 dev_err(&intf->dev, "could not register video device\n");
738 video_device_release(radio->videodev);
739 kfree(radio->buffer);
744 usb_set_intfdata(intf, radio);
748 static int __init amradio_init(void)
750 int retval = usb_register(&usb_amradio_driver);
752 pr_info(KBUILD_MODNAME
753 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
756 pr_err(KBUILD_MODNAME
757 ": usb_register failed. Error number %d\n", retval);
762 static void __exit amradio_exit(void)
764 usb_deregister(&usb_amradio_driver);
767 module_init(amradio_init);
768 module_exit(amradio_exit);