Re: [PATCH v2 11/11] tools: gpio: implement gpio-watch

From: Kent Gibson
Date: Thu Dec 05 2019 - 04:44:17 EST


On Wed, Dec 04, 2019 at 04:59:41PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@xxxxxxxxxxxx>
>
> Add a simple program that allows to test the new LINECHANGED_FD ioctl().
>

A minor nit - the ioctl has since been changed to LINEINFO_WATCH.

Do you have anything else to test the ioctls?
Either way, I'll try to find some time to add some to my gpiod library.

Kent.

> Signed-off-by: Bartosz Golaszewski <bgolaszewski@xxxxxxxxxxxx>
> ---
> tools/gpio/.gitignore | 1 +
> tools/gpio/Build | 1 +
> tools/gpio/Makefile | 11 +++-
> tools/gpio/gpio-watch.c | 112 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 124 insertions(+), 1 deletion(-)
> create mode 100644 tools/gpio/gpio-watch.c
>
> diff --git a/tools/gpio/.gitignore b/tools/gpio/.gitignore
> index a94c0e83b209..fffd32969d62 100644
> --- a/tools/gpio/.gitignore
> +++ b/tools/gpio/.gitignore
> @@ -1,4 +1,5 @@
> gpio-event-mon
> gpio-hammer
> lsgpio
> +gpio-watch
> include/linux/gpio.h
> diff --git a/tools/gpio/Build b/tools/gpio/Build
> index 4141f35837db..67c7b7f6a717 100644
> --- a/tools/gpio/Build
> +++ b/tools/gpio/Build
> @@ -2,3 +2,4 @@ gpio-utils-y += gpio-utils.o
> lsgpio-y += lsgpio.o gpio-utils.o
> gpio-hammer-y += gpio-hammer.o gpio-utils.o
> gpio-event-mon-y += gpio-event-mon.o gpio-utils.o
> +gpio-watch-y += gpio-watch.o
> diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile
> index 6080de58861f..842287e42c83 100644
> --- a/tools/gpio/Makefile
> +++ b/tools/gpio/Makefile
> @@ -18,7 +18,7 @@ MAKEFLAGS += -r
>
> override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
>
> -ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
> +ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon gpio-watch
> ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
>
> all: $(ALL_PROGRAMS)
> @@ -66,6 +66,15 @@ $(GPIO_EVENT_MON_IN): prepare FORCE $(OUTPUT)gpio-utils-in.o
> $(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN)
> $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
>
> +#
> +# gpio-watch
> +#
> +GPIO_WATCH_IN := $(OUTPUT)gpio-watch-in.o
> +$(GPIO_WATCH_IN): prepare FORCE
> + $(Q)$(MAKE) $(build)=gpio-watch
> +$(OUTPUT)gpio-watch: $(GPIO_WATCH_IN)
> + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
> +
> clean:
> rm -f $(ALL_PROGRAMS)
> rm -f $(OUTPUT)include/linux/gpio.h
> diff --git a/tools/gpio/gpio-watch.c b/tools/gpio/gpio-watch.c
> new file mode 100644
> index 000000000000..69aee43655ae
> --- /dev/null
> +++ b/tools/gpio/gpio-watch.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * gpio-watch - monitor unrequested lines for property changes using the
> + * character device
> + *
> + * Copyright (C) 2019 BayLibre SAS
> + * Author: Bartosz Golaszewski <bgolaszewski@xxxxxxxxxxxx>
> + */
> +
> +#include <ctype.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <linux/gpio.h>
> +#include <poll.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <unistd.h>
> +
> +static bool isnumber(const char *str)
> +{
> + size_t sz = strlen(str);
> + int i;
> +
> + for (i = 0; i < sz; i++) {
> + if (!isdigit(str[i]))
> + return false;
> + }
> +
> + return true;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + struct gpioline_info_changed chg;
> + struct gpioline_info req;
> + struct pollfd pfd;
> + int fd, i, j, ret;
> + char *event;
> + ssize_t rd;
> +
> + if (argc < 3)
> + goto err_usage;
> +
> + fd = open(argv[1], O_RDWR | O_CLOEXEC);
> + if (fd < 0) {
> + perror("unable to open gpiochip");
> + return EXIT_FAILURE;
> + }
> +
> + for (i = 0, j = 2; i < argc - 2; i++, j++) {
> + if (!isnumber(argv[j]))
> + goto err_usage;
> +
> + memset(&req, 0, sizeof(req));
> + req.line_offset = atoi(argv[j]);
> +
> + ret = ioctl(fd, GPIO_GET_LINEINFO_WATCH_IOCTL, &req);
> + if (ret) {
> + perror("unable to set up line watch");
> + return EXIT_FAILURE;
> + }
> + }
> +
> + pfd.fd = fd;
> + pfd.events = POLLIN | POLLPRI;
> +
> + for (;;) {
> + ret = poll(&pfd, 1, 5000);
> + if (ret < 0) {
> + perror("error polling the linechanged fd");
> + return EXIT_FAILURE;
> + } else if (ret > 0) {
> + memset(&chg, 0, sizeof(chg));
> + rd = read(pfd.fd, &chg, sizeof(chg));
> + if (rd < 0 || rd != sizeof(chg)) {
> + if (rd != sizeof(chg))
> + errno = EIO;
> +
> + perror("error reading line change event");
> + return EXIT_FAILURE;
> + }
> +
> + switch (chg.event_type) {
> + case GPIOLINE_CHANGED_REQUESTED:
> + event = "requested";
> + break;
> + case GPIOLINE_CHANGED_RELEASED:
> + event = "released";
> + break;
> + case GPIOLINE_CHANGED_CONFIG:
> + event = "config changed";
> + break;
> + default:
> + fprintf(stderr,
> + "invalid event type received from the kernel\n");
> + return EXIT_FAILURE;
> + }
> +
> + printf("line %u: %s at %llu\n",
> + chg.info.line_offset, event, chg.timestamp);
> + }
> + }
> +
> + return 0;
> +
> +err_usage:
> + printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]);
> + return EXIT_FAILURE;
> +}
> --
> 2.23.0
>