* [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
In V4L2 the practice is to have the KernelDoc documentation in the header
and not in .c source code files. This consequently makes the V4L2 fwnode
function documentation part of the Media documentation build.
Also correct the link related function and argument naming in
documentation.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
---
drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
include/media/v4l2-fwnode.h | 81 ++++++++++++++++++++++++++++++++++-
2 files changed, 80 insertions(+), 76 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 40b2fbfe8865..706f9e7b90f1 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -181,25 +181,6 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
vep->bus_type = V4L2_MBUS_CSI1;
}
-/**
- * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
- * @fwnode: pointer to the endpoint's fwnode handle
- * @vep: pointer to the V4L2 fwnode data structure
- *
- * All properties are optional. If none are found, we don't set any flags. This
- * means the port has a static configuration and no properties have to be
- * specified explicitly. If any properties that identify the bus as parallel
- * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
- * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
- * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
- * reference to @fwnode.
- *
- * NOTE: This function does not parse properties the size of which is variable
- * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
- * new drivers instead.
- *
- * Return: 0 on success or a negative error code on failure.
- */
int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep)
{
@@ -239,14 +220,6 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
-/*
- * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
- * v4l2_fwnode_endpoint_alloc_parse()
- * @vep - the V4L2 fwnode the resources of which are to be released
- *
- * It is safe to call this function with NULL argument or on a V4L2 fwnode the
- * parsing of which failed.
- */
void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
{
if (IS_ERR_OR_NULL(vep))
@@ -257,29 +230,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
-/**
- * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
- * @fwnode: pointer to the endpoint's fwnode handle
- *
- * All properties are optional. If none are found, we don't set any flags. This
- * means the port has a static configuration and no properties have to be
- * specified explicitly. If any properties that identify the bus as parallel
- * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
- * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
- * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
- * reference to @fwnode.
- *
- * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
- * v4l2_fwnode_endpoint_parse():
- *
- * 1. It also parses variable size data.
- *
- * 2. The memory it has allocated to store the variable size data must be freed
- * using v4l2_fwnode_endpoint_free() when no longer needed.
- *
- * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
- * on error.
- */
struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
struct fwnode_handle *fwnode)
{
@@ -322,24 +272,6 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
-/**
- * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints
- * @__fwnode: pointer to the endpoint's fwnode at the local end of the link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Fill the link structure with the local and remote nodes and port numbers.
- * The local_node and remote_node fields are set to point to the local and
- * remote port's parent nodes respectively (the port parent node being the
- * parent node of the port node if that node isn't a 'ports' node, or the
- * grand-parent node of the port node otherwise).
- *
- * A reference is taken to both the local and remote nodes, the caller must use
- * v4l2_fwnode_endpoint_put_link() to drop the references when done with the
- * link.
- *
- * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
- * found.
- */
int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
struct v4l2_fwnode_link *link)
{
@@ -374,13 +306,6 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
-/**
- * v4l2_fwnode_put_link() - drop references to nodes in a link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Drop references to the local and remote nodes in the link. This function
- * must be called on every link parsed with v4l2_fwnode_parse_link().
- */
void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
{
fwnode_handle_put(link->local_node);
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 7adec9851d9e..68eb22ba571b 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -113,13 +113,92 @@ struct v4l2_fwnode_link {
unsigned int remote_port;
};
+/**
+ * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
+ * @fwnode: pointer to the endpoint's fwnode handle
+ * @vep: pointer to the V4L2 fwnode data structure
+ *
+ * All properties are optional. If none are found, we don't set any flags. This
+ * means the port has a static configuration and no properties have to be
+ * specified explicitly. If any properties that identify the bus as parallel
+ * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
+ * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
+ * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
+ * reference to @fwnode.
+ *
+ * NOTE: This function does not parse properties the size of which is variable
+ * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
+ * new drivers instead.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep);
+
+/*
+ * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
+ * v4l2_fwnode_endpoint_alloc_parse()
+ * @vep - the V4L2 fwnode the resources of which are to be released
+ *
+ * It is safe to call this function with NULL argument or on a V4L2 fwnode the
+ * parsing of which failed.
+ */
+void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
+ * @fwnode: pointer to the endpoint's fwnode handle
+ *
+ * All properties are optional. If none are found, we don't set any flags. This
+ * means the port has a static configuration and no properties have to be
+ * specified explicitly. If any properties that identify the bus as parallel
+ * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
+ * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
+ * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
+ * reference to @fwnode.
+ *
+ * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
+ * v4l2_fwnode_endpoint_parse():
+ *
+ * 1. It also parses variable size data.
+ *
+ * 2. The memory it has allocated to store the variable size data must be freed
+ * using v4l2_fwnode_endpoint_free() when no longer needed.
+ *
+ * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
+ * on error.
+ */
struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
struct fwnode_handle *fwnode);
-void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_parse_link() - parse a link between two endpoints
+ * @fwnode: pointer to the endpoint's fwnode at the local end of the link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Fill the link structure with the local and remote nodes and port numbers.
+ * The local_node and remote_node fields are set to point to the local and
+ * remote port's parent nodes respectively (the port parent node being the
+ * parent node of the port node if that node isn't a 'ports' node, or the
+ * grand-parent node of the port node otherwise).
+ *
+ * A reference is taken to both the local and remote nodes, the caller must use
+ * v4l2_fwnode_put_link() to drop the references when done with the
+ * link.
+ *
+ * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
+ * found.
+ */
int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
struct v4l2_fwnode_link *link);
+
+/**
+ * v4l2_fwnode_put_link() - drop references to nodes in a link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Drop references to the local and remote nodes in the link. This function
+ * must be called on every link parsed with v4l2_fwnode_parse_link().
+ */
void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
#endif /* _V4L2_FWNODE_H */
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
In V4L2 the practice is to have the KernelDoc documentation in the header
and not in .c source code files. This consequently makes the V4L2 fwnode
function documentation part of the Media documentation build.
Also correct the link related function and argument naming in
documentation.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
include/media/v4l2-fwnode.h | 81 ++++++++++++++++++++++++++++++++++-
2 files changed, 80 insertions(+), 76 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 40b2fbfe8865..706f9e7b90f1 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -181,25 +181,6 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
vep->bus_type = V4L2_MBUS_CSI1;
}
-/**
- * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
- * @fwnode: pointer to the endpoint's fwnode handle
- * @vep: pointer to the V4L2 fwnode data structure
- *
- * All properties are optional. If none are found, we don't set any flags. This
- * means the port has a static configuration and no properties have to be
- * specified explicitly. If any properties that identify the bus as parallel
- * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
- * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
- * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
- * reference to @fwnode.
- *
- * NOTE: This function does not parse properties the size of which is variable
- * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
- * new drivers instead.
- *
- * Return: 0 on success or a negative error code on failure.
- */
int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep)
{
@@ -239,14 +220,6 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
-/*
- * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
- * v4l2_fwnode_endpoint_alloc_parse()
- * @vep - the V4L2 fwnode the resources of which are to be released
- *
- * It is safe to call this function with NULL argument or on a V4L2 fwnode the
- * parsing of which failed.
- */
void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
{
if (IS_ERR_OR_NULL(vep))
@@ -257,29 +230,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
-/**
- * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
- * @fwnode: pointer to the endpoint's fwnode handle
- *
- * All properties are optional. If none are found, we don't set any flags. This
- * means the port has a static configuration and no properties have to be
- * specified explicitly. If any properties that identify the bus as parallel
- * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
- * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
- * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
- * reference to @fwnode.
- *
- * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
- * v4l2_fwnode_endpoint_parse():
- *
- * 1. It also parses variable size data.
- *
- * 2. The memory it has allocated to store the variable size data must be freed
- * using v4l2_fwnode_endpoint_free() when no longer needed.
- *
- * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
- * on error.
- */
struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
struct fwnode_handle *fwnode)
{
@@ -322,24 +272,6 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
-/**
- * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints
- * @__fwnode: pointer to the endpoint's fwnode at the local end of the link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Fill the link structure with the local and remote nodes and port numbers.
- * The local_node and remote_node fields are set to point to the local and
- * remote port's parent nodes respectively (the port parent node being the
- * parent node of the port node if that node isn't a 'ports' node, or the
- * grand-parent node of the port node otherwise).
- *
- * A reference is taken to both the local and remote nodes, the caller must use
- * v4l2_fwnode_endpoint_put_link() to drop the references when done with the
- * link.
- *
- * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
- * found.
- */
int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
struct v4l2_fwnode_link *link)
{
@@ -374,13 +306,6 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
-/**
- * v4l2_fwnode_put_link() - drop references to nodes in a link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Drop references to the local and remote nodes in the link. This function
- * must be called on every link parsed with v4l2_fwnode_parse_link().
- */
void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
{
fwnode_handle_put(link->local_node);
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 7adec9851d9e..68eb22ba571b 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -113,13 +113,92 @@ struct v4l2_fwnode_link {
unsigned int remote_port;
};
+/**
+ * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
+ * @fwnode: pointer to the endpoint's fwnode handle
+ * @vep: pointer to the V4L2 fwnode data structure
+ *
+ * All properties are optional. If none are found, we don't set any flags. This
+ * means the port has a static configuration and no properties have to be
+ * specified explicitly. If any properties that identify the bus as parallel
+ * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
+ * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
+ * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
+ * reference to @fwnode.
+ *
+ * NOTE: This function does not parse properties the size of which is variable
+ * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
+ * new drivers instead.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep);
+
+/*
+ * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
+ * v4l2_fwnode_endpoint_alloc_parse()
+ * @vep - the V4L2 fwnode the resources of which are to be released
+ *
+ * It is safe to call this function with NULL argument or on a V4L2 fwnode the
+ * parsing of which failed.
+ */
+void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
+ * @fwnode: pointer to the endpoint's fwnode handle
+ *
+ * All properties are optional. If none are found, we don't set any flags. This
+ * means the port has a static configuration and no properties have to be
+ * specified explicitly. If any properties that identify the bus as parallel
+ * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
+ * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
+ * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
+ * reference to @fwnode.
+ *
+ * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
+ * v4l2_fwnode_endpoint_parse():
+ *
+ * 1. It also parses variable size data.
+ *
+ * 2. The memory it has allocated to store the variable size data must be freed
+ * using v4l2_fwnode_endpoint_free() when no longer needed.
+ *
+ * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
+ * on error.
+ */
struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
struct fwnode_handle *fwnode);
-void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_parse_link() - parse a link between two endpoints
+ * @fwnode: pointer to the endpoint's fwnode at the local end of the link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Fill the link structure with the local and remote nodes and port numbers.
+ * The local_node and remote_node fields are set to point to the local and
+ * remote port's parent nodes respectively (the port parent node being the
+ * parent node of the port node if that node isn't a 'ports' node, or the
+ * grand-parent node of the port node otherwise).
+ *
+ * A reference is taken to both the local and remote nodes, the caller must use
+ * v4l2_fwnode_put_link() to drop the references when done with the
+ * link.
+ *
+ * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
+ * found.
+ */
int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
struct v4l2_fwnode_link *link);
+
+/**
+ * v4l2_fwnode_put_link() - drop references to nodes in a link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Drop references to the local and remote nodes in the link. This function
+ * must be called on every link parsed with v4l2_fwnode_parse_link().
+ */
void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
#endif /* _V4L2_FWNODE_H */
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
[parent not found: <20170915141724.23124-2-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>]
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-19 10:48 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 10:48 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> In V4L2 the practice is to have the KernelDoc documentation in the header
> and not in .c source code files. This consequently makes the V4L2 fwnode
> function documentation part of the Media documentation build.
>
> Also correct the link related function and argument naming in
> documentation.
>
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
I'm still very opposed to this. In addition to increasing the risk of
documentation becoming stale, it also makes review more difficult. I'm
reviewing patch 05/25 of this series and I have to jump around the patch to
verify that the documentation matches the implementation, it's really
annoying.
We should instead move all function documentation from header files to source
files.
> ---
> drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
> include/media/v4l2-fwnode.h | 81 +++++++++++++++++++++++++++++++-
> 2 files changed, 80 insertions(+), 76 deletions(-)
[snip]
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 10:48 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 10:48 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> In V4L2 the practice is to have the KernelDoc documentation in the header
> and not in .c source code files. This consequently makes the V4L2 fwnode
> function documentation part of the Media documentation build.
>
> Also correct the link related function and argument naming in
> documentation.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
I'm still very opposed to this. In addition to increasing the risk of
documentation becoming stale, it also makes review more difficult. I'm
reviewing patch 05/25 of this series and I have to jump around the patch to
verify that the documentation matches the implementation, it's really
annoying.
We should instead move all function documentation from header files to source
files.
> ---
> drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
> include/media/v4l2-fwnode.h | 81 +++++++++++++++++++++++++++++++-
> 2 files changed, 80 insertions(+), 76 deletions(-)
[snip]
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-19 10:48 ` Laurent Pinchart
@ 2017-09-19 11:04 ` Hans Verkuil
-1 siblings, 0 replies; 137+ messages in thread
From: Hans Verkuil @ 2017-09-19 11:04 UTC (permalink / raw)
To: Laurent Pinchart, Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
pavel-+ZI9xUNit7I, sre-DgEjT+Ai2ygdnm+yROfE0A
On 09/19/17 12:48, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
>> In V4L2 the practice is to have the KernelDoc documentation in the header
>> and not in .c source code files. This consequently makes the V4L2 fwnode
>> function documentation part of the Media documentation build.
>>
>> Also correct the link related function and argument naming in
>> documentation.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
>> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
>> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
>> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
>
> I'm still very opposed to this. In addition to increasing the risk of
> documentation becoming stale, it also makes review more difficult. I'm
> reviewing patch 05/25 of this series and I have to jump around the patch to
> verify that the documentation matches the implementation, it's really
> annoying.
>
> We should instead move all function documentation from header files to source
> files.
I disagree with this. Yes, it makes reviewing harder, but when you have to
*use* these functions as e.g. a driver developer, then having it in the
header is much more convenient.
Regards,
Hans
>
>> ---
>> drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
>> include/media/v4l2-fwnode.h | 81 +++++++++++++++++++++++++++++++-
>> 2 files changed, 80 insertions(+), 76 deletions(-)
>
> [snip]
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 11:04 ` Hans Verkuil
0 siblings, 0 replies; 137+ messages in thread
From: Hans Verkuil @ 2017-09-19 11:04 UTC (permalink / raw)
To: Laurent Pinchart, Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, devicetree,
pavel, sre
On 09/19/17 12:48, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
>> In V4L2 the practice is to have the KernelDoc documentation in the header
>> and not in .c source code files. This consequently makes the V4L2 fwnode
>> function documentation part of the Media documentation build.
>>
>> Also correct the link related function and argument naming in
>> documentation.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
>> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
>> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
>> Acked-by: Pavel Machek <pavel@ucw.cz>
>
> I'm still very opposed to this. In addition to increasing the risk of
> documentation becoming stale, it also makes review more difficult. I'm
> reviewing patch 05/25 of this series and I have to jump around the patch to
> verify that the documentation matches the implementation, it's really
> annoying.
>
> We should instead move all function documentation from header files to source
> files.
I disagree with this. Yes, it makes reviewing harder, but when you have to
*use* these functions as e.g. a driver developer, then having it in the
header is much more convenient.
Regards,
Hans
>
>> ---
>> drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
>> include/media/v4l2-fwnode.h | 81 +++++++++++++++++++++++++++++++-
>> 2 files changed, 80 insertions(+), 76 deletions(-)
>
> [snip]
>
^ permalink raw reply [flat|nested] 137+ messages in thread
[parent not found: <29354478-ec46-278b-c457-4e6f3cc6848c-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>]
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-19 11:04 ` Hans Verkuil
@ 2017-09-19 11:07 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:07 UTC (permalink / raw)
To: Hans Verkuil
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
pavel-+ZI9xUNit7I, sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Hans,
On Tuesday, 19 September 2017 14:04:36 EEST Hans Verkuil wrote:
> On 09/19/17 12:48, Laurent Pinchart wrote:
> > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> >> In V4L2 the practice is to have the KernelDoc documentation in the header
> >> and not in .c source code files. This consequently makes the V4L2 fwnode
> >> function documentation part of the Media documentation build.
> >>
> >> Also correct the link related function and argument naming in
> >> documentation.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
> >> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> >> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> >
> > I'm still very opposed to this. In addition to increasing the risk of
> > documentation becoming stale, it also makes review more difficult. I'm
> > reviewing patch 05/25 of this series and I have to jump around the patch
> > to verify that the documentation matches the implementation, it's really
> > annoying.
> >
> > We should instead move all function documentation from header files to
> > source files.
>
> I disagree with this. Yes, it makes reviewing harder, but when you have to
> *use* these functions as e.g. a driver developer, then having it in the
> header is much more convenient.
When writing a driver you can use the compiled documentation. We're lacking
reviewers in V4L2, we should make their life easier if we want to attract
more.
Furthermore, if documentation becomes stale, it will become useless for driver
authors, regardless of where it's stored.
> >> ---
> >>
> >> drivers/media/v4l2-core/v4l2-fwnode.c | 75 -----------------------------
> >> include/media/v4l2-fwnode.h | 81 +++++++++++++++++++++++++++-
> >> 2 files changed, 80 insertions(+), 76 deletions(-)
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 11:07 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:07 UTC (permalink / raw)
To: Hans Verkuil
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
devicetree, pavel, sre
Hi Hans,
On Tuesday, 19 September 2017 14:04:36 EEST Hans Verkuil wrote:
> On 09/19/17 12:48, Laurent Pinchart wrote:
> > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> >> In V4L2 the practice is to have the KernelDoc documentation in the header
> >> and not in .c source code files. This consequently makes the V4L2 fwnode
> >> function documentation part of the Media documentation build.
> >>
> >> Also correct the link related function and argument naming in
> >> documentation.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> Acked-by: Pavel Machek <pavel@ucw.cz>
> >
> > I'm still very opposed to this. In addition to increasing the risk of
> > documentation becoming stale, it also makes review more difficult. I'm
> > reviewing patch 05/25 of this series and I have to jump around the patch
> > to verify that the documentation matches the implementation, it's really
> > annoying.
> >
> > We should instead move all function documentation from header files to
> > source files.
>
> I disagree with this. Yes, it makes reviewing harder, but when you have to
> *use* these functions as e.g. a driver developer, then having it in the
> header is much more convenient.
When writing a driver you can use the compiled documentation. We're lacking
reviewers in V4L2, we should make their life easier if we want to attract
more.
Furthermore, if documentation becomes stale, it will become useless for driver
authors, regardless of where it's stored.
> >> ---
> >>
> >> drivers/media/v4l2-core/v4l2-fwnode.c | 75 -----------------------------
> >> include/media/v4l2-fwnode.h | 81 +++++++++++++++++++++++++++-
> >> 2 files changed, 80 insertions(+), 76 deletions(-)
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-19 11:04 ` Hans Verkuil
@ 2017-09-19 11:22 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 11:22 UTC (permalink / raw)
To: Hans Verkuil
Cc: Laurent Pinchart, Sakari Ailus,
linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
pavel-+ZI9xUNit7I, sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Hans,
On Tue, Sep 19, 2017 at 01:04:36PM +0200, Hans Verkuil wrote:
> On 09/19/17 12:48, Laurent Pinchart wrote:
> > Hi Sakari,
> >
> > Thank you for the patch.
> >
> > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> >> In V4L2 the practice is to have the KernelDoc documentation in the header
> >> and not in .c source code files. This consequently makes the V4L2 fwnode
> >> function documentation part of the Media documentation build.
> >>
> >> Also correct the link related function and argument naming in
> >> documentation.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
> >> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> >> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> >
> > I'm still very opposed to this. In addition to increasing the risk of
> > documentation becoming stale, it also makes review more difficult. I'm
> > reviewing patch 05/25 of this series and I have to jump around the patch to
> > verify that the documentation matches the implementation, it's really
> > annoying.
> >
> > We should instead move all function documentation from header files to source
> > files.
>
> I disagree with this. Yes, it makes reviewing harder, but when you have to
> *use* these functions as e.g. a driver developer, then having it in the
> header is much more convenient.
For developers writing a driver and _not_ using e.g. the HTML
documentation, programs like cscope point the user to the implementation of
the function --- which is in the .c file, not the header. This is what I
personally tend to do at least; for most of the time I ignore where exactly
a given function is implemented (this is actually not self-evident in V4L2
outside async / fwnode).
The rest of the kernel appears to generally have the KernelDoc in .c files,
for a reason or another:
14:05:15 nauris sailus [~/scratch/src/linux]git grep '/\*\*$' -- include/|wc -l
6997
14:14:46 nauris sailus [~/scratch/src/linux]git grep '/\*\*$' -- drivers/ net/ mm/ lib/ kernel/ fs/ firmware/ init/ ipc/ block/ crypto/ |wc -l
44756
I think I'm slightly leaning towards moving it: having the documentation
where the implementation is does help keeping it up-to-date. It's currently
all too easy to change a function without realising it was actually
documented somewhere.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 11:22 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 11:22 UTC (permalink / raw)
To: Hans Verkuil
Cc: Laurent Pinchart, Sakari Ailus, linux-media, niklas.soderlund,
maxime.ripard, robh, devicetree, pavel, sre
Hi Hans,
On Tue, Sep 19, 2017 at 01:04:36PM +0200, Hans Verkuil wrote:
> On 09/19/17 12:48, Laurent Pinchart wrote:
> > Hi Sakari,
> >
> > Thank you for the patch.
> >
> > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> >> In V4L2 the practice is to have the KernelDoc documentation in the header
> >> and not in .c source code files. This consequently makes the V4L2 fwnode
> >> function documentation part of the Media documentation build.
> >>
> >> Also correct the link related function and argument naming in
> >> documentation.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> Acked-by: Pavel Machek <pavel@ucw.cz>
> >
> > I'm still very opposed to this. In addition to increasing the risk of
> > documentation becoming stale, it also makes review more difficult. I'm
> > reviewing patch 05/25 of this series and I have to jump around the patch to
> > verify that the documentation matches the implementation, it's really
> > annoying.
> >
> > We should instead move all function documentation from header files to source
> > files.
>
> I disagree with this. Yes, it makes reviewing harder, but when you have to
> *use* these functions as e.g. a driver developer, then having it in the
> header is much more convenient.
For developers writing a driver and _not_ using e.g. the HTML
documentation, programs like cscope point the user to the implementation of
the function --- which is in the .c file, not the header. This is what I
personally tend to do at least; for most of the time I ignore where exactly
a given function is implemented (this is actually not self-evident in V4L2
outside async / fwnode).
The rest of the kernel appears to generally have the KernelDoc in .c files,
for a reason or another:
14:05:15 nauris sailus [~/scratch/src/linux]git grep '/\*\*$' -- include/|wc -l
6997
14:14:46 nauris sailus [~/scratch/src/linux]git grep '/\*\*$' -- drivers/ net/ mm/ lib/ kernel/ fs/ firmware/ init/ ipc/ block/ crypto/ |wc -l
44756
I think I'm slightly leaning towards moving it: having the documentation
where the implementation is does help keeping it up-to-date. It's currently
all too easy to change a function without realising it was actually
documented somewhere.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus@iki.fi
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-19 10:48 ` Laurent Pinchart
@ 2017-09-19 11:10 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 11:10 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Laurent,
On Tue, Sep 19, 2017 at 01:48:27PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> > In V4L2 the practice is to have the KernelDoc documentation in the header
> > and not in .c source code files. This consequently makes the V4L2 fwnode
> > function documentation part of the Media documentation build.
> >
> > Also correct the link related function and argument naming in
> > documentation.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
> > Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> > Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
>
> I'm still very opposed to this. In addition to increasing the risk of
> documentation becoming stale, it also makes review more difficult. I'm
> reviewing patch 05/25 of this series and I have to jump around the patch to
> verify that the documentation matches the implementation, it's really
> annoying.
I'd like to have this discussion separately from the patchset, which is
right now in its 13th version. This patch simply makes the current state
consistent; V4L2 async was the only part of V4L2 with KernelDoc
documentation in .c files.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 11:10 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 11:10 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 01:48:27PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> > In V4L2 the practice is to have the KernelDoc documentation in the header
> > and not in .c source code files. This consequently makes the V4L2 fwnode
> > function documentation part of the Media documentation build.
> >
> > Also correct the link related function and argument naming in
> > documentation.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > Acked-by: Pavel Machek <pavel@ucw.cz>
>
> I'm still very opposed to this. In addition to increasing the risk of
> documentation becoming stale, it also makes review more difficult. I'm
> reviewing patch 05/25 of this series and I have to jump around the patch to
> verify that the documentation matches the implementation, it's really
> annoying.
I'd like to have this discussion separately from the patchset, which is
right now in its 13th version. This patch simply makes the current state
consistent; V4L2 async was the only part of V4L2 with KernelDoc
documentation in .c files.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus@iki.fi
^ permalink raw reply [flat|nested] 137+ messages in thread
[parent not found: <20170919111036.5va2unwqh2vymojr-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>]
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-19 11:10 ` Sakari Ailus
@ 2017-09-19 11:14 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:14 UTC (permalink / raw)
To: Sakari Ailus
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Sakari,
On Tuesday, 19 September 2017 14:10:37 EEST Sakari Ailus wrote:
> On Tue, Sep 19, 2017 at 01:48:27PM +0300, Laurent Pinchart wrote:
> > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> >> In V4L2 the practice is to have the KernelDoc documentation in the
> >> header and not in .c source code files. This consequently makes the V4L2
> >> fwnode function documentation part of the Media documentation build.
> >>
> >> Also correct the link related function and argument naming in
> >> documentation.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
> >> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> >> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> >
> > I'm still very opposed to this. In addition to increasing the risk of
> > documentation becoming stale, it also makes review more difficult. I'm
> > reviewing patch 05/25 of this series and I have to jump around the patch
> > to verify that the documentation matches the implementation, it's really
> > annoying.
>
> I'd like to have this discussion separately from the patchset, which is
> right now in its 13th version. This patch simply makes the current state
> consistent; V4L2 async was the only part of V4L2 with KernelDoc
> documentation in .c files.
But there's no need to move the documentation at this point until we reach an
agreement, is there ?
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 11:14 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:14 UTC (permalink / raw)
To: Sakari Ailus
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Sakari,
On Tuesday, 19 September 2017 14:10:37 EEST Sakari Ailus wrote:
> On Tue, Sep 19, 2017 at 01:48:27PM +0300, Laurent Pinchart wrote:
> > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> >> In V4L2 the practice is to have the KernelDoc documentation in the
> >> header and not in .c source code files. This consequently makes the V4L2
> >> fwnode function documentation part of the Media documentation build.
> >>
> >> Also correct the link related function and argument naming in
> >> documentation.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> Acked-by: Pavel Machek <pavel@ucw.cz>
> >
> > I'm still very opposed to this. In addition to increasing the risk of
> > documentation becoming stale, it also makes review more difficult. I'm
> > reviewing patch 05/25 of this series and I have to jump around the patch
> > to verify that the documentation matches the implementation, it's really
> > annoying.
>
> I'd like to have this discussion separately from the patchset, which is
> right now in its 13th version. This patch simply makes the current state
> consistent; V4L2 async was the only part of V4L2 with KernelDoc
> documentation in .c files.
But there's no need to move the documentation at this point until we reach an
agreement, is there ?
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
2017-09-19 11:14 ` Laurent Pinchart
@ 2017-09-19 11:25 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 11:25 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Laurent,
On Tue, Sep 19, 2017 at 02:14:39PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tuesday, 19 September 2017 14:10:37 EEST Sakari Ailus wrote:
> > On Tue, Sep 19, 2017 at 01:48:27PM +0300, Laurent Pinchart wrote:
> > > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> > >> In V4L2 the practice is to have the KernelDoc documentation in the
> > >> header and not in .c source code files. This consequently makes the V4L2
> > >> fwnode function documentation part of the Media documentation build.
> > >>
> > >> Also correct the link related function and argument naming in
> > >> documentation.
> > >>
> > >> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> > >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>
> > >> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> > >> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> > >
> > > I'm still very opposed to this. In addition to increasing the risk of
> > > documentation becoming stale, it also makes review more difficult. I'm
> > > reviewing patch 05/25 of this series and I have to jump around the patch
> > > to verify that the documentation matches the implementation, it's really
> > > annoying.
> >
> > I'd like to have this discussion separately from the patchset, which is
> > right now in its 13th version. This patch simply makes the current state
> > consistent; V4L2 async was the only part of V4L2 with KernelDoc
> > documentation in .c files.
>
> But there's no need to move the documentation at this point until we reach an
> agreement, is there ?
The status quo has is that the KernelDoc is in headers. Generally, if you
change parts that appear to lack framework-wide changes already done, you
do those changes before making other changes since it's a no-brainer.
Which is what this patch represents.
If we end up moving the KernelDoc to .c files moving this back could result
into an extra patch. I'm not too worried about that frankly.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 01/25] v4l: fwnode: Move KernelDoc documentation to the header
@ 2017-09-19 11:25 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 11:25 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 02:14:39PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tuesday, 19 September 2017 14:10:37 EEST Sakari Ailus wrote:
> > On Tue, Sep 19, 2017 at 01:48:27PM +0300, Laurent Pinchart wrote:
> > > On Friday, 15 September 2017 17:17:00 EEST Sakari Ailus wrote:
> > >> In V4L2 the practice is to have the KernelDoc documentation in the
> > >> header and not in .c source code files. This consequently makes the V4L2
> > >> fwnode function documentation part of the Media documentation build.
> > >>
> > >> Also correct the link related function and argument naming in
> > >> documentation.
> > >>
> > >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > >> Acked-by: Pavel Machek <pavel@ucw.cz>
> > >
> > > I'm still very opposed to this. In addition to increasing the risk of
> > > documentation becoming stale, it also makes review more difficult. I'm
> > > reviewing patch 05/25 of this series and I have to jump around the patch
> > > to verify that the documentation matches the implementation, it's really
> > > annoying.
> >
> > I'd like to have this discussion separately from the patchset, which is
> > right now in its 13th version. This patch simply makes the current state
> > consistent; V4L2 async was the only part of V4L2 with KernelDoc
> > documentation in .c files.
>
> But there's no need to move the documentation at this point until we reach an
> agreement, is there ?
The status quo has is that the KernelDoc is in headers. Generally, if you
change parts that appear to lack framework-wide changes already done, you
do those changes before making other changes since it's a no-brainer.
Which is what this patch represents.
If we end up moving the KernelDoc to .c files moving this back could result
into an extra patch. I'm not too worried about that frankly.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus@iki.fi
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 03/25] v4l: async: Use more intuitive names for internal functions
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Rename internal functions to make the names of the functions better
describe what they do.
Old name New name
v4l2_async_test_notify v4l2_async_match_notify
v4l2_async_belongs v4l2_async_find_match
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
---
drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index e109d9da4653..831f185ecd47 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);
static LIST_HEAD(notifier_list);
static DEFINE_MUTEX(list_lock);
-static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd)
+static struct v4l2_async_subdev *v4l2_async_find_match(
+ struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
{
bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
struct v4l2_async_subdev *asd;
@@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
return NULL;
}
-static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd)
+static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
{
int ret;
@@ -175,11 +175,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
int ret;
- asd = v4l2_async_belongs(notifier, sd);
+ asd = v4l2_async_find_match(notifier, sd);
if (!asd)
continue;
- ret = v4l2_async_test_notify(notifier, sd, asd);
+ ret = v4l2_async_match_notify(notifier, sd, asd);
if (ret < 0) {
mutex_unlock(&list_lock);
return ret;
@@ -236,9 +236,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
INIT_LIST_HEAD(&sd->async_list);
list_for_each_entry(notifier, ¬ifier_list, list) {
- struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
+ struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
+ sd);
if (asd) {
- int ret = v4l2_async_test_notify(notifier, sd, asd);
+ int ret = v4l2_async_match_notify(notifier, sd, asd);
mutex_unlock(&list_lock);
return ret;
}
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 03/25] v4l: async: Use more intuitive names for internal functions
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Rename internal functions to make the names of the functions better
describe what they do.
Old name New name
v4l2_async_test_notify v4l2_async_match_notify
v4l2_async_belongs v4l2_async_find_match
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index e109d9da4653..831f185ecd47 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);
static LIST_HEAD(notifier_list);
static DEFINE_MUTEX(list_lock);
-static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd)
+static struct v4l2_async_subdev *v4l2_async_find_match(
+ struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
{
bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
struct v4l2_async_subdev *asd;
@@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
return NULL;
}
-static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd)
+static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
{
int ret;
@@ -175,11 +175,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
int ret;
- asd = v4l2_async_belongs(notifier, sd);
+ asd = v4l2_async_find_match(notifier, sd);
if (!asd)
continue;
- ret = v4l2_async_test_notify(notifier, sd, asd);
+ ret = v4l2_async_match_notify(notifier, sd, asd);
if (ret < 0) {
mutex_unlock(&list_lock);
return ret;
@@ -236,9 +236,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
INIT_LIST_HEAD(&sd->async_list);
list_for_each_entry(notifier, ¬ifier_list, list) {
- struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
+ struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
+ sd);
if (asd) {
- int ret = v4l2_async_test_notify(notifier, sd, asd);
+ int ret = v4l2_async_match_notify(notifier, sd, asd);
mutex_unlock(&list_lock);
return ret;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 05/25] v4l: fwnode: Support generic parsing of graph endpoints in a device
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Add two functions for parsing devices graph endpoints:
v4l2_async_notifier_parse_fwnode_endpoints and
v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
over all endpoints whereas the latter only iterates over the endpoints in
a given port.
The former is mostly useful for existing drivers that currently implement
the iteration over all the endpoints themselves whereas the latter is
especially intended for devices with both sinks and sources: async
sub-devices for external devices connected to the device's sources will
have already been set up, or they are part of the master device.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/media/v4l2-core/v4l2-async.c | 30 ++++++
drivers/media/v4l2-core/v4l2-fwnode.c | 185 ++++++++++++++++++++++++++++++++++
include/media/v4l2-async.h | 24 ++++-
include/media/v4l2-fwnode.h | 117 +++++++++++++++++++++
4 files changed, 354 insertions(+), 2 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 831f185ecd47..bf0215dde616 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -22,6 +22,7 @@
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
@@ -219,6 +220,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
}
EXPORT_SYMBOL(v4l2_async_notifier_unregister);
+void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
+{
+ unsigned int i;
+
+ if (!notifier->max_subdevs)
+ return;
+
+ for (i = 0; i < notifier->num_subdevs; i++) {
+ struct v4l2_async_subdev *asd = notifier->subdevs[i];
+
+ switch (asd->match_type) {
+ case V4L2_ASYNC_MATCH_FWNODE:
+ fwnode_handle_put(asd->match.fwnode.fwnode);
+ break;
+ default:
+ WARN_ON_ONCE(true);
+ }
+
+ kfree(asd);
+ }
+
+ notifier->max_subdevs = 0;
+ notifier->num_subdevs = 0;
+
+ kvfree(notifier->subdevs);
+ notifier->subdevs = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_release);
+
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *notifier;
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 706f9e7b90f1..44ee35f6aad5 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -19,6 +19,7 @@
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/property.h>
@@ -26,6 +27,7 @@
#include <linux/string.h>
#include <linux/types.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
enum v4l2_fwnode_bus_type {
@@ -313,6 +315,189 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
+static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
+ unsigned int max_subdevs)
+{
+ struct v4l2_async_subdev **subdevs;
+
+ if (max_subdevs <= notifier->max_subdevs)
+ return 0;
+
+ subdevs = kvmalloc_array(
+ max_subdevs, sizeof(*notifier->subdevs),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!subdevs)
+ return -ENOMEM;
+
+ if (notifier->subdevs) {
+ memcpy(subdevs, notifier->subdevs,
+ sizeof(*subdevs) * notifier->num_subdevs);
+
+ kvfree(notifier->subdevs);
+ }
+
+ notifier->subdevs = subdevs;
+ notifier->max_subdevs = max_subdevs;
+
+ return 0;
+}
+
+static int v4l2_async_notifier_fwnode_parse_endpoint(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ struct fwnode_handle *endpoint, unsigned int asd_struct_size,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ struct v4l2_async_subdev *asd;
+ struct v4l2_fwnode_endpoint *vep;
+ int ret = 0;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return -ENOMEM;
+
+ asd->match.fwnode.fwnode =
+ fwnode_graph_get_remote_port_parent(endpoint);
+ if (!asd->match.fwnode.fwnode) {
+ dev_warn(dev, "bad remote port parent\n");
+ ret = -EINVAL;
+ goto out_err;
+ }
+
+ /* Ignore endpoints the parsing of which failed. */
+ vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
+ if (IS_ERR(vep)) {
+ ret = PTR_ERR(vep);
+ dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
+ ret);
+ goto out_err;
+ }
+
+ ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
+ if (ret == -ENOTCONN)
+ dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port,
+ vep->base.id);
+ else if (ret < 0)
+ dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n",
+ vep->base.port, vep->base.id, ret);
+ v4l2_fwnode_endpoint_free(vep);
+ if (ret < 0)
+ goto out_err;
+
+ asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+ notifier->subdevs[notifier->num_subdevs] = asd;
+ notifier->num_subdevs++;
+
+ return 0;
+
+out_err:
+ fwnode_handle_put(asd->match.fwnode.fwnode);
+ kfree(asd);
+
+ return ret == -ENOTCONN ? 0 : ret;
+}
+
+static int __v4l2_async_notifier_parse_fwnode_endpoints(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size, unsigned int port, bool has_port,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ struct fwnode_handle *fwnode = NULL;
+ unsigned int max_subdevs = notifier->max_subdevs;
+ int ret;
+
+ if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
+ return -EINVAL;
+
+ for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
+ dev_fwnode(dev), fwnode)); ) {
+ if (!fwnode_device_is_available(
+ fwnode_graph_get_port_parent(fwnode)))
+ continue;
+
+ if (has_port) {
+ struct fwnode_endpoint ep;
+
+ ret = fwnode_graph_parse_endpoint(fwnode, &ep);
+ if (ret) {
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+
+ if (ep.port != port)
+ continue;
+ }
+ max_subdevs++;
+ }
+
+ /* No subdevs to add? Return here. */
+ if (max_subdevs == notifier->max_subdevs)
+ return 0;
+
+ ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
+ if (ret)
+ return ret;
+
+ for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
+ dev_fwnode(dev), fwnode)); ) {
+ if (!fwnode_device_is_available(
+ fwnode_graph_get_port_parent(fwnode)))
+ continue;
+
+ if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (has_port) {
+ struct fwnode_endpoint ep;
+
+ ret = fwnode_graph_parse_endpoint(fwnode, &ep);
+ if (ret)
+ break;
+
+ if (ep.port != port)
+ continue;
+ }
+
+ ret = v4l2_async_notifier_fwnode_parse_endpoint(
+ dev, notifier, fwnode, asd_struct_size, parse_endpoint);
+ if (ret < 0)
+ break;
+ }
+
+ fwnode_handle_put(fwnode);
+
+ return ret;
+}
+
+int v4l2_async_notifier_parse_fwnode_endpoints(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ return __v4l2_async_notifier_parse_fwnode_endpoints(
+ dev, notifier, asd_struct_size, 0, false, parse_endpoint);
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
+
+int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size, unsigned int port,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ return __v4l2_async_notifier_parse_fwnode_endpoints(
+ dev, notifier, asd_struct_size, port, true, parse_endpoint);
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index c69d8c8a66d0..96fa1afc00dd 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -18,7 +18,6 @@ struct device;
struct device_node;
struct v4l2_device;
struct v4l2_subdev;
-struct v4l2_async_notifier;
/* A random max subdevice number, used to allocate an array on stack */
#define V4L2_MAX_SUBDEVS 128U
@@ -50,6 +49,10 @@ enum v4l2_async_match_type {
* @match: union of per-bus type matching data sets
* @list: used to link struct v4l2_async_subdev objects, waiting to be
* probed, to a notifier->waiting list
+ *
+ * When this struct is used as a member in a driver specific struct,
+ * the driver specific struct shall contain the @struct
+ * v4l2_async_subdev as its first member.
*/
struct v4l2_async_subdev {
enum v4l2_async_match_type match_type;
@@ -78,7 +81,8 @@ struct v4l2_async_subdev {
/**
* struct v4l2_async_notifier - v4l2_device notifier data
*
- * @num_subdevs: number of subdevices
+ * @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
* @waiting: list of struct v4l2_async_subdev, waiting for their drivers
@@ -90,6 +94,7 @@ struct v4l2_async_subdev {
*/
struct v4l2_async_notifier {
unsigned int num_subdevs;
+ unsigned int max_subdevs;
struct v4l2_async_subdev **subdevs;
struct v4l2_device *v4l2_dev;
struct list_head waiting;
@@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
/**
+ * v4l2_async_notifier_release - release notifier resources
+ * @notifier: the notifier the resources of which are to be released
+ *
+ * Release memory resources related to a notifier, including the async
+ * sub-devices allocated for the purposes of the notifier. The user is
+ * responsible for releasing the notifier's resources after calling
+ * @v4l2_async_notifier_parse_fwnode_endpoints.
+ *
+ * There is no harm from calling v4l2_async_notifier_release in other
+ * cases as long as its memory has been zeroed after it has been
+ * allocated.
+ */
+void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier);
+
+/**
* v4l2_async_register_subdev - registers a sub-device to the asynchronous
* subdevice framework
*
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 68eb22ba571b..83afac48ea6b 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -25,6 +25,8 @@
#include <media/v4l2-mediabus.h>
struct fwnode_handle;
+struct v4l2_async_notifier;
+struct v4l2_async_subdev;
#define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4
@@ -201,4 +203,119 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
*/
void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
+/**
+ * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
+ * device node
+ * @dev: the device the endpoints of which are to be parsed
+ * @notifier: notifier for @dev
+ * @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.
+ * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
+ * endpoint. Optional.
+ * Return: %0 on success
+ * %-ENOTCONN if the endpoint is to be skipped but this
+ * should not be considered as an error
+ * %-EINVAL if the endpoint configuration is invalid
+ *
+ * Parse the fwnode endpoints of the @dev device and populate the async sub-
+ * devices array of the notifier. The @parse_endpoint callback function is
+ * called for each endpoint with the corresponding async sub-device pointer to
+ * let the caller initialize the driver-specific part of the async sub-device
+ * structure.
+ *
+ * The notifier memory shall be zeroed before this function is called on the
+ * notifier.
+ *
+ * This function may not be called on a registered notifier and may be called on
+ * a notifier only once.
+ *
+ * Do not change the notifier's subdevs array, take references to the subdevs
+ * array itself or change the notifier's num_subdevs field. This is because this
+ * function allocates and reallocates the subdevs array based on parsing
+ * endpoints.
+ *
+ * The @struct v4l2_fwnode_endpoint passed to the callback function
+ * @parse_endpoint is released once the function is finished. If there is a need
+ * to retain that configuration, the user needs to allocate memory for it.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even if the function returned an error.
+ *
+ * Return: %0 on success, including when no async sub-devices are found
+ * %-ENOMEM if memory allocation failed
+ * %-EINVAL if graph or endpoint parsing failed
+ * Other error codes as returned by @parse_endpoint
+ */
+int v4l2_async_notifier_parse_fwnode_endpoints(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd));
+
+/**
+ * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
+ * endpoints of a port in a
+ * device node
+ * @dev: the device the endpoints of which are to be parsed
+ * @notifier: notifier for @dev
+ * @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.
+ * @port: port number where endpoints are to be parsed
+ * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
+ * endpoint. Optional.
+ * Return: %0 on success
+ * %-ENOTCONN if the endpoint is to be skipped but this
+ * should not be considered as an error
+ * %-EINVAL if the endpoint configuration is invalid
+ *
+ * This function is just like @v4l2_async_notifier_parse_fwnode_endpoints with
+ * the exception that it only parses endpoints in a given port. This is useful
+ * on devices that have both sinks and sources: the async sub-devices connected
+ * to sources have already been set up by another driver (on capture devices).
+ *
+ * Parse the fwnode endpoints of the @dev device on a given @port and populate
+ * the async sub-devices array of the notifier. The @parse_endpoint callback
+ * function is called for each endpoint with the corresponding async sub-device
+ * pointer to let the caller initialize the driver-specific part of the async
+ * sub-device structure.
+ *
+ * The notifier memory shall be zeroed before this function is called on the
+ * notifier the first time.
+ *
+ * This function may not be called on a registered notifier and may be called on
+ * a notifier only once per port.
+ *
+ * Do not change the notifier's subdevs array, take references to the subdevs
+ * array itself or change the notifier's num_subdevs field. This is because this
+ * function allocates and reallocates the subdevs array based on parsing
+ * endpoints.
+ *
+ * The @struct v4l2_fwnode_endpoint passed to the callback function
+ * @parse_endpoint is released once the function is finished. If there is a need
+ * to retain that configuration, the user needs to allocate memory for it.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even if the function returned an error.
+ *
+ * Return: %0 on success, including when no async sub-devices are found
+ * %-ENOMEM if memory allocation failed
+ * %-EINVAL if graph or endpoint parsing failed
+ * Other error codes as returned by @parse_endpoint
+ */
+int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size, unsigned int port,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd));
+
#endif /* _V4L2_FWNODE_H */
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 05/25] v4l: fwnode: Support generic parsing of graph endpoints in a device
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Add two functions for parsing devices graph endpoints:
v4l2_async_notifier_parse_fwnode_endpoints and
v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
over all endpoints whereas the latter only iterates over the endpoints in
a given port.
The former is mostly useful for existing drivers that currently implement
the iteration over all the endpoints themselves whereas the latter is
especially intended for devices with both sinks and sources: async
sub-devices for external devices connected to the device's sources will
have already been set up, or they are part of the master device.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/v4l2-core/v4l2-async.c | 30 ++++++
drivers/media/v4l2-core/v4l2-fwnode.c | 185 ++++++++++++++++++++++++++++++++++
include/media/v4l2-async.h | 24 ++++-
include/media/v4l2-fwnode.h | 117 +++++++++++++++++++++
4 files changed, 354 insertions(+), 2 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 831f185ecd47..bf0215dde616 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -22,6 +22,7 @@
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
@@ -219,6 +220,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
}
EXPORT_SYMBOL(v4l2_async_notifier_unregister);
+void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
+{
+ unsigned int i;
+
+ if (!notifier->max_subdevs)
+ return;
+
+ for (i = 0; i < notifier->num_subdevs; i++) {
+ struct v4l2_async_subdev *asd = notifier->subdevs[i];
+
+ switch (asd->match_type) {
+ case V4L2_ASYNC_MATCH_FWNODE:
+ fwnode_handle_put(asd->match.fwnode.fwnode);
+ break;
+ default:
+ WARN_ON_ONCE(true);
+ }
+
+ kfree(asd);
+ }
+
+ notifier->max_subdevs = 0;
+ notifier->num_subdevs = 0;
+
+ kvfree(notifier->subdevs);
+ notifier->subdevs = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_release);
+
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *notifier;
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 706f9e7b90f1..44ee35f6aad5 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -19,6 +19,7 @@
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/property.h>
@@ -26,6 +27,7 @@
#include <linux/string.h>
#include <linux/types.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
enum v4l2_fwnode_bus_type {
@@ -313,6 +315,189 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
+static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
+ unsigned int max_subdevs)
+{
+ struct v4l2_async_subdev **subdevs;
+
+ if (max_subdevs <= notifier->max_subdevs)
+ return 0;
+
+ subdevs = kvmalloc_array(
+ max_subdevs, sizeof(*notifier->subdevs),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!subdevs)
+ return -ENOMEM;
+
+ if (notifier->subdevs) {
+ memcpy(subdevs, notifier->subdevs,
+ sizeof(*subdevs) * notifier->num_subdevs);
+
+ kvfree(notifier->subdevs);
+ }
+
+ notifier->subdevs = subdevs;
+ notifier->max_subdevs = max_subdevs;
+
+ return 0;
+}
+
+static int v4l2_async_notifier_fwnode_parse_endpoint(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ struct fwnode_handle *endpoint, unsigned int asd_struct_size,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ struct v4l2_async_subdev *asd;
+ struct v4l2_fwnode_endpoint *vep;
+ int ret = 0;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return -ENOMEM;
+
+ asd->match.fwnode.fwnode =
+ fwnode_graph_get_remote_port_parent(endpoint);
+ if (!asd->match.fwnode.fwnode) {
+ dev_warn(dev, "bad remote port parent\n");
+ ret = -EINVAL;
+ goto out_err;
+ }
+
+ /* Ignore endpoints the parsing of which failed. */
+ vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
+ if (IS_ERR(vep)) {
+ ret = PTR_ERR(vep);
+ dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
+ ret);
+ goto out_err;
+ }
+
+ ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
+ if (ret == -ENOTCONN)
+ dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port,
+ vep->base.id);
+ else if (ret < 0)
+ dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n",
+ vep->base.port, vep->base.id, ret);
+ v4l2_fwnode_endpoint_free(vep);
+ if (ret < 0)
+ goto out_err;
+
+ asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+ notifier->subdevs[notifier->num_subdevs] = asd;
+ notifier->num_subdevs++;
+
+ return 0;
+
+out_err:
+ fwnode_handle_put(asd->match.fwnode.fwnode);
+ kfree(asd);
+
+ return ret == -ENOTCONN ? 0 : ret;
+}
+
+static int __v4l2_async_notifier_parse_fwnode_endpoints(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size, unsigned int port, bool has_port,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ struct fwnode_handle *fwnode = NULL;
+ unsigned int max_subdevs = notifier->max_subdevs;
+ int ret;
+
+ if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
+ return -EINVAL;
+
+ for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
+ dev_fwnode(dev), fwnode)); ) {
+ if (!fwnode_device_is_available(
+ fwnode_graph_get_port_parent(fwnode)))
+ continue;
+
+ if (has_port) {
+ struct fwnode_endpoint ep;
+
+ ret = fwnode_graph_parse_endpoint(fwnode, &ep);
+ if (ret) {
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+
+ if (ep.port != port)
+ continue;
+ }
+ max_subdevs++;
+ }
+
+ /* No subdevs to add? Return here. */
+ if (max_subdevs == notifier->max_subdevs)
+ return 0;
+
+ ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
+ if (ret)
+ return ret;
+
+ for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
+ dev_fwnode(dev), fwnode)); ) {
+ if (!fwnode_device_is_available(
+ fwnode_graph_get_port_parent(fwnode)))
+ continue;
+
+ if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (has_port) {
+ struct fwnode_endpoint ep;
+
+ ret = fwnode_graph_parse_endpoint(fwnode, &ep);
+ if (ret)
+ break;
+
+ if (ep.port != port)
+ continue;
+ }
+
+ ret = v4l2_async_notifier_fwnode_parse_endpoint(
+ dev, notifier, fwnode, asd_struct_size, parse_endpoint);
+ if (ret < 0)
+ break;
+ }
+
+ fwnode_handle_put(fwnode);
+
+ return ret;
+}
+
+int v4l2_async_notifier_parse_fwnode_endpoints(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ return __v4l2_async_notifier_parse_fwnode_endpoints(
+ dev, notifier, asd_struct_size, 0, false, parse_endpoint);
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
+
+int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size, unsigned int port,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd))
+{
+ return __v4l2_async_notifier_parse_fwnode_endpoints(
+ dev, notifier, asd_struct_size, port, true, parse_endpoint);
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index c69d8c8a66d0..96fa1afc00dd 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -18,7 +18,6 @@ struct device;
struct device_node;
struct v4l2_device;
struct v4l2_subdev;
-struct v4l2_async_notifier;
/* A random max subdevice number, used to allocate an array on stack */
#define V4L2_MAX_SUBDEVS 128U
@@ -50,6 +49,10 @@ enum v4l2_async_match_type {
* @match: union of per-bus type matching data sets
* @list: used to link struct v4l2_async_subdev objects, waiting to be
* probed, to a notifier->waiting list
+ *
+ * When this struct is used as a member in a driver specific struct,
+ * the driver specific struct shall contain the @struct
+ * v4l2_async_subdev as its first member.
*/
struct v4l2_async_subdev {
enum v4l2_async_match_type match_type;
@@ -78,7 +81,8 @@ struct v4l2_async_subdev {
/**
* struct v4l2_async_notifier - v4l2_device notifier data
*
- * @num_subdevs: number of subdevices
+ * @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
* @waiting: list of struct v4l2_async_subdev, waiting for their drivers
@@ -90,6 +94,7 @@ struct v4l2_async_subdev {
*/
struct v4l2_async_notifier {
unsigned int num_subdevs;
+ unsigned int max_subdevs;
struct v4l2_async_subdev **subdevs;
struct v4l2_device *v4l2_dev;
struct list_head waiting;
@@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
/**
+ * v4l2_async_notifier_release - release notifier resources
+ * @notifier: the notifier the resources of which are to be released
+ *
+ * Release memory resources related to a notifier, including the async
+ * sub-devices allocated for the purposes of the notifier. The user is
+ * responsible for releasing the notifier's resources after calling
+ * @v4l2_async_notifier_parse_fwnode_endpoints.
+ *
+ * There is no harm from calling v4l2_async_notifier_release in other
+ * cases as long as its memory has been zeroed after it has been
+ * allocated.
+ */
+void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier);
+
+/**
* v4l2_async_register_subdev - registers a sub-device to the asynchronous
* subdevice framework
*
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 68eb22ba571b..83afac48ea6b 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -25,6 +25,8 @@
#include <media/v4l2-mediabus.h>
struct fwnode_handle;
+struct v4l2_async_notifier;
+struct v4l2_async_subdev;
#define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4
@@ -201,4 +203,119 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
*/
void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
+/**
+ * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
+ * device node
+ * @dev: the device the endpoints of which are to be parsed
+ * @notifier: notifier for @dev
+ * @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.
+ * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
+ * endpoint. Optional.
+ * Return: %0 on success
+ * %-ENOTCONN if the endpoint is to be skipped but this
+ * should not be considered as an error
+ * %-EINVAL if the endpoint configuration is invalid
+ *
+ * Parse the fwnode endpoints of the @dev device and populate the async sub-
+ * devices array of the notifier. The @parse_endpoint callback function is
+ * called for each endpoint with the corresponding async sub-device pointer to
+ * let the caller initialize the driver-specific part of the async sub-device
+ * structure.
+ *
+ * The notifier memory shall be zeroed before this function is called on the
+ * notifier.
+ *
+ * This function may not be called on a registered notifier and may be called on
+ * a notifier only once.
+ *
+ * Do not change the notifier's subdevs array, take references to the subdevs
+ * array itself or change the notifier's num_subdevs field. This is because this
+ * function allocates and reallocates the subdevs array based on parsing
+ * endpoints.
+ *
+ * The @struct v4l2_fwnode_endpoint passed to the callback function
+ * @parse_endpoint is released once the function is finished. If there is a need
+ * to retain that configuration, the user needs to allocate memory for it.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even if the function returned an error.
+ *
+ * Return: %0 on success, including when no async sub-devices are found
+ * %-ENOMEM if memory allocation failed
+ * %-EINVAL if graph or endpoint parsing failed
+ * Other error codes as returned by @parse_endpoint
+ */
+int v4l2_async_notifier_parse_fwnode_endpoints(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd));
+
+/**
+ * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
+ * endpoints of a port in a
+ * device node
+ * @dev: the device the endpoints of which are to be parsed
+ * @notifier: notifier for @dev
+ * @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.
+ * @port: port number where endpoints are to be parsed
+ * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
+ * endpoint. Optional.
+ * Return: %0 on success
+ * %-ENOTCONN if the endpoint is to be skipped but this
+ * should not be considered as an error
+ * %-EINVAL if the endpoint configuration is invalid
+ *
+ * This function is just like @v4l2_async_notifier_parse_fwnode_endpoints with
+ * the exception that it only parses endpoints in a given port. This is useful
+ * on devices that have both sinks and sources: the async sub-devices connected
+ * to sources have already been set up by another driver (on capture devices).
+ *
+ * Parse the fwnode endpoints of the @dev device on a given @port and populate
+ * the async sub-devices array of the notifier. The @parse_endpoint callback
+ * function is called for each endpoint with the corresponding async sub-device
+ * pointer to let the caller initialize the driver-specific part of the async
+ * sub-device structure.
+ *
+ * The notifier memory shall be zeroed before this function is called on the
+ * notifier the first time.
+ *
+ * This function may not be called on a registered notifier and may be called on
+ * a notifier only once per port.
+ *
+ * Do not change the notifier's subdevs array, take references to the subdevs
+ * array itself or change the notifier's num_subdevs field. This is because this
+ * function allocates and reallocates the subdevs array based on parsing
+ * endpoints.
+ *
+ * The @struct v4l2_fwnode_endpoint passed to the callback function
+ * @parse_endpoint is released once the function is finished. If there is a need
+ * to retain that configuration, the user needs to allocate memory for it.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even if the function returned an error.
+ *
+ * Return: %0 on success, including when no async sub-devices are found
+ * %-ENOMEM if memory allocation failed
+ * %-EINVAL if graph or endpoint parsing failed
+ * Other error codes as returned by @parse_endpoint
+ */
+int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+ struct device *dev, struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size, unsigned int port,
+ int (*parse_endpoint)(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd));
+
#endif /* _V4L2_FWNODE_H */
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
* Re: [PATCH v13 05/25] v4l: fwnode: Support generic parsing of graph endpoints in a device
2017-09-15 14:17 ` Sakari Ailus
(?)
@ 2017-09-19 8:03 ` Hans Verkuil
2017-09-19 8:20 ` Sakari Ailus
-1 siblings, 1 reply; 137+ messages in thread
From: Hans Verkuil @ 2017-09-19 8:03 UTC (permalink / raw)
To: Sakari Ailus, linux-media
Cc: niklas.soderlund, maxime.ripard, robh, laurent.pinchart,
devicetree, pavel, sre
On 09/15/2017 04:17 PM, Sakari Ailus wrote:
> Add two functions for parsing devices graph endpoints:
> v4l2_async_notifier_parse_fwnode_endpoints and
> v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
> over all endpoints whereas the latter only iterates over the endpoints in
> a given port.
>
> The former is mostly useful for existing drivers that currently implement
> the iteration over all the endpoints themselves whereas the latter is
> especially intended for devices with both sinks and sources: async
> sub-devices for external devices connected to the device's sources will
> have already been set up, or they are part of the master device.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 30 ++++++
> drivers/media/v4l2-core/v4l2-fwnode.c | 185 ++++++++++++++++++++++++++++++++++
> include/media/v4l2-async.h | 24 ++++-
> include/media/v4l2-fwnode.h | 117 +++++++++++++++++++++
> 4 files changed, 354 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 831f185ecd47..bf0215dde616 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -22,6 +22,7 @@
>
> #include <media/v4l2-async.h>
> #include <media/v4l2-device.h>
> +#include <media/v4l2-fwnode.h>
> #include <media/v4l2-subdev.h>
>
> static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> @@ -219,6 +220,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> }
> EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>
> +void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
> +{
> + unsigned int i;
> +
> + if (!notifier->max_subdevs)
> + return;
> +
> + for (i = 0; i < notifier->num_subdevs; i++) {
> + struct v4l2_async_subdev *asd = notifier->subdevs[i];
> +
> + switch (asd->match_type) {
> + case V4L2_ASYNC_MATCH_FWNODE:
> + fwnode_handle_put(asd->match.fwnode.fwnode);
> + break;
> + default:
> + WARN_ON_ONCE(true);
Please add a break here.
> + }
> +
> + kfree(asd);
> + }
> +
> + notifier->max_subdevs = 0;
> + notifier->num_subdevs = 0;
> +
> + kvfree(notifier->subdevs);
> + notifier->subdevs = NULL;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_release);
> +
> int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> {
> struct v4l2_async_notifier *notifier;
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 706f9e7b90f1..44ee35f6aad5 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -19,6 +19,7 @@
> */
> #include <linux/acpi.h>
> #include <linux/kernel.h>
> +#include <linux/mm.h>
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/property.h>
> @@ -26,6 +27,7 @@
> #include <linux/string.h>
> #include <linux/types.h>
>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-fwnode.h>
>
> enum v4l2_fwnode_bus_type {
> @@ -313,6 +315,189 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> }
> EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
>
> +static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
> + unsigned int max_subdevs)
> +{
> + struct v4l2_async_subdev **subdevs;
> +
> + if (max_subdevs <= notifier->max_subdevs)
> + return 0;
> +
> + subdevs = kvmalloc_array(
> + max_subdevs, sizeof(*notifier->subdevs),
> + GFP_KERNEL | __GFP_ZERO);
> + if (!subdevs)
> + return -ENOMEM;
> +
> + if (notifier->subdevs) {
> + memcpy(subdevs, notifier->subdevs,
> + sizeof(*subdevs) * notifier->num_subdevs);
> +
> + kvfree(notifier->subdevs);
> + }
> +
> + notifier->subdevs = subdevs;
> + notifier->max_subdevs = max_subdevs;
> +
> + return 0;
> +}
> +
> +static int v4l2_async_notifier_fwnode_parse_endpoint(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + struct fwnode_handle *endpoint, unsigned int asd_struct_size,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd))
> +{
> + struct v4l2_async_subdev *asd;
> + struct v4l2_fwnode_endpoint *vep;
> + int ret = 0;
> +
> + asd = kzalloc(asd_struct_size, GFP_KERNEL);
> + if (!asd)
> + return -ENOMEM;
> +
> + asd->match.fwnode.fwnode =
> + fwnode_graph_get_remote_port_parent(endpoint);
> + if (!asd->match.fwnode.fwnode) {
> + dev_warn(dev, "bad remote port parent\n");
> + ret = -EINVAL;
> + goto out_err;
> + }
> +
> + /* Ignore endpoints the parsing of which failed. */
> + vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
> + if (IS_ERR(vep)) {
> + ret = PTR_ERR(vep);
> + dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
> + ret);
> + goto out_err;
> + }
> +
> + ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
> + if (ret == -ENOTCONN)
> + dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port,
> + vep->base.id);
> + else if (ret < 0)
> + dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n",
> + vep->base.port, vep->base.id, ret);
> + v4l2_fwnode_endpoint_free(vep);
> + if (ret < 0)
> + goto out_err;
> +
> + asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> + notifier->subdevs[notifier->num_subdevs] = asd;
> + notifier->num_subdevs++;
> +
> + return 0;
> +
> +out_err:
> + fwnode_handle_put(asd->match.fwnode.fwnode);
> + kfree(asd);
> +
> + return ret == -ENOTCONN ? 0 : ret;
> +}
> +
> +static int __v4l2_async_notifier_parse_fwnode_endpoints(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size, unsigned int port, bool has_port,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd))
> +{
> + struct fwnode_handle *fwnode = NULL;
> + unsigned int max_subdevs = notifier->max_subdevs;
> + int ret;
> +
> + if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
> + return -EINVAL;
> +
> + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> + dev_fwnode(dev), fwnode)); ) {
You can replace this by:
while ((fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode))) {
> + if (!fwnode_device_is_available(
> + fwnode_graph_get_port_parent(fwnode)))
> + continue;
> +
> + if (has_port) {
> + struct fwnode_endpoint ep;
> +
> + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> + if (ret) {
> + fwnode_handle_put(fwnode);
> + return ret;
> + }
> +
> + if (ep.port != port)
> + continue;
> + }
> + max_subdevs++;
> + }
> +
> + /* No subdevs to add? Return here. */
> + if (max_subdevs == notifier->max_subdevs)
> + return 0;
> +
> + ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
> + if (ret)
> + return ret;
> +
> + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> + dev_fwnode(dev), fwnode)); ) {
Same here: this can be a 'while'.
> + if (!fwnode_device_is_available(
> + fwnode_graph_get_port_parent(fwnode)))
> + continue;
> +
> + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> + ret = -EINVAL;
> + break;
> + }
> +
> + if (has_port) {
> + struct fwnode_endpoint ep;
> +
> + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> + if (ret)
> + break;
> +
> + if (ep.port != port)
> + continue;
> + }
> +
> + ret = v4l2_async_notifier_fwnode_parse_endpoint(
> + dev, notifier, fwnode, asd_struct_size, parse_endpoint);
> + if (ret < 0)
> + break;
> + }
> +
> + fwnode_handle_put(fwnode);
> +
> + return ret;
> +}
> +
> +int v4l2_async_notifier_parse_fwnode_endpoints(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd))
> +{
> + return __v4l2_async_notifier_parse_fwnode_endpoints(
> + dev, notifier, asd_struct_size, 0, false, parse_endpoint);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
> +
> +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size, unsigned int port,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd))
> +{
> + return __v4l2_async_notifier_parse_fwnode_endpoints(
> + dev, notifier, asd_struct_size, port, true, parse_endpoint);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
> +
> MODULE_LICENSE("GPL");
> MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
> MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index c69d8c8a66d0..96fa1afc00dd 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -18,7 +18,6 @@ struct device;
> struct device_node;
> struct v4l2_device;
> struct v4l2_subdev;
> -struct v4l2_async_notifier;
>
> /* A random max subdevice number, used to allocate an array on stack */
> #define V4L2_MAX_SUBDEVS 128U
> @@ -50,6 +49,10 @@ enum v4l2_async_match_type {
> * @match: union of per-bus type matching data sets
> * @list: used to link struct v4l2_async_subdev objects, waiting to be
> * probed, to a notifier->waiting list
> + *
> + * When this struct is used as a member in a driver specific struct,
> + * the driver specific struct shall contain the @struct
> + * v4l2_async_subdev as its first member.
> */
> struct v4l2_async_subdev {
> enum v4l2_async_match_type match_type;
> @@ -78,7 +81,8 @@ struct v4l2_async_subdev {
> /**
> * struct v4l2_async_notifier - v4l2_device notifier data
> *
> - * @num_subdevs: number of subdevices
> + * @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
> * @waiting: list of struct v4l2_async_subdev, waiting for their drivers
> @@ -90,6 +94,7 @@ struct v4l2_async_subdev {
> */
> struct v4l2_async_notifier {
> unsigned int num_subdevs;
> + unsigned int max_subdevs;
> struct v4l2_async_subdev **subdevs;
> struct v4l2_device *v4l2_dev;
> struct list_head waiting;
> @@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
>
> /**
> + * v4l2_async_notifier_release - release notifier resources
> + * @notifier: the notifier the resources of which are to be released
> + *
> + * Release memory resources related to a notifier, including the async
> + * sub-devices allocated for the purposes of the notifier. The user is
> + * responsible for releasing the notifier's resources after calling
> + * @v4l2_async_notifier_parse_fwnode_endpoints.
> + *
> + * There is no harm from calling v4l2_async_notifier_release in other
> + * cases as long as its memory has been zeroed after it has been
> + * allocated.
> + */
> +void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier);
> +
> +/**
> * v4l2_async_register_subdev - registers a sub-device to the asynchronous
> * subdevice framework
> *
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 68eb22ba571b..83afac48ea6b 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -25,6 +25,8 @@
> #include <media/v4l2-mediabus.h>
>
> struct fwnode_handle;
> +struct v4l2_async_notifier;
> +struct v4l2_async_subdev;
>
> #define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4
>
> @@ -201,4 +203,119 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> */
> void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
>
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> + * device node
> + * @dev: the device the endpoints of which are to be parsed
> + * @notifier: notifier for @dev
> + * @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.
> + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> + * endpoint. Optional.
> + * Return: %0 on success
> + * %-ENOTCONN if the endpoint is to be skipped but this
> + * should not be considered as an error
> + * %-EINVAL if the endpoint configuration is invalid
> + *
> + * Parse the fwnode endpoints of the @dev device and populate the async sub-
> + * devices array of the notifier. The @parse_endpoint callback function is
> + * called for each endpoint with the corresponding async sub-device pointer to
> + * let the caller initialize the driver-specific part of the async sub-device
> + * structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on the
> + * notifier.
> + *
> + * This function may not be called on a registered notifier and may be called on
> + * a notifier only once.
> + *
> + * Do not change the notifier's subdevs array, take references to the subdevs
> + * array itself or change the notifier's num_subdevs field. This is because this
> + * function allocates and reallocates the subdevs array based on parsing
> + * endpoints.
> + *
> + * The @struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_endpoint is released once the function is finished. If there is a need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call to
> + * v4l2_async_notifier_release() after it has been unregistered and the async
> + * sub-devices are no longer in use, even if the function returned an error.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + * %-ENOMEM if memory allocation failed
> + * %-EINVAL if graph or endpoint parsing failed
> + * Other error codes as returned by @parse_endpoint
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoints(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd));
> +
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
> + * endpoints of a port in a
> + * device node
> + * @dev: the device the endpoints of which are to be parsed
> + * @notifier: notifier for @dev
> + * @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.
> + * @port: port number where endpoints are to be parsed
> + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> + * endpoint. Optional.
> + * Return: %0 on success
> + * %-ENOTCONN if the endpoint is to be skipped but this
> + * should not be considered as an error
> + * %-EINVAL if the endpoint configuration is invalid
> + *
> + * This function is just like @v4l2_async_notifier_parse_fwnode_endpoints with
> + * the exception that it only parses endpoints in a given port. This is useful
> + * on devices that have both sinks and sources: the async sub-devices connected
on -> for
> + * to sources have already been set up by another driver (on capture devices).
on -> for
So if I understand this correctly for devices with both sinks and sources you use
this function to just parse the sink ports. And you have to give explicit port
numbers since you can't tell from parsing the device tree if a port is a sink or
source port, right? Only the driver knows this.
> + *
> + * Parse the fwnode endpoints of the @dev device on a given @port and populate
> + * the async sub-devices array of the notifier. The @parse_endpoint callback
> + * function is called for each endpoint with the corresponding async sub-device
> + * pointer to let the caller initialize the driver-specific part of the async
> + * sub-device structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on the
> + * notifier the first time.
> + *
> + * This function may not be called on a registered notifier and may be called on
> + * a notifier only once per port.
> + *
> + * Do not change the notifier's subdevs array, take references to the subdevs
> + * array itself or change the notifier's num_subdevs field. This is because this
> + * function allocates and reallocates the subdevs array based on parsing
> + * endpoints.
> + *
> + * The @struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_endpoint is released once the function is finished. If there is a need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call to
> + * v4l2_async_notifier_release() after it has been unregistered and the async
> + * sub-devices are no longer in use, even if the function returned an error.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + * %-ENOMEM if memory allocation failed
> + * %-EINVAL if graph or endpoint parsing failed
> + * Other error codes as returned by @parse_endpoint
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size, unsigned int port,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd));
> +
> #endif /* _V4L2_FWNODE_H */
>
Regards,
Hans
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 05/25] v4l: fwnode: Support generic parsing of graph endpoints in a device
2017-09-19 8:03 ` Hans Verkuil
@ 2017-09-19 8:20 ` Sakari Ailus
[not found] ` <20170919082015.vt6olgirnvmpcrpa-z7MJbOB4PBP+e+fPlCVrcFDQ4js95KgL@public.gmane.org>
0 siblings, 1 reply; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 8:20 UTC (permalink / raw)
To: Hans Verkuil
Cc: linux-media, niklas.soderlund, maxime.ripard, robh,
laurent.pinchart, devicetree, pavel, sre
Hi Hans,
Thank you for the review.
On Tue, Sep 19, 2017 at 10:03:27AM +0200, Hans Verkuil wrote:
> On 09/15/2017 04:17 PM, Sakari Ailus wrote:
> > Add two functions for parsing devices graph endpoints:
> > v4l2_async_notifier_parse_fwnode_endpoints and
> > v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
> > over all endpoints whereas the latter only iterates over the endpoints in
> > a given port.
> >
> > The former is mostly useful for existing drivers that currently implement
> > the iteration over all the endpoints themselves whereas the latter is
> > especially intended for devices with both sinks and sources: async
> > sub-devices for external devices connected to the device's sources will
> > have already been set up, or they are part of the master device.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> > drivers/media/v4l2-core/v4l2-async.c | 30 ++++++
> > drivers/media/v4l2-core/v4l2-fwnode.c | 185 ++++++++++++++++++++++++++++++++++
> > include/media/v4l2-async.h | 24 ++++-
> > include/media/v4l2-fwnode.h | 117 +++++++++++++++++++++
> > 4 files changed, 354 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 831f185ecd47..bf0215dde616 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -22,6 +22,7 @@
> >
> > #include <media/v4l2-async.h>
> > #include <media/v4l2-device.h>
> > +#include <media/v4l2-fwnode.h>
> > #include <media/v4l2-subdev.h>
> >
> > static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> > @@ -219,6 +220,35 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> > }
> > EXPORT_SYMBOL(v4l2_async_notifier_unregister);
> >
> > +void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
> > +{
> > + unsigned int i;
> > +
> > + if (!notifier->max_subdevs)
> > + return;
> > +
> > + for (i = 0; i < notifier->num_subdevs; i++) {
> > + struct v4l2_async_subdev *asd = notifier->subdevs[i];
> > +
> > + switch (asd->match_type) {
> > + case V4L2_ASYNC_MATCH_FWNODE:
> > + fwnode_handle_put(asd->match.fwnode.fwnode);
> > + break;
> > + default:
> > + WARN_ON_ONCE(true);
>
> Please add a break here.
Yes.
>
> > + }
> > +
> > + kfree(asd);
> > + }
> > +
> > + notifier->max_subdevs = 0;
> > + notifier->num_subdevs = 0;
> > +
> > + kvfree(notifier->subdevs);
> > + notifier->subdevs = NULL;
> > +}
> > +EXPORT_SYMBOL_GPL(v4l2_async_notifier_release);
> > +
> > int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> > {
> > struct v4l2_async_notifier *notifier;
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index 706f9e7b90f1..44ee35f6aad5 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -19,6 +19,7 @@
> > */
> > #include <linux/acpi.h>
> > #include <linux/kernel.h>
> > +#include <linux/mm.h>
> > #include <linux/module.h>
> > #include <linux/of.h>
> > #include <linux/property.h>
> > @@ -26,6 +27,7 @@
> > #include <linux/string.h>
> > #include <linux/types.h>
> >
> > +#include <media/v4l2-async.h>
> > #include <media/v4l2-fwnode.h>
> >
> > enum v4l2_fwnode_bus_type {
> > @@ -313,6 +315,189 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > }
> > EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> >
> > +static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
> > + unsigned int max_subdevs)
> > +{
> > + struct v4l2_async_subdev **subdevs;
> > +
> > + if (max_subdevs <= notifier->max_subdevs)
> > + return 0;
> > +
> > + subdevs = kvmalloc_array(
> > + max_subdevs, sizeof(*notifier->subdevs),
> > + GFP_KERNEL | __GFP_ZERO);
> > + if (!subdevs)
> > + return -ENOMEM;
> > +
> > + if (notifier->subdevs) {
> > + memcpy(subdevs, notifier->subdevs,
> > + sizeof(*subdevs) * notifier->num_subdevs);
> > +
> > + kvfree(notifier->subdevs);
> > + }
> > +
> > + notifier->subdevs = subdevs;
> > + notifier->max_subdevs = max_subdevs;
> > +
> > + return 0;
> > +}
> > +
> > +static int v4l2_async_notifier_fwnode_parse_endpoint(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + struct fwnode_handle *endpoint, unsigned int asd_struct_size,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd))
> > +{
> > + struct v4l2_async_subdev *asd;
> > + struct v4l2_fwnode_endpoint *vep;
> > + int ret = 0;
> > +
> > + asd = kzalloc(asd_struct_size, GFP_KERNEL);
> > + if (!asd)
> > + return -ENOMEM;
> > +
> > + asd->match.fwnode.fwnode =
> > + fwnode_graph_get_remote_port_parent(endpoint);
> > + if (!asd->match.fwnode.fwnode) {
> > + dev_warn(dev, "bad remote port parent\n");
> > + ret = -EINVAL;
> > + goto out_err;
> > + }
> > +
> > + /* Ignore endpoints the parsing of which failed. */
> > + vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
> > + if (IS_ERR(vep)) {
> > + ret = PTR_ERR(vep);
> > + dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
> > + ret);
> > + goto out_err;
> > + }
> > +
> > + ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
> > + if (ret == -ENOTCONN)
> > + dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port,
> > + vep->base.id);
> > + else if (ret < 0)
> > + dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n",
> > + vep->base.port, vep->base.id, ret);
> > + v4l2_fwnode_endpoint_free(vep);
> > + if (ret < 0)
> > + goto out_err;
> > +
> > + asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> > + notifier->subdevs[notifier->num_subdevs] = asd;
> > + notifier->num_subdevs++;
> > +
> > + return 0;
> > +
> > +out_err:
> > + fwnode_handle_put(asd->match.fwnode.fwnode);
> > + kfree(asd);
> > +
> > + return ret == -ENOTCONN ? 0 : ret;
> > +}
> > +
> > +static int __v4l2_async_notifier_parse_fwnode_endpoints(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size, unsigned int port, bool has_port,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd))
> > +{
> > + struct fwnode_handle *fwnode = NULL;
> > + unsigned int max_subdevs = notifier->max_subdevs;
> > + int ret;
> > +
> > + if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
> > + return -EINVAL;
> > +
> > + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> > + dev_fwnode(dev), fwnode)); ) {
>
> You can replace this by:
>
> while ((fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), fwnode))) {
>
> > + if (!fwnode_device_is_available(
> > + fwnode_graph_get_port_parent(fwnode)))
> > + continue;
> > +
> > + if (has_port) {
> > + struct fwnode_endpoint ep;
> > +
> > + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> > + if (ret) {
> > + fwnode_handle_put(fwnode);
> > + return ret;
> > + }
> > +
> > + if (ep.port != port)
> > + continue;
> > + }
> > + max_subdevs++;
> > + }
> > +
> > + /* No subdevs to add? Return here. */
> > + if (max_subdevs == notifier->max_subdevs)
> > + return 0;
> > +
> > + ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
> > + if (ret)
> > + return ret;
> > +
> > + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> > + dev_fwnode(dev), fwnode)); ) {
>
> Same here: this can be a 'while'.
The fwnode = NULL assignment still needs to be done. A for loop has a
natural initialiser for the loop, I think it's cleaner than using while
here.
The macro would be implemented this way as well.
For the loop above this one, I'd use for for consistency: it's the same
loop after all.
This reminds me --- I'll send the patch for the macro.
>
> > + if (!fwnode_device_is_available(
> > + fwnode_graph_get_port_parent(fwnode)))
> > + continue;
> > +
> > + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> > + ret = -EINVAL;
> > + break;
> > + }
> > +
> > + if (has_port) {
> > + struct fwnode_endpoint ep;
> > +
> > + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> > + if (ret)
> > + break;
> > +
> > + if (ep.port != port)
> > + continue;
> > + }
> > +
> > + ret = v4l2_async_notifier_fwnode_parse_endpoint(
> > + dev, notifier, fwnode, asd_struct_size, parse_endpoint);
> > + if (ret < 0)
> > + break;
> > + }
> > +
> > + fwnode_handle_put(fwnode);
> > +
> > + return ret;
> > +}
> > +
> > +int v4l2_async_notifier_parse_fwnode_endpoints(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd))
> > +{
> > + return __v4l2_async_notifier_parse_fwnode_endpoints(
> > + dev, notifier, asd_struct_size, 0, false, parse_endpoint);
> > +}
> > +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
> > +
> > +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size, unsigned int port,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd))
> > +{
> > + return __v4l2_async_notifier_parse_fwnode_endpoints(
> > + dev, notifier, asd_struct_size, port, true, parse_endpoint);
> > +}
> > +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
> > +
> > MODULE_LICENSE("GPL");
> > MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
> > MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index c69d8c8a66d0..96fa1afc00dd 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -18,7 +18,6 @@ struct device;
> > struct device_node;
> > struct v4l2_device;
> > struct v4l2_subdev;
> > -struct v4l2_async_notifier;
> >
> > /* A random max subdevice number, used to allocate an array on stack */
> > #define V4L2_MAX_SUBDEVS 128U
> > @@ -50,6 +49,10 @@ enum v4l2_async_match_type {
> > * @match: union of per-bus type matching data sets
> > * @list: used to link struct v4l2_async_subdev objects, waiting to be
> > * probed, to a notifier->waiting list
> > + *
> > + * When this struct is used as a member in a driver specific struct,
> > + * the driver specific struct shall contain the @struct
> > + * v4l2_async_subdev as its first member.
> > */
> > struct v4l2_async_subdev {
> > enum v4l2_async_match_type match_type;
> > @@ -78,7 +81,8 @@ struct v4l2_async_subdev {
> > /**
> > * struct v4l2_async_notifier - v4l2_device notifier data
> > *
> > - * @num_subdevs: number of subdevices
> > + * @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
> > * @waiting: list of struct v4l2_async_subdev, waiting for their drivers
> > @@ -90,6 +94,7 @@ struct v4l2_async_subdev {
> > */
> > struct v4l2_async_notifier {
> > unsigned int num_subdevs;
> > + unsigned int max_subdevs;
> > struct v4l2_async_subdev **subdevs;
> > struct v4l2_device *v4l2_dev;
> > struct list_head waiting;
> > @@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> > void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
> >
> > /**
> > + * v4l2_async_notifier_release - release notifier resources
> > + * @notifier: the notifier the resources of which are to be released
> > + *
> > + * Release memory resources related to a notifier, including the async
> > + * sub-devices allocated for the purposes of the notifier. The user is
> > + * responsible for releasing the notifier's resources after calling
> > + * @v4l2_async_notifier_parse_fwnode_endpoints.
> > + *
> > + * There is no harm from calling v4l2_async_notifier_release in other
> > + * cases as long as its memory has been zeroed after it has been
> > + * allocated.
> > + */
> > +void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier);
> > +
> > +/**
> > * v4l2_async_register_subdev - registers a sub-device to the asynchronous
> > * subdevice framework
> > *
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 68eb22ba571b..83afac48ea6b 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -25,6 +25,8 @@
> > #include <media/v4l2-mediabus.h>
> >
> > struct fwnode_handle;
> > +struct v4l2_async_notifier;
> > +struct v4l2_async_subdev;
> >
> > #define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4
> >
> > @@ -201,4 +203,119 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > */
> > void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> >
> > +/**
> > + * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> > + * device node
> > + * @dev: the device the endpoints of which are to be parsed
> > + * @notifier: notifier for @dev
> > + * @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.
> > + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> > + * endpoint. Optional.
> > + * Return: %0 on success
> > + * %-ENOTCONN if the endpoint is to be skipped but this
> > + * should not be considered as an error
> > + * %-EINVAL if the endpoint configuration is invalid
> > + *
> > + * Parse the fwnode endpoints of the @dev device and populate the async sub-
> > + * devices array of the notifier. The @parse_endpoint callback function is
> > + * called for each endpoint with the corresponding async sub-device pointer to
> > + * let the caller initialize the driver-specific part of the async sub-device
> > + * structure.
> > + *
> > + * The notifier memory shall be zeroed before this function is called on the
> > + * notifier.
> > + *
> > + * This function may not be called on a registered notifier and may be called on
> > + * a notifier only once.
> > + *
> > + * Do not change the notifier's subdevs array, take references to the subdevs
> > + * array itself or change the notifier's num_subdevs field. This is because this
> > + * function allocates and reallocates the subdevs array based on parsing
> > + * endpoints.
> > + *
> > + * The @struct v4l2_fwnode_endpoint passed to the callback function
> > + * @parse_endpoint is released once the function is finished. If there is a need
> > + * to retain that configuration, the user needs to allocate memory for it.
> > + *
> > + * Any notifier populated using this function must be released with a call to
> > + * v4l2_async_notifier_release() after it has been unregistered and the async
> > + * sub-devices are no longer in use, even if the function returned an error.
> > + *
> > + * Return: %0 on success, including when no async sub-devices are found
> > + * %-ENOMEM if memory allocation failed
> > + * %-EINVAL if graph or endpoint parsing failed
> > + * Other error codes as returned by @parse_endpoint
> > + */
> > +int v4l2_async_notifier_parse_fwnode_endpoints(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd));
> > +
> > +/**
> > + * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
> > + * endpoints of a port in a
> > + * device node
> > + * @dev: the device the endpoints of which are to be parsed
> > + * @notifier: notifier for @dev
> > + * @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.
> > + * @port: port number where endpoints are to be parsed
> > + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> > + * endpoint. Optional.
> > + * Return: %0 on success
> > + * %-ENOTCONN if the endpoint is to be skipped but this
> > + * should not be considered as an error
> > + * %-EINVAL if the endpoint configuration is invalid
> > + *
> > + * This function is just like @v4l2_async_notifier_parse_fwnode_endpoints with
> > + * the exception that it only parses endpoints in a given port. This is useful
> > + * on devices that have both sinks and sources: the async sub-devices connected
>
> on -> for
>
> > + * to sources have already been set up by another driver (on capture devices).
>
> on -> for
Agreed on both.
>
> So if I understand this correctly for devices with both sinks and sources you use
> this function to just parse the sink ports. And you have to give explicit port
> numbers since you can't tell from parsing the device tree if a port is a sink or
> source port, right? Only the driver knows this.
Correct. The graph data structure in DT isn't directed, so this is only
known by the driver.
>
> > + *
> > + * Parse the fwnode endpoints of the @dev device on a given @port and populate
> > + * the async sub-devices array of the notifier. The @parse_endpoint callback
> > + * function is called for each endpoint with the corresponding async sub-device
> > + * pointer to let the caller initialize the driver-specific part of the async
> > + * sub-device structure.
> > + *
> > + * The notifier memory shall be zeroed before this function is called on the
> > + * notifier the first time.
> > + *
> > + * This function may not be called on a registered notifier and may be called on
> > + * a notifier only once per port.
> > + *
> > + * Do not change the notifier's subdevs array, take references to the subdevs
> > + * array itself or change the notifier's num_subdevs field. This is because this
> > + * function allocates and reallocates the subdevs array based on parsing
> > + * endpoints.
> > + *
> > + * The @struct v4l2_fwnode_endpoint passed to the callback function
> > + * @parse_endpoint is released once the function is finished. If there is a need
> > + * to retain that configuration, the user needs to allocate memory for it.
> > + *
> > + * Any notifier populated using this function must be released with a call to
> > + * v4l2_async_notifier_release() after it has been unregistered and the async
> > + * sub-devices are no longer in use, even if the function returned an error.
> > + *
> > + * Return: %0 on success, including when no async sub-devices are found
> > + * %-ENOMEM if memory allocation failed
> > + * %-EINVAL if graph or endpoint parsing failed
> > + * Other error codes as returned by @parse_endpoint
> > + */
> > +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size, unsigned int port,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd));
> > +
> > #endif /* _V4L2_FWNODE_H */
> >
>
--
Kind regards,
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 05/25] v4l: fwnode: Support generic parsing of graph endpoints in a device
2017-09-15 14:17 ` Sakari Ailus
(?)
(?)
@ 2017-09-19 11:35 ` Laurent Pinchart
2017-09-19 12:11 ` Sakari Ailus
-1 siblings, 1 reply; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:35 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:04 EEST Sakari Ailus wrote:
> Add two functions for parsing devices graph endpoints:
> v4l2_async_notifier_parse_fwnode_endpoints and
> v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
> over all endpoints whereas the latter only iterates over the endpoints in
> a given port.
>
> The former is mostly useful for existing drivers that currently implement
> the iteration over all the endpoints themselves whereas the latter is
> especially intended for devices with both sinks and sources: async
> sub-devices for external devices connected to the device's sources will
> have already been set up, or they are part of the master device.
Did you mean s/or they/as they/ ?
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 30 ++++++
> drivers/media/v4l2-core/v4l2-fwnode.c | 185 +++++++++++++++++++++++++++++++
> include/media/v4l2-async.h | 24 ++++-
> include/media/v4l2-fwnode.h | 117 +++++++++++++++++++++
> 4 files changed, 354 insertions(+), 2 deletions(-)
[snip]
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c
> b/drivers/media/v4l2-core/v4l2-fwnode.c index 706f9e7b90f1..44ee35f6aad5
> 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
[snip]
> +static int v4l2_async_notifier_fwnode_parse_endpoint(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + struct fwnode_handle *endpoint, unsigned int asd_struct_size,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd))
> +{
> + struct v4l2_async_subdev *asd;
> + struct v4l2_fwnode_endpoint *vep;
> + int ret = 0;
> +
> + asd = kzalloc(asd_struct_size, GFP_KERNEL);
> + if (!asd)
> + return -ENOMEM;
> +
> + asd->match.fwnode.fwnode =
> + fwnode_graph_get_remote_port_parent(endpoint);
> + if (!asd->match.fwnode.fwnode) {
> + dev_warn(dev, "bad remote port parent\n");
> + ret = -EINVAL;
> + goto out_err;
> + }
> +
> + /* Ignore endpoints the parsing of which failed. */
I think this comment is outdated.
> + vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
> + if (IS_ERR(vep)) {
> + ret = PTR_ERR(vep);
> + dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
> + ret);
> + goto out_err;
> + }
> +
> + ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
> + if (ret == -ENOTCONN)
> + dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port,
> + vep->base.id);
How about "ignoring port@%u/endpoint@%u\n" ? It would make the message more
explicit.
> + else if (ret < 0)
> + dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n",
Same here.
> + vep->base.port, vep->base.id, ret);
> + v4l2_fwnode_endpoint_free(vep);
> + if (ret < 0)
> + goto out_err;
> +
> + asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
I'd move this line right before setting asd->match.fwnode.fwnode.
> + notifier->subdevs[notifier->num_subdevs] = asd;
> + notifier->num_subdevs++;
> +
> + return 0;
> +
> +out_err:
> + fwnode_handle_put(asd->match.fwnode.fwnode);
> + kfree(asd);
> +
> + return ret == -ENOTCONN ? 0 : ret;
> +}
> +
> +static int __v4l2_async_notifier_parse_fwnode_endpoints(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size, unsigned int port, bool has_port,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd))
> +{
> + struct fwnode_handle *fwnode = NULL;
> + unsigned int max_subdevs = notifier->max_subdevs;
> + int ret;
> +
> + if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
> + return -EINVAL;
> +
> + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> + dev_fwnode(dev), fwnode)); ) {
> + if (!fwnode_device_is_available(
> + fwnode_graph_get_port_parent(fwnode)))
Doesn't fwnode_graph_get_port_parent() increment the refcount on the parent,
which you should then release ?
> + continue;
> +
> + if (has_port) {
> + struct fwnode_endpoint ep;
> +
> + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> + if (ret) {
> + fwnode_handle_put(fwnode);
> + return ret;
> + }
> +
> + if (ep.port != port)
> + continue;
> + }
> + max_subdevs++;
> + }
> +
> + /* No subdevs to add? Return here. */
> + if (max_subdevs == notifier->max_subdevs)
> + return 0;
> +
> + ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
> + if (ret)
> + return ret;
> +
> + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> + dev_fwnode(dev), fwnode)); ) {
> + if (!fwnode_device_is_available(
> + fwnode_graph_get_port_parent(fwnode)))
Same here.
> + continue;
> +
> + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> + ret = -EINVAL;
> + break;
> + }
> +
> + if (has_port) {
> + struct fwnode_endpoint ep;
> +
> + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> + if (ret)
> + break;
> +
> + if (ep.port != port)
> + continue;
> + }
> +
> + ret = v4l2_async_notifier_fwnode_parse_endpoint(
> + dev, notifier, fwnode, asd_struct_size, parse_endpoint);
> + if (ret < 0)
> + break;
> + }
> +
> + fwnode_handle_put(fwnode);
> +
> + return ret;
> +}
[snip]
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index c69d8c8a66d0..96fa1afc00dd 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -18,7 +18,6 @@ struct device;
> struct device_node;
> struct v4l2_device;
> struct v4l2_subdev;
> -struct v4l2_async_notifier;
>
> /* A random max subdevice number, used to allocate an array on stack */
> #define V4L2_MAX_SUBDEVS 128U
> @@ -50,6 +49,10 @@ enum v4l2_async_match_type {
> * @match: union of per-bus type matching data sets
> * @list: used to link struct v4l2_async_subdev objects, waiting to be
> * probed, to a notifier->waiting list
> + *
> + * When this struct is used as a member in a driver specific struct,
> + * the driver specific struct shall contain the @struct
> + * v4l2_async_subdev as its first member.
Unless I'm mistaken @ is used to refer to function arguments (sphinx typesets
it using <strong> in HTML). References to structures can be created with &.
Have you compiled the documentation ? :-)
> */
> struct v4l2_async_subdev {
> enum v4l2_async_match_type match_type;
> @@ -78,7 +81,8 @@ struct v4l2_async_subdev {
> /**
> * struct v4l2_async_notifier - v4l2_device notifier data
> *
> - * @num_subdevs: number of subdevices
> + * @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
> * @waiting: list of struct v4l2_async_subdev, waiting for their drivers
> @@ -90,6 +94,7 @@ struct v4l2_async_subdev {
> */
> struct v4l2_async_notifier {
> unsigned int num_subdevs;
> + unsigned int max_subdevs;
> struct v4l2_async_subdev **subdevs;
> struct v4l2_device *v4l2_dev;
> struct list_head waiting;
> @@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device
> *v4l2_dev, void v4l2_async_notifier_unregister(struct v4l2_async_notifier
> *notifier);
>
> /**
> + * v4l2_async_notifier_release - release notifier resources
> + * @notifier: the notifier the resources of which are to be released
> + *
> + * Release memory resources related to a notifier, including the async
> + * sub-devices allocated for the purposes of the notifier. The user is
> + * responsible for releasing the notifier's resources after calling
> + * @v4l2_async_notifier_parse_fwnode_endpoints.
Don't use @. If you want sphinx to generate a link, just append () after the
function name.
> + *
> + * There is no harm from calling v4l2_async_notifier_release in other
Here too.
> + * cases as long as its memory has been zeroed after it has been
> + * allocated.
As the function WARNs for types other than V4L2_ASYNC_MATCH_FWNODE you might
want to mention that in the documentation.
> + */
> +void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier);
> +
> +/**
> * v4l2_async_register_subdev - registers a sub-device to the asynchronous
> * subdevice framework
> *
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 68eb22ba571b..83afac48ea6b 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -25,6 +25,8 @@
> #include <media/v4l2-mediabus.h>
>
> struct fwnode_handle;
> +struct v4l2_async_notifier;
> +struct v4l2_async_subdev;
>
> #define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4
>
> @@ -201,4 +203,119 @@ int v4l2_fwnode_parse_link(struct fwnode_handle
> *fwnode, */
> void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
>
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints
> in a
> + * device node
> + * @dev: the device the endpoints of which are to be parsed
> + * @notifier: notifier for @dev
> + * @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.
> + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> + * endpoint. Optional.
> + * Return: %0 on success
> + * %-ENOTCONN if the endpoint is to be skipped but this
> + * should not be considered as an error
> + * %-EINVAL if the endpoint configuration is invalid
> + *
> + * Parse the fwnode endpoints of the @dev device and populate the async
> sub-
> + * devices array of the notifier. The @parse_endpoint callback function is
> + * called for each endpoint with the corresponding async sub-device pointer
> to
> + * let the caller initialize the driver-specific part of the async sub-
> device
> + * structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on
> the
> + * notifier.
> + *
> + * This function may not be called on a registered notifier and may be
> called on
> + * a notifier only once.
> + *
> + * Do not change the notifier's subdevs array, take references to the
> subdevs
> + * array itself or change the notifier's num_subdevs field. This is because
> this
> + * function allocates and reallocates the subdevs array based on parsing
> + * endpoints.
> + *
> + * The @struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_endpoint is released once the function is finished. If there is a
> need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call
> to
> + * v4l2_async_notifier_release() after it has been unregistered and the
> async
> + * sub-devices are no longer in use, even if the function returned an
> error.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + * %-ENOMEM if memory allocation failed
> + * %-EINVAL if graph or endpoint parsing failed
> + * Other error codes as returned by @parse_endpoint
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoints(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd));
> +
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
> + * endpoints of a port in a
> + * device node
This clearly shows that the function name is getting a bit long :-)
> + * @dev: the device the endpoints of which are to be parsed
> + * @notifier: notifier for @dev
> + * @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.
> + * @port: port number where endpoints are to be parsed
> + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> + * endpoint. Optional.
> + * Return: %0 on success
> + * %-ENOTCONN if the endpoint is to be skipped but this
> + * should not be considered as an error
> + * %-EINVAL if the endpoint configuration is invalid
> + *
> + * This function is just like @v4l2_async_notifier_parse_fwnode_endpoints
> with
> + * the exception that it only parses endpoints in a given port. This is
> useful
> + * on devices that have both sinks and sources: the async sub-devices
> connected
> + * to sources have already been set up by another driver (on capture
> devices).
> + *
> + * Parse the fwnode endpoints of the @dev device on a given @port and
> populate
> + * the async sub-devices array of the notifier. The @parse_endpoint
> callback
> + * function is called for each endpoint with the corresponding async sub-
> device
> + * pointer to let the caller initialize the driver-specific part of the
> async
> + * sub-device structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on
> the
> + * notifier the first time.
> + *
> + * This function may not be called on a registered notifier and may be
> called on
> + * a notifier only once per port.
> + *
> + * Do not change the notifier's subdevs array, take references to the
> subdevs
> + * array itself or change the notifier's num_subdevs field. This is because
> this
> + * function allocates and reallocates the subdevs array based on parsing
> + * endpoints.
> + *
> + * The @struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_endpoint is released once the function is finished. If there is a
> need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call
> to
> + * v4l2_async_notifier_release() after it has been unregistered and the
> async
> + * sub-devices are no longer in use, even if the function returned an
> error.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + * %-ENOMEM if memory allocation failed
> + * %-EINVAL if graph or endpoint parsing failed
> + * Other error codes as returned by @parse_endpoint
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> + struct device *dev, struct v4l2_async_notifier *notifier,
> + size_t asd_struct_size, unsigned int port,
> + int (*parse_endpoint)(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd));
> +
> #endif /* _V4L2_FWNODE_H */
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 05/25] v4l: fwnode: Support generic parsing of graph endpoints in a device
2017-09-19 11:35 ` Laurent Pinchart
@ 2017-09-19 12:11 ` Sakari Ailus
[not found] ` <20170919121131.6m4cf4ftzhq7vpnc-z7MJbOB4PBP+e+fPlCVrcFDQ4js95KgL@public.gmane.org>
0 siblings, 1 reply; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 12:11 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 02:35:01PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
Thanks for the review!
>
> On Friday, 15 September 2017 17:17:04 EEST Sakari Ailus wrote:
> > Add two functions for parsing devices graph endpoints:
> > v4l2_async_notifier_parse_fwnode_endpoints and
> > v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
> > over all endpoints whereas the latter only iterates over the endpoints in
> > a given port.
> >
> > The former is mostly useful for existing drivers that currently implement
> > the iteration over all the endpoints themselves whereas the latter is
> > especially intended for devices with both sinks and sources: async
> > sub-devices for external devices connected to the device's sources will
> > have already been set up, or they are part of the master device.
>
> Did you mean s/or they/as they/ ?
No. There are two options here: either the sub-devices a sub-device is
connected to (through a graph endpoint) is instantiated through the async
framework *or* through the master device driver. But not by both of them at
the same time.
>
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> > drivers/media/v4l2-core/v4l2-async.c | 30 ++++++
> > drivers/media/v4l2-core/v4l2-fwnode.c | 185 +++++++++++++++++++++++++++++++
> > include/media/v4l2-async.h | 24 ++++-
> > include/media/v4l2-fwnode.h | 117 +++++++++++++++++++++
> > 4 files changed, 354 insertions(+), 2 deletions(-)
>
> [snip]
>
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c
> > b/drivers/media/v4l2-core/v4l2-fwnode.c index 706f9e7b90f1..44ee35f6aad5
> > 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
>
> [snip]
>
> > +static int v4l2_async_notifier_fwnode_parse_endpoint(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + struct fwnode_handle *endpoint, unsigned int asd_struct_size,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd))
> > +{
> > + struct v4l2_async_subdev *asd;
> > + struct v4l2_fwnode_endpoint *vep;
> > + int ret = 0;
> > +
> > + asd = kzalloc(asd_struct_size, GFP_KERNEL);
> > + if (!asd)
> > + return -ENOMEM;
> > +
> > + asd->match.fwnode.fwnode =
> > + fwnode_graph_get_remote_port_parent(endpoint);
> > + if (!asd->match.fwnode.fwnode) {
> > + dev_warn(dev, "bad remote port parent\n");
> > + ret = -EINVAL;
> > + goto out_err;
> > + }
> > +
> > + /* Ignore endpoints the parsing of which failed. */
>
> I think this comment is outdated.
Hmm. Yes. I'll remove it.
>
> > + vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
> > + if (IS_ERR(vep)) {
> > + ret = PTR_ERR(vep);
> > + dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
> > + ret);
> > + goto out_err;
> > + }
> > +
> > + ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
> > + if (ret == -ENOTCONN)
> > + dev_dbg(dev, "ignoring endpoint %u,%u\n", vep->base.port,
> > + vep->base.id);
>
> How about "ignoring port@%u/endpoint@%u\n" ? It would make the message more
> explicit.
Works for me.
>
> > + else if (ret < 0)
> > + dev_warn(dev, "driver could not parse endpoint %u,%u (%d)\n",
>
> Same here.
>
> > + vep->base.port, vep->base.id, ret);
> > + v4l2_fwnode_endpoint_free(vep);
> > + if (ret < 0)
> > + goto out_err;
> > +
> > + asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
>
> I'd move this line right before setting asd->match.fwnode.fwnode.
I'll move it.
>
> > + notifier->subdevs[notifier->num_subdevs] = asd;
> > + notifier->num_subdevs++;
> > +
> > + return 0;
> > +
> > +out_err:
> > + fwnode_handle_put(asd->match.fwnode.fwnode);
> > + kfree(asd);
> > +
> > + return ret == -ENOTCONN ? 0 : ret;
> > +}
> > +
> > +static int __v4l2_async_notifier_parse_fwnode_endpoints(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size, unsigned int port, bool has_port,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd))
> > +{
> > + struct fwnode_handle *fwnode = NULL;
> > + unsigned int max_subdevs = notifier->max_subdevs;
> > + int ret;
> > +
> > + if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
> > + return -EINVAL;
> > +
> > + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> > + dev_fwnode(dev), fwnode)); ) {
> > + if (!fwnode_device_is_available(
> > + fwnode_graph_get_port_parent(fwnode)))
>
> Doesn't fwnode_graph_get_port_parent() increment the refcount on the parent,
> which you should then release ?
Good catch. I'll fix this for v14.
>
> > + continue;
> > +
> > + if (has_port) {
> > + struct fwnode_endpoint ep;
> > +
> > + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> > + if (ret) {
> > + fwnode_handle_put(fwnode);
> > + return ret;
> > + }
> > +
> > + if (ep.port != port)
> > + continue;
> > + }
> > + max_subdevs++;
> > + }
> > +
> > + /* No subdevs to add? Return here. */
> > + if (max_subdevs == notifier->max_subdevs)
> > + return 0;
> > +
> > + ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
> > + if (ret)
> > + return ret;
> > +
> > + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> > + dev_fwnode(dev), fwnode)); ) {
> > + if (!fwnode_device_is_available(
> > + fwnode_graph_get_port_parent(fwnode)))
>
> Same here.
Yes.
>
> > + continue;
> > +
> > + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> > + ret = -EINVAL;
> > + break;
> > + }
> > +
> > + if (has_port) {
> > + struct fwnode_endpoint ep;
> > +
> > + ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> > + if (ret)
> > + break;
> > +
> > + if (ep.port != port)
> > + continue;
> > + }
> > +
> > + ret = v4l2_async_notifier_fwnode_parse_endpoint(
> > + dev, notifier, fwnode, asd_struct_size, parse_endpoint);
> > + if (ret < 0)
> > + break;
> > + }
> > +
> > + fwnode_handle_put(fwnode);
> > +
> > + return ret;
> > +}
>
> [snip]
>
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index c69d8c8a66d0..96fa1afc00dd 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -18,7 +18,6 @@ struct device;
> > struct device_node;
> > struct v4l2_device;
> > struct v4l2_subdev;
> > -struct v4l2_async_notifier;
> >
> > /* A random max subdevice number, used to allocate an array on stack */
> > #define V4L2_MAX_SUBDEVS 128U
> > @@ -50,6 +49,10 @@ enum v4l2_async_match_type {
> > * @match: union of per-bus type matching data sets
> > * @list: used to link struct v4l2_async_subdev objects, waiting to be
> > * probed, to a notifier->waiting list
> > + *
> > + * When this struct is used as a member in a driver specific struct,
> > + * the driver specific struct shall contain the @struct
> > + * v4l2_async_subdev as its first member.
>
> Unless I'm mistaken @ is used to refer to function arguments (sphinx typesets
> it using <strong> in HTML). References to structures can be created with &.
> Have you compiled the documentation ? :-)
Yes, but I've probably changed it since doing so. I'll do that again before
v14.
>
> > */
> > struct v4l2_async_subdev {
> > enum v4l2_async_match_type match_type;
> > @@ -78,7 +81,8 @@ struct v4l2_async_subdev {
> > /**
> > * struct v4l2_async_notifier - v4l2_device notifier data
> > *
> > - * @num_subdevs: number of subdevices
> > + * @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
> > * @waiting: list of struct v4l2_async_subdev, waiting for their drivers
> > @@ -90,6 +94,7 @@ struct v4l2_async_subdev {
> > */
> > struct v4l2_async_notifier {
> > unsigned int num_subdevs;
> > + unsigned int max_subdevs;
> > struct v4l2_async_subdev **subdevs;
> > struct v4l2_device *v4l2_dev;
> > struct list_head waiting;
> > @@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device
> > *v4l2_dev, void v4l2_async_notifier_unregister(struct v4l2_async_notifier
> > *notifier);
> >
> > /**
> > + * v4l2_async_notifier_release - release notifier resources
> > + * @notifier: the notifier the resources of which are to be released
> > + *
> > + * Release memory resources related to a notifier, including the async
> > + * sub-devices allocated for the purposes of the notifier. The user is
> > + * responsible for releasing the notifier's resources after calling
> > + * @v4l2_async_notifier_parse_fwnode_endpoints.
>
> Don't use @. If you want sphinx to generate a link, just append () after the
> function name.
>
> > + *
> > + * There is no harm from calling v4l2_async_notifier_release in other
>
> Here too.
Ack.
>
> > + * cases as long as its memory has been zeroed after it has been
> > + * allocated.
>
> As the function WARNs for types other than V4L2_ASYNC_MATCH_FWNODE you might
> want to mention that in the documentation.
I wouldn't. The user would have to do something very wrong to get there.
The user isn't allowed to touch the notifier's subdevs array directly and
the existing functions only use fwnode matching. This is documented in the
user-visible parsing functions themselves.
>
> > + */
> > +void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier);
> > +
> > +/**
> > * v4l2_async_register_subdev - registers a sub-device to the asynchronous
> > * subdevice framework
> > *
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 68eb22ba571b..83afac48ea6b 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -25,6 +25,8 @@
> > #include <media/v4l2-mediabus.h>
> >
> > struct fwnode_handle;
> > +struct v4l2_async_notifier;
> > +struct v4l2_async_subdev;
> >
> > #define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4
> >
> > @@ -201,4 +203,119 @@ int v4l2_fwnode_parse_link(struct fwnode_handle
> > *fwnode, */
> > void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> >
> > +/**
> > + * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints
> > in a
> > + * device node
> > + * @dev: the device the endpoints of which are to be parsed
> > + * @notifier: notifier for @dev
> > + * @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.
> > + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> > + * endpoint. Optional.
> > + * Return: %0 on success
> > + * %-ENOTCONN if the endpoint is to be skipped but this
> > + * should not be considered as an error
> > + * %-EINVAL if the endpoint configuration is invalid
> > + *
> > + * Parse the fwnode endpoints of the @dev device and populate the async
> > sub-
> > + * devices array of the notifier. The @parse_endpoint callback function is
> > + * called for each endpoint with the corresponding async sub-device pointer
> > to
> > + * let the caller initialize the driver-specific part of the async sub-
> > device
> > + * structure.
> > + *
> > + * The notifier memory shall be zeroed before this function is called on
> > the
> > + * notifier.
> > + *
> > + * This function may not be called on a registered notifier and may be
> > called on
> > + * a notifier only once.
> > + *
> > + * Do not change the notifier's subdevs array, take references to the
> > subdevs
> > + * array itself or change the notifier's num_subdevs field. This is because
> > this
> > + * function allocates and reallocates the subdevs array based on parsing
> > + * endpoints.
> > + *
> > + * The @struct v4l2_fwnode_endpoint passed to the callback function
> > + * @parse_endpoint is released once the function is finished. If there is a
> > need
> > + * to retain that configuration, the user needs to allocate memory for it.
> > + *
> > + * Any notifier populated using this function must be released with a call
> > to
> > + * v4l2_async_notifier_release() after it has been unregistered and the
> > async
> > + * sub-devices are no longer in use, even if the function returned an
> > error.
> > + *
> > + * Return: %0 on success, including when no async sub-devices are found
> > + * %-ENOMEM if memory allocation failed
> > + * %-EINVAL if graph or endpoint parsing failed
> > + * Other error codes as returned by @parse_endpoint
> > + */
> > +int v4l2_async_notifier_parse_fwnode_endpoints(
> > + struct device *dev, struct v4l2_async_notifier *notifier,
> > + size_t asd_struct_size,
> > + int (*parse_endpoint)(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd));
> > +
> > +/**
> > + * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
> > + * endpoints of a port in a
> > + * device node
>
> This clearly shows that the function name is getting a bit long :-)
Yes. The arguments are few and the function is likely not used many times
in a driver.
If you have a better suggestion I'd be happy to have one.
--
Regards,
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 07/25] rcar-vin: Use generic parser for parsing fwnode endpoints
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Instead of using driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
of the device.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
---
drivers/media/platform/rcar-vin/rcar-core.c | 112 +++++++++-------------------
drivers/media/platform/rcar-vin/rcar-dma.c | 10 +--
drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++--
drivers/media/platform/rcar-vin/rcar-vin.h | 4 +-
4 files changed, 48 insertions(+), 92 deletions(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 142de447aaaa..62b4a94f9a39 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
#include "rcar-vin.h"
@@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)
int ret;
/* Verify subdevices mbus format */
- if (!rvin_mbus_supported(&vin->digital)) {
+ if (!rvin_mbus_supported(vin->digital)) {
vin_err(vin, "Unsupported media bus format for %s\n",
- vin->digital.subdev->name);
+ vin->digital->subdev->name);
return -EINVAL;
}
vin_dbg(vin, "Found media bus format for %s: %d\n",
- vin->digital.subdev->name, vin->digital.code);
+ vin->digital->subdev->name, vin->digital->code);
ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
if (ret < 0) {
@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,
vin_dbg(vin, "unbind digital subdev %s\n", subdev->name);
rvin_v4l2_remove(vin);
- vin->digital.subdev = NULL;
+ vin->digital->subdev = NULL;
}
static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
@@ -120,117 +121,70 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
if (ret < 0)
return ret;
- vin->digital.source_pad = ret;
+ vin->digital->source_pad = ret;
ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
- vin->digital.sink_pad = ret < 0 ? 0 : ret;
+ vin->digital->sink_pad = ret < 0 ? 0 : ret;
- vin->digital.subdev = subdev;
+ vin->digital->subdev = subdev;
vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
- subdev->name, vin->digital.source_pad,
- vin->digital.sink_pad);
+ subdev->name, vin->digital->source_pad,
+ vin->digital->sink_pad);
return 0;
}
-static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
- struct device_node *ep,
- struct v4l2_mbus_config *mbus_cfg)
+static int rvin_digital_parse_v4l2(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd)
{
- struct v4l2_fwnode_endpoint v4l2_ep;
- int ret;
+ struct rvin_dev *vin = dev_get_drvdata(dev);
+ struct rvin_graph_entity *rvge =
+ container_of(asd, struct rvin_graph_entity, asd);
- ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
- if (ret) {
- vin_err(vin, "Could not parse v4l2 endpoint\n");
- return -EINVAL;
- }
+ if (vep->base.port || vep->base.id)
+ return -ENOTCONN;
- mbus_cfg->type = v4l2_ep.bus_type;
+ rvge->mbus_cfg.type = vep->bus_type;
- switch (mbus_cfg->type) {
+ switch (rvge->mbus_cfg.type) {
case V4L2_MBUS_PARALLEL:
vin_dbg(vin, "Found PARALLEL media bus\n");
- mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
+ rvge->mbus_cfg.flags = vep->bus.parallel.flags;
break;
case V4L2_MBUS_BT656:
vin_dbg(vin, "Found BT656 media bus\n");
- mbus_cfg->flags = 0;
+ rvge->mbus_cfg.flags = 0;
break;
default:
vin_err(vin, "Unknown media bus type\n");
return -EINVAL;
}
- return 0;
-}
-
-static int rvin_digital_graph_parse(struct rvin_dev *vin)
-{
- struct device_node *ep, *np;
- int ret;
-
- vin->digital.asd.match.fwnode.fwnode = NULL;
- vin->digital.subdev = NULL;
-
- /*
- * Port 0 id 0 is local digital input, try to get it.
- * Not all instances can or will have this, that is OK
- */
- ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
- if (!ep)
- return 0;
-
- np = of_graph_get_remote_port_parent(ep);
- if (!np) {
- vin_err(vin, "No remote parent for digital input\n");
- of_node_put(ep);
- return -EINVAL;
- }
- of_node_put(np);
-
- ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
- of_node_put(ep);
- if (ret)
- return ret;
-
- vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
- vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+ vin->digital = rvge;
return 0;
}
static int rvin_digital_graph_init(struct rvin_dev *vin)
{
- struct v4l2_async_subdev **subdevs = NULL;
int ret;
- ret = rvin_digital_graph_parse(vin);
+ ret = v4l2_async_notifier_parse_fwnode_endpoints(
+ vin->dev, &vin->notifier,
+ sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
if (ret)
return ret;
- if (!vin->digital.asd.match.fwnode.fwnode) {
- vin_dbg(vin, "No digital subdevice found\n");
- return -ENODEV;
- }
-
- /* Register the subdevices notifier. */
- subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
- if (subdevs == NULL)
- return -ENOMEM;
-
- subdevs[0] = &vin->digital.asd;
-
- vin_dbg(vin, "Found digital subdevice %pOF\n",
- to_of_node(subdevs[0]->match.fwnode.fwnode));
+ if (vin->digital)
+ vin_dbg(vin, "Found digital subdevice %pOF\n",
+ to_of_node(
+ vin->digital->asd.match.fwnode.fwnode));
- vin->notifier.num_subdevs = 1;
- vin->notifier.subdevs = subdevs;
vin->notifier.bound = rvin_digital_notify_bound;
vin->notifier.unbind = rvin_digital_notify_unbind;
vin->notifier.complete = rvin_digital_notify_complete;
-
ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
if (ret < 0) {
vin_err(vin, "Notifier registration failed\n");
@@ -290,6 +244,8 @@ static int rcar_vin_probe(struct platform_device *pdev)
if (ret)
return ret;
+ platform_set_drvdata(pdev, vin);
+
ret = rvin_digital_graph_init(vin);
if (ret < 0)
goto error;
@@ -297,11 +253,10 @@ static int rcar_vin_probe(struct platform_device *pdev)
pm_suspend_ignore_children(&pdev->dev, true);
pm_runtime_enable(&pdev->dev);
- platform_set_drvdata(pdev, vin);
-
return 0;
error:
rvin_dma_remove(vin);
+ v4l2_async_notifier_release(&vin->notifier);
return ret;
}
@@ -313,6 +268,7 @@ static int rcar_vin_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&vin->notifier);
+ v4l2_async_notifier_release(&vin->notifier);
rvin_dma_remove(vin);
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index b136844499f6..23fdff7a7370 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)
/*
* Input interface
*/
- switch (vin->digital.code) {
+ switch (vin->digital->code) {
case MEDIA_BUS_FMT_YUYV8_1X16:
/* BT.601/BT.1358 16bit YCbCr422 */
vnmc |= VNMC_INF_YUV16;
@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)
break;
case MEDIA_BUS_FMT_UYVY8_2X8:
/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
- vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
+ vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
input_is_yuv = true;
break;
@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)
break;
case MEDIA_BUS_FMT_UYVY10_2X10:
/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
- vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
+ vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
input_is_yuv = true;
break;
@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin)
dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
/* Hsync Signal Polarity Select */
- if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
+ if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_HPS;
/* Vsync Signal Polarity Select */
- if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
+ if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_VPS;
/*
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index dd37ea811680..b479b882da12 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)
struct v4l2_mbus_framefmt *mf = &fmt.format;
int ret;
- fmt.pad = vin->digital.source_pad;
+ fmt.pad = vin->digital->source_pad;
ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
if (ret)
@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin,
sd = vin_to_source(vin);
- v4l2_fill_mbus_format(&format.format, pix, vin->digital.code);
+ v4l2_fill_mbus_format(&format.format, pix, vin->digital->code);
pad_cfg = v4l2_subdev_alloc_pad_config(sd);
if (pad_cfg == NULL)
return -ENOMEM;
- format.pad = vin->digital.source_pad;
+ format.pad = vin->digital->source_pad;
field = pix->field;
@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
if (timings->pad)
return -EINVAL;
- timings->pad = vin->digital.sink_pad;
+ timings->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
if (cap->pad)
return -EINVAL;
- cap->pad = vin->digital.sink_pad;
+ cap->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
if (edid->pad)
return -EINVAL;
- edid->pad = vin->digital.sink_pad;
+ edid->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, get_edid, edid);
@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
if (edid->pad)
return -EINVAL;
- edid->pad = vin->digital.sink_pad;
+ edid->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, set_edid, edid);
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 9bfb5a7c4dc4..5382078143fb 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -126,7 +126,7 @@ struct rvin_dev {
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_async_notifier notifier;
- struct rvin_graph_entity digital;
+ struct rvin_graph_entity *digital;
struct mutex lock;
struct vb2_queue queue;
@@ -145,7 +145,7 @@ struct rvin_dev {
struct v4l2_rect compose;
};
-#define vin_to_source(vin) vin->digital.subdev
+#define vin_to_source(vin) ((vin)->digital->subdev)
/* Debug */
#define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 07/25] rcar-vin: Use generic parser for parsing fwnode endpoints
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Instead of using driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
of the device.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/platform/rcar-vin/rcar-core.c | 112 +++++++++-------------------
drivers/media/platform/rcar-vin/rcar-dma.c | 10 +--
drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++--
drivers/media/platform/rcar-vin/rcar-vin.h | 4 +-
4 files changed, 48 insertions(+), 92 deletions(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 142de447aaaa..62b4a94f9a39 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
#include "rcar-vin.h"
@@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)
int ret;
/* Verify subdevices mbus format */
- if (!rvin_mbus_supported(&vin->digital)) {
+ if (!rvin_mbus_supported(vin->digital)) {
vin_err(vin, "Unsupported media bus format for %s\n",
- vin->digital.subdev->name);
+ vin->digital->subdev->name);
return -EINVAL;
}
vin_dbg(vin, "Found media bus format for %s: %d\n",
- vin->digital.subdev->name, vin->digital.code);
+ vin->digital->subdev->name, vin->digital->code);
ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
if (ret < 0) {
@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,
vin_dbg(vin, "unbind digital subdev %s\n", subdev->name);
rvin_v4l2_remove(vin);
- vin->digital.subdev = NULL;
+ vin->digital->subdev = NULL;
}
static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
@@ -120,117 +121,70 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
if (ret < 0)
return ret;
- vin->digital.source_pad = ret;
+ vin->digital->source_pad = ret;
ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
- vin->digital.sink_pad = ret < 0 ? 0 : ret;
+ vin->digital->sink_pad = ret < 0 ? 0 : ret;
- vin->digital.subdev = subdev;
+ vin->digital->subdev = subdev;
vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
- subdev->name, vin->digital.source_pad,
- vin->digital.sink_pad);
+ subdev->name, vin->digital->source_pad,
+ vin->digital->sink_pad);
return 0;
}
-static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
- struct device_node *ep,
- struct v4l2_mbus_config *mbus_cfg)
+static int rvin_digital_parse_v4l2(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd)
{
- struct v4l2_fwnode_endpoint v4l2_ep;
- int ret;
+ struct rvin_dev *vin = dev_get_drvdata(dev);
+ struct rvin_graph_entity *rvge =
+ container_of(asd, struct rvin_graph_entity, asd);
- ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
- if (ret) {
- vin_err(vin, "Could not parse v4l2 endpoint\n");
- return -EINVAL;
- }
+ if (vep->base.port || vep->base.id)
+ return -ENOTCONN;
- mbus_cfg->type = v4l2_ep.bus_type;
+ rvge->mbus_cfg.type = vep->bus_type;
- switch (mbus_cfg->type) {
+ switch (rvge->mbus_cfg.type) {
case V4L2_MBUS_PARALLEL:
vin_dbg(vin, "Found PARALLEL media bus\n");
- mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
+ rvge->mbus_cfg.flags = vep->bus.parallel.flags;
break;
case V4L2_MBUS_BT656:
vin_dbg(vin, "Found BT656 media bus\n");
- mbus_cfg->flags = 0;
+ rvge->mbus_cfg.flags = 0;
break;
default:
vin_err(vin, "Unknown media bus type\n");
return -EINVAL;
}
- return 0;
-}
-
-static int rvin_digital_graph_parse(struct rvin_dev *vin)
-{
- struct device_node *ep, *np;
- int ret;
-
- vin->digital.asd.match.fwnode.fwnode = NULL;
- vin->digital.subdev = NULL;
-
- /*
- * Port 0 id 0 is local digital input, try to get it.
- * Not all instances can or will have this, that is OK
- */
- ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
- if (!ep)
- return 0;
-
- np = of_graph_get_remote_port_parent(ep);
- if (!np) {
- vin_err(vin, "No remote parent for digital input\n");
- of_node_put(ep);
- return -EINVAL;
- }
- of_node_put(np);
-
- ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
- of_node_put(ep);
- if (ret)
- return ret;
-
- vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
- vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+ vin->digital = rvge;
return 0;
}
static int rvin_digital_graph_init(struct rvin_dev *vin)
{
- struct v4l2_async_subdev **subdevs = NULL;
int ret;
- ret = rvin_digital_graph_parse(vin);
+ ret = v4l2_async_notifier_parse_fwnode_endpoints(
+ vin->dev, &vin->notifier,
+ sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
if (ret)
return ret;
- if (!vin->digital.asd.match.fwnode.fwnode) {
- vin_dbg(vin, "No digital subdevice found\n");
- return -ENODEV;
- }
-
- /* Register the subdevices notifier. */
- subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
- if (subdevs == NULL)
- return -ENOMEM;
-
- subdevs[0] = &vin->digital.asd;
-
- vin_dbg(vin, "Found digital subdevice %pOF\n",
- to_of_node(subdevs[0]->match.fwnode.fwnode));
+ if (vin->digital)
+ vin_dbg(vin, "Found digital subdevice %pOF\n",
+ to_of_node(
+ vin->digital->asd.match.fwnode.fwnode));
- vin->notifier.num_subdevs = 1;
- vin->notifier.subdevs = subdevs;
vin->notifier.bound = rvin_digital_notify_bound;
vin->notifier.unbind = rvin_digital_notify_unbind;
vin->notifier.complete = rvin_digital_notify_complete;
-
ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
if (ret < 0) {
vin_err(vin, "Notifier registration failed\n");
@@ -290,6 +244,8 @@ static int rcar_vin_probe(struct platform_device *pdev)
if (ret)
return ret;
+ platform_set_drvdata(pdev, vin);
+
ret = rvin_digital_graph_init(vin);
if (ret < 0)
goto error;
@@ -297,11 +253,10 @@ static int rcar_vin_probe(struct platform_device *pdev)
pm_suspend_ignore_children(&pdev->dev, true);
pm_runtime_enable(&pdev->dev);
- platform_set_drvdata(pdev, vin);
-
return 0;
error:
rvin_dma_remove(vin);
+ v4l2_async_notifier_release(&vin->notifier);
return ret;
}
@@ -313,6 +268,7 @@ static int rcar_vin_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&vin->notifier);
+ v4l2_async_notifier_release(&vin->notifier);
rvin_dma_remove(vin);
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index b136844499f6..23fdff7a7370 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)
/*
* Input interface
*/
- switch (vin->digital.code) {
+ switch (vin->digital->code) {
case MEDIA_BUS_FMT_YUYV8_1X16:
/* BT.601/BT.1358 16bit YCbCr422 */
vnmc |= VNMC_INF_YUV16;
@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)
break;
case MEDIA_BUS_FMT_UYVY8_2X8:
/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
- vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
+ vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
input_is_yuv = true;
break;
@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)
break;
case MEDIA_BUS_FMT_UYVY10_2X10:
/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
- vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
+ vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
input_is_yuv = true;
break;
@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin)
dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
/* Hsync Signal Polarity Select */
- if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
+ if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_HPS;
/* Vsync Signal Polarity Select */
- if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
+ if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_VPS;
/*
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index dd37ea811680..b479b882da12 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)
struct v4l2_mbus_framefmt *mf = &fmt.format;
int ret;
- fmt.pad = vin->digital.source_pad;
+ fmt.pad = vin->digital->source_pad;
ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
if (ret)
@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin,
sd = vin_to_source(vin);
- v4l2_fill_mbus_format(&format.format, pix, vin->digital.code);
+ v4l2_fill_mbus_format(&format.format, pix, vin->digital->code);
pad_cfg = v4l2_subdev_alloc_pad_config(sd);
if (pad_cfg == NULL)
return -ENOMEM;
- format.pad = vin->digital.source_pad;
+ format.pad = vin->digital->source_pad;
field = pix->field;
@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
if (timings->pad)
return -EINVAL;
- timings->pad = vin->digital.sink_pad;
+ timings->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
if (cap->pad)
return -EINVAL;
- cap->pad = vin->digital.sink_pad;
+ cap->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
if (edid->pad)
return -EINVAL;
- edid->pad = vin->digital.sink_pad;
+ edid->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, get_edid, edid);
@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
if (edid->pad)
return -EINVAL;
- edid->pad = vin->digital.sink_pad;
+ edid->pad = vin->digital->sink_pad;
ret = v4l2_subdev_call(sd, pad, set_edid, edid);
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 9bfb5a7c4dc4..5382078143fb 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -126,7 +126,7 @@ struct rvin_dev {
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_async_notifier notifier;
- struct rvin_graph_entity digital;
+ struct rvin_graph_entity *digital;
struct mutex lock;
struct vb2_queue queue;
@@ -145,7 +145,7 @@ struct rvin_dev {
struct v4l2_rect compose;
};
-#define vin_to_source(vin) vin->digital.subdev
+#define vin_to_source(vin) ((vin)->digital->subdev)
/* Debug */
#define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
[parent not found: <20170915141724.23124-8-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>]
* Re: [PATCH v13 07/25] rcar-vin: Use generic parser for parsing fwnode endpoints
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-19 11:53 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:53 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:06 EEST Sakari Ailus wrote:
> Instead of using driver implementation, use
Same comment as for patch 06/25.
> v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
> of the device.
>
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> ---
> drivers/media/platform/rcar-vin/rcar-core.c | 112 ++++++++-----------------
> drivers/media/platform/rcar-vin/rcar-dma.c | 10 +--
> drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++--
> drivers/media/platform/rcar-vin/rcar-vin.h | 4 +-
> 4 files changed, 48 insertions(+), 92 deletions(-)
>
> diff --git a/drivers/media/platform/rcar-vin/rcar-core.c
> b/drivers/media/platform/rcar-vin/rcar-core.c index
> 142de447aaaa..62b4a94f9a39 100644
> --- a/drivers/media/platform/rcar-vin/rcar-core.c
> +++ b/drivers/media/platform/rcar-vin/rcar-core.c
[snip]
> @@ -120,117 +121,70 @@ static int rvin_digital_notify_bound(struct
[snip]
> -static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
> - struct device_node *ep,
> - struct v4l2_mbus_config *mbus_cfg)
> +static int rvin_digital_parse_v4l2(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd)
> {
> - struct v4l2_fwnode_endpoint v4l2_ep;
> - int ret;
> + struct rvin_dev *vin = dev_get_drvdata(dev);
Doesn't this show that we miss a context argument to the callback function ?
Storing the context in device driver data is probably OK if the driver parsing
the endpoints controls the struct device, but is that always the case ?
> + struct rvin_graph_entity *rvge =
> + container_of(asd, struct rvin_graph_entity, asd);
>
> - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
> - if (ret) {
> - vin_err(vin, "Could not parse v4l2 endpoint\n");
> - return -EINVAL;
> - }
> + if (vep->base.port || vep->base.id)
> + return -ENOTCONN;
>
> - mbus_cfg->type = v4l2_ep.bus_type;
> + rvge->mbus_cfg.type = vep->bus_type;
>
> - switch (mbus_cfg->type) {
> + switch (rvge->mbus_cfg.type) {
> case V4L2_MBUS_PARALLEL:
> vin_dbg(vin, "Found PARALLEL media bus\n");
> - mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
> + rvge->mbus_cfg.flags = vep->bus.parallel.flags;
> break;
> case V4L2_MBUS_BT656:
> vin_dbg(vin, "Found BT656 media bus\n");
> - mbus_cfg->flags = 0;
> + rvge->mbus_cfg.flags = 0;
> break;
> default:
> vin_err(vin, "Unknown media bus type\n");
> return -EINVAL;
> }
>
> - return 0;
> -}
> -
> -static int rvin_digital_graph_parse(struct rvin_dev *vin)
> -{
> - struct device_node *ep, *np;
> - int ret;
> -
> - vin->digital.asd.match.fwnode.fwnode = NULL;
> - vin->digital.subdev = NULL;
> -
> - /*
> - * Port 0 id 0 is local digital input, try to get it.
> - * Not all instances can or will have this, that is OK
> - */
> - ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
> - if (!ep)
> - return 0;
> -
> - np = of_graph_get_remote_port_parent(ep);
> - if (!np) {
> - vin_err(vin, "No remote parent for digital input\n");
> - of_node_put(ep);
> - return -EINVAL;
> - }
> - of_node_put(np);
> -
> - ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
> - of_node_put(ep);
> - if (ret)
> - return ret;
> -
> - vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
> - vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> + vin->digital = rvge;
>
> return 0;
> }
>
> static int rvin_digital_graph_init(struct rvin_dev *vin)
> {
> - struct v4l2_async_subdev **subdevs = NULL;
> int ret;
>
> - ret = rvin_digital_graph_parse(vin);
> + ret = v4l2_async_notifier_parse_fwnode_endpoints(
> + vin->dev, &vin->notifier,
> + sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
> if (ret)
> return ret;
>
> - if (!vin->digital.asd.match.fwnode.fwnode) {
> - vin_dbg(vin, "No digital subdevice found\n");
> - return -ENODEV;
> - }
> -
> - /* Register the subdevices notifier. */
> - subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
> - if (subdevs == NULL)
> - return -ENOMEM;
> -
> - subdevs[0] = &vin->digital.asd;
> -
> - vin_dbg(vin, "Found digital subdevice %pOF\n",
> - to_of_node(subdevs[0]->match.fwnode.fwnode));
> + if (vin->digital)
> + vin_dbg(vin, "Found digital subdevice %pOF\n",
> + to_of_node(
> + vin->digital->asd.match.fwnode.fwnode));
Isn't this is a change in behaviour ? The driver currently returns -ENODEV
when no digital subdev is found.
> - vin->notifier.num_subdevs = 1;
> - vin->notifier.subdevs = subdevs;
> vin->notifier.bound = rvin_digital_notify_bound;
> vin->notifier.unbind = rvin_digital_notify_unbind;
> vin->notifier.complete = rvin_digital_notify_complete;
> -
> ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
> if (ret < 0) {
> vin_err(vin, "Notifier registration failed\n");
[snip]
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 07/25] rcar-vin: Use generic parser for parsing fwnode endpoints
@ 2017-09-19 11:53 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:53 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:06 EEST Sakari Ailus wrote:
> Instead of using driver implementation, use
Same comment as for patch 06/25.
> v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
> of the device.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
> drivers/media/platform/rcar-vin/rcar-core.c | 112 ++++++++-----------------
> drivers/media/platform/rcar-vin/rcar-dma.c | 10 +--
> drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++--
> drivers/media/platform/rcar-vin/rcar-vin.h | 4 +-
> 4 files changed, 48 insertions(+), 92 deletions(-)
>
> diff --git a/drivers/media/platform/rcar-vin/rcar-core.c
> b/drivers/media/platform/rcar-vin/rcar-core.c index
> 142de447aaaa..62b4a94f9a39 100644
> --- a/drivers/media/platform/rcar-vin/rcar-core.c
> +++ b/drivers/media/platform/rcar-vin/rcar-core.c
[snip]
> @@ -120,117 +121,70 @@ static int rvin_digital_notify_bound(struct
[snip]
> -static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
> - struct device_node *ep,
> - struct v4l2_mbus_config *mbus_cfg)
> +static int rvin_digital_parse_v4l2(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd)
> {
> - struct v4l2_fwnode_endpoint v4l2_ep;
> - int ret;
> + struct rvin_dev *vin = dev_get_drvdata(dev);
Doesn't this show that we miss a context argument to the callback function ?
Storing the context in device driver data is probably OK if the driver parsing
the endpoints controls the struct device, but is that always the case ?
> + struct rvin_graph_entity *rvge =
> + container_of(asd, struct rvin_graph_entity, asd);
>
> - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
> - if (ret) {
> - vin_err(vin, "Could not parse v4l2 endpoint\n");
> - return -EINVAL;
> - }
> + if (vep->base.port || vep->base.id)
> + return -ENOTCONN;
>
> - mbus_cfg->type = v4l2_ep.bus_type;
> + rvge->mbus_cfg.type = vep->bus_type;
>
> - switch (mbus_cfg->type) {
> + switch (rvge->mbus_cfg.type) {
> case V4L2_MBUS_PARALLEL:
> vin_dbg(vin, "Found PARALLEL media bus\n");
> - mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
> + rvge->mbus_cfg.flags = vep->bus.parallel.flags;
> break;
> case V4L2_MBUS_BT656:
> vin_dbg(vin, "Found BT656 media bus\n");
> - mbus_cfg->flags = 0;
> + rvge->mbus_cfg.flags = 0;
> break;
> default:
> vin_err(vin, "Unknown media bus type\n");
> return -EINVAL;
> }
>
> - return 0;
> -}
> -
> -static int rvin_digital_graph_parse(struct rvin_dev *vin)
> -{
> - struct device_node *ep, *np;
> - int ret;
> -
> - vin->digital.asd.match.fwnode.fwnode = NULL;
> - vin->digital.subdev = NULL;
> -
> - /*
> - * Port 0 id 0 is local digital input, try to get it.
> - * Not all instances can or will have this, that is OK
> - */
> - ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
> - if (!ep)
> - return 0;
> -
> - np = of_graph_get_remote_port_parent(ep);
> - if (!np) {
> - vin_err(vin, "No remote parent for digital input\n");
> - of_node_put(ep);
> - return -EINVAL;
> - }
> - of_node_put(np);
> -
> - ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
> - of_node_put(ep);
> - if (ret)
> - return ret;
> -
> - vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
> - vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> + vin->digital = rvge;
>
> return 0;
> }
>
> static int rvin_digital_graph_init(struct rvin_dev *vin)
> {
> - struct v4l2_async_subdev **subdevs = NULL;
> int ret;
>
> - ret = rvin_digital_graph_parse(vin);
> + ret = v4l2_async_notifier_parse_fwnode_endpoints(
> + vin->dev, &vin->notifier,
> + sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
> if (ret)
> return ret;
>
> - if (!vin->digital.asd.match.fwnode.fwnode) {
> - vin_dbg(vin, "No digital subdevice found\n");
> - return -ENODEV;
> - }
> -
> - /* Register the subdevices notifier. */
> - subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
> - if (subdevs == NULL)
> - return -ENOMEM;
> -
> - subdevs[0] = &vin->digital.asd;
> -
> - vin_dbg(vin, "Found digital subdevice %pOF\n",
> - to_of_node(subdevs[0]->match.fwnode.fwnode));
> + if (vin->digital)
> + vin_dbg(vin, "Found digital subdevice %pOF\n",
> + to_of_node(
> + vin->digital->asd.match.fwnode.fwnode));
Isn't this is a change in behaviour ? The driver currently returns -ENODEV
when no digital subdev is found.
> - vin->notifier.num_subdevs = 1;
> - vin->notifier.subdevs = subdevs;
> vin->notifier.bound = rvin_digital_notify_bound;
> vin->notifier.unbind = rvin_digital_notify_unbind;
> vin->notifier.complete = rvin_digital_notify_complete;
> -
> ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
> if (ret < 0) {
> vin_err(vin, "Notifier registration failed\n");
[snip]
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 07/25] rcar-vin: Use generic parser for parsing fwnode endpoints
2017-09-19 11:53 ` Laurent Pinchart
(?)
@ 2017-09-19 12:39 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 12:39 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 02:53:16PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:06 EEST Sakari Ailus wrote:
> > Instead of using driver implementation, use
>
> Same comment as for patch 06/25.
Will fix.
>
> > v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
> > of the device.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > ---
> > drivers/media/platform/rcar-vin/rcar-core.c | 112 ++++++++-----------------
> > drivers/media/platform/rcar-vin/rcar-dma.c | 10 +--
> > drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++--
> > drivers/media/platform/rcar-vin/rcar-vin.h | 4 +-
> > 4 files changed, 48 insertions(+), 92 deletions(-)
> >
> > diff --git a/drivers/media/platform/rcar-vin/rcar-core.c
> > b/drivers/media/platform/rcar-vin/rcar-core.c index
> > 142de447aaaa..62b4a94f9a39 100644
> > --- a/drivers/media/platform/rcar-vin/rcar-core.c
> > +++ b/drivers/media/platform/rcar-vin/rcar-core.c
>
> [snip]
>
> > @@ -120,117 +121,70 @@ static int rvin_digital_notify_bound(struct
>
> [snip]
>
> > -static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
> > - struct device_node *ep,
> > - struct v4l2_mbus_config *mbus_cfg)
> > +static int rvin_digital_parse_v4l2(struct device *dev,
> > + struct v4l2_fwnode_endpoint *vep,
> > + struct v4l2_async_subdev *asd)
> > {
> > - struct v4l2_fwnode_endpoint v4l2_ep;
> > - int ret;
> > + struct rvin_dev *vin = dev_get_drvdata(dev);
>
> Doesn't this show that we miss a context argument to the callback function ?
> Storing the context in device driver data is probably OK if the driver parsing
> the endpoints controls the struct device, but is that always the case ?
How does a driver know the hardware other than, uh, the device?
I guess we could add a private pointer when the async notifier is
registered if there's a real need for it. The notifier could be an
alternative but it wouldn't be applicable to sub-devices.
>
> > + struct rvin_graph_entity *rvge =
> > + container_of(asd, struct rvin_graph_entity, asd);
> >
> > - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
> > - if (ret) {
> > - vin_err(vin, "Could not parse v4l2 endpoint\n");
> > - return -EINVAL;
> > - }
> > + if (vep->base.port || vep->base.id)
> > + return -ENOTCONN;
> >
> > - mbus_cfg->type = v4l2_ep.bus_type;
> > + rvge->mbus_cfg.type = vep->bus_type;
> >
> > - switch (mbus_cfg->type) {
> > + switch (rvge->mbus_cfg.type) {
> > case V4L2_MBUS_PARALLEL:
> > vin_dbg(vin, "Found PARALLEL media bus\n");
> > - mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
> > + rvge->mbus_cfg.flags = vep->bus.parallel.flags;
> > break;
> > case V4L2_MBUS_BT656:
> > vin_dbg(vin, "Found BT656 media bus\n");
> > - mbus_cfg->flags = 0;
> > + rvge->mbus_cfg.flags = 0;
> > break;
> > default:
> > vin_err(vin, "Unknown media bus type\n");
> > return -EINVAL;
> > }
> >
> > - return 0;
> > -}
> > -
> > -static int rvin_digital_graph_parse(struct rvin_dev *vin)
> > -{
> > - struct device_node *ep, *np;
> > - int ret;
> > -
> > - vin->digital.asd.match.fwnode.fwnode = NULL;
> > - vin->digital.subdev = NULL;
> > -
> > - /*
> > - * Port 0 id 0 is local digital input, try to get it.
> > - * Not all instances can or will have this, that is OK
> > - */
> > - ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
> > - if (!ep)
> > - return 0;
> > -
> > - np = of_graph_get_remote_port_parent(ep);
> > - if (!np) {
> > - vin_err(vin, "No remote parent for digital input\n");
> > - of_node_put(ep);
> > - return -EINVAL;
> > - }
> > - of_node_put(np);
> > -
> > - ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
> > - of_node_put(ep);
> > - if (ret)
> > - return ret;
> > -
> > - vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
> > - vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> > + vin->digital = rvge;
> >
> > return 0;
> > }
> >
> > static int rvin_digital_graph_init(struct rvin_dev *vin)
> > {
> > - struct v4l2_async_subdev **subdevs = NULL;
> > int ret;
> >
> > - ret = rvin_digital_graph_parse(vin);
> > + ret = v4l2_async_notifier_parse_fwnode_endpoints(
> > + vin->dev, &vin->notifier,
> > + sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
> > if (ret)
> > return ret;
> >
> > - if (!vin->digital.asd.match.fwnode.fwnode) {
> > - vin_dbg(vin, "No digital subdevice found\n");
> > - return -ENODEV;
> > - }
> > -
> > - /* Register the subdevices notifier. */
> > - subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
> > - if (subdevs == NULL)
> > - return -ENOMEM;
> > -
> > - subdevs[0] = &vin->digital.asd;
> > -
> > - vin_dbg(vin, "Found digital subdevice %pOF\n",
> > - to_of_node(subdevs[0]->match.fwnode.fwnode));
> > + if (vin->digital)
> > + vin_dbg(vin, "Found digital subdevice %pOF\n",
> > + to_of_node(
> > + vin->digital->asd.match.fwnode.fwnode));
>
> Isn't this is a change in behaviour ? The driver currently returns -ENODEV
> when no digital subdev is found.
Seems so, I'll address that in v14.
>
> > - vin->notifier.num_subdevs = 1;
> > - vin->notifier.subdevs = subdevs;
> > vin->notifier.bound = rvin_digital_notify_bound;
> > vin->notifier.unbind = rvin_digital_notify_unbind;
> > vin->notifier.complete = rvin_digital_notify_complete;
> > -
> > ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
> > if (ret < 0) {
> > vin_err(vin, "Notifier registration failed\n");
>
--
Regards,
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 09/25] omap3isp: Print the name of the entity where no source pads could be found
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
If no source pads are found in an entity, print the name of the entity.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
---
drivers/media/platform/omap3isp/isp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 3b1a9cd0e591..9a694924e46e 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1669,8 +1669,8 @@ static int isp_link_entity(
break;
}
if (i == entity->num_pads) {
- dev_err(isp->dev, "%s: no source pad in external entity\n",
- __func__);
+ dev_err(isp->dev, "%s: no source pad in external entity %s\n",
+ __func__, entity->name);
return -EINVAL;
}
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 09/25] omap3isp: Print the name of the entity where no source pads could be found
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
If no source pads are found in an entity, print the name of the entity.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/media/platform/omap3isp/isp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 3b1a9cd0e591..9a694924e46e 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1669,8 +1669,8 @@ static int isp_link_entity(
break;
}
if (i == entity->num_pads) {
- dev_err(isp->dev, "%s: no source pad in external entity\n",
- __func__);
+ dev_err(isp->dev, "%s: no source pad in external entity %s\n",
+ __func__, entity->name);
return -EINVAL;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
* Re: [PATCH v13 09/25] omap3isp: Print the name of the entity where no source pads could be found
2017-09-15 14:17 ` Sakari Ailus
(?)
@ 2017-09-19 11:56 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 11:56 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:08 EEST Sakari Ailus wrote:
> If no source pads are found in an entity, print the name of the entity.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> drivers/media/platform/omap3isp/isp.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/platform/omap3isp/isp.c
> b/drivers/media/platform/omap3isp/isp.c index 3b1a9cd0e591..9a694924e46e
> 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -1669,8 +1669,8 @@ static int isp_link_entity(
> break;
> }
> if (i == entity->num_pads) {
> - dev_err(isp->dev, "%s: no source pad in external entity\n",
> - __func__);
> + dev_err(isp->dev, "%s: no source pad in external entity %s\n",
> + __func__, entity->name);
> return -EINVAL;
> }
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Add three helper functions to call async operations callbacks. Besides
simplifying callbacks, this allows async notifiers to have no ops set,
i.e. it can be left NULL.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
---
drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++++++++++----------
include/media/v4l2-async.h | 1 +
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 7b2125b3d62f..c35d04b9122f 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -25,6 +25,34 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
+static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ if (!n->ops || !n->ops->bound)
+ return 0;
+
+ return n->ops->bound(n, subdev, asd);
+}
+
+static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ if (!n->ops || !n->ops->unbind)
+ return;
+
+ n->ops->unbind(n, subdev, asd);
+}
+
+static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
+{
+ if (!n->ops || !n->ops->complete)
+ return 0;
+
+ return n->ops->complete(n);
+}
+
static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
#if IS_ENABLED(CONFIG_I2C)
@@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
{
int ret;
- if (notifier->ops->bound) {
- ret = notifier->ops->bound(notifier, sd, asd);
- if (ret < 0)
- return ret;
- }
+ ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
+ if (ret < 0)
+ return ret;
ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
if (ret < 0) {
- if (notifier->ops->unbind)
- notifier->ops->unbind(notifier, sd, asd);
+ v4l2_async_notifier_call_unbind(notifier, sd, asd);
return ret;
}
@@ -123,8 +148,8 @@ 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, ¬ifier->done);
- if (list_empty(¬ifier->waiting) && notifier->ops->complete)
- return notifier->ops->complete(notifier);
+ if (list_empty(¬ifier->waiting))
+ return v4l2_async_notifier_call_complete(notifier);
return 0;
}
@@ -210,8 +235,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) {
v4l2_async_cleanup(sd);
- if (notifier->ops->unbind)
- notifier->ops->unbind(notifier, sd, sd->asd);
+ v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
}
mutex_unlock(&list_lock);
@@ -300,8 +324,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
v4l2_async_cleanup(sd);
- if (notifier->ops->unbind)
- notifier->ops->unbind(notifier, sd, sd->asd);
+ v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
mutex_unlock(&list_lock);
}
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 3c48f8b66d12..3bc8a7c0d83f 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -164,4 +164,5 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd);
* @sd: pointer to &struct v4l2_subdev
*/
void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
+
#endif
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Add three helper functions to call async operations callbacks. Besides
simplifying callbacks, this allows async notifiers to have no ops set,
i.e. it can be left NULL.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++++++++++----------
include/media/v4l2-async.h | 1 +
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 7b2125b3d62f..c35d04b9122f 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -25,6 +25,34 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
+static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ if (!n->ops || !n->ops->bound)
+ return 0;
+
+ return n->ops->bound(n, subdev, asd);
+}
+
+static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ if (!n->ops || !n->ops->unbind)
+ return;
+
+ n->ops->unbind(n, subdev, asd);
+}
+
+static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
+{
+ if (!n->ops || !n->ops->complete)
+ return 0;
+
+ return n->ops->complete(n);
+}
+
static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
#if IS_ENABLED(CONFIG_I2C)
@@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
{
int ret;
- if (notifier->ops->bound) {
- ret = notifier->ops->bound(notifier, sd, asd);
- if (ret < 0)
- return ret;
- }
+ ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
+ if (ret < 0)
+ return ret;
ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
if (ret < 0) {
- if (notifier->ops->unbind)
- notifier->ops->unbind(notifier, sd, asd);
+ v4l2_async_notifier_call_unbind(notifier, sd, asd);
return ret;
}
@@ -123,8 +148,8 @@ 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, ¬ifier->done);
- if (list_empty(¬ifier->waiting) && notifier->ops->complete)
- return notifier->ops->complete(notifier);
+ if (list_empty(¬ifier->waiting))
+ return v4l2_async_notifier_call_complete(notifier);
return 0;
}
@@ -210,8 +235,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) {
v4l2_async_cleanup(sd);
- if (notifier->ops->unbind)
- notifier->ops->unbind(notifier, sd, sd->asd);
+ v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
}
mutex_unlock(&list_lock);
@@ -300,8 +324,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
v4l2_async_cleanup(sd);
- if (notifier->ops->unbind)
- notifier->ops->unbind(notifier, sd, sd->asd);
+ v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
mutex_unlock(&list_lock);
}
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 3c48f8b66d12..3bc8a7c0d83f 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -164,4 +164,5 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd);
* @sd: pointer to &struct v4l2_subdev
*/
void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
+
#endif
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
[parent not found: <20170915141724.23124-12-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>]
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-16 7:13 ` Pavel Machek
-1 siblings, 0 replies; 137+ messages in thread
From: Pavel Machek @ 2017-09-16 7:13 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, sre-DgEjT+Ai2ygdnm+yROfE0A
[-- Attachment #1: Type: text/plain, Size: 716 bytes --]
On Fri 2017-09-15 17:17:10, Sakari Ailus wrote:
> Add three helper functions to call async operations callbacks. Besides
> simplifying callbacks, this allows async notifiers to have no ops set,
> i.e. it can be left NULL.
>
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
I'd remove "_call" from these names; they are long enough already and
do not add much. But either way is okay.
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
@ 2017-09-16 7:13 ` Pavel Machek
0 siblings, 0 replies; 137+ messages in thread
From: Pavel Machek @ 2017-09-16 7:13 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, sre
[-- Attachment #1: Type: text/plain, Size: 640 bytes --]
On Fri 2017-09-15 17:17:10, Sakari Ailus wrote:
> Add three helper functions to call async operations callbacks. Besides
> simplifying callbacks, this allows async notifiers to have no ops set,
> i.e. it can be left NULL.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
I'd remove "_call" from these names; they are long enough already and
do not add much. But either way is okay.
Acked-by: Pavel Machek <pavel@ucw.cz>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-19 12:01 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 12:01 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> Add three helper functions to call async operations callbacks. Besides
> simplifying callbacks, this allows async notifiers to have no ops set,
> i.e. it can be left NULL.
>
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++++++++--------
> include/media/v4l2-async.h | 1 +
> 2 files changed, 37 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> b/drivers/media/v4l2-core/v4l2-async.c index 7b2125b3d62f..c35d04b9122f
> 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -25,6 +25,34 @@
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-subdev.h>
>
> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
> + struct v4l2_subdev *subdev,
> + struct v4l2_async_subdev *asd)
> +{
> + if (!n->ops || !n->ops->bound)
> + return 0;
> +
> + return n->ops->bound(n, subdev, asd);
> +}
> +
> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
> + struct v4l2_subdev *subdev,
> + struct v4l2_async_subdev *asd)
> +{
> + if (!n->ops || !n->ops->unbind)
> + return;
> +
> + n->ops->unbind(n, subdev, asd);
> +}
> +
> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
> +{
> + if (!n->ops || !n->ops->complete)
> + return 0;
> +
> + return n->ops->complete(n);
> +}
> +
Wouldn't it be enough to add a single v4l2_async_notifier_call() macro ?
#define v4l2_async_notifier_call(n, op, args...) \
((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
Apart from that,
Reviewed-by: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev
> *asd) {
> #if IS_ENABLED(CONFIG_I2C)
> @@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct
> v4l2_async_notifier *notifier, {
> int ret;
>
> - if (notifier->ops->bound) {
> - ret = notifier->ops->bound(notifier, sd, asd);
> - if (ret < 0)
> - return ret;
> - }
> + ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> + if (ret < 0)
> + return ret;
>
> ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> if (ret < 0) {
> - if (notifier->ops->unbind)
> - notifier->ops->unbind(notifier, sd, asd);
> + v4l2_async_notifier_call_unbind(notifier, sd, asd);
> return ret;
> }
>
> @@ -123,8 +148,8 @@ 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, ¬ifier->done);
>
> - if (list_empty(¬ifier->waiting) && notifier->ops->complete)
> - return notifier->ops->complete(notifier);
> + if (list_empty(¬ifier->waiting))
> + return v4l2_async_notifier_call_complete(notifier);
>
> return 0;
> }
> @@ -210,8 +235,7 @@ void v4l2_async_notifier_unregister(struct
> v4l2_async_notifier *notifier) list_for_each_entry_safe(sd, tmp,
> ¬ifier->done, async_list) { v4l2_async_cleanup(sd);
>
> - if (notifier->ops->unbind)
> - notifier->ops->unbind(notifier, sd, sd->asd);
> + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> }
>
> mutex_unlock(&list_lock);
> @@ -300,8 +324,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev
> *sd)
>
> v4l2_async_cleanup(sd);
>
> - if (notifier->ops->unbind)
> - notifier->ops->unbind(notifier, sd, sd->asd);
> + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>
> mutex_unlock(&list_lock);
> }
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 3c48f8b66d12..3bc8a7c0d83f 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -164,4 +164,5 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd);
> * @sd: pointer to &struct v4l2_subdev
> */
> void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
> +
> #endif
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
@ 2017-09-19 12:01 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 12:01 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> Add three helper functions to call async operations callbacks. Besides
> simplifying callbacks, this allows async notifiers to have no ops set,
> i.e. it can be left NULL.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++++++++--------
> include/media/v4l2-async.h | 1 +
> 2 files changed, 37 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> b/drivers/media/v4l2-core/v4l2-async.c index 7b2125b3d62f..c35d04b9122f
> 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -25,6 +25,34 @@
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-subdev.h>
>
> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
> + struct v4l2_subdev *subdev,
> + struct v4l2_async_subdev *asd)
> +{
> + if (!n->ops || !n->ops->bound)
> + return 0;
> +
> + return n->ops->bound(n, subdev, asd);
> +}
> +
> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
> + struct v4l2_subdev *subdev,
> + struct v4l2_async_subdev *asd)
> +{
> + if (!n->ops || !n->ops->unbind)
> + return;
> +
> + n->ops->unbind(n, subdev, asd);
> +}
> +
> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
> +{
> + if (!n->ops || !n->ops->complete)
> + return 0;
> +
> + return n->ops->complete(n);
> +}
> +
Wouldn't it be enough to add a single v4l2_async_notifier_call() macro ?
#define v4l2_async_notifier_call(n, op, args...) \
((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
Apart from that,
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev
> *asd) {
> #if IS_ENABLED(CONFIG_I2C)
> @@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct
> v4l2_async_notifier *notifier, {
> int ret;
>
> - if (notifier->ops->bound) {
> - ret = notifier->ops->bound(notifier, sd, asd);
> - if (ret < 0)
> - return ret;
> - }
> + ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> + if (ret < 0)
> + return ret;
>
> ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> if (ret < 0) {
> - if (notifier->ops->unbind)
> - notifier->ops->unbind(notifier, sd, asd);
> + v4l2_async_notifier_call_unbind(notifier, sd, asd);
> return ret;
> }
>
> @@ -123,8 +148,8 @@ 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, ¬ifier->done);
>
> - if (list_empty(¬ifier->waiting) && notifier->ops->complete)
> - return notifier->ops->complete(notifier);
> + if (list_empty(¬ifier->waiting))
> + return v4l2_async_notifier_call_complete(notifier);
>
> return 0;
> }
> @@ -210,8 +235,7 @@ void v4l2_async_notifier_unregister(struct
> v4l2_async_notifier *notifier) list_for_each_entry_safe(sd, tmp,
> ¬ifier->done, async_list) { v4l2_async_cleanup(sd);
>
> - if (notifier->ops->unbind)
> - notifier->ops->unbind(notifier, sd, sd->asd);
> + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> }
>
> mutex_unlock(&list_lock);
> @@ -300,8 +324,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev
> *sd)
>
> v4l2_async_cleanup(sd);
>
> - if (notifier->ops->unbind)
> - notifier->ops->unbind(notifier, sd, sd->asd);
> + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>
> mutex_unlock(&list_lock);
> }
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 3c48f8b66d12..3bc8a7c0d83f 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -164,4 +164,5 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd);
> * @sd: pointer to &struct v4l2_subdev
> */
> void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
> +
> #endif
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-19 12:01 ` Laurent Pinchart
(?)
@ 2017-09-19 12:13 ` Sakari Ailus
2017-09-19 12:43 ` Laurent Pinchart
-1 siblings, 1 reply; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 12:13 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> > Add three helper functions to call async operations callbacks. Besides
> > simplifying callbacks, this allows async notifiers to have no ops set,
> > i.e. it can be left NULL.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > ---
> > drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++++++++--------
> > include/media/v4l2-async.h | 1 +
> > 2 files changed, 37 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c
> > b/drivers/media/v4l2-core/v4l2-async.c index 7b2125b3d62f..c35d04b9122f
> > 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -25,6 +25,34 @@
> > #include <media/v4l2-fwnode.h>
> > #include <media/v4l2-subdev.h>
> >
> > +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
> > + struct v4l2_subdev *subdev,
> > + struct v4l2_async_subdev *asd)
> > +{
> > + if (!n->ops || !n->ops->bound)
> > + return 0;
> > +
> > + return n->ops->bound(n, subdev, asd);
> > +}
> > +
> > +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
> > + struct v4l2_subdev *subdev,
> > + struct v4l2_async_subdev *asd)
> > +{
> > + if (!n->ops || !n->ops->unbind)
> > + return;
> > +
> > + n->ops->unbind(n, subdev, asd);
> > +}
> > +
> > +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
> > +{
> > + if (!n->ops || !n->ops->complete)
> > + return 0;
> > +
> > + return n->ops->complete(n);
> > +}
> > +
>
> Wouldn't it be enough to add a single v4l2_async_notifier_call() macro ?
>
> #define v4l2_async_notifier_call(n, op, args...) \
> ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
I actually had that in an earlier version but I changed it based on review
comments from Hans. A single macro isn't enough: some functions have int
return type. I think the way it is now is nicer.
>
> Apart from that,
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> > static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev
> > *asd) {
> > #if IS_ENABLED(CONFIG_I2C)
> > @@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct
> > v4l2_async_notifier *notifier, {
> > int ret;
> >
> > - if (notifier->ops->bound) {
> > - ret = notifier->ops->bound(notifier, sd, asd);
> > - if (ret < 0)
> > - return ret;
> > - }
> > + ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> > + if (ret < 0)
> > + return ret;
> >
> > ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> > if (ret < 0) {
> > - if (notifier->ops->unbind)
> > - notifier->ops->unbind(notifier, sd, asd);
> > + v4l2_async_notifier_call_unbind(notifier, sd, asd);
> > return ret;
> > }
> >
> > @@ -123,8 +148,8 @@ 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, ¬ifier->done);
> >
> > - if (list_empty(¬ifier->waiting) && notifier->ops->complete)
> > - return notifier->ops->complete(notifier);
> > + if (list_empty(¬ifier->waiting))
> > + return v4l2_async_notifier_call_complete(notifier);
> >
> > return 0;
> > }
> > @@ -210,8 +235,7 @@ void v4l2_async_notifier_unregister(struct
> > v4l2_async_notifier *notifier) list_for_each_entry_safe(sd, tmp,
> > ¬ifier->done, async_list) { v4l2_async_cleanup(sd);
> >
> > - if (notifier->ops->unbind)
> > - notifier->ops->unbind(notifier, sd, sd->asd);
> > + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> > }
> >
> > mutex_unlock(&list_lock);
> > @@ -300,8 +324,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev
> > *sd)
> >
> > v4l2_async_cleanup(sd);
> >
> > - if (notifier->ops->unbind)
> > - notifier->ops->unbind(notifier, sd, sd->asd);
> > + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> >
> > mutex_unlock(&list_lock);
> > }
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 3c48f8b66d12..3bc8a7c0d83f 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -164,4 +164,5 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd);
> > * @sd: pointer to &struct v4l2_subdev
> > */
> > void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
> > +
> > #endif
>
>
> --
> Regards,
>
> Laurent Pinchart
>
--
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-19 12:13 ` Sakari Ailus
@ 2017-09-19 12:43 ` Laurent Pinchart
2017-09-19 14:50 ` Sakari Ailus
0 siblings, 1 reply; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 12:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
On Tuesday, 19 September 2017 15:13:11 EEST Sakari Ailus wrote:
> On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> > On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> >> Add three helper functions to call async operations callbacks. Besides
> >> simplifying callbacks, this allows async notifiers to have no ops set,
> >> i.e. it can be left NULL.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> ---
> >>
> >> drivers/media/v4l2-core/v4l2-async.c | 49 +++++++++++++++++++++--------
> >> include/media/v4l2-async.h | 1 +
> >> 2 files changed, 37 insertions(+), 13 deletions(-)
> >>
> >> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> >> b/drivers/media/v4l2-core/v4l2-async.c index 7b2125b3d62f..c35d04b9122f
> >> 100644
> >> --- a/drivers/media/v4l2-core/v4l2-async.c
> >> +++ b/drivers/media/v4l2-core/v4l2-async.c
> >> @@ -25,6 +25,34 @@
> >>
> >> #include <media/v4l2-fwnode.h>
> >> #include <media/v4l2-subdev.h>
> >>
> >> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier
> >> *n,
> >> + struct v4l2_subdev *subdev,
> >> + struct v4l2_async_subdev *asd)
> >> +{
> >> + if (!n->ops || !n->ops->bound)
> >> + return 0;
> >> +
> >> + return n->ops->bound(n, subdev, asd);
> >> +}
> >> +
> >> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier
> >> *n,
> >> + struct v4l2_subdev *subdev,
> >> + struct v4l2_async_subdev *asd)
> >> +{
> >> + if (!n->ops || !n->ops->unbind)
> >> + return;
> >> +
> >> + n->ops->unbind(n, subdev, asd);
> >> +}
> >> +
> >> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier
> >> *n)
> >> +{
> >> + if (!n->ops || !n->ops->complete)
> >> + return 0;
> >> +
> >> + return n->ops->complete(n);
> >> +}
> >> +
> >
> > Wouldn't it be enough to add a single v4l2_async_notifier_call() macro ?
> >
> > #define v4l2_async_notifier_call(n, op, args...) \
> >
> > ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
>
> I actually had that in an earlier version but I changed it based on review
> comments from Hans. A single macro isn't enough: some functions have int
> return type. I think the way it is now is nicer.
What bothers me there is the overhead of a function call.
By the way, what's the use case for ops being NULL ?
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-19 12:43 ` Laurent Pinchart
@ 2017-09-19 14:50 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 14:50 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Laurent,
On Tue, Sep 19, 2017 at 03:43:48PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tuesday, 19 September 2017 15:13:11 EEST Sakari Ailus wrote:
> > On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> > > On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> > >> Add three helper functions to call async operations callbacks. Besides
> > >> simplifying callbacks, this allows async notifiers to have no ops set,
> > >> i.e. it can be left NULL.
> > >>
> > >> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> > >> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> > >> ---
> > >>
> > >> drivers/media/v4l2-core/v4l2-async.c | 49 +++++++++++++++++++++--------
> > >> include/media/v4l2-async.h | 1 +
> > >> 2 files changed, 37 insertions(+), 13 deletions(-)
> > >>
> > >> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> > >> b/drivers/media/v4l2-core/v4l2-async.c index 7b2125b3d62f..c35d04b9122f
> > >> 100644
> > >> --- a/drivers/media/v4l2-core/v4l2-async.c
> > >> +++ b/drivers/media/v4l2-core/v4l2-async.c
> > >> @@ -25,6 +25,34 @@
> > >>
> > >> #include <media/v4l2-fwnode.h>
> > >> #include <media/v4l2-subdev.h>
> > >>
> > >> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier
> > >> *n,
> > >> + struct v4l2_subdev *subdev,
> > >> + struct v4l2_async_subdev *asd)
> > >> +{
> > >> + if (!n->ops || !n->ops->bound)
> > >> + return 0;
> > >> +
> > >> + return n->ops->bound(n, subdev, asd);
> > >> +}
> > >> +
> > >> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier
> > >> *n,
> > >> + struct v4l2_subdev *subdev,
> > >> + struct v4l2_async_subdev *asd)
> > >> +{
> > >> + if (!n->ops || !n->ops->unbind)
> > >> + return;
> > >> +
> > >> + n->ops->unbind(n, subdev, asd);
> > >> +}
> > >> +
> > >> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier
> > >> *n)
> > >> +{
> > >> + if (!n->ops || !n->ops->complete)
> > >> + return 0;
> > >> +
> > >> + return n->ops->complete(n);
> > >> +}
> > >> +
> > >
> > > Wouldn't it be enough to add a single v4l2_async_notifier_call() macro ?
> > >
> > > #define v4l2_async_notifier_call(n, op, args...) \
> > >
> > > ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
> >
> > I actually had that in an earlier version but I changed it based on review
> > comments from Hans. A single macro isn't enough: some functions have int
> > return type. I think the way it is now is nicer.
>
> What bothers me there is the overhead of a function call.
Overhead... of a function call?
Do you really mean what you're saying? :-) The functions will be called a
relatively small number of times during module loading / device probing.
>
> By the way, what's the use case for ops being NULL ?
If a driver has no need for any of the callbacks, there's no benefit from
having to set ops struct either. This applies to devices that are
associated to the sensor, for instance.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
@ 2017-09-19 14:50 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 14:50 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 03:43:48PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tuesday, 19 September 2017 15:13:11 EEST Sakari Ailus wrote:
> > On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> > > On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> > >> Add three helper functions to call async operations callbacks. Besides
> > >> simplifying callbacks, this allows async notifiers to have no ops set,
> > >> i.e. it can be left NULL.
> > >>
> > >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > >> ---
> > >>
> > >> drivers/media/v4l2-core/v4l2-async.c | 49 +++++++++++++++++++++--------
> > >> include/media/v4l2-async.h | 1 +
> > >> 2 files changed, 37 insertions(+), 13 deletions(-)
> > >>
> > >> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> > >> b/drivers/media/v4l2-core/v4l2-async.c index 7b2125b3d62f..c35d04b9122f
> > >> 100644
> > >> --- a/drivers/media/v4l2-core/v4l2-async.c
> > >> +++ b/drivers/media/v4l2-core/v4l2-async.c
> > >> @@ -25,6 +25,34 @@
> > >>
> > >> #include <media/v4l2-fwnode.h>
> > >> #include <media/v4l2-subdev.h>
> > >>
> > >> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier
> > >> *n,
> > >> + struct v4l2_subdev *subdev,
> > >> + struct v4l2_async_subdev *asd)
> > >> +{
> > >> + if (!n->ops || !n->ops->bound)
> > >> + return 0;
> > >> +
> > >> + return n->ops->bound(n, subdev, asd);
> > >> +}
> > >> +
> > >> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier
> > >> *n,
> > >> + struct v4l2_subdev *subdev,
> > >> + struct v4l2_async_subdev *asd)
> > >> +{
> > >> + if (!n->ops || !n->ops->unbind)
> > >> + return;
> > >> +
> > >> + n->ops->unbind(n, subdev, asd);
> > >> +}
> > >> +
> > >> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier
> > >> *n)
> > >> +{
> > >> + if (!n->ops || !n->ops->complete)
> > >> + return 0;
> > >> +
> > >> + return n->ops->complete(n);
> > >> +}
> > >> +
> > >
> > > Wouldn't it be enough to add a single v4l2_async_notifier_call() macro ?
> > >
> > > #define v4l2_async_notifier_call(n, op, args...) \
> > >
> > > ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
> >
> > I actually had that in an earlier version but I changed it based on review
> > comments from Hans. A single macro isn't enough: some functions have int
> > return type. I think the way it is now is nicer.
>
> What bothers me there is the overhead of a function call.
Overhead... of a function call?
Do you really mean what you're saying? :-) The functions will be called a
relatively small number of times during module loading / device probing.
>
> By the way, what's the use case for ops being NULL ?
If a driver has no need for any of the callbacks, there's no benefit from
having to set ops struct either. This applies to devices that are
associated to the sensor, for instance.
--
Regards,
Sakari Ailus
e-mail: sakari.ailus@iki.fi
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-19 14:50 ` Sakari Ailus
(?)
@ 2017-09-19 16:27 ` Laurent Pinchart
2017-09-20 15:54 ` Sakari Ailus
-1 siblings, 1 reply; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 16:27 UTC (permalink / raw)
To: Sakari Ailus
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Sakari,
On Tuesday, 19 September 2017 17:50:49 EEST Sakari Ailus wrote:
> On Tue, Sep 19, 2017 at 03:43:48PM +0300, Laurent Pinchart wrote:
> > On Tuesday, 19 September 2017 15:13:11 EEST Sakari Ailus wrote:
> >> On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> >>> On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> >>>> Add three helper functions to call async operations callbacks.
> >>>> Besides simplifying callbacks, this allows async notifiers to have no
> >>>> ops set, i.e. it can be left NULL.
> >>>>
> >>>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >>>> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> >>>> ---
> >>>>
> >>>> drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++--------
> >>>> include/media/v4l2-async.h | 1 +
> >>>> 2 files changed, 37 insertions(+), 13 deletions(-)
> >>>>
> >>>> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> >>>> b/drivers/media/v4l2-core/v4l2-async.c index
> >>>> 7b2125b3d62f..c35d04b9122f
> >>>> 100644
> >>>> --- a/drivers/media/v4l2-core/v4l2-async.c
> >>>> +++ b/drivers/media/v4l2-core/v4l2-async.c
> >>>> @@ -25,6 +25,34 @@
> >>>>
> >>>> #include <media/v4l2-fwnode.h>
> >>>> #include <media/v4l2-subdev.h>
> >>>>
> >>>> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier
> >>>> *n,
> >>>> + struct v4l2_subdev *subdev,
> >>>> + struct v4l2_async_subdev *asd)
> >>>> +{
> >>>> + if (!n->ops || !n->ops->bound)
> >>>> + return 0;
> >>>> +
> >>>> + return n->ops->bound(n, subdev, asd);
> >>>> +}
> >>>> +
> >>>> +static void v4l2_async_notifier_call_unbind(struct
> >>>> v4l2_async_notifier
> >>>> *n,
> >>>> + struct v4l2_subdev *subdev,
> >>>> + struct v4l2_async_subdev *asd)
> >>>> +{
> >>>> + if (!n->ops || !n->ops->unbind)
> >>>> + return;
> >>>> +
> >>>> + n->ops->unbind(n, subdev, asd);
> >>>> +}
> >>>> +
> >>>> +static int v4l2_async_notifier_call_complete(struct
> >>>> v4l2_async_notifier
> >>>> *n)
> >>>> +{
> >>>> + if (!n->ops || !n->ops->complete)
> >>>> + return 0;
> >>>> +
> >>>> + return n->ops->complete(n);
> >>>> +}
> >>>> +
> >>>
> >>> Wouldn't it be enough to add a single v4l2_async_notifier_call() macro
> >>> ?
> >>>
> >>> #define v4l2_async_notifier_call(n, op, args...) \
> >>>
> >>> ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
> >>
> >> I actually had that in an earlier version but I changed it based on
> >> review comments from Hans. A single macro isn't enough: some functions
> >> have int return type. I think the way it is now is nicer.
> >
> > What bothers me there is the overhead of a function call.
>
> Overhead... of a function call?
>
> Do you really mean what you're saying? :-) The functions will be called a
> relatively small number of times during module loading / device probing.
That's why I haven't said it's a big deal :-) There's of course no need to
optimize that if the tradeoff is large, but if all operations had the same
return type a macro could have been useful (although in this very specific
case I'm more concerned about code size than about CPU cycles).
> > By the way, what's the use case for ops being NULL ?
>
> If a driver has no need for any of the callbacks, there's no benefit from
> having to set ops struct either. This applies to devices that are
> associated to the sensor, for instance.
So in that case the subdev notifier is only registered to delay the complete()
callback until the flash and lens controllers are available, with the sensor
itself having no need to access the flash and lens controllers ?
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
2017-09-19 16:27 ` Laurent Pinchart
@ 2017-09-20 15:54 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-20 15:54 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Laurent,
On Tue, Sep 19, 2017 at 07:27:17PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tuesday, 19 September 2017 17:50:49 EEST Sakari Ailus wrote:
> > On Tue, Sep 19, 2017 at 03:43:48PM +0300, Laurent Pinchart wrote:
> > > On Tuesday, 19 September 2017 15:13:11 EEST Sakari Ailus wrote:
> > >> On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> > >>> On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> > >>>> Add three helper functions to call async operations callbacks.
> > >>>> Besides simplifying callbacks, this allows async notifiers to have no
> > >>>> ops set, i.e. it can be left NULL.
> > >>>>
> > >>>> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> > >>>> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> > >>>> ---
> > >>>>
> > >>>> drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++--------
> > >>>> include/media/v4l2-async.h | 1 +
> > >>>> 2 files changed, 37 insertions(+), 13 deletions(-)
> > >>>>
> > >>>> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> > >>>> b/drivers/media/v4l2-core/v4l2-async.c index
> > >>>> 7b2125b3d62f..c35d04b9122f
> > >>>> 100644
> > >>>> --- a/drivers/media/v4l2-core/v4l2-async.c
> > >>>> +++ b/drivers/media/v4l2-core/v4l2-async.c
> > >>>> @@ -25,6 +25,34 @@
> > >>>>
> > >>>> #include <media/v4l2-fwnode.h>
> > >>>> #include <media/v4l2-subdev.h>
> > >>>>
> > >>>> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier
> > >>>> *n,
> > >>>> + struct v4l2_subdev *subdev,
> > >>>> + struct v4l2_async_subdev *asd)
> > >>>> +{
> > >>>> + if (!n->ops || !n->ops->bound)
> > >>>> + return 0;
> > >>>> +
> > >>>> + return n->ops->bound(n, subdev, asd);
> > >>>> +}
> > >>>> +
> > >>>> +static void v4l2_async_notifier_call_unbind(struct
> > >>>> v4l2_async_notifier
> > >>>> *n,
> > >>>> + struct v4l2_subdev *subdev,
> > >>>> + struct v4l2_async_subdev *asd)
> > >>>> +{
> > >>>> + if (!n->ops || !n->ops->unbind)
> > >>>> + return;
> > >>>> +
> > >>>> + n->ops->unbind(n, subdev, asd);
> > >>>> +}
> > >>>> +
> > >>>> +static int v4l2_async_notifier_call_complete(struct
> > >>>> v4l2_async_notifier
> > >>>> *n)
> > >>>> +{
> > >>>> + if (!n->ops || !n->ops->complete)
> > >>>> + return 0;
> > >>>> +
> > >>>> + return n->ops->complete(n);
> > >>>> +}
> > >>>> +
> > >>>
> > >>> Wouldn't it be enough to add a single v4l2_async_notifier_call() macro
> > >>> ?
> > >>>
> > >>> #define v4l2_async_notifier_call(n, op, args...) \
> > >>>
> > >>> ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
> > >>
> > >> I actually had that in an earlier version but I changed it based on
> > >> review comments from Hans. A single macro isn't enough: some functions
> > >> have int return type. I think the way it is now is nicer.
> > >
> > > What bothers me there is the overhead of a function call.
> >
> > Overhead... of a function call?
> >
> > Do you really mean what you're saying? :-) The functions will be called a
> > relatively small number of times during module loading / device probing.
>
> That's why I haven't said it's a big deal :-) There's of course no need to
> optimize that if the tradeoff is large, but if all operations had the same
> return type a macro could have been useful (although in this very specific
> case I'm more concerned about code size than about CPU cycles).
Code size in the async framework? Generally calling a function doesn't take
a lot of code, and the kernel is, well, full of function calls. I'm frankly
more concerned about the number of lines of code to maintain and
readability of that code.
>
> > > By the way, what's the use case for ops being NULL ?
> >
> > If a driver has no need for any of the callbacks, there's no benefit from
> > having to set ops struct either. This applies to devices that are
> > associated to the sensor, for instance.
>
> So in that case the subdev notifier is only registered to delay the complete()
> callback until the flash and lens controllers are available, with the sensor
> itself having no need to access the flash and lens controllers ?
Essentially yes. In the future we'll need to make use of the association
information to tell which devices are related but this shouldn't be a job
for individual drivers.
--
Regards,
Sakari Ailus
sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 11/25] v4l: async: Introduce helpers for calling async ops callbacks
@ 2017-09-20 15:54 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-20 15:54 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 07:27:17PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tuesday, 19 September 2017 17:50:49 EEST Sakari Ailus wrote:
> > On Tue, Sep 19, 2017 at 03:43:48PM +0300, Laurent Pinchart wrote:
> > > On Tuesday, 19 September 2017 15:13:11 EEST Sakari Ailus wrote:
> > >> On Tue, Sep 19, 2017 at 03:01:14PM +0300, Laurent Pinchart wrote:
> > >>> On Friday, 15 September 2017 17:17:10 EEST Sakari Ailus wrote:
> > >>>> Add three helper functions to call async operations callbacks.
> > >>>> Besides simplifying callbacks, this allows async notifiers to have no
> > >>>> ops set, i.e. it can be left NULL.
> > >>>>
> > >>>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >>>> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > >>>> ---
> > >>>>
> > >>>> drivers/media/v4l2-core/v4l2-async.c | 49 ++++++++++++++++++--------
> > >>>> include/media/v4l2-async.h | 1 +
> > >>>> 2 files changed, 37 insertions(+), 13 deletions(-)
> > >>>>
> > >>>> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> > >>>> b/drivers/media/v4l2-core/v4l2-async.c index
> > >>>> 7b2125b3d62f..c35d04b9122f
> > >>>> 100644
> > >>>> --- a/drivers/media/v4l2-core/v4l2-async.c
> > >>>> +++ b/drivers/media/v4l2-core/v4l2-async.c
> > >>>> @@ -25,6 +25,34 @@
> > >>>>
> > >>>> #include <media/v4l2-fwnode.h>
> > >>>> #include <media/v4l2-subdev.h>
> > >>>>
> > >>>> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier
> > >>>> *n,
> > >>>> + struct v4l2_subdev *subdev,
> > >>>> + struct v4l2_async_subdev *asd)
> > >>>> +{
> > >>>> + if (!n->ops || !n->ops->bound)
> > >>>> + return 0;
> > >>>> +
> > >>>> + return n->ops->bound(n, subdev, asd);
> > >>>> +}
> > >>>> +
> > >>>> +static void v4l2_async_notifier_call_unbind(struct
> > >>>> v4l2_async_notifier
> > >>>> *n,
> > >>>> + struct v4l2_subdev *subdev,
> > >>>> + struct v4l2_async_subdev *asd)
> > >>>> +{
> > >>>> + if (!n->ops || !n->ops->unbind)
> > >>>> + return;
> > >>>> +
> > >>>> + n->ops->unbind(n, subdev, asd);
> > >>>> +}
> > >>>> +
> > >>>> +static int v4l2_async_notifier_call_complete(struct
> > >>>> v4l2_async_notifier
> > >>>> *n)
> > >>>> +{
> > >>>> + if (!n->ops || !n->ops->complete)
> > >>>> + return 0;
> > >>>> +
> > >>>> + return n->ops->complete(n);
> > >>>> +}
> > >>>> +
> > >>>
> > >>> Wouldn't it be enough to add a single v4l2_async_notifier_call() macro
> > >>> ?
> > >>>
> > >>> #define v4l2_async_notifier_call(n, op, args...) \
> > >>>
> > >>> ((n)->ops && (n)->ops->op ? (n)->ops->op(n, ##args) : 0)
> > >>
> > >> I actually had that in an earlier version but I changed it based on
> > >> review comments from Hans. A single macro isn't enough: some functions
> > >> have int return type. I think the way it is now is nicer.
> > >
> > > What bothers me there is the overhead of a function call.
> >
> > Overhead... of a function call?
> >
> > Do you really mean what you're saying? :-) The functions will be called a
> > relatively small number of times during module loading / device probing.
>
> That's why I haven't said it's a big deal :-) There's of course no need to
> optimize that if the tradeoff is large, but if all operations had the same
> return type a macro could have been useful (although in this very specific
> case I'm more concerned about code size than about CPU cycles).
Code size in the async framework? Generally calling a function doesn't take
a lot of code, and the kernel is, well, full of function calls. I'm frankly
more concerned about the number of lines of code to maintain and
readability of that code.
>
> > > By the way, what's the use case for ops being NULL ?
> >
> > If a driver has no need for any of the callbacks, there's no benefit from
> > having to set ops struct either. This applies to devices that are
> > associated to the sensor, for instance.
>
> So in that case the subdev notifier is only registered to delay the complete()
> callback until the flash and lens controllers are available, with the sensor
> itself having no need to access the flash and lens controllers ?
Essentially yes. In the future we'll need to make use of the association
information to tell which devices are related but this shouldn't be a job
for individual drivers.
--
Regards,
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/media/v4l2-core/v4l2-async.c | 218 ++++++++++++++++++++++++++++++-----
include/media/v4l2-async.h | 16 ++-
2 files changed, 203 insertions(+), 31 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 4be2f16af051..52fe22b9b6b4 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,127 @@ 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, ¬ifier_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(¬ifier->waiting))
+ return false;
+
+ list_for_each_entry(sd, ¬ifier->done, async_list) {
+ struct v4l2_async_notifier *subdev_notifier =
+ v4l2_async_find_subdev_notifier(sd);
+
+ if (subdev_notifier &&
+ !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(¬ifier->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.
+ */
+ notifier = notifier->parent;
+ } while (notifier);
+
+ 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 +265,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, ¬ifier->done);
- if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
INIT_LIST_HEAD(¬ifier->done);
@@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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(¬ifier->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
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
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 | 218 ++++++++++++++++++++++++++++++-----
include/media/v4l2-async.h | 16 ++-
2 files changed, 203 insertions(+), 31 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 4be2f16af051..52fe22b9b6b4 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,127 @@ 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, ¬ifier_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(¬ifier->waiting))
+ return false;
+
+ list_for_each_entry(sd, ¬ifier->done, async_list) {
+ struct v4l2_async_notifier *subdev_notifier =
+ v4l2_async_find_subdev_notifier(sd);
+
+ if (subdev_notifier &&
+ !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(¬ifier->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.
+ */
+ notifier = notifier->parent;
+ } while (notifier);
+
+ 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 +265,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, ¬ifier->done);
- if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
INIT_LIST_HEAD(¬ifier->done);
@@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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(¬ifier->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
^ permalink raw reply related [flat|nested] 137+ messages in thread
[parent not found: <20170915141724.23124-15-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>]
* Re: [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-19 8:06 ` Hans Verkuil
-1 siblings, 0 replies; 137+ messages in thread
From: Hans Verkuil @ 2017-09-19 8:06 UTC (permalink / raw)
To: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
On 09/15/2017 04:17 PM, Sakari Ailus wrote:
> 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Regards,
Hans
> ---
> drivers/media/v4l2-core/v4l2-async.c | 218 ++++++++++++++++++++++++++++++-----
> include/media/v4l2-async.h | 16 ++-
> 2 files changed, 203 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 4be2f16af051..52fe22b9b6b4 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,127 @@ 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, ¬ifier_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(¬ifier->waiting))
> + return false;
> +
> + list_for_each_entry(sd, ¬ifier->done, async_list) {
> + struct v4l2_async_notifier *subdev_notifier =
> + v4l2_async_find_subdev_notifier(sd);
> +
> + if (subdev_notifier &&
> + !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(¬ifier->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.
> + */
> + notifier = notifier->parent;
> + } while (notifier);
> +
> + 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 +265,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, ¬ifier->done);
>
> - if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
> INIT_LIST_HEAD(¬ifier->done);
>
> @@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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(¬ifier->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
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
@ 2017-09-19 8:06 ` Hans Verkuil
0 siblings, 0 replies; 137+ messages in thread
From: Hans Verkuil @ 2017-09-19 8:06 UTC (permalink / raw)
To: Sakari Ailus, linux-media
Cc: niklas.soderlund, maxime.ripard, robh, laurent.pinchart,
devicetree, pavel, sre
On 09/15/2017 04:17 PM, Sakari Ailus wrote:
> 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>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Regards,
Hans
> ---
> drivers/media/v4l2-core/v4l2-async.c | 218 ++++++++++++++++++++++++++++++-----
> include/media/v4l2-async.h | 16 ++-
> 2 files changed, 203 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 4be2f16af051..52fe22b9b6b4 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,127 @@ 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, ¬ifier_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(¬ifier->waiting))
> + return false;
> +
> + list_for_each_entry(sd, ¬ifier->done, async_list) {
> + struct v4l2_async_notifier *subdev_notifier =
> + v4l2_async_find_subdev_notifier(sd);
> +
> + if (subdev_notifier &&
> + !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(¬ifier->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.
> + */
> + notifier = notifier->parent;
> + } while (notifier);
> +
> + 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 +265,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, ¬ifier->done);
>
> - if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
> INIT_LIST_HEAD(¬ifier->done);
>
> @@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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(¬ifier->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
>
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-19 13:52 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 13:52 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:13 EEST Sakari Ailus wrote:
> 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.
This is a bit hard to review, shouldn't it be split in two patches, one that
refactors the functions, and another one that allows binding notifiers to
subdevs ?
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 218 +++++++++++++++++++++++++++-----
> include/media/v4l2-async.h | 16 ++-
> 2 files changed, 203 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> b/drivers/media/v4l2-core/v4l2-async.c index 4be2f16af051..52fe22b9b6b4
> 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);
Forward declarations are often a sign that something is wrong :-/ If you
really need to keep this I'd move it right before the function that needs it.
> static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev
> *asd) {
> #if IS_ENABLED(CONFIG_I2C)
> @@ -124,14 +128,127 @@ 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, ¬ifier_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(¬ifier->waiting))
> + return false;
> +
> + list_for_each_entry(sd, ¬ifier->done, async_list) {
> + struct v4l2_async_notifier *subdev_notifier =
> + v4l2_async_find_subdev_notifier(sd);
> +
> + if (subdev_notifier &&
> + !v4l2_async_subdev_notifiers_complete(subdev_notifier))
> + return false;
This will loop forever if two subdevs add each other to their respective
notifiers. We might not have any use case for that right now, but it's bound
to happen, at least as a bug during development, and an infinite loop (with an
additional stack overflow bonus) isn't very nice to debug.
> + }
> +
> + 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(¬ifier->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.
> + */
> + notifier = notifier->parent;
> + } while (notifier);
> +
> + 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 +265,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, ¬ifier->done);
>
> - if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
> INIT_LIST_HEAD(¬ifier->done);
>
> @@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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);
How about list_move() ?
This seems to be new code, and by the look of it, I wonder whether it doesn't
belong in the reprobing removal patch.
> + }
>
> + 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(¬ifier->list);
> +
> + mutex_unlock(&list_lock);
> +}
> EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>
> void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
[snip]
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
@ 2017-09-19 13:52 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 13:52 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:13 EEST Sakari Ailus wrote:
> 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.
This is a bit hard to review, shouldn't it be split in two patches, one that
refactors the functions, and another one that allows binding notifiers to
subdevs ?
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 218 +++++++++++++++++++++++++++-----
> include/media/v4l2-async.h | 16 ++-
> 2 files changed, 203 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> b/drivers/media/v4l2-core/v4l2-async.c index 4be2f16af051..52fe22b9b6b4
> 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);
Forward declarations are often a sign that something is wrong :-/ If you
really need to keep this I'd move it right before the function that needs it.
> static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev
> *asd) {
> #if IS_ENABLED(CONFIG_I2C)
> @@ -124,14 +128,127 @@ 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, ¬ifier_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(¬ifier->waiting))
> + return false;
> +
> + list_for_each_entry(sd, ¬ifier->done, async_list) {
> + struct v4l2_async_notifier *subdev_notifier =
> + v4l2_async_find_subdev_notifier(sd);
> +
> + if (subdev_notifier &&
> + !v4l2_async_subdev_notifiers_complete(subdev_notifier))
> + return false;
This will loop forever if two subdevs add each other to their respective
notifiers. We might not have any use case for that right now, but it's bound
to happen, at least as a bug during development, and an infinite loop (with an
additional stack overflow bonus) isn't very nice to debug.
> + }
> +
> + 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(¬ifier->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.
> + */
> + notifier = notifier->parent;
> + } while (notifier);
> +
> + 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 +265,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, ¬ifier->done);
>
> - if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
> INIT_LIST_HEAD(¬ifier->done);
>
> @@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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);
How about list_move() ?
This seems to be new code, and by the look of it, I wonder whether it doesn't
belong in the reprobing removal patch.
> + }
>
> + 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(¬ifier->list);
> +
> + mutex_unlock(&list_lock);
> +}
> EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>
> void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
[snip]
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 14/25] v4l: async: Allow binding notifiers to sub-devices
2017-09-19 13:52 ` Laurent Pinchart
(?)
@ 2017-09-19 15:17 ` Sakari Ailus
[not found] ` <20170919151732.4yafxfcxrreizd7r-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
-1 siblings, 1 reply; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 15:17 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard, robh,
hverkuil, devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 04:52:29PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:13 EEST Sakari Ailus wrote:
> > 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.
>
> This is a bit hard to review, shouldn't it be split in two patches, one that
> refactors the functions, and another one that allows binding notifiers to
> subdevs ?
>
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> > drivers/media/v4l2-core/v4l2-async.c | 218 +++++++++++++++++++++++++++-----
> > include/media/v4l2-async.h | 16 ++-
> > 2 files changed, 203 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c
> > b/drivers/media/v4l2-core/v4l2-async.c index 4be2f16af051..52fe22b9b6b4
> > 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);
>
> Forward declarations are often a sign that something is wrong :-/ If you
> really need to keep this I'd move it right before the function that needs it.
"Something being wrong" here is that we have a data structure (the graph)
and a portion of the graph is parsed at any given point of time; there is
no central location with the knowledge of each node in the graph. Therefore
the process is recursive: you only learn of new nodes to parse when you
have parsed something.
I can move the declaration closer to where it's used.
>
> > static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev
> > *asd) {
> > #if IS_ENABLED(CONFIG_I2C)
> > @@ -124,14 +128,127 @@ 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, ¬ifier_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(¬ifier->waiting))
> > + return false;
> > +
> > + list_for_each_entry(sd, ¬ifier->done, async_list) {
> > + struct v4l2_async_notifier *subdev_notifier =
> > + v4l2_async_find_subdev_notifier(sd);
> > +
> > + if (subdev_notifier &&
> > + !v4l2_async_subdev_notifiers_complete(subdev_notifier))
> > + return false;
>
> This will loop forever if two subdevs add each other to their respective
> notifiers. We might not have any use case for that right now, but it's bound
> to happen, at least as a bug during development, and an infinite loop (with an
> additional stack overflow bonus) isn't very nice to debug.
Well, yes. If you have a driver bug then this is what could happen.
One option is to check whether an fwnode has already been associated with
an async subdev and fail if it is. I was originally thinking of adding that
but then ended up postponing that for later. I can add that to v14.
>
> > + }
> > +
> > + 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(¬ifier->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.
> > + */
> > + notifier = notifier->parent;
> > + } while (notifier);
> > +
> > + 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 +265,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, ¬ifier->done);
> >
> > - if (list_empty(¬ifier->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 +290,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(¬ifier->waiting);
> > INIT_LIST_HEAD(¬ifier->done);
> >
> > @@ -200,18 +325,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 +338,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(¬ifier->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, ¬ifier->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);
>
> How about list_move() ?
Yeah.
>
> This seems to be new code, and by the look of it, I wonder whether it doesn't
> belong in the reprobing removal patch.
This is not related to re-probing. Here we're moving an async sub-device
back to the global sub-device list when its notifier is going away.
>
> > + }
> >
> > + 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(¬ifier->list);
> > +
> > + mutex_unlock(&list_lock);
> > +}
> > EXPORT_SYMBOL(v4l2_async_notifier_unregister);
> >
> > void v4l2_async_notifier_release(struct v4l2_async_notifier *notifier)
>
--
Regards,
Sakari Ailus
e-mail: sakari.ailus@iki.fi
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 19/25] v4l: fwnode: Add convenience function for parsing common external refs
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Add v4l2_fwnode_parse_reference_sensor_common for parsing common
sensor properties that refer to adjacent devices such as flash or lens
driver chips.
As this is an association only, there's little a regular driver needs to
know about these devices as such.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
---
drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++
include/media/v4l2-async.h | 3 ++-
include/media/v4l2-fwnode.h | 21 +++++++++++++++++++++
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 968a345a288f..7de2fd195e19 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -768,6 +768,41 @@ static int v4l2_fwnode_reference_parse_int_props(
return ret;
}
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+ struct device *dev, struct v4l2_async_notifier *notifier)
+{
+ static const char *led_props[] = { "led" };
+ static const struct {
+ const char *name;
+ const char **props;
+ unsigned int nprops;
+ } props[] = {
+ { "flash-leds", led_props, ARRAY_SIZE(led_props) },
+ { "lens-focus", NULL, 0 },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(props); i++) {
+ int ret;
+
+ if (props[i].props && is_acpi_node(dev_fwnode(dev)))
+ ret = v4l2_fwnode_reference_parse_int_props(
+ dev, notifier, props[i].name,
+ props[i].props, props[i].nprops);
+ else
+ ret = v4l2_fwnode_reference_parse(
+ dev, notifier, props[i].name);
+ if (ret && ret != -ENOENT) {
+ dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
+ props[i].name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index a13803a6371d..378e20e3b44d 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -155,7 +155,8 @@ 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. The user is
* responsible for releasing the notifier's resources after calling
- * @v4l2_async_notifier_parse_fwnode_endpoints.
+ * @v4l2_async_notifier_parse_fwnode_endpoints or
+ * @v4l2_fwnode_reference_parse_sensor_common.
*
* There is no harm from calling v4l2_async_notifier_release in other
* cases as long as its memory has been zeroed after it has been
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 83afac48ea6b..7f315383c0ae 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -318,4 +318,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd));
+/**
+ * v4l2_fwnode_reference_parse_sensor_common - parse common references on
+ * sensors for async sub-devices
+ * @dev: the device node the properties of which are parsed for references
+ * @notifier: the async notifier where the async subdevs will be added
+ *
+ * Parse common sensor properties for remote devices related to the
+ * sensor and set up async sub-devices for them.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even in the case the function returned an
+ * error.
+ *
+ * Return: 0 on success
+ * -ENOMEM if memory allocation failed
+ * -EINVAL if property parsing failed
+ */
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+ struct device *dev, struct v4l2_async_notifier *notifier);
+
#endif /* _V4L2_FWNODE_H */
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 19/25] v4l: fwnode: Add convenience function for parsing common external refs
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Add v4l2_fwnode_parse_reference_sensor_common for parsing common
sensor properties that refer to adjacent devices such as flash or lens
driver chips.
As this is an association only, there's little a regular driver needs to
know about these devices as such.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++
include/media/v4l2-async.h | 3 ++-
include/media/v4l2-fwnode.h | 21 +++++++++++++++++++++
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 968a345a288f..7de2fd195e19 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -768,6 +768,41 @@ static int v4l2_fwnode_reference_parse_int_props(
return ret;
}
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+ struct device *dev, struct v4l2_async_notifier *notifier)
+{
+ static const char *led_props[] = { "led" };
+ static const struct {
+ const char *name;
+ const char **props;
+ unsigned int nprops;
+ } props[] = {
+ { "flash-leds", led_props, ARRAY_SIZE(led_props) },
+ { "lens-focus", NULL, 0 },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(props); i++) {
+ int ret;
+
+ if (props[i].props && is_acpi_node(dev_fwnode(dev)))
+ ret = v4l2_fwnode_reference_parse_int_props(
+ dev, notifier, props[i].name,
+ props[i].props, props[i].nprops);
+ else
+ ret = v4l2_fwnode_reference_parse(
+ dev, notifier, props[i].name);
+ if (ret && ret != -ENOENT) {
+ dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
+ props[i].name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index a13803a6371d..378e20e3b44d 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -155,7 +155,8 @@ 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. The user is
* responsible for releasing the notifier's resources after calling
- * @v4l2_async_notifier_parse_fwnode_endpoints.
+ * @v4l2_async_notifier_parse_fwnode_endpoints or
+ * @v4l2_fwnode_reference_parse_sensor_common.
*
* There is no harm from calling v4l2_async_notifier_release in other
* cases as long as its memory has been zeroed after it has been
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 83afac48ea6b..7f315383c0ae 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -318,4 +318,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd));
+/**
+ * v4l2_fwnode_reference_parse_sensor_common - parse common references on
+ * sensors for async sub-devices
+ * @dev: the device node the properties of which are parsed for references
+ * @notifier: the async notifier where the async subdevs will be added
+ *
+ * Parse common sensor properties for remote devices related to the
+ * sensor and set up async sub-devices for them.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even in the case the function returned an
+ * error.
+ *
+ * Return: 0 on success
+ * -ENOMEM if memory allocation failed
+ * -EINVAL if property parsing failed
+ */
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+ struct device *dev, struct v4l2_async_notifier *notifier);
+
#endif /* _V4L2_FWNODE_H */
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 21/25] smiapp: Add support for flash and lens devices
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Parse async sub-devices by using
v4l2_subdev_fwnode_reference_parse_sensor_common().
These types devices aren't directly related to the sensor, but are
nevertheless handled by the smiapp driver due to the relationship of these
component to the main part of the camera module --- the sensor.
This does not yet address providing the user space with information on how
to associate the sensor or lens devices but the kernel now has the
necessary information to do that.
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
---
drivers/media/i2c/smiapp/smiapp-core.c | 38 +++++++++++++++++++++++++++-------
drivers/media/i2c/smiapp/smiapp.h | 4 +++-
2 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 700f433261d0..a4735a96ea41 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -31,7 +31,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/smiapp.h>
-#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-device.h>
@@ -2887,17 +2887,24 @@ static int smiapp_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+ rval = v4l2_async_notifier_parse_fwnode_sensor_common(
+ &client->dev, &sensor->notifier);
+ if (rval < 0)
+ return rval;
+
sensor->vana = devm_regulator_get(&client->dev, "vana");
if (IS_ERR(sensor->vana)) {
dev_err(&client->dev, "could not get regulator for vana\n");
- return PTR_ERR(sensor->vana);
+ rval = PTR_ERR(sensor->vana);
+ goto out_release_async_notifier;
}
sensor->ext_clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(sensor->ext_clk)) {
dev_err(&client->dev, "could not get clock (%ld)\n",
PTR_ERR(sensor->ext_clk));
- return -EPROBE_DEFER;
+ rval = -EPROBE_DEFER;
+ goto out_release_async_notifier;
}
rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
@@ -2905,17 +2912,19 @@ static int smiapp_probe(struct i2c_client *client,
dev_err(&client->dev,
"unable to set clock freq to %u\n",
sensor->hwcfg->ext_clk);
- return rval;
+ goto out_release_async_notifier;
}
sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
GPIOD_OUT_LOW);
- if (IS_ERR(sensor->xshutdown))
- return PTR_ERR(sensor->xshutdown);
+ if (IS_ERR(sensor->xshutdown)) {
+ rval = PTR_ERR(sensor->xshutdown);
+ goto out_release_async_notifier;
+ }
rval = smiapp_power_on(&client->dev);
if (rval < 0)
- return rval;
+ goto out_release_async_notifier;
rval = smiapp_identify_module(sensor);
if (rval) {
@@ -3092,9 +3101,14 @@ static int smiapp_probe(struct i2c_client *client,
if (rval < 0)
goto out_media_entity_cleanup;
+ rval = v4l2_async_subdev_notifier_register(&sensor->src->sd,
+ &sensor->notifier);
+ if (rval)
+ goto out_media_entity_cleanup;
+
rval = v4l2_async_register_subdev(&sensor->src->sd);
if (rval < 0)
- goto out_media_entity_cleanup;
+ goto out_unregister_async_notifier;
pm_runtime_set_active(&client->dev);
pm_runtime_get_noresume(&client->dev);
@@ -3105,6 +3119,9 @@ static int smiapp_probe(struct i2c_client *client,
return 0;
+out_unregister_async_notifier:
+ v4l2_async_notifier_unregister(&sensor->notifier);
+
out_media_entity_cleanup:
media_entity_cleanup(&sensor->src->sd.entity);
@@ -3114,6 +3131,9 @@ static int smiapp_probe(struct i2c_client *client,
out_power_off:
smiapp_power_off(&client->dev);
+out_release_async_notifier:
+ v4l2_async_notifier_release(&sensor->notifier);
+
return rval;
}
@@ -3124,6 +3144,8 @@ static int smiapp_remove(struct i2c_client *client)
unsigned int i;
v4l2_async_unregister_subdev(subdev);
+ v4l2_async_notifier_unregister(&sensor->notifier);
+ v4l2_async_notifier_release(&sensor->notifier);
pm_runtime_disable(&client->dev);
if (!pm_runtime_status_suspended(&client->dev))
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index f74d695018b9..be92cb5713f4 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -20,9 +20,10 @@
#define __SMIAPP_PRIV_H_
#include <linux/mutex.h>
+#include <media/i2c/smiapp.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
-#include <media/i2c/smiapp.h>
#include "smiapp-pll.h"
#include "smiapp-reg.h"
@@ -172,6 +173,7 @@ struct smiapp_subdev {
* struct smiapp_sensor - Main device structure
*/
struct smiapp_sensor {
+ struct v4l2_async_notifier notifier;
/*
* "mutex" is used to serialise access to all fields here
* except v4l2_ctrls at the end of the struct. "mutex" is also
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 21/25] smiapp: Add support for flash and lens devices
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Parse async sub-devices by using
v4l2_subdev_fwnode_reference_parse_sensor_common().
These types devices aren't directly related to the sensor, but are
nevertheless handled by the smiapp driver due to the relationship of these
component to the main part of the camera module --- the sensor.
This does not yet address providing the user space with information on how
to associate the sensor or lens devices but the kernel now has the
necessary information to do that.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/media/i2c/smiapp/smiapp-core.c | 38 +++++++++++++++++++++++++++-------
drivers/media/i2c/smiapp/smiapp.h | 4 +++-
2 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 700f433261d0..a4735a96ea41 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -31,7 +31,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/smiapp.h>
-#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-device.h>
@@ -2887,17 +2887,24 @@ static int smiapp_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+ rval = v4l2_async_notifier_parse_fwnode_sensor_common(
+ &client->dev, &sensor->notifier);
+ if (rval < 0)
+ return rval;
+
sensor->vana = devm_regulator_get(&client->dev, "vana");
if (IS_ERR(sensor->vana)) {
dev_err(&client->dev, "could not get regulator for vana\n");
- return PTR_ERR(sensor->vana);
+ rval = PTR_ERR(sensor->vana);
+ goto out_release_async_notifier;
}
sensor->ext_clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(sensor->ext_clk)) {
dev_err(&client->dev, "could not get clock (%ld)\n",
PTR_ERR(sensor->ext_clk));
- return -EPROBE_DEFER;
+ rval = -EPROBE_DEFER;
+ goto out_release_async_notifier;
}
rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
@@ -2905,17 +2912,19 @@ static int smiapp_probe(struct i2c_client *client,
dev_err(&client->dev,
"unable to set clock freq to %u\n",
sensor->hwcfg->ext_clk);
- return rval;
+ goto out_release_async_notifier;
}
sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
GPIOD_OUT_LOW);
- if (IS_ERR(sensor->xshutdown))
- return PTR_ERR(sensor->xshutdown);
+ if (IS_ERR(sensor->xshutdown)) {
+ rval = PTR_ERR(sensor->xshutdown);
+ goto out_release_async_notifier;
+ }
rval = smiapp_power_on(&client->dev);
if (rval < 0)
- return rval;
+ goto out_release_async_notifier;
rval = smiapp_identify_module(sensor);
if (rval) {
@@ -3092,9 +3101,14 @@ static int smiapp_probe(struct i2c_client *client,
if (rval < 0)
goto out_media_entity_cleanup;
+ rval = v4l2_async_subdev_notifier_register(&sensor->src->sd,
+ &sensor->notifier);
+ if (rval)
+ goto out_media_entity_cleanup;
+
rval = v4l2_async_register_subdev(&sensor->src->sd);
if (rval < 0)
- goto out_media_entity_cleanup;
+ goto out_unregister_async_notifier;
pm_runtime_set_active(&client->dev);
pm_runtime_get_noresume(&client->dev);
@@ -3105,6 +3119,9 @@ static int smiapp_probe(struct i2c_client *client,
return 0;
+out_unregister_async_notifier:
+ v4l2_async_notifier_unregister(&sensor->notifier);
+
out_media_entity_cleanup:
media_entity_cleanup(&sensor->src->sd.entity);
@@ -3114,6 +3131,9 @@ static int smiapp_probe(struct i2c_client *client,
out_power_off:
smiapp_power_off(&client->dev);
+out_release_async_notifier:
+ v4l2_async_notifier_release(&sensor->notifier);
+
return rval;
}
@@ -3124,6 +3144,8 @@ static int smiapp_remove(struct i2c_client *client)
unsigned int i;
v4l2_async_unregister_subdev(subdev);
+ v4l2_async_notifier_unregister(&sensor->notifier);
+ v4l2_async_notifier_release(&sensor->notifier);
pm_runtime_disable(&client->dev);
if (!pm_runtime_status_suspended(&client->dev))
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index f74d695018b9..be92cb5713f4 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -20,9 +20,10 @@
#define __SMIAPP_PRIV_H_
#include <linux/mutex.h>
+#include <media/i2c/smiapp.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
-#include <media/i2c/smiapp.h>
#include "smiapp-pll.h"
#include "smiapp-reg.h"
@@ -172,6 +173,7 @@ struct smiapp_subdev {
* struct smiapp_sensor - Main device structure
*/
struct smiapp_sensor {
+ struct v4l2_async_notifier notifier;
/*
* "mutex" is used to serialise access to all fields here
* except v4l2_ctrls at the end of the struct. "mutex" is also
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
[parent not found: <20170915141724.23124-22-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>]
* Re: [PATCH v13 21/25] smiapp: Add support for flash and lens devices
2017-09-15 14:17 ` Sakari Ailus
@ 2017-09-19 12:08 ` Laurent Pinchart
-1 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 12:08 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:20 EEST Sakari Ailus wrote:
> Parse async sub-devices by using
> v4l2_subdev_fwnode_reference_parse_sensor_common().
>
> These types devices aren't directly related to the sensor, but are
> nevertheless handled by the smiapp driver due to the relationship of these
> component to the main part of the camera module --- the sensor.
>
> This does not yet address providing the user space with information on how
> to associate the sensor or lens devices but the kernel now has the
> necessary information to do that.
>
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
Something is bothering me here, not so much in the contents of the patch
itself than in its nature. There are four patches in this series that add
support for flash and lens devices to the smiapp, et8ek8, ov5670 and ov13858
drivers. We have way more sensor drivers than that, and I don't really want to
patch them all to support flash and lens. I believe a less intrusive approach,
more focussed on the V4L2 core, is needed.
> ---
> drivers/media/i2c/smiapp/smiapp-core.c | 38 ++++++++++++++++++++++++-------
> drivers/media/i2c/smiapp/smiapp.h | 4 +++-
> 2 files changed, 33 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/media/i2c/smiapp/smiapp-core.c
> b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d0..a4735a96ea41
> 100644
> --- a/drivers/media/i2c/smiapp/smiapp-core.c
> +++ b/drivers/media/i2c/smiapp/smiapp-core.c
> @@ -31,7 +31,7 @@
> #include <linux/regulator/consumer.h>
> #include <linux/slab.h>
> #include <linux/smiapp.h>
> -#include <linux/v4l2-mediabus.h>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-device.h>
>
> @@ -2887,17 +2887,24 @@ static int smiapp_probe(struct i2c_client *client,
> v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
> sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
>
> + rval = v4l2_async_notifier_parse_fwnode_sensor_common(
> + &client->dev, &sensor->notifier);
> + if (rval < 0)
> + return rval;
> +
> sensor->vana = devm_regulator_get(&client->dev, "vana");
> if (IS_ERR(sensor->vana)) {
> dev_err(&client->dev, "could not get regulator for vana\n");
> - return PTR_ERR(sensor->vana);
> + rval = PTR_ERR(sensor->vana);
> + goto out_release_async_notifier;
> }
>
> sensor->ext_clk = devm_clk_get(&client->dev, NULL);
> if (IS_ERR(sensor->ext_clk)) {
> dev_err(&client->dev, "could not get clock (%ld)\n",
> PTR_ERR(sensor->ext_clk));
> - return -EPROBE_DEFER;
> + rval = -EPROBE_DEFER;
> + goto out_release_async_notifier;
> }
>
> rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
> @@ -2905,17 +2912,19 @@ static int smiapp_probe(struct i2c_client *client,
> dev_err(&client->dev,
> "unable to set clock freq to %u\n",
> sensor->hwcfg->ext_clk);
> - return rval;
> + goto out_release_async_notifier;
> }
>
> sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
> GPIOD_OUT_LOW);
> - if (IS_ERR(sensor->xshutdown))
> - return PTR_ERR(sensor->xshutdown);
> + if (IS_ERR(sensor->xshutdown)) {
> + rval = PTR_ERR(sensor->xshutdown);
> + goto out_release_async_notifier;
> + }
>
> rval = smiapp_power_on(&client->dev);
> if (rval < 0)
> - return rval;
> + goto out_release_async_notifier;
>
> rval = smiapp_identify_module(sensor);
> if (rval) {
> @@ -3092,9 +3101,14 @@ static int smiapp_probe(struct i2c_client *client,
> if (rval < 0)
> goto out_media_entity_cleanup;
>
> + rval = v4l2_async_subdev_notifier_register(&sensor->src->sd,
> + &sensor->notifier);
> + if (rval)
> + goto out_media_entity_cleanup;
> +
> rval = v4l2_async_register_subdev(&sensor->src->sd);
> if (rval < 0)
> - goto out_media_entity_cleanup;
> + goto out_unregister_async_notifier;
>
> pm_runtime_set_active(&client->dev);
> pm_runtime_get_noresume(&client->dev);
> @@ -3105,6 +3119,9 @@ static int smiapp_probe(struct i2c_client *client,
>
> return 0;
>
> +out_unregister_async_notifier:
> + v4l2_async_notifier_unregister(&sensor->notifier);
> +
> out_media_entity_cleanup:
> media_entity_cleanup(&sensor->src->sd.entity);
>
> @@ -3114,6 +3131,9 @@ static int smiapp_probe(struct i2c_client *client,
> out_power_off:
> smiapp_power_off(&client->dev);
>
> +out_release_async_notifier:
> + v4l2_async_notifier_release(&sensor->notifier);
> +
> return rval;
> }
>
> @@ -3124,6 +3144,8 @@ static int smiapp_remove(struct i2c_client *client)
> unsigned int i;
>
> v4l2_async_unregister_subdev(subdev);
> + v4l2_async_notifier_unregister(&sensor->notifier);
> + v4l2_async_notifier_release(&sensor->notifier);
>
> pm_runtime_disable(&client->dev);
> if (!pm_runtime_status_suspended(&client->dev))
> diff --git a/drivers/media/i2c/smiapp/smiapp.h
> b/drivers/media/i2c/smiapp/smiapp.h index f74d695018b9..be92cb5713f4 100644
> --- a/drivers/media/i2c/smiapp/smiapp.h
> +++ b/drivers/media/i2c/smiapp/smiapp.h
> @@ -20,9 +20,10 @@
> #define __SMIAPP_PRIV_H_
>
> #include <linux/mutex.h>
> +#include <media/i2c/smiapp.h>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-ctrls.h>
> #include <media/v4l2-subdev.h>
> -#include <media/i2c/smiapp.h>
>
> #include "smiapp-pll.h"
> #include "smiapp-reg.h"
> @@ -172,6 +173,7 @@ struct smiapp_subdev {
> * struct smiapp_sensor - Main device structure
> */
> struct smiapp_sensor {
> + struct v4l2_async_notifier notifier;
> /*
> * "mutex" is used to serialise access to all fields here
> * except v4l2_ctrls at the end of the struct. "mutex" is also
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 21/25] smiapp: Add support for flash and lens devices
@ 2017-09-19 12:08 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 12:08 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
Thank you for the patch.
On Friday, 15 September 2017 17:17:20 EEST Sakari Ailus wrote:
> Parse async sub-devices by using
> v4l2_subdev_fwnode_reference_parse_sensor_common().
>
> These types devices aren't directly related to the sensor, but are
> nevertheless handled by the smiapp driver due to the relationship of these
> component to the main part of the camera module --- the sensor.
>
> This does not yet address providing the user space with information on how
> to associate the sensor or lens devices but the kernel now has the
> necessary information to do that.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
Something is bothering me here, not so much in the contents of the patch
itself than in its nature. There are four patches in this series that add
support for flash and lens devices to the smiapp, et8ek8, ov5670 and ov13858
drivers. We have way more sensor drivers than that, and I don't really want to
patch them all to support flash and lens. I believe a less intrusive approach,
more focussed on the V4L2 core, is needed.
> ---
> drivers/media/i2c/smiapp/smiapp-core.c | 38 ++++++++++++++++++++++++-------
> drivers/media/i2c/smiapp/smiapp.h | 4 +++-
> 2 files changed, 33 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/media/i2c/smiapp/smiapp-core.c
> b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d0..a4735a96ea41
> 100644
> --- a/drivers/media/i2c/smiapp/smiapp-core.c
> +++ b/drivers/media/i2c/smiapp/smiapp-core.c
> @@ -31,7 +31,7 @@
> #include <linux/regulator/consumer.h>
> #include <linux/slab.h>
> #include <linux/smiapp.h>
> -#include <linux/v4l2-mediabus.h>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-device.h>
>
> @@ -2887,17 +2887,24 @@ static int smiapp_probe(struct i2c_client *client,
> v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
> sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
>
> + rval = v4l2_async_notifier_parse_fwnode_sensor_common(
> + &client->dev, &sensor->notifier);
> + if (rval < 0)
> + return rval;
> +
> sensor->vana = devm_regulator_get(&client->dev, "vana");
> if (IS_ERR(sensor->vana)) {
> dev_err(&client->dev, "could not get regulator for vana\n");
> - return PTR_ERR(sensor->vana);
> + rval = PTR_ERR(sensor->vana);
> + goto out_release_async_notifier;
> }
>
> sensor->ext_clk = devm_clk_get(&client->dev, NULL);
> if (IS_ERR(sensor->ext_clk)) {
> dev_err(&client->dev, "could not get clock (%ld)\n",
> PTR_ERR(sensor->ext_clk));
> - return -EPROBE_DEFER;
> + rval = -EPROBE_DEFER;
> + goto out_release_async_notifier;
> }
>
> rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
> @@ -2905,17 +2912,19 @@ static int smiapp_probe(struct i2c_client *client,
> dev_err(&client->dev,
> "unable to set clock freq to %u\n",
> sensor->hwcfg->ext_clk);
> - return rval;
> + goto out_release_async_notifier;
> }
>
> sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
> GPIOD_OUT_LOW);
> - if (IS_ERR(sensor->xshutdown))
> - return PTR_ERR(sensor->xshutdown);
> + if (IS_ERR(sensor->xshutdown)) {
> + rval = PTR_ERR(sensor->xshutdown);
> + goto out_release_async_notifier;
> + }
>
> rval = smiapp_power_on(&client->dev);
> if (rval < 0)
> - return rval;
> + goto out_release_async_notifier;
>
> rval = smiapp_identify_module(sensor);
> if (rval) {
> @@ -3092,9 +3101,14 @@ static int smiapp_probe(struct i2c_client *client,
> if (rval < 0)
> goto out_media_entity_cleanup;
>
> + rval = v4l2_async_subdev_notifier_register(&sensor->src->sd,
> + &sensor->notifier);
> + if (rval)
> + goto out_media_entity_cleanup;
> +
> rval = v4l2_async_register_subdev(&sensor->src->sd);
> if (rval < 0)
> - goto out_media_entity_cleanup;
> + goto out_unregister_async_notifier;
>
> pm_runtime_set_active(&client->dev);
> pm_runtime_get_noresume(&client->dev);
> @@ -3105,6 +3119,9 @@ static int smiapp_probe(struct i2c_client *client,
>
> return 0;
>
> +out_unregister_async_notifier:
> + v4l2_async_notifier_unregister(&sensor->notifier);
> +
> out_media_entity_cleanup:
> media_entity_cleanup(&sensor->src->sd.entity);
>
> @@ -3114,6 +3131,9 @@ static int smiapp_probe(struct i2c_client *client,
> out_power_off:
> smiapp_power_off(&client->dev);
>
> +out_release_async_notifier:
> + v4l2_async_notifier_release(&sensor->notifier);
> +
> return rval;
> }
>
> @@ -3124,6 +3144,8 @@ static int smiapp_remove(struct i2c_client *client)
> unsigned int i;
>
> v4l2_async_unregister_subdev(subdev);
> + v4l2_async_notifier_unregister(&sensor->notifier);
> + v4l2_async_notifier_release(&sensor->notifier);
>
> pm_runtime_disable(&client->dev);
> if (!pm_runtime_status_suspended(&client->dev))
> diff --git a/drivers/media/i2c/smiapp/smiapp.h
> b/drivers/media/i2c/smiapp/smiapp.h index f74d695018b9..be92cb5713f4 100644
> --- a/drivers/media/i2c/smiapp/smiapp.h
> +++ b/drivers/media/i2c/smiapp/smiapp.h
> @@ -20,9 +20,10 @@
> #define __SMIAPP_PRIV_H_
>
> #include <linux/mutex.h>
> +#include <media/i2c/smiapp.h>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-ctrls.h>
> #include <media/v4l2-subdev.h>
> -#include <media/i2c/smiapp.h>
>
> #include "smiapp-pll.h"
> #include "smiapp-reg.h"
> @@ -172,6 +173,7 @@ struct smiapp_subdev {
> * struct smiapp_sensor - Main device structure
> */
> struct smiapp_sensor {
> + struct v4l2_async_notifier notifier;
> /*
> * "mutex" is used to serialise access to all fields here
> * except v4l2_ctrls at the end of the struct. "mutex" is also
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 21/25] smiapp: Add support for flash and lens devices
2017-09-19 12:08 ` Laurent Pinchart
(?)
@ 2017-09-19 12:20 ` Sakari Ailus
2017-09-19 12:38 ` Laurent Pinchart
-1 siblings, 1 reply; 137+ messages in thread
From: Sakari Ailus @ 2017-09-19 12:20 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Laurent,
On Tue, Sep 19, 2017 at 03:08:25PM +0300, Laurent Pinchart wrote:
> Hi Sakari,
>
> Thank you for the patch.
>
> On Friday, 15 September 2017 17:17:20 EEST Sakari Ailus wrote:
> > Parse async sub-devices by using
> > v4l2_subdev_fwnode_reference_parse_sensor_common().
> >
> > These types devices aren't directly related to the sensor, but are
> > nevertheless handled by the smiapp driver due to the relationship of these
> > component to the main part of the camera module --- the sensor.
> >
> > This does not yet address providing the user space with information on how
> > to associate the sensor or lens devices but the kernel now has the
> > necessary information to do that.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > Acked-by: Pavel Machek <pavel@ucw.cz>
>
> Something is bothering me here, not so much in the contents of the patch
> itself than in its nature. There are four patches in this series that add
> support for flash and lens devices to the smiapp, et8ek8, ov5670 and ov13858
> drivers. We have way more sensor drivers than that, and I don't really want to
> patch them all to support flash and lens. I believe a less intrusive approach,
> more focussed on the V4L2 core, is needed.
You could move this to the framework, yes. Nothing prevents that. Perhaps a
flag telling the framework whether this should be done? Just being
opportunistic might work as well.
>
> > ---
> > drivers/media/i2c/smiapp/smiapp-core.c | 38 ++++++++++++++++++++++++-------
> > drivers/media/i2c/smiapp/smiapp.h | 4 +++-
> > 2 files changed, 33 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/media/i2c/smiapp/smiapp-core.c
> > b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d0..a4735a96ea41
> > 100644
> > --- a/drivers/media/i2c/smiapp/smiapp-core.c
> > +++ b/drivers/media/i2c/smiapp/smiapp-core.c
> > @@ -31,7 +31,7 @@
> > #include <linux/regulator/consumer.h>
> > #include <linux/slab.h>
> > #include <linux/smiapp.h>
> > -#include <linux/v4l2-mediabus.h>
> > +#include <media/v4l2-async.h>
> > #include <media/v4l2-fwnode.h>
> > #include <media/v4l2-device.h>
> >
> > @@ -2887,17 +2887,24 @@ static int smiapp_probe(struct i2c_client *client,
> > v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
> > sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
> >
> > + rval = v4l2_async_notifier_parse_fwnode_sensor_common(
> > + &client->dev, &sensor->notifier);
> > + if (rval < 0)
> > + return rval;
> > +
> > sensor->vana = devm_regulator_get(&client->dev, "vana");
> > if (IS_ERR(sensor->vana)) {
> > dev_err(&client->dev, "could not get regulator for vana\n");
> > - return PTR_ERR(sensor->vana);
> > + rval = PTR_ERR(sensor->vana);
> > + goto out_release_async_notifier;
> > }
> >
> > sensor->ext_clk = devm_clk_get(&client->dev, NULL);
> > if (IS_ERR(sensor->ext_clk)) {
> > dev_err(&client->dev, "could not get clock (%ld)\n",
> > PTR_ERR(sensor->ext_clk));
> > - return -EPROBE_DEFER;
> > + rval = -EPROBE_DEFER;
> > + goto out_release_async_notifier;
> > }
> >
> > rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
> > @@ -2905,17 +2912,19 @@ static int smiapp_probe(struct i2c_client *client,
> > dev_err(&client->dev,
> > "unable to set clock freq to %u\n",
> > sensor->hwcfg->ext_clk);
> > - return rval;
> > + goto out_release_async_notifier;
> > }
> >
> > sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
> > GPIOD_OUT_LOW);
> > - if (IS_ERR(sensor->xshutdown))
> > - return PTR_ERR(sensor->xshutdown);
> > + if (IS_ERR(sensor->xshutdown)) {
> > + rval = PTR_ERR(sensor->xshutdown);
> > + goto out_release_async_notifier;
> > + }
> >
> > rval = smiapp_power_on(&client->dev);
> > if (rval < 0)
> > - return rval;
> > + goto out_release_async_notifier;
> >
> > rval = smiapp_identify_module(sensor);
> > if (rval) {
> > @@ -3092,9 +3101,14 @@ static int smiapp_probe(struct i2c_client *client,
> > if (rval < 0)
> > goto out_media_entity_cleanup;
> >
> > + rval = v4l2_async_subdev_notifier_register(&sensor->src->sd,
> > + &sensor->notifier);
> > + if (rval)
> > + goto out_media_entity_cleanup;
> > +
> > rval = v4l2_async_register_subdev(&sensor->src->sd);
> > if (rval < 0)
> > - goto out_media_entity_cleanup;
> > + goto out_unregister_async_notifier;
> >
> > pm_runtime_set_active(&client->dev);
> > pm_runtime_get_noresume(&client->dev);
> > @@ -3105,6 +3119,9 @@ static int smiapp_probe(struct i2c_client *client,
> >
> > return 0;
> >
> > +out_unregister_async_notifier:
> > + v4l2_async_notifier_unregister(&sensor->notifier);
> > +
> > out_media_entity_cleanup:
> > media_entity_cleanup(&sensor->src->sd.entity);
> >
> > @@ -3114,6 +3131,9 @@ static int smiapp_probe(struct i2c_client *client,
> > out_power_off:
> > smiapp_power_off(&client->dev);
> >
> > +out_release_async_notifier:
> > + v4l2_async_notifier_release(&sensor->notifier);
> > +
> > return rval;
> > }
> >
> > @@ -3124,6 +3144,8 @@ static int smiapp_remove(struct i2c_client *client)
> > unsigned int i;
> >
> > v4l2_async_unregister_subdev(subdev);
> > + v4l2_async_notifier_unregister(&sensor->notifier);
> > + v4l2_async_notifier_release(&sensor->notifier);
> >
> > pm_runtime_disable(&client->dev);
> > if (!pm_runtime_status_suspended(&client->dev))
> > diff --git a/drivers/media/i2c/smiapp/smiapp.h
> > b/drivers/media/i2c/smiapp/smiapp.h index f74d695018b9..be92cb5713f4 100644
> > --- a/drivers/media/i2c/smiapp/smiapp.h
> > +++ b/drivers/media/i2c/smiapp/smiapp.h
> > @@ -20,9 +20,10 @@
> > #define __SMIAPP_PRIV_H_
> >
> > #include <linux/mutex.h>
> > +#include <media/i2c/smiapp.h>
> > +#include <media/v4l2-async.h>
> > #include <media/v4l2-ctrls.h>
> > #include <media/v4l2-subdev.h>
> > -#include <media/i2c/smiapp.h>
> >
> > #include "smiapp-pll.h"
> > #include "smiapp-reg.h"
> > @@ -172,6 +173,7 @@ struct smiapp_subdev {
> > * struct smiapp_sensor - Main device structure
> > */
> > struct smiapp_sensor {
> > + struct v4l2_async_notifier notifier;
> > /*
> > * "mutex" is used to serialise access to all fields here
> > * except v4l2_ctrls at the end of the struct. "mutex" is also
>
>
> --
> Regards,
>
> Laurent Pinchart
>
--
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 137+ messages in thread
* Re: [PATCH v13 21/25] smiapp: Add support for flash and lens devices
2017-09-19 12:20 ` Sakari Ailus
@ 2017-09-19 12:38 ` Laurent Pinchart
0 siblings, 0 replies; 137+ messages in thread
From: Laurent Pinchart @ 2017-09-19 12:38 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, niklas.soderlund, maxime.ripard, robh, hverkuil,
devicetree, pavel, sre
Hi Sakari,
On Tuesday, 19 September 2017 15:20:34 EEST Sakari Ailus wrote:
> On Tue, Sep 19, 2017 at 03:08:25PM +0300, Laurent Pinchart wrote:
> > On Friday, 15 September 2017 17:17:20 EEST Sakari Ailus wrote:
> >> Parse async sub-devices by using
> >> v4l2_subdev_fwnode_reference_parse_sensor_common().
> >>
> >> These types devices aren't directly related to the sensor, but are
> >> nevertheless handled by the smiapp driver due to the relationship of
> >> these component to the main part of the camera module --- the sensor.
> >>
> >> This does not yet address providing the user space with information on
> >> how to associate the sensor or lens devices but the kernel now has the
> >> necessary information to do that.
> >>
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> Acked-by: Pavel Machek <pavel@ucw.cz>
> >
> > Something is bothering me here, not so much in the contents of the patch
> > itself than in its nature. There are four patches in this series that add
> > support for flash and lens devices to the smiapp, et8ek8, ov5670 and
> > ov13858 drivers. We have way more sensor drivers than that, and I don't
> > really want to patch them all to support flash and lens. I believe a less
> > intrusive approach, more focussed on the V4L2 core, is needed.
>
> You could move this to the framework, yes. Nothing prevents that. Perhaps a
> flag telling the framework whether this should be done? Just being
> opportunistic might work as well.
How is would be done is another matter which I haven't thought about yet :-)
My point is that I don't think converting all drivers is a good idea, you
should aim for an implementation in the core.
> >> ---
> >>
> >> drivers/media/i2c/smiapp/smiapp-core.c | 38 ++++++++++++++++++++-------
> >> drivers/media/i2c/smiapp/smiapp.h | 4 +++-
> >> 2 files changed, 33 insertions(+), 9 deletions(-)
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 137+ messages in thread
* [PATCH v13 23/25] ov5670: Add support for flash and lens devices
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Parse async sub-devices by using
v4l2_subdev_fwnode_reference_parse_sensor_common().
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
---
drivers/media/i2c/ov5670.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index 6f7a1d6d2200..a791701fa2b9 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#define OV5670_REG_CHIP_ID 0x300a
#define OV5670_CHIP_ID 0x005670
@@ -1807,6 +1808,7 @@ static const struct ov5670_mode supported_modes[] = {
struct ov5670 {
struct v4l2_subdev sd;
struct media_pad pad;
+ struct v4l2_async_notifier notifier;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
@@ -2473,11 +2475,13 @@ static int ov5670_probe(struct i2c_client *client)
return -EINVAL;
ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL);
- if (!ov5670) {
- ret = -ENOMEM;
- err_msg = "devm_kzalloc() error";
- goto error_print;
- }
+ if (!ov5670)
+ return -ENOMEM;
+
+ ret = v4l2_async_notifier_parse_fwnode_sensor_common(
+ &client->dev, &ov5670->notifier);
+ if (ret < 0)
+ return ret;
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops);
@@ -2486,7 +2490,7 @@ static int ov5670_probe(struct i2c_client *client)
ret = ov5670_identify_module(ov5670);
if (ret) {
err_msg = "ov5670_identify_module() error";
- goto error_print;
+ goto error_release_notifier;
}
mutex_init(&ov5670->mutex);
@@ -2513,11 +2517,18 @@ static int ov5670_probe(struct i2c_client *client)
goto error_handler_free;
}
+ ret = v4l2_async_subdev_notifier_register(&ov5670->sd,
+ &ov5670->notifier);
+ if (ret) {
+ err_msg = "can't register async notifier";
+ goto error_entity_cleanup;
+ }
+
/* Async register for subdev */
ret = v4l2_async_register_subdev(&ov5670->sd);
if (ret < 0) {
err_msg = "v4l2_async_register_subdev() error";
- goto error_entity_cleanup;
+ goto error_unregister_notifier;
}
ov5670->streaming = false;
@@ -2533,6 +2544,9 @@ static int ov5670_probe(struct i2c_client *client)
return 0;
+error_unregister_notifier:
+ v4l2_async_notifier_unregister(&ov5670->notifier);
+
error_entity_cleanup:
media_entity_cleanup(&ov5670->sd.entity);
@@ -2542,7 +2556,8 @@ static int ov5670_probe(struct i2c_client *client)
error_mutex_destroy:
mutex_destroy(&ov5670->mutex);
-error_print:
+error_release_notifier:
+ v4l2_async_notifier_release(&ov5670->notifier);
dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret);
return ret;
@@ -2554,6 +2569,8 @@ static int ov5670_remove(struct i2c_client *client)
struct ov5670 *ov5670 = to_ov5670(sd);
v4l2_async_unregister_subdev(sd);
+ v4l2_async_notifier_unregister(&ov5670->notifier);
+ v4l2_async_notifier_release(&ov5670->notifier);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
mutex_destroy(&ov5670->mutex);
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 23/25] ov5670: Add support for flash and lens devices
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Parse async sub-devices by using
v4l2_subdev_fwnode_reference_parse_sensor_common().
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/i2c/ov5670.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index 6f7a1d6d2200..a791701fa2b9 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#define OV5670_REG_CHIP_ID 0x300a
#define OV5670_CHIP_ID 0x005670
@@ -1807,6 +1808,7 @@ static const struct ov5670_mode supported_modes[] = {
struct ov5670 {
struct v4l2_subdev sd;
struct media_pad pad;
+ struct v4l2_async_notifier notifier;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
@@ -2473,11 +2475,13 @@ static int ov5670_probe(struct i2c_client *client)
return -EINVAL;
ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL);
- if (!ov5670) {
- ret = -ENOMEM;
- err_msg = "devm_kzalloc() error";
- goto error_print;
- }
+ if (!ov5670)
+ return -ENOMEM;
+
+ ret = v4l2_async_notifier_parse_fwnode_sensor_common(
+ &client->dev, &ov5670->notifier);
+ if (ret < 0)
+ return ret;
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops);
@@ -2486,7 +2490,7 @@ static int ov5670_probe(struct i2c_client *client)
ret = ov5670_identify_module(ov5670);
if (ret) {
err_msg = "ov5670_identify_module() error";
- goto error_print;
+ goto error_release_notifier;
}
mutex_init(&ov5670->mutex);
@@ -2513,11 +2517,18 @@ static int ov5670_probe(struct i2c_client *client)
goto error_handler_free;
}
+ ret = v4l2_async_subdev_notifier_register(&ov5670->sd,
+ &ov5670->notifier);
+ if (ret) {
+ err_msg = "can't register async notifier";
+ goto error_entity_cleanup;
+ }
+
/* Async register for subdev */
ret = v4l2_async_register_subdev(&ov5670->sd);
if (ret < 0) {
err_msg = "v4l2_async_register_subdev() error";
- goto error_entity_cleanup;
+ goto error_unregister_notifier;
}
ov5670->streaming = false;
@@ -2533,6 +2544,9 @@ static int ov5670_probe(struct i2c_client *client)
return 0;
+error_unregister_notifier:
+ v4l2_async_notifier_unregister(&ov5670->notifier);
+
error_entity_cleanup:
media_entity_cleanup(&ov5670->sd.entity);
@@ -2542,7 +2556,8 @@ static int ov5670_probe(struct i2c_client *client)
error_mutex_destroy:
mutex_destroy(&ov5670->mutex);
-error_print:
+error_release_notifier:
+ v4l2_async_notifier_release(&ov5670->notifier);
dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret);
return ret;
@@ -2554,6 +2569,8 @@ static int ov5670_remove(struct i2c_client *client)
struct ov5670 *ov5670 = to_ov5670(sd);
v4l2_async_unregister_subdev(sd);
+ v4l2_async_notifier_unregister(&ov5670->notifier);
+ v4l2_async_notifier_release(&ov5670->notifier);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
mutex_destroy(&ov5670->mutex);
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 24/25] ov13858: Add support for flash and lens devices
2017-09-15 14:16 ` Sakari Ailus
@ 2017-09-15 14:17 ` Sakari Ailus
-1 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media-u79uwXL29TY76Z2rM5mHXA
Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
devicetree-u79uwXL29TY76Z2rM5mHXA, pavel-+ZI9xUNit7I,
sre-DgEjT+Ai2ygdnm+yROfE0A
Parse async sub-devices by using
v4l2_subdev_fwnode_reference_parse_sensor_common().
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
---
drivers/media/i2c/ov13858.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index af7af0d14c69..a8a9fb0a1756 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#define OV13858_REG_VALUE_08BIT 1
#define OV13858_REG_VALUE_16BIT 2
@@ -1028,6 +1029,7 @@ static const struct ov13858_mode supported_modes[] = {
struct ov13858 {
struct v4l2_subdev sd;
struct media_pad pad;
+ struct v4l2_async_notifier notifier;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
@@ -1715,6 +1717,11 @@ static int ov13858_probe(struct i2c_client *client,
if (!ov13858)
return -ENOMEM;
+ ret = v4l2_async_notifier_parse_fwnode_sensor_common(
+ &client->dev, &ov13858->notifier);
+ if (ret < 0)
+ return ret;
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops);
@@ -1722,7 +1729,7 @@ static int ov13858_probe(struct i2c_client *client,
ret = ov13858_identify_module(ov13858);
if (ret) {
dev_err(&client->dev, "failed to find sensor: %d\n", ret);
- return ret;
+ goto error_notifier_release;
}
/* Set default mode to max resolution */
@@ -1730,7 +1737,7 @@ static int ov13858_probe(struct i2c_client *client,
ret = ov13858_init_controls(ov13858);
if (ret)
- return ret;
+ goto error_notifier_release;
/* Initialize subdev */
ov13858->sd.internal_ops = &ov13858_internal_ops;
@@ -1746,9 +1753,14 @@ static int ov13858_probe(struct i2c_client *client,
goto error_handler_free;
}
+ ret = v4l2_async_subdev_notifier_register(&ov13858->sd,
+ &ov13858->notifier);
+ if (ret)
+ goto error_media_entity;
+
ret = v4l2_async_register_subdev(&ov13858->sd);
if (ret < 0)
- goto error_media_entity;
+ goto error_notifier_unregister;
/*
* Device is already turned on by i2c-core with ACPI domain PM.
@@ -1761,11 +1773,17 @@ static int ov13858_probe(struct i2c_client *client,
return 0;
+error_notifier_unregister:
+ v4l2_async_notifier_unregister(&ov13858->notifier);
+
error_media_entity:
media_entity_cleanup(&ov13858->sd.entity);
error_handler_free:
ov13858_free_controls(ov13858);
+
+error_notifier_release:
+ v4l2_async_notifier_release(&ov13858->notifier);
dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
return ret;
@@ -1777,6 +1795,8 @@ static int ov13858_remove(struct i2c_client *client)
struct ov13858 *ov13858 = to_ov13858(sd);
v4l2_async_unregister_subdev(sd);
+ v4l2_async_notifier_unregister(&ov13858->notifier);
+ v4l2_async_notifier_release(&ov13858->notifier);
media_entity_cleanup(&sd->entity);
ov13858_free_controls(ov13858);
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 137+ messages in thread
* [PATCH v13 24/25] ov13858: Add support for flash and lens devices
@ 2017-09-15 14:17 ` Sakari Ailus
0 siblings, 0 replies; 137+ messages in thread
From: Sakari Ailus @ 2017-09-15 14:17 UTC (permalink / raw)
To: linux-media
Cc: niklas.soderlund, maxime.ripard, robh, hverkuil,
laurent.pinchart, devicetree, pavel, sre
Parse async sub-devices by using
v4l2_subdev_fwnode_reference_parse_sensor_common().
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/i2c/ov13858.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index af7af0d14c69..a8a9fb0a1756 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#define OV13858_REG_VALUE_08BIT 1
#define OV13858_REG_VALUE_16BIT 2
@@ -1028,6 +1029,7 @@ static const struct ov13858_mode supported_modes[] = {
struct ov13858 {
struct v4l2_subdev sd;
struct media_pad pad;
+ struct v4l2_async_notifier notifier;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
@@ -1715,6 +1717,11 @@ static int ov13858_probe(struct i2c_client *client,
if (!ov13858)
return -ENOMEM;
+ ret = v4l2_async_notifier_parse_fwnode_sensor_common(
+ &client->dev, &ov13858->notifier);
+ if (ret < 0)
+ return ret;
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops);
@@ -1722,7 +1729,7 @@ static int ov13858_probe(struct i2c_client *client,
ret = ov13858_identify_module(ov13858);
if (ret) {
dev_err(&client->dev, "failed to find sensor: %d\n", ret);
- return ret;
+ goto error_notifier_release;
}
/* Set default mode to max resolution */
@@ -1730,7 +1737,7 @@ static int ov13858_probe(struct i2c_client *client,
ret = ov13858_init_controls(ov13858);
if (ret)
- return ret;
+ goto error_notifier_release;
/* Initialize subdev */
ov13858->sd.internal_ops = &ov13858_internal_ops;
@@ -1746,9 +1753,14 @@ static int ov13858_probe(struct i2c_client *client,
goto error_handler_free;
}
+ ret = v4l2_async_subdev_notifier_register(&ov13858->sd,
+ &ov13858->notifier);
+ if (ret)
+ goto error_media_entity;
+
ret = v4l2_async_register_subdev(&ov13858->sd);
if (ret < 0)
- goto error_media_entity;
+ goto error_notifier_unregister;
/*
* Device is already turned on by i2c-core with ACPI domain PM.
@@ -1761,11 +1773,17 @@ static int ov13858_probe(struct i2c_client *client,
return 0;
+error_notifier_unregister:
+ v4l2_async_notifier_unregister(&ov13858->notifier);
+
error_media_entity:
media_entity_cleanup(&ov13858->sd.entity);
error_handler_free:
ov13858_free_controls(ov13858);
+
+error_notifier_release:
+ v4l2_async_notifier_release(&ov13858->notifier);
dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
return ret;
@@ -1777,6 +1795,8 @@ static int ov13858_remove(struct i2c_client *client)
struct ov13858 *ov13858 = to_ov13858(sd);
v4l2_async_unregister_subdev(sd);
+ v4l2_async_notifier_unregister(&ov13858->notifier);
+ v4l2_async_notifier_release(&ov13858->notifier);
media_entity_cleanup(&sd->entity);
ov13858_free_controls(ov13858);
--
2.11.0
^ permalink raw reply related [flat|nested] 137+ messages in thread