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