You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核空间如何正确使用新的gpiod_export()函数导出GPIO?

内核v5.10中如何使用新的GPIO描述符接口导出GPIO?

在Linux内核v4.14中,我们通过以下代码从内核驱动导出GPIO,之后可在用户空间通过cat /sys/kernel/debug/gpio查看所有导出的GPIO:

static struct gpio ct_gen2_gpios[] __initdata = {
    {22, GPIOF_OUT_INIT_LOW, "gpo1" },
    {23, GPIOF_OUT_INIT_LOW, "gpo0" },
    // ... 其他GPIO定义
};

gpio_request_array(my_gpios, ARRAY_SIZE(my_gpios));
for (i = 0; i < ARRAY_SIZE(my_gpios); i++) {
    gpio_export(ct_gen2_gpios[i].gpio, 1);  // 升级内核后此方法失效
}

升级到内核v5.10后,传统gpio.h被弃用,上述代码无法再导出GPIO。我们看到新的接口:

int gpiod_export(struct gpio_desc *desc, bool direction_may_change);

struct gpio_desc {
    struct gpio_device  *gdev;
    unsigned long       flags;

    /* Connection label */
    const char      *label;
    /* Name of the GPIO */
    const char      *name;
    // ... 其他字段
};

但找不到获取或创建struct gpio_desc(特别是struct gpio_device *gdev字段)的示例,请问如何使用新的描述符接口正确导出GPIO?


解决方案

你需要替换传统的gpio_request_array和gpio_export为基于GPIO描述符的接口,核心步骤是先获取对应GPIO的struct gpio_desc实例,再配置属性后导出。以下是适配v5.10内核的完整实现:

1. 定义GPIO信息

不再使用旧的struct gpio数组,改用struct gpiod_lookup_table统一管理GPIO映射关系:

#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>

// 定义GPIO映射:[gpio控制器名, GPIO编号, 别名, 电平属性]
static struct gpiod_lookup_table ct_gen2_gpio_table = {
    .dev_id = "my_driver", // 你的驱动设备标识
    .table = {
        GPIO_LOOKUP("gpiochip0", 22, "gpo1", GPIO_ACTIVE_HIGH),
        GPIO_LOOKUP("gpiochip0", 23, "gpo0", GPIO_ACTIVE_HIGH),
        // ... 其他GPIO定义
        GPIO_LOOKUP_END,
    },
};

注:gpiochip0是系统中GPIO控制器的名称,可通过cat /sys/class/gpio/查看实际存在的控制器。

2. 请求并配置GPIO描述符

批量注册映射表后,逐个获取GPIO描述符并设置初始状态:

struct gpio_desc *descs[2]; // 对应上面定义的2个GPIO,可根据实际数量调整
int i, ret;

// 注册GPIO映射表
gpiod_add_lookup_table(&ct_gen2_gpio_table);

// 逐个获取GPIO描述符并配置初始输出低电平
for (i = 0; i < ARRAY_SIZE(descs); i++) {
    descs[i] = gpiod_get(dev, ct_gen2_gpio_table.table[i].con_id, GPIOD_OUT_LOW);
    if (IS_ERR(descs[i])) {
        ret = PTR_ERR(descs[i]);
        goto err_cleanup;
    }
    // 设置GPIO标签,会在/sys/kernel/debug/gpio中显示
    gpiod_set_label(descs[i], ct_gen2_gpio_table.table[i].con_id);
}

3. 导出GPIO到用户空间

使用gpiod_export完成导出,第二个参数设为1表示允许用户空间修改GPIO方向:

for (i = 0; i < ARRAY_SIZE(descs); i++) {
    ret = gpiod_export(descs[i], 1);
    if (ret) {
        dev_err(dev, "Failed to export GPIO %s\n", ct_gen2_gpio_table.table[i].con_id);
        goto err_export_cleanup;
    }
    // 可选:在驱动目录下创建GPIO的符号链接,方便用户空间访问
    gpiod_export_link(dev, ct_gen2_gpio_table.table[i].con_id, descs[i]);
}

4. 驱动卸载时清理资源

err_export_cleanup:
for (i = 0; i < ARRAY_SIZE(descs); i++) {
    if (!IS_ERR_OR_NULL(descs[i])) {
        gpiod_unexport(descs[i]);
        gpiod_put(descs[i]);
    }
}
err_cleanup:
gpiod_remove_lookup_table(&ct_gen2_gpio_table);

关键说明

  • gpiod_get是获取GPIO描述符的核心接口,第三个参数GPIOD_OUT_LOW对应旧接口的GPIOF_OUT_INIT_LOW,用于指定初始状态。
  • 导出后,用户空间可通过/sys/class/gpio/gpioX/节点操作GPIO,同时/sys/kernel/debug/gpio中会显示该GPIO的信息。

内容的提问来源于stack exchange,提问作者Glen G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:58:20