* [PATCH v7 00/17] media: imx: Switch to subdev notifiers
@ 2018-09-29 18:40 Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 01/17] media: v4l2-fwnode: ignore endpoints that have no remote port parent Steve Longerbeam
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Steve Longerbeam @ 2018-09-29 18:40 UTC (permalink / raw)
To: linux-media
This patchset converts the imx-media driver and its dependent
subdevs to use subdev notifiers.
There are a couple shortcomings in v4l2-core that prevented
subdev notifiers from working correctly in imx-media:
1. v4l2_async_notifier_fwnode_parse_endpoint() treats a fwnode
endpoint that is not connected to a remote device as an error.
But in the case of the video-mux subdev, this is not an error,
it is OK if some of the mux inputs have no connection. Also,
Documentation/devicetree/bindings/media/video-interfaces.txt explicitly
states that the 'remote-endpoint' property is optional. So the first
patch is a small modification to ignore empty endpoints in
v4l2_async_notifier_fwnode_parse_endpoint() and allow
__v4l2_async_notifier_parse_fwnode_endpoints() to continue to
parse the remaining port endpoints of the device.
2. In the imx-media graph, multiple subdevs will encounter the same
upstream subdev (such as the imx6-mipi-csi2 receiver), and so
v4l2_async_notifier_parse_fwnode_endpoints() will add imx6-mipi-csi2
multiple times. This is treated as an error by
v4l2_async_notifier_register() later.
To get around this problem, add an v4l2_async_notifier_add_subdev()
which first verifies the provided asd does not already exist in the
given notifier asd list or in other registered notifiers. If the asd
exists, the function returns -EEXIST and it's up to the caller to
decide if that is an error (in imx-media case it is never an error).
Patches 2-5 deal with adding that support.
3. Patch 6 adds v4l2_async_register_fwnode_subdev(), which is a
convenience function for parsing a subdev's fwnode port endpoints
for connected remote subdevs, registering a subdev notifier, and
then registering the sub-device itself.
4. Patches 7-14 update the subdev drivers to register a subdev notifier
with endpoint parsing, and the changes to imx-media to support that.
5. Finally, the last 3 patches endeavor to completely remove support for
the notifier->subdevs[] array in platform drivers and v4l2 core. All
platform drivers are modified to make use of
v4l2_async_notifier_add_subdev() and its related convenience functions
to add asd's to the notifier @asd_list, and any allocation or reference
to the notifier->subdevs[] array removed. After that large patch,
notifier->subdevs[] array is stripped from v4l2-async and v4l2-subdev
docs are updated to reflect the new method of adding asd's to notifiers.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Patches 07-14 (video-mux and the imx patches) are
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Patches 01-14 are
Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
on i.MX6 with Toshiba TC358743 connected via MIPI CSI-2.
History:
v7:
- Comment, error message, and whitespace fixes in patch 02/17.
Suggested by Mauro Chehab.
- Fixed merge conflict in drivers/media/platform/ti-vpe/cal.c.
- Make patch author and SoB email addresses the same.
v6:
- Export v4l2_async_notifier_init(), which must be called by all
drivers before the first call to v4l2_async_notifier_add_subdev().
Suggested by Sakari Ailus.
- Removed @num_subdevs from struct v4l2_async_notifier, and the macro
V4L2_MAX_SUBDEVS. Sugested by Sakari.
- Fixed a double device node put in vpif_capture.c. Reported by Sakari.
- Fixed wrong printk format qualifiers in xilinx-vipp.c. Reported by
Dan Carpenter.
v5:
- see point 5 above.
v4:
- small non-functional code cleanup in video-mux.c.
- strip TODO for comparing custom asd's for equivalence.
- add three more convenience functions: v4l2_async_notifier_add_fwnode_subdev,
v4l2_async_notifier_add_i2c_subdev, v4l2_async_notifier_add_devname_subdev.
- strip support in v4l2_async_register_fwnode_subdev for sub-devices
that register from port nodes.
v3:
- code optimization in asd_equal(), and remove unneeded braces,
suggested by Sakari Ailus.
- add a NULL asd pointer check to v4l2_async_notifier_asd_valid().
- fix an error-out path in v4l2_async_register_fwnode_subdev() that
forgot to put device.
v2:
- don't pass an empty endpoint to the parse_endpoint callback,
v4l2_async_notifier_fwnode_parse_endpoint() now just ignores them
and returns success.
- Fix a couple compile warnings and errors seen in i386 and sh archs.
Steve Longerbeam (17):
media: v4l2-fwnode: ignore endpoints that have no remote port parent
media: v4l2: async: Allow searching for asd of any type
media: v4l2: async: Add v4l2_async_notifier_add_subdev
media: v4l2: async: Add convenience functions to allocate and add
asd's
media: v4l2-fwnode: Switch to v4l2_async_notifier_add_subdev
media: v4l2-fwnode: Add a convenience function for registering subdevs
with notifiers
media: platform: video-mux: Register a subdev notifier
media: imx: csi: Register a subdev notifier
media: imx: mipi csi-2: Register a subdev notifier
media: staging/imx: of: Remove recursive graph walk
media: staging/imx: Loop through all registered subdevs for media
links
media: staging/imx: Rename root notifier
media: staging/imx: Switch to v4l2_async_notifier_add_*_subdev
media: staging/imx: TODO: Remove one assumption about OF graph parsing
media: platform: Switch to v4l2_async_notifier_add_subdev
media: v4l2: async: Remove notifier subdevs array
[media] v4l2-subdev.rst: Update doc regarding subdev descriptors
Documentation/media/kapi/v4l2-subdev.rst | 30 +-
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 14 +-
drivers/media/platform/Kconfig | 1 +
drivers/media/platform/am437x/am437x-vpfe.c | 82 +++---
drivers/media/platform/atmel/atmel-isc.c | 15 +-
drivers/media/platform/atmel/atmel-isi.c | 17 +-
drivers/media/platform/cadence/cdns-csi2rx.c | 28 +-
drivers/media/platform/davinci/vpif_capture.c | 71 ++---
drivers/media/platform/davinci/vpif_display.c | 20 +-
drivers/media/platform/exynos4-is/media-dev.c | 32 ++-
drivers/media/platform/exynos4-is/media-dev.h | 1 -
drivers/media/platform/omap3isp/isp.c | 1 +
drivers/media/platform/pxa_camera.c | 25 +-
drivers/media/platform/qcom/camss/camss.c | 89 +++---
drivers/media/platform/qcom/camss/camss.h | 2 +-
drivers/media/platform/rcar-vin/rcar-core.c | 6 +-
drivers/media/platform/rcar-vin/rcar-csi2.c | 22 +-
drivers/media/platform/rcar_drif.c | 18 +-
drivers/media/platform/renesas-ceu.c | 53 ++--
.../media/platform/soc_camera/soc_camera.c | 35 ++-
drivers/media/platform/stm32/stm32-dcmi.c | 24 +-
drivers/media/platform/ti-vpe/cal.c | 33 ++-
drivers/media/platform/video-mux.c | 36 ++-
drivers/media/platform/xilinx/xilinx-vipp.c | 173 ++++++-----
drivers/media/platform/xilinx/xilinx-vipp.h | 4 -
drivers/media/v4l2-core/v4l2-async.c | 268 +++++++++++++-----
drivers/media/v4l2-core/v4l2-fwnode.c | 198 ++++++-------
drivers/staging/media/imx/TODO | 29 +-
drivers/staging/media/imx/imx-media-csi.c | 57 +++-
drivers/staging/media/imx/imx-media-dev.c | 145 +++-------
.../staging/media/imx/imx-media-internal-sd.c | 5 +-
drivers/staging/media/imx/imx-media-of.c | 106 +------
drivers/staging/media/imx/imx-media.h | 6 +-
drivers/staging/media/imx/imx6-mipi-csi2.c | 31 +-
include/media/v4l2-async.h | 101 ++++++-
include/media/v4l2-fwnode.h | 52 +++-
36 files changed, 1038 insertions(+), 792 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v7 01/17] media: v4l2-fwnode: ignore endpoints that have no remote port parent
2018-09-29 18:40 [PATCH v7 00/17] media: imx: Switch to subdev notifiers Steve Longerbeam
@ 2018-09-29 18:40 ` Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 02/17] media: v4l2: async: Allow searching for asd of any type Steve Longerbeam
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Steve Longerbeam @ 2018-09-29 18:40 UTC (permalink / raw)
To: linux-media
Cc: Mauro Carvalho Chehab, Sakari Ailus, Hans Verkuil,
Niklas Söderlund, Sebastian Reichel, Tomasz Figa,
Jacopo Mondi, open list
Documentation/devicetree/bindings/media/video-interfaces.txt states that
the 'remote-endpoint' property is optional.
So v4l2_async_notifier_fwnode_parse_endpoint() should not return error
if the endpoint has no remote port parent. Just ignore the endpoint,
skip adding an asd to the notifier and return 0.
__v4l2_async_notifier_parse_fwnode_endpoints() will then continue
parsing the remaining port endpoints of the device.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
Changes since v6:
- none
Changes since v5:
- none
Changes since v4:
- none
Changes since v3:
- none
Changes since v2:
- none
Changes since v1:
- don't pass an empty endpoint to the parse_endpoint callback,
v4l2_async_notifier_fwnode_parse_endpoint() now just ignores them
and returns success. The current users of
v4l2_async_notifier_parse_fwnode_endpoints() (omap3isp, rcar-vin,
intel-ipu3) no longer need modification.
---
drivers/media/v4l2-core/v4l2-fwnode.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 169bdbb1f61a..0b8c736b1606 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -367,7 +367,7 @@ static int v4l2_async_notifier_fwnode_parse_endpoint(
fwnode_graph_get_remote_port_parent(endpoint);
if (!asd->match.fwnode) {
dev_warn(dev, "bad remote port parent\n");
- ret = -EINVAL;
+ ret = -ENOTCONN;
goto out_err;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v7 02/17] media: v4l2: async: Allow searching for asd of any type
2018-09-29 18:40 [PATCH v7 00/17] media: imx: Switch to subdev notifiers Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 01/17] media: v4l2-fwnode: ignore endpoints that have no remote port parent Steve Longerbeam
@ 2018-09-29 18:40 ` Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 03/17] media: v4l2: async: Add v4l2_async_notifier_add_subdev Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 04/17] media: v4l2: async: Add convenience functions to allocate and add asd's Steve Longerbeam
3 siblings, 0 replies; 5+ messages in thread
From: Steve Longerbeam @ 2018-09-29 18:40 UTC (permalink / raw)
To: linux-media
Cc: Mauro Carvalho Chehab, Niklas Söderlund, Sakari Ailus,
Sebastian Reichel, Hans Verkuil, open list
Generalize v4l2_async_notifier_fwnode_has_async_subdev() to allow
searching for any type of async subdev, not just fwnodes. Rename to
v4l2_async_notifier_has_async_subdev() and pass it an asd pointer.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
Changes since v6:
- elaborate on comment for asd_equal(), suggested by Mauro Chehab.
- whitespace checkpatch fixes, suggested by Mauro.
- made an error message more clear in __v4l2_async_notifier_register(),
suggested by Mauro.
Changes since v5:
- none
Changes since v4:
- none
Changes since v3:
- removed TODO to support asd compare with CUSTOM match type in
asd_equal().
Changes since v2:
- code optimization in asd_equal(), and remove unneeded braces,
suggested by Sakari Ailus.
Changes since v1:
- none
---
drivers/media/v4l2-core/v4l2-async.c | 77 +++++++++++++++++-----------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 2b08d03b251d..f09d354b96a0 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -124,6 +124,31 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
return NULL;
}
+/* Compare two async sub-device descriptors for equivalence */
+static bool asd_equal(struct v4l2_async_subdev *asd_x,
+ struct v4l2_async_subdev *asd_y)
+{
+ if (asd_x->match_type != asd_y->match_type)
+ return false;
+
+ switch (asd_x->match_type) {
+ case V4L2_ASYNC_MATCH_DEVNAME:
+ return strcmp(asd_x->match.device_name,
+ asd_y->match.device_name) == 0;
+ case V4L2_ASYNC_MATCH_I2C:
+ return asd_x->match.i2c.adapter_id ==
+ asd_y->match.i2c.adapter_id &&
+ asd_x->match.i2c.address ==
+ asd_y->match.i2c.address;
+ case V4L2_ASYNC_MATCH_FWNODE:
+ return asd_x->match.fwnode == asd_y->match.fwnode;
+ default:
+ break;
+ }
+
+ return false;
+}
+
/* 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)
@@ -308,29 +333,23 @@ static void v4l2_async_notifier_unbind_all_subdevs(
notifier->parent = NULL;
}
-/* See if an fwnode can be found in a notifier's lists. */
-static bool __v4l2_async_notifier_fwnode_has_async_subdev(
- struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
+/* See if an async sub-device can be found in a notifier's lists. */
+static bool
+__v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd)
{
- struct v4l2_async_subdev *asd;
+ struct v4l2_async_subdev *asd_y;
struct v4l2_subdev *sd;
- list_for_each_entry(asd, ¬ifier->waiting, list) {
- if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
- continue;
-
- if (asd->match.fwnode == fwnode)
+ list_for_each_entry(asd_y, ¬ifier->waiting, list)
+ if (asd_equal(asd, asd_y))
return true;
- }
list_for_each_entry(sd, ¬ifier->done, async_list) {
if (WARN_ON(!sd->asd))
continue;
- if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
- continue;
-
- if (sd->asd->match.fwnode == fwnode)
+ if (asd_equal(asd, sd->asd))
return true;
}
@@ -338,32 +357,29 @@ static bool __v4l2_async_notifier_fwnode_has_async_subdev(
}
/*
- * Find out whether an async sub-device was set up for an fwnode already or
+ * Find out whether an async sub-device was set up already or
* whether it exists in a given notifier before @this_index.
*/
-static bool v4l2_async_notifier_fwnode_has_async_subdev(
- struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
- unsigned int this_index)
+static bool
+v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd,
+ unsigned int this_index)
{
unsigned int j;
lockdep_assert_held(&list_lock);
- /* Check that an fwnode is not being added more than once. */
+ /* Check that an asd is not being added more than once. */
for (j = 0; j < this_index; j++) {
- struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
- struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
+ struct v4l2_async_subdev *asd_y = notifier->subdevs[j];
- if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
- asd->match.fwnode ==
- other_asd->match.fwnode)
+ if (asd_equal(asd, asd_y))
return true;
}
- /* Check than an fwnode did not exist in other notifiers. */
+ /* Check that an asd does not exist in other notifiers. */
list_for_each_entry(notifier, ¬ifier_list, list)
- if (__v4l2_async_notifier_fwnode_has_async_subdev(
- notifier, fwnode))
+ if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
return true;
return false;
@@ -392,12 +408,11 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
case V4L2_ASYNC_MATCH_CUSTOM:
case V4L2_ASYNC_MATCH_DEVNAME:
case V4L2_ASYNC_MATCH_I2C:
- break;
case V4L2_ASYNC_MATCH_FWNODE:
- if (v4l2_async_notifier_fwnode_has_async_subdev(
- notifier, asd->match.fwnode, i)) {
+ if (v4l2_async_notifier_has_async_subdev(notifier,
+ asd, i)) {
dev_err(dev,
- "fwnode has already been registered or in notifier's subdev list\n");
+ "subdev descriptor already listed in this or other notifiers\n");
ret = -EEXIST;
goto err_unlock;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v7 03/17] media: v4l2: async: Add v4l2_async_notifier_add_subdev
2018-09-29 18:40 [PATCH v7 00/17] media: imx: Switch to subdev notifiers Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 01/17] media: v4l2-fwnode: ignore endpoints that have no remote port parent Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 02/17] media: v4l2: async: Allow searching for asd of any type Steve Longerbeam
@ 2018-09-29 18:40 ` Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 04/17] media: v4l2: async: Add convenience functions to allocate and add asd's Steve Longerbeam
3 siblings, 0 replies; 5+ messages in thread
From: Steve Longerbeam @ 2018-09-29 18:40 UTC (permalink / raw)
To: linux-media
Cc: Mauro Carvalho Chehab, Niklas Söderlund, Sakari Ailus,
Sebastian Reichel, Hans Verkuil, open list
v4l2_async_notifier_add_subdev() adds an asd to the notifier. It checks
that no other equivalent asd's have already been added to this notifier's
asd list, or to other registered notifier's waiting or done lists, and
increments num_subdevs.
v4l2_async_notifier_add_subdev() does not make use of the notifier subdevs
array, otherwise it would have to re-allocate the array every time the
function was called. In place of the subdevs array, the function adds
the newly allocated asd to a new master asd_list. The function will
return error with a WARN() if it is ever called with the subdevs array
allocated.
Drivers are now required to call a v4l2_async_notifier_init(), before the
first call to v4l2_async_notifier_add_subdev(), in order to initialize
the asd_list.
In v4l2_async_notifier_has_async_subdev(), __v4l2_async_notifier_register(),
and v4l2_async_notifier_cleanup(), maintain backward compatibility with
the subdevs array, by alternatively operate on the subdevs array or a
non-empty notifier->asd_list.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
Changes since v6:
- add "already listed asd" message from __v4l2_async_notifier_register()
to v4l2_async_notifier_asd_valid() as a debug message.
Changes since v5:
- export v4l2_async_notifier_init() which must be called by drivers.
Suggested by Sakari Ailus.
Changes since v4:
- none
Changes since v3:
- init notifier lists after the sanity checks.
Changes since v2:
- add a NULL asd pointer check to v4l2_async_notifier_asd_valid().
Changes since v1:
- none
---
drivers/media/v4l2-core/v4l2-async.c | 191 +++++++++++++++++++++------
include/media/v4l2-async.h | 34 ++++-
2 files changed, 182 insertions(+), 43 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index f09d354b96a0..7925875d09b7 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -365,16 +365,26 @@ v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd,
unsigned int this_index)
{
+ struct v4l2_async_subdev *asd_y;
unsigned int j;
lockdep_assert_held(&list_lock);
/* Check that an asd is not being added more than once. */
- for (j = 0; j < this_index; j++) {
- struct v4l2_async_subdev *asd_y = notifier->subdevs[j];
-
- if (asd_equal(asd, asd_y))
- return true;
+ if (notifier->subdevs) {
+ for (j = 0; j < this_index; j++) {
+ asd_y = notifier->subdevs[j];
+ if (asd_equal(asd, asd_y))
+ return true;
+ }
+ } else {
+ j = 0;
+ list_for_each_entry(asd_y, ¬ifier->asd_list, asd_list) {
+ if (j++ >= this_index)
+ break;
+ if (asd_equal(asd, asd_y))
+ return true;
+ }
}
/* Check that an asd does not exist in other notifiers. */
@@ -385,10 +395,48 @@ v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
return false;
}
-static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
+static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd,
+ unsigned int this_index)
{
struct device *dev =
notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
+
+ if (!asd)
+ return -EINVAL;
+
+ switch (asd->match_type) {
+ case V4L2_ASYNC_MATCH_CUSTOM:
+ case V4L2_ASYNC_MATCH_DEVNAME:
+ case V4L2_ASYNC_MATCH_I2C:
+ case V4L2_ASYNC_MATCH_FWNODE:
+ if (v4l2_async_notifier_has_async_subdev(notifier, asd,
+ this_index)) {
+ dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
+ return -EEXIST;
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid match type %u on %p\n",
+ asd->match_type, asd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
+{
+ mutex_lock(&list_lock);
+
+ INIT_LIST_HEAD(¬ifier->asd_list);
+
+ mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(v4l2_async_notifier_init);
+
+static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
+{
struct v4l2_async_subdev *asd;
int ret;
int i;
@@ -401,29 +449,25 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
mutex_lock(&list_lock);
- for (i = 0; i < notifier->num_subdevs; i++) {
- asd = notifier->subdevs[i];
+ if (notifier->subdevs) {
+ for (i = 0; i < notifier->num_subdevs; i++) {
+ asd = notifier->subdevs[i];
- switch (asd->match_type) {
- case V4L2_ASYNC_MATCH_CUSTOM:
- case V4L2_ASYNC_MATCH_DEVNAME:
- case V4L2_ASYNC_MATCH_I2C:
- case V4L2_ASYNC_MATCH_FWNODE:
- if (v4l2_async_notifier_has_async_subdev(notifier,
- asd, i)) {
- dev_err(dev,
- "subdev descriptor already listed in this or other notifiers\n");
- ret = -EEXIST;
+ ret = v4l2_async_notifier_asd_valid(notifier, asd, i);
+ if (ret)
goto err_unlock;
- }
- break;
- default:
- dev_err(dev, "Invalid match type %u on %p\n",
- asd->match_type, asd);
- ret = -EINVAL;
- goto err_unlock;
+
+ list_add_tail(&asd->list, ¬ifier->waiting);
+ }
+ } else {
+ i = 0;
+ list_for_each_entry(asd, ¬ifier->asd_list, asd_list) {
+ ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
+ if (ret)
+ goto err_unlock;
+
+ list_add_tail(&asd->list, ¬ifier->waiting);
}
- list_add_tail(&asd->list, ¬ifier->waiting);
}
ret = v4l2_async_notifier_try_all_subdevs(notifier);
@@ -513,36 +557,99 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
}
EXPORT_SYMBOL(v4l2_async_notifier_unregister);
-void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
+static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
{
+ struct v4l2_async_subdev *asd, *tmp;
unsigned int i;
- if (!notifier || !notifier->max_subdevs)
+ if (!notifier)
return;
- for (i = 0; i < notifier->num_subdevs; i++) {
- struct v4l2_async_subdev *asd = notifier->subdevs[i];
+ if (notifier->subdevs) {
+ if (!notifier->max_subdevs)
+ return;
- switch (asd->match_type) {
- case V4L2_ASYNC_MATCH_FWNODE:
- fwnode_handle_put(asd->match.fwnode);
- break;
- default:
- WARN_ON_ONCE(true);
- break;
+ for (i = 0; i < notifier->num_subdevs; i++) {
+ asd = notifier->subdevs[i];
+
+ switch (asd->match_type) {
+ case V4L2_ASYNC_MATCH_FWNODE:
+ fwnode_handle_put(asd->match.fwnode);
+ break;
+ default:
+ break;
+ }
+
+ kfree(asd);
}
- kfree(asd);
+ notifier->max_subdevs = 0;
+ kvfree(notifier->subdevs);
+ notifier->subdevs = NULL;
+ } else {
+ list_for_each_entry_safe(asd, tmp,
+ ¬ifier->asd_list, asd_list) {
+ switch (asd->match_type) {
+ case V4L2_ASYNC_MATCH_FWNODE:
+ fwnode_handle_put(asd->match.fwnode);
+ break;
+ default:
+ break;
+ }
+
+ list_del(&asd->asd_list);
+ kfree(asd);
+ }
}
- notifier->max_subdevs = 0;
notifier->num_subdevs = 0;
+}
+
+void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
+{
+ mutex_lock(&list_lock);
+
+ __v4l2_async_notifier_cleanup(notifier);
- kvfree(notifier->subdevs);
- notifier->subdevs = NULL;
+ mutex_unlock(&list_lock);
}
EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
+int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd)
+{
+ int ret;
+
+ mutex_lock(&list_lock);
+
+ if (notifier->num_subdevs >= V4L2_MAX_SUBDEVS) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ /*
+ * If caller uses this function, it cannot also allocate and
+ * place asd's in the notifier->subdevs array.
+ */
+ if (WARN_ON(notifier->subdevs)) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ret = v4l2_async_notifier_asd_valid(notifier, asd,
+ notifier->num_subdevs);
+ if (ret)
+ goto unlock;
+
+ list_add_tail(&asd->asd_list, ¬ifier->asd_list);
+ notifier->num_subdevs++;
+
+unlock:
+ mutex_unlock(&list_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
+
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *subdev_notifier;
@@ -616,7 +723,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
mutex_lock(&list_lock);
__v4l2_async_notifier_unregister(sd->subdev_notifier);
- v4l2_async_notifier_cleanup(sd->subdev_notifier);
+ __v4l2_async_notifier_cleanup(sd->subdev_notifier);
kfree(sd->subdev_notifier);
sd->subdev_notifier = NULL;
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 1592d323c577..ab4d7acb7960 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -73,6 +73,8 @@ enum v4l2_async_match_type {
* @match.custom.priv:
* Driver-specific private struct with match parameters
* to be used if %V4L2_ASYNC_MATCH_CUSTOM.
+ * @asd_list: used to add struct v4l2_async_subdev objects to the
+ * master notifier @asd_list
* @list: used to link struct v4l2_async_subdev objects, waiting to be
* probed, to a notifier->waiting list
*
@@ -98,6 +100,7 @@ struct v4l2_async_subdev {
/* v4l2-async core private: not to be used by drivers */
struct list_head list;
+ struct list_head asd_list;
};
/**
@@ -127,6 +130,7 @@ struct v4l2_async_notifier_operations {
* @v4l2_dev: v4l2_device of the root notifier, NULL otherwise
* @sd: sub-device that registered the notifier, NULL otherwise
* @parent: parent notifier
+ * @asd_list: master list of struct v4l2_async_subdev, replaces @subdevs
* @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
@@ -139,11 +143,37 @@ struct v4l2_async_notifier {
struct v4l2_device *v4l2_dev;
struct v4l2_subdev *sd;
struct v4l2_async_notifier *parent;
+ struct list_head asd_list;
struct list_head waiting;
struct list_head done;
struct list_head list;
};
+/**
+ * v4l2_async_notifier_init - Initialize a notifier.
+ *
+ * @notifier: pointer to &struct v4l2_async_notifier
+ *
+ * This function initializes the notifier @asd_list. It must be called
+ * before the first call to @v4l2_async_notifier_add_subdev.
+ */
+void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier);
+
+/**
+ * v4l2_async_notifier_add_subdev - Add an async subdev to the
+ * notifier's master asd list.
+ *
+ * @notifier: pointer to &struct v4l2_async_notifier
+ * @asd: pointer to &struct v4l2_async_subdev
+ *
+ * This can be used before registering a notifier to add an
+ * asd to the notifiers @asd_list. If the caller uses this
+ * method to compose an asd list, it must never allocate
+ * or place asd's in the @subdevs array.
+ */
+int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd);
+
/**
* v4l2_async_notifier_register - registers a subdevice asynchronous notifier
*
@@ -177,7 +207,9 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
* Release memory resources related to a notifier, including the async
* sub-devices allocated for the purposes of the notifier but not the notifier
* itself. The user is responsible for calling this function to clean up the
- * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints or
+ * notifier after calling
+ * @v4l2_async_notifier_add_subdev,
+ * @v4l2_async_notifier_parse_fwnode_endpoints or
* @v4l2_fwnode_reference_parse_sensor_common.
*
* There is no harm from calling v4l2_async_notifier_cleanup in other
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v7 04/17] media: v4l2: async: Add convenience functions to allocate and add asd's
2018-09-29 18:40 [PATCH v7 00/17] media: imx: Switch to subdev notifiers Steve Longerbeam
` (2 preceding siblings ...)
2018-09-29 18:40 ` [PATCH v7 03/17] media: v4l2: async: Add v4l2_async_notifier_add_subdev Steve Longerbeam
@ 2018-09-29 18:40 ` Steve Longerbeam
3 siblings, 0 replies; 5+ messages in thread
From: Steve Longerbeam @ 2018-09-29 18:40 UTC (permalink / raw)
To: linux-media
Cc: Mauro Carvalho Chehab, Niklas Söderlund, Sakari Ailus,
Sebastian Reichel, Hans Verkuil, open list
Add these convenience functions, which allocate an asd of match type
fwnode, i2c, or device-name, of size asd_struct_size, and then adds
them to the notifier asd_list.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/media/v4l2-core/v4l2-async.c | 76 ++++++++++++++++++++++++++++
include/media/v4l2-async.h | 62 +++++++++++++++++++++++
2 files changed, 138 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 7925875d09b7..196573f4ec48 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -650,6 +650,82 @@ int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
}
EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
+ struct fwnode_handle *fwnode,
+ unsigned int asd_struct_size)
+{
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return ERR_PTR(-ENOMEM);
+
+ asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+ asd->match.fwnode = fwnode;
+
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret) {
+ kfree(asd);
+ return ERR_PTR(ret);
+ }
+
+ return asd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
+
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier,
+ int adapter_id, unsigned short address,
+ unsigned int asd_struct_size)
+{
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return ERR_PTR(-ENOMEM);
+
+ asd->match_type = V4L2_ASYNC_MATCH_I2C;
+ asd->match.i2c.adapter_id = adapter_id;
+ asd->match.i2c.address = address;
+
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret) {
+ kfree(asd);
+ return ERR_PTR(ret);
+ }
+
+ return asd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev);
+
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier,
+ const char *device_name,
+ unsigned int asd_struct_size)
+{
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return ERR_PTR(-ENOMEM);
+
+ asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
+ asd->match.device_name = device_name;
+
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret) {
+ kfree(asd);
+ return ERR_PTR(ret);
+ }
+
+ return asd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
+
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *subdev_notifier;
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index ab4d7acb7960..3489e4ccb29b 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -174,6 +174,68 @@ void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier);
int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd);
+/**
+ * v4l2_async_notifier_add_fwnode_subdev - Allocate and add a fwnode async
+ * subdev to the notifier's master asd_list.
+ *
+ * @notifier: pointer to &struct v4l2_async_notifier
+ * @fwnode: fwnode handle of the sub-device to be matched
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ * sizeof(struct v4l2_async_subdev). The &struct
+ * v4l2_async_subdev shall be the first member of
+ * the driver's async sub-device struct, i.e. both
+ * begin at the same memory address.
+ *
+ * This can be used before registering a notifier to add a
+ * fwnode-matched asd to the notifiers master asd_list. If the caller
+ * uses this method to compose an asd list, it must never allocate
+ * or place asd's in the @subdevs array.
+ */
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
+ struct fwnode_handle *fwnode,
+ unsigned int asd_struct_size);
+
+/**
+ * v4l2_async_notifier_add_i2c_subdev - Allocate and add an i2c async
+ * subdev to the notifier's master asd_list.
+ *
+ * @notifier: pointer to &struct v4l2_async_notifier
+ * @adapter_id: I2C adapter ID to be matched
+ * @address: I2C address of sub-device to be matched
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ * sizeof(struct v4l2_async_subdev). The &struct
+ * v4l2_async_subdev shall be the first member of
+ * the driver's async sub-device struct, i.e. both
+ * begin at the same memory address.
+ *
+ * Same as above but for I2C matched sub-devices.
+ */
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier,
+ int adapter_id, unsigned short address,
+ unsigned int asd_struct_size);
+
+/**
+ * v4l2_async_notifier_add_devname_subdev - Allocate and add a device-name
+ * async subdev to the notifier's master asd_list.
+ *
+ * @notifier: pointer to &struct v4l2_async_notifier
+ * @device_name: device name string to be matched
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ * sizeof(struct v4l2_async_subdev). The &struct
+ * v4l2_async_subdev shall be the first member of
+ * the driver's async sub-device struct, i.e. both
+ * begin at the same memory address.
+ *
+ * Same as above but for device-name matched sub-devices.
+ */
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier,
+ const char *device_name,
+ unsigned int asd_struct_size);
+
+
/**
* v4l2_async_notifier_register - registers a subdevice asynchronous notifier
*
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2018-09-30 1:11 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-29 18:40 [PATCH v7 00/17] media: imx: Switch to subdev notifiers Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 01/17] media: v4l2-fwnode: ignore endpoints that have no remote port parent Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 02/17] media: v4l2: async: Allow searching for asd of any type Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 03/17] media: v4l2: async: Add v4l2_async_notifier_add_subdev Steve Longerbeam
2018-09-29 18:40 ` [PATCH v7 04/17] media: v4l2: async: Add convenience functions to allocate and add asd's Steve Longerbeam
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).