Merge remote-tracking branch 'spi/for-5.10' into spi-linus
[linux-2.6-microblaze.git] / 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 gpio_v2_line_info_changed chg;
25         struct gpio_v2_line_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.offset = strtoul(argv[j], &end, 0);
44                 if (*end != '\0')
45                         goto err_usage;
46
47                 ret = ioctl(fd, GPIO_V2_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 GPIO_V2_LINE_CHANGED_REQUESTED:
75                                 event = "requested";
76                                 break;
77                         case GPIO_V2_LINE_CHANGED_RELEASED:
78                                 event = "released";
79                                 break;
80                         case GPIO_V2_LINE_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.offset, event, chg.timestamp_ns);
91                 }
92         }
93
94         return 0;
95
96 err_usage:
97         printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]);
98         return EXIT_FAILURE;
99 }