From 075bfc9575aedca15e61f5f1cfa300409e2979fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 23 Oct 2021 17:26:07 -0600 Subject: [PATCH] dm: core: Add a way to obtain a string list At present we support reading a string list a string at a time. Apart from being inefficient, this makes it impossible to separate reading of the devicetree into the of_to_plat() method where it belongs, since any code which needs access to the string must read it from the devicetree. Add a function which returns the string property as an array of pointers to the strings, which is easily used by clients. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 26 ++++++++++++++++++++++++++ drivers/core/read.c | 6 ++++++ include/dm/ofnode.h | 20 ++++++++++++++++++++ include/dm/read.h | 28 ++++++++++++++++++++++++++++ test/dm/ofnode.c | 20 ++++++++++++++++++++ 5 files changed, 100 insertions(+) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 08705ef..709bea2 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -456,6 +456,32 @@ int ofnode_read_string_count(ofnode node, const char *property) } } +int ofnode_read_string_list(ofnode node, const char *property, + const char ***listp) +{ + const char **prop; + int count; + int i; + + *listp = NULL; + count = ofnode_read_string_count(node, property); + if (count < 0) + return count; + if (!count) + return 0; + + prop = calloc(count + 1, sizeof(char *)); + if (!prop) + return -ENOMEM; + + for (i = 0; i < count; i++) + ofnode_read_string_index(node, property, i, &prop[i]); + prop[count] = NULL; + *listp = prop; + + return count; +} + static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in, struct ofnode_phandle_args *out) { diff --git a/drivers/core/read.c b/drivers/core/read.c index 4307ca4..31f9e78 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -205,6 +205,12 @@ int dev_read_string_count(const struct udevice *dev, const char *propname) return ofnode_read_string_count(dev_ofnode(dev), propname); } +int dev_read_string_list(const struct udevice *dev, const char *propname, + const char ***listp) +{ + return ofnode_read_string_list(dev_ofnode(dev), propname, listp); +} + int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name, const char *cells_name, int cell_count, int index, struct ofnode_phandle_args *out_args) diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 0eae8f9..6601bd8 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -610,6 +610,26 @@ int ofnode_read_string_index(ofnode node, const char *propname, int index, int ofnode_read_string_count(ofnode node, const char *property); /** + * ofnode_read_string_list() - read a list of strings + * + * This produces a list of string pointers with each one pointing to a string + * in the string list. If the property does not exist, it returns {NULL}. + * + * The data is allocated and the caller is reponsible for freeing the return + * value (the list of string pointers). The strings themselves may not be + * changed as they point directly into the devicetree property. + * + * @node: node to check + * @listp: returns an allocated, NULL-terminated list of strings if the return + * value is > 0, else is set to NULL + * @return number of strings in list, 0 if none, -ENOMEM if out of memory, + * -EINVAL if no such property, -EENODATA if property is empty + * @return: NULL-terminated list of strings (NULL if no property or empty) + */ +int ofnode_read_string_list(ofnode node, const char *property, + const char ***listp); + +/** * ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list * * This function is useful to parse lists of phandles and their arguments. diff --git a/include/dm/read.h b/include/dm/read.h index 890bf3d..75c6ad6 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -371,6 +371,27 @@ int dev_read_string_index(const struct udevice *dev, const char *propname, * number of strings in the list, or -ve error value if not found */ int dev_read_string_count(const struct udevice *dev, const char *propname); + +/** + * dev_read_string_list() - read a list of strings + * + * This produces a list of string pointers with each one pointing to a string + * in the string list. If the property does not exist, it returns {NULL}. + * + * The data is allocated and the caller is reponsible for freeing the return + * value (the list of string pointers). The strings themselves may not be + * changed as they point directly into the devicetree property. + * + * @dev: device to examine + * @propname: name of the property containing the string list + * @listp: returns an allocated, NULL-terminated list of strings if the return + * value is > 0, else is set to NULL + * @return number of strings in list, 0 if none, -ENOMEM if out of memory, + * -ENOENT if no such property + */ +int dev_read_string_list(const struct udevice *dev, const char *propname, + const char ***listp); + /** * dev_read_phandle_with_args() - Find a node pointed by phandle in a list * @@ -906,6 +927,13 @@ static inline int dev_read_string_count(const struct udevice *dev, return ofnode_read_string_count(dev_ofnode(dev), propname); } +static inline int dev_read_string_list(const struct udevice *dev, + const char *propname, + const char ***listp) +{ + return ofnode_read_string_list(dev_ofnode(dev), propname, listp); +} + static inline int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name, const char *cells_name, int cell_count, int index, struct ofnode_phandle_args *out_args) diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index c72e082..5e7c968 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -354,6 +354,7 @@ DM_TEST(dm_test_ofnode_for_each_compatible_node, UT_TESTF_SCAN_FDT); static int dm_test_ofnode_string(struct unit_test_state *uts) { + const char **val; const char *out; ofnode node; @@ -366,6 +367,10 @@ static int dm_test_ofnode_string(struct unit_test_state *uts) ut_asserteq_str("test string", out); ut_asserteq(0, ofnode_stringlist_search(node, "str-value", "test string")); + ut_asserteq(1, ofnode_read_string_list(node, "str-value", &val)); + ut_asserteq_str("test string", val[0]); + ut_assertnull(val[1]); + free(val); /* list of strings */ ut_asserteq(5, ofnode_read_string_count(node, "mux-control-names")); @@ -374,6 +379,15 @@ static int dm_test_ofnode_string(struct unit_test_state *uts) ut_asserteq_str("mux0", out); ut_asserteq(0, ofnode_stringlist_search(node, "mux-control-names", "mux0")); + ut_asserteq(5, ofnode_read_string_list(node, "mux-control-names", + &val)); + ut_asserteq_str("mux0", val[0]); + ut_asserteq_str("mux1", val[1]); + ut_asserteq_str("mux2", val[2]); + ut_asserteq_str("mux3", val[3]); + ut_asserteq_str("mux4", val[4]); + ut_assertnull(val[5]); + free(val); ut_assertok(ofnode_read_string_index(node, "mux-control-names", 4, &out)); @@ -387,6 +401,7 @@ DM_TEST(dm_test_ofnode_string, 0); static int dm_test_ofnode_string_err(struct unit_test_state *uts) { + const char **val; const char *out; ofnode node; @@ -401,16 +416,21 @@ static int dm_test_ofnode_string_err(struct unit_test_state *uts) ut_asserteq(-EINVAL, ofnode_read_string_count(node, "missing")); ut_asserteq(-EINVAL, ofnode_read_string_index(node, "missing", 0, &out)); + ut_asserteq(-EINVAL, ofnode_read_string_list(node, "missing", &val)); /* empty property */ ut_asserteq(-ENODATA, ofnode_read_string_count(node, "bool-value")); ut_asserteq(-ENODATA, ofnode_read_string_index(node, "bool-value", 0, &out)); + ut_asserteq(-ENODATA, ofnode_read_string_list(node, "bool-value", + &val)); /* badly formatted string list */ ut_asserteq(-EILSEQ, ofnode_read_string_count(node, "int64-value")); ut_asserteq(-EILSEQ, ofnode_read_string_index(node, "int64-value", 0, &out)); + ut_asserteq(-EILSEQ, ofnode_read_string_list(node, "int64-value", + &val)); /* out of range / not found */ ut_asserteq(-ENODATA, ofnode_read_string_index(node, "str-value", 1, -- 2.7.4