unflatten_dt_node ( dtb解析主要函数,解析完构成了 device node 树,会调用of_platform_populate函数创建platform device )

转载于 :http://www.voidcn.com/blog/bin_linux96/article/p-1210202.html  

/*
* * 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 unsigned long unflatten_dt_node(struct boot_param_header *blob, 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 = be32_to_cpup((__be32 *)(*p)); //每个有孩子的设备节点,其tag一定是OF_DT_BEGIN_NODE if (tag != OF_DT_BEGIN_NODE) { pr_err("Weird tag at start of node: %x\n", tag); return mem; } *p += 4; //地址+4,这样指向节点的名称 pathp = (char *)*p; l = allocl = strlen(pathp) + 1; //该节点名称的长度 *p = ALIGN(*p + l, 4); ///*p 指向带分析的属性 /* 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 '/'. */ /*计算fullpath的长度 */ 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; } } /* 分配一个设备节点 */ //mem = 0 , np就是分配的 struct device node 大小的内存的指针 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); //下面是判断,填充np,构造出device node /* allnextpp指向前一个设备链表的指针 */ if (allnextpp) { //第二次扫描 nextpp 存在要进入 if 内执行 memset(np, 0, sizeof(*np)); np->full_name = ((char *)np) + sizeof(struct device_node); if (new_format) { char *fn = np->full_name; /* rebuild full path for new format */ if (dad && dad->parent) { strcpy(fn, dad->full_name); //把父亲节点绝对路径先拷贝 #ifdef DEBUG if ((strlen(fn) + l + 1) != allocl) { pr_debug("%s: p: %d, l: %d, a: %d\n", pathp, (int)strlen(fn), l, allocl); } #endif fn += strlen(fn); } *(fn++) = '/'; memcpy(fn, pathp, l); //拷贝本节点的名称 } else memcpy(np->full_name, pathp, l); prev_pp = &np->properties; //prev_pp指向节点的属性 **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; //child指向第一个孩子 else dad->next->sibling = np; //把np插入next,这样孩子节点形成链表 dad->next = np; //指向最新挂接的child node } kref_init(&np->kref); } /* process properties */ /*分析设备的属性*/ while (1) { u32 sz, noff; char *pname; tag = be32_to_cpup((__be32 *)(*p)); if (tag == OF_DT_NOP) { //空属性,则跳过 *p += 4; continue; } /* tag不是属性则退出,对于有孩子节点退出时为OF_DT_BEGIN_NODE; * 对于叶子节点退出时为OF_DT_END_NODE. */ if (tag != OF_DT_PROP) break; *p += 4; //地址加4 sz = be32_to_cpup((__be32 *)(*p)); //属性的大小,是以为占多少整形指针计算的。例如网卡interrupts = <35 2 36 2 40 2>;,其值为24 noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; //指向value if (be32_to_cpu(blob->version) < 0x10) *p = ALIGN(*p, sz >= 8 ? 8 : 4); pname = of_fdt_get_string(blob, noff); //属性名称 if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; } if (strcmp(pname, "name") == 0) //如果有名称为name的属性 has_name = 1; l = strlen(pname) + 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); //分配属性结构 if (allnextpp) { /* 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((__be32*)*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((__be32 *)*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) { //如果没有name,就创建一个 char *p1 = pathp, *ps = pathp, *pa = NULL; int sz; 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) { pp->name = "name"; pp->length = sz; pp->value = pp + 1; *prev_pp = pp; prev_pp = &pp->next; memcpy(pp->value, ps, sz - 1); //名字的值只去其中的@钱的字符,例如pcie@ffe0a000-> pcie ((char *)pp->value)[sz - 1] = 0; pr_debug("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);//设置设备类型 if (!np->name) np->name = "<NULL>"; if (!np->type) np->type = "<NULL>"; } while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {//对于tag为这2个取值 if (tag == OF_DT_NOP) //空属性则指向下个属性 *p += 4; else mem = unflatten_dt_node(blob, mem, p, np, allnextpp, fpsize); //OF_DT_BEGIN_NODE则表明其还有子节点,所以递归分析其子节点 tag = be32_to_cpup((__be32 *)(*p)); } if (tag != OF_DT_END_NODE) { //对于叶子节点或者分析完成 pr_err("Weird tag at end of node: %x\n", tag); return mem; } *p += 4; return mem; }

 

posted on 2017-02-23 12:37  Red_Point  阅读(2184)  评论(0编辑  收藏  举报

导航