Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 823beb7e authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent dc6d2a2f
Loading
Loading
Loading
Loading
+31 −17
Original line number Diff line number Diff line
@@ -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) {
+1 −8
Original line number Diff line number Diff line
@@ -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);