diff options
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 134 |
1 files changed, 114 insertions, 20 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index a7264644003f..7c79e94a35ea 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -420,13 +420,12 @@ static struct of_modalias_table of_modalias_table[] = { | |||
420 | * @len: Length of modalias value | 420 | * @len: Length of modalias value |
421 | * | 421 | * |
422 | * Based on the value of the compatible property, this routine will determine | 422 | * Based on the value of the compatible property, this routine will determine |
423 | * an appropriate modalias value for a particular device tree node. Three | 423 | * an appropriate modalias value for a particular device tree node. Two |
424 | * separate methods are used to derive a modalias value. | 424 | * separate methods are attempted to derive a modalias value. |
425 | * | 425 | * |
426 | * First method is to lookup the compatible value in of_modalias_table. | 426 | * First method is to lookup the compatible value in of_modalias_table. |
427 | * Second is to look for a "linux,<modalias>" entry in the compatible list | 427 | * Second is to strip off the manufacturer prefix from the first |
428 | * and used that for modalias. Third is to strip off the manufacturer | 428 | * compatible entry and use the remainder as modalias |
429 | * prefix from the first compatible entry and use the remainder as modalias | ||
430 | * | 429 | * |
431 | * This routine returns 0 on success | 430 | * This routine returns 0 on success |
432 | */ | 431 | */ |
@@ -449,21 +448,7 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) | |||
449 | if (!compatible) | 448 | if (!compatible) |
450 | return -ENODEV; | 449 | return -ENODEV; |
451 | 450 | ||
452 | /* 2. search for linux,<modalias> entry */ | 451 | /* 2. take first compatible entry and strip manufacturer */ |
453 | p = compatible; | ||
454 | while (cplen > 0) { | ||
455 | if (!strncmp(p, "linux,", 6)) { | ||
456 | p += 6; | ||
457 | strlcpy(modalias, p, len); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | i = strlen(p) + 1; | ||
462 | p += i; | ||
463 | cplen -= i; | ||
464 | } | ||
465 | |||
466 | /* 3. take first compatible entry and strip manufacturer */ | ||
467 | p = strchr(compatible, ','); | 452 | p = strchr(compatible, ','); |
468 | if (!p) | 453 | if (!p) |
469 | return -ENODEV; | 454 | return -ENODEV; |
@@ -473,3 +458,112 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) | |||
473 | } | 458 | } |
474 | EXPORT_SYMBOL_GPL(of_modalias_node); | 459 | EXPORT_SYMBOL_GPL(of_modalias_node); |
475 | 460 | ||
461 | /** | ||
462 | * of_parse_phandles_with_args - Find a node pointed by phandle in a list | ||
463 | * @np: pointer to a device tree node containing a list | ||
464 | * @list_name: property name that contains a list | ||
465 | * @cells_name: property name that specifies phandles' arguments count | ||
466 | * @index: index of a phandle to parse out | ||
467 | * @out_node: pointer to device_node struct pointer (will be filled) | ||
468 | * @out_args: pointer to arguments pointer (will be filled) | ||
469 | * | ||
470 | * 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 | ||
472 | * appropriate errno value. | ||
473 | * | ||
474 | * Example: | ||
475 | * | ||
476 | * phandle1: node1 { | ||
477 | * #list-cells = <2>; | ||
478 | * } | ||
479 | * | ||
480 | * phandle2: node2 { | ||
481 | * #list-cells = <1>; | ||
482 | * } | ||
483 | * | ||
484 | * node3 { | ||
485 | * list = <&phandle1 1 2 &phandle2 3>; | ||
486 | * } | ||
487 | * | ||
488 | * To get a device_node of the `node2' node you may call this: | ||
489 | * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); | ||
490 | */ | ||
491 | int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | ||
492 | const char *cells_name, int index, | ||
493 | struct device_node **out_node, | ||
494 | const void **out_args) | ||
495 | { | ||
496 | int ret = -EINVAL; | ||
497 | const u32 *list; | ||
498 | const u32 *list_end; | ||
499 | int size; | ||
500 | int cur_index = 0; | ||
501 | struct device_node *node = NULL; | ||
502 | const void *args; | ||
503 | |||
504 | list = of_get_property(np, list_name, &size); | ||
505 | if (!list) { | ||
506 | ret = -ENOENT; | ||
507 | goto err0; | ||
508 | } | ||
509 | list_end = list + size / sizeof(*list); | ||
510 | |||
511 | while (list < list_end) { | ||
512 | const u32 *cells; | ||
513 | const phandle *phandle; | ||
514 | |||
515 | phandle = list; | ||
516 | args = list + 1; | ||
517 | |||
518 | /* one cell hole in the list = <>; */ | ||
519 | if (!*phandle) { | ||
520 | list++; | ||
521 | goto next; | ||
522 | } | ||
523 | |||
524 | node = of_find_node_by_phandle(*phandle); | ||
525 | if (!node) { | ||
526 | pr_debug("%s: could not find phandle\n", | ||
527 | np->full_name); | ||
528 | goto err0; | ||
529 | } | ||
530 | |||
531 | cells = of_get_property(node, cells_name, &size); | ||
532 | if (!cells || size != sizeof(*cells)) { | ||
533 | pr_debug("%s: could not get %s for %s\n", | ||
534 | np->full_name, cells_name, node->full_name); | ||
535 | goto err1; | ||
536 | } | ||
537 | |||
538 | /* Next phandle is at offset of one phandle cell + #cells */ | ||
539 | list += 1 + *cells; | ||
540 | if (list > list_end) { | ||
541 | pr_debug("%s: insufficient arguments length\n", | ||
542 | np->full_name); | ||
543 | goto err1; | ||
544 | } | ||
545 | next: | ||
546 | if (cur_index == index) | ||
547 | break; | ||
548 | |||
549 | of_node_put(node); | ||
550 | node = NULL; | ||
551 | cur_index++; | ||
552 | } | ||
553 | |||
554 | if (!node) { | ||
555 | ret = -ENOENT; | ||
556 | goto err0; | ||
557 | } | ||
558 | |||
559 | *out_node = node; | ||
560 | *out_args = args; | ||
561 | |||
562 | return 0; | ||
563 | err1: | ||
564 | of_node_put(node); | ||
565 | err0: | ||
566 | pr_debug("%s failed with status %d\n", __func__, ret); | ||
567 | return ret; | ||
568 | } | ||
569 | EXPORT_SYMBOL(of_parse_phandles_with_args); | ||