diff mbox

[2/2] tools/gpio: add the gpio-hammer tool

Message ID 1461660866-18683-2-git-send-email-linus.walleij@linaro.org
State New
Headers show

Commit Message

Linus Walleij April 26, 2016, 8:54 a.m. UTC
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]

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 tools/gpio/Makefile      |   5 +-
 tools/gpio/gpio-hammer.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+), 2 deletions(-)
 create mode 100644 tools/gpio/gpio-hammer.c

Comments

Michael Welling April 27, 2016, 4 p.m. UTC | #1
On Tue, Apr 26, 2016 at 10:54:26AM +0200, Linus Walleij wrote:
> 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]
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Tested-by: Michael Welling <mwelling@ieee.org>

Below is the output from my target. You will notice that a kernel warning is spewed out if I use the mcp23s08.
The processor GPIOs work fine as verified by blinking LEDs.

root@som3517-som200:~# ./lsgpio 
GPIO chip: gpiochip4, "mcp23s08", 8 GPIO lines
        line  0: unnamed unused
        line  1: unnamed unused
        line  2: unnamed unused
        line  3: unnamed unused
        line  4: unnamed unused
        line  5: unnamed unused
        line  6: unnamed unused
        line  7: unnamed unused
GPIO chip: gpiochip3, "gpio", 32 GPIO lines
        line  0: unnamed unused
        line  1: unnamed unused
        line  2: unnamed unused
        line  3: unnamed unused
        line  4: unnamed unused
        line  5: unnamed unused
        line  6: unnamed unused
        line  7: unnamed unused
        line  8: unnamed "spi1.3" [kernel output]
        line  9: unnamed unused
        line 10: unnamed unused
        line 11: unnamed unused
        line 12: unnamed unused
        line 13: unnamed unused
        line 14: unnamed unused
        line 15: unnamed unused
        line 16: unnamed unused
        line 17: unnamed unused
        line 18: unnamed unused
        line 19: unnamed unused
        line 20: unnamed unused
        line 21: unnamed unused
        line 22: unnamed unused
        line 23: unnamed unused
        line 24: unnamed unused
        line 25: unnamed unused
        line 26: unnamed unused
        line 27: unnamed unused
        line 28: unnamed unused
        line 29: unnamed unused
        line 30: unnamed unused
        line 31: unnamed unused
GPIO chip: gpiochip2, "gpio", 32 GPIO lines
        line  0: unnamed unused
        line  1: unnamed unused
        line  2: unnamed unused
        line  3: unnamed unused
        line  4: unnamed unused
        line  5: unname[   40.820783] random: nonblocking pool is initialized
d unused
        line  6: unnamed unused
        line  7: unnamed unused
        line  8: unnamed unused
        line  9: unnamed unused
        line 10: unnamed unused
        line 11: unnamed unused
        line 12: unnamed unused
        line 13: unnamed unused
        line 14: unnamed unused
        line 15: unnamed unused
        line 16: unnamed unused
        line 17: unnamed unused
        line 18: unnamed unused
        line 19: unnamed unused
        line 20: unnamed unused
        line 21: unnamed unused
        line 22: unnamed unused
        line 23: unnamed unused
        line 24: unnamed unused
        line 25: unnamed unused
        line 26: unnamed unused
        line 27: unnamed unused
        line 28: unnamed unused
        line 29: unnamed unused
        line 30: unnamed unused
        line 31: unnamed unused
