Linux GPIO subsystem development
 help / color / mirror / Atom feed
From: Benjamin Valentin <benjamin.valentin@beuth-hochschule.de>
To: linux-gpio@vger.kernel.org
Subject: GPIO fd won't generate signal
Date: Tue, 21 Apr 2020 23:09:45 +0200	[thread overview]
Message-ID: <20200421230945.11c862e2@rechenknecht2k11> (raw)

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

                 reply	other threads:[~2020-04-21 21:16 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200421230945.11c862e2@rechenknecht2k11 \
    --to=benjamin.valentin@beuth-hochschule.de \
    --cc=linux-gpio@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox