162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * gpio-watch - monitor unrequested lines for property changes using the 462306a36Sopenharmony_ci * character device 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2019 BayLibre SAS 762306a36Sopenharmony_ci * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <ctype.h> 1162306a36Sopenharmony_ci#include <errno.h> 1262306a36Sopenharmony_ci#include <fcntl.h> 1362306a36Sopenharmony_ci#include <inttypes.h> 1462306a36Sopenharmony_ci#include <linux/gpio.h> 1562306a36Sopenharmony_ci#include <poll.h> 1662306a36Sopenharmony_ci#include <stdbool.h> 1762306a36Sopenharmony_ci#include <stdio.h> 1862306a36Sopenharmony_ci#include <stdlib.h> 1962306a36Sopenharmony_ci#include <string.h> 2062306a36Sopenharmony_ci#include <sys/ioctl.h> 2162306a36Sopenharmony_ci#include <unistd.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciint main(int argc, char **argv) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct gpio_v2_line_info_changed chg; 2662306a36Sopenharmony_ci struct gpio_v2_line_info req; 2762306a36Sopenharmony_ci struct pollfd pfd; 2862306a36Sopenharmony_ci int fd, i, j, ret; 2962306a36Sopenharmony_ci char *event, *end; 3062306a36Sopenharmony_ci ssize_t rd; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (argc < 3) 3362306a36Sopenharmony_ci goto err_usage; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci fd = open(argv[1], O_RDWR | O_CLOEXEC); 3662306a36Sopenharmony_ci if (fd < 0) { 3762306a36Sopenharmony_ci perror("unable to open gpiochip"); 3862306a36Sopenharmony_ci return EXIT_FAILURE; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci for (i = 0, j = 2; i < argc - 2; i++, j++) { 4262306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci req.offset = strtoul(argv[j], &end, 0); 4562306a36Sopenharmony_ci if (*end != '\0') 4662306a36Sopenharmony_ci goto err_usage; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci ret = ioctl(fd, GPIO_V2_GET_LINEINFO_WATCH_IOCTL, &req); 4962306a36Sopenharmony_ci if (ret) { 5062306a36Sopenharmony_ci perror("unable to set up line watch"); 5162306a36Sopenharmony_ci return EXIT_FAILURE; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci pfd.fd = fd; 5662306a36Sopenharmony_ci pfd.events = POLLIN | POLLPRI; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci for (;;) { 5962306a36Sopenharmony_ci ret = poll(&pfd, 1, 5000); 6062306a36Sopenharmony_ci if (ret < 0) { 6162306a36Sopenharmony_ci perror("error polling the linechanged fd"); 6262306a36Sopenharmony_ci return EXIT_FAILURE; 6362306a36Sopenharmony_ci } else if (ret > 0) { 6462306a36Sopenharmony_ci memset(&chg, 0, sizeof(chg)); 6562306a36Sopenharmony_ci rd = read(pfd.fd, &chg, sizeof(chg)); 6662306a36Sopenharmony_ci if (rd < 0 || rd != sizeof(chg)) { 6762306a36Sopenharmony_ci if (rd != sizeof(chg)) 6862306a36Sopenharmony_ci errno = EIO; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci perror("error reading line change event"); 7162306a36Sopenharmony_ci return EXIT_FAILURE; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci switch (chg.event_type) { 7562306a36Sopenharmony_ci case GPIO_V2_LINE_CHANGED_REQUESTED: 7662306a36Sopenharmony_ci event = "requested"; 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci case GPIO_V2_LINE_CHANGED_RELEASED: 7962306a36Sopenharmony_ci event = "released"; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci case GPIO_V2_LINE_CHANGED_CONFIG: 8262306a36Sopenharmony_ci event = "config changed"; 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci default: 8562306a36Sopenharmony_ci fprintf(stderr, 8662306a36Sopenharmony_ci "invalid event type received from the kernel\n"); 8762306a36Sopenharmony_ci return EXIT_FAILURE; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci printf("line %u: %s at %" PRIu64 "\n", 9162306a36Sopenharmony_ci chg.info.offset, event, (uint64_t)chg.timestamp_ns); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cierr_usage: 9862306a36Sopenharmony_ci printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]); 9962306a36Sopenharmony_ci return EXIT_FAILURE; 10062306a36Sopenharmony_ci} 101