blob: ebc9d9979c719e6c63bdbd953c11cf3437685c58 [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
Alexey Klimovdb821802009-02-05 08:53:02 -030090/*
91 * Commands that device should understand
92 * List isnt full and will be updated with implementation of new functions
93 */
94#define AMRADIO_SET_MUTE 0xab
95
96/* Comfortable defines for amradio_set_mute */
97#define AMRADIO_START 0x00
98#define AMRADIO_STOP 0x01
99
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300100/* module parameter */
101static int radio_nr = -1;
102module_param(radio_nr, int, 0);
103MODULE_PARM_DESC(radio_nr, "Radio Nr");
104
105static struct v4l2_queryctrl radio_qctrl[] = {
106 {
107 .id = V4L2_CID_AUDIO_MUTE,
108 .name = "Mute",
109 .minimum = 0,
110 .maximum = 1,
111 .step = 1,
112 .default_value = 1,
113 .type = V4L2_CTRL_TYPE_BOOLEAN,
114 },
115/* HINT: the disabled controls are only here to satify kradio and such apps */
116 { .id = V4L2_CID_AUDIO_VOLUME,
117 .flags = V4L2_CTRL_FLAG_DISABLED,
118 },
119 {
120 .id = V4L2_CID_AUDIO_BALANCE,
121 .flags = V4L2_CTRL_FLAG_DISABLED,
122 },
123 {
124 .id = V4L2_CID_AUDIO_BASS,
125 .flags = V4L2_CTRL_FLAG_DISABLED,
126 },
127 {
128 .id = V4L2_CID_AUDIO_TREBLE,
129 .flags = V4L2_CTRL_FLAG_DISABLED,
130 },
131 {
132 .id = V4L2_CID_AUDIO_LOUDNESS,
133 .flags = V4L2_CTRL_FLAG_DISABLED,
134 },
135};
136
137static int usb_amradio_probe(struct usb_interface *intf,
138 const struct usb_device_id *id);
139static void usb_amradio_disconnect(struct usb_interface *intf);
Hans Verkuilbec43662008-12-30 06:58:20 -0300140static int usb_amradio_open(struct file *file);
141static int usb_amradio_close(struct file *file);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300142static int usb_amradio_suspend(struct usb_interface *intf,
143 pm_message_t message);
144static int usb_amradio_resume(struct usb_interface *intf);
145
146/* Data for one (physical) device */
147struct amradio_device {
148 /* reference to USB and video device */
149 struct usb_device *usbdev;
150 struct video_device *videodev;
151
152 unsigned char *buffer;
153 struct mutex lock; /* buffer locking */
154 int curfreq;
155 int stereo;
156 int users;
157 int removed;
158 int muted;
159};
160
161/* USB Device ID List */
162static struct usb_device_id usb_amradio_device_table[] = {
163 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
164 USB_CLASS_HID, 0, 0) },
165 { } /* Terminating entry */
166};
167
168MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
169
170/* USB subsystem interface */
171static struct usb_driver usb_amradio_driver = {
Alexey Klimove60b0222008-11-04 15:02:36 -0300172 .name = MR800_DRIVER_NAME,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300173 .probe = usb_amradio_probe,
174 .disconnect = usb_amradio_disconnect,
175 .suspend = usb_amradio_suspend,
176 .resume = usb_amradio_resume,
177 .reset_resume = usb_amradio_resume,
178 .id_table = usb_amradio_device_table,
Alexey Klimovf2ce9172008-12-27 21:31:49 -0300179 .supports_autosuspend = 0,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300180};
181
Alexey Klimovdb821802009-02-05 08:53:02 -0300182/* switch on/off the radio. Send 8 bytes to device */
183static int amradio_set_mute(struct amradio_device *radio, char argument)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300184{
185 int retval;
186 int size;
187
Alexey Klimov34801302008-11-19 00:36:29 -0300188 /* safety check */
189 if (radio->removed)
190 return -EIO;
191
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300192 mutex_lock(&radio->lock);
193
194 radio->buffer[0] = 0x00;
195 radio->buffer[1] = 0x55;
196 radio->buffer[2] = 0xaa;
197 radio->buffer[3] = 0x00;
Alexey Klimovdb821802009-02-05 08:53:02 -0300198 radio->buffer[4] = AMRADIO_SET_MUTE;
199 radio->buffer[5] = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300200 radio->buffer[6] = 0x00;
201 radio->buffer[7] = 0x00;
202
203 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
204 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
205
206 if (retval) {
207 mutex_unlock(&radio->lock);
208 return retval;
209 }
210
Alexey Klimovdb821802009-02-05 08:53:02 -0300211 radio->muted = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300212
Alexey Klimov7f03a582009-01-25 20:07:28 -0300213 mutex_unlock(&radio->lock);
214
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300215 return retval;
216}
217
218/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
219static int amradio_setfreq(struct amradio_device *radio, int freq)
220{
221 int retval;
222 int size;
223 unsigned short freq_send = 0x13 + (freq >> 3) / 25;
224
Alexey Klimov34801302008-11-19 00:36:29 -0300225 /* safety check */
226 if (radio->removed)
227 return -EIO;
228
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300229 mutex_lock(&radio->lock);
230
231 radio->buffer[0] = 0x00;
232 radio->buffer[1] = 0x55;
233 radio->buffer[2] = 0xaa;
234 radio->buffer[3] = 0x03;
235 radio->buffer[4] = 0xa4;
236 radio->buffer[5] = 0x00;
237 radio->buffer[6] = 0x00;
238 radio->buffer[7] = 0x08;
239
240 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
241 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
242
243 if (retval) {
244 mutex_unlock(&radio->lock);
245 return retval;
246 }
247
248 /* frequency is calculated from freq_send and placed in first 2 bytes */
249 radio->buffer[0] = (freq_send >> 8) & 0xff;
250 radio->buffer[1] = freq_send & 0xff;
251 radio->buffer[2] = 0x01;
252 radio->buffer[3] = 0x00;
253 radio->buffer[4] = 0x00;
254 /* 5 and 6 bytes of buffer already = 0x00 */
255 radio->buffer[7] = 0x00;
256
257 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
258 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
259
260 if (retval) {
261 mutex_unlock(&radio->lock);
262 return retval;
263 }
264
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300265 radio->stereo = 0;
266
Alexey Klimov7f03a582009-01-25 20:07:28 -0300267 mutex_unlock(&radio->lock);
268
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300269 return retval;
270}
271
272/* USB subsystem interface begins here */
273
274/* handle unplugging of the device, release data structures
275if nothing keeps us from doing it. If something is still
276keeping us busy, the release callback of v4l will take care
277of releasing it. */
278static void usb_amradio_disconnect(struct usb_interface *intf)
279{
280 struct amradio_device *radio = usb_get_intfdata(intf);
281
Alexey Klimovf4e90432008-12-27 21:30:34 -0300282 mutex_lock(&radio->lock);
Alexey Klimov34801302008-11-19 00:36:29 -0300283 radio->removed = 1;
Alexey Klimovf4e90432008-12-27 21:30:34 -0300284 mutex_unlock(&radio->lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300285
Alexey Klimovf4e90432008-12-27 21:30:34 -0300286 usb_set_intfdata(intf, NULL);
287 video_unregister_device(radio->videodev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300288}
289
290/* vidioc_querycap - query device capabilities */
291static int vidioc_querycap(struct file *file, void *priv,
292 struct v4l2_capability *v)
293{
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300294 struct amradio_device *radio = video_drvdata(file);
295
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300296 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
297 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300298 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300299 v->version = RADIO_VERSION;
300 v->capabilities = V4L2_CAP_TUNER;
301 return 0;
302}
303
304/* vidioc_g_tuner - get tuner attributes */
305static int vidioc_g_tuner(struct file *file, void *priv,
306 struct v4l2_tuner *v)
307{
308 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
309
Alexey Klimov34801302008-11-19 00:36:29 -0300310 /* safety check */
311 if (radio->removed)
312 return -EIO;
313
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300314 if (v->index > 0)
315 return -EINVAL;
316
317/* TODO: Add function which look is signal stereo or not
318 * amradio_getstat(radio);
319 */
320 radio->stereo = -1;
321 strcpy(v->name, "FM");
322 v->type = V4L2_TUNER_RADIO;
323 v->rangelow = FREQ_MIN * FREQ_MUL;
324 v->rangehigh = FREQ_MAX * FREQ_MUL;
325 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
326 v->capability = V4L2_TUNER_CAP_LOW;
327 if (radio->stereo)
328 v->audmode = V4L2_TUNER_MODE_STEREO;
329 else
330 v->audmode = V4L2_TUNER_MODE_MONO;
331 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
332 v->afc = 0; /* Don't know what is this */
333 return 0;
334}
335
336/* vidioc_s_tuner - set tuner attributes */
337static int vidioc_s_tuner(struct file *file, void *priv,
338 struct v4l2_tuner *v)
339{
Alexey Klimov34801302008-11-19 00:36:29 -0300340 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
341
342 /* safety check */
343 if (radio->removed)
344 return -EIO;
345
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300346 if (v->index > 0)
347 return -EINVAL;
348 return 0;
349}
350
351/* vidioc_s_frequency - set tuner radio frequency */
352static int vidioc_s_frequency(struct file *file, void *priv,
353 struct v4l2_frequency *f)
354{
355 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300356 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300357
Alexey Klimov34801302008-11-19 00:36:29 -0300358 /* safety check */
359 if (radio->removed)
360 return -EIO;
361
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300362 radio->curfreq = f->frequency;
Alexey Klimova5d69472009-02-05 08:48:43 -0300363 retval = amradio_setfreq(radio, radio->curfreq);
364 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300365 amradio_dev_warn(&radio->videodev->dev,
366 "set frequency failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300367 return 0;
368}
369
370/* vidioc_g_frequency - get tuner radio frequency */
371static int vidioc_g_frequency(struct file *file, void *priv,
372 struct v4l2_frequency *f)
373{
374 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
375
Alexey Klimov34801302008-11-19 00:36:29 -0300376 /* safety check */
377 if (radio->removed)
378 return -EIO;
379
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300380 f->type = V4L2_TUNER_RADIO;
381 f->frequency = radio->curfreq;
382 return 0;
383}
384
385/* vidioc_queryctrl - enumerate control items */
386static int vidioc_queryctrl(struct file *file, void *priv,
387 struct v4l2_queryctrl *qc)
388{
389 int i;
390
391 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
392 if (qc->id && qc->id == radio_qctrl[i].id) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300393 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300394 return 0;
395 }
396 }
397 return -EINVAL;
398}
399
400/* vidioc_g_ctrl - get the value of a control */
401static int vidioc_g_ctrl(struct file *file, void *priv,
402 struct v4l2_control *ctrl)
403{
404 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
405
Alexey Klimov34801302008-11-19 00:36:29 -0300406 /* safety check */
407 if (radio->removed)
408 return -EIO;
409
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300410 switch (ctrl->id) {
411 case V4L2_CID_AUDIO_MUTE:
412 ctrl->value = radio->muted;
413 return 0;
414 }
415 return -EINVAL;
416}
417
418/* vidioc_s_ctrl - set the value of a control */
419static int vidioc_s_ctrl(struct file *file, void *priv,
420 struct v4l2_control *ctrl)
421{
422 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300423 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300424
Alexey Klimov34801302008-11-19 00:36:29 -0300425 /* safety check */
426 if (radio->removed)
427 return -EIO;
428
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300429 switch (ctrl->id) {
430 case V4L2_CID_AUDIO_MUTE:
431 if (ctrl->value) {
Alexey Klimovdb821802009-02-05 08:53:02 -0300432 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimova5d69472009-02-05 08:48:43 -0300433 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300434 amradio_dev_warn(&radio->videodev->dev,
435 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300436 return -1;
437 }
438 } else {
Alexey Klimovdb821802009-02-05 08:53:02 -0300439 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300440 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300441 amradio_dev_warn(&radio->videodev->dev,
442 "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300443 return -1;
444 }
445 }
446 return 0;
447 }
448 return -EINVAL;
449}
450
451/* vidioc_g_audio - get audio attributes */
452static int vidioc_g_audio(struct file *file, void *priv,
453 struct v4l2_audio *a)
454{
455 if (a->index > 1)
456 return -EINVAL;
457
458 strcpy(a->name, "Radio");
459 a->capability = V4L2_AUDCAP_STEREO;
460 return 0;
461}
462
463/* vidioc_s_audio - set audio attributes */
464static int vidioc_s_audio(struct file *file, void *priv,
465 struct v4l2_audio *a)
466{
467 if (a->index != 0)
468 return -EINVAL;
469 return 0;
470}
471
472/* vidioc_g_input - get input */
473static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
474{
475 *i = 0;
476 return 0;
477}
478
479/* vidioc_s_input - set input */
480static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
481{
482 if (i != 0)
483 return -EINVAL;
484 return 0;
485}
486
487/* open device - amradio_start() and amradio_setfreq() */
Hans Verkuilbec43662008-12-30 06:58:20 -0300488static int usb_amradio_open(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300489{
490 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300491 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300492
Alexey Klimov0fabb782008-10-19 23:56:23 -0300493 lock_kernel();
494
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300495 radio->users = 1;
496 radio->muted = 1;
497
Alexey Klimovdb821802009-02-05 08:53:02 -0300498 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300499 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300500 amradio_dev_warn(&radio->videodev->dev,
501 "radio did not start up properly\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300502 radio->users = 0;
Alexey Klimov0fabb782008-10-19 23:56:23 -0300503 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300504 return -EIO;
505 }
Alexey Klimova5d69472009-02-05 08:48:43 -0300506
507 retval = amradio_setfreq(radio, radio->curfreq);
508 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300509 amradio_dev_warn(&radio->videodev->dev,
510 "set frequency failed\n");
Alexey Klimov0fabb782008-10-19 23:56:23 -0300511
512 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300513 return 0;
514}
515
Alexey Klimovf4e90432008-12-27 21:30:34 -0300516/*close device */
Hans Verkuilbec43662008-12-30 06:58:20 -0300517static int usb_amradio_close(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300518{
519 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov34801302008-11-19 00:36:29 -0300520 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300521
522 if (!radio)
523 return -ENODEV;
Alexey Klimov34801302008-11-19 00:36:29 -0300524
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300525 radio->users = 0;
Alexey Klimov34801302008-11-19 00:36:29 -0300526
Alexey Klimovf4e90432008-12-27 21:30:34 -0300527 if (!radio->removed) {
Alexey Klimovdb821802009-02-05 08:53:02 -0300528 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimov34801302008-11-19 00:36:29 -0300529 if (retval < 0)
530 amradio_dev_warn(&radio->videodev->dev,
531 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300532 }
Alexey Klimov34801302008-11-19 00:36:29 -0300533
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300534 return 0;
535}
536
537/* Suspend device - stop device. Need to be checked and fixed */
538static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
539{
540 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300541 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300542
Alexey Klimovdb821802009-02-05 08:53:02 -0300543 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimova5d69472009-02-05 08:48:43 -0300544 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300545 dev_warn(&intf->dev, "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300546
Alexey Klimove60b0222008-11-04 15:02:36 -0300547 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300548
549 return 0;
550}
551
552/* Resume device - start device. Need to be checked and fixed */
553static int usb_amradio_resume(struct usb_interface *intf)
554{
555 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300556 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300557
Alexey Klimovdb821802009-02-05 08:53:02 -0300558 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300559 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300560 dev_warn(&intf->dev, "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300561
Alexey Klimove60b0222008-11-04 15:02:36 -0300562 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300563
564 return 0;
565}
566
567/* File system interface */
Hans Verkuilbec43662008-12-30 06:58:20 -0300568static const struct v4l2_file_operations usb_amradio_fops = {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300569 .owner = THIS_MODULE,
570 .open = usb_amradio_open,
571 .release = usb_amradio_close,
572 .ioctl = video_ioctl2,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300573};
574
575static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
576 .vidioc_querycap = vidioc_querycap,
577 .vidioc_g_tuner = vidioc_g_tuner,
578 .vidioc_s_tuner = vidioc_s_tuner,
579 .vidioc_g_frequency = vidioc_g_frequency,
580 .vidioc_s_frequency = vidioc_s_frequency,
581 .vidioc_queryctrl = vidioc_queryctrl,
582 .vidioc_g_ctrl = vidioc_g_ctrl,
583 .vidioc_s_ctrl = vidioc_s_ctrl,
584 .vidioc_g_audio = vidioc_g_audio,
585 .vidioc_s_audio = vidioc_s_audio,
586 .vidioc_g_input = vidioc_g_input,
587 .vidioc_s_input = vidioc_s_input,
588};
589
Alexey Klimovf4e90432008-12-27 21:30:34 -0300590static void usb_amradio_device_release(struct video_device *videodev)
591{
592 struct amradio_device *radio = video_get_drvdata(videodev);
593
594 /* we call v4l to free radio->videodev */
595 video_device_release(videodev);
596
597 /* free rest memory */
598 kfree(radio->buffer);
599 kfree(radio);
600}
601
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300602/* V4L2 interface */
603static struct video_device amradio_videodev_template = {
604 .name = "AverMedia MR 800 USB FM Radio",
605 .fops = &usb_amradio_fops,
606 .ioctl_ops = &usb_amradio_ioctl_ops,
Alexey Klimovf4e90432008-12-27 21:30:34 -0300607 .release = usb_amradio_device_release,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300608};
609
Alexey Klimova5d69472009-02-05 08:48:43 -0300610/* check if the device is present and register with v4l and usb if it is */
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300611static int usb_amradio_probe(struct usb_interface *intf,
612 const struct usb_device_id *id)
613{
614 struct amradio_device *radio;
Alexey Klimova5d69472009-02-05 08:48:43 -0300615 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300616
617 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
618
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300619 if (!radio) {
620 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300621 return -ENOMEM;
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300622 }
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300623
624 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
625
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300626 if (!radio->buffer) {
627 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300628 kfree(radio);
629 return -ENOMEM;
630 }
631
632 radio->videodev = video_device_alloc();
633
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300634 if (!radio->videodev) {
635 dev_err(&intf->dev, "video_device_alloc failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300636 kfree(radio->buffer);
637 kfree(radio);
638 return -ENOMEM;
639 }
640
641 memcpy(radio->videodev, &amradio_videodev_template,
642 sizeof(amradio_videodev_template));
643
644 radio->removed = 0;
645 radio->users = 0;
646 radio->usbdev = interface_to_usbdev(intf);
647 radio->curfreq = 95.16 * FREQ_MUL;
648
649 mutex_init(&radio->lock);
650
651 video_set_drvdata(radio->videodev, radio);
Alexey Klimova5d69472009-02-05 08:48:43 -0300652 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
653 if (retval < 0) {
Alexey Klimov65c51dc2009-02-05 08:49:58 -0300654 dev_err(&intf->dev, "could not register video device\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300655 video_device_release(radio->videodev);
656 kfree(radio->buffer);
657 kfree(radio);
658 return -EIO;
659 }
660
661 usb_set_intfdata(intf, radio);
662 return 0;
663}
664
665static int __init amradio_init(void)
666{
667 int retval = usb_register(&usb_amradio_driver);
668
Alexey Klimove60b0222008-11-04 15:02:36 -0300669 pr_info(KBUILD_MODNAME
670 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
671
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300672 if (retval)
Alexey Klimove60b0222008-11-04 15:02:36 -0300673 pr_err(KBUILD_MODNAME
674 ": usb_register failed. Error number %d\n", retval);
675
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300676 return retval;
677}
678
679static void __exit amradio_exit(void)
680{
681 usb_deregister(&usb_amradio_driver);
682}
683
684module_init(amradio_init);
685module_exit(amradio_exit);
686