blob: ef909a583e9e4f7650ffd3653678c3e8e652b48c [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));
Alexey Klimova5d69472009-02-05 08:48:43 -0300378 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300379
Alexey Klimov34801302008-11-19 00:36:29 -0300380 /* safety check */
381 if (radio->removed)
382 return -EIO;
383
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300384 radio->curfreq = f->frequency;
Alexey Klimova5d69472009-02-05 08:48:43 -0300385 retval = amradio_setfreq(radio, radio->curfreq);
386 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300387 amradio_dev_warn(&radio->videodev->dev,
388 "set frequency failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300389 return 0;
390}
391
392/* vidioc_g_frequency - get tuner radio frequency */
393static int vidioc_g_frequency(struct file *file, void *priv,
394 struct v4l2_frequency *f)
395{
396 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
397
Alexey Klimov34801302008-11-19 00:36:29 -0300398 /* safety check */
399 if (radio->removed)
400 return -EIO;
401
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300402 f->type = V4L2_TUNER_RADIO;
403 f->frequency = radio->curfreq;
404 return 0;
405}
406
407/* vidioc_queryctrl - enumerate control items */
408static int vidioc_queryctrl(struct file *file, void *priv,
409 struct v4l2_queryctrl *qc)
410{
411 int i;
412
413 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
414 if (qc->id && qc->id == radio_qctrl[i].id) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300415 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300416 return 0;
417 }
418 }
419 return -EINVAL;
420}
421
422/* vidioc_g_ctrl - get the value of a control */
423static int vidioc_g_ctrl(struct file *file, void *priv,
424 struct v4l2_control *ctrl)
425{
426 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
427
Alexey Klimov34801302008-11-19 00:36:29 -0300428 /* safety check */
429 if (radio->removed)
430 return -EIO;
431
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300432 switch (ctrl->id) {
433 case V4L2_CID_AUDIO_MUTE:
434 ctrl->value = radio->muted;
435 return 0;
436 }
437 return -EINVAL;
438}
439
440/* vidioc_s_ctrl - set the value of a control */
441static int vidioc_s_ctrl(struct file *file, void *priv,
442 struct v4l2_control *ctrl)
443{
444 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300445 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300446
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) {
Alexey Klimova5d69472009-02-05 08:48:43 -0300454 retval = amradio_stop(radio);
455 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300456 amradio_dev_warn(&radio->videodev->dev,
457 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300458 return -1;
459 }
460 } else {
Alexey Klimova5d69472009-02-05 08:48:43 -0300461 retval = amradio_start(radio);
462 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300463 amradio_dev_warn(&radio->videodev->dev,
464 "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300465 return -1;
466 }
467 }
468 return 0;
469 }
470 return -EINVAL;
471}
472
473/* vidioc_g_audio - get audio attributes */
474static int vidioc_g_audio(struct file *file, void *priv,
475 struct v4l2_audio *a)
476{
477 if (a->index > 1)
478 return -EINVAL;
479
480 strcpy(a->name, "Radio");
481 a->capability = V4L2_AUDCAP_STEREO;
482 return 0;
483}
484
485/* vidioc_s_audio - set audio attributes */
486static int vidioc_s_audio(struct file *file, void *priv,
487 struct v4l2_audio *a)
488{
489 if (a->index != 0)
490 return -EINVAL;
491 return 0;
492}
493
494/* vidioc_g_input - get input */
495static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
496{
497 *i = 0;
498 return 0;
499}
500
501/* vidioc_s_input - set input */
502static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
503{
504 if (i != 0)
505 return -EINVAL;
506 return 0;
507}
508
509/* open device - amradio_start() and amradio_setfreq() */
Hans Verkuilbec43662008-12-30 06:58:20 -0300510static int usb_amradio_open(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300511{
512 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300513 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300514
Alexey Klimov0fabb782008-10-19 23:56:23 -0300515 lock_kernel();
516
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300517 radio->users = 1;
518 radio->muted = 1;
519
Alexey Klimova5d69472009-02-05 08:48:43 -0300520 retval = amradio_start(radio);
521 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300522 amradio_dev_warn(&radio->videodev->dev,
523 "radio did not start up properly\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300524 radio->users = 0;
Alexey Klimov0fabb782008-10-19 23:56:23 -0300525 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300526 return -EIO;
527 }
Alexey Klimova5d69472009-02-05 08:48:43 -0300528
529 retval = amradio_setfreq(radio, radio->curfreq);
530 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300531 amradio_dev_warn(&radio->videodev->dev,
532 "set frequency failed\n");
Alexey Klimov0fabb782008-10-19 23:56:23 -0300533
534 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300535 return 0;
536}
537
Alexey Klimovf4e90432008-12-27 21:30:34 -0300538/*close device */
Hans Verkuilbec43662008-12-30 06:58:20 -0300539static int usb_amradio_close(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300540{
541 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov34801302008-11-19 00:36:29 -0300542 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300543
544 if (!radio)
545 return -ENODEV;
Alexey Klimov34801302008-11-19 00:36:29 -0300546
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300547 radio->users = 0;
Alexey Klimov34801302008-11-19 00:36:29 -0300548
Alexey Klimovf4e90432008-12-27 21:30:34 -0300549 if (!radio->removed) {
Alexey Klimov34801302008-11-19 00:36:29 -0300550 retval = amradio_stop(radio);
551 if (retval < 0)
552 amradio_dev_warn(&radio->videodev->dev,
553 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300554 }
Alexey Klimov34801302008-11-19 00:36:29 -0300555
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);
Alexey Klimova5d69472009-02-05 08:48:43 -0300563 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300564
Alexey Klimova5d69472009-02-05 08:48:43 -0300565 retval = amradio_stop(radio);
566 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300567 dev_warn(&intf->dev, "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300568
Alexey Klimove60b0222008-11-04 15:02:36 -0300569 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300570
571 return 0;
572}
573
574/* Resume device - start device. Need to be checked and fixed */
575static int usb_amradio_resume(struct usb_interface *intf)
576{
577 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300578 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300579
Alexey Klimova5d69472009-02-05 08:48:43 -0300580 retval = amradio_start(radio);
581 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300582 dev_warn(&intf->dev, "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300583
Alexey Klimove60b0222008-11-04 15:02:36 -0300584 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300585
586 return 0;
587}
588
589/* File system interface */
Hans Verkuilbec43662008-12-30 06:58:20 -0300590static const struct v4l2_file_operations usb_amradio_fops = {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300591 .owner = THIS_MODULE,
592 .open = usb_amradio_open,
593 .release = usb_amradio_close,
594 .ioctl = video_ioctl2,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300595};
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
Alexey Klimovf4e90432008-12-27 21:30:34 -0300612static void usb_amradio_device_release(struct video_device *videodev)
613{
614 struct amradio_device *radio = video_get_drvdata(videodev);
615
616 /* we call v4l to free radio->videodev */
617 video_device_release(videodev);
618
619 /* free rest memory */
620 kfree(radio->buffer);
621 kfree(radio);
622}
623
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300624/* V4L2 interface */
625static struct video_device amradio_videodev_template = {
626 .name = "AverMedia MR 800 USB FM Radio",
627 .fops = &usb_amradio_fops,
628 .ioctl_ops = &usb_amradio_ioctl_ops,
Alexey Klimovf4e90432008-12-27 21:30:34 -0300629 .release = usb_amradio_device_release,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300630};
631
Alexey Klimova5d69472009-02-05 08:48:43 -0300632/* check if the device is present and register with v4l and usb if it is */
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300633static int usb_amradio_probe(struct usb_interface *intf,
634 const struct usb_device_id *id)
635{
636 struct amradio_device *radio;
Alexey Klimova5d69472009-02-05 08:48:43 -0300637 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300638
639 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
640
Alexey Klimova5d69472009-02-05 08:48:43 -0300641 if (!radio)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300642 return -ENOMEM;
643
644 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
645
646 if (!(radio->buffer)) {
647 kfree(radio);
648 return -ENOMEM;
649 }
650
651 radio->videodev = video_device_alloc();
652
653 if (!(radio->videodev)) {
654 kfree(radio->buffer);
655 kfree(radio);
656 return -ENOMEM;
657 }
658
659 memcpy(radio->videodev, &amradio_videodev_template,
660 sizeof(amradio_videodev_template));
661
662 radio->removed = 0;
663 radio->users = 0;
664 radio->usbdev = interface_to_usbdev(intf);
665 radio->curfreq = 95.16 * FREQ_MUL;
666
667 mutex_init(&radio->lock);
668
669 video_set_drvdata(radio->videodev, radio);
Alexey Klimova5d69472009-02-05 08:48:43 -0300670 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
671 if (retval < 0) {
Alexey Klimov65c51dc2009-02-05 08:49:58 -0300672 dev_err(&intf->dev, "could not register video device\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300673 video_device_release(radio->videodev);
674 kfree(radio->buffer);
675 kfree(radio);
676 return -EIO;
677 }
678
679 usb_set_intfdata(intf, radio);
680 return 0;
681}
682
683static int __init amradio_init(void)
684{
685 int retval = usb_register(&usb_amradio_driver);
686
Alexey Klimove60b0222008-11-04 15:02:36 -0300687 pr_info(KBUILD_MODNAME
688 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
689
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300690 if (retval)
Alexey Klimove60b0222008-11-04 15:02:36 -0300691 pr_err(KBUILD_MODNAME
692 ": usb_register failed. Error number %d\n", retval);
693
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300694 return retval;
695}
696
697static void __exit amradio_exit(void)
698{
699 usb_deregister(&usb_amradio_driver);
700}
701
702module_init(amradio_init);
703module_exit(amradio_exit);
704