-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: 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
Showing
4 changed files
with
535 additions
and
288 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= | ||
} | ||
|
Oops, something went wrong.