On 26/09/17 00:25, Sakari Ailus wrote: > v4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under > the device's own fwnode, it will follow child fwnodes with the given > property-value pair and return the resulting fwnode. > > Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx> > --- > drivers/media/v4l2-core/v4l2-fwnode.c | 201 ++++++++++++++++++++++++++++++++++ > 1 file changed, 201 insertions(+) > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c > index f739dfd16cf7..f93049c361e4 100644 > --- a/drivers/media/v4l2-core/v4l2-fwnode.c > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c > @@ -578,6 +578,207 @@ static int v4l2_fwnode_reference_parse( > return ret; > } > > +/* > + * v4l2_fwnode_reference_get_int_prop - parse a reference with integer > + * arguments > + * @dev: struct device pointer > + * @notifier: notifier for @dev > + * @prop: the name of the property > + * @index: the index of the reference to get > + * @props: the array of integer property names > + * @nprops: the number of integer property names in @nprops > + * > + * Find fwnodes referred to by a property @prop, then under that > + * iteratively, @nprops times, follow each child node which has a > + * property in @props array at a given child index the value of which > + * matches the integer argument at an index. "at an index". Still makes no sense to me. Which index? > + * > + * For example, if this function was called with arguments and values > + * @dev corresponding to device "SEN", @prop == "flash-leds", @index > + * == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below > + * it would return the node marked with THISONE. The @dev argument in > + * the ASL below. I know I asked for this before, but can you change the example to one where nprops = 2? I think that will help understanding this. > + * > + * Device (LED) > + * { > + * Name (_DSD, Package () { > + * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), > + * Package () { > + * Package () { "led0", "LED0" }, > + * Package () { "led1", "LED1" }, > + * } > + * }) > + * Name (LED0, Package () { > + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), > + * Package () { > + * Package () { "led", 0 }, > + * } > + * }) > + * Name (LED1, Package () { > + * // THISONE > + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), > + * Package () { > + * Package () { "led", 1 }, > + * } > + * }) > + * } > + * > + * Device (SEN) > + * { > + * Name (_DSD, Package () { > + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), > + * Package () { > + * Package () { > + * "flash-leds", > + * Package () { ^LED, 0, ^LED, 1 }, > + * } > + * } > + * }) > + * } > + * > + * where > + * > + * LED LED driver device > + * LED0 First LED > + * LED1 Second LED > + * SEN Camera sensor device (or another device the LED is > + * related to) > + * > + * Return: 0 on success > + * -ENOENT if no entries (or the property itself) were found > + * -EINVAL if property parsing otherwise failed > + * -ENOMEM if memory allocation failed > + */ > +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop( > + struct fwnode_handle *fwnode, const char *prop, unsigned int index, > + const char **props, unsigned int nprops) > +{ > + struct fwnode_reference_args fwnode_args; > + unsigned int *args = fwnode_args.args; > + struct fwnode_handle *child; > + int ret; > + > + /* > + * Obtain remote fwnode as well as the integer arguments. > + * > + * Note that right now both -ENODATA and -ENOENT may signal > + * out-of-bounds access. Return -ENOENT in that case. > + */ > + ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops, > + index, &fwnode_args); > + if (ret) > + return ERR_PTR(ret == -ENODATA ? -ENOENT : ret); > + > + /* > + * Find a node in the tree under the referred fwnode corresponding the corresponding -> corresponding to > + * integer arguments. > + */ > + fwnode = fwnode_args.fwnode; > + while (nprops--) { > + u32 val; > + > + /* Loop over all child nodes under fwnode. */ > + fwnode_for_each_child_node(fwnode, child) { > + if (fwnode_property_read_u32(child, *props, &val)) > + continue; > + > + /* Found property, see if its value matches. */ > + if (val == *args) > + break; > + } > + > + fwnode_handle_put(fwnode); > + > + /* No property found; return an error here. */ > + if (!child) { > + fwnode = ERR_PTR(-ENOENT); > + break; > + } > + > + props++; > + args++; > + fwnode = child; > + } > + > + return fwnode; > +} > + > +/* > + * v4l2_fwnode_reference_parse_int_props - parse references for async sub-devices > + * @dev: struct device pointer > + * @notifier: notifier for @dev > + * @prop: the name of the property > + * @props: the array of integer property names > + * @nprops: the number of integer properties > + * > + * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in > + * property @prop with integer arguments with child nodes matching in properties > + * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier > + * accordingly. > + * > + * While it is technically possible to use this function on DT, it is only > + * meaningful on ACPI. On Device tree you can refer to any node in the tree but > + * on ACPI the references are limited to devices. > + * > + * Return: 0 on success > + * -ENOENT if no entries (or the property itself) were found > + * -EINVAL if property parsing otherwisefailed > + * -ENOMEM if memory allocation failed > + */ > +static int v4l2_fwnode_reference_parse_int_props( > + struct device *dev, struct v4l2_async_notifier *notifier, > + const char *prop, const char **props, unsigned int nprops) > +{ > + struct fwnode_handle *fwnode; > + unsigned int index; > + int ret; > + > + for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop( > + dev_fwnode(dev), prop, index, props, > + nprops))); index++) > + fwnode_handle_put(fwnode); > + > + /* > + * Note that right now both -ENODATA and -ENOENT may signal > + * out-of-bounds access. Return the error in cases other than that. > + */ > + if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA) > + return PTR_ERR(fwnode); > + > + ret = v4l2_async_notifier_realloc(notifier, > + notifier->num_subdevs + index); > + if (ret) > + return -ENOMEM; > + > + for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop( > + dev_fwnode(dev), prop, index, props, > + nprops))); index++) { > + struct v4l2_async_subdev *asd; > + > + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { > + ret = -EINVAL; > + goto error; > + } > + > + asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL); > + if (!asd) { > + ret = -ENOMEM; > + goto error; > + } > + > + notifier->subdevs[notifier->num_subdevs] = asd; > + asd->match.fwnode.fwnode = fwnode; > + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; > + notifier->num_subdevs++; > + } > + > + return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); > + > +error: > + fwnode_handle_put(fwnode); > + return ret; > +} > + > MODULE_LICENSE("GPL"); > MODULE_AUTHOR("Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx>"); > MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx>"); > Regards, Hans