forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
8.5 KiB
403 lines
8.5 KiB
#!/bin/bash -efu |
|
# SPDX-License-Identifier: GPL-2.0 |
|
|
|
#exit status |
|
#0: success |
|
#1: fail |
|
#4: skip test - including run as non-root user |
|
|
|
BASE=${0%/*} |
|
DEBUGFS= |
|
GPIO_DEBUGFS= |
|
dev_type="cdev" |
|
module="gpio-mockup" |
|
verbose= |
|
full_test= |
|
random= |
|
uapi_opt= |
|
active_opt= |
|
bias_opt= |
|
line_set_pid= |
|
|
|
# Kselftest return codes |
|
ksft_fail=1 |
|
ksft_skip=4 |
|
|
|
usage() |
|
{ |
|
echo "Usage:" |
|
echo "$0 [-frv] [-t type]" |
|
echo "-f: full test (minimal set run by default)" |
|
echo "-r: test random lines as well as fence posts" |
|
echo "-t: interface type:" |
|
echo " cdev (character device ABI) - default" |
|
echo " cdev_v1 (deprecated character device ABI)" |
|
echo " sysfs (deprecated SYSFS ABI)" |
|
echo "-v: verbose progress reporting" |
|
exit $ksft_fail |
|
} |
|
|
|
skip() |
|
{ |
|
echo "$*" >&2 |
|
echo "GPIO $module test SKIP" |
|
exit $ksft_skip |
|
} |
|
|
|
prerequisite() |
|
{ |
|
[ $(id -u) -eq 0 ] || skip "must be run as root" |
|
|
|
DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ') |
|
[ -d "$DEBUGFS" ] || skip "debugfs is not mounted" |
|
|
|
GPIO_DEBUGFS=$DEBUGFS/$module |
|
} |
|
|
|
remove_module() |
|
{ |
|
modprobe -r -q $module |
|
} |
|
|
|
cleanup() |
|
{ |
|
set +e |
|
release_line |
|
remove_module |
|
jobs -p | xargs -r kill > /dev/null 2>&1 |
|
} |
|
|
|
fail() |
|
{ |
|
echo "test failed: $*" >&2 |
|
echo "GPIO $module test FAIL" |
|
exit $ksft_fail |
|
} |
|
|
|
try_insert_module() |
|
{ |
|
modprobe -q $module "$1" || fail "insert $module failed with error $?" |
|
} |
|
|
|
log() |
|
{ |
|
[ -z "$verbose" ] || echo "$*" |
|
} |
|
|
|
# The following line helpers, release_Line, get_line and set_line, all |
|
# make use of the global $chip and $offset variables. |
|
# |
|
# This implementation drives the GPIO character device (cdev) uAPI. |
|
# Other implementations may override these to test different uAPIs. |
|
|
|
# Release any resources related to the line |
|
release_line() |
|
{ |
|
[ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true |
|
line_set_pid= |
|
} |
|
|
|
# Read the current value of the line |
|
get_line() |
|
{ |
|
release_line |
|
|
|
local cdev_opts=${uapi_opt}${active_opt} |
|
$BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset |
|
echo $? |
|
} |
|
|
|
# Set the state of the line |
|
# |
|
# Changes to line configuration are provided as parameters. |
|
# The line is assumed to be an output if the line value 0 or 1 is |
|
# specified, else an input. |
|
set_line() |
|
{ |
|
local val= |
|
|
|
release_line |
|
|
|
# parse config options... |
|
for option in $*; do |
|
case $option in |
|
active-low) |
|
active_opt="-l " |
|
;; |
|
active-high) |
|
active_opt= |
|
;; |
|
bias-none) |
|
bias_opt= |
|
;; |
|
pull-down) |
|
bias_opt="-bpull-down " |
|
;; |
|
pull-up) |
|
bias_opt="-bpull-up " |
|
;; |
|
0) |
|
val=0 |
|
;; |
|
1) |
|
val=1 |
|
;; |
|
esac |
|
done |
|
|
|
local cdev_opts=${uapi_opt}${active_opt} |
|
if [ "$val" ]; then |
|
$BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset & |
|
# failure to set is detected by reading mockup and toggling values |
|
line_set_pid=$! |
|
# allow for gpio-mockup-cdev to launch and request line |
|
# (there is limited value in checking if line has been requested) |
|
sleep 0.01 |
|
elif [ "$bias_opt" ]; then |
|
cdev_opts=${cdev_opts}${bias_opt} |
|
$BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true |
|
fi |
|
} |
|
|
|
assert_line() |
|
{ |
|
local val |
|
# don't need any retry here as set_mock allows for propagation |
|
val=$(get_line) |
|
[ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected" |
|
} |
|
|
|
# The following mockup helpers all make use of the $mock_line |
|
assert_mock() |
|
{ |
|
local backoff_wait=10 |
|
local retry=0 |
|
local val |
|
# retry allows for set propagation from uAPI to mockup |
|
while true; do |
|
val=$(< $mock_line) |
|
[ "$val" = "$1" ] && break |
|
retry=$((retry + 1)) |
|
[ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected" |
|
sleep $(printf "%0.2f" $((backoff_wait))e-3) |
|
backoff_wait=$((backoff_wait * 2)) |
|
done |
|
} |
|
|
|
set_mock() |
|
{ |
|
echo "$1" > $mock_line |
|
# allow for set propagation - so we won't be in a race with set_line |
|
assert_mock "$1" |
|
} |
|
|
|
# test the functionality of a line |
|
# |
|
# The line is set from the mockup side and is read from the userspace side |
|
# (input), and is set from the userspace side and is read from the mockup side |
|
# (output). |
|
# |
|
# Setting the mockup pull using the userspace interface bias settings is |
|
# tested where supported by the userspace interface (cdev). |
|
test_line() |
|
{ |
|
chip=$1 |
|
offset=$2 |
|
log "test_line $chip $offset" |
|
mock_line=$GPIO_DEBUGFS/$chip/$offset |
|
[ -e "$mock_line" ] || fail "missing line $chip:$offset" |
|
|
|
# test input active-high |
|
set_mock 1 |
|
set_line input active-high |
|
assert_line 1 |
|
set_mock 0 |
|
assert_line 0 |
|
set_mock 1 |
|
assert_line 1 |
|
|
|
if [ "$full_test" ]; then |
|
if [ "$dev_type" != "sysfs" ]; then |
|
# test pulls |
|
set_mock 0 |
|
set_line input pull-up |
|
assert_line 1 |
|
set_mock 0 |
|
assert_line 0 |
|
|
|
set_mock 1 |
|
set_line input pull-down |
|
assert_line 0 |
|
set_mock 1 |
|
assert_line 1 |
|
|
|
set_line bias-none |
|
fi |
|
|
|
# test input active-low |
|
set_mock 0 |
|
set_line active-low |
|
assert_line 1 |
|
set_mock 1 |
|
assert_line 0 |
|
set_mock 0 |
|
assert_line 1 |
|
|
|
# test output active-high |
|
set_mock 1 |
|
set_line active-high 0 |
|
assert_mock 0 |
|
set_line 1 |
|
assert_mock 1 |
|
set_line 0 |
|
assert_mock 0 |
|
fi |
|
|
|
# test output active-low |
|
set_mock 0 |
|
set_line active-low 0 |
|
assert_mock 1 |
|
set_line 1 |
|
assert_mock 0 |
|
set_line 0 |
|
assert_mock 1 |
|
|
|
release_line |
|
} |
|
|
|
test_no_line() |
|
{ |
|
log test_no_line "$*" |
|
[ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2" |
|
} |
|
|
|
# Load the module and check that the expected number of gpiochips, with the |
|
# expected number of lines, are created and are functional. |
|
# |
|
# $1 is the gpio_mockup_ranges parameter for the module |
|
# The remaining parameters are the number of lines, n, expected for each of |
|
# the gpiochips expected to be created. |
|
# |
|
# For each gpiochip the fence post lines, 0 and n-1, are tested, and the |
|
# line on the far side of the fence post, n, is tested to not exist. |
|
# |
|
# If the $random flag is set then a random line in the middle of the |
|
# gpiochip is tested as well. |
|
insmod_test() |
|
{ |
|
local ranges= |
|
local gc= |
|
local width= |
|
|
|
[ "${1:-}" ] || fail "missing ranges" |
|
ranges=$1 ; shift |
|
try_insert_module "gpio_mockup_ranges=$ranges" |
|
log "GPIO $module test with ranges: <$ranges>:" |
|
# e.g. /sys/kernel/debug/gpio-mockup/gpiochip1 |
|
gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort) |
|
for chip in $gpiochip; do |
|
gc=${chip##*/} |
|
[ "${1:-}" ] || fail "unexpected chip - $gc" |
|
width=$1 ; shift |
|
test_line $gc 0 |
|
if [ "$random" -a $width -gt 2 ]; then |
|
test_line $gc $((RANDOM % ($width - 2) + 1)) |
|
fi |
|
test_line $gc $(($width - 1)) |
|
test_no_line $gc $width |
|
done |
|
[ "${1:-}" ] && fail "missing expected chip of width $1" |
|
remove_module || fail "failed to remove module with error $?" |
|
} |
|
|
|
while getopts ":frvt:" opt; do |
|
case $opt in |
|
f) |
|
full_test=true |
|
;; |
|
r) |
|
random=true |
|
;; |
|
t) |
|
dev_type=$OPTARG |
|
;; |
|
v) |
|
verbose=true |
|
;; |
|
*) |
|
usage |
|
;; |
|
esac |
|
done |
|
shift $((OPTIND - 1)) |
|
|
|
[ "${1:-}" ] && fail "unknown argument '$1'" |
|
|
|
prerequisite |
|
|
|
trap 'exit $ksft_fail' SIGTERM SIGINT |
|
trap cleanup EXIT |
|
|
|
case "$dev_type" in |
|
sysfs) |
|
source $BASE/gpio-mockup-sysfs.sh |
|
echo "WARNING: gpio sysfs ABI is deprecated." |
|
;; |
|
cdev_v1) |
|
echo "WARNING: gpio cdev ABI v1 is deprecated." |
|
uapi_opt="-u1 " |
|
;; |
|
cdev) |
|
;; |
|
*) |
|
fail "unknown interface type: $dev_type" |
|
;; |
|
esac |
|
|
|
remove_module || fail "can't remove existing $module module" |
|
|
|
# manual gpio allocation tests fail if a physical chip already exists |
|
[ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0" |
|
|
|
echo "1. Module load tests" |
|
echo "1.1. dynamic allocation of gpio" |
|
insmod_test "-1,32" 32 |
|
insmod_test "-1,23,-1,32" 23 32 |
|
insmod_test "-1,23,-1,26,-1,32" 23 26 32 |
|
if [ "$full_test" ]; then |
|
echo "1.2. manual allocation of gpio" |
|
insmod_test "0,32" 32 |
|
insmod_test "0,32,32,60" 32 28 |
|
insmod_test "0,32,40,64,64,96" 32 24 32 |
|
echo "1.3. dynamic and manual allocation of gpio" |
|
insmod_test "-1,32,32,62" 32 30 |
|
insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32 |
|
insmod_test "-1,32,32,60,-1,29" 32 28 29 |
|
insmod_test "-1,32,40,64,-1,5" 32 24 5 |
|
insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31 |
|
fi |
|
echo "2. Module load error tests" |
|
echo "2.1 gpio overflow" |
|
# Currently: The max number of gpio(1024) is defined in arm architecture. |
|
insmod_test "-1,1024" |
|
if [ "$full_test" ]; then |
|
echo "2.2 no lines defined" |
|
insmod_test "0,0" |
|
echo "2.3 ignore range overlap" |
|
insmod_test "0,32,0,1" 32 |
|
insmod_test "0,32,1,5" 32 |
|
insmod_test "0,32,30,35" 32 |
|
insmod_test "0,32,31,32" 32 |
|
insmod_test "10,32,30,35" 22 |
|
insmod_test "10,32,9,14" 22 |
|
insmod_test "0,32,20,21,40,56" 32 16 |
|
insmod_test "0,32,32,64,32,40" 32 32 |
|
insmod_test "0,32,32,64,36,37" 32 32 |
|
insmod_test "0,32,35,64,34,36" 32 29 |
|
insmod_test "0,30,35,64,35,45" 30 29 |
|
insmod_test "0,32,40,56,30,33" 32 16 |
|
insmod_test "0,32,40,56,30,41" 32 16 |
|
insmod_test "0,32,40,56,39,45" 32 16 |
|
fi |
|
|
|
echo "GPIO $module test PASS"
|
|
|