/* * gpio-hammer - example swiss army knife to shake GPIO lines on a system * * Copyright (C) 2016 Linus Walleij * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * Usage: * gpio-hammer -n -o -o */ #include #include #include #include #include #include #include #include #include #include #include #include int hammer_device(const char *device_name, unsigned int *lines, int nlines, unsigned int loops) { struct gpiohandle_request req; struct gpiohandle_data data; char *chrdev_name; char swirr[] = "-\\|/"; int fd; int ret; int i, j; unsigned int iteration = 0; ret = asprintf(&chrdev_name, "/dev/%s", device_name); if (ret < 0) return -ENOMEM; fd = open(chrdev_name, 0); if (fd == -1) { ret = -errno; fprintf(stderr, "Failed to open %s\n", chrdev_name); goto exit_close_error; } /* Request lines as output */ for (i = 0; i < nlines; i++) req.lineoffsets[i] = lines[i]; req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */ strcpy(req.consumer_label, "gpio-hammer"); req.lines = nlines; ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue GET LINEHANDLE " "IOCTL (%d)\n", ret); goto exit_close_error; } /* Read initial states */ ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " "VALUES IOCTL (%d)\n", ret); goto exit_close_error; } fprintf(stdout, "Hammer lines ["); for (i = 0; i < nlines; i++) { fprintf(stdout, "%d", lines[i]); if (i != (nlines - 1)) fprintf(stdout, ", "); } fprintf(stdout, "] on %s, initial states: [", device_name); for (i = 0; i < nlines; i++) { fprintf(stdout, "%d", data.values[i]); if (i != (nlines - 1)) fprintf(stdout, ", "); } fprintf(stdout, "]\n"); /* Hammertime! */ j = 0; while (1) { /* Invert all lines so we blink */ for (i = 0; i < nlines; i++) data.values[i] = !data.values[i]; ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE " "VALUES IOCTL (%d)\n", ret); goto exit_close_error; } /* Re-read values to get status */ ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " "VALUES IOCTL (%d)\n", ret); goto exit_close_error; } fprintf(stdout, "[%c] ", swirr[j]); j++; if (j == sizeof(swirr)-1) j = 0; fprintf(stdout, "["); for (i = 0; i < nlines; i++) { fprintf(stdout, "%d: %d", lines[i], data.values[i]); if (i != (nlines - 1)) fprintf(stdout, ", "); } fprintf(stdout, "]\r"); fflush(stdout); sleep(1); iteration++; if (loops && iteration == loops) break; } fprintf(stdout, "\n"); ret = 0; exit_close_error: if (close(fd) == -1) perror("Failed to close GPIO character device file"); free(chrdev_name); return ret; } void print_usage(void) { fprintf(stderr, "Usage: gpio-hammer [options]...\n" "Hammer GPIO lines, 0->1->0->1...\n" " -n Hammer GPIOs on a named device (must be stated)\n" " -o Offset[s] to hammer, at least one, several can be stated\n" " [-c ] Do loops (optional, infinite loop if not stated)\n" " -? This helptext\n" "\n" "Example:\n" "gpio-hammer -n gpiochip0 -o 4\n" ); } int main(int argc, char **argv) { const char *device_name = NULL; unsigned int lines[GPIOHANDLES_MAX]; unsigned int loops = 0; int nlines; int c; int i; i = 0; while ((c = getopt(argc, argv, "c:n:o:?")) != -1) { switch (c) { case 'c': loops = strtoul(optarg, NULL, 10); break; case 'n': device_name = optarg; break; case 'o': /* * Avoid overflow. Do not immediately error, we want to * be able to accurately report on the amount of times * '-o' was given to give an accurate error message */ if (i < GPIOHANDLES_MAX) lines[i] = strtoul(optarg, NULL, 10); i++; break; case '?': print_usage(); return -1; } } if (i >= GPIOHANDLES_MAX) { fprintf(stderr, "Only %d occurences of '-o' are allowed, %d were found\n", GPIOHANDLES_MAX, i + 1); return -1; } nlines = i; if (!device_name || !nlines) { print_usage(); return -1; } return hammer_device(device_name, lines, nlines, loops); }