All of lore.kernel.org
 help / color / mirror / Atom feed
* v4l2_device release callback and dsbr100 unlocked_ioctl
@ 2011-01-03 13:54 Hans Verkuil
  2011-01-03 13:54 ` [RFC PATCH 1/4] v4l2-device: add kref and a release function Hans Verkuil
  0 siblings, 1 reply; 5+ messages in thread
From: Hans Verkuil @ 2011-01-03 13:54 UTC (permalink / raw)
  To: linux-media; +Cc: David Ellingsworth


This patch series adds reference counting to v4l2_device and a top-level
release callback. This is needed to correctly handle hotplug disconnects.

There are three reasons why this is needed:

1) drivers with multiple device nodes shouldn't call release() until all
   device nodes are no longer referenced. This is hard to implement without
   reference counting in struct v4l2_device.

2) The typical disconnect sequence is this (from radio-mr800.c):

static void usb_amradio_disconnect(struct usb_interface *intf)
{
        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));

        mutex_lock(&radio->lock);
        /* increase the device node's refcount */
        get_device(&radio->videodev.dev);
        v4l2_device_disconnect(&radio->v4l2_dev);
        video_unregister_device(&radio->videodev);
        mutex_unlock(&radio->lock);
        /* decrease the device node's refcount, allowing it to be released */
        put_device(&radio->videodev.dev);
}

The low-level get/put_device calls are needed because otherwise the
video_unregister_device will cause the video_device's release callback to be
called which kfree()s the radio struct. So without the get_device the
mutex_unlock might access freed memory.

Using such low-level calls is very ugly though, and with the new API it can
be rewritten to:

static void usb_amradio_disconnect(struct usb_interface *intf)
{
        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));

        mutex_lock(&radio->lock);
        v4l2_device_get(&radio->v4l2_dev);
        v4l2_device_disconnect(&radio->v4l2_dev);
        video_unregister_device(&radio->videodev);
        mutex_unlock(&radio->lock);
        v4l2_device_put(&radio->v4l2_dev);
}

3) drivers with a mix of v4l and dvb/alsa/... device nodes need a way to increase
   or decrease the v4l2_device refcount for every non-v4l2 device node that is
   created or removed. The purpose is the same: the top-level release should only
   be called when the last reference is gone.

The other two patches convert dsbr100 to .unlocked_ioctl using core-assisted
locking, and then simplify the code using the proper disconnect construct. The
radio->removed field is deleted since the v4l2 framework will guarantee that
once a device node is unregistered no ioctl can ever be made. So the 'removed'
check is now no longer needed.

The refcount patches have been posted before and are unchanged.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC PATCH 1/4] v4l2-device: add kref and a release function
  2011-01-03 13:54 v4l2_device release callback and dsbr100 unlocked_ioctl Hans Verkuil
@ 2011-01-03 13:54 ` Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 2/4] v4l2-framework.txt: document new v4l2_device release() callback Hans Verkuil
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Hans Verkuil @ 2011-01-03 13:54 UTC (permalink / raw)
  To: linux-media; +Cc: David Ellingsworth

The video_device struct has proper ref counting and its release function
will be called when the last user releases it. But no such support was
available for struct v4l2_device. This made it hard to determine when a
USB driver can release the device if it has multiple device nodes.

With one device node it is easy of course, since when the device node is
released, the whole device can be released.

This patch adds refcounting to v4l2_device. When registering device nodes
the v4l2_device refcount will be increased, when releasing device nodes
it will be decreased. The (optional) release function will be called when
the last device node was released.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/video/v4l2-dev.c    |    8 ++++++++
 drivers/media/video/v4l2-device.c |   15 +++++++++++++++
 include/media/v4l2-device.h       |   11 +++++++++++
 3 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 359e232..ff3aa90 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -143,6 +143,7 @@ static inline void video_put(struct video_device *vdev)
 static void v4l2_device_release(struct device *cd)
 {
 	struct video_device *vdev = to_video_device(cd);
+	struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
 
 	mutex_lock(&videodev_lock);
 	if (video_device[vdev->minor] != vdev) {
@@ -169,6 +170,10 @@ static void v4l2_device_release(struct device *cd)
 	/* Release video_device and perform other
 	   cleanups as needed. */
 	vdev->release(vdev);
+
+	/* Decrease v4l2_device refcount */
+	if (v4l2_dev)
+		v4l2_device_put(v4l2_dev);
 }
 
 static struct class video_class = {
@@ -581,6 +586,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
 		printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
 			name_base, nr, video_device_node_name(vdev));
 
+	/* Increase v4l2_device refcount */
+	if (vdev->v4l2_dev)
+		v4l2_device_get(vdev->v4l2_dev);
 	/* Part 5: Activate this minor. The char device can now be used. */
 	set_bit(V4L2_FL_REGISTERED, &vdev->flags);
 	mutex_lock(&videodev_lock);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 7fe6f92..031ddbc 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -54,6 +54,21 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 
+static void v4l2_device_release(struct kref *ref)
+{
+	struct v4l2_device *v4l2_dev =
+		container_of(ref, struct v4l2_device, ref);
+
+	if (v4l2_dev->release)
+		v4l2_dev->release(v4l2_dev);
+}
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev)
+{
+	return kref_put(&v4l2_dev->ref, v4l2_device_release);
+}
+EXPORT_SYMBOL_GPL(v4l2_device_put);
+
 int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
 						atomic_t *instance)
 {
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
index b16f307..7279fa6 100644
--- a/include/media/v4l2-device.h
+++ b/include/media/v4l2-device.h
@@ -53,8 +53,19 @@ struct v4l2_device {
 	struct v4l2_ctrl_handler *ctrl_handler;
 	/* BKL replacement mutex. Temporary solution only. */
 	struct mutex ioctl_lock;
+	/* Keep track of the references to this struct. */
+	struct kref ref;
+	/* Release function that is called when the ref count goes to 0. */
+	void (*release)(struct v4l2_device *v4l2_dev);
 };
 
+static inline void v4l2_device_get(struct v4l2_device *v4l2_dev)
+{
+	kref_get(&v4l2_dev->ref);
+}
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev);
+
 /* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
    dev may be NULL in rare cases (ISA devices). In that case you
    must fill in the v4l2_dev->name field before calling this function. */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH 2/4] v4l2-framework.txt: document new v4l2_device release() callback
  2011-01-03 13:54 ` [RFC PATCH 1/4] v4l2-device: add kref and a release function Hans Verkuil
@ 2011-01-03 13:54   ` Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 3/4] dsbr100: convert to unlocked_ioctl Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 4/4] dsbr100: ensure correct disconnect sequence Hans Verkuil
  2 siblings, 0 replies; 5+ messages in thread
From: Hans Verkuil @ 2011-01-03 13:54 UTC (permalink / raw)
  To: linux-media; +Cc: David Ellingsworth

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 Documentation/video4linux/v4l2-framework.txt |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index f22f35c..a6003d7 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -167,6 +167,21 @@ static int __devinit drv_probe(struct pci_dev *pdev,
 	state->instance = atomic_inc_return(&drv_instance) - 1;
 }
 
+If you have multiple device nodes then it can be difficult to know when it is
+safe to unregister v4l2_device. For this purpose v4l2_device has refcounting
+support. The refcount is increased whenever video_register_device is called and
+it is decreased whenever that device node is released. When the refcount reaches
+zero, then the v4l2_device release() callback is called. You can do your final
+cleanup there.
+
+If other device nodes (e.g. ALSA) are created, then you can increase and
+decrease the refcount manually as well by calling:
+
+void v4l2_device_get(struct v4l2_device *v4l2_dev);
+
+or:
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev);
 
 struct v4l2_subdev
 ------------------
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH 3/4] dsbr100: convert to unlocked_ioctl
  2011-01-03 13:54 ` [RFC PATCH 1/4] v4l2-device: add kref and a release function Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 2/4] v4l2-framework.txt: document new v4l2_device release() callback Hans Verkuil
@ 2011-01-03 13:54   ` Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 4/4] dsbr100: ensure correct disconnect sequence Hans Verkuil
  2 siblings, 0 replies; 5+ messages in thread
From: Hans Verkuil @ 2011-01-03 13:54 UTC (permalink / raw)
  To: linux-media; +Cc: David Ellingsworth

Use core-assisted locking so .ioctl can be replaced by .unlocked_ioctl.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/radio/dsbr100.c |   79 ++++++++++++++++-------------------------
 1 files changed, 31 insertions(+), 48 deletions(-)

diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index ed9cd7a..bf2dd6f 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -148,7 +148,7 @@ struct dsbr100_device {
 	struct v4l2_device v4l2_dev;
 
 	u8 *transfer_buffer;
-	struct mutex lock;	/* buffer locking */
+	struct mutex v4l2_lock;
 	int curfreq;
 	int stereo;
 	int removed;
@@ -182,8 +182,6 @@ static int dsbr100_start(struct dsbr100_device *radio)
 	int retval;
 	int request;
 
-	mutex_lock(&radio->lock);
-
 	retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		USB_REQ_GET_STATUS,
@@ -207,11 +205,9 @@ static int dsbr100_start(struct dsbr100_device *radio)
 	}
 
 	radio->status = STARTED;
-	mutex_unlock(&radio->lock);
 	return (radio->transfer_buffer)[0];
 
 usb_control_msg_failed:
-	mutex_unlock(&radio->lock);
 	dev_err(&radio->usbdev->dev,
 		"%s - usb_control_msg returned %i, request %i\n",
 			__func__, retval, request);
@@ -225,8 +221,6 @@ static int dsbr100_stop(struct dsbr100_device *radio)
 	int retval;
 	int request;
 
-	mutex_lock(&radio->lock);
-
 	retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		USB_REQ_GET_STATUS,
@@ -250,11 +244,9 @@ static int dsbr100_stop(struct dsbr100_device *radio)
 	}
 
 	radio->status = STOPPED;
-	mutex_unlock(&radio->lock);
 	return (radio->transfer_buffer)[0];
 
 usb_control_msg_failed:
-	mutex_unlock(&radio->lock);
 	dev_err(&radio->usbdev->dev,
 		"%s - usb_control_msg returned %i, request %i\n",
 			__func__, retval, request);
@@ -269,8 +261,6 @@ static int dsbr100_setfreq(struct dsbr100_device *radio)
 	int request;
 	int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
 
-	mutex_lock(&radio->lock);
-
 	retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		DSB100_TUNE,
@@ -306,12 +296,10 @@ static int dsbr100_setfreq(struct dsbr100_device *radio)
 	}
 
 	radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
-	mutex_unlock(&radio->lock);
 	return (radio->transfer_buffer)[0];
 
 usb_control_msg_failed:
 	radio->stereo = -1;
-	mutex_unlock(&radio->lock);
 	dev_err(&radio->usbdev->dev,
 		"%s - usb_control_msg returned %i, request %i\n",
 			__func__, retval, request);
@@ -324,8 +312,6 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
 {
 	int retval;
 
-	mutex_lock(&radio->lock);
-
 	retval = usb_control_msg(radio->usbdev,
 		usb_rcvctrlpipe(radio->usbdev, 0),
 		USB_REQ_GET_STATUS,
@@ -340,33 +326,8 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
 	} else {
 		radio->stereo = !(radio->transfer_buffer[0] & 0x01);
 	}
-
-	mutex_unlock(&radio->lock);
-}
-
-/* USB subsystem interface begins here */
-
-/*
- * Handle unplugging of the device.
- * We call video_unregister_device in any case.
- * The last function called in this procedure is
- * usb_dsbr100_video_device_release
- */
-static void usb_dsbr100_disconnect(struct usb_interface *intf)
-{
-	struct dsbr100_device *radio = usb_get_intfdata(intf);
-
-	usb_set_intfdata (intf, NULL);
-
-	mutex_lock(&radio->lock);
-	radio->removed = 1;
-	mutex_unlock(&radio->lock);
-
-	video_unregister_device(&radio->videodev);
-	v4l2_device_disconnect(&radio->v4l2_dev);
 }
 
