diff options
author | Grant Likely <grant.likely@linaro.org> | 2014-03-14 13:07:12 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-05-22 22:35:06 -0400 |
commit | c22e650e66b862babe9c00bebb20b8029c7b0362 (patch) | |
tree | 21c0c5115af3cb4cec650b818d1ec03839a0fe0b | |
parent | 0d0e02d605c5696a5076510f564fefe659127aa4 (diff) |
of: Make of_find_node_by_path() handle /aliases
Make of_find_node_by_path() handle aliases as prefixes. To make this
work the name search is refactored to search by path component instead
of by full string. This should be a more efficient search, and it makes
it possible to start a search at a subnode of a tree.
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[grant.likely: Rework to not require allocating at runtime]
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Grant Likely <grant.likely@linaro.org>
-rw-r--r-- | drivers/of/base.c | 67 |
1 files changed, 61 insertions, 6 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 9df50c74162c..e67b308819c9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -783,23 +783,78 @@ struct device_node *of_get_child_by_name(const struct device_node *node, | |||
783 | } | 783 | } |
784 | EXPORT_SYMBOL(of_get_child_by_name); | 784 | EXPORT_SYMBOL(of_get_child_by_name); |
785 | 785 | ||
786 | static struct device_node *__of_find_node_by_path(struct device_node *parent, | ||
787 | const char *path) | ||
788 | { | ||
789 | struct device_node *child; | ||
790 | int len = strchrnul(path, '/') - path; | ||
791 | |||
792 | if (!len) | ||
793 | return NULL; | ||
794 | |||
795 | __for_each_child_of_node(parent, child) { | ||
796 | const char *name = strrchr(child->full_name, '/'); | ||
797 | if (WARN(!name, "malformed device_node %s\n", child->full_name)) | ||
798 | continue; | ||
799 | name++; | ||
800 | if (strncmp(path, name, len) == 0 && (strlen(name) == len)) | ||
801 | return child; | ||
802 | } | ||
803 | return NULL; | ||
804 | } | ||
805 | |||
786 | /** | 806 | /** |
787 | * of_find_node_by_path - Find a node matching a full OF path | 807 | * of_find_node_by_path - Find a node matching a full OF path |
788 | * @path: The full path to match | 808 | * @path: Either the full path to match, or if the path does not |
809 | * start with '/', the name of a property of the /aliases | ||
810 | * node (an alias). In the case of an alias, the node | ||
811 | * matching the alias' value will be returned. | ||
812 | * | ||
813 | * Valid paths: | ||
814 | * /foo/bar Full path | ||
815 | * foo Valid alias | ||
816 | * foo/bar Valid alias + relative path | ||
789 | * | 817 | * |
790 | * Returns a node pointer with refcount incremented, use | 818 | * Returns a node pointer with refcount incremented, use |
791 | * of_node_put() on it when done. | 819 | * of_node_put() on it when done. |
792 | */ | 820 | */ |
793 | struct device_node *of_find_node_by_path(const char *path) | 821 | struct device_node *of_find_node_by_path(const char *path) |
794 | { | 822 | { |
795 | struct device_node *np = of_allnodes; | 823 | struct device_node *np = NULL; |
824 | struct property *pp; | ||
796 | unsigned long flags; | 825 | unsigned long flags; |
797 | 826 | ||
827 | if (strcmp(path, "/") == 0) | ||
828 | return of_node_get(of_allnodes); | ||
829 | |||
830 | /* The path could begin with an alias */ | ||
831 | if (*path != '/') { | ||
832 | char *p = strchrnul(path, '/'); | ||
833 | int len = p - path; | ||
834 | |||
835 | /* of_aliases must not be NULL */ | ||
836 | if (!of_aliases) | ||
837 | return NULL; | ||
838 | |||
839 | for_each_property_of_node(of_aliases, pp) { | ||
840 | if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) { | ||
841 | np = of_find_node_by_path(pp->value); | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | if (!np) | ||
846 | return NULL; | ||
847 | path = p; | ||
848 | } | ||
849 | |||
850 | /* Step down the tree matching path components */ | ||
798 | raw_spin_lock_irqsave(&devtree_lock, flags); | 851 | raw_spin_lock_irqsave(&devtree_lock, flags); |
799 | for (; np; np = np->allnext) { | 852 | if (!np) |
800 | if (np->full_name && (of_node_cmp(np->full_name, path) == 0) | 853 | np = of_node_get(of_allnodes); |
801 | && of_node_get(np)) | 854 | while (np && *path == '/') { |
802 | break; | 855 | path++; /* Increment past '/' delimiter */ |
856 | np = __of_find_node_by_path(np, path); | ||
857 | path = strchrnul(path, '/'); | ||
803 | } | 858 | } |
804 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 859 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
805 | return np; | 860 | return np; |