60 秒回答模板

驱动里用 GPIO 通常优先走 descriptor API,比如 devm_gpiod_get 或 devm_gpiod_get_optional,从设备树的 xxx-gpios 属性拿到描述符,再用 gpiod_direction_input/output、gpiod_set_value_cansleep、gpiod_get_value 等操作。申请中断一般先通过 platform_get_irq、gpiod_to_irq 或 fwnode 接口拿 IRQ 号,再用 devm_request_irq 或 devm_request_threaded_irq 注册处理函数,必要时配置触发边沿和 threaded handler。不能直接操作寄存器的原因是 Linux 内核要统一管理资源所有权、pinctrl 复用、GPIO controller、irqchip、时钟电源、并发访问和跨 SoC 可移植性。直接写寄存器可能和其他驱动抢引脚、破坏电源管理、绕过中断层级和锁,还会让同一驱动无法适配不同板子。

考点 GPIO 申请链
难度 真实面经题
回答目标 证明自己熟悉 Linux 驱动资源申请接口,并理解框架管理资源的必要性。

深入解析

01

GPIO 用描述符表达资源

descriptor API 把板级编号、极性、控制器差异隐藏起来。驱动只关心这是 reset、enable 或 interrupt 引脚,不需要硬编码 SoC GPIO 编号。

02

IRQ 通过中断子系统注册

中断号可能来自设备树 interrupts,也可能由 GPIO 转换而来。request_threaded_irq 可以把快速顶半部和可睡眠的线程化处理分开,适合大多数外设中断。

03

pinctrl 和 GPIO 不是一回事

引脚要先复用成 GPIO 或外设功能,再由 GPIO 子系统控制电平。直接写 GPIO 寄存器可能忽略引脚复用、电气配置和低功耗状态。

04

资源申请防止冲突

内核通过 request 模型知道哪个驱动拥有哪个引脚和中断,能处理卸载、错误清理、共享限制和调试信息。直接写寄存器会破坏这个可见性。

易错点

  • 在驱动里硬编码 GPIO 寄存器地址和 bit,绕过内核框架。
  • 不申请 GPIO 就直接使用,和其他驱动或 pinctrl 状态冲突。
  • 中断处理里做可能睡眠的操作,却没有使用线程化中断。
  • 忽略 GPIO 极性和设备树中的 active low 描述。

面试官追问

gpiod_set_value 和 gpiod_set_value_cansleep 怎么选?

如果 GPIO 控制器操作可能睡眠,例如挂在慢速总线上,就要用 cansleep 版本,并且不能在硬中断上下文调用。

什么时候用 threaded IRQ?

中断处理需要访问慢速总线、睡眠锁或较长处理时,用 threaded IRQ 把耗时工作放到线程上下文,顶半部只做快速确认。

如果面试官让你现场排查,你会先看哪些证据?

我会先看 dmesg 和返回码,再查 /sys 下设备、驱动和资源状态,必要时加 trace/ftrace 或最小日志,先证明问题出在设备生成、匹配、资源获取、回调路径还是用户态交互。