blob: 624e98b575cf1b873f1032b350648f91a54ede68 [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);
Hans Verkuilbec43662008-12-30 06:58:20 -0300130static int usb_amradio_open(struct file *file);
131static int usb_amradio_close(struct file *file);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300132static 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 */
144 int curfreq;
145 int stereo;
146 int users;
147 int removed;
148 int muted;
149};
150
151/* USB Device ID List */
152static struct usb_device_id usb_amradio_device_table[] = {
153 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
154 USB_CLASS_HID, 0, 0) },
155 { } /* Terminating entry */
156};
157
158MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
159
160/* USB subsystem interface */
161static struct usb_driver usb_amradio_driver = {
Alexey Klimove60b0222008-11-04 15:02:36 -0300162 .name = MR800_DRIVER_NAME,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300163 .probe = usb_amradio_probe,
164 .disconnect = usb_amradio_disconnect,
165 .suspend = usb_amradio_suspend,
166 .resume = usb_amradio_resume,
167 .reset_resume = usb_amradio_resume,
168 .id_table = usb_amradio_device_table,
Alexey Klimovf2ce9172008-12-27 21:31:49 -0300169 .supports_autosuspend = 0,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300170};
171
172/* switch on radio. Send 8 bytes to device. */
173static int amradio_start(struct amradio_device *radio)
174{
175 int retval;
176 int size;
177
178 mutex_lock(&radio->lock);
179
180 radio->buffer[0] = 0x00;
181 radio->buffer[1] = 0x55;
182 radio->buffer[2] = 0xaa;
183 radio->buffer[3] = 0x00;
184 radio->buffer[4] = 0xab;
185 radio->buffer[5] = 0x00;
186 radio->buffer[6] = 0x00;
187 radio->buffer[7] = 0x00;
188
189 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
190 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
191
192 if (retval) {
193 mutex_unlock(&radio->lock);
194 return retval;
195 }
196
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300197 radio->muted = 0;
198
Alexey Klimov7f03a582009-01-25 20:07:28 -0300199 mutex_unlock(&radio->lock);
200
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300201 return retval;
202}
203
204/* switch off radio */
205static int amradio_stop(struct amradio_device *radio)
206{
207 int retval;
208 int size;
209
Alexey Klimov34801302008-11-19 00:36:29 -0300210 /* safety check */
211 if (radio->removed)
212 return -EIO;
213
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300214 mutex_lock(&radio->lock);
215
216 radio->buffer[0] = 0x00;
217 radio->buffer[1] = 0x55;
218 radio->buffer[2] = 0xaa;
219 radio->buffer[3] = 0x00;
220 radio->buffer[4] = 0xab;
221 radio->buffer[5] = 0x01;
222 radio->buffer[6] = 0x00;
223 radio->buffer[7] = 0x00;
224
225 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
226 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
227
228 if (retval) {
229 mutex_unlock(&radio->lock);
230 return retval;
231 }
232
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300233 radio->muted = 1;
234
Alexey Klimov7f03a582009-01-25 20:07:28 -0300235 mutex_unlock(&radio->lock);
236
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300237 return retval;
238}
239
240/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
241static int amradio_setfreq(struct amradio_device *radio, int freq)
242{
243 int retval;
244 int size;
245 unsigned short freq_send = 0x13 + (freq >> 3) / 25;
246
Alexey Klimov34801302008-11-19 00:36:29 -0300247 /* safety check */
248 if (radio->removed)
249 return -EIO;
250
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300251 mutex_lock(&radio->lock);
252
253 radio->buffer[0] = 0x00;
254 radio->buffer[1] = 0x55;
255 radio->buffer[2] = 0xaa;
256 radio->buffer[3] = 0x03;
257 radio->buffer[4] = 0xa4;
258 radio->buffer[5] = 0x00;
259 radio->buffer[6] = 0x00;
260 radio->buffer[7] = 0x08;
261
262 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
263 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
264
265 if (retval) {
266 mutex_unlock(&radio->lock);
267 return retval;
268 }
269
270 /* frequency is calculated from freq_send and placed in first 2 bytes */
271 radio->buffer[0] = (freq_send >> 8) & 0xff;
272 radio->buffer[1] = freq_send & 0xff;
273 radio->buffer[2] = 0x01;
274 radio->buffer[3] = 0x00;
275 radio->buffer[4] = 0x00;
276 /* 5 and 6 bytes of buffer already = 0x00 */
277 radio->buffer[7] = 0x00;
278
279 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
280 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
281
282 if (retval) {
283 mutex_unlock(&radio->lock);
284 return retval;
285 }
286
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300287 radio->stereo = 0;
288
Alexey Klimov7f03a582009-01-25 20:07:28 -0300289 mutex_unlock(&radio->lock);
290
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300291 return retval;
292}
293
294/* USB subsystem interface begins here */
295
296/* handle unplugging of the device, release data structures
297if nothing keeps us from doing it. If something is still
298keeping us busy, the release callback of v4l will take care
299of releasing it. */
300static void usb_amradio_disconnect(struct usb_interface *intf)
301{
302 struct amradio_device *radio = usb_get_intfdata(intf);
303
Alexey Klimovf4e90432008-12-27 21:30:34 -0300304 mutex_lock(&radio->lock);
Alexey Klimov34801302008-11-19 00:36:29 -0300305 radio->removed = 1;
Alexey Klimovf4e90432008-12-27 21:30:34 -0300306 mutex_unlock(&radio->lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300307
Alexey Klimovf4e90432008-12-27 21:30:34 -0300308 usb_set_intfdata(intf, NULL);
309 video_unregister_device(radio->videodev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300310}
311
312/* vidioc_querycap - query device capabilities */
313static int vidioc_querycap(struct file *file, void *priv,
314 struct v4l2_capability *v)
315{
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300316 struct amradio_device *radio = video_drvdata(file);
317
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300318 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
319 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300320 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300321 v->version = RADIO_VERSION;
322 v->capabilities = V4L2_CAP_TUNER;
323 return 0;
324}
325
326/* vidioc_g_tuner - get tuner attributes */
327static int vidioc_g_tuner(struct file *file, void *priv,
328 struct v4l2_tuner *v)
329{
330 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
331
Alexey Klimov34801302008-11-19 00:36:29 -0300332 /* safety check */
333 if (radio->removed)
334 return -EIO;
335
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300336 if (v->index > 0)
337 return -EINVAL;
338
339/* TODO: Add function which look is signal stereo or not
340 * amradio_getstat(radio);
341 */
342 radio->stereo = -1;
343 strcpy(v->name, "FM");
344 v->type = V4L2_TUNER_RADIO;
345 v->rangelow = FREQ_MIN * FREQ_MUL;
346 v->rangehigh = FREQ_MAX * FREQ_MUL;
347 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
348 v->capability = V4L2_TUNER_CAP_LOW;
349 if (radio->stereo)
350 v->audmode = V4L2_TUNER_MODE_STEREO;
351 else
352 v->audmode = V4L2_TUNER_MODE_MONO;
353 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
354 v->afc = 0; /* Don't know what is this */
355 return 0;
356}
357
358/* vidioc_s_tuner - set tuner attributes */
359static int vidioc_s_tuner(struct file *file, void *priv,
360 struct v4l2_tuner *v)
361{
Alexey Klimov34801302008-11-19 00:36:29 -0300362 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
363
364 /* safety check */
365 if (radio->removed)
366 return -EIO;
367
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300368 if (v->index > 0)
369 return -EINVAL;
370 return 0;
371}
372
373/* vidioc_s_frequency - set tuner radio frequency */
374static int vidioc_s_frequency(struct file *file, void *priv,
375 struct v4l2_frequency *f)
376{
377 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
378
Alexey Klimov34801302008-11-19 00:36:29 -0300379 /* safety check */
380 if (radio->removed)
381 return -EIO;
382
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300383 radio->curfreq = f->frequency;
384 if (amradio_setfreq(radio, radio->curfreq) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300385 amradio_dev_warn(&radio->videodev->dev,
386 "set frequency failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300387 return 0;
388}
389
390/* vidioc_g_frequency - get tuner radio frequency */
391static int vidioc_g_frequency(struct file *file, void *priv,
392 struct v4l2_frequency *f)
393{
394 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
395
Alexey Klimov34801302008-11-19 00:36:29 -0300396 /* safety check */
397 if (radio->removed)
398 return -EIO;
399
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300400 f->type = V4L2_TUNER_RADIO;
401 f->frequency = radio->curfreq;
402 return 0;
403}
404
405/* vidioc_queryctrl - enumerate control items */
406static int vidioc_queryctrl(struct file *file, void *priv,
407 struct v4l2_queryctrl *qc)
408{
409 int i;
410
411 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
412 if (qc->id && qc->id == radio_qctrl[i].id) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300413 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300414 return 0;
415 }
416 }
417 return -EINVAL;
418}
419
420/* vidioc_g_ctrl - get the value of a control */
421static int vidioc_g_ctrl(struct file *file, void *priv,
422 struct v4l2_control *ctrl)
423{
424 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
425
Alexey Klimov34801302008-11-19 00:36:29 -0300426 /* safety check */
427 if (radio->removed)
428 return -EIO;
429
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300430 switch (ctrl->id) {
431 case V4L2_CID_AUDIO_MUTE:
432 ctrl->value = radio->muted;
433 return 0;
434 }
435 return -EINVAL;
436}
437
438/* vidioc_s_ctrl - set the value of a control */
439static int vidioc_s_ctrl(struct file *file, void *priv,
440 struct v4l2_control *ctrl)
441{
442 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
443
Alexey Klimov34801302008-11-19 00:36:29 -0300444 /* safety check */
445 if (radio->removed)
446 return -EIO;
447
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300448 switch (ctrl->id) {
449 case V4L2_CID_AUDIO_MUTE:
450 if (ctrl->value) {
451 if (amradio_stop(radio) < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300452 amradio_dev_warn(&radio->videodev->dev,
453 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300454 return -1;
455 }
456 } else {
457 if (amradio_start(radio) < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300458 amradio_dev_warn(&radio->videodev->dev,
459 "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300460 return -1;
461 }
462 }
463 return 0;
464 }
465 return -EINVAL;
466}
467
468/* vidioc_g_audio - get audio attributes */
469static int vidioc_g_audio(struct file *file, void *priv,
470 struct v4l2_audio *a)
471{
472 if (a->index > 1)
473 return -EINVAL;
474
475 strcpy(a->name, "Radio");
476 a->capability = V4L2_AUDCAP_STEREO;
477 return 0;
478}
479
480/* vidioc_s_audio - set audio attributes */
481static int vidioc_s_audio(struct file *file, void *priv,
482 struct v4l2_audio *a)
483{
484 if (a->index != 0)
485 return -EINVAL;
486 return 0;
487}
488
489/* vidioc_g_input - get input */
490static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
491{
492 *i = 0;
493 return 0;
494}
495
496/* vidioc_s_input - set input */
497static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
498{
499 if (i != 0)
500 return -EINVAL;
501 return 0;
502}
503
504/* open device - amradio_start() and amradio_setfreq() */
Hans Verkuilbec43662008-12-30 06:58:20 -0300505static int usb_amradio_open(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300506{
507 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
508
Alexey Klimov0fabb782008-10-19 23:56:23 -0300509 lock_kernel();
510
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300511 radio->users = 1;
512 radio->muted = 1;
513
514 if (amradio_start(radio) < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300515 amradio_dev_warn(&radio->videodev->dev,
516 "radio did not start up properly\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300517 radio->users = 0;
Alexey Klimov0fabb782008-10-19 23:56:23 -0300518 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300519 return -EIO;
520 }
521 if (amradio_setfreq(radio, radio->curfreq) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300522 amradio_dev_warn(&radio->videodev->dev,
523 "set frequency failed\n");
Alexey Klimov0fabb782008-10-19 23:56:23 -0300524
525 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300526 return 0;
527}
528
Alexey Klimovf4e90432008-12-27 21:30:34 -0300529/*close device */
Hans Verkuilbec43662008-12-30 06:58:20 -0300530static int usb_amradio_close(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300531{
532 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov34801302008-11-19 00:36:29 -0300533 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300534
535 if (!radio)
536 return -ENODEV;
Alexey Klimov34801302008-11-19 00:36:29 -0300537
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300538 radio->users = 0;
Alexey Klimov34801302008-11-19 00:36:29 -0300539
Alexey Klimovf4e90432008-12-27 21:30:34 -0300540 if (!radio->removed) {
Alexey Klimov34801302008-11-19 00:36:29 -0300541 retval = amradio_stop(radio);
542 if (retval < 0)
543 amradio_dev_warn(&radio->videodev->dev,
544 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300545 }
Alexey Klimov34801302008-11-19 00:36:29 -0300546
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300547 return 0;
548}
549
550/* Suspend device - stop device. Need to be checked and fixed */
551static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
552{
553 struct amradio_device *radio = usb_get_intfdata(intf);
554
555 if (amradio_stop(radio) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300556 dev_warn(&intf->dev, "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300557
Alexey Klimove60b0222008-11-04 15:02:36 -0300558 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300559
560 return 0;
561}
562
563/* Resume device - start device. Need to be checked and fixed */
564static int usb_amradio_resume(struct usb_interface *intf)
565{
566 struct amradio_device *radio = usb_get_intfdata(intf);
567
568 if (amradio_start(radio) < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300569 dev_warn(&intf->dev, "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300570
Alexey Klimove60b0222008-11-04 15:02:36 -0300571 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300572
573 return 0;
574}
575
576/* File system interface */
Hans Verkuilbec43662008-12-30 06:58:20 -0300577static const struct v4l2_file_operations usb_amradio_fops = {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300578 .owner = THIS_MODULE,
579 .open = usb_amradio_open,
580 .release = usb_amradio_close,
581 .ioctl = video_ioctl2,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300582};
583
584static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
585 .vidioc_querycap = vidioc_querycap,
586 .vidioc_g_tuner = vidioc_g_tuner,
587 .vidioc_s_tuner = vidioc_s_tuner,
588 .vidioc_g_frequency = vidioc_g_frequency,
589 .vidioc_s_frequency = vidioc_s_frequency,
590 .vidioc_queryctrl = vidioc_queryctrl,
591 .vidioc_g_ctrl = vidioc_g_ctrl,
592 .vidioc_s_ctrl = vidioc_s_ctrl,
593 .vidioc_g_audio = vidioc_g_audio,
594 .vidioc_s_audio = vidioc_s_audio,
595 .vidioc_g_input = vidioc_g_input,
596 .vidioc_s_input = vidioc_s_input,
597};
598
Alexey Klimovf4e90432008-12-27 21:30:34 -0300599static void usb_amradio_device_release(struct video_device *videodev)
600{
601 struct amradio_device *radio = video_get_drvdata(videodev);
602
603 /* we call v4l to free radio->videodev */
604 video_device_release(videodev);
605
606 /* free rest memory */
607 kfree(radio->buffer);
608 kfree(radio);
609}
610
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300611/* V4L2 interface */
612static struct video_device amradio_videodev_template = {
613 .name = "AverMedia MR 800 USB FM Radio",
614 .fops = &usb_amradio_fops,
615 .ioctl_ops = &usb_amradio_ioctl_ops,
Alexey Klimovf4e90432008-12-27 21:30:34 -0300616 .release = usb_amradio_device_release,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300617};
618
619/* check if the device is present and register with v4l and
620usb if it is */
621static int usb_amradio_probe(struct usb_interface *intf,
622 const struct usb_device_id *id)
623{
624 struct amradio_device *radio;
625
626 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
627
628 if (!(radio))
629 return -ENOMEM;
630
631 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
632
633 if (!(radio->buffer)) {
634 kfree(radio);
635 return -ENOMEM;
636 }
637
638 radio->videodev = video_device_alloc();
639
640 if (!(radio->videodev)) {
641 kfree(radio->buffer);
642 kfree(radio);
643 return -ENOMEM;
644 }
645
646 memcpy(radio->videodev, &amradio_videodev_template,
647 sizeof(amradio_videodev_template));
648
649 radio->removed = 0;
650 radio->users = 0;
651 radio->usbdev = interface_to_usbdev(intf);
652 radio->curfreq = 95.16 * FREQ_MUL;
653
654 mutex_init(&radio->lock);
655
656 video_set_drvdata(radio->videodev, radio);
657 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300658 dev_warn(&intf->dev, "could not register video device\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300659 video_device_release(radio->videodev);
660 kfree(radio->buffer);
661 kfree(radio);
662 return -EIO;
663 }
664
665 usb_set_intfdata(intf, radio);
666 return 0;
667}
668
669static int __init amradio_init(void)
670{
671 int retval = usb_register(&usb_amradio_driver);
672
Alexey Klimove60b0222008-11-04 15:02:36 -0300673 pr_info(KBUILD_MODNAME
674 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
675
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300676 if (retval)
Alexey Klimove60b0222008-11-04 15:02:36 -0300677 pr_err(KBUILD_MODNAME
678 ": usb_register failed. Error number %d\n", retval);
679
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300680 return retval;
681}
682
683static void __exit amradio_exit(void)
684{
685 usb_deregister(&usb_amradio_driver);
686}
687
688module_init(amradio_init);
689module_exit(amradio_exit);
690