Commit 8bc395a6 authored by Kent Gibson's avatar Kent Gibson Committed by Bartosz Golaszewski

selftests: gpio: rework and simplify test implementation

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: 8a39f597 ("gpio: mockup: rework device probing")
Signed-off-by: default avatarKent Gibson <warthog618@gmail.com>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarBartosz Golaszewski <bgolaszewski@baylibre.com>
parent 27f8feea
# SPDX-License-Identifier: GPL-2.0 # 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_PROGS := gpio-mockup.sh
TEST_FILES := gpio-mockup-sysfs.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 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)
// 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;
}
# SPDX-License-Identifier: GPL-2.0 # 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"` # Overrides functions in gpio-mockup.sh to test using the GPIO SYSFS uAPI
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 SYSFS=`grep -w sysfs /proc/mounts | cut -f2 -d' '`
if [ $val = "0" ]; then [ -d "$SYSFS" ] || skip "sysfs is not mounted"
val="1"
else
val="0"
fi
fi
if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then GPIO_SYSFS="${SYSFS}/class/gpio"
echo -n "." [ -d "$GPIO_SYSFS" ] || skip "CONFIG_GPIO_SYSFS is not selected"
else
echo "test fail, exit"
die
fi
}
test_pin_logic() PLATFORM_SYSFS=$SYSFS/devices/platform
{
nr=$1
direction=$2
active_low=$3
value=$4
echo $direction > $GPIO_SYSFS/gpio$nr/direction sysfs_nr=
echo $active_low > $GPIO_SYSFS/gpio$nr/active_low sysfs_ldir=
if [ $direction = "out" ]; then
echo $value > $GPIO_SYSFS/gpio$nr/value
fi
is_consistent $nr
}
test_one_pin() # determine the sysfs GPIO number given the $chip and $offset
# e.g. gpiochip1:32
find_sysfs_nr()
{ {
nr=$1 # e.g. /sys/devices/platform/gpio-mockup.1/gpiochip1
local platform=$(find $PLATFORM_SYSFS -mindepth 2 -maxdepth 2 -type d -name $chip)
echo -n "test pin<$nr>" [ "$platform" ] || fail "can't find platform of $chip"
# e.g. /sys/devices/platform/gpio-mockup.1/gpio/gpiochip508/base
echo $nr > $GPIO_SYSFS/export 2>/dev/null local base=$(find ${platform%/*}/gpio/ -mindepth 2 -maxdepth 2 -type f -name base)
[ "$base" ] || fail "can't find base of $chip"
if [ X$? != X0 ]; then sysfs_nr=$(($(< "$base") + $offset))
echo "test GPIO pin $nr failed" sysfs_ldir="$GPIO_SYSFS/gpio$sysfs_nr"
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() acquire_line()
{ {
nr=$1 [ "$sysfs_nr" ] && return
find_sysfs_nr
echo $nr > $GPIO_SYSFS/export 2>/dev/null echo "$sysfs_nr" > "$GPIO_SYSFS/export"
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() # 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 acquire_line
name=`basename $chip`
base=`cat $chip/base` for option in $*; do
ngpio=`cat $chip/ngpio` case $option in
printf "%-10s %-5s %-5s\n" $name $base $ngpio active-high)
if [ $ngpio = "0" ]; then echo 0 > "$sysfs_ldir/active_low"
echo "number of gpio is zero is not allowed". ;;
fi active-low)
test_one_pin $base echo 1 > "$sysfs_ldir/active_low"
test_one_pin $(($base + $ngpio - 1)) ;;
test_one_pin $((( RANDOM % $ngpio ) + $base )) 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` [ "$sysfs_nr" ] || return 0
if [ X"$gpiochip" = X ]; then echo "$sysfs_nr" > "$GPIO_SYSFS/unexport"
if [ X"$valid" = Xfalse ]; then sysfs_nr=
echo "successful" sysfs_ldir=
else
echo "fail"
die
fi
else
for chip in $gpiochip; do
test_chip $chip
done
fi
} }
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment