media: v4l2-async: Add notifier operation to destroy asd instances
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Tue, 14 Jun 2022 19:10:48 +0000 (20:10 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Sun, 17 Jul 2022 10:20:08 +0000 (11:20 +0100)
Drivers typically extend the v4l2_async_subdev structure by embedding it
in a driver-specific structure, to store per-subdev custom data. The
v4l2_async_subdev instances are freed by the v4l2-async framework, which
makes this mechanism cumbersome to use safely when custom data needs
special treatment to be destroyed (such as freeing additional memory, or
releasing references to kernel objects).

To ease this, add a .destroy() operation to the
v4l2_async_notifier_operations structure. The operation is called right
before the v4l2_async_subdev is freed, giving drivers a chance to
destroy data if needed.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Documentation/driver-api/media/v4l2-subdev.rst
drivers/media/v4l2-core/v4l2-async.c
include/media/v4l2-async.h

index cf3b52bdbfb9216c53a3f3065ef9c85d9cfb37bc..6f8d79926aa555a83a72ec773f975ecd6991aa4b 100644 (file)
@@ -243,6 +243,12 @@ notifier callback is called. After all subdevices have been located the
 .complete() callback is called. When a subdevice is removed from the
 system the .unbind() method is called. All three callbacks are optional.
 
+Drivers can store any type of custom data in their driver-specific
+:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
+handling when the structure is freed, drivers must implement the ``.destroy()``
+notifier callback. The framework will call it right before freeing the
+:c:type:`v4l2_async_subdev`.
+
 Calling subdev operations
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
index b16f3ce8e5ef1488dcea0b8821fc0c96ab15a1b1..2f1b718a91893d261526476c46cf202d7fc759eb 100644 (file)
@@ -52,6 +52,15 @@ static int v4l2_async_nf_call_complete(struct v4l2_async_notifier *n)
        return n->ops->complete(n);
 }
 
+static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
+                                      struct v4l2_async_subdev *asd)
+{
+       if (!n->ops || !n->ops->destroy)
+               return;
+
+       n->ops->destroy(asd);
+}
+
 static bool match_i2c(struct v4l2_async_notifier *notifier,
                      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
@@ -633,6 +642,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
                }
 
                list_del(&asd->asd_list);
+               v4l2_async_nf_call_destroy(notifier, asd);
                kfree(asd);
        }
 }
index 13ff3ad948f4394fca63b088b87734762e178644..25eb1d138c06902cdca58f49338859eebcf3df79 100644 (file)
@@ -81,6 +81,7 @@ struct v4l2_async_subdev {
  * @complete:  All subdevices have been probed successfully. The complete
  *             callback is only executed for the root notifier.
  * @unbind:    a subdevice is leaving
+ * @destroy:   the asd is about to be freed
  */
 struct v4l2_async_notifier_operations {
        int (*bound)(struct v4l2_async_notifier *notifier,
@@ -90,6 +91,7 @@ struct v4l2_async_notifier_operations {
        void (*unbind)(struct v4l2_async_notifier *notifier,
                       struct v4l2_subdev *subdev,
                       struct v4l2_async_subdev *asd);
+       void (*destroy)(struct v4l2_async_subdev *asd);
 };
 
 /**