Initial commit

This commit is contained in:
jack
2026-04-06 21:59:41 +08:00
commit 760bdf2c9b
28 changed files with 2310 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
#!/bin/bash
#
# Chromebox 10 代 - Linux 音频硬件拓扑收集脚本
# 用于 C1a 任务:在 Linux 下收集硬件拓扑信息
#
# 用法: ./collect_linux_audio_topology.sh [输出文件]
# 默认输出到: audio_topology/collected/audio_topology_linux_$(hostname)_$(date).txt
#
# 建议: 用 sudo 运行以获取 dmesg/journalctlpactl/wpctl 需图形会话,
# 若用 sudo 会尝试以 SUDO_USER 身份调用,否则可在桌面终端直接运行
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUTPUT_DIR="${SCRIPT_DIR}/collected"
mkdir -p "$OUTPUT_DIR"
OUTPUT="${1:-${OUTPUT_DIR}/audio_topology_linux_$(hostname)_$(date +%Y%m%d_%H%M%S).txt}"
TMP_DIR=$(mktemp -d)
trap "rm -rf $TMP_DIR" EXIT
log() {
echo "[$(date +%H:%M:%S)] $*"
}
section() {
echo "" >> "$OUTPUT"
echo "========================================" >> "$OUTPUT"
echo "### $1" >> "$OUTPUT"
echo "========================================" >> "$OUTPUT"
echo "" >> "$OUTPUT"
}
run_cmd() {
local desc="$1"
shift
echo "# $desc" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
if "$@" >> "$OUTPUT" 2>&1; then
true
else
echo "(命令返回非零,可能部分信息缺失)" >> "$OUTPUT"
fi
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
}
log "开始收集 Linux 音频硬件拓扑..."
log "输出文件: $OUTPUT"
: > "$OUTPUT"
echo "# Chromebox 10 代 - Linux 音频硬件拓扑" >> "$OUTPUT"
echo "# 收集时间: $(date -Iseconds)" >> "$OUTPUT"
echo "# 主机: $(hostname)" >> "$OUTPUT"
echo "" >> "$OUTPUT"
# --- 系统信息 ---
section "系统信息"
run_cmd "uname -a" uname -a
run_cmd "内核版本" uname -r
run_cmd "/proc/version" cat /proc/version
if command -v alsactl &>/dev/null; then
run_cmd "ALSA 版本" alsactl --version 2>/dev/null || echo "alsactl 无版本信息"
fi
# --- PCI 音频设备 ---
section "PCI 音频相关设备"
if command -v lspci &>/dev/null; then
run_cmd "lspci -nn | grep -i audio (含设备 ID便于查驱动/quirks)" bash -c "lspci -nn | grep -i audio || echo '(无匹配)'"
run_cmd "lspci | grep -i audio" bash -c "lspci | grep -i audio || echo '(无匹配)'"
run_cmd "lspci -v | grep -A 15 -i audio" bash -c "lspci -v 2>/dev/null | grep -A 15 -i audio || echo '(无匹配)'"
fi
# --- 播放/录音设备列表 ---
section "ALSA 设备列表"
if command -v aplay &>/dev/null; then
run_cmd "aplay -l (播放设备)" aplay -l
run_cmd "aplay -L (ALSA 设备描述)" aplay -L 2>/dev/null || true
else
echo "# aplay 未安装" >> "$OUTPUT"
fi
if command -v arecord &>/dev/null; then
run_cmd "arecord -l (录音设备)" arecord -l
fi
run_cmd "cat /proc/asound/cards" cat /proc/asound/cards
run_cmd "cat /proc/asound/pcm (PCM 设备明细)" cat /proc/asound/pcm
# --- /proc/asound 目录结构 ---
section "/proc/asound 目录结构"
run_cmd "ls -la /proc/asound" ls -la /proc/asound
for card_dir in /proc/asound/card[0-9]*; do
if [ -d "$card_dir" ]; then
card=$(basename "$card_dir")
echo "# $card 目录内容:" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
ls -la "$card_dir" 2>/dev/null >> "$OUTPUT" || true
echo "\`\`\`" >> "$OUTPUT"
fi
done
# --- Codec 信息 (HDA) ---
section "HDA Codec 信息"
for codec in /proc/asound/card*/codec*; do
if [ -f "$codec" ]; then
echo "# $codec" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
cat "$codec" >> "$OUTPUT" 2>/dev/null || echo "(无法读取)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
fi
done
if ! ls /proc/asound/card*/codec* &>/dev/null; then
echo "(未找到 codec 文件)" >> "$OUTPUT"
fi
# --- ELD 内容 (HDMI 显示器音频能力,对 HDMI 无声排查很重要) ---
section "HDMI ELD 内容"
for eld in /proc/asound/card*/eld*; do
if [ -f "$eld" ]; then
echo "# $eld" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
cat "$eld" >> "$OUTPUT" 2>/dev/null || echo "(无法读取,或 ELD 为空/未连接)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
fi
done
# --- /sys/class/sound 拓扑 ---
section "/sys/class/sound 设备"
if [ -d /sys/class/sound ]; then
run_cmd "ls -la /sys/class/sound" ls -la /sys/class/sound
for card in /sys/class/sound/card[0-9]*; do
if [ -d "$card" ]; then
name=$(basename "$card")
echo "# $name 设备属性:" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
for f in id number; do
if [ -f "$card/$f" ]; then
echo "$f: $(cat "$card/$f" 2>/dev/null)" >> "$OUTPUT"
fi
done
echo "\`\`\`" >> "$OUTPUT"
fi
done
fi
# --- 内核日志中的音频相关信息 ---
section "内核日志 (dmesg) 音频相关"
echo "# dmesg | grep -iE 'snd|hda|audio|codec|hdmi'" >> "$OUTPUT"
echo "# 提示: 若此处显示「需要 root」请用 sudo 重新运行本脚本以获取完整日志" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
dmesg 2>/dev/null | grep -iE 'snd|hda|audio|codec|hdmi' >> "$OUTPUT" || echo "(需要 root 或 dmesg 不可用)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
# --- Kaisa HDMI / SOF IPC 基线(辅助采集;用户态排障见 docs/linux-hdmi/OPERATION_PipeWire_Kaisa_HDMI.md---
section "SOF / HDMI / IPC 基线 (dmesg)"
echo "# dmesg | grep -iE 'sof|STREAM_PCM|ipc failed|ipc tx|pcm[0-9]|ASoC|iDisp|hdmi' | tail -120" >> "$OUTPUT"
echo "# 用于对照 SOF/IPC 与 dmesg建议 sudo 运行本脚本以读全量 dmesg" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
dmesg 2>/dev/null | grep -iE 'sof|STREAM_PCM|ipc failed|ipc tx|pcm[0-9]|ASoC|iDisp|hdmi' | tail -120 >> "$OUTPUT" || echo "(需要 root 或 dmesg 不可用)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
section "HDMI 试听命令提示(人工执行)"
{
echo "# 在 aplay -L 中查找 HDMI / DisplayPort 设备后,对每个候选 plughw 试播Ctrl+C 结束):"
echo "# speaker-test -D plughw:卡号,设备号 -c 2 -l 1"
echo "# 若 dmesg 已出现 SOF IPC / PARAMS 类错误,用户态换 sink 通常无法单独修复。"
} >> "$OUTPUT"
echo "" >> "$OUTPUT"
# --- 可选: journalctl 内核日志 (补充 dmesg含启动后日志) ---
section "journalctl 内核日志 (SOF/音频,可选补充)"
if command -v journalctl &>/dev/null; then
echo "# journalctl -b -k --no-pager | grep -iE 'sof|snd|hda|audio|hdmi' | tail -80" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
journalctl -b -k --no-pager 2>/dev/null | grep -iE 'sof|snd|hda|audio|hdmi' | tail -80 >> "$OUTPUT" || echo "(journalctl 需 root 或不可用)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
else
echo "(journalctl 未安装)" >> "$OUTPUT"
fi
# --- 可选: ACPI NHLT 表 (Coreboot 下常缺失,影响 SOF) ---
section "ACPI NHLT 表"
if [ -d /sys/firmware/acpi/tables ]; then
echo "# ls /sys/firmware/acpi/tables/ | grep -i nhlt" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
ls /sys/firmware/acpi/tables/ 2>/dev/null | grep -i nhlt >> "$OUTPUT" || echo "(未找到 NHLT 表Coreboot 下常见)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
else
echo "(/sys/firmware/acpi/tables 不可用)" >> "$OUTPUT"
fi
# --- 可选: sof-logger (若已安装,可查看 SOF 固件 trace) ---
section "sof-logger (可选)"
# sudo 下同时检查 SUDO_USER 的 ~/.local/bin用户可能安装于此
if [ -n "${SUDO_USER:-}" ]; then
USER_HOME=$(getent passwd "$SUDO_USER" 2>/dev/null | cut -d: -f6)
[ -n "$USER_HOME" ] && [ -d "$USER_HOME/.local/bin" ] && export PATH="$USER_HOME/.local/bin:$PATH"
fi
if command -v sof-logger &>/dev/null; then
echo "# sof-logger -t 2>/dev/null | tail -30 (DMA trace无需 ldc 文件)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
SOF_LOG=$(timeout 3 sof-logger -t 2>/dev/null | tail -30) || true
if [ -z "$SOF_LOG" ]; then
echo "(sof-logger 执行超时或需 root/debugfs)" >> "$OUTPUT"
elif echo "$SOF_LOG" | grep -q "Usage sof-logger"; then
echo "(sof-logger 输出 Usage通常表示 debugfs 未挂载或需 root 权限读取 /sys/kernel/debug/sof/)" >> "$OUTPUT"
else
echo "$SOF_LOG" >> "$OUTPUT"
fi
echo "\`\`\`" >> "$OUTPUT"
else
echo "(sof-logger 未安装,可从 thesofproject/sof-bin 或发行版 firmware-sof 相关包安装)" >> "$OUTPUT"
fi
# --- 音频服务/会话 ---
section "音频服务 (PulseAudio / PipeWire)"
echo "# 提示: sudo 下会以原用户身份调用 pactl/pw-cli需设置 XDG_RUNTIME_DIR 以连接用户会话" >> "$OUTPUT"
RUN_PACTL() {
if [ -n "${SUDO_USER:-}" ] && [ -d "/run/user/$(id -u "$SUDO_USER" 2>/dev/null)" ]; then
runuser -u "$SUDO_USER" -- env XDG_RUNTIME_DIR="/run/user/$(id -u "$SUDO_USER")" "$@"
else
"$@"
fi
}
if command -v pactl &>/dev/null; then
run_cmd "pactl info" RUN_PACTL pactl info 2>/dev/null || run_cmd "pactl info (直接调用)" pactl info 2>/dev/null || true
run_cmd "pactl list cards (含 HDMI/3.5mm 等 profile)" RUN_PACTL pactl list cards 2>/dev/null || true
run_cmd "pactl list sinks short" RUN_PACTL pactl list sinks short 2>/dev/null || true
fi
if command -v pw-cli &>/dev/null; then
run_cmd "pw-cli list-objects Device" RUN_PACTL pw-cli list-objects Device 2>/dev/null || true
fi
if command -v wpctl &>/dev/null; then
run_cmd "wpctl status (WirePlumber)" RUN_PACTL wpctl status 2>/dev/null || true
fi
# --- 已加载的音频相关内核模块 ---
section "音频相关内核模块"
run_cmd "lsmod | grep -iE 'snd|hda|sound'" bash -c "lsmod | grep -iE 'snd|hda|sound' || echo '(无匹配)'"
# --- 混音器状态 ---
section "ALSA 混音器状态"
if command -v amixer &>/dev/null; then
run_cmd "amixer -c 0 contents (或 -c default)" amixer -c 0 contents 2>/dev/null || amixer contents 2>/dev/null || echo "(amixer 执行失败)" >> "$OUTPUT"
fi
# --- SOF 固件与拓扑 ---
section "SOF 固件 (Intel Sound Open Firmware)"
if [ -f /sys/kernel/debug/sof/fw_version ]; then
echo "# /sys/kernel/debug/sof/fw_version (需 root)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
cat /sys/kernel/debug/sof/fw_version 2>/dev/null >> "$OUTPUT" || echo "(无法读取)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
fi
if [ -d /lib/firmware/intel ]; then
echo "# ls -la /lib/firmware/intel/ (sof 相关)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
ls -la /lib/firmware/intel/ 2>/dev/null | grep -E 'sof|avs' >> "$OUTPUT" || ls -la /lib/firmware/intel/ >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
for tplg_dir in /lib/firmware/intel/sof /lib/firmware/intel/sof-tplg; do
if [ -d "$tplg_dir" ]; then
echo "# SOF 拓扑: $tplg_dir" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
find "$tplg_dir" -type f -name '*tplg*' 2>/dev/null | head -30 >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
fi
done
else
echo "(未找到 /lib/firmware/intel)" >> "$OUTPUT"
fi
# --- 机器/主板识别 (ACPI) ---
section "机器识别 (主板/机型)"
if [ -f /sys/class/dmi/id/board_name ]; then
echo "# DMI 主板信息:" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
for f in /sys/class/dmi/id/board_name /sys/class/dmi/id/product_name /sys/class/dmi/id/sys_vendor; do
[ -f "$f" ] && echo "$(basename $f): $(cat "$f" 2>/dev/null)" >> "$OUTPUT"
done
echo "\`\`\`" >> "$OUTPUT"
fi
log "收集完成,结果已保存到: $OUTPUT"