core: fallback when UVC fails
This commit is contained in:
parent
953f29dec7
commit
da6aa6c425
@ -8,6 +8,25 @@ set -euo pipefail
|
||||
log() { printf '[lesavka-core] %s\n' "$*"; }
|
||||
cleanup() { echo "" >"$G/UDC" 2>/dev/null || true; }
|
||||
|
||||
DISABLE_UAC=${LESAVKA_DISABLE_UAC:-}
|
||||
DISABLE_UVC=${LESAVKA_DISABLE_UVC:-}
|
||||
UVC_FALLBACK=${LESAVKA_UVC_FALLBACK:-1}
|
||||
|
||||
wait_for_enum() {
|
||||
local tries=${1:-50} # 50 x 100ms = 5s
|
||||
UDC_STATE="unknown"
|
||||
UDC_SPEED="unknown"
|
||||
for ((i=0; i<tries; i++)); do
|
||||
UDC_STATE=$(cat "/sys/class/udc/$UDC/state" 2>/dev/null || echo "unknown")
|
||||
UDC_SPEED=$(cat "/sys/class/udc/$UDC/current_speed" 2>/dev/null || echo "unknown")
|
||||
if [[ "$UDC_STATE" != "not attached" && "$UDC_STATE" != "unknown" ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
exec 2> >(tee -a /tmp/lesavka-core.debug.$(date +%s).log)
|
||||
set -x
|
||||
echo "[lesavka-core] running: $0 (sha1sum=$(sha1sum "$0" | cut -d' ' -f1))"
|
||||
@ -103,114 +122,102 @@ printf '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00'\
|
||||
'\x05\x01\x09\x30\x09\x31\x09\x38\x15\x81\x25\x7f\x75\x08\x95\x03\x81\x06'\
|
||||
'\xc0\xc0' >"$G/functions/hid.usb1/report_desc"
|
||||
|
||||
# ---------- UAC2 function - speaker + mic, 2×48 kHz stereo ---------
|
||||
mkdir -p "$G/functions/uac2.usb0"
|
||||
U="$G/functions/uac2.usb0"
|
||||
# Playback (speaker)
|
||||
echo 0x3 >"$U/p_chmask" # L+R
|
||||
echo 48000 >"$U/p_srate"
|
||||
echo 2 >"$U/p_ssize" # 16 bit
|
||||
# Capture (microphone)
|
||||
echo 0x3 >"$U/c_chmask"
|
||||
echo 48000 >"$U/c_srate"
|
||||
echo 2 >"$U/c_ssize"
|
||||
# Optional: allocate a few extra request buffers
|
||||
echo 32 >"$U/req_number" 2>/dev/null || true
|
||||
if [[ -z $DISABLE_UAC ]]; then
|
||||
# ---------- UAC2 function - speaker + mic, 2×48 kHz stereo ---------
|
||||
mkdir -p "$G/functions/uac2.usb0"
|
||||
U="$G/functions/uac2.usb0"
|
||||
# Playback (speaker)
|
||||
echo 0x3 >"$U/p_chmask" # L+R
|
||||
echo 48000 >"$U/p_srate"
|
||||
echo 2 >"$U/p_ssize" # 16 bit
|
||||
# Capture (microphone)
|
||||
echo 0x3 >"$U/c_chmask"
|
||||
echo 48000 >"$U/c_srate"
|
||||
echo 2 >"$U/c_ssize"
|
||||
# Optional: allocate a few extra request buffers
|
||||
echo 32 >"$U/req_number" 2>/dev/null || true
|
||||
else
|
||||
log "🔇 UAC2 disabled (LESAVKA_DISABLE_UAC set)"
|
||||
fi
|
||||
|
||||
# ----------------------- UVC function (usb‑video) ------------------
|
||||
mkdir -p "$G/functions/uvc.usb0"
|
||||
F="$G/functions/uvc.usb0"
|
||||
if [[ -z $DISABLE_UVC ]]; then
|
||||
# ----------------------- UVC function (usb‑video) ------------------
|
||||
mkdir -p "$G/functions/uvc.usb0"
|
||||
F="$G/functions/uvc.usb0"
|
||||
|
||||
# ── 1. FORMAT DESCRIPTOR (uncompressed YUY2, 16 bpp) ──────────────
|
||||
mkdir -p "$F/streaming/uncompressed/u"
|
||||
# GUID = {59555932-0000-0010-8000-00aa00389b71} (“YUY2”) little‑endian
|
||||
printf '\x59\x55\x59\x32\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71' \
|
||||
>"$F/streaming/uncompressed/u/guidFormat"
|
||||
echo 16 >"$F/streaming/uncompressed/u/bBitsPerPixel"
|
||||
# ── 1. FORMAT DESCRIPTOR (uncompressed YUY2, 16 bpp) ──────────────
|
||||
mkdir -p "$F/streaming/uncompressed/yuyv"
|
||||
# GUID = {59555932-0000-0010-8000-00aa00389b71} (“YUY2”) little-endian
|
||||
printf '\x59\x55\x59\x32\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71' \
|
||||
>"$F/streaming/uncompressed/yuyv/guidFormat"
|
||||
echo 16 >"$F/streaming/uncompressed/yuyv/bBitsPerPixel"
|
||||
|
||||
# ── 2. FRAME DESCRIPTOR (index 1 @ 30 fps) ────────────────────────
|
||||
mkdir -p "$F/streaming/uncompressed/u/f1"
|
||||
echo 1280 >"$F/streaming/uncompressed/u/f1/wWidth"
|
||||
echo 720 >"$F/streaming/uncompressed/u/f1/wHeight"
|
||||
echo 1843200 >"$F/streaming/uncompressed/u/f1/dwMaxVideoFrameBufferSize"
|
||||
echo 333333 >"$F/streaming/uncompressed/u/f1/dwDefaultFrameInterval" # 30 fps
|
||||
echo 333333 >"$F/streaming/uncompressed/u/f1/dwFrameInterval"
|
||||
# ── 2. FRAME DESCRIPTOR (720p @ 30 fps) ───────────────────────────
|
||||
mkdir -p "$F/streaming/uncompressed/yuyv/720p"
|
||||
echo 1280 >"$F/streaming/uncompressed/yuyv/720p/wWidth"
|
||||
echo 720 >"$F/streaming/uncompressed/yuyv/720p/wHeight"
|
||||
echo 1843200 >"$F/streaming/uncompressed/yuyv/720p/dwMaxVideoFrameBufferSize"
|
||||
echo 333333 >"$F/streaming/uncompressed/yuyv/720p/dwDefaultFrameInterval"
|
||||
cat <<'EOF' >"$F/streaming/uncompressed/yuyv/720p/dwFrameInterval"
|
||||
333333
|
||||
EOF
|
||||
|
||||
# ── 3. REQUIRED HEADER LINKS (absolute‑paths, no “1”) ──────────────
|
||||
header_h="$F/streaming/header/h" # convenience variables
|
||||
fmt_dir="$F/streaming/uncompressed/u"
|
||||
# ── 3. REQUIRED HEADER LINKS (per UVC gadget docs) ────────────────
|
||||
mkdir -p "$F/streaming/header/h"
|
||||
pushd "$F/streaming/header/h" >/dev/null
|
||||
ln -s ../../uncompressed/yuyv yuyv
|
||||
popd >/dev/null
|
||||
|
||||
mkdir -p "$header_h"
|
||||
|
||||
# wait until the kernel has rebuilt the directory and added its attribute
|
||||
# files (bmInfo is always created by the driver)
|
||||
for _ in {1..50}; do
|
||||
[ -e "$header_h/bmInfo" ] && break
|
||||
sleep 0.010 # max 0.5 s total
|
||||
done
|
||||
|
||||
# ABSOLUTE symlink → no relative elements, name is “fmt” (not “1”)
|
||||
ln -sf "$fmt_dir" "$header_h/fmt"
|
||||
# echo 1 >"$header_h/bNumFormats"
|
||||
# echo 0 >"$header_h/bmInfo"
|
||||
|
||||
# per‑speed class directories (absolute links)
|
||||
for s in fs hs ss; do
|
||||
mkdir -p "$F/streaming/class/$s"
|
||||
ln -sf "$header_h" "$F/streaming/class/$s/h"
|
||||
done
|
||||
for s in fs hs ss; do
|
||||
mkdir -p "$F/streaming/class/$s"
|
||||
pushd "$F/streaming/class/$s" >/dev/null
|
||||
ln -s ../../header/h h
|
||||
popd >/dev/null
|
||||
done
|
||||
|
||||
# ── 4. Video‑Control interface ─────────────────────────────────────
|
||||
set +e # relax errors for configfs quirks
|
||||
mkdir -p "$F/control/header/h" # real dir – mandatory
|
||||
mkdir -p "$F/control/class" # parent once
|
||||
mkdir -p "$F/control/class/fs" "$F/control/class/hs" "$F/control/class/ss" 2>/dev/null || true
|
||||
|
||||
echo "[lesavka-core] ★ directory tree just before links:"
|
||||
tree -L 3 "$F/control" | sed 's/^/[lesavka-core] /'
|
||||
|
||||
for s in fs hs ss; do
|
||||
# best-effort: some UDCs reject certain speeds; skip on failure
|
||||
if mkdir -p "$F/control/class/$s" 2>/dev/null; then
|
||||
ln -snf "$F/control/header/h" "$F/control/class/$s/h" 2>/dev/null || \
|
||||
log "⚠️ control/class/$s/h link missing (continuing)"
|
||||
else
|
||||
log "⚠️ skipping control/class/$s (mkdir failed)"
|
||||
fi
|
||||
done
|
||||
|
||||
for s in fs hs ss; do
|
||||
[ -L "$F/control/class/$s/h" ] || log "⚠️ $s/h link missing (continuing)"
|
||||
done
|
||||
|
||||
echo "[lesavka-core] ★ directory tree just before bind:"
|
||||
tree -L 3 "$F/control" | sed 's/^/[lesavka-core] /'
|
||||
|
||||
for s in fs hs ss; do
|
||||
[ -L "$F/control/class/$s" ] || log "⚠️ $s link missing (continuing)"
|
||||
done
|
||||
set -e # back to strict mode
|
||||
mkdir -p "$F/control/header/h"
|
||||
set +e
|
||||
for s in fs hs ss; do
|
||||
mkdir -p "$F/control/class/$s" 2>/dev/null || continue
|
||||
pushd "$F/control/class/$s" >/dev/null
|
||||
ln -s ../../header/h h 2>/dev/null || true
|
||||
popd >/dev/null
|
||||
done
|
||||
set -e
|
||||
|
||||
# optional: hide unsupported controls
|
||||
echo 0 >"$F/control/terminal/camera/default/bmControls" 2>/dev/null || true
|
||||
echo 0 >"$F/control/processing/default/bmControls" 2>/dev/null || true
|
||||
echo 0 >"$F/control/terminal/camera/default/bmControls" 2>/dev/null || true
|
||||
echo 0 >"$F/control/processing/default/bmControls" 2>/dev/null || true
|
||||
|
||||
# friendly label
|
||||
set +e
|
||||
mkdir -p "$F/control/header/strings/0x409" 2>/dev/null || log "⚠️ skipping control/header strings (mkdir failed)"
|
||||
echo "Lesavka UVC" >"$F/control/header/strings/0x409/label" 2>/dev/null || log "⚠️ unable to set UVC label (continuing)"
|
||||
set -e
|
||||
mkdir -p "$F/control/header/h/strings/0x409" 2>/dev/null || true
|
||||
echo "Lesavka UVC" >"$F/control/header/h/strings/0x409/label" 2>/dev/null || true
|
||||
else
|
||||
log "📷 UVC disabled (LESAVKA_DISABLE_UVC set)"
|
||||
fi
|
||||
|
||||
# ----------------------- configuration -----------------------------
|
||||
mkdir -p "$G/configs/c.1/strings/0x409"
|
||||
echo 500 > "$G/configs/c.1/MaxPower"
|
||||
# echo "Config 1" > "$G/configs/c.1/strings/0x409/configuration"
|
||||
echo "Config 1: HID + UAC2" >"$G/configs/c.1/strings/0x409/configuration"
|
||||
config_label="Config 1: HID"
|
||||
if [[ -z $DISABLE_UAC ]]; then
|
||||
config_label+=" + UAC2"
|
||||
fi
|
||||
if [[ -z $DISABLE_UVC ]]; then
|
||||
config_label+=" + UVC"
|
||||
fi
|
||||
echo "$config_label" >"$G/configs/c.1/strings/0x409/configuration"
|
||||
|
||||
ln -s $G/functions/hid.usb0 $G/configs/c.1/
|
||||
ln -s $G/functions/hid.usb1 $G/configs/c.1/
|
||||
ln -s $U $G/configs/c.1/
|
||||
ln -s $G/functions/uvc.usb0 $G/configs/c.1/
|
||||
if [[ -z $DISABLE_UAC ]]; then
|
||||
ln -s $U $G/configs/c.1/
|
||||
fi
|
||||
if [[ -z $DISABLE_UVC ]]; then
|
||||
ln -s $G/functions/uvc.usb0 $G/configs/c.1/
|
||||
fi
|
||||
|
||||
# mkdir -p $G/functions/hid.usb0/os_desc
|
||||
# mkdir -p $G/functions/hid.usb1/os_desc
|
||||
@ -233,6 +240,19 @@ ln -s $G/functions/uvc.usb0 $G/configs/c.1/
|
||||
# 4. Bind gadget
|
||||
#──────────────────────────────────────────────────
|
||||
echo "$UDC" >"$G/UDC"
|
||||
log "🎉 gadget bound on $UDC (hidg0, hidg1, UAC2 L+R, UVC)"
|
||||
parts="hidg0,hidg1"
|
||||
[[ -z $DISABLE_UAC ]] && parts+=",UAC2"
|
||||
[[ -z $DISABLE_UVC ]] && parts+=",UVC"
|
||||
log "🎉 gadget bound on $UDC ($parts)"
|
||||
|
||||
if wait_for_enum 50; then
|
||||
log "✅ UDC state is '$UDC_STATE' (speed=$UDC_SPEED)"
|
||||
else
|
||||
log "⚠️ UDC state is '$UDC_STATE' (speed=$UDC_SPEED). Host not enumerated."
|
||||
if [[ -z $DISABLE_UVC && "$UVC_FALLBACK" != "0" ]]; then
|
||||
log "♻️ retrying without UVC (LESAVKA_UVC_FALLBACK=0 to disable)"
|
||||
exec env LESAVKA_DISABLE_UVC=1 LESAVKA_UVC_FALLBACK=0 "$0"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user