Linux kernel driver initialization sequence is adjusted

  

kernel starts when the respective drive initialization do_basic_setup work file in init /main.c do .static void __init do_basic_setup (void) {/* drivers will () function Send hotplug events */init_workqueues();usermodehelper_init();driver_init();

#ifdef CONFIG_SYSCTLsysctl_init();#endif

/* Networking initialization needs a process context */sock_init() ;

do_initcalls();} where driver_init() does some core initialization, and the code understands it. The corresponding driver initialization is done in do_initcalls(). static void __init do_initcalls(void) {initcall_t *call;int count = preempt_count();

for (call = __initcall_start; call < __initcall_end; call++) {char *msg;

if (initcall_debug) {printk(KERN_DEBUG " Calling initcall 0x% p ", * call); print_fn_descriptor_symbol (":% s () ", (unsigned long) * call); printk (" \\ n ");}

( * call) ();

msg = NULL; if (preempt_count ()! = count) {msg = " pree Mption imbalance";preempt_count() = count;}if (irqs_disabled()) {msg = "disabled interrupts";local_irq_enable();}if (msg) {printk(KERN_WARNING "error in initcall at 0x%p: " ;"returned with %s\ ", *call, msg);}}

/* Make sure there is no pending stuff from the initcall sequence */flush_scheduled_work();}This __initcall_start is in The file arch/xxx/kernel/vmlinux.lds.S (where xxx is the name of your architecture, such as i386) This file is used when the kernel is ld. It defines each sectioin and you can see it. In this document there is a .initcall.init, code is as follows:. __ initcall_start =; initcall.init:.. {* (. Initcall1.init) * (. Initcall2.init) * (. Initcall3.init) * (initcall4. Init) *(.initcall5.init) *(.initcall6.init) *(.initcall7.init)}

There are 7 initialization priorities, and the kernel will load in order of priority. These priorities are defined in the file include/linux/init.h. You notice that the implementation of the macro __define_initcall is understood. The relevant code is as follows:

#define __define_initcall(level,fn) \\static initcall_t __initcall_##fn __attribute_used__ \\__attribute__((__section__(".initcall" level ".init"))) = fn

#define core_initcall(fn) __define_initcall("1",fn)#define postcore_initcall (fn) __define_initcall (" 2 ", fn) #define arch_initcall (fn) __define_initcall (" 3 ", fn) #define subsys_initcall (fn) __define_initcall (" 4 ", fn) #define fs_initcall (fn) __define_initcall ("5",fn)#define device_initcall(fn) __define_initcall(& Quot;6",fn)#define late_initcall(fn) __define_initcall("7",fn)

We can see that the module_init commonly used in device drivers we write often corresponds to the priority. 6:#define __initcall(fn) device_initcall(fn)

#define module_init(x) __initcall(x);

____________

How do I feel your problem Not because of the loading order? Guess. I also wrote the touchscreen driver, I feel that touchscreen uses more serio, but also useful i2c. You should seal these structures in your own driver, an input_dev structure, a Is serio (or i2c_driver), then control the load order. Module_init should be registered i2c_driver, then register input_dev when attach_adapter.



Today When you are doing a driver, you need to use the API provided by another driver (I2C), and you encounter a dependency problem during kernel initialization.

My driver is running before I2C initialization, and the API provided by I2C is still unavailable. I checked a lot of information. Some people on the Internet said that the order of starting all drivers using the module_init macro is uncertain (I didn't find the authoritative data).

All __init functions also store a function pointer in the section .initcall.init. At initialization, the kernel will call these __init function pointers through these function pointers, and after the entire initialization is completed, Free the entire init section (including .init.text, .initcall.init, etc.).

Note that the order in which these functions are called during kernel initialization is only related to the order of the function pointers here, and is independent of the order in which the functions described in 1) are in the .init.text section. In the 2.4 kernel, the order of these function pointers is also related to the order of the links, which is undefined. In the 2.6 kernel, the initcall.init section is divided into 7 subsections, which are

de>.initcall1.init .initcall2.init .initcall3.init .initcall4.init .initcall5.init .initcall6. Init .initcall7.initde>

When you need to put the function fn in the .initcall1.init section, just declare

de>core_initcall(fn);de>

Just fine.

The definitions of the other sections are:

de>core_initcall(fn) --->.initcall1.init postcore_initcall(fn) --->.initcall2. init arch_initcall (fn) --- & gt; .initcall3.init subsys_initcall (fn) --- & gt; .initcall4.init fs_initcall (fn) --- & gt; .initcall5.init device_initcall (fn) --- & gt ;. Initcall6.init late_initcall(fn) --->.initcall7.initde>

The 2.4-compatible initcall(fn) is equivalent to device_initcall(fn). The order between the sub-sections is determined, that is, the function pointer in .initcall1.init is called first, then the function pointer in .initcall2.init is called, and so on. The order of the function pointers in each subsection is related to the link order and is undefined.

Copyright © Windows knowledge All Rights Reserved