xref: /linux/tools/gpio/gpio-hammer.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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 
hammer_device(const char * device_name,unsigned int * lines,int num_lines,unsigned int loops)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, "%u", 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, "%u: %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 
print_usage(void)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 
main(int argc,char ** argv)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 }
177