• linux 设备驱动加载的先后顺序


    Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢。

    1、初始化宏

    Linux系统使用两种方式去加载系统中的模块:动态和静态。

    静态加载:将所有模块的程序编译到Linux内核中,由do_initcall函数加载

    核心进程(/init/main.c)kernel_inità do_basic_setup()àdo_initcalls()该函数中会将在__initcall_start和__initcall_end之间定义的各个模块依次加载。那么在__initcall_start 和 __initcall_end之间都有些什么呢?

    找到/arch/powerpc/kernel/vmlinux.lds文件,找到.initcall.init段:

    .initcall.init : {
    
      __initcall_start = .;
    
      *(.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 = .;
    
    }
    

    可以看出在这两个宏之间依次排列了14个等级的宏,由于这其中的宏是按先后顺序链接的,所以也就表示,这14个宏有优先级:0>1>1s>2>2s………>7>7s。

    那么这些宏有什么具体的意义呢,这就要看include/linux/init.h文件:

    #define pure_initcall(fn)              __define_initcall("0",fn,0)
    
    #define core_initcall(fn)              __define_initcall("1",fn,1)
    
    #define core_initcall_sync(fn)           __define_initcall("1s",fn,1s)
    
    #define postcore_initcall(fn)              __define_initcall("2",fn,2)
    
    #define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
    
    #define arch_initcall(fn)        __define_initcall("3",fn,3)
    
    #define arch_initcall_sync(fn)            __define_initcall("3s",fn,3s)
    
    #define subsys_initcall(fn)          __define_initcall("4",fn,4)
    
    #define subsys_initcall_sync(fn)       __define_initcall("4s",fn,4s)
    
    #define fs_initcall(fn)                   __define_initcall("5",fn,5)
    
    #define fs_initcall_sync(fn)         __define_initcall("5s",fn,5s)
    
    #define rootfs_initcall(fn)            __define_initcall("rootfs",fn,rootfs)
    
    #define device_initcall(fn)          __define_initcall("6",fn,6)
    
    #define device_initcall_sync(fn)       __define_initcall("6s",fn,6s)
    
    #define late_initcall(fn)         __define_initcall("7",fn,7)
    
    #define late_initcall_sync(fn)             __define_initcall("7s",fn,7s)
    

    这里就定义了具体的宏,我们平时用的module_init在静态编译时就相当于device_initcall。举个例子,在2.6.24的内核中:gianfar_device使用的是arch_initcall,而gianfar_driver使用的是module_init,因为arch_initcall的优先级大于module_init,所以gianfar设备驱动的device先于driver在总线上添加。

    2、编译顺序

    同一级别的初始化是和编译顺序有关的,并不是和设备列表一致。
    【问题】
    背光驱动初始化先于LCD驱动初始化,导致LCD驱动初始化时出现闪屏的现象。
    【解决过程】

    2.1 mach-xxx.c中platform devices列表如下:

    /* platform devices */
    static struct platform_device *athena_evt_platform_devices[] __initdata = {
    //&xxx_led_device,
    &xxx_rtc_device,
    &xxx_uart0_device,
    &xxx_uart1_device,
    &xxx_uart2_device,
    &xxx_uart3_device, 
    &xxx_nand_device,
    &xxx_i2c_device,
    
    &xxx_lcd_device,
    &xxxpwm_backlight_device,
            ...
    };
    

    LCD(xxx_lcd_device)设备先于PWM(xxxpwm_backlight_device)设备。
    可见驱动的初始化顺序并不是和这个表定义的顺序始终保持一致的。(记得PM操作 - resume/suspend的顺序
    是和这个表的顺序保持一致的)

    2.2 怀疑和编译顺序有关

    Z:kerneldriversvideoMakefile:背光驱动(backlight/)的编译限于LCD驱动(xxxfb.o)的编译

    obj-$(CONFIG_VT)   += console/
    obj-$(CONFIG_LOGO)   += logo/
    obj-y   += backlight/ display/
    ...
    obj-$(CONFIG_FB_xxx)   += xxxfb.o ak_logo.o
    obj-$(CONFIG_FB_AK88)   += ak88-fb/
    

    这样编译生成的System.map中的顺序为:

    c001f540 t __initcall_pwm_backlight_init6
    c001f544 t __initcall_display_class_init6
    c001f548 t __initcall_xxxfb_init6
    

    Makefile更改为:

    obj-$(CONFIG_VT)   += console/
    obj-$(CONFIG_LOGO)   += logo/
    obj-y   += display/
    ...
    obj-$(CONFIG_FB_xxx)   += xxxfb.o ak_logo.o
    obj-$(CONFIG_FB_AK88)   += ak88-fb/
    obj-y   += backlight/
    

    这样编译生成的System.map中的顺序为:

    c001f53c t __initcall_display_class_init6
    c001f540 t __initcall_xxxfb_init6
    c001f544 t __initcall_genericbl_init6
    c001f548 t __initcall_pwm_backlight_init6
    

    加载运行:
    xxxpwm_backlight_device的probe就会在xxx_lcd_device的probe之后执行,即LCD初始化先于PWM的初始化。

  • 相关阅读:
    (转)python编写登录接口
    (转)Python之文件读写
    (转)python strip()函数 去空格 函数的用法
    (转)模块readline解析
    (转)跟着老男孩一步步学习Shell高级编程实战
    图片服务器优化 解决流量和存储问题
    某大型网站图片服务器改造方案
    雅虎网页优化14条原则
    独立的图片服务器架构
    城市分站设计思路
  • 原文地址:https://www.cnblogs.com/linhaostudy/p/9112264.html
Copyright © 2020-2023  润新知