diff options
Diffstat (limited to 'drivers/media/radio/dsbr100.c')
-rw-r--r-- | drivers/media/radio/dsbr100.c | 381 |
1 files changed, 290 insertions, 91 deletions
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index a5ca176a7b08..5474a22c1b22 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* A driver for the D-Link DSB-R100 USB radio. The R100 plugs | 1 | /* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21. |
2 | 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 | ||
@@ -33,6 +33,10 @@ | |||
33 | 33 | ||
34 | History: | 34 | History: |
35 | 35 | ||
36 | Version 0.44: | ||
37 | Add suspend/resume functions, fix unplug of device, | ||
38 | a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com> | ||
39 | |||
36 | Version 0.43: | 40 | Version 0.43: |
37 | Oliver Neukum: avoided DMA coherency issue | 41 | Oliver Neukum: avoided DMA coherency issue |
38 | 42 | ||
@@ -93,8 +97,8 @@ | |||
93 | */ | 97 | */ |
94 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ | 98 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ |
95 | 99 | ||
96 | #define DRIVER_VERSION "v0.41" | 100 | #define DRIVER_VERSION "v0.44" |
97 | #define RADIO_VERSION KERNEL_VERSION(0,4,1) | 101 | #define RADIO_VERSION KERNEL_VERSION(0, 4, 4) |
98 | 102 | ||
99 | static struct v4l2_queryctrl radio_qctrl[] = { | 103 | static struct v4l2_queryctrl radio_qctrl[] = { |
100 | { | 104 | { |
@@ -104,7 +108,27 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
104 | .maximum = 1, | 108 | .maximum = 1, |
105 | .default_value = 1, | 109 | .default_value = 1, |
106 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 110 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
107 | } | 111 | }, |
112 | /* HINT: the disabled controls are only here to satify kradio and such apps */ | ||
113 | { .id = V4L2_CID_AUDIO_VOLUME, | ||
114 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
115 | }, | ||
116 | { | ||
117 | .id = V4L2_CID_AUDIO_BALANCE, | ||
118 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
119 | }, | ||
120 | { | ||
121 | .id = V4L2_CID_AUDIO_BASS, | ||
122 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
123 | }, | ||
124 | { | ||
125 | .id = V4L2_CID_AUDIO_TREBLE, | ||
126 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
127 | }, | ||
128 | { | ||
129 | .id = V4L2_CID_AUDIO_LOUDNESS, | ||
130 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
131 | }, | ||
108 | }; | 132 | }; |
109 | 133 | ||
110 | #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" | 134 | #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" |
@@ -125,12 +149,16 @@ devices, that would be 76 and 91. */ | |||
125 | #define FREQ_MAX 108.0 | 149 | #define FREQ_MAX 108.0 |
126 | #define FREQ_MUL 16000 | 150 | #define FREQ_MUL 16000 |
127 | 151 | ||
152 | #define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev) | ||
128 | 153 | ||
129 | static int usb_dsbr100_probe(struct usb_interface *intf, | 154 | static int usb_dsbr100_probe(struct usb_interface *intf, |
130 | const struct usb_device_id *id); | 155 | const struct usb_device_id *id); |
131 | static void usb_dsbr100_disconnect(struct usb_interface *intf); | 156 | static void usb_dsbr100_disconnect(struct usb_interface *intf); |
132 | static int usb_dsbr100_open(struct inode *inode, struct file *file); | 157 | static int usb_dsbr100_open(struct inode *inode, struct file *file); |
133 | static int usb_dsbr100_close(struct inode *inode, struct file *file); | 158 | static int usb_dsbr100_close(struct inode *inode, struct file *file); |
159 | static int usb_dsbr100_suspend(struct usb_interface *intf, | ||
160 | pm_message_t message); | ||
161 | static int usb_dsbr100_resume(struct usb_interface *intf); | ||
134 | 162 | ||
135 | static int radio_nr = -1; | 163 | static int radio_nr = -1; |
136 | module_param(radio_nr, int, 0); | 164 | module_param(radio_nr, int, 0); |
@@ -138,8 +166,9 @@ module_param(radio_nr, int, 0); | |||
138 | /* Data for one (physical) device */ | 166 | /* Data for one (physical) device */ |
139 | struct dsbr100_device { | 167 | struct dsbr100_device { |
140 | struct usb_device *usbdev; | 168 | struct usb_device *usbdev; |
141 | struct video_device *videodev; | 169 | struct video_device videodev; |
142 | u8 *transfer_buffer; | 170 | u8 *transfer_buffer; |
171 | struct mutex lock; /* buffer locking */ | ||
143 | int curfreq; | 172 | int curfreq; |
144 | int stereo; | 173 | int stereo; |
145 | int users; | 174 | int users; |
@@ -147,7 +176,6 @@ struct dsbr100_device { | |||
147 | int muted; | 176 | int muted; |
148 | }; | 177 | }; |
149 | 178 | ||
150 | |||
151 | static struct usb_device_id usb_dsbr100_device_table [] = { | 179 | static struct usb_device_id usb_dsbr100_device_table [] = { |
152 | { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, | 180 | { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, |
153 | { } /* Terminating entry */ | 181 | { } /* Terminating entry */ |
@@ -157,10 +185,14 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); | |||
157 | 185 | ||
158 | /* USB subsystem interface */ | 186 | /* USB subsystem interface */ |
159 | static struct usb_driver usb_dsbr100_driver = { | 187 | static struct usb_driver usb_dsbr100_driver = { |
160 | .name = "dsbr100", | 188 | .name = "dsbr100", |
161 | .probe = usb_dsbr100_probe, | 189 | .probe = usb_dsbr100_probe, |
162 | .disconnect = usb_dsbr100_disconnect, | 190 | .disconnect = usb_dsbr100_disconnect, |
163 | .id_table = usb_dsbr100_device_table, | 191 | .id_table = usb_dsbr100_device_table, |
192 | .suspend = usb_dsbr100_suspend, | ||
193 | .resume = usb_dsbr100_resume, | ||
194 | .reset_resume = usb_dsbr100_resume, | ||
195 | .supports_autosuspend = 0, | ||
164 | }; | 196 | }; |
165 | 197 | ||
166 | /* Low-level device interface begins here */ | 198 | /* Low-level device interface begins here */ |
@@ -168,95 +200,190 @@ static struct usb_driver usb_dsbr100_driver = { | |||
168 | /* switch on radio */ | 200 | /* switch on radio */ |
169 | static int dsbr100_start(struct dsbr100_device *radio) | 201 | static int dsbr100_start(struct dsbr100_device *radio) |
170 | { | 202 | { |
171 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 203 | int retval; |
172 | USB_REQ_GET_STATUS, | 204 | int request; |
173 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 205 | |
174 | 0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 || | 206 | mutex_lock(&radio->lock); |
175 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 207 | |
176 | DSB100_ONOFF, | 208 | retval = usb_control_msg(radio->usbdev, |
177 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 209 | usb_rcvctrlpipe(radio->usbdev, 0), |
178 | 0x01, 0x00, radio->transfer_buffer, 8, 300) < 0) | 210 | USB_REQ_GET_STATUS, |
179 | return -1; | 211 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
180 | radio->muted=0; | 212 | 0x00, 0xC7, radio->transfer_buffer, 8, 300); |
213 | |||
214 | if (retval < 0) { | ||
215 | request = USB_REQ_GET_STATUS; | ||
216 | goto usb_control_msg_failed; | ||
217 | } | ||
218 | |||
219 | retval = usb_control_msg(radio->usbdev, | ||
220 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
221 | DSB100_ONOFF, | ||
222 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
223 | 0x01, 0x00, radio->transfer_buffer, 8, 300); | ||
224 | |||
225 | if (retval < 0) { | ||
226 | request = DSB100_ONOFF; | ||
227 | goto usb_control_msg_failed; | ||
228 | } | ||
229 | |||
230 | radio->muted = 0; | ||
231 | mutex_unlock(&radio->lock); | ||
181 | return (radio->transfer_buffer)[0]; | 232 | return (radio->transfer_buffer)[0]; |
182 | } | ||
183 | 233 | ||
234 | usb_control_msg_failed: | ||
235 | mutex_unlock(&radio->lock); | ||
236 | dev_err(&radio->usbdev->dev, | ||
237 | "%s - usb_control_msg returned %i, request %i\n", | ||
238 | __func__, retval, request); | ||
239 | return retval; | ||
240 | |||
241 | } | ||
184 | 242 | ||
185 | /* switch off radio */ | 243 | /* switch off radio */ |
186 | static int dsbr100_stop(struct dsbr100_device *radio) | 244 | static int dsbr100_stop(struct dsbr100_device *radio) |
187 | { | 245 | { |
188 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 246 | int retval; |
189 | USB_REQ_GET_STATUS, | 247 | int request; |
190 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 248 | |
191 | 0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 || | 249 | mutex_lock(&radio->lock); |
192 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 250 | |
193 | DSB100_ONOFF, | 251 | retval = usb_control_msg(radio->usbdev, |
194 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 252 | usb_rcvctrlpipe(radio->usbdev, 0), |
195 | 0x00, 0x00, radio->transfer_buffer, 8, 300) < 0) | 253 | USB_REQ_GET_STATUS, |
196 | return -1; | 254 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
197 | radio->muted=1; | 255 | 0x16, 0x1C, radio->transfer_buffer, 8, 300); |
256 | |||
257 | if (retval < 0) { | ||
258 | request = USB_REQ_GET_STATUS; | ||
259 | goto usb_control_msg_failed; | ||
260 | } | ||
261 | |||
262 | retval = usb_control_msg(radio->usbdev, | ||
263 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
264 | DSB100_ONOFF, | ||
265 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
266 | 0x00, 0x00, radio->transfer_buffer, 8, 300); | ||
267 | |||
268 | if (retval < 0) { | ||
269 | request = DSB100_ONOFF; | ||
270 | goto usb_control_msg_failed; | ||
271 | } | ||
272 | |||
273 | radio->muted = 1; | ||
274 | mutex_unlock(&radio->lock); | ||
198 | return (radio->transfer_buffer)[0]; | 275 | return (radio->transfer_buffer)[0]; |
276 | |||
277 | usb_control_msg_failed: | ||
278 | mutex_unlock(&radio->lock); | ||
279 | dev_err(&radio->usbdev->dev, | ||
280 | "%s - usb_control_msg returned %i, request %i\n", | ||
281 | __func__, retval, request); | ||
282 | return retval; | ||
283 | |||
199 | } | 284 | } |
200 | 285 | ||
201 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ | 286 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ |
202 | static int dsbr100_setfreq(struct dsbr100_device *radio, int freq) | 287 | static int dsbr100_setfreq(struct dsbr100_device *radio, int freq) |
203 | { | 288 | { |
289 | int retval; | ||
290 | int request; | ||
291 | |||
204 | freq = (freq / 16 * 80) / 1000 + 856; | 292 | freq = (freq / 16 * 80) / 1000 + 856; |
205 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 293 | mutex_lock(&radio->lock); |
206 | DSB100_TUNE, | 294 | |
207 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 295 | retval = usb_control_msg(radio->usbdev, |
208 | (freq >> 8) & 0x00ff, freq & 0xff, | 296 | usb_rcvctrlpipe(radio->usbdev, 0), |
209 | radio->transfer_buffer, 8, 300) < 0 || | 297 | DSB100_TUNE, |
210 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 298 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
211 | USB_REQ_GET_STATUS, | 299 | (freq >> 8) & 0x00ff, freq & 0xff, |
212 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 300 | radio->transfer_buffer, 8, 300); |
213 | 0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 || | 301 | |
214 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 302 | if (retval < 0) { |
215 | USB_REQ_GET_STATUS, | 303 | request = DSB100_TUNE; |
216 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 304 | goto usb_control_msg_failed; |
217 | 0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) { | ||
218 | radio->stereo = -1; | ||
219 | return -1; | ||
220 | } | 305 | } |
306 | |||
307 | retval = usb_control_msg(radio->usbdev, | ||
308 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
309 | USB_REQ_GET_STATUS, | ||
310 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
311 | 0x96, 0xB7, radio->transfer_buffer, 8, 300); | ||
312 | |||
313 | if (retval < 0) { | ||
314 | request = USB_REQ_GET_STATUS; | ||
315 | goto usb_control_msg_failed; | ||
316 | } | ||
317 | |||
318 | retval = usb_control_msg(radio->usbdev, | ||
319 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
320 | USB_REQ_GET_STATUS, | ||
321 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
322 | 0x00, 0x24, radio->transfer_buffer, 8, 300); | ||
323 | |||
324 | if (retval < 0) { | ||
325 | request = USB_REQ_GET_STATUS; | ||
326 | goto usb_control_msg_failed; | ||
327 | } | ||
328 | |||
221 | radio->stereo = !((radio->transfer_buffer)[0] & 0x01); | 329 | radio->stereo = !((radio->transfer_buffer)[0] & 0x01); |
330 | mutex_unlock(&radio->lock); | ||
222 | return (radio->transfer_buffer)[0]; | 331 | return (radio->transfer_buffer)[0]; |
332 | |||
333 | usb_control_msg_failed: | ||
334 | radio->stereo = -1; | ||
335 | mutex_unlock(&radio->lock); | ||
336 | dev_err(&radio->usbdev->dev, | ||
337 | "%s - usb_control_msg returned %i, request %i\n", | ||
338 | __func__, retval, request); | ||
339 | return retval; | ||
223 | } | 340 | } |
224 | 341 | ||
225 | /* return the device status. This is, in effect, just whether it | 342 | /* return the device status. This is, in effect, just whether it |
226 | sees a stereo signal or not. Pity. */ | 343 | sees a stereo signal or not. Pity. */ |
227 | static void dsbr100_getstat(struct dsbr100_device *radio) | 344 | static void dsbr100_getstat(struct dsbr100_device *radio) |
228 | { | 345 | { |
229 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | 346 | int retval; |
347 | |||
348 | mutex_lock(&radio->lock); | ||
349 | |||
350 | retval = usb_control_msg(radio->usbdev, | ||
351 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
230 | USB_REQ_GET_STATUS, | 352 | USB_REQ_GET_STATUS, |
231 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 353 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
232 | 0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0) | 354 | 0x00 , 0x24, radio->transfer_buffer, 8, 300); |
355 | |||
356 | if (retval < 0) { | ||
233 | radio->stereo = -1; | 357 | radio->stereo = -1; |
234 | else | 358 | dev_err(&radio->usbdev->dev, |
359 | "%s - usb_control_msg returned %i, request %i\n", | ||
360 | __func__, retval, USB_REQ_GET_STATUS); | ||
361 | } else { | ||
235 | radio->stereo = !(radio->transfer_buffer[0] & 0x01); | 362 | radio->stereo = !(radio->transfer_buffer[0] & 0x01); |
236 | } | 363 | } |
237 | 364 | ||
365 | mutex_unlock(&radio->lock); | ||
366 | } | ||
238 | 367 | ||
239 | /* USB subsystem interface begins here */ | 368 | /* USB subsystem interface begins here */ |
240 | 369 | ||
241 | /* handle unplugging of the device, release data structures | 370 | /* |
242 | if nothing keeps us from doing it. If something is still | 371 | * Handle unplugging of the device. |
243 | keeping us busy, the release callback of v4l will take care | 372 | * We call video_unregister_device in any case. |
244 | of releasing it. */ | 373 | * The last function called in this procedure is |
374 | * usb_dsbr100_video_device_release | ||
375 | */ | ||
245 | static void usb_dsbr100_disconnect(struct usb_interface *intf) | 376 | static void usb_dsbr100_disconnect(struct usb_interface *intf) |
246 | { | 377 | { |
247 | struct dsbr100_device *radio = usb_get_intfdata(intf); | 378 | struct dsbr100_device *radio = usb_get_intfdata(intf); |
248 | 379 | ||
249 | usb_set_intfdata (intf, NULL); | 380 | usb_set_intfdata (intf, NULL); |
250 | if (radio) { | 381 | |
251 | video_unregister_device(radio->videodev); | 382 | mutex_lock(&radio->lock); |
252 | radio->videodev = NULL; | 383 | radio->removed = 1; |
253 | if (radio->users) { | 384 | mutex_unlock(&radio->lock); |
254 | kfree(radio->transfer_buffer); | 385 | |
255 | kfree(radio); | 386 | video_unregister_device(&radio->videodev); |
256 | } else { | ||
257 | radio->removed = 1; | ||
258 | } | ||
259 | } | ||
260 | } | 387 | } |
261 | 388 | ||
262 | 389 | ||
@@ -276,6 +403,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
276 | { | 403 | { |
277 | struct dsbr100_device *radio = video_drvdata(file); | 404 | struct dsbr100_device *radio = video_drvdata(file); |
278 | 405 | ||
406 | /* safety check */ | ||
407 | if (radio->removed) | ||
408 | return -EIO; | ||
409 | |||
279 | if (v->index > 0) | 410 | if (v->index > 0) |
280 | return -EINVAL; | 411 | return -EINVAL; |
281 | 412 | ||
@@ -297,6 +428,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
297 | static int vidioc_s_tuner(struct file *file, void *priv, | 428 | static int vidioc_s_tuner(struct file *file, void *priv, |
298 | struct v4l2_tuner *v) | 429 | struct v4l2_tuner *v) |
299 | { | 430 | { |
431 | struct dsbr100_device *radio = video_drvdata(file); | ||
432 | |||
433 | /* safety check */ | ||
434 | if (radio->removed) | ||
435 | return -EIO; | ||
436 | |||
300 | if (v->index > 0) | 437 | if (v->index > 0) |
301 | return -EINVAL; | 438 | return -EINVAL; |
302 | 439 | ||
@@ -307,9 +444,15 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
307 | struct v4l2_frequency *f) | 444 | struct v4l2_frequency *f) |
308 | { | 445 | { |
309 | struct dsbr100_device *radio = video_drvdata(file); | 446 | struct dsbr100_device *radio = video_drvdata(file); |
447 | int retval; | ||
448 | |||
449 | /* safety check */ | ||
450 | if (radio->removed) | ||
451 | return -EIO; | ||
310 | 452 | ||
311 | radio->curfreq = f->frequency; | 453 | radio->curfreq = f->frequency; |
312 | if (dsbr100_setfreq(radio, radio->curfreq) == -1) | 454 | retval = dsbr100_setfreq(radio, radio->curfreq); |
455 | if (retval < 0) | ||
313 | dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); | 456 | dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); |
314 | return 0; | 457 | return 0; |
315 | } | 458 | } |
@@ -319,6 +462,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
319 | { | 462 | { |
320 | struct dsbr100_device *radio = video_drvdata(file); | 463 | struct dsbr100_device *radio = video_drvdata(file); |
321 | 464 | ||
465 | /* safety check */ | ||
466 | if (radio->removed) | ||
467 | return -EIO; | ||
468 | |||
322 | f->type = V4L2_TUNER_RADIO; | 469 | f->type = V4L2_TUNER_RADIO; |
323 | f->frequency = radio->curfreq; | 470 | f->frequency = radio->curfreq; |
324 | return 0; | 471 | return 0; |
@@ -343,6 +490,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
343 | { | 490 | { |
344 | struct dsbr100_device *radio = video_drvdata(file); | 491 | struct dsbr100_device *radio = video_drvdata(file); |
345 | 492 | ||
493 | /* safety check */ | ||
494 | if (radio->removed) | ||
495 | return -EIO; | ||
496 | |||
346 | switch (ctrl->id) { | 497 | switch (ctrl->id) { |
347 | case V4L2_CID_AUDIO_MUTE: | 498 | case V4L2_CID_AUDIO_MUTE: |
348 | ctrl->value = radio->muted; | 499 | ctrl->value = radio->muted; |
@@ -355,17 +506,24 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
355 | struct v4l2_control *ctrl) | 506 | struct v4l2_control *ctrl) |
356 | { | 507 | { |
357 | struct dsbr100_device *radio = video_drvdata(file); | 508 | struct dsbr100_device *radio = video_drvdata(file); |
509 | int retval; | ||
510 | |||
511 | /* safety check */ | ||
512 | if (radio->removed) | ||
513 | return -EIO; | ||
358 | 514 | ||
359 | switch (ctrl->id) { | 515 | switch (ctrl->id) { |
360 | case V4L2_CID_AUDIO_MUTE: | 516 | case V4L2_CID_AUDIO_MUTE: |
361 | if (ctrl->value) { | 517 | if (ctrl->value) { |
362 | if (dsbr100_stop(radio) == -1) { | 518 | retval = dsbr100_stop(radio); |
519 | if (retval < 0) { | ||
363 | dev_warn(&radio->usbdev->dev, | 520 | dev_warn(&radio->usbdev->dev, |
364 | "Radio did not respond properly\n"); | 521 | "Radio did not respond properly\n"); |
365 | return -EBUSY; | 522 | return -EBUSY; |
366 | } | 523 | } |
367 | } else { | 524 | } else { |
368 | if (dsbr100_start(radio) == -1) { | 525 | retval = dsbr100_start(radio); |
526 | if (retval < 0) { | ||
369 | dev_warn(&radio->usbdev->dev, | 527 | dev_warn(&radio->usbdev->dev, |
370 | "Radio did not respond properly\n"); | 528 | "Radio did not respond properly\n"); |
371 | return -EBUSY; | 529 | return -EBUSY; |
@@ -417,7 +575,8 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file) | |||
417 | radio->users = 1; | 575 | radio->users = 1; |
418 | radio->muted = 1; | 576 | radio->muted = 1; |
419 | 577 | ||
420 | if (dsbr100_start(radio) < 0) { | 578 | retval = dsbr100_start(radio); |
579 | if (retval < 0) { | ||
421 | dev_warn(&radio->usbdev->dev, | 580 | dev_warn(&radio->usbdev->dev, |
422 | "Radio did not start up properly\n"); | 581 | "Radio did not start up properly\n"); |
423 | radio->users = 0; | 582 | radio->users = 0; |
@@ -426,9 +585,9 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file) | |||
426 | } | 585 | } |
427 | 586 | ||
428 | retval = dsbr100_setfreq(radio, radio->curfreq); | 587 | retval = dsbr100_setfreq(radio, radio->curfreq); |
429 | 588 | if (retval < 0) | |
430 | if (retval == -1) | 589 | dev_warn(&radio->usbdev->dev, |
431 | printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n"); | 590 | "set frequency failed\n"); |
432 | 591 | ||
433 | unlock_kernel(); | 592 | unlock_kernel(); |
434 | return 0; | 593 | return 0; |
@@ -437,17 +596,62 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file) | |||
437 | static int usb_dsbr100_close(struct inode *inode, struct file *file) | 596 | static int usb_dsbr100_close(struct inode *inode, struct file *file) |
438 | { | 597 | { |
439 | struct dsbr100_device *radio = video_drvdata(file); | 598 | struct dsbr100_device *radio = video_drvdata(file); |
599 | int retval; | ||
440 | 600 | ||
441 | if (!radio) | 601 | if (!radio) |
442 | return -ENODEV; | 602 | return -ENODEV; |
603 | |||
443 | radio->users = 0; | 604 | radio->users = 0; |
444 | if (radio->removed) { | 605 | if (!radio->removed) { |
445 | kfree(radio->transfer_buffer); | 606 | retval = dsbr100_stop(radio); |
446 | kfree(radio); | 607 | if (retval < 0) { |
608 | dev_warn(&radio->usbdev->dev, | ||
609 | "dsbr100_stop failed\n"); | ||
610 | } | ||
611 | |||
447 | } | 612 | } |
448 | return 0; | 613 | return 0; |
449 | } | 614 | } |
450 | 615 | ||
616 | /* Suspend device - stop device. */ | ||
617 | static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) | ||
618 | { | ||
619 | struct dsbr100_device *radio = usb_get_intfdata(intf); | ||
620 | int retval; | ||
621 | |||
622 | retval = dsbr100_stop(radio); | ||
623 | if (retval < 0) | ||
624 | dev_warn(&intf->dev, "dsbr100_stop failed\n"); | ||
625 | |||
626 | dev_info(&intf->dev, "going into suspend..\n"); | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | /* Resume device - start device. */ | ||
632 | static int usb_dsbr100_resume(struct usb_interface *intf) | ||
633 | { | ||
634 | struct dsbr100_device *radio = usb_get_intfdata(intf); | ||
635 | int retval; | ||
636 | |||
637 | retval = dsbr100_start(radio); | ||
638 | if (retval < 0) | ||
639 | dev_warn(&intf->dev, "dsbr100_start failed\n"); | ||
640 | |||
641 | dev_info(&intf->dev, "coming out of suspend..\n"); | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | /* free data structures */ | ||
647 | static void usb_dsbr100_video_device_release(struct video_device *videodev) | ||
648 | { | ||
649 | struct dsbr100_device *radio = videodev_to_radio(videodev); | ||
650 | |||
651 | kfree(radio->transfer_buffer); | ||
652 | kfree(radio); | ||
653 | } | ||
654 | |||
451 | /* File system interface */ | 655 | /* File system interface */ |
452 | static const struct file_operations usb_dsbr100_fops = { | 656 | static const struct file_operations usb_dsbr100_fops = { |
453 | .owner = THIS_MODULE, | 657 | .owner = THIS_MODULE, |
@@ -476,19 +680,19 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { | |||
476 | }; | 680 | }; |
477 | 681 | ||
478 | /* V4L2 interface */ | 682 | /* V4L2 interface */ |
479 | static struct video_device dsbr100_videodev_template = { | 683 | static struct video_device dsbr100_videodev_data = { |
480 | .name = "D-Link DSB-R 100", | 684 | .name = "D-Link DSB-R 100", |
481 | .fops = &usb_dsbr100_fops, | 685 | .fops = &usb_dsbr100_fops, |
482 | .ioctl_ops = &usb_dsbr100_ioctl_ops, | 686 | .ioctl_ops = &usb_dsbr100_ioctl_ops, |
483 | .release = video_device_release, | 687 | .release = usb_dsbr100_video_device_release, |
484 | }; | 688 | }; |
485 | 689 | ||
486 | /* check if the device is present and register with v4l and | 690 | /* check if the device is present and register with v4l and usb if it is */ |
487 | usb if it is */ | ||
488 | static int usb_dsbr100_probe(struct usb_interface *intf, | 691 | static int usb_dsbr100_probe(struct usb_interface *intf, |
489 | const struct usb_device_id *id) | 692 | const struct usb_device_id *id) |
490 | { | 693 | { |
491 | struct dsbr100_device *radio; | 694 | struct dsbr100_device *radio; |
695 | int retval; | ||
492 | 696 | ||
493 | radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL); | 697 | radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL); |
494 | 698 | ||
@@ -501,23 +705,18 @@ static int usb_dsbr100_probe(struct usb_interface *intf, | |||
501 | kfree(radio); | 705 | kfree(radio); |
502 | return -ENOMEM; | 706 | return -ENOMEM; |
503 | } | 707 | } |
504 | radio->videodev = video_device_alloc(); | ||
505 | 708 | ||
506 | if (!(radio->videodev)) { | 709 | mutex_init(&radio->lock); |
507 | kfree(radio->transfer_buffer); | 710 | radio->videodev = dsbr100_videodev_data; |
508 | kfree(radio); | 711 | |
509 | return -ENOMEM; | ||
510 | } | ||
511 | memcpy(radio->videodev, &dsbr100_videodev_template, | ||
512 | sizeof(dsbr100_videodev_template)); | ||
513 | radio->removed = 0; | 712 | radio->removed = 0; |
514 | radio->users = 0; | 713 | radio->users = 0; |
515 | radio->usbdev = interface_to_usbdev(intf); | 714 | radio->usbdev = interface_to_usbdev(intf); |
516 | radio->curfreq = FREQ_MIN * FREQ_MUL; | 715 | radio->curfreq = FREQ_MIN * FREQ_MUL; |
517 | video_set_drvdata(radio->videodev, radio); | 716 | video_set_drvdata(&radio->videodev, radio); |
518 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) { | 717 | retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); |
519 | dev_warn(&intf->dev, "Could not register video device\n"); | 718 | if (retval < 0) { |
520 | video_device_release(radio->videodev); | 719 | dev_err(&intf->dev, "couldn't register video device\n"); |
521 | kfree(radio->transfer_buffer); | 720 | kfree(radio->transfer_buffer); |
522 | kfree(radio); | 721 | kfree(radio); |
523 | return -EIO; | 722 | return -EIO; |