最近在调试wifi和音频驱动,使用initramfs把根文件系统编译进内核,音频驱动选择对oss的支持,驱动注册成功后会生成 /dev/dsp 设备节点。
但是测试过程中并没有生成/dev/dsp设备节点,折腾后发现音频驱动和设备必须在根文件系统启动前注册好,否则/dev/dsp设备节点不会生成。
解决办法:
- 修改initramfs根文件在Linux内核启动时的加载时机。
修改内核源码 initramfs.c 文件,把rootfs_initcall(populate_rootfs) 修改成 late_initcall_sync(populate_rootfs) 或 late_initcall(populate_rootfs) ,这样延迟initramfs的加载时机,让音频驱动注册完后在启动根文件系统。
修改后测试,可以顺利生成/dev/dsp设备节点。 - 更换根文件系统格式,只是调试是没initramfs方便,需要存储介质放置根文件系统,比如nand使用 ubifs 格式,U盘或SD卡使用 ext4 格式。查看ubifs源码发现,ubifs的加载时机使用late_initcall。使用ubifs测试时,/dev/dsp设备节点可以顺利生成。
根文件系统的启动时机跟wifi的 firmware 文件加载也有点关系,firmware文件放在根文件系统的 /lib/firmware 目录下的。测试时发现使用initramfs格式的根文件系统(编译进内核)以顺利加载wifi模块的firmware文件,ubifs格式的根文件系统则加载firmware失败,提示找不到文件。
可以判断是因为,两种文件系统的加载时机不一样导致的,initramfs在wifi模块注册前已经把根文件系统准备好,驱动注册时可以访问到根文件系统的/lib/firmware目录。而ubifs在wifi模块注册后才加载根文件系统,导致wifi驱动注册时找不到/lib/firmware目录。
知道原因就好解决问题:
- 可以把wifi驱动编译成 .ko 模块,放到板卡的根文件系统下,在根文件系统准备好后再通过 insmod 或 modprobe 命令加载wifi驱动,firmware文件无意外也是可以顺利加载。
- 修改根文件系统的加载时机,比如rootfs_initcall,但这个不建议,可能会破坏内核的兼容性,只建议调试时使用。
- 修改wifi驱动的加载时机,这个可以尝试测试下。