onboard audio: JMISC HPH wiring, UCM fix, update scripts for git deploy

This commit is contained in:
2026-06-23 21:25:51 -07:00
parent a135dc4452
commit d239d58c44
22 changed files with 227 additions and 77 deletions
+132
View File
@@ -0,0 +1,132 @@
#!/bin/bash
# configure-usb-audio.sh
# Configure the Arduino Uno Q as a composite USB gadget:
# UAC1 (USB Audio Class) + gmidi (USB MIDI)
#
# The host sees one device with both an audio sink and a MIDI port,
# allowing MIDI input over the same USB connection as audio output.
#
# Based on Linux USB gadget configfs setup.
# The Uno Q's USB peripheral controller is exposed via configfs.
set -euo pipefail
GADGET_DIR="/sys/kernel/config/usb_gadget"
GADGET_NAME="g1"
UDC_DIR="/sys/class/udc"
# Gadget config
VID="0x2341" # Arduino VID
PID="0x006A" # Custom PID (Uno Q audio + MIDI)
SERIAL="$(cat /sys/firmware/devicetree/base/serial-number 2>/dev/null | tr -d '\0' || cat /proc/cpuinfo 2>/dev/null | grep Serial | head -1 | awk '{print $3}' || echo 'UnoQ')"
MANUFACTURER="Arduino"
PRODUCT="Uno Q Audio Synth"
# USB audio params
CHANNELS=2 # stereo out
SAMPLE_RATE=48000
SAMPLE_SIZE=2 # bytes (2 = 16-bit; kernel UAC1 gadget expects bytes, not bits)
# Find UDC (USB Device Controller)
find_udc() {
for controller in "$UDC_DIR"/*; do
if [ -d "$controller" ]; then
basename "$controller"
return 0
fi
done
echo "ERROR: No UDC found" >&2
exit 1
}
create_gadget() {
local udc="$1"
# Remove existing gadget if present
if [ -d "$GADGET_DIR/$GADGET_NAME" ]; then
echo "" > "$GADGET_DIR/$GADGET_NAME/UDC" 2>/dev/null || true
for _ in $(seq 1 50); do
if [ ! -f "$GADGET_DIR/$GADGET_NAME/UDC" ] || [ -z "$(cat "$GADGET_DIR/$GADGET_NAME/UDC" 2>/dev/null)" ]; then
break
fi
sleep 0.1
done
for config in "$GADGET_DIR/$GADGET_NAME/configs"/*/; do
config=$(basename "$config")
for func in "$GADGET_DIR/$GADGET_NAME/configs/$config/"*.*/; do
func=$(basename "$func")
[ -L "$GADGET_DIR/$GADGET_NAME/configs/$config/$func" ] && rm -f "$GADGET_DIR/$GADGET_NAME/configs/$config/$func"
done
rmdir "$GADGET_DIR/$GADGET_NAME/configs/$config" 2>/dev/null || true
done
for func in "$GADGET_DIR/$GADGET_NAME/functions"/*/; do
func=$(basename "$func")
rmdir "$GADGET_DIR/$GADGET_NAME/functions/$func" 2>/dev/null || true
done
rmdir "$GADGET_DIR/$GADGET_NAME" 2>/dev/null || true
fi
mkdir -p "$GADGET_DIR/$GADGET_NAME"
echo "$VID" > "$GADGET_DIR/$GADGET_NAME/idVendor"
echo "$PID" > "$GADGET_DIR/$GADGET_NAME/idProduct"
echo "0x0100" > "$GADGET_DIR/$GADGET_NAME/bcdDevice"
echo "0x0200" > "$GADGET_DIR/$GADGET_NAME/bcdUSB"
mkdir -p "$GADGET_DIR/$GADGET_NAME/strings/0x409"
echo "$SERIAL" > "$GADGET_DIR/$GADGET_NAME/strings/0x409/serialnumber"
echo "$MANUFACTURER" > "$GADGET_DIR/$GADGET_NAME/strings/0x409/manufacturer"
echo "$PRODUCT" > "$GADGET_DIR/$GADGET_NAME/strings/0x409/product"
# Create UAC1 function (audio output, wide host compatibility)
mkdir -p "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0"
echo "$CHANNELS" > "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0/p_chmask"
echo "$SAMPLE_RATE" > "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0/p_srate"
echo "$SAMPLE_SIZE" > "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0/p_ssize"
echo "$CHANNELS" > "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0/c_chmask"
echo "$SAMPLE_RATE" > "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0/c_srate"
echo "$SAMPLE_SIZE" > "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0/c_ssize"
# Create MIDI function (MIDI input from host)
mkdir -p "$GADGET_DIR/$GADGET_NAME/functions/midi.gs0"
echo 1 > "$GADGET_DIR/$GADGET_NAME/functions/midi.gs0/in_ports"
echo 1 > "$GADGET_DIR/$GADGET_NAME/functions/midi.gs0/out_ports"
# Create configuration
mkdir -p "$GADGET_DIR/$GADGET_NAME/configs/c.1"
mkdir -p "$GADGET_DIR/$GADGET_NAME/configs/c.1/strings/0x409"
echo "Audio + MIDI" > "$GADGET_DIR/$GADGET_NAME/configs/c.1/strings/0x409/configuration"
echo 250 > "$GADGET_DIR/$GADGET_NAME/configs/c.1/MaxPower"
# Link both functions to the same config (composite device)
ln -s "$GADGET_DIR/$GADGET_NAME/functions/uac1.gs0" "$GADGET_DIR/$GADGET_NAME/configs/c.1/"
ln -s "$GADGET_DIR/$GADGET_NAME/functions/midi.gs0" "$GADGET_DIR/$GADGET_NAME/configs/c.1/"
# Bind to UDC
echo "$udc" > "$GADGET_DIR/$GADGET_NAME/UDC"
echo "USB gadget '$GADGET_NAME' bound to $udc (UAC1 audio + gmidi)"
}
case "${1:-start}" in
start)
udc=$(find_udc)
create_gadget "$udc"
;;
stop)
if [ -d "$GADGET_DIR/$GADGET_NAME" ]; then
udc=$(cat "$GADGET_DIR/$GADGET_NAME/UDC" 2>/dev/null || true)
[ -n "$udc" ] && echo "" > "$GADGET_DIR/$GADGET_NAME/UDC" 2>/dev/null || true
fi
echo "USB gadget '$GADGET_NAME' stopped"
;;
status)
if [ -d "$GADGET_DIR/$GADGET_NAME/UDC" ]; then
echo "Gadget: $(cat "$GADGET_DIR/$GADGET_NAME/UDC" 2>/dev/null || echo 'not bound')"
else
echo "Gadget: not configured"
fi
;;
*)
echo "Usage: $0 {start|stop|status}"
exit 1
;;
esac