Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2a144dd0 LW |
2 | /* |
3 | * gpio-hammer - example swiss army knife to shake GPIO lines on a system | |
4 | * | |
5 | * Copyright (C) 2016 Linus Walleij | |
6 | * | |
2a144dd0 LW |
7 | * Usage: |
8 | * gpio-hammer -n <device-name> -o <offset1> -o <offset2> | |
9 | */ | |
10 | ||
11 | #include <unistd.h> | |
12 | #include <stdlib.h> | |
13 | #include <stdbool.h> | |
14 | #include <stdio.h> | |
15 | #include <dirent.h> | |
16 | #include <errno.h> | |
17 | #include <string.h> | |
18 | #include <poll.h> | |
19 | #include <fcntl.h> | |
20 | #include <getopt.h> | |
21 | #include <sys/ioctl.h> | |
22 | #include <linux/gpio.h> | |
74100bb9 | 23 | #include "gpio-utils.h" |
2a144dd0 | 24 | |
ed60aee0 | 25 | int hammer_device(const char *device_name, unsigned int *lines, int num_lines, |
2a144dd0 LW |
26 | unsigned int loops) |
27 | { | |
7ff6d1d2 KG |
28 | struct gpio_v2_line_values values; |
29 | struct gpio_v2_line_config config; | |
2a144dd0 LW |
30 | char swirr[] = "-\\|/"; |
31 | int fd; | |
32 | int ret; | |
33 | int i, j; | |
34 | unsigned int iteration = 0; | |
35 | ||
7ff6d1d2 KG |
36 | memset(&config, 0, sizeof(config)); |
37 | config.flags = GPIO_V2_LINE_FLAG_OUTPUT; | |
38 | ||
39 | ret = gpiotools_request_line(device_name, lines, num_lines, | |
40 | &config, "gpio-hammer"); | |
2a144dd0 | 41 | if (ret < 0) |
74100bb9 BJZ |
42 | goto exit_error; |
43 | else | |
44 | fd = ret; | |
2a144dd0 | 45 | |
7ff6d1d2 KG |
46 | values.mask = 0; |
47 | values.bits = 0; | |
48 | for (i = 0; i < num_lines; i++) | |
49 | gpiotools_set_bit(&values.mask, i); | |
50 | ||
51 | ret = gpiotools_get_values(fd, &values); | |
74100bb9 | 52 | if (ret < 0) |
2a144dd0 | 53 | goto exit_close_error; |
2a144dd0 | 54 | |
2a144dd0 | 55 | fprintf(stdout, "Hammer lines ["); |
ed60aee0 | 56 | for (i = 0; i < num_lines; i++) { |
2a144dd0 | 57 | fprintf(stdout, "%d", lines[i]); |
ed60aee0 | 58 | if (i != (num_lines - 1)) |
2a144dd0 LW |
59 | fprintf(stdout, ", "); |
60 | } | |
61 | fprintf(stdout, "] on %s, initial states: [", device_name); | |
ed60aee0 | 62 | for (i = 0; i < num_lines; i++) { |
7ff6d1d2 | 63 | fprintf(stdout, "%d", gpiotools_test_bit(values.bits, i)); |
ed60aee0 | 64 | if (i != (num_lines - 1)) |
2a144dd0 LW |
65 | fprintf(stdout, ", "); |
66 | } | |
67 | fprintf(stdout, "]\n"); | |
68 | ||
69 | /* Hammertime! */ | |
70 | j = 0; | |
71 | while (1) { | |
72 | /* Invert all lines so we blink */ | |
ed60aee0 | 73 | for (i = 0; i < num_lines; i++) |
7ff6d1d2 | 74 | gpiotools_change_bit(&values.bits, i); |
2a144dd0 | 75 | |
7ff6d1d2 | 76 | ret = gpiotools_set_values(fd, &values); |
74100bb9 | 77 | if (ret < 0) |
2a144dd0 | 78 | goto exit_close_error; |
74100bb9 | 79 | |
2a144dd0 | 80 | /* Re-read values to get status */ |
7ff6d1d2 | 81 | ret = gpiotools_get_values(fd, &values); |
74100bb9 | 82 | if (ret < 0) |
2a144dd0 | 83 | goto exit_close_error; |
2a144dd0 LW |
84 | |
85 | fprintf(stdout, "[%c] ", swirr[j]); | |
86 | j++; | |
1003bc16 | 87 | if (j == sizeof(swirr) - 1) |
2a144dd0 LW |
88 | j = 0; |
89 | ||
90 | fprintf(stdout, "["); | |
ed60aee0 | 91 | for (i = 0; i < num_lines; i++) { |
7ff6d1d2 KG |
92 | fprintf(stdout, "%d: %d", lines[i], |
93 | gpiotools_test_bit(values.bits, i)); | |
ed60aee0 | 94 | if (i != (num_lines - 1)) |
2a144dd0 LW |
95 | fprintf(stdout, ", "); |
96 | } | |
97 | fprintf(stdout, "]\r"); | |
98 | fflush(stdout); | |
99 | sleep(1); | |
100 | iteration++; | |
101 | if (loops && iteration == loops) | |
102 | break; | |
103 | } | |
104 | fprintf(stdout, "\n"); | |
105 | ret = 0; | |
106 | ||
107 | exit_close_error: | |
7ff6d1d2 | 108 | gpiotools_release_line(fd); |
74100bb9 | 109 | exit_error: |
2a144dd0 LW |
110 | return ret; |
111 | } | |
112 | ||
113 | void print_usage(void) | |
114 | { | |
115 | fprintf(stderr, "Usage: gpio-hammer [options]...\n" | |
116 | "Hammer GPIO lines, 0->1->0->1...\n" | |
117 | " -n <name> Hammer GPIOs on a named device (must be stated)\n" | |
118 | " -o <n> Offset[s] to hammer, at least one, several can be stated\n" | |
119 | " [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n" | |
120 | " -? This helptext\n" | |
121 | "\n" | |
122 | "Example:\n" | |
123 | "gpio-hammer -n gpiochip0 -o 4\n" | |
124 | ); | |
125 | } | |
126 | ||
127 | int main(int argc, char **argv) | |
128 | { | |
129 | const char *device_name = NULL; | |
130 | unsigned int lines[GPIOHANDLES_MAX]; | |
131 | unsigned int loops = 0; | |
ed60aee0 | 132 | int num_lines; |
2a144dd0 LW |
133 | int c; |
134 | int i; | |
135 | ||
136 | i = 0; | |
137 | while ((c = getopt(argc, argv, "c:n:o:?")) != -1) { | |
138 | switch (c) { | |
139 | case 'c': | |
140 | loops = strtoul(optarg, NULL, 10); | |
141 | break; | |
142 | case 'n': | |
143 | device_name = optarg; | |
144 | break; | |
145 | case 'o': | |
d1ee7e1f GR |
146 | /* |
147 | * Avoid overflow. Do not immediately error, we want to | |
148 | * be able to accurately report on the amount of times | |
149 | * '-o' was given to give an accurate error message | |
150 | */ | |
151 | if (i < GPIOHANDLES_MAX) | |
152 | lines[i] = strtoul(optarg, NULL, 10); | |
153 | ||
2a144dd0 LW |
154 | i++; |
155 | break; | |
156 | case '?': | |
157 | print_usage(); | |
158 | return -1; | |
159 | } | |
160 | } | |
d1ee7e1f GR |
161 | |
162 | if (i >= GPIOHANDLES_MAX) { | |
163 | fprintf(stderr, | |
55f17e2a | 164 | "Only %d occurrences of '-o' are allowed, %d were found\n", |
d1ee7e1f GR |
165 | GPIOHANDLES_MAX, i + 1); |
166 | return -1; | |
167 | } | |
168 | ||
ed60aee0 | 169 | num_lines = i; |
2a144dd0 | 170 | |
ed60aee0 | 171 | if (!device_name || !num_lines) { |
2a144dd0 LW |
172 | print_usage(); |
173 | return -1; | |
174 | } | |
ed60aee0 | 175 | return hammer_device(device_name, lines, num_lines, loops); |
2a144dd0 | 176 | } |