diff options
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 7c79e94a35ea..cd17092b82bd 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -329,6 +329,41 @@ struct device_node *of_find_compatible_node(struct device_node *from, | |||
329 | EXPORT_SYMBOL(of_find_compatible_node); | 329 | EXPORT_SYMBOL(of_find_compatible_node); |
330 | 330 | ||
331 | /** | 331 | /** |
332 | * of_find_node_with_property - Find a node which has a property with | ||
333 | * the given name. | ||
334 | * @from: The node to start searching from or NULL, the node | ||
335 | * you pass will not be searched, only the next one | ||
336 | * will; typically, you pass what the previous call | ||
337 | * returned. of_node_put() will be called on it | ||
338 | * @prop_name: The name of the property to look for. | ||
339 | * | ||
340 | * Returns a node pointer with refcount incremented, use | ||
341 | * of_node_put() on it when done. | ||
342 | */ | ||
343 | struct device_node *of_find_node_with_property(struct device_node *from, | ||
344 | const char *prop_name) | ||
345 | { | ||
346 | struct device_node *np; | ||
347 | struct property *pp; | ||
348 | |||
349 | read_lock(&devtree_lock); | ||
350 | np = from ? from->allnext : allnodes; | ||
351 | for (; np; np = np->allnext) { | ||
352 | for (pp = np->properties; pp != 0; pp = pp->next) { | ||
353 | if (of_prop_cmp(pp->name, prop_name) == 0) { | ||
354 | of_node_get(np); | ||
355 | goto out; | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | out: | ||
360 | of_node_put(from); | ||
361 | read_unlock(&devtree_lock); | ||
362 | return np; | ||
363 | } | ||
364 | EXPORT_SYMBOL(of_find_node_with_property); | ||
365 | |||
366 | /** | ||
332 | * of_match_node - Tell if an device_node has a matching of_match structure | 367 | * of_match_node - Tell if an device_node has a matching of_match structure |
333 | * @matches: array of of device match structures to search in | 368 | * @matches: array of of device match structures to search in |
334 | * @node: the of device structure to match against | 369 | * @node: the of device structure to match against |
@@ -464,8 +499,8 @@ EXPORT_SYMBOL_GPL(of_modalias_node); | |||
464 | * @list_name: property name that contains a list | 499 | * @list_name: property name that contains a list |
465 | * @cells_name: property name that specifies phandles' arguments count | 500 | * @cells_name: property name that specifies phandles' arguments count |
466 | * @index: index of a phandle to parse out | 501 | * @index: index of a phandle to parse out |
467 | * @out_node: pointer to device_node struct pointer (will be filled) | 502 | * @out_node: optional pointer to device_node struct pointer (will be filled) |
468 | * @out_args: pointer to arguments pointer (will be filled) | 503 | * @out_args: optional pointer to arguments pointer (will be filled) |
469 | * | 504 | * |
470 | * This function is useful to parse lists of phandles and their arguments. | 505 | * This function is useful to parse lists of phandles and their arguments. |
471 | * Returns 0 on success and fills out_node and out_args, on error returns | 506 | * Returns 0 on success and fills out_node and out_args, on error returns |
@@ -499,7 +534,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | |||
499 | int size; | 534 | int size; |
500 | int cur_index = 0; | 535 | int cur_index = 0; |
501 | struct device_node *node = NULL; | 536 | struct device_node *node = NULL; |
502 | const void *args; | 537 | const void *args = NULL; |
503 | 538 | ||
504 | list = of_get_property(np, list_name, &size); | 539 | list = of_get_property(np, list_name, &size); |
505 | if (!list) { | 540 | if (!list) { |
@@ -512,14 +547,12 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | |||
512 | const u32 *cells; | 547 | const u32 *cells; |
513 | const phandle *phandle; | 548 | const phandle *phandle; |
514 | 549 | ||
515 | phandle = list; | 550 | phandle = list++; |
516 | args = list + 1; | 551 | args = list; |
517 | 552 | ||
518 | /* one cell hole in the list = <>; */ | 553 | /* one cell hole in the list = <>; */ |
519 | if (!*phandle) { | 554 | if (!*phandle) |
520 | list++; | ||
521 | goto next; | 555 | goto next; |
522 | } | ||
523 | 556 | ||
524 | node = of_find_node_by_phandle(*phandle); | 557 | node = of_find_node_by_phandle(*phandle); |
525 | if (!node) { | 558 | if (!node) { |
@@ -535,8 +568,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | |||
535 | goto err1; | 568 | goto err1; |
536 | } | 569 | } |
537 | 570 | ||
538 | /* Next phandle is at offset of one phandle cell + #cells */ | 571 | list += *cells; |
539 | list += 1 + *cells; | ||
540 | if (list > list_end) { | 572 | if (list > list_end) { |
541 | pr_debug("%s: insufficient arguments length\n", | 573 | pr_debug("%s: insufficient arguments length\n", |
542 | np->full_name); | 574 | np->full_name); |
@@ -548,16 +580,26 @@ next: | |||
548 | 580 | ||
549 | of_node_put(node); | 581 | of_node_put(node); |
550 | node = NULL; | 582 | node = NULL; |
583 | args = NULL; | ||
551 | cur_index++; | 584 | cur_index++; |
552 | } | 585 | } |
553 | 586 | ||
554 | if (!node) { | 587 | if (!node) { |
555 | ret = -ENOENT; | 588 | /* |
589 | * args w/o node indicates that the loop above has stopped at | ||
590 | * the 'hole' cell. Report this differently. | ||
591 | */ | ||
592 | if (args) | ||
593 | ret = -EEXIST; | ||
594 | else | ||
595 | ret = -ENOENT; | ||
556 | goto err0; | 596 | goto err0; |
557 | } | 597 | } |
558 | 598 | ||
559 | *out_node = node; | 599 | if (out_node) |
560 | *out_args = args; | 600 | *out_node = node; |
601 | if (out_args) | ||
602 | *out_args = args; | ||
561 | 603 | ||
562 | return 0; | 604 | return 0; |
563 | err1: | 605 | err1: |