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, "%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 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 } 177