设备树中/aliases节点的作用

阅读linux内核驱动代码,会遇到of_alias_get_id(...)接口,通过函数名可以猜测其是在获取别名(aliase)的id,id是指代的什么呢?下面通过源码来看看其到达是在获取什么id?

在uart,spi,i2c等驱动中都使用of_alias_get_id获取别分对应的id值:

of_alias_get_id(np, "serial");

of_alias_get_id(ctlr->dev.of_node, "spi")

of_alias_get_id(dev->of_node, "i2c");

1、设备树配置

//aliases别名节点配置

aliases {

csi0 = &mipi_csi_0;

dpu0 = &dpu1;

ethernet0 = &fec1;

ethernet1 = &fec2;

dsi_phy0 = &mipi_dsi_phy1;

dsi_phy1 = &mipi_dsi_phy2;

mipi_dsi0 = &mipi_dsi1;

mipi_dsi1 = &mipi_dsi2;

ldb0 = &ldb1;

ldb1 = &ldb2;

isi0 = &isi_0;

isi1 = &isi_1;

isi2 = &isi_2;

isi3 = &isi_3;

isi4 = &isi_4;

isi5 = &isi_5;

isi6 = &isi_6;

isi7 = &isi_7;

serial0 = &lpuart0;

serial1 = &lpuart1;

serial2 = &lpuart2;

serial3 = &lpuart3;

mmc0 = &usdhc1;

mmc1 = &usdhc2;

mmc2 = &usdhc3;

can0 = &flexcan1;

can1 = &flexcan2;

can2 = &flexcan3;

i2c1 = &i2c1;

i2c2 = &i2c2;

i2c5 = &i2c_rpbus_5;

i2c12 = &i2c_rpbus_12;

i2c13 = &i2c_rpbus_13;

i2c14 = &i2c_rpbus_14;

i2c15 = &i2c_rpbus_15;

spi0 = &lpspi0;

spi1 = &lpspi1;

spi2 = &lpspi2;

spi3 = &lpspi3;

};

2、数据结构

/**

* struct alias_prop - Alias property in 'aliases' node

* @link: List node to link the structure in aliases_lookup list

* @alias: Alias property name

* @np: Pointer to device_node that the alias stands for

* @id: Index value from end of alias name,id

* @stem: Alias string without the index,主干名称

*

* The structure represents one alias property of 'aliases' node as

* an entry in aliases_lookup list.

*/

struct alias_prop {

struct list_head link; //将别名属性 alias_prop 挂接到aliases_lookup链表上

const char *alias;

struct device_node *np;

int id;

char stem[0];

};

extern struct list_head aliases_lookup;

3、函数分析

/**

* of_alias_scan - Scan all properties of the 'aliases' node

*

* The function scans all the properties of the 'aliases' node and populates

* the global lookup table with the properties. It returns the

* number of alias properties found, or an error code in case of failure.

*

* @dt_alloc: An allocator that provides a virtual address to memory

* for storing the resulting tree

*/

void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))

{

struct property *pp;

//寻找设备树/aliases节点

of_aliases = of_find_node_by_path("/aliases");

//寻找设备树/chosen节点

of_chosen = of_find_node_by_path("/chosen");

if (of_chosen == NULL)

of_chosen = of_find_node_by_path("/chosen@0");

if (of_chosen) {

/* linux,stdout-path and /aliases/stdout are for legacy compatibility */

const char *name = NULL;

if (of_property_read_string(of_chosen, "stdout-path", &name))

of_property_read_string(of_chosen, "linux,stdout-path",&name);

if (IS_ENABLED(CONFIG_PPC) && !name)

of_property_read_string(of_aliases, "stdout", &name);

if (name)

of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);

}

if (!of_aliases)

return;

//遍历/aliases下面的节点

for_each_property_of_node(of_aliases, pp) {

const char *start = pp->name;

const char *end = start + strlen(start);

struct device_node *np;

struct alias_prop *ap;

int id, len;

/* Skip those we do not want to proceed */

if (!strcmp(pp->name, "name") ||

!strcmp(pp->name, "phandle") ||

!strcmp(pp->name, "linux,phandle"))

continue;

//别名对应的节点

np = of_find_node_by_path(pp->value);

if (!np)

continue;

/* walk the alias backwards to extract the id and work out the 'stem' string */

//将主干和后面的id进行分离

while (isdigit(*(end-1)) && end > start)

end--;

len = end - start;

if (kstrtoint(end, 10, &id) < 0) //将id由字符串转换为数字

continue;

/* Allocate an alias_prop with enough space for the stem */

ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap));

if (!ap)

continue;

memset(ap, 0, sizeof(*ap) + len + 1);

ap->alias = start;

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;

ap->id = id;

strncpy(ap->stem, stem, stem_len); //主干名称

ap->stem[stem_len] = 0;

list_add_tail(&ap->link, &aliases_lookup);//将struct alias_prop挂接到aliases_lookup链表上

pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n",ap->alias, ap->stem, ap->id, np);

}

/**

* of_alias_get_id - Get alias id for the given device_node

* @np: Pointer to the given device_node

* @stem: Alias stem of the given device_node

*

* The function travels the lookup table to get the alias id for the given

* device_node and alias stem. It returns the alias id if found.

*/

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) {

if (strcmp(app->stem, stem) != 0) //比较主干名称

continue;

if (np == app->np) {

id = app->id;

break;

}

}

mutex_unlock(&of_mutex);

return id;

}

设备树(device tree)机制是Linux内核从linux-3.x版本开始引进的一种机制,目的是解决内核源码的arch/arm目录下代码混乱的问题:随着ARM生态的快速发展,在内核源码的arch/arm目录下,存放着几十种arm芯片和几百个开发板相关的源文件,很多开发板和处理器的断、寄存器等相关硬件资源都在这个目录下以.c或.h的文件格式定义。而对于内核来说,与这些硬件耦合,会导致内核代码混乱不堪,每个开发板上运行的内核镜像都必须单独编译配置,无法通用。什么时候Linux内核能像Windows镜像那样,无论你的电脑什么配置,一个Windows安装包,都可以直接下载安装运行呢?设备树机制,实现了Linux内核和硬件平台的解耦:每个硬件平台的硬件资源使用一个设备树文件(xxx.dts)来描述,而不是在arch/arm下以.c 或 .h 文件来定义。Linux内核是一个通用的内核,在启动过程,在通过解析设备树的硬件资源来初始化某个具体的平台。 引入设备树后,很多和内核驱动开发的工作也发生了变化:以往驱动工程师关注的头文件宏定义、寄存器定义,现在这些基本上不用关注,关注的重点则转向了如何根据硬件平台去配置和修改设备树文件。很多驱动的编程接口也发生了变化,开始慢慢使用device tree提供的编程接口去开发驱动。本期课程主要面向嵌入式开发人员,分享Linux下驱动开发所需要的设备树知识和必备技能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值