-
 static int vidioc_querycap(struct file *file, void *priv,
 					struct v4l2_capability *v)
 {
@@ -432,9 +393,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 	if (radio->removed)
 		return -EIO;
 
-	mutex_lock(&radio->lock);
 	radio->curfreq = f->frequency;
-	mutex_unlock(&radio->lock);
 
 	retval = dsbr100_setfreq(radio);
 	if (retval < 0)
@@ -548,12 +507,36 @@ static int vidioc_s_audio(struct file *file, void *priv,
 	return 0;
 }
 
+/* USB subsystem interface begins here */
+
+/*
+ * Handle unplugging of the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_dsbr100_video_device_release
+ */
+static void usb_dsbr100_disconnect(struct usb_interface *intf)
+{
+	struct dsbr100_device *radio = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+
+	mutex_lock(&radio->v4l2_lock);
+	radio->removed = 1;
+	mutex_unlock(&radio->v4l2_lock);
+
+	video_unregister_device(&radio->videodev);
+	v4l2_device_disconnect(&radio->v4l2_dev);
+}
+
+
 /* Suspend device - stop device. */
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 	int retval;
 
+	mutex_lock(&radio->v4l2_lock);
 	if (radio->status == STARTED) {
 		retval = dsbr100_stop(radio);
 		if (retval < 0)
@@ -564,11 +547,9 @@ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 		 * we set status equal to STARTED.
 		 * On resume we will check status and run radio if needed.
 		 */
-
-		mutex_lock(&radio->lock);
 		radio->status = STARTED;
-		mutex_unlock(&radio->lock);
 	}
+	mutex_unlock(&radio->v4l2_lock);
 
 	dev_info(&intf->dev, "going into suspend..\n");
 
@@ -581,11 +562,13 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 	int retval;
 
+	mutex_lock(&radio->v4l2_lock);
 	if (radio->status == STARTED) {
 		retval = dsbr100_start(radio);
 		if (retval < 0)
 			dev_warn(&intf->dev, "dsbr100_start failed\n");
 	}
+	mutex_unlock(&radio->v4l2_lock);
 
 	dev_info(&intf->dev, "coming out of suspend..\n");
 
@@ -605,7 +588,7 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
 /* File system interface */
 static const struct v4l2_file_operations usb_dsbr100_fops = {
 	.owner		= THIS_MODULE,
-	.ioctl		= video_ioctl2,
+	.unlocked_ioctl	= video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
@@ -653,13 +636,13 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 		return retval;
 	}
 
+	mutex_init(&radio->v4l2_lock);
 	strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
 	radio->videodev.v4l2_dev = v4l2_dev;
 	radio->videodev.fops = &usb_dsbr100_fops;
 	radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
 	radio->videodev.release = usb_dsbr100_video_device_release;
-
-	mutex_init(&radio->lock);
+	radio->videodev.lock = &radio->v4l2_lock;
 
 	radio->removed = 0;
 	radio->usbdev = interface_to_usbdev(intf);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH 4/4] dsbr100: ensure correct disconnect sequence.
  2011-01-03 13:54 ` [RFC PATCH 1/4] v4l2-device: add kref and a release function Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 2/4] v4l2-framework.txt: document new v4l2_device release() callback Hans Verkuil
  2011-01-03 13:54   ` [RFC PATCH 3/4] dsbr100: convert to unlocked_ioctl Hans Verkuil
