Alexander Zhang
Alexander Zhang

Reputation: 207

`ioctl` to read and write GPIO: invalid argument

I'm imitating the gpio-hammer example in Linux source code. I'm using Raspberry Pi 3B+ and want an LED to blink.

Here's what I do:

#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);
    }
}

I can compile the gpio-hammer example on RPi and run it with ./gpio-hammer -n gpiochip0 -o 8. Attached to gpiochip0 line8 is an LED and it blinks.

But my program does not work. It fails with

Failed to issue GPIOHANDLE_GET_LINE_VALUES_IOCTL (-22), Invalid argument

I looked into the implement of gpiolib. The ioctl of gpio line handle returns EINVAL (22) if ioctl cmd is not GPIOHANDLE_GET_LINE_VALUES_IOCTL nor GPIOHANDLE_SET_LINE_VALUES_IOCTL. But that's not the case. What's going wrong?

Upvotes: 3

Views: 6305

Answers (1)

Alexander Zhang
Alexander Zhang

Reputation: 207

In linux/gpio.h, the description of struct gpiohandle_request says:

/*
 * ...
 * @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;
};

When use GPIO_GET_LINEHANDLE_IOCTL, the file handle of GPIO chip device is passed through the first argument of ioctl(), and another file handle will be sent back in gpiohandle_request::fd, if the operation successes. This new fd should be used in ioctl of GPIO_GET_LINE_VALUES_IOCTL or GPIO_SET_LINE_VALUES_IOCTL.

So the code should be

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;
}

Upvotes: 1

Related Questions