@@ -705,6 +705,30 @@ void media_device_unregister_entity_notify(struct media_device *mdev,
}
EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
+static void __media_device_release(struct media_device *mdev)
+{
+ dev_dbg(mdev->dev, "Media device released\n");
+
+ ida_destroy(&mdev->entity_internal_idx);
+ mdev->entity_internal_idx_max = 0;
+ media_graph_walk_cleanup(&mdev->pm_count_walk);
+ mutex_destroy(&mdev->graph_mutex);
+ mutex_destroy(&mdev->req_queue_mutex);
+}
+
+static void media_device_release(struct media_devnode *devnode)
+{
+ struct media_device *mdev = to_media_device(devnode);
+
+ __media_device_release(mdev);
+
+ if (mdev->ops && mdev->ops->release)
+ mdev->ops->release(mdev);
+ else
+ dev_warn(mdev->dev,
+ "calling media_device_release but no release callback set!\n");
+}
+
void media_device_init(struct media_device *mdev)
{
INIT_LIST_HEAD(&mdev->entities);
@@ -717,6 +741,17 @@ void media_device_init(struct media_device *mdev)
mutex_init(&mdev->graph_mutex);
ida_init(&mdev->entity_internal_idx);
atomic_set(&mdev->request_id, 0);
+
+ /*
+ * Set the release callback to the media device if we have one
+ * set. Otherwise, the caller is responsible for calling
+ * media_device_cleanup() in order to release resources
+ * related to the media device, i.e. the media device is not
+ * refcounted. This is deprecated.
+ */
+ if (mdev->ops && mdev->ops->release)
+ mdev->devnode.release = media_device_release;
+
media_devnode_init(&mdev->devnode);
if (!*mdev->bus_info)
@@ -729,12 +764,8 @@ EXPORT_SYMBOL_GPL(media_device_init);
void media_device_cleanup(struct media_device *mdev)
{
- ida_destroy(&mdev->entity_internal_idx);
- mdev->entity_internal_idx_max = 0;
- media_graph_walk_cleanup(&mdev->pm_count_walk);
- mutex_destroy(&mdev->graph_mutex);
- mutex_destroy(&mdev->req_queue_mutex);
- put_device(&mdev->devnode.dev);
+ __media_device_release(mdev);
+ media_device_put(mdev);
}
EXPORT_SYMBOL_GPL(media_device_cleanup);
@@ -62,6 +62,7 @@ struct media_entity_notify {
* request (and thus the buffer) must be available to the driver.
* And once a buffer is queued, then the driver can complete
* or delete objects from the request before req_queue exits.
+ * @release: Release the resources of the media device.
*/
struct media_device_ops {
int (*link_notify)(struct media_link *link, u32 flags,
@@ -70,6 +71,7 @@ struct media_device_ops {
void (*req_free)(struct media_request *req);
int (*req_validate)(struct media_request *req);
void (*req_queue)(struct media_request *req);
+ void (*release)(struct media_device *mdev);
};
/**
@@ -219,6 +221,30 @@ struct usb_device;
*/
void media_device_init(struct media_device *mdev);
+/**
+ * media_device_get() - Get a reference to a media device
+ *
+ * @mdev: media device
+ */
+#define media_device_get(mdev) \
+ do { \
+ dev_dbg((mdev)->dev, "%s: get media device %s\n", \
+ __func__, (mdev)->bus_info); \
+ get_device(&(mdev)->devnode.dev); \
+ } while (0)
+
+/**
+ * media_device_put() - Put a reference to a media device
+ *
+ * @mdev: media device
+ */
+#define media_device_put(mdev) \
+ do { \
+ dev_dbg((mdev)->dev, "%s: put media device %s\n", \
+ __func__, (mdev)->bus_info); \
+ put_device(&(mdev)->devnode.dev); \
+ } while (0)
+
/**
* media_device_cleanup() - Cleanups a media device element
*
@@ -432,6 +458,8 @@ void __media_device_usb_init(struct media_device *mdev,
const char *driver_name);
#else
+#define media_device_get(mdev) do { } while (0)
+#define media_device_put(mdev) do { } while (0)
static inline int media_device_register(struct media_device *mdev)
{
return 0;
As the struct media_device embeds struct media_devnode, the lifetime of that object must be that same than that of the media_device. References are obtained by media_device_get() and released by media_device_put(). In order to use refcounting, the driver must set the release callback before calling media_device_init() on the media device. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> --- drivers/media/mc/mc-device.c | 43 +++++++++++++++++++++++++++++++----- include/media/media-device.h | 28 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-)