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; }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM