GPIO sysfs 割り込みサンプルプログラム

#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>

#define GPIO_PATH "/sys/class/gpio/%s/%s"
#define GPIO_DEFAULT_NAME "gpio105"

#define USLEEP(usec)

int
main(int argc, const char **argv)
{
        int fds;
        int i;
        const char *gpio_name;
        int flag;
        static char buf[256];

        gpio_name = ((argc == 1)?GPIO_DEFAULT_NAME:argv[argc - 1]);

        if ( argc == 3 ) {
                // detect-usb-gpio gpio105 do-init
                sprintf(buf, GPIO_PATH, gpio_name, "/direction");

                fds = open(buf, O_RDWR);
                write(fds, "in", 2);
                close(fds);

                sprintf(buf, GPIO_PATH, gpio_name, "/edge");
                fds = open(buf, O_RDWR);

                if ( argv[1][1] == 'f' ) {
                        write(fds, "falling", 7);
                } else {
                        write(fds, "rising", 6);
                }
                close(fds);
        }

        char val;
        struct pollfd pfd;
        int rv;

        sprintf(buf, GPIO_PATH, gpio_name, "/value");
        fds = open(buf, O_RDWR);

          rv = read(fds, &val, 1);
        if ( rv != 1 ) {
                return 255;
        }

#if 0
        fprintf(stderr, "wait...");
#endif

        pfd.fd = fds;
        pfd.events = POLLPRI | POLLERR;
// ここで POLLIN を付け加えないこと。
// 付け加えると、read 可能なのですぐに poll が正常終了する
// これは Linux の Documentation/gpio.txt にあるとおり。
        pfd.revents = 0;
        poll(&pfd, 1, -1);

// 必要なら read する。
// すでに読んでいるので lseek する
        lseek(fds, 0, SEEK_SET);
        rv = read(fds, &val, 1);
        close(fds);

        if ( rv != 1 ) {
                return 254;
        }
#if 0
        printf("%c\n", val);
#endif

        return rv;
}

gpio の割り込みを sysfs から待つ方法。poll か select で待つことができる。poll で待つときは POLLPRI | POLLERR でまつ。ここがポイント。
POLLIN で待つと意図通りに割り込みを待てない。(ただ読むだけ)
Documentation/gpio.txt を参考にしてほしい。どうやら、カーネルのバージョンがあがったことで挙動が変わったとのこと。2.6.26 は POLLIN でもどうさするらしい。


通常は値を呼んでそれで割り込みを待つという事をやりたいはずだから、poll の前に一回、read することになると思う。read はなぜか、必須のようだ。read しないと poll がすぐに終了する。一度 read したら、その後は lseek で最初に巻き戻しておかないと(あるいは open し直す)値を再読み込みできない。