summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@linux.intel.com>2013-12-12 16:36:46 +0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-13 20:41:44 +0400
commitb2a06aecb24329e16edc3108b8192d65ace8da75 (patch)
tree114ac342659d1e9fb598cb55bc93d158369b735b
parent85de721c46ba8ad9b283b2b3e307c9a3e8425042 (diff)
downloadlinux-b2a06aecb24329e16edc3108b8192d65ace8da75.tar.xz
[media] v4l: Only get module if it's different than the driver for v4l2_dev
When the sub-device is registered, increment the use count of the sub-device owner only if it's different from the owner of the driver for the media device. This avoids increasing the use count by the module itself and thus making it possible to unload it when it's not in use. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c18
-rw-r--r--include/media/v4l2-subdev.h1
2 files changed, 16 insertions, 3 deletions
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 02d1b6327117..015f92aab44a 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -158,7 +158,17 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
/* Warn if we apparently re-register a subdev */
WARN_ON(sd->v4l2_dev != NULL);
- if (!try_module_get(sd->owner))
+ /*
+ * The reason to acquire the module here is to avoid unloading
+ * a module of sub-device which is registered to a media
+ * device. To make it possible to unload modules for media
+ * devices that also register sub-devices, do not
+ * try_module_get() such sub-device owners.
+ */
+ sd->owner_v4l2_dev = v4l2_dev->dev && v4l2_dev->dev->driver &&
+ sd->owner == v4l2_dev->dev->driver->owner;
+
+ if (!sd->owner_v4l2_dev && !try_module_get(sd->owner))
return -ENODEV;
sd->v4l2_dev = v4l2_dev;
@@ -192,7 +202,8 @@ error_unregister:
if (sd->internal_ops && sd->internal_ops->unregistered)
sd->internal_ops->unregistered(sd);
error_module:
- module_put(sd->owner);
+ if (!sd->owner_v4l2_dev)
+ module_put(sd->owner);
sd->v4l2_dev = NULL;
return err;
}
@@ -280,6 +291,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
}
#endif
video_unregister_device(sd->devnode);
- module_put(sd->owner);
+ if (!sd->owner_v4l2_dev)
+ module_put(sd->owner);
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index ee1cb2d354a8..ee0ae769ca94 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -584,6 +584,7 @@ struct v4l2_subdev {
#endif
struct list_head list;
struct module *owner;
+ bool owner_v4l2_dev;
u32 flags;
struct v4l2_device *v4l2_dev;
const struct v4l2_subdev_ops *ops;