blob: 7b7a1cfb121dce6f049403f083175d43c92fa5a2 [file] [log] [blame]
Alexey Klimov2aa72f32008-10-01 09:40:59 -03001/*
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
Alexey Klimove60b0222008-11-04 15:02:36 -030075/* 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)
79
Alexey Klimov2aa72f32008-10-01 09:40:59 -030080/* Probably USB_TIMEOUT should be modified in module parameter */
81#define BUFFER_LENGTH 8
82#define USB_TIMEOUT 500
83
84/* Frequency limits in MHz -- these are European values. For Japanese
85devices, that would be 76 and 91. */
86#define FREQ_MIN 87.5
87#define FREQ_MAX 108.0
88#define FREQ_MUL 16000
89
90/* module parameter */
91static int radio_nr = -1;
92module_param(radio_nr, int, 0);
93MODULE_PARM_DESC(radio_nr, "Radio Nr");
94
95static struct v4l2_queryctrl radio_qctrl[] = {
96 {
97 .id = V4L2_CID_AUDIO_MUTE,
98 .name = "Mute",
99 .minimum = 0,
100 .maximum = 1,
101 .step = 1,
102 .default_value = 1,
103 .type = V4L2_CTRL_TYPE_BOOLEAN,
104 },
105/* HINT: the disabled controls are only here to satify kradio and such apps */
106 { .id = V4L2_CID_AUDIO_VOLUME,
107 .flags = V4L2_CTRL_FLAG_DISABLED,
108 },
109 {
110 .id = V4L2_CID_AUDIO_BALANCE,
111 .flags = V4L2_CTRL_FLAG_DISABLED,
112 },
113 {
114 .id = V4L2_CID_AUDIO_BASS,
115 .flags = V4L2_CTRL_FLAG_DISABLED,
116 },
117 {
118 .id = V4L2_CID_AUDIO_TREBLE,
119 .flags = V4L2_CTRL_FLAG_DISABLED,
120 },
121 {
122 .id = V4L2_CID_AUDIO_LOUDNESS,
123 .flags = V4L2_CTRL_FLAG_DISABLED,
124 },
125};
126
127static int usb_amradio_probe(struct usb_interface *intf,
128 const struct usb_device_id *id);
129static void usb_amradio_disconnect(struct usb_interface *intf);
130static int usb_amradio_open(struct inode *inode, struct file *file);
131static int usb_amradio_close(struct inode *inode, struct file *file);
132static int usb_amradio_suspend(struct usb_interface *intf,
133 pm_message_t message);
134static int usb_amradio_resume(struct usb_interface *intf);
135
136/* Data for one (physical) device */
137struct amradio_device {
138 /* reference to USB and video device */
139 struct usb_device *usbdev;
140 struct video_device *videodev;
141
142 unsigned char *buffer;
143 struct mutex lock; /* buffer locking */
Alexey Klimov34801302008-11-19 00:36:29 -0300144 struct mutex disconnect_lock;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300145 int curfreq;
146 int stereo;
147 int users;
148 int removed;
149 int muted;
150};
151
152/* USB Device ID List */
153static struct usb_device_id usb_amradio_device_table[] = {
154 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
155 USB_CLASS_HID, 0, 0) },
156 { } /* Terminating entry */
157};
158
159MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
160
161/* USB subsystem interface */
162static struct usb_driver usb_amradio_driver = {
Alexey Klimove60b0222008-11-04 15:02:36 -0300163 .name = MR800_DRIVER_NAME,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300164 .probe = usb_amradio_probe,
165 .disconnect = usb_amradio_disconnect,
166 .suspend = usb_amradio_suspend,
167 .resume = usb_amradio_resume,
168 .reset_resume = usb_amradio_resume,
169 .id_table = usb_amradio_device_table,
170 .supports_autosuspend = 1,
171};
172
173/* switch on radio. Send 8 bytes to device. */
174static int amradio_start(struct amradio_device *radio)
175{
176 int retval;
177 int size;
178
179 mutex_lock(&radio->lock);
180
181 radio->buffer[0] = 0x00;
182 radio->buffer[1] = 0x55;
183 radio->buffer[2] = 0xaa;
184 radio->buffer[3] = 0x00;
185 radio->buffer[4] = 0xab;
186 radio->buffer[5] = 0x00;
187 radio->buffer[6] = 0x00;
188 radio->buffer[7] = 0x00;
189
190 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
191 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
192
193 if (retval) {
194 mutex_unlock(&radio->lock);
195 return retval;
196 }
197
198 mutex_unlock(&radio->lock);
199
200 radio->muted = 0;
201
202 return retval;
203}
204
205/* switch off radio */
206static int amradio_stop(struct amradio_device *radio)
207{
208 int retval;
209 int size;
210
Alexey Klimov34801302008-11-19 00:36:29 -0300211 /* safety check */
212 if (radio->removed)
213 return -EIO;
214
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300215 mutex_lock(&radio->lock);
216
217 radio->buffer[0] = 0x00;
218 radio->buffer[1] = 0x55;
219 radio->buffer[2] = 0xaa;
220 radio->buffer[3] = 0x00;
221 radio->buffer[4] = 0xab;
222 radio->buffer[5] = 0x01;
223 radio->buffer[6] = 0x00;
224 radio->buffer[7] = 0x00;
225
226 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
227 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
228
229 if (retval) {
230 mutex_unlock(&radio->lock);
231 return retval;
232 }
233
234 mutex_unlock(&radio->lock);
235
236 radio->muted = 1;
237
238 return retval;
239}
240
241/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
242static int amradio_setfreq(struct amradio_device *radio, int freq)
243{
244 int retval;
245 int size;
246 unsigned short freq_send = 0x13 + (freq >> 3) / 25;
247
Alexey Klimov34801302008-11-19 00:36:29 -0300248 /* safety check */
249 if (radio->removed)
250 return -EIO;
251
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300252 mutex_lock(&radio->lock);
253
254 radio->buffer[0] = 0x00;
255 radio->buffer[1] = 0x55;
256 radio->buffer[2] = 0xaa;
257 radio->buffer[3] = 0x03;
258 radio->buffer[4] = 0xa4;
259 radio->buffer[5] = 0x00;
260 radio->buffer[6] = 0x00;
261 radio->buffer[7] = 0x08;
262
263 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
264 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
265
266 if (retval) {
267 mutex_unlock(&radio->lock);
268 return retval;
269 }
270
271 /* frequency is calculated from freq_send and placed in first 2 bytes */
272 radio->buffer[0] = (freq_send >> 8) & 0xff;
273 radio->buffer[1] = freq_send & 0xff;
274 radio->buffer[2] = 0x01;
275 radio->buffer[3] = 0x00;
276 radio->buffer[4] = 0x00;
277 /* 5 and 6 bytes of buffer already = 0x00 */
278 radio->buffer[7] = 0x00;
279
280 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
281 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
282
283 if (retval) {
284 mutex_unlock(&radio->lock);
285 return retval;
286 }
287
288 mutex_unlock(&radio->lock);
289
290 radio->stereo = 0;
291
292 return retval;
293}
294
295/* USB subsystem interface begins here */
296
297/* handle unplugging of the device, release data structures
298if nothing keeps us from doing it. If something is still
299keeping us busy, the release callback of v4l will take care
300of releasing it. */
301static void usb_amradio_disconnect(struct usb_interface *intf)
302{
303 struct amradio_device *radio = usb_get_intfdata(intf);
304
Alexey Klimov34801302008-11-19 00:36:29 -0300305 mutex_lock(&radio->disconnect_lock);
306 radio->removed = 1;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300307 usb_set_intfdata(intf, NULL);
308
Alexey Klimov34801302008-11-19 00:36:29 -0300309 if (radio->users == 0) {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300310 video_unregister_device(radio->videodev);
Alexey Klimov34801302008-11-19 00:36:29 -0300311 kfree(radio->buffer);
312 kfree(radio);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300313 }
Alexey Klimov34801302008-11-19 00:36:29 -0300314 mutex_unlock(&radio->disconnect_lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300315}
316
317/* vidioc_querycap - query device capabilities */
318static int vidioc_querycap(struct file *file, void *priv,
319 struct v4l2_capability *v)
320{
321 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
322 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
323 sprintf(v->bus_info, "USB");
324 v->version = RADIO_VERSION;
325 v->capabilities = V4L2_CAP_TUNER;
326 return 0;
327}
328
329/* vidioc_g_tuner - get tuner attributes */
330static int vidioc_g_tuner(struct file *file, void *priv,
331 struct v4l2_tuner *v)
332{
333 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
334
Alexey Klimov34801302008-11-19 00:36:29 -0300335 /* safety check */
336 if (radio->removed)
337 return -EIO;
338
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300339 if (v->index > 0)
340 return -EINVAL;
341
342/* TODO: Add function which look is signal stereo or not
343 * amradio_getstat(radio);
344 */
345 radio->stereo = -1;
346 strcpy(v->name, "FM");
347 v->type = V4L2_TUNER_RADIO;
348 v->rangelow = FREQ_MIN * FREQ_MUL;
349 v->rangehigh = FREQ_MAX * FREQ_MUL;
350 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
351 v->capability = V4L2_TUNER_CAP_LOW;
352 if (radio->stereo)
353 v->audmode = V4L2_TUNER_MODE_STEREO;
354 else
355 v->audmode = V4L2_TUNER_MODE_MONO;
356 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
357 v->afc = 0; /* Don't know what is this */
358 return 0;
359}
360
361/* vidioc_s_tuner - set tuner attributes */
362static int vidioc_s_tuner(struct file *file, void *priv,
363 struct v4l2_tuner *v)
364{
Alexey Klimov34801302008-11-19 00:36:29 -0300365 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
366
367 /* safety check */
368 if (radio->removed)
369 return -EIO;
370
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300371 if (v->index > 0)
372 return -EINVAL;
373 return 0;
374}
375
376/* vidioc_s_frequency - set tuner radio frequency */
377static int vidioc_s_frequency(struct file *file, void *priv,
378 struct v4l2_frequency *f)
379{
380 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
381
Alexey Klimov34801302008-11-19 00:36:29 -0300382 /* safety check */
383 if (radio->removed)
384 return -EIO;
385
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300386 radio->curfreq = f->frequency;
387 if (amradio_setfreq(radio, radio->curfreq) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300388 amradio_dev_warn(&radio->videodev->dev,
389 "set frequency failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300390 return 0;
391}
392
393/* vidioc_g_frequency - get tuner radio frequency */
394static int vidioc_g_frequency(struct file *file, void *priv,
395 struct v4l2_frequency *f)
396{
397 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
398
Alexey Klimov34801302008-11-19 00:36:29 -0300399 /* safety check */
400 if (radio->removed)
401 return -EIO;
402
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300403 f->type = V4L2_TUNER_RADIO;
404 f->frequency = radio->curfreq;
405 return 0;
406}
407
408/* vidioc_queryctrl - enumerate control items */
409static int vidioc_queryctrl(struct file *file, void *priv,
410 struct v4l2_queryctrl *qc)
411{
412 int i;
413
414 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
415 if (qc->id && qc->id == radio_qctrl[i].id) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300416 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300417 return 0;
418 }
419 }
420 return -EINVAL;
421}
422
423/* vidioc_g_ctrl - get the value of a control */
424static int vidioc_g_ctrl(struct file *file, void *priv,
425 struct v4l2_control *ctrl)
426{
427 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
428
Alexey Klimov34801302008-11-19 00:36:29 -0300429 /* safety check */
430 if (radio->removed)
431 return -EIO;
432
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300433 switch (ctrl->id) {
434 case V4L2_CID_AUDIO_MUTE:
435 ctrl->value = radio->muted;
436 return 0;
437 }
438 return -EINVAL;
439}
440
441/* vidioc_s_ctrl - set the value of a control */
442static int vidioc_s_ctrl(struct file *file, void *priv,
443 struct v4l2_control *ctrl)
444{
445 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
446
Alexey Klimov34801302008-11-19 00:36:29 -0300447 /* safety check */
448 if (radio->removed)
449 return -EIO;
450
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300451 switch (ctrl->id) {
452 case V4L2_CID_AUDIO_MUTE:
453 if (ctrl->value) {
454 if (amradio_stop(radio) < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300455 amradio_dev_warn(&radio->videodev->dev,
456 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300457 return -1;
458 }
459 } else {
460 if (amradio_start(radio) < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300461 amradio_dev_warn(&radio->videodev->dev,
462 "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300463 return -1;
464 }
465 }
466 return 0;
467 }
468 return -EINVAL;
469}
470
471/* vidioc_g_audio - get audio attributes */
472static int vidioc_g_audio(struct file *file, void *priv,
473 struct v4l2_audio *a)
474{
475 if (a->index > 1)
476 return -EINVAL;
477
478 strcpy(a->name, "Radio");
479 a->capability = V4L2_AUDCAP_STEREO;
480 return 0;
481}
482
483/* vidioc_s_audio - set audio attributes */
484static int vidioc_s_audio(struct file *file, void *priv,
485 struct v4l2_audio *a)
486{
487 if (a->index != 0)
488 return -EINVAL;
489 return 0;
490}
491
492/* vidioc_g_input - get input */
493static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
494{
495 *i = 0;
496 return 0;
497}
498
499/* vidioc_s_input - set input */
500static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
501{
502 if (i != 0)
503 return -EINVAL;
504 return 0;
505}
506
507/* open device - amradio_start() and amradio_setfreq() */
508static int usb_amradio_open(struct inode *inode, struct file *file)
509{
510 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
511
Alexey Klimov0fabb782008-10-19 23:56:23 -0300512 lock_kernel();
513
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300514 radio->users = 1;
515 radio->muted = 1;
516
517 if (amradio_start(radio) < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300518 amradio_dev_warn(&radio->videodev->dev,
519 "radio did not start up properly\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300520 radio->users = 0;
Alexey Klimov0fabb782008-10-19 23:56:23 -0300521 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300522 return -EIO;
523 }
524 if (amradio_setfreq(radio, radio->curfreq) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300525 amradio_dev_warn(&radio->videodev->dev,
526 "set frequency failed\n");
Alexey Klimov0fabb782008-10-19 23:56:23 -0300527
528 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300529 return 0;
530}
531
532/*close device - free driver structures */
533static int usb_amradio_close(struct inode *inode, struct file *file)
534{
535 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov34801302008-11-19 00:36:29 -0300536 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300537
538 if (!radio)
539 return -ENODEV;
Alexey Klimov34801302008-11-19 00:36:29 -0300540
541 mutex_lock(&radio->disconnect_lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300542 radio->users = 0;
543 if (radio->removed) {
Alexey Klimov34801302008-11-19 00:36:29 -0300544 video_unregister_device(radio->videodev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300545 kfree(radio->buffer);
546 kfree(radio);
Alexey Klimov34801302008-11-19 00:36:29 -0300547
548 } else {
549 retval = amradio_stop(radio);
550 if (retval < 0)
551 amradio_dev_warn(&radio->videodev->dev,
552 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300553 }
Alexey Klimov34801302008-11-19 00:36:29 -0300554
555 mutex_unlock(&radio->disconnect_lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300556 return 0;
557}
558
559/* Suspend device - stop device. Need to be checked and fixed */
560static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
561{
562 struct amradio_device *radio = usb_get_intfdata(intf);
563
564 if (amradio_stop(radio) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300565 dev_warn(&intf->dev, "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300566
Alexey Klimove60b0222008-11-04 15:02:36 -0300567 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300568
569 return 0;
570}
571
572/* Resume device - start device. Need to be checked and fixed */
573static int usb_amradio_resume(struct usb_interface *intf)
574{
575 struct amradio_device *radio = usb_get_intfdata(intf);
576
577 if (amradio_start(radio) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300578 dev_warn(&intf->dev, "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300579
Alexey Klimove60b0222008-11-04 15:02:36 -0300580 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300581
582 return 0;
583}
584
585/* File system interface */
586static const struct file_operations usb_amradio_fops = {
587 .owner = THIS_MODULE,
588 .open = usb_amradio_open,
589 .release = usb_amradio_close,
590 .ioctl = video_ioctl2,
591#ifdef CONFIG_COMPAT
592 .compat_ioctl = v4l_compat_ioctl32,
593#endif
594 .llseek = no_llseek,
595};
596
597static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
598 .vidioc_querycap = vidioc_querycap,
599 .vidioc_g_tuner = vidioc_g_tuner,
600 .vidioc_s_tuner = vidioc_s_tuner,
601 .vidioc_g_frequency = vidioc_g_frequency,
602 .vidioc_s_frequency = vidioc_s_frequency,
603 .vidioc_queryctrl = vidioc_queryctrl,
604 .vidioc_g_ctrl = vidioc_g_ctrl,
605 .vidioc_s_ctrl = vidioc_s_ctrl,
606 .vidioc_g_audio = vidioc_g_audio,
607 .vidioc_s_audio = vidioc_s_audio,
608 .vidioc_g_input = vidioc_g_input,
609 .vidioc_s_input = vidioc_s_input,
610};
611
612/* V4L2 interface */
613static struct video_device amradio_videodev_template = {
614 .name = "AverMedia MR 800 USB FM Radio",
615 .fops = &usb_amradio_fops,
616 .ioctl_ops = &usb_amradio_ioctl_ops,
617 .release = video_device_release,
618};
619
620/* check if the device is present and register with v4l and
621usb if it is */
622static int usb_amradio_probe(struct usb_interface *intf,
623 const struct usb_device_id *id)
624{
625 struct amradio_device *radio;
626
627 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
628
629 if (!(radio))
630 return -ENOMEM;
631
632 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
633
634 if (!(radio->buffer)) {
635 kfree(radio);
636 return -ENOMEM;
637 }
638
639 radio->videodev = video_device_alloc();
640
641 if (!(radio->videodev)) {
642 kfree(radio->buffer);
643 kfree(radio);
644 return -ENOMEM;
645 }
646
647 memcpy(radio->videodev, &amradio_videodev_template,
648 sizeof(amradio_videodev_template));
649
650 radio->removed = 0;
651 radio->users = 0;
652 radio->usbdev = interface_to_usbdev(intf);
653 radio->curfreq = 95.16 * FREQ_MUL;
654
Alexey Klimov34801302008-11-19 00:36:29 -0300655 mutex_init(&radio->disconnect_lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300656 mutex_init(&radio->lock);
657
658 video_set_drvdata(radio->videodev, radio);
659 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300660 dev_warn(&intf->dev, "could not register video device\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300661 video_device_release(radio->videodev);
662 kfree(radio->buffer);
663 kfree(radio);
664 return -EIO;
665 }
666
667 usb_set_intfdata(intf, radio);
668 return 0;
669}
670
671static int __init amradio_init(void)
672{
673 int retval = usb_register(&usb_amradio_driver);
674
Alexey Klimove60b0222008-11-04 15:02:36 -0300675 pr_info(KBUILD_MODNAME
676 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
677
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300678 if (retval)
Alexey Klimove60b0222008-11-04 15:02:36 -0300679 pr_err(KBUILD_MODNAME
680 ": usb_register failed. Error number %d\n", retval);
681
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300682 return retval;
683}
684
685static void __exit amradio_exit(void)
686{
687 usb_deregister(&usb_amradio_driver);
688}
689
690module_init(amradio_init);
691module_exit(amradio_exit);
692