All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/3] Add gpio test framework
@ 2016-10-14  2:48 Bamvor Jian Zhang
  2016-10-14  2:48 ` [PATCH v4 1/3] tools/gpio: add gpio basic opereations Bamvor Jian Zhang
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Bamvor Jian Zhang @ 2016-10-14  2:48 UTC (permalink / raw)
  To: linus.walleij; +Cc: linux-gpio, broonie, mwelling, shuahkh

These series of patches try to add support for testing of gpio
subsystem based on the proposal from Linus Walleij. The first three
version is here[1][2][3].

The basic idea is implement a virtual gpio device(gpio-mockup) base
on gpiolib. Tester could test the gpiolib by manipulating gpio-mockup
device through chardev(default) or sysfs and check the result from
debugfs. Reference the following figure:

   sysfs/chardev      debugfs
     |                   |
  gpiolib----------------/
     |
 gpio-mockup

In order to avoid conflict with other gpio exist in the system,
only dynamic allocation is tested by default. User could pass -f to
do full test.

The test script could also test other (real) gpio device, such as
pl061 in my qemu:
./gpio-mockup.sh -m 9030000.pl061

Originally, there are 5 patches. 2 of them are merged by Linus:
a6a1cf3 gpio: MAINTAINERS: Add an entry for GPIO mockup driver
0f98dd1 gpio/mockup: add virtual gpio device

There series only include the others:
tools/gpio: add gpio basic opereations
tools/gpio: re-work gpio hammer with gpio operations
selftest/gpio: add gpio test case

[1] http://comments.gmane.org/gmane.linux.kernel.gpio/11883
[2] http://www.spinics.net/lists/linux-gpio/msg11700.html
[2] http://www.spinics.net/lists/linux-gpio/msg16255.html

Changes since v3:
1.  Rename the api in gpio-utils.[ch] with gpiotools.
2.  Update in kernel document according to the
    "Documentation/kernel-docs.txt", and move it to implementation.
3.  Remove useless label of goto according to the suggestion from
    Michael Welling.

Changes since v2:
1.  Switch to chardev.
2.  Add basic gpio operation for chardev.

Changes since v1:
1.  Change value of gpio to boolean.
2.  Only test dynamic allocation by default.

Bamvor Jian Zhang (3):
  tools/gpio: add gpio basic opereations
  tools/gpio: re-work gpio hammer with gpio operations
  selftest/gpio: add gpio test case

 tools/gpio/gpio-hammer.c                           |  67 ++---
 tools/gpio/gpio-utils.c                            | 257 ++++++++++++++++
 tools/gpio/gpio-utils.h                            |  16 +
 tools/testing/selftests/Makefile                   |   1 +
 tools/testing/selftests/gpio/Makefile              |  23 ++
 tools/testing/selftests/gpio/gpio-mockup-chardev.c | 324 +++++++++++++++++++++
 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh  | 134 +++++++++
 tools/testing/selftests/gpio/gpio-mockup.sh        | 200 +++++++++++++
 8 files changed, 972 insertions(+), 50 deletions(-)
 create mode 100644 tools/testing/selftests/gpio/Makefile
 create mode 100644 tools/testing/selftests/gpio/gpio-mockup-chardev.c
 create mode 100755 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
 create mode 100755 tools/testing/selftests/gpio/gpio-mockup.sh

-- 
1.8.4.5


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 1/3] tools/gpio: add gpio basic opereations
  2016-10-14  2:48 [PATCH v4 0/3] Add gpio test framework Bamvor Jian Zhang
@ 2016-10-14  2:48 ` Bamvor Jian Zhang
  2016-10-21 11:46   ` Linus Walleij
  2016-10-14  2:48 ` [PATCH v4 2/3] tools/gpio: re-work gpio hammer with gpio operations Bamvor Jian Zhang
  2016-10-14  2:48 ` [PATCH v4 3/3] selftest/gpio: add gpio test case Bamvor Jian Zhang
  2 siblings, 1 reply; 13+ messages in thread
From: Bamvor Jian Zhang @ 2016-10-14  2:48 UTC (permalink / raw)
  To: linus.walleij; +Cc: linux-gpio, broonie, mwelling, shuahkh

From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

Add basic gpio operations. User could get/set gpio value for specific
line of gpiochip.

Reference "tools/gpio/gpio-hammer.c" or
"tools/testing/selftest/gpio/gpio-mockup-chardev.c" for how to use it.

Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
Reviewed-by: Michael Welling <mwelling@ieee.org>
---
 tools/gpio/gpio-utils.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/gpio/gpio-utils.h |  16 +++
 2 files changed, 273 insertions(+)

diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c
index 8208718..f6209cd 100644
--- a/tools/gpio/gpio-utils.c
+++ b/tools/gpio/gpio-utils.c
@@ -2,10 +2,267 @@
  * GPIO tools - helpers library for the GPIO tools
  *
  * Copyright (C) 2015 Linus Walleij
+ * Copyright (C) 2016 Bamvor Jian Zhang
  *
  * 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.
  */
 
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <linux/gpio.h>
 #include "gpio-utils.h"
+
+#define COMSUMER "gpio-utils"
+
+/**
+ * doc: Operation of gpio
+ *
+ * Provide the api of gpiochip for chardev interface. There are two
+ * types of api.  The first one provide as same function as each
+ * ioctl, including request and release for lines of gpio, read/write
+ * the value of gpio. If the user want to do lots of read and write of
+ * lines of gpio, user should use this type of api.
+ *
+ * The second one provide the easy to use api for user. Each of the
+ * following api will request gpio lines, do the operation and then
+ * release these lines.
+ */
+/**
+ * gpiotools_request_linehandle() - request gpio lines in a gpiochip
+ * @device_name:	The name of gpiochip without prefix "/dev/",
+ *			such as "gpiochip0"
+ * @lines:		An array desired lines, specified by offset
+ *			index for the associated GPIO device.
+ * @nline:		The number of lines to request.
+ * @flag:		The new flag for requsted gpio. Reference
+ *			"linux/gpio.h" for the meaning of flag.
+ * @data:		Default value will be set to gpio when flag is
+ *			GPIOHANDLE_REQUEST_OUTPUT.
+ * @consumer_label:	The name of consumer, such as "sysfs",
+ *			"powerkey". This is useful for other users to
+ *			know who is using.
+ *
+ * Request gpio lines through the ioctl provided by chardev. User
+ * could call gpiotools_set_values() and gpiotools_get_values() to
+ * read and write respectively through the returned fd. Call
+ * gpiotools_release_linehandle() to release these lines after that.
+ *
+ * Return:		On success return the fd;
+ *			On failure return the errno.
+ */
+int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
+				 unsigned int nlines, unsigned int flag,
+				 struct gpiohandle_data *data,
+				 const char *consumer_label)
+{
+	struct gpiohandle_request req;
+	char *chrdev_name;
+	int fd;
+	int i;
+	int ret;
+
+	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;
+	}
+
+	for (i = 0; i < nlines; i++)
+		req.lineoffsets[i] = lines[i];
+
+	req.flags = flag;
+	strcpy(req.consumer_label, consumer_label);
+	req.lines = nlines;
+	if (flag & GPIOHANDLE_REQUEST_OUTPUT)
+		memcpy(req.default_values, data, sizeof(req.default_values));
+
+	ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
+	if (ret == -1) {
+		ret = -errno;
+		fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",
+			ret);
+	}
+
+exit_close_error:
+	if (close(fd) == -1)
+		perror("Failed to close GPIO character device file");
+	free(chrdev_name);
+	return ret < 0 ? ret : req.fd;
+}
+/**
+ * gpiotools_set_values(): Set the value of gpio(s)
+ * @fd:			The fd returned by
+ *			gpiotools_request_linehandle().
+ * @data:		The array of values want to set.
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_set_values(const int fd, struct gpiohandle_data *data)
+{
+	int ret;
+
+	ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data);
+	if (ret == -1) {
+		ret = -errno;
+		fprintf(stderr, "Failed to issue %s (%d)\n",
+			"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret);
+	}
+
+	return ret;
+}
+
+/**
+ * gpiotools_get_values(): Get the value of gpio(s)
+ * @fd:			The fd returned by
+ *			gpiotools_request_linehandle().
+ * @data:		The array of values get from hardware.
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_get_values(const int fd, struct gpiohandle_data *data)
+{
+	int ret;
+
+	ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data);
+	if (ret == -1) {
+		ret = -errno;
+		fprintf(stderr, "Failed to issue %s (%d)\n",
+			"GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret);
+	}
+
+	return ret;
+}
+
+/**
+ * gpiotools_release_linehandle(): Release the line(s) of gpiochip
+ * @fd:			The fd returned by
+ *			gpiotools_request_linehandle().
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_release_linehandle(const int fd)
+{
+	int ret;
+
+	ret = close(fd);
+	if (ret == -1) {
+		perror("Failed to close GPIO LINEHANDLE device file");
+		ret = -errno;
+	}
+
+	return ret;
+}
+
+/**
+ * gpiotools_get(): Get value from specific line
+ * @device_name:	The name of gpiochip without prefix "/dev/",
+ *			such as "gpiochip0"
+ * @line:		number of line, such as 2.
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_get(const char *device_name, unsigned int line)
+{
+	struct gpiohandle_data data;
+	unsigned int lines[] = {line};
+
+	gpiotools_gets(device_name, lines, 1, &data);
+	return data.values[0];
+}
+
+
+/**
+ * gpiotools_gets(): Get values from specific lines.
+ * @device_name:	The name of gpiochip without prefix "/dev/",
+ *			such as "gpiochip0".
+ * @lines:		An array desired lines, specified by offset
+ *			index for the associated GPIO device.
+ * @nline:		The number of lines to request.
+ * @data:		The array of values get from gpiochip.
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_gets(const char *device_name, unsigned int *lines,
+		   unsigned int nlines, struct gpiohandle_data *data)
+{
+	int fd;
+	int ret;
+	int ret_close;
+
+	ret = gpiotools_request_linehandle(device_name, lines, nlines,
+					   GPIOHANDLE_REQUEST_INPUT, data,
+					   COMSUMER);
+	if (ret < 0)
+		return ret;
+
+	fd = ret;
+	ret = gpiotools_get_values(fd, data);
+	ret_close = gpiotools_release_linehandle(fd);
+	return ret < 0 ? ret : ret_close;
+}
+
+/**
+ * gpiotools_set(): Set value to specific line
+ * @device_name:	The name of gpiochip without prefix "/dev/",
+ *			such as "gpiochip0"
+ * @line:		number of line, such as 2.
+ * @value:		The value of gpio, must be 0(low) or 1(high).
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_set(const char *device_name, unsigned int line,
+		  unsigned int value)
+{
+	struct gpiohandle_data data;
+	unsigned int lines[] = {line};
+
+	data.values[0] = value;
+	return gpiotools_sets(device_name, lines, 1, &data);
+}
+
+/**
+ * gpiotools_sets(): Set values to specific lines.
+ * @device_name:	The name of gpiochip without prefix "/dev/",
+ *			such as "gpiochip0".
+ * @lines:		An array desired lines, specified by offset
+ *			index for the associated GPIO device.
+ * @nline:		The number of lines to request.
+ * @data:		The array of values set to gpiochip, must be
+ *			0(low) or 1(high).
+ *
+ * Return:		On success return 0;
+ *			On failure return the errno.
+ */
+int gpiotools_sets(const char *device_name, unsigned int *lines,
+		   unsigned int nlines, struct gpiohandle_data *data)
+{
+	int ret;
+
+	ret = gpiotools_request_linehandle(device_name, lines, nlines,
+					   GPIOHANDLE_REQUEST_OUTPUT, data,
+					   COMSUMER);
+	if (ret < 0)
+		return ret;
+
+	return gpiotools_release_linehandle(ret);
+}
+
diff --git a/tools/gpio/gpio-utils.h b/tools/gpio/gpio-utils.h
index 5f57133..344ea04 100644
--- a/tools/gpio/gpio-utils.h
+++ b/tools/gpio/gpio-utils.h
@@ -24,4 +24,20 @@ static inline int check_prefix(const char *str, const char *prefix)
 		strncmp(str, prefix, strlen(prefix)) == 0;
 }
 
+int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
+				 unsigned int nlines, unsigned int flag,
+				 struct gpiohandle_data *data,
+				 const char *consumer_label);
+int gpiotools_set_values(const int fd, struct gpiohandle_data *data);
+int gpiotools_get_values(const int fd, struct gpiohandle_data *data);
+int gpiotools_release_linehandle(const int fd);
+
+int gpiotools_get(const char *device_name, unsigned int line);
+int gpiotools_gets(const char *device_name, unsigned int *lines,
+		   unsigned int nlines, struct gpiohandle_data *data);
+int gpiotools_set(const char *device_name, unsigned int line,
+		  unsigned int value);
+int gpiotools_sets(const char *device_name, unsigned int *lines,
+		   unsigned int nlines, struct gpiohandle_data *data);
+
 #endif /* _GPIO_UTILS_H_ */
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 2/3] tools/gpio: re-work gpio hammer with gpio operations
  2016-10-14  2:48 [PATCH v4 0/3] Add gpio test framework Bamvor Jian Zhang
  2016-10-14  2:48 ` [PATCH v4 1/3] tools/gpio: add gpio basic opereations Bamvor Jian Zhang
@ 2016-10-14  2:48 ` Bamvor Jian Zhang
  2016-10-21 11:47   ` Linus Walleij
  2016-10-14  2:48 ` [PATCH v4 3/3] selftest/gpio: add gpio test case Bamvor Jian Zhang
  2 siblings, 1 reply; 13+ messages in thread
From: Bamvor Jian Zhang @ 2016-10-14  2:48 UTC (permalink / raw)
  To: linus.walleij; +Cc: linux-gpio, broonie, mwelling, shuahkh

From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
---
 tools/gpio/gpio-hammer.c | 67 ++++++++++++------------------------------------
 1 file changed, 17 insertions(+), 50 deletions(-)

diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c
index 37b3f14..f1eab58 100644
--- a/tools/gpio/gpio-hammer.c
+++ b/tools/gpio/gpio-hammer.c
@@ -23,54 +23,31 @@
 #include <getopt.h>
 #include <sys/ioctl.h>
 #include <linux/gpio.h>
+#include "gpio-utils.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);
+	memset(&data.values, 0, sizeof(data.values));
+	ret = gpiotools_request_linehandle(device_name, lines, nlines,
+					   GPIOHANDLE_REQUEST_OUTPUT, &data,
+					   "gpio-hammler");
 	if (ret < 0)
-		return -ENOMEM;
+		goto exit_error;
+	else
+		fd = ret;
 
-	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);
+	ret = gpiotools_get_values(fd, &data);
+	if (ret < 0)
 		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]);
@@ -92,23 +69,14 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
 		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);
+		ret = gpiotools_set_values(fd, &data);
+		if (ret < 0)
 			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);
+		ret = gpiotools_get_values(fd, &data);
+		if (ret < 0)
 			goto exit_close_error;
-		}
 
 		fprintf(stdout, "[%c] ", swirr[j]);
 		j++;
@@ -132,9 +100,8 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
 	ret = 0;
 
 exit_close_error:
-	if (close(fd) == -1)
-		perror("Failed to close GPIO character device file");
-	free(chrdev_name);
+	gpiotools_release_linehandle(fd);
+exit_error:
 	return ret;
 }
 
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 3/3] selftest/gpio: add gpio test case
  2016-10-14  2:48 [PATCH v4 0/3] Add gpio test framework Bamvor Jian Zhang
  2016-10-14  2:48 ` [PATCH v4 1/3] tools/gpio: add gpio basic opereations Bamvor Jian Zhang
  2016-10-14  2:48 ` [PATCH v4 2/3] tools/gpio: re-work gpio hammer with gpio operations Bamvor Jian Zhang
@ 2016-10-14  2:48 ` Bamvor Jian Zhang
  2016-10-21 11:54   ` Linus Walleij
  2 siblings, 1 reply; 13+ messages in thread
From: Bamvor Jian Zhang @ 2016-10-14  2:48 UTC (permalink / raw)
  To: linus.walleij; +Cc: linux-gpio, broonie, mwelling, shuahkh

From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

This test script try to do whitebox testing for gpio subsystem(
based on gpiolib). It manipulate gpio device through chardev or
sysfs and check the result from debugfs. This script test
gpio-mockup through chardev by default.

In details, it test the following things:
1.  Add single, multi gpiochip to do overlap check.
2.  Test direction and output value for valid pin.
3.  Test dynamic allocation of gpio base.

Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" to know how to
use it.

Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
---
 tools/testing/selftests/Makefile                   |   1 +
 tools/testing/selftests/gpio/Makefile              |  23 ++
 tools/testing/selftests/gpio/gpio-mockup-chardev.c | 324 +++++++++++++++++++++
 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh  | 134 +++++++++
 tools/testing/selftests/gpio/gpio-mockup.sh        | 200 +++++++++++++
 5 files changed, 682 insertions(+)
 create mode 100644 tools/testing/selftests/gpio/Makefile
 create mode 100644 tools/testing/selftests/gpio/gpio-mockup-chardev.c
 create mode 100755 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
 create mode 100755 tools/testing/selftests/gpio/gpio-mockup.sh

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index ff9e5f2..2437dbc 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -6,6 +6,7 @@ TARGETS += exec
 TARGETS += firmware
 TARGETS += ftrace
 TARGETS += futex
+TARGETS += gpio
 TARGETS += ipc
 TARGETS += kcmp
 TARGETS += lib
diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
new file mode 100644
index 0000000..e1144ba
--- /dev/null
+++ b/tools/testing/selftests/gpio/Makefile
@@ -0,0 +1,23 @@
+
+TEST_PROGS := gpio-mockup.sh
+TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES)
+BINARIES := gpio-mockup-chardev
+
+include ../lib.mk
+
+all: $(BINARIES)
+
+clean:
+	$(RM) $(BINARIES)
+
+CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
+LDLIBS += -lmount -I/usr/include/libmount
+
+$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
+
+../../../gpio/gpio-utils.o:
+	make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
+
+../../../../usr/include/linux/gpio.h:
+	make -C ../../../.. headers_install
+
diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
new file mode 100644
index 0000000..667e916
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
@@ -0,0 +1,324 @@
+/*
+ * GPIO chardev test helper
+ *
+ * Copyright (C) 2016 Bamvor Jian Zhang
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <libmount.h>
+#include <err.h>
+#include <dirent.h>
+#include <linux/gpio.h>
+#include "../../../gpio/gpio-utils.h"
+
+#define CONSUMER	"gpio-selftest"
+#define	GC_NUM		10
+enum direction {
+	OUT,
+	IN
+};
+
+static int get_debugfs(char **path)
+{
+	struct libmnt_context *cxt;
+	struct libmnt_table *tb;
+	struct libmnt_iter *itr = NULL;
+	struct libmnt_fs *fs;
+	int found = 0;
+
+	cxt = mnt_new_context();
+	if (!cxt)
+		err(EXIT_FAILURE, "libmount context allocation failed");
+
+	itr = mnt_new_iter(MNT_ITER_FORWARD);
+	if (!itr)
+		err(EXIT_FAILURE, "failed to initialize libmount iterator");
+
+	if (mnt_context_get_mtab(cxt, &tb))
+		err(EXIT_FAILURE, "failed to read mtab");
+
+	while (mnt_table_next_fs(tb, itr, &fs) == 0) {
+		const char *type = mnt_fs_get_fstype(fs);
+
+		if (!strcmp(type, "debugfs")) {
+			found = 1;
+			break;
+		}
+	}
+	if (found)
+		asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
+
+	mnt_free_iter(itr);
+	mnt_free_context(cxt);
+
+	if (!found)
+		return -1;
+
+	return 0;
+}
+
+static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
+{
+	char *debugfs;
+	FILE *f;
+	char *line = NULL;
+	size_t len = 0;
+	char *cur;
+	int found = 0;
+
+	if (get_debugfs(&debugfs) != 0)
+		err(EXIT_FAILURE, "debugfs is not mounted");
+
+	f = fopen(debugfs, "r");
+	if (!f)
+		err(EXIT_FAILURE, "read from gpio debugfs failed");
+
+	/*
+	 * gpio-2   (                    |gpio-selftest               ) in  lo
+	 */
+	while (getline(&line, &len, f) != -1) {
+		cur = strstr(line, consumer);
+		if (cur == NULL)
+			continue;
+
+		cur = strchr(line, ')');
+		if (!cur)
+			continue;
+
+		cur += 2;
+		if (!strncmp(cur, "out", 3)) {
+			*dir = OUT;
+			cur += 4;
+		} else if (!strncmp(cur, "in", 2)) {
+			*dir = IN;
+			cur += 4;
+		}
+
+		if (!strncmp(cur, "hi", 2))
+			*value = 1;
+		else if (!strncmp(cur, "lo", 2))
+			*value = 0;
+
+		found = 1;
+		break;
+	}
+	free(debugfs);
+	fclose(f);
+	free(line);
+
+	if (!found)
+		return -1;
+
+	return 0;
+}
+
+static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
+{
+	struct gpiochip_info *cinfo;
+	struct gpiochip_info *current;
+	const struct dirent *ent;
+	DIR *dp;
+	char *chrdev_name;
+	int fd;
+	int i = 0;
+
+	cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
+	if (!cinfo)
+		err(EXIT_FAILURE, "gpiochip_info allocation failed");
+
+	current = cinfo;
+	dp = opendir("/dev");
+	if (!dp) {
+		*ret = -errno;
+		goto error_out;
+	} else {
+		*ret = 0;
+	}
+
+	while (ent = readdir(dp), ent) {
+		if (check_prefix(ent->d_name, "gpiochip")) {
+			*ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
+			if (*ret < 0)
+				goto error_out;
+
+			fd = open(chrdev_name, 0);
+			if (fd == -1) {
+				*ret = -errno;
+				fprintf(stderr, "Failed to open %s\n",
+					chrdev_name);
+				goto error_close_dir;
+			}
+			*ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
+			if (*ret == -1) {
+				perror("Failed to issue CHIPINFO IOCTL\n");
+				goto error_close_dir;
+			}
+			close(fd);
+			if (strcmp(current->label, gpiochip_name) == 0
+			    || check_prefix(current->label, gpiochip_name)) {
+				*ret = 0;
+				current++;
+				i++;
+			}
+		}
+	}
+
+	if ((!*ret && i == 0) || *ret < 0) {
+		free(cinfo);
+		cinfo = NULL;
+	}
+	if (!*ret && i > 0) {
+		cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
+		*ret = i;
+	}
+
+error_close_dir:
+	closedir(dp);
+error_out:
+	if (*ret < 0)
+		err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
+
+	return cinfo;
+}
+
+int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
+{
+	struct gpiohandle_data data;
+	unsigned int lines[] = {line};
+	int fd;
+	int debugfs_dir = IN;
+	int debugfs_value = 0;
+	int ret;
+
+	data.values[0] = value;
+	ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
+					   CONSUMER);
+	if (ret < 0)
+		goto fail_out;
+	else
+		fd = ret;
+
+	ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
+	if (ret) {
+		ret = -EINVAL;
+		goto fail_out;
+	}
+	if (flag & GPIOHANDLE_REQUEST_INPUT) {
+		if (debugfs_dir != IN) {
+			errno = -EINVAL;
+			ret = -errno;
+		}
+	} else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
+		if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
+			debugfs_value = !debugfs_value;
+
+		if (!(debugfs_dir == OUT && value == debugfs_value))
+			errno = -EINVAL;
+		ret = -errno;
+
+	}
+	gpiotools_release_linehandle(fd);
+
+fail_out:
+	if (ret)
+		err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
+		    cinfo->name, line, flag, value);
+
+	return ret;
+}
+
+void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
+{
+	printf("line<%d>", line);
+	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
+	printf(".");
+	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
+	printf(".");
+	gpio_pin_test(cinfo, line,
+		      GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
+		      0);
+	printf(".");
+	gpio_pin_test(cinfo, line,
+		      GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
+		      1);
+	printf(".");
+	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
+	printf(".");
+}
+
+/*
+ * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
+ * Return 0 if successful or exit with EXIT_FAILURE if test failed.
+ * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
+ *			  gpio-mockup
+ * is_valid_gpio_chip:	  Whether the gpio_chip is valid. 1 means valid,
+ *			  0 means invalid which could not be found by
+ *			  list_gpiochip.
+ */
+int main(int argc, char *argv[])
+{
+	char *prefix;
+	int valid;
+	struct gpiochip_info *cinfo;
+	struct gpiochip_info *current;
+	int i;
+	int ret;
+
+	if (argc < 3) {
+		printf("Usage: %s prefix is_valid", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	prefix = argv[1];
+	valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
+
+	printf("Test gpiochip %s: ", prefix);
+	cinfo = list_gpiochip(prefix, &ret);
+	if (!cinfo) {
+		if (!valid && ret == 0) {
+			printf("Invalid test successful\n");
+			ret = 0;
+			goto out;
+		} else {
+			ret = -EINVAL;
+			goto out;
+		}
+	} else if (cinfo && !valid) {
+		ret = -EINVAL;
+		goto out;
+	}
+	current = cinfo;
+	for (i = 0; i < ret; i++) {
+		gpio_pin_tests(current, 0);
+		gpio_pin_tests(current, current->lines - 1);
+		gpio_pin_tests(current, random() % current->lines);
+		current++;
+	}
+	ret = 0;
+	printf("successful\n");
+
+out:
+	if (ret)
+		fprintf(stderr, "gpio<%s> test failed\n", prefix);
+
+	if (cinfo)
+		free(cinfo);
+
+	if (ret)
+		exit(EXIT_FAILURE);
+
+	return ret;
+}
diff --git a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
new file mode 100755
index 0000000..085d7a3
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
@@ -0,0 +1,134 @@
+
+is_consistent()
+{
+	val=
+
+	active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low`
+	val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value`
+	dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction`
+
+	gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"`
+	dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'`
+	val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'`
+	if [ $val_debugfs = "lo" ]; then
+		val=0
+	elif [ $val_debugfs = "hi" ]; then
+		val=1
+	fi
+
+	if [ $active_low_sysfs = "1" ]; then
+		if [ $val = "0" ]; then
+			val="1"
+		else
+			val="0"
+		fi
+	fi
+
+	if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
+		echo -n "."
+	else
+		echo "test fail, exit"
+		die
+	fi
+}
+
+test_pin_logic()
+{
+	nr=$1
+	direction=$2
+	active_low=$3
+	value=$4
+
+	echo $direction > $GPIO_SYSFS/gpio$nr/direction
+	echo $active_low > $GPIO_SYSFS/gpio$nr/active_low
+	if [ $direction = "out" ]; then
+		echo $value > $GPIO_SYSFS/gpio$nr/value
+	fi
+	is_consistent $nr
+}
+
+test_one_pin()
+{
+	nr=$1
+
+	echo -n "test pin<$nr>"
+
+	echo $nr > $GPIO_SYSFS/export 2>/dev/null
+
+	if [ X$? != X0 ]; then
+		echo "test GPIO pin $nr failed"
+		die
+	fi
+
+	#"Checking if the sysfs is consistent with debugfs: "
+	is_consistent $nr
+
+	#"Checking the logic of active_low: "
+	test_pin_logic $nr out 1 1
+	test_pin_logic $nr out 1 0
+	test_pin_logic $nr out 0 1
+	test_pin_logic $nr out 0 0
+
+	#"Checking the logic of direction: "
+	test_pin_logic $nr in 1 1
+	test_pin_logic $nr out 1 0
+	test_pin_logic $nr low 0 1
+	test_pin_logic $nr high 0 0
+
+	echo $nr > $GPIO_SYSFS/unexport
+
+	echo "successful"
+}
+
+test_one_pin_fail()
+{
+	nr=$1
+
+	echo $nr > $GPIO_SYSFS/export 2>/dev/null
+
+	if [ X$? != X0 ]; then
+		echo "test invalid pin $nr successful"
+	else
+		echo "test invalid pin $nr failed"
+		echo $nr > $GPIO_SYSFS/unexport 2>/dev/null
+		die
+	fi
+}
+
+list_chip()
+{
+	echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
+}
+
+test_chip()
+{
+	chip=$1
+	name=`basename $chip`
+	base=`cat $chip/base`
+	ngpio=`cat $chip/ngpio`
+	printf "%-10s %-5s %-5s\n" $name $base $ngpio
+	if [ $ngpio = "0" ]; then
+		echo "number of gpio is zero is not allowed".
+	fi
+	test_one_pin $base
+	test_one_pin $(($base + $ngpio - 1))
+	test_one_pin $((( RANDOM % $ngpio )  + $base ))
+}
+
+test_chips_sysfs()
+{
+       gpiochip=`list_chip $module`
+       if [ X"$gpiochip" = X ]; then
+               if [ X"$valid" = Xfalse ]; then
+                       echo "successful"
+               else
+                       echo "fail"
+                       die
+               fi
+       else
+               for chip in $gpiochip; do
+                       test_chip $chip
+               done
+       fi
+}
+
diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh
new file mode 100755
index 0000000..256b094
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio-mockup.sh
@@ -0,0 +1,200 @@
+#!/bin/bash
+
+#exit status
+#1: run as non-root user
+#2: sysfs/debugfs not mount
+#3: insert module fail when gpio-mockup is a module.
+#4: other reason.
+
+SYSFS=
+GPIO_SYSFS=
+GPIO_DRV_SYSFS=
+DEBUGFS=
+GPIO_DEBUGFS=
+dev_type=
+module=
+
+usage()
+{
+	echo "Usage:"
+	echo "$0 [-f] [-m name] [-t type]"
+	echo "-f:  full test. It maybe conflict with existence gpio device."
+	echo "-m:  module name, default name is gpio-mockup. It could also test"
+	echo "     other gpio device."
+	echo "-t:  interface type: sysfs or chardev(char device). The latter"
+	echo "     one is default"
+	echo ""
+	echo "$0 -h"
+	echo "This usage"
+}
+
+prerequisite()
+{
+	msg="skip all tests:"
+	if [ $UID != 0 ]; then
+		echo $msg must be run as root >&2
+		exit 1
+	fi
+	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
+	if [ ! -d "$SYSFS" ]; then
+		echo $msg sysfs is not mounted >&2
+		exit 2
+	fi
+	GPIO_SYSFS=`echo $SYSFS/class/gpio`
+	GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
+	DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+	if [ ! -d "$DEBUGFS" ]; then
+		echo $msg debugfs is not mounted >&2
+		exit 2
+	fi
+	GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
+	source gpio-mockup-sysfs.sh
+}
+
+try_insert_module()
+{
+	if [ -d "$GPIO_DRV_SYSFS" ]; then
+		echo "$GPIO_DRV_SYSFS exist. Skip insert module"
+	else
+		modprobe -q $module $1
+		if [ X$? != X0 ]; then
+			echo $msg insmod $module failed >&2
+			exit 3
+		fi
+	fi
+}
+
+remove_module()
+{
+	modprobe -r -q $module
+}
+
+die()
+{
+	remove_module
+	exit 4
+}
+
+test_chips()
+{
+	if [ X$dev_type = Xsysfs ]; then
+		test_chips_sysfs $*
+	else
+		$BASE/gpio-mockup-chardev $*
+	fi
+}
+
+gpio_test()
+{
+	param=$1
+	valid=$2
+
+	if [ X"$param" = X ]; then
+		die
+	fi
+	try_insert_module "gpio_mockup_ranges=$param"
+	echo -n "GPIO $module test with ranges: <"
+	echo "$param>: "
+	printf "%-10s %s\n" $param
+	test_chips $module $valid
+	remove_module
+}
+
+BASE=`dirname $0`
+
+dev_type=
+TEMP=`getopt -o fhm:t: -n '$0' -- "$@"`
+
+if [ "$?" != "0" ]; then
+        echo "Parameter process failed, Terminating..." >&2
+        exit 1
+fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+while true; do
+	case $1 in
+	-f)
+		full_test=true
+		shift
+		;;
+	-h)
+		usage
+		exit
+		;;
+	-m)
+		module=$2
+		shift 2
+		;;
+	-t)
+		dev_type=$2
+		shift 2
+		;;
+	--)
+		shift
+		break
+		;;
+	*)
+		echo "Internal error!"
+		exit 1
+		;;
+	esac
+done
+
+if [ X"$module" = X ]; then
+	module="gpio-mockup"
+fi
+
+if [ X$dev_type != Xsysfs ]; then
+	dev_type="chardev"
+fi
+
+prerequisite
+
+echo "1.  Test dynamic allocation of gpio successful means insert gpiochip and"
+echo "    manipulate gpio pin successful"
+gpio_test "-1,32" true
+gpio_test "-1,32,-1,32" true
+gpio_test "-1,32,-1,32,-1,32" true
+if [ X$full_test = Xtrue ]; then
+	gpio_test "-1,32,32,64" true
+	gpio_test "-1,32,40,64,-1,5" true
+	gpio_test "-1,32,32,64,-1,32" true
+	gpio_test "0,32,32,64,-1,32,-1,32" true
+	gpio_test "-1,32,-1,32,0,32,32,64" true
+	echo "2.  Do basic test: successful means insert gpiochip and"
+	echo "    manipulate gpio pin successful"
+	gpio_test "0,32" true
+	gpio_test "0,32,32,64" true
+	gpio_test "0,32,40,64,64,96" true
+fi
+echo "3.  Error test: successful means insert gpiochip failed"
+echo "3.1 Test number of gpio overflow"
+#Currently: The max number of gpio(1024) is defined in arm architecture.
+gpio_test "-1,32,-1,1024" false
+if [ X$full_test = Xtrue ]; then
+	echo "3.2 Test zero line of gpio"
+	gpio_test "0,0" false
+	echo "3.3 Test range overlap"
+	echo "3.3.1 Test corner case"
+	gpio_test "0,32,0,1" false
+	gpio_test "0,32,32,64,32,40" false
+	gpio_test "0,32,35,64,35,45" false
+	gpio_test "0,32,31,32" false
+	gpio_test "0,32,32,64,36,37" false
+	gpio_test "0,32,35,64,34,36" false
+	echo "3.3.2 Test inserting invalid second gpiochip"
+	gpio_test "0,32,30,35" false
+	gpio_test "0,32,1,5" false
+	gpio_test "10,32,9,14" false
+	gpio_test "10,32,30,35" false
+	echo "3.3.3 Test others"
+	gpio_test "0,32,40,56,39,45" false
+	gpio_test "0,32,40,56,30,33" false
+	gpio_test "0,32,40,56,30,41" false
+	gpio_test "0,32,40,56,20,21" false
+fi
+
+echo GPIO test PASS
+
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] tools/gpio: add gpio basic opereations
  2016-10-14  2:48 ` [PATCH v4 1/3] tools/gpio: add gpio basic opereations Bamvor Jian Zhang
@ 2016-10-21 11:46   ` Linus Walleij
  0 siblings, 0 replies; 13+ messages in thread
From: Linus Walleij @ 2016-10-21 11:46 UTC (permalink / raw)
  To: Bamvor Jian Zhang; +Cc: linux-gpio, Mark Brown, Michael Welling, shuahkh

On Fri, Oct 14, 2016 at 4:48 AM, Bamvor Jian Zhang
<bamvor.zhangjian@huawei.com> wrote:

> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>
> Add basic gpio operations. User could get/set gpio value for specific
> line of gpiochip.
>
> Reference "tools/gpio/gpio-hammer.c" or
> "tools/testing/selftest/gpio/gpio-mockup-chardev.c" for how to use it.
>
> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
> Reviewed-by: Michael Welling <mwelling@ieee.org>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/3] tools/gpio: re-work gpio hammer with gpio operations
  2016-10-14  2:48 ` [PATCH v4 2/3] tools/gpio: re-work gpio hammer with gpio operations Bamvor Jian Zhang
@ 2016-10-21 11:47   ` Linus Walleij
  0 siblings, 0 replies; 13+ messages in thread
From: Linus Walleij @ 2016-10-21 11:47 UTC (permalink / raw)
  To: Bamvor Jian Zhang; +Cc: linux-gpio, Mark Brown, Michael Welling, shuahkh

On Fri, Oct 14, 2016 at 4:48 AM, Bamvor Jian Zhang
<bamvor.zhangjian@huawei.com> wrote:

> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>
> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 3/3] selftest/gpio: add gpio test case
  2016-10-14  2:48 ` [PATCH v4 3/3] selftest/gpio: add gpio test case Bamvor Jian Zhang
@ 2016-10-21 11:54   ` Linus Walleij
  2016-10-21 14:43     ` Bamvor Zhang Jian
  2016-11-16 23:42     ` Shuah Khan
  0 siblings, 2 replies; 13+ messages in thread
From: Linus Walleij @ 2016-10-21 11:54 UTC (permalink / raw)
  To: Bamvor Jian Zhang; +Cc: linux-gpio, Mark Brown, Michael Welling, shuahkh

On Fri, Oct 14, 2016 at 4:48 AM, Bamvor Jian Zhang
<bamvor.zhangjian@huawei.com> wrote:

> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>
> This test script try to do whitebox testing for gpio subsystem(
> based on gpiolib). It manipulate gpio device through chardev or
> sysfs and check the result from debugfs. This script test
> gpio-mockup through chardev by default.
>
> In details, it test the following things:
> 1.  Add single, multi gpiochip to do overlap check.
> 2.  Test direction and output value for valid pin.
> 3.  Test dynamic allocation of gpio base.
>
> Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" to know how to
> use it.
>
> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

I like the overall idea with this, but some comments:

> +CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/

Is this really what people are doing?

Isn't -I/usr/include the right way to express this?

> +LDLIBS += -lmount -I/usr/include/libmount
> +
> +$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
> +
> +../../../gpio/gpio-utils.o:
> +       make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio

Ah, that is clever. I hope I can get an ACK from Shuah if this is
how we're supposed to handle cross dependencies of common
helper code in the kernel.

It looks a bit spaghetti, unfortunately.

> +../../../../usr/include/linux/gpio.h:
> +       make -C ../../../.. headers_install

Don't do this please, you would have to be root and it's very
fragile. How does tests in general resolve dependencies on
kernel headers? Please look around a bit and check what
they do. I think they just expect them to be installed.

I like the tests overall, but I'm a bit suspicious about the
sysfs tests. Maybe these should atleast print something
about the sysfs ABI being deprecated.

Anyways I merged the first two patches so now we only have to
figure out this final patch!

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 3/3] selftest/gpio: add gpio test case
  2016-10-21 11:54   ` Linus Walleij
@ 2016-10-21 14:43     ` Bamvor Zhang Jian
  2016-11-16 23:42     ` Shuah Khan
  1 sibling, 0 replies; 13+ messages in thread
From: Bamvor Zhang Jian @ 2016-10-21 14:43 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Bamvor Jian Zhang, linux-gpio, Mark Brown, Michael Welling,
	Shuah Khan, Ben Hutchings, rdunlap, acme

Hi, Linus

On 21 October 2016 at 19:54, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Fri, Oct 14, 2016 at 4:48 AM, Bamvor Jian Zhang
> <bamvor.zhangjian@huawei.com> wrote:
>
>> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>>
>> This test script try to do whitebox testing for gpio subsystem(
>> based on gpiolib). It manipulate gpio device through chardev or
>> sysfs and check the result from debugfs. This script test
>> gpio-mockup through chardev by default.
>>
>> In details, it test the following things:
>> 1.  Add single, multi gpiochip to do overlap check.
>> 2.  Test direction and output value for valid pin.
>> 3.  Test dynamic allocation of gpio base.
>>
>> Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" to know how to
>> use it.
>>
>> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>
> I like the overall idea with this, but some comments:
>
>> +CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
>
> Is this really what people are doing?
>
> Isn't -I/usr/include the right way to express this?
"/usr/include" is not correct for cross-compiling.

>
>> +LDLIBS += -lmount -I/usr/include/libmount
>> +
>> +$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
>> +
>> +../../../gpio/gpio-utils.o:
>> +       make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
>
> Ah, that is clever. I hope I can get an ACK from Shuah if this is
> how we're supposed to handle cross dependencies of common
> helper code in the kernel.
There are similar code in "tools/perf/tests/make". But I am not sure
if it is who I suppose to do.

> It looks a bit spaghetti, unfortunately.
>
>> +../../../../usr/include/linux/gpio.h:
>> +       make -C ../../../.. headers_install
>
> Don't do this please, you would have to be root and it's very
> fragile.
Sorry for this. At least, I should make use of INSTALL_HDR_PATH.

>How does tests in general resolve dependencies on
>kernel headers? Please look around a bit and check what
>they do. I think they just expect them to be installed.
I check the relative file through "grep usr.include tools/ -R -l",
there are three types:
1.  Use relative path like me but do not "make headers_install"
2.  Like my patch: use relative path and install headers when missing.
3.  Use /usr/include

And there is a discussion from Ben Hutchings[1]:
   Tools include UAPI headers in one of two ways, neither of which is
   reliable:
   - Assume the current headers are on the system include path
   - Include unprocessed UAPI headers through a relative path

   The right thing to do is to run 'make headers_install' and add
   usr/ to the front of the system include path.  But we'd want a
   way to avoid re-doing that when the UAPI headers haven't changed.

And there is a checker in "tools/perf/Makefile.perf" for $(PERF_IN)
target. But it is very long. We definitely need a better solution.
It may be in seperate patch.

how about introduce a dedicate Makefile in tools directory which
install necessary header to user defined path
(path/to/linux/usr/include by default)?

Or I just remove the following lines in this patch, and update it after
we find better solution?
../../../../usr/include/linux/gpio.h:
       make -C ../../../.. headers_install

cc: Ben Hutchings, Randy Dunlap and Arnaldo Carvalho de Melo.

>I like the tests overall, but I'm a bit suspicious about the
>sysfs tests. Maybe these should atleast print something
>about the sysfs ABI being deprecated.
Sound reasonable. I could add a prompt and wait user confirm when user
want to test through sysfs. Is it what you want?
I think we could remove the sysfs script when we remove the sysfs
interface of gpio in kernel.
>
>Anyways I merged the first two patches so now we only have to
>figure out this final patch!
Thanks all your help:)

Regards

Bamvor
>
>Yours,
>Linus Walleij

[1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2016-August/003270.html


> --
> 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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 3/3] selftest/gpio: add gpio test case
  2016-10-21 11:54   ` Linus Walleij
  2016-10-21 14:43     ` Bamvor Zhang Jian
@ 2016-11-16 23:42     ` Shuah Khan
  2016-11-18 11:41       ` Zhangjian (Bamvor)
  2016-11-21 10:16       ` [PATCH v5] " bamvor.zhangjian
  1 sibling, 2 replies; 13+ messages in thread
From: Shuah Khan @ 2016-11-16 23:42 UTC (permalink / raw)
  To: Linus Walleij, Bamvor Jian Zhang
  Cc: linux-gpio, Mark Brown, Michael Welling, Shuah Khan, Shuah Khan

