用户空间的 GPIO Sysfs 接口¶
警告
此 API 已被 GPIO 字符设备用户空间 API 取代,并且 ABI 文档已移至 Documentation/ABI/obsolete/sysfs-gpio。
新的开发应使用 GPIO 字符设备用户空间 API,并鼓励现有开发尽快迁移,因为此 API 将在未来移除。
此接口将在迁移期间继续维护,但新功能将仅添加到新的 API 中。
过时的 sysfs ABI¶
使用 “gpiolib” 实现者框架的平台可以选择配置一个 sysfs 用户界面来控制 GPIO。这与 debugfs 接口不同,因为它提供了对 GPIO 方向和值的控制,而不仅仅是显示 GPIO 状态摘要。此外,它可以在没有调试支持的生产系统上存在。
如果有系统的适当硬件文档,用户空间可以知道例如 GPIO #23 控制用于保护闪存存储器中引导加载程序段的写保护线。系统升级过程可能需要临时删除该保护,首先导入一个 GPIO,然后更改其输出状态,然后在重新启用写保护之前更新代码。在正常使用中,GPIO #23 永远不会被触及,内核也无需了解它。
再次取决于适当的硬件文档,在某些系统上,用户空间 GPIO 可用于确定标准内核不知道的系统配置数据。对于某些任务,简单的用户空间 GPIO 驱动程序可能就是系统真正需要的全部。
Sysfs 中的路径¶
/sys/class/gpio 中有三种类型的条目
用于获取用户空间对 GPIO 控制的控制接口;
GPIO 本身;以及
GPIO 控制器(“gpio_chip” 实例)。
除了包括 “device” 符号链接的标准文件之外。
控制接口是只写的
/sys/class/gpio/
- “export” ...
用户空间可以通过将其编号写入此文件,来请求内核将 GPIO 的控制权导出到用户空间。
示例:“echo 19 > export” 将为 GPIO #19 创建一个 “gpio19” 节点,如果该节点不是由内核代码请求的。
- “unexport” ...
撤消导出到用户空间的效果。
示例:“echo 19 > unexport” 将删除使用 “export” 文件导出的 “gpio19” 节点。
GPIO 信号具有类似 /sys/class/gpio/gpio42/ (对于 GPIO #42)的路径,并具有以下读/写属性
/sys/class/gpio/gpioN/
- “direction” ...
读取为 “in” 或 “out”。通常可以写入此值。写入 “out” 默认将该值初始化为低电平。为确保无故障运行,可以将值 “low” 和 “high” 写入以将 GPIO 配置为具有该初始值的输出。
请注意,如果内核不支持更改 GPIO 的方向,或者它是由未明确允许用户空间重新配置此 GPIO 方向的内核代码导出的,则此属性将不存在。
- “value” ...
读取为 0(非活动)或 1(活动)。如果将 GPIO 配置为输出,则可以写入此值;任何非零值都被视为活动状态。
如果引脚可以配置为中断生成中断,并且已配置为生成中断(请参阅 “edge” 的描述),则可以在该文件上使用 poll(2) ,并且每当触发中断时,poll(2) 都会返回。如果使用 poll(2) ,请设置事件 POLLPRI 和 POLLERR。如果使用 select(2) ,请在 exceptfds 中设置文件描述符。 poll(2) 返回后,请使用 pread(2) 读取偏移量为零的值。或者,可以使用 lseek(2) 将文件定位到 sysfs 文件的开头,然后读取新值,或者关闭文件并重新打开以读取该值。
- “edge” ...
读取为 “none”、“rising”、“falling” 或 “both”。写入这些字符串以选择将使 “value” 文件上的 poll(2) 返回的信号边沿。
仅当引脚可以配置为中断生成输入引脚时,此文件才存在。
- “active_low” ...
读取为 0(假)或 1(真)。写入任何非零值以反转读取和写入的值属性。现有和后续通过 “rising” 和 “falling” 边沿的 edge 属性进行配置的 poll(2) 支持将遵循此设置。
GPIO 控制器具有类似 /sys/class/gpio/gpiochip42/ (对于实现从 #42 开始的 GPIO 的控制器)的路径,并具有以下只读属性
/sys/class/gpio/gpiochipN/
- “base” ...
与 N 相同,此芯片管理的第一个 GPIO
- “label” ...
为诊断提供(并非总是唯一)
- “ngpio” ...
此管理多少个 GPIO (N 到 N + ngpio - 1)
在大多数情况下,电路板文档应涵盖哪些 GPIO 用于什么目的。但是,这些数字并不总是稳定的;子卡上的 GPIO 可能因使用的基板或堆栈中的其他卡而异。在这种情况下,您可能需要使用 gpiochip 节点(可能与原理图结合使用)来确定用于给定信号的正确 GPIO 编号。
从内核代码导出¶
内核代码可以显式管理已使用 gpio_request() 请求的 GPIO 的导出
/* export the GPIO to userspace */
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
/* reverse gpiod_export() */
void gpiod_unexport(struct gpio_desc *desc);
/* create a sysfs link to an exported GPIO node */
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
内核驱动程序请求 GPIO 后,只能通过 gpiod_export()
在 sysfs 接口中使其可用。驱动程序可以控制信号方向是否可以更改。这有助于驱动程序防止用户空间代码意外地损坏重要的系统状态。
这种显式导出可以帮助调试(通过使某些类型的实验更容易),或者可以提供一个始终存在的接口,适合作为板级支持包的一部分进行记录。
导出 GPIO 后,gpiod_export_link()
允许从 sysfs 中的其他位置创建到 GPIO sysfs 节点的符号链接。驱动程序可以使用它在 sysfs 中他们自己的设备下提供带有描述性名称的接口。