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 27 int hammer_device(const char *device_name, unsigned int *lines, int nlines, 28 unsigned int loops) 29 { 30 struct gpiohandle_request req; 31 struct gpiohandle_data data; 32 char *chrdev_name; 33 char swirr[] = "-\\|/"; 34 int fd; 35 int ret; 36 int i, j; 37 unsigned int iteration = 0; 38 39 ret = asprintf(&chrdev_name, "/dev/%s", device_name); 40 if (ret < 0) 41 return -ENOMEM; 42 43 fd = open(chrdev_name, 0); 44 if (fd == -1) { 45 ret = -errno; 46 fprintf(stderr, "Failed to open %s\n", chrdev_name); 47 goto exit_close_error; 48 } 49 50 /* Request lines as output */ 51 for (i = 0; i < nlines; i++) 52 req.lineoffsets[i] = lines[i]; 53 req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */ 54 strcpy(req.consumer_label, "gpio-hammer"); 55 req.lines = nlines; 56 ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); 57 if (ret == -1) { 58 ret = -errno; 59 fprintf(stderr, "Failed to issue GET LINEHANDLE " 60 "IOCTL (%d)\n", 61 ret); 62 goto exit_close_error; 63 } 64 65 /* Read initial states */ 66 ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); 67 if (ret == -1) { 68 ret = -errno; 69 fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " 70 "VALUES IOCTL (%d)\n", 71 ret); 72 goto exit_close_error; 73 } 74 fprintf(stdout, "Hammer lines ["); 75 for (i = 0; i < nlines; i++) { 76 fprintf(stdout, "%d", lines[i]); 77 if (i != (nlines - 1)) 78 fprintf(stdout, ", "); 79 } 80 fprintf(stdout, "] on %s, initial states: [", device_name); 81 for (i = 0; i < nlines; i++) { 82 fprintf(stdout, "%d", data.values[i]); 83 if (i != (nlines - 1)) 84 fprintf(stdout, ", "); 85 } 86 fprintf(stdout, "]\n"); 87 88 /* Hammertime! */ 89 j = 0; 90 while (1) { 91 /* Invert all lines so we blink */ 92 for (i = 0; i < nlines; i++) 93 data.values[i] = !data.values[i]; 94 95 ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); 96 if (ret == -1) { 97 ret = -errno; 98 fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE " 99 "VALUES IOCTL (%d)\n", 100 ret); 101 goto exit_close_error; 102 } 103 /* Re-read values to get status */ 104 ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); 105 if (ret == -1) { 106 ret = -errno; 107 fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " 108 "VALUES IOCTL (%d)\n", 109 ret); 110 goto exit_close_error; 111 } 112 113 fprintf(stdout, "[%c] ", swirr[j]); 114 j++; 115 if (j == sizeof(swirr)-1) 116 j = 0; 117 118 fprintf(stdout, "["); 119 for (i = 0; i < nlines; i++) { 120 fprintf(stdout, "%d: %d", lines[i], data.values[i]); 121 if (i != (nlines - 1)) 122 fprintf(stdout, ", "); 123 } 124 fprintf(stdout, "]\r"); 125 fflush(stdout); 126 sleep(1); 127 iteration++; 128 if (loops && iteration == loops) 129 break; 130 } 131 fprintf(stdout, "\n"); 132 ret = 0; 133 134 exit_close_error: 135 if (close(fd) == -1) 136 perror("Failed to close GPIO character device file"); 137 free(chrdev_name); 138 return ret; 139 } 140 141 void print_usage(void) 142 { 143 fprintf(stderr, "Usage: gpio-hammer [options]...\n" 144 "Hammer GPIO lines, 0->1->0->1...\n" 145 " -n <name> Hammer GPIOs on a named device (must be stated)\n" 146 " -o <n> Offset[s] to hammer, at least one, several can be stated\n" 147 " [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n" 148 " -? This helptext\n" 149 "\n" 150 "Example:\n" 151 "gpio-hammer -n gpiochip0 -o 4\n" 152 ); 153 } 154 155 int main(int argc, char **argv) 156 { 157 const char *device_name = NULL; 158 unsigned int lines[GPIOHANDLES_MAX]; 159 unsigned int loops = 0; 160 int nlines; 161 int c; 162 int i; 163 164 i = 0; 165 while ((c = getopt(argc, argv, "c:n:o:?")) != -1) { 166 switch (c) { 167 case 'c': 168 loops = strtoul(optarg, NULL, 10); 169 break; 170 case 'n': 171 device_name = optarg; 172 break; 173 case 'o': 174 lines[i] = strtoul(optarg, NULL, 10); 175 i++; 176 break; 177 case '?': 178 print_usage(); 179 return -1; 180 } 181 } 182 nlines = i; 183 184 if (!device_name || !nlines) { 185 print_usage(); 186 return -1; 187 } 188 return hammer_device(device_name, lines, nlines, loops); 189 } 190