162306a36Sopenharmony_ci#!/bin/bash -efu 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#exit status 562306a36Sopenharmony_ci#0: success 662306a36Sopenharmony_ci#1: fail 762306a36Sopenharmony_ci#4: skip test - including run as non-root user 862306a36Sopenharmony_ci 962306a36Sopenharmony_ciBASE=${0%/*} 1062306a36Sopenharmony_ciDEBUGFS= 1162306a36Sopenharmony_ciGPIO_DEBUGFS= 1262306a36Sopenharmony_cidev_type="cdev" 1362306a36Sopenharmony_cimodule="gpio-mockup" 1462306a36Sopenharmony_civerbose= 1562306a36Sopenharmony_cifull_test= 1662306a36Sopenharmony_cirandom= 1762306a36Sopenharmony_ciuapi_opt= 1862306a36Sopenharmony_ciactive_opt= 1962306a36Sopenharmony_cibias_opt= 2062306a36Sopenharmony_ciline_set_pid= 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci# Kselftest return codes 2362306a36Sopenharmony_ciksft_fail=1 2462306a36Sopenharmony_ciksft_skip=4 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciusage() 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci echo "Usage:" 2962306a36Sopenharmony_ci echo "$0 [-frv] [-t type]" 3062306a36Sopenharmony_ci echo "-f: full test (minimal set run by default)" 3162306a36Sopenharmony_ci echo "-r: test random lines as well as fence posts" 3262306a36Sopenharmony_ci echo "-t: interface type:" 3362306a36Sopenharmony_ci echo " cdev (character device ABI) - default" 3462306a36Sopenharmony_ci echo " cdev_v1 (deprecated character device ABI)" 3562306a36Sopenharmony_ci echo " sysfs (deprecated SYSFS ABI)" 3662306a36Sopenharmony_ci echo "-v: verbose progress reporting" 3762306a36Sopenharmony_ci exit $ksft_fail 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ciskip() 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci echo "$*" >&2 4362306a36Sopenharmony_ci echo "GPIO $module test SKIP" 4462306a36Sopenharmony_ci exit $ksft_skip 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciprerequisite() 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci [ $(id -u) -eq 0 ] || skip "must be run as root" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ') 5262306a36Sopenharmony_ci [ -d "$DEBUGFS" ] || skip "debugfs is not mounted" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci GPIO_DEBUGFS=$DEBUGFS/$module 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciremove_module() 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci modprobe -r -q $module 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cicleanup() 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci set +e 6562306a36Sopenharmony_ci release_line 6662306a36Sopenharmony_ci remove_module 6762306a36Sopenharmony_ci jobs -p | xargs -r kill > /dev/null 2>&1 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cifail() 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci echo "test failed: $*" >&2 7362306a36Sopenharmony_ci echo "GPIO $module test FAIL" 7462306a36Sopenharmony_ci exit $ksft_fail 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_citry_insert_module() 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci modprobe -q $module "$1" || fail "insert $module failed with error $?" 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cilog() 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci [ -z "$verbose" ] || echo "$*" 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci# The following line helpers, release_Line, get_line and set_line, all 8862306a36Sopenharmony_ci# make use of the global $chip and $offset variables. 8962306a36Sopenharmony_ci# 9062306a36Sopenharmony_ci# This implementation drives the GPIO character device (cdev) uAPI. 9162306a36Sopenharmony_ci# Other implementations may override these to test different uAPIs. 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci# Release any resources related to the line 9462306a36Sopenharmony_cirelease_line() 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci [ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true 9762306a36Sopenharmony_ci line_set_pid= 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci# Read the current value of the line 10162306a36Sopenharmony_ciget_line() 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci release_line 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci local cdev_opts=${uapi_opt}${active_opt} 10662306a36Sopenharmony_ci $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset 10762306a36Sopenharmony_ci echo $? 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci# Set the state of the line 11162306a36Sopenharmony_ci# 11262306a36Sopenharmony_ci# Changes to line configuration are provided as parameters. 11362306a36Sopenharmony_ci# The line is assumed to be an output if the line value 0 or 1 is 11462306a36Sopenharmony_ci# specified, else an input. 11562306a36Sopenharmony_ciset_line() 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci local val= 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci release_line 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci # parse config options... 12262306a36Sopenharmony_ci for option in $*; do 12362306a36Sopenharmony_ci case $option in 12462306a36Sopenharmony_ci active-low) 12562306a36Sopenharmony_ci active_opt="-l " 12662306a36Sopenharmony_ci ;; 12762306a36Sopenharmony_ci active-high) 12862306a36Sopenharmony_ci active_opt= 12962306a36Sopenharmony_ci ;; 13062306a36Sopenharmony_ci bias-none) 13162306a36Sopenharmony_ci bias_opt= 13262306a36Sopenharmony_ci ;; 13362306a36Sopenharmony_ci pull-down) 13462306a36Sopenharmony_ci bias_opt="-bpull-down " 13562306a36Sopenharmony_ci ;; 13662306a36Sopenharmony_ci pull-up) 13762306a36Sopenharmony_ci bias_opt="-bpull-up " 13862306a36Sopenharmony_ci ;; 13962306a36Sopenharmony_ci 0) 14062306a36Sopenharmony_ci val=0 14162306a36Sopenharmony_ci ;; 14262306a36Sopenharmony_ci 1) 14362306a36Sopenharmony_ci val=1 14462306a36Sopenharmony_ci ;; 14562306a36Sopenharmony_ci esac 14662306a36Sopenharmony_ci done 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci local cdev_opts=${uapi_opt}${active_opt} 14962306a36Sopenharmony_ci if [ "$val" ]; then 15062306a36Sopenharmony_ci $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset & 15162306a36Sopenharmony_ci # failure to set is detected by reading mockup and toggling values 15262306a36Sopenharmony_ci line_set_pid=$! 15362306a36Sopenharmony_ci # allow for gpio-mockup-cdev to launch and request line 15462306a36Sopenharmony_ci # (there is limited value in checking if line has been requested) 15562306a36Sopenharmony_ci sleep 0.01 15662306a36Sopenharmony_ci elif [ "$bias_opt" ]; then 15762306a36Sopenharmony_ci cdev_opts=${cdev_opts}${bias_opt} 15862306a36Sopenharmony_ci $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true 15962306a36Sopenharmony_ci fi 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciassert_line() 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci local val 16562306a36Sopenharmony_ci # don't need any retry here as set_mock allows for propagation 16662306a36Sopenharmony_ci val=$(get_line) 16762306a36Sopenharmony_ci [ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected" 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci# The following mockup helpers all make use of the $mock_line 17162306a36Sopenharmony_ciassert_mock() 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci local backoff_wait=10 17462306a36Sopenharmony_ci local retry=0 17562306a36Sopenharmony_ci local val 17662306a36Sopenharmony_ci # retry allows for set propagation from uAPI to mockup 17762306a36Sopenharmony_ci while true; do 17862306a36Sopenharmony_ci val=$(< $mock_line) 17962306a36Sopenharmony_ci [ "$val" = "$1" ] && break 18062306a36Sopenharmony_ci retry=$((retry + 1)) 18162306a36Sopenharmony_ci [ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected" 18262306a36Sopenharmony_ci sleep $(printf "%0.2f" $((backoff_wait))e-3) 18362306a36Sopenharmony_ci backoff_wait=$((backoff_wait * 2)) 18462306a36Sopenharmony_ci done 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciset_mock() 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci echo "$1" > $mock_line 19062306a36Sopenharmony_ci # allow for set propagation - so we won't be in a race with set_line 19162306a36Sopenharmony_ci assert_mock "$1" 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci# test the functionality of a line 19562306a36Sopenharmony_ci# 19662306a36Sopenharmony_ci# The line is set from the mockup side and is read from the userspace side 19762306a36Sopenharmony_ci# (input), and is set from the userspace side and is read from the mockup side 19862306a36Sopenharmony_ci# (output). 19962306a36Sopenharmony_ci# 20062306a36Sopenharmony_ci# Setting the mockup pull using the userspace interface bias settings is 20162306a36Sopenharmony_ci# tested where supported by the userspace interface (cdev). 20262306a36Sopenharmony_citest_line() 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci chip=$1 20562306a36Sopenharmony_ci offset=$2 20662306a36Sopenharmony_ci log "test_line $chip $offset" 20762306a36Sopenharmony_ci mock_line=$GPIO_DEBUGFS/$chip/$offset 20862306a36Sopenharmony_ci [ -e "$mock_line" ] || fail "missing line $chip:$offset" 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci # test input active-high 21162306a36Sopenharmony_ci set_mock 1 21262306a36Sopenharmony_ci set_line input active-high 21362306a36Sopenharmony_ci assert_line 1 21462306a36Sopenharmony_ci set_mock 0 21562306a36Sopenharmony_ci assert_line 0 21662306a36Sopenharmony_ci set_mock 1 21762306a36Sopenharmony_ci assert_line 1 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if [ "$full_test" ]; then 22062306a36Sopenharmony_ci if [ "$dev_type" != "sysfs" ]; then 22162306a36Sopenharmony_ci # test pulls 22262306a36Sopenharmony_ci set_mock 0 22362306a36Sopenharmony_ci set_line input pull-up 22462306a36Sopenharmony_ci assert_line 1 22562306a36Sopenharmony_ci set_mock 0 22662306a36Sopenharmony_ci assert_line 0 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci set_mock 1 22962306a36Sopenharmony_ci set_line input pull-down 23062306a36Sopenharmony_ci assert_line 0 23162306a36Sopenharmony_ci set_mock 1 23262306a36Sopenharmony_ci assert_line 1 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci set_line bias-none 23562306a36Sopenharmony_ci fi 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci # test input active-low 23862306a36Sopenharmony_ci set_mock 0 23962306a36Sopenharmony_ci set_line active-low 24062306a36Sopenharmony_ci assert_line 1 24162306a36Sopenharmony_ci set_mock 1 24262306a36Sopenharmony_ci assert_line 0 24362306a36Sopenharmony_ci set_mock 0 24462306a36Sopenharmony_ci assert_line 1 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci # test output active-high 24762306a36Sopenharmony_ci set_mock 1 24862306a36Sopenharmony_ci set_line active-high 0 24962306a36Sopenharmony_ci assert_mock 0 25062306a36Sopenharmony_ci set_line 1 25162306a36Sopenharmony_ci assert_mock 1 25262306a36Sopenharmony_ci set_line 0 25362306a36Sopenharmony_ci assert_mock 0 25462306a36Sopenharmony_ci fi 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci # test output active-low 25762306a36Sopenharmony_ci set_mock 0 25862306a36Sopenharmony_ci set_line active-low 0 25962306a36Sopenharmony_ci assert_mock 1 26062306a36Sopenharmony_ci set_line 1 26162306a36Sopenharmony_ci assert_mock 0 26262306a36Sopenharmony_ci set_line 0 26362306a36Sopenharmony_ci assert_mock 1 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci release_line 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_citest_no_line() 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci log test_no_line "$*" 27162306a36Sopenharmony_ci [ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2" 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci# Load the module and check that the expected number of gpiochips, with the 27562306a36Sopenharmony_ci# expected number of lines, are created and are functional. 27662306a36Sopenharmony_ci# 27762306a36Sopenharmony_ci# $1 is the gpio_mockup_ranges parameter for the module 27862306a36Sopenharmony_ci# The remaining parameters are the number of lines, n, expected for each of 27962306a36Sopenharmony_ci# the gpiochips expected to be created. 28062306a36Sopenharmony_ci# 28162306a36Sopenharmony_ci# For each gpiochip the fence post lines, 0 and n-1, are tested, and the 28262306a36Sopenharmony_ci# line on the far side of the fence post, n, is tested to not exist. 28362306a36Sopenharmony_ci# 28462306a36Sopenharmony_ci# If the $random flag is set then a random line in the middle of the 28562306a36Sopenharmony_ci# gpiochip is tested as well. 28662306a36Sopenharmony_ciinsmod_test() 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci local ranges= 28962306a36Sopenharmony_ci local gc= 29062306a36Sopenharmony_ci local width= 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci [ "${1:-}" ] || fail "missing ranges" 29362306a36Sopenharmony_ci ranges=$1 ; shift 29462306a36Sopenharmony_ci try_insert_module "gpio_mockup_ranges=$ranges" 29562306a36Sopenharmony_ci log "GPIO $module test with ranges: <$ranges>:" 29662306a36Sopenharmony_ci # e.g. /sys/kernel/debug/gpio-mockup/gpiochip1 29762306a36Sopenharmony_ci gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort) 29862306a36Sopenharmony_ci for chip in $gpiochip; do 29962306a36Sopenharmony_ci gc=${chip##*/} 30062306a36Sopenharmony_ci [ "${1:-}" ] || fail "unexpected chip - $gc" 30162306a36Sopenharmony_ci width=$1 ; shift 30262306a36Sopenharmony_ci test_line $gc 0 30362306a36Sopenharmony_ci if [ "$random" -a $width -gt 2 ]; then 30462306a36Sopenharmony_ci test_line $gc $((RANDOM % ($width - 2) + 1)) 30562306a36Sopenharmony_ci fi 30662306a36Sopenharmony_ci test_line $gc $(($width - 1)) 30762306a36Sopenharmony_ci test_no_line $gc $width 30862306a36Sopenharmony_ci done 30962306a36Sopenharmony_ci [ "${1:-}" ] && fail "missing expected chip of width $1" 31062306a36Sopenharmony_ci remove_module || fail "failed to remove module with error $?" 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciwhile getopts ":frvt:" opt; do 31462306a36Sopenharmony_ci case $opt in 31562306a36Sopenharmony_ci f) 31662306a36Sopenharmony_ci full_test=true 31762306a36Sopenharmony_ci ;; 31862306a36Sopenharmony_ci r) 31962306a36Sopenharmony_ci random=true 32062306a36Sopenharmony_ci ;; 32162306a36Sopenharmony_ci t) 32262306a36Sopenharmony_ci dev_type=$OPTARG 32362306a36Sopenharmony_ci ;; 32462306a36Sopenharmony_ci v) 32562306a36Sopenharmony_ci verbose=true 32662306a36Sopenharmony_ci ;; 32762306a36Sopenharmony_ci *) 32862306a36Sopenharmony_ci usage 32962306a36Sopenharmony_ci ;; 33062306a36Sopenharmony_ci esac 33162306a36Sopenharmony_cidone 33262306a36Sopenharmony_cishift $((OPTIND - 1)) 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci[ "${1:-}" ] && fail "unknown argument '$1'" 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ciprerequisite 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_citrap 'exit $ksft_fail' SIGTERM SIGINT 33962306a36Sopenharmony_citrap cleanup EXIT 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cicase "$dev_type" in 34262306a36Sopenharmony_cisysfs) 34362306a36Sopenharmony_ci source $BASE/gpio-mockup-sysfs.sh 34462306a36Sopenharmony_ci echo "WARNING: gpio sysfs ABI is deprecated." 34562306a36Sopenharmony_ci ;; 34662306a36Sopenharmony_cicdev_v1) 34762306a36Sopenharmony_ci echo "WARNING: gpio cdev ABI v1 is deprecated." 34862306a36Sopenharmony_ci uapi_opt="-u1 " 34962306a36Sopenharmony_ci ;; 35062306a36Sopenharmony_cicdev) 35162306a36Sopenharmony_ci ;; 35262306a36Sopenharmony_ci*) 35362306a36Sopenharmony_ci fail "unknown interface type: $dev_type" 35462306a36Sopenharmony_ci ;; 35562306a36Sopenharmony_ciesac 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ciremove_module || fail "can't remove existing $module module" 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci# manual gpio allocation tests fail if a physical chip already exists 36062306a36Sopenharmony_ci[ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0" 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ciecho "1. Module load tests" 36362306a36Sopenharmony_ciecho "1.1. dynamic allocation of gpio" 36462306a36Sopenharmony_ciinsmod_test "-1,32" 32 36562306a36Sopenharmony_ciinsmod_test "-1,23,-1,32" 23 32 36662306a36Sopenharmony_ciinsmod_test "-1,23,-1,26,-1,32" 23 26 32 36762306a36Sopenharmony_ciif [ "$full_test" ]; then 36862306a36Sopenharmony_ci echo "1.2. manual allocation of gpio" 36962306a36Sopenharmony_ci insmod_test "0,32" 32 37062306a36Sopenharmony_ci insmod_test "0,32,32,60" 32 28 37162306a36Sopenharmony_ci insmod_test "0,32,40,64,64,96" 32 24 32 37262306a36Sopenharmony_ci echo "1.3. dynamic and manual allocation of gpio" 37362306a36Sopenharmony_ci insmod_test "-1,32,32,62" 32 30 37462306a36Sopenharmony_ci insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32 37562306a36Sopenharmony_ci insmod_test "-1,32,32,60,-1,29" 32 28 29 37662306a36Sopenharmony_ci insmod_test "-1,32,40,64,-1,5" 32 24 5 37762306a36Sopenharmony_ci insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31 37862306a36Sopenharmony_cifi 37962306a36Sopenharmony_ciecho "2. Module load error tests" 38062306a36Sopenharmony_ciecho "2.1 gpio overflow" 38162306a36Sopenharmony_ci# Currently: The max number of gpio(1024) is defined in arm architecture. 38262306a36Sopenharmony_ciinsmod_test "-1,1024" 38362306a36Sopenharmony_ciif [ "$full_test" ]; then 38462306a36Sopenharmony_ci echo "2.2 no lines defined" 38562306a36Sopenharmony_ci insmod_test "0,0" 38662306a36Sopenharmony_ci echo "2.3 ignore range overlap" 38762306a36Sopenharmony_ci insmod_test "0,32,0,1" 32 38862306a36Sopenharmony_ci insmod_test "0,32,1,5" 32 38962306a36Sopenharmony_ci insmod_test "0,32,30,35" 32 39062306a36Sopenharmony_ci insmod_test "0,32,31,32" 32 39162306a36Sopenharmony_ci insmod_test "10,32,30,35" 22 39262306a36Sopenharmony_ci insmod_test "10,32,9,14" 22 39362306a36Sopenharmony_ci insmod_test "0,32,20,21,40,56" 32 16 39462306a36Sopenharmony_ci insmod_test "0,32,32,64,32,40" 32 32 39562306a36Sopenharmony_ci insmod_test "0,32,32,64,36,37" 32 32 39662306a36Sopenharmony_ci insmod_test "0,32,35,64,34,36" 32 29 39762306a36Sopenharmony_ci insmod_test "0,30,35,64,35,45" 30 29 39862306a36Sopenharmony_ci insmod_test "0,32,40,56,30,33" 32 16 39962306a36Sopenharmony_ci insmod_test "0,32,40,56,30,41" 32 16 40062306a36Sopenharmony_ci insmod_test "0,32,40,56,39,45" 32 16 40162306a36Sopenharmony_cifi 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ciecho "GPIO $module test PASS" 404