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) |