Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
5d778648 a1ac5dc2

+166 -363
+166 -363
drivers/media/radio/dsbr100.c
··· 1 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 3 - only deals with initialisation and frequency setting, the 4 - audio data has to be handled by a sound driver. 5 - 6 - Major issue: I can't find out where the device reports the signal 7 - strength, and indeed the windows software appearantly just looks 8 - at the stereo indicator as well. So, scanning will only find 9 - stereo stations. Sad, but I can't help it. 10 - 11 - Also, the windows program sends oodles of messages over to the 12 - device, and I couldn't figure out their meaning. My suspicion 13 - is that they don't have any:-) 14 - 15 - You might find some interesting stuff about this module at 16 - http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr 17 - 18 - Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de> 19 - 20 - This program is free software; you can redistribute it and/or modify 21 - it under the terms of the GNU General Public License as published by 22 - the Free Software Foundation; either version 2 of the License, or 23 - (at your option) any later version. 24 - 25 - This program is distributed in the hope that it will be useful, 26 - but WITHOUT ANY WARRANTY; without even the implied warranty of 27 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 - GNU General Public License for more details. 29 - 30 - You should have received a copy of the GNU General Public License 31 - along with this program; if not, write to the Free Software 32 - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33 - 34 - History: 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 - 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 4 + * audio data has to be handled by a sound driver. 5 + * 6 + * Major issue: I can't find out where the device reports the signal 7 + * strength, and indeed the windows software appearantly just looks 8 + * at the stereo indicator as well. So, scanning will only find 9 + * stereo stations. Sad, but I can't help it. 10 + * 11 + * Also, the windows program sends oodles of messages over to the 12 + * device, and I couldn't figure out their meaning. My suspicion 13 + * is that they don't have any:-) 14 + * 15 + * You might find some interesting stuff about this module at 16 + * http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr 17 + * 18 + * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. 19 + * 20 + * Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de> 21 + * 22 + * This program is free software; you can redistribute it and/or modify 23 + * it under the terms of the GNU General Public License as published by 24 + * the Free Software Foundation; either version 2 of the License, or 25 + * (at your option) any later version. 26 + * 27 + * This program is distributed in the hope that it will be useful, 28 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 29 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 + * GNU General Public License for more details. 31 + * 32 + * You should have received a copy of the GNU General Public License 33 + * along with this program; if not, write to the Free Software 34 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 90 35 */ 91 36 92 37 #include <linux/kernel.h> ··· 40 95 #include <linux/slab.h> 41 96 #include <linux/input.h> 42 97 #include <linux/videodev2.h> 98 + #include <linux/usb.h> 43 99 #include <media/v4l2-device.h> 44 100 #include <media/v4l2-ioctl.h> 45 - #include <linux/usb.h> 101 + #include <media/v4l2-ctrls.h> 102 + #include <media/v4l2-event.h> 46 103 47 104 /* 48 105 * Version Information 49 106 */ 50 - #define DRIVER_VERSION "0.4.7" 51 - 52 - #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" 53 - #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" 107 + MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>"); 108 + MODULE_DESCRIPTION("D-Link DSB-R100 USB FM radio driver"); 109 + MODULE_LICENSE("GPL"); 110 + MODULE_VERSION("1.1.0"); 54 111 55 112 #define DSB100_VENDOR 0x04b4 56 113 #define DSB100_PRODUCT 0x1002 ··· 69 122 #define FREQ_MAX 108.0 70 123 #define FREQ_MUL 16000 71 124 72 - /* defines for radio->status */ 73 - #define STARTED 0 74 - #define STOPPED 1 75 - 76 125 #define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev) 77 - 78 - static int usb_dsbr100_probe(struct usb_interface *intf, 79 - const struct usb_device_id *id); 80 - static void usb_dsbr100_disconnect(struct usb_interface *intf); 81 - static int usb_dsbr100_suspend(struct usb_interface *intf, 82 - pm_message_t message); 83 - static int usb_dsbr100_resume(struct usb_interface *intf); 84 126 85 127 static int radio_nr = -1; 86 128 module_param(radio_nr, int, 0); ··· 79 143 struct usb_device *usbdev; 80 144 struct video_device videodev; 81 145 struct v4l2_device v4l2_dev; 146 + struct v4l2_ctrl_handler hdl; 82 147 83 148 u8 *transfer_buffer; 84 149 struct mutex v4l2_lock; 85 150 int curfreq; 86 - int stereo; 87 - int status; 88 - }; 89 - 90 - static struct usb_device_id usb_dsbr100_device_table [] = { 91 - { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, 92 - { } /* Terminating entry */ 93 - }; 94 - 95 - MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); 96 - 97 - /* USB subsystem interface */ 98 - static struct usb_driver usb_dsbr100_driver = { 99 - .name = "dsbr100", 100 - .probe = usb_dsbr100_probe, 101 - .disconnect = usb_dsbr100_disconnect, 102 - .id_table = usb_dsbr100_device_table, 103 - .suspend = usb_dsbr100_suspend, 104 - .resume = usb_dsbr100_resume, 105 - .reset_resume = usb_dsbr100_resume, 106 - .supports_autosuspend = 0, 151 + bool stereo; 152 + bool muted; 107 153 }; 108 154 109 155 /* Low-level device interface begins here */ 110 156 157 + /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 158 + static int dsbr100_setfreq(struct dsbr100_device *radio, unsigned freq) 159 + { 160 + unsigned f = (freq / 16 * 80) / 1000 + 856; 161 + int retval = 0; 162 + 163 + if (!radio->muted) { 164 + retval = usb_control_msg(radio->usbdev, 165 + usb_rcvctrlpipe(radio->usbdev, 0), 166 + DSB100_TUNE, 167 + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 168 + (f >> 8) & 0x00ff, f & 0xff, 169 + radio->transfer_buffer, 8, 300); 170 + if (retval >= 0) 171 + mdelay(1); 172 + } 173 + 174 + if (retval >= 0) { 175 + radio->curfreq = freq; 176 + return 0; 177 + } 178 + dev_err(&radio->usbdev->dev, 179 + "%s - usb_control_msg returned %i, request %i\n", 180 + __func__, retval, DSB100_TUNE); 181 + return retval; 182 + } 183 + 111 184 /* switch on radio */ 112 185 static int dsbr100_start(struct dsbr100_device *radio) 113 186 { 114 - int retval; 115 - int request; 116 - 117 - retval = usb_control_msg(radio->usbdev, 118 - usb_rcvctrlpipe(radio->usbdev, 0), 119 - USB_REQ_GET_STATUS, 120 - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 121 - 0x00, 0xC7, radio->transfer_buffer, 8, 300); 122 - 123 - if (retval < 0) { 124 - request = USB_REQ_GET_STATUS; 125 - goto usb_control_msg_failed; 126 - } 127 - 128 - retval = usb_control_msg(radio->usbdev, 187 + int retval = usb_control_msg(radio->usbdev, 129 188 usb_rcvctrlpipe(radio->usbdev, 0), 130 189 DSB100_ONOFF, 131 190 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 132 191 0x01, 0x00, radio->transfer_buffer, 8, 300); 133 192 134 - if (retval < 0) { 135 - request = DSB100_ONOFF; 136 - goto usb_control_msg_failed; 137 - } 138 - 139 - radio->status = STARTED; 140 - return (radio->transfer_buffer)[0]; 141 - 142 - usb_control_msg_failed: 193 + if (retval >= 0) 194 + return dsbr100_setfreq(radio, radio->curfreq); 143 195 dev_err(&radio->usbdev->dev, 144 196 "%s - usb_control_msg returned %i, request %i\n", 145 - __func__, retval, request); 197 + __func__, retval, DSB100_ONOFF); 146 198 return retval; 147 199 148 200 } ··· 138 214 /* switch off radio */ 139 215 static int dsbr100_stop(struct dsbr100_device *radio) 140 216 { 141 - int retval; 142 - int request; 143 - 144 - retval = usb_control_msg(radio->usbdev, 145 - usb_rcvctrlpipe(radio->usbdev, 0), 146 - USB_REQ_GET_STATUS, 147 - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 148 - 0x16, 0x1C, radio->transfer_buffer, 8, 300); 149 - 150 - if (retval < 0) { 151 - request = USB_REQ_GET_STATUS; 152 - goto usb_control_msg_failed; 153 - } 154 - 155 - retval = usb_control_msg(radio->usbdev, 217 + int retval = usb_control_msg(radio->usbdev, 156 218 usb_rcvctrlpipe(radio->usbdev, 0), 157 219 DSB100_ONOFF, 158 220 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 159 221 0x00, 0x00, radio->transfer_buffer, 8, 300); 160 222 161 - if (retval < 0) { 162 - request = DSB100_ONOFF; 163 - goto usb_control_msg_failed; 164 - } 165 - 166 - radio->status = STOPPED; 167 - return (radio->transfer_buffer)[0]; 168 - 169 - usb_control_msg_failed: 223 + if (retval >= 0) 224 + return 0; 170 225 dev_err(&radio->usbdev->dev, 171 226 "%s - usb_control_msg returned %i, request %i\n", 172 - __func__, retval, request); 227 + __func__, retval, DSB100_ONOFF); 173 228 return retval; 174 229 175 - } 176 - 177 - /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 178 - static int dsbr100_setfreq(struct dsbr100_device *radio) 179 - { 180 - int retval; 181 - int request; 182 - int freq = (radio->curfreq / 16 * 80) / 1000 + 856; 183 - 184 - retval = usb_control_msg(radio->usbdev, 185 - usb_rcvctrlpipe(radio->usbdev, 0), 186 - DSB100_TUNE, 187 - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 188 - (freq >> 8) & 0x00ff, freq & 0xff, 189 - radio->transfer_buffer, 8, 300); 190 - 191 - if (retval < 0) { 192 - request = DSB100_TUNE; 193 - goto usb_control_msg_failed; 194 - } 195 - 196 - retval = usb_control_msg(radio->usbdev, 197 - usb_rcvctrlpipe(radio->usbdev, 0), 198 - USB_REQ_GET_STATUS, 199 - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 200 - 0x96, 0xB7, radio->transfer_buffer, 8, 300); 201 - 202 - if (retval < 0) { 203 - request = USB_REQ_GET_STATUS; 204 - goto usb_control_msg_failed; 205 - } 206 - 207 - retval = usb_control_msg(radio->usbdev, 208 - usb_rcvctrlpipe(radio->usbdev, 0), 209 - USB_REQ_GET_STATUS, 210 - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 211 - 0x00, 0x24, radio->transfer_buffer, 8, 300); 212 - 213 - if (retval < 0) { 214 - request = USB_REQ_GET_STATUS; 215 - goto usb_control_msg_failed; 216 - } 217 - 218 - radio->stereo = !((radio->transfer_buffer)[0] & 0x01); 219 - return (radio->transfer_buffer)[0]; 220 - 221 - usb_control_msg_failed: 222 - radio->stereo = -1; 223 - dev_err(&radio->usbdev->dev, 224 - "%s - usb_control_msg returned %i, request %i\n", 225 - __func__, retval, request); 226 - return retval; 227 230 } 228 231 229 232 /* return the device status. This is, in effect, just whether it 230 233 sees a stereo signal or not. Pity. */ 231 234 static void dsbr100_getstat(struct dsbr100_device *radio) 232 235 { 233 - int retval; 234 - 235 - retval = usb_control_msg(radio->usbdev, 236 + int retval = usb_control_msg(radio->usbdev, 236 237 usb_rcvctrlpipe(radio->usbdev, 0), 237 238 USB_REQ_GET_STATUS, 238 239 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 239 - 0x00 , 0x24, radio->transfer_buffer, 8, 300); 240 + 0x00, 0x24, radio->transfer_buffer, 8, 300); 240 241 241 242 if (retval < 0) { 242 - radio->stereo = -1; 243 + radio->stereo = false; 243 244 dev_err(&radio->usbdev->dev, 244 245 "%s - usb_control_msg returned %i, request %i\n", 245 246 __func__, retval, USB_REQ_GET_STATUS); ··· 181 332 strlcpy(v->driver, "dsbr100", sizeof(v->driver)); 182 333 strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); 183 334 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); 184 - v->capabilities = V4L2_CAP_TUNER; 335 + v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; 336 + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; 185 337 return 0; 186 338 } 187 339 ··· 199 349 v->type = V4L2_TUNER_RADIO; 200 350 v->rangelow = FREQ_MIN * FREQ_MUL; 201 351 v->rangehigh = FREQ_MAX * FREQ_MUL; 202 - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 203 - v->capability = V4L2_TUNER_CAP_LOW; 204 - if(radio->stereo) 205 - v->audmode = V4L2_TUNER_MODE_STEREO; 206 - else 207 - v->audmode = V4L2_TUNER_MODE_MONO; 208 - v->signal = 0xffff; /* We can't get the signal strength */ 352 + v->rxsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : 353 + V4L2_TUNER_SUB_MONO; 354 + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; 355 + v->audmode = V4L2_TUNER_MODE_STEREO; 356 + v->signal = radio->stereo ? 0xffff : 0; /* We can't get the signal strength */ 209 357 return 0; 210 358 } 211 359 ··· 217 369 struct v4l2_frequency *f) 218 370 { 219 371 struct dsbr100_device *radio = video_drvdata(file); 220 - int retval; 221 372 222 - radio->curfreq = f->frequency; 373 + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) 374 + return -EINVAL; 223 375 224 - retval = dsbr100_setfreq(radio); 225 - if (retval < 0) 226 - dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); 227 - return 0; 376 + return dsbr100_setfreq(radio, clamp_t(unsigned, f->frequency, 377 + FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL)); 228 378 } 229 379 230 380 static int vidioc_g_frequency(struct file *file, void *priv, ··· 230 384 { 231 385 struct dsbr100_device *radio = video_drvdata(file); 232 386 387 + if (f->tuner) 388 + return -EINVAL; 233 389 f->type = V4L2_TUNER_RADIO; 234 390 f->frequency = radio->curfreq; 235 391 return 0; 236 392 } 237 393 238 - static int vidioc_queryctrl(struct file *file, void *priv, 239 - struct v4l2_queryctrl *qc) 394 + static int usb_dsbr100_s_ctrl(struct v4l2_ctrl *ctrl) 240 395 { 241 - switch (qc->id) { 242 - case V4L2_CID_AUDIO_MUTE: 243 - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); 244 - } 245 - 246 - return -EINVAL; 247 - } 248 - 249 - static int vidioc_g_ctrl(struct file *file, void *priv, 250 - struct v4l2_control *ctrl) 251 - { 252 - struct dsbr100_device *radio = video_drvdata(file); 396 + struct dsbr100_device *radio = 397 + container_of(ctrl->handler, struct dsbr100_device, hdl); 253 398 254 399 switch (ctrl->id) { 255 400 case V4L2_CID_AUDIO_MUTE: 256 - ctrl->value = radio->status; 257 - return 0; 401 + radio->muted = ctrl->val; 402 + return radio->muted ? dsbr100_stop(radio) : dsbr100_start(radio); 258 403 } 259 404 return -EINVAL; 260 405 } 261 406 262 - static int vidioc_s_ctrl(struct file *file, void *priv, 263 - struct v4l2_control *ctrl) 264 - { 265 - struct dsbr100_device *radio = video_drvdata(file); 266 - int retval; 267 - 268 - switch (ctrl->id) { 269 - case V4L2_CID_AUDIO_MUTE: 270 - if (ctrl->value) { 271 - retval = dsbr100_stop(radio); 272 - if (retval < 0) { 273 - dev_warn(&radio->usbdev->dev, 274 - "Radio did not respond properly\n"); 275 - return -EBUSY; 276 - } 277 - } else { 278 - retval = dsbr100_start(radio); 279 - if (retval < 0) { 280 - dev_warn(&radio->usbdev->dev, 281 - "Radio did not respond properly\n"); 282 - return -EBUSY; 283 - } 284 - } 285 - return 0; 286 - } 287 - return -EINVAL; 288 - } 289 - 290 - static int vidioc_g_audio(struct file *file, void *priv, 291 - struct v4l2_audio *a) 292 - { 293 - if (a->index > 1) 294 - return -EINVAL; 295 - 296 - strcpy(a->name, "Radio"); 297 - a->capability = V4L2_AUDCAP_STEREO; 298 - return 0; 299 - } 300 - 301 - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 302 - { 303 - *i = 0; 304 - return 0; 305 - } 306 - 307 - static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 308 - { 309 - return i ? -EINVAL : 0; 310 - } 311 - 312 - static int vidioc_s_audio(struct file *file, void *priv, 313 - struct v4l2_audio *a) 314 - { 315 - return a->index ? -EINVAL : 0; 316 - } 317 407 318 408 /* USB subsystem interface begins here */ 319 409 ··· 264 482 struct dsbr100_device *radio = usb_get_intfdata(intf); 265 483 266 484 mutex_lock(&radio->v4l2_lock); 485 + /* 486 + * Disconnect is also called on unload, and in that case we need to 487 + * mute the device. This call will silently fail if it is called 488 + * after a physical disconnect. 489 + */ 490 + usb_control_msg(radio->usbdev, 491 + usb_rcvctrlpipe(radio->usbdev, 0), 492 + DSB100_ONOFF, 493 + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 494 + 0x00, 0x00, radio->transfer_buffer, 8, 300); 267 495 usb_set_intfdata(intf, NULL); 268 496 video_unregister_device(&radio->videodev); 269 497 v4l2_device_disconnect(&radio->v4l2_dev); ··· 286 494 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) 287 495 { 288 496 struct dsbr100_device *radio = usb_get_intfdata(intf); 289 - int retval; 290 497 291 498 mutex_lock(&radio->v4l2_lock); 292 - if (radio->status == STARTED) { 293 - retval = dsbr100_stop(radio); 294 - if (retval < 0) 295 - dev_warn(&intf->dev, "dsbr100_stop failed\n"); 296 - 297 - /* After dsbr100_stop() status set to STOPPED. 298 - * If we want driver to start radio on resume 299 - * we set status equal to STARTED. 300 - * On resume we will check status and run radio if needed. 301 - */ 302 - radio->status = STARTED; 303 - } 499 + if (!radio->muted && dsbr100_stop(radio) < 0) 500 + dev_warn(&intf->dev, "dsbr100_stop failed\n"); 304 501 mutex_unlock(&radio->v4l2_lock); 305 502 306 503 dev_info(&intf->dev, "going into suspend..\n"); 307 - 308 504 return 0; 309 505 } 310 506 ··· 300 520 static int usb_dsbr100_resume(struct usb_interface *intf) 301 521 { 302 522 struct dsbr100_device *radio = usb_get_intfdata(intf); 303 - int retval; 304 523 305 524 mutex_lock(&radio->v4l2_lock); 306 - if (radio->status == STARTED) { 307 - retval = dsbr100_start(radio); 308 - if (retval < 0) 309 - dev_warn(&intf->dev, "dsbr100_start failed\n"); 310 - } 525 + if (!radio->muted && dsbr100_start(radio) < 0) 526 + dev_warn(&intf->dev, "dsbr100_start failed\n"); 311 527 mutex_unlock(&radio->v4l2_lock); 312 528 313 529 dev_info(&intf->dev, "coming out of suspend..\n"); 314 - 315 530 return 0; 316 531 } 317 532 ··· 315 540 { 316 541 struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev); 317 542 543 + v4l2_ctrl_handler_free(&radio->hdl); 318 544 v4l2_device_unregister(&radio->v4l2_dev); 319 545 kfree(radio->transfer_buffer); 320 546 kfree(radio); 321 547 } 322 548 549 + static const struct v4l2_ctrl_ops usb_dsbr100_ctrl_ops = { 550 + .s_ctrl = usb_dsbr100_s_ctrl, 551 + }; 552 + 323 553 /* File system interface */ 324 554 static const struct v4l2_file_operations usb_dsbr100_fops = { 325 555 .owner = THIS_MODULE, 326 556 .unlocked_ioctl = video_ioctl2, 557 + .open = v4l2_fh_open, 558 + .release = v4l2_fh_release, 559 + .poll = v4l2_ctrl_poll, 327 560 }; 328 561 329 562 static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { ··· 340 557 .vidioc_s_tuner = vidioc_s_tuner, 341 558 .vidioc_g_frequency = vidioc_g_frequency, 342 559 .vidioc_s_frequency = vidioc_s_frequency, 343 - .vidioc_queryctrl = vidioc_queryctrl, 344 - .vidioc_g_ctrl = vidioc_g_ctrl, 345 - .vidioc_s_ctrl = vidioc_s_ctrl, 346 - .vidioc_g_audio = vidioc_g_audio, 347 - .vidioc_s_audio = vidioc_s_audio, 348 - .vidioc_g_input = vidioc_g_input, 349 - .vidioc_s_input = vidioc_s_input, 560 + .vidioc_log_status = v4l2_ctrl_log_status, 561 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 562 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 350 563 }; 351 564 352 565 /* check if the device is present and register with v4l and usb if it is */ ··· 371 592 retval = v4l2_device_register(&intf->dev, v4l2_dev); 372 593 if (retval < 0) { 373 594 v4l2_err(v4l2_dev, "couldn't register v4l2_device\n"); 374 - kfree(radio->transfer_buffer); 375 - kfree(radio); 376 - return retval; 595 + goto err_reg_dev; 377 596 } 378 597 598 + v4l2_ctrl_handler_init(&radio->hdl, 1); 599 + v4l2_ctrl_new_std(&radio->hdl, &usb_dsbr100_ctrl_ops, 600 + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); 601 + if (radio->hdl.error) { 602 + retval = radio->hdl.error; 603 + v4l2_err(v4l2_dev, "couldn't register control\n"); 604 + goto err_reg_ctrl; 605 + } 379 606 mutex_init(&radio->v4l2_lock); 380 607 strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name)); 381 608 radio->videodev.v4l2_dev = v4l2_dev; ··· 389 604 radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; 390 605 radio->videodev.release = video_device_release_empty; 391 606 radio->videodev.lock = &radio->v4l2_lock; 607 + radio->videodev.ctrl_handler = &radio->hdl; 608 + set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); 392 609 393 610 radio->usbdev = interface_to_usbdev(intf); 394 611 radio->curfreq = FREQ_MIN * FREQ_MUL; 395 - radio->status = STOPPED; 612 + radio->muted = true; 396 613 397 614 video_set_drvdata(&radio->videodev, radio); 615 + usb_set_intfdata(intf, radio); 398 616 399 617 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); 400 - if (retval < 0) { 401 - v4l2_err(v4l2_dev, "couldn't register video device\n"); 402 - v4l2_device_unregister(v4l2_dev); 403 - kfree(radio->transfer_buffer); 404 - kfree(radio); 405 - return -EIO; 406 - } 407 - usb_set_intfdata(intf, radio); 408 - return 0; 618 + if (retval == 0) 619 + return 0; 620 + v4l2_err(v4l2_dev, "couldn't register video device\n"); 621 + 622 + err_reg_ctrl: 623 + v4l2_ctrl_handler_free(&radio->hdl); 624 + v4l2_device_unregister(v4l2_dev); 625 + err_reg_dev: 626 + kfree(radio->transfer_buffer); 627 + kfree(radio); 628 + return retval; 409 629 } 410 630 411 - module_usb_driver(usb_dsbr100_driver); 631 + static struct usb_device_id usb_dsbr100_device_table[] = { 632 + { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, 633 + { } /* Terminating entry */ 634 + }; 412 635 413 - MODULE_AUTHOR( DRIVER_AUTHOR ); 414 - MODULE_DESCRIPTION( DRIVER_DESC ); 415 - MODULE_LICENSE("GPL"); 416 - MODULE_VERSION(DRIVER_VERSION); 636 + MODULE_DEVICE_TABLE(usb, usb_dsbr100_device_table); 637 + 638 + /* USB subsystem interface */ 639 + static struct usb_driver usb_dsbr100_driver = { 640 + .name = "dsbr100", 641 + .probe = usb_dsbr100_probe, 642 + .disconnect = usb_dsbr100_disconnect, 643 + .id_table = usb_dsbr100_device_table, 644 + .suspend = usb_dsbr100_suspend, 645 + .resume = usb_dsbr100_resume, 646 + .reset_resume = usb_dsbr100_resume, 647 + }; 648 + 649 + module_usb_driver(usb_dsbr100_driver);