Skip to content

Commit

Permalink
selftests: gpio: rework and simplify test implementation
Browse files Browse the repository at this point in the history
The GPIO mockup selftests are overly complicated with separate
implementations of the tests for sysfs and cdev uAPI, and with the cdev
implementation being dependent on tools/gpio and libmount.

Rework the test implementation to provide a common test suite with a
simplified pluggable uAPI interface.  The cdev implementation utilises
the GPIO uAPI directly to remove the dependence on tools/gpio.
The simplified uAPI interface removes the need for any file system mount
checks in C, and so removes the dependence on libmount.

The rework also fixes the sysfs test implementation which has been broken
since the device created in the multiple gpiochip case was split into
separate devices.

Fixes: 8a39f59 ("gpio: mockup: rework device probing")
Signed-off-by: Kent Gibson <warthog618@gmail.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
  • Loading branch information
Kent Gibson authored and Bartosz Golaszewski committed Feb 15, 2021
1 parent 27f8fee commit 8bc395a
Show file tree
Hide file tree
Showing 4 changed files with 535 additions and 288 deletions.
26 changes: 1 addition & 25 deletions tools/testing/selftests/gpio/Makefile
Original file line number Diff line number Diff line change
@@ -1,31 +1,7 @@
# SPDX-License-Identifier: GPL-2.0

VAR_CFLAGS := $(shell pkg-config --cflags mount 2>/dev/null)
VAR_LDLIBS := $(shell pkg-config --libs mount 2>/dev/null)
ifeq ($(VAR_LDLIBS),)
VAR_LDLIBS := -lmount -I/usr/include/libmount
endif

CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/ $(VAR_CFLAGS)
LDLIBS += $(VAR_LDLIBS)

TEST_PROGS := gpio-mockup.sh
TEST_FILES := gpio-mockup-sysfs.sh
TEST_GEN_PROGS_EXTENDED := gpio-mockup-chardev
TEST_GEN_PROGS_EXTENDED := gpio-mockup-cdev

KSFT_KHDR_INSTALL := 1
include ../lib.mk

GPIODIR := $(realpath ../../../gpio)
GPIOOUT := $(OUTPUT)/tools-gpio/
GPIOOBJ := $(GPIOOUT)/gpio-utils.o

CLEAN += ; $(RM) -rf $(GPIOOUT)

$(TEST_GEN_PROGS_EXTENDED): $(GPIOOBJ)

$(GPIOOUT):
mkdir -p $@

$(GPIOOBJ): $(GPIOOUT)
$(MAKE) OUTPUT=$(GPIOOUT) -C $(GPIODIR)
139 changes: 139 additions & 0 deletions tools/testing/selftests/gpio/gpio-mockup-cdev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO mockup cdev test helper
*
* Copyright (C) 2020 Kent Gibson
*/

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>

#define CONSUMER "gpio-mockup-cdev"

static int request_line_v1(int cfd, unsigned int offset,
uint32_t flags, unsigned int val)
{
struct gpiohandle_request req;
int ret;

memset(&req, 0, sizeof(req));
req.lines = 1;
req.lineoffsets[0] = offset;
req.flags = flags;
strcpy(req.consumer_label, CONSUMER);
if (flags & GPIOHANDLE_REQUEST_OUTPUT)
req.default_values[0] = val;

ret = ioctl(cfd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1)
return -errno;
return req.fd;
}

static int get_value_v1(int lfd)
{
struct gpiohandle_data vals;
int ret;

memset(&vals, 0, sizeof(vals));
ret = ioctl(lfd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &vals);
if (ret == -1)
return -errno;
return vals.values[0];
}

static void usage(char *prog)
{
printf("Usage: %s [-l] [-b <bias>] [-s <value>] [-u <uAPI>] <gpiochip> <offset>\n", prog);
printf(" -b: set line bias to one of pull-down, pull-up, disabled\n");
printf(" (default is to leave bias unchanged):\n");
printf(" -l: set line active low (default is active high)\n");
printf(" -s: set line value (default is to get line value)\n");
exit(-1);
}

static int wait_signal(void)
{
int sig;
sigset_t wset;

sigemptyset(&wset);
sigaddset(&wset, SIGHUP);
sigaddset(&wset, SIGINT);
sigaddset(&wset, SIGTERM);
sigwait(&wset, &sig);

return sig;
}

