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:\kernel\drivers\video\Makefile:背光驱动(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的初始化。
linux 设备驱动加载的先后顺序的更多相关文章
- linux设备和驱动加载的先后顺序
点击打开链接 Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...
- Linux设备驱动程序加载/卸载方法 insmod和modprobe命令
linux加载/卸载驱动有两种方法. 1.modprobe 注:在使用这个命令加载模块前先使用depmod -a命令生成modules.dep文件,该文件位于/lib/modules/$(uname ...
- Linux内核模块驱动加载与dmesg调试
因为近期用到了Linux内核的相关知识,下面随笔将给出内核模块的编写记录,供大家参考. 1.运行环境 Ubuntu 版本:20.04 Linux内核版本:5.4.0-42-generic gcc版本: ...
- 最新内核3.4)Linux 设备树加载I2C client adapter 的流程(内核3.4 高通)【转】
转自:https://blog.csdn.net/lsn946803746/article/details/52515225 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转 ...
- ARM架构下linux设备树加载的方法
引入设备树后bootloader加载DTB方法: 1. 标准方法 将linux kernel放到内存地址为<kernel img addr>的内存中. 将DTB放到地址为<dtb a ...
- linux 内核驱动加载过程中 向文件系统中的文件进行读写操作
utils.h 文件: #ifndef __UTILS_H__ #define __UTILS_H__ void a2f(const char *s, ...); #endif utils.c 文件: ...
- linux 设备驱动概述
linux 设备驱动概述 目前,Linux软件工程师大致可分为两个层次: (1)Linux应用软件工程师(Application Software Engineer): 主要利用C库函数和 ...
- linux下自动加载设备驱动程序模块
假设你的设备驱动程序为:yourdrivername.ko 1 cp yourdrivername.ko /lib/modules/"version"/kernel/driver ...
- 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级
Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏: include\linux\init.h #define pure_initcall(fn) __define_initcall(& ...
随机推荐
- java入门,学习笔记
编译 通过javac编译java程序,会编译出一个后缀为class的文件,我们再通过java虚拟机(jvm)执行编译后的java程序. 在java中始终有一个main函数,它作为程序的入口,程序从这个 ...
- tomcat关闭后线程依然运行解决办法
tomcat关闭后线程依然运行解决办法,设置线程为守护线程 守护线程与非守护线程 最近在看多线程的Timer章节,发现运用到了守护线程,感觉Java的基础知识还是需要补充. Java分为两种线程:用户 ...
- linux上搭建ftp、vsftp, 解决访问ftp超时连接, 解决用户指定访问其根目录,解决ftp主动连接、被动连接的问题
linux上搭建ftp 重要 解决如何搭建ftp 解决用户指定访问其根目录 解决访问ftp超时连接 解决ftp主动连接.被动连接的问题 1.安装ftp ...
- 【IT笔试面试题整理】删除无序链表中重复的节点
[试题描述]定义一个函数,输入一个链表,删除无序链表中重复的节点 [参考代码] 方法一: Without a buffer, we can iterate with two pointers: &qu ...
- Dicom图像解析
医疗图像解析 Dicom 后缀: .dcm..DCM Dicom中规定的坐标系是以人坐标系为绝对坐标系的,规定X轴正向指向病人的左侧,Y轴正向指向病人的背部,Z轴正向指向病人的头部.但是,坐标点的位置 ...
- es6学习笔记3--解构和对象
1.解构 在接收数据的地方(比如赋值的左边),解构使你使用模式去获取部分数据. 下面的代码是解构的一个例子: let obj = { first: 'Jane', last: 'Doe' }; let ...
- vector向量容器(常用的使用方法总结)
关于STL中vector容器的学习,编译运行后边看代码,边看执行结果效果更佳,还是想说看别人的代码一百遍,不如自己动手写一遍. vector向量容器不但能像数组一样对元素进行随机访问,还能随时在尾部插 ...
- 从零开始学JAVA(09)-使用SpringMVC4 + Mybatis + MySql 例子(注解方式开发)
项目需要,继续学习springmvc,这里加入Mybatis对数据库的访问,并写下一个简单的例子便于以后学习,希望对看的人有帮助.上一篇被移出博客主页,这一篇努力排版整齐,更原创,希望不要再被移出主页 ...
- iOS不同网络情况调试
有时我们需要对app进行不同网络状况的测试,这时我们可以用到iPhone中的开发者功能进行测试. 按照下图所示打开网络调试功能: 可以看到系统默认配置的网络条件还 ...
- Java异常捕获之一道try-catch-finally语句题
今天,学习了try-catch-finally语句,本来觉得蛮简单.易懂的.搜了一道相关类型的题.结果信心被泼了盆冷水.先把题Mark一下,出去透透风. public class TestEx { p ...