GPIO chip: gpiochip1, "gpio", 32 GPIO lines
        line  0: unnamed unused
        line  1: unnamed unused
        line  2: unnamed unused
        line  3: unnamed unused
        line  4: unnamed unused
        line  5: unnamed unused
        line  6: unnamed unused
        line  7: unnamed unused
        line  8: unnamed unused
        line  9: unnamed unused
        line 10: unnamed unused
        line 11: unnamed unused
        line 12: unnamed "cd" [kernel active-low]
        line 13: unnamed "enable" [kernel output]
        line 14: unnamed "spi1.2" [kernel output]
        line 15: unnamed unused
        line 16: unnamed unused
        line 17: unnamed unused
        line 18: unnamed unused
        line 19: unnamed unused
        line 20: unnamed unused
        line 21: unnamed unused
        line 22: unnamed unused
        line 23: unnamed unused
        line 24: unnamed unused
        line 25: unnamed unused
        line 26: unnamed unused
        line 27: unnamed unused
        line 28: unnamed unused
        line 29: unnamed unused
        line 30: unnamed unused
        line 31: unnamed unused
GPIO chip: gpiochip0, "gpio", 32 GPIO lines
        line  0: unnamed unused
        line  1: unnamed unused
        line  2: unnamed unused
        line  3: unnamed unused
        line  4: unnamed unused
        line  5: unnamed "spi1.0" [kernel output]
        line  6: unnamed "spi1.1" [kernel output]
        line  7: unnamed unused
        line  8: unnamed unused
        line  9: unnamed unused
        line 10: unnamed unused
        line 11: unnamed unused
        line 12: unnamed unused
        line 13: unnamed unused
        line 14: unnamed unused
        line 15: unnamed unused
        line 16: unnamed unused
        line 17: unnamed unused
        line 18: unnamed unused
        line 19: unnamed unused
        line 20: unnamed unused
        line 21: unnamed unused
        line 22: unnamed unused
        line 23: unnamed unused
        line 24: unnamed unused
        line 25: unnamed unused
        line 26: unnamed unused
        line 27: unnamed unused
        line 28: unnamed unused
        line 29: unnamed unused
        line 30: unnamed unused
        line 31: unnamed unused
root@som3517-som200:~# ./gpio-hammer -n gpiochip0 -o7
Hammer lines [7] on gpiochip0, initial states: [1]
^C] [7: 1]
root@som3517-som200:~# ./gpio-hammer -n gpiochip3 -o4                                                                                                                                                                                        
Hammer lines [4] on gpiochip3, initial states: [1]
^C] [4: 1]
root@som3517-som200:~# ./gpio-hammer -n gpiochip1 -o9                                                                                                                                                                                        
Hammer lines [9] on gpiochip1, initial states: [1]
^C] [9: 0]
root@som3517-som200:~# ./gpio-hammer -n gpiochip4 -o0                                                                                                                                                                                        
[  187.511606] ------------[ cut here ]------------
[  187.516949] WARNING: CPU: 0 PID: 830 at /home/michael/projects/linux/linux-git/drivers/gpio/gpiolib.c:1907 gpiod_get_value+0x60/0xa4
[  187.529770] Modules linked in:
[  187.533082] CPU: 0 PID: 830 Comm: gpio-hammer Tainted: G        W       4.6.0-rc1-00084-g6f4ee91-dirty #2
[  187.543231] Hardware name: Generic AM33XX (Flattened Device Tree)
[  187.549753] [<c010fee4>] (unwind_backtrace) from [<c010c10c>] (show_stack+0x10/0x14)
[  187.557993] [<c010c10c>] (show_stack) from [<c0464074>] (dump_stack+0xb0/0xe4)
[  187.565695] [<c0464074>] (dump_stack) from [<c01345d4>] (__warn+0xd4/0x100)
[  187.573109] [<c01345d4>] (__warn) from [<c01346ac>] (warn_slowpath_null+0x20/0x28)
[  187.581163] [<c01346ac>] (warn_slowpath_null) from [<c049e3d8>] (gpiod_get_value+0x60/0xa4)
[  187.590046] [<c049e3d8>] (gpiod_get_value) from [<c049f7a8>] (linehandle_ioctl+0x114/0x19c)
[  187.598932] [<c049f7a8>] (linehandle_ioctl) from [<c0296710>] (do_vfs_ioctl+0x8c/0xa18)
[  187.607445] [<c0296710>] (do_vfs_ioctl) from [<c0297108>] (SyS_ioctl+0x6c/0x7c)
[  187.615233] [<c0297108>] (SyS_ioctl) from [<c0107820>] (ret_fast_syscall+0x0/0x1c)
[  187.623616] ---[ end trace 9b8ac986d34a8efa ]---
.
.

root@som3517-som200:~# uname -a
Linux som3517-som200 4.6.0-rc1-00084-g6f4ee91-dirty #2 SMP Wed Apr 27 10:46:00 CDT 2016 armv7l GNU/Linux
root@som3517-som200:~# cat /proc/cpuinfo 
processor       : 0
model name      : ARMv7 Processor rev 2 (v7l)
BogoMIPS        : 273.94
Features        : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x3
CPU part        : 0xc08
CPU revision    : 2

Hardware        : Generic AM33XX (Flattened Device Tree)
Revision        : 0000
Serial          : 0000000000000000

> ---
>  tools/gpio/Makefile      |   5 +-
>  tools/gpio/gpio-hammer.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 192 insertions(+), 2 deletions(-)
>  create mode 100644 tools/gpio/gpio-hammer.c
> 
> 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);
> +}
> -- 
> 2.4.11
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexander Stein April 28, 2016, 7:47 a.m. UTC | #2
On Tuesday 26 April 2016 10:54:26, Linus Walleij wrote:
> 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]
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

This might be a stupid question, but how do I build those tools? I've never 
done this before and failed with the following command:
> ARCH=arm CROSS_COMPILE=/opt/OSELAS.Toolchain-2013.12.2/arm-cortexa8-linux-
gnueabi/gcc-4.8.3-glibc-2.18-binutils-2.24-kernel-3.12-sanitized/bin/arm-
cortexa8-linux-gnueabi- make O=build_arm V=1 tools/gpio

results:

make -C /home/alex/repo/linux/build_arm KBUILD_SRC=/home/alex/repo/linux \
-f /home/alex/repo/linux/Makefile tools/gpio
make[1]: Verzeichnis „/home/alex/repo/linux/build_arm“ wird betreten
mkdir -p ./tools
make LDFLAGS= MAKEFLAGS="" O=/home/alex/repo/linux/build_arm subdir=tools -C 
../tools/ gpio
mkdir -p /home/alex/repo/linux/build_arm/tools/gpio && make 
O=/home/alex/repo/linux/build_arm subdir=tools/gpio --no-print-directory -C 
gpio 
/opt/OSELAS.Toolchain-2013.12.2/arm-cortexa8-linux-gnueabi/gcc-4.8.3-
glibc-2.18-binutils-2.24-kernel-3.12-sanitized/bin/arm-cortexa8-linux-gnueabi-
gcc -O2 -Wall -g -D_GNU_SOURCE   -c -o lsgpio.o lsgpio.c
lsgpio.c:25:24: fatal error: linux/gpio.h: No such file or directory
 #include <linux/gpio.h>

Apparently the includes to $(srcdir)/include and 
$(srcdir)/arch/${ARCH}/include are missing.

Best regards,
Alexander

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij May 31, 2016, 11:59 a.m. UTC | #3
On Wed, Apr 27, 2016 at 6:00 PM, Michael Welling <mwelling@ieee.org> wrote:
> On Tue, Apr 26, 2016 at 10:54:26AM +0200, Linus Walleij wrote:
>> 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]
>>
>> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>
> Tested-by: Michael Welling <mwelling@ieee.org>

Thanks! :)

> Below is the output from my target.

You can now get rid of all the "unnamed" in the first column
by supplying the line/rail names in gpio-line-names = "A", "B" ...;
in the GPIO controller node in the device tree for the platform,
if it uses device tree too boot.

