linux/tools/gpio/gpio-event-mon.c
<<
>>
Prefs
   1/*
   2 * gpio-event-mon - monitor GPIO line events from userspace
   3 *
   4 * Copyright (C) 2016 Linus Walleij
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published by
   8 * the Free Software Foundation.
   9 *
  10 * Usage:
  11 *      gpio-event-mon -n <device-name> -o <offset>
  12 */
  13
  14#include <unistd.h>
  15#include <stdlib.h>
  16#include <stdbool.h>
  17#include <stdio.h>
  18#include <dirent.h>
  19#include <errno.h>
  20#include <string.h>
  21#include <poll.h>
  22#include <fcntl.h>
  23#include <getopt.h>
  24#include <inttypes.h>
  25#include <sys/ioctl.h>
  26#include <linux/gpio.h>
  27
  28int monitor_device(const char *device_name,
  29                   unsigned int line,
  30                   u_int32_t handleflags,
  31                   u_int32_t eventflags,
  32                   unsigned int loops)
  33{
  34        struct gpioevent_request req;
  35        struct gpiohandle_data data;
  36        char *chrdev_name;
  37        int fd;
  38        int ret;
  39        int i = 0;
  40
  41        ret = asprintf(&chrdev_name, "/dev/%s", device_name);
  42        if (ret < 0)
  43                return -ENOMEM;
  44
  45        fd = open(chrdev_name, 0);
  46        if (fd == -1) {
  47                ret = -errno;
  48                fprintf(stderr, "Failed to open %s\n", chrdev_name);
  49                goto exit_close_error;
  50        }
  51
  52        req.lineoffset = line;
  53        req.handleflags = handleflags;
  54        req.eventflags = eventflags;
  55        strcpy(req.consumer_label, "gpio-event-mon");
  56
  57        ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
  58        if (ret == -1) {
  59                ret = -errno;
  60                fprintf(stderr, "Failed to issue GET EVENT "
  61                        "IOCTL (%d)\n",
  62                        ret);
  63                goto exit_close_error;
  64        }
  65
  66        /* Read initial states */
  67        ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
  68        if (ret == -1) {
  69                ret = -errno;
  70                fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
  71                        "VALUES IOCTL (%d)\n",
  72                        ret);
  73                goto exit_close_error;
  74        }
  75
  76        fprintf(stdout, "Monitoring line %d on %s\n", line, device_name);
  77        fprintf(stdout, "Initial line value: %d\n", data.values[0]);
  78
  79        while (1) {
  80                struct gpioevent_data event;
  81
  82                ret = read(req.fd, &event, sizeof(event));
  83                if (ret == -1) {
  84                        if (errno == -EAGAIN) {
  85                                fprintf(stderr, "nothing available\n");
  86                                continue;
  87                        } else {
  88                                ret = -errno;
  89                                fprintf(stderr, "Failed to read event (%d)\n",
  90                                        ret);
  91                                break;
  92                        }
  93                }
  94
  95                if (ret != sizeof(event)) {
  96                        fprintf(stderr, "Reading event failed\n");
  97                        ret = -EIO;
  98                        break;
  99                }
 100                fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp);
 101                switch (event.id) {
 102                case GPIOEVENT_EVENT_RISING_EDGE:
 103                        fprintf(stdout, "rising edge");
 104                        break;
 105                case GPIOEVENT_EVENT_FALLING_EDGE:
 106                        fprintf(stdout, "falling edge");
 107                        break;
 108                default:
 109                        fprintf(stdout, "unknown event");
 110                }
 111                fprintf(stdout, "\n");
 112
 113                i++;
 114                if (i == loops)
 115                        break;
 116        }
 117
 118exit_close_error:
 119        if (close(fd) == -1)
 120                perror("Failed to close GPIO character device file");
 121        free(chrdev_name);
 122        return ret;
 123}
 124
 125void print_usage(void)
 126{
 127        fprintf(stderr, "Usage: gpio-event-mon [options]...\n"
 128                "Listen to events on GPIO lines, 0->1 1->0\n"
 129                "  -n <name>  Listen on GPIOs on a named device (must be stated)\n"
 130                "  -o <n>     Offset to monitor\n"
 131                "  -d         Set line as open drain\n"
 132                "  -s         Set line as open source\n"
 133                "  -r         Listen for rising edges\n"
 134                "  -f         Listen for falling edges\n"
 135                " [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
 136                "  -?         This helptext\n"
 137                "\n"
 138                "Example:\n"
 139                "gpio-event-mon -n gpiochip0 -o 4 -r -f\n"
 140        );
 141}
 142
 143int main(int argc, char **argv)
 144{
 145        const char *device_name = NULL;
 146        unsigned int line = -1;
 147        unsigned int loops = 0;
 148        u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT;
 149        u_int32_t eventflags = 0;
 150        int c;
 151
 152        while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) {
 153                switch (c) {
 154                case 'c':
 155                        loops = strtoul(optarg, NULL, 10);
 156                        break;
 157                case 'n':
 158                        device_name = optarg;
 159                        break;
 160                case 'o':
 161                        line = strtoul(optarg, NULL, 10);
 162                        break;
 163                case 'd':
 164                        handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
 165                        break;
 166                case 's':
 167                        handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
 168                        break;
 169                case 'r':
 170                        eventflags |= GPIOEVENT_REQUEST_RISING_EDGE;
 171                        break;
 172                case 'f':
 173                        eventflags |= GPIOEVENT_REQUEST_FALLING_EDGE;
 174                        break;
 175                case '?':
 176                        print_usage();
 177                        return -1;
 178                }
 179        }
 180
 181        if (!device_name || line == -1) {
 182                print_usage();
 183                return -1;
 184        }
 185        if (!eventflags) {
 186                printf("No flags specified, listening on both rising and "
 187                       "falling edges\n");
 188                eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
 189        }
 190        return monitor_device(device_name, line, handleflags,
 191                              eventflags, loops);
 192}
 193