在设备树中有一个叫做aliases的节点:
/ { #address-cells = <1>; #size-cells = <1>; aliases { fimc0 = &fimc0; fimc1 = &fimc1; fimc2 = &fimc2; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; ······ }; ...... };
在Linux内核启动的时候会解析这个节点:
start_kernel setup_arch unflatten_device_tree of_alias_scan void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) { struct property *pp; /* 找到/aliases节点对应的device_node */ of_aliases = of_find_node_by_path("/aliases"); /* 找到/chosen节点对应的device_node */ of_chosen = of_find_node_by_path("/chosen"); /* 如果没有/chosen的话,就找/chosen@0节点 */ if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); /* 遍历/aliases节点的属性 */ for_each_property_of_node(of_aliases, pp) { const char *start = pp->name; // 属性的名字 const char *end = start + strlen(start); // 名字的结尾,*end是'\0' struct device_node *np; struct alias_prop *ap; int id, len; /* Skip those we do not want to proceed */ /* 忽略名字是name、phandle、linux,phandle的属性 */ if (!strcmp(pp->name, "name") || !strcmp(pp->name, "phandle") || !strcmp(pp->name, "linux,phandle")) continue; /* 根据属性的值获得这个值对应的节点 */ /* 比如这个这个属性,fimc2 = "/soc/camera/fimc@fb400000"通过路径来找到节点 */ np = of_find_node_by_path(pp->value); if (!np) continue; /* 正常一个属性名字是fimc1,i2c0,这样,这里是把end指针指向数字前面那一个位置, * 比如fimc2的c字符的地址 */ while (isdigit(*(end-1)) && end > start) end--; len = end - start; /* 这个len就是名字除去数字的长度 */ /* 把end字符串后面的数字,由字符串转换成数字复制给id,比如fimc2的,数子2 */ if (kstrtoint(end, 10, &id) < 0) continue; /* Allocate an alias_prop with enough space for the stem */ /* 分配内存,多分配的"len+1"用于存放stem的名字 */ ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap)); if (!ap) continue; memset(ap, 0, sizeof(*ap) + len + 1); ap->alias = start; /* ap->alias指向字符串"fimc2 */ of_alias_add(ap, np, id, start, len); } } static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len) { ap->np = np; // np是"/soc/camera/fimc@fb400000";"对应的节点device_node ap->id = id; // id的值是2,代表设备序号,使用的时候要用到 //由于stem_len是名字除去数字的长度,所以ap->stem被赋值为"fimc" strncpy(ap->stem, stem, stem_len); ap->stem[stem_len] = 0; list_add_tail(&ap->link, &aliases_lookup); //将这个ap加入到全局aliases_lookup链表中 pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n", ap->alias, ap->stem, ap->id, np); }
在注册i2c控制器时:
int i2c_add_adapter(struct i2c_adapter *adapter) { struct device *dev = &adapter->dev; int id; if (dev->of_node) { //获取与这个device_node对应的alias_prop的id。如果以 i2c2 = &i2c2;节点为例,这里得到的id就是2 id = of_alias_get_id(dev->of_node, "i2c"); if (id >= 0) { adapter->nr = id; return __i2c_add_numbered_adapter(adapter); } } id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); adapter->nr = id; return i2c_register_adapter(adapter); } int of_alias_get_id(struct device_node *np, const char *stem) { struct alias_prop *app; int id = -ENODEV; mutex_lock(&of_mutex); /* 遍历全局链表aliases_lookup */ list_for_each_entry(app, &aliases_lookup, link) { /* 找到 stem 是 "i2c" 的alias_prop */ if (strcmp(app->stem, stem) != 0) continue; /* 所有的i2c控制的stem都叫"i2c",所以要保证设备节点一致 */ if (np == app->np) { id = app->id; /* 最终返回找到的编号名字 */ break; } } mutex_unlock(&of_mutex); return id; }
从上面的分析可知alias节点的作用:
比如SoC上有多个i2c控制器,alias相当于给每个i2c控制器分配一个唯一的编号,如上面的i2c2对应的alias是i2c2,那么这个编号就是2,将来就可以在/dev下看到名为i2c-2的设备节点。
标签:node,i2c,ap,stem,alias,aliases,id,设备 From: https://www.cnblogs.com/god-of-death/p/17299316.html