mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
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: 8a39f597bc ("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>
This commit is contained in:
committed by
Bartosz Golaszewski
parent
27f8feea40
commit
8bc395a6a2
@@ -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
tools/testing/selftests/gpio/gpio-mockup-cdev.c
Normal file
139
tools/testing/selftests/gpio/gpio-mockup-cdev.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -1,135 +1,77 @@
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
is_consistent()
|
||||
|
||||
# Overrides functions in gpio-mockup.sh to test using the GPIO SYSFS uAPI
|
||||
|
||||
SYSFS=`grep -w sysfs /proc/mounts | cut -f2 -d' '`
|
||||
[ -d "$SYSFS" ] || skip "sysfs is not mounted"
|
||||
|
||||
GPIO_SYSFS="${SYSFS}/class/gpio"
|
||||
[ -d "$GPIO_SYSFS" ] || skip "CONFIG_GPIO_SYSFS is not selected"
|
||||
|
||||
PLATFORM_SYSFS=$SYSFS/devices/platform
|
||||
|
||||
sysfs_nr=
|
||||
sysfs_ldir=
|
||||
|
||||
# determine the sysfs GPIO number given the $chip and $offset
|
||||
# e.g. gpiochip1:32
|
||||
find_sysfs_nr()
|
||||
{
|
||||
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
|
||||
# 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_pin_logic()
|
||||
acquire_line()
|
||||
{
|
||||
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
|
||||
[ "$sysfs_nr" ] && return
|
||||
find_sysfs_nr
|
||||
echo "$sysfs_nr" > "$GPIO_SYSFS/export"
|
||||
}
|
||||
|
||||
test_one_pin()
|
||||
# The helpers being overridden...
|
||||
get_line()
|
||||
{
|
||||
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 "$sysfs_ldir/value" ] && echo $(< "$sysfs_ldir/value")
|
||||
}
|
||||
|
||||
test_one_pin_fail()
|
||||
set_line()
|
||||
{
|
||||
nr=$1
|
||||
acquire_line
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
list_chip()
|
||||
release_line()
|
||||
{
|
||||
echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
|
||||
[ "$sysfs_nr" ] || return 0
|
||||
echo "$sysfs_nr" > "$GPIO_SYSFS/unexport"
|
||||
sysfs_nr=
|
||||
sysfs_ldir=
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user