Skip to content

Commit

Permalink
V4L/DVB: hdpvr: fix disconnect sequence
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed May 19, 2010
1 parent a2bdc5e commit f2b305c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 28 deletions.
33 changes: 5 additions & 28 deletions drivers/media/video/hdpvr/hdpvr-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,6 @@ static int hdpvr_probe(struct usb_interface *interface,
}
#endif /* CONFIG_I2C */

/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);

/* let the user know what node this device is now attached to */
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
video_device_node_name(dev->video_dev));
Expand All @@ -391,44 +388,24 @@ static int hdpvr_probe(struct usb_interface *interface,

static void hdpvr_disconnect(struct usb_interface *interface)
{
struct hdpvr_device *dev;

dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));

v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
video_device_node_name(dev->video_dev));
/* prevent more I/O from starting and stop any ongoing */
mutex_lock(&dev->io_mutex);
dev->status = STATUS_DISCONNECTED;
v4l2_device_disconnect(&dev->v4l2_dev);
video_unregister_device(dev->video_dev);
wake_up_interruptible(&dev->wait_data);
wake_up_interruptible(&dev->wait_buffer);
mutex_unlock(&dev->io_mutex);
v4l2_device_disconnect(&dev->v4l2_dev);
msleep(100);
flush_workqueue(dev->workqueue);
mutex_lock(&dev->io_mutex);
hdpvr_cancel_queue(dev);
destroy_workqueue(dev->workqueue);
mutex_unlock(&dev->io_mutex);

/* deregister I2C adapter */
#ifdef CONFIG_I2C
mutex_lock(&dev->i2c_mutex);
if (dev->i2c_adapter)
i2c_del_adapter(dev->i2c_adapter);
kfree(dev->i2c_adapter);
dev->i2c_adapter = NULL;
mutex_unlock(&dev->i2c_mutex);
#endif /* CONFIG_I2C */

video_unregister_device(dev->video_dev);
atomic_dec(&dev_nr);

v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
video_device_node_name(dev->video_dev));

v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev->usbc_buf);
kfree(dev);
}


Expand Down
18 changes: 18 additions & 0 deletions drivers/media/video/hdpvr/hdpvr-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,24 @@ static void hdpvr_device_release(struct video_device *vdev)
struct hdpvr_device *dev = video_get_drvdata(vdev);

hdpvr_delete(dev);
mutex_lock(&dev->io_mutex);
destroy_workqueue(dev->workqueue);
mutex_unlock(&dev->io_mutex);

v4l2_device_unregister(&dev->v4l2_dev);

/* deregister I2C adapter */
#ifdef CONFIG_I2C
mutex_lock(&dev->i2c_mutex);
if (dev->i2c_adapter)
i2c_del_adapter(dev->i2c_adapter);
kfree(dev->i2c_adapter);
dev->i2c_adapter = NULL;
mutex_unlock(&dev->i2c_mutex);
#endif /* CONFIG_I2C */

kfree(dev->usbc_buf);
kfree(dev);
}

static const struct video_device hdpvr_video_template = {
Expand Down
5 changes: 5 additions & 0 deletions drivers/media/video/hdpvr/hdpvr.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ struct hdpvr_device {
u8 *usbc_buf;
};

static inline struct hdpvr_device *to_hdpvr_dev(struct v4l2_device *v4l2_dev)
{
return container_of(v4l2_dev, struct hdpvr_device, v4l2_dev);
}


/* buffer one bulk urb of data */
struct hdpvr_buffer {
Expand Down

0 comments on commit f2b305c

Please sign in to comment.