Browse Source

V4L/DVB (11044): v4l2-device: add v4l2_device_disconnect

Call v4l2_device_disconnect when the parent of a hotpluggable device
disconnects. This ensures that you do not have a pointer to a device that
is no longer present.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Hans Verkuil 16 years ago
parent
commit
ae6cfaace1

+ 0 - 1
Documentation/video4linux/CARDLIST.bttv

@@ -157,4 +157,3 @@
 156 -> IVCE-8784                                           [0000:f050,0001:f050,0002:f050,0003:f050]
 156 -> IVCE-8784                                           [0000:f050,0001:f050,0002:f050,0003:f050]
 157 -> Geovision GV-800(S) (master)                        [800a:763d]
 157 -> Geovision GV-800(S) (master)                        [800a:763d]
 158 -> Geovision GV-800(S) (slave)                         [800b:763d,800c:763d,800d:763d]
 158 -> Geovision GV-800(S) (slave)                         [800b:763d,800c:763d,800d:763d]
-159 -> ProVideo PV183                                      [1830:1540,1831:1540,1832:1540,1833:1540,1834:1540,1835:1540,1836:1540,1837:1540]

+ 11 - 0
Documentation/video4linux/v4l2-framework.txt

@@ -105,6 +105,17 @@ You unregister with:
 
 
 Unregistering will also automatically unregister all subdevs from the device.
 Unregistering will also automatically unregister all subdevs from the device.
 
 
+If you have a hotpluggable device (e.g. a USB device), then when a disconnect
+happens the parent device becomes invalid. Since v4l2_device has a pointer to
+that parent device it has to be cleared as well to mark that the parent is
+gone. To do this call:
+
+	v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+
+This does *not* unregister the subdevs, so you still need to call the
+v4l2_device_unregister() function for that. If your driver is not hotpluggable,
+then there is no need to call v4l2_device_disconnect().
+
 Sometimes you need to iterate over all devices registered by a specific
 Sometimes you need to iterate over all devices registered by a specific
 driver. This is usually the case if multiple device drivers use the same
 driver. This is usually the case if multiple device drivers use the same
 hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
 hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv

+ 11 - 4
drivers/media/video/v4l2-device.c

@@ -49,19 +49,26 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
 }
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 
 
+void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
+{
+	if (v4l2_dev->dev) {
+		dev_set_drvdata(v4l2_dev->dev, NULL);
+		v4l2_dev->dev = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
+
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 {
 {
 	struct v4l2_subdev *sd, *next;
 	struct v4l2_subdev *sd, *next;
 
 
 	if (v4l2_dev == NULL)
 	if (v4l2_dev == NULL)
 		return;
 		return;
-	if (v4l2_dev->dev)
-		dev_set_drvdata(v4l2_dev->dev, NULL);
+	v4l2_device_disconnect(v4l2_dev);
+
 	/* Unregister subdevs */
 	/* Unregister subdevs */
 	list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
 	list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
 		v4l2_device_unregister_subdev(sd);
 		v4l2_device_unregister_subdev(sd);
-
-	v4l2_dev->dev = NULL;
 }
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
 

+ 5 - 1
include/media/v4l2-device.h

@@ -53,7 +53,11 @@ struct v4l2_device {
    dev may be NULL in rare cases (ISA devices). In that case you
    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. */
    must fill in the v4l2_dev->name field before calling this function. */
 int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
 int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
-/* Set v4l2_dev->dev->driver_data to NULL and unregister all sub-devices */
+/* Set v4l2_dev->dev to NULL. Call when the USB parent disconnects.
+   Since the parent disappears this ensures that v4l2_dev doesn't have an
+   invalid parent pointer. */
+void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+/* Unregister all sub-devices and any other resources related to v4l2_dev. */
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
 
 
 /* Register a subdev with a v4l2 device. While registered the subdev module
 /* Register a subdev with a v4l2 device. While registered the subdev module