作者信息

作者: 彭东林

邮箱: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是'\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是i2c,那麼這個編號就是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")

... ...

完。

基于tiny4412的Linux内核移植 --- aliases节点解析的更多相关文章

  1. 基于tiny4412的Linux内核移植 --- aliases节点解析【转】

    转自:https://www.cnblogs.com/pengdonglin137/p/5252348.html 阅读目录(Content) 作者信息 平台简介 正文 回到顶部(go to top) ...

  2. 基于tiny4412的Linux内核移植 -- 设备树的展开

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  3. 基于tiny4412的Linux内核移植 -- 设备树的展开【转】

    转自:https://www.cnblogs.com/pengdonglin137/p/5248114.html#_lab2_3_1 阅读目录(Content) 作者信息 平台简介 摘要 正文 一.根 ...

  4. 基于tiny4412的Linux内核移植(支持device tree)(三)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  5. 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  6. 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  7. 基于tiny4412的Linux内核移植(支持device tree)(一)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  8. 基于tiny4412的Linux内核移植 -- PWM子系统学习(八)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  9. 基于tiny4412的Linux内核移植 -- SD卡驱动移植(五)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

随机推荐

  1. SQL行转列和列转行

    行列互转,是一个经常遇到的需求.实现的方法,有case when方式和2005之后的内置pivot和unpivot方法来实现. 在读了技术内幕那一节后,虽说这些解决方案早就用过了,却没有系统性的认识和 ...

  2. 初识React,Virutal DOM, State以及生命周期

    这是React分类下的第一篇文章,是在了解了一些基本面后,看Tyler文章,边看边理解边写的. React可以看做是MVC中的V,关注的是视图层.React的组件就像Angular的Directive ...

  3. Java SimpleDateFormat[转]

    [补充] [转] http://stackoverflow.com/questions/2603638/why-cant-this-simpledateformat-parse-this-date-s ...

  4. Tomcat 安全配置与性能优化

    一.Tomcat内存优化 1.JAVA_OPTS参数说明 Tomcat内存优化主要是对 tomcat 启动参数优化,我们可以在 tomcat 的启动脚本 catalina.sh 中设置 JAVA_OP ...

  5. 【转载】Scarbee Pre-Bass 贝司的使用教程

    Fender(芬达)的顶级型号Precision贝司的缩写! 好了,在了解完关于这个Bass音色的一些背景后,我们开始使用Pre-Bass了,先在Kontakt 3.5或Kontakt 4中读取它,由 ...

  6. 深入剖析 redis 主从复制

    主从概述 redis 支持 master-slave(主从)模式,redis server 可以设置为另一个 redis server 的主机(从机),从机定期从主机拿数据.特殊的,一个 从机同样可以 ...

  7. Flash Builder中“Error: #2036 加载未完成”错误的解决方法

    复制了一个名称为A的widget包,重命名为B,包含B.mxml和B.xml(配置文件),编译后无法加载B包创建的widget,报错为: 解决办法: 1.在工程的根目录下找到.actionScript ...

  8. SQL的主键和外键约束

    SQL的主键和外键的作用: 外键取值规则:空值或参照的主键值. (1)插入非空值时,如果主键表中没有这个值,则不能插入. (2)更新时,不能改为主键表中没有的值. (3)删除主键表记录时,你可以在建外 ...

  9. Customer IEnuramble Extension

    public static class IEnurambleExtension { public static IEnumerable<TSource> DistinctBy<TSo ...

  10. SQLSERVER建立MYSQL连接服务器

    1. 在SQL SERVER端安装MYSQL的ODBC驱动 2. 在ODBC数据源添加MYSQL(控制面板\所有控制面板项\管理工具) 在用户DSN 和系统DSN添加配置驱动程序 注:字符集一定要和M ...