logger的驱动程序为文件logger.c, 位于内核driver/staging/android目录.
从最后一行device_initcall
(logger_init
)入口, 内核在启动时调用logger_init
函数.
device_initcall是在内核include/linux/init.h中定义的宏, 其临近有多个如xxx_initcall的定义.根据init.h中定义, 在配置为非module的驱动中, xxx_initcall最终都是#define_initcall(level, fn, id), 其中level决定在内核启动过程中调用优先级,如下:
#define device_initcall(fn) define_initcall(“6”,fn,6)
在配置为module的驱动中, xxx_initcall定义为module_init
.
#define device_initcall(fn) module_init(fn)
注意配置为非module模块时, init.h中同样定义了module_init
宏, 但是有如下定义:
#define
initcall(fn) device_initcall(fn)
define module_init(x) __initcall(x)
从Kconfig配置可知, logger驱动可配置为内置模块或可卸载模块, 而binder和ashm模块只能配置为内置模块.
关于define_initcall的解释可以参考这篇文章, 或者参考linux内核分析或linux驱动开发的相关书籍.摘录修改部分内容:
宏定义define_initcall(level,fn, id)对于内核的初始化很重要,他指示编译器在编译的时候,将一系列初始化函数的起始地址值按照一定的顺序放在一个section中。在内核初始化段,do_initcalls() 将按顺序从该section中以函数指针的形式取出这些函数的起始地址,来依次完成相应的初始化。
#define define_initcall(level,fn,id) \
static initcall_t initcall##fn##id used \
attribute((section(“.initcall” level “.init”))) = fn其中 initcall_t 是个函数指针类型:
typedef int (*initcall_t)(void);
而属性 attribute((section())) 则表示把对象放在一个这个由括号中的名称所指代的section中。所以这个宏定义的的含义是:
1) 声明一个名称为initcall##fn##id的函数指针(其中##表示替换连接,);
2) 将这个函数指针初始化为fn;
3) 编译的时候需要把这个函数指针变量放置到名称为 “.initcall” level “.init"的section中(比如level=“1”,代表这个section的名称是 “.initcall1.init”)。