> You will notice that a kernel warning is
> spewed out if I use the mcp23s08.
> The processor GPIOs work fine as verified by blinking LEDs.
>
> root@som3517-som200:~# ./lsgpio
> GPIO chip: gpiochip4, "mcp23s08", 8 GPIO lines
>         line  0: unnamed unused
>         line  1: unnamed unused
>         line  2: unnamed unused
>         line  3: unnamed unused
>         line  4: unnamed unused
>         line  5: unnamed unused
>         line  6: unnamed unused
>         line  7: unnamed unused

> root@som3517-som200:~# ./gpio-hammer -n gpiochip4 -o0
> [  187.511606] ------------[ cut here ]------------
> [  187.516949] WARNING: CPU: 0 PID: 830 at /home/michael/projects/linux/linux-git/drivers/gpio/gpiolib.c:1907 gpiod_get_value+0x60/0xa4

Ah that's right, I have to use gpiod_get_value_cansleep(). Will
fix that.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michael Welling June 1, 2016, 3:43 a.m. UTC | #4
On Tue, May 31, 2016 at 01:59:42PM +0200, Linus Walleij wrote:
> On Wed, Apr 27, 2016 at 6:00 PM, Michael Welling <mwelling@ieee.org> wrote:
> > On Tue, Apr 26, 2016 at 10:54:26AM +0200, Linus Walleij wrote:
> >> 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]
> >>
> >> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> >
> > Tested-by: Michael Welling <mwelling@ieee.org>
> 
> Thanks! :)

No problem. I wish I could help more.
I like how the support has progressed.

Did you ever find a solution for the exhausted char dev problem?

> 
> > Below is the output from my target.
> 
> You can now get rid of all the "unnamed" in the first column
> by supplying the line/rail names in gpio-line-names = "A", "B" ...;
> in the GPIO controller node in the device tree for the platform,
> if it uses device tree too boot.

Yeah I saw that.. not bored enough to name all of the GPIOs.

> 
> > You will notice that a kernel warning is
> > spewed out if I use the mcp23s08.
> > The processor GPIOs work fine as verified by blinking LEDs.
> >
> > root@som3517-som200:~# ./lsgpio
> > GPIO chip: gpiochip4, "mcp23s08", 8 GPIO lines
> >         line  0: unnamed unused
> >         line  1: unnamed unused
> >         line  2: unnamed unused
> >         line  3: unnamed unused
> >         line  4: unnamed unused
> >         line  5: unnamed unused
> >         line  6: unnamed unused
> >         line  7: unnamed unused
> 
> > root@som3517-som200:~# ./gpio-hammer -n gpiochip4 -o0
> > [  187.511606] ------------[ cut here ]------------
> > [  187.516949] WARNING: CPU: 0 PID: 830 at /home/michael/projects/linux/linux-git/drivers/gpio/gpiolib.c:1907 gpiod_get_value+0x60/0xa4
> 
> Ah that's right, I have to use gpiod_get_value_cansleep(). Will
> fix that.
> 
> Yours,
> Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij June 1, 2016, 5:35 p.m. UTC | #5
On Wed, Jun 1, 2016 at 5:43 AM, Michael Welling <mwelling@ieee.org> wrote:

> Did you ever find a solution for the exhausted char dev problem?

Not really. It seems it turned up that all systems that bugged were randomly
generated QEMU models, not real systems.

They were also really doing far out stuff already, overwriting existing chardevs
all over the place, which can be seen in logs after commit
49db08c35887 "chrdev: emit a warning when we go below dynamic major range"
which I got merged.

I'm now working on an event ABI so we get feature complete and also surpass
the old sysfs.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michael Welling June 1, 2016, 6:09 p.m. UTC | #6
On Wed, Jun 01, 2016 at 07:35:28PM +0200, Linus Walleij wrote:
> On Wed, Jun 1, 2016 at 5:43 AM, Michael Welling <mwelling@ieee.org> wrote:
> 
> > Did you ever find a solution for the exhausted char dev problem?
> 
> Not really. It seems it turned up that all systems that bugged were randomly
> generated QEMU models, not real systems.
> 
> They were also really doing far out stuff already, overwriting existing chardevs
> all over the place, which can be seen in logs after commit
> 49db08c35887 "chrdev: emit a warning when we go below dynamic major range"
> which I got merged.
>

