prom.c

来自「linux2.6.16版本」· C语言 代码 · 共 1,974 行 · 第 1/4 页

C
1,974
字号
	const char *type, const char *compatible){	struct device_node *np;	read_lock(&devtree_lock);	np = from ? from->allnext : allnodes;	for (; np != 0; np = np->allnext) {		if (type != NULL		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))			continue;		if (device_is_compatible(np, compatible) && of_node_get(np))			break;	}	if (from)		of_node_put(from);	read_unlock(&devtree_lock);	return np;}EXPORT_SYMBOL(of_find_compatible_node);/** *	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 != 0; np = np->allnext) {		if (np->full_name != 0 && strcasecmp(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_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 != 0; np = np->allnext)		if (np->linux_phandle == handle)			break;	if (np)		of_node_get(np);	read_unlock(&devtree_lock);	return np;}EXPORT_SYMBOL(of_find_node_by_phandle);/** *	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 != 0; np = np->allnext)		if (of_node_get(np))			break;	if (prev)		of_node_put(prev);	read_unlock(&devtree_lock);	return np;}EXPORT_SYMBOL(of_find_all_nodes);/** *	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_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 != 0; next = next->sibling)		if (of_node_get(next))			break;	if (prev)		of_node_put(prev);	read_unlock(&devtree_lock);	return next;}EXPORT_SYMBOL(of_get_next_child);/** *	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;	if (!OF_IS_DYNAMIC(node))		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->intrs);	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);/* * Plug a device node into the tree and global list. */void of_attach_node(struct device_node *np){	write_lock(&devtree_lock);	np->sibling = np->parent->child;	np->allnext = allnodes;	np->parent->child = np;	allnodes = np;	write_unlock(&devtree_lock);}/* * "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(const struct device_node *np){	struct device_node *parent;	write_lock(&devtree_lock);	parent = np->parent;	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;	}	write_unlock(&devtree_lock);}#ifdef CONFIG_PPC_PSERIES/* * Fix up the uninitialized fields in a new device node: * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields * * A lot of boot-time code is duplicated here, because functions such * as finish_node_interrupts, interpret_pci_props, etc. cannot use the * slab allocator. * * This should probably be split up into smaller chunks. */static int of_finish_dynamic_node(struct device_node *node){	struct device_node *parent = of_get_parent(node);	int err = 0;	phandle *ibm_phandle;	node->name = get_property(node, "name", NULL);	node->type = get_property(node, "device_type", NULL);	if (!parent) {		err = -ENODEV;		goto out;	}	/* We don't support that function on PowerMac, at least	 * not yet	 */	if (_machine == PLATFORM_POWERMAC)		return -ENODEV;	/* fix up new node's linux_phandle field */	if ((ibm_phandle = (unsigned int *)get_property(node,							"ibm,phandle", NULL)))		node->linux_phandle = *ibm_phandle;out:	of_node_put(parent);	return err;}static int prom_reconfig_notifier(struct notifier_block *nb,				  unsigned long action, void *node){	int err;	switch (action) {	case PSERIES_RECONFIG_ADD:		err = of_finish_dynamic_node(node);		if (!err)			finish_node(node, NULL, 0);		if (err < 0) {			printk(KERN_ERR "finish_node returned %d\n", err);			err = NOTIFY_BAD;		}		break;	default:		err = NOTIFY_DONE;		break;	}	return err;}static struct notifier_block prom_reconfig_nb = {	.notifier_call = prom_reconfig_notifier,	.priority = 10, /* This one needs to run first */};static int __init prom_reconfig_setup(void){	return pSeries_reconfig_notifier_register(&prom_reconfig_nb);}__initcall(prom_reconfig_setup);#endifstruct property *of_find_property(struct device_node *np, const char *name,				  int *lenp){	struct property *pp;	read_lock(&devtree_lock);	for (pp = np->properties; pp != 0; pp = pp->next)		if (strcmp(pp->name, name) == 0) {			if (lenp != 0)				*lenp = pp->length;			break;		}	read_unlock(&devtree_lock);	return pp;}/* * Find a property with a given name for a given node * and return the value. */unsigned char *get_property(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(get_property);/* * Add a property to a node */int prom_add_property(struct device_node* np, struct property* prop){	struct property **next;	prop->next = NULL;		write_lock(&devtree_lock);	next = &np->properties;	while (*next) {		if (strcmp(prop->name, (*next)->name) == 0) {			/* duplicate ! don't insert it */			write_unlock(&devtree_lock);			return -1;		}		next = &(*next)->next;	}	*next = prop;	write_unlock(&devtree_lock);#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;}/* * 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;	int found = 0;	write_lock(&devtree_lock);	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(&devtree_lock);	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;}/* * 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;	int found = 0;	write_lock(&devtree_lock);	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(&devtree_lock);	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;}#ifdef CONFIG_KEXEC/* We may have allocated the flat device tree inside the crash kernel region * in prom_init. If so we need to move it out into regular memory. */void kdump_move_device_tree(void){	unsigned long start, end;	struct boot_param_header *new;	start = __pa((unsigned long)initial_boot_params);	end = start + initial_boot_params->totalsize;	if (end < crashk_res.start || start > crashk_res.end)		return;	new = (struct boot_param_header*)		__va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE));	memcpy(new, initial_boot_params, initial_boot_params->totalsize);	initial_boot_params = new;	DBG("Flat device tree blob moved to %p\n", initial_boot_params);	/* XXX should we unreserve the old DT? */}#endif /* CONFIG_KEXEC */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?