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

时间:2012-10-12 18:30:46

标签: linux operating-system linux-kernel linux-device-driver

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

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

2 个答案:

答案 0 :(得分:5)

内置驱动程序的 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中每个子目录的内置.o 文件中。因此,在内核启动期间,每个内置驱动程序的 init 例程最终由do_initcalls()中的init/main.c执行。

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

<强>更新
在内核命令行上传递选项“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

答案 1 :(得分:2)

由内核init.h中的注释指定

  

“module_init()将在do_initcalls()(如果内置)或模块中调用   插入时间(如果是模块)。“

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

  

define module_init(x)__ incitcall(x);

如果你仔细观察那么

  

定义__initcall(fn)device_initcall(fn)

  

定义device_initcall(fn)__ undefine_initcall(“6”,fn,6)

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