1224 lines · 31.5 KB · C
RawDownload
/* * 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/ctype.h>#include <linux/module.h>#include <linux/of.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/proc_fs.h> /** * struct alias_prop - Alias property in 'aliases' node * @link:	List node to link the structure in aliases_lookup list * @alias:	Alias property name * @np:		Pointer to device_node that the alias stands for * @id:		Index value from end of alias name * @stem:	Alias string without the index * * The structure represents one alias property of 'aliases' node as * an entry in aliases_lookup list. */struct alias_prop {	struct list_head link;	const char *alias;	struct device_node *np;	int id;	char stem[0];}; static LIST_HEAD(aliases_lookup); struct device_node *allnodes;struct device_node *of_chosen;struct device_node *of_aliases; static DEFINE_MUTEX(of_aliases_mutex); /* 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) {

Lines 1–500 of 1224.