GNU Linux-libre 4.14.303-gnu1
[releases.git] / tools / gpio / gpio-hammer.c
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 #include "gpio-utils.h"
27
28 int hammer_device(const char *device_name, unsigned int *lines, int nlines,
29                   unsigned int loops)
30 {
31         struct gpiohandle_data data;
32         char swirr[] = "-\\|/";
33         int fd;
34         int ret;
35         int i, j;
36         unsigned int iteration = 0;
37
38         memset(&data.values, 0, sizeof(data.values));
39         ret = gpiotools_request_linehandle(device_name, lines, nlines,
40                                            GPIOHANDLE_REQUEST_OUTPUT, &data,
41                                            "gpio-hammer");
42         if (ret < 0)
43                 goto exit_error;
44         else
45                 fd = ret;
46
47         ret = gpiotools_get_values(fd, &data);
48         if (ret < 0)
49                 goto exit_close_error;
50
51         fprintf(stdout, "Hammer lines [");
52         for (i = 0; i < nlines; i++) {
53                 fprintf(stdout, "%d", lines[i]);
54                 if (i != (nlines - 1))
55                         fprintf(stdout, ", ");
56         }
57         fprintf(stdout, "] on %s, initial states: [", device_name);
58         for (i = 0; i < nlines; i++) {
59                 fprintf(stdout, "%d", data.values[i]);
60                 if (i != (nlines - 1))
61                         fprintf(stdout, ", ");
62         }
63         fprintf(stdout, "]\n");
64
65         /* Hammertime! */
66         j = 0;
67         while (1) {
68                 /* Invert all lines so we blink */
69                 for (i = 0; i < nlines; i++)
70                         data.values[i] = !data.values[i];
71
72                 ret = gpiotools_set_values(fd, &data);
73                 if (ret < 0)
74                         goto exit_close_error;
75
76                 /* Re-read values to get status */
77                 ret = gpiotools_get_values(fd, &data);
78                 if (ret < 0)
79                         goto exit_close_error;
80
81                 fprintf(stdout, "[%c] ", swirr[j]);
82                 j++;
83                 if (j == sizeof(swirr)-1)
84                         j = 0;
85
86                 fprintf(stdout, "[");
87                 for (i = 0; i < nlines; i++) {
88                         fprintf(stdout, "%d: %d", lines[i], data.values[i]);
89                         if (i != (nlines - 1))
90                                 fprintf(stdout, ", ");
91                 }
92                 fprintf(stdout, "]\r");
93                 fflush(stdout);
94                 sleep(1);
95                 iteration++;
96                 if (loops && iteration == loops)
97                         break;
98         }
99         fprintf(stdout, "\n");
100         ret = 0;
101
102 exit_close_error:
103         gpiotools_release_linehandle(fd);
104 exit_error:
105         return ret;
106 }
107
108 void print_usage(void)
109 {
110         fprintf(stderr, "Usage: gpio-hammer [options]...\n"
111                 "Hammer GPIO lines, 0->1->0->1...\n"
112                 "  -n <name>  Hammer GPIOs on a named device (must be stated)\n"
113                 "  -o <n>     Offset[s] to hammer, at least one, several can be stated\n"
114                 " [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
115                 "  -?         This helptext\n"
116                 "\n"
117                 "Example:\n"
118                 "gpio-hammer -n gpiochip0 -o 4\n"
119         );
120 }
121
122 int main(int argc, char **argv)
123 {
124         const char *device_name = NULL;
125         unsigned int lines[GPIOHANDLES_MAX];
126         unsigned int loops = 0;
127         int nlines;
128         int c;
129         int i;
130
131         i = 0;
132         while ((c = getopt(argc, argv, "c:n:o:?")) != -1) {
133                 switch (c) {
134                 case 'c':
135                         loops = strtoul(optarg, NULL, 10);
136                         break;
137                 case 'n':
138                         device_name = optarg;
139                         break;
140                 case 'o':
141                         /*
142                          * Avoid overflow. Do not immediately error, we want to
143                          * be able to accurately report on the amount of times
144                          * '-o' was given to give an accurate error message
145                          */
146                         if (i < GPIOHANDLES_MAX)
147                                 lines[i] = strtoul(optarg, NULL, 10);
148
149                         i++;
150                         break;
151                 case '?':
152                         print_usage();
153                         return -1;
154                 }
155         }
156
157         if (i >= GPIOHANDLES_MAX) {
158                 fprintf(stderr,
159                         "Only %d occurences of '-o' are allowed, %d were found\n",
160                         GPIOHANDLES_MAX, i + 1);
161                 return -1;
162         }
163
164         nlines = i;
165
166         if (!device_name || !nlines) {
167                 print_usage();
168                 return -1;
169         }
170         return hammer_device(device_name, lines, nlines, loops);
171 }