diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/arch/arm/boot/dts/testcases/tests-phandle.dtsi index ec0c4e6212c..0007d3cd7dc 100644 --- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi +++ b/arch/arm/boot/dts/testcases/tests-phandle.dtsi @@ -31,6 +31,8 @@ phandle-list-bad-phandle = <12345678 0 0>; phandle-list-bad-args = <&provider2 1 0>, <&provider3 0>; + empty-property; + unterminated-string = [40 41 42 43]; }; }; }; diff --git a/drivers/of/base.c b/drivers/of/base.c index 133908a6fd8..13ba72875e2 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -761,6 +761,42 @@ int of_property_read_string_index(struct device_node *np, const char *propname, } EXPORT_SYMBOL_GPL(of_property_read_string_index); +/** + * of_property_match_string() - Find string in a list and return index + * @np: pointer to node containing string list property + * @propname: string list property name + * @string: pointer to string to search for in string list + * + * This function searches a string list property and returns the index + * of a specific string value. + */ +int of_property_match_string(struct device_node *np, const char *propname, + const char *string) +{ + struct property *prop = of_find_property(np, propname, NULL); + size_t l; + int i; + const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + p = prop->value; + end = p + prop->length; + + for (i = 0; p < end; i++, p += l) { + l = strlen(p) + 1; + if (p + l > end) + return -EILSEQ; + pr_debug("comparing %s with %s\n", string, p); + if (strcmp(string, p) == 0) + return i; /* Found it; return index */ + } + return -ENODATA; +} +EXPORT_SYMBOL_GPL(of_property_match_string); /** * of_property_count_strings - Find and return the number of strings from a diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 9d2b4803a9d..f24ffd7088d 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -120,6 +120,34 @@ static void __init of_selftest_parse_phandle_with_args(void) pr_info("end - %s\n", passed_all ? "PASS" : "FAIL"); } +static void __init of_selftest_property_match_string(void) +{ + struct device_node *np; + int rc; + + pr_info("start\n"); + np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); + if (!np) { + pr_err("No testcase data in device tree\n"); + return; + } + + rc = of_property_match_string(np, "phandle-list-names", "first"); + selftest(rc == 0, "first expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "second"); + selftest(rc == 1, "second expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "third"); + selftest(rc == 2, "third expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "fourth"); + selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); + rc = of_property_match_string(np, "missing-property", "blah"); + selftest(rc == -EINVAL, "missing property; rc=%i", rc); + rc = of_property_match_string(np, "empty-property", "blah"); + selftest(rc == -ENODATA, "empty property; rc=%i", rc); + rc = of_property_match_string(np, "unterminated-string", "blah"); + selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); +} + static int __init of_selftest(void) { struct device_node *np; @@ -133,6 +161,7 @@ static int __init of_selftest(void) pr_info("start of selftest - you will see error messages\n"); of_selftest_parse_phandle_with_args(); + of_selftest_property_match_string(); pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL"); return 0; } diff --git a/include/linux/of.h b/include/linux/of.h index a75a831e205..5a4a3adb17e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -217,6 +217,9 @@ extern int of_property_read_string(struct device_node *np, extern int of_property_read_string_index(struct device_node *np, const char *propname, int index, const char **output); +extern int of_property_match_string(struct device_node *np, + const char *propname, + const char *string); extern int of_property_count_strings(struct device_node *np, const char *propname); extern int of_device_is_compatible(const struct device_node *device,