Linux 驱动把设备接入内核子系统,向用户空间提供稳定得多的接口。开发前先检查系统已有 LED、input、IIO、I²C、SPI 等子系统是否支持需求;绕过已有驱动直接翻引脚,会重复处理中断、电源管理和并发。

一次设备接入经过哪些环节

总线或固件描述提供设备信息,驱动通过匹配表找到适用设备,probe 获取时钟、电源、GPIO、中断和寄存器等资源,然后注册到相应子系统。资源尚未准备好时可能推迟探测,probe 失败必须返回错误并清理已申请资源。

设备树中的 compatible 应对应正式绑定,reg、interrupts、clocks 和 pinctrl 等属性遵守相关规范。不能给任意字符串起一个 compatible 名字,就期待系统自动知道硬件含义。资源的逻辑编号、物理引脚号和板上连接器编号也需要区分。

GPIO 与传感器接口

新应用若确实需要用户空间 GPIO 原型控制,使用 GPIO 字符设备与 libgpiod;旧 sysfs GPIO 导出接口不适合作为新设计起点。字符设备使用 gpiochip 与 line offset,请求后持有相应资源。active-low 表示逻辑有效状态与电平关系,不应在应用和驱动两层同时反转。

对传感器,IIO 子系统提供通道、比例、偏置、缓冲与触发等接口。一次读原始值还不够:要检查单位、scale、offset、通道类型和采样时刻。GPIO 位翻转无法替代适合该设备的硬件驱动。

在装有对应工具的 Linux 上,可先运行只读观察:

uname -a
cat /proc/interrupts
gpiodetect
gpioinfo

工具输出取决于内核配置、libgpiod 版本和硬件;不要把某台机器的 line offset 硬编码成所有设备通用的引脚。本文未在目标板执行这些命令,且不会要求接线后立即写未知引脚。

用户空间 I/O 的实际语义

read 可能短读,写也可能只提交一部分数据;非阻塞接口遇到暂时无数据通常返回对应错误,不能解释成永久断开。阻塞、超时和取消需要分别设计,事件循环应避免一条慢连接阻塞全部设备。

字符设备的用户 ABI 要明确数据布局、字节序、长度和版本;用户指针不能在内核里直接当可信指针访问。驱动与 DMA 交互还要使用平台提供的 DMA 映射接口,不能把普通虚拟地址当成设备可访问的总线地址。

本地可运行 流式网关项目 的 socketpair 分块实验,观察一次读取只得到半帧时解析器如何保留状态。它验证流式接口逻辑,不执行内核驱动或 GPIO。

调试一条完整路径

假设传感器没有读数:先核对供电和总线波形,再检查设备树是否启用正确总线、地址和引脚,查看驱动是否匹配、probe 是否报错,随后检查 /sys 与 /dev 暴露的接口、权限和业务配置。开启追踪时记录目标事件和采样负担,日志洪泛也可能改变时序。

练习:给“设备节点不存在”“节点存在但权限拒绝”“读数固定不变”“中断计数快速增长”分别提出两个可区分的原因和验证方法。迁移一个 GPIO 原型到既有 LED 或 input 驱动,说明应用可以减少哪些硬件细节。

面试自查:设备树与驱动哪个负责行为?字符设备文件与普通文件的区别是什么?为什么用户空间位翻转不适合精确定时?devm 资源管理解决什么,仍有哪些生命周期问题需要处理?

参考:Linux GPIO 字符设备 ABI、GPIO descriptor consumer 接口、Industrial I/O、Linux 设备模型。