]> Pileus Git - ~andy/linux/blobdiff - drivers/of/base.c
Merge branch 'akpm' (Andrew's patch-bomb)
[~andy/linux] / drivers / of / base.c
index 9b6588ef067334a51558c333eb9a0467dd3ca3c2..580644986945cb704d94de09bb602848fd13aede 100644 (file)
@@ -88,7 +88,7 @@ int of_n_size_cells(struct device_node *np)
 }
 EXPORT_SYMBOL(of_n_size_cells);
 
-#if !defined(CONFIG_SPARC)   /* SPARC doesn't do ref counting (yet) */
+#if defined(CONFIG_OF_DYNAMIC)
 /**
  *     of_node_get - Increment refcount of a node
  *     @node:  Node to inc refcount, NULL is supported to
@@ -161,7 +161,7 @@ void of_node_put(struct device_node *node)
                kref_put(&node->kref, of_node_release);
 }
 EXPORT_SYMBOL(of_node_put);
-#endif /* !CONFIG_SPARC */
+#endif /* CONFIG_OF_DYNAMIC */
 
 struct property *of_find_property(const struct device_node *np,
                                  const char *name,
@@ -752,7 +752,7 @@ int of_property_read_string_index(struct device_node *np, const char *propname,
 
        for (i = 0; total < prop->length; total += l, p += l) {
                l = strlen(p) + 1;
-               if ((*p != 0) && (i++ == index)) {
+               if (i++ == index) {
                        *output = p;
                        return 0;
                }
@@ -761,6 +761,42 @@ int of_property_read_string_index(struct device_node *np, const char *propname,
 }
 EXPORT_SYMBOL_GPL(of_property_read_string_index);
 
+/**
+ * of_property_match_string() - Find string in a list and return index
+ * @np: pointer to node containing string list property
+ * @propname: string list property name
+ * @string: pointer to string to search for in string list
+ *
+ * This function searches a string list property and returns the index
+ * of a specific string value.
+ */
+int of_property_match_string(struct device_node *np, const char *propname,
+                            const char *string)
+{
+       struct property *prop = of_find_property(np, propname, NULL);
+       size_t l;
+       int i;
+       const char *p, *end;
+
+       if (!prop)
+               return -EINVAL;
+       if (!prop->value)
+               return -ENODATA;
+
+       p = prop->value;
+       end = p + prop->length;
+
+       for (i = 0; p < end; i++, p += l) {
+               l = strlen(p) + 1;
+               if (p + l > end)
+                       return -EILSEQ;
+               pr_debug("comparing %s with %s\n", string, p);
+               if (strcmp(string, p) == 0)
+                       return i; /* Found it; return index */
+       }
+       return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(of_property_match_string);
 
 /**
  * of_property_count_strings - Find and return the number of strings from a
@@ -790,11 +826,9 @@ int of_property_count_strings(struct device_node *np, const char *propname)
 
        p = prop->value;
 
-       for (i = 0; total < prop->length; total += l, p += l) {
+       for (i = 0; total < prop->length; total += l, p += l, i++)
                l = strlen(p) + 1;
-               if (*p != 0)
-                       i++;
-       }
+
        return i;
 }
 EXPORT_SYMBOL_GPL(of_property_count_strings);
@@ -824,17 +858,19 @@ of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
 EXPORT_SYMBOL(of_parse_phandle);
 
 /**
- * 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:
  *
@@ -851,94 +887,96 @@ EXPORT_SYMBOL(of_parse_phandle);
  * }
  *
  * 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,
+int of_parse_phandle_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)
+                               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 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 -EINVAL;
        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;
+               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\n",
-                                np->full_name);
-                       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);
+                               break;
+                       }
+                       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);
+                               break;
+                       }
 
-               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;
+                       /*
+                        * 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);
+                               break;
+                       }
                }
 
-               list += be32_to_cpup(cells);
-               if (list > list_end) {
-                       pr_debug("%s: insufficient arguments length\n",
-                                np->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.
+                */
+               if (cur_index == index) {
+                       if (!phandle)
+                               return -ENOENT;
+
+                       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++);
+                       }
+                       return 0;
                }
-next:
-               if (cur_index == index)
-                       break;
 
                of_node_put(node);
                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;
-
-       return 0;
-err1:
-       of_node_put(node);
-err0:
-       pr_debug("%s failed with status %d\n", __func__, ret);
-       return ret;
+       /* Loop exited without finding a valid entry; return an error */
+       if (node)
+               of_node_put(node);
+       return -EINVAL;
 }
-EXPORT_SYMBOL(of_parse_phandles_with_args);
+EXPORT_SYMBOL(of_parse_phandle_with_args);
 
 /**
  * prom_add_property - Add a property to a node
@@ -1159,7 +1197,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
        if (!of_aliases)
                return;
 
-       for_each_property(pp, of_aliases->properties) {
+       for_each_property_of_node(of_aliases, pp) {
                const char *start = pp->name;
                const char *end = start + strlen(start);
                struct device_node *np;