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 /drivers/of | |
| 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>
Diffstat (limited to 'drivers/of')
| -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; |
