diff options
Diffstat (limited to 'drivers/of/base.c')
| -rw-r--r-- | drivers/of/base.c | 128 |
1 files changed, 73 insertions, 55 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index ff85450d5683..89e888a78899 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
| @@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) | |||
| 342 | } | 342 | } |
| 343 | EXPORT_SYMBOL(of_get_cpu_node); | 343 | EXPORT_SYMBOL(of_get_cpu_node); |
| 344 | 344 | ||
| 345 | /** Checks if the given "compat" string matches one of the strings in | 345 | /** |
| 346 | * the device's "compatible" property | 346 | * __of_device_is_compatible() - Check if the node matches given constraints |
| 347 | * @device: pointer to node | ||
| 348 | * @compat: required compatible string, NULL or "" for any match | ||
| 349 | * @type: required device_type value, NULL or "" for any match | ||
| 350 | * @name: required node name, NULL or "" for any match | ||
| 351 | * | ||
| 352 | * Checks if the given @compat, @type and @name strings match the | ||
| 353 | * properties of the given @device. A constraints can be skipped by | ||
| 354 | * passing NULL or an empty string as the constraint. | ||
| 355 | * | ||
| 356 | * Returns 0 for no match, and a positive integer on match. The return | ||
| 357 | * value is a relative score with larger values indicating better | ||
| 358 | * matches. The score is weighted for the most specific compatible value | ||
| 359 | * to get the highest score. Matching type is next, followed by matching | ||
| 360 | * name. Practically speaking, this results in the following priority | ||
| 361 | * order for matches: | ||
| 362 | * | ||
| 363 | * 1. specific compatible && type && name | ||
| 364 | * 2. specific compatible && type | ||
| 365 | * 3. specific compatible && name | ||
| 366 | * 4. specific compatible | ||
| 367 | * 5. general compatible && type && name | ||
| 368 | * 6. general compatible && type | ||
| 369 | * 7. general compatible && name | ||
| 370 | * 8. general compatible | ||
| 371 | * 9. type && name | ||
| 372 | * 10. type | ||
| 373 | * 11. name | ||
| 347 | */ | 374 | */ |
| 348 | static int __of_device_is_compatible(const struct device_node *device, | 375 | static int __of_device_is_compatible(const struct device_node *device, |
| 349 | const char *compat) | 376 | const char *compat, const char *type, const char *name) |
| 350 | { | 377 | { |
| 351 | const char* cp; | 378 | struct property *prop; |
| 352 | int cplen, l; | 379 | const char *cp; |
| 380 | int index = 0, score = 0; | ||
| 381 | |||
| 382 | /* Compatible match has highest priority */ | ||
| 383 | if (compat && compat[0]) { | ||
| 384 | prop = __of_find_property(device, "compatible", NULL); | ||
| 385 | for (cp = of_prop_next_string(prop, NULL); cp; | ||
| 386 | cp = of_prop_next_string(prop, cp), index++) { | ||
| 387 | if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { | ||
| 388 | score = INT_MAX/2 - (index << 2); | ||
| 389 | break; | ||
| 390 | } | ||
| 391 | } | ||
| 392 | if (!score) | ||
| 393 | return 0; | ||
| 394 | } | ||
| 353 | 395 | ||
| 354 | cp = __of_get_property(device, "compatible", &cplen); | 396 | /* Matching type is better than matching name */ |
| 355 | if (cp == NULL) | 397 | if (type && type[0]) { |
| 356 | return 0; | 398 | if (!device->type || of_node_cmp(type, device->type)) |
| 357 | while (cplen > 0) { | 399 | return 0; |
| 358 | if (of_compat_cmp(cp, compat, strlen(compat)) == 0) | 400 | score += 2; |
| 359 | return 1; | ||
| 360 | l = strlen(cp) + 1; | ||
| 361 | cp += l; | ||
| 362 | cplen -= l; | ||
| 363 | } | 401 | } |
| 364 | 402 | ||
| 365 | return 0; | 403 | /* Matching name is a bit better than not */ |
| 404 | if (name && name[0]) { | ||
| 405 | if (!device->name || of_node_cmp(name, device->name)) | ||
| 406 | return 0; | ||
| 407 | score++; | ||
| 408 | } | ||
| 409 | |||
| 410 | return score; | ||
| 366 | } | 411 | } |
| 367 | 412 | ||
| 368 | /** Checks if the given "compat" string matches one of the strings in | 413 | /** Checks if the given "compat" string matches one of the strings in |
| @@ -375,7 +420,7 @@ int of_device_is_compatible(const struct device_node *device, | |||
| 375 | int res; | 420 | int res; |
| 376 | 421 | ||
| 377 | raw_spin_lock_irqsave(&devtree_lock, flags); | 422 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 378 | res = __of_device_is_compatible(device, compat); | 423 | res = __of_device_is_compatible(device, compat, NULL, NULL); |
| 379 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 424 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 380 | return res; | 425 | return res; |
| 381 | } | 426 | } |
| @@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from, | |||
| 681 | raw_spin_lock_irqsave(&devtree_lock, flags); | 726 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 682 | np = from ? from->allnext : of_allnodes; | 727 | np = from ? from->allnext : of_allnodes; |
| 683 | for (; np; np = np->allnext) { | 728 | for (; np; np = np->allnext) { |
| 684 | if (type | 729 | if (__of_device_is_compatible(np, compatible, type, NULL) && |
| 685 | && !(np->type && (of_node_cmp(np->type, type) == 0))) | ||
| 686 | continue; | ||
| 687 | if (__of_device_is_compatible(np, compatible) && | ||
| 688 | of_node_get(np)) | 730 | of_node_get(np)) |
| 689 | break; | 731 | break; |
| 690 | } | 732 | } |
| @@ -734,43 +776,22 @@ static | |||
| 734 | const struct of_device_id *__of_match_node(const struct of_device_id *matches, | 776 | const struct of_device_id *__of_match_node(const struct of_device_id *matches, |
| 735 | const struct device_node *node) | 777 | const struct device_node *node) |
| 736 | { | 778 | { |
| 737 | const char *cp; | 779 | const struct of_device_id *best_match = NULL; |
| 738 | int cplen, l; | 780 | int score, best_score = 0; |
| 739 | 781 | ||
| 740 | if (!matches) | 782 | if (!matches) |
| 741 | return NULL; | 783 | return NULL; |
| 742 | 784 | ||
| 743 | cp = __of_get_property(node, "compatible", &cplen); | 785 | for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { |
| 744 | do { | 786 | score = __of_device_is_compatible(node, matches->compatible, |
| 745 | const struct of_device_id *m = matches; | 787 | matches->type, matches->name); |
| 746 | 788 | if (score > best_score) { | |
| 747 | /* Check against matches with current compatible string */ | 789 | best_match = matches; |
| 748 | while (m->name[0] || m->type[0] || m->compatible[0]) { | 790 | best_score = score; |
| 749 | int match = 1; | ||
| 750 | if (m->name[0]) | ||
| 751 | match &= node->name | ||
| 752 | && !strcmp(m->name, node->name); | ||
| 753 | if (m->type[0]) | ||
| 754 | match &= node->type | ||
| 755 | && !strcmp(m->type, node->type); | ||
| 756 | if (m->compatible[0]) | ||
| 757 | match &= cp | ||
| 758 | && !of_compat_cmp(m->compatible, cp, | ||
| 759 | strlen(m->compatible)); | ||
| 760 | if (match) | ||
| 761 | return m; | ||
| 762 | m++; | ||
| 763 | } | ||
| 764 | |||
| 765 | /* Get node's next compatible string */ | ||
| 766 | if (cp) { | ||
| 767 | l = strlen(cp) + 1; | ||
| 768 | cp += l; | ||
| 769 | cplen -= l; | ||
| 770 | } | 791 | } |
| 771 | } while (cp && (cplen > 0)); | 792 | } |
| 772 | 793 | ||
| 773 | return NULL; | 794 | return best_match; |
| 774 | } | 795 | } |
| 775 | 796 | ||
| 776 | /** | 797 | /** |
| @@ -778,10 +799,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches, | |||
| 778 | * @matches: array of of device match structures to search in | 799 | * @matches: array of of device match structures to search in |
| 779 | * @node: the of device structure to match against | 800 | * @node: the of device structure to match against |
| 780 | * | 801 | * |
| 781 | * Low level utility function used by device matching. Matching order | 802 | * Low level utility function used by device matching. |
| 782 | * is to compare each of the node's compatibles with all given matches | ||
| 783 | * first. This implies node's compatible is sorted from specific to | ||
| 784 | * generic while matches can be in any order. | ||
| 785 | */ | 803 | */ |
| 786 | const struct of_device_id *of_match_node(const struct of_device_id *matches, | 804 | const struct of_device_id *of_match_node(const struct of_device_id *matches, |
| 787 | const struct device_node *node) | 805 | const struct device_node *node) |
