1#!/bin/bash -efu 2# SPDX-License-Identifier: GPL-2.0 3 4#exit status 5#0: success 6#1: fail 7#4: skip test - including run as non-root user 8 9BASE=${0%/*} 10DEBUGFS= 11GPIO_DEBUGFS= 12dev_type="cdev" 13module="gpio-mockup" 14verbose= 15full_test= 16random= 17uapi_opt= 18active_opt= 19bias_opt= 20line_set_pid= 21 22# Kselftest return codes 23ksft_fail=1 24ksft_skip=4 25 26usage() 27{ 28 echo "Usage:" 29 echo "$0 [-frv] [-t type]" 30 echo "-f: full test (minimal set run by default)" 31 echo "-r: test random lines as well as fence posts" 32 echo "-t: interface type:" 33 echo " cdev (character device ABI) - default" 34 echo " cdev_v1 (deprecated character device ABI)" 35 echo " sysfs (deprecated SYSFS ABI)" 36 echo "-v: verbose progress reporting" 37 exit $ksft_fail 38} 39 40skip() 41{ 42 echo "$*" >&2 43 echo "GPIO $module test SKIP" 44 exit $ksft_skip 45} 46 47prerequisite() 48{ 49 [ $(id -u) -eq 0 ] || skip "must be run as root" 50 51 DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ') 52 [ -d "$DEBUGFS" ] || skip "debugfs is not mounted" 53 54 GPIO_DEBUGFS=$DEBUGFS/$module 55} 56 57remove_module() 58{ 59 modprobe -r -q $module 60} 61 62cleanup() 63{ 64 set +e 65 release_line 66 remove_module 67 jobs -p | xargs -r kill > /dev/null 2>&1 68} 69 70fail() 71{ 72 echo "test failed: $*" >&2 73 echo "GPIO $module test FAIL" 74 exit $ksft_fail 75} 76 77try_insert_module() 78{ 79 modprobe -q $module "$1" || fail "insert $module failed with error $?" 80} 81 82log() 83{ 84 [ -z "$verbose" ] || echo "$*" 85} 86 87# The following line helpers, release_Line, get_line and set_line, all 88# make use of the global $chip and $offset variables. 89# 90# This implementation drives the GPIO character device (cdev) uAPI. 91# Other implementations may override these to test different uAPIs. 92 93# Release any resources related to the line 94release_line() 95{ 96 [ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true 97 line_set_pid= 98} 99 100# Read the current value of the line 101get_line() 102{ 103 release_line 104 105 local cdev_opts=${uapi_opt}${active_opt} 106 $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset 107 echo $? 108} 109 110# Set the state of the line 111# 112# Changes to line configuration are provided as parameters. 113# The line is assumed to be an output if the line value 0 or 1 is 114# specified, else an input. 115set_line() 116{ 117 local val= 118 119 release_line 120 121 # parse config options... 122 for option in $*; do 123 case $option in 124 active-low) 125 active_opt="-l " 126 ;; 127 active-high) 128 active_opt= 129 ;; 130 bias-none) 131 bias_opt= 132 ;; 133 pull-down) 134 bias_opt="-bpull-down " 135 ;; 136 pull-up) 137 bias_opt="-bpull-up " 138 ;; 139 0) 140 val=0 141 ;; 142 1) 143 val=1 144 ;; 145 esac 146 done 147 148 local cdev_opts=${uapi_opt}${active_opt} 149 if [ "$val" ]; then 150 $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset & 151 # failure to set is detected by reading mockup and toggling values 152 line_set_pid=$! 153 # allow for gpio-mockup-cdev to launch and request line 154 # (there is limited value in checking if line has been requested) 155 sleep 0.01 156 elif [ "$bias_opt" ]; then 157 cdev_opts=${cdev_opts}${bias_opt} 158 $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true 159 fi 160} 161 162assert_line() 163{ 164 local val 165 # don't need any retry here as set_mock allows for propagation 166 val=$(get_line) 167 [ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected" 168} 169 170# The following mockup helpers all make use of the $mock_line 171assert_mock() 172{ 173 local backoff_wait=10 174 local retry=0 175 local val 176 # retry allows for set propagation from uAPI to mockup 177 while true; do 178 val=$(< $mock_line) 179 [ "$val" = "$1" ] && break 180 retry=$((retry + 1)) 181 [ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected" 182 sleep $(printf "%0.2f" $((backoff_wait))e-3) 183 backoff_wait=$((backoff_wait * 2)) 184 done 185} 186 187set_mock() 188{ 189 echo "$1" > $mock_line 190 # allow for set propagation - so we won't be in a race with set_line 191 assert_mock "$1" 192} 193 194# test the functionality of a line 195# 196# The line is set from the mockup side and is read from the userspace side 197# (input), and is set from the userspace side and is read from the mockup side 198# (output). 199# 200# Setting the mockup pull using the userspace interface bias settings is 201# tested where supported by the userspace interface (cdev). 202test_line() 203{ 204 chip=$1 205 offset=$2 206 log "test_line $chip $offset" 207 mock_line=$GPIO_DEBUGFS/$chip/$offset 208 [ -e "$mock_line" ] || fail "missing line $chip:$offset" 209 210 # test input active-high 211 set_mock 1 212 set_line input active-high 213 assert_line 1 214 set_mock 0 215 assert_line 0 216 set_mock 1 217 assert_line 1 218 219 if [ "$full_test" ]; then 220 if [ "$dev_type" != "sysfs" ]; then 221 # test pulls 222 set_mock 0 223 set_line input pull-up 224 assert_line 1 225 set_mock 0 226 assert_line 0 227 228 set_mock 1 229 set_line input pull-down 230 assert_line 0 231 set_mock 1 232 assert_line 1 233 234 set_line bias-none 235 fi 236 237 # test input active-low 238 set_mock 0 239 set_line active-low 240 assert_line 1 241 set_mock 1 242 assert_line 0 243 set_mock 0 244 assert_line 1 245 246 # test output active-high 247 set_mock 1 248 set_line active-high 0 249 assert_mock 0 250 set_line 1 251 assert_mock 1 252 set_line 0 253 assert_mock 0 254 fi 255 256 # test output active-low 257 set_mock 0 258 set_line active-low 0 259 assert_mock 1 260 set_line 1 261 assert_mock 0 262 set_line 0 263 assert_mock 1 264 265 release_line 266} 267 268test_no_line() 269{ 270 log test_no_line "$*" 271 [ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2" 272} 273 274# Load the module and check that the expected number of gpiochips, with the 275# expected number of lines, are created and are functional. 276# 277# $1 is the gpio_mockup_ranges parameter for the module 278# The remaining parameters are the number of lines, n, expected for each of 279# the gpiochips expected to be created. 280# 281# For each gpiochip the fence post lines, 0 and n-1, are tested, and the 282# line on the far side of the fence post, n, is tested to not exist. 283# 284# If the $random flag is set then a random line in the middle of the 285# gpiochip is tested as well. 286insmod_test() 287{ 288 local ranges= 289 local gc= 290 local width= 291 292 [ "${1:-}" ] || fail "missing ranges" 293 ranges=$1 ; shift 294 try_insert_module "gpio_mockup_ranges=$ranges" 295 log "GPIO $module test with ranges: <$ranges>:" 296 # e.g. /sys/kernel/debug/gpio-mockup/gpiochip1 297 gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort) 298 for chip in $gpiochip; do 299 gc=${chip##*/} 300 [ "${1:-}" ] || fail "unexpected chip - $gc" 301 width=$1 ; shift 302 test_line $gc 0 303 if [ "$random" -a $width -gt 2 ]; then 304 test_line $gc $((RANDOM % ($width - 2) + 1)) 305 fi 306 test_line $gc $(($width - 1)) 307 test_no_line $gc $width 308 done 309 [ "${1:-}" ] && fail "missing expected chip of width $1" 310 remove_module || fail "failed to remove module with error $?" 311} 312 313while getopts ":frvt:" opt; do 314 case $opt in 315 f) 316 full_test=true 317 ;; 318 r) 319 random=true 320 ;; 321 t) 322 dev_type=$OPTARG 323 ;; 324 v) 325 verbose=true 326 ;; 327 *) 328 usage 329 ;; 330 esac 331done 332shift $((OPTIND - 1)) 333 334[ "${1:-}" ] && fail "unknown argument '$1'" 335 336prerequisite 337 338trap 'exit $ksft_fail' SIGTERM SIGINT 339trap cleanup EXIT 340 341case "$dev_type" in 342sysfs) 343 source $BASE/gpio-mockup-sysfs.sh 344 echo "WARNING: gpio sysfs ABI is deprecated." 345 ;; 346cdev_v1) 347 echo "WARNING: gpio cdev ABI v1 is deprecated." 348 uapi_opt="-u1 " 349 ;; 350cdev) 351 ;; 352*) 353 fail "unknown interface type: $dev_type" 354 ;; 355esac 356 357remove_module || fail "can't remove existing $module module" 358 359# manual gpio allocation tests fail if a physical chip already exists 360[ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0" 361 362echo "1. Module load tests" 363echo "1.1. dynamic allocation of gpio" 364insmod_test "-1,32" 32 365insmod_test "-1,23,-1,32" 23 32 366insmod_test "-1,23,-1,26,-1,32" 23 26 32 367if [ "$full_test" ]; then 368 echo "1.2. manual allocation of gpio" 369 insmod_test "0,32" 32 370 insmod_test "0,32,32,60" 32 28 371 insmod_test "0,32,40,64,64,96" 32 24 32 372 echo "1.3. dynamic and manual allocation of gpio" 373 insmod_test "-1,32,32,62" 32 30 374 insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32 375 insmod_test "-1,32,32,60,-1,29" 32 28 29 376 insmod_test "-1,32,40,64,-1,5" 32 24 5 377 insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31 378fi 379echo "2. Module load error tests" 380echo "2.1 no lines defined" 381insmod_test "0,0" 382if [ "$full_test" ]; then 383 echo "2.2 ignore range overlap" 384 insmod_test "0,32,0,1" 32 385 insmod_test "0,32,1,5" 32 386 insmod_test "0,32,30,35" 32 387 insmod_test "0,32,31,32" 32 388 insmod_test "10,32,30,35" 22 389 insmod_test "10,32,9,14" 22 390 insmod_test "0,32,20,21,40,56" 32 16 391 insmod_test "0,32,32,64,32,40" 32 32 392 insmod_test "0,32,32,64,36,37" 32 32 393 insmod_test "0,32,35,64,34,36" 32 29 394 insmod_test "0,30,35,64,35,45" 30 29 395 insmod_test "0,32,40,56,30,33" 32 16 396 insmod_test "0,32,40,56,30,41" 32 16 397 insmod_test "0,32,40,56,39,45" 32 16 398fi 399 400echo "GPIO $module test PASS" 401