devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: linux-media@vger.kernel.org
Cc: niklas.soderlund@ragnatech.se, maxime.ripard@free-electrons.com,
	robh@kernel.org, hverkuil@xs4all.nl,
	laurent.pinchart@ideasonboard.com, devicetree@vger.kernel.org,
	pavel@ucw.cz, sre@kernel.org
Subject: [PATCH v12 15/26] v4l: async: Allow binding notifiers to sub-devices
Date: Tue, 12 Sep 2017 16:41:49 +0300	[thread overview]
Message-ID: <20170912134200.19556-16-sakari.ailus@linux.intel.com> (raw)
In-Reply-To: <20170912134200.19556-1-sakari.ailus@linux.intel.com>

Registering a notifier has required the knowledge of struct v4l2_device
for the reason that sub-devices generally are registered to the
v4l2_device (as well as the media device, also available through
v4l2_device).

This information is not available for sub-device drivers at probe time.

What this patch does is that it allows registering notifiers without
having v4l2_device around. Instead the sub-device pointer is stored in the
notifier. Once the sub-device of the driver that registered the notifier
is registered, the notifier will gain the knowledge of the v4l2_device,
and the binding of async sub-devices from the sub-device driver's notifier
may proceed.

The root notifier's complete callback is only called when all sub-device
notifiers are completed.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 219 ++++++++++++++++++++++++++++++-----
 include/media/v4l2-async.h           |  16 ++-
 2 files changed, 204 insertions(+), 31 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 4525b03d59c1..5082b01d2b96 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -53,6 +53,10 @@ static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
 	return n->ops->complete(n);
 }
 
+static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+				   struct v4l2_subdev *sd,
+				   struct v4l2_async_subdev *asd);
+
 static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
 #if IS_ENABLED(CONFIG_I2C)
@@ -124,14 +128,128 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
 	return NULL;
 }
 
+/* Find the sub-device notifier registered by a sub-device driver. */
+static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
+	struct v4l2_subdev *sd)
+{
+	struct v4l2_async_notifier *n;
+
+	list_for_each_entry(n, &notifier_list, list)
+		if (n->sd == sd)
+			return n;
+
+	return NULL;
+}
+
+/* Return true if all sub-device notifiers are complete, false otherwise. */
+static bool v4l2_async_subdev_notifiers_complete(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd;
+
+	if (!list_empty(&notifier->waiting))
+		return false;
+
+	list_for_each_entry(sd, &notifier->done, async_list) {
+		struct v4l2_async_notifier *subdev_notifier =
+			v4l2_async_find_subdev_notifier(sd);
+
+		if (!subdev_notifier)
+			continue;
+
+		if (!v4l2_async_subdev_notifiers_complete(subdev_notifier))
+			return false;
+	}
+
+	return true;
+}
+
+/* Get v4l2_device related to the notifier if one can be found. */
+static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
+	struct v4l2_async_notifier *notifier)
+{
+	while (notifier->parent)
+		notifier = notifier->parent;
+
+	return notifier->v4l2_dev;
+}
+
+/* Test all async sub-devices in a notifier for a match. */
+static int v4l2_async_notifier_try_all_subdevs(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd;
+
+	if (!v4l2_async_notifier_find_v4l2_dev(notifier))
+		return 0;
+
+again:
+	list_for_each_entry(sd, &subdev_list, async_list) {
+		struct v4l2_async_subdev *asd;
+		int ret;
+
+		asd = v4l2_async_find_match(notifier, sd);
+		if (!asd)
+			continue;
+
+		ret = v4l2_async_match_notify(notifier, sd, asd);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * v4l2_async_match_notify() may lead to registering a
+		 * new notifier and thus changing the async subdevs
+		 * list. In order to proceed safely from here, restart
+		 * parsing the list from the beginning.
+		 */
+		goto again;
+	}
+
+	return 0;
+}
+
+/* Try completing a notifier. */
+static int v4l2_async_notifier_try_complete(
+	struct v4l2_async_notifier *notifier)
+{
+	do {
+		int ret;
+
+		/* Any local async sub-devices left? */
+		if (!list_empty(&notifier->waiting))
+			return 0;
+
+		/*
+		 * Any sub-device notifiers waiting for async subdevs
+		 * to be bound?
+		 */
+		if (!v4l2_async_subdev_notifiers_complete(notifier))
+			return 0;
+
+		/* Proceed completing the notifier */
+		ret = v4l2_async_notifier_call_complete(notifier);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * Obtain notifier's parent. If there is one, repeat
+		 * the process, otherwise we're done here.
+		 */
+	} while ((notifier = notifier->parent));
+
+	return 0;
+}
+
 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *sd,
 				   struct v4l2_async_subdev *asd)
 {
+	struct v4l2_async_notifier *subdev_notifier;
 	int ret;
 
-	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
-	if (ret < 0)
+	ret = v4l2_device_register_subdev(
+		v4l2_async_notifier_find_v4l2_dev(notifier), sd);
+	if (ret)
 		return ret;
 
 	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
@@ -148,10 +266,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	/* Move from the global subdevice list to notifier's done */
 	list_move(&sd->async_list, &notifier->done);
 
-	if (list_empty(&notifier->waiting))
-		return v4l2_async_notifier_call_complete(notifier);
+	/*
+	 * See if the sub-device has a notifier. If it does, proceed
+	 * with checking for its async sub-devices.
+	 */
+	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
+	if (subdev_notifier && !subdev_notifier->parent) {
+		subdev_notifier->parent = notifier;
+		ret = v4l2_async_notifier_try_all_subdevs(subdev_notifier);
+		if (ret)
+			return ret;
+	}
 
-	return 0;
+	/* Try completing the notifier and its parent(s). */
+	return v4l2_async_notifier_try_complete(notifier);
 }
 
 static void v4l2_async_cleanup(struct v4l2_subdev *sd)
@@ -163,17 +291,15 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	sd->dev = NULL;
 }
 
-int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
-				 struct v4l2_async_notifier *notifier)
+static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_subdev *sd, *tmp;
 	struct v4l2_async_subdev *asd;
+	int ret;
 	int i;
 
-	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
 		return -EINVAL;
 
-	notifier->v4l2_dev = v4l2_dev;
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
@@ -200,18 +326,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
 	mutex_lock(&list_lock);
 
-	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
-		int ret;
-
-		asd = v4l2_async_find_match(notifier, sd);
-		if (!asd)
-			continue;
-
-		ret = v4l2_async_match_notify(notifier, sd, asd);
-		if (ret < 0) {
-			mutex_unlock(&list_lock);
-			return ret;
-		}
+	ret = v4l2_async_notifier_try_all_subdevs(notifier);
+	if (ret) {
+		mutex_unlock(&list_lock);
+		return ret;
 	}
 
 	/* Keep also completed notifiers on the list */
@@ -221,29 +339,70 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
 	return 0;
 }
+
+int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
+				 struct v4l2_async_notifier *notifier)
+{
+	if (WARN_ON(!v4l2_dev || notifier->sd))
+		return -EINVAL;
+
+	notifier->v4l2_dev = v4l2_dev;
+
+	return __v4l2_async_notifier_register(notifier);
+}
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
-void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
+					struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_subdev *sd, *tmp;
+	if (WARN_ON(!sd || notifier->v4l2_dev))
+		return -EINVAL;
 
-	if (!notifier->v4l2_dev)
-		return;
+	notifier->sd = sd;
 
-	mutex_lock(&list_lock);
+	return __v4l2_async_notifier_register(notifier);
+}
+EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
 
-	list_del(&notifier->list);
+/* Unbind all sub-devices in the notifier tree. */
+static void v4l2_async_notifier_unbind_all_subdevs(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd, *tmp;
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
+		struct v4l2_async_notifier *subdev_notifier =
+			v4l2_async_find_subdev_notifier(sd);
+
+		if (subdev_notifier)
+			v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
+
 		v4l2_async_cleanup(sd);
 
 		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
-	}
 
-	mutex_unlock(&list_lock);
+		list_del(&sd->async_list);
+		list_add(&sd->async_list, &subdev_list);
+	}
 
+	notifier->parent = NULL;
+	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
 }