int main(int argc, char *argv[])
{
char *chip;
int opt, ret, cfd, lfd;
unsigned int offset, val;
uint32_t flags_v1;

ret = 0;
flags_v1 = GPIOHANDLE_REQUEST_INPUT;

while ((opt = getopt(argc, argv, "lb:s:u:")) != -1) {
switch (opt) {
case 'l':
flags_v1 |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
break;
case 'b':
if (strcmp("pull-up", optarg) == 0)
flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
else if (strcmp("pull-down", optarg) == 0)
flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
else if (strcmp("disabled", optarg) == 0)
flags_v1 |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
break;
case 's':
val = atoi(optarg);
flags_v1 &= ~GPIOHANDLE_REQUEST_INPUT;
flags_v1 |= GPIOHANDLE_REQUEST_OUTPUT;
break;
default:
usage(argv[0]);
}
}

if (argc < optind + 2)
usage(argv[0]);

chip = argv[optind];
offset = atoi(argv[optind + 1]);

cfd = open(chip, 0);
if (cfd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", chip, strerror(errno));
return -errno;
}

lfd = request_line_v1(cfd, offset, flags_v1, val);

close(cfd);

if (lfd < 0) {
fprintf(stderr, "Failed to request %s:%d: %s\n", chip, offset, strerror(-lfd));
return lfd;
}

if (flags_v1 & GPIOHANDLE_REQUEST_OUTPUT)
wait_signal();
else
ret = get_value_v1(lfd);

close(lfd);

return ret;
}
168 changes: 55 additions & 113 deletions tools/testing/selftests/gpio/gpio-mockup-sysfs.sh
Original file line number Diff line number Diff line change
@@ -1,135 +1,77 @@

# SPDX-License-Identifier: GPL-2.0
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
# Overrides functions in gpio-mockup.sh to test using the GPIO SYSFS uAPI

if [ $active_low_sysfs = "1" ]; then
if [ $val = "0" ]; then
val="1"
else
val="0"
fi
fi
SYSFS=`grep -w sysfs /proc/mounts | cut -f2 -d' '`
[ -d "$SYSFS" ] || skip "sysfs is not mounted"

if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
echo -n "."
else
echo "test fail, exit"
die
fi
}
GPIO_SYSFS="${SYSFS}/class/gpio"
[ -d "$GPIO_SYSFS" ] || skip "CONFIG_GPIO_SYSFS is not selected"

test_pin_logic()
{
nr=$1
direction=$2
active_low=$3
value=$4
PLATFORM_SYSFS=$SYSFS/devices/platform

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
}
sysfs_nr=
sysfs_ldir=

test_one_pin()
# determine the sysfs GPIO number given the $chip and $offset
# e.g. gpiochip1:32
find_sysfs_nr()
{
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"
# e.g. /sys/devices/platform/gpio-mockup.1/gpiochip1
local platform=$(find $PLATFORM_SYSFS -mindepth 2 -maxdepth 2 -type d -name $chip)
[ "$platform" ] || fail "can't find platform of $chip"
# e.g. /sys/devices/platform/gpio-mockup.1/gpio/gpiochip508/base
local base=$(find ${platform%/*}/gpio/ -mindepth 2 -maxdepth 2 -type f -name base)
[ "$base" ] || fail "can't find base of $chip"
sysfs_nr=$(($(< "$base") + $offset))
sysfs_ldir="$GPIO_SYSFS/gpio$sysfs_nr"
}

test_one_pin_fail()
acquire_line()
{
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
[ "$sysfs_nr" ] && return
find_sysfs_nr
echo "$sysfs_nr" > "$GPIO_SYSFS/export"
}

list_chip()
# The helpers being overridden...
get_line()
{
echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
[ -e "$sysfs_ldir/value" ] && echo $(< "$sysfs_ldir/value")
}

test_chip()
set_line()
{
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 ))
acquire_line

for option in $*; do
case $option in
active-high)
echo 0 > "$sysfs_ldir/active_low"
;;
active-low)
echo 1 > "$sysfs_ldir/active_low"
;;
input)
echo "in" > "$sysfs_ldir/direction"
;;
0)
echo "out" > "$sysfs_ldir/direction"
echo 0 > "$sysfs_ldir/value"
;;
1)
echo "out" > "$sysfs_ldir/direction"
echo 1 > "$sysfs_ldir/value"
;;
esac
done
}

test_chips_sysfs()
release_line()
{
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
[ "$sysfs_nr" ] || return 0
echo "$sysfs_nr" > "$GPIO_SYSFS/unexport"
sysfs_nr=
sysfs_ldir=
}

Loading

0 comments on commit 8bc395a

Please sign in to comment.