1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57#include <linux/kernel.h>
58#include <linux/module.h>
59#include <linux/init.h>
60#include <linux/slab.h>
61#include <linux/input.h>
62#include <linux/videodev2.h>
63#include <media/v4l2-device.h>
64#include <media/v4l2-ioctl.h>
65#include <linux/usb.h>
66#include <linux/mutex.h>
67
68
69#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
70#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
71#define DRIVER_VERSION "0.1.2"
72
73MODULE_AUTHOR(DRIVER_AUTHOR);
74MODULE_DESCRIPTION(DRIVER_DESC);
75MODULE_LICENSE("GPL");
76MODULE_VERSION(DRIVER_VERSION);
77
78#define USB_AMRADIO_VENDOR 0x07ca
79#define USB_AMRADIO_PRODUCT 0xb800
80
81
82#define MR800_DRIVER_NAME "radio-mr800"
83#define amradio_dev_warn(dev, fmt, arg...) \
84 dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
85
86#define amradio_dev_err(dev, fmt, arg...) \
87 dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
88
89
90#define BUFFER_LENGTH 8
91#define USB_TIMEOUT 500
92
93
94
95#define FREQ_MIN 87.5
96#define FREQ_MAX 108.0
97#define FREQ_MUL 16000
98
99
100
101
102
103#define AMRADIO_SET_FREQ 0xa4
104#define AMRADIO_SET_MUTE 0xab
105#define AMRADIO_SET_MONO 0xae
106
107
108#define AMRADIO_START 0x00
109#define AMRADIO_STOP 0x01
110
111
112#define WANT_STEREO 0x00
113#define WANT_MONO 0x01
114
115
116static int radio_nr = -1;
117module_param(radio_nr, int, 0);
118MODULE_PARM_DESC(radio_nr, "Radio Nr");
119
120static int usb_amradio_probe(struct usb_interface *intf,
121 const struct usb_device_id *id);
122static void usb_amradio_disconnect(struct usb_interface *intf);
123static int usb_amradio_open(struct file *file);
124static int usb_amradio_close(struct file *file);
125static int usb_amradio_suspend(struct usb_interface *intf,
126 pm_message_t message);
127static int usb_amradio_resume(struct usb_interface *intf);
128
129
130struct amradio_device {
131
132 struct usb_device *usbdev;
133 struct usb_interface *intf;
134 struct video_device videodev;
135 struct v4l2_device v4l2_dev;
136
137 unsigned char *buffer;
138 struct mutex lock;
139 int curfreq;
140 int stereo;
141 int muted;
142 int initialized;
143};
144
145static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev)
146{
147 return container_of(v4l2_dev, struct amradio_device, v4l2_dev);
148}
149
150
151static struct usb_device_id usb_amradio_device_table[] = {
152 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
153 USB_CLASS_HID, 0, 0) },
154 { }
155};
156
157MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
158
159
160static struct usb_driver usb_amradio_driver = {
161 .name = MR800_DRIVER_NAME,
162 .probe = usb_amradio_probe,
163 .disconnect = usb_amradio_disconnect,
164 .suspend = usb_amradio_suspend,
165 .resume = usb_amradio_resume,
166 .reset_resume = usb_amradio_resume,
167 .id_table = usb_amradio_device_table,
168 .supports_autosuspend = 1,
169};
170
171
172static int amradio_set_mute(struct amradio_device *radio, char argument)
173{
174 int retval;
175 int size;
176
177 radio->buffer[0] = 0x00;
178 radio->buffer[1] = 0x55;
179 radio->buffer[2] = 0xaa;
180 radio->buffer[3] = 0x00;
181 radio->buffer[4] = AMRADIO_SET_MUTE;
182 radio->buffer[5] = argument;
183 radio->buffer[6] = 0x00;
184 radio->buffer[7] = 0x00;
185
186 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
187 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
188
189 if (retval < 0 || size != BUFFER_LENGTH) {
190 amradio_dev_warn(&radio->videodev.dev, "set mute failed\n");
191 return retval;
192 }
193
194 radio->muted = argument;
195
196 return retval;
197}
198
199
200static int amradio_setfreq(struct amradio_device *radio, int freq)
201{
202 int retval;
203 int size;
204 unsigned short freq_send = 0x10 + (freq >> 3) / 25;
205
206 radio->buffer[0] = 0x00;
207 radio->buffer[1] = 0x55;
208 radio->buffer[2] = 0xaa;
209 radio->buffer[3] = 0x03;
210 radio->buffer[4] = AMRADIO_SET_FREQ;
211 radio->buffer[5] = 0x00;
212 radio->buffer[6] = 0x00;
213 radio->buffer[7] = 0x08;
214
215 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
216 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
217
218 if (retval < 0 || size != BUFFER_LENGTH)
219 goto out_err;
220
221
222 radio->buffer[0] = (freq_send >> 8) & 0xff;
223 radio->buffer[1] = freq_send & 0xff;
224 radio->buffer[2] = 0x01;
225 radio->buffer[3] = 0x00;
226 radio->buffer[4] = 0x00;
227
228 radio->buffer[7] = 0x00;
229
230 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
231 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
232
233 if (retval < 0 || size != BUFFER_LENGTH)
234 goto out_err;
235
236 radio->curfreq = freq;
237 goto out;
238
239out_err:
240 amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n");
241out:
242 return retval;
243}
244
245static int amradio_set_stereo(struct amradio_device *radio, char argument)
246{
247 int retval;
248 int size;
249
250 radio->buffer[0] = 0x00;
251 radio->buffer[1] = 0x55;
252 radio->buffer[2] = 0xaa;
253 radio->buffer[3] = 0x00;
254 radio->buffer[4] = AMRADIO_SET_MONO;
255 radio->buffer[5] = argument;
256 radio->buffer[6] = 0x00;
257 radio->buffer[7] = 0x00;
258
259 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
260 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
261
262 if (retval < 0 || size != BUFFER_LENGTH) {
263 amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n");
264 return retval;
265 }
266
267 if (argument == WANT_STEREO)
268 radio->stereo = 1;
269 else
270 radio->stereo = 0;
271
272 return retval;
273}
274
275
276
277
278
279
280static void usb_amradio_disconnect(struct usb_interface *intf)
281{
282 struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
283
284 mutex_lock(&radio->lock);
285
286 get_device(&radio->videodev.dev);
287 v4l2_device_disconnect(&radio->v4l2_dev);
288 video_unregister_device(&radio->videodev);
289 mutex_unlock(&radio->lock);
290
291 put_device(&radio->videodev.dev);
292}
293
294
295static int vidioc_querycap(struct file *file, void *priv,
296 struct v4l2_capability *v)
297{
298 struct amradio_device *radio = file->private_data;
299
300 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
301 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
302 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
303 v->capabilities = V4L2_CAP_TUNER;
304 return 0;
305}
306
307
308static int vidioc_g_tuner(struct file *file, void *priv,
309 struct v4l2_tuner *v)
310{
311 struct amradio_device *radio = file->private_data;
312 int retval;
313
314 if (v->index > 0)
315 return -EINVAL;
316
317
318
319
320
321
322
323
324
325 retval = amradio_set_stereo(radio, WANT_STEREO);
326
327 strcpy(v->name, "FM");
328 v->type = V4L2_TUNER_RADIO;
329 v->rangelow = FREQ_MIN * FREQ_MUL;
330 v->rangehigh = FREQ_MAX * FREQ_MUL;
331 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
332 v->capability = V4L2_TUNER_CAP_LOW;
333 if (radio->stereo)
334 v->audmode = V4L2_TUNER_MODE_STEREO;
335 else
336 v->audmode = V4L2_TUNER_MODE_MONO;
337 v->signal = 0xffff;
338 v->afc = 0;
339
340 return retval;
341}
342
343
344static int vidioc_s_tuner(struct file *file, void *priv,
345 struct v4l2_tuner *v)
346{
347 struct amradio_device *radio = file->private_data;
348 int retval = -EINVAL;
349
350 if (v->index > 0)
351 return -EINVAL;
352
353
354 switch (v->audmode) {
355 case V4L2_TUNER_MODE_MONO:
356 retval = amradio_set_stereo(radio, WANT_MONO);
357 break;
358 case V4L2_TUNER_MODE_STEREO:
359 retval = amradio_set_stereo(radio, WANT_STEREO);
360 break;
361 }
362
363 return retval;
364}
365
366
367static int vidioc_s_frequency(struct file *file, void *priv,
368 struct v4l2_frequency *f)
369{
370 struct amradio_device *radio = file->private_data;
371
372 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
373 return -EINVAL;
374 return amradio_setfreq(radio, f->frequency);
375}
376
377
378static int vidioc_g_frequency(struct file *file, void *priv,
379 struct v4l2_frequency *f)
380{
381 struct amradio_device *radio = file->private_data;
382
383 if (f->tuner != 0)
384 return -EINVAL;
385 f->type = V4L2_TUNER_RADIO;
386 f->frequency = radio->curfreq;
387
388 return 0;
389}
390
391
392static int vidioc_queryctrl(struct file *file, void *priv,
393 struct v4l2_queryctrl *qc)
394{
395 switch (qc->id) {
396 case V4L2_CID_AUDIO_MUTE:
397 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
398 }
399
400 return -EINVAL;
401}
402
403
404static int vidioc_g_ctrl(struct file *file, void *priv,
405 struct v4l2_control *ctrl)
406{
407 struct amradio_device *radio = file->private_data;
408
409 switch (ctrl->id) {
410 case V4L2_CID_AUDIO_MUTE:
411 ctrl->value = radio->muted;
412 return 0;
413 }
414
415 return -EINVAL;
416}
417
418
419static int vidioc_s_ctrl(struct file *file, void *priv,
420 struct v4l2_control *ctrl)
421{
422 struct amradio_device *radio = file->private_data;
423 int retval = -EINVAL;
424
425 switch (ctrl->id) {
426 case V4L2_CID_AUDIO_MUTE:
427 if (ctrl->value)
428 retval = amradio_set_mute(radio, AMRADIO_STOP);
429 else
430 retval = amradio_set_mute(radio, AMRADIO_START);
431
432 break;
433 }
434
435 return retval;
436}
437
438
439static int vidioc_g_audio(struct file *file, void *priv,
440 struct v4l2_audio *a)
441{
442 if (a->index > 1)
443 return -EINVAL;
444
445 strcpy(a->name, "Radio");
446 a->capability = V4L2_AUDCAP_STEREO;
447 return 0;
448}
449
450
451static int vidioc_s_audio(struct file *file, void *priv,
452 struct v4l2_audio *a)
453{
454 if (a->index != 0)
455 return -EINVAL;
456 return 0;
457}
458
459
460static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
461{
462 *i = 0;
463 return 0;
464}
465
466
467static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
468{
469 if (i != 0)
470 return -EINVAL;
471 return 0;
472}
473
474static int usb_amradio_init(struct amradio_device *radio)
475{
476 int retval;
477
478 retval = amradio_set_mute(radio, AMRADIO_STOP);
479 if (retval)
480 goto out_err;
481
482 retval = amradio_set_stereo(radio, WANT_STEREO);
483 if (retval)
484 goto out_err;
485
486 radio->initialized = 1;
487 goto out;
488
489out_err:
490 amradio_dev_err(&radio->videodev.dev, "initialization failed\n");
491out:
492 return retval;
493}
494
495
496static int usb_amradio_open(struct file *file)
497{
498 struct amradio_device *radio = video_drvdata(file);
499 int retval;
500
501 file->private_data = radio;
502 retval = usb_autopm_get_interface(radio->intf);
503 if (retval)
504 return retval;
505
506 if (unlikely(!radio->initialized)) {
507 retval = usb_amradio_init(radio);
508 if (retval)
509 usb_autopm_put_interface(radio->intf);
510 }
511 return retval;
512}
513
514
515static int usb_amradio_close(struct file *file)
516{
517 struct amradio_device *radio = file->private_data;
518
519 if (video_is_registered(&radio->videodev))
520 usb_autopm_put_interface(radio->intf);
521 return 0;
522}
523
524
525static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
526{
527 struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
528
529 mutex_lock(&radio->lock);
530 if (!radio->muted && radio->initialized) {
531 amradio_set_mute(radio, AMRADIO_STOP);
532 radio->muted = 0;
533 }
534 mutex_unlock(&radio->lock);
535
536 dev_info(&intf->dev, "going into suspend..\n");
537 return 0;
538}
539
540
541static int usb_amradio_resume(struct usb_interface *intf)
542{
543 struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
544
545 mutex_lock(&radio->lock);
546 if (unlikely(!radio->initialized))
547 goto unlock;
548
549 if (radio->stereo)
550 amradio_set_stereo(radio, WANT_STEREO);
551 else
552 amradio_set_stereo(radio, WANT_MONO);
553
554 amradio_setfreq(radio, radio->curfreq);
555
556 if (!radio->muted)
557 amradio_set_mute(radio, AMRADIO_START);
558
559unlock:
560 mutex_unlock(&radio->lock);
561
562 dev_info(&intf->dev, "coming out of suspend..\n");
563 return 0;
564}
565
566
567static const struct v4l2_file_operations usb_amradio_fops = {
568 .owner = THIS_MODULE,
569 .open = usb_amradio_open,
570 .release = usb_amradio_close,
571 .unlocked_ioctl = video_ioctl2,
572};
573
574static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
575 .vidioc_querycap = vidioc_querycap,
576 .vidioc_g_tuner = vidioc_g_tuner,
577 .vidioc_s_tuner = vidioc_s_tuner,
578 .vidioc_g_frequency = vidioc_g_frequency,
579 .vidioc_s_frequency = vidioc_s_frequency,
580 .vidioc_queryctrl = vidioc_queryctrl,
581 .vidioc_g_ctrl = vidioc_g_ctrl,
582 .vidioc_s_ctrl = vidioc_s_ctrl,
583 .vidioc_g_audio = vidioc_g_audio,
584 .vidioc_s_audio = vidioc_s_audio,
585 .vidioc_g_input = vidioc_g_input,
586 .vidioc_s_input = vidioc_s_input,
587};
588
589static void usb_amradio_video_device_release(struct video_device *videodev)
590{
591 struct amradio_device *radio = video_get_drvdata(videodev);
592
593
594 kfree(radio->buffer);
595 kfree(radio);
596}
597
598
599static int usb_amradio_probe(struct usb_interface *intf,
600 const struct usb_device_id *id)
601{
602 struct amradio_device *radio;
603 int retval = 0;
604
605 radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
606
607 if (!radio) {
608 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
609 retval = -ENOMEM;
610 goto err;
611 }
612
613 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
614
615 if (!radio->buffer) {
616 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
617 retval = -ENOMEM;
618 goto err_nobuf;
619 }
620
621 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
622 if (retval < 0) {
623 dev_err(&intf->dev, "couldn't register v4l2_device\n");
624 goto err_v4l2;
625 }
626
627 mutex_init(&radio->lock);
628
629 strlcpy(radio->videodev.name, radio->v4l2_dev.name,
630 sizeof(radio->videodev.name));
631 radio->videodev.v4l2_dev = &radio->v4l2_dev;
632 radio->videodev.fops = &usb_amradio_fops;
633 radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
634 radio->videodev.release = usb_amradio_video_device_release;
635 radio->videodev.lock = &radio->lock;
636
637 radio->usbdev = interface_to_usbdev(intf);
638 radio->intf = intf;
639 radio->curfreq = 95.16 * FREQ_MUL;
640
641 video_set_drvdata(&radio->videodev, radio);
642
643 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
644 radio_nr);
645 if (retval < 0) {
646 dev_err(&intf->dev, "could not register video device\n");
647 goto err_vdev;
648 }
649
650 return 0;
651
652err_vdev:
653 v4l2_device_unregister(&radio->v4l2_dev);
654err_v4l2:
655 kfree(radio->buffer);
656err_nobuf:
657 kfree(radio);
658err:
659 return retval;
660}
661
662module_usb_driver(usb_amradio_driver);
663