On 10/21/2016 05:54 AM, Linus Walleij wrote:
> On Fri, Oct 14, 2016 at 4:48 AM, Bamvor Jian Zhang
> <bamvor.zhangjian@huawei.com> wrote:
> 
>> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>>
>> This test script try to do whitebox testing for gpio subsystem(
>> based on gpiolib). It manipulate gpio device through chardev or
>> sysfs and check the result from debugfs. This script test
>> gpio-mockup through chardev by default.
>>
>> In details, it test the following things:
>> 1.  Add single, multi gpiochip to do overlap check.
>> 2.  Test direction and output value for valid pin.
>> 3.  Test dynamic allocation of gpio base.
>>
>> Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" to know how to
>> use it.
>>
>> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
> 
> I like the overall idea with this, but some comments:
> 
>> +CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
> 
> Is this really what people are doing?
> 
> Isn't -I/usr/include the right way to express this?
> 
>> +LDLIBS += -lmount -I/usr/include/libmount
>> +
>> +$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
>> +
>> +../../../gpio/gpio-utils.o:
>> +       make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
> 
> Ah, that is clever. I hope I can get an ACK from Shuah if this is
> how we're supposed to handle cross dependencies of common
> helper code in the kernel.
> 
> It looks a bit spaghetti, unfortunately.

Yeah it does. Let's get this in for now and we can try to improve
it.

Sorry for the delay, here is the ack


> 
>> +../../../../usr/include/linux/gpio.h:
>> +       make -C ../../../.. headers_install
> 
> Don't do this please, you would have to be root and it's very
> fragile. How does tests in general resolve dependencies on
> kernel headers? Please look around a bit and check what
> they do. I think they just expect them to be installed.

Yeah - it is a good idea to have the user install the headers.
It shouldn't be done in the script without use consent.

> 
> I like the tests overall, but I'm a bit suspicious about the
> sysfs tests. Maybe these should atleast print something
> about the sysfs ABI being deprecated.

Has this concern been addressed. Once the above are fixed.

Acked-by: Shuah Khan <shuahkh@osg.samsung.com>

> 
> Anyways I merged the first two patches so now we only have to
> figure out this final patch!

Acked-by: Shuah Khan <shuahkh@osg.samsung.com>


