mirror of
https://github.com/jiegec/usbip.git
synced 2026-10-26 07:57:09 -04:00
The GitHub runner's Azure kernel has CONFIG_USB_HID disabled, so it cannot enumerate the simulated HID keyboard over USB/IP. Install and boot the Ubuntu generic kernel instead (which ships usbhid/hid-generic as modules and usbip/cdc-acm in linux-modules-extra), bundle + load the full module chain (hid, hid-generic, usbhid, usbip-core, vhci-hcd, cdc-acm) in the guest, and restore the keyboard check as a gating assertion. Now both the CDC ACM serial device and the HID keyboard are verified in CI.
160 lines
4.8 KiB
Bash
Executable File
160 lines
4.8 KiB
Bash
Executable File
#!/bin/busybox sh
|
|
# QEMU end-to-end usbip test init script.
|
|
#
|
|
# Runs *inside* the QEMU guest. It:
|
|
# 1. mounts proc/sys/devtmpfs
|
|
# 2. loads vhci-hcd + cdc_acm kernel modules
|
|
# 3. starts the compiled usbip demo server (our library under test)
|
|
# 4. uses the usbip client to attach the simulated HID keyboard + CDC ACM serial
|
|
# 5. verifies the serial device emits 'a' and the keyboard emits KEY_1
|
|
# 6. prints "TEST_RESULT: PASS" or "TEST_RESULT: FAIL" and powers off
|
|
#
|
|
# The workflow greps the serial console output for TEST_RESULT.
|
|
set -x
|
|
|
|
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
|
export PATH
|
|
|
|
mount -t proc proc /proc
|
|
mount -t sysfs sysfs /sys
|
|
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true
|
|
mkdir -p /dev/pts
|
|
mount -t devpts devpts /dev/pts 2>/dev/null || true
|
|
mount -t tmpfs tmpfs /tmp 2>/dev/null || true
|
|
|
|
# Bring up loopback so the usbip client can reach the local server on 127.0.0.1
|
|
ifconfig lo 127.0.0.1 netmask 255.0.0.0 up 2>/dev/null || echo "WARN: could not bring up lo"
|
|
|
|
echo "=== init: mounting done ==="
|
|
|
|
K=$(uname -r)
|
|
echo "=== kernel: $K ==="
|
|
|
|
echo "=== loading modules ==="
|
|
for mod in usb-common usbcore hid hid-generic usbhid usbip-core vhci-hcd cdc-acm; do
|
|
ko=$(find /lib/modules \( -name "$mod.ko" -o -name "$mod.ko.*" \) -print -quit 2>/dev/null)
|
|
if [ -z "$ko" ]; then
|
|
echo "- $mod: not present (built-in?)"
|
|
continue
|
|
fi
|
|
echo "- loading $ko"
|
|
insmod "$ko" || echo "WARN: failed to load $ko"
|
|
done
|
|
sleep 1
|
|
|
|
echo "=== usbip tool present? ==="
|
|
ls -la /usr/sbin/usbip /usr/bin/usbip /demo_server 2>&1
|
|
|
|
usbip_version=$(/usr/sbin/usbip 2>&1 | head -1 || true)
|
|
echo "usbip version check: $usbip_version"
|
|
|
|
echo "=== starting usbip demo server ==="
|
|
RUST_LOG=info /demo_server > /tmp/server.log 2>&1 &
|
|
SERVER_PID=$!
|
|
sleep 2
|
|
if ! kill -0 $SERVER_PID 2>/dev/null; then
|
|
echo "!!! demo server died, log:"
|
|
cat /tmp/server.log
|
|
fi
|
|
|
|
echo "=== usbip list ==="
|
|
usbip list -r 127.0.0.1
|
|
|
|
# Extract busids (e.g. 1-1, 1-2) from "usbip list -r" output
|
|
BUSIDS=$(usbip list -r 127.0.0.1 2>/dev/null \
|
|
| sed -n 's/^[[:space:]]*\([0-9][0-9-]*\):.*/\1/p')
|
|
echo "=== bus ids: [$BUSIDS] ==="
|
|
|
|
PASS=1
|
|
|
|
if [ -z "$BUSIDS" ]; then
|
|
echo "TEST_RESULT: FAIL (no exportable devices)"
|
|
dmesg | tail -40
|
|
poweroff -f
|
|
sleep 1
|
|
exit 1
|
|
fi
|
|
|
|
for BUSID in $BUSIDS; do
|
|
echo "=== attaching $BUSID ==="
|
|
# Note: the usbip tool may report a spurious "record connection" error after a
|
|
# successful attach; the kernel still enumerates the device, so we don't abort here.
|
|
usbip attach -r 127.0.0.1 -b "$BUSID"
|
|
echo "=== attach exit: $? ==="
|
|
sleep 2
|
|
done
|
|
|
|
echo "=== waiting for devices ==="
|
|
for i in $(seq 1 30); do
|
|
ACM=$(ls /dev/ttyACM* 2>/dev/null | head -1)
|
|
echo "iter $i: ACM=[$ACM]"
|
|
if [ -n "$ACM" ]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# HID over USB/IP is best-effort (some kernels do not support it); give it a moment.
|
|
sleep 3
|
|
EV=$(awk '
|
|
/^S:.*vhci_hcd/ { f=1 }
|
|
f && /^H:/ { if (match($0, /event[0-9]+/)) { print substr($0, RSTART, RLENGTH); exit } }
|
|
' /proc/bus/input/devices)
|
|
echo "after-wait: ACM=[$ACM] event=[$EV]"
|
|
|
|
echo "=== /proc/bus/input/devices ==="
|
|
cat /proc/bus/input/devices 2>/dev/null
|
|
echo
|
|
echo "=== /dev listing ==="
|
|
ls -la /dev/ttyACM* /dev/input/ 2>/dev/null
|
|
|
|
# ---- Serial test: read one raw byte from /dev/ttyACM0, expect 'a' (0x61) ----
|
|
if [ -n "$ACM" ]; then
|
|
echo "=== serial test: reading $ACM (raw) ==="
|
|
stty -F "$ACM" raw -echo 2>/dev/null || true
|
|
DATA=$(timeout 8 dd if="$ACM" bs=1 count=1 2>/dev/null | od -An -tx1 -v | tr -d ' \n')
|
|
echo "serial byte: [$DATA]"
|
|
case "$DATA" in
|
|
61) echo "SERIAL_TEST: PASS (got 'a' = 0x61)" ;;
|
|
*) echo "SERIAL_TEST: FAIL ([$DATA])"; PASS=0 ;;
|
|
esac
|
|
else
|
|
echo "SERIAL_TEST: FAIL (no /dev/ttyACM device)"; PASS=0
|
|
fi
|
|
|
|
# ---- Keyboard test: read the vhci HID event device, look for KEY_1 (code=2) ----
|
|
if [ -n "$EV" ]; then
|
|
echo "=== keyboard test: reading /dev/input/$EV (timeout 6s) ==="
|
|
timeout 6 cat "/dev/input/$EV" > /tmp/kbd.bin 2>/dev/null
|
|
HEX=$(od -An -tx1 -v /tmp/kbd.bin | tr -d ' \n')
|
|
echo "kbd bytes: $HEX"
|
|
# EV_KEY(type=1) KEY_1(code=2) value=1(down) -> LE bytes "0100 0200 01000000"
|
|
case "$HEX" in
|
|
*0100020001000000*) echo "KEYBOARD_TEST: PASS (KEY_1 down event seen)" ;;
|
|
*) echo "KEYBOARD_TEST: FAIL"; PASS=0 ;;
|
|
esac
|
|
else
|
|
echo "KEYBOARD_TEST: FAIL (no vhci input event device)"; PASS=0
|
|
fi
|
|
|
|
echo "=== server.log (tail) ==="
|
|
tail -40 /tmp/server.log 2>/dev/null
|
|
|
|
echo "=== dmesg: usb 1-1 / 1-2 / hid / errors ==="
|
|
dmesg | grep -iE 'usb [0-9]-|vhci_hcd|hid|input:|error|timeout|reset|not responding|descriptor' | head -40
|
|
|
|
if [ "$PASS" = "1" ]; then
|
|
echo "TEST_RESULT: PASS"
|
|
else
|
|
echo "TEST_RESULT: FAIL"
|
|
fi
|
|
|
|
echo "=== dmesg tail ==="
|
|
dmesg | tail -20
|
|
|
|
sync
|
|
sleep 1
|
|
poweroff -f
|
|
sleep 1
|
|
exit 0
|