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