On 09/12/2017 03:41 PM, Sakari Ailus wrote: > This is just like like v4l2_async_notifier_parse_fwnode_endpoints but it > only parses endpoints on a single port. The behaviour is useful on devices > that have both sinks and sources, in other words only some of these should > be parsed. I think it would be better to merge this patch with the preceding patch. It does not make a lot of sense to have this separate IMHO. That said: Acked-by: Hans Verkuil <hans.verkuil@xxxxxxxxx> Regards, Hans > > Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx> > --- > drivers/media/v4l2-core/v4l2-fwnode.c | 59 ++++++++++++++++++++++++++++++++--- > include/media/v4l2-fwnode.h | 59 +++++++++++++++++++++++++++++++++++ > 2 files changed, 113 insertions(+), 5 deletions(-) > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c > index d978f2d714ca..44ee35f6aad5 100644 > --- a/drivers/media/v4l2-core/v4l2-fwnode.c > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c > @@ -398,9 +398,9 @@ static int v4l2_async_notifier_fwnode_parse_endpoint( > return ret == -ENOTCONN ? 0 : ret; > } > > -int v4l2_async_notifier_parse_fwnode_endpoints( > +static int __v4l2_async_notifier_parse_fwnode_endpoints( > struct device *dev, struct v4l2_async_notifier *notifier, > - size_t asd_struct_size, > + 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)) > @@ -413,10 +413,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints( > return -EINVAL; > > for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint( > - dev_fwnode(dev), fwnode)); ) > - if (fwnode_device_is_available( > + dev_fwnode(dev), fwnode)); ) { > + if (!fwnode_device_is_available( > fwnode_graph_get_port_parent(fwnode))) > - max_subdevs++; > + 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) > @@ -437,6 +452,17 @@ int v4l2_async_notifier_parse_fwnode_endpoints( > 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) > @@ -447,8 +473,31 @@ int v4l2_async_notifier_parse_fwnode_endpoints( > > 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@xxxxxxxxxxxxxxx>"); > MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx>"); > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h > index 31fb77e470fa..b2eed4f33e6a 100644 > --- a/include/media/v4l2-fwnode.h > +++ b/include/media/v4l2-fwnode.h > @@ -257,4 +257,63 @@ int v4l2_async_notifier_parse_fwnode_endpoints( > 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. > + * > + * 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. > + * > + * 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 */ >