GPIO fd won't generate signal

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

AFAIU a GPIO fd will generate a POLLPRI event when an interrupt occurs
on the GPIO.
I can wait for this event using poll() just fine.

fcntl(fd, F_SETOWN, getpid()) should then turn such an event into a
signal that can be caught by the signal handler of the process.

This however does not work. Is this an omission by the GPIO API or am I
understanding the API wrong here?

Attached you find a little program to reproduce this:

When running on a raspberry pi, bridge GPIO20 and GPIO26.
The program will periodically toggle GPIO26, this should generate an
interrupt on GPIO20.
I can poll() GPIO20 but no signal is generated.

#include <fcntl.h>
#include <linux/gpio.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define PIN_IN  (20)
#define PIN_OUT (26)

static int fd_in; /* to be read in the signal handler */

/* configure input pin */
static int setup_pin_int(int fd, int pin, int mode, int flank) {
    struct gpioevent_request req = {
        .lineoffset  = pin,
        .handleflags = mode,
        .eventflags  = flank
    };

    int res = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);

    if (res < 0) {
        return res;
    }

    return req.fd;
}

/* configure output pin */
static int setup_pin_out(int fd, int pin, int mode) {
    struct gpiohandle_request req = {
        .lineoffsets[0] = pin,
        .flags          = mode,
        .lines          = 1
    };

    int res = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);

    if (res < 0) {
        return res;
    }

    return req.fd;
}

static void pin_set(int fd, uint8_t val) {
    ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &val);
}

/* print which edge triggered the event */
static void sigurg_handler(void) {
    struct gpioevent_data event;
    read(fd_in, &event, sizeof(event));

    if (event.id == GPIOEVENT_EVENT_RISING_EDGE) {
        puts("rising");
    }
    if (event.id == GPIOEVENT_EVENT_FALLING_EDGE) {
        puts("falling");
    }
}

static void signal_handler(int signal) {
    printf("got signal: %x\n", signal);

    if (signal == SIGURG) {
        sigurg_handler();
    }
}

static void register_signal(int signal, void (*handler)(int)) {
    struct sigaction sa = {
        .sa_handler = handler
    };

    sigaction(signal, &sa, NULL);
}

/* calling poll() on the fd works as expected */
static void _do_poll(int fd) {

    struct pollfd pfd = {
        .fd = fd,
        .events = POLLIN | POLLPRI
    };

    if (poll(&pfd, 1, 1000) > 0) {
        sigurg_handler();
    }
}

int main(void) {

    int pins[2];

    int fd = open("/dev/gpiochip0", O_RDWR);
    pins[0] = setup_pin_int(fd, PIN_IN, GPIOHANDLE_REQUEST_INPUT,
    GPIOEVENT_REQUEST_BOTH_EDGES); pins[1] = setup_pin_out(fd, PIN_OUT,
    GPIOHANDLE_REQUEST_OUTPUT);

    fd_in = pins[0];

    /* register signal handler */
    register_signal(SIGIO, signal_handler);
    register_signal(SIGURG, signal_handler);

    /* make the fd generate signals */
    fcntl(fd_in, F_SETOWN, getpid());
    fcntl(fd_in, F_SETFL, O_NONBLOCK | O_ASYNC);

    /* toggle the output pin each second */
    int state;
    while (1) {
        state = !state;
        sleep(1);

        printf("set %d\n", state);
        pin_set(pins[1], state);

        /* poll() is working on the fd */
//        _do_poll(fd_in);
    }

    close(fd);

    return 0;
}

I can send signals to the process with kill -23 <pid> just fine and the
signal handler will be caught.
Just not when the GPIO event occurs.

Thank you!
Benjamin



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux