轉(zhuǎn)自http://www.cnblogs.com/pengdonglin137/p/5252348.html
在設備樹中有一個叫做aliases的節(jié)點:
1: / { 2: ... ... 3: 4: chosen { 5: stdout-path = "/serial@13800000"; 6: bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 ethmac=1C:6F:65:34:51:7E init=/linuxrc"; 7: }; 8: 9: aliases { 10: spi0 = "/spi@13920000"; 11: spi1 = "/spi@13930000"; 12: spi2 = "/spi@13940000"; 13: i2c0 = "/i2c@13860000"; 14: i2c1 = "/i2c@13870000"; 15: i2c2 = "/i2c@13880000"; 16: i2c3 = "/i2c@13890000"; 17: ... ... 18: }; 19: ... ... 20: };在Linux內(nèi)核啟動的時候會解析這個節(jié)點:
start_kernel ---> setup_arch ---> unflatten_device_tree ---> of_alias_scan
在of_alias_scan中會掃描這個節(jié)點:
of_alias_scan:
1: void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) 2: { 3: struct PRoperty *pp; 4: 5: of_aliases = of_find_node_by_path("/aliases"); // 找到/aliases節(jié)點對應的device_node 6: of_chosen = of_find_node_by_path("/chosen"); // 找到/chosen節(jié)點對應的device_node 7: if (of_chosen == NULL) // 如果沒有/chosen的話,就找/chosen@0節(jié)點 8: of_chosen = of_find_node_by_path("/chosen@0"); 9: 10: if (of_chosen) { 11: /* linux,stdout-path and /aliases/stdout are for legacy compatibility */ 12: const char *name = of_get_property(of_chosen, "stdout-path", NULL); 13: if (!name) 14: name = of_get_property(of_chosen, "linux,stdout-path", NULL); 15: if (IS_ENABLED(CONFIG_PPC) && !name) 16: name = of_get_property(of_aliases, "stdout", NULL); 17: if (name) 18: of_stdout = of_find_node_opts_by_path(name, &of_stdout_options); 19: } 20: 21: if (!of_aliases) 22: return; 23: 24: for_each_property_of_node(of_aliases, pp) { // 遍歷/aliases節(jié)點的屬性,以屬性i2c2 = "/i2c@13880000";為例 25: const char *start = pp->name; // 屬性的名字,如"i2c2" 26: const char *end = start + strlen(start); // 名字的結(jié)尾,*end是'/0' 27: struct device_node *np; 28: struct alias_prop *ap; 29: int id, len; 30: 31: /* 不處理名字是name、phandle、linux,phandle的屬性 */ 32: if (!strcmp(pp->name, "name") || 33: !strcmp(pp->name, "phandle") || 34: !strcmp(pp->name, "linux,phandle")) 35: continue; 36: 37: np = of_find_node_by_path(pp->value); 38: /* 39: 根據(jù)屬性的值(如"/i2c@13880000")獲得這個值對應的節(jié)點 40: i2c@13880000 { 41: #address-cells = <0x1>; 42: #size-cells = <0x0>; 43: compatible = "samsung,s3c2440-i2c"; 44: reg = <0x13880000 0x100>; 45: interrupts = <0x0 0x3c 0x0>; 46: clocks = <0x7 0x13f>; 47: clock-names = "i2c"; 48: pinctrl-names = "default"; 49: pinctrl-0 = <0x22>; 50: status = "disabled"; 51: }; 52: */ 53: if (!np) 54: continue; 55: 56: /* walk the alias backwards to extract the id and work out 57: * the 'stem' string */ 58: while (isdigit(*(end-1)) && end > start) //對于"i2c2",end最終會指向字符'2'的地址 59: end--; 60: len = end - start; // 獲得"i2c"的長度(不包含結(jié)尾的數(shù)字2),就是3 61: 62: if (kstrtoint(end, 10, &id) < 0) // 將end指向的字符'2'轉(zhuǎn)化為數(shù)字2,賦值給id 63: continue; 64: 65: /* Allocate an alias_prop with enough space for the stem */ 66: ap = dt_alloc(sizeof(*ap) + len + 1, 4); // 分配內(nèi)存,多分配的"len+1"用于存放stem的名字 67: if (!ap) 68: continue; 69: memset(ap, 0, sizeof(*ap) + len + 1); 70: ap->alias = start; // ap->alias指向字符串"i2c2" 71: of_alias_add(ap, np, id, start, len); 72: } 73: }of_alias_add:
1: static void of_alias_add(struct alias_prop *ap, struct device_node *np, 2: int id, const char *stem, int stem_len) 3: { 4: ap->np = np; // np是"/i2c@13880000"對應的節(jié)點device_node 5: ap->id = id; // id的值是2 6: strncpy(ap->stem, stem, stem_len); // 由于stem_len是3,所以ap->stem被賦值為"i2c" 7: ap->stem[stem_len] = 0; 8: list_add_tail(&ap->link, &aliases_lookup); // 將這個ap加入到全局aliases_lookup鏈表中 9: pr_debug("adding DT alias:%s: stem=%s id=%i node=%s/n", 10: ap->alias, ap->stem, ap->id, of_node_full_name(np)); 11: }使用:
在drivers/i2c/i2c-core.c中:
1: int i2c_add_adapter(struct i2c_adapter *adapter) 2: { 3: struct device *dev = &adapter->dev; 4: int id; 5: 6: if (dev->of_node) { 7: id = of_alias_get_id(dev->of_node, "i2c"); 8: if (id >= 0) { 9: adapter->nr = id; 10: return __i2c_add_numbered_adapter(adapter); 11: } 12: } 13: ... ... 14: }第7行調(diào)用of_alias_get_id獲得與這個device_node(即/i2c@13880000節(jié)點)對應的alias_prop的id,如果以/i2c@13880000節(jié)點為例,這里得到的id就是2。
of_alias_get_id:
1: int of_alias_get_id(struct device_node *np, const char *stem) 2: { 3: struct alias_prop *app; 4: int id = -ENODEV; 5: 6: mutex_lock(&of_mutex); 7: list_for_each_entry(app, &aliases_lookup, link) { // 遍歷全局鏈表aliases_lookup 8: if (strcmp(app->stem, stem) != 0) // 找到 stem 是 "i2c" 的alias_prop 9: continue; 10: 11: if (np == app->np) { // 判斷這個alias_prop指向的device_node是不是跟傳入的匹配 12: id = app->id; // 獲得 id,2 13: break; 14: } 15: } 16: mutex_unlock(&of_mutex); 17: 18: return id; 19: }
從上面的分析就可以知道alias節(jié)點的作用了:
比如SoC上有如果多個i2c控制器,alias的相當於給每個i2c控制器分配一個唯一的編號,如上面的i2c@13880000對應的alias是i2c2,那麼這個編號就是2,將來就可以在/dev下看到名爲i2c-2的設備節(jié)點。
在內(nèi)核中可以看到很多地方都會調(diào)用of_alias_get_id,他的作用就是根據(jù)傳入的device node,在alias中找到對應的唯一編號,如:
of_alias_get_id(pdev->dev.of_node, "spi")
of_alias_get_id(node, "fimc")
of_alias_get_id(pdev->dev.of_node, "serial")
of_alias_get_id(pdev->dev.of_node, "uart")
of_alias_get_id(dev->of_node, "gpio")
... ...
完。
新聞熱點
疑難解答