从device_node到并入设备驱动模型
此篇博客有很多参考其他文章的内容,由于参考内容繁杂,不一一标注角标了,在末尾会贴上所有参考博客的link,如有侵权,请联系本人处理,谢谢。
深入,并且广泛
-沉默犀牛
上一篇文章已经详细的分析了两个问题:
1.如何根据Device Tree的信息,找到最适合的machine_desc
2.如何将DTB转换成节点是device_node的树状结构
那么为什么要做这两件事情呢?
我们现在要做的事情是把DTS中描述的节点(status = okay的)注册到kernel中,DTS的信息我们的kernel没法直接识别啊,就得通过上述的2把DTS中描述的每一个节点,转换成device_node结构体,我们可以认为DTS中写的每一个节点在这里都被解析为一个device_node。(该结构体中有parent、child、sibling成员,通过这些成员把device_node给连接成了树状结构)好,现在我们有了完全代表了DTS信息,又能被kernel识别的device_node,现在就要把这些device_node一个个的创建起来(比如有的device_node要注册到platform总线上,有的要注册到i2c总线…),这个创建的过程,就需要我们上述1中的machine_desc了!在定义machine_desc结构体的时候,会定义一个回调函数:xxxx_init(大部分情况)就是这个xxxx_init把device_node都注册起来。
再补充上面一段话的三个点
1.xxxx_init函数只是注册了platform总线上的device_node,那其他的呢?比如i2c上的device呢?在注册i2c总线时,调用qup_i2c_probe(),这个接口会添加i2c适配器,适配器添加完成后会调用of_i2c_register_devices()接口来i2c总线节点的子节点,然后调用i2c_new_device(),生成i2c设备。
2.我在定义回调函数后面写了个大部分情况,也就代表有的时候不会定义这个回调函数,那么kernel怎么注册device_node呢?事实上kernel会检测machine_desc有没有init函数,如果有,则调用;如果没有,则调用of提供的接口直接注册所有platform的device,这里就有一个问题了:这个machine_desc如果没有定义init函数,那我还要它干嘛呢?我去看(根据DTS选择最适配的machine_desc)那一段代码时发现,如果没有找到合适的machine_desc的话,有一行注释:does not return! 这似乎意味着,找不到合适的machine_desc也没啥关系,kernel还是会继续运行下去,platform上的device还是可以注册上。如果这一点的理解有误,请留言纠正,大恩不言谢!
3.DTS中的节点都转换成了device_node,但是DTS中描述的节点并不都是device啊,比如cpus node,memory node,choose node等。对于这些节点的处理,我会在下一篇文章中说明。
经过前面的介绍和解释,我们明确了这一篇文章的主题:
那些platform总线下的device_node如何注册到platform总线上的?
执行流程
进入kernel的入口后,会按照如下的调用流程start_kernel
->rest_init
->kernel_init
->kernel_init_freeable
->
do_basic_setup
->do_initcalls
,do_initcalls
函数中,在do_initcalls函数中,kernel会依次执行各个initcall函数。
代码验证
在上述的调用流程中,会调用到调用customize_machine
,也正是这个函数,检测了machine_desc是否有xxxx_init函数,代码如下:
static int __init customize_machine(void)
{
if (machine_desc->init_machine) //如果有init_machine()函数,则执行
machine_desc->init_machine();
else //否则直接调用of提供的接口来注册device
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
return 0;
}
arch_initcall(customize_machine);
以高通msm8953为例,看看它有没有定义init_machine函数:
DT_MACHINE_START(MSM8953_DT,
"Qualcomm Technologies, Inc. MSM8953 (Flattened Device Tree)")
.init_machine = msm8953_init, //这里定义了init函数
.dt_compat = msm8953_dt_match, //这个参数就是之前匹配machine_desc用的
//这个参数将于DTS中的compatible属性值来比较
MACHINE_END
再看看这个函数的内容:
static void __init msm8953_init(void