18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * gpio-watch - monitor unrequested lines for property changes using the 48c2ecf20Sopenharmony_ci * character device 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2019 BayLibre SAS 78c2ecf20Sopenharmony_ci * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <ctype.h> 118c2ecf20Sopenharmony_ci#include <errno.h> 128c2ecf20Sopenharmony_ci#include <fcntl.h> 138c2ecf20Sopenharmony_ci#include <inttypes.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio.h> 158c2ecf20Sopenharmony_ci#include <poll.h> 168c2ecf20Sopenharmony_ci#include <stdbool.h> 178c2ecf20Sopenharmony_ci#include <stdio.h> 188c2ecf20Sopenharmony_ci#include <stdlib.h> 198c2ecf20Sopenharmony_ci#include <string.h> 208c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 218c2ecf20Sopenharmony_ci#include <unistd.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciint main(int argc, char **argv) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct gpio_v2_line_info_changed chg; 268c2ecf20Sopenharmony_ci struct gpio_v2_line_info req; 278c2ecf20Sopenharmony_ci struct pollfd pfd; 288c2ecf20Sopenharmony_ci int fd, i, j, ret; 298c2ecf20Sopenharmony_ci char *event, *end; 308c2ecf20Sopenharmony_ci ssize_t rd; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (argc < 3) 338c2ecf20Sopenharmony_ci goto err_usage; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci fd = open(argv[1], O_RDWR | O_CLOEXEC); 368c2ecf20Sopenharmony_ci if (fd < 0) { 378c2ecf20Sopenharmony_ci perror("unable to open gpiochip"); 388c2ecf20Sopenharmony_ci return EXIT_FAILURE; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci for (i = 0, j = 2; i < argc - 2; i++, j++) { 428c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(req)); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci req.offset = strtoul(argv[j], &end, 0); 458c2ecf20Sopenharmony_ci if (*end != '\0') 468c2ecf20Sopenharmony_ci goto err_usage; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci ret = ioctl(fd, GPIO_V2_GET_LINEINFO_WATCH_IOCTL, &req); 498c2ecf20Sopenharmony_ci if (ret) { 508c2ecf20Sopenharmony_ci perror("unable to set up line watch"); 518c2ecf20Sopenharmony_ci return EXIT_FAILURE; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci pfd.fd = fd; 568c2ecf20Sopenharmony_ci pfd.events = POLLIN | POLLPRI; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci for (;;) { 598c2ecf20Sopenharmony_ci ret = poll(&pfd, 1, 5000); 608c2ecf20Sopenharmony_ci if (ret < 0) { 618c2ecf20Sopenharmony_ci perror("error polling the linechanged fd"); 628c2ecf20Sopenharmony_ci return EXIT_FAILURE; 638c2ecf20Sopenharmony_ci } else if (ret > 0) { 648c2ecf20Sopenharmony_ci memset(&chg, 0, sizeof(chg)); 658c2ecf20Sopenharmony_ci rd = read(pfd.fd, &chg, sizeof(chg)); 668c2ecf20Sopenharmony_ci if (rd < 0 || rd != sizeof(chg)) { 678c2ecf20Sopenharmony_ci if (rd != sizeof(chg)) 688c2ecf20Sopenharmony_ci errno = EIO; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci perror("error reading line change event"); 718c2ecf20Sopenharmony_ci return EXIT_FAILURE; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci switch (chg.event_type) { 758c2ecf20Sopenharmony_ci case GPIO_V2_LINE_CHANGED_REQUESTED: 768c2ecf20Sopenharmony_ci event = "requested"; 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case GPIO_V2_LINE_CHANGED_RELEASED: 798c2ecf20Sopenharmony_ci event = "released"; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case GPIO_V2_LINE_CHANGED_CONFIG: 828c2ecf20Sopenharmony_ci event = "config changed"; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci default: 858c2ecf20Sopenharmony_ci fprintf(stderr, 868c2ecf20Sopenharmony_ci "invalid event type received from the kernel\n"); 878c2ecf20Sopenharmony_ci return EXIT_FAILURE; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci printf("line %u: %s at %" PRIu64 "\n", 918c2ecf20Sopenharmony_ci chg.info.offset, event, (uint64_t)chg.timestamp_ns); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cierr_usage: 988c2ecf20Sopenharmony_ci printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]); 998c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1008c2ecf20Sopenharmony_ci} 101