5

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

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

4

2 回答 2

6

内置驱动程序的initmodule_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.
 */

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

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

更新
在内核命令行上传递选项“initcall_debug”将导致每次 initcall 的计时信息打印到控制台。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

于 2012-10-13T01:36:50.593 回答
2

如内核 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 (注意:仅适用于静态编译的模块)。

于 2012-10-20T12:14:25.413 回答