/* * Procedures for creating, accessing and interpreting the device tree. * * Paul Mackerras August 1996. * Copyright (C) 1996-2005 Paul Mackerras. * * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. * {engebret|bergner}@us.ibm.com * * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net * * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and * Grant Likely. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/console.h>#include <linux/ctype.h>#include <linux/cpu.h>#include <linux/module.h>#include <linux/of.h>#include <linux/of_graph.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/proc_fs.h> #include "of_private.h" LIST_HEAD(aliases_lookup); struct device_node *of_root;EXPORT_SYMBOL(of_root);struct device_node *of_chosen;struct device_node *of_aliases;struct device_node *of_stdout;static const char *of_stdout_options; struct kset *of_kset; /* * Used to protect the of_aliases, to hold off addition of nodes to sysfs. * This mutex must be held whenever modifications are being made to the * device tree. The of_{attach,detach}_node() and * of_{add,remove,update}_property() helpers make sure this happens. */DEFINE_MUTEX(of_mutex); /* use when traversing tree through the child, sibling, * or parent members of struct device_node. */DEFINE_RAW_SPINLOCK(devtree_lock); int of_n_addr_cells(struct device_node *np){ const __be32 *ip; do { if (np->parent) np = np->parent; ip = of_get_property(np, "#address-cells", NULL); if (ip) return be32_to_cpup(ip); } while (np->parent); /* No #address-cells property for the root node */ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;}EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np){ const __be32 *ip; do { if (np->parent) np = np->parent; ip = of_get_property(np, "#size-cells", NULL); if (ip) return be32_to_cpup(ip); } while (np->parent); /* No #size-cells property for the root node */ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;}EXPORT_SYMBOL(of_n_size_cells); #ifdef CONFIG_NUMAint __weak of_node_to_nid(struct device_node *np){ return NUMA_NO_NODE;}#endif #ifndef CONFIG_OF_DYNAMICstatic void of_node_release(struct kobject *kobj){ /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */}#endif /* CONFIG_OF_DYNAMIC */ struct kobj_type of_node_ktype = { .release = of_node_release,}; static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t offset, size_t count){ struct property *pp = container_of(bin_attr, struct property, attr); return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);} static const char *safe_name(struct kobject *kobj, const char *orig_name){ const char *name = orig_name; struct kernfs_node *kn; int i = 0; /* don't be a hero. After 16 tries give up */ while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { sysfs_put(kn); if (name != orig_name) kfree(name); name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); } if (name != orig_name) pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", kobject_name(kobj), name); return name;} int __of_add_property_sysfs(struct device_node *np, struct property *pp){ int rc; /* Important: Don't leak passwords */ bool secure = strncmp(pp->name, "security-", 9) == 0; if (!IS_ENABLED(CONFIG_SYSFS)) return 0; if (!of_kset || !of_node_is_attached(np)) return 0; sysfs_bin_attr_init(&pp->attr); pp->attr.attr.name = safe_name(&np->kobj, pp->name); pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; pp->attr.size = secure ? 0 : pp->length; pp->attr.read = of_node_property_read; rc = sysfs_create_bin_file(&np->kobj, &pp->attr); WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); return rc;} int __of_attach_node_sysfs(struct device_node *np){ const char *name; struct property *pp; int rc; if (!IS_ENABLED(CONFIG_SYSFS)) return 0; if (!of_kset) return 0; np->kobj.kset = of_kset; if (!np->parent) { /* Nodes without parents are new top level trees */ rc = kobject_add(&np->kobj, NULL, "%s", safe_name(&of_kset->kobj, "base")); } else { name = safe_name(&np->parent->kobj, kbasename(np->full_name)); if (!name || !name[0]) return -EINVAL; rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name); } if (rc) return rc; for_each_property_of_node(np, pp) __of_add_property_sysfs(np, pp); return 0;} void __init of_core_init(void){ struct device_node *np; /* Create the kset, and register existing nodes */ mutex_lock(&of_mutex); of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); if (!of_kset) { mutex_unlock(&of_mutex); pr_err("devicetree: failed to register existing nodes\n"); return; } for_each_of_allnodes(np) __of_attach_node_sysfs(np); mutex_unlock(&of_mutex); /* Symlink in /proc as required by userspace ABI */ if (of_root) proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");} static struct property *__of_find_property(const struct device_node *np, const char *name, int *lenp){ struct property *pp; if (!np) return NULL; for (pp = np->properties; pp; pp = pp->next) { if (of_prop_cmp(pp->name, name) == 0) { if (lenp) *lenp = pp->length; break; } } return pp;} struct property *of_find_property(const struct device_node *np, const char *name, int *lenp){ struct property *pp; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); pp = __of_find_property(np, name, lenp); raw_spin_unlock_irqrestore(&devtree_lock, flags); return pp;}EXPORT_SYMBOL(of_find_property); struct device_node *__of_find_all_nodes(struct device_node *prev){ struct device_node *np; if (!prev) { np = of_root; } else if (prev->child) { np = prev->child; } else { /* Walk back up looking for a sibling, or the end of the structure */ np = prev; while (np->parent && !np->sibling) np = np->parent; np = np->sibling; /* Might be null at the end of the tree */ } return np;} /** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_all_nodes(struct device_node *prev){ struct device_node *np; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); np = __of_find_all_nodes(prev); of_node_get(np); of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_all_nodes); /* * Find a property with a given name for a given node * and return the value. */const void *__of_get_property(const struct device_node *np, const char *name, int *lenp){ struct property *pp = __of_find_property(np, name, lenp); return pp ? pp->value : NULL;} /* * Find a property with a given name for a given node * and return the value. */const void *of_get_property(const struct device_node *np, const char *name, int *lenp){ struct property *pp = of_find_property(np, name, lenp); return pp ? pp->value : NULL;}EXPORT_SYMBOL(of_get_property); /* * arch_match_cpu_phys_id - Match the given logical CPU and physical id * * @cpu: logical cpu index of a core/thread * @phys_id: physical identifier of a core/thread * * CPU logical to physical index mapping is architecture specific. * However this __weak function provides a default match of physical * id to logical cpu index. phys_id provided here is usually values read * from the device tree which must match the hardware internal registers. * * Returns true if the physical identifier and the logical cpu index * correspond to the same core/thread, false otherwise. */bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id){ return (u32)phys_id == cpu;} /** * Checks if the given "prop_name" property holds the physical id of the * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not * NULL, local thread number within the core is returned in it. */static bool __of_find_n_match_cpu_property(struct device_node *cpun, const char *prop_name, int cpu, unsigned int *thread){ const __be32 *cell; int ac, prop_len, tid; u64 hwid; ac = of_n_addr_cells(cpun); cell = of_get_property(cpun, prop_name, &prop_len); if (!cell || !ac) return false; prop_len /= sizeof(*cell) * ac; for (tid = 0; tid < prop_len; tid++) { hwid = of_read_number(cell, ac); if (arch_match_cpu_phys_id(cpu, hwid)) { if (thread) *thread = tid; return true; } cell += ac; } return false;} /* * arch_find_n_match_cpu_physical_id - See if the given device node is * for the cpu corresponding to logical cpu 'cpu'. Return true if so, * else false. If 'thread' is non-NULL, the local thread number within the * core is returned in it. */bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, int cpu, unsigned int *thread){ /* Check for non-standard "ibm,ppc-interrupt-server#s" property * for thread ids on PowerPC. If it doesn't exist fallback to * standard "reg" property. */ if (IS_ENABLED(CONFIG_PPC) && __of_find_n_match_cpu_property(cpun, "ibm,ppc-interrupt-server#s", cpu, thread)) return true; if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) return true; return false;} /** * of_get_cpu_node - Get device node associated with the given logical CPU * * @cpu: CPU number(logical index) for which device node is required * @thread: if not NULL, local thread number within the physical core is * returned * * The main purpose of this function is to retrieve the device node for the * given logical CPU index. It should be used to initialize the of_node in * cpu device. Once of_node in cpu device is populated, all the further * references can use that instead. * * CPU logical to physical index mapping is architecture specific and is built * before booting secondary cores. This function uses arch_match_cpu_phys_id * which can be overridden by architecture specific implementation. * * Returns a node pointer for the logical cpu if found, else NULL. */struct device_node *of_get_cpu_node(int cpu, unsigned int *thread){ struct device_node *cpun; for_each_node_by_type(cpun, "cpu") { if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) return cpun; } return NULL;}EXPORT_SYMBOL(of_get_cpu_node); /** * __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 *type, const char *name){ 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; } /* Matching type is better than matching name */ if (type && type[0]) { if (!device->type || of_node_cmp(type, device->type)) return 0; score += 2; } /* 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 * the device's "compatible" property */int of_device_is_compatible(const struct device_node *device, const char *compat){ unsigned long flags; int res; raw_spin_lock_irqsave(&devtree_lock, flags); res = __of_device_is_compatible(device, compat, NULL, NULL); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res;}EXPORT_SYMBOL(of_device_is_compatible); /** * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property.Lines 1–500 of 2310. Load more
/* * Procedures for creating, accessing and interpreting the device tree. * * Paul Mackerras August 1996. * Copyright (C) 1996-2005 Paul Mackerras. * * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. * {engebret|bergner}@us.ibm.com * * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net * * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and * Grant Likely. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/console.h> #include <linux/ctype.h> #include <linux/cpu.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/proc_fs.h> #include "of_private.h" LIST_HEAD(aliases_lookup); struct device_node *of_root; EXPORT_SYMBOL(of_root); struct device_node *of_chosen; struct device_node *of_aliases; struct device_node *of_stdout; static const char *of_stdout_options; struct kset *of_kset; /* * Used to protect the of_aliases, to hold off addition of nodes to sysfs. * This mutex must be held whenever modifications are being made to the * device tree. The of_{attach,detach}_node() and * of_{add,remove,update}_property() helpers make sure this happens. */ DEFINE_MUTEX(of_mutex); /* use when traversing tree through the child, sibling, * or parent members of struct device_node. */ DEFINE_RAW_SPINLOCK(devtree_lock); int of_n_addr_cells(struct device_node *np) { const __be32 *ip; do { if (np->parent) np = np->parent; ip = of_get_property(np, "#address-cells", NULL); if (ip) return be32_to_cpup(ip); } while (np->parent); /* No #address-cells property for the root node */ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; } EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np) { const __be32 *ip; do { if (np->parent) np = np->parent; ip = of_get_property(np, "#size-cells", NULL); if (ip) return be32_to_cpup(ip); } while (np->parent); /* No #size-cells property for the root node */ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; } EXPORT_SYMBOL(of_n_size_cells); #ifdef CONFIG_NUMA int __weak of_node_to_nid(struct device_node *np) { return NUMA_NO_NODE; } #endif #ifndef CONFIG_OF_DYNAMIC static void of_node_release(struct kobject *kobj) { /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ } #endif /* CONFIG_OF_DYNAMIC */ struct kobj_type of_node_ktype = { .release = of_node_release, }; static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t offset, size_t count) { struct property *pp = container_of(bin_attr, struct property, attr); return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); } static const char *safe_name(struct kobject *kobj, const char *orig_name) { const char *name = orig_name; struct kernfs_node *kn; int i = 0; /* don't be a hero. After 16 tries give up */ while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { sysfs_put(kn); if (name != orig_name) kfree(name); name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); } if (name != orig_name) pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", kobject_name(kobj), name); return name; } int __of_add_property_sysfs(struct device_node *np, struct property *pp) { int rc; /* Important: Don't leak passwords */ bool secure = strncmp(pp->name, "security-", 9) == 0; if (!IS_ENABLED(CONFIG_SYSFS)) return 0; if (!of_kset || !of_node_is_attached(np)) return 0; sysfs_bin_attr_init(&pp->attr); pp->attr.attr.name = safe_name(&np->kobj, pp->name); pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; pp->attr.size = secure ? 0 : pp->length; pp->attr.read = of_node_property_read; rc = sysfs_create_bin_file(&np->kobj, &pp->attr); WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); return rc; } int __of_attach_node_sysfs(struct device_node *np) { const char *name; struct property *pp; int rc; if (!IS_ENABLED(CONFIG_SYSFS)) return 0; if (!of_kset) return 0; np->kobj.kset = of_kset; if (!np->parent) { /* Nodes without parents are new top level trees */ rc = kobject_add(&np->kobj, NULL, "%s", safe_name(&of_kset->kobj, "base")); } else { name = safe_name(&np->parent->kobj, kbasename(np->full_name)); if (!name || !name[0]) return -EINVAL; rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name); } if (rc) return rc; for_each_property_of_node(np, pp) __of_add_property_sysfs(np, pp); return 0; } void __init of_core_init(void) { struct device_node *np; /* Create the kset, and register existing nodes */ mutex_lock(&of_mutex); of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); if (!of_kset) { mutex_unlock(&of_mutex); pr_err("devicetree: failed to register existing nodes\n"); return; } for_each_of_allnodes(np) __of_attach_node_sysfs(np); mutex_unlock(&of_mutex); /* Symlink in /proc as required by userspace ABI */ if (of_root) proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); } static struct property *__of_find_property(const struct device_node *np, const char *name, int *lenp) { struct property *pp; if (!np) return NULL; for (pp = np->properties; pp; pp = pp->next) { if (of_prop_cmp(pp->name, name) == 0) { if (lenp) *lenp = pp->length; break; } } return pp; } struct property *of_find_property(const struct device_node *np, const char *name, int *lenp) { struct property *pp; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); pp = __of_find_property(np, name, lenp); raw_spin_unlock_irqrestore(&devtree_lock, flags); return pp; } EXPORT_SYMBOL(of_find_property); struct device_node *__of_find_all_nodes(struct device_node *prev) { struct device_node *np; if (!prev) { np = of_root; } else if (prev->child) { np = prev->child; } else { /* Walk back up looking for a sibling, or the end of the structure */ np = prev; while (np->parent && !np->sibling) np = np->parent; np = np->sibling; /* Might be null at the end of the tree */ } return np; } /** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */ struct device_node *of_find_all_nodes(struct device_node *prev) { struct device_node *np; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); np = __of_find_all_nodes(prev); of_node_get(np); of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; } EXPORT_SYMBOL(of_find_all_nodes); /* * Find a property with a given name for a given node * and return the value. */ const void *__of_get_property(const struct device_node *np, const char *name, int *lenp) { struct property *pp = __of_find_property(np, name, lenp); return pp ? pp->value : NULL; } /* * Find a property with a given name for a given node * and return the value. */ const void *of_get_property(const struct device_node *np, const char *name, int *lenp) { struct property *pp = of_find_property(np, name, lenp); return pp ? pp->value : NULL; } EXPORT_SYMBOL(of_get_property); /* * arch_match_cpu_phys_id - Match the given logical CPU and physical id * * @cpu: logical cpu index of a core/thread * @phys_id: physical identifier of a core/thread * * CPU logical to physical index mapping is architecture specific. * However this __weak function provides a default match of physical * id to logical cpu index. phys_id provided here is usually values read * from the device tree which must match the hardware internal registers. * * Returns true if the physical identifier and the logical cpu index * correspond to the same core/thread, false otherwise. */ bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id) { return (u32)phys_id == cpu; } /** * Checks if the given "prop_name" property holds the physical id of the * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not * NULL, local thread number within the core is returned in it. */ static bool __of_find_n_match_cpu_property(struct device_node *cpun, const char *prop_name, int cpu, unsigned int *thread) { const __be32 *cell; int ac, prop_len, tid; u64 hwid; ac = of_n_addr_cells(cpun); cell = of_get_property(cpun, prop_name, &prop_len); if (!cell || !ac) return false; prop_len /= sizeof(*cell) * ac; for (tid = 0; tid < prop_len; tid++) { hwid = of_read_number(cell, ac); if (arch_match_cpu_phys_id(cpu, hwid)) { if (thread) *thread = tid; return true; } cell += ac; } return false; } /* * arch_find_n_match_cpu_physical_id - See if the given device node is * for the cpu corresponding to logical cpu 'cpu'. Return true if so, * else false. If 'thread' is non-NULL, the local thread number within the * core is returned in it. */ bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, int cpu, unsigned int *thread) { /* Check for non-standard "ibm,ppc-interrupt-server#s" property * for thread ids on PowerPC. If it doesn't exist fallback to * standard "reg" property. */ if (IS_ENABLED(CONFIG_PPC) && __of_find_n_match_cpu_property(cpun, "ibm,ppc-interrupt-server#s", cpu, thread)) return true; if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) return true; return false; } /** * of_get_cpu_node - Get device node associated with the given logical CPU * * @cpu: CPU number(logical index) for which device node is required * @thread: if not NULL, local thread number within the physical core is * returned * * The main purpose of this function is to retrieve the device node for the * given logical CPU index. It should be used to initialize the of_node in * cpu device. Once of_node in cpu device is populated, all the further * references can use that instead. * * CPU logical to physical index mapping is architecture specific and is built * before booting secondary cores. This function uses arch_match_cpu_phys_id * which can be overridden by architecture specific implementation. * * Returns a node pointer for the logical cpu if found, else NULL. */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) { struct device_node *cpun; for_each_node_by_type(cpun, "cpu") { if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) return cpun; } return NULL; } EXPORT_SYMBOL(of_get_cpu_node); /** * __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 *type, const char *name) { 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; } /* Matching type is better than matching name */ if (type && type[0]) { if (!device->type || of_node_cmp(type, device->type)) return 0; score += 2; } /* 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 * the device's "compatible" property */ int of_device_is_compatible(const struct device_node *device, const char *compat) { unsigned long flags; int res; raw_spin_lock_irqsave(&devtree_lock, flags); res = __of_device_is_compatible(device, compat, NULL, NULL); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res; } EXPORT_SYMBOL(of_device_is_compatible); /** * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property.