If you have written the driver module under Linux, you are not new to this macro. Module_init macro has different content when the module macro is not defined. If this macro is not defined, it basically indicates that your module is compiled into the kernel (obj-Y ).
1. If the module is not defined, module_init is defined as follows:
# Define module_init (x) _ initcall (X );
Because
# 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
Therefore, module_init (X) is finally expanded:
Static initcall_t _ initcall _ # FN # ID _ used \
_ Attribute _ (_ Section _ (". initcall" level ". init") = FN
To put it bluntly, if the initialization function of the module corresponding to your driver is int gpio_init (void), module_init (gpio_init) is actually equal:
Static initcall_t_ Initcall_gpio_init_6_ Used _ attribute _ (_ Section _ (". initcall6.init") =Gpio_init;
Declare the Variable _ initcall_gpio_init_init_init of the initcall_t (typedef int (* initcall_t) (void) function pointer type and assign the value to gpio_init.
The function pointer variable declaration here is special in that the variable is placed in a section named ". initcall6.init. Next, combine
. 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 = .;
}
And do_initcils:
Static void _ init do_initcils (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 ();
}
It is easy to understand when the initialization function in module_init in your module is called: during system startupStart_kernel ()-> rest_init ()-> kernel_init ()-> do_basic_setup ()-> do_initcils ().
2. When the module is defined (most driver modules that can be dynamically loaded belong to this, obj-m), module_init is defined as follows:
# Define module_init (initfn )\
Static inline initcall_t _ inittest (void )\
{Return initfn ;}\
Int init_module (void) _ attribute _ (alias (# initfn )));
The key point of this macro definition is to use alias to change initfn to init_module. The previous _ inittest definition is actually a kind of technique used to perform a static type check on initfn. If you define the module initialization function as void gpio_init (void), for example) or int gpio_init (INT), there will be warning similar to the following during compilation:
Gpio/fsl-gpio.c: In function '_ inittest ':
Gpio/fsl-gpio.c: 46: Warning: return from incompatible pointer type
Use module_init to alias the module initialization function as init_module. In this way, the system will call sys_init_module () to locate the init_module entry address.
If objdump-T gpio. Ko, you will find that init_module and gpio_init are at the same address offset. In short, in this case, the module's initialization function is called during insmod.