1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0 3# Copyright (C) 2025 Bartosz Golaszewski <brgl@bgdev.pl> 4# Copyright (C) 2025 Koichiro Den <koichiro.den@canonical.com> 5 6BASE_DIR=$(dirname "$0") 7CONFIGFS_SIM_DIR="/sys/kernel/config/gpio-sim" 8CONFIGFS_AGG_DIR="/sys/kernel/config/gpio-aggregator" 9SYSFS_AGG_DIR="/sys/bus/platform/drivers/gpio-aggregator" 10MODULE="gpio-aggregator" 11 12fail() { 13 echo "$*" >&2 14 echo "GPIO $MODULE test FAIL" 15 exit 1 16} 17 18skip() { 19 echo "$*" >&2 20 echo "GPIO $MODULE test SKIP" 21 exit 4 22} 23 24# gpio-sim 25sim_enable_chip() { 26 local CHIP=$1 27 28 echo 1 > "$CONFIGFS_SIM_DIR/$CHIP/live" || fail "Unable to enable the chip" 29} 30 31sim_disable_chip() { 32 local CHIP=$1 33 34 echo 0 > "$CONFIGFS_SIM_DIR/$CHIP/live" || fail "Unable to disable the chip" 35} 36 37sim_configfs_cleanup() { 38 local NOCHECK=${1:-0} 39 40 for CHIP_DIR in "$CONFIGFS_SIM_DIR"/*; do 41 [ -d "$CHIP_DIR" ] || continue 42 echo 0 > "$CHIP_DIR/live" 43 find "$CHIP_DIR" -depth -type d -exec rmdir {} \; 44 done 45 [ "$NOCHECK" -eq 1 ] && return; 46 remaining=$(find "$CONFIGFS_SIM_DIR" -mindepth 1 -type d 2> /dev/null) 47 if [ -n "$remaining" ]; then 48 fail "Directories remain in $CONFIGFS_SIM_DIR: $remaining" 49 fi 50} 51 52sim_get_chip_label() { 53 local CHIP=$1 54 local BANK=$2 55 local CHIP_NAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/$BANK/chip_name" 2> /dev/null) || \ 56 fail "Unable to read the chip name from configfs" 57 58 $BASE_DIR/gpio-chip-info "/dev/$CHIP_NAME" label || \ 59 fail "Unable to read the chip label from the character device" 60} 61 62# gpio-aggregator 63agg_create_chip() { 64 local CHIP=$1 65 66 mkdir "$CONFIGFS_AGG_DIR/$CHIP" 67} 68 69agg_remove_chip() { 70 local CHIP=$1 71 72 find "$CONFIGFS_AGG_DIR/$CHIP/" -depth -type d -exec rmdir {} \; || \ 73 fail "Unable to remove $CONFIGFS_AGG_DIR/$CHIP" 74} 75 76agg_create_line() { 77 local CHIP=$1 78 local LINE=$2 79 80 mkdir "$CONFIGFS_AGG_DIR/$CHIP/$LINE" 81} 82 83agg_remove_line() { 84 local CHIP=$1 85 local LINE=$2 86 87 rmdir "$CONFIGFS_AGG_DIR/$CHIP/$LINE" 88} 89 90agg_set_key() { 91 local CHIP=$1 92 local LINE=$2 93 local KEY=$3 94 95 echo "$KEY" > "$CONFIGFS_AGG_DIR/$CHIP/$LINE/key" || fail "Unable to set the lookup key" 96} 97 98agg_set_offset() { 99 local CHIP=$1 100 local LINE=$2 101 local OFFSET=$3 102 103 echo "$OFFSET" > "$CONFIGFS_AGG_DIR/$CHIP/$LINE/offset" || \ 104 fail "Unable to set the lookup offset" 105} 106 107agg_set_line_name() { 108 local CHIP=$1 109 local LINE=$2 110 local NAME=$3 111 112 echo "$NAME" > "$CONFIGFS_AGG_DIR/$CHIP/$LINE/name" || fail "Unable to set the line name" 113} 114 115agg_enable_chip() { 116 local CHIP=$1 117 118 echo 1 > "$CONFIGFS_AGG_DIR/$CHIP/live" || fail "Unable to enable the chip" 119} 120 121agg_disable_chip() { 122 local CHIP=$1 123 124 echo 0 > "$CONFIGFS_AGG_DIR/$CHIP/live" || fail "Unable to disable the chip" 125} 126 127agg_configfs_cleanup() { 128 local NOCHECK=${1:-0} 129 130 for CHIP_DIR in "$CONFIGFS_AGG_DIR"/*; do 131 [ -d "$CHIP_DIR" ] || continue 132 echo 0 > "$CHIP_DIR/live" 2> /dev/null 133 find "$CHIP_DIR" -depth -type d -exec rmdir {} \; 134 done 135 [ "$NOCHECK" -eq 1 ] && return; 136 remaining=$(find "$CONFIGFS_AGG_DIR" -mindepth 1 -type d 2> /dev/null) 137 if [ -n "$remaining" ]; then 138 fail "Directories remain in $CONFIGFS_AGG_DIR: $remaining" 139 fi 140} 141 142agg_configfs_dev_name() { 143 local CHIP=$1 144 145 cat "$CONFIGFS_AGG_DIR/$CHIP/dev_name" 2> /dev/null || \ 146 fail "Unable to read the device name from configfs" 147} 148 149agg_configfs_chip_name() { 150 local CHIP=$1 151 local DEV_NAME=$(agg_configfs_dev_name "$CHIP") 152 local CHIP_LIST=$(find "/sys/devices/platform/$DEV_NAME" \ 153 -maxdepth 1 -type d -name "gpiochip[0-9]*" 2> /dev/null) 154 local CHIP_COUNT=$(echo "$CHIP_LIST" | wc -l) 155 156 if [ -z "$CHIP_LIST" ]; then 157 fail "No gpiochip in /sys/devices/platform/$DEV_NAME/" 158 elif [ "$CHIP_COUNT" -ne 1 ]; then 159 fail "Multiple gpiochips unexpectedly found: $CHIP_LIST" 160 fi 161 basename "$CHIP_LIST" 162} 163 164agg_get_chip_num_lines() { 165 local CHIP=$1 166 local N_DIR=$(ls -d $CONFIGFS_AGG_DIR/$CHIP/line[0-9]* 2> /dev/null | wc -l) 167 local N_LINES 168 169 if [ "$(cat $CONFIGFS_AGG_DIR/$CHIP/live)" = 0 ]; then 170 echo "$N_DIR" 171 else 172 N_LINES=$( 173 $BASE_DIR/gpio-chip-info \ 174 "/dev/$(agg_configfs_chip_name "$CHIP")" num-lines 175 ) || fail "Unable to read the number of lines from the character device" 176 if [ $N_DIR != $N_LINES ]; then 177 fail "Discrepancy between two sources for the number of lines" 178 fi 179 echo "$N_LINES" 180 fi 181} 182 183agg_get_chip_label() { 184 local CHIP=$1 185 186 $BASE_DIR/gpio-chip-info "/dev/$(agg_configfs_chip_name "$CHIP")" label || \ 187 fail "Unable to read the chip label from the character device" 188} 189 190agg_get_line_name() { 191 local CHIP=$1 192 local OFFSET=$2 193 local NAME_CONFIGFS=$(cat "$CONFIGFS_AGG_DIR/$CHIP/line${OFFSET}/name") 194 local NAME_CDEV 195 196 if [ "$(cat "$CONFIGFS_AGG_DIR/$CHIP/live")" = 0 ]; then 197 echo "$NAME_CONFIGFS" 198 else 199 NAME_CDEV=$( 200 $BASE_DIR/gpio-line-name \ 201 "/dev/$(agg_configfs_chip_name "$CHIP")" "$OFFSET" 202 ) || fail "Unable to read the line name from the character device" 203 if [ "$NAME_CONFIGFS" != "$NAME_CDEV" ]; then 204 fail "Discrepancy between two sources for the name of line" 205 fi 206 echo "$NAME_CDEV" 207 fi 208} 209 210 211# Load the modules. This will pull in configfs if needed too. 212modprobe gpio-sim || skip "unable to load the gpio-sim module" 213modprobe gpio-aggregator || skip "unable to load the gpio-aggregator module" 214 215# Make sure configfs is mounted at /sys/kernel/config. Wait a bit if needed. 216for IDX in $(seq 5); do 217 if [ "$IDX" -eq "5" ]; then 218 skip "configfs not mounted at /sys/kernel/config" 219 fi 220 221 mountpoint -q /sys/kernel/config && break 222 sleep 0.1 223done 224 225# If the module was already loaded: remove all previous chips 226agg_configfs_cleanup 227sim_configfs_cleanup 228 229trap "exit 1" SIGTERM SIGINT 230trap "agg_configfs_cleanup 1; sim_configfs_cleanup 1" EXIT 231 232# Use gpio-sim chips as the test backend 233for CHIP in $(seq -f "chip%g" 0 1); do 234 mkdir $CONFIGFS_SIM_DIR/$CHIP 235 for BANK in $(seq -f "bank%g" 0 1); do 236 mkdir -p "$CONFIGFS_SIM_DIR/$CHIP/$BANK" 237 echo "${CHIP}_${BANK}" > "$CONFIGFS_SIM_DIR/$CHIP/$BANK/label" || \ 238 fail "unable to set the chip label" 239 echo 16 > "$CONFIGFS_SIM_DIR/$CHIP/$BANK/num_lines" || \ 240 fail "unable to set the number of lines" 241 for IDX in $(seq 0 15); do 242 LINE_NAME="${CHIP}${BANK}_${IDX}" 243 LINE_DIR="$CONFIGFS_SIM_DIR/$CHIP/$BANK/line$IDX" 244 mkdir -p $LINE_DIR 245 echo "$LINE_NAME" > "$LINE_DIR/name" || fail "unable to set the line name" 246 done 247 done 248 sim_enable_chip "$CHIP" 249done 250 251echo "1. GPIO aggregator creation/deletion" 252 253echo "1.1. Creation/deletion via configfs" 254 255echo "1.1.1. Minimum creation/deletion" 256agg_create_chip agg0 257agg_create_line agg0 line0 258agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank0)" 259agg_set_offset agg0 line0 5 260agg_set_line_name agg0 line0 test0 261agg_enable_chip agg0 262test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 1 || fail "chip unexpectedly dead" 263test "$(agg_get_chip_label agg0)" = "$(agg_configfs_dev_name agg0)" || \ 264 fail "label is inconsistent" 265test "$(agg_get_chip_num_lines agg0)" = "1" || fail "number of lines is not 1" 266test "$(agg_get_line_name agg0 0)" = "test0" || fail "line name is unset" 267agg_disable_chip agg0 268agg_remove_line agg0 line0 269agg_remove_chip agg0 270 271echo "1.1.2. Complex creation/deletion" 272agg_create_chip agg0 273agg_create_line agg0 line0 274agg_create_line agg0 line1 275agg_create_line agg0 line2 276agg_create_line agg0 line3 277agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank0)" 278agg_set_key agg0 line1 "$(sim_get_chip_label chip0 bank1)" 279agg_set_key agg0 line2 "$(sim_get_chip_label chip1 bank0)" 280agg_set_key agg0 line3 "$(sim_get_chip_label chip1 bank1)" 281agg_set_offset agg0 line0 1 282agg_set_offset agg0 line1 3 283agg_set_offset agg0 line2 5 284agg_set_offset agg0 line3 7 285agg_set_line_name agg0 line0 test0 286agg_set_line_name agg0 line1 test1 287agg_set_line_name agg0 line2 test2 288agg_set_line_name agg0 line3 test3 289agg_enable_chip agg0 290test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 1 || fail "chip unexpectedly dead" 291test "$(agg_get_chip_label agg0)" = "$(agg_configfs_dev_name agg0)" || \ 292 fail "label is inconsistent" 293test "$(agg_get_chip_num_lines agg0)" = "4" || fail "number of lines is not 1" 294test "$(agg_get_line_name agg0 0)" = "test0" || fail "line name is unset" 295test "$(agg_get_line_name agg0 1)" = "test1" || fail "line name is unset" 296test "$(agg_get_line_name agg0 2)" = "test2" || fail "line name is unset" 297test "$(agg_get_line_name agg0 3)" = "test3" || fail "line name is unset" 298agg_disable_chip agg0 299agg_remove_line agg0 line0 300agg_remove_line agg0 line1 301agg_remove_line agg0 line2 302agg_remove_line agg0 line3 303agg_remove_chip agg0 304 305echo "1.1.3. Can't instantiate a chip without any line" 306agg_create_chip agg0 307echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" 308test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || fail "chip unexpectedly alive" 309agg_remove_chip agg0 310 311echo "1.1.4. Can't instantiate a chip with invalid configuration" 312agg_create_chip agg0 313agg_create_line agg0 line0 314agg_set_key agg0 line0 "chipX_bankX" 315agg_set_offset agg0 line0 99 316agg_set_line_name agg0 line0 test0 317echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" 318test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || fail "chip unexpectedly alive" 319agg_remove_line agg0 line0 320agg_remove_chip agg0 321 322echo "1.1.5. Can't instantiate a chip asynchronously via deferred probe" 323agg_create_chip agg0 324agg_create_line agg0 line0 325agg_set_key agg0 line0 "chip0_bank0" 326agg_set_offset agg0 line0 5 327agg_set_line_name agg0 line0 test0 328sim_disable_chip chip0 329echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" 330test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || fail "chip unexpectedly alive" 331sim_enable_chip chip0 332sleep 1 333test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || \ 334 fail "chip unexpectedly transitioned to 'live' state" 335agg_remove_line agg0 line0 336agg_remove_chip agg0 337 338echo "1.1.6. Can't instantiate a chip with _sysfs prefix" 339mkdir "$CONFIGFS_AGG_DIR/_sysfs" 2> /dev/null && fail "chip _sysfs unexpectedly created" 340mkdir "$CONFIGFS_AGG_DIR/_sysfs.foo" 2> /dev/null && fail "chip _sysfs.foo unexpectedly created" 341 342echo "1.2. Creation/deletion via sysfs" 343 344echo "1.2.1. Minimum creation/deletion" 345echo "chip0_bank0 0" > "$SYSFS_AGG_DIR/new_device" 346CHIPNAME=$(agg_configfs_chip_name _sysfs.0) 347test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 1 || fail "chip unexpectedly dead" 348test "$(agg_get_chip_label _sysfs.0)" = "$(agg_configfs_dev_name _sysfs.0)" || \ 349 fail "label is inconsistent" 350test "$(agg_get_chip_num_lines _sysfs.0)" = "1" || fail "number of lines is not 1" 351test "$(agg_get_line_name _sysfs.0 0)" = "" || fail "line name is unset" 352echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" 353test -d $CONFIGFS_AGG_DIR/_sysfs.0 && fail "_sysfs.0 unexpectedly remains" 354test -d /dev/${CHIPNAME} && fail "/dev/${CHIPNAME} unexpectedly remains" 355 356echo "1.2.2. Complex creation/deletion" 357echo "chip0bank0_0 chip1_bank1 10-11" > "$SYSFS_AGG_DIR/new_device" 358CHIPNAME=$(agg_configfs_chip_name _sysfs.0) 359test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 1 || fail "chip unexpectedly dead" 360test "$(agg_get_chip_label _sysfs.0)" = "$(agg_configfs_dev_name _sysfs.0)" || \ 361 fail "label is inconsistent" 362test "$(agg_get_chip_num_lines _sysfs.0)" = "3" || fail "number of lines is not 3" 363test "$(agg_get_line_name _sysfs.0 0)" = "" || fail "line name is unset" 364test "$(agg_get_line_name _sysfs.0 1)" = "" || fail "line name is unset" 365test "$(agg_get_line_name _sysfs.0 2)" = "" || fail "line name is unset" 366echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" 367test -d $CONFIGFS_AGG_DIR/_sysfs.0 && fail "_sysfs.0 unexpectedly remains" 368test -d /dev/${CHIPNAME} && fail "/dev/${CHIPNAME} unexpectedly remains" 369 370echo "1.2.3. Asynchronous creation with deferred probe" 371sim_disable_chip chip0 372echo 'chip0_bank0 0' > $SYSFS_AGG_DIR/new_device 373sleep 1 374test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 0 || fail "chip unexpectedly alive" 375sim_enable_chip chip0 376sleep 1 377CHIPNAME=$(agg_configfs_chip_name _sysfs.0) 378test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 1 || fail "chip unexpectedly remains dead" 379test "$(agg_get_chip_label _sysfs.0)" = "$(agg_configfs_dev_name _sysfs.0)" || \ 380 fail "label is inconsistent" 381test "$(agg_get_chip_num_lines _sysfs.0)" = "1" || fail "number of lines is not 1" 382test "$(agg_get_line_name _sysfs.0 0)" = "" || fail "line name unexpectedly set" 383echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" 384test -d $CONFIGFS_AGG_DIR/_sysfs.0 && fail "_sysfs.0 unexpectedly remains" 385test -d /dev/${CHIPNAME} && fail "/dev/${CHIPNAME} unexpectedly remains" 386 387echo "1.2.4. Can't instantiate a chip with invalid configuration" 388echo "xyz 0" > "$SYSFS_AGG_DIR/new_device" 389test "$(cat $CONFIGFS_AGG_DIR/_sysfs.0/live)" = 0 || fail "chip unexpectedly alive" 390echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" 391 392echo "2. GPIO aggregator configuration" 393 394echo "2.1. Configuring aggregators instantiated via configfs" 395setup_2_1() { 396 agg_create_chip agg0 397 agg_create_line agg0 line0 398 agg_create_line agg0 line1 399 agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank0)" 400 agg_set_key agg0 line1 "$(sim_get_chip_label chip1 bank0)" 401 agg_set_offset agg0 line0 1 402 agg_set_offset agg0 line1 3 403 agg_set_line_name agg0 line0 test0 404 agg_set_line_name agg0 line1 test1 405 agg_enable_chip agg0 406} 407teardown_2_1() { 408 agg_configfs_cleanup 409} 410 411echo "2.1.1. While offline" 412 413echo "2.1.1.1. Line can be added/removed" 414setup_2_1 415agg_disable_chip agg0 416agg_create_line agg0 line2 417agg_set_key agg0 line2 "$(sim_get_chip_label chip0 bank1)" 418agg_set_offset agg0 line2 5 419agg_enable_chip agg0 420test "$(agg_get_chip_num_lines agg0)" = "3" || fail "number of lines is not 1" 421teardown_2_1 422 423echo "2.1.1.2. Line key can be modified" 424setup_2_1 425agg_disable_chip agg0 426agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank1)" 427agg_set_key agg0 line1 "$(sim_get_chip_label chip1 bank1)" 428agg_enable_chip agg0 429teardown_2_1 430 431echo "2.1.1.3. Line name can be modified" 432setup_2_1 433agg_disable_chip agg0 434agg_set_line_name agg0 line0 new0 435agg_set_line_name agg0 line1 new1 436agg_enable_chip agg0 437test "$(agg_get_line_name agg0 0)" = "new0" || fail "line name is unset" 438test "$(agg_get_line_name agg0 1)" = "new1" || fail "line name is unset" 439teardown_2_1 440 441echo "2.1.1.4. Line offset can be modified" 442setup_2_1 443agg_disable_chip agg0 444agg_set_offset agg0 line0 5 445agg_set_offset agg0 line1 7 446agg_enable_chip agg0 447teardown_2_1 448 449echo "2.1.1.5. Can re-enable a chip after valid reconfiguration" 450setup_2_1 451agg_disable_chip agg0 452agg_set_key agg0 line0 "$(sim_get_chip_label chip1 bank1)" 453agg_set_offset agg0 line0 15 454agg_set_key agg0 line1 "$(sim_get_chip_label chip0 bank1)" 455agg_set_offset agg0 line0 14 456agg_create_line agg0 line2 457agg_set_key agg0 line2 "$(sim_get_chip_label chip0 bank1)" 458agg_set_offset agg0 line2 13 459agg_enable_chip agg0 460test "$(agg_get_chip_num_lines agg0)" = "3" || fail "number of lines is not 1" 461teardown_2_1 462 463echo "2.1.1.7. Can't re-enable a chip with invalid reconfiguration" 464setup_2_1 465agg_disable_chip agg0 466agg_set_key agg0 line0 invalidkey 467echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" 468teardown_2_1 469setup_2_1 470agg_disable_chip agg0 471agg_set_offset agg0 line0 99 472echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" 473teardown_2_1 474 475echo "2.1.2. While online" 476 477echo "2.1.2.1. Can't add/remove line" 478setup_2_1 479mkdir "$CONFIGFS_AGG_DIR/agg0/line2" 2> /dev/null && fail "line unexpectedly added" 480rmdir "$CONFIGFS_AGG_DIR/agg0/line1" 2> /dev/null && fail "line unexpectedly removed" 481teardown_2_1 482 483echo "2.1.2.2. Can't modify line key" 484setup_2_1 485echo "chip1_bank1" > "$CONFIGFS_AGG_DIR/agg0/line0/key" 2> /dev/null && \ 486 fail "lookup key unexpectedly updated" 487teardown_2_1 488 489echo "2.1.2.3. Can't modify line name" 490setup_2_1 491echo "new0" > "$CONFIGFS_AGG_DIR/agg0/line0/name" 2> /dev/null && \ 492 fail "name unexpectedly updated" 493teardown_2_1 494 495echo "2.1.2.4. Can't modify line offset" 496setup_2_1 497echo "5" > "$CONFIGFS_AGG_DIR/agg0/line0/offset" 2> /dev/null && \ 498 fail "offset unexpectedly updated" 499teardown_2_1 500 501echo "2.2. Configuring aggregators instantiated via sysfs" 502setup_2_2() { 503 echo "chip0_bank0 1 chip1_bank0 3" > "$SYSFS_AGG_DIR/new_device" 504} 505teardown_2_2() { 506 echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" 507} 508 509echo "2.2.1. While online" 510 511echo "2.2.1.1. Can toggle live" 512setup_2_2 513agg_disable_chip _sysfs.0 514agg_enable_chip _sysfs.0 515teardown_2_2 516 517echo "2.2.1.2. Can't add/remove line" 518setup_2_2 519mkdir "$CONFIGFS_AGG_DIR/_sysfs.0/line2" 2> /dev/null && fail "line unexpectedly added" 520rmdir "$CONFIGFS_AGG_DIR/_sysfs.0/line1" 2> /dev/null && fail "line unexpectedly removed" 521teardown_2_2 522 523echo "2.2.1.3. Can't modify line key" 524setup_2_2 525echo "chip1_bank1" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/key" 2> /dev/null && \ 526 fail "lookup key unexpectedly updated" 527teardown_2_2 528 529echo "2.2.1.4. Can't modify line name" 530setup_2_2 531echo "new0" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/name" 2> /dev/null && \ 532 fail "name unexpectedly updated" 533teardown_2_2 534 535echo "2.2.1.5. Can't modify line offset" 536setup_2_2 537echo "5" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/offset" 2> /dev/null && \ 538 fail "offset unexpectedly updated" 539teardown_2_2 540 541echo "2.2.2. While waiting for deferred probe" 542 543echo "2.2.2.1. Can't add/remove line despite live = 0" 544sim_disable_chip chip0 545setup_2_2 546mkdir "$CONFIGFS_AGG_DIR/_sysfs.0/line2" 2> /dev/null && fail "line unexpectedly added" 547rmdir "$CONFIGFS_AGG_DIR/_sysfs.0/line1" 2> /dev/null && fail "line unexpectedly removed" 548teardown_2_2 549sim_enable_chip chip0 550 551echo "2.2.2.2. Can't modify line key" 552sim_disable_chip chip0 553setup_2_2 554echo "chip1_bank1" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/key" 2> /dev/null && \ 555 fail "lookup key unexpectedly updated" 556teardown_2_2 557sim_enable_chip chip0 558 559echo "2.2.2.3. Can't modify line name" 560sim_disable_chip chip0 561setup_2_2 562echo "new0" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/name" 2> /dev/null && \ 563 fail "name unexpectedly updated" 564teardown_2_2 565sim_enable_chip chip0 566 567echo "2.2.2.4. Can't modify line offset" 568sim_disable_chip chip0 569setup_2_2 570echo 5 > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/offset" 2> /dev/null && \ 571 fail "offset unexpectedly updated" 572teardown_2_2 573sim_enable_chip chip0 574 575echo "2.2.2.5. Can't toggle live" 576sim_disable_chip chip0 577setup_2_2 578test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 0 || fail "chip unexpectedly alive" 579echo 1 > "$CONFIGFS_AGG_DIR/_sysfs.0/live" 2> /dev/null && fail "chip unexpectedly enabled" 580teardown_2_2 581sim_enable_chip chip0 582 583echo "2.2.3. While offline" 584 585echo "2.2.3.1. Can't add/remove line despite live = 0" 586setup_2_2 587agg_disable_chip _sysfs.0 588mkdir "$CONFIGFS_AGG_DIR/_sysfs.0/line2" 2> /dev/null && fail "line unexpectedly added" 589rmdir "$CONFIGFS_AGG_DIR/_sysfs.0/line1" 2> /dev/null && fail "line unexpectedly removed" 590teardown_2_2 591 592echo "2.2.3.2. Line key can be modified" 593setup_2_2 594agg_disable_chip _sysfs.0 595agg_set_key _sysfs.0 line0 "$(sim_get_chip_label chip0 bank1)" 596agg_set_key _sysfs.0 line1 "$(sim_get_chip_label chip1 bank1)" 597agg_enable_chip _sysfs.0 598teardown_2_2 599 600echo "2.2.3.3. Line name can be modified" 601setup_2_2 602agg_disable_chip _sysfs.0 603agg_set_line_name _sysfs.0 line0 new0 604agg_set_line_name _sysfs.0 line1 new1 605agg_enable_chip _sysfs.0 606test "$(agg_get_line_name _sysfs.0 0)" = "new0" || fail "line name is unset" 607test "$(agg_get_line_name _sysfs.0 1)" = "new1" || fail "line name is unset" 608teardown_2_2 609 610echo "2.2.3.4. Line offset can be modified" 611setup_2_2 612agg_disable_chip _sysfs.0 613agg_set_offset _sysfs.0 line0 5 614agg_set_offset _sysfs.0 line1 7 615agg_enable_chip _sysfs.0 616teardown_2_2 617 618echo "2.2.3.5. Can re-enable a chip with valid reconfiguration" 619setup_2_2 620agg_disable_chip _sysfs.0 621agg_set_key _sysfs.0 line0 "$(sim_get_chip_label chip1 bank1)" 622agg_set_offset _sysfs.0 line0 15 623agg_set_key _sysfs.0 line1 "$(sim_get_chip_label chip0 bank1)" 624agg_set_offset _sysfs.0 line0 14 625agg_enable_chip _sysfs.0 626teardown_2_2 627 628echo "2.2.3.6. Can't re-enable a chip with invalid reconfiguration" 629setup_2_2 630agg_disable_chip _sysfs.0 631agg_set_key _sysfs.0 line0 invalidkey 632echo 1 > "$CONFIGFS_AGG_DIR/_sysfs.0/live" 2> /dev/null && fail "chip unexpectedly enabled" 633teardown_2_2 634setup_2_2 635agg_disable_chip _sysfs.0 636agg_set_offset _sysfs.0 line0 99 637echo 1 > "$CONFIGFS_AGG_DIR/_sysfs.0/live" 2> /dev/null && fail "chip unexpectedly enabled" 638teardown_2_2 639 640echo "3. Module unload" 641 642echo "3.1. Can't unload module if there is at least one device created via configfs" 643agg_create_chip agg0 644modprobe -r gpio-aggregator 2> /dev/null 645test -d /sys/module/gpio_aggregator || fail "module unexpectedly unloaded" 646agg_remove_chip agg0 647 648echo "3.2. Can unload module if there is no device created via configfs" 649echo "chip0_bank0 1 chip1_bank0 3" > "$SYSFS_AGG_DIR/new_device" 650modprobe -r gpio-aggregator 2> /dev/null 651test -d /sys/module/gpio_aggregator && fail "module unexpectedly remains to be loaded" 652modprobe gpio-aggregator 2> /dev/null 653 654echo "4. GPIO forwarder functional" 655SETTINGS="chip0:bank0:2 chip0:bank1:4 chip1:bank0:6 chip1:bank1:8" 656setup_4() { 657 local OFFSET=0 658 agg_create_chip agg0 659 for SETTING in $SETTINGS; do 660 CHIP=$(echo "$SETTING" | cut -d: -f1) 661 BANK=$(echo "$SETTING" | cut -d: -f2) 662 LINE=$(echo "$SETTING" | cut -d: -f3) 663 agg_create_line agg0 "line${OFFSET}" 664 agg_set_key agg0 "line${OFFSET}" "$(sim_get_chip_label "$CHIP" "$BANK")" 665 agg_set_offset agg0 "line${OFFSET}" "$LINE" 666 OFFSET=$(expr $OFFSET + 1) 667 done 668 agg_enable_chip agg0 669} 670teardown_4() { 671 agg_configfs_cleanup 672} 673 674echo "4.1. Forwarding set values" 675setup_4 676OFFSET=0 677for SETTING in $SETTINGS; do 678 CHIP=$(echo "$SETTING" | cut -d: -f1) 679 BANK=$(echo "$SETTING" | cut -d: -f2) 680 LINE=$(echo "$SETTING" | cut -d: -f3) 681 DEVNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/dev_name") 682 CHIPNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/$BANK/chip_name") 683 VAL_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio${LINE}/value" 684 test $(cat $VAL_PATH) = "0" || fail "incorrect value read from sysfs" 685 $BASE_DIR/gpio-mockup-cdev -s 1 "/dev/$(agg_configfs_chip_name agg0)" "$OFFSET" & 686 mock_pid=$! 687 sleep 0.1 # FIXME Any better way? 688 test "$(cat $VAL_PATH)" = "1" || fail "incorrect value read from sysfs" 689 kill "$mock_pid" 690 OFFSET=$(expr $OFFSET + 1) 691done 692teardown_4 693 694echo "4.2. Forwarding set config" 695setup_4 696OFFSET=0 697for SETTING in $SETTINGS; do 698 CHIP=$(echo "$SETTING" | cut -d: -f1) 699 BANK=$(echo "$SETTING" | cut -d: -f2) 700 LINE=$(echo "$SETTING" | cut -d: -f3) 701 DEVNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/dev_name") 702 CHIPNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/$BANK/chip_name") 703 VAL_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio${LINE}/value" 704 $BASE_DIR/gpio-mockup-cdev -b pull-up "/dev/$(agg_configfs_chip_name agg0)" "$OFFSET" 705 test $(cat "$VAL_PATH") = "1" || fail "incorrect value read from sysfs" 706 OFFSET=$(expr $OFFSET + 1) 707done 708teardown_4 709 710echo "5. Race condition verification" 711 712echo "5.1. Stress test of new_device/delete_device and module load/unload" 713for _ in $(seq 1000); do 714 { 715 echo "dummy 0" > "$SYSFS_AGG_DIR/new_device" 716 cat "$CONFIGFS_AGG_DIR/_sysfs.0/dev_name" > "$SYSFS_AGG_DIR/delete_device" 717 } 2> /dev/null 718done & 719writer_pid=$! 720while kill -0 "$writer_pid" 2> /dev/null; do 721 { 722 modprobe gpio-aggregator 723 modprobe -r gpio-aggregator 724 } 2> /dev/null 725done 726 727echo "GPIO $MODULE test PASS" 728