> 
> Yours,
> Linus Walleij
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 3/3] selftest/gpio: add gpio test case
  2016-11-16 23:42     ` Shuah Khan
@ 2016-11-18 11:41       ` Zhangjian (Bamvor)
  2016-11-21 10:16       ` [PATCH v5] " bamvor.zhangjian
  1 sibling, 0 replies; 13+ messages in thread
From: Zhangjian (Bamvor) @ 2016-11-18 11:41 UTC (permalink / raw)
  To: Shuah Khan, Linus Walleij
  Cc: linux-gpio, Mark Brown, Michael Welling, Shuah Khan, Bamvor Zhang Jian

Hi, Shuah

On 2016/11/17 7:42, Shuah Khan wrote:
> On 10/21/2016 05:54 AM, Linus Walleij wrote:
>> On Fri, Oct 14, 2016 at 4:48 AM, Bamvor Jian Zhang
>> <bamvor.zhangjian@huawei.com> wrote:
>>
>>> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>>>
>>> This test script try to do whitebox testing for gpio subsystem(
>>> based on gpiolib). It manipulate gpio device through chardev or
>>> sysfs and check the result from debugfs. This script test
>>> gpio-mockup through chardev by default.
>>>
>>> In details, it test the following things:
>>> 1.  Add single, multi gpiochip to do overlap check.
>>> 2.  Test direction and output value for valid pin.
>>> 3.  Test dynamic allocation of gpio base.
>>>
>>> Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" to know how to
>>> use it.
>>>
>>> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>>
>> I like the overall idea with this, but some comments:
>>
>>> +CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
>>
>> Is this really what people are doing?
>>
>> Isn't -I/usr/include the right way to express this?
>>
>>> +LDLIBS += -lmount -I/usr/include/libmount
>>> +
>>> +$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
>>> +
>>> +../../../gpio/gpio-utils.o:
>>> +       make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
>>
>> Ah, that is clever. I hope I can get an ACK from Shuah if this is
>> how we're supposed to handle cross dependencies of common
>> helper code in the kernel.
>>
>> It looks a bit spaghetti, unfortunately.
>
> Yeah it does. Let's get this in for now and we can try to improve
> it.
>
> Sorry for the delay, here is the ack
>
>
>>
>>> +../../../../usr/include/linux/gpio.h:
>>> +       make -C ../../../.. headers_install
>>
>> Don't do this please, you would have to be root and it's very
>> fragile. How does tests in general resolve dependencies on
>> kernel headers? Please look around a bit and check what
>> they do. I think they just expect them to be installed.
>
> Yeah - it is a good idea to have the user install the headers.
> It shouldn't be done in the script without use consent.
I am tring to follow you. Do you want a better solution or just
install to usr/include(and update all the similar issue in
tools or selftests in another patch)?

../../../../usr/include/linux/gpio.h:
         make -C ../../../.. headers_install INSTALL_HDR_PATH=`pwd`/../../../../usr/
>
>>
>> I like the tests overall, but I'm a bit suspicious about the
>> sysfs tests. Maybe these should atleast print something
>> about the sysfs ABI being deprecated.
>
> Has this concern been addressed. Once the above are fixed.
Sure. I will add a warning for sysfs ABI of gpio.

Regards

Bamvor
>
> Acked-by: Shuah Khan <shuahkh@osg.samsung.com>
>
>>
>> Anyways I merged the first two patches so now we only have to
>> figure out this final patch!
>
> Acked-by: Shuah Khan <shuahkh@osg.samsung.com>
>
>
>>
>> Yours,
>> Linus Walleij
>>
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v5] selftest/gpio: add gpio test case
  2016-11-16 23:42     ` Shuah Khan
  2016-11-18 11:41       ` Zhangjian (Bamvor)
@ 2016-11-21 10:16       ` bamvor.zhangjian
  2016-12-13 12:42         ` Zhangjian (Bamvor)
  1 sibling, 1 reply; 13+ messages in thread
From: bamvor.zhangjian @ 2016-11-21 10:16 UTC (permalink / raw)
  To: shuahkh, linus.walleij
  Cc: linux-gpio, bamvor.zhangjian, broonie, mwelling, shuah, bamvor.zhangjian

From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

This test script try to do whitebox testing for gpio subsystem(based on
gpiolib). It manipulate gpio device through chardev or sysfs and check
the result from debugfs. This script test gpio-mockup through chardev by
default. User could test other gpio chip by passing the module name.
Some of the testcases are turned off by default to avoid the conflicting
with gpiochip in system.

In details, it test the following things:
1.  Test direction and output value for valid pin.
2.  Test dynamic allocation of gpio base.
3.  Add single, multi gpiochip to do overlap check.

Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" for usage.

Acked-by: Shuah Khan <shuahkh@osg.samsung.com>
Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
---
Changes since v4:
1.  Install header to to linux/usr/include instead of default path
2.  Print being deprecated for sysfs ABI.

 tools/testing/selftests/Makefile                   |   1 +
 tools/testing/selftests/gpio/Makefile              |  23 ++
 tools/testing/selftests/gpio/gpio-mockup-chardev.c | 324 +++++++++++++++++++++
 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh  | 134 +++++++++
 tools/testing/selftests/gpio/gpio-mockup.sh        | 201 +++++++++++++
 5 files changed, 683 insertions(+)
 create mode 100644 tools/testing/selftests/gpio/Makefile
 create mode 100644 tools/testing/selftests/gpio/gpio-mockup-chardev.c
 create mode 100755 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
 create mode 100755 tools/testing/selftests/gpio/gpio-mockup.sh

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index ff9e5f2..2437dbc 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -6,6 +6,7 @@ TARGETS += exec
 TARGETS += firmware
 TARGETS += ftrace
 TARGETS += futex
+TARGETS += gpio
 TARGETS += ipc
 TARGETS += kcmp
 TARGETS += lib
diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
new file mode 100644
index 0000000..205e4d1
--- /dev/null
+++ b/tools/testing/selftests/gpio/Makefile
@@ -0,0 +1,23 @@
+
+TEST_PROGS := gpio-mockup.sh
+TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES)
+BINARIES := gpio-mockup-chardev
+
+include ../lib.mk
+
+all: $(BINARIES)
+
+clean:
+	$(RM) $(BINARIES)
+
+CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
+LDLIBS += -lmount -I/usr/include/libmount
+
+$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
+
+../../../gpio/gpio-utils.o:
+	make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
+
+../../../../usr/include/linux/gpio.h:
+	make -C ../../../.. headers_install INSTALL_HDR_PATH=$(shell pwd)/../../../../usr/
+
diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
new file mode 100644
index 0000000..667e916
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
@@ -0,0 +1,324 @@
+/*
+ * GPIO chardev test helper
+ *
+ * Copyright (C) 2016 Bamvor Jian Zhang
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <libmount.h>
+#include <err.h>
+#include <dirent.h>
+#include <linux/gpio.h>
+#include "../../../gpio/gpio-utils.h"
+
+#define CONSUMER	"gpio-selftest"
+#define	GC_NUM		10
+enum direction {
+	OUT,
+	IN
+};
+
+static int get_debugfs(char **path)
+{
+	struct libmnt_context *cxt;
+	struct libmnt_table *tb;
+	struct libmnt_iter *itr = NULL;
+	struct libmnt_fs *fs;
+	int found = 0;
+
+	cxt = mnt_new_context();
+	if (!cxt)
+		err(EXIT_FAILURE, "libmount context allocation failed");
+
+	itr = mnt_new_iter(MNT_ITER_FORWARD);
+	if (!itr)
+		err(EXIT_FAILURE, "failed to initialize libmount iterator");
+
+	if (mnt_context_get_mtab(cxt, &tb))
+		err(EXIT_FAILURE, "failed to read mtab");
+
+	while (mnt_table_next_fs(tb, itr, &fs) == 0) {
+		const char *type = mnt_fs_get_fstype(fs);
+
+		if (!strcmp(type, "debugfs")) {
+			found = 1;
+			break;
+		}
+	}
+	if (found)
+		asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
+
+	mnt_free_iter(itr);
+	mnt_free_context(cxt);
+
+	if (!found)
+		return -1;
+
+	return 0;
+}
+
+static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
+{
+	char *debugfs;
+	FILE *f;
+	char *line = NULL;
+	size_t len = 0;
+	char *cur;
+	int found = 0;
+
+	if (get_debugfs(&debugfs) != 0)
+		err(EXIT_FAILURE, "debugfs is not mounted");
+
+	f = fopen(debugfs, "r");
+	if (!f)
+		err(EXIT_FAILURE, "read from gpio debugfs failed");
+
+	/*
+	 * gpio-2   (                    |gpio-selftest               ) in  lo
+	 */
+	while (getline(&line, &len, f) != -1) {
+		cur = strstr(line, consumer);
+		if (cur == NULL)
+			continue;
+
+		cur = strchr(line, ')');
+		if (!cur)
+			continue;
+
+		cur += 2;
+		if (!strncmp(cur, "out", 3)) {
+			*dir = OUT;
+			cur += 4;
+		} else if (!strncmp(cur, "in", 2)) {
+			*dir = IN;
+			cur += 4;
+		}
+
+		if (!strncmp(cur, "hi", 2))
+			*value = 1;
+		else if (!strncmp(cur, "lo", 2))
+			*value = 0;
+
+		found = 1;
+		break;
+	}
+	free(debugfs);
+	fclose(f);
+	free(line);
+
+	if (!found)
+		return -1;
+
+	return 0;
+}
+
+static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
+{
+	struct gpiochip_info *cinfo;
+	struct gpiochip_info *current;
+	const struct dirent *ent;
+	DIR *dp;
+	char *chrdev_name;
+	int fd;
+	int i = 0;
+
+	cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
+	if (!cinfo)
+		err(EXIT_FAILURE, "gpiochip_info allocation failed");
+
+	current = cinfo;
+	dp = opendir("/dev");
+	if (!dp) {
+		*ret = -errno;
+		goto error_out;
+	} else {
+		*ret = 0;
+	}
+
+	while (ent = readdir(dp), ent) {
+		if (check_prefix(ent->d_name, "gpiochip")) {
+			*ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
+			if (*ret < 0)
+				goto error_out;
+
+			fd = open(chrdev_name, 0);
+			if (fd == -1) {
+				*ret = -errno;
+				fprintf(stderr, "Failed to open %s\n",
+					chrdev_name);
+				goto error_close_dir;
+			}
+			*ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
+			if (*ret == -1) {
+				perror("Failed to issue CHIPINFO IOCTL\n");
+				goto error_close_dir;
+			}
+			close(fd);
+			if (strcmp(current->label, gpiochip_name) == 0
+			    || check_prefix(current->label, gpiochip_name)) {
+				*ret = 0;
+				current++;
+				i++;
+			}
+		}
+	}
+
+	if ((!*ret && i == 0) || *ret < 0) {
+		free(cinfo);
+		cinfo = NULL;
+	}
+	if (!*ret && i > 0) {
+		cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
+		*ret = i;
+	}
+
+error_close_dir:
+	closedir(dp);
+error_out:
+	if (*ret < 0)
+		err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
+
+	return cinfo;
+}
+
+int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
+{
+	struct gpiohandle_data data;
+	unsigned int lines[] = {line};
+	int fd;
+	int debugfs_dir = IN;
+	int debugfs_value = 0;
+	int ret;
+
+	data.values[0] = value;
+	ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
+					   CONSUMER);
+	if (ret < 0)
+		goto fail_out;
+	else
+		fd = ret;
+
+	ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
+	if (ret) {
+		ret = -EINVAL;
+		goto fail_out;
+	}
+	if (flag & GPIOHANDLE_REQUEST_INPUT) {
+		if (debugfs_dir != IN) {
+			errno = -EINVAL;
+			ret = -errno;
+		}
+	} else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
+		if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
+			debugfs_value = !debugfs_value;
+
+		if (!(debugfs_dir == OUT && value == debugfs_value))
+			errno = -EINVAL;
+		ret = -errno;
+
+	}
+	gpiotools_release_linehandle(fd);
+
+fail_out:
+	if (ret)
+		err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
+		    cinfo->name, line, flag, value);
+
+	return ret;
+}
+
+void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
+{
+	printf("line<%d>", line);
+	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
+	printf(".");
+	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
+	printf(".");
+	gpio_pin_test(cinfo, line,
+		      GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
+		      0);
+	printf(".");
+	gpio_pin_test(cinfo, line,
+		      GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
+		      1);
+	printf(".");
+	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
+	printf(".");
+}
+
+/*
+ * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
+ * Return 0 if successful or exit with EXIT_FAILURE if test failed.
+ * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
+ *			  gpio-mockup
+ * is_valid_gpio_chip:	  Whether the gpio_chip is valid. 1 means valid,
+ *			  0 means invalid which could not be found by
+ *			  list_gpiochip.
+ */
+int main(int argc, char *argv[])
+{
+	char *prefix;
+	int valid;
+	struct gpiochip_info *cinfo;
+	struct gpiochip_info *current;
+	int i;
+	int ret;
+
+	if (argc < 3) {
+		printf("Usage: %s prefix is_valid", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	prefix = argv[1];
+	valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
+
+	printf("Test gpiochip %s: ", prefix);
+	cinfo = list_gpiochip(prefix, &ret);
+	if (!cinfo) {
+		if (!valid && ret == 0) {
+			printf("Invalid test successful\n");
+			ret = 0;
+			goto out;
+		} else {
+			ret = -EINVAL;
+			goto out;
+		}
+	} else if (cinfo && !valid) {
+		ret = -EINVAL;
+		goto out;
+	}
+	current = cinfo;
+	for (i = 0; i < ret; i++) {
+		gpio_pin_tests(current, 0);
+		gpio_pin_tests(current, current->lines - 1);
+		gpio_pin_tests(current, random() % current->lines);
+		current++;
+	}
+	ret = 0;
+	printf("successful\n");
+
+out:
+	if (ret)
+		fprintf(stderr, "gpio<%s> test failed\n", prefix);
+
+	if (cinfo)
+		free(cinfo);
+
+	if (ret)
+		exit(EXIT_FAILURE);
+
+	return ret;
+}
diff --git a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
new file mode 100755
index 0000000..085d7a3
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
@@ -0,0 +1,134 @@
+
+is_consistent()
+{
+	val=
+
+	active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low`
+	val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value`
+	dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction`
+
+	gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"`
+	dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'`
+	val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'`
+	if [ $val_debugfs = "lo" ]; then
+		val=0
+	elif [ $val_debugfs = "hi" ]; then
+		val=1
+	fi
+
+	if [ $active_low_sysfs = "1" ]; then
+		if [ $val = "0" ]; then
+			val="1"
+		else
+			val="0"
+		fi
+	fi
+
+	if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
+		echo -n "."
+	else
+		echo "test fail, exit"
+		die
+	fi
+}
+
+test_pin_logic()
+{
+	nr=$1
+	direction=$2
+	active_low=$3
+	value=$4
+
+	echo $direction > $GPIO_SYSFS/gpio$nr/direction
+	echo $active_low > $GPIO_SYSFS/gpio$nr/active_low
+	if [ $direction = "out" ]; then
+		echo $value > $GPIO_SYSFS/gpio$nr/value
+	fi
+	is_consistent $nr
+}
+
+test_one_pin()
+{
+	nr=$1
+
+	echo -n "test pin<$nr>"
+
+	echo $nr > $GPIO_SYSFS/export 2>/dev/null
+
+	if [ X$? != X0 ]; then
+		echo "test GPIO pin $nr failed"
+		die
+	fi
+
+	#"Checking if the sysfs is consistent with debugfs: "
+	is_consistent $nr
+
+	#"Checking the logic of active_low: "
+	test_pin_logic $nr out 1 1
+	test_pin_logic $nr out 1 0
+	test_pin_logic $nr out 0 1
+	test_pin_logic $nr out 0 0
+
+	#"Checking the logic of direction: "
+	test_pin_logic $nr in 1 1
+	test_pin_logic $nr out 1 0
+	test_pin_logic $nr low 0 1
+	test_pin_logic $nr high 0 0
+
+	echo $nr > $GPIO_SYSFS/unexport
+
+	echo "successful"
+}
+
+test_one_pin_fail()
+{
+	nr=$1
+
+	echo $nr > $GPIO_SYSFS/export 2>/dev/null
+
+	if [ X$? != X0 ]; then
+		echo "test invalid pin $nr successful"
+	else
+		echo "test invalid pin $nr failed"
+		echo $nr > $GPIO_SYSFS/unexport 2>/dev/null
+		die
+	fi
+}
+
+list_chip()
+{
+	echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
+}
+
+test_chip()
+{
+	chip=$1
+	name=`basename $chip`
+	base=`cat $chip/base`
+	ngpio=`cat $chip/ngpio`
+	printf "%-10s %-5s %-5s\n" $name $base $ngpio
+	if [ $ngpio = "0" ]; then
+		echo "number of gpio is zero is not allowed".
+	fi
+	test_one_pin $base
+	test_one_pin $(($base + $ngpio - 1))
+	test_one_pin $((( RANDOM % $ngpio )  + $base ))
+}
+
+test_chips_sysfs()
+{
+       gpiochip=`list_chip $module`
+       if [ X"$gpiochip" = X ]; then
+               if [ X"$valid" = Xfalse ]; then
+                       echo "successful"
+               else
+                       echo "fail"
+                       die
+               fi
+       else
+               for chip in $gpiochip; do
+                       test_chip $chip
+               done
+       fi
+}
+
diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh
new file mode 100755
index 0000000..b183439
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio-mockup.sh
@@ -0,0 +1,201 @@
+#!/bin/bash
+
+#exit status
+#1: run as non-root user
+#2: sysfs/debugfs not mount
+#3: insert module fail when gpio-mockup is a module.
+#4: other reason.
+
+SYSFS=
+GPIO_SYSFS=
+GPIO_DRV_SYSFS=
+DEBUGFS=
+GPIO_DEBUGFS=
+dev_type=
+module=
+
+usage()
+{
+	echo "Usage:"
+	echo "$0 [-f] [-m name] [-t type]"
+	echo "-f:  full test. It maybe conflict with existence gpio device."
+	echo "-m:  module name, default name is gpio-mockup. It could also test"
+	echo "     other gpio device."
+	echo "-t:  interface type: chardev(char device) and sysfs(being"
+	echo "     deprecated). The first one is default"
+	echo ""
+	echo "$0 -h"
+	echo "This usage"
+}
+
+prerequisite()
+{
+	msg="skip all tests:"
+	if [ $UID != 0 ]; then
+		echo $msg must be run as root >&2
+		exit 1
+	fi
+	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
+	if [ ! -d "$SYSFS" ]; then
+		echo $msg sysfs is not mounted >&2
+		exit 2
+	fi
+	GPIO_SYSFS=`echo $SYSFS/class/gpio`
+	GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
+	DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+	if [ ! -d "$DEBUGFS" ]; then
+		echo $msg debugfs is not mounted >&2
+		exit 2
+	fi
+	GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
+	source gpio-mockup-sysfs.sh
+}
+
+try_insert_module()
+{
+	if [ -d "$GPIO_DRV_SYSFS" ]; then
+		echo "$GPIO_DRV_SYSFS exist. Skip insert module"
+	else
+		modprobe -q $module $1
+		if [ X$? != X0 ]; then
+			echo $msg insmod $module failed >&2
+			exit 3
+		fi
+	fi
+}
+
+remove_module()
+{
+	modprobe -r -q $module
+}
+
+die()
+{
+	remove_module
+	exit 4
+}
+
+test_chips()
+{
+	if [ X$dev_type = Xsysfs ]; then
+		echo "WARNING: sysfs ABI of gpio is going to deprecated."
+		test_chips_sysfs $*
+	else
+		$BASE/gpio-mockup-chardev $*
+	fi
+}
+
+gpio_test()
+{
+	param=$1
+	valid=$2
+
+	if [ X"$param" = X ]; then
+		die
+	fi
+	try_insert_module "gpio_mockup_ranges=$param"
+	echo -n "GPIO $module test with ranges: <"
+	echo "$param>: "
+	printf "%-10s %s\n" $param
+	test_chips $module $valid
+	remove_module
+}
+
+BASE=`dirname $0`
+
+dev_type=
+TEMP=`getopt -o fhm:t: -n '$0' -- "$@"`
+
+if [ "$?" != "0" ]; then
+        echo "Parameter process failed, Terminating..." >&2
+        exit 1
+fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+while true; do
+	case $1 in
+	-f)
+		full_test=true
+		shift
+		;;
+	-h)
+		usage
+		exit
+		;;
+	-m)
+		module=$2
+		shift 2
+		;;
+	-t)
+		dev_type=$2
+		shift 2
+		;;
+	--)
+		shift
+		break
+		;;
+	*)
+		echo "Internal error!"
+		exit 1
+		;;
+	esac
+done
+
+if [ X"$module" = X ]; then
+	module="gpio-mockup"
+fi
+
+if [ X$dev_type != Xsysfs ]; then
+	dev_type="chardev"
+fi
+
+prerequisite
+
+echo "1.  Test dynamic allocation of gpio successful means insert gpiochip and"
+echo "    manipulate gpio pin successful"
+gpio_test "-1,32" true
+gpio_test "-1,32,-1,32" true
+gpio_test "-1,32,-1,32,-1,32" true
+if [ X$full_test = Xtrue ]; then
+	gpio_test "-1,32,32,64" true
+	gpio_test "-1,32,40,64,-1,5" true
+	gpio_test "-1,32,32,64,-1,32" true
+	gpio_test "0,32,32,64,-1,32,-1,32" true
+	gpio_test "-1,32,-1,32,0,32,32,64" true
+	echo "2.  Do basic test: successful means insert gpiochip and"
+	echo "    manipulate gpio pin successful"
+	gpio_test "0,32" true
+	gpio_test "0,32,32,64" true
+	gpio_test "0,32,40,64,64,96" true
+fi
+echo "3.  Error test: successful means insert gpiochip failed"
+echo "3.1 Test number of gpio overflow"
+#Currently: The max number of gpio(1024) is defined in arm architecture.
+gpio_test "-1,32,-1,1024" false
+if [ X$full_test = Xtrue ]; then
+	echo "3.2 Test zero line of gpio"
+	gpio_test "0,0" false
+	echo "3.3 Test range overlap"
+	echo "3.3.1 Test corner case"
+	gpio_test "0,32,0,1" false
+	gpio_test "0,32,32,64,32,40" false
+	gpio_test "0,32,35,64,35,45" false
+	gpio_test "0,32,31,32" false
+	gpio_test "0,32,32,64,36,37" false
+	gpio_test "0,32,35,64,34,36" false
+	echo "3.3.2 Test inserting invalid second gpiochip"
+	gpio_test "0,32,30,35" false
+	gpio_test "0,32,1,5" false
+	gpio_test "10,32,9,14" false
+	gpio_test "10,32,30,35" false
+	echo "3.3.3 Test others"
+	gpio_test "0,32,40,56,39,45" false
+	gpio_test "0,32,40,56,30,33" false
+	gpio_test "0,32,40,56,30,41" false
+	gpio_test "0,32,40,56,20,21" false
+fi
+
+echo GPIO test PASS
+
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v5] selftest/gpio: add gpio test case
  2016-11-21 10:16       ` [PATCH v5] " bamvor.zhangjian
@ 2016-12-13 12:42         ` Zhangjian (Bamvor)
  2016-12-13 14:33           ` Shuah Khan
  0 siblings, 1 reply; 13+ messages in thread
From: Zhangjian (Bamvor) @ 2016-12-13 12:42 UTC (permalink / raw)
  To: shuahkh, linus.walleij
  Cc: linux-gpio, broonie, mwelling, shuah, bamvor.zhangjian

Ping.

On 2016/11/21 18:16, bamvor.zhangjian@huawei.com wrote:
> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>
> This test script try to do whitebox testing for gpio subsystem(based on
> gpiolib). It manipulate gpio device through chardev or sysfs and check
> the result from debugfs. This script test gpio-mockup through chardev by
> default. User could test other gpio chip by passing the module name.
> Some of the testcases are turned off by default to avoid the conflicting
> with gpiochip in system.
>
> In details, it test the following things:
> 1.  Test direction and output value for valid pin.
> 2.  Test dynamic allocation of gpio base.
> 3.  Add single, multi gpiochip to do overlap check.
>
> Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" for usage.
>
> Acked-by: Shuah Khan <shuahkh@osg.samsung.com>
> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
> ---
> Changes since v4:
> 1.  Install header to to linux/usr/include instead of default path
> 2.  Print being deprecated for sysfs ABI.
>
>  tools/testing/selftests/Makefile                   |   1 +
>  tools/testing/selftests/gpio/Makefile              |  23 ++
>  tools/testing/selftests/gpio/gpio-mockup-chardev.c | 324 +++++++++++++++++++++
>  tools/testing/selftests/gpio/gpio-mockup-sysfs.sh  | 134 +++++++++
>  tools/testing/selftests/gpio/gpio-mockup.sh        | 201 +++++++++++++
>  5 files changed, 683 insertions(+)
>  create mode 100644 tools/testing/selftests/gpio/Makefile
>  create mode 100644 tools/testing/selftests/gpio/gpio-mockup-chardev.c
>  create mode 100755 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
>  create mode 100755 tools/testing/selftests/gpio/gpio-mockup.sh
>
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index ff9e5f2..2437dbc 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -6,6 +6,7 @@ TARGETS += exec
>  TARGETS += firmware
>  TARGETS += ftrace
>  TARGETS += futex
> +TARGETS += gpio
>  TARGETS += ipc
>  TARGETS += kcmp
>  TARGETS += lib
> diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
> new file mode 100644
> index 0000000..205e4d1
> --- /dev/null
> +++ b/tools/testing/selftests/gpio/Makefile
> @@ -0,0 +1,23 @@
> +
> +TEST_PROGS := gpio-mockup.sh
> +TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES)
> +BINARIES := gpio-mockup-chardev
> +
> +include ../lib.mk
> +
> +all: $(BINARIES)
> +
> +clean:
> +	$(RM) $(BINARIES)
> +
> +CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
> +LDLIBS += -lmount -I/usr/include/libmount
> +
> +$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
> +
> +../../../gpio/gpio-utils.o:
> +	make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
> +
> +../../../../usr/include/linux/gpio.h:
> +	make -C ../../../.. headers_install INSTALL_HDR_PATH=$(shell pwd)/../../../../usr/
> +
> diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
> new file mode 100644
> index 0000000..667e916
> --- /dev/null
> +++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
> @@ -0,0 +1,324 @@
> +/*
> + * GPIO chardev test helper
> + *
> + * Copyright (C) 2016 Bamvor Jian Zhang
> + *
> + * 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.
> + */
> +
> +#define _GNU_SOURCE
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <getopt.h>
> +#include <sys/ioctl.h>
> +#include <libmount.h>
> +#include <err.h>
> +#include <dirent.h>
> +#include <linux/gpio.h>
> +#include "../../../gpio/gpio-utils.h"
> +
> +#define CONSUMER	"gpio-selftest"
> +#define	GC_NUM		10
> +enum direction {
> +	OUT,
> +	IN
> +};
> +
> +static int get_debugfs(char **path)
> +{
> +	struct libmnt_context *cxt;
> +	struct libmnt_table *tb;
> +	struct libmnt_iter *itr = NULL;
> +	struct libmnt_fs *fs;
> +	int found = 0;
> +
> +	cxt = mnt_new_context();
> +	if (!cxt)
> +		err(EXIT_FAILURE, "libmount context allocation failed");
> +
> +	itr = mnt_new_iter(MNT_ITER_FORWARD);
> +	if (!itr)
> +		err(EXIT_FAILURE, "failed to initialize libmount iterator");
> +
> +	if (mnt_context_get_mtab(cxt, &tb))
> +		err(EXIT_FAILURE, "failed to read mtab");
> +
> +	while (mnt_table_next_fs(tb, itr, &fs) == 0) {
> +		const char *type = mnt_fs_get_fstype(fs);
> +
> +		if (!strcmp(type, "debugfs")) {
> +			found = 1;
> +			break;
> +		}
> +	}
> +	if (found)
> +		asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
> +
> +	mnt_free_iter(itr);
> +	mnt_free_context(cxt);
> +
> +	if (!found)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
> +{
> +	char *debugfs;
> +	FILE *f;
> +	char *line = NULL;
> +	size_t len = 0;
> +	char *cur;
> +	int found = 0;
> +
> +	if (get_debugfs(&debugfs) != 0)
> +		err(EXIT_FAILURE, "debugfs is not mounted");
> +
> +	f = fopen(debugfs, "r");
> +	if (!f)
> +		err(EXIT_FAILURE, "read from gpio debugfs failed");
> +
> +	/*
> +	 * gpio-2   (                    |gpio-selftest               ) in  lo
> +	 */
> +	while (getline(&line, &len, f) != -1) {
> +		cur = strstr(line, consumer);
> +		if (cur == NULL)
> +			continue;
> +
> +		cur = strchr(line, ')');
> +		if (!cur)
> +			continue;
> +
> +		cur += 2;
> +		if (!strncmp(cur, "out", 3)) {
> +			*dir = OUT;
> +			cur += 4;
> +		} else if (!strncmp(cur, "in", 2)) {
> +			*dir = IN;
> +			cur += 4;
> +		}
> +
> +		if (!strncmp(cur, "hi", 2))
> +			*value = 1;
> +		else if (!strncmp(cur, "lo", 2))
> +			*value = 0;
> +
> +		found = 1;
> +		break;
> +	}
> +	free(debugfs);
> +	fclose(f);
> +	free(line);
> +
> +	if (!found)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
> +{
> +	struct gpiochip_info *cinfo;
> +	struct gpiochip_info *current;
> +	const struct dirent *ent;
> +	DIR *dp;
> +	char *chrdev_name;
> +	int fd;
> +	int i = 0;
> +
> +	cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
> +	if (!cinfo)
> +		err(EXIT_FAILURE, "gpiochip_info allocation failed");
> +
> +	current = cinfo;
> +	dp = opendir("/dev");
> +	if (!dp) {
> +		*ret = -errno;
> +		goto error_out;
> +	} else {
> +		*ret = 0;
> +	}
> +
> +	while (ent = readdir(dp), ent) {
> +		if (check_prefix(ent->d_name, "gpiochip")) {
> +			*ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
> +			if (*ret < 0)
> +				goto error_out;
> +
> +			fd = open(chrdev_name, 0);
> +			if (fd == -1) {
> +				*ret = -errno;
> +				fprintf(stderr, "Failed to open %s\n",
> +					chrdev_name);
> +				goto error_close_dir;
> +			}
> +			*ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
> +			if (*ret == -1) {
> +				perror("Failed to issue CHIPINFO IOCTL\n");
> +				goto error_close_dir;
> +			}
> +			close(fd);
> +			if (strcmp(current->label, gpiochip_name) == 0
> +			    || check_prefix(current->label, gpiochip_name)) {
> +				*ret = 0;
> +				current++;
> +				i++;
> +			}
> +		}
> +	}
> +
> +	if ((!*ret && i == 0) || *ret < 0) {
> +		free(cinfo);
> +		cinfo = NULL;
> +	}
> +	if (!*ret && i > 0) {
> +		cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
> +		*ret = i;
> +	}
> +
> +error_close_dir:
> +	closedir(dp);
> +error_out:
> +	if (*ret < 0)
> +		err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
> +
> +	return cinfo;
> +}
> +
> +int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
> +{
> +	struct gpiohandle_data data;
> +	unsigned int lines[] = {line};
> +	int fd;
> +	int debugfs_dir = IN;
> +	int debugfs_value = 0;
> +	int ret;
> +
> +	data.values[0] = value;
> +	ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
> +					   CONSUMER);
> +	if (ret < 0)
> +		goto fail_out;
> +	else
> +		fd = ret;
> +
> +	ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
> +	if (ret) {
> +		ret = -EINVAL;
> +		goto fail_out;
> +	}
> +	if (flag & GPIOHANDLE_REQUEST_INPUT) {
> +		if (debugfs_dir != IN) {
> +			errno = -EINVAL;
> +			ret = -errno;
> +		}
> +	} else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
> +		if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
> +			debugfs_value = !debugfs_value;
> +
> +		if (!(debugfs_dir == OUT && value == debugfs_value))
> +			errno = -EINVAL;
> +		ret = -errno;
> +
> +	}
> +	gpiotools_release_linehandle(fd);
> +
> +fail_out:
> +	if (ret)
> +		err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
> +		    cinfo->name, line, flag, value);
> +
> +	return ret;
> +}
> +
> +void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
> +{
> +	printf("line<%d>", line);
> +	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
> +	printf(".");
> +	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
> +	printf(".");
> +	gpio_pin_test(cinfo, line,
> +		      GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
> +		      0);
> +	printf(".");
> +	gpio_pin_test(cinfo, line,
> +		      GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
> +		      1);
> +	printf(".");
> +	gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
> +	printf(".");
> +}
> +
> +/*
> + * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
> + * Return 0 if successful or exit with EXIT_FAILURE if test failed.
> + * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
> + *			  gpio-mockup
> + * is_valid_gpio_chip:	  Whether the gpio_chip is valid. 1 means valid,
> + *			  0 means invalid which could not be found by
> + *			  list_gpiochip.
> + */
> +int main(int argc, char *argv[])
> +{
> +	char *prefix;
> +	int valid;
> +	struct gpiochip_info *cinfo;
> +	struct gpiochip_info *current;
> +	int i;
> +	int ret;
> +
> +	if (argc < 3) {
> +		printf("Usage: %s prefix is_valid", argv[0]);
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	prefix = argv[1];
> +	valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
> +
> +	printf("Test gpiochip %s: ", prefix);
> +	cinfo = list_gpiochip(prefix, &ret);
> +	if (!cinfo) {
> +		if (!valid && ret == 0) {
> +			printf("Invalid test successful\n");
> +			ret = 0;
> +			goto out;
> +		} else {
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +	} else if (cinfo && !valid) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +	current = cinfo;
> +	for (i = 0; i < ret; i++) {
> +		gpio_pin_tests(current, 0);
> +		gpio_pin_tests(current, current->lines - 1);
> +		gpio_pin_tests(current, random() % current->lines);
> +		current++;
> +	}
> +	ret = 0;
> +	printf("successful\n");
> +
> +out:
> +	if (ret)
> +		fprintf(stderr, "gpio<%s> test failed\n", prefix);
> +
> +	if (cinfo)
> +		free(cinfo);
> +
> +	if (ret)
> +		exit(EXIT_FAILURE);
> +
> +	return ret;
> +}
> diff --git a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
> new file mode 100755
> index 0000000..085d7a3
> --- /dev/null
> +++ b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
> @@ -0,0 +1,134 @@
> +
> +is_consistent()
> +{
> +	val=
> +
> +	active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low`
> +	val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value`
> +	dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction`
> +
> +	gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"`
> +	dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'`
> +	val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'`
> +	if [ $val_debugfs = "lo" ]; then
> +		val=0
> +	elif [ $val_debugfs = "hi" ]; then
> +		val=1
> +	fi
> +
> +	if [ $active_low_sysfs = "1" ]; then
> +		if [ $val = "0" ]; then
> +			val="1"
> +		else
> +			val="0"
> +		fi
> +	fi
> +
> +	if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
> +		echo -n "."
> +	else
> +		echo "test fail, exit"
> +		die
> +	fi
> +}
> +
> +test_pin_logic()
> +{
> +	nr=$1
> +	direction=$2
> +	active_low=$3
> +	value=$4
> +
> +	echo $direction > $GPIO_SYSFS/gpio$nr/direction
> +	echo $active_low > $GPIO_SYSFS/gpio$nr/active_low
> +	if [ $direction = "out" ]; then
> +		echo $value > $GPIO_SYSFS/gpio$nr/value
> +	fi
> +	is_consistent $nr
> +}
> +
> +test_one_pin()
> +{
> +	nr=$1
> +
> +	echo -n "test pin<$nr>"
> +
> +	echo $nr > $GPIO_SYSFS/export 2>/dev/null
> +
> +	if [ X$? != X0 ]; then
> +		echo "test GPIO pin $nr failed"
> +		die
> +	fi
> +
> +	#"Checking if the sysfs is consistent with debugfs: "
> +	is_consistent $nr
> +
> +	#"Checking the logic of active_low: "
> +	test_pin_logic $nr out 1 1
> +	test_pin_logic $nr out 1 0
> +	test_pin_logic $nr out 0 1
> +	test_pin_logic $nr out 0 0
> +
> +	#"Checking the logic of direction: "
> +	test_pin_logic $nr in 1 1
> +	test_pin_logic $nr out 1 0
> +	test_pin_logic $nr low 0 1
> +	test_pin_logic $nr high 0 0
> +
> +	echo $nr > $GPIO_SYSFS/unexport
> +
> +	echo "successful"
> +}
> +
> +test_one_pin_fail()
> +{
> +	nr=$1
> +
> +	echo $nr > $GPIO_SYSFS/export 2>/dev/null
> +
> +	if [ X$? != X0 ]; then
> +		echo "test invalid pin $nr successful"
> +	else
> +		echo "test invalid pin $nr failed"
> +		echo $nr > $GPIO_SYSFS/unexport 2>/dev/null
> +		die
> +	fi
> +}
> +
> +list_chip()
> +{
> +	echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
> +}
> +
> +test_chip()
> +{
> +	chip=$1
> +	name=`basename $chip`
> +	base=`cat $chip/base`
> +	ngpio=`cat $chip/ngpio`
> +	printf "%-10s %-5s %-5s\n" $name $base $ngpio
> +	if [ $ngpio = "0" ]; then
> +		echo "number of gpio is zero is not allowed".
> +	fi
> +	test_one_pin $base
> +	test_one_pin $(($base + $ngpio - 1))
> +	test_one_pin $((( RANDOM % $ngpio )  + $base ))
> +}
> +
> +test_chips_sysfs()
> +{
> +       gpiochip=`list_chip $module`
> +       if [ X"$gpiochip" = X ]; then
> +               if [ X"$valid" = Xfalse ]; then
> +                       echo "successful"
> +               else
> +                       echo "fail"
> +                       die
> +               fi
> +       else
> +               for chip in $gpiochip; do
> +                       test_chip $chip
> +               done
> +       fi
> +}
> +
> diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh
> new file mode 100755
> index 0000000..b183439
> --- /dev/null
> +++ b/tools/testing/selftests/gpio/gpio-mockup.sh
> @@ -0,0 +1,201 @@
> +#!/bin/bash
> +
> +#exit status
> +#1: run as non-root user
> +#2: sysfs/debugfs not mount
> +#3: insert module fail when gpio-mockup is a module.
> +#4: other reason.
> +
> +SYSFS=
> +GPIO_SYSFS=
> +GPIO_DRV_SYSFS=
> +DEBUGFS=
> +GPIO_DEBUGFS=
> +dev_type=
> +module=
> +
> +usage()
> +{
> +	echo "Usage:"
> +	echo "$0 [-f] [-m name] [-t type]"
> +	echo "-f:  full test. It maybe conflict with existence gpio device."
> +	echo "-m:  module name, default name is gpio-mockup. It could also test"
> +	echo "     other gpio device."
> +	echo "-t:  interface type: chardev(char device) and sysfs(being"
> +	echo "     deprecated). The first one is default"
> +	echo ""
> +	echo "$0 -h"
> +	echo "This usage"
> +}
> +
> +prerequisite()
> +{
> +	msg="skip all tests:"
> +	if [ $UID != 0 ]; then
> +		echo $msg must be run as root >&2
> +		exit 1
> +	fi
> +	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
> +	if [ ! -d "$SYSFS" ]; then
> +		echo $msg sysfs is not mounted >&2
> +		exit 2
> +	fi
> +	GPIO_SYSFS=`echo $SYSFS/class/gpio`
> +	GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
> +	DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
> +	if [ ! -d "$DEBUGFS" ]; then
> +		echo $msg debugfs is not mounted >&2
> +		exit 2
> +	fi
> +	GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
> +	source gpio-mockup-sysfs.sh
> +}
> +
> +try_insert_module()
> +{
> +	if [ -d "$GPIO_DRV_SYSFS" ]; then
> +		echo "$GPIO_DRV_SYSFS exist. Skip insert module"
> +	else
> +		modprobe -q $module $1
> +		if [ X$? != X0 ]; then
> +			echo $msg insmod $module failed >&2
> +			exit 3
> +		fi
> +	fi
> +}
> +
> +remove_module()
> +{
> +	modprobe -r -q $module
> +}
> +
> +die()
> +{
> +	remove_module
> +	exit 4
> +}
> +
> +test_chips()
> +{
> +	if [ X$dev_type = Xsysfs ]; then
> +		echo "WARNING: sysfs ABI of gpio is going to deprecated."
> +		test_chips_sysfs $*
> +	else
> +		$BASE/gpio-mockup-chardev $*
> +	fi
> +}
> +
> +gpio_test()
> +{
> +	param=$1
> +	valid=$2
> +
> +	if [ X"$param" = X ]; then
> +		die
> +	fi
> +	try_insert_module "gpio_mockup_ranges=$param"
> +	echo -n "GPIO $module test with ranges: <"
> +	echo "$param>: "
> +	printf "%-10s %s\n" $param
> +	test_chips $module $valid
> +	remove_module
> +}
> +
> +BASE=`dirname $0`
> +
> +dev_type=
> +TEMP=`getopt -o fhm:t: -n '$0' -- "$@"`
> +
> +if [ "$?" != "0" ]; then
> +        echo "Parameter process failed, Terminating..." >&2
> +        exit 1
> +fi
> +
> +# Note the quotes around `$TEMP': they are essential!
> +eval set -- "$TEMP"
> +
> +while true; do
> +	case $1 in
> +	-f)
> +		full_test=true
> +		shift
> +		;;
> +	-h)
> +		usage
> +		exit
> +		;;
> +	-m)
> +		module=$2
> +		shift 2
> +		;;
> +	-t)
> +		dev_type=$2
> +		shift 2
> +		;;
> +	--)
> +		shift
> +		break
> +		;;
> +	*)
> +		echo "Internal error!"
> +		exit 1
> +		;;
> +	esac
> +done
> +
> +if [ X"$module" = X ]; then
> +	module="gpio-mockup"
> +fi
> +
> +if [ X$dev_type != Xsysfs ]; then
> +	dev_type="chardev"
> +fi
> +
> +prerequisite
> +
> +echo "1.  Test dynamic allocation of gpio successful means insert gpiochip and"
> +echo "    manipulate gpio pin successful"
> +gpio_test "-1,32" true
> +gpio_test "-1,32,-1,32" true
> +gpio_test "-1,32,-1,32,-1,32" true
> +if [ X$full_test = Xtrue ]; then
> +	gpio_test "-1,32,32,64" true
> +	gpio_test "-1,32,40,64,-1,5" true
> +	gpio_test "-1,32,32,64,-1,32" true
> +	gpio_test "0,32,32,64,-1,32,-1,32" true
> +	gpio_test "-1,32,-1,32,0,32,32,64" true
> +	echo "2.  Do basic test: successful means insert gpiochip and"
> +	echo "    manipulate gpio pin successful"
> +	gpio_test "0,32" true
> +	gpio_test "0,32,32,64" true
> +	gpio_test "0,32,40,64,64,96" true
> +fi
> +echo "3.  Error test: successful means insert gpiochip failed"
> +echo "3.1 Test number of gpio overflow"
> +#Currently: The max number of gpio(1024) is defined in arm architecture.
> +gpio_test "-1,32,-1,1024" false
> +if [ X$full_test = Xtrue ]; then
> +	echo "3.2 Test zero line of gpio"
> +	gpio_test "0,0" false
> +	echo "3.3 Test range overlap"
> +	echo "3.3.1 Test corner case"
> +	gpio_test "0,32,0,1" false
> +	gpio_test "0,32,32,64,32,40" false
> +	gpio_test "0,32,35,64,35,45" false
> +	gpio_test "0,32,31,32" false
> +	gpio_test "0,32,32,64,36,37" false
> +	gpio_test "0,32,35,64,34,36" false
> +	echo "3.3.2 Test inserting invalid second gpiochip"
> +	gpio_test "0,32,30,35" false
> +	gpio_test "0,32,1,5" false
> +	gpio_test "10,32,9,14" false
> +	gpio_test "10,32,30,35" false
> +	echo "3.3.3 Test others"
> +	gpio_test "0,32,40,56,39,45" false
> +	gpio_test "0,32,40,56,30,33" false
> +	gpio_test "0,32,40,56,30,41" false
> +	gpio_test "0,32,40,56,20,21" false
> +fi
> +
> +echo GPIO test PASS
> +
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5] selftest/gpio: add gpio test case
  2016-12-13 12:42         ` Zhangjian (Bamvor)
@ 2016-12-13 14:33           ` Shuah Khan
  0 siblings, 0 replies; 13+ messages in thread
