作为一个linux驱动开发者,大家肯定会写过形形色色的驱动。一般的流程是首先在dts配置设备的相关属性,然后编写相应的driver,基于linux内核device-bus-driver架构,device和driver会在某个时候match上,然后执行driver的probe函数,完成设备的相关初始化工作。如果打开一个项目的dts,会发现里面很多设备节点,那么这些设备是以什么样的原则给注册到系统中呢?
下文以4.9内核版本,平台为arm64 为例来讲解具体的设备注册过程。
1. 根设备及其子设备的注册
路径:drivers/of/platform.c
static int __init of_platform_default_populate_init(void)
{
struct device_node *node;
if (!of_have_populated_dt())
return -ENODEV;
/*
* Handle ramoops explicitly, since it is inside /reserved-memory,
* which lacks a "compatible" property.
*/
node = of_find_node_by_path("/reserved-memory");
if (node) {
node = of_find_compatible_node(node, NULL, "ramoops");
if (node)
of_platform_device_create(node, NULL, NULL);
}
/* Populate everything else. */
of_platform_default_populate(NULL, NULL, NULL);
return 0;
}
arch_initcall_sync(of_platform_default_populate_init);
首先单独处理了reserved-memory节点下属性为ramoops的节点,该节点主要用于保存kernel oops信息, 然后接下来调用 of_platform_default_populate()函数来处理剩余的节点。
路径:drivers/of/platform.c
int of_platform_default_populate(struct device_node *root,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
return of_platform_populate(root, of_default_bus_match_table, lookup,
parent);
}
EXPORT_SYMBOL_GPL(of_platform_default_populate);
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path("/");
if (!root)
return -EINVAL;
pr_debug("%s()\n", __func__);
pr_debug(" starting at: %s\n", root->full_name);
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc) {
of_node_put(child);
break;
}
}
of_node_set_flag(root, OF_POPULATED_BUS);
of_node_put(root);
return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
首先获取root节点的device_node, 在根节点初始化的过程中,root节点即为dts中的"/", 然后一次遍历"/"的子节点,并依次调用of_platform_bus_create函数递归的创建匹配上match的设备及其子设备。
路径:drivers/of/platform.c
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
/* Make sure it has a compatible property */
if (strict