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@xxxxxxxxxxxxxxx> --- drivers/media/mc/mc-device.c | 43 +++++++++++++++++++++++++++++++----- include/media/media-device.h | 28 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index f4d880fcd977..c13cbdfdbaab 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -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); diff --git a/include/media/media-device.h b/include/media/media-device.h index a33820075aa4..7e8bca6756ba 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -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; -- 2.30.2