From: Shuah Khan @ 2016-12-13 14:33 UTC (permalink / raw)
  To: Zhangjian (Bamvor), shuahkh, linus.walleij
  Cc: linux-gpio, broonie, mwelling, bamvor.zhangjian, Shuah Khan

On 12/13/2016 05:42 AM, Zhangjian (Bamvor) wrote:
> Ping.
> 
> On 2016/11/21 18:16, bamvor.zhangjian@huawei.com wrote:
>> From: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
>>
>> This test script try to do whitebox testing for gpio subsystem(based on
>> gpiolib). It manipulate gpio device through chardev or sysfs and check
>> the result from debugfs. This script test gpio-mockup through chardev by
>> default. User could test other gpio chip by passing the module name.
>> Some of the testcases are turned off by default to avoid the conflicting
>> with gpiochip in system.
>>
>> In details, it test the following things:
>> 1.  Test direction and output value for valid pin.
>> 2.  Test dynamic allocation of gpio base.
>> 3.  Add single, multi gpiochip to do overlap check.
>>
>> Run "tools/testing/selftests/gpio/gpio-mockup.sh -h" for usage.
>>
>> Acked-by: Shuah Khan <shuahkh@osg.samsung.com>
>> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

Hi Linus/Bemovar,

It is now in linux-kselftest next for 4.10-rc1

