2012-10-12 43 views
4

在Linux中,如果设备驱动程序被构建为可加载的内核模块,然后在插入的设备驱动程序内核模块,内核由module_init()宏调用设备驱动程序的初始化函数如指出。函数调用编译到内核

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

回答

5

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

我假定这些小节设备驱动程序对应于子目录drivers目录Linux内核源树的内,那链接顺序被记录在drivers内置in.o文件中的每个子目录。所以内核引导的初始化例行每个内置驱动程序的过程中,通过do_initcalls()init/main.c最终执行。

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

UPDATE
跑过内核命令行选项“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

+0

假设我想为驱动程序使用device_initcall,我有一个问题。在需要调用此驱动程序的boardfile的哪一部分中。 – kzs

+1

通过*“boardfile”*,我假设您指的是arch或mach或板初始化代码,通常在引导过程中很早就被称为。 'init/main.c'中的'do_initcalls()'通常在大多数HW初始化之后发生。内核代码很少被构造成调用驱动程序,除非它是'ops'函数或其他模块接口入口点。你真的问过什么样的“电话”? – sawdust

+0

是的,你得到了电路板文件。并且do_initcalls何时被调用非常明确。 “你真的问过什么样的”呼叫“?为此,我想这样说:假设我有3种switch_dev类型的设备(它们的状态需要导出到用户空间)。在这里,设备调用device_initcall(随例程提供,使对象switch_dev-> kobj可用于其他2个设备)。其他两个设备使用正常的module_init。我的兴趣是将device_initcall例程移动到board文件并为所有模块使用module_init 3.如何做到这一点? – kzs

2

按规定在内核中的评论init.h里

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

如果你看看初始化。h然后你会看到

define module_init(x)__initcall(x);

而且如果你仔细观察,然后

定义__initcall(FN)device_initcall(FN)

而且

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

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