GNU Linux-libre 6.9-gnu
[releases.git] / tools / gpio / gpio-hammer.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * gpio-hammer - example swiss army knife to shake GPIO lines on a system
4  *
5  * Copyright (C) 2016 Linus Walleij
6  *
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>
23 #include "gpio-utils.h"
24
25 int hammer_device(const char *device_name, unsigned int *lines, int num_lines,
26                   unsigned int loops)
27 {
28         struct gpio_v2_line_values values;
29         struct gpio_v2_line_config config;
30         char swirr[] = "-\\|/";
31         int fd;
32         int ret;
33         int i, j;
34         unsigned int iteration = 0;
35
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");
41         if (ret < 0)
42                 goto exit_error;
43         else
44                 fd = ret;
45
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);
52         if (ret < 0)
53                 goto exit_close_error;
54
55         fprintf(stdout, "Hammer lines [");
56         for (i = 0; i < num_lines; i++) {
57                 fprintf(stdout, "%d", lines[i]);
58                 if (i != (num_lines - 1))
59                         fprintf(stdout, ", ");
60         }
61         fprintf(stdout, "] on %s, initial states: [", device_name);
62         for (i = 0; i < num_lines; i++) {
63                 fprintf(stdout, "%d", gpiotools_test_bit(values.bits, i));
64                 if (i != (num_lines - 1))
65                         fprintf(stdout, ", ");
66         }
67         fprintf(stdout, "]\n");
68
69         /* Hammertime! */
70         j = 0;
71         while (1) {
72                 /* Invert all lines so we blink */
73                 for (i = 0; i < num_lines; i++)
74                         gpiotools_change_bit(&values.bits, i);
75
76                 ret = gpiotools_set_values(fd, &values);
77                 if (ret < 0)
78                         goto exit_close_error;
79
80                 /* Re-read values to get status */
81                 ret = gpiotools_get_values(fd, &values);
82                 if (ret < 0)
83                         goto exit_close_error;
84
85                 fprintf(stdout, "[%c] ", swirr[j]);
86                 j++;
87                 if (j == sizeof(swirr) - 1)
88                         j = 0;
89
90                 fprintf(stdout, "[");
91                 for (i = 0; i < num_lines; i++) {
92                         fprintf(stdout, "%d: %d", lines[i],
93                                 gpiotools_test_bit(values.bits, i));
94                         if (i != (num_lines - 1))
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:
108         gpiotools_release_line(fd);
109 exit_error:
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;
132         int num_lines;
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':
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
154                         i++;
155                         break;
156                 case '?':
157                         print_usage();
158                         return -1;
159                 }
160         }
161
162         if (i >= GPIOHANDLES_MAX) {
163                 fprintf(stderr,
164                         "Only %d occurrences of '-o' are allowed, %d were found\n",
165                         GPIOHANDLES_MAX, i + 1);
166                 return -1;
167         }
168
169         num_lines = i;
170
171         if (!device_name || !num_lines) {
172                 print_usage();
173                 return -1;
174         }
175         return hammer_device(device_name, lines, num_lines, loops);
176 }