thanks,
-- Shuah

>> ---
>> Changes since v4:
>> 1.  Install header to to linux/usr/include instead of default path
>> 2.  Print being deprecated for sysfs ABI.
>>
>>  tools/testing/selftests/Makefile                   |   1 +
>>  tools/testing/selftests/gpio/Makefile              |  23 ++
>>  tools/testing/selftests/gpio/gpio-mockup-chardev.c | 324 +++++++++++++++++++++
>>  tools/testing/selftests/gpio/gpio-mockup-sysfs.sh  | 134 +++++++++
>>  tools/testing/selftests/gpio/gpio-mockup.sh        | 201 +++++++++++++
>>  5 files changed, 683 insertions(+)
>>  create mode 100644 tools/testing/selftests/gpio/Makefile
>>  create mode 100644 tools/testing/selftests/gpio/gpio-mockup-chardev.c
>>  create mode 100755 tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
>>  create mode 100755 tools/testing/selftests/gpio/gpio-mockup.sh
>>
>> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
>> index ff9e5f2..2437dbc 100644
>> --- a/tools/testing/selftests/Makefile
>> +++ b/tools/testing/selftests/Makefile
>> @@ -6,6 +6,7 @@ TARGETS += exec
>>  TARGETS += firmware
>>  TARGETS += ftrace
>>  TARGETS += futex
>> +TARGETS += gpio
>>  TARGETS += ipc
>>  TARGETS += kcmp
>>  TARGETS += lib
>> diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
>> new file mode 100644
>> index 0000000..205e4d1
>> --- /dev/null
>> +++ b/tools/testing/selftests/gpio/Makefile
>> @@ -0,0 +1,23 @@
>> +
>> +TEST_PROGS := gpio-mockup.sh
>> +TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES)
>> +BINARIES := gpio-mockup-chardev
>> +
>> +include ../lib.mk
>> +
>> +all: $(BINARIES)
>> +
>> +clean:
>> +    $(RM) $(BINARIES)
>> +
>> +CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
>> +LDLIBS += -lmount -I/usr/include/libmount
>> +
>> +$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
>> +
>> +../../../gpio/gpio-utils.o:
>> +    make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
>> +
>> +../../../../usr/include/linux/gpio.h:
>> +    make -C ../../../.. headers_install INSTALL_HDR_PATH=$(shell pwd)/../../../../usr/
>> +
>> diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
>> new file mode 100644
>> index 0000000..667e916
>> --- /dev/null
>> +++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c
>> @@ -0,0 +1,324 @@
>> +/*
>> + * GPIO chardev test helper
>> + *
>> + * Copyright (C) 2016 Bamvor Jian Zhang
>> + *
>> + * 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.
>> + */
>> +
>> +#define _GNU_SOURCE
>> +#include <unistd.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <errno.h>
>> +#include <string.h>
>> +#include <fcntl.h>
>> +#include <getopt.h>
>> +#include <sys/ioctl.h>
>> +#include <libmount.h>
>> +#include <err.h>
>> +#include <dirent.h>
>> +#include <linux/gpio.h>
>> +#include "../../../gpio/gpio-utils.h"
>> +
>> +#define CONSUMER    "gpio-selftest"
>> +#define    GC_NUM        10
>> +enum direction {
>> +    OUT,
>> +    IN
>> +};
>> +
>> +static int get_debugfs(char **path)
>> +{
>> +    struct libmnt_context *cxt;
>> +    struct libmnt_table *tb;
>> +    struct libmnt_iter *itr = NULL;
>> +    struct libmnt_fs *fs;
>> +    int found = 0;
>> +
>> +    cxt = mnt_new_context();
>> +    if (!cxt)
>> +        err(EXIT_FAILURE, "libmount context allocation failed");
>> +
>> +    itr = mnt_new_iter(MNT_ITER_FORWARD);
>> +    if (!itr)
>> +        err(EXIT_FAILURE, "failed to initialize libmount iterator");
>> +
>> +    if (mnt_context_get_mtab(cxt, &tb))
>> +        err(EXIT_FAILURE, "failed to read mtab");
>> +
>> +    while (mnt_table_next_fs(tb, itr, &fs) == 0) {
>> +        const char *type = mnt_fs_get_fstype(fs);
>> +
>> +        if (!strcmp(type, "debugfs")) {
>> +            found = 1;
>> +            break;
>> +        }
>> +    }
>> +    if (found)
>> +        asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
>> +
>> +    mnt_free_iter(itr);
>> +    mnt_free_context(cxt);
>> +
>> +    if (!found)
>> +        return -1;
>> +
>> +    return 0;
>> +}
>> +
>> +static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
>> +{
>> +    char *debugfs;
>> +    FILE *f;
>> +    char *line = NULL;
>> +    size_t len = 0;
>> +    char *cur;
>> +    int found = 0;
>> +
>> +    if (get_debugfs(&debugfs) != 0)
>> +        err(EXIT_FAILURE, "debugfs is not mounted");
>> +
>> +    f = fopen(debugfs, "r");
>> +    if (!f)
>> +        err(EXIT_FAILURE, "read from gpio debugfs failed");
>> +
>> +    /*
>> +     * gpio-2   (                    |gpio-selftest               ) in  lo
>> +     */
>> +    while (getline(&line, &len, f) != -1) {
>> +        cur = strstr(line, consumer);
>> +        if (cur == NULL)
>> +            continue;
>> +
>> +        cur = strchr(line, ')');
>> +        if (!cur)
>> +            continue;
>> +
>> +        cur += 2;
>> +        if (!strncmp(cur, "out", 3)) {
>> +            *dir = OUT;
>> +            cur += 4;
>> +        } else if (!strncmp(cur, "in", 2)) {
>> +            *dir = IN;
>> +            cur += 4;
>> +        }
>> +
>> +        if (!strncmp(cur, "hi", 2))
>> +            *value = 1;
>> +        else if (!strncmp(cur, "lo", 2))
>> +            *value = 0;
>> +
>> +        found = 1;
>> +        break;
>> +    }
>> +    free(debugfs);
>> +    fclose(f);
>> +    free(line);
>> +
>> +    if (!found)
>> +        return -1;
>> +
>> +    return 0;
>> +}
>> +
>> +static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
>> +{
>> +    struct gpiochip_info *cinfo;
>> +    struct gpiochip_info *current;
>> +    const struct dirent *ent;
>> +    DIR *dp;
>> +    char *chrdev_name;
>> +    int fd;
>> +    int i = 0;
>> +
>> +    cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
>> +    if (!cinfo)
>> +        err(EXIT_FAILURE, "gpiochip_info allocation failed");
>> +
>> +    current = cinfo;
>> +    dp = opendir("/dev");
>> +    if (!dp) {
>> +        *ret = -errno;
>> +        goto error_out;
>> +    } else {
>> +        *ret = 0;
>> +    }
>> +
>> +    while (ent = readdir(dp), ent) {
>> +        if (check_prefix(ent->d_name, "gpiochip")) {
>> +            *ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
>> +            if (*ret < 0)
>> +                goto error_out;
>> +
>> +            fd = open(chrdev_name, 0);
>> +            if (fd == -1) {
>> +                *ret = -errno;
>> +                fprintf(stderr, "Failed to open %s\n",
>> +                    chrdev_name);
>> +                goto error_close_dir;
>> +            }
>> +            *ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
>> +            if (*ret == -1) {
>> +                perror("Failed to issue CHIPINFO IOCTL\n");
>> +                goto error_close_dir;
>> +            }
>> +            close(fd);
>> +            if (strcmp(current->label, gpiochip_name) == 0
>> +                || check_prefix(current->label, gpiochip_name)) {
>> +                *ret = 0;
>> +                current++;
>> +                i++;
>> +            }
>> +        }
>> +    }
>> +
>> +    if ((!*ret && i == 0) || *ret < 0) {
>> +        free(cinfo);
>> +        cinfo = NULL;
>> +    }
>> +    if (!*ret && i > 0) {
>> +        cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
>> +        *ret = i;
>> +    }
>> +
>> +error_close_dir:
>> +    closedir(dp);
>> +error_out:
>> +    if (*ret < 0)
>> +        err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
>> +
>> +    return cinfo;
>> +}
>> +
>> +int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
>> +{
>> +    struct gpiohandle_data data;
>> +    unsigned int lines[] = {line};
>> +    int fd;
>> +    int debugfs_dir = IN;
>> +    int debugfs_value = 0;
>> +    int ret;
>> +
>> +    data.values[0] = value;
>> +    ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
>> +                       CONSUMER);
>> +    if (ret < 0)
>> +        goto fail_out;
>> +    else
>> +        fd = ret;
>> +
>> +    ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
>> +    if (ret) {
>> +        ret = -EINVAL;
>> +        goto fail_out;
>> +    }
>> +    if (flag & GPIOHANDLE_REQUEST_INPUT) {
>> +        if (debugfs_dir != IN) {
>> +            errno = -EINVAL;
>> +            ret = -errno;
>> +        }
>> +    } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
>> +        if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
>> +            debugfs_value = !debugfs_value;
>> +
>> +        if (!(debugfs_dir == OUT && value == debugfs_value))
>> +            errno = -EINVAL;
>> +        ret = -errno;
>> +
>> +    }
>> +    gpiotools_release_linehandle(fd);
>> +
>> +fail_out:
>> +    if (ret)
>> +        err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
>> +            cinfo->name, line, flag, value);
>> +
>> +    return ret;
>> +}
>> +
>> +void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
>> +{
>> +    printf("line<%d>", line);
>> +    gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
>> +    printf(".");
>> +    gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
>> +    printf(".");
>> +    gpio_pin_test(cinfo, line,
>> +              GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
>> +              0);
>> +    printf(".");
>> +    gpio_pin_test(cinfo, line,
>> +              GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
>> +              1);
>> +    printf(".");
>> +    gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
>> +    printf(".");
>> +}
>> +
>> +/*
>> + * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
>> + * Return 0 if successful or exit with EXIT_FAILURE if test failed.
>> + * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
>> + *              gpio-mockup
>> + * is_valid_gpio_chip:      Whether the gpio_chip is valid. 1 means valid,
>> + *              0 means invalid which could not be found by
>> + *              list_gpiochip.
>> + */
>> +int main(int argc, char *argv[])
>> +{
>> +    char *prefix;
>> +    int valid;
>> +    struct gpiochip_info *cinfo;
>> +    struct gpiochip_info *current;
>> +    int i;
>> +    int ret;
>> +
>> +    if (argc < 3) {
>> +        printf("Usage: %s prefix is_valid", argv[0]);
>> +        exit(EXIT_FAILURE);
>> +    }
>> +
>> +    prefix = argv[1];
>> +    valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
>> +
>> +    printf("Test gpiochip %s: ", prefix);
>> +    cinfo = list_gpiochip(prefix, &ret);
>> +    if (!cinfo) {
>> +        if (!valid && ret == 0) {
>> +            printf("Invalid test successful\n");
>> +            ret = 0;
>> +            goto out;
>> +        } else {
>> +            ret = -EINVAL;
>> +            goto out;
>> +        }
>> +    } else if (cinfo && !valid) {
>> +        ret = -EINVAL;
>> +        goto out;
>> +    }
>> +    current = cinfo;
>> +    for (i = 0; i < ret; i++) {
>> +        gpio_pin_tests(current, 0);
>> +        gpio_pin_tests(current, current->lines - 1);
>> +        gpio_pin_tests(current, random() % current->lines);
>> +        current++;
>> +    }
>> +    ret = 0;
>> +    printf("successful\n");
>> +
>> +out:
>> +    if (ret)
>> +        fprintf(stderr, "gpio<%s> test failed\n", prefix);
>> +
>> +    if (cinfo)
>> +        free(cinfo);
>> +
>> +    if (ret)
>> +        exit(EXIT_FAILURE);
>> +
>> +    return ret;
>> +}
>> diff --git a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
>> new file mode 100755
>> index 0000000..085d7a3
>> --- /dev/null
>> +++ b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
>> @@ -0,0 +1,134 @@
>> +
>> +is_consistent()
>> +{
>> +    val=
>> +
>> +    active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low`
>> +    val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value`
>> +    dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction`
>> +
>> +    gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"`
>> +    dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'`
>> +    val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'`
>> +    if [ $val_debugfs = "lo" ]; then
>> +        val=0
>> +    elif [ $val_debugfs = "hi" ]; then
>> +        val=1
>> +    fi
>> +
>> +    if [ $active_low_sysfs = "1" ]; then
>> +        if [ $val = "0" ]; then
>> +            val="1"
>> +        else
>> +            val="0"
>> +        fi
>> +    fi
>> +
>> +    if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
>> +        echo -n "."
>> +    else
>> +        echo "test fail, exit"
>> +        die
>> +    fi
>> +}
>> +
>> +test_pin_logic()
>> +{
>> +    nr=$1
>> +    direction=$2
>> +    active_low=$3
>> +    value=$4
>> +
>> +    echo $direction > $GPIO_SYSFS/gpio$nr/direction
>> +    echo $active_low > $GPIO_SYSFS/gpio$nr/active_low
>> +    if [ $direction = "out" ]; then
>> +        echo $value > $GPIO_SYSFS/gpio$nr/value
>> +    fi
>> +    is_consistent $nr
>> +}
>> +
>> +test_one_pin()
>> +{
>> +    nr=$1
>> +
>> +    echo -n "test pin<$nr>"
>> +
>> +    echo $nr > $GPIO_SYSFS/export 2>/dev/null
>> +
>> +    if [ X$? != X0 ]; then
>> +        echo "test GPIO pin $nr failed"
>> +        die
>> +    fi
>> +
>> +    #"Checking if the sysfs is consistent with debugfs: "
>> +    is_consistent $nr
>> +
>> +    #"Checking the logic of active_low: "
>> +    test_pin_logic $nr out 1 1
>> +    test_pin_logic $nr out 1 0
>> +    test_pin_logic $nr out 0 1
>> +    test_pin_logic $nr out 0 0
>> +
>> +    #"Checking the logic of direction: "
>> +    test_pin_logic $nr in 1 1
>> +    test_pin_logic $nr out 1 0
>> +    test_pin_logic $nr low 0 1
>> +    test_pin_logic $nr high 0 0
>> +
>> +    echo $nr > $GPIO_SYSFS/unexport
>> +
>> +    echo "successful"
>> +}
>> +
>> +test_one_pin_fail()
>> +{
>> +    nr=$1
>> +
>> +    echo $nr > $GPIO_SYSFS/export 2>/dev/null
>> +
>> +    if [ X$? != X0 ]; then
>> +        echo "test invalid pin $nr successful"
>> +    else
>> +        echo "test invalid pin $nr failed"
>> +        echo $nr > $GPIO_SYSFS/unexport 2>/dev/null
>> +        die
>> +    fi
>> +}
>> +
>> +list_chip()
>> +{
>> +    echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
>> +}
>> +
>> +test_chip()
>> +{
>> +    chip=$1
>> +    name=`basename $chip`
>> +    base=`cat $chip/base`
>> +    ngpio=`cat $chip/ngpio`
>> +    printf "%-10s %-5s %-5s\n" $name $base $ngpio
>> +    if [ $ngpio = "0" ]; then
>> +        echo "number of gpio is zero is not allowed".
>> +    fi
>> +    test_one_pin $base
>> +    test_one_pin $(($base + $ngpio - 1))
>> +    test_one_pin $((( RANDOM % $ngpio )  + $base ))
>> +}
>> +
>> +test_chips_sysfs()
>> +{
>> +       gpiochip=`list_chip $module`
>> +       if [ X"$gpiochip" = X ]; then
>> +               if [ X"$valid" = Xfalse ]; then
>> +                       echo "successful"
>> +               else
>> +                       echo "fail"
>> +                       die
>> +               fi
>> +       else
>> +               for chip in $gpiochip; do
>> +                       test_chip $chip
>> +               done
>> +       fi
>> +}
>> +
>> diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh
>> new file mode 100755
>> index 0000000..b183439
>> --- /dev/null
>> +++ b/tools/testing/selftests/gpio/gpio-mockup.sh
>> @@ -0,0 +1,201 @@
>> +#!/bin/bash
>> +
>> +#exit status
>> +#1: run as non-root user
>> +#2: sysfs/debugfs not mount
>> +#3: insert module fail when gpio-mockup is a module.
>> +#4: other reason.
>> +
>> +SYSFS=
>> +GPIO_SYSFS=
>> +GPIO_DRV_SYSFS=
>> +DEBUGFS=
>> +GPIO_DEBUGFS=
>> +dev_type=
>> +module=
>> +
>> +usage()
>> +{
>> +    echo "Usage:"
>> +    echo "$0 [-f] [-m name] [-t type]"
>> +    echo "-f:  full test. It maybe conflict with existence gpio device."
>> +    echo "-m:  module name, default name is gpio-mockup. It could also test"
>> +    echo "     other gpio device."
>> +    echo "-t:  interface type: chardev(char device) and sysfs(being"
>> +    echo "     deprecated). The first one is default"
>> +    echo ""
>> +    echo "$0 -h"
>> +    echo "This usage"
>> +}
>> +
>> +prerequisite()
>> +{
>> +    msg="skip all tests:"
>> +    if [ $UID != 0 ]; then
>> +        echo $msg must be run as root >&2
>> +        exit 1
>> +    fi
>> +    SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
>> +    if [ ! -d "$SYSFS" ]; then
>> +        echo $msg sysfs is not mounted >&2
>> +        exit 2
>> +    fi
>> +    GPIO_SYSFS=`echo $SYSFS/class/gpio`
>> +    GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
>> +    DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
>> +    if [ ! -d "$DEBUGFS" ]; then
>> +        echo $msg debugfs is not mounted >&2
>> +        exit 2
>> +    fi
>> +    GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
>> +    source gpio-mockup-sysfs.sh
>> +}
>> +
>> +try_insert_module()
>> +{
>> +    if [ -d "$GPIO_DRV_SYSFS" ]; then
>> +        echo "$GPIO_DRV_SYSFS exist. Skip insert module"
>> +    else
>> +        modprobe -q $module $1
>> +        if [ X$? != X0 ]; then
>> +            echo $msg insmod $module failed >&2
>> +            exit 3
>> +        fi
>> +    fi
>> +}
>> +
>> +remove_module()
>> +{
>> +    modprobe -r -q $module
>> +}
>> +
>> +die()
>> +{
>> +    remove_module
>> +    exit 4
>> +}
>> +
>> +test_chips()
>> +{
>> +    if [ X$dev_type = Xsysfs ]; then
>> +        echo "WARNING: sysfs ABI of gpio is going to deprecated."
>> +        test_chips_sysfs $*
>> +    else
>> +        $BASE/gpio-mockup-chardev $*
>> +    fi
>> +}
>> +
>> +gpio_test()
>> +{
>> +    param=$1
>> +    valid=$2
>> +
>> +    if [ X"$param" = X ]; then
>> +        die
>> +    fi
>> +    try_insert_module "gpio_mockup_ranges=$param"
>> +    echo -n "GPIO $module test with ranges: <"
>> +    echo "$param>: "
>> +    printf "%-10s %s\n" $param
>> +    test_chips $module $valid
>> +    remove_module
>> +}
>> +
>> +BASE=`dirname $0`
>> +
>> +dev_type=
>> +TEMP=`getopt -o fhm:t: -n '$0' -- "$@"`
>> +
>> +if [ "$?" != "0" ]; then
>> +        echo "Parameter process failed, Terminating..." >&2
>> +        exit 1
>> +fi
>> +
>> +# Note the quotes around `$TEMP': they are essential!
>> +eval set -- "$TEMP"
>> +
>> +while true; do
>> +    case $1 in
>> +    -f)
>> +        full_test=true
>> +        shift
>> +        ;;
>> +    -h)
>> +        usage
>> +        exit
>> +        ;;
>> +    -m)
>> +        module=$2
>> +        shift 2
>> +        ;;
>> +    -t)
>> +        dev_type=$2
>> +        shift 2
>> +        ;;
>> +    --)
>> +        shift
>> +        break
>> +        ;;
>> +    *)
>> +        echo "Internal error!"
>> +        exit 1
>> +        ;;
>> +    esac
>> +done
>> +
>> +if [ X"$module" = X ]; then
>> +    module="gpio-mockup"
>> +fi
>> +
>> +if [ X$dev_type != Xsysfs ]; then
>> +    dev_type="chardev"
>> +fi
>> +
>> +prerequisite
>> +
>> +echo "1.  Test dynamic allocation of gpio successful means insert gpiochip and"
>> +echo "    manipulate gpio pin successful"
>> +gpio_test "-1,32" true
>> +gpio_test "-1,32,-1,32" true
>> +gpio_test "-1,32,-1,32,-1,32" true
>> +if [ X$full_test = Xtrue ]; then
>> +    gpio_test "-1,32,32,64" true
>> +    gpio_test "-1,32,40,64,-1,5" true
>> +    gpio_test "-1,32,32,64,-1,32" true
>> +    gpio_test "0,32,32,64,-1,32,-1,32" true
>> +    gpio_test "-1,32,-1,32,0,32,32,64" true
>> +    echo "2.  Do basic test: successful means insert gpiochip and"
>> +    echo "    manipulate gpio pin successful"
>> +    gpio_test "0,32" true
>> +    gpio_test "0,32,32,64" true
>> +    gpio_test "0,32,40,64,64,96" true
>> +fi
>> +echo "3.  Error test: successful means insert gpiochip failed"
>> +echo "3.1 Test number of gpio overflow"
>> +#Currently: The max number of gpio(1024) is defined in arm architecture.
>> +gpio_test "-1,32,-1,1024" false
>> +if [ X$full_test = Xtrue ]; then
>> +    echo "3.2 Test zero line of gpio"
>> +    gpio_test "0,0" false
>> +    echo "3.3 Test range overlap"
>> +    echo "3.3.1 Test corner case"
>> +    gpio_test "0,32,0,1" false
>> +    gpio_test "0,32,32,64,32,40" false
>> +    gpio_test "0,32,35,64,35,45" false
>> +    gpio_test "0,32,31,32" false
>> +    gpio_test "0,32,32,64,36,37" false
>> +    gpio_test "0,32,35,64,34,36" false
>> +    echo "3.3.2 Test inserting invalid second gpiochip"
>> +    gpio_test "0,32,30,35" false
>> +    gpio_test "0,32,1,5" false
>> +    gpio_test "10,32,9,14" false
>> +    gpio_test "10,32,30,35" false
>> +    echo "3.3.3 Test others"
>> +    gpio_test "0,32,40,56,39,45" false
>> +    gpio_test "0,32,40,56,30,33" false
>> +    gpio_test "0,32,40,56,30,41" false
>> +    gpio_test "0,32,40,56,20,21" false
>> +fi
>> +
>> +echo GPIO test PASS
>> +
>>
> 
> 
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-12-13 14:41 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-14  2:48 [PATCH v4 0/3] Add gpio test framework Bamvor Jian Zhang
2016-10-14  2:48 ` [PATCH v4 1/3] tools/gpio: add gpio basic opereations Bamvor Jian Zhang
2016-10-21 11:46   ` Linus Walleij
2016-10-14  2:48 ` [PATCH v4 2/3] tools/gpio: re-work gpio hammer with gpio operations Bamvor Jian Zhang
2016-10-21 11:47   ` Linus Walleij
2016-10-14  2:48 ` [PATCH v4 3/3] selftest/gpio: add gpio test case Bamvor Jian Zhang
2016-10-21 11:54   ` Linus Walleij
2016-10-21 14:43     ` Bamvor Zhang Jian
2016-11-16 23:42     ` Shuah Khan
2016-11-18 11:41       ` Zhangjian (Bamvor)
2016-11-21 10:16       ` [PATCH v5] " bamvor.zhangjian
2016-12-13 12:42         ` Zhangjian (Bamvor)
2016-12-13 14:33           ` Shuah Khan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.