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