diff options
| -rw-r--r-- | drivers/of/base.c | 88 | ||||
| -rw-r--r-- | drivers/of/selftest.c | 66 | ||||
| -rw-r--r-- | drivers/of/testcase-data/tests-phandle.dtsi | 2 | ||||
| -rw-r--r-- | include/linux/of.h | 84 |
4 files changed, 154 insertions, 86 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 2305dc0382bc..3823edf2d012 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
| @@ -1280,52 +1280,6 @@ int of_property_read_string(struct device_node *np, const char *propname, | |||
| 1280 | EXPORT_SYMBOL_GPL(of_property_read_string); | 1280 | EXPORT_SYMBOL_GPL(of_property_read_string); |
| 1281 | 1281 | ||
| 1282 | /** | 1282 | /** |
| 1283 | * of_property_read_string_index - Find and read a string from a multiple | ||
| 1284 | * strings property. | ||
| 1285 | * @np: device node from which the property value is to be read. | ||
| 1286 | * @propname: name of the property to be searched. | ||
| 1287 | * @index: index of the string in the list of strings | ||
| 1288 | * @out_string: pointer to null terminated return string, modified only if | ||
| 1289 | * return value is 0. | ||
| 1290 | * | ||
| 1291 | * Search for a property in a device tree node and retrieve a null | ||
| 1292 | * terminated string value (pointer to data, not a copy) in the list of strings | ||
| 1293 | * contained in that property. | ||
| 1294 | * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if | ||
| 1295 | * property does not have a value, and -EILSEQ if the string is not | ||
| 1296 | * null-terminated within the length of the property data. | ||
| 1297 | * | ||
| 1298 | * The out_string pointer is modified only if a valid string can be decoded. | ||
| 1299 | */ | ||
| 1300 | int of_property_read_string_index(struct device_node *np, const char *propname, | ||
| 1301 | int index, const char **output) | ||
| 1302 | { | ||
| 1303 | struct property *prop = of_find_property(np, propname, NULL); | ||
| 1304 | int i = 0; | ||
| 1305 | size_t l = 0, total = 0; | ||
| 1306 | const char *p; | ||
| 1307 | |||
| 1308 | if (!prop) | ||
| 1309 | return -EINVAL; | ||
| 1310 | if (!prop->value) | ||
| 1311 | return -ENODATA; | ||
| 1312 | if (strnlen(prop->value, prop->length) >= prop->length) | ||
| 1313 | return -EILSEQ; | ||
| 1314 | |||
| 1315 | p = prop->value; | ||
| 1316 | |||
| 1317 | for (i = 0; total < prop->length; total += l, p += l) { | ||
| 1318 | l = strlen(p) + 1; | ||
| 1319 | if (i++ == index) { | ||
| 1320 | *output = p; | ||
| 1321 | return 0; | ||
| 1322 | } | ||
| 1323 | } | ||
| 1324 | return -ENODATA; | ||
| 1325 | } | ||
| 1326 | EXPORT_SYMBOL_GPL(of_property_read_string_index); | ||
| 1327 | |||
| 1328 | /** | ||
| 1329 | * of_property_match_string() - Find string in a list and return index | 1283 | * of_property_match_string() - Find string in a list and return index |
| 1330 | * @np: pointer to node containing string list property | 1284 | * @np: pointer to node containing string list property |
| 1331 | * @propname: string list property name | 1285 | * @propname: string list property name |
| @@ -1351,7 +1305,7 @@ int of_property_match_string(struct device_node *np, const char *propname, | |||
| 1351 | end = p + prop->length; | 1305 | end = p + prop->length; |
| 1352 | 1306 | ||
| 1353 | for (i = 0; p < end; i++, p += l) { | 1307 | for (i = 0; p < end; i++, p += l) { |
| 1354 | l = strlen(p) + 1; | 1308 | l = strnlen(p, end - p) + 1; |
| 1355 | if (p + l > end) | 1309 | if (p + l > end) |
| 1356 | return -EILSEQ; | 1310 | return -EILSEQ; |
| 1357 | pr_debug("comparing %s with %s\n", string, p); | 1311 | pr_debug("comparing %s with %s\n", string, p); |
| @@ -1363,39 +1317,41 @@ int of_property_match_string(struct device_node *np, const char *propname, | |||
| 1363 | EXPORT_SYMBOL_GPL(of_property_match_string); | 1317 | EXPORT_SYMBOL_GPL(of_property_match_string); |
| 1364 | 1318 | ||
| 1365 | /** | 1319 | /** |
| 1366 | * of_property_count_strings - Find and return the number of strings from a | 1320 | * of_property_read_string_util() - Utility helper for parsing string properties |
| 1367 | * multiple strings property. | ||
| 1368 | * @np: device node from which the property value is to be read. | 1321 | * @np: device node from which the property value is to be read. |
| 1369 | * @propname: name of the property to be searched. | 1322 | * @propname: name of the property to be searched. |
| 1323 | * @out_strs: output array of string pointers. | ||
| 1324 | * @sz: number of array elements to read. | ||
| 1325 | * @skip: Number of strings to skip over at beginning of list. | ||
| 1370 | * | 1326 | * |
| 1371 | * Search for a property in a device tree node and retrieve the number of null | 1327 | * Don't call this function directly. It is a utility helper for the |
| 1372 | * terminated string contain in it. Returns the number of strings on | 1328 | * of_property_read_string*() family of functions. |
| 1373 | * success, -EINVAL if the property does not exist, -ENODATA if property | ||
| 1374 | * does not have a value, and -EILSEQ if the string is not null-terminated | ||
| 1375 | * within the length of the property data. | ||
| 1376 | */ | 1329 | */ |
| 1377 | int of_property_count_strings(struct device_node *np, const char *propname) | 1330 | int of_property_read_string_helper(struct device_node *np, const char *propname, |
| 1331 | const char **out_strs, size_t sz, int skip) | ||
| 1378 | { | 1332 | { |
| 1379 | struct property *prop = of_find_property(np, propname, NULL); | 1333 | struct property *prop = of_find_property(np, propname, NULL); |
| 1380 | int i = 0; | 1334 | int l = 0, i = 0; |
| 1381 | size_t l = 0, total = 0; | 1335 | const char *p, *end; |
| 1382 | const char *p; | ||
| 1383 | 1336 | ||
| 1384 | if (!prop) | 1337 | if (!prop) |
| 1385 | return -EINVAL; | 1338 | return -EINVAL; |
| 1386 | if (!prop->value) | 1339 | if (!prop->value) |
| 1387 | return -ENODATA; | 1340 | return -ENODATA; |
| 1388 | if (strnlen(prop->value, prop->length) >= prop->length) | ||
| 1389 | return -EILSEQ; | ||
| 1390 | |||
| 1391 | p = prop->value; | 1341 | p = prop->value; |
| 1342 | end = p + prop->length; | ||
| 1392 | 1343 | ||
| 1393 | for (i = 0; total < prop->length; total += l, p += l, i++) | 1344 | for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) { |
| 1394 | l = strlen(p) + 1; | 1345 | l = strnlen(p, end - p) + 1; |
| 1395 | 1346 | if (p + l > end) | |
| 1396 | return i; | 1347 | return -EILSEQ; |
| 1348 | if (out_strs && i >= skip) | ||
| 1349 | *out_strs++ = p; | ||
| 1350 | } | ||
| 1351 | i -= skip; | ||
| 1352 | return i <= 0 ? -ENODATA : i; | ||
| 1397 | } | 1353 | } |
| 1398 | EXPORT_SYMBOL_GPL(of_property_count_strings); | 1354 | EXPORT_SYMBOL_GPL(of_property_read_string_helper); |
| 1399 | 1355 | ||
| 1400 | void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) | 1356 | void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) |
| 1401 | { | 1357 | { |
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 78001270a598..11b873c54a77 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
| @@ -339,8 +339,9 @@ static void __init of_selftest_parse_phandle_with_args(void) | |||
| 339 | selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); | 339 | selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | static void __init of_selftest_property_match_string(void) | 342 | static void __init of_selftest_property_string(void) |
| 343 | { | 343 | { |
| 344 | const char *strings[4]; | ||
| 344 | struct device_node *np; | 345 | struct device_node *np; |
| 345 | int rc; | 346 | int rc; |
| 346 | 347 | ||
| @@ -357,13 +358,66 @@ static void __init of_selftest_property_match_string(void) | |||
| 357 | rc = of_property_match_string(np, "phandle-list-names", "third"); | 358 | rc = of_property_match_string(np, "phandle-list-names", "third"); |
| 358 | selftest(rc == 2, "third expected:0 got:%i\n", rc); | 359 | selftest(rc == 2, "third expected:0 got:%i\n", rc); |
| 359 | rc = of_property_match_string(np, "phandle-list-names", "fourth"); | 360 | rc = of_property_match_string(np, "phandle-list-names", "fourth"); |
| 360 | selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); | 361 | selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc); |
| 361 | rc = of_property_match_string(np, "missing-property", "blah"); | 362 | rc = of_property_match_string(np, "missing-property", "blah"); |
| 362 | selftest(rc == -EINVAL, "missing property; rc=%i", rc); | 363 | selftest(rc == -EINVAL, "missing property; rc=%i\n", rc); |
| 363 | rc = of_property_match_string(np, "empty-property", "blah"); | 364 | rc = of_property_match_string(np, "empty-property", "blah"); |
| 364 | selftest(rc == -ENODATA, "empty property; rc=%i", rc); | 365 | selftest(rc == -ENODATA, "empty property; rc=%i\n", rc); |
| 365 | rc = of_property_match_string(np, "unterminated-string", "blah"); | 366 | rc = of_property_match_string(np, "unterminated-string", "blah"); |
| 366 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); | 367 | selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); |
| 368 | |||
| 369 | /* of_property_count_strings() tests */ | ||
| 370 | rc = of_property_count_strings(np, "string-property"); | ||
| 371 | selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); | ||
| 372 | rc = of_property_count_strings(np, "phandle-list-names"); | ||
| 373 | selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); | ||
| 374 | rc = of_property_count_strings(np, "unterminated-string"); | ||
| 375 | selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); | ||
| 376 | rc = of_property_count_strings(np, "unterminated-string-list"); | ||
| 377 | selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); | ||
| 378 | |||
| 379 | /* of_property_read_string_index() tests */ | ||
| 380 | rc = of_property_read_string_index(np, "string-property", 0, strings); | ||
| 381 | selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 382 | strings[0] = NULL; | ||
| 383 | rc = of_property_read_string_index(np, "string-property", 1, strings); | ||
| 384 | selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 385 | rc = of_property_read_string_index(np, "phandle-list-names", 0, strings); | ||
| 386 | selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 387 | rc = of_property_read_string_index(np, "phandle-list-names", 1, strings); | ||
| 388 | selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 389 | rc = of_property_read_string_index(np, "phandle-list-names", 2, strings); | ||
| 390 | selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 391 | strings[0] = NULL; | ||
| 392 | rc = of_property_read_string_index(np, "phandle-list-names", 3, strings); | ||
| 393 | selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 394 | strings[0] = NULL; | ||
| 395 | rc = of_property_read_string_index(np, "unterminated-string", 0, strings); | ||
| 396 | selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 397 | rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings); | ||
| 398 | selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 399 | strings[0] = NULL; | ||
| 400 | rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */ | ||
| 401 | selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
| 402 | strings[1] = NULL; | ||
| 403 | |||
| 404 | /* of_property_read_string_array() tests */ | ||
| 405 | rc = of_property_read_string_array(np, "string-property", strings, 4); | ||
| 406 | selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); | ||
| 407 | rc = of_property_read_string_array(np, "phandle-list-names", strings, 4); | ||
| 408 | selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); | ||
| 409 | rc = of_property_read_string_array(np, "unterminated-string", strings, 4); | ||
| 410 | selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); | ||
| 411 | /* -- An incorrectly formed string should cause a failure */ | ||
| 412 | rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4); | ||
| 413 | selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); | ||
| 414 | /* -- parsing the correctly formed strings should still work: */ | ||
| 415 | strings[2] = NULL; | ||
| 416 | rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2); | ||
| 417 | selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc); | ||
| 418 | strings[1] = NULL; | ||
| 419 | rc = of_property_read_string_array(np, "phandle-list-names", strings, 1); | ||
| 420 | selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]); | ||
| 367 | } | 421 | } |
| 368 | 422 | ||
| 369 | #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ | 423 | #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ |
| @@ -881,7 +935,7 @@ static int __init of_selftest(void) | |||
| 881 | of_selftest_find_node_by_name(); | 935 | of_selftest_find_node_by_name(); |
| 882 | of_selftest_dynamic(); | 936 | of_selftest_dynamic(); |
| 883 | of_selftest_parse_phandle_with_args(); | 937 | of_selftest_parse_phandle_with_args(); |
| 884 | of_selftest_property_match_string(); | 938 | of_selftest_property_string(); |
| 885 | of_selftest_property_copy(); | 939 | of_selftest_property_copy(); |
| 886 | of_selftest_changeset(); | 940 | of_selftest_changeset(); |
| 887 | of_selftest_parse_interrupts(); | 941 | of_selftest_parse_interrupts(); |
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi index ce0fe083d406..5b1527e8a7fb 100644 --- a/drivers/of/testcase-data/tests-phandle.dtsi +++ b/drivers/of/testcase-data/tests-phandle.dtsi | |||
| @@ -39,7 +39,9 @@ | |||
| 39 | phandle-list-bad-args = <&provider2 1 0>, | 39 | phandle-list-bad-args = <&provider2 1 0>, |
| 40 | <&provider3 0>; | 40 | <&provider3 0>; |
| 41 | empty-property; | 41 | empty-property; |
| 42 | string-property = "foobar"; | ||
| 42 | unterminated-string = [40 41 42 43]; | 43 | unterminated-string = [40 41 42 43]; |
| 44 | unterminated-string-list = "first", "second", [40 41 42 43]; | ||
| 43 | }; | 45 | }; |
| 44 | }; | 46 | }; |
| 45 | }; | 47 | }; |
diff --git a/include/linux/of.h b/include/linux/of.h index 6545e7aec7bb..29f0adc5f3e4 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
| @@ -267,14 +267,12 @@ extern int of_property_read_u64(const struct device_node *np, | |||
| 267 | extern int of_property_read_string(struct device_node *np, | 267 | extern int of_property_read_string(struct device_node *np, |
| 268 | const char *propname, | 268 | const char *propname, |
| 269 | const char **out_string); | 269 | const char **out_string); |
| 270 | extern int of_property_read_string_index(struct device_node *np, | ||
| 271 | const char *propname, | ||
| 272 | int index, const char **output); | ||
| 273 | extern int of_property_match_string(struct device_node *np, | 270 | extern int of_property_match_string(struct device_node *np, |
| 274 | const char *propname, | 271 | const char *propname, |
| 275 | const char *string); | 272 | const char *string); |
| 276 | extern int of_property_count_strings(struct device_node *np, | 273 | extern int of_property_read_string_helper(struct device_node *np, |
| 277 | const char *propname); | 274 | const char *propname, |
| 275 | const char **out_strs, size_t sz, int index); | ||
| 278 | extern int of_device_is_compatible(const struct device_node *device, | 276 | extern int of_device_is_compatible(const struct device_node *device, |
| 279 | const char *); | 277 | const char *); |
| 280 | extern int of_device_is_available(const struct device_node *device); | 278 | extern int of_device_is_available(const struct device_node *device); |
| @@ -486,15 +484,9 @@ static inline int of_property_read_string(struct device_node *np, | |||
| 486 | return -ENOSYS; | 484 | return -ENOSYS; |
| 487 | } | 485 | } |
| 488 | 486 | ||
| 489 | static inline int of_property_read_string_index(struct device_node *np, | 487 | static inline int of_property_read_string_helper(struct device_node *np, |
| 490 | const char *propname, int index, | 488 | const char *propname, |
| 491 | const char **out_string) | 489 | const char **out_strs, size_t sz, int index) |
| 492 | { | ||
| 493 | return -ENOSYS; | ||
| 494 | } | ||
| 495 | |||
| 496 | static inline int of_property_count_strings(struct device_node *np, | ||
| 497 | const char *propname) | ||
| 498 | { | 490 | { |
| 499 | return -ENOSYS; | 491 | return -ENOSYS; |
| 500 | } | 492 | } |
| @@ -668,6 +660,70 @@ static inline int of_property_count_u64_elems(const struct device_node *np, | |||
| 668 | } | 660 | } |
| 669 | 661 | ||
| 670 | /** | 662 | /** |
| 663 | * of_property_read_string_array() - Read an array of strings from a multiple | ||
| 664 | * strings property. | ||
| 665 | * @np: device node from which the property value is to be read. | ||
| 666 | * @propname: name of the property to be searched. | ||
| 667 | * @out_strs: output array of string pointers. | ||
| 668 | * @sz: number of array elements to read. | ||
| 669 | * | ||
| 670 | * Search for a property in a device tree node and retrieve a list of | ||
| 671 | * terminated string values (pointer to data, not a copy) in that property. | ||
| 672 | * | ||
| 673 | * If @out_strs is NULL, the number of strings in the property is returned. | ||
| 674 | */ | ||
| 675 | static inline int of_property_read_string_array(struct device_node *np, | ||
| 676 | const char *propname, const char **out_strs, | ||
| 677 | size_t sz) | ||
| 678 | { | ||
| 679 | return of_property_read_string_helper(np, propname, out_strs, sz, 0); | ||
| 680 | } | ||
| 681 | |||
| 682 | /** | ||
| 683 | * of_property_count_strings() - Find and return the number of strings from a | ||
| 684 | * multiple strings property. | ||
| 685 | * @np: device node from which the property value is to be read. | ||
| 686 | * @propname: name of the property to be searched. | ||
| 687 | * | ||
| 688 | * Search for a property in a device tree node and retrieve the number of null | ||
| 689 | * terminated string contain in it. Returns the number of strings on | ||
| 690 | * success, -EINVAL if the property does not exist, -ENODATA if property | ||
| 691 | * does not have a value, and -EILSEQ if the string is not null-terminated | ||
| 692 | * within the length of the property data. | ||
| 693 | */ | ||
| 694 | static inline int of_property_count_strings(struct device_node *np, | ||
| 695 | const char *propname) | ||
| 696 | { | ||
| 697 | return of_property_read_string_helper(np, propname, NULL, 0, 0); | ||
| 698 | } | ||
| 699 | |||
| 700 | /** | ||
| 701 | * of_property_read_string_index() - Find and read a string from a multiple | ||
| 702 | * strings property. | ||
| 703 | * @np: device node from which the property value is to be read. | ||
| 704 | * @propname: name of the property to be searched. | ||
| 705 | * @index: index of the string in the list of strings | ||
| 706 | * @out_string: pointer to null terminated return string, modified only if | ||
| 707 | * return value is 0. | ||
| 708 | * | ||
| 709 | * Search for a property in a device tree node and retrieve a null | ||
| 710 | * terminated string value (pointer to data, not a copy) in the list of strings | ||
| 711 | * contained in that property. | ||
| 712 | * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if | ||
| 713 | * property does not have a value, and -EILSEQ if the string is not | ||
| 714 | * null-terminated within the length of the property data. | ||
| 715 | * | ||
| 716 | * The out_string pointer is modified only if a valid string can be decoded. | ||
| 717 | */ | ||
| 718 | static inline int of_property_read_string_index(struct device_node *np, | ||
| 719 | const char *propname, | ||
| 720 | int index, const char **output) | ||
| 721 | { | ||
| 722 | int rc = of_property_read_string_helper(np, propname, output, 1, index); | ||
| 723 | return rc < 0 ? rc : 0; | ||
| 724 | } | ||
| 725 | |||
| 726 | /** | ||
| 671 | * of_property_read_bool - Findfrom a property | 727 | * of_property_read_bool - Findfrom a property |
| 672 | * @np: device node from which the property value is to be read. | 728 | * @np: device node from which the property value is to be read. |
| 673 | * @propname: name of the property to be searched. | 729 | * @propname: name of the property to be searched. |
