Commit ae6cfaac authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6273fda6
...@@ -157,4 +157,3 @@ ...@@ -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]
...@@ -105,6 +105,17 @@ You unregister with: ...@@ -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
......
...@@ -49,19 +49,26 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) ...@@ -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) v4l2_device_disconnect(v4l2_dev);
dev_set_drvdata(v4l2_dev->dev, NULL);
/* 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);
......
...@@ -53,7 +53,11 @@ struct v4l2_device { ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment