DM9000驱动具体分析
发布时间:2021-12-13 10:58:16 所属栏目:教程 来源:互联网
导读:1 模块的初始化和退出函数 初始化与退出函数: module_init(dm9000_init); module_exit(dm9000_cleanup); 其实是宏定义,在模块执行时告诉内核初始化函数和去初始化的位置让其执行初始化和退出操作。 目前linux支持两种方式运行设备驱动,一种是built-in ker
1 模块的初始化和退出函数 初始化与退出函数: module_init(dm9000_init); module_exit(dm9000_cleanup); 其实是宏定义,在模块执行时告诉内核初始化函数和去初始化的位置让其执行初始化和退出操作。 目前linux支持两种方式运行设备驱动,一种是built-in kernel,另一种module。 1.1 built-in module_init(x) 相关宏定义: #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 typedef int (*initcall_t)(void); 把上面的宏变换展开: Static initcall_t __initcall_dm9000_init_6 __used __attribute__((__section__(“.initcall” 6 “.init”)))=dm9000_init 其实是定义了一个Static initcall_t类型的函数指针__initcall_dm9000_init_6 这里我们需要了解一下gcc的__attribute__机制,是在编译的过程中告诉编译器该函数一些属性,__attribute__((__section__(“.initcall” 6 “.init”)))意思是把函数放入“.initcall” 6 “.init” 段中,然后把dm9000_init赋值给它。 __used也是一个__attribute__相关宏: #if __GNUC_MINOR__ >= 3 # define __used __attribute__((__used__)) #else # define __used __attribute__((__unused__)) #endif http://gcc.gnu.org/onlinedocs/gcc-4.3.2//gcc/Function-Attributes.html 中关于used与unused有解释,__attribute__修饰的函数或变量可能使用/不使用,可以避免编译器产生告警。 结合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 = .; } 系统启动时 start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls() 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(); } 1.2module 按如下宏展开: /* Each module must use one module_init(). */ #define module_init(initfn) static inline initcall_t __inittest(void) { return initfn; } int init_module(void) __attribute__((alias(#initfn))); /* This is only required if you want to be unloadable. */ #define module_exit(exitfn) static inline exitcall_t __exittest(void) { return exitfn; } void cleanup_module(void) __attribute__((alias(#exitfn))); 在用insmod加载模块时会调用模块的init函数. ![]() (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |