diff options
| -rw-r--r-- | drivers/of/base.c | 20 | ||||
| -rw-r--r-- | drivers/of/unittest.c | 30 | ||||
| -rw-r--r-- | include/linux/of.h | 14 |
3 files changed, 59 insertions, 5 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 99bc95e83d09..bdf051d0a7e6 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
| @@ -714,10 +714,15 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent, | |||
| 714 | { | 714 | { |
| 715 | struct device_node *child; | 715 | struct device_node *child; |
| 716 | int len = strchrnul(path, '/') - path; | 716 | int len = strchrnul(path, '/') - path; |
| 717 | int term; | ||
| 717 | 718 | ||
| 718 | if (!len) | 719 | if (!len) |
| 719 | return NULL; | 720 | return NULL; |
| 720 | 721 | ||
| 722 | term = strchrnul(path, ':') - path; | ||
| 723 | if (term < len) | ||
| 724 | len = term; | ||
| 725 | |||
| 721 | __for_each_child_of_node(parent, child) { | 726 | __for_each_child_of_node(parent, child) { |
| 722 | const char *name = strrchr(child->full_name, '/'); | 727 | const char *name = strrchr(child->full_name, '/'); |
| 723 | if (WARN(!name, "malformed device_node %s\n", child->full_name)) | 728 | if (WARN(!name, "malformed device_node %s\n", child->full_name)) |
| @@ -730,11 +735,14 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent, | |||
| 730 | } | 735 | } |
| 731 | 736 | ||
| 732 | /** | 737 | /** |
| 733 | * of_find_node_by_path - Find a node matching a full OF path | 738 | * of_find_node_opts_by_path - Find a node matching a full OF path |
| 734 | * @path: Either the full path to match, or if the path does not | 739 | * @path: Either the full path to match, or if the path does not |
| 735 | * start with '/', the name of a property of the /aliases | 740 | * start with '/', the name of a property of the /aliases |
| 736 | * node (an alias). In the case of an alias, the node | 741 | * node (an alias). In the case of an alias, the node |
| 737 | * matching the alias' value will be returned. | 742 | * matching the alias' value will be returned. |
| 743 | * @opts: Address of a pointer into which to store the start of | ||
| 744 | * an options string appended to the end of the path with | ||
| 745 | * a ':' separator. | ||
| 738 | * | 746 | * |
| 739 | * Valid paths: | 747 | * Valid paths: |
| 740 | * /foo/bar Full path | 748 | * /foo/bar Full path |
| @@ -744,11 +752,15 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent, | |||
| 744 | * Returns a node pointer with refcount incremented, use | 752 | * Returns a node pointer with refcount incremented, use |
| 745 | * of_node_put() on it when done. | 753 | * of_node_put() on it when done. |
| 746 | */ | 754 | */ |
| 747 | struct device_node *of_find_node_by_path(const char *path) | 755 | struct device_node *of_find_node_opts_by_path(const char *path, const char **opts) |
| 748 | { | 756 | { |
| 749 | struct device_node *np = NULL; | 757 | struct device_node *np = NULL; |
| 750 | struct property *pp; | 758 | struct property *pp; |
| 751 | unsigned long flags; | 759 | unsigned long flags; |
| 760 | const char *separator = strchr(path, ':'); | ||
| 761 | |||
| 762 | if (opts) | ||
| 763 | *opts = separator ? separator + 1 : NULL; | ||
| 752 | 764 | ||
| 753 | if (strcmp(path, "/") == 0) | 765 | if (strcmp(path, "/") == 0) |
| 754 | return of_node_get(of_root); | 766 | return of_node_get(of_root); |
| @@ -756,7 +768,7 @@ struct device_node *of_find_node_by_path(const char *path) | |||
| 756 | /* The path could begin with an alias */ | 768 | /* The path could begin with an alias */ |
| 757 | if (*path != '/') { | 769 | if (*path != '/') { |
| 758 | char *p = strchrnul(path, '/'); | 770 | char *p = strchrnul(path, '/'); |
| 759 | int len = p - path; | 771 | int len = separator ? separator - path : p - path; |
| 760 | 772 | ||
| 761 | /* of_aliases must not be NULL */ | 773 | /* of_aliases must not be NULL */ |
| 762 | if (!of_aliases) | 774 | if (!of_aliases) |
| @@ -785,7 +797,7 @@ struct device_node *of_find_node_by_path(const char *path) | |||
| 785 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 797 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 786 | return np; | 798 | return np; |
| 787 | } | 799 | } |
| 788 | EXPORT_SYMBOL(of_find_node_by_path); | 800 | EXPORT_SYMBOL(of_find_node_opts_by_path); |
| 789 | 801 | ||
| 790 | /** | 802 | /** |
| 791 | * of_find_node_by_name - Find a node by its "name" property | 803 | * of_find_node_by_name - Find a node by its "name" property |
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 7a7ae07d592f..1807a0458648 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c | |||
| @@ -47,6 +47,7 @@ static bool selftest_live_tree; | |||
| 47 | static void __init of_selftest_find_node_by_name(void) | 47 | static void __init of_selftest_find_node_by_name(void) |
| 48 | { | 48 | { |
| 49 | struct device_node *np; | 49 | struct device_node *np; |
| 50 | const char *options; | ||
| 50 | 51 | ||
| 51 | np = of_find_node_by_path("/testcase-data"); | 52 | np = of_find_node_by_path("/testcase-data"); |
| 52 | selftest(np && !strcmp("/testcase-data", np->full_name), | 53 | selftest(np && !strcmp("/testcase-data", np->full_name), |
| @@ -87,6 +88,35 @@ static void __init of_selftest_find_node_by_name(void) | |||
| 87 | np = of_find_node_by_path("testcase-alias/missing-path"); | 88 | np = of_find_node_by_path("testcase-alias/missing-path"); |
| 88 | selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name); | 89 | selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name); |
| 89 | of_node_put(np); | 90 | of_node_put(np); |
| 91 | |||
| 92 | np = of_find_node_opts_by_path("/testcase-data:testoption", &options); | ||
| 93 | selftest(np && !strcmp("testoption", options), | ||
| 94 | "option path test failed\n"); | ||
| 95 | of_node_put(np); | ||
| 96 | |||
| 97 | np = of_find_node_opts_by_path("/testcase-data:testoption", NULL); | ||
| 98 | selftest(np, "NULL option path test failed\n"); | ||
| 99 | of_node_put(np); | ||
| 100 | |||
| 101 | np = of_find_node_opts_by_path("testcase-alias:testaliasoption", | ||
| 102 | &options); | ||
| 103 | selftest(np && !strcmp("testaliasoption", options), | ||
| 104 | "option alias path test failed\n"); | ||
| 105 | of_node_put(np); | ||
| 106 | |||
| 107 | np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL); | ||
| 108 | selftest(np, "NULL option alias path test failed\n"); | ||
| 109 | of_node_put(np); | ||
| 110 | |||
| 111 | options = "testoption"; | ||
| 112 | np = of_find_node_opts_by_path("testcase-alias", &options); | ||
| 113 | selftest(np && !options, "option clearing test failed\n"); | ||
| 114 | of_node_put(np); | ||
| 115 | |||
| 116 | options = "testoption"; | ||
| 117 | np = of_find_node_opts_by_path("/", &options); | ||
| 118 | selftest(np && !options, "option clearing root node test failed\n"); | ||
| 119 | of_node_put(np); | ||
| 90 | } | 120 | } |
| 91 | 121 | ||
| 92 | static void __init of_selftest_dynamic(void) | 122 | static void __init of_selftest_dynamic(void) |
diff --git a/include/linux/of.h b/include/linux/of.h index aa01cf5852f8..8b021db3e16e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
| @@ -236,7 +236,13 @@ extern struct device_node *of_find_matching_node_and_match( | |||
| 236 | const struct of_device_id *matches, | 236 | const struct of_device_id *matches, |
| 237 | const struct of_device_id **match); | 237 | const struct of_device_id **match); |
| 238 | 238 | ||
| 239 | extern struct device_node *of_find_node_by_path(const char *path); | 239 | extern struct device_node *of_find_node_opts_by_path(const char *path, |
| 240 | const char **opts); | ||
| 241 | static inline struct device_node *of_find_node_by_path(const char *path) | ||
| 242 | { | ||
| 243 | return of_find_node_opts_by_path(path, NULL); | ||
| 244 | } | ||
| 245 | |||
| 240 | extern struct device_node *of_find_node_by_phandle(phandle handle); | 246 | extern struct device_node *of_find_node_by_phandle(phandle handle); |
| 241 | extern struct device_node *of_get_parent(const struct device_node *node); | 247 | extern struct device_node *of_get_parent(const struct device_node *node); |
| 242 | extern struct device_node *of_get_next_parent(struct device_node *node); | 248 | extern struct device_node *of_get_next_parent(struct device_node *node); |
| @@ -383,6 +389,12 @@ static inline struct device_node *of_find_node_by_path(const char *path) | |||
| 383 | return NULL; | 389 | return NULL; |
| 384 | } | 390 | } |
| 385 | 391 | ||
| 392 | static inline struct device_node *of_find_node_opts_by_path(const char *path, | ||
| 393 | const char **opts) | ||
| 394 | { | ||
| 395 | return NULL; | ||
| 396 | } | ||
| 397 | |||
| 386 | static inline struct device_node *of_get_parent(const struct device_node *node) | 398 | static inline struct device_node *of_get_parent(const struct device_node *node) |
| 387 | { | 399 | { |
| 388 | return NULL; | 400 | return NULL; |