Yeah I noticed that their config was pretty crazy.
 
> I'm now working on an event ABI so we get feature complete and also surpass
> the old sysfs.
>

Okay I will review and test it when the patch shows up.

Is there a way to name a group of GPIOs?

It seems you are passing around a byte of data for each GPIO state.
Is there a reason why the bits couldn't bit masked into single variable
given the max number of handles is 64?

> Yours,
> Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij June 1, 2016, 9:40 p.m. UTC | #7
On Wed, Jun 1, 2016 at 8:09 PM, Michael Welling <mwelling@ieee.org> wrote:

> Is there a way to name a group of GPIOs?

Do you mean from the producer side or the consumer side?
There is gpio-line-names in DT for the producer side.

From the consumer side the same consumer name will be used
on all lines if more than one is selected, which I think makes
sense. (It's just a label after all.)

> It seems you are passing around a byte of data for each GPIO state.
> Is there a reason why the bits couldn't bit masked into single variable
> given the max number of handles is 64?

Sorry not following, I guess you need to post me some part of
the patch or so...

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michael Welling June 2, 2016, 2:59 p.m. UTC | #8
On Wed, Jun 01, 2016 at 11:40:04PM +0200, Linus Walleij wrote:
> On Wed, Jun 1, 2016 at 8:09 PM, Michael Welling <mwelling@ieee.org> wrote:
> 
> > Is there a way to name a group of GPIOs?
> 
> Do you mean from the producer side or the consumer side?

Producer side is what I am thinking.

> There is gpio-line-names in DT for the producer side.
> 
The gpio-line-names are naming individual GPIO on a controller.
I am looking to take a set of GPIOs and name them as a group and
be able to access them by that name. Either individually or
simultaneously.
 
> From the consumer side the same consumer name will be used
> on all lines if more than one is selected, which I think makes
> sense. (It's just a label after all.)
> 
> > It seems you are passing around a byte of data for each GPIO state.
> > Is there a reason why the bits couldn't bit masked into single variable
> > given the max number of handles is 64?
> 
> Sorry not following, I guess you need to post me some part of
> the patch or so...

+       fprintf(stdout, "] on %s, initial states: [", device_name);
+       for (i = 0; i < nlines; i++) {
+               fprintf(stdout, "%d", data.values[i]);

data.values[i];

Each bit is stored in a byte.

> 
> Yours,
> Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij June 15, 2016, 9:48 a.m. UTC | #9
On Thu, Jun 2, 2016 at 4:59 PM, Michael Welling <mwelling@ieee.org> wrote:
> On Wed, Jun 01, 2016 at 11:40:04PM +0200, Linus Walleij wrote:
>> On Wed, Jun 1, 2016 at 8:09 PM, Michael Welling <mwelling@ieee.org> wrote:
>>
>> > Is there a way to name a group of GPIOs?
>>
>> Do you mean from the producer side or the consumer side?
>
> Producer side is what I am thinking.
>
>> There is gpio-line-names in DT for the producer side.
>>
> The gpio-line-names are naming individual GPIO on a controller.
> I am looking to take a set of GPIOs and name them as a group and
> be able to access them by that name. Either individually or
> simultaneously.

There is no such mechanism currently, all lines are individual
resources.

>> Sorry not following, I guess you need to post me some part of
>> the patch or so...
>
> +       fprintf(stdout, "] on %s, initial states: [", device_name);
> +       for (i = 0; i < nlines; i++) {
> +               fprintf(stdout, "%d", data.values[i]);
>
> data.values[i];
>
> Each bit is stored in a byte.

Yeah the userspace interface is wasteful in that sense. It's a trade-off
between storage and simplicity and I had to choose something.

If I try to bitstuff the bits then I need to add another ABI to describe
how the bits are stuffed in the words. So I get complexity somewhere
else instead.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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);
+}