aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/hdpvr
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2010-05-02 07:01:04 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-19 11:58:57 -0400
commitf2b305cd6711b7b3ce30db93b50bc5d6312950c8 (patch)
treefd70d24d94642f029024afd755e900b9264ff3b0 /drivers/media/video/hdpvr
parenta2bdc5e6c4fefea6b0d576a4f610e47456647577 (diff)
V4L/DVB: hdpvr: fix disconnect sequence
Disconnecting the HDPVR caused a kernel oops if lockdep was enabled. In addition, if an app still had video0 open and attempted to call ioctl when the device was already disconnected the system would crash. Move the freeing and cleanup code to the release function: that is the right place for it since you know when you get there that nobody is using the device. Also removed usb_set_intfdata: v4l2_device_register sets this already to v4l2_dev. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/hdpvr')
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c33
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c18
-rw-r--r--drivers/media/video/hdpvr/hdpvr.h5
3 files changed, 28 insertions, 28 deletions
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 2fc9865fd486..830d47b05e1d 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -373,9 +373,6 @@ static int hdpvr_probe(struct usb_interface *interface,
373 } 373 }
374#endif /* CONFIG_I2C */ 374#endif /* CONFIG_I2C */
375 375
376 /* save our data pointer in this interface device */
377 usb_set_intfdata(interface, dev);
378
379 /* let the user know what node this device is now attached to */ 376 /* let the user know what node this device is now attached to */
380 v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", 377 v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
381 video_device_node_name(dev->video_dev)); 378 video_device_node_name(dev->video_dev));
@@ -391,44 +388,24 @@ error:
391 388
392static void hdpvr_disconnect(struct usb_interface *interface) 389static void hdpvr_disconnect(struct usb_interface *interface)
393{ 390{
394 struct hdpvr_device *dev; 391 struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));
395
396 dev = usb_get_intfdata(interface);
397 usb_set_intfdata(interface, NULL);
398 392
393 v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
394 video_device_node_name(dev->video_dev));
399 /* prevent more I/O from starting and stop any ongoing */ 395 /* prevent more I/O from starting and stop any ongoing */
400 mutex_lock(&dev->io_mutex); 396 mutex_lock(&dev->io_mutex);
401 dev->status = STATUS_DISCONNECTED; 397 dev->status = STATUS_DISCONNECTED;
402 v4l2_device_disconnect(&dev->v4l2_dev);
403 video_unregister_device(dev->video_dev);
404 wake_up_interruptible(&dev->wait_data); 398 wake_up_interruptible(&dev->wait_data);
405 wake_up_interruptible(&dev->wait_buffer); 399 wake_up_interruptible(&dev->wait_buffer);
406 mutex_unlock(&dev->io_mutex); 400 mutex_unlock(&dev->io_mutex);
401 v4l2_device_disconnect(&dev->v4l2_dev);
407 msleep(100); 402 msleep(100);
408 flush_workqueue(dev->workqueue); 403 flush_workqueue(dev->workqueue);
409 mutex_lock(&dev->io_mutex); 404 mutex_lock(&dev->io_mutex);
410 hdpvr_cancel_queue(dev); 405 hdpvr_cancel_queue(dev);
411 destroy_workqueue(dev->workqueue);
412 mutex_unlock(&dev->io_mutex); 406 mutex_unlock(&dev->io_mutex);
413 407 video_unregister_device(dev->video_dev);
414 /* deregister I2C adapter */
415#ifdef CONFIG_I2C
416 mutex_lock(&dev->i2c_mutex);
417 if (dev->i2c_adapter)
418 i2c_del_adapter(dev->i2c_adapter);
419 kfree(dev->i2c_adapter);
420 dev->i2c_adapter = NULL;
421 mutex_unlock(&dev->i2c_mutex);
422#endif /* CONFIG_I2C */
423
424 atomic_dec(&dev_nr); 408 atomic_dec(&dev_nr);
425
426 v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
427 video_device_node_name(dev->video_dev));
428
429 v4l2_device_unregister(&dev->v4l2_dev);
430 kfree(dev->usbc_buf);
431 kfree(dev);
432} 409}
433 410
434 411
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 196f82de48f0..d2f0ee29737f 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -1214,6 +1214,24 @@ static void hdpvr_device_release(struct video_device *vdev)
1214 struct hdpvr_device *dev = video_get_drvdata(vdev); 1214 struct hdpvr_device *dev = video_get_drvdata(vdev);
1215 1215
1216 hdpvr_delete(dev); 1216 hdpvr_delete(dev);
1217 mutex_lock(&dev->io_mutex);
1218 destroy_workqueue(dev->workqueue);
1219 mutex_unlock(&dev->io_mutex);
1220
1221 v4l2_device_unregister(&dev->v4l2_dev);
1222
1223 /* deregister I2C adapter */
1224#ifdef CONFIG_I2C
1225 mutex_lock(&dev->i2c_mutex);
1226 if (dev->i2c_adapter)
1227 i2c_del_adapter(dev->i2c_adapter);
1228 kfree(dev->i2c_adapter);
1229 dev->i2c_adapter = NULL;
1230 mutex_unlock(&dev->i2c_mutex);
1231#endif /* CONFIG_I2C */
1232
1233 kfree(dev->usbc_buf);
1234 kfree(dev);
1217} 1235}
1218 1236
1219static const struct video_device hdpvr_video_template = { 1237static const struct video_device hdpvr_video_template = {
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index 49ae25d83d10..b0f046df3cd8 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -111,6 +111,11 @@ struct hdpvr_device {
111 u8 *usbc_buf; 111 u8 *usbc_buf;
112}; 112};
113 113
114static inline struct hdpvr_device *to_hdpvr_dev(struct v4l2_device *v4l2_dev)
115{
116 return container_of(v4l2_dev, struct hdpvr_device, v4l2_dev);
117}
118
114 119
115/* buffer one bulk urb of data */ 120/* buffer one bulk urb of data */
116struct hdpvr_buffer { 121struct hdpvr_buffer {