Linux 编译到内核中的驱动程序的初始化函数调用

Linux 编译到内核中的驱动程序的初始化函数调用,linux,operating-system,linux-kernel,linux-device-driver,Linux,Operating System,Linux Kernel,Linux Device Driver,在Linux中,如果将设备驱动程序构建为可加载的内核模块,那么在插入设备驱动程序内核模块时,内核将调用设备驱动程序的init函数,正如module_init()宏所指出的那样 对于静态编译到内核中的设备驱动程序,这是如何工作的?如何调用它们的init函数?内置驱动程序的init例程仍然可以使用模块init()宏来声明该入口点。或者,当驱动程序永远不会编译为可加载模块时,驱动程序可以使用device\u initcall()。或者,要在启动序列的早期移动其初始化,驱动程序可以使用subsys\u

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

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

内置驱动程序的init例程仍然可以使用
模块init()
宏来声明该入口点。或者,当驱动程序永远不会编译为可加载模块时,驱动程序可以使用
device\u initcall()
。或者,要在启动序列的早期移动其初始化,驱动程序可以使用
subsys\u 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例程最终由
init/main.c
中的
do_initcalls()
执行

设备驱动程序的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

参考:

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

“模块_init()将在do_initcalls()期间(如果内置)或在模块处调用 插入时间(如果是模块)。”

如果您查看init.h,那么您将看到

定义模块_init(x)_initcall(x); 如果你仔细观察的话

定义初始化调用(fn)设备初始化调用(fn) 及

定义设备初始化调用(fn)\定义初始化调用(“6”,fn,6)
因此,基本上模块init在引导时会导致initcall(注意:仅用于静态编译的模块。

假设我想将设备initcall用于驱动程序,我有一个问题。在boardfile的哪个部分中,您需要调用此驱动程序。通过“boardfile”,我假设您指的是arch或mach或电路板初始化代码,通常在引导过程的早期调用<
init/main.c
中的code>do_initcalls()通常发生在大部分硬件初始化之后。内核代码很少被构造成调用驱动程序,除非它是
ops
函数或其他模块接口入口点。你到底在问什么样的电话?是的,你有wrt板文件。而且do_initcalls什么时候会被调用是非常清楚的
你真正想问的是什么类型的“呼叫”?
对于这一点,我想这样问:假设我有3种类型为switch\u dev的设备(它们的状态需要导出到用户空间)。这里,deviceone调用device_initcall(随例程提供,该例程使对象开关_dev->kobj可用于其他2个设备)。其他两个设备使用普通模块_init。我的兴趣是将设备_initcall例程移动到板文件中,并对所有3个模块使用模块_init。如何做到这一点?@zair-您可能应该开始一个新问题,并提供详细信息和要求。通常,您不应该将设备初始化内容移动到线路板文件中。这可能是糟糕的代码结构,因为您不希望非必要的代码影响早期内核启动。