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 30 int 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 120 exit_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 127 void 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 145 int 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