阅读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;
}