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