Blame view

tools/gpio/gpio-event-mon.c 5.56 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
97f69747d   Linus Walleij   tools/gpio: add t...
2
  /*
925baf394   Baruch Siach   tools/gpio: fix g...
3
   * gpio-event-mon - monitor GPIO line events from userspace
97f69747d   Linus Walleij   tools/gpio: add t...
4
5
6
   *
   * Copyright (C) 2016 Linus Walleij
   *
97f69747d   Linus Walleij   tools/gpio: add t...
7
8
9
10
11
12
13
   * Usage:
   *	gpio-event-mon -n <device-name> -o <offset>
   */
  
  #include <unistd.h>
  #include <stdlib.h>
  #include <stdbool.h>
92e70b83c   Jonathan Neuschäfer   tools/gpio: Don't...
14
  #include <stdint.h>
97f69747d   Linus Walleij   tools/gpio: add t...
15
16
17
18
19
20
21
22
23
  #include <stdio.h>
  #include <dirent.h>
  #include <errno.h>
  #include <string.h>
  #include <poll.h>
  #include <fcntl.h>
  #include <getopt.h>
  #include <inttypes.h>
  #include <sys/ioctl.h>
1696784eb   Joel Stanley   tools/gpio: Fix b...
24
  #include <sys/types.h>
97f69747d   Linus Walleij   tools/gpio: add t...
25
  #include <linux/gpio.h>
0acda979d   Kent Gibson   tools: gpio: port...
26
  #include "gpio-utils.h"
97f69747d   Linus Walleij   tools/gpio: add t...
27
28
  
  int monitor_device(const char *device_name,
62757c32d   Kent Gibson   tools: gpio: add ...
29
30
  		   unsigned int *lines,
  		   unsigned int num_lines,
0acda979d   Kent Gibson   tools: gpio: port...
31
  		   struct gpio_v2_line_config *config,
97f69747d   Linus Walleij   tools/gpio: add t...
32
33
  		   unsigned int loops)
  {
0acda979d   Kent Gibson   tools: gpio: port...
34
  	struct gpio_v2_line_values values;
97f69747d   Linus Walleij   tools/gpio: add t...
35
  	char *chrdev_name;
0acda979d   Kent Gibson   tools: gpio: port...
36
  	int cfd, lfd;
97f69747d   Linus Walleij   tools/gpio: add t...
37
38
39
40
41
42
  	int ret;
  	int i = 0;
  
  	ret = asprintf(&chrdev_name, "/dev/%s", device_name);
  	if (ret < 0)
  		return -ENOMEM;
0acda979d   Kent Gibson   tools: gpio: port...
43
44
  	cfd = open(chrdev_name, 0);
  	if (cfd == -1) {
97f69747d   Linus Walleij   tools/gpio: add t...
45
46
47
  		ret = -errno;
  		fprintf(stderr, "Failed to open %s
  ", chrdev_name);
df51f402e   Kent Gibson   tools: gpio: fix ...
48
  		goto exit_free_name;
97f69747d   Linus Walleij   tools/gpio: add t...
49
  	}
62757c32d   Kent Gibson   tools: gpio: add ...
50
  	ret = gpiotools_request_line(device_name, lines, num_lines, config,
0acda979d   Kent Gibson   tools: gpio: port...
51
52
53
54
55
  				     "gpio-event-mon");
  	if (ret < 0)
  		goto exit_device_close;
  	else
  		lfd = ret;
97f69747d   Linus Walleij   tools/gpio: add t...
56
57
  
  	/* Read initial states */
62757c32d   Kent Gibson   tools: gpio: add ...
58
  	values.mask = 0;
0acda979d   Kent Gibson   tools: gpio: port...
59
  	values.bits = 0;
62757c32d   Kent Gibson   tools: gpio: add ...
60
61
  	for (i = 0; i < num_lines; i++)
  		gpiotools_set_bit(&values.mask, i);
0acda979d   Kent Gibson   tools: gpio: port...
62
63
64
65
66
  	ret = gpiotools_get_values(lfd, &values);
  	if (ret < 0) {
  		fprintf(stderr,
  			"Failed to issue GPIO LINE GET VALUES IOCTL (%d)
  ",
97f69747d   Linus Walleij   tools/gpio: add t...
67
  			ret);
0acda979d   Kent Gibson   tools: gpio: port...
68
  		goto exit_line_close;
97f69747d   Linus Walleij   tools/gpio: add t...
69
  	}
62757c32d   Kent Gibson   tools: gpio: add ...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  	if (num_lines == 1) {
  		fprintf(stdout, "Monitoring line %d on %s
  ", lines[0], device_name);
  		fprintf(stdout, "Initial line value: %d
  ",
  			gpiotools_test_bit(values.bits, 0));
  	} else {
  		fprintf(stdout, "Monitoring lines %d", lines[0]);
  		for (i = 1; i < num_lines - 1; i++)
  			fprintf(stdout, ", %d", lines[i]);
  		fprintf(stdout, " and %d on %s
  ", lines[i], device_name);
  		fprintf(stdout, "Initial line values: %d",
  			gpiotools_test_bit(values.bits, 0));
  		for (i = 1; i < num_lines - 1; i++)
  			fprintf(stdout, ", %d",
  				gpiotools_test_bit(values.bits, i));
  		fprintf(stdout, " and %d
  ",
  			gpiotools_test_bit(values.bits, i));
  	}
97f69747d   Linus Walleij   tools/gpio: add t...
91
92
  
  	while (1) {
0acda979d   Kent Gibson   tools: gpio: port...
93
  		struct gpio_v2_line_event event;
97f69747d   Linus Walleij   tools/gpio: add t...
94

0acda979d   Kent Gibson   tools: gpio: port...
95
  		ret = read(lfd, &event, sizeof(event));
97f69747d   Linus Walleij   tools/gpio: add t...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  		if (ret == -1) {
  			if (errno == -EAGAIN) {
  				fprintf(stderr, "nothing available
  ");
  				continue;
  			} else {
  				ret = -errno;
  				fprintf(stderr, "Failed to read event (%d)
  ",
  					ret);
  				break;
  			}
  		}
  
  		if (ret != sizeof(event)) {
  			fprintf(stderr, "Reading event failed
  ");
  			ret = -EIO;
  			break;
  		}
0acda979d   Kent Gibson   tools: gpio: port...
116
117
118
  		fprintf(stdout, "GPIO EVENT at %llu on line %d (%d|%d) ",
  			event.timestamp_ns, event.offset, event.line_seqno,
  			event.seqno);
97f69747d   Linus Walleij   tools/gpio: add t...
119
  		switch (event.id) {
0acda979d   Kent Gibson   tools: gpio: port...
120
  		case GPIO_V2_LINE_EVENT_RISING_EDGE:
97f69747d   Linus Walleij   tools/gpio: add t...
121
122
  			fprintf(stdout, "rising edge");
  			break;
0acda979d   Kent Gibson   tools: gpio: port...
123
  		case GPIO_V2_LINE_EVENT_FALLING_EDGE:
97f69747d   Linus Walleij   tools/gpio: add t...
124
125
126
127
128
129
130
131
132
133
134
135
  			fprintf(stdout, "falling edge");
  			break;
  		default:
  			fprintf(stdout, "unknown event");
  		}
  		fprintf(stdout, "
  ");
  
  		i++;
  		if (i == loops)
  			break;
  	}
0acda979d   Kent Gibson   tools: gpio: port...
136
137
138
139
140
  exit_line_close:
  	if (close(lfd) == -1)
  		perror("Failed to close line file");
  exit_device_close:
  	if (close(cfd) == -1)
97f69747d   Linus Walleij   tools/gpio: add t...
141
  		perror("Failed to close GPIO character device file");
df51f402e   Kent Gibson   tools: gpio: fix ...
142
  exit_free_name:
97f69747d   Linus Walleij   tools/gpio: add t...
143
144
145
146
147
148
149
150
151
152
153
154
  	free(chrdev_name);
  	return ret;
  }
  
  void print_usage(void)
  {
  	fprintf(stderr, "Usage: gpio-event-mon [options]...
  "
  		"Listen to events on GPIO lines, 0->1 1->0
  "
  		"  -n <name>  Listen on GPIOs on a named device (must be stated)
  "
62757c32d   Kent Gibson   tools: gpio: add ...
155
156
  		"  -o <n>     Offset of line to monitor (may be repeated)
  "
97f69747d   Linus Walleij   tools/gpio: add t...
157
158
159
160
161
162
163
164
  		"  -d         Set line as open drain
  "
  		"  -s         Set line as open source
  "
  		"  -r         Listen for rising edges
  "
  		"  -f         Listen for falling edges
  "
cf048e05b   Kent Gibson   tools: gpio: add ...
165
166
  		"  -b <n>     Debounce the line with period n microseconds
  "
97f69747d   Linus Walleij   tools/gpio: add t...
167
168
169
170
171
172
173
174
  		" [-c <n>]    Do <n> loops (optional, infinite loop if not stated)
  "
  		"  -?         This helptext
  "
  		"
  "
  		"Example:
  "
cf048e05b   Kent Gibson   tools: gpio: add ...
175
176
  		"gpio-event-mon -n gpiochip0 -o 4 -r -f -b 10000
  "
97f69747d   Linus Walleij   tools/gpio: add t...
177
178
  	);
  }
0acda979d   Kent Gibson   tools: gpio: port...
179
180
181
  #define EDGE_FLAGS \
  	(GPIO_V2_LINE_FLAG_EDGE_RISING | \
  	 GPIO_V2_LINE_FLAG_EDGE_FALLING)
97f69747d   Linus Walleij   tools/gpio: add t...
182
183
184
  int main(int argc, char **argv)
  {
  	const char *device_name = NULL;
62757c32d   Kent Gibson   tools: gpio: add ...
185
186
  	unsigned int lines[GPIO_V2_LINES_MAX];
  	unsigned int num_lines = 0;
97f69747d   Linus Walleij   tools/gpio: add t...
187
  	unsigned int loops = 0;
0acda979d   Kent Gibson   tools: gpio: port...
188
  	struct gpio_v2_line_config config;
cf048e05b   Kent Gibson   tools: gpio: add ...
189
190
  	int c, attr, i;
  	unsigned long debounce_period_us = 0;
97f69747d   Linus Walleij   tools/gpio: add t...
191

0acda979d   Kent Gibson   tools: gpio: port...
192
193
  	memset(&config, 0, sizeof(config));
  	config.flags = GPIO_V2_LINE_FLAG_INPUT;
cf048e05b   Kent Gibson   tools: gpio: add ...
194
  	while ((c = getopt(argc, argv, "c:n:o:b:dsrf?")) != -1) {
97f69747d   Linus Walleij   tools/gpio: add t...
195
196
197
198
199
200
201
202
  		switch (c) {
  		case 'c':
  			loops = strtoul(optarg, NULL, 10);
  			break;
  		case 'n':
  			device_name = optarg;
  			break;
  		case 'o':
62757c32d   Kent Gibson   tools: gpio: add ...
203
204
205
206
207
208
  			if (num_lines >= GPIO_V2_LINES_MAX) {
  				print_usage();
  				return -1;
  			}
  			lines[num_lines] = strtoul(optarg, NULL, 10);
  			num_lines++;
97f69747d   Linus Walleij   tools/gpio: add t...
209
  			break;
cf048e05b   Kent Gibson   tools: gpio: add ...
210
211
212
  		case 'b':
  			debounce_period_us = strtoul(optarg, NULL, 10);
  			break;
97f69747d   Linus Walleij   tools/gpio: add t...
213
  		case 'd':
0acda979d   Kent Gibson   tools: gpio: port...
214
  			config.flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN;
97f69747d   Linus Walleij   tools/gpio: add t...
215
216
  			break;
  		case 's':
0acda979d   Kent Gibson   tools: gpio: port...
217
  			config.flags |= GPIO_V2_LINE_FLAG_OPEN_SOURCE;
97f69747d   Linus Walleij   tools/gpio: add t...
218
219
  			break;
  		case 'r':
0acda979d   Kent Gibson   tools: gpio: port...
220
  			config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING;
97f69747d   Linus Walleij   tools/gpio: add t...
221
222
  			break;
  		case 'f':
0acda979d   Kent Gibson   tools: gpio: port...
223
  			config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
97f69747d   Linus Walleij   tools/gpio: add t...
224
225
226
227
228
229
  			break;
  		case '?':
  			print_usage();
  			return -1;
  		}
  	}
cf048e05b   Kent Gibson   tools: gpio: add ...
230
231
232
233
234
235
236
237
  	if (debounce_period_us) {
  		attr = config.num_attrs;
  		config.num_attrs++;
  		for (i = 0; i < num_lines; i++)
  			gpiotools_set_bit(&config.attrs[attr].mask, i);
  		config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
  		config.attrs[attr].attr.debounce_period_us = debounce_period_us;
  	}
62757c32d   Kent Gibson   tools: gpio: add ...
238
  	if (!device_name || num_lines == 0) {
97f69747d   Linus Walleij   tools/gpio: add t...
239
240
241
  		print_usage();
  		return -1;
  	}
0acda979d   Kent Gibson   tools: gpio: port...
242
  	if (!(config.flags & EDGE_FLAGS)) {
97f69747d   Linus Walleij   tools/gpio: add t...
243
244
245
  		printf("No flags specified, listening on both rising and "
  		       "falling edges
  ");
0acda979d   Kent Gibson   tools: gpio: port...
246
  		config.flags |= EDGE_FLAGS;
97f69747d   Linus Walleij   tools/gpio: add t...
247
  	}
62757c32d   Kent Gibson   tools: gpio: add ...
248
  	return monitor_device(device_name, lines, num_lines, &config, loops);
97f69747d   Linus Walleij   tools/gpio: add t...
249
  }