1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0 3# Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl> 4 5BASE_DIR=`dirname $0` 6CONFIGFS_DIR="/sys/kernel/config/gpio-sim" 7MODULE="gpio-sim" 8 9fail() { 10 echo "$*" >&2 11 echo "GPIO $MODULE test FAIL" 12 exit 1 13} 14 15skip() { 16 echo "$*" >&2 17 echo "GPIO $MODULE test SKIP" 18 exit 4 19} 20 21remove_chip() { 22 local CHIP=$1 23 24 for FILE in $CONFIGFS_DIR/$CHIP/*; do 25 BANK=`basename $FILE` 26 if [ "$BANK" = "live" -o "$BANK" = "dev_name" ]; then 27 continue 28 fi 29 30 LINES=`ls $CONFIGFS_DIR/$CHIP/$BANK/ | grep -E ^line` 31 if [ "$?" = 0 ]; then 32 for LINE in $LINES; do 33 if [ -e $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog ]; then 34 rmdir $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog || \ 35 fail "Unable to remove the hog" 36 fi 37 38 rmdir $CONFIGFS_DIR/$CHIP/$BANK/$LINE || \ 39 fail "Unable to remove the line" 40 done 41 fi 42 43 rmdir $CONFIGFS_DIR/$CHIP/$BANK 44 done 45 46 rmdir $CONFIGFS_DIR/$CHIP || fail "Unable to remove the chip" 47} 48 49create_chip() { 50 local CHIP=$1 51 52 mkdir $CONFIGFS_DIR/$CHIP 53} 54 55create_bank() { 56 local CHIP=$1 57 local BANK=$2 58 59 mkdir $CONFIGFS_DIR/$CHIP/$BANK 60} 61 62set_label() { 63 local CHIP=$1 64 local BANK=$2 65 local LABEL=$3 66 67 echo $LABEL > $CONFIGFS_DIR/$CHIP/$BANK/label || fail "Unable to set the chip label" 68} 69 70set_num_lines() { 71 local CHIP=$1 72 local BANK=$2 73 local NUM_LINES=$3 74 75 echo $NUM_LINES > $CONFIGFS_DIR/$CHIP/$BANK/num_lines || \ 76 fail "Unable to set the number of lines" 77} 78 79set_line_name() { 80 local CHIP=$1 81 local BANK=$2 82 local OFFSET=$3 83 local NAME=$4 84 local LINE_DIR=$CONFIGFS_DIR/$CHIP/$BANK/line$OFFSET 85 86 test -d $LINE_DIR || mkdir $LINE_DIR 87 echo $NAME > $LINE_DIR/name || fail "Unable to set the line name" 88} 89 90enable_chip() { 91 local CHIP=$1 92 93 echo 1 > $CONFIGFS_DIR/$CHIP/live || fail "Unable to enable the chip" 94} 95 96disable_chip() { 97 local CHIP=$1 98 99 echo 0 > $CONFIGFS_DIR/$CHIP/live || fail "Unable to disable the chip" 100} 101 102configfs_cleanup() { 103 for CHIP in `ls $CONFIGFS_DIR/`; do 104 disable_chip $CHIP 105 remove_chip $CHIP 106 done 107} 108 109configfs_chip_name() { 110 local CHIP=$1 111 local BANK=$2 112 113 cat $CONFIGFS_DIR/$CHIP/$BANK/chip_name 2> /dev/null || \ 114 fail "unable to read the chip name from configfs" 115} 116 117configfs_dev_name() { 118 local CHIP=$1 119 120 cat $CONFIGFS_DIR/$CHIP/dev_name 2> /dev/null || \ 121 fail "unable to read the device name from configfs" 122} 123 124get_chip_num_lines() { 125 local CHIP=$1 126 local BANK=$2 127 128 $BASE_DIR/gpio-chip-info /dev/`configfs_chip_name $CHIP $BANK` num-lines || \ 129 fail "unable to read the number of lines from the character device" 130} 131 132get_chip_label() { 133 local CHIP=$1 134 local BANK=$2 135 136 $BASE_DIR/gpio-chip-info /dev/`configfs_chip_name $CHIP $BANK` label || \ 137 fail "unable to read the chip label from the character device" 138} 139 140get_line_name() { 141 local CHIP=$1 142 local BANK=$2 143 local OFFSET=$3 144 145 $BASE_DIR/gpio-line-name /dev/`configfs_chip_name $CHIP $BANK` $OFFSET || \ 146 fail "unable to read the line name from the character device" 147} 148 149sysfs_set_pull() { 150 local DEV=$1 151 local BANK=$2 152 local OFFSET=$3 153 local PULL=$4 154 local DEVNAME=`configfs_dev_name $DEV` 155 local CHIPNAME=`configfs_chip_name $DEV $BANK` 156 local SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio$OFFSET/pull" 157 158 echo $PULL > $SYSFS_PATH || fail "Unable to set line pull in sysfs" 159} 160 161# Load the gpio-sim module. This will pull in configfs if needed too. 162modprobe gpio-sim || skip "unable to load the gpio-sim module" 163# Make sure configfs is mounted at /sys/kernel/config. Wait a bit if needed. 164for IDX in `seq 5`; do 165 if [ "$IDX" -eq "5" ]; then 166 skip "configfs not mounted at /sys/kernel/config" 167 fi 168 169 mountpoint -q /sys/kernel/config && break 170 sleep 0.1 171done 172# If the module was already loaded: remove all previous chips 173configfs_cleanup 174 175trap "exit 1" SIGTERM SIGINT 176trap configfs_cleanup EXIT 177 178echo "1. chip_name and dev_name attributes" 179 180echo "1.1. Chip name is communicated to user" 181create_chip chip 182create_bank chip bank 183enable_chip chip 184test -n `cat $CONFIGFS_DIR/chip/bank/chip_name` || fail "chip_name doesn't work" 185disable_chip chip 186remove_chip chip 187 188echo "1.2. chip_name returns 'none' if the chip is still pending" 189create_chip chip 190create_bank chip bank 191test "`cat $CONFIGFS_DIR/chip/bank/chip_name`" = "none" || \ 192 fail "chip_name doesn't return 'none' for a pending chip" 193remove_chip chip 194 195echo "1.3. Device name is communicated to user" 196create_chip chip 197create_bank chip bank 198enable_chip chip 199test -n `cat $CONFIGFS_DIR/chip/dev_name` || fail "dev_name doesn't work" 200disable_chip chip 201remove_chip chip 202 203echo "2. Creating and configuring simulated chips" 204 205echo "2.1. Default number of lines is 1" 206create_chip chip 207create_bank chip bank 208enable_chip chip 209test "`get_chip_num_lines chip bank`" = "1" || fail "default number of lines is not 1" 210disable_chip chip 211remove_chip chip 212 213echo "2.2. Number of lines can be specified" 214create_chip chip 215create_bank chip bank 216set_num_lines chip bank 16 217enable_chip chip 218test "`get_chip_num_lines chip bank`" = "16" || fail "number of lines is not 16" 219disable_chip chip 220remove_chip chip 221 222echo "2.3. Label can be set" 223create_chip chip 224create_bank chip bank 225set_label chip bank foobar 226enable_chip chip 227test "`get_chip_label chip bank`" = "foobar" || fail "label is incorrect" 228disable_chip chip 229remove_chip chip 230 231echo "2.4. Label can be left empty" 232create_chip chip 233create_bank chip bank 234enable_chip chip 235test -z "`cat $CONFIGFS_DIR/chip/bank/label`" || fail "label is not empty" 236disable_chip chip 237remove_chip chip 238 239echo "2.5. Line names can be configured" 240create_chip chip 241create_bank chip bank 242set_num_lines chip bank 16 243set_line_name chip bank 0 foo 244set_line_name chip bank 2 bar 245enable_chip chip 246test "`get_line_name chip bank 0`" = "foo" || fail "line name is incorrect" 247test "`get_line_name chip bank 2`" = "bar" || fail "line name is incorrect" 248disable_chip chip 249remove_chip chip 250 251echo "2.6. Line config can remain unused if offset is greater than number of lines" 252create_chip chip 253create_bank chip bank 254set_num_lines chip bank 2 255set_line_name chip bank 5 foobar 256enable_chip chip 257test "`get_line_name chip bank 0`" = "" || fail "line name is incorrect" 258test "`get_line_name chip bank 1`" = "" || fail "line name is incorrect" 259disable_chip chip 260remove_chip chip 261 262echo "2.7. Line configfs directory names are sanitized" 263create_chip chip 264create_bank chip bank 265mkdir $CONFIGFS_DIR/chip/bank/line12foobar 2> /dev/null && \ 266 fail "invalid configfs line name accepted" 267mkdir $CONFIGFS_DIR/chip/bank/line_no_offset 2> /dev/null && \ 268 fail "invalid configfs line name accepted" 269remove_chip chip 270 271echo "2.8. Multiple chips can be created" 272CHIPS="chip0 chip1 chip2" 273for CHIP in $CHIPS; do 274 create_chip $CHIP 275 create_bank $CHIP bank 276 enable_chip $CHIP 277done 278for CHIP in $CHIPS; do 279 disable_chip $CHIP 280 remove_chip $CHIP 281done 282 283echo "2.9. Can't modify settings when chip is live" 284create_chip chip 285create_bank chip bank 286enable_chip chip 287echo foobar > $CONFIGFS_DIR/chip/bank/label 2> /dev/null && \ 288 fail "Setting label of a live chip should fail" 289echo 8 > $CONFIGFS_DIR/chip/bank/num_lines 2> /dev/null && \ 290 fail "Setting number of lines of a live chip should fail" 291disable_chip chip 292remove_chip chip 293 294echo "2.10. Can't create line items when chip is live" 295create_chip chip 296create_bank chip bank 297enable_chip chip 298mkdir $CONFIGFS_DIR/chip/bank/line0 2> /dev/null && fail "Creating line item should fail" 299disable_chip chip 300remove_chip chip 301 302echo "2.11. Probe errors are propagated to user-space" 303create_chip chip 304create_bank chip bank 305set_num_lines chip bank 99999 306echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Probe error was not propagated" 307remove_chip chip 308 309echo "2.12. Cannot enable a chip without any GPIO banks" 310create_chip chip 311echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Chip enabled without any GPIO banks" 312remove_chip chip 313 314echo "2.13. Duplicate chip labels are not allowed" 315create_chip chip 316create_bank chip bank0 317set_label chip bank0 foobar 318create_bank chip bank1 319set_label chip bank1 foobar 320echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Duplicate chip labels were not rejected" 321remove_chip chip 322 323echo "2.14. Lines can be hogged" 324create_chip chip 325create_bank chip bank 326set_num_lines chip bank 8 327mkdir -p $CONFIGFS_DIR/chip/bank/line4/hog 328enable_chip chip 329$BASE_DIR/gpio-mockup-cdev -s 1 /dev/`configfs_chip_name chip bank` 4 2> /dev/null && \ 330 fail "Setting the value of a hogged line shouldn't succeed" 331disable_chip chip 332remove_chip chip 333 334echo "3. Controlling simulated chips" 335 336echo "3.1. Pull can be set over sysfs" 337create_chip chip 338create_bank chip bank 339set_num_lines chip bank 8 340enable_chip chip 341sysfs_set_pull chip bank 0 pull-up 342$BASE_DIR/gpio-mockup-cdev /dev/`configfs_chip_name chip bank` 0 343test "$?" = "1" || fail "pull set incorrectly" 344sysfs_set_pull chip bank 0 pull-down 345$BASE_DIR/gpio-mockup-cdev /dev/`configfs_chip_name chip bank` 1 346test "$?" = "0" || fail "pull set incorrectly" 347disable_chip chip 348remove_chip chip 349 350echo "3.2. Pull can be read from sysfs" 351create_chip chip 352create_bank chip bank 353set_num_lines chip bank 8 354enable_chip chip 355DEVNAME=`configfs_dev_name chip` 356CHIPNAME=`configfs_chip_name chip bank` 357SYSFS_PATH=/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/pull 358test `cat $SYSFS_PATH` = "pull-down" || fail "reading the pull failed" 359sysfs_set_pull chip bank 0 pull-up 360test `cat $SYSFS_PATH` = "pull-up" || fail "reading the pull failed" 361disable_chip chip 362remove_chip chip 363 364echo "3.3. Incorrect input in sysfs is rejected" 365create_chip chip 366create_bank chip bank 367set_num_lines chip bank 8 368enable_chip chip 369DEVNAME=`configfs_dev_name chip` 370CHIPNAME=`configfs_chip_name chip bank` 371SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/pull" 372echo foobar > $SYSFS_PATH 2> /dev/null && fail "invalid input not detected" 373disable_chip chip 374remove_chip chip 375 376echo "3.4. Can't write to value" 377create_chip chip 378create_bank chip bank 379enable_chip chip 380DEVNAME=`configfs_dev_name chip` 381CHIPNAME=`configfs_chip_name chip bank` 382SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value" 383echo 1 > $SYSFS_PATH 2> /dev/null && fail "writing to 'value' succeeded unexpectedly" 384disable_chip chip 385remove_chip chip 386 387echo "4. Simulated GPIO chips are functional" 388 389echo "4.1. Values can be read from sysfs" 390create_chip chip 391create_bank chip bank 392set_num_lines chip bank 8 393enable_chip chip 394DEVNAME=`configfs_dev_name chip` 395CHIPNAME=`configfs_chip_name chip bank` 396SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value" 397test `cat $SYSFS_PATH` = "0" || fail "incorrect value read from sysfs" 398$BASE_DIR/gpio-mockup-cdev -s 1 /dev/`configfs_chip_name chip bank` 0 & 399sleep 0.1 # FIXME Any better way? 400test `cat $SYSFS_PATH` = "1" || fail "incorrect value read from sysfs" 401kill $! 402disable_chip chip 403remove_chip chip 404 405echo "4.2. Bias settings work correctly" 406create_chip chip 407create_bank chip bank 408set_num_lines chip bank 8 409enable_chip chip 410DEVNAME=`configfs_dev_name chip` 411CHIPNAME=`configfs_chip_name chip bank` 412SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value" 413$BASE_DIR/gpio-mockup-cdev -b pull-up /dev/`configfs_chip_name chip bank` 0 414test `cat $SYSFS_PATH` = "1" || fail "bias setting does not work" 415disable_chip chip 416remove_chip chip 417 418echo "GPIO $MODULE test PASS" 419