Make of_find_node_by_path() handle aliases as prefixes. Originally by David Daney <ddaney@xxxxxxxxxxxxxxxxxx>, but reworked according to remark by Grant Likely. Handles all cases without allocating memory as requested by Grant Likely <grant.likely@xxxxxxxxxx> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@xxxxxxxxxxxx> --- drivers/of/base.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 7083fad..19bcdb4 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -773,22 +773,83 @@ EXPORT_SYMBOL(of_get_child_by_name); /** * of_find_node_by_path - Find a node matching a full OF path * @path: The full path to match + * @path: Either the full path to match, or if the path does not + * start with '/', the name of a property of the /aliases + * node (an alias). In the case of an alias, the node + * matching the alias' value will be returned. + * + * Valid paths: + * /foo/bar Full path + * foo Valid alias + * foo/bar Valid alias + relative path * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */ struct device_node *of_find_node_by_path(const char *path) { - struct device_node *np = of_allnodes; + struct device_node *np = NULL; + int len; + const char *p = NULL; + struct property *prop; unsigned long flags; + /* under lock (not very nice) */ raw_spin_lock_irqsave(&devtree_lock, flags); - for (; np; np = np->allnext) { - if (np->full_name && (of_node_cmp(np->full_name, path) == 0) - && of_node_get(np)) + + len = strlen(path); + + /* path begins with an alias */ + if (path[0] != '/') { + + /* now find the relative path (if any)*/ + p = strchr(path, '/'); + if (p != NULL) + len = p - path; + + /* of_aliases must not be NULL */ + if (!of_aliases) + goto out; + + /* find matching alias */ + for_each_property_of_node(of_aliases, prop) + if (strlen(prop->name) == len && + strncmp(prop->name, path, len) == 0) + break; + + /* not found; bail */ + if (prop == NULL) + goto out; + + path = prop->value; + } + + /* path lookup */ + for_each_of_allnodes(np) { + + if (!np->full_name) + continue; + + if (p == NULL) { + /* full component */ + if (strcasecmp(np->full_name, path) != 0) + continue; + } else { + /* last component (including '/') */ + if (strncasecmp(np->full_name, path, len) != 0) + continue; + + if (strcasecmp(np->full_name + len, p) != 0) + continue; + } + + if (of_node_get(np)) break; } + +out: raw_spin_unlock_irqrestore(&devtree_lock, flags); + return np; } EXPORT_SYMBOL(of_find_node_by_path); -- 1.7.12 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html