aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2012-04-27 07:13:26 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-04 14:01:14 -0400
commit5d778648ed571f8dfe9e105c540661dd7451b315 (patch)
tree71fa9be28bd29427a47a06fcc8d6003d40c99ade /drivers
parenta1ac5dc28d2b4ca78e183229f7c595ffd725241c (diff)
[media] dsbr100: clean up and update to the latest v4l2 framework
This driver now complies with the v4l2-compliance tests and uses the v4l2 frameworks correctly. It has been tested with the radio-keene FM transmitter as well. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/radio/dsbr100.c527
1 files changed, 165 insertions, 362 deletions
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index bf813a63ab2a..63b112b555b2 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -1,92 +1,37 @@
1/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21. 1/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
2 The device plugs into both the USB and an analog audio input, so this thing 2 * The device plugs into both the USB and an analog audio input, so this thing
3 only deals with initialisation and frequency setting, the 3 * only deals with initialisation and frequency setting, the
4 audio data has to be handled by a sound driver. 4 * audio data has to be handled by a sound driver.
5 5 *
6 Major issue: I can't find out where the device reports the signal 6 * Major issue: I can't find out where the device reports the signal
7 strength, and indeed the windows software appearantly just looks 7 * strength, and indeed the windows software appearantly just looks
8 at the stereo indicator as well. So, scanning will only find 8 * at the stereo indicator as well. So, scanning will only find
9 stereo stations. Sad, but I can't help it. 9 * stereo stations. Sad, but I can't help it.
10 10 *
11 Also, the windows program sends oodles of messages over to the 11 * Also, the windows program sends oodles of messages over to the
12 device, and I couldn't figure out their meaning. My suspicion 12 * device, and I couldn't figure out their meaning. My suspicion
13 is that they don't have any:-) 13 * is that they don't have any:-)
14 14 *
15 You might find some interesting stuff about this module at 15 * You might find some interesting stuff about this module at
16 http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr 16 * http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
17 17 *
18 Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de> 18 * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
19 19 *
20 This program is free software; you can redistribute it and/or modify 20 * Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
21 it under the terms of the GNU General Public License as published by 21 *
22 the Free Software Foundation; either version 2 of the License, or 22 * This program is free software; you can redistribute it and/or modify
23 (at your option) any later version. 23 * it under the terms of the GNU General Public License as published by
24 24 * the Free Software Foundation; either version 2 of the License, or
25 This program is distributed in the hope that it will be useful, 25 * (at your option) any later version.
26 but WITHOUT ANY WARRANTY; without even the implied warranty of 26 *
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * This program is distributed in the hope that it will be useful,
28 GNU General Public License for more details. 28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 You should have received a copy of the GNU General Public License 30 * GNU General Public License for more details.
31 along with this program; if not, write to the Free Software 31 *
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32 * You should have received a copy of the GNU General Public License
33 33 * along with this program; if not, write to the Free Software
34 History: 34 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35
36 Version 0.46:
37 Removed usb_dsbr100_open/close calls and radio->users counter. Also,
38 radio->muted changed to radio->status and suspend/resume calls updated.
39
40 Version 0.45:
41 Converted to v4l2_device.
42
43 Version 0.44:
44 Add suspend/resume functions, fix unplug of device,
45 a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
46
47 Version 0.43:
48 Oliver Neukum: avoided DMA coherency issue
49
50 Version 0.42:
51 Converted dsbr100 to use video_ioctl2
52 by Douglas Landgraf <dougsland@gmail.com>
53
54 Version 0.41-ac1:
55 Alan Cox: Some cleanups and fixes
56
57 Version 0.41:
58 Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
59
60 Version 0.40:
61 Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
62
63 Version 0.30:
64 Markus: Updates for 2.5.x kernel and more ISO compliant source
65
66 Version 0.25:
67 PSL and Markus: Cleanup, radio now doesn't stop on device close
68
69 Version 0.24:
70 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
71 right. Some minor cleanup, improved standalone compilation
72
73 Version 0.23:
74 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
75
76 Version 0.22:
77 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
78 thanks to Mike Cox for pointing the problem out.
79
80 Version 0.21:
81 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
82 to adhere to Documentation/CodingStyle
83
84 Version 0.2:
85 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
86 Markus: Copyright clarification
87
88 Version 0.01: Markus: initial release
89
90*/ 35*/
91 36
92#include <linux/kernel.h> 37#include <linux/kernel.h>
@@ -95,17 +40,19 @@
95#include <linux/slab.h> 40#include <linux/slab.h>
96#include <linux/input.h> 41#include <linux/input.h>
97#include <linux/videodev2.h> 42#include <linux/videodev2.h>
43#include <linux/usb.h>
98#include <media/v4l2-device.h> 44#include <media/v4l2-device.h>
99#include <media/v4l2-ioctl.h> 45#include <media/v4l2-ioctl.h>
100#include <linux/usb.h> 46#include <media/v4l2-ctrls.h>
47#include <media/v4l2-event.h>
101 48
102/* 49/*
103 * Version Information 50 * Version Information
104 */ 51 */
105#define DRIVER_VERSION "0.4.7" 52MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
106 53MODULE_DESCRIPTION("D-Link DSB-R100 USB FM radio driver");
107#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" 54MODULE_LICENSE("GPL");
108#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" 55MODULE_VERSION("1.1.0");
109 56
110#define DSB100_VENDOR 0x04b4 57#define DSB100_VENDOR 0x04b4
111#define DSB100_PRODUCT 0x1002 58#define DSB100_PRODUCT 0x1002
@@ -122,19 +69,8 @@ devices, that would be 76 and 91. */
122#define FREQ_MAX 108.0 69#define FREQ_MAX 108.0
123#define FREQ_MUL 16000 70#define FREQ_MUL 16000
124 71
125/* defines for radio->status */
126#define STARTED 0
127#define STOPPED 1
128
129#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev) 72#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
130 73
131static int usb_dsbr100_probe(struct usb_interface *intf,
132 const struct usb_device_id *id);
133static void usb_dsbr100_disconnect(struct usb_interface *intf);
134static int usb_dsbr100_suspend(struct usb_interface *intf,
135 pm_message_t message);
136static int usb_dsbr100_resume(struct usb_interface *intf);
137
138static int radio_nr = -1; 74static int radio_nr = -1;
139module_param(radio_nr, int, 0); 75module_param(radio_nr, int, 0);
140 76
@@ -143,179 +79,92 @@ struct dsbr100_device {
143 struct usb_device *usbdev; 79 struct usb_device *usbdev;
144 struct video_device videodev; 80 struct video_device videodev;
145 struct v4l2_device v4l2_dev; 81 struct v4l2_device v4l2_dev;
82 struct v4l2_ctrl_handler hdl;
146 83
147 u8 *transfer_buffer; 84 u8 *transfer_buffer;
148 struct mutex v4l2_lock; 85 struct mutex v4l2_lock;
149 int curfreq; 86 int curfreq;
150 int stereo; 87 bool stereo;
151 int status; 88 bool muted;
152};
153
154static struct usb_device_id usb_dsbr100_device_table [] = {
155 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
156 { } /* Terminating entry */
157};
158
159MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
160
161/* USB subsystem interface */
162static struct usb_driver usb_dsbr100_driver = {
163 .name = "dsbr100",
164 .probe = usb_dsbr100_probe,
165 .disconnect = usb_dsbr100_disconnect,
166 .id_table = usb_dsbr100_device_table,
167 .suspend = usb_dsbr100_suspend,
168 .resume = usb_dsbr100_resume,
169 .reset_resume = usb_dsbr100_resume,
170 .supports_autosuspend = 0,
171}; 89};
172 90
173/* Low-level device interface begins here */ 91/* Low-level device interface begins here */
174 92
175/* switch on radio */ 93/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
176static int dsbr100_start(struct dsbr100_device *radio) 94static int dsbr100_setfreq(struct dsbr100_device *radio, unsigned freq)
177{ 95{
178 int retval; 96 unsigned f = (freq / 16 * 80) / 1000 + 856;
179 int request; 97 int retval = 0;
180 98
181 retval = usb_control_msg(radio->usbdev, 99 if (!radio->muted) {
182 usb_rcvctrlpipe(radio->usbdev, 0), 100 retval = usb_control_msg(radio->usbdev,
183 USB_REQ_GET_STATUS, 101 usb_rcvctrlpipe(radio->usbdev, 0),
184 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 102 DSB100_TUNE,
185 0x00, 0xC7, radio->transfer_buffer, 8, 300); 103 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
186 104 (f >> 8) & 0x00ff, f & 0xff,
187 if (retval < 0) { 105 radio->transfer_buffer, 8, 300);
188 request = USB_REQ_GET_STATUS; 106 if (retval >= 0)
189 goto usb_control_msg_failed; 107 mdelay(1);
190 } 108 }
191 109
192 retval = usb_control_msg(radio->usbdev, 110 if (retval >= 0) {
193 usb_rcvctrlpipe(radio->usbdev, 0), 111 radio->curfreq = freq;
194 DSB100_ONOFF, 112 return 0;
195 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
196 0x01, 0x00, radio->transfer_buffer, 8, 300);
197
198 if (retval < 0) {
199 request = DSB100_ONOFF;
200 goto usb_control_msg_failed;
201 } 113 }
202
203 radio->status = STARTED;
204 return (radio->transfer_buffer)[0];
205
206usb_control_msg_failed:
207 dev_err(&radio->usbdev->dev, 114 dev_err(&radio->usbdev->dev,
208 "%s - usb_control_msg returned %i, request %i\n", 115 "%s - usb_control_msg returned %i, request %i\n",
209 __func__, retval, request); 116 __func__, retval, DSB100_TUNE);
210 return retval; 117 return retval;
211
212} 118}
213 119
214/* switch off radio */ 120/* switch on radio */
215static int dsbr100_stop(struct dsbr100_device *radio) 121static int dsbr100_start(struct dsbr100_device *radio)
216{ 122{
217 int retval; 123 int retval = usb_control_msg(radio->usbdev,
218 int request;
219
220 retval = usb_control_msg(radio->usbdev,
221 usb_rcvctrlpipe(radio->usbdev, 0),
222 USB_REQ_GET_STATUS,
223 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
224 0x16, 0x1C, radio->transfer_buffer, 8, 300);
225
226 if (retval < 0) {
227 request = USB_REQ_GET_STATUS;
228 goto usb_control_msg_failed;
229 }
230
231 retval = usb_control_msg(radio->usbdev,
232 usb_rcvctrlpipe(radio->usbdev, 0), 124 usb_rcvctrlpipe(radio->usbdev, 0),
233 DSB100_ONOFF, 125 DSB100_ONOFF,
234 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 126 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
235 0x00, 0x00, radio->transfer_buffer, 8, 300); 127 0x01, 0x00, radio->transfer_buffer, 8, 300);
236
237 if (retval < 0) {
238 request = DSB100_ONOFF;
239 goto usb_control_msg_failed;
240 }
241
242 radio->status = STOPPED;
243 return (radio->transfer_buffer)[0];
244 128
245usb_control_msg_failed: 129 if (retval >= 0)
130 return dsbr100_setfreq(radio, radio->curfreq);
246 dev_err(&radio->usbdev->dev, 131 dev_err(&radio->usbdev->dev,
247 "%s - usb_control_msg returned %i, request %i\n", 132 "%s - usb_control_msg returned %i, request %i\n",
248 __func__, retval, request); 133 __func__, retval, DSB100_ONOFF);
249 return retval; 134 return retval;
250 135
251} 136}
252 137
253/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 138/* switch off radio */
254static int dsbr100_setfreq(struct dsbr100_device *radio) 139static int dsbr100_stop(struct dsbr100_device *radio)
255{ 140{
256 int retval; 141 int retval = usb_control_msg(radio->usbdev,
257 int request;
258 int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
259
260 retval = usb_control_msg(radio->usbdev,
261 usb_rcvctrlpipe(radio->usbdev, 0),
262 DSB100_TUNE,
263 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
264 (freq >> 8) & 0x00ff, freq & 0xff,
265 radio->transfer_buffer, 8, 300);
266
267 if (retval < 0) {
268 request = DSB100_TUNE;
269 goto usb_control_msg_failed;
270 }
271
272 retval = usb_control_msg(radio->usbdev,
273 usb_rcvctrlpipe(radio->usbdev, 0), 142 usb_rcvctrlpipe(radio->usbdev, 0),
274 USB_REQ_GET_STATUS, 143 DSB100_ONOFF,
275 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 144 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
276 0x96, 0xB7, radio->transfer_buffer, 8, 300); 145 0x00, 0x00, radio->transfer_buffer, 8, 300);
277
278 if (retval < 0) {
279 request = USB_REQ_GET_STATUS;
280 goto usb_control_msg_failed;
281 }
282
283 retval = usb_control_msg(radio->usbdev,
284 usb_rcvctrlpipe(radio->usbdev, 0),
285 USB_REQ_GET_STATUS,
286 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
287 0x00, 0x24, radio->transfer_buffer, 8, 300);
288
289 if (retval < 0) {
290 request = USB_REQ_GET_STATUS;
291 goto usb_control_msg_failed;
292 }
293
294 radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
295 return (radio->transfer_buffer)[0];
296 146
297usb_control_msg_failed: 147 if (retval >= 0)
298 radio->stereo = -1; 148 return 0;
299 dev_err(&radio->usbdev->dev, 149 dev_err(&radio->usbdev->dev,
300 "%s - usb_control_msg returned %i, request %i\n", 150 "%s - usb_control_msg returned %i, request %i\n",
301 __func__, retval, request); 151 __func__, retval, DSB100_ONOFF);
302 return retval; 152 return retval;
153
303} 154}
304 155
305/* return the device status. This is, in effect, just whether it 156/* return the device status. This is, in effect, just whether it
306sees a stereo signal or not. Pity. */ 157sees a stereo signal or not. Pity. */
307static void dsbr100_getstat(struct dsbr100_device *radio) 158static void dsbr100_getstat(struct dsbr100_device *radio)
308{ 159{
309 int retval; 160 int retval = usb_control_msg(radio->usbdev,
310
311 retval = usb_control_msg(radio->usbdev,
312 usb_rcvctrlpipe(radio->usbdev, 0), 161 usb_rcvctrlpipe(radio->usbdev, 0),
313 USB_REQ_GET_STATUS, 162 USB_REQ_GET_STATUS,
314 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 163 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
315 0x00 , 0x24, radio->transfer_buffer, 8, 300); 164 0x00, 0x24, radio->transfer_buffer, 8, 300);
316 165
317 if (retval < 0) { 166 if (retval < 0) {
318 radio->stereo = -1; 167 radio->stereo = false;
319 dev_err(&radio->usbdev->dev, 168 dev_err(&radio->usbdev->dev,
320 "%s - usb_control_msg returned %i, request %i\n", 169 "%s - usb_control_msg returned %i, request %i\n",
321 __func__, retval, USB_REQ_GET_STATUS); 170 __func__, retval, USB_REQ_GET_STATUS);
@@ -332,7 +181,8 @@ static int vidioc_querycap(struct file *file, void *priv,
332 strlcpy(v->driver, "dsbr100", sizeof(v->driver)); 181 strlcpy(v->driver, "dsbr100", sizeof(v->driver));
333 strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); 182 strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
334 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); 183 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
335 v->capabilities = V4L2_CAP_TUNER; 184 v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
185 v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
336 return 0; 186 return 0;
337} 187}
338 188
@@ -349,13 +199,11 @@ static int vidioc_g_tuner(struct file *file, void *priv,
349 v->type = V4L2_TUNER_RADIO; 199 v->type = V4L2_TUNER_RADIO;
350 v->rangelow = FREQ_MIN * FREQ_MUL; 200 v->rangelow = FREQ_MIN * FREQ_MUL;
351 v->rangehigh = FREQ_MAX * FREQ_MUL; 201 v->rangehigh = FREQ_MAX * FREQ_MUL;
352 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 202 v->rxsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO :
353 v->capability = V4L2_TUNER_CAP_LOW; 203 V4L2_TUNER_SUB_MONO;
354 if(radio->stereo) 204 v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
355 v->audmode = V4L2_TUNER_MODE_STEREO; 205 v->audmode = V4L2_TUNER_MODE_STEREO;
356 else 206 v->signal = radio->stereo ? 0xffff : 0; /* We can't get the signal strength */
357 v->audmode = V4L2_TUNER_MODE_MONO;
358 v->signal = 0xffff; /* We can't get the signal strength */
359 return 0; 207 return 0;
360} 208}
361 209
@@ -369,14 +217,12 @@ static int vidioc_s_frequency(struct file *file, void *priv,
369 struct v4l2_frequency *f) 217 struct v4l2_frequency *f)
370{ 218{
371 struct dsbr100_device *radio = video_drvdata(file); 219 struct dsbr100_device *radio = video_drvdata(file);
372 int retval;
373 220
374 radio->curfreq = f->frequency; 221 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
222 return -EINVAL;
375 223
376 retval = dsbr100_setfreq(radio); 224 return dsbr100_setfreq(radio, clamp_t(unsigned, f->frequency,
377 if (retval < 0) 225 FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
378 dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
379 return 0;
380} 226}
381 227
382static int vidioc_g_frequency(struct file *file, void *priv, 228static int vidioc_g_frequency(struct file *file, void *priv,
@@ -384,90 +230,26 @@ static int vidioc_g_frequency(struct file *file, void *priv,
384{ 230{
385 struct dsbr100_device *radio = video_drvdata(file); 231 struct dsbr100_device *radio = video_drvdata(file);
386 232
233 if (f->tuner)
234 return -EINVAL;
387 f->type = V4L2_TUNER_RADIO; 235 f->type = V4L2_TUNER_RADIO;
388 f->frequency = radio->curfreq; 236 f->frequency = radio->curfreq;
389 return 0; 237 return 0;
390} 238}
391 239
392static int vidioc_queryctrl(struct file *file, void *priv, 240static int usb_dsbr100_s_ctrl(struct v4l2_ctrl *ctrl)
393 struct v4l2_queryctrl *qc)
394{
395 switch (qc->id) {
396 case V4L2_CID_AUDIO_MUTE:
397 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
398 }
399
400 return -EINVAL;
401}
402
403static int vidioc_g_ctrl(struct file *file, void *priv,
404 struct v4l2_control *ctrl)
405{ 241{
406 struct dsbr100_device *radio = video_drvdata(file); 242 struct dsbr100_device *radio =
243 container_of(ctrl->handler, struct dsbr100_device, hdl);
407 244
408 switch (ctrl->id) { 245 switch (ctrl->id) {
409 case V4L2_CID_AUDIO_MUTE: 246 case V4L2_CID_AUDIO_MUTE:
410 ctrl->value = radio->status; 247 radio->muted = ctrl->val;
411 return 0; 248 return radio->muted ? dsbr100_stop(radio) : dsbr100_start(radio);
412 } 249 }
413 return -EINVAL; 250 return -EINVAL;
414} 251}
415 252
416static int vidioc_s_ctrl(struct file *file, void *priv,
417 struct v4l2_control *ctrl)
418{
419 struct dsbr100_device *radio = video_drvdata(file);
420 int retval;
421
422 switch (ctrl->id) {
423 case V4L2_CID_AUDIO_MUTE:
424 if (ctrl->value) {
425 retval = dsbr100_stop(radio);
426 if (retval < 0) {
427 dev_warn(&radio->usbdev->dev,
428 "Radio did not respond properly\n");
429 return -EBUSY;
430 }
431 } else {
432 retval = dsbr100_start(radio);
433 if (retval < 0) {
434 dev_warn(&radio->usbdev->dev,
435 "Radio did not respond properly\n");
436 return -EBUSY;
437 }
438 }
439 return 0;
440 }
441 return -EINVAL;
442}
443
444static int vidioc_g_audio(struct file *file, void *priv,
445 struct v4l2_audio *a)
446{
447 if (a->index > 1)
448 return -EINVAL;
449
450 strcpy(a->name, "Radio");
451 a->capability = V4L2_AUDCAP_STEREO;
452 return 0;
453}
454
455static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
456{
457 *i = 0;
458 return 0;
459}
460
461static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
462{
463 return i ? -EINVAL : 0;
464}
465
466static int vidioc_s_audio(struct file *file, void *priv,
467 struct v4l2_audio *a)
468{
469 return a->index ? -EINVAL : 0;
470}
471 253
472/* USB subsystem interface begins here */ 254/* USB subsystem interface begins here */
473 255
@@ -482,6 +264,16 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
482 struct dsbr100_device *radio = usb_get_intfdata(intf); 264 struct dsbr100_device *radio = usb_get_intfdata(intf);
483 265
484 mutex_lock(&radio->v4l2_lock); 266 mutex_lock(&radio->v4l2_lock);
267 /*
268 * Disconnect is also called on unload, and in that case we need to
269 * mute the device. This call will silently fail if it is called
270 * after a physical disconnect.
271 */
272 usb_control_msg(radio->usbdev,
273 usb_rcvctrlpipe(radio->usbdev, 0),
274 DSB100_ONOFF,
275 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
276 0x00, 0x00, radio->transfer_buffer, 8, 300);
485 usb_set_intfdata(intf, NULL); 277 usb_set_intfdata(intf, NULL);
486 video_unregister_device(&radio->videodev); 278 video_unregister_device(&radio->videodev);
487 v4l2_device_disconnect(&radio->v4l2_dev); 279 v4l2_device_disconnect(&radio->v4l2_dev);
@@ -494,25 +286,13 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
494static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) 286static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
495{ 287{
496 struct dsbr100_device *radio = usb_get_intfdata(intf); 288 struct dsbr100_device *radio = usb_get_intfdata(intf);
497 int retval;
498 289
499 mutex_lock(&radio->v4l2_lock); 290 mutex_lock(&radio->v4l2_lock);
500 if (radio->status == STARTED) { 291 if (!radio->muted && dsbr100_stop(radio) < 0)
501 retval = dsbr100_stop(radio); 292 dev_warn(&intf->dev, "dsbr100_stop failed\n");
502 if (retval < 0)
503 dev_warn(&intf->dev, "dsbr100_stop failed\n");
504
505 /* After dsbr100_stop() status set to STOPPED.
506 * If we want driver to start radio on resume
507 * we set status equal to STARTED.
508 * On resume we will check status and run radio if needed.
509 */
510 radio->status = STARTED;
511 }
512 mutex_unlock(&radio->v4l2_lock); 293 mutex_unlock(&radio->v4l2_lock);
513 294
514 dev_info(&intf->dev, "going into suspend..\n"); 295 dev_info(&intf->dev, "going into suspend..\n");
515
516 return 0; 296 return 0;
517} 297}
518 298
@@ -520,18 +300,13 @@ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
520static int usb_dsbr100_resume(struct usb_interface *intf) 300static int usb_dsbr100_resume(struct usb_interface *intf)
521{ 301{
522 struct dsbr100_device *radio = usb_get_intfdata(intf); 302 struct dsbr100_device *radio = usb_get_intfdata(intf);
523 int retval;
524 303
525 mutex_lock(&radio->v4l2_lock); 304 mutex_lock(&radio->v4l2_lock);
526 if (radio->status == STARTED) { 305 if (!radio->muted && dsbr100_start(radio) < 0)
527 retval = dsbr100_start(radio); 306 dev_warn(&intf->dev, "dsbr100_start failed\n");
528 if (retval < 0)
529 dev_warn(&intf->dev, "dsbr100_start failed\n");
530 }
531 mutex_unlock(&radio->v4l2_lock); 307 mutex_unlock(&radio->v4l2_lock);
532 308
533 dev_info(&intf->dev, "coming out of suspend..\n"); 309 dev_info(&intf->dev, "coming out of suspend..\n");
534
535 return 0; 310 return 0;
536} 311}
537 312
@@ -540,15 +315,23 @@ static void usb_dsbr100_release(struct v4l2_device *v4l2_dev)
540{ 315{
541 struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev); 316 struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
542 317
318 v4l2_ctrl_handler_free(&radio->hdl);
543 v4l2_device_unregister(&radio->v4l2_dev); 319 v4l2_device_unregister(&radio->v4l2_dev);
544 kfree(radio->transfer_buffer); 320 kfree(radio->transfer_buffer);
545 kfree(radio); 321 kfree(radio);
546} 322}
547 323
324static const struct v4l2_ctrl_ops usb_dsbr100_ctrl_ops = {
325 .s_ctrl = usb_dsbr100_s_ctrl,
326};
327
548/* File system interface */ 328/* File system interface */
549static const struct v4l2_file_operations usb_dsbr100_fops = { 329static const struct v4l2_file_operations usb_dsbr100_fops = {
550 .owner = THIS_MODULE, 330 .owner = THIS_MODULE,
551 .unlocked_ioctl = video_ioctl2, 331 .unlocked_ioctl = video_ioctl2,
332 .open = v4l2_fh_open,
333 .release = v4l2_fh_release,
334 .poll = v4l2_ctrl_poll,
552}; 335};
553 336
554static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { 337static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
@@ -557,13 +340,9 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
557 .vidioc_s_tuner = vidioc_s_tuner, 340 .vidioc_s_tuner = vidioc_s_tuner,
558 .vidioc_g_frequency = vidioc_g_frequency, 341 .vidioc_g_frequency = vidioc_g_frequency,
559 .vidioc_s_frequency = vidioc_s_frequency, 342 .vidioc_s_frequency = vidioc_s_frequency,
560 .vidioc_queryctrl = vidioc_queryctrl, 343 .vidioc_log_status = v4l2_ctrl_log_status,
561 .vidioc_g_ctrl = vidioc_g_ctrl, 344 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
562 .vidioc_s_ctrl = vidioc_s_ctrl, 345 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
563 .vidioc_g_audio = vidioc_g_audio,
564 .vidioc_s_audio = vidioc_s_audio,
565 .vidioc_g_input = vidioc_g_input,
566 .vidioc_s_input = vidioc_s_input,
567}; 346};
568 347
569/* check if the device is present and register with v4l and usb if it is */ 348/* check if the device is present and register with v4l and usb if it is */
@@ -592,11 +371,17 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
592 retval = v4l2_device_register(&intf->dev, v4l2_dev); 371 retval = v4l2_device_register(&intf->dev, v4l2_dev);
593 if (retval < 0) { 372 if (retval < 0) {
594 v4l2_err(v4l2_dev, "couldn't register v4l2_device\n"); 373 v4l2_err(v4l2_dev, "couldn't register v4l2_device\n");
595 kfree(radio->transfer_buffer); 374 goto err_reg_dev;
596 kfree(radio);
597 return retval;
598 } 375 }
599 376
377 v4l2_ctrl_handler_init(&radio->hdl, 1);
378 v4l2_ctrl_new_std(&radio->hdl, &usb_dsbr100_ctrl_ops,
379 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
380 if (radio->hdl.error) {
381 retval = radio->hdl.error;
382 v4l2_err(v4l2_dev, "couldn't register control\n");
383 goto err_reg_ctrl;
384 }
600 mutex_init(&radio->v4l2_lock); 385 mutex_init(&radio->v4l2_lock);
601 strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name)); 386 strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
602 radio->videodev.v4l2_dev = v4l2_dev; 387 radio->videodev.v4l2_dev = v4l2_dev;
@@ -604,28 +389,46 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
604 radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; 389 radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
605 radio->videodev.release = video_device_release_empty; 390 radio->videodev.release = video_device_release_empty;
606 radio->videodev.lock = &radio->v4l2_lock; 391 radio->videodev.lock = &radio->v4l2_lock;
392 radio->videodev.ctrl_handler = &radio->hdl;
393 set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
607 394
608 radio->usbdev = interface_to_usbdev(intf); 395 radio->usbdev = interface_to_usbdev(intf);
609 radio->curfreq = FREQ_MIN * FREQ_MUL; 396 radio->curfreq = FREQ_MIN * FREQ_MUL;
610 radio->status = STOPPED; 397 radio->muted = true;
611 398
612 video_set_drvdata(&radio->videodev, radio); 399 video_set_drvdata(&radio->videodev, radio);
400 usb_set_intfdata(intf, radio);
613 401
614 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); 402 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
615 if (retval < 0) { 403 if (retval == 0)
616 v4l2_err(v4l2_dev, "couldn't register video device\n"); 404 return 0;
617 v4l2_device_unregister(v4l2_dev); 405 v4l2_err(v4l2_dev, "couldn't register video device\n");
618 kfree(radio->transfer_buffer); 406
619 kfree(radio); 407err_reg_ctrl:
620 return -EIO; 408 v4l2_ctrl_handler_free(&radio->hdl);
621 } 409 v4l2_device_unregister(v4l2_dev);
622 usb_set_intfdata(intf, radio); 410err_reg_dev:
623 return 0; 411 kfree(radio->transfer_buffer);
412 kfree(radio);
413 return retval;
624} 414}
625 415
626module_usb_driver(usb_dsbr100_driver); 416static struct usb_device_id usb_dsbr100_device_table[] = {
417 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
418 { } /* Terminating entry */
419};
627 420
628MODULE_AUTHOR( DRIVER_AUTHOR ); 421MODULE_DEVICE_TABLE(usb, usb_dsbr100_device_table);
629MODULE_DESCRIPTION( DRIVER_DESC ); 422
630MODULE_LICENSE("GPL"); 423/* USB subsystem interface */
631MODULE_VERSION(DRIVER_VERSION); 424static struct usb_driver usb_dsbr100_driver = {
425 .name = "dsbr100",
426 .probe = usb_dsbr100_probe,
427 .disconnect = usb_dsbr100_disconnect,
428 .id_table = usb_dsbr100_device_table,
429 .suspend = usb_dsbr100_suspend,
430 .resume = usb_dsbr100_resume,
431 .reset_resume = usb_dsbr100_resume,
432};
433
434module_usb_driver(usb_dsbr100_driver);