基於tiny4412的Linux內核移植 --- aliases節點解析

做者信息

做者: 彭東林node

郵箱:pengdonglin137@163.comlinux

QQ:405728433git

平臺簡介

開發板:tiny4412ADK + S700 + 4GB Flashapp

要移植的內核版本:Linux-4.4.0 (支持device tree)工具

u-boot版本:友善之臂自帶的 U-Boot 2010.12 (爲支持uImage啓動,作了少量改動)spa

busybox版本:busybox 1.25debug

交叉編譯工具鏈: arm-none-linux-gnueabi-gcc code

      (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29))ip

正文

    在設備樹中有一個叫作aliases的節點:內存

 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內核啓動的時候會解析這個節點:

start_kernel
    ---> setup_arch
            ---> unflatten_device_tree
                    ---> of_alias_scan

在of_alias_scan中會掃描這個節點:

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節點對應的device_node
 6:     of_chosen = of_find_node_by_path("/chosen"); // 找到/chosen節點對應的device_node
 7:     if (of_chosen == NULL) // 若是沒有/chosen的話,就找/chosen@0節點
 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節點的屬性,以屬性i2c2 = "/i2c@13880000";爲例
 25:         const char *start = pp->name; // 屬性的名字,如"i2c2"
 26:         const char *end = start + strlen(start); // 名字的結尾,*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:  根據屬性的值(如"/i2c@13880000")得到這個值對應的節點
 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"的長度(不包含結尾的數字2),就是3
 61:  
 62:         if (kstrtoint(end, 10, &id) < 0) // 將end指向的字符'2'轉化爲數字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); // 分配內存,多分配的"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"對應的節點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行調用of_alias_get_id得到與這個device_node(即/i2c@13880000節點)對應的alias_prop的id,若是以/i2c@13880000節點爲例,這裏獲得的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節點的做用了:

好比SoC上有若是多個i2c控制器,alias的相當於給每個i2c控制器分配一個惟一的編號,如上面的i2c@13880000對應的alias是i2c2,那麼這個編號就是2,將來就能夠在/dev下看到名爲i2c-2的設備節點。

在內核中能夠看到不少地方都會調用of_alias_get_id,他的做用就是根據傳入的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")

... ...

完。

相關文章
相關標籤/搜索