xref: /openbmc/linux/tools/gpio/gpio-watch.c (revision f8bade6c9a6213c2c5ba6e5bf32415ecab6e41e5)
133f0c47bSBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0-only
233f0c47bSBartosz Golaszewski /*
333f0c47bSBartosz Golaszewski  * gpio-watch - monitor unrequested lines for property changes using the
433f0c47bSBartosz Golaszewski  *              character device
533f0c47bSBartosz Golaszewski  *
633f0c47bSBartosz Golaszewski  * Copyright (C) 2019 BayLibre SAS
733f0c47bSBartosz Golaszewski  * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
833f0c47bSBartosz Golaszewski  */
933f0c47bSBartosz Golaszewski 
1033f0c47bSBartosz Golaszewski #include <ctype.h>
1133f0c47bSBartosz Golaszewski #include <errno.h>
1233f0c47bSBartosz Golaszewski #include <fcntl.h>
13*1fc7c1efSKent Gibson #include <inttypes.h>
1433f0c47bSBartosz Golaszewski #include <linux/gpio.h>
1533f0c47bSBartosz Golaszewski #include <poll.h>
1633f0c47bSBartosz Golaszewski #include <stdbool.h>
1733f0c47bSBartosz Golaszewski #include <stdio.h>
1833f0c47bSBartosz Golaszewski #include <stdlib.h>
1933f0c47bSBartosz Golaszewski #include <string.h>
2033f0c47bSBartosz Golaszewski #include <sys/ioctl.h>
2133f0c47bSBartosz Golaszewski #include <unistd.h>
2233f0c47bSBartosz Golaszewski 
main(int argc,char ** argv)2333f0c47bSBartosz Golaszewski int main(int argc, char **argv)
2433f0c47bSBartosz Golaszewski {
25e86a863bSKent Gibson 	struct gpio_v2_line_info_changed chg;
26e86a863bSKent Gibson 	struct gpio_v2_line_info req;
2733f0c47bSBartosz Golaszewski 	struct pollfd pfd;
2833f0c47bSBartosz Golaszewski 	int fd, i, j, ret;
2933f0c47bSBartosz Golaszewski 	char *event, *end;
3033f0c47bSBartosz Golaszewski 	ssize_t rd;
3133f0c47bSBartosz Golaszewski 
3233f0c47bSBartosz Golaszewski 	if (argc < 3)
3333f0c47bSBartosz Golaszewski 		goto err_usage;
3433f0c47bSBartosz Golaszewski 
3533f0c47bSBartosz Golaszewski 	fd = open(argv[1], O_RDWR | O_CLOEXEC);
3633f0c47bSBartosz Golaszewski 	if (fd < 0) {
3733f0c47bSBartosz Golaszewski 		perror("unable to open gpiochip");
3833f0c47bSBartosz Golaszewski 		return EXIT_FAILURE;
3933f0c47bSBartosz Golaszewski 	}
4033f0c47bSBartosz Golaszewski 
4133f0c47bSBartosz Golaszewski 	for (i = 0, j = 2; i < argc - 2; i++, j++) {
4233f0c47bSBartosz Golaszewski 		memset(&req, 0, sizeof(req));
4333f0c47bSBartosz Golaszewski 
44e86a863bSKent Gibson 		req.offset = strtoul(argv[j], &end, 0);
4533f0c47bSBartosz Golaszewski 		if (*end != '\0')
4633f0c47bSBartosz Golaszewski 			goto err_usage;
4733f0c47bSBartosz Golaszewski 
48e86a863bSKent Gibson 		ret = ioctl(fd, GPIO_V2_GET_LINEINFO_WATCH_IOCTL, &req);
4933f0c47bSBartosz Golaszewski 		if (ret) {
5033f0c47bSBartosz Golaszewski 			perror("unable to set up line watch");
5133f0c47bSBartosz Golaszewski 			return EXIT_FAILURE;
5233f0c47bSBartosz Golaszewski 		}
5333f0c47bSBartosz Golaszewski 	}
5433f0c47bSBartosz Golaszewski 
5533f0c47bSBartosz Golaszewski 	pfd.fd = fd;
5633f0c47bSBartosz Golaszewski 	pfd.events = POLLIN | POLLPRI;
5733f0c47bSBartosz Golaszewski 
5833f0c47bSBartosz Golaszewski 	for (;;) {
5933f0c47bSBartosz Golaszewski 		ret = poll(&pfd, 1, 5000);
6033f0c47bSBartosz Golaszewski 		if (ret < 0) {
6133f0c47bSBartosz Golaszewski 			perror("error polling the linechanged fd");
6233f0c47bSBartosz Golaszewski 			return EXIT_FAILURE;
6333f0c47bSBartosz Golaszewski 		} else if (ret > 0) {
6433f0c47bSBartosz Golaszewski 			memset(&chg, 0, sizeof(chg));
6533f0c47bSBartosz Golaszewski 			rd = read(pfd.fd, &chg, sizeof(chg));
6633f0c47bSBartosz Golaszewski 			if (rd < 0 || rd != sizeof(chg)) {
6733f0c47bSBartosz Golaszewski 				if (rd != sizeof(chg))
6833f0c47bSBartosz Golaszewski 					errno = EIO;
6933f0c47bSBartosz Golaszewski 
7033f0c47bSBartosz Golaszewski 				perror("error reading line change event");
7133f0c47bSBartosz Golaszewski 				return EXIT_FAILURE;
7233f0c47bSBartosz Golaszewski 			}
7333f0c47bSBartosz Golaszewski 
7433f0c47bSBartosz Golaszewski 			switch (chg.event_type) {
75e86a863bSKent Gibson 			case GPIO_V2_LINE_CHANGED_REQUESTED:
7633f0c47bSBartosz Golaszewski 				event = "requested";
7733f0c47bSBartosz Golaszewski 				break;
78e86a863bSKent Gibson 			case GPIO_V2_LINE_CHANGED_RELEASED:
7933f0c47bSBartosz Golaszewski 				event = "released";
8033f0c47bSBartosz Golaszewski 				break;
81e86a863bSKent Gibson 			case GPIO_V2_LINE_CHANGED_CONFIG:
8233f0c47bSBartosz Golaszewski 				event = "config changed";
8333f0c47bSBartosz Golaszewski 				break;
8433f0c47bSBartosz Golaszewski 			default:
8533f0c47bSBartosz Golaszewski 				fprintf(stderr,
8633f0c47bSBartosz Golaszewski 					"invalid event type received from the kernel\n");
8733f0c47bSBartosz Golaszewski 				return EXIT_FAILURE;
8833f0c47bSBartosz Golaszewski 			}
8933f0c47bSBartosz Golaszewski 
90*1fc7c1efSKent Gibson 			printf("line %u: %s at %" PRIu64 "\n",
91*1fc7c1efSKent Gibson 			       chg.info.offset, event, (uint64_t)chg.timestamp_ns);
9233f0c47bSBartosz Golaszewski 		}
9333f0c47bSBartosz Golaszewski 	}
9433f0c47bSBartosz Golaszewski 
9533f0c47bSBartosz Golaszewski 	return 0;
9633f0c47bSBartosz Golaszewski 
9733f0c47bSBartosz Golaszewski err_usage:
9833f0c47bSBartosz Golaszewski 	printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]);
9933f0c47bSBartosz Golaszewski 	return EXIT_FAILURE;
10033f0c47bSBartosz Golaszewski }
101