Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools: gpio: implement gpio-watch

Add a simple program that allows to test the new LINECHANGED_FD ioctl().

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

+111 -1
+1
tools/gpio/.gitignore
··· 1 1 gpio-event-mon 2 2 gpio-hammer 3 + gpio-watch 3 4 lsgpio 4 5 include/linux/gpio.h
+1
tools/gpio/Build
··· 2 2 lsgpio-y += lsgpio.o gpio-utils.o 3 3 gpio-hammer-y += gpio-hammer.o gpio-utils.o 4 4 gpio-event-mon-y += gpio-event-mon.o gpio-utils.o 5 + gpio-watch-y += gpio-watch.o
+10 -1
tools/gpio/Makefile
··· 18 18 19 19 override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include 20 20 21 - ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon 21 + ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon gpio-watch 22 22 ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) 23 23 24 24 all: $(ALL_PROGRAMS) ··· 64 64 $(GPIO_EVENT_MON_IN): prepare FORCE $(OUTPUT)gpio-utils-in.o 65 65 $(Q)$(MAKE) $(build)=gpio-event-mon 66 66 $(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN) 67 + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ 68 + 69 + # 70 + # gpio-watch 71 + # 72 + GPIO_WATCH_IN := $(OUTPUT)gpio-watch-in.o 73 + $(GPIO_WATCH_IN): prepare FORCE 74 + $(Q)$(MAKE) $(build)=gpio-watch 75 + $(OUTPUT)gpio-watch: $(GPIO_WATCH_IN) 67 76 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ 68 77 69 78 clean:
+99
tools/gpio/gpio-watch.c
··· 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 gpioline_info_changed chg; 25 + struct gpioline_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.line_offset = strtoul(argv[j], &end, 0); 44 + if (*end != '\0') 45 + goto err_usage; 46 + 47 + ret = ioctl(fd, GPIO_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 GPIOLINE_CHANGED_REQUESTED: 75 + event = "requested"; 76 + break; 77 + case GPIOLINE_CHANGED_RELEASED: 78 + event = "released"; 79 + break; 80 + case GPIOLINE_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.line_offset, event, chg.timestamp); 91 + } 92 + } 93 + 94 + return 0; 95 + 96 + err_usage: 97 + printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]); 98 + return EXIT_FAILURE; 99 + }