]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/radio/radio-mr800.c
math-emu: Fix thinko in _FP_DIV
[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         radio->users = 1;
473         radio->muted = 1;
474
475         if (amradio_start(radio) < 0) {
476                 warn("Radio did not start up properly");
477                 radio->users = 0;
478                 return -EIO;
479         }
480         if (amradio_setfreq(radio, radio->curfreq) < 0)
481                 warn("Set frequency failed");
482         return 0;
483 }
484
485 /*close device - free driver structures */
486 static int usb_amradio_close(struct inode *inode, struct file *file)
487 {
488         struct amradio_device *radio = video_get_drvdata(video_devdata(file));
489
490         if (!radio)
491                 return -ENODEV;
492         radio->users = 0;
493         if (radio->removed) {
494                 kfree(radio->buffer);
495                 kfree(radio);
496         }
497         return 0;
498 }
499
500 /* Suspend device - stop device. Need to be checked and fixed */
501 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
502 {
503         struct amradio_device *radio = usb_get_intfdata(intf);
504
505         if (amradio_stop(radio) < 0)
506                 warn("amradio_stop() failed");
507
508         info("radio-mr800: Going into suspend..");
509
510         return 0;
511 }
512
513 /* Resume device - start device. Need to be checked and fixed */
514 static int usb_amradio_resume(struct usb_interface *intf)
515 {
516         struct amradio_device *radio = usb_get_intfdata(intf);
517
518         if (amradio_start(radio) < 0)
519                 warn("amradio_start() failed");
520
521         info("radio-mr800: Coming out of suspend..");
522
523         return 0;
524 }
525
526 /* File system interface */
527 static const struct file_operations usb_amradio_fops = {
528         .owner          = THIS_MODULE,
529         .open           = usb_amradio_open,
530         .release        = usb_amradio_close,
531         .ioctl          = video_ioctl2,
532 #ifdef CONFIG_COMPAT
533         .compat_ioctl   = v4l_compat_ioctl32,
534 #endif
535         .llseek         = no_llseek,
536 };
537
538 static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
539         .vidioc_querycap    = vidioc_querycap,
540         .vidioc_g_tuner     = vidioc_g_tuner,
541         .vidioc_s_tuner     = vidioc_s_tuner,
542         .vidioc_g_frequency = vidioc_g_frequency,
543         .vidioc_s_frequency = vidioc_s_frequency,
544         .vidioc_queryctrl   = vidioc_queryctrl,
545         .vidioc_g_ctrl      = vidioc_g_ctrl,
546         .vidioc_s_ctrl      = vidioc_s_ctrl,
547         .vidioc_g_audio     = vidioc_g_audio,
548         .vidioc_s_audio     = vidioc_s_audio,
549         .vidioc_g_input     = vidioc_g_input,
550         .vidioc_s_input     = vidioc_s_input,
551 };
552
553 /* V4L2 interface */
554 static struct video_device amradio_videodev_template = {
555         .name           = "AverMedia MR 800 USB FM Radio",
556         .fops           = &usb_amradio_fops,
557         .ioctl_ops      = &usb_amradio_ioctl_ops,
558         .release        = video_device_release,
559 };
560
561 /* check if the device is present and register with v4l and
562 usb if it is */
563 static int usb_amradio_probe(struct usb_interface *intf,
564                                 const struct usb_device_id *id)
565 {
566         struct amradio_device *radio;
567
568         radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
569
570         if (!(radio))
571                 return -ENOMEM;
572
573         radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
574
575         if (!(radio->buffer)) {
576                 kfree(radio);
577                 return -ENOMEM;
578         }
579
580         radio->videodev = video_device_alloc();
581
582         if (!(radio->videodev)) {
583                 kfree(radio->buffer);
584                 kfree(radio);
585                 return -ENOMEM;
586         }
587
588         memcpy(radio->videodev, &amradio_videodev_template,
589                 sizeof(amradio_videodev_template));
590
591         radio->removed = 0;
592         radio->users = 0;
593         radio->usbdev = interface_to_usbdev(intf);
594         radio->curfreq = 95.16 * FREQ_MUL;
595
596         mutex_init(&radio->lock);
597
598         video_set_drvdata(radio->videodev, radio);
599         if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
600                 warn("Could not register video device");
601                 video_device_release(radio->videodev);
602                 kfree(radio->buffer);
603                 kfree(radio);
604                 return -EIO;
605         }
606
607         usb_set_intfdata(intf, radio);
608         return 0;
609 }
610
611 static int __init amradio_init(void)
612 {
613         int retval = usb_register(&usb_amradio_driver);
614
615         info(DRIVER_VERSION " " DRIVER_DESC);
616         if (retval)
617                 err("usb_register failed. Error number %d", retval);
618         return retval;
619 }
620
621 static void __exit amradio_exit(void)
622 {
623         usb_deregister(&usb_amradio_driver);
624 }
625
626 module_init(amradio_init);
627 module_exit(amradio_exit);
628