欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

prom.c

h内核
C
第 1 页 / 共 4 页
字号:
		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;	}	kfree(node->intrs);	kfree(node->addrs);	kfree(node->full_name);	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);/** *	derive_parent - basically like dirname(1) *	@path:  the full_name of a node to be added to the tree * *	Returns the node which should be the parent of the node *	described by path.  E.g., for path = "/foo/bar", returns *	the node with full_name = "/foo". */static struct device_node *derive_parent(const char *path){	struct device_node *parent = NULL;	char *parent_path = "/";	size_t parent_path_len = strrchr(path, '/') - path + 1;	/* reject if path is "/" */	if (!strcmp(path, "/"))		return NULL;	if (strrchr(path, '/') != path) {		parent_path = kmalloc(parent_path_len, GFP_KERNEL);		if (!parent_path)			return NULL;		strlcpy(parent_path, path, parent_path_len);	}	parent = of_find_node_by_path(parent_path);	if (strcmp(parent_path, "/"))		kfree(parent_path);	return parent;}/* * Routines for "runtime" addition and removal of device tree nodes. */#ifdef CONFIG_PROC_DEVICETREE/* * Add a node to /proc/device-tree. */static void add_node_proc_entries(struct device_node *np){	struct proc_dir_entry *ent;	ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde);	if (ent)		proc_device_tree_add_node(np, ent);}static void remove_node_proc_entries(struct device_node *np){	struct property *pp = np->properties;	struct device_node *parent = np->parent;	while (pp) {		remove_proc_entry(pp->name, np->pde);		pp = pp->next;	}	/* Assuming that symlinks have the same parent directory as	 * np->pde.	 */	if (np->name_link)		remove_proc_entry(np->name_link->name, parent->pde);	if (np->addr_link)		remove_proc_entry(np->addr_link->name, parent->pde);	if (np->pde)		remove_proc_entry(np->pde->name, parent->pde);}#else /* !CONFIG_PROC_DEVICETREE */static void add_node_proc_entries(struct device_node *np){	return;}static void remove_node_proc_entries(struct device_node *np){	return;}#endif /* CONFIG_PROC_DEVICETREE *//* * Fix up n_intrs and intrs fields in a new device node * */static int of_finish_dynamic_node_interrupts(struct device_node *node){	int intrcells, intlen, i;	unsigned *irq, *ints, virq;	struct device_node *ic;	ints = (unsigned int *)get_property(node, "interrupts", &intlen);	intrcells = prom_n_intr_cells(node);	intlen /= intrcells * sizeof(unsigned int);	node->n_intrs = intlen;	node->intrs = kmalloc(sizeof(struct interrupt_info) * intlen,			      GFP_KERNEL);	if (!node->intrs)		return -ENOMEM;	for (i = 0; i < intlen; ++i) {		int n, j;		node->intrs[i].line = 0;		node->intrs[i].sense = 1;		n = map_interrupt(&irq, &ic, node, ints, intrcells);		if (n <= 0)			continue;		virq = virt_irq_create_mapping(irq[0]);		if (virq == NO_IRQ) {			printk(KERN_CRIT "Could not allocate interrupt "			       "number for %s\n", node->full_name);			return -ENOMEM;		}		node->intrs[i].line = irq_offset_up(virq);		if (n > 1)			node->intrs[i].sense = irq[1];		if (n > 2) {			printk(KERN_DEBUG "hmmm, got %d intr cells for %s:", n,			       node->full_name);			for (j = 0; j < n; ++j)				printk(" %d", irq[j]);			printk("\n");		}		ints += intrcells;	}	return 0;}/* * 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);	u32 *regs;	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 (systemcfg->platform == 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;	/* do the work of interpret_pci_props */	if (parent->type && !strcmp(parent->type, "pci")) {		struct address_range *adr;		struct pci_reg_property *pci_addrs;		int i, l;		pci_addrs = (struct pci_reg_property *)			get_property(node, "assigned-addresses", &l);		if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {			i = 0;			adr = kmalloc(sizeof(struct address_range) * 				      (l / sizeof(struct pci_reg_property)),				      GFP_KERNEL);			if (!adr) {				err = -ENOMEM;				goto out;			}			while ((l -= sizeof(struct pci_reg_property)) >= 0) {				adr[i].space = pci_addrs[i].addr.a_hi;				adr[i].address = pci_addrs[i].addr.a_lo;				adr[i].size = pci_addrs[i].size_lo;				++i;			}			node->addrs = adr;			node->n_addrs = i;		}	}	/* now do the work of finish_node_interrupts */	if (get_property(node, "interrupts", NULL)) {		err = of_finish_dynamic_node_interrupts(node);		if (err) goto out;	}	/* now do the rough equivalent of update_dn_pci_info, this	 * probably is not correct for phb's, but should work for	 * IOAs and slots.	 */	node->phb = parent->phb;	regs = (u32 *)get_property(node, "reg", NULL);	if (regs) {		node->busno = (regs[0] >> 16) & 0xff;		node->devfn = (regs[0] >> 8) & 0xff;	}out:	of_node_put(parent);	return err;}/* * Given a path and a property list, construct an OF device node, add * it to the device tree and global list, and place it in * /proc/device-tree.  This function may sleep. */int of_add_node(const char *path, struct property *proplist){	struct device_node *np;	int err = 0;	np = kmalloc(sizeof(struct device_node), GFP_KERNEL);	if (!np)		return -ENOMEM;	memset(np, 0, sizeof(*np));	np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);	if (!np->full_name) {		kfree(np);		return -ENOMEM;	}	strcpy(np->full_name, path);	np->properties = proplist;	OF_MARK_DYNAMIC(np);	kref_init(&np->kref);	of_node_get(np);	np->parent = derive_parent(path);	if (!np->parent) {		kfree(np);		return -EINVAL; /* could also be ENOMEM, though */	}	if (0 != (err = of_finish_dynamic_node(np))) {		kfree(np);		return err;	}	write_lock(&devtree_lock);	np->sibling = np->parent->child;	np->allnext = allnodes;	np->parent->child = np;	allnodes = np;	write_unlock(&devtree_lock);	add_node_proc_entries(np);	of_node_put(np->parent);	of_node_put(np);	return 0;}/* * Prepare an OF node for removal from system */static void of_cleanup_node(struct device_node *np){	if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))		iommu_free_table(np);}/* * "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. */int of_remove_node(struct device_node *np){	struct device_node *parent, *child;	parent = of_get_parent(np);	if (!parent)		return -EINVAL;	if ((child = of_get_next_child(np, NULL))) {		of_node_put(child);		return -EBUSY;	}	of_cleanup_node(np);	write_lock(&devtree_lock);	remove_node_proc_entries(np);	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);	of_node_put(parent);	of_node_put(np); /* Must decrement the refcount */	return 0;}/* * 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;	for (pp = np->properties; pp != 0; pp = pp->next)		if (strcmp(pp->name, name) == 0) {			if (lenp != 0)				*lenp = pp->length;			return pp->value;		}	return NULL;}/* * Add a property to a node */voidprom_add_property(struct device_node* np, struct property* prop){	struct property **next = &np->properties;	prop->next = NULL;		while (*next)		next = &(*next)->next;	*next = prop;}#if 0voidprint_properties(struct device_node *np){	struct property *pp;	char *cp;	int i, n;	for (pp = np->properties; pp != 0; pp = pp->next) {		printk(KERN_INFO "%s", pp->name);		for (i = strlen(pp->name); i < 16; ++i)			printk(" ");		cp = (char *) pp->value;		for (i = pp->length; i > 0; --i, ++cp)			if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))			    || (i == 1 && *cp != 0))				break;		if (i == 0 && pp->length > 1) {			/* looks like a string */			printk(" %s\n", (char *) pp->value);		} else {			/* dump it in hex */			n = pp->length;			if (n > 64)				n = 64;			if (pp->length % 4 == 0) {				unsigned int *p = (unsigned int *) pp->value;				n /= 4;				for (i = 0; i < n; ++i) {					if (i != 0 && (i % 4) == 0)						printk("\n                ");					printk(" %08x", *p++);				}			} else {				unsigned char *bp = pp->value;				for (i = 0; i < n; ++i) {					if (i != 0 && (i % 16) == 0)						printk("\n                ");					printk(" %02x", *bp++);				}			}			printk("\n");			if (pp->length > 64)				printk("                 ... (length = %d)\n",				       pp->length);		}	}}#endif

⌨️ 快捷键说明

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