forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Linus Walleij <[email protected]>
- Loading branch information
Showing
2 changed files
with
192 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |