init函数调用编译进内核的驱动程序

在Linux中,如果设备驱动程序是作为可加载内核模块构build的,那么在插入设备驱动程序内核模块时,内核调用module_init()macros指出的设备驱动程序的init函数。

这是如何工作的静态编译到内核的设备驱动程序? 他们的init函数是如何调用的?

内置驱动程序的init例程仍然可以使用module_init()宏声明该入口点。 或者驱动程序可以使用device_initcall()当驱动程序永远不会被编译为可加载模块。 或者在引导序列的早期移动它的初始化,驱动程序可以使用subsys_initcall()

include/linux/init.h中,调用这些init例程的顺序如下所示:

 /* initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined * by link order. * For backwards compatibility, initcall() puts the call in * the device init subsection. * * The `id' arg to __define_initcall() is needed so that multiple initcalls * can point at the same handler without causing duplicate-symbol build errors. */ 

我假设设备驱动程序的这些小节与Linux内核源代码树的drivers目录中的子目录相对应,并且链接顺序记录在drivers中每个子目录的built-in.o文件中。 因此,在内核启动期间,每个内置驱动程序的init例程最终由init/main.c do_initcalls()执行。

设备驱动程序的init例程负责探测系统,以确认硬件设备是否存在。 探测失败时,驱动程序不应分配任何资源或注册任何设备。

更新
在内核命令行上传递选项“initcall_debug”将导致定时信息被打印到每个初始调用的控制台。 initcalls用于初始化静态链接的内核驱动程序和子系统,并为Linux启动过程贡献了大量的时间。 输出如下所示:

 calling tty_class_init+0x0/0x44 @ 1 initcall tty_class_init+0x0/0x44 returned 0 after 9765 usecs calling spi_init+0x0/0x90 @ 1 initcall spi_init+0x0/0x90 returned 0 after 9765 usecs 

参考: http : //elinux.org/Initcall_Debug

正如内核init.h中的注释所指定的那样

“module_init()将在do_initcalls()(如果内置)或模块插入时(如果一个模块)被调用。

如果你看看init.h,那么你会看到

定义module_init(x)__initcall(x);

如果你仔细观察

定义__initcall(fn)device_initcall(fn)

定义device_initcall(fn)__define_initcall(“6”,fn,6)

所以基本上,init 模块在引导的时候会导致initcall( 注意:仅适用于静态编译的模块 )。