Signed-off-by: Lucas Stach <[email protected]>
---
 drivers/of/base.c | 168 +++++++++++++++++++++++++++++++-----------------------
 drivers/of/gpio.c |   9 ++-
 include/of.h      |  14 +++--
 3 files changed, 111 insertions(+), 80 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 4241e65..b3d012c 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -406,17 +406,19 @@ int of_property_write_u32_array(struct device_node *np,
 }
 
 /**
- * of_parse_phandles_with_args - Find a node pointed by phandle in a list
+ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
  * @np:                pointer to a device tree node containing a list
  * @list_name: property name that contains a list
  * @cells_name:        property name that specifies phandles' arguments count
  * @index:     index of a phandle to parse out
- * @out_node:  optional pointer to device_node struct pointer (will be filled)
- * @out_args:  optional pointer to arguments pointer (will be filled)
+ * @out_args:  optional pointer to output arguments structure (will be filled)
  *
  * This function is useful to parse lists of phandles and their arguments.
- * Returns 0 on success and fills out_node and out_args, on error returns
- * appropriate errno value.
+ * Returns 0 on success and fills out_args, on error returns appropriate
+ * errno value.
+ *
+ * Caller is responsible to call of_node_put() on the returned out_args->node
+ * pointer.
  *
  * Example:
  *
@@ -433,92 +435,116 @@ int of_property_write_u32_array(struct device_node *np,
  * }
  *
  * To get a device_node of the `node2' node you may call this:
- * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
+ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
  */
