|  | /* | 
|  | * 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); |