V4L/DVB (9512): cx18: Fix write retries for registers that always change - part 3.
[linux-block.git] / drivers / media / radio / radio-mr800.c
CommitLineData
2aa72f3b
AK
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
68MODULE_AUTHOR(DRIVER_AUTHOR);
69MODULE_DESCRIPTION(DRIVER_DESC);
70MODULE_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
80devices, 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 */
86static int radio_nr = -1;
87module_param(radio_nr, int, 0);
88MODULE_PARM_DESC(radio_nr, "Radio Nr");
89
90static 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
122static int usb_amradio_probe(struct usb_interface *intf,
123 const struct usb_device_id *id);
124static void usb_amradio_disconnect(struct usb_interface *intf);
125static int usb_amradio_open(struct inode *inode, struct file *file);
126static int usb_amradio_close(struct inode *inode, struct file *file);
127static int usb_amradio_suspend(struct usb_interface *intf,
128 pm_message_t message);
129static int usb_amradio_resume(struct usb_interface *intf);
130
131/* Data for one (physical) device */
132struct 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 */
147static 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
153MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
154
155/* USB subsystem interface */
156static 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. */
168static 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 */
200static 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 */
232static 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
284if nothing keeps us from doing it. If something is still
285keeping us busy, the release callback of v4l will take care
286of releasing it. */
287static 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 */
306static 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 */
318static 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 */
346static 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 */
355static 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 */
367static 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 */
378static 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 */
394static 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 */
408static 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 */
432static 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 */
444static 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 */
453static 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 */
460static 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() */
468static int usb_amradio_open(struct inode *inode, struct file *file)
469{
470 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
471
0fabb783
AK
472 lock_kernel();
473
2aa72f3b
AK
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;
0fabb783 480 unlock_kernel();
2aa72f3b
AK
481 return -EIO;
482 }
483 if (amradio_setfreq(radio, radio->curfreq) < 0)
484 warn("Set frequency failed");
0fabb783
AK
485
486 unlock_kernel();
2aa72f3b
AK
487 return 0;
488}
489
490/*close device - free driver structures */
491static 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 */
506static 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 */
519static 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 */
532static 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
543static 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 */
559static 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
567usb if it is */
568static 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
616static 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
626static void __exit amradio_exit(void)
627{
628 usb_deregister(&usb_amradio_driver);
629}
630
631module_init(amradio_init);
632module_exit(amradio_exit);
633