|  | /* | 
|  | * 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/module.h> | 
|  | #include <linux/of.h> | 
|  | #include <linux/spinlock.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/proc_fs.h> | 
|  |  | 
|  | struct device_node *allnodes; | 
|  | struct device_node *of_chosen; | 
|  |  | 
|  | /* 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 __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); | 
|  |  | 
|  | #if !defined(CONFIG_SPARC)   /* SPARC doesn't do ref counting (yet) */ | 
|  | /** | 
|  | *	of_node_get - Increment refcount of a node | 
|  | *	@node:	Node to inc refcount, NULL is supported to | 
|  | *		simplify writing of callers | 
|  | * | 
|  | *	Returns node. | 
|  | */ | 
|  | struct device_node *of_node_get(struct device_node *node) | 
|  | { | 
|  | if (node) | 
|  | kref_get(&node->kref); | 
|  | return node; | 
|  | } | 
|  | EXPORT_SYMBOL(of_node_get); | 
|  |  | 
|  | static inline struct device_node *kref_to_device_node(struct kref *kref) | 
|  | { | 
|  | return container_of(kref, struct device_node, kref); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *	of_node_release - release a dynamically allocated node | 
|  | *	@kref:  kref element of the node to be released | 
|  | * | 
|  | *	In of_node_put() this function is passed to kref_put() | 
|  | *	as the destructor. | 
|  | */ | 
|  | static void of_node_release(struct kref *kref) | 
|  | { | 
|  | struct device_node *node = kref_to_device_node(kref); | 
|  | struct property *prop = node->properties; | 
|  |  | 
|  | /* We should never be releasing nodes that haven't been detached. */ | 
|  | if (!of_node_check_flag(node, OF_DETACHED)) { | 
|  | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); | 
|  | dump_stack(); | 
|  | kref_init(&node->kref); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!of_node_check_flag(node, OF_DYNAMIC)) | 
|  | return; | 
|  |  | 
|  | while (prop) { | 
|  | struct property *next = prop->next; | 
|  | kfree(prop->name); | 
|  | kfree(prop->value); | 
|  | kfree(prop); | 
|  | prop = next; | 
|  |  | 
|  | if (!prop) { | 
|  | prop = node->deadprops; | 
|  | node->deadprops = NULL; | 
|  | } | 
|  | } | 
|  | kfree(node->full_name); | 
|  | kfree(node->data); | 
|  | kfree(node); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *	of_node_put - Decrement refcount of a node | 
|  | *	@node:	Node to dec refcount, NULL is supported to | 
|  | *		simplify writing of callers | 
|  | * | 
|  | */ | 
|  | void of_node_put(struct device_node *node) | 
|  | { | 
|  | if (node) | 
|  | kref_put(&node->kref, of_node_release); | 
|  | } | 
|  | EXPORT_SYMBOL(of_node_put); | 
|  | #endif /* !CONFIG_SPARC */ | 
|  |  | 
|  | 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); | 
|  |  | 
|  | /** | 
|  | * 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; | 
|  |  | 
|  | read_lock(&devtree_lock); | 
|  | np = prev ? prev->allnext : allnodes; | 
|  | for (; np != NULL; np = np->allnext) | 
|  | if (of_node_get(np)) | 
|  | break; | 
|  | of_node_put(prev); | 
|  | read_unlock(&devtree_lock); | 
|  | 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; | 
|  | } | 
|  | 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_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. | 
|  | * | 
|  | * Returns true if the root node has the given value in its | 
|  | * compatible property. | 
|  | */ | 
|  | int of_machine_is_compatible(const char *compat) | 
|  | { | 
|  | struct device_node *root; | 
|  | int rc = 0; | 
|  |  | 
|  | root = of_find_node_by_path("/"); | 
|  | if (root) { | 
|  | rc = of_device_is_compatible(root, compat); | 
|  | of_node_put(root); | 
|  | } | 
|  | return rc; | 
|  | } | 
|  | EXPORT_SYMBOL(of_machine_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_find_node_with_property - Find a node which has a property with | 
|  | *                                   the given name. | 
|  | *	@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 | 
|  | *	@prop_name:	The name of the property to look for. | 
|  | * | 
|  | *	Returns a node pointer with refcount incremented, use | 
|  | *	of_node_put() on it when done. | 
|  | */ | 
|  | struct device_node *of_find_node_with_property(struct device_node *from, | 
|  | const char *prop_name) | 
|  | { | 
|  | struct device_node *np; | 
|  | struct property *pp; | 
|  |  | 
|  | read_lock(&devtree_lock); | 
|  | np = from ? from->allnext : allnodes; | 
|  | for (; np; np = np->allnext) { | 
|  | for (pp = np->properties; pp != 0; pp = pp->next) { | 
|  | if (of_prop_cmp(pp->name, prop_name) == 0) { | 
|  | of_node_get(np); | 
|  | goto out; | 
|  | } | 
|  | } | 
|  | } | 
|  | out: | 
|  | of_node_put(from); | 
|  | read_unlock(&devtree_lock); | 
|  | return np; | 
|  | } | 
|  | EXPORT_SYMBOL(of_find_node_with_property); | 
|  |  | 
|  | /** | 
|  | * 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) | 
|  | { | 
|  | if (!matches) | 
|  | return NULL; | 
|  |  | 
|  | 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); | 
|  |  | 
|  | /** | 
|  | * of_modalias_node - Lookup appropriate modalias for a device node | 
|  | * @node:	pointer to a device tree node | 
|  | * @modalias:	Pointer to buffer that modalias value will be copied into | 
|  | * @len:	Length of modalias value | 
|  | * | 
|  | * Based on the value of the compatible property, this routine will attempt | 
|  | * to choose an appropriate modalias value for a particular device tree node. | 
|  | * It does this by stripping the manufacturer prefix (as delimited by a ',') | 
|  | * from the first entry in the compatible list property. | 
|  | * | 
|  | * This routine returns 0 on success, <0 on failure. | 
|  | */ | 
|  | int of_modalias_node(struct device_node *node, char *modalias, int len) | 
|  | { | 
|  | const char *compatible, *p; | 
|  | int cplen; | 
|  |  | 
|  | compatible = of_get_property(node, "compatible", &cplen); | 
|  | if (!compatible || strlen(compatible) > cplen) | 
|  | return -ENODEV; | 
|  | p = strchr(compatible, ','); | 
|  | strlcpy(modalias, p ? p + 1 : compatible, len); | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(of_modalias_node); | 
|  |  | 
|  | /** | 
|  | * of_find_node_by_phandle - Find a node given a phandle | 
|  | * @handle:	phandle of the node to find | 
|  | * | 
|  | * Returns a node pointer with refcount incremented, use | 
|  | * of_node_put() on it when done. | 
|  | */ | 
|  | struct device_node *of_find_node_by_phandle(phandle handle) | 
|  | { | 
|  | struct device_node *np; | 
|  |  | 
|  | read_lock(&devtree_lock); | 
|  | for (np = allnodes; np; np = np->allnext) | 
|  | if (np->phandle == handle) | 
|  | break; | 
|  | of_node_get(np); | 
|  | read_unlock(&devtree_lock); | 
|  | return np; | 
|  | } | 
|  | EXPORT_SYMBOL(of_find_node_by_phandle); | 
|  |  | 
|  | /** | 
|  | * of_parse_phandle - Resolve a phandle property to a device_node pointer | 
|  | * @np: Pointer to device node holding phandle property | 
|  | * @phandle_name: Name of property holding a phandle value | 
|  | * @index: For properties holding a table of phandles, this is the index into | 
|  | *         the table | 
|  | * | 
|  | * Returns the device_node pointer with refcount incremented.  Use | 
|  | * of_node_put() on it when done. | 
|  | */ | 
|  | struct device_node * | 
|  | of_parse_phandle(struct device_node *np, const char *phandle_name, int index) | 
|  | { | 
|  | const __be32 *phandle; | 
|  | int size; | 
|  |  | 
|  | phandle = of_get_property(np, phandle_name, &size); | 
|  | if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) | 
|  | return NULL; | 
|  |  | 
|  | return of_find_node_by_phandle(be32_to_cpup(phandle + index)); | 
|  | } | 
|  | EXPORT_SYMBOL(of_parse_phandle); | 
|  |  | 
|  | /** | 
|  | * of_parse_phandles_with_args - Find a node pointed by phandle in a list | 
|  | * @np:		pointer to a device tree node containing a list | 
|  | * @list_name:	property name that contains a list | 
|  | * @cells_name:	property name that specifies phandles' arguments count | 
|  | * @index:	index of a phandle to parse out | 
|  | * @out_node:	optional pointer to device_node struct pointer (will be filled) | 
|  | * @out_args:	optional pointer to arguments pointer (will be filled) | 
|  | * | 
|  | * This function is useful to parse lists of phandles and their arguments. | 
|  | * Returns 0 on success and fills out_node and out_args, on error returns | 
|  | * appropriate errno value. | 
|  | * | 
|  | * Example: | 
|  | * | 
|  | * phandle1: node1 { | 
|  | * 	#list-cells = <2>; | 
|  | * } | 
|  | * | 
|  | * phandle2: node2 { | 
|  | * 	#list-cells = <1>; | 
|  | * } | 
|  | * | 
|  | * node3 { | 
|  | * 	list = <&phandle1 1 2 &phandle2 3>; | 
|  | * } | 
|  | * | 
|  | * To get a device_node of the `node2' node you may call this: | 
|  | * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); | 
|  | */ | 
|  | int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | 
|  | const char *cells_name, int index, | 
|  | struct device_node **out_node, | 
|  | const void **out_args) | 
|  | { | 
|  | int ret = -EINVAL; | 
|  | const __be32 *list; | 
|  | const __be32 *list_end; | 
|  | int size; | 
|  | int cur_index = 0; | 
|  | struct device_node *node = NULL; | 
|  | const void *args = NULL; | 
|  |  | 
|  | list = of_get_property(np, list_name, &size); | 
|  | if (!list) { | 
|  | ret = -ENOENT; | 
|  | goto err0; | 
|  | } | 
|  | list_end = list + size / sizeof(*list); | 
|  |  | 
|  | while (list < list_end) { | 
|  | const __be32 *cells; | 
|  | phandle phandle; | 
|  |  | 
|  | phandle = be32_to_cpup(list++); | 
|  | args = list; | 
|  |  | 
|  | /* one cell hole in the list = <>; */ | 
|  | if (!phandle) | 
|  | goto next; | 
|  |  | 
|  | node = of_find_node_by_phandle(phandle); | 
|  | if (!node) { | 
|  | pr_debug("%s: could not find phandle\n", | 
|  | np->full_name); | 
|  | goto err0; | 
|  | } | 
|  |  | 
|  | cells = of_get_property(node, cells_name, &size); | 
|  | if (!cells || size != sizeof(*cells)) { | 
|  | pr_debug("%s: could not get %s for %s\n", | 
|  | np->full_name, cells_name, node->full_name); | 
|  | goto err1; | 
|  | } | 
|  |  | 
|  | list += be32_to_cpup(cells); | 
|  | if (list > list_end) { | 
|  | pr_debug("%s: insufficient arguments length\n", | 
|  | np->full_name); | 
|  | goto err1; | 
|  | } | 
|  | next: | 
|  | if (cur_index == index) | 
|  | break; | 
|  |  | 
|  | of_node_put(node); | 
|  | node = NULL; | 
|  | args = NULL; | 
|  | cur_index++; | 
|  | } | 
|  |  | 
|  | if (!node) { | 
|  | /* | 
|  | * args w/o node indicates that the loop above has stopped at | 
|  | * the 'hole' cell. Report this differently. | 
|  | */ | 
|  | if (args) | 
|  | ret = -EEXIST; | 
|  | else | 
|  | ret = -ENOENT; | 
|  | goto err0; | 
|  | } | 
|  |  | 
|  | if (out_node) | 
|  | *out_node = node; | 
|  | if (out_args) | 
|  | *out_args = args; | 
|  |  | 
|  | return 0; | 
|  | err1: | 
|  | of_node_put(node); | 
|  | err0: | 
|  | pr_debug("%s failed with status %d\n", __func__, ret); | 
|  | return ret; | 
|  | } | 
|  | EXPORT_SYMBOL(of_parse_phandles_with_args); | 
|  |  | 
|  | /** | 
|  | * prom_add_property - Add a property to a node | 
|  | */ | 
|  | int prom_add_property(struct device_node *np, struct property *prop) | 
|  | { | 
|  | struct property **next; | 
|  | unsigned long flags; | 
|  |  | 
|  | prop->next = NULL; | 
|  | write_lock_irqsave(&devtree_lock, flags); | 
|  | next = &np->properties; | 
|  | while (*next) { | 
|  | if (strcmp(prop->name, (*next)->name) == 0) { | 
|  | /* duplicate ! don't insert it */ | 
|  | write_unlock_irqrestore(&devtree_lock, flags); | 
|  | return -1; | 
|  | } | 
|  | next = &(*next)->next; | 
|  | } | 
|  | *next = prop; | 
|  | write_unlock_irqrestore(&devtree_lock, flags); | 
|  |  | 
|  | #ifdef CONFIG_PROC_DEVICETREE | 
|  | /* try to add to proc as well if it was initialized */ | 
|  | if (np->pde) | 
|  | proc_device_tree_add_prop(np->pde, prop); | 
|  | #endif /* CONFIG_PROC_DEVICETREE */ | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * prom_remove_property - Remove a property from a node. | 
|  | * | 
|  | * Note that we don't actually remove it, since we have given out | 
|  | * who-knows-how-many pointers to the data using get-property. | 
|  | * Instead we just move the property to the "dead properties" | 
|  | * list, so it won't be found any more. | 
|  | */ | 
|  | int prom_remove_property(struct device_node *np, struct property *prop) | 
|  | { | 
|  | struct property **next; | 
|  | unsigned long flags; | 
|  | int found = 0; | 
|  |  | 
|  | write_lock_irqsave(&devtree_lock, flags); | 
|  | next = &np->properties; | 
|  | while (*next) { | 
|  | if (*next == prop) { | 
|  | /* found the node */ | 
|  | *next = prop->next; | 
|  | prop->next = np->deadprops; | 
|  | np->deadprops = prop; | 
|  | found = 1; | 
|  | break; | 
|  | } | 
|  | next = &(*next)->next; | 
|  | } | 
|  | write_unlock_irqrestore(&devtree_lock, flags); | 
|  |  | 
|  | if (!found) | 
|  | return -ENODEV; | 
|  |  | 
|  | #ifdef CONFIG_PROC_DEVICETREE | 
|  | /* try to remove the proc node as well */ | 
|  | if (np->pde) | 
|  | proc_device_tree_remove_prop(np->pde, prop); | 
|  | #endif /* CONFIG_PROC_DEVICETREE */ | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * prom_update_property - Update a property in a node. | 
|  | * | 
|  | * Note that we don't actually remove it, since we have given out | 
|  | * who-knows-how-many pointers to the data using get-property. | 
|  | * Instead we just move the property to the "dead properties" list, | 
|  | * and add the new property to the property list | 
|  | */ | 
|  | int prom_update_property(struct device_node *np, | 
|  | struct property *newprop, | 
|  | struct property *oldprop) | 
|  | { | 
|  | struct property **next; | 
|  | unsigned long flags; | 
|  | int found = 0; | 
|  |  | 
|  | write_lock_irqsave(&devtree_lock, flags); | 
|  | next = &np->properties; | 
|  | while (*next) { | 
|  | if (*next == oldprop) { | 
|  | /* found the node */ | 
|  | newprop->next = oldprop->next; | 
|  | *next = newprop; | 
|  | oldprop->next = np->deadprops; | 
|  | np->deadprops = oldprop; | 
|  | found = 1; | 
|  | break; | 
|  | } | 
|  | next = &(*next)->next; | 
|  | } | 
|  | write_unlock_irqrestore(&devtree_lock, flags); | 
|  |  | 
|  | if (!found) | 
|  | return -ENODEV; | 
|  |  | 
|  | #ifdef CONFIG_PROC_DEVICETREE | 
|  | /* try to add to proc as well if it was initialized */ | 
|  | if (np->pde) | 
|  | proc_device_tree_update_prop(np->pde, newprop, oldprop); | 
|  | #endif /* CONFIG_PROC_DEVICETREE */ | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_OF_DYNAMIC) | 
|  | /* | 
|  | * Support for dynamic device trees. | 
|  | * | 
|  | * On some platforms, the device tree can be manipulated at runtime. | 
|  | * The routines in this section support adding, removing and changing | 
|  | * device tree nodes. | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * of_attach_node - Plug a device node into the tree and global list. | 
|  | */ | 
|  | void of_attach_node(struct device_node *np) | 
|  | { | 
|  | unsigned long flags; | 
|  |  | 
|  | write_lock_irqsave(&devtree_lock, flags); | 
|  | np->sibling = np->parent->child; | 
|  | np->allnext = allnodes; | 
|  | np->parent->child = np; | 
|  | allnodes = np; | 
|  | write_unlock_irqrestore(&devtree_lock, flags); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * of_detach_node - "Unplug" a node from the device tree. | 
|  | * | 
|  | * The caller must hold a reference to the node.  The memory associated with | 
|  | * the node is not freed until its refcount goes to zero. | 
|  | */ | 
|  | void of_detach_node(struct device_node *np) | 
|  | { | 
|  | struct device_node *parent; | 
|  | unsigned long flags; | 
|  |  | 
|  | write_lock_irqsave(&devtree_lock, flags); | 
|  |  | 
|  | parent = np->parent; | 
|  | if (!parent) | 
|  | goto out_unlock; | 
|  |  | 
|  | if (allnodes == np) | 
|  | allnodes = np->allnext; | 
|  | else { | 
|  | struct device_node *prev; | 
|  | for (prev = allnodes; | 
|  | prev->allnext != np; | 
|  | prev = prev->allnext) | 
|  | ; | 
|  | prev->allnext = np->allnext; | 
|  | } | 
|  |  | 
|  | if (parent->child == np) | 
|  | parent->child = np->sibling; | 
|  | else { | 
|  | struct device_node *prevsib; | 
|  | for (prevsib = np->parent->child; | 
|  | prevsib->sibling != np; | 
|  | prevsib = prevsib->sibling) | 
|  | ; | 
|  | prevsib->sibling = np->sibling; | 
|  | } | 
|  |  | 
|  | of_node_set_flag(np, OF_DETACHED); | 
|  |  | 
|  | out_unlock: | 
|  | write_unlock_irqrestore(&devtree_lock, flags); | 
|  | } | 
|  | #endif /* defined(CONFIG_OF_DYNAMIC) */ | 
|  |  |