`ioctl` 读写 GPIO:无效参数

Posted

技术标签:

【中文标题】`ioctl` 读写 GPIO:无效参数【英文标题】:`ioctl` to read and write GPIO: invalid argument 【发布时间】:2019-11-18 14:11:20 【问题描述】:

我正在模仿 Linux 源代码中的 gpio-hammer 示例。我正在使用 Raspberry Pi 3B+ 并希望 LED 闪烁。

这是我的工作:

#include <linux/gpio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>

int main(int argc, const char **argv) 
    int fd, ret;
    struct gpiohandle_request req;
    struct gpiohandle_data data;

    char *gpio_dev_name = "/dev/gpiochip0";
    unsigned int gpio_line = 8;

    memset(&data.values, 0, sizeof(data.values));

    // open device
    fd = open(gpio_dev_name, 0);
    if (fd == -1) 
    fprintf(stderr, "Failed to open %s, %s\n",
                gpio_dev_name, strerror(errno));
    

    // request gpio output
    req.lineoffsets[0] = gpio_line;
    req.flags = GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW;
    strcpy(req.consumer_label, "blink");
    req.lines = 1;
    memcpy(req.default_values, &data, sizeof(req.default_values));

    ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
    if (ret == -1) 
        fprintf(stderr, "Failed to issue %s (%d), %s\n",
                "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));
    

    // blink
    while (1) 
        // read data
        ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
        if (ret == -1) 
            ret = -errno;
            fprintf(stderr, "Failed to issue %s (%d), %s\n", 
                    "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret, strerror(errno));
            exit(ret);
        

        // flip digits
        data.values[0] = !data.values[0];

        // set data
        ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
        if (ret == -1) 
            ret = -errno;
            fprintf(stderr, "Failed to issue %s (%d), %s\n", 
                    "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret, strerror(errno));
            exit(ret);
        

        // delay
        sleep(1);
    

我可以在 RPi 上编译 gpio-hammer 示例并使用./gpio-hammer -n gpiochip0 -o 8 运行它。连接到 gpiochip0 line8 的是一个 LED,它会闪烁。

但是我的程序不起作用。它失败了

Failed to issue GPIOHANDLE_GET_LINE_VALUES_IOCTL (-22), Invalid argument

我查看了gpiolib 的实现。如果 ioctl cmd 不是 GPIOHANDLE_GET_LINE_VALUES_IOCTL 也不是 GPIOHANDLE_SET_LINE_VALUES_IOCTL,则 gpio 行句柄的 ioctl 返回 EINVAL (22)。但事实并非如此。怎么了?

【问题讨论】:

首先,open()调用的错误检查在哪里?其次,您在哪个迭代中遇到问题?我建议限制迭代次数并使用 for-loop 打印计数以进行调试。 另外,使用gpio-hammer 的输出更新帖子。 【参考方案1】:

linux/gpio.h 中,struct gpiohandle_request 的description 表示:

/*
 * ...
 * @fd: if successful this field will contain a valid anonymous file handle
 * after a GPIO_GET_LINEHANDLE_IOCTL operation, zero or negative value
 * means error
 */
struct gpiohandle_request 
    __u32 lineoffsets[GPIOHANDLES_MAX];
    __u32 flags;
    __u8 default_values[GPIOHANDLES_MAX];
    char consumer_label[32];
    __u32 lines;
    int fd;
;

使用GPIO_GET_LINEHANDLE_IOCTL时,GPIO芯片设备的文件句柄通过ioctl()的第一个参数传入,另一个文件句柄将被送回gpiohandle_request::fd,如果操作成功。这个新的fd 应该用在ioctlGPIO_GET_LINE_VALUES_IOCTLGPIO_SET_LINE_VALUES_IOCTL 中。

所以代码应该是

ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1) 
    fprintf(stderr, "Failed to issue %s (%d), %s\n",
            "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));

else 
    if (close(fd) == -1) 
        fprintf(stderr, "Failed to close GPIO char dev.\n");
    
    fd = req.fd;

【讨论】:

以上是关于`ioctl` 读写 GPIO:无效参数的主要内容,如果未能解决你的问题,请参考以下文章

ioctl“无法发送 spi 消息:无效参数”Beaglebone Black

调用 IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER 时句柄无效

ValueError:发送的通道在 Raspberry Pi 上无效 - 使用 Python 控制 GPIO Pin 2 (BOARD) 会导致错误

关于 Qt在海思平台使用脚本和文件控制GPIO口写入高低无效 的解决方法

关于 Qt在海思平台使用脚本和文件控制GPIO口写入高低无效 的解决方法

gpio IOCTL控制