⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prom.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
				adr[i].space = rp[i].space;				adr[i].address = rp[i].address;				adr[i].size = rp[i].size;			}			++i;		}		np->addrs = adr;		np->n_addrs = i;		(*mem_start) += i * sizeof(struct address_range);	}	return 0;}static int __init interpret_root_props(struct device_node *np,				       unsigned long *mem_start,				       int naddrc, int nsizec,				       int measure_only){	struct address_range *adr;	int i, l;	unsigned int *rp;	int rpsize = (naddrc + nsizec) * sizeof(unsigned int);	rp = (unsigned int *) get_property(np, "reg", &l);	if (rp != 0 && l >= rpsize) {		i = 0;		adr = (struct address_range *) (*mem_start);		while ((l -= rpsize) >= 0) {			if (!measure_only) {				adr[i].space = 0;				adr[i].address = rp[naddrc - 1];				adr[i].size = rp[naddrc + nsizec - 1];			}			++i;			rp += naddrc + nsizec;		}		np->addrs = adr;		np->n_addrs = i;		(*mem_start) += i * sizeof(struct address_range);	}	return 0;}static int __devinit finish_node(struct device_node *np,				 unsigned long *mem_start,				 interpret_func *ifunc,				 int naddrc, int nsizec,				 int measure_only){	struct device_node *child;	int *ip, rc = 0;	/* get the device addresses and interrupts */	if (ifunc != NULL)		rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);	if (rc)		goto out;	rc = finish_node_interrupts(np, mem_start, measure_only);	if (rc)		goto out;	/* Look for #address-cells and #size-cells properties. */	ip = (int *) get_property(np, "#address-cells", NULL);	if (ip != NULL)		naddrc = *ip;	ip = (int *) get_property(np, "#size-cells", NULL);	if (ip != NULL)		nsizec = *ip;	if (!strcmp(np->name, "device-tree") || np->parent == NULL)		ifunc = interpret_root_props;	else if (np->type == 0)		ifunc = NULL;	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))		ifunc = interpret_pci_props;	else if (!strcmp(np->type, "dbdma"))		ifunc = interpret_dbdma_props;	else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)		ifunc = interpret_macio_props;	else if (!strcmp(np->type, "isa"))		ifunc = interpret_isa_props;	else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))		ifunc = interpret_root_props;	else if (!((ifunc == interpret_dbdma_props		    || ifunc == interpret_macio_props)		   && (!strcmp(np->type, "escc")		       || !strcmp(np->type, "media-bay"))))		ifunc = NULL;	for (child = np->child; child != NULL; child = child->sibling) {		rc = finish_node(child, mem_start, ifunc,				 naddrc, nsizec, measure_only);		if (rc)			goto out;	}out:	return rc;}static void __init scan_interrupt_controllers(void){	struct device_node *np;	int n = 0;	char *name, *ic;	int iclen;	for (np = allnodes; np != NULL; np = np->allnext) {		ic = get_property(np, "interrupt-controller", &iclen);		name = get_property(np, "name", NULL);		/* checking iclen makes sure we don't get a false		   match on /chosen.interrupt_controller */		if ((name != NULL		     && strcmp(name, "interrupt-controller") == 0)		    || (ic != NULL && iclen == 0			&& strcmp(name, "AppleKiwi"))) {			if (n == 0)				dflt_interrupt_controller = np;			++n;		}	}	num_interrupt_controllers = n;}/** * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). * It traverses the device tree and fills in some of the additional, * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt * mapping is also initialized at this point. */void __init finish_device_tree(void){	unsigned long start, end, size = 0;	DBG(" -> finish_device_tree\n");#ifdef CONFIG_PPC64	/* Initialize virtual IRQ map */	virt_irq_init();#endif	scan_interrupt_controllers();	/*	 * Finish device-tree (pre-parsing some properties etc...)	 * We do this in 2 passes. One with "measure_only" set, which	 * will only measure the amount of memory needed, then we can	 * allocate that memory, and call finish_node again. However,	 * we must be careful as most routines will fail nowadays when	 * prom_alloc() returns 0, so we must make sure our first pass	 * doesn't start at 0. We pre-initialize size to 16 for that	 * reason and then remove those additional 16 bytes	 */	size = 16;	finish_node(allnodes, &size, NULL, 0, 0, 1);	size -= 16;	end = start = (unsigned long) __va(lmb_alloc(size, 128));	finish_node(allnodes, &end, NULL, 0, 0, 0);	BUG_ON(end != start + size);	DBG(" <- finish_device_tree\n");}static inline char *find_flat_dt_string(u32 offset){	return ((char *)initial_boot_params) +		initial_boot_params->off_dt_strings + offset;}/** * This function is used to scan the flattened device-tree, it is * used to extract the memory informations at boot before we can * unflatten the tree */int __init of_scan_flat_dt(int (*it)(unsigned long node,				     const char *uname, int depth,				     void *data),			   void *data){	unsigned long p = ((unsigned long)initial_boot_params) +		initial_boot_params->off_dt_struct;	int rc = 0;	int depth = -1;	do {		u32 tag = *((u32 *)p);		char *pathp;				p += 4;		if (tag == OF_DT_END_NODE) {			depth --;			continue;		}		if (tag == OF_DT_NOP)			continue;		if (tag == OF_DT_END)			break;		if (tag == OF_DT_PROP) {			u32 sz = *((u32 *)p);			p += 8;			if (initial_boot_params->version < 0x10)				p = _ALIGN(p, sz >= 8 ? 8 : 4);			p += sz;			p = _ALIGN(p, 4);			continue;		}		if (tag != OF_DT_BEGIN_NODE) {			printk(KERN_WARNING "Invalid tag %x scanning flattened"			       " device tree !\n", tag);			return -EINVAL;		}		depth++;		pathp = (char *)p;		p = _ALIGN(p + strlen(pathp) + 1, 4);		if ((*pathp) == '/') {			char *lp, *np;			for (lp = NULL, np = pathp; *np; np++)				if ((*np) == '/')					lp = np+1;			if (lp != NULL)				pathp = lp;		}		rc = it(p, pathp, depth, data);		if (rc != 0)			break;			} while(1);	return rc;}/** * This  function can be used within scan_flattened_dt callback to get * access to properties */void* __init of_get_flat_dt_prop(unsigned long node, const char *name,				 unsigned long *size){	unsigned long p = node;	do {		u32 tag = *((u32 *)p);		u32 sz, noff;		const char *nstr;		p += 4;		if (tag == OF_DT_NOP)			continue;		if (tag != OF_DT_PROP)			return NULL;		sz = *((u32 *)p);		noff = *((u32 *)(p + 4));		p += 8;		if (initial_boot_params->version < 0x10)			p = _ALIGN(p, sz >= 8 ? 8 : 4);		nstr = find_flat_dt_string(noff);		if (nstr == NULL) {			printk(KERN_WARNING "Can't find property index"			       " name !\n");			return NULL;		}		if (strcmp(name, nstr) == 0) {			if (size)				*size = sz;			return (void *)p;		}		p += sz;		p = _ALIGN(p, 4);	} while(1);}static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,				       unsigned long align){	void *res;	*mem = _ALIGN(*mem, align);	res = (void *)*mem;	*mem += size;	return res;}static unsigned long __init unflatten_dt_node(unsigned long mem,					      unsigned long *p,					      struct device_node *dad,					      struct device_node ***allnextpp,					      unsigned long fpsize){	struct device_node *np;	struct property *pp, **prev_pp = NULL;	char *pathp;	u32 tag;	unsigned int l, allocl;	int has_name = 0;	int new_format = 0;	tag = *((u32 *)(*p));	if (tag != OF_DT_BEGIN_NODE) {		printk("Weird tag at start of node: %x\n", tag);		return mem;	}	*p += 4;	pathp = (char *)*p;	l = allocl = strlen(pathp) + 1;	*p = _ALIGN(*p + l, 4);	/* version 0x10 has a more compact unit name here instead of the full	 * path. we accumulate the full path size using "fpsize", we'll rebuild	 * it later. We detect this because the first character of the name is	 * not '/'.	 */	if ((*pathp) != '/') {		new_format = 1;		if (fpsize == 0) {			/* root node: special case. fpsize accounts for path			 * plus terminating zero. root node only has '/', so			 * fpsize should be 2, but we want to avoid the first			 * level nodes to have two '/' so we use fpsize 1 here			 */			fpsize = 1;			allocl = 2;		} else {			/* account for '/' and path size minus terminal 0			 * already in 'l'			 */			fpsize += l;			allocl = fpsize;		}	}	np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,				__alignof__(struct device_node));	if (allnextpp) {		memset(np, 0, sizeof(*np));		np->full_name = ((char*)np) + sizeof(struct device_node);		if (new_format) {			char *p = np->full_name;			/* rebuild full path for new format */			if (dad && dad->parent) {				strcpy(p, dad->full_name);#ifdef DEBUG				if ((strlen(p) + l + 1) != allocl) {					DBG("%s: p: %d, l: %d, a: %d\n",					    pathp, strlen(p), l, allocl);				}#endif				p += strlen(p);			}			*(p++) = '/';			memcpy(p, pathp, l);		} else			memcpy(np->full_name, pathp, l);		prev_pp = &np->properties;		**allnextpp = np;		*allnextpp = &np->allnext;		if (dad != NULL) {			np->parent = dad;			/* we temporarily use the next field as `last_child'*/			if (dad->next == 0)				dad->child = np;			else				dad->next->sibling = np;			dad->next = np;		}		kref_init(&np->kref);	}	while(1) {		u32 sz, noff;		char *pname;		tag = *((u32 *)(*p));		if (tag == OF_DT_NOP) {			*p += 4;			continue;		}		if (tag != OF_DT_PROP)			break;		*p += 4;		sz = *((u32 *)(*p));		noff = *((u32 *)((*p) + 4));		*p += 8;		if (initial_boot_params->version < 0x10)			*p = _ALIGN(*p, sz >= 8 ? 8 : 4);		pname = find_flat_dt_string(noff);		if (pname == NULL) {			printk("Can't find property name in list !\n");			break;		}		if (strcmp(pname, "name") == 0)			has_name = 1;		l = strlen(pname) + 1;		pp = unflatten_dt_alloc(&mem, sizeof(struct property),					__alignof__(struct property));		if (allnextpp) {			if (strcmp(pname, "linux,phandle") == 0) {				np->node = *((u32 *)*p);				if (np->linux_phandle == 0)					np->linux_phandle = np->node;			}			if (strcmp(pname, "ibm,phandle") == 0)				np->linux_phandle = *((u32 *)*p);			pp->name = pname;			pp->length = sz;			pp->value = (void *)*p;			*prev_pp = pp;			prev_pp = &pp->next;		}		*p = _ALIGN((*p) + sz, 4);	}	/* with version 0x10 we may not have the name property, recreate	 * it here from the unit name if absent	 */	if (!has_name) {		char *p = pathp, *ps = pathp, *pa = NULL;		int sz;		while (*p) {			if ((*p) == '@')				pa = p;			if ((*p) == '/')				ps = p + 1;			p++;		}		if (pa < ps)			pa = p;		sz = (pa - ps) + 1;		pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,					__alignof__(struct property));		if (allnextpp) {			pp->name = "name";			pp->length = sz;			pp->value = (unsigned char *)(pp + 1);			*prev_pp = pp;			prev_pp = &pp->next;			memcpy(pp->value, ps, sz - 1);			((char *)pp->value)[sz - 1] = 0;			DBG("fixed up name for %s -> %s\n", pathp, pp->value);		}	}	if (allnextpp) {		*prev_pp = NULL;		np->name = get_property(np, "name", NULL);		np->type = get_property(np, "device_type", NULL);		if (!np->name)			np->name = "<NULL>";		if (!np->type)			np->type = "<NULL>";	}	while (tag == OF_DT_BEGIN_NODE) {		mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);		tag = *((u32 *)(*p));	}	if (tag != OF_DT_END_NODE) {		printk("Weird tag at end of node: %x\n", tag);		return mem;	}	*p += 4;	return mem;}/** * unflattens the device-tree passed by the firmware, creating the * tree of struct device_node. It also fills the "name" and "type" * pointers of the nodes so the normal device-tree walking functions * can be used (this used to be done by finish_device_tree) */void __init unflatten_device_tree(void){	unsigned long start, mem, size;	struct device_node **allnextp = &allnodes;	char *p = NULL;	int l = 0;	DBG(" -> unflatten_device_tree()\n");	/* First pass, scan for size */	start = ((unsigned long)initial_boot_params) +		initial_boot_params->off_dt_struct;	size = unflatten_dt_node(0, &start, NULL, NULL, 0);	size = (size | 3) + 1;	DBG("  size is %lx, allocating...\n", size);	/* Allocate memory for the expanded device tree */	mem = lmb_alloc(size + 4, __alignof__(struct device_node));	if (!mem) {		DBG("Couldn't allocate memory with lmb_alloc()!\n");		panic("Couldn't allocate memory with lmb_alloc()!\n");	}	mem = (unsigned long) __va(mem);	((u32 *)mem)[size / 4] = 0xdeadbeef;	DBG("  unflattening %lx...\n", mem);	/* Second pass, do actual unflattening */	start = ((unsigned long)initial_boot_params) +		initial_boot_params->off_dt_struct;	unflatten_dt_node(mem, &start, NULL, &allnextp, 0);	if (*((u32 *)start) != OF_DT_END)		printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));	if (((u32 *)mem)[size / 4] != 0xdeadbeef)		printk(KERN_WARNING "End of tree marker overwritten: %08x\n",		       ((u32 *)mem)[size / 4] );	*allnextp = NULL;	/* Get pointer to OF "/chosen" node for use everywhere */	of_chosen = of_find_node_by_path("/chosen");	if (of_chosen == NULL)		of_chosen = of_find_node_by_path("/chosen@0");	/* Retreive command line */	if (of_chosen != NULL) {		p = (char *)get_property(of_chosen, "bootargs", &l);		if (p != NULL && l > 0)			strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE));	}#ifdef CONFIG_CMDLINE	if (l == 0 || (l == 1 && (*p) == 0))		strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);#endif /* CONFIG_CMDLINE */	DBG("Command line is: %s\n", cmd_line);	DBG(" <- unflatten_device_tree()\n");}static int __init early_init_dt_scan_cpus(unsigned long node,					  const char *uname, int depth, void *data){	u32 *prop;	unsigned long size;	char *type = of_get_flat_dt_prop(node, "device_type", &size);

⌨️ 快捷键说明

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