|
@@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
|
|
|
}
|
|
|
EXPORT_SYMBOL(of_get_cpu_node);
|
|
|
|
|
|
-/** Checks if the given "compat" string matches one of the strings in
|
|
|
- * the device's "compatible" property
|
|
|
+/**
|
|
|
+ * __of_device_is_compatible() - Check if the node matches given constraints
|
|
|
+ * @device: pointer to node
|
|
|
+ * @compat: required compatible string, NULL or "" for any match
|
|
|
+ * @type: required device_type value, NULL or "" for any match
|
|
|
+ * @name: required node name, NULL or "" for any match
|
|
|
+ *
|
|
|
+ * Checks if the given @compat, @type and @name strings match the
|
|
|
+ * properties of the given @device. A constraints can be skipped by
|
|
|
+ * passing NULL or an empty string as the constraint.
|
|
|
+ *
|
|
|
+ * Returns 0 for no match, and a positive integer on match. The return
|
|
|
+ * value is a relative score with larger values indicating better
|
|
|
+ * matches. The score is weighted for the most specific compatible value
|
|
|
+ * to get the highest score. Matching type is next, followed by matching
|
|
|
+ * name. Practically speaking, this results in the following priority
|
|
|
+ * order for matches:
|
|
|
+ *
|
|
|
+ * 1. specific compatible && type && name
|
|
|
+ * 2. specific compatible && type
|
|
|
+ * 3. specific compatible && name
|
|
|
+ * 4. specific compatible
|
|
|
+ * 5. general compatible && type && name
|
|
|
+ * 6. general compatible && type
|
|
|
+ * 7. general compatible && name
|
|
|
+ * 8. general compatible
|
|
|
+ * 9. type && name
|
|
|
+ * 10. type
|
|
|
+ * 11. name
|
|
|
*/
|
|
|
static int __of_device_is_compatible(const struct device_node *device,
|
|
|
- const char *compat)
|
|
|
+ const char *compat, const char *type, const char *name)
|
|
|
{
|
|
|
- const char* cp;
|
|
|
- int cplen, l;
|
|
|
+ struct property *prop;
|
|
|
+ const char *cp;
|
|
|
+ int index = 0, score = 0;
|
|
|
+
|
|
|
+ /* Compatible match has highest priority */
|
|
|
+ if (compat && compat[0]) {
|
|
|
+ prop = __of_find_property(device, "compatible", NULL);
|
|
|
+ for (cp = of_prop_next_string(prop, NULL); cp;
|
|
|
+ cp = of_prop_next_string(prop, cp), index++) {
|
|
|
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
|
|
|
+ score = INT_MAX/2 - (index << 2);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!score)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- cp = __of_get_property(device, "compatible", &cplen);
|
|
|
- if (cp == NULL)
|
|
|
- return 0;
|
|
|
- while (cplen > 0) {
|
|
|
- if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
|
|
|
- return 1;
|
|
|
- l = strlen(cp) + 1;
|
|
|
- cp += l;
|
|
|
- cplen -= l;
|
|
|
+ /* Matching type is better than matching name */
|
|
|
+ if (type && type[0]) {
|
|
|
+ if (!device->type || of_node_cmp(type, device->type))
|
|
|
+ return 0;
|
|
|
+ score += 2;
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ /* Matching name is a bit better than not */
|
|
|
+ if (name && name[0]) {
|
|
|
+ if (!device->name || of_node_cmp(name, device->name))
|
|
|
+ return 0;
|
|
|
+ score++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return score;
|
|
|
}
|
|
|
|
|
|
/** 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,
|
|
|
int res;
|
|
|
|
|
|
raw_spin_lock_irqsave(&devtree_lock, flags);
|
|
|
- res = __of_device_is_compatible(device, compat);
|
|
|
+ res = __of_device_is_compatible(device, compat, NULL, NULL);
|
|
|
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
|
|
return res;
|
|
|
}
|
|
@@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
|
|
|
raw_spin_lock_irqsave(&devtree_lock, flags);
|
|
|
np = from ? from->allnext : of_allnodes;
|
|
|
for (; np; np = np->allnext) {
|
|
|
- if (type
|
|
|
- && !(np->type && (of_node_cmp(np->type, type) == 0)))
|
|
|
- continue;
|
|
|
- if (__of_device_is_compatible(np, compatible) &&
|
|
|
+ if (__of_device_is_compatible(np, compatible, type, NULL) &&
|
|
|
of_node_get(np))
|
|
|
break;
|
|
|
}
|
|
@@ -730,65 +772,26 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL(of_find_node_with_property);
|
|
|
|
|
|
-static const struct of_device_id *
|
|
|
-of_match_compatible(const struct of_device_id *matches,
|
|
|
- const struct device_node *node)
|
|
|
-{
|
|
|
- const char *cp;
|
|
|
- int cplen, l;
|
|
|
- const struct of_device_id *m;
|
|
|
-
|
|
|
- cp = __of_get_property(node, "compatible", &cplen);
|
|
|
- while (cp && (cplen > 0)) {
|
|
|
- m = matches;
|
|
|
- while (m->name[0] || m->type[0] || m->compatible[0]) {
|
|
|
- /* Only match for the entries without type and name */
|
|
|
- if (m->name[0] || m->type[0] ||
|
|
|
- of_compat_cmp(m->compatible, cp,
|
|
|
- strlen(m->compatible)))
|
|
|
- m++;
|
|
|
- else
|
|
|
- return m;
|
|
|
- }
|
|
|
-
|
|
|
- /* Get node's next compatible string */
|
|
|
- l = strlen(cp) + 1;
|
|
|
- cp += l;
|
|
|
- cplen -= l;
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
static
|
|
|
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
|
|
|
const struct device_node *node)
|
|
|
{
|
|
|
- const struct of_device_id *m;
|
|
|
+ const struct of_device_id *best_match = NULL;
|
|
|
+ int score, best_score = 0;
|
|
|
|
|
|
if (!matches)
|
|
|
return NULL;
|
|
|
|
|
|
- m = of_match_compatible(matches, node);
|
|
|
- if (m)
|
|
|
- return m;
|
|
|
-
|
|
|
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
|
|
|
- int match = 1;
|
|
|
- if (matches->name[0])
|
|
|
- match &= node->name
|
|
|
- && !strcmp(matches->name, node->name);
|
|
|
- if (matches->type[0])
|
|
|
- match &= node->type
|
|
|
- && !strcmp(matches->type, node->type);
|
|
|
- if (matches->compatible[0])
|
|
|
- match &= __of_device_is_compatible(node,
|
|
|
- matches->compatible);
|
|
|
- if (match)
|
|
|
- return matches;
|
|
|
- matches++;
|
|
|
+ for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
|
|
|
+ score = __of_device_is_compatible(node, matches->compatible,
|
|
|
+ matches->type, matches->name);
|
|
|
+ if (score > best_score) {
|
|
|
+ best_match = matches;
|
|
|
+ best_score = score;
|
|
|
+ }
|
|
|
}
|
|
|
- return NULL;
|
|
|
+
|
|
|
+ return best_match;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -796,12 +799,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
|
|
|
* @matches: array of of device match structures to search in
|
|
|
* @node: the of device structure to match against
|
|
|
*
|
|
|
- * Low level utility function used by device matching. We have two ways
|
|
|
- * of matching:
|
|
|
- * - Try to find the best compatible match by comparing each compatible
|
|
|
- * string of device node with all the given matches respectively.
|
|
|
- * - If the above method failed, then try to match the compatible by using
|
|
|
- * __of_device_is_compatible() besides the match in type and name.
|
|
|
+ * Low level utility function used by device matching.
|
|
|
*/
|
|
|
const struct of_device_id *of_match_node(const struct of_device_id *matches,
|
|
|
const struct device_node *node)
|