#!/bin/bash
set -e
TEST_REQS_FW_SYSFS_FALLBACK="yes"
TEST_REQS_FW_SET_CUSTOM_PATH="no"
TEST_DIR=$(dirname $0)
source $TEST_DIR/fw_lib.sh
check_mods
check_setup
verify_reqs
setup_tmp_file
trap "test_finish" EXIT
load_fw()
{
local name="$1"
local file="$2"
echo -n "$name" >"$DIR"/trigger_request &
local timeout=10
while [ ! -e "$DIR"/"$name"/loading ]; do
sleep 0.1
timeout=$(( $timeout - 1 ))
if [ "$timeout" -eq 0 ]; then
echo "$0: firmware interface never appeared" >&2
exit 1
fi
done
echo 1 >"$DIR"/"$name"/loading
cat "$file" >"$DIR"/"$name"/data
echo 0 >"$DIR"/"$name"/loading
wait
}
load_fw_cancel()
{
local name="$1"
local file="$2"
echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &
local timeout=10
while [ ! -e "$DIR"/"$name"/loading ]; do
sleep 0.1
timeout=$(( $timeout - 1 ))
if [ "$timeout" -eq 0 ]; then
echo "$0: firmware interface never appeared" >&2
exit 1
fi
done
echo -1 >"$DIR"/"$name"/loading
wait
}
load_fw_custom()
{
if [ ! -e "$DIR"/trigger_custom_fallback ]; then
echo "$0: custom fallback trigger not present, ignoring test" >&2
exit $ksft_skip
fi
local name="$1"
local file="$2"
echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
local timeout=10
while [ ! -e "$DIR"/"$name"/loading ]; do
sleep 0.1
timeout=$(( $timeout - 1 ))
if [ "$timeout" -eq 0 ]; then
echo "$0: firmware interface never appeared" >&2
exit 1
fi
done
echo 1 >"$DIR"/"$name"/loading
cat "$file" >"$DIR"/"$name"/data
echo 0 >"$DIR"/"$name"/loading
wait
return 0
}
load_fw_custom_cancel()
{
if [ ! -e "$DIR"/trigger_custom_fallback ]; then
echo "$0: canceling custom fallback trigger not present, ignoring test" >&2
exit $ksft_skip
fi
local name="$1"
local file="$2"
echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
local timeout=10
while [ ! -e "$DIR"/"$name"/loading ]; do
sleep 0.1
timeout=$(( $timeout - 1 ))
if [ "$timeout" -eq 0 ]; then
echo "$0: firmware interface never appeared" >&2
exit 1
fi
done
echo -1 >"$DIR"/"$name"/loading
wait
return 0
}
load_fw_fallback_with_child()
{
local name="$1"
local file="$2"
echo 4 >/sys/class/firmware/timeout
sleep 1 &
SECONDS_BEFORE=$(date +%s)
echo -n "$name" >"$DIR"/trigger_request 2>/dev/null
SECONDS_AFTER=$(date +%s)
SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE))
if [ "$SECONDS_DELTA" -lt 4 ]; then
RET=1
else
RET=0
fi
wait
return $RET
}
test_syfs_timeout()
{
DEVPATH="$DIR"/"nope-$NAME"/loading
echo -n 2 >/sys/class/firmware/timeout
echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &
sleep 1
if [ ! -f $DEVPATH ]; then
echo "$0: fallback mechanism immediately cancelled"
echo ""
echo "The file never appeared: $DEVPATH"
echo ""
echo "This might be a distribution udev rule setup by your distribution"
echo "to immediately cancel all fallback requests, this must be"
echo "removed before running these tests. To confirm look for"
echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"
echo "and see if you have something like this:"
echo ""
echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""
echo ""
echo "If you do remove this file or comment out this line before"
echo "proceeding with these tests."
exit 1
fi
if diff -q "$FW" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not expected to match" >&2
exit 1
else
echo "$0: timeout works"
fi
}
run_sysfs_main_tests()
{
test_syfs_timeout
echo 4 >/sys/class/firmware/timeout
load_fw "$NAME" "$0"
if diff -q "$FW" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not expected to match" >&2
exit 1
else
echo "$0: firmware comparison works"
fi
load_fw "$NAME" "$FW"
if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not loaded" >&2
exit 1
else
echo "$0: fallback mechanism works"
fi
load_fw_cancel "nope-$NAME" "$FW"
if diff -q "$FW" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was expected to be cancelled" >&2
exit 1
else
echo "$0: cancelling fallback mechanism works"
fi
set +e
load_fw_fallback_with_child "nope-signal-$NAME" "$FW"
if [ "$?" -eq 0 ]; then
echo "$0: SIGCHLD on sync ignored as expected" >&2
else
echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2
exit 1
fi
set -e
}
run_sysfs_custom_load_tests()
{
RANDOM_FILE_PATH=$(setup_random_file)
RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not loaded" >&2
exit 1
else
echo "$0: custom fallback loading mechanism works"
fi
fi
RANDOM_FILE_PATH=$(setup_random_file)
RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not loaded" >&2
exit 1
else
echo "$0: custom fallback loading mechanism works"
fi
fi
RANDOM_FILE_REAL="$RANDOM_FILE_PATH"
FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)
FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"
if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then
if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was expected to be cancelled" >&2
exit 1
else
echo "$0: cancelling custom fallback mechanism works"
fi
fi
}
if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then
run_sysfs_main_tests
fi
run_sysfs_custom_load_tests
exit 0