diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2016-04-26 04:47:09 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-06-15 03:29:04 -0400 |
commit | 2a144dd09118d9ba8cb57ef65eb573af222c455c (patch) | |
tree | 21e57956bbbbcb623cb7c55a419247b1ebf949d7 /tools/gpio | |
parent | d7c51b47ac11e66f547b55640405c1c474642d72 (diff) |
tools/gpio: add the gpio-hammer tool
The gpio-hammer is used from userspace as an example of how
to retrieve a GPIO handle for one or several GPIO lines and
hammer the outputs from low to high and back again. It will
pulse the selected lines once per second for a specified
number of times or indefinitely if no loop count is
supplied.
Example output:
$ gpio-hammer -n gpiochip0 -o5 -o6 -o7
Hammer lines [5, 6, 7] on gpiochip0, initial states: [1, 1, 1]
[-] [5: 0, 6: 0, 7: 0]
Tested-by: Michael Welling <mwelling@ieee.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'tools/gpio')
-rw-r--r-- | tools/gpio/Makefile | 5 | ||||
-rw-r--r-- | tools/gpio/gpio-hammer.c | 189 |
2 files changed, 192 insertions, 2 deletions
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index c155d6bc47a7..aea23949054e 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile | |||
@@ -1,12 +1,13 @@ | |||
1 | CC = $(CROSS_COMPILE)gcc | 1 | CC = $(CROSS_COMPILE)gcc |
2 | CFLAGS += -O2 -Wall -g -D_GNU_SOURCE | 2 | CFLAGS += -O2 -Wall -g -D_GNU_SOURCE |
3 | 3 | ||
4 | all: lsgpio | 4 | all: lsgpio gpio-hammer |
5 | 5 | ||
6 | lsgpio: lsgpio.o gpio-utils.o | 6 | lsgpio: lsgpio.o gpio-utils.o |
7 | gpio-hammer: gpio-hammer.o gpio-utils.o | ||
7 | 8 | ||
8 | %.o: %.c gpio-utils.h | 9 | %.o: %.c gpio-utils.h |
9 | 10 | ||
10 | .PHONY: clean | 11 | .PHONY: clean |
11 | clean: | 12 | clean: |
12 | rm -f *.o lsgpio | 13 | rm -f *.o lsgpio gpio-hammer |
diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c new file mode 100644 index 000000000000..37b3f141053d --- /dev/null +++ b/tools/gpio/gpio-hammer.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * gpio-hammer - example swiss army knife to shake GPIO lines on a system | ||
3 | * | ||
4 | * Copyright (C) 2016 Linus Walleij | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * Usage: | ||
11 | * gpio-hammer -n <device-name> -o <offset1> -o <offset2> | ||
12 | */ | ||
13 | |||
14 | #include <unistd.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <stdbool.h> | ||
17 | #include <stdio.h> | ||
18 | #include <dirent.h> | ||
19 | #include <errno.h> | ||
20 | #include <string.h> | ||
21 | #include <poll.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <getopt.h> | ||
24 | #include <sys/ioctl.h> | ||
25 | #include <linux/gpio.h> | ||
26 | |||
27 | int hammer_device(const char *device_name, unsigned int *lines, int nlines, | ||
28 | unsigned int loops) | ||
29 | { | ||
30 | struct gpiohandle_request req; | ||
31 | struct gpiohandle_data data; | ||
32 | char *chrdev_name; | ||
33 | char swirr[] = "-\\|/"; | ||
34 | int fd; | ||
35 | int ret; | ||
36 | int i, j; | ||
37 | unsigned int iteration = 0; | ||
38 | |||
39 | ret = asprintf(&chrdev_name, "/dev/%s", device_name); | ||
40 | if (ret < 0) | ||
41 | return -ENOMEM; | ||
42 | |||
43 | fd = open(chrdev_name, 0); | ||
44 | if (fd == -1) { | ||
45 | ret = -errno; | ||
46 | fprintf(stderr, "Failed to open %s\n", chrdev_name); | ||
47 | goto exit_close_error; | ||
48 | } | ||
49 | |||
50 | /* Request lines as output */ | ||
51 | for (i = 0; i < nlines; i++) | ||
52 | req.lineoffsets[i] = lines[i]; | ||
53 | req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */ | ||
54 | strcpy(req.consumer_label, "gpio-hammer"); | ||
55 | req.lines = nlines; | ||
56 | ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); | ||
57 | if (ret == -1) { | ||
58 | ret = -errno; | ||
59 | fprintf(stderr, "Failed to issue GET LINEHANDLE " | ||
60 | "IOCTL (%d)\n", | ||
61 | ret); | ||
62 | goto exit_close_error; | ||
63 | } | ||
64 | |||
65 | /* Read initial states */ | ||
66 | ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); | ||
67 | if (ret == -1) { | ||
68 | ret = -errno; | ||
69 | fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " | ||
70 | "VALUES IOCTL (%d)\n", | ||
71 | ret); | ||
72 | goto exit_close_error; | ||
73 | } | ||
74 | fprintf(stdout, "Hammer lines ["); | ||
75 | for (i = 0; i < nlines; i++) { | ||
76 | fprintf(stdout, "%d", lines[i]); | ||
77 | if (i != (nlines - 1)) | ||
78 | fprintf(stdout, ", "); | ||
79 | } | ||
80 | fprintf(stdout, "] on %s, initial states: [", device_name); | ||
81 | for (i = 0; i < nlines; i++) { | ||
82 | fprintf(stdout, "%d", data.values[i]); | ||
83 | if (i != (nlines - 1)) | ||
84 | fprintf(stdout, ", "); | ||
85 | } | ||
86 | fprintf(stdout, "]\n"); | ||
87 | |||
88 | /* Hammertime! */ | ||
89 | j = 0; | ||
90 | while (1) { | ||
91 | /* Invert all lines so we blink */ | ||
92 | for (i = 0; i < nlines; i++) | ||
93 | data.values[i] = !data.values[i]; | ||
94 | |||
95 | ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); | ||
96 | if (ret == -1) { | ||
97 | ret = -errno; | ||
98 | fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE " | ||
99 | "VALUES IOCTL (%d)\n", | ||
100 | ret); | ||
101 | goto exit_close_error; | ||
102 | } | ||
103 | /* Re-read values to get status */ | ||
104 | ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); | ||
105 | if (ret == -1) { | ||
106 | ret = -errno; | ||
107 | fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " | ||
108 | "VALUES IOCTL (%d)\n", | ||
109 | ret); | ||
110 | goto exit_close_error; | ||
111 | } | ||
112 | |||
113 | fprintf(stdout, "[%c] ", swirr[j]); | ||
114 | j++; | ||
115 | if (j == sizeof(swirr)-1) | ||
116 | j = 0; | ||
117 | |||
118 | fprintf(stdout, "["); | ||
119 | for (i = 0; i < nlines; i++) { | ||
120 | fprintf(stdout, "%d: %d", lines[i], data.values[i]); | ||
121 | if (i != (nlines - 1)) | ||
122 | fprintf(stdout, ", "); | ||
123 | } | ||
124 | fprintf(stdout, "]\r"); | ||
125 | fflush(stdout); | ||
126 | sleep(1); | ||
127 | iteration++; | ||
128 | if (loops && iteration == loops) | ||
129 | break; | ||
130 | } | ||
131 | fprintf(stdout, "\n"); | ||
132 | ret = 0; | ||
133 | |||
134 | exit_close_error: | ||
135 | if (close(fd) == -1) | ||
136 | perror("Failed to close GPIO character device file"); | ||
137 | free(chrdev_name); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | void print_usage(void) | ||
142 | { | ||
143 | fprintf(stderr, "Usage: gpio-hammer [options]...\n" | ||
144 | "Hammer GPIO lines, 0->1->0->1...\n" | ||
145 | " -n <name> Hammer GPIOs on a named device (must be stated)\n" | ||
146 | " -o <n> Offset[s] to hammer, at least one, several can be stated\n" | ||
147 | " [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n" | ||
148 | " -? This helptext\n" | ||
149 | "\n" | ||
150 | "Example:\n" | ||
151 | "gpio-hammer -n gpiochip0 -o 4\n" | ||
152 | ); | ||
153 | } | ||
154 | |||
155 | int main(int argc, char **argv) | ||
156 | { | ||
157 | const char *device_name = NULL; | ||
158 | unsigned int lines[GPIOHANDLES_MAX]; | ||
159 | unsigned int loops = 0; | ||
160 | int nlines; | ||
161 | int c; | ||
162 | int i; | ||
163 | |||
164 | i = 0; | ||
165 | while ((c = getopt(argc, argv, "c:n:o:?")) != -1) { | ||
166 | switch (c) { | ||
167 | case 'c': | ||
168 | loops = strtoul(optarg, NULL, 10); | ||
169 | break; | ||
170 | case 'n': | ||
171 | device_name = optarg; | ||
172 | break; | ||
173 | case 'o': | ||
174 | lines[i] = strtoul(optarg, NULL, 10); | ||
175 | i++; | ||
176 | break; | ||
177 | case '?': | ||
178 | print_usage(); | ||
179 | return -1; | ||
180 | } | ||
181 | } | ||
182 | nlines = i; | ||
183 | |||
184 | if (!device_name || !nlines) { | ||
185 | print_usage(); | ||
186 | return -1; | ||
187 | } | ||
188 | return hammer_device(device_name, lines, nlines, loops); | ||
189 | } | ||