diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-03-11 14:16:45 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-25 19:10:30 +0100 |
commit | 823beb7e22d04ed545e7adfcd5ec8db934218872 (patch) | |
tree | 2a24866bde29638428ebf82d2945ef7c4ce0e0dd /drivers/media/usb/au0828 | |
parent | [media] au8522_decoder: remove obsolete control ops (diff) | |
download | linux-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.c | 48 | ||||
-rw-r--r-- | drivers/media/usb/au0828/au0828-video.c | 9 |
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); |