kernel解析设备树生成设备节点过程

来源:互联网 发布:童声配音软件 编辑:程序博客网 时间:2024/03/29 17:32
/** * unflatten_device_tree - create tree of device_nodes from flat blob * * 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. */void __init unflatten_device_tree(void){__unflatten_device_tree(initial_boot_params, &of_allnodes,early_init_dt_alloc_memory_arch);/* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */of_alias_scan(early_init_dt_alloc_memory_arch);}/** * __unflatten_device_tree - create tree of device_nodes from flat blob * * unflattens a device-tree, 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. * @blob: The blob to expand * @mynodes: The device_node tree created by the call * @dt_alloc: An allocator that provides a virtual address to memory * for the resulting tree */static void __unflatten_device_tree(void *blob,     struct device_node **mynodes,     void * (*dt_alloc)(u64 size, u64 align)){unsigned long size;int start;void *mem;struct device_node **allnextp = mynodes;pr_debug(" -> unflatten_device_tree()\n");if (!blob) {pr_debug("No device tree pointer\n");return;}pr_debug("Unflattening device tree:\n");pr_debug("magic: %08x\n", fdt_magic(blob));pr_debug("size: %08x\n", fdt_totalsize(blob));pr_debug("version: %08x\n", fdt_version(blob));if (fdt_check_header(blob)) {pr_err("Invalid device tree blob header\n");return;}/* First pass, scan for size */start = 0;size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);size = ALIGN(size, 4);pr_debug("  size is %lx, allocating...\n", size);/* Allocate memory for the expanded device tree *///计算设备节点和属性需要用到的字节数mem = dt_alloc(size + 4, __alignof__(struct device_node));memset(mem, 0, size);*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);pr_debug("  unflattening %p...\n", mem);/* Second pass, do actual unflattening *///解析设备树,生成设备节点及其属性start = 0;unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);if (be32_to_cpup(mem + size) != 0xdeadbeef)pr_warning("End of tree marker overwritten: %08x\n",   be32_to_cpup(mem + size));*allnextp = NULL;pr_debug(" <- unflatten_device_tree()\n");} unflatten_dt_node - Alloc and populate a device_node from the flat tree /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @blob: The parent device tree blob * @mem: Memory chunk to use for allocating device nodes and properties * @p: pointer to node in flat tree * @dad: Parent struct device_node * @allnextpp: pointer to ->allnext from last allocated device_node * @fpsize: Size of the node path up at the current depth. */static void * unflatten_dt_node(void *blob,void *mem,int *poffset,struct device_node *dad,struct device_node ***allnextpp,unsigned long fpsize){const __be32 *p;struct device_node *np;struct property *pp, **prev_pp = NULL;const char *pathp;unsigned int l, allocl;static int depth = 0;int old_depth;int offset;int has_name = 0;int new_format = 0;printk("kevin,%s\n",__func__);//获得根设备节点的名字,为“”pathp = fdt_get_name(blob, *poffset, &l);if (!pathp)return mem;allocl = l++;/* 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 '/'. */printk("kevin,pathp=%s\n",pathp);if ((*pathp) != '/') {new_format = 1;if (fpsize == 0) {printk("kevin,fpsize==0\n");/* 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;l = 1;pathp = "";} else {/* account for '/' and path size minus terminal 0 * already in 'l' */printk("kevin,fpsize!=0\n");fpsize += l;allocl = fpsize;}} printk("kevin,fpsize=%lu,allocl=%u\n",fpsize,allocl);np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,__alignof__(struct device_node));if (allnextpp) {char *fn;printk("kevin,allnextpp is not  null\n");memset(np, 0, sizeof(*np));np->full_name = fn = ((char *)np) + sizeof(*np);if (new_format) {/* rebuild full path for new format */if (dad && dad->parent) {strcpy(fn, dad->full_name);printk("kevin,dad->full_name=%s\n",dad->full_name);#ifdef DEBUGif ((strlen(fn) + l + 1) != allocl) {pr_debug("%s: p: %d, l: %d, a: %d\n",pathp, (int)strlen(fn),l, allocl);}#endiffn += strlen(fn);}*(fn++) = '/';}memcpy(fn, pathp, l);printk("kevin,np->full_name=%s\n",fn);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 == NULL)dad->child = np;elsedad->next->sibling = np;dad->next = np;}kref_init(&np->kref);}else{printk("kevin,allnextpp is null\n");}/* process properties */for (offset = fdt_first_property_offset(blob, *poffset);     (offset >= 0);     (offset = fdt_next_property_offset(blob, offset))) {const char *pname;u32 sz;if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) {offset = -FDT_ERR_INTERNAL;break;}if (pname == NULL) {pr_info("Can't find property name in list !\n");break;}printk("kevin,pname=%s\n",pname);if (strcmp(pname, "name") == 0)has_name = 1;pp = unflatten_dt_alloc(&mem, sizeof(struct property),__alignof__(struct property));if (allnextpp) {printk("kevin,allnextpp exist 1\n");/* We accept flattened tree phandles either in * ePAPR-style "phandle" properties, or the * legacy "linux,phandle" properties.  If both * appear and have different values, things * will get weird.  Don't do that. */if ((strcmp(pname, "phandle") == 0) ||    (strcmp(pname, "linux,phandle") == 0)) {if (np->phandle == 0)np->phandle = be32_to_cpup(p);}/* And we process the "ibm,phandle" property * used in pSeries dynamic device tree * stuff */if (strcmp(pname, "ibm,phandle") == 0)np->phandle = be32_to_cpup(p);pp->name = (char *)pname;pp->length = sz;pp->value = (__be32 *)p;*prev_pp = pp;prev_pp = &pp->next;}}/* with version 0x10 we may not have the name property, recreate * it here from the unit name if absent */if (!has_name) {const char *p1 = pathp, *ps = pathp, *pa = NULL;int sz;printk("kevin,allnextpp has no name p1=%s\n",p1);while (*p1) {if ((*p1) == '@')pa = p1;if ((*p1) == '/')ps = p1 + 1;p1++;}if (pa < ps)pa = p1;sz = (pa - ps) + 1;pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,__alignof__(struct property));if (allnextpp) {printk("kevin,allnextpp exist 2\n");pp->name = "name";pp->length = sz;pp->value = pp + 1;*prev_pp = pp;prev_pp = &pp->next;memcpy(pp->value, ps, sz - 1);((char *)pp->value)[sz - 1] = 0;printk("kevin,fixed up name for %s -> %s\n", pathp,(char *)pp->value);}}if (allnextpp) {*prev_pp = NULL;np->name = of_get_property(np, "name", NULL);np->type = of_get_property(np, "device_type", NULL);printk("kevin,allnextpp exist 3\n");if (!np->name)np->name = "<NULL>";if (!np->type)np->type = "<NULL>";}old_depth = depth;*poffset = fdt_next_node(blob, *poffset, &depth);printk("kevin,*poffset=%d,depth=%d,mem=%lu\n",*poffset,depth,(unsigned long)mem);if (depth < 0)depth = 0;while (*poffset > 0 && depth > old_depth)mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,fpsize);if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)pr_err("unflatten: error %d processing FDT\n", *poffset);return mem;}

原创粉丝点击