@ 2011-01-03 13:54   ` Hans Verkuil
  2 siblings, 0 replies; 5+ messages in thread
From: Hans Verkuil @ 2011-01-03 13:54 UTC (permalink / raw)
  To: linux-media; +Cc: David Ellingsworth

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/radio/dsbr100.c |   58 ++++++++--------------------------------
 1 files changed, 12 insertions(+), 46 deletions(-)

diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index bf2dd6f..b5dff79 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -129,7 +129,7 @@ devices, that would be 76 and 91.  */
 #define STARTED	0
 #define STOPPED	1
 
-#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
+#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
 
 static int usb_dsbr100_probe(struct usb_interface *intf,
 			     const struct usb_device_id *id);
@@ -151,7 +151,6 @@ struct dsbr100_device {
 	struct mutex v4l2_lock;
 	int curfreq;
 	int stereo;
-	int removed;
 	int status;
 };
 
@@ -346,10 +345,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 {
 	struct dsbr100_device *radio = video_drvdata(file);
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
 	if (v->index > 0)
 		return -EINVAL;
 
@@ -371,16 +366,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct dsbr100_device *radio = video_drvdata(file);
-
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	return 0;
+	return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
@@ -389,10 +375,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 	struct dsbr100_device *radio = video_drvdata(file);
 	int retval;
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
 	radio->curfreq = f->frequency;
 
 	retval = dsbr100_setfreq(radio);
@@ -406,10 +388,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct dsbr100_device *radio = video_drvdata(file);
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = radio->curfreq;
 	return 0;
@@ -431,10 +409,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
 	struct dsbr100_device *radio = video_drvdata(file);
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 		ctrl->value = radio->status;
@@ -449,10 +423,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 	struct dsbr100_device *radio = video_drvdata(file);
 	int retval;
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 		if (ctrl->value) {
@@ -494,17 +464,13 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-	if (i != 0)
-		return -EINVAL;
-	return 0;
+	return i ? -EINVAL : 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv,
 					struct v4l2_audio *a)
 {
-	if (a->index != 0)
-		return -EINVAL;
-	return 0;
+	return a->index ? -EINVAL : 0;
 }
 
 /* USB subsystem interface begins here */
@@ -519,14 +485,14 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 
-	usb_set_intfdata(intf, NULL);
-
 	mutex_lock(&radio->v4l2_lock);
-	radio->removed = 1;
-	mutex_unlock(&radio->v4l2_lock);
+	usb_set_intfdata(intf, NULL);
 
+	v4l2_device_get(&radio->v4l2_dev);
 	video_unregister_device(&radio->videodev);
 	v4l2_device_disconnect(&radio->v4l2_dev);
+	mutex_unlock(&radio->v4l2_lock);
+	v4l2_device_put(&radio->v4l2_dev);
 }
 
 
@@ -576,9 +542,9 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
 }
 
 /* free data structures */
-static void usb_dsbr100_video_device_release(struct video_device *videodev)
+static void usb_dsbr100_release(struct v4l2_device *v4l2_dev)
 {
-	struct dsbr100_device *radio = videodev_to_radio(videodev);
+	struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
 
 	v4l2_device_unregister(&radio->v4l2_dev);
 	kfree(radio->transfer_buffer);
@@ -627,6 +593,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 	}
 
 	v4l2_dev = &radio->v4l2_dev;
+	v4l2_dev->release = usb_dsbr100_release;
 
 	retval = v4l2_device_register(&intf->dev, v4l2_dev);
 	if (retval < 0) {
@@ -641,10 +608,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 	radio->videodev.v4l2_dev = v4l2_dev;
 	radio->videodev.fops = &usb_dsbr100_fops;
 	radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
-	radio->videodev.release = usb_dsbr100_video_device_release;
+	radio->videodev.release = video_device_release_empty;
 	radio->videodev.lock = &radio->v4l2_lock;
 
-	radio->removed = 0;
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->curfreq = FREQ_MIN * FREQ_MUL;
 	radio->status = STOPPED;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-01-03 13:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-03 13:54 v4l2_device release callback and dsbr100 unlocked_ioctl Hans Verkuil
2011-01-03 13:54 ` [RFC PATCH 1/4] v4l2-device: add kref and a release function Hans Verkuil
2011-01-03 13:54   ` [RFC PATCH 2/4] v4l2-framework.txt: document new v4l2_device release() callback Hans Verkuil
2011-01-03 13:54   ` [RFC PATCH 3/4] dsbr100: convert to unlocked_ioctl Hans Verkuil
2011-01-03 13:54   ` [RFC PATCH 4/4] dsbr100: ensure correct disconnect sequence Hans Verkuil

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.