添加驱动
在 linux-esp32-s31 源码树中添加外设驱动,使用与设备相符的 Linux 子系统,例如 I2C、SPI、ALSA、IIO、PWM、Counter、SocketCAN 或其他标准框架。集成驱动时,一并维护硬件描述、内核构建选项和启用设备的覆盖层。
1. 参考完整的集成示例
现有的 I2C0 支持展示了各部分如何配合。下表中的路径均相对于 linux-esp32-s31。
集成部分 |
I2C0 示例 |
|---|---|
驱动与设备匹配 |
|
绑定 |
|
基础硬件节点 |
|
启用覆盖层 |
|
内核构建 |
|
覆盖层构建 |
|
添加新外设时,先添加或复用相应绑定,在基础设备树中描述实际资源,并为可选硬件提供覆盖层。按照添加覆盖层说明引脚选择和资源占用声明。设备实际使用 DMA、稳压器或电源域时,再描述相应依赖。
2. 获取资源并注册到子系统
I2C 示例的 probe 先映射寄存器资源,获取并启用时钟,注册托管的时钟关闭动作,获取可选复位,然后初始化总线时序。随后,它请求 IRQ 并注册 I2C 适配器。资源提供方返回的错误通过 dev_err_probe() 传递;提供方返回 -EPROBE_DEFER 时,该错误会得到保留。
Probe 与清理动作注册。
在适合资源生命周期的地方使用托管辅助函数,并传递资源获取时的实际错误。共享硬件和执行上下文的规则见时钟、复位与电源、中断与 SMP以及 DMA 与缓存。
设计错误处理、驱动移除和设备挂起路径时,应考虑正在进行的传输。先停止接收新任务,等待硬件和回调停止,再释放资源。如果设备需要保存或恢复状态,应添加挂起和恢复操作。托管分配本身并未规定如何停止活动传输;使用 DMA 时,应遵守 DMA 指南中的终止和同步规则。
3. 构建驱动与覆盖层
添加驱动的 Kconfig 依赖和对象文件规则,在 arch/riscv/configs/esp32s31_defconfig 及主项目 configs/kernel/ 配置片段中启用驱动,并在 DTS 目录的 Makefile 中注册新的覆盖层目标。持久改动应保存在这些输入中,不应只修改生成的 out/linux/.config。
主项目的 Linux 构建目标。
构建启用 CONFIG_TRIM_UNUSED_KSYMS=y;新增模块必须与内核一起构建,才能保留其需要的导出。无线构建从外部载荷的未定义符号生成 out/generated/radio-kernel-symbols.txt,并通过 CONFIG_UNUSED_KSYMS_WHITELIST 传入内核;不要手工编辑该生成文件。其他树外使用者需要各自的导出保留集成。选为 m 的驱动还需显式添加打包和安装步骤,主项目不会自动安装所有 .ko。
在主项目中构建并验证匹配的内核、rootfs/模块及无线 XIP 载荷,再烧录完整组件集:
make image
make flash-existing-all PORT=/dev/ttyUSB0
根文件系统的 post-build 步骤将构建好的覆盖层安装到 /usr/lib/s31-overlays。前置准备及持久化数据注意事项见构建配置和烧录与首次启动。
开发板重启后,按照添加覆盖层中的流程启用覆盖层。
4. 验证行为
对于现有的 I2C/SPI 示例,以下主机测试会提取并测试 I2C 命令和长传输逻辑,以及 SPI 目标设备缓冲区的复制逻辑:
python -m unittest tools.tests.test_s31_feature_contracts.DriverContracts.test_driver_wire_contracts -v
测试框架将选定的源码函数与模拟输入一起编译。为新驱动添加测试时,可优先检查能够脱离硬件运行的解析、传输构造和错误处理逻辑。
在开发板上检查覆盖层应用结果和 probe 输出,通过子系统的用户空间 API 操作设备,并使用已知对端或仪器核对数据。测试无效设置、超时恢复、重复传输,以及使用方关闭设备后的驱动移除。如果驱动支持挂起和恢复,应结合预期唤醒源,分别在传输进行中或刚完成时测试该路径。记录结果时,一并记录接线、构建版本和执行命令。