Linux 设备和驱动加载的先后顺序 2

本文深入探讨了Linux系统中模块的静态和动态加载机制,详细解释了initcall宏的作用及其优先级排序,帮助开发者了解如何控制内核模块的加载顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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

核心进程(/init/main.ckernel_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在总线上添加。

<think>我们正在讨论的是Android系统驱动加载阶段的调整,特别是摄像头麦克风的加载顺序。用户的问题集中在系统驱动层面,而不是应用层(如之前的PhoneGap示例)。因此,我们需要深入Linux内核Android初始化过程。关键点:1.驱动加载顺序由内核的初始化顺序决定。2.我们可以通过修改内核初始化顺序(调整驱动模块的初始化级别)或修改设备树(DTS)来调整设备注册的先后顺序。具体步骤: ###方法一:调整内核模块初始化顺序(适用于模块化驱动)如果摄像头麦克风的驱动编译为模块(.ko文件),则可以在init.rc脚本中调整加载顺序。1.**修改初始化脚本**(如`init.rc`或`init.<device>.rc`):在设备启动脚本中,使用`insmod`命令按顺序加载驱动模块:```rc#先加载麦克风驱动insmod /vendor/lib/modules/snd-usb-audio.ko#再加载摄像头驱动insmod /vendor/lib/modules/uvcvideo.ko```2.**确保模块依赖关系正确**:如果摄像头驱动依赖于麦克风驱动(通常不会),则必须按依赖顺序加载。如果没有依赖,则加载顺序就是注册设备的顺序。###方法二:调整内核初始化顺序(适用于内置驱动)如果驱动直接编译进内核(built-in),则在内核源码中调整初始化顺序。在内核中,驱动初始化函数使用`subsys_initcall`、`module_init`等宏定义,这些宏定义了驱动的初始化级别。相同级别的初始化顺序由链接顺序决定。1. **修改链接顺序**:通过调整Makefile中的obj-y顺序来改变初始化顺序。例如,在`drivers/media/usb/Makefile`中:```makefile#先链接音频驱动(麦克风)obj-y +=snd-usb/#再链接视频驱动(摄像头)obj-y+= uvc/```2. **使用初始化级别宏**:如果两个驱动不在同一个目录,我们可以通过改变初始化宏的级别来调整顺序。例如,将麦克风驱动的初始化级别设置为`subsys_initcall_sync`,而摄像头驱动设置为`subsys_initcall`,则麦克风驱动会先初始化(因为`_sync`表示在初始化阶段同步等待,但实际上级别相同则顺序由链接顺序决定)。更可靠的方法是调整链接顺序。###方法三:设备树(DTS)调整设备树可以描述硬件信息,包括设备在总线上的顺序。但是,USB设备的枚举顺序通常由物理连接顺序USB控制器决定。不过,我们可以通过设备树调整同一条总线上设备的初始化顺序(如果设备是内置的,比如集成在SoC上的USB控制器)。在设备树中,设备的节点顺序有时会影响初始化顺序(但并非总是如此)。我们可以尝试将麦克风设备节点放在摄像头设备节点之前。例如,在RK3588的设备树中:```dts&usb_host0_ehci{status ="okay";/*麦克风设备节点 */usb_mic:device@1 {reg= <1>;compatible= "usb-audio";};/*摄像头设备节点*/usb_camera: device@2{reg =<2>;compatible= "usb-video";}; };```注意:这种方法并不保证在所有情况下都有效,因为USB设备枚举顺序还受USB协议控制器影响。 ###方法四:延迟摄像头驱动的初始化如果无法调整顺序,可以延迟摄像头驱动的初始化,确保麦克风驱动先完成初始化。在摄像头驱动中增加延迟:```c//在摄像头驱动的探测函数中staticint camera_probe(struct usb_interface *intf, conststruct usb_device_id *id){//延迟5毫秒(根据实际情况调整)msleep(5);// ...正常初始化} ```但这种方法不优雅,而且延迟时间难以确定。###验证方法1.查看内核日志:```bashadb shelldmesg |grep -E "usb-audio|uvcvideo"```观察哪个驱动的初始化日志先出现。2.查看设备节点创建顺序:```bashadb shellls -l /dev```查看音频设备(如/dev/snd/pcmC0D0c)视频设备(如/dev/video0)的创建时间。 ###注意事项-调整驱动顺序可能影响系统稳定性,需谨慎。-不同内核版本硬件平台可能有差异。由于用户的问题背景是RK3588Android11,建议优先尝试方法一(模块加载顺序)或方法二(内核链接顺序)。如果这些方法无效,可能需要更深入地分析USB核心的初始化过程,或者考虑在框架层调整(如之前的回答中提到的延迟处理)。引用:[^1]:关于驱动初始化顺序,可参考Linux内核文档:`Documentation/driver-model/design-patterns.txt` `Documentation/kernel-hacking/hacking.rst`。</think>在 Android 系统驱动加载阶段调整摄像头麦克风的加载顺序,需要深入内核硬件抽象层进行修改。以下是系统级的解决方案: ### 一、内核驱动加载顺序调整 1. **修改设备初始化顺序** 在内核源码中编辑 `init/main.c`,调整设备初始化序列: ```c static int __init customize_initcall_order(void) { // 优先初始化音频子系统(麦克风) subsys_initcall(snd_init); // 延迟初始化视频子系统(摄像头) device_initcall(v4l2_init); return 0; } core_initcall(customize_initcall_order); ``` 通过调整 `subsys_initcall` `device_initcall` 的调用顺序控制加载优先级[^1]。 2. **设备树(DTS)硬件节点排序** 在设备树文件中调整节点声明顺序: ```dts / { // 优先声明音频节点 sound: sound { compatible = "audio-device"; status = "okay"; }; // 后置声明摄像头节点 camera: camera { compatible = "video-device"; status = "okay"; }; }; ``` 设备树节点顺序直接影响驱动探测(probe)顺序[^1]。 ### 二、驱动层延迟机制 在摄像头驱动中添加延迟初始化: ```c // drivers/media/v4l2-core/v4l2-device.c static int __init v4l2_init(void) { msleep(500); // 延迟500ms确保音频驱动加载 pr_info("Delayed camera driver init\n"); return platform_driver_register(&v4l2_driver); } module_init(v4l2_init); ``` ### 三、Android HAL层控制 1. **修改硬件服务启动顺序** 在 `init.rc` 中调整服务启动顺序: ```rc # 先启动音频服务 start audioserver on property:audioserver.ready=1 # 再启动摄像头服务 start cameraserver ``` 2. **HAL 层依赖注入** 在相机 HAL 中显式检查音频服务状态: ```c // hardware/interfaces/camera/provider/2.4/default/CameraProvider.cpp status_t CameraProvider::initialize() { // 等待音频服务就绪 while(!property_get_bool("audio.ready", false)) { usleep(100000); // 100ms轮询 } return initializeImpl(); } ``` ### 四、验证方法 1. **查看内核加载顺序**: ```bash adb shell dmesg | grep -E "snd_init|v4l2_init" # 期望输出: # <6>[ 0.650000] snd_init: audio driver loaded # <6>[ 1.150000] v4l2_init: camera driver loaded ``` 2. **检查服务状态**: ```bash adb shell ps -A | grep -E "audioserver|cameraserver" # 期望输出: # system 1234 1 audioserver # system 1256 1 cameraserver ``` ### 五、动态优先级调整(运行时) 通过 sysfs 动态调整设备状态: ```bash # 暂停摄像头设备 echo suspend > /sys/bus/usb/devices/1-1.2/power/control # 优先使用麦克风 arecord -D plughw:0,0 test.wav # 恢复摄像头 echo auto > /sys/bus/usb/devices/1-1.2/power/control ``` > **关键注意事项**: > 1. 内核初始化顺序由 `initcall` 级别决定: > `core_initcall > subsys_initcall > device_initcall` > 2. USB 设备枚举顺序还受物理端口位置影响 > 3. Android 10+ 强制使用 Treble 架构,HAL 修改需兼容 VINTF[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值