diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2016-04-26 10:47:09 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-06-15 09:29:04 +0200 |
commit | 2a144dd09118d9ba8cb57ef65eb573af222c455c (patch) | |
tree | 21e57956bbbbcb623cb7c55a419247b1ebf949d7 /tools/gpio | |
parent | gpio: userspace ABI for reading/writing GPIO lines (diff) | |
download | linux-2a144dd09118d9ba8cb57ef65eb573af222c455c.tar.xz linux-2a144dd09118d9ba8cb57ef65eb573af222c455c.zip |
tools/gpio: add the gpio-hammer tool
The gpio-hammer is used from userspace as an example of how
to retrieve a GPIO handle for one or several GPIO lines and
hammer the outputs from low to high and back again. It will
pulse the selected lines once per second for a specified
number of times or indefinitely if no loop count is
supplied.
Example output:
$ gpio-hammer -n gpiochip0 -o5 -o6 -o7
Hammer lines [5, 6, 7] on gpiochip0, initial states: [1, 1, 1]
[-] [5: 0, 6: 0, 7: 0]
Tested-by: Michael Welling <mwelling@ieee.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'tools/gpio')
-rw-r--r-- | tools/gpio/Makefile | 5 | ||||
-rw-r--r-- | tools/gpio/gpio-hammer.c | 189 |
2 files changed, 192 insertions, 2 deletions
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index c155d6bc47a7..aea23949054e 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -1,12 +1,13 @@ CC = $(CROSS_COMPILE)gcc CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -all: lsgpio +all: lsgpio gpio-hammer lsgpio: lsgpio.o gpio-utils.o +gpio-hammer: gpio-hammer.o gpio-utils.o %.o: %.c gpio-utils.h .PHONY: clean clean: - rm -f *.o lsgpio + rm -f *.o lsgpio gpio-hammer diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c new file mode 100644 index 000000000000..37b3f141053d --- /dev/null +++ b/tools/gpio/gpio-hammer.c @@ -0,0 +1,189 @@ +/* + * 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 <device-name> -o <offset1> -o <offset2> + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <poll.h> +#include <fcntl.h> +#include <getopt.h> +#include <sys/ioctl.h> +#include <linux/gpio.h> + +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 <name> Hammer GPIOs on a named device (must be stated)\n" + " -o <n> Offset[s] to hammer, at least one, several can be stated\n" + " [-c <n>] Do <n> 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': + lines[i] = strtoul(optarg, NULL, 10); + i++; + break; + case '?': + print_usage(); + return -1; + } + } + nlines = i; + + if (!device_name || !nlines) { + print_usage(); + return -1; + } + return hammer_device(device_name, lines, nlines, loops); +} |