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 9 BASE=${0%/*} 10 DEBUGFS= 11 GPIO_DEBUGFS= 12 dev_type="cdev" 13 module="gpio-mockup" 14 verbose= 15 full_test= 16 random= 17 uapi_opt= 18 active_opt= 19 bias_opt= 20 line_set_pid= 21 22 # Kselftest return codes 23 ksft_fail=1 24 ksft_skip=4 25 26 usage() 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 40 skip() 41 { 42 echo "$*" >&2 43 echo "GPIO $module test SKIP" 44 exit $ksft_skip 45 } 46 47 prerequisite() 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 57 remove_module() 58 { 59 modprobe -r -q $module 60 } 61 62 cleanup() 63 { 64 set +e 65 release_line 66 remove_module 67 jobs -p | xargs -r kill > /dev/null 2>&1 68 } 69 70 fail() 71 { 72 echo "test failed: $*" >&2 73 echo "GPIO $module test FAIL" 74 exit $ksft_fail 75 } 76 77 try_insert_module() 78 { 79 modprobe -q $module "$1" || fail "insert $module failed with error $?" 80 } 81 82 log() 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 94 release_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 101 get_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. 115 set_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 162 assert_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 171 assert_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 187 set_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). 202 test_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 268 test_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. 286 insmod_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 313 while 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 331 done 332 shift $((OPTIND - 1)) 333 334 [ "${1:-}" ] && fail "unknown argument '$1'" 335 336 prerequisite 337 338 trap 'exit $ksft_fail' SIGTERM SIGINT 339 trap cleanup EXIT 340 341 case "$dev_type" in 342 sysfs) 343 source $BASE/gpio-mockup-sysfs.sh 344 echo "WARNING: gpio sysfs ABI is deprecated." 345 ;; 346 cdev_v1) 347 echo "WARNING: gpio cdev ABI v1 is deprecated." 348 uapi_opt="-u1 " 349 ;; 350 cdev) 351 ;; 352 *) 353 fail "unknown interface type: $dev_type" 354 ;; 355 esac 356 357 remove_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 362 echo "1. Module load tests" 363 echo "1.1. dynamic allocation of gpio" 364 insmod_test "-1,32" 32 365 insmod_test "-1,23,-1,32" 23 32 366 insmod_test "-1,23,-1,26,-1,32" 23 26 32 367 if [ "$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 378 fi 379 echo "2. Module load error tests" 380 echo "2.1 no lines defined" 381 insmod_test "0,0" 382 if [ "$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 398 fi 399 400 echo "GPIO $module test PASS"
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.