-int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
-                               const char *cells_name, int index,
-                               struct device_node **out_node,
-                               const void **out_args)
+static int __of_parse_phandle_with_args(const struct device_node *np,
+                                       const char *list_name,
+                                       const char *cells_name, int index,
+                                       struct of_phandle_args *out_args)
 {
-       int ret = -EINVAL;
-       const __be32 *list;
-       const __be32 *list_end;
-       int size;
-       int cur_index = 0;
+       const __be32 *list, *list_end;
+       int rc = 0, size, cur_index = 0;
+       uint32_t count = 0;
        struct device_node *node = NULL;
-       const void *args = NULL;
+       phandle phandle;
 
+       /* Retrieve the phandle list property */
        list = of_get_property(np, list_name, &size);
-       if (!list) {
-               ret = -ENOENT;
-               goto err0;
-       }
+       if (!list)
+               return -ENOENT;
        list_end = list + size / sizeof(*list);
 
+       /* Loop over the phandles until all the requested entry is found */
        while (list < list_end) {
-               const __be32 *cells;
-               phandle phandle;
+               rc = -EINVAL;
+               count = 0;
 
+               /*
+                * If phandle is 0, then it is an empty entry with no
+                * arguments.  Skip forward to the next entry.
+                */
                phandle = be32_to_cpup(list++);
-               args = list;
-
-               /* one cell hole in the list = <>; */
-               if (!phandle)
-                       goto next;
-
-               node = of_find_node_by_phandle(phandle);
-               if (!node) {
-                       pr_debug("%s: could not find phandle %d\n",
-                                np->full_name, phandle);
-                       goto err0;
+               if (phandle) {
+                       /*
+                        * Find the provider node and parse the #*-cells
+                        * property to determine the argument length
+                        */
+                       node = of_find_node_by_phandle(phandle);
+                       if (!node) {
+                               pr_err("%s: could not find phandle\n",
+                                        np->full_name);
+                               goto err;
+                       }
+                       if (of_property_read_u32(node, cells_name, &count)) {
+                               pr_err("%s: could not get %s for %s\n",
+                                        np->full_name, cells_name,
+                                        node->full_name);
+                               goto err;
+                       }
+
+                       /*
+                        * Make sure that the arguments actually fit in the
+                        * remaining property data length
+                        */
+                       if (list + count > list_end) {
+                               pr_err("%s: arguments longer than property\n",
+                                        np->full_name);
+                               goto err;
+                       }
                }
 
-               cells = of_get_property(node, cells_name, &size);
-               if (!cells || size != sizeof(*cells)) {
-                       pr_debug("%s: could not get %s for %s\n",
-                                np->full_name, cells_name, node->full_name);
-                       goto err1;
+               /*
+                * All of the error cases above bail out of the loop, so at
+                * this point, the parsing is successful. If the requested
+                * index matches, then fill the out_args structure and return,
+                * or return -ENOENT for an empty entry.
+                */
+               rc = -ENOENT;
+               if (cur_index == index) {
+                       if (!phandle)
+                               goto err;
+
+                       if (out_args) {
+                               int i;
+                               if (WARN_ON(count > MAX_PHANDLE_ARGS))
+                                       count = MAX_PHANDLE_ARGS;
+                               out_args->np = node;
+                               out_args->args_count = count;
+                               for (i = 0; i < count; i++)
+                                       out_args->args[i] = 
be32_to_cpup(list++);
+                       }
+
+                       /* Found it! return success */
+                       return 0;
                }
 
-               list += be32_to_cpup(cells);
-               if (list > list_end) {
-                       pr_debug("%s: insufficient arguments length\n",
-                                np->full_name);
-                       goto err1;
-               }
-next:
-               if (cur_index == index)
-                       break;
-
                node = NULL;
-               args = NULL;
+               list += count;
                cur_index++;
        }
 
-       if (!node) {
-               /*
-                * args w/o node indicates that the loop above has stopped at
-                * the 'hole' cell. Report this differently.
-                */
-               if (args)
-                       ret = -EEXIST;
-               else
-                       ret = -ENOENT;
-               goto err0;
-       }
-
-       if (out_node)
-               *out_node = node;
-       if (out_args)
-               *out_args = args;
+       /*
+        * Unlock node before returning result; will be one of:
+        * -ENOENT : index is for empty phandle
+        * -EINVAL : parsing error on data
+        * [1..n]  : Number of phandle (count mode; when index = -1)
+        */
+       rc = index < 0 ? cur_index : -ENOENT;
+ err:
+       return rc;
+}
 
-       return 0;
-err1:
-err0:
-       pr_debug("%s failed with status %d\n", __func__, ret);
-       return ret;
+int of_parse_phandle_with_args(const struct device_node *np,
+                               const char *list_name,
+                               const char *cells_name, int index,
+                               struct of_phandle_args *out_args)
+{
+       if (index < 0)
+               return -EINVAL;
+       return __of_parse_phandle_with_args(np, list_name, cells_name,
+                                           index, out_args);
 }
-EXPORT_SYMBOL(of_parse_phandles_with_args);
+EXPORT_SYMBOL(of_parse_phandle_with_args);
 
 /**
  * of_machine_is_compatible - Test root of device tree for a given compatible 
value
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 83b72c0..cd3e1b7 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -9,17 +9,16 @@ int of_get_named_gpio(struct device_node *np,
                                    const char *propname, int index)
 {
        int ret;
-       struct device_node *gpio_np;
-       const void *gpio_spec;
+       struct of_phandle_args gpio_spec;
 
-       ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
-                                         &gpio_np, &gpio_spec);
+       ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
+                                        &gpio_spec);
        if (ret) {
                pr_debug("%s: can't parse gpios property: %d\n", __func__, ret);
                return -EINVAL;
        }
 
-       ret = gpio_get_num(gpio_np->device, be32_to_cpup(gpio_spec));
+       ret = gpio_get_num(gpio_spec.np->device, gpio_spec.args[0]);
        if (ret < 0)
                return ret;
 
diff --git a/include/of.h b/include/of.h
index 300b706..f00d1b4 100644
--- a/include/of.h
+++ b/include/of.h
@@ -32,6 +32,13 @@ struct device_node {
        phandle phandle;
 };
 
+#define MAX_PHANDLE_ARGS 8
+struct of_phandle_args {
+       struct device_node *np;
+       int args_count;
+       uint32_t args[MAX_PHANDLE_ARGS];
+};
+
 struct of_device_id {
        char *compatible;
        unsigned long data;
@@ -130,10 +137,9 @@ static inline int of_property_write_u32(struct device_node 
*np,
 const void *of_get_property(const struct device_node *np, const char *name,
                         int *lenp);
 
-int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
-                               const char *cells_name, int index,
-                               struct device_node **out_node,
-                               const void **out_args);
+int of_parse_phandle_with_args(const struct device_node *np,
+                              const char *list_name, const char *cells_name,
+                              int index, struct of_phandle_args *out_args);
 
 int of_get_named_gpio(struct device_node *np,
                                    const char *propname, int index);
-- 
1.8.2.1


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to