编译到内核中的驱动程序的 init 函数调用 [英] init function invocation of drivers compiled into kernel

查看:21
本文介绍了编译到内核中的驱动程序的 init 函数调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

解决方案

内置驱动的init例程仍然可以使用module_init()宏来声明那个入口点.或者,当驱动程序永远不会被编译为可加载模块时,驱动程序可以使用 device_initcall().或者要在启动序列的早期移动其初始化,驱动程序可以使用 subsys_initcall().

include/linux/init.h 中,调用这些 init 例程的顺序描述为:

/* 初始化调用现在按功能分组为单独的* 小节.确定小节内的顺序* 按链接顺序.* 为了向后兼容,initcall() 将调用放入* 设备初始化小节.** 需要 __define_initcall() 的 `id' 参数,以便多个 initcalls* 可以指向同一个处理程序而不会导致重复符号构建错误.*/

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

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

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

调用 tty_class_init+0x0/0x44 @ 1initcall tty_class_init+0x0/0x44 在 9765 使用后返回 0调用 spi_init+0x0/0x90 @ 1initcall spi_init+0x0/0x90 在 9765 微秒后返回 0

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

In Linux if device drivers are built as loadable kernel modules, then upon inserting the device driver kernel module, the kernel calls the init function of the device driver as pointed out by module_init() macro.

How does this work for device drivers that are statically compiled into the kernel ? How is their init function called ?

解决方案

The init routine of a built-in driver can still use the module_init() macro to declare that entry point. Or the driver can use device_initcall() when the driver would never be compiled as a loadable module. Or to move its initialization very early in the boot sequence, the driver could use subsys_initcall().

In include/linux/init.h the sequence for invoking these init routines is described as:

/* 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.
 */

I assume that these subsections for device drivers correspond to the subdirectories within the drivers directory of the Linux kernel source tree, and that the link order is recorded in the built-in.o file of each subdirectory in drivers. So during kernel boot the init routine of each built-in driver is eventually executed by do_initcalls() in init/main.c.

The init routine of the device driver is responsible for probing the system to verify that the HW device actually exists. The driver should not allocate any resources or register any devices when the probe fails.

UPDATE:
Passing the option "initcall_debug" on the kernel command line will cause timing information to be printed to the console for each initcall. initcalls are used to initialize statically linked kernel drivers and subsystems and contribute a significant amount of time to the Linux boot process. The output looks like:

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

Reference: http://elinux.org/Initcall_Debug

这篇关于编译到内核中的驱动程序的 init 函数调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