1#!/bin/sh 2# This validates that the kernel will fall back to using the user helper 3# to load firmware it can't find on disk itself. We must request a firmware 4# that the kernel won't find, and any installed helper (e.g. udev) also 5# won't find so that we can do the load ourself manually. 6set -e 7 8modprobe test_firmware 9 10DIR=/sys/devices/virtual/misc/test_firmware 11 12# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ 13# These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that 14# as an indicator for CONFIG_FW_LOADER_USER_HELPER. 15HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) 16 17if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then 18 OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) 19else 20 echo "usermode helper disabled so ignoring test" 21 exit 0 22fi 23 24FWPATH=$(mktemp -d) 25FW="$FWPATH/test-firmware.bin" 26 27test_finish() 28{ 29 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout 30 rm -f "$FW" 31 rmdir "$FWPATH" 32} 33 34load_fw() 35{ 36 local name="$1" 37 local file="$2" 38 39 # This will block until our load (below) has finished. 40 echo -n "$name" >"$DIR"/trigger_request & 41 42 # Give kernel a chance to react. 43 local timeout=10 44 while [ ! -e "$DIR"/"$name"/loading ]; do 45 sleep 0.1 46 timeout=$(( $timeout - 1 )) 47 if [ "$timeout" -eq 0 ]; then 48 echo "$0: firmware interface never appeared" >&2 49 exit 1 50 fi 51 done 52 53 echo 1 >"$DIR"/"$name"/loading 54 cat "$file" >"$DIR"/"$name"/data 55 echo 0 >"$DIR"/"$name"/loading 56 57 # Wait for request to finish. 58 wait 59} 60 61trap "test_finish" EXIT 62 63# This is an unlikely real-world firmware content. :) 64echo "ABCD0123" >"$FW" 65NAME=$(basename "$FW") 66 67DEVPATH="$DIR"/"nope-$NAME"/loading 68 69# Test failure when doing nothing (timeout works). 70echo -n 2 >/sys/class/firmware/timeout 71echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 72 73# Give the kernel some time to load the loading file, must be less 74# than the timeout above. 75sleep 1 76if [ ! -f $DEVPATH ]; then 77 echo "$0: fallback mechanism immediately cancelled" 78 echo "" 79 echo "The file never appeared: $DEVPATH" 80 echo "" 81 echo "This might be a distribution udev rule setup by your distribution" 82 echo "to immediately cancel all fallback requests, this must be" 83 echo "removed before running these tests. To confirm look for" 84 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" 85 echo "and see if you have something like this:" 86 echo "" 87 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" 88 echo "" 89 echo "If you do remove this file or comment out this line before" 90 echo "proceeding with these tests." 91 exit 1 92fi 93 94if diff -q "$FW" /dev/test_firmware >/dev/null ; then 95 echo "$0: firmware was not expected to match" >&2 96 exit 1 97else 98 echo "$0: timeout works" 99fi 100 101# Put timeout high enough for us to do work but not so long that failures 102# slow down this test too much. 103echo 4 >/sys/class/firmware/timeout 104 105# Load this script instead of the desired firmware. 106load_fw "$NAME" "$0" 107if diff -q "$FW" /dev/test_firmware >/dev/null ; then 108 echo "$0: firmware was not expected to match" >&2 109 exit 1 110else 111 echo "$0: firmware comparison works" 112fi 113 114# Do a proper load, which should work correctly. 115load_fw "$NAME" "$FW" 116if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 117 echo "$0: firmware was not loaded" >&2 118 exit 1 119else 120 echo "$0: user helper firmware loading works" 121fi 122 123exit 0 124