@@ -700,6 +700,31 @@ 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);
+
+ if (mdev->ops && mdev->ops->release) {
+ /*
+ * If release op isn't set, __media_device_release() is called
+ * via media_device_cleanup().
+ */
+ __media_device_release(mdev);
+ mdev->ops->release(mdev);
+ }
+}
+
void media_device_init(struct media_device *mdev)
{
INIT_LIST_HEAD(&mdev->entities);
@@ -713,6 +738,7 @@ void media_device_init(struct media_device *mdev)
ida_init(&mdev->entity_internal_idx);
atomic_set(&mdev->request_id, 0);
+ mdev->devnode.release = media_device_release;
media_devnode_init(&mdev->devnode);
if (!*mdev->bus_info)
@@ -725,12 +751,9 @@ 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);
+ WARN_ON(mdev->ops && mdev->ops->release);
+ __media_device_release(mdev);
+ media_device_put(mdev);
}
EXPORT_SYMBOL_GPL(media_device_cleanup);
@@ -200,6 +200,7 @@ static const struct file_operations media_devnode_fops = {
void media_devnode_init(struct media_devnode *devnode)
{
device_initialize(&devnode->dev);
+ devnode->dev.release = media_devnode_release;
}
int __must_check media_devnode_register(struct media_devnode *devnode,
@@ -229,7 +230,6 @@ int __must_check media_devnode_register(struct media_devnode *devnode,
devnode->dev.bus = &media_bus_type;
devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
- devnode->dev.release = media_devnode_release;
if (devnode->parent)
devnode->dev.parent = devnode->parent;
dev_set_name(&devnode->dev, "media%d", devnode->minor);
@@ -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,32 @@ struct usb_device;
*/
void media_device_init(struct media_device *mdev);
+/**
+ * media_device_get() - atomically increment the reference count for the media
+ * device
+ *
+ * Returns: the media device
+ *
+ * @mdev: media device
+ */
+static inline struct media_device *media_device_get(struct media_device *mdev)
+{
+ get_device(&mdev->devnode.dev);
+
+ return mdev;
+}
+
+/**
+ * media_device_put() - atomically decrement the reference count for the media
+ * device
+ *
+ * @mdev: media device
+ */
+static inline void media_device_put(struct media_device *mdev)
+{
+ put_device(&mdev->devnode.dev);
+}
+
/**
* media_device_cleanup() - Cleanups a media device element
*
@@ -435,6 +463,13 @@ void __media_device_usb_init(struct media_device *mdev,
static inline void media_device_init(struct media_device *mdev)
{
}
+static inline struct media_device *media_device_get(struct media_device *mdev)
+{
+ return NULL;
+}
+static inline void media_device_put(struct media_device *mdev)
+{
+}
static inline int media_device_register(struct media_device *mdev)
{
return 0;