背景介绍:本文是基于内核4.19.x,不同内核版本略有不同
由于本人才疏学浅有讲的不对的地方请指正,这也算是个人的一个笔记。
本文概况讲一下platform_device, platform bus, platform_driver三者的注册流程。由于内核版本3.x引入devicetree后,所以这里有必需说一下devicetree在什么时候解析,而又在什么时候创建成platform_device。
先上图:
图一
1.先看看devicetree是在什么时候转化成device_node
bootloader除了做一些必要的硬件初始化后,最后一步是将kernel镜像,devicetree的dtb文件加载到内存,并指定rootfs。最后跳转到kernel的地址进行执行。首先会执行head.S里面的汇编,后面会跳转到start_kernel, 这就到了熟悉的C语言了。
根据上面的函数调用流程图(图一),start_kernel->setup_arch->unflatten_device_tree, unflatten_device_tree这个函数会将dtb文件解析,并把每个dtb的node,放入到device_node结构中去。根节点是struct device_node *of_root, 这是一个全局指针,通过结构内的parent, child, sibling把所有device_node通过树状结构连接起来。而这个树根就是of_root。
struct device_node {
const char *name;
const char *type;
phandle phandle;
const char *full_name;
struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent; //指向父节点
struct device_node *child; //指向孩子节点
struct device_node *sibling; //指向兄弟节点
#if defined(CONFIG_OF_KOBJ)
struct kobject kobj;
#endif
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
2.platform bus注册时间
start_kernel->rest_init->kernel_init->kernel_init_freeable->do_basic_setup->driver_init->platform_bus_init
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match, //platform_device, platform_driver的匹配函数
.uevent = platform_uevent,
.dma_configure = platform_dma_configure,
.pm = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
/*
* 下面主要是创建了一个叫做platform的device,后续所有的
* platform_device注册后都会放在platform下,在sysfs表现为/sys/devices/platform
*
*/
error = device_register(&platform_bus);
if (error) {
put_device(&platform_bus);
return error;
}
/*
* 下面主要注册platform bus,最主要的事情,应该有一下几点
* 初始化bus的存放devices的链表,用于存放device
* 初始化bus的存放drivers的链表,用于存放driver
* 注册platform_match回调函数,用于platform_device, platform_driver的匹配函数
* 在sysfs中表现为/sys/bus/platform, 并在其下面创建了devices,drivers两个文件夹
*/
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
of_platform_register_reconfig_notifier();
return error;
}
由于后面platform_device, platform_driver注册时都会用到platform bus中的链表,所以platform bus要最先初始化。
3.platform_device, platform_driver的初始化以及注册
3.1 为什么是这里是platform_device比platform_driver先注册呢?
arch_initcall_sync(of_platform_default_populate_init);
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
3.2 platform_driver注册是放在哪个段的呢?
这里随便找一个platform_driver注册
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
.shutdown = gpio_led_shutdown,
.driver = {
.name = "leds-gpio",
.of_match_table = of_gpio_leds_match,
},
};
module_platform_driver(gpio_led_driver);
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
将宏展开最后得到:
static init __init gpio_led_driver_init(void)
{
return platform_driver_register(&gpio_led_driver);
}
module_init(gpio_led_driver_init);
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall(fn, 6)
module_init最后会将函数放在device_initcall这个代码段里。
do_initcalls会依次调用lds脚本里面从上到下的代码段里面的函数,所以platform_device会先初始化注册。
platform_device的创建并注册:of_platform_default_populate_init函数主要的功能就是将根节点为of_root,device_node构成的树状结构中符合规则的device_node分别创建成platform_device,并将其注册。
最后是platform_driver的注册。三者的注册顺序到这里就讲完了。
事实上platform_device, platform_driver谁先注册谁后注册都没有影响。如果你的platform_device是在devicetree里面配置的,那么就是按照上面讲的,先注册platform bus, 再注册platform_device, 最后注册platform_driver。