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