+
+void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+{
+	if (!notifier->v4l2_dev && !notifier->sd)
+		return;
+
+	mutex_lock(&list_lock);
+
+	v4l2_async_notifier_unbind_all_subdevs(notifier);
+
+	list_del(&notifier->list);
+
+	mutex_unlock(&list_lock);
+}
 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 
 void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 3bc8a7c0d83f..a13803a6371d 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -102,7 +102,9 @@ struct v4l2_async_notifier_operations {
  * @num_subdevs: number of subdevices used in the subdevs array
  * @max_subdevs: number of subdevices allocated in the subdevs array
  * @subdevs:	array of pointers to subdevice descriptors
- * @v4l2_dev:	pointer to struct v4l2_device
+ * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
+ * @sd:		sub-device that registered the notifier, NULL otherwise
+ * @parent:	parent notifier
  * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
  * @done:	list of struct v4l2_subdev, already probed
  * @list:	member in a global list of notifiers
@@ -113,6 +115,8 @@ struct v4l2_async_notifier {
 	unsigned int max_subdevs;
 	struct v4l2_async_subdev **subdevs;
 	struct v4l2_device *v4l2_dev;
+	struct v4l2_subdev *sd;
+	struct v4l2_async_notifier *parent;
 	struct list_head waiting;
 	struct list_head done;
 	struct list_head list;
@@ -128,6 +132,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 				 struct v4l2_async_notifier *notifier);
 
 /**
+ * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous
+ *					 notifier for a sub-device
+ *
+ * @sd: pointer to &struct v4l2_subdev
+ * @notifier: pointer to &struct v4l2_async_notifier
+ */
+int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
+					struct v4l2_async_notifier *notifier);
+
+/**
  * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier
  *
  * @notifier: pointer to &struct v4l2_async_notifier
-- 
2.11.0

  parent reply	other threads:[~2017-09-12 13:41 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-12 13:41 [PATCH v12 00/30] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 03/26] v4l: async: Use more intuitive names for internal functions Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 04/26] v4l: async: Add V4L2 async documentation to the documentation build Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 05/26] v4l: fwnode: Support generic parsing of graph endpoints in a device Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 06/26] v4l: fwnode: Support generic parsing of graph endpoints, per port Sakari Ailus
2017-09-13  7:01   ` Hans Verkuil
2017-09-13  7:06     ` Hans Verkuil
     [not found]       ` <a6cdf6cb-6abc-ac3b-274d-e8b43e2ac2c6-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2017-09-13  8:18         ` Sakari Ailus
     [not found] ` <20170912134200.19556-1-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-12 13:41   ` [PATCH v12 01/26] v4l: fwnode: Move KernelDoc documentation to the header Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 02/26] v4l: async: Remove re-probing support Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 07/26] omap3isp: Use generic parser for parsing fwnode endpoints Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 11/26] v4l: async: Move async subdev notifier operations to a separate structure Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 13/26] v4l: async: Register sub-devices before calling bound callback Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 16/26] dt: bindings: Add a binding for flash LED devices associated to a sensor Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 17/26] dt: bindings: Add lens-focus binding for image sensors Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 18/26] v4l: fwnode: Add a helper function for parsing generic references Sakari Ailus
     [not found]     ` <20170912134200.19556-19-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-13  7:27       ` Hans Verkuil
     [not found]         ` <020b9c86-dd73-3516-4a0e-827db9680b55-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2017-09-13  9:24           ` Sakari Ailus
     [not found]             ` <20170913092430.cbdgerkhiuxakbxv-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
2017-09-13  9:28               ` Hans Verkuil
2017-09-13 10:07                 ` Sakari Ailus
2017-09-13 10:32                   ` Hans Verkuil
2017-09-15 14:05                     ` Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 19/26] v4l: fwnode: Add a helper function to obtain device / interger references Sakari Ailus
     [not found]     ` <20170912134200.19556-20-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-13  7:57       ` Hans Verkuil
2017-09-13 10:04         ` Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 22/26] smiapp: Add support for flash and lens devices Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 24/26] ov5670: " Sakari Ailus
2017-09-12 13:41   ` [PATCH v12 25/26] ov13858: " Sakari Ailus
2017-09-12 13:42   ` [PATCH v12 26/26] arm: dts: omap3: N9/N950: Add flash references to the camera Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 08/26] rcar-vin: Use generic parser for parsing fwnode endpoints Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 09/26] omap3isp: Fix check for our own sub-devices Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 10/26] omap3isp: Print the name of the entity where no source pads could be found Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 12/26] v4l: async: Introduce helpers for calling async ops callbacks Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 14/26] v4l: async: Allow async notifier register call succeed with no subdevs Sakari Ailus
2017-09-12 13:41 ` Sakari Ailus [this message]
     [not found]   ` <20170912134200.19556-16-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-13  7:17     ` [PATCH v12 15/26] v4l: async: Allow binding notifiers to sub-devices Hans Verkuil
     [not found]       ` <575bf15b-62d2-3a51-d550-d462578471f7-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2017-09-13  8:29         ` Sakari Ailus
     [not found]           ` <20170913082901.fbxxphn7s3ljn3mc-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
2017-09-13  9:25             ` Hans Verkuil
2017-09-12 13:41 ` [PATCH v12 20/26] v4l: fwnode: Add convenience function for parsing common external refs Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 21/26] dt: bindings: smiapp: Document lens-focus and flash-leds properties Sakari Ailus
2017-09-12 13:41 ` [PATCH v12 23/26] et8ek8: Add support for flash and lens devices Sakari Ailus
     [not found]   ` <20170912134200.19556-24-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-13  7:59     ` Hans Verkuil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170912134200.19556-16-sakari.ailus@linux.intel.com \
    --to=sakari.ailus@linux.intel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=hverkuil@xs4all.nl \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-media@vger.kernel.org \
    --cc=maxime.ripard@free-electrons.com \
    --cc=niklas.soderlund@ragnatech.se \
    --cc=pavel@ucw.cz \
    --cc=robh@kernel.org \
    --cc=sre@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).