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