blob: 0374c6ada43f32a40d1f7e65f5d277f5950ac900 [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 */
Alexey Klimovf7c1a382009-02-05 08:54:17 -030094#define AMRADIO_SET_FREQ 0xa4
Alexey Klimovdb821802009-02-05 08:53:02 -030095#define AMRADIO_SET_MUTE 0xab
96
97/* Comfortable defines for amradio_set_mute */
98#define AMRADIO_START 0x00
99#define AMRADIO_STOP 0x01
100
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300101/* module parameter */
102static int radio_nr = -1;
103module_param(radio_nr, int, 0);
104MODULE_PARM_DESC(radio_nr, "Radio Nr");
105
106static struct v4l2_queryctrl radio_qctrl[] = {
107 {
108 .id = V4L2_CID_AUDIO_MUTE,
109 .name = "Mute",
110 .minimum = 0,
111 .maximum = 1,
112 .step = 1,
113 .default_value = 1,
114 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 },
116/* HINT: the disabled controls are only here to satify kradio and such apps */
117 { .id = V4L2_CID_AUDIO_VOLUME,
118 .flags = V4L2_CTRL_FLAG_DISABLED,
119 },
120 {
121 .id = V4L2_CID_AUDIO_BALANCE,
122 .flags = V4L2_CTRL_FLAG_DISABLED,
123 },
124 {
125 .id = V4L2_CID_AUDIO_BASS,
126 .flags = V4L2_CTRL_FLAG_DISABLED,
127 },
128 {
129 .id = V4L2_CID_AUDIO_TREBLE,
130 .flags = V4L2_CTRL_FLAG_DISABLED,
131 },
132 {
133 .id = V4L2_CID_AUDIO_LOUDNESS,
134 .flags = V4L2_CTRL_FLAG_DISABLED,
135 },
136};
137
138static int usb_amradio_probe(struct usb_interface *intf,
139 const struct usb_device_id *id);
140static void usb_amradio_disconnect(struct usb_interface *intf);
Hans Verkuilbec43662008-12-30 06:58:20 -0300141static int usb_amradio_open(struct file *file);
142static int usb_amradio_close(struct file *file);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300143static int usb_amradio_suspend(struct usb_interface *intf,
144 pm_message_t message);
145static int usb_amradio_resume(struct usb_interface *intf);
146
147/* Data for one (physical) device */
148struct amradio_device {
149 /* reference to USB and video device */
150 struct usb_device *usbdev;
151 struct video_device *videodev;
152
153 unsigned char *buffer;
154 struct mutex lock; /* buffer locking */
155 int curfreq;
156 int stereo;
157 int users;
158 int removed;
159 int muted;
160};
161
162/* USB Device ID List */
163static struct usb_device_id usb_amradio_device_table[] = {
164 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
165 USB_CLASS_HID, 0, 0) },
166 { } /* Terminating entry */
167};
168
169MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
170
171/* USB subsystem interface */
172static struct usb_driver usb_amradio_driver = {
Alexey Klimove60b0222008-11-04 15:02:36 -0300173 .name = MR800_DRIVER_NAME,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300174 .probe = usb_amradio_probe,
175 .disconnect = usb_amradio_disconnect,
176 .suspend = usb_amradio_suspend,
177 .resume = usb_amradio_resume,
178 .reset_resume = usb_amradio_resume,
179 .id_table = usb_amradio_device_table,
Alexey Klimovf2ce9172008-12-27 21:31:49 -0300180 .supports_autosuspend = 0,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300181};
182
Alexey Klimovdb821802009-02-05 08:53:02 -0300183/* switch on/off the radio. Send 8 bytes to device */
184static int amradio_set_mute(struct amradio_device *radio, char argument)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300185{
186 int retval;
187 int size;
188
Alexey Klimov34801302008-11-19 00:36:29 -0300189 /* safety check */
190 if (radio->removed)
191 return -EIO;
192
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300193 mutex_lock(&radio->lock);
194
195 radio->buffer[0] = 0x00;
196 radio->buffer[1] = 0x55;
197 radio->buffer[2] = 0xaa;
198 radio->buffer[3] = 0x00;
Alexey Klimovdb821802009-02-05 08:53:02 -0300199 radio->buffer[4] = AMRADIO_SET_MUTE;
200 radio->buffer[5] = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300201 radio->buffer[6] = 0x00;
202 radio->buffer[7] = 0x00;
203
204 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
205 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
206
207 if (retval) {
208 mutex_unlock(&radio->lock);
209 return retval;
210 }
211
Alexey Klimovdb821802009-02-05 08:53:02 -0300212 radio->muted = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300213
Alexey Klimov7f03a582009-01-25 20:07:28 -0300214 mutex_unlock(&radio->lock);
215
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300216 return retval;
217}
218
219/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
220static int amradio_setfreq(struct amradio_device *radio, int freq)
221{
222 int retval;
223 int size;
Alexey Klimovf7c1a382009-02-05 08:54:17 -0300224 unsigned short freq_send = 0x10 + (freq >> 3) / 25;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300225
Alexey Klimov34801302008-11-19 00:36:29 -0300226 /* safety check */
227 if (radio->removed)
228 return -EIO;
229
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300230 mutex_lock(&radio->lock);
231
232 radio->buffer[0] = 0x00;
233 radio->buffer[1] = 0x55;
234 radio->buffer[2] = 0xaa;
235 radio->buffer[3] = 0x03;
Alexey Klimovf7c1a382009-02-05 08:54:17 -0300236 radio->buffer[4] = AMRADIO_SET_FREQ;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300237 radio->buffer[5] = 0x00;
238 radio->buffer[6] = 0x00;
239 radio->buffer[7] = 0x08;
240
241 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
242 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
243
244 if (retval) {
245 mutex_unlock(&radio->lock);
246 return retval;
247 }
248
249 /* frequency is calculated from freq_send and placed in first 2 bytes */
250 radio->buffer[0] = (freq_send >> 8) & 0xff;
251 radio->buffer[1] = freq_send & 0xff;
252 radio->buffer[2] = 0x01;
253 radio->buffer[3] = 0x00;
254 radio->buffer[4] = 0x00;
255 /* 5 and 6 bytes of buffer already = 0x00 */
256 radio->buffer[7] = 0x00;
257
258 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
259 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
260
261 if (retval) {
262 mutex_unlock(&radio->lock);
263 return retval;
264 }
265
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300266 radio->stereo = 0;
267
Alexey Klimov7f03a582009-01-25 20:07:28 -0300268 mutex_unlock(&radio->lock);
269
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300270 return retval;
271}
272
273/* USB subsystem interface begins here */
274
275/* handle unplugging of the device, release data structures
276if nothing keeps us from doing it. If something is still
277keeping us busy, the release callback of v4l will take care
278of releasing it. */
279static void usb_amradio_disconnect(struct usb_interface *intf)
280{
281 struct amradio_device *radio = usb_get_intfdata(intf);
282
Alexey Klimovf4e90432008-12-27 21:30:34 -0300283 mutex_lock(&radio->lock);
Alexey Klimov34801302008-11-19 00:36:29 -0300284 radio->removed = 1;
Alexey Klimovf4e90432008-12-27 21:30:34 -0300285 mutex_unlock(&radio->lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300286
Alexey Klimovf4e90432008-12-27 21:30:34 -0300287 usb_set_intfdata(intf, NULL);
288 video_unregister_device(radio->videodev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300289}
290
291/* vidioc_querycap - query device capabilities */
292static int vidioc_querycap(struct file *file, void *priv,
293 struct v4l2_capability *v)
294{
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300295 struct amradio_device *radio = video_drvdata(file);
296
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300297 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
298 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300299 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300300 v->version = RADIO_VERSION;
301 v->capabilities = V4L2_CAP_TUNER;
302 return 0;
303}
304
305/* vidioc_g_tuner - get tuner attributes */
306static int vidioc_g_tuner(struct file *file, void *priv,
307 struct v4l2_tuner *v)
308{
309 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
310
Alexey Klimov34801302008-11-19 00:36:29 -0300311 /* safety check */
312 if (radio->removed)
313 return -EIO;
314
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300315 if (v->index > 0)
316 return -EINVAL;
317
318/* TODO: Add function which look is signal stereo or not
319 * amradio_getstat(radio);
320 */
321 radio->stereo = -1;
322 strcpy(v->name, "FM");
323 v->type = V4L2_TUNER_RADIO;
324 v->rangelow = FREQ_MIN * FREQ_MUL;
325 v->rangehigh = FREQ_MAX * FREQ_MUL;
326 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
327 v->capability = V4L2_TUNER_CAP_LOW;
328 if (radio->stereo)
329 v->audmode = V4L2_TUNER_MODE_STEREO;
330 else
331 v->audmode = V4L2_TUNER_MODE_MONO;
332 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
333 v->afc = 0; /* Don't know what is this */
334 return 0;
335}
336
337/* vidioc_s_tuner - set tuner attributes */
338static int vidioc_s_tuner(struct file *file, void *priv,
339 struct v4l2_tuner *v)
340{
Alexey Klimov34801302008-11-19 00:36:29 -0300341 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
342
343 /* safety check */
344 if (radio->removed)
345 return -EIO;
346
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300347 if (v->index > 0)
348 return -EINVAL;
349 return 0;
350}
351
352/* vidioc_s_frequency - set tuner radio frequency */
353static int vidioc_s_frequency(struct file *file, void *priv,
354 struct v4l2_frequency *f)
355{
356 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300357 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300358
Alexey Klimov34801302008-11-19 00:36:29 -0300359 /* safety check */
360 if (radio->removed)
361 return -EIO;
362
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300363 radio->curfreq = f->frequency;
Alexey Klimova5d69472009-02-05 08:48:43 -0300364 retval = amradio_setfreq(radio, radio->curfreq);
365 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300366 amradio_dev_warn(&radio->videodev->dev,
367 "set frequency failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300368 return 0;
369}
370
371/* vidioc_g_frequency - get tuner radio frequency */
372static int vidioc_g_frequency(struct file *file, void *priv,
373 struct v4l2_frequency *f)
374{
375 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
376
Alexey Klimov34801302008-11-19 00:36:29 -0300377 /* safety check */
378 if (radio->removed)
379 return -EIO;
380
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300381 f->type = V4L2_TUNER_RADIO;
382 f->frequency = radio->curfreq;
383 return 0;
384}
385
386/* vidioc_queryctrl - enumerate control items */
387static int vidioc_queryctrl(struct file *file, void *priv,
388 struct v4l2_queryctrl *qc)
389{
390 int i;
391
392 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
393 if (qc->id && qc->id == radio_qctrl[i].id) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300394 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300395 return 0;
396 }
397 }
398 return -EINVAL;
399}
400
401/* vidioc_g_ctrl - get the value of a control */
402static int vidioc_g_ctrl(struct file *file, void *priv,
403 struct v4l2_control *ctrl)
404{
405 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
406
Alexey Klimov34801302008-11-19 00:36:29 -0300407 /* safety check */
408 if (radio->removed)
409 return -EIO;
410
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300411 switch (ctrl->id) {
412 case V4L2_CID_AUDIO_MUTE:
413 ctrl->value = radio->muted;
414 return 0;
415 }
416 return -EINVAL;
417}
418
419/* vidioc_s_ctrl - set the value of a control */
420static int vidioc_s_ctrl(struct file *file, void *priv,
421 struct v4l2_control *ctrl)
422{
423 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300424 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300425
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 if (ctrl->value) {
Alexey Klimovdb821802009-02-05 08:53:02 -0300433 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimova5d69472009-02-05 08:48:43 -0300434 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300435 amradio_dev_warn(&radio->videodev->dev,
436 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300437 return -1;
438 }
439 } else {
Alexey Klimovdb821802009-02-05 08:53:02 -0300440 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300441 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300442 amradio_dev_warn(&radio->videodev->dev,
443 "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300444 return -1;
445 }
446 }
447 return 0;
448 }
449 return -EINVAL;
450}
451
452/* vidioc_g_audio - get audio attributes */
453static int vidioc_g_audio(struct file *file, void *priv,
454 struct v4l2_audio *a)
455{
456 if (a->index > 1)
457 return -EINVAL;
458
459 strcpy(a->name, "Radio");
460 a->capability = V4L2_AUDCAP_STEREO;
461 return 0;
462}
463
464/* vidioc_s_audio - set audio attributes */
465static int vidioc_s_audio(struct file *file, void *priv,
466 struct v4l2_audio *a)
467{
468 if (a->index != 0)
469 return -EINVAL;
470 return 0;
471}
472
473/* vidioc_g_input - get input */
474static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
475{
476 *i = 0;
477 return 0;
478}
479
480/* vidioc_s_input - set input */
481static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
482{
483 if (i != 0)
484 return -EINVAL;
485 return 0;
486}
487
488/* open device - amradio_start() and amradio_setfreq() */
Hans Verkuilbec43662008-12-30 06:58:20 -0300489static int usb_amradio_open(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300490{
491 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300492 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300493
Alexey Klimov0fabb782008-10-19 23:56:23 -0300494 lock_kernel();
495
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300496 radio->users = 1;
497 radio->muted = 1;
498
Alexey Klimovdb821802009-02-05 08:53:02 -0300499 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300500 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300501 amradio_dev_warn(&radio->videodev->dev,
502 "radio did not start up properly\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300503 radio->users = 0;
Alexey Klimov0fabb782008-10-19 23:56:23 -0300504 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300505 return -EIO;
506 }
Alexey Klimova5d69472009-02-05 08:48:43 -0300507
508 retval = amradio_setfreq(radio, radio->curfreq);
509 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300510 amradio_dev_warn(&radio->videodev->dev,
511 "set frequency failed\n");
Alexey Klimov0fabb782008-10-19 23:56:23 -0300512
513 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300514 return 0;
515}
516
Alexey Klimovf4e90432008-12-27 21:30:34 -0300517/*close device */
Hans Verkuilbec43662008-12-30 06:58:20 -0300518static int usb_amradio_close(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300519{
520 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov34801302008-11-19 00:36:29 -0300521 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300522
523 if (!radio)
524 return -ENODEV;
Alexey Klimov34801302008-11-19 00:36:29 -0300525
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300526 radio->users = 0;
Alexey Klimov34801302008-11-19 00:36:29 -0300527
Alexey Klimovf4e90432008-12-27 21:30:34 -0300528 if (!radio->removed) {
Alexey Klimovdb821802009-02-05 08:53:02 -0300529 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimov34801302008-11-19 00:36:29 -0300530 if (retval < 0)
531 amradio_dev_warn(&radio->videodev->dev,
532 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300533 }
Alexey Klimov34801302008-11-19 00:36:29 -0300534
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300535 return 0;
536}
537
538/* Suspend device - stop device. Need to be checked and fixed */
539static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
540{
541 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300542 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300543
Alexey Klimovdb821802009-02-05 08:53:02 -0300544 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimova5d69472009-02-05 08:48:43 -0300545 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300546 dev_warn(&intf->dev, "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300547
Alexey Klimove60b0222008-11-04 15:02:36 -0300548 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300549
550 return 0;
551}
552
553/* Resume device - start device. Need to be checked and fixed */
554static int usb_amradio_resume(struct usb_interface *intf)
555{
556 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300557 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300558
Alexey Klimovdb821802009-02-05 08:53:02 -0300559 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300560 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300561 dev_warn(&intf->dev, "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300562
Alexey Klimove60b0222008-11-04 15:02:36 -0300563 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300564
565 return 0;
566}
567
568/* File system interface */
Hans Verkuilbec43662008-12-30 06:58:20 -0300569static const struct v4l2_file_operations usb_amradio_fops = {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300570 .owner = THIS_MODULE,
571 .open = usb_amradio_open,
572 .release = usb_amradio_close,
573 .ioctl = video_ioctl2,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300574};
575
576static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
577 .vidioc_querycap = vidioc_querycap,
578 .vidioc_g_tuner = vidioc_g_tuner,
579 .vidioc_s_tuner = vidioc_s_tuner,
580 .vidioc_g_frequency = vidioc_g_frequency,
581 .vidioc_s_frequency = vidioc_s_frequency,
582 .vidioc_queryctrl = vidioc_queryctrl,
583 .vidioc_g_ctrl = vidioc_g_ctrl,
584 .vidioc_s_ctrl = vidioc_s_ctrl,
585 .vidioc_g_audio = vidioc_g_audio,
586 .vidioc_s_audio = vidioc_s_audio,
587 .vidioc_g_input = vidioc_g_input,
588 .vidioc_s_input = vidioc_s_input,
589};
590
Alexey Klimovf4e90432008-12-27 21:30:34 -0300591static void usb_amradio_device_release(struct video_device *videodev)
592{
593 struct amradio_device *radio = video_get_drvdata(videodev);
594
595 /* we call v4l to free radio->videodev */
596 video_device_release(videodev);
597
598 /* free rest memory */
599 kfree(radio->buffer);
600 kfree(radio);
601}
602
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300603/* V4L2 interface */
604static struct video_device amradio_videodev_template = {
605 .name = "AverMedia MR 800 USB FM Radio",
606 .fops = &usb_amradio_fops,
607 .ioctl_ops = &usb_amradio_ioctl_ops,
Alexey Klimovf4e90432008-12-27 21:30:34 -0300608 .release = usb_amradio_device_release,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300609};
610
Alexey Klimova5d69472009-02-05 08:48:43 -0300611/* check if the device is present and register with v4l and usb if it is */
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300612static int usb_amradio_probe(struct usb_interface *intf,
613 const struct usb_device_id *id)
614{
615 struct amradio_device *radio;
Alexey Klimova5d69472009-02-05 08:48:43 -0300616 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300617
618 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
619
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300620 if (!radio) {
621 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300622 return -ENOMEM;
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300623 }
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300624
625 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
626
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300627 if (!radio->buffer) {
628 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300629 kfree(radio);
630 return -ENOMEM;
631 }
632
633 radio->videodev = video_device_alloc();
634
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300635 if (!radio->videodev) {
636 dev_err(&intf->dev, "video_device_alloc failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300637 kfree(radio->buffer);
638 kfree(radio);
639 return -ENOMEM;
640 }
641
642 memcpy(radio->videodev, &amradio_videodev_template,
643 sizeof(amradio_videodev_template));
644
645 radio->removed = 0;
646 radio->users = 0;
647 radio->usbdev = interface_to_usbdev(intf);
648 radio->curfreq = 95.16 * FREQ_MUL;
649
650 mutex_init(&radio->lock);
651
652 video_set_drvdata(radio->videodev, radio);
Alexey Klimova5d69472009-02-05 08:48:43 -0300653 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
654 if (retval < 0) {
Alexey Klimov65c51dc2009-02-05 08:49:58 -0300655 dev_err(&intf->dev, "could not register video device\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300656 video_device_release(radio->videodev);
657 kfree(radio->buffer);
658 kfree(radio);
659 return -EIO;
660 }
661
662 usb_set_intfdata(intf, radio);
663 return 0;
664}
665
666static int __init amradio_init(void)
667{
668 int retval = usb_register(&usb_amradio_driver);
669
Alexey Klimove60b0222008-11-04 15:02:36 -0300670 pr_info(KBUILD_MODNAME
671 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
672
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300673 if (retval)
Alexey Klimove60b0222008-11-04 15:02:36 -0300674 pr_err(KBUILD_MODNAME
675 ": usb_register failed. Error number %d\n", retval);
676
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300677 return retval;
678}
679
680static void __exit amradio_exit(void)
681{
682 usb_deregister(&usb_amradio_driver);
683}
684
685module_init(amradio_init);
686module_exit(amradio_exit);
687