blob: 0a96edae678622fb6a670c277895b2e6acca6070 [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/*
Alexey Klimov71f07d92009-02-05 08:58:31 -030025 * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c
Alexey Klimov2aa72f32008-10-01 09:40:59 -030026 *
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.
André Goddard Rosaaf901ca2009-11-14 13:09:05 -020031 * Probably, this driver could be improved through using their
Alexey Klimov2aa72f32008-10-01 09:40:59 -030032 * achievements (specifications given).
Alexey Klimov71f07d92009-02-05 08:58:31 -030033 * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio
34 * in 2007. He allowed to use his driver to improve current mr800 radio driver.
35 * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492
Alexey Klimov2aa72f32008-10-01 09:40:59 -030036 *
Alexey Klimov2aa72f32008-10-01 09:40:59 -030037 * Version 0.01: First working version.
38 * It's required to blacklist AverMedia USB Radio
39 * in usbhid/hid-quirks.c
Alexey Klimov71f07d92009-02-05 08:58:31 -030040 * Version 0.10: A lot of cleanups and fixes: unpluging the device,
41 * few mutex locks were added, codinstyle issues, etc.
42 * Added stereo support. Thanks to
43 * Douglas Schilling Landgraf <dougsland@gmail.com> and
44 * David Ellingsworth <david@identd.dyndns.org>
45 * for discussion, help and support.
Alexey Klimovb4662482009-04-03 18:45:27 -030046 * Version 0.11: Converted to v4l2_device.
Alexey Klimov2aa72f32008-10-01 09:40:59 -030047 *
48 * Many things to do:
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +020049 * - Correct power management of device (suspend & resume)
Alexey Klimov2aa72f32008-10-01 09:40:59 -030050 * - Add code for scanning and smooth tuning
Alexey Klimov2aa72f32008-10-01 09:40:59 -030051 * - Add code for sensitivity value
52 * - Correct mistakes
53 * - In Japan another FREQ_MIN and FREQ_MAX
54 */
55
56/* kernel includes */
57#include <linux/kernel.h>
58#include <linux/module.h>
59#include <linux/init.h>
60#include <linux/slab.h>
61#include <linux/input.h>
62#include <linux/videodev2.h>
Alexey Klimovb4662482009-04-03 18:45:27 -030063#include <media/v4l2-device.h>
Alexey Klimov2aa72f32008-10-01 09:40:59 -030064#include <media/v4l2-ioctl.h>
Hans Verkuil85578b02012-04-27 12:30:40 -030065#include <media/v4l2-ctrls.h>
66#include <media/v4l2-event.h>
Alexey Klimov2aa72f32008-10-01 09:40:59 -030067#include <linux/usb.h>
Alessio Igor Bogani24c44d82009-05-12 17:39:27 -030068#include <linux/mutex.h>
Alexey Klimov2aa72f32008-10-01 09:40:59 -030069
70/* driver and module definitions */
71#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
72#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
Mauro Carvalho Chehab29834c12011-06-25 10:15:42 -030073#define DRIVER_VERSION "0.1.2"
Alexey Klimov2aa72f32008-10-01 09:40:59 -030074
75MODULE_AUTHOR(DRIVER_AUTHOR);
76MODULE_DESCRIPTION(DRIVER_DESC);
77MODULE_LICENSE("GPL");
Mauro Carvalho Chehab29834c12011-06-25 10:15:42 -030078MODULE_VERSION(DRIVER_VERSION);
Alexey Klimov2aa72f32008-10-01 09:40:59 -030079
80#define USB_AMRADIO_VENDOR 0x07ca
81#define USB_AMRADIO_PRODUCT 0xb800
82
Alexey Klimove60b0222008-11-04 15:02:36 -030083/* dev_warn macro with driver name */
84#define MR800_DRIVER_NAME "radio-mr800"
85#define amradio_dev_warn(dev, fmt, arg...) \
86 dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
87
David Ellingsworth502d5012009-09-23 18:13:50 -030088#define amradio_dev_err(dev, fmt, arg...) \
89 dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
90
Alexey Klimov2aa72f32008-10-01 09:40:59 -030091/* Probably USB_TIMEOUT should be modified in module parameter */
92#define BUFFER_LENGTH 8
93#define USB_TIMEOUT 500
94
95/* Frequency limits in MHz -- these are European values. For Japanese
96devices, that would be 76 and 91. */
97#define FREQ_MIN 87.5
98#define FREQ_MAX 108.0
99#define FREQ_MUL 16000
100
Alexey Klimovdb821802009-02-05 08:53:02 -0300101/*
102 * Commands that device should understand
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300103 * List isn't full and will be updated with implementation of new functions
Alexey Klimovdb821802009-02-05 08:53:02 -0300104 */
Alexey Klimovf7c1a382009-02-05 08:54:17 -0300105#define AMRADIO_SET_FREQ 0xa4
Alexey Klimovdb821802009-02-05 08:53:02 -0300106#define AMRADIO_SET_MUTE 0xab
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300107#define AMRADIO_SET_MONO 0xae
Alexey Klimovdb821802009-02-05 08:53:02 -0300108
109/* Comfortable defines for amradio_set_mute */
110#define AMRADIO_START 0x00
111#define AMRADIO_STOP 0x01
112
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300113/* Comfortable defines for amradio_set_stereo */
114#define WANT_STEREO 0x00
115#define WANT_MONO 0x01
116
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300117/* module parameter */
118static int radio_nr = -1;
119module_param(radio_nr, int, 0);
120MODULE_PARM_DESC(radio_nr, "Radio Nr");
121
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300122/* Data for one (physical) device */
123struct amradio_device {
124 /* reference to USB and video device */
125 struct usb_device *usbdev;
Oliver Neukumd89ce0d2009-11-09 19:09:49 -0300126 struct usb_interface *intf;
Hans Verkuil85578b02012-04-27 12:30:40 -0300127 struct video_device vdev;
Alexey Klimovb4662482009-04-03 18:45:27 -0300128 struct v4l2_device v4l2_dev;
Hans Verkuil85578b02012-04-27 12:30:40 -0300129 struct v4l2_ctrl_handler hdl;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300130
131 unsigned char *buffer;
132 struct mutex lock; /* buffer locking */
133 int curfreq;
134 int stereo;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300135 int muted;
136};
137
Hans Verkuila2bdc5e2010-05-02 05:36:32 -0300138static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev)
139{
140 return container_of(v4l2_dev, struct amradio_device, v4l2_dev);
141}
David Ellingsworthceb99e12009-09-23 17:45:31 -0300142
Alexey Klimovdb821802009-02-05 08:53:02 -0300143/* switch on/off the radio. Send 8 bytes to device */
144static int amradio_set_mute(struct amradio_device *radio, char argument)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300145{
146 int retval;
147 int size;
148
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300149 radio->buffer[0] = 0x00;
150 radio->buffer[1] = 0x55;
151 radio->buffer[2] = 0xaa;
152 radio->buffer[3] = 0x00;
Alexey Klimovdb821802009-02-05 08:53:02 -0300153 radio->buffer[4] = AMRADIO_SET_MUTE;
154 radio->buffer[5] = argument;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300155 radio->buffer[6] = 0x00;
156 radio->buffer[7] = 0x00;
157
158 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
159 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
160
Alexey Klimove57458d2009-02-05 09:00:03 -0300161 if (retval < 0 || size != BUFFER_LENGTH) {
Hans Verkuil85578b02012-04-27 12:30:40 -0300162 amradio_dev_warn(&radio->vdev.dev, "set mute failed\n");
163 return retval < 0 ? retval : -EIO;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300164 }
Alexey Klimovdb821802009-02-05 08:53:02 -0300165 radio->muted = argument;
Hans Verkuil85578b02012-04-27 12:30:40 -0300166 return 0;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300167}
168
169/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
170static int amradio_setfreq(struct amradio_device *radio, int freq)
171{
Hans Verkuil85578b02012-04-27 12:30:40 -0300172 unsigned short freq_send = 0x10 + (freq >> 3) / 25;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300173 int retval;
174 int size;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300175
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300176 radio->buffer[0] = 0x00;
177 radio->buffer[1] = 0x55;
178 radio->buffer[2] = 0xaa;
179 radio->buffer[3] = 0x03;
Alexey Klimovf7c1a382009-02-05 08:54:17 -0300180 radio->buffer[4] = AMRADIO_SET_FREQ;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300181 radio->buffer[5] = 0x00;
182 radio->buffer[6] = 0x00;
183 radio->buffer[7] = 0x08;
184
185 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
186 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
187
David Ellingsworth4aebc282009-09-22 21:22:19 -0300188 if (retval < 0 || size != BUFFER_LENGTH)
Hans Verkuil85578b02012-04-27 12:30:40 -0300189 goto out;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300190
191 /* frequency is calculated from freq_send and placed in first 2 bytes */
192 radio->buffer[0] = (freq_send >> 8) & 0xff;
193 radio->buffer[1] = freq_send & 0xff;
194 radio->buffer[2] = 0x01;
195 radio->buffer[3] = 0x00;
196 radio->buffer[4] = 0x00;
197 /* 5 and 6 bytes of buffer already = 0x00 */
198 radio->buffer[7] = 0x00;
199
200 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
201 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
202
Hans Verkuil85578b02012-04-27 12:30:40 -0300203 if (retval >= 0 && size == BUFFER_LENGTH) {
204 radio->curfreq = freq;
205 return 0;
206 }
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300207
David Ellingsworth16a72f42009-09-23 18:28:02 -0300208out:
Hans Verkuil85578b02012-04-27 12:30:40 -0300209 amradio_dev_warn(&radio->vdev.dev, "set frequency failed\n");
210 return retval < 0 ? retval : -EIO;
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300211}
212
213static int amradio_set_stereo(struct amradio_device *radio, char argument)
214{
215 int retval;
216 int size;
217
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300218 radio->buffer[0] = 0x00;
219 radio->buffer[1] = 0x55;
220 radio->buffer[2] = 0xaa;
221 radio->buffer[3] = 0x00;
222 radio->buffer[4] = AMRADIO_SET_MONO;
223 radio->buffer[5] = argument;
224 radio->buffer[6] = 0x00;
225 radio->buffer[7] = 0x00;
226
227 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
228 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
229
230 if (retval < 0 || size != BUFFER_LENGTH) {
Hans Verkuil85578b02012-04-27 12:30:40 -0300231 amradio_dev_warn(&radio->vdev.dev, "set stereo failed\n");
232 return retval < 0 ? retval : -EIO;
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300233 }
234
Hans Verkuil85578b02012-04-27 12:30:40 -0300235 radio->stereo = (argument == WANT_STEREO);
236 return 0;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300237}
238
Alexey Klimov71f07d92009-02-05 08:58:31 -0300239/* Handle unplugging the device.
240 * We call video_unregister_device in any case.
241 * The last function called in this procedure is
242 * usb_amradio_device_release.
243 */
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300244static void usb_amradio_disconnect(struct usb_interface *intf)
245{
Hans Verkuila2bdc5e2010-05-02 05:36:32 -0300246 struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300247
Alexey Klimovf4e90432008-12-27 21:30:34 -0300248 mutex_lock(&radio->lock);
Hans Verkuil85578b02012-04-27 12:30:40 -0300249 usb_set_intfdata(intf, NULL);
250 video_unregister_device(&radio->vdev);
Alexey Klimovb4662482009-04-03 18:45:27 -0300251 v4l2_device_disconnect(&radio->v4l2_dev);
Hans Verkuila682d4c2010-10-17 09:26:18 -0300252 mutex_unlock(&radio->lock);
Hans Verkuil85578b02012-04-27 12:30:40 -0300253 v4l2_device_put(&radio->v4l2_dev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300254}
255
256/* vidioc_querycap - query device capabilities */
257static int vidioc_querycap(struct file *file, void *priv,
258 struct v4l2_capability *v)
259{
Hans Verkuil85578b02012-04-27 12:30:40 -0300260 struct amradio_device *radio = video_drvdata(file);
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300261
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300262 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
263 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
Alexey Klimovc7181cf2009-01-25 20:05:58 -0300264 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
Hans Verkuil85578b02012-04-27 12:30:40 -0300265 v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
266 v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300267 return 0;
268}
269
270/* vidioc_g_tuner - get tuner attributes */
271static int vidioc_g_tuner(struct file *file, void *priv,
272 struct v4l2_tuner *v)
273{
Hans Verkuil85578b02012-04-27 12:30:40 -0300274 struct amradio_device *radio = video_drvdata(file);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300275
276 if (v->index > 0)
277 return -EINVAL;
278
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300279 strcpy(v->name, "FM");
280 v->type = V4L2_TUNER_RADIO;
281 v->rangelow = FREQ_MIN * FREQ_MUL;
282 v->rangehigh = FREQ_MAX * FREQ_MUL;
Hans Verkuil85578b02012-04-27 12:30:40 -0300283 v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
284 /* We do not know how to get hold of the stereo indicator, so
285 all we can do is give back both mono and stereo, which
286 effectively means that we don't know. */
287 v->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
288 v->signal = 0xffff;
289 v->audmode = radio->stereo ?
290 V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
291 return 0;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300292}
293
294/* vidioc_s_tuner - set tuner attributes */
295static int vidioc_s_tuner(struct file *file, void *priv,
296 struct v4l2_tuner *v)
297{
Hans Verkuil85578b02012-04-27 12:30:40 -0300298 struct amradio_device *radio = video_drvdata(file);
Alexey Klimov34801302008-11-19 00:36:29 -0300299
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300300 if (v->index > 0)
301 return -EINVAL;
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300302
303 /* mono/stereo selector */
304 switch (v->audmode) {
305 case V4L2_TUNER_MODE_MONO:
Hans Verkuil85578b02012-04-27 12:30:40 -0300306 return amradio_set_stereo(radio, WANT_MONO);
307 default:
308 return amradio_set_stereo(radio, WANT_STEREO);
Alexey Klimov1bb16d72009-02-05 08:56:07 -0300309 }
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300310}
311
312/* vidioc_s_frequency - set tuner radio frequency */
313static int vidioc_s_frequency(struct file *file, void *priv,
314 struct v4l2_frequency *f)
315{
Hans Verkuil85578b02012-04-27 12:30:40 -0300316 struct amradio_device *radio = video_drvdata(file);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300317
Hans Verkuil85578b02012-04-27 12:30:40 -0300318 if (f->tuner != 0)
Hans Verkuila3a9e282009-11-27 04:33:25 -0300319 return -EINVAL;
Hans Verkuil85578b02012-04-27 12:30:40 -0300320 return amradio_setfreq(radio, clamp_t(unsigned, f->frequency,
321 FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300322}
323
324/* vidioc_g_frequency - get tuner radio frequency */
325static int vidioc_g_frequency(struct file *file, void *priv,
326 struct v4l2_frequency *f)
327{
Hans Verkuil85578b02012-04-27 12:30:40 -0300328 struct amradio_device *radio = video_drvdata(file);
Alexey Klimov34801302008-11-19 00:36:29 -0300329
Hans Verkuil85578b02012-04-27 12:30:40 -0300330 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
Hans Verkuila3a9e282009-11-27 04:33:25 -0300331 return -EINVAL;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300332 f->type = V4L2_TUNER_RADIO;
333 f->frequency = radio->curfreq;
David Ellingsworth4aebc282009-09-22 21:22:19 -0300334
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300335 return 0;
336}
337
Hans Verkuil85578b02012-04-27 12:30:40 -0300338static int usb_amradio_s_ctrl(struct v4l2_ctrl *ctrl)
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300339{
Hans Verkuil85578b02012-04-27 12:30:40 -0300340 struct amradio_device *radio =
341 container_of(ctrl->handler, struct amradio_device, hdl);
Alexey Klimov34801302008-11-19 00:36:29 -0300342
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300343 switch (ctrl->id) {
344 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil85578b02012-04-27 12:30:40 -0300345 return amradio_set_mute(radio,
346 ctrl->val ? AMRADIO_STOP : AMRADIO_START);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300347 }
David Ellingsworth4aebc282009-09-22 21:22:19 -0300348
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300349 return -EINVAL;
350}
351
David Ellingsworth502d5012009-09-23 18:13:50 -0300352static int usb_amradio_init(struct amradio_device *radio)
353{
354 int retval;
355
356 retval = amradio_set_mute(radio, AMRADIO_STOP);
David Ellingsworth16a72f42009-09-23 18:28:02 -0300357 if (retval)
David Ellingsworth502d5012009-09-23 18:13:50 -0300358 goto out_err;
David Ellingsworth502d5012009-09-23 18:13:50 -0300359
360 retval = amradio_set_stereo(radio, WANT_STEREO);
David Ellingsworth16a72f42009-09-23 18:28:02 -0300361 if (retval)
David Ellingsworth502d5012009-09-23 18:13:50 -0300362 goto out_err;
David Ellingsworth502d5012009-09-23 18:13:50 -0300363
David Ellingsworth502d5012009-09-23 18:13:50 -0300364 goto out;
365
366out_err:
Hans Verkuil85578b02012-04-27 12:30:40 -0300367 amradio_dev_err(&radio->vdev.dev, "initialization failed\n");
David Ellingsworth502d5012009-09-23 18:13:50 -0300368out:
369 return retval;
370}
371
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300372/* Suspend device - stop device. Need to be checked and fixed */
373static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
374{
Hans Verkuila2bdc5e2010-05-02 05:36:32 -0300375 struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300376
Hans Verkuila682d4c2010-10-17 09:26:18 -0300377 mutex_lock(&radio->lock);
Hans Verkuil85578b02012-04-27 12:30:40 -0300378 if (!radio->muted) {
David Ellingsworth16a72f42009-09-23 18:28:02 -0300379 amradio_set_mute(radio, AMRADIO_STOP);
David Ellingsworthd8970e52009-09-23 18:24:47 -0300380 radio->muted = 0;
381 }
Hans Verkuila682d4c2010-10-17 09:26:18 -0300382 mutex_unlock(&radio->lock);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300383
Alexey Klimove60b0222008-11-04 15:02:36 -0300384 dev_info(&intf->dev, "going into suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300385 return 0;
386}
387
388/* Resume device - start device. Need to be checked and fixed */
389static int usb_amradio_resume(struct usb_interface *intf)
390{
Hans Verkuila2bdc5e2010-05-02 05:36:32 -0300391 struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300392
Hans Verkuila682d4c2010-10-17 09:26:18 -0300393 mutex_lock(&radio->lock);
David Ellingsworthd8970e52009-09-23 18:24:47 -0300394 if (radio->stereo)
David Ellingsworth16a72f42009-09-23 18:28:02 -0300395 amradio_set_stereo(radio, WANT_STEREO);
David Ellingsworthd8970e52009-09-23 18:24:47 -0300396 else
David Ellingsworth16a72f42009-09-23 18:28:02 -0300397 amradio_set_stereo(radio, WANT_MONO);
David Ellingsworthd8970e52009-09-23 18:24:47 -0300398
David Ellingsworth16a72f42009-09-23 18:28:02 -0300399 amradio_setfreq(radio, radio->curfreq);
David Ellingsworthd8970e52009-09-23 18:24:47 -0300400
David Ellingsworth16a72f42009-09-23 18:28:02 -0300401 if (!radio->muted)
402 amradio_set_mute(radio, AMRADIO_START);
David Ellingsworthd8970e52009-09-23 18:24:47 -0300403
Hans Verkuila682d4c2010-10-17 09:26:18 -0300404 mutex_unlock(&radio->lock);
405
Alexey Klimove60b0222008-11-04 15:02:36 -0300406 dev_info(&intf->dev, "coming out of suspend..\n");
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300407 return 0;
408}
409
Hans Verkuil85578b02012-04-27 12:30:40 -0300410static const struct v4l2_ctrl_ops usb_amradio_ctrl_ops = {
411 .s_ctrl = usb_amradio_s_ctrl,
412};
413
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300414/* File system interface */
Hans Verkuilbec43662008-12-30 06:58:20 -0300415static const struct v4l2_file_operations usb_amradio_fops = {
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300416 .owner = THIS_MODULE,
Hans Verkuil85578b02012-04-27 12:30:40 -0300417 .open = v4l2_fh_open,
418 .release = v4l2_fh_release,
419 .poll = v4l2_ctrl_poll,
Hans Verkuil361ae542010-09-26 08:01:18 -0300420 .unlocked_ioctl = video_ioctl2,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300421};
422
423static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
424 .vidioc_querycap = vidioc_querycap,
425 .vidioc_g_tuner = vidioc_g_tuner,
426 .vidioc_s_tuner = vidioc_s_tuner,
427 .vidioc_g_frequency = vidioc_g_frequency,
428 .vidioc_s_frequency = vidioc_s_frequency,
Hans Verkuil85578b02012-04-27 12:30:40 -0300429 .vidioc_log_status = v4l2_ctrl_log_status,
430 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
431 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300432};
433
Hans Verkuil85578b02012-04-27 12:30:40 -0300434static void usb_amradio_release(struct v4l2_device *v4l2_dev)
Alexey Klimovf4e90432008-12-27 21:30:34 -0300435{
Hans Verkuil85578b02012-04-27 12:30:40 -0300436 struct amradio_device *radio = to_amradio_dev(v4l2_dev);
Alexey Klimovb4662482009-04-03 18:45:27 -0300437
Alexey Klimovf4e90432008-12-27 21:30:34 -0300438 /* free rest memory */
Hans Verkuil85578b02012-04-27 12:30:40 -0300439 v4l2_ctrl_handler_free(&radio->hdl);
440 v4l2_device_unregister(&radio->v4l2_dev);
Alexey Klimovf4e90432008-12-27 21:30:34 -0300441 kfree(radio->buffer);
442 kfree(radio);
443}
444
Alexey Klimova5d69472009-02-05 08:48:43 -0300445/* check if the device is present and register with v4l and usb if it is */
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300446static int usb_amradio_probe(struct usb_interface *intf,
447 const struct usb_device_id *id)
448{
449 struct amradio_device *radio;
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300450 int retval = 0;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300451
Alexey Klimovb4662482009-04-03 18:45:27 -0300452 radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300453
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300454 if (!radio) {
455 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300456 retval = -ENOMEM;
457 goto err;
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300458 }
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300459
460 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
461
Alexey Klimov8edafcc2009-02-05 08:51:51 -0300462 if (!radio->buffer) {
463 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300464 retval = -ENOMEM;
465 goto err_nobuf;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300466 }
467
David Ellingsworthd1939e42009-09-22 21:48:43 -0300468 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
Alexey Klimovb4662482009-04-03 18:45:27 -0300469 if (retval < 0) {
470 dev_err(&intf->dev, "couldn't register v4l2_device\n");
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300471 goto err_v4l2;
Alexey Klimovb4662482009-04-03 18:45:27 -0300472 }
473
Hans Verkuil85578b02012-04-27 12:30:40 -0300474 v4l2_ctrl_handler_init(&radio->hdl, 1);
475 v4l2_ctrl_new_std(&radio->hdl, &usb_amradio_ctrl_ops,
476 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
477 if (radio->hdl.error) {
478 retval = radio->hdl.error;
479 dev_err(&intf->dev, "couldn't register control\n");
480 goto err_ctrl;
481 }
Hans Verkuil361ae542010-09-26 08:01:18 -0300482 mutex_init(&radio->lock);
483
Hans Verkuil85578b02012-04-27 12:30:40 -0300484 radio->v4l2_dev.ctrl_handler = &radio->hdl;
485 radio->v4l2_dev.release = usb_amradio_release;
486 strlcpy(radio->vdev.name, radio->v4l2_dev.name,
487 sizeof(radio->vdev.name));
488 radio->vdev.v4l2_dev = &radio->v4l2_dev;
489 radio->vdev.fops = &usb_amradio_fops;
490 radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops;
491 radio->vdev.release = video_device_release_empty;
492 radio->vdev.lock = &radio->lock;
493 set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300494
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300495 radio->usbdev = interface_to_usbdev(intf);
Oliver Neukumd89ce0d2009-11-09 19:09:49 -0300496 radio->intf = intf;
Hans Verkuil85578b02012-04-27 12:30:40 -0300497 usb_set_intfdata(intf, &radio->v4l2_dev);
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300498 radio->curfreq = 95.16 * FREQ_MUL;
499
Hans Verkuil85578b02012-04-27 12:30:40 -0300500 video_set_drvdata(&radio->vdev, radio);
501 retval = usb_amradio_init(radio);
502 if (retval)
503 goto err_vdev;
Alexey Klimovb4662482009-04-03 18:45:27 -0300504
Hans Verkuil85578b02012-04-27 12:30:40 -0300505 retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO,
David Ellingsworth7a7d92e2009-09-22 21:37:30 -0300506 radio_nr);
Alexey Klimova5d69472009-02-05 08:48:43 -0300507 if (retval < 0) {
Alexey Klimov65c51dc2009-02-05 08:49:58 -0300508 dev_err(&intf->dev, "could not register video device\n");
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300509 goto err_vdev;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300510 }
511
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300512 return 0;
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300513
514err_vdev:
Hans Verkuil85578b02012-04-27 12:30:40 -0300515 v4l2_ctrl_handler_free(&radio->hdl);
516err_ctrl:
David Ellingsworthd1939e42009-09-22 21:48:43 -0300517 v4l2_device_unregister(&radio->v4l2_dev);
David Ellingsworth1b8bbb32009-09-22 21:43:19 -0300518err_v4l2:
519 kfree(radio->buffer);
520err_nobuf:
521 kfree(radio);
522err:
523 return retval;
Alexey Klimov2aa72f32008-10-01 09:40:59 -0300524}
525
Hans Verkuil85578b02012-04-27 12:30:40 -0300526/* USB Device ID List */
527static struct usb_device_id usb_amradio_device_table[] = {
528 { USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
529 USB_CLASS_HID, 0, 0) },
530 { } /* Terminating entry */
531};
532
533MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
534
535/* USB subsystem interface */
536static struct usb_driver usb_amradio_driver = {
537 .name = MR800_DRIVER_NAME,
538 .probe = usb_amradio_probe,
539 .disconnect = usb_amradio_disconnect,
540 .suspend = usb_amradio_suspend,
541 .resume = usb_amradio_resume,
542 .reset_resume = usb_amradio_resume,
543 .id_table = usb_amradio_device_table,
544};
545
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800546module_usb_driver(usb_amradio_driver);