aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlexey Klimov <klimov.linux@gmail.com>2008-12-27 19:32:49 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:40:09 -0500
commit3a0efc3200386b9288e1d3d3be0a9f5d6f286906 (patch)
tree650ed52ad72760b8f3bcadcfd104b00ecc68d678 /drivers
parentf2ce9179eab9a1551e91e3c97498e9350a087e39 (diff)
V4L/DVB (10054): dsbr100: fix unplug oops
This patch corrects unplug procedure. Patch adds usb_dsbr100_video_device_release, new macros - videodev_to_radio, mutex lock and a lot of safety checks. Struct video_device videodev is embedded in dsbr100_device structure. Signed-off-by: Alexey Klimov <klimov.linux@gmail.com> Signed-off-by: Douglas Schilling Landgraf <dougsland@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/radio/dsbr100.c106
1 files changed, 77 insertions, 29 deletions
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index eafa547ca96b..84914fb267be 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -145,6 +145,7 @@ devices, that would be 76 and 91. */
145#define FREQ_MAX 108.0 145#define FREQ_MAX 108.0
146#define FREQ_MUL 16000 146#define FREQ_MUL 16000
147 147
148#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
148 149
149static int usb_dsbr100_probe(struct usb_interface *intf, 150static int usb_dsbr100_probe(struct usb_interface *intf,
150 const struct usb_device_id *id); 151 const struct usb_device_id *id);
@@ -161,8 +162,9 @@ module_param(radio_nr, int, 0);
161/* Data for one (physical) device */ 162/* Data for one (physical) device */
162struct dsbr100_device { 163struct dsbr100_device {
163 struct usb_device *usbdev; 164 struct usb_device *usbdev;
164 struct video_device *videodev; 165 struct video_device videodev;
165 u8 *transfer_buffer; 166 u8 *transfer_buffer;
167 struct mutex lock; /* buffer locking */
166 int curfreq; 168 int curfreq;
167 int stereo; 169 int stereo;
168 int users; 170 int users;
@@ -195,6 +197,7 @@ static struct usb_driver usb_dsbr100_driver = {
195/* switch on radio */ 197/* switch on radio */
196static int dsbr100_start(struct dsbr100_device *radio) 198static int dsbr100_start(struct dsbr100_device *radio)
197{ 199{
200 mutex_lock(&radio->lock);
198 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), 201 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
199 USB_REQ_GET_STATUS, 202 USB_REQ_GET_STATUS,
200 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 203 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@@ -202,9 +205,13 @@ static int dsbr100_start(struct dsbr100_device *radio)
202 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), 205 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
203 DSB100_ONOFF, 206 DSB100_ONOFF,
204 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 207 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
205 0x01, 0x00, radio->transfer_buffer, 8, 300) < 0) 208 0x01, 0x00, radio->transfer_buffer, 8, 300) < 0) {
209 mutex_unlock(&radio->lock);
206 return -1; 210 return -1;
211 }
212
207 radio->muted=0; 213 radio->muted=0;
214 mutex_unlock(&radio->lock);
208 return (radio->transfer_buffer)[0]; 215 return (radio->transfer_buffer)[0];
209} 216}
210 217
@@ -212,6 +219,7 @@ static int dsbr100_start(struct dsbr100_device *radio)
212/* switch off radio */ 219/* switch off radio */
213static int dsbr100_stop(struct dsbr100_device *radio) 220static int dsbr100_stop(struct dsbr100_device *radio)
214{ 221{
222 mutex_lock(&radio->lock);
215 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), 223 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
216 USB_REQ_GET_STATUS, 224 USB_REQ_GET_STATUS,
217 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 225 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@@ -219,9 +227,13 @@ static int dsbr100_stop(struct dsbr100_device *radio)
219 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), 227 usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
220 DSB100_ONOFF, 228 DSB100_ONOFF,
221 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 229 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
222 0x00, 0x00, radio->transfer_buffer, 8, 300) < 0) 230 0x00, 0x00, radio->transfer_buffer, 8, 300) < 0) {
231 mutex_unlock(&radio->lock);
223 return -1; 232 return -1;
233 }
234
224 radio->muted=1; 235 radio->muted=1;
236 mutex_unlock(&radio->lock);
225 return (radio->transfer_buffer)[0]; 237 return (radio->transfer_buffer)[0];
226} 238}
227 239
@@ -229,6 +241,7 @@ static int dsbr100_stop(struct dsbr100_device *radio)
229static int dsbr100_setfreq(struct dsbr100_device *radio, int freq) 241static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
230{ 242{
231 freq = (freq / 16 * 80) / 1000 + 856; 243 freq = (freq / 16 * 80) / 1000 + 856;
244 mutex_lock(&radio->lock);
232 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), 245 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
233 DSB100_TUNE, 246 DSB100_TUNE,
234 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 247 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@@ -243,9 +256,12 @@ static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
243 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 256 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
244 0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) { 257 0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
245 radio->stereo = -1; 258 radio->stereo = -1;
259 mutex_unlock(&radio->lock);
246 return -1; 260 return -1;
247 } 261 }
262
248 radio->stereo = !((radio->transfer_buffer)[0] & 0x01); 263 radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
264 mutex_unlock(&radio->lock);
249 return (radio->transfer_buffer)[0]; 265 return (radio->transfer_buffer)[0];
250} 266}
251 267
@@ -253,6 +269,7 @@ static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
253sees a stereo signal or not. Pity. */ 269sees a stereo signal or not. Pity. */
254static void dsbr100_getstat(struct dsbr100_device *radio) 270static void dsbr100_getstat(struct dsbr100_device *radio)
255{ 271{
272 mutex_lock(&radio->lock);
256 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), 273 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
257 USB_REQ_GET_STATUS, 274 USB_REQ_GET_STATUS,
258 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 275 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@@ -260,6 +277,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
260 radio->stereo = -1; 277 radio->stereo = -1;
261 else 278 else
262 radio->stereo = !(radio->transfer_buffer[0] & 0x01); 279 radio->stereo = !(radio->transfer_buffer[0] & 0x01);
280 mutex_unlock(&radio->lock);
263} 281}
264 282
265 283
@@ -274,16 +292,12 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
274 struct dsbr100_device *radio = usb_get_intfdata(intf); 292 struct dsbr100_device *radio = usb_get_intfdata(intf);
275 293
276 usb_set_intfdata (intf, NULL); 294 usb_set_intfdata (intf, NULL);
277 if (radio) { 295
278 video_unregister_device(radio->videodev); 296 mutex_lock(&radio->lock);
279 radio->videodev = NULL; 297 radio->removed = 1;
280 if (radio->users) { 298 mutex_unlock(&radio->lock);
281 kfree(radio->transfer_buffer); 299
282 kfree(radio); 300 video_unregister_device(&radio->videodev);
283 } else {
284 radio->removed = 1;
285 }
286 }
287} 301}
288 302
289 303
@@ -303,6 +317,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
303{ 317{
304 struct dsbr100_device *radio = video_drvdata(file); 318 struct dsbr100_device *radio = video_drvdata(file);
305 319
320 /* safety check */
321 if (radio->removed)
322 return -EIO;
323
306 if (v->index > 0) 324 if (v->index > 0)
307 return -EINVAL; 325 return -EINVAL;
308 326
@@ -324,6 +342,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
324static int vidioc_s_tuner(struct file *file, void *priv, 342static int vidioc_s_tuner(struct file *file, void *priv,
325 struct v4l2_tuner *v) 343 struct v4l2_tuner *v)
326{ 344{
345 struct dsbr100_device *radio = video_drvdata(file);
346
347 /* safety check */
348 if (radio->removed)
349 return -EIO;
350
327 if (v->index > 0) 351 if (v->index > 0)
328 return -EINVAL; 352 return -EINVAL;
329 353
@@ -335,6 +359,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
335{ 359{
336 struct dsbr100_device *radio = video_drvdata(file); 360 struct dsbr100_device *radio = video_drvdata(file);
337 361
362 /* safety check */
363 if (radio->removed)
364 return -EIO;
365
338 radio->curfreq = f->frequency; 366 radio->curfreq = f->frequency;
339 if (dsbr100_setfreq(radio, radio->curfreq) == -1) 367 if (dsbr100_setfreq(radio, radio->curfreq) == -1)
340 dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); 368 dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
@@ -346,6 +374,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
346{ 374{
347 struct dsbr100_device *radio = video_drvdata(file); 375 struct dsbr100_device *radio = video_drvdata(file);
348 376
377 /* safety check */
378 if (radio->removed)
379 return -EIO;
380
349 f->type = V4L2_TUNER_RADIO; 381 f->type = V4L2_TUNER_RADIO;
350 f->frequency = radio->curfreq; 382 f->frequency = radio->curfreq;
351 return 0; 383 return 0;
@@ -370,6 +402,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
370{ 402{
371 struct dsbr100_device *radio = video_drvdata(file); 403 struct dsbr100_device *radio = video_drvdata(file);
372 404
405 /* safety check */
406 if (radio->removed)
407 return -EIO;
408
373 switch (ctrl->id) { 409 switch (ctrl->id) {
374 case V4L2_CID_AUDIO_MUTE: 410 case V4L2_CID_AUDIO_MUTE:
375 ctrl->value = radio->muted; 411 ctrl->value = radio->muted;
@@ -383,6 +419,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
383{ 419{
384 struct dsbr100_device *radio = video_drvdata(file); 420 struct dsbr100_device *radio = video_drvdata(file);
385 421
422 /* safety check */
423 if (radio->removed)
424 return -EIO;
425
386 switch (ctrl->id) { 426 switch (ctrl->id) {
387 case V4L2_CID_AUDIO_MUTE: 427 case V4L2_CID_AUDIO_MUTE:
388 if (ctrl->value) { 428 if (ctrl->value) {
@@ -464,13 +504,19 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
464static int usb_dsbr100_close(struct inode *inode, struct file *file) 504static int usb_dsbr100_close(struct inode *inode, struct file *file)
465{ 505{
466 struct dsbr100_device *radio = video_drvdata(file); 506 struct dsbr100_device *radio = video_drvdata(file);
507 int retval;
467 508
468 if (!radio) 509 if (!radio)
469 return -ENODEV; 510 return -ENODEV;
511
470 radio->users = 0; 512 radio->users = 0;
471 if (radio->removed) { 513 if (!radio->removed) {
472 kfree(radio->transfer_buffer); 514 retval = dsbr100_stop(radio);
473 kfree(radio); 515 if (retval == -1) {
516 dev_warn(&radio->usbdev->dev,
517 "dsbr100_stop failed\n");
518 }
519
474 } 520 }
475 return 0; 521 return 0;
476} 522}
@@ -505,6 +551,14 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
505 return 0; 551 return 0;
506} 552}
507 553
554static void usb_dsbr100_video_device_release(struct video_device *videodev)
555{
556 struct dsbr100_device *radio = videodev_to_radio(videodev);
557
558 kfree(radio->transfer_buffer);
559 kfree(radio);
560}
561
508/* File system interface */ 562/* File system interface */
509static const struct file_operations usb_dsbr100_fops = { 563static const struct file_operations usb_dsbr100_fops = {
510 .owner = THIS_MODULE, 564 .owner = THIS_MODULE,
@@ -533,11 +587,11 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
533}; 587};
534 588
535/* V4L2 interface */ 589/* V4L2 interface */
536static struct video_device dsbr100_videodev_template = { 590static struct video_device dsbr100_videodev_data = {
537 .name = "D-Link DSB-R 100", 591 .name = "D-Link DSB-R 100",
538 .fops = &usb_dsbr100_fops, 592 .fops = &usb_dsbr100_fops,
539 .ioctl_ops = &usb_dsbr100_ioctl_ops, 593 .ioctl_ops = &usb_dsbr100_ioctl_ops,
540 .release = video_device_release, 594 .release = usb_dsbr100_video_device_release,
541}; 595};
542 596
543/* check if the device is present and register with v4l and 597/* check if the device is present and register with v4l and
@@ -558,23 +612,17 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
558 kfree(radio); 612 kfree(radio);
559 return -ENOMEM; 613 return -ENOMEM;
560 } 614 }
561 radio->videodev = video_device_alloc();
562 615
563 if (!(radio->videodev)) { 616 mutex_init(&radio->lock);
564 kfree(radio->transfer_buffer); 617 radio->videodev = dsbr100_videodev_data;
565 kfree(radio); 618
566 return -ENOMEM;
567 }
568 memcpy(radio->videodev, &dsbr100_videodev_template,
569 sizeof(dsbr100_videodev_template));
570 radio->removed = 0; 619 radio->removed = 0;
571 radio->users = 0; 620 radio->users = 0;
572 radio->usbdev = interface_to_usbdev(intf); 621 radio->usbdev = interface_to_usbdev(intf);
573 radio->curfreq = FREQ_MIN * FREQ_MUL; 622 radio->curfreq = FREQ_MIN * FREQ_MUL;
574 video_set_drvdata(radio->videodev, radio); 623 video_set_drvdata(&radio->videodev, radio);
575 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) { 624 if (video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
576 dev_warn(&intf->dev, "Could not register video device\n"); 625 dev_warn(&intf->dev, "Could not register video device\n");
577 video_device_release(radio->videodev);
578 kfree(radio->transfer_buffer); 626 kfree(radio->transfer_buffer);
579 kfree(radio); 627 kfree(radio);
580 return -EIO; 628 return -EIO;