Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2994393
  • 博文数量: 523
  • 博客积分: 11908
  • 博客等级: 上将
  • 技术积分: 5475
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:50
文章分类

全部博文(523)

文章存档

2019年(3)

2013年(4)

2012年(71)

2011年(78)

2010年(57)

2009年(310)

分类: LINUX

2011-05-11 17:38:15

module_init()

linux内核中通过module_init函数指定初始化函数,分两种:

1、             静态编译进内核

对于静态编译进内核的,什么时候执行呢?

start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()

在执行do_initcalls之前调用了:

driver_init();     //建立设备模型子系统

在没有定义#ifndef MODULE的情况下,基本上表明阁下的模块是要编译进内核的(obj-y)

#define module_init(x)   __initcall(x);

#define __initcall(fn) device_initcall(fn)

 

#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
所以,module_init(x)最终展开为:

static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
更直白点,假设阁下driver所对应的模块的初始化函数为int gpio_init(void),那么module_init(gpio_init)实际上等于:
static initcall_t  __initcall_gpio_init_6 __used __attribute__((__section__(".initcall6.init"))) = gpio_init;
就是声明一类型为initcall_ttypedef int (*initcall_t)(void))函数指针类型的变量__initcall_gpio_init_6并将gpio_init赋值与它。

这里的函数指针变量声明比较特殊的地方在于,将这个变量放在了一名为".initcall6.init"节中。接下来结合vmlinux.lds中的
.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
   __initcall_start = .;
   *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
   __initcall_end = .;
   }
以及do_initcalls
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++)
do_one_initcall(*call);

/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
那么就不难理解阁下模块中的module_init中的初始化函数何时被调用了:在系统启动过程中start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()

在静态加载驱动的时候,我们那个gpio_init_cleanupmodule_exit函数永远不会被执行,所以去掉是完全可以的,不过为了程序看起来结构清晰,也为了与动态加载的程序兼容,还是建议保留着。

静态编译进内核,在系统启动的时候,会按顺序初始化相应的函数,当系统动态检测到设备存在时,会自动执行相应的函数,生成设备名。

 

2、按照模块动态加载

运行make menuconfig,在内核配置中进入Loadable module support,选择Enable loadable module supportKernel module loader(NEW)两个选项。在应用程序配置中进入busybox,选择insmod, rmmod, lsmod三个选项。

执行insmod时,会执行module_init()对应的函数。

然后mknod设备节点。

 

 

 

 

阅读(2139) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~