zoukankan      html  css  js  c++  java
  • 基于tiny4412的Linux内核移植 --- aliases节点解析【转】

    转自:https://www.cnblogs.com/pengdonglin137/p/5252348.html

    作者信息

    作者: 彭东林

    邮箱:pengdonglin137@163.com

    QQ:405728433

    平台简介

    开发板:tiny4412ADK + S700 + 4GB Flash

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

    u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动)

    busybox版本:busybox 1.25

    交叉编译工具链: arm-none-linux-gnueabi-gcc

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

    正文

        在设备树中有一个叫做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是''
      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
    ",
      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")

    ... ...

    完。

  • 相关阅读:
    CodeForces 659F Polycarp and Hay
    CodeForces 713C Sonya and Problem Wihtout a Legend
    CodeForces 712D Memory and Scores
    CodeForces 689E Mike and Geometry Problem
    CodeForces 675D Tree Construction
    CodeForces 671A Recycling Bottles
    CodeForces 667C Reberland Linguistics
    CodeForces 672D Robin Hood
    CodeForces 675E Trains and Statistic
    CodeForces 676D Theseus and labyrinth
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/11736538.html
Copyright © 2011-2022 走看看