【问题标题】:init function invocation of drivers compiled into kernel编译到内核中的驱动程序的 init 函数调用
【发布时间】:2015-01-22 16:29:46
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    内置驱动程序的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 中每个子目录的 built-in.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
    

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

    【讨论】:

    • 假设我想使用 device_initcall 作为驱动程序,我有一个问题。您需要在 boardfile 的哪个部分调用此驱动程序。
    • 通过 "boardfile",我假设您指的是通常在启动过程的早期调用的 arch 或 mach 或板初始化代码。 do_initcalls() in init/main.c 通常发生在大部分硬件初始化之后。内核代码很少被结构化来调用驱动程序,除非它是ops 函数或其他模块接口入口点。您真正要问的是哪种“电话”?
    • 是的,你有 wrt 板文件。并且很清楚 do_initcalls 何时会被调用。 What kind of "call" are you really asking about?为此我想这样提出问题:假设我有3种switch_dev类型的设备(它们的状态需要导出到用户空间)。在这里,设备 1 调用 device_initcall(提供了使对象 switch_dev->kobj 可用于其他 2 个设备的例程)。其他两个设备使用普通的 module_init。我的兴趣是将 device_initcall 例程移动到板文件并为所有 3 使用 module_init。如何做到这一点?
    • @zair - 您可能应该开始一个新问题,并提供详细信息和要求。一般来说,你不应该将设备初始化的东西移动到板文件中。这可能是糟糕的代码结构,因为您不希望非必要代码影响内核的早期启动。
    【解决方案2】:

    由内核 init.h 中的 cmets 指定

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

    【讨论】:

      猜你喜欢
      • 2018-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-28
      • 2015-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多