On 09/19/17 12:00, Sakari Ailus wrote:
> Hi Hans,
> 
> On Tue, Sep 19, 2017 at 10:40:14AM +0200, Hans Verkuil wrote:
>> On 09/19/2017 10:20 AM, Sakari Ailus wrote:
>>> 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:
> ...
>>>>> +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.
>>
>> After the previous while fwnode is NULL again (since that's when the while
>> stops).
>>
>>>
>>> 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 this is going to be replaced by a macro, then disregard my comment.
> 
> Yes. I just sent that to linux-acpi (as well as devicetree and to you).
> 
> ...
> 
>>>>> +/**
>>>>> + * 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.
>>
>> I think this should be clarified.
>>
>> I wonder if there is any way around it. I don't have time to dig into this, 
>> but
>> isn't it possible to tell that the source ports are already configured?
> 
> Well, this is essentially what the documentation is attempting to convey.
> :-)
> 
> I can add this / change the existing wording, if you think it could help.

Yes please. The documentation is just missing the little fact that the DT can't
tell the difference between a sink and source port, hence the driver has to be
explicit about which ports to parse in a case like this.

Regards,

        Hans

Reply via email to