| /* | |
| * 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. | |
| * | |
| * 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/module.h> | |
| #include <linux/of.h> | |
| #include <linux/spinlock.h> | |
| struct device_node *allnodes; | |
| /* use when traversing tree through the allnext, child, sibling, | |
| * or parent members of struct device_node. | |
| */ | |
| DEFINE_RWLOCK(devtree_lock); | |
| int of_n_addr_cells(struct device_node *np) | |
| { | |
| const int *ip; | |
| do { | |
| if (np->parent) | |
| np = np->parent; | |
| ip = of_get_property(np, "#address-cells", NULL); | |
| if (ip) | |
| return *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 int *ip; | |
| do { | |
| if (np->parent) | |
| np = np->parent; | |
| ip = of_get_property(np, "#size-cells", NULL); | |
| if (ip) | |
| return *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); | |
| struct property *of_find_property(const struct device_node *np, | |
| const char *name, | |
| int *lenp) | |
| { | |
| struct property *pp; | |
| if (!np) | |
| return NULL; | |
| read_lock(&devtree_lock); | |
| for (pp = np->properties; pp != 0; pp = pp->next) { | |
| if (of_prop_cmp(pp->name, name) == 0) { | |
| if (lenp != 0) | |
| *lenp = pp->length; | |
| break; | |
| } | |
| } | |
| read_unlock(&devtree_lock); | |
| return pp; | |
| } | |
| EXPORT_SYMBOL(of_find_property); | |
| /* | |
| * 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); | |
| /** 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) | |
| { | |
| const char* cp; | |
| int cplen, l; | |
| 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; | |
| } | |
| return 0; | |
| } | |
| EXPORT_SYMBOL(of_device_is_compatible); | |
| /** | |
| * of_device_is_available - check if a device is available for use | |
| * | |
| * @device: Node to check for availability | |
| * | |
| * Returns 1 if the status property is absent or set to "okay" or "ok", | |
| * 0 otherwise | |
| */ | |
| int of_device_is_available(const struct device_node *device) | |
| { | |
| const char *status; | |
| int statlen; | |
| status = of_get_property(device, "status", &statlen); | |
| if (status == NULL) | |
| return 1; | |
| if (statlen > 0) { | |
| if (!strcmp(status, "okay") || !strcmp(status, "ok")) | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| EXPORT_SYMBOL(of_device_is_available); | |
| /** | |
| * of_get_parent - Get a node's parent if any | |
| * @node: Node to get parent | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_get_parent(const struct device_node *node) | |
| { | |
| struct device_node *np; | |
| if (!node) | |
| return NULL; | |
| read_lock(&devtree_lock); | |
| np = of_node_get(node->parent); | |
| read_unlock(&devtree_lock); | |
| return np; | |
| } | |
| EXPORT_SYMBOL(of_get_parent); | |
| /** | |
| * of_get_next_parent - Iterate to a node's parent | |
| * @node: Node to get parent of | |
| * | |
| * This is like of_get_parent() except that it drops the | |
| * refcount on the passed node, making it suitable for iterating | |
| * through a node's parents. | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_get_next_parent(struct device_node *node) | |
| { | |
| struct device_node *parent; | |
| if (!node) | |
| return NULL; | |
| read_lock(&devtree_lock); | |
| parent = of_node_get(node->parent); | |
| of_node_put(node); | |
| read_unlock(&devtree_lock); | |
| return parent; | |
| } | |
| /** | |
| * of_get_next_child - Iterate a node childs | |
| * @node: parent node | |
| * @prev: previous child of the parent node, or NULL to get first | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_get_next_child(const struct device_node *node, | |
| struct device_node *prev) | |
| { | |
| struct device_node *next; | |
| read_lock(&devtree_lock); | |
| next = prev ? prev->sibling : node->child; | |
| for (; next; next = next->sibling) | |
| if (of_node_get(next)) | |
| break; | |
| of_node_put(prev); | |
| read_unlock(&devtree_lock); | |
| return next; | |
| } | |
| EXPORT_SYMBOL(of_get_next_child); | |
| /** | |
| * of_find_node_by_path - Find a node matching a full OF path | |
| * @path: The full path to match | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_find_node_by_path(const char *path) | |
| { | |
| struct device_node *np = allnodes; | |
| read_lock(&devtree_lock); | |
| for (; np; np = np->allnext) { | |
| if (np->full_name && (of_node_cmp(np->full_name, path) == 0) | |
| && of_node_get(np)) | |
| break; | |
| } | |
| read_unlock(&devtree_lock); | |
| return np; | |
| } | |
| EXPORT_SYMBOL(of_find_node_by_path); | |
| /** | |
| * of_find_node_by_name - Find a node by its "name" property | |
| * @from: The node to start searching from or NULL, the node | |
| * you pass will not be searched, only the next one | |
| * will; typically, you pass what the previous call | |
| * returned. of_node_put() will be called on it | |
| * @name: The name string to match against | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_find_node_by_name(struct device_node *from, | |
| const char *name) | |
| { | |
| struct device_node *np; | |
| read_lock(&devtree_lock); | |
| np = from ? from->allnext : allnodes; | |
| for (; np; np = np->allnext) | |
| if (np->name && (of_node_cmp(np->name, name) == 0) | |
| && of_node_get(np)) | |
| break; | |
| of_node_put(from); | |
| read_unlock(&devtree_lock); | |
| return np; | |
| } | |
| EXPORT_SYMBOL(of_find_node_by_name); | |
| /** | |
| * of_find_node_by_type - Find a node by its "device_type" property | |
| * @from: The node to start searching from, or NULL to start searching | |
| * the entire device tree. The node you pass will not be | |
| * searched, only the next one will; typically, you pass | |
| * what the previous call returned. of_node_put() will be | |
| * called on from for you. | |
| * @type: The type string to match against | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_find_node_by_type(struct device_node *from, | |
| const char *type) | |
| { | |
| struct device_node *np; | |
| read_lock(&devtree_lock); | |
| np = from ? from->allnext : allnodes; | |
| for (; np; np = np->allnext) | |
| if (np->type && (of_node_cmp(np->type, type) == 0) | |
| && of_node_get(np)) | |
| break; | |
| of_node_put(from); | |
| read_unlock(&devtree_lock); | |
| return np; | |
| } | |
| EXPORT_SYMBOL(of_find_node_by_type); | |
| /** | |
| * of_find_compatible_node - Find a node based on type and one of the | |
| * tokens in its "compatible" property | |
| * @from: The node to start searching from or NULL, the node | |
| * you pass will not be searched, only the next one | |
| * will; typically, you pass what the previous call | |
| * returned. of_node_put() will be called on it | |
| * @type: The type string to match "device_type" or NULL to ignore | |
| * @compatible: The string to match to one of the tokens in the device | |
| * "compatible" list. | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_find_compatible_node(struct device_node *from, | |
| const char *type, const char *compatible) | |
| { | |
| struct device_node *np; | |
| read_lock(&devtree_lock); | |
| np = from ? from->allnext : 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) && of_node_get(np)) | |
| break; | |
| } | |
| of_node_put(from); | |
| read_unlock(&devtree_lock); | |
| return np; | |
| } | |
| EXPORT_SYMBOL(of_find_compatible_node); | |
| /** | |
| * of_match_node - Tell if an device_node has a matching of_match structure | |
| * @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. | |
| */ | |
| const struct of_device_id *of_match_node(const struct of_device_id *matches, | |
| const struct device_node *node) | |
| { | |
| 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++; | |
| } | |
| return NULL; | |
| } | |
| EXPORT_SYMBOL(of_match_node); | |
| /** | |
| * of_find_matching_node - Find a node based on an of_device_id match | |
| * table. | |
| * @from: The node to start searching from or NULL, the node | |
| * you pass will not be searched, only the next one | |
| * will; typically, you pass what the previous call | |
| * returned. of_node_put() will be called on it | |
| * @matches: array of of device match structures to search in | |
| * | |
| * Returns a node pointer with refcount incremented, use | |
| * of_node_put() on it when done. | |
| */ | |
| struct device_node *of_find_matching_node(struct device_node *from, | |
| const struct of_device_id *matches) | |
| { | |
| struct device_node *np; | |
| read_lock(&devtree_lock); | |
| np = from ? from->allnext : allnodes; | |
| for (; np; np = np->allnext) { | |
| if (of_match_node(matches, np) && of_node_get(np)) | |
| break; | |
| } | |
| of_node_put(from); | |
| read_unlock(&devtree_lock); | |
| return np; | |
| } | |
| EXPORT_SYMBOL(of_find_matching_node); |