diff options
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 146 |
1 files changed, 75 insertions, 71 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 9b6588ef0673..c6db9ab9046e 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -824,17 +824,19 @@ of_parse_phandle(struct device_node *np, const char *phandle_name, int index) | |||
824 | EXPORT_SYMBOL(of_parse_phandle); | 824 | EXPORT_SYMBOL(of_parse_phandle); |
825 | 825 | ||
826 | /** | 826 | /** |
827 | * of_parse_phandles_with_args - Find a node pointed by phandle in a list | 827 | * of_parse_phandle_with_args() - Find a node pointed by phandle in a list |
828 | * @np: pointer to a device tree node containing a list | 828 | * @np: pointer to a device tree node containing a list |
829 | * @list_name: property name that contains a list | 829 | * @list_name: property name that contains a list |
830 | * @cells_name: property name that specifies phandles' arguments count | 830 | * @cells_name: property name that specifies phandles' arguments count |
831 | * @index: index of a phandle to parse out | 831 | * @index: index of a phandle to parse out |
832 | * @out_node: optional pointer to device_node struct pointer (will be filled) | 832 | * @out_args: optional pointer to output arguments structure (will be filled) |
833 | * @out_args: optional pointer to arguments pointer (will be filled) | ||
834 | * | 833 | * |
835 | * This function is useful to parse lists of phandles and their arguments. | 834 | * This function is useful to parse lists of phandles and their arguments. |
836 | * Returns 0 on success and fills out_node and out_args, on error returns | 835 | * Returns 0 on success and fills out_args, on error returns appropriate |
837 | * appropriate errno value. | 836 | * errno value. |
837 | * | ||
838 | * Caller is responsible to call of_node_put() on the returned out_args->node | ||
839 | * pointer. | ||
838 | * | 840 | * |
839 | * Example: | 841 | * Example: |
840 | * | 842 | * |
@@ -851,94 +853,96 @@ EXPORT_SYMBOL(of_parse_phandle); | |||
851 | * } | 853 | * } |
852 | * | 854 | * |
853 | * To get a device_node of the `node2' node you may call this: | 855 | * To get a device_node of the `node2' node you may call this: |
854 | * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); | 856 | * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); |
855 | */ | 857 | */ |
856 | int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | 858 | int of_parse_phandle_with_args(struct device_node *np, const char *list_name, |
857 | const char *cells_name, int index, | 859 | const char *cells_name, int index, |
858 | struct device_node **out_node, | 860 | struct of_phandle_args *out_args) |
859 | const void **out_args) | ||
860 | { | 861 | { |
861 | int ret = -EINVAL; | 862 | const __be32 *list, *list_end; |
862 | const __be32 *list; | 863 | int size, cur_index = 0; |
863 | const __be32 *list_end; | 864 | uint32_t count = 0; |
864 | int size; | ||
865 | int cur_index = 0; | ||
866 | struct device_node *node = NULL; | 865 | struct device_node *node = NULL; |
867 | const void *args = NULL; | 866 | phandle phandle; |
868 | 867 | ||
868 | /* Retrieve the phandle list property */ | ||
869 | list = of_get_property(np, list_name, &size); | 869 | list = of_get_property(np, list_name, &size); |
870 | if (!list) { | 870 | if (!list) |
871 | ret = -ENOENT; | 871 | return -EINVAL; |
872 | goto err0; | ||
873 | } | ||
874 | list_end = list + size / sizeof(*list); | 872 | list_end = list + size / sizeof(*list); |
875 | 873 | ||
874 | /* Loop over the phandles until all the requested entry is found */ | ||
876 | while (list < list_end) { | 875 | while (list < list_end) { |
877 | const __be32 *cells; | 876 | count = 0; |
878 | phandle phandle; | ||
879 | 877 | ||
878 | /* | ||
879 | * If phandle is 0, then it is an empty entry with no | ||
880 | * arguments. Skip forward to the next entry. | ||
881 | */ | ||
880 | phandle = be32_to_cpup(list++); | 882 | phandle = be32_to_cpup(list++); |
881 | args = list; | 883 | if (phandle) { |
882 | 884 | /* | |
883 | /* one cell hole in the list = <>; */ | 885 | * Find the provider node and parse the #*-cells |
884 | if (!phandle) | 886 | * property to determine the argument length |
885 | goto next; | 887 | */ |
886 | 888 | node = of_find_node_by_phandle(phandle); | |
887 | node = of_find_node_by_phandle(phandle); | 889 | if (!node) { |
888 | if (!node) { | 890 | pr_err("%s: could not find phandle\n", |
889 | pr_debug("%s: could not find phandle\n", | 891 | np->full_name); |
890 | np->full_name); | 892 | break; |
891 | goto err0; | 893 | } |
892 | } | 894 | if (of_property_read_u32(node, cells_name, &count)) { |
895 | pr_err("%s: could not get %s for %s\n", | ||
896 | np->full_name, cells_name, | ||
897 | node->full_name); | ||
898 | break; | ||
899 | } | ||
893 | 900 | ||
894 | cells = of_get_property(node, cells_name, &size); | 901 | /* |
895 | if (!cells || size != sizeof(*cells)) { | 902 | * Make sure that the arguments actually fit in the |
896 | pr_debug("%s: could not get %s for %s\n", | 903 | * remaining property data length |
897 | np->full_name, cells_name, node->full_name); | 904 | */ |
898 | goto err1; | 905 | if (list + count > list_end) { |
906 | pr_err("%s: arguments longer than property\n", | ||
907 | np->full_name); | ||
908 | break; | ||
909 | } | ||
899 | } | 910 | } |
900 | 911 | ||
901 | list += be32_to_cpup(cells); | 912 | /* |
902 | if (list > list_end) { | 913 | * All of the error cases above bail out of the loop, so at |
903 | pr_debug("%s: insufficient arguments length\n", | 914 | * this point, the parsing is successful. If the requested |
904 | np->full_name); | 915 | * index matches, then fill the out_args structure and return, |
905 | goto err1; | 916 | * or return -ENOENT for an empty entry. |
917 | */ | ||
918 | if (cur_index == index) { | ||
919 | if (!phandle) | ||
920 | return -ENOENT; | ||
921 | |||
922 | if (out_args) { | ||
923 | int i; | ||
924 | if (WARN_ON(count > MAX_PHANDLE_ARGS)) | ||
925 | count = MAX_PHANDLE_ARGS; | ||
926 | out_args->np = node; | ||
927 | out_args->args_count = count; | ||
928 | for (i = 0; i < count; i++) | ||
929 | out_args->args[i] = be32_to_cpup(list++); | ||
930 | } | ||
931 | return 0; | ||
906 | } | 932 | } |
907 | next: | ||
908 | if (cur_index == index) | ||
909 | break; | ||
910 | 933 | ||
911 | of_node_put(node); | 934 | of_node_put(node); |
912 | node = NULL; | 935 | node = NULL; |
913 | args = NULL; | 936 | list += count; |
914 | cur_index++; | 937 | cur_index++; |
915 | } | 938 | } |
916 | 939 | ||
917 | if (!node) { | 940 | /* Loop exited without finding a valid entry; return an error */ |
918 | /* | 941 | if (node) |
919 | * args w/o node indicates that the loop above has stopped at | 942 | of_node_put(node); |
920 | * the 'hole' cell. Report this differently. | 943 | return -EINVAL; |
921 | */ | ||
922 | if (args) | ||
923 | ret = -EEXIST; | ||
924 | else | ||
925 | ret = -ENOENT; | ||
926 | goto err0; | ||
927 | } | ||
928 | |||
929 | if (out_node) | ||
930 | *out_node = node; | ||
931 | if (out_args) | ||
932 | *out_args = args; | ||
933 | |||
934 | return 0; | ||
935 | err1: | ||
936 | of_node_put(node); | ||
937 | err0: | ||
938 | pr_debug("%s failed with status %d\n", __func__, ret); | ||
939 | return ret; | ||
940 | } | 944 | } |
941 | EXPORT_SYMBOL(of_parse_phandles_with_args); | 945 | EXPORT_SYMBOL(of_parse_phandle_with_args); |
942 | 946 | ||
943 | /** | 947 | /** |
944 | * prom_add_property - Add a property to a node | 948 | * prom_add_property - Add a property to a node |