1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * gpio-watch - monitor unrequested lines for property changes using the 4 * character device 5 * 6 * Copyright (C) 2019 BayLibre SAS 7 * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 8 */ 9 10 #include <ctype.h> 11 #include <errno.h> 12 #include <fcntl.h> 13 #include <linux/gpio.h> 14 #include <poll.h> 15 #include <stdbool.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/ioctl.h> 20 #include <unistd.h> 21 22 int main(int argc, char **argv) 23 { 24 struct gpio_v2_line_info_changed chg; 25 struct gpio_v2_line_info req; 26 struct pollfd pfd; 27 int fd, i, j, ret; 28 char *event, *end; 29 ssize_t rd; 30 31 if (argc < 3) 32 goto err_usage; 33 34 fd = open(argv[1], O_RDWR | O_CLOEXEC); 35 if (fd < 0) { 36 perror("unable to open gpiochip"); 37 return EXIT_FAILURE; 38 } 39 40 for (i = 0, j = 2; i < argc - 2; i++, j++) { 41 memset(&req, 0, sizeof(req)); 42 43 req.offset = strtoul(argv[j], &end, 0); 44 if (*end != '\0') 45 goto err_usage; 46 47 ret = ioctl(fd, GPIO_V2_GET_LINEINFO_WATCH_IOCTL, &req); 48 if (ret) { 49 perror("unable to set up line watch"); 50 return EXIT_FAILURE; 51 } 52 } 53 54 pfd.fd = fd; 55 pfd.events = POLLIN | POLLPRI; 56 57 for (;;) { 58 ret = poll(&pfd, 1, 5000); 59 if (ret < 0) { 60 perror("error polling the linechanged fd"); 61 return EXIT_FAILURE; 62 } else if (ret > 0) { 63 memset(&chg, 0, sizeof(chg)); 64 rd = read(pfd.fd, &chg, sizeof(chg)); 65 if (rd < 0 || rd != sizeof(chg)) { 66 if (rd != sizeof(chg)) 67 errno = EIO; 68 69 perror("error reading line change event"); 70 return EXIT_FAILURE; 71 } 72 73 switch (chg.event_type) { 74 case GPIO_V2_LINE_CHANGED_REQUESTED: 75 event = "requested"; 76 break; 77 case GPIO_V2_LINE_CHANGED_RELEASED: 78 event = "released"; 79 break; 80 case GPIO_V2_LINE_CHANGED_CONFIG: 81 event = "config changed"; 82 break; 83 default: 84 fprintf(stderr, 85 "invalid event type received from the kernel\n"); 86 return EXIT_FAILURE; 87 } 88 89 printf("line %u: %s at %llu\n", 90 chg.info.offset, event, chg.timestamp_ns); 91 } 92 } 93 94 return 0; 95 96 err_usage: 97 printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]); 98 return EXIT_FAILURE; 99 } 100