blob: 25ccf21c469edfc25f0c58dd6047debb7c93bb14 [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
Alexey Klimov1bb16d72009-02-05 08:56:07 -030096#define AMRADIO_SET_MONO 0xae
Alexey Klimovdb821802009-02-05 08:53:02 -030097
98/* Comfortable defines for amradio_set_mute */
99#define AMRADIO_START 0x00
100#define AMRADIO_STOP 0x01
101
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300102/* Comfortable defines for amradio_set_stereo */
103#define WANT_STEREO 0x00
104#define WANT_MONO 0x01
105
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300106/* module parameter */
107static int radio_nr = -1;
108module_param(radio_nr, int, 0);
109MODULE_PARM_DESC(radio_nr, "Radio Nr");
110
111static struct v4l2_queryctrl radio_qctrl[] = {
112 {
113 .id = V4L2_CID_AUDIO_MUTE,
114 .name = "Mute",
115 .minimum = 0,
116 .maximum = 1,
117 .step = 1,
118 .default_value = 1,
119 .type = V4L2_CTRL_TYPE_BOOLEAN,
120 },
121/* HINT: the disabled controls are only here to satify kradio and such apps */
122 { .id = V4L2_CID_AUDIO_VOLUME,
123 .flags = V4L2_CTRL_FLAG_DISABLED,
124 },
125 {
126 .id = V4L2_CID_AUDIO_BALANCE,
127 .flags = V4L2_CTRL_FLAG_DISABLED,
128 },
129 {
130 .id = V4L2_CID_AUDIO_BASS,
131 .flags = V4L2_CTRL_FLAG_DISABLED,
132 },
133 {
134 .id = V4L2_CID_AUDIO_TREBLE,
135 .flags = V4L2_CTRL_FLAG_DISABLED,
136 },
137 {
138 .id = V4L2_CID_AUDIO_LOUDNESS,
139 .flags = V4L2_CTRL_FLAG_DISABLED,
140 },
141};
142
143static int usb_amradio_probe(struct usb_interface *intf,
144 const struct usb_device_id *id);
145static void usb_amradio_disconnect(struct usb_interface *intf);
Hans Verkuilbec43662008-12-30 06:58:20 -0300146static int usb_amradio_open(struct file *file);
147static int usb_amradio_close(struct file *file);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300148static int usb_amradio_suspend(struct usb_interface *intf,
149 pm_message_t message);
150static int usb_amradio_resume(struct usb_interface *intf);
151
152/* Data for one (physical) device */
153struct amradio_device {
154 /* reference to USB and video device */
155 struct usb_device *usbdev;
156 struct video_device *videodev;
157
158 unsigned char *buffer;
159 struct mutex lock; /* buffer locking */
160 int curfreq;
161 int stereo;
162 int users;
163 int removed;
164 int muted;
165};
166
167/* USB Device ID List */
168static struct usb_device_id usb_amradio_device_table[] = {
169 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
170 USB_CLASS_HID, 0, 0) },
171 { } /* Terminating entry */
172};
173
174MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
175
176/* USB subsystem interface */
177static struct usb_driver usb_amradio_driver = {
Alexey Klimove60b0222008-11-04 15:02:36 -0300178 .name = MR800_DRIVER_NAME,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300179 .probe = usb_amradio_probe,
180 .disconnect = usb_amradio_disconnect,
181 .suspend = usb_amradio_suspend,
182 .resume = usb_amradio_resume,
183 .reset_resume = usb_amradio_resume,
184 .id_table = usb_amradio_device_table,
Alexey Klimovf2ce9172008-12-27 21:31:49 -0300185 .supports_autosuspend = 0,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300186};
187
Alexey Klimovdb821802009-02-05 08:53:02 -0300188/* switch on/off the radio. Send 8 bytes to device */
189static int amradio_set_mute(struct amradio_device *radio, char argument)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300190{
191 int retval;
192 int size;
193
Alexey Klimov34801302008-11-19 00:36:29 -0300194 /* safety check */
195 if (radio->removed)
196 return -EIO;
197
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300198 mutex_lock(&radio->lock);
199
200 radio->buffer[0] = 0x00;
201 radio->buffer[1] = 0x55;
202 radio->buffer[2] = 0xaa;
203 radio->buffer[3] = 0x00;
Alexey Klimovdb821802009-02-05 08:53:02 -0300204 radio->buffer[4] = AMRADIO_SET_MUTE;
205 radio->buffer[5] = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300206 radio->buffer[6] = 0x00;
207 radio->buffer[7] = 0x00;
208
209 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
210 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
211
212 if (retval) {
213 mutex_unlock(&radio->lock);
214 return retval;
215 }
216
Alexey Klimovdb821802009-02-05 08:53:02 -0300217 radio->muted = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300218
Alexey Klimov7f03a582009-01-25 20:07:28 -0300219 mutex_unlock(&radio->lock);
220
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300221 return retval;
222}
223
224/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
225static int amradio_setfreq(struct amradio_device *radio, int freq)
226{
227 int retval;
228 int size;
Alexey Klimovf7c1a382009-02-05 08:54:17 -0300229 unsigned short freq_send = 0x10 + (freq >> 3) / 25;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300230
Alexey Klimov34801302008-11-19 00:36:29 -0300231 /* safety check */
232 if (radio->removed)
233 return -EIO;
234
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300235 mutex_lock(&radio->lock);
236
237 radio->buffer[0] = 0x00;
238 radio->buffer[1] = 0x55;
239 radio->buffer[2] = 0xaa;
240 radio->buffer[3] = 0x03;
Alexey Klimovf7c1a382009-02-05 08:54:17 -0300241 radio->buffer[4] = AMRADIO_SET_FREQ;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300242 radio->buffer[5] = 0x00;
243 radio->buffer[6] = 0x00;
244 radio->buffer[7] = 0x08;
245
246 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
247 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
248
249 if (retval) {
250 mutex_unlock(&radio->lock);
251 return retval;
252 }
253
254 /* frequency is calculated from freq_send and placed in first 2 bytes */
255 radio->buffer[0] = (freq_send >> 8) & 0xff;
256 radio->buffer[1] = freq_send & 0xff;
257 radio->buffer[2] = 0x01;
258 radio->buffer[3] = 0x00;
259 radio->buffer[4] = 0x00;
260 /* 5 and 6 bytes of buffer already = 0x00 */
261 radio->buffer[7] = 0x00;
262
263 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
264 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
265
266 if (retval) {
267 mutex_unlock(&radio->lock);
268 return retval;
269 }
270
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300271 mutex_unlock(&radio->lock);
272
273 return retval;
274}
275
276static int amradio_set_stereo(struct amradio_device *radio, char argument)
277{
278 int retval;
279 int size;
280
281 /* safety check */
282 if (radio->removed)
283 return -EIO;
284
285 mutex_lock(&radio->lock);
286
287 radio->buffer[0] = 0x00;
288 radio->buffer[1] = 0x55;
289 radio->buffer[2] = 0xaa;
290 radio->buffer[3] = 0x00;
291 radio->buffer[4] = AMRADIO_SET_MONO;
292 radio->buffer[5] = argument;
293 radio->buffer[6] = 0x00;
294 radio->buffer[7] = 0x00;
295
296 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
297 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
298
299 if (retval < 0 || size != BUFFER_LENGTH) {
300 radio->stereo = -1;
301 mutex_unlock(&radio->lock);
302 return retval;
303 }
304
305 radio->stereo = 1;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300306
Alexey Klimov7f03a582009-01-25 20:07:28 -0300307 mutex_unlock(&radio->lock);
308
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300309 return retval;
310}
311
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300312
313
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300314/* USB subsystem interface begins here */
315
316/* handle unplugging of the device, release data structures
317if nothing keeps us from doing it. If something is still
318keeping us busy, the release callback of v4l will take care
319of releasing it. */
320static void usb_amradio_disconnect(struct usb_interface *intf)
321{
322 struct amradio_device *radio = usb_get_intfdata(intf);
323
Alexey Klimovf4e90432008-12-27 21:30:34 -0300324 mutex_lock(&radio->lock);
Alexey Klimov34801302008-11-19 00:36:29 -0300325 radio->removed = 1;
Alexey Klimovf4e90432008-12-27 21:30:34 -0300326 mutex_unlock(&radio->lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300327
Alexey Klimovf4e90432008-12-27 21:30:34 -0300328 usb_set_intfdata(intf, NULL);
329 video_unregister_device(radio->videodev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300330}
331
332/* vidioc_querycap - query device capabilities */
333static int vidioc_querycap(struct file *file, void *priv,
334 struct v4l2_capability *v)
335{
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300336 struct amradio_device *radio = video_drvdata(file);
337
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300338 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
339 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300340 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300341 v->version = RADIO_VERSION;
342 v->capabilities = V4L2_CAP_TUNER;
343 return 0;
344}
345
346/* vidioc_g_tuner - get tuner attributes */
347static int vidioc_g_tuner(struct file *file, void *priv,
348 struct v4l2_tuner *v)
349{
350 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300351 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300352
Alexey Klimov34801302008-11-19 00:36:29 -0300353 /* safety check */
354 if (radio->removed)
355 return -EIO;
356
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300357 if (v->index > 0)
358 return -EINVAL;
359
360/* TODO: Add function which look is signal stereo or not
361 * amradio_getstat(radio);
362 */
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300363
364/* we call amradio_set_stereo to set radio->stereo
365 * Honestly, amradio_getstat should cover this in future and
366 * amradio_set_stereo shouldn't be here
367 */
368 retval = amradio_set_stereo(radio, WANT_STEREO);
369 if (retval < 0)
370 amradio_dev_warn(&radio->videodev->dev,
371 "set stereo failed\n");
372
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300373 strcpy(v->name, "FM");
374 v->type = V4L2_TUNER_RADIO;
375 v->rangelow = FREQ_MIN * FREQ_MUL;
376 v->rangehigh = FREQ_MAX * FREQ_MUL;
377 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
378 v->capability = V4L2_TUNER_CAP_LOW;
379 if (radio->stereo)
380 v->audmode = V4L2_TUNER_MODE_STEREO;
381 else
382 v->audmode = V4L2_TUNER_MODE_MONO;
383 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
384 v->afc = 0; /* Don't know what is this */
385 return 0;
386}
387
388/* vidioc_s_tuner - set tuner attributes */
389static int vidioc_s_tuner(struct file *file, void *priv,
390 struct v4l2_tuner *v)
391{
Alexey Klimov34801302008-11-19 00:36:29 -0300392 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300393 int retval;
Alexey Klimov34801302008-11-19 00:36:29 -0300394
395 /* safety check */
396 if (radio->removed)
397 return -EIO;
398
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300399 if (v->index > 0)
400 return -EINVAL;
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300401
402 /* mono/stereo selector */
403 switch (v->audmode) {
404 case V4L2_TUNER_MODE_MONO:
405 retval = amradio_set_stereo(radio, WANT_MONO);
406 if (retval < 0)
407 amradio_dev_warn(&radio->videodev->dev,
408 "set mono failed\n");
409 break;
410 case V4L2_TUNER_MODE_STEREO:
411 retval = amradio_set_stereo(radio, WANT_STEREO);
412 if (retval < 0)
413 amradio_dev_warn(&radio->videodev->dev,
414 "set stereo failed\n");
415 break;
416 default:
417 return -EINVAL;
418 }
419
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300420 return 0;
421}
422
423/* vidioc_s_frequency - set tuner radio frequency */
424static int vidioc_s_frequency(struct file *file, void *priv,
425 struct v4l2_frequency *f)
426{
427 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300428 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300429
Alexey Klimov34801302008-11-19 00:36:29 -0300430 /* safety check */
431 if (radio->removed)
432 return -EIO;
433
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300434 radio->curfreq = f->frequency;
Alexey Klimova5d69472009-02-05 08:48:43 -0300435 retval = amradio_setfreq(radio, radio->curfreq);
436 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300437 amradio_dev_warn(&radio->videodev->dev,
438 "set frequency failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300439 return 0;
440}
441
442/* vidioc_g_frequency - get tuner radio frequency */
443static int vidioc_g_frequency(struct file *file, void *priv,
444 struct v4l2_frequency *f)
445{
446 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
447
Alexey Klimov34801302008-11-19 00:36:29 -0300448 /* safety check */
449 if (radio->removed)
450 return -EIO;
451
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300452 f->type = V4L2_TUNER_RADIO;
453 f->frequency = radio->curfreq;
454 return 0;
455}
456
457/* vidioc_queryctrl - enumerate control items */
458static int vidioc_queryctrl(struct file *file, void *priv,
459 struct v4l2_queryctrl *qc)
460{
461 int i;
462
463 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
464 if (qc->id && qc->id == radio_qctrl[i].id) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300465 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300466 return 0;
467 }
468 }
469 return -EINVAL;
470}
471
472/* vidioc_g_ctrl - get the value of a control */
473static int vidioc_g_ctrl(struct file *file, void *priv,
474 struct v4l2_control *ctrl)
475{
476 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
477
Alexey Klimov34801302008-11-19 00:36:29 -0300478 /* safety check */
479 if (radio->removed)
480 return -EIO;
481
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300482 switch (ctrl->id) {
483 case V4L2_CID_AUDIO_MUTE:
484 ctrl->value = radio->muted;
485 return 0;
486 }
487 return -EINVAL;
488}
489
490/* vidioc_s_ctrl - set the value of a control */
491static int vidioc_s_ctrl(struct file *file, void *priv,
492 struct v4l2_control *ctrl)
493{
494 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300495 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300496
Alexey Klimov34801302008-11-19 00:36:29 -0300497 /* safety check */
498 if (radio->removed)
499 return -EIO;
500
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300501 switch (ctrl->id) {
502 case V4L2_CID_AUDIO_MUTE:
503 if (ctrl->value) {
Alexey Klimovdb821802009-02-05 08:53:02 -0300504 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimova5d69472009-02-05 08:48:43 -0300505 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300506 amradio_dev_warn(&radio->videodev->dev,
507 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300508 return -1;
509 }
510 } else {
Alexey Klimovdb821802009-02-05 08:53:02 -0300511 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300512 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300513 amradio_dev_warn(&radio->videodev->dev,
514 "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300515 return -1;
516 }
517 }
518 return 0;
519 }
520 return -EINVAL;
521}
522
523/* vidioc_g_audio - get audio attributes */
524static int vidioc_g_audio(struct file *file, void *priv,
525 struct v4l2_audio *a)
526{
527 if (a->index > 1)
528 return -EINVAL;
529
530 strcpy(a->name, "Radio");
531 a->capability = V4L2_AUDCAP_STEREO;
532 return 0;
533}
534
535/* vidioc_s_audio - set audio attributes */
536static int vidioc_s_audio(struct file *file, void *priv,
537 struct v4l2_audio *a)
538{
539 if (a->index != 0)
540 return -EINVAL;
541 return 0;
542}
543
544/* vidioc_g_input - get input */
545static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
546{
547 *i = 0;
548 return 0;
549}
550
551/* vidioc_s_input - set input */
552static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
553{
554 if (i != 0)
555 return -EINVAL;
556 return 0;
557}
558
559/* open device - amradio_start() and amradio_setfreq() */
Hans Verkuilbec43662008-12-30 06:58:20 -0300560static int usb_amradio_open(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300561{
562 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimova5d69472009-02-05 08:48:43 -0300563 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300564
Alexey Klimov0fabb782008-10-19 23:56:23 -0300565 lock_kernel();
566
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300567 radio->users = 1;
568 radio->muted = 1;
569
Alexey Klimovdb821802009-02-05 08:53:02 -0300570 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300571 if (retval < 0) {
Alexey Klimove60b0222008-11-04 15:02:36 -0300572 amradio_dev_warn(&radio->videodev->dev,
573 "radio did not start up properly\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300574 radio->users = 0;
Alexey Klimov0fabb782008-10-19 23:56:23 -0300575 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300576 return -EIO;
577 }
Alexey Klimova5d69472009-02-05 08:48:43 -0300578
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300579 retval = amradio_set_stereo(radio, WANT_STEREO);
580 if (retval < 0)
581 amradio_dev_warn(&radio->videodev->dev,
582 "set stereo failed\n");
583
Alexey Klimova5d69472009-02-05 08:48:43 -0300584 retval = amradio_setfreq(radio, radio->curfreq);
585 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300586 amradio_dev_warn(&radio->videodev->dev,
587 "set frequency failed\n");
Alexey Klimov0fabb782008-10-19 23:56:23 -0300588
589 unlock_kernel();
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300590 return 0;
591}
592
Alexey Klimovf4e90432008-12-27 21:30:34 -0300593/*close device */
Hans Verkuilbec43662008-12-30 06:58:20 -0300594static int usb_amradio_close(struct file *file)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300595{
596 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
Alexey Klimov34801302008-11-19 00:36:29 -0300597 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300598
599 if (!radio)
600 return -ENODEV;
Alexey Klimov34801302008-11-19 00:36:29 -0300601
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300602 radio->users = 0;
Alexey Klimov34801302008-11-19 00:36:29 -0300603
Alexey Klimovf4e90432008-12-27 21:30:34 -0300604 if (!radio->removed) {
Alexey Klimovdb821802009-02-05 08:53:02 -0300605 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimov34801302008-11-19 00:36:29 -0300606 if (retval < 0)
607 amradio_dev_warn(&radio->videodev->dev,
608 "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300609 }
Alexey Klimov34801302008-11-19 00:36:29 -0300610
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300611 return 0;
612}
613
614/* Suspend device - stop device. Need to be checked and fixed */
615static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
616{
617 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300618 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300619
Alexey Klimovdb821802009-02-05 08:53:02 -0300620 retval = amradio_set_mute(radio, AMRADIO_STOP);
Alexey Klimova5d69472009-02-05 08:48:43 -0300621 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300622 dev_warn(&intf->dev, "amradio_stop failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300623
Alexey Klimove60b0222008-11-04 15:02:36 -0300624 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300625
626 return 0;
627}
628
629/* Resume device - start device. Need to be checked and fixed */
630static int usb_amradio_resume(struct usb_interface *intf)
631{
632 struct amradio_device *radio = usb_get_intfdata(intf);
Alexey Klimova5d69472009-02-05 08:48:43 -0300633 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300634
Alexey Klimovdb821802009-02-05 08:53:02 -0300635 retval = amradio_set_mute(radio, AMRADIO_START);
Alexey Klimova5d69472009-02-05 08:48:43 -0300636 if (retval < 0)
Alexey Klimove60b0222008-11-04 15:02:36 -0300637 dev_warn(&intf->dev, "amradio_start failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300638
Alexey Klimove60b0222008-11-04 15:02:36 -0300639 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300640
641 return 0;
642}
643
644/* File system interface */
Hans Verkuilbec43662008-12-30 06:58:20 -0300645static const struct v4l2_file_operations usb_amradio_fops = {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300646 .owner = THIS_MODULE,
647 .open = usb_amradio_open,
648 .release = usb_amradio_close,
649 .ioctl = video_ioctl2,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300650};
651
652static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
653 .vidioc_querycap = vidioc_querycap,
654 .vidioc_g_tuner = vidioc_g_tuner,
655 .vidioc_s_tuner = vidioc_s_tuner,
656 .vidioc_g_frequency = vidioc_g_frequency,
657 .vidioc_s_frequency = vidioc_s_frequency,
658 .vidioc_queryctrl = vidioc_queryctrl,
659 .vidioc_g_ctrl = vidioc_g_ctrl,
660 .vidioc_s_ctrl = vidioc_s_ctrl,
661 .vidioc_g_audio = vidioc_g_audio,
662 .vidioc_s_audio = vidioc_s_audio,
663 .vidioc_g_input = vidioc_g_input,
664 .vidioc_s_input = vidioc_s_input,
665};
666
Alexey Klimovf4e90432008-12-27 21:30:34 -0300667static void usb_amradio_device_release(struct video_device *videodev)
668{
669 struct amradio_device *radio = video_get_drvdata(videodev);
670
671 /* we call v4l to free radio->videodev */
672 video_device_release(videodev);
673
674 /* free rest memory */
675 kfree(radio->buffer);
676 kfree(radio);
677}
678
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300679/* V4L2 interface */
680static struct video_device amradio_videodev_template = {
681 .name = "AverMedia MR 800 USB FM Radio",
682 .fops = &usb_amradio_fops,
683 .ioctl_ops = &usb_amradio_ioctl_ops,
Alexey Klimovf4e90432008-12-27 21:30:34 -0300684 .release = usb_amradio_device_release,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300685};
686
Alexey Klimova5d69472009-02-05 08:48:43 -0300687/* check if the device is present and register with v4l and usb if it is */
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300688static int usb_amradio_probe(struct usb_interface *intf,
689 const struct usb_device_id *id)
690{
691 struct amradio_device *radio;
Alexey Klimova5d69472009-02-05 08:48:43 -0300692 int retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300693
694 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
695
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300696 if (!radio) {
697 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300698 return -ENOMEM;
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300699 }
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300700
701 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
702
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300703 if (!radio->buffer) {
704 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300705 kfree(radio);
706 return -ENOMEM;
707 }
708
709 radio->videodev = video_device_alloc();
710
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300711 if (!radio->videodev) {
712 dev_err(&intf->dev, "video_device_alloc failed\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300713 kfree(radio->buffer);
714 kfree(radio);
715 return -ENOMEM;
716 }
717
718 memcpy(radio->videodev, &amradio_videodev_template,
719 sizeof(amradio_videodev_template));
720
721 radio->removed = 0;
722 radio->users = 0;
723 radio->usbdev = interface_to_usbdev(intf);
724 radio->curfreq = 95.16 * FREQ_MUL;
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300725 radio->stereo = -1;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300726
727 mutex_init(&radio->lock);
728
729 video_set_drvdata(radio->videodev, radio);
Alexey Klimova5d69472009-02-05 08:48:43 -0300730 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
731 if (retval < 0) {
Alexey Klimov65c51dc2009-02-05 08:49:58 -0300732 dev_err(&intf->dev, "could not register video device\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300733 video_device_release(radio->videodev);
734 kfree(radio->buffer);
735 kfree(radio);
736 return -EIO;
737 }
738
739 usb_set_intfdata(intf, radio);
740 return 0;
741}
742
743static int __init amradio_init(void)
744{
745 int retval = usb_register(&usb_amradio_driver);
746
Alexey Klimove60b0222008-11-04 15:02:36 -0300747 pr_info(KBUILD_MODNAME
748 ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
749
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300750 if (retval)
Alexey Klimove60b0222008-11-04 15:02:36 -0300751 pr_err(KBUILD_MODNAME
752 ": usb_register failed. Error number %d\n", retval);
753
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300754 return retval;
755}
756
757static void __exit amradio_exit(void)
758{
759 usb_deregister(&usb_amradio_driver);
760}
761
762module_init(amradio_init);
763module_exit(amradio_exit);
764