summaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/au0828
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2013-03-11 14:16:45 +0100
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-25 19:10:30 +0100
commit823beb7e22d04ed545e7adfcd5ec8db934218872 (patch)
tree2a24866bde29638428ebf82d2945ef7c4ce0e0dd /drivers/media/usb/au0828
parent[media] au8522_decoder: remove obsolete control ops (diff)
downloadlinux-823beb7e22d04ed545e7adfcd5ec8db934218872.tar.xz
linux-823beb7e22d04ed545e7adfcd5ec8db934218872.zip
[media] au0828: fix disconnect sequence
The driver crashed when the device was disconnected while an application still had a device node open. Fixed by using the release() callback of struct v4l2_device. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/au0828')
-rw-r--r--drivers/media/usb/au0828/au0828-core.c48
-rw-r--r--drivers/media/usb/au0828/au0828-video.c9
2 files changed, 32 insertions, 25 deletions
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index ffd3bcba9c10..bd9d19a73efd 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -125,36 +125,48 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
return status;
}
-static void au0828_usb_disconnect(struct usb_interface *interface)
+static void au0828_usb_release(struct au0828_dev *dev)
{
- struct au0828_dev *dev = usb_get_intfdata(interface);
-
- dprintk(1, "%s()\n", __func__);
-
- /* Digital TV */
- au0828_dvb_unregister(dev);
-
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_unregister(dev);
-#endif
-
/* I2C */
au0828_i2c_unregister(dev);
+ kfree(dev);
+}
+
#ifdef CONFIG_VIDEO_AU0828_V4L2
+static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
+{
+ struct au0828_dev *dev =
+ container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
+
v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
v4l2_device_unregister(&dev->v4l2_dev);
+ au0828_usb_release(dev);
+}
#endif
- usb_set_intfdata(interface, NULL);
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+ struct au0828_dev *dev = usb_get_intfdata(interface);
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Digital TV */
+ au0828_dvb_unregister(dev);
+ usb_set_intfdata(interface, NULL);
mutex_lock(&dev->mutex);
dev->usbdev = NULL;
mutex_unlock(&dev->mutex);
-
- kfree(dev);
-
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+ au0828_analog_unregister(dev);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ v4l2_device_put(&dev->v4l2_dev);
+ return;
+ }
+#endif
+ au0828_usb_release(dev);
}
static int au0828_usb_probe(struct usb_interface *interface,
@@ -203,6 +215,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
dev->boardnr = id->driver_info;
#ifdef CONFIG_VIDEO_AU0828_V4L2
+ dev->v4l2_dev.release = au0828_usb_v4l2_release;
+
/* Create the v4l2_device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 691df9157e51..3b525cb0078f 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -1063,14 +1063,7 @@ static int au0828_v4l2_close(struct file *filp)
res_free(fh, AU0828_RESOURCE_VBI);
}
- if (dev->users == 1) {
- if (dev->dev_state & DEV_DISCONNECTED) {
- au0828_analog_unregister(dev);
- kfree(fh);
- kfree(dev);
- return 0;
- }
-
+ if (dev->users == 1 && video_is_registered(video_devdata(filp))) {
au0828_analog_stream_disable(dev);
au0828_uninit_isoc(dev);