新内核固件缺失修复案例:WiFi + 声卡
开始操作前本人使用USB共享网络:
适用场景:在 Ubuntu 22.04 LTS 上升级主线内核(6.x+)后,WiFi 或声卡消失。
电脑信息
| 项目 | 详情 |
|---|---|
| 型号 | Lenovo 小新 Pro 16c IAH10 (XiaoXinPro-16c-IAH10) |
| 系统 | Ubuntu 22.04.5 LTS (Jammy) |
| 内核 | 6.12.95-061295-generic(自行升级的主线内核) |
| 网卡 | Intel Wi-Fi 6 AX201 160MHz (8086:7740) |
| 声卡 | Intel Arrow Lake Audio (8086:7728),Conexant SN6140 解码器 |
通用根因
两个问题本质相同:新内核的驱动需要新版固件,但 Ubuntu 22.04 的固件包太旧。
┌────────────────────────────────────────────────────┐
│ Ubuntu 22.04 LTS (2022.04 发布) │
│ ├── linux-firmware → 2022.03 版本 │
│ ├── firmware-sof-signed → 2.0 (2022 年) │
│ └── 内核 6.12 (2024.12) │
│ ├── iwlwifi 需要 API v90+ 固件 → 缺失! │
│ └── SOF 需要 Arrow Lake 固件 → 缺失! │
└────────────────────────────────────────────────────┘
一、WiFi 修复:Intel AX201 固件缺失 (bz-b0-hr-b0)
故障现象
- 系统只有有线网卡 (
enx0a10d7dd5f41),完全没有 WiFi 接口 nmcli device status看不到任何wlan0/wlp*设备ip link show无无线网卡rfkill list显示ideapad_wlan未被软/硬屏蔽
排查过程
1. 确认硬件存在
bash
$ lspci -nn -s 00:14.3
00:14.3 Network controller [0280]: Intel Corporation Device [8086:7740]
设备存在,PCI ID 为 8086:7740。
2. 检查驱动状态
bash
$ lsmod | grep iwlwifi
iwlwifi 647168 0 # ← 0 users,驱动没有绑定到设备
cfg80211 1413120 1 iwlwifi
$ nmcli device status
DEVICE TYPE STATE CONNECTION
enx0a10d7dd5f41 ethernet 已连接 有线连接 1
lo loopback 未托管 --
# 没有任何 WiFi 设备
iwlwifi 模块已加载但未被任何设备使用 --- 驱动识别了设备但固件加载失败后退出了。
3. 查看内核日志(关键!)
bash
$ cat /var/log/syslog | grep iwl
输出关键信息:
iwlwifi 0000:00:14.3: Detected Intel(R) Wi-Fi 6 AX201 160MHz
iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-bz-b0-hr-b0-93.ucode failed with error -2
iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-bz-b0-hr-b0-92.ucode failed with error -2
iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-bz-b0-hr-b0-91.ucode failed with error -2
iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-bz-b0-hr-b0-90.ucode failed with error -2
iwlwifi 0000:00:14.3: no suitable firmware found!
iwlwifi 0000:00:14.3: minimum version required: iwlwifi-bz-b0-hr-b0-90
iwlwifi 0000:00:14.3: maximum version supported: iwlwifi-bz-b0-hr-b0-93
iwlwifi 0000:00:14.3: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
- 驱动需要
bz-b0-hr-b0固件 API 版本 v90-v93 - 内核按 93→92→91→90 顺序尝试加载,全部失败(
error -2= 文件不存在)
4. 确认本地固件缺失
bash
$ ls /lib/firmware/iwlwifi-bz*
iwlwifi-bz-b0-fm-c0-92.ucode iwlwifi-bz-b0-fm-c0.pnvm
iwlwifi-bz-b0-fm-c0-94.ucode iwlwifi-bz-b0-gf-a0-92.ucode
iwlwifi-bz-b0-fm-c0-96.ucode iwlwifi-bz-b0-gf-a0-94.ucode
iwlwifi-bz-b0-gf-a0-96.ucode
iwlwifi-bz-b0-gf-a0.pnvm
系统只有 fm-c0(FM Radio)和 gf-a0(Gale Force)变体固件,缺少 hr-b0(Harrison Peak)变体。
bash
$ apt-cache policy linux-firmware
已安装:20220329.git681281e4-0ubuntu3.42 # 2022 年 3 月版本,太旧
5. 尝试过的失败方案
| 方案 | 结果 | 原因 |
|---|---|---|
git clone linux-firmware.git |
❌ 超时 | kernel.org 在国内极慢,100s 仅下载 280KB,总量 >1GB |
curl kernel.org /plain/ 端点 |
❌ 404 | git.kernel.org 的 cgit 不给二进制固件文件返回 200 |
curl GitHub 镜像 |
❌ 无法访问 | github.com 无响应 |
Symlink gf-a0→hr-b0 |
❌ 超时 | Failed to start RT ucode: -110 (ETIMEDOUT),RF 模块硬件不兼容 |
6. 成功方案
从 Debian testing 下载 firmware-iwlwifi 包(仅 23MB,Tsighua 镜像速度快):
bash
# 下载
curl -L "https://mirrors.tuna.tsinghua.edu.cn/debian/pool/non-free-firmware/f/firmware-nonfree/firmware-iwlwifi_20260519-1_all.deb" \
-o /tmp/firmware-iwlwifi.deb
# 提取
dpkg-deb -x /tmp/firmware-iwlwifi.deb /tmp/fw-extract/
# 安装正确变体 + 版本的固件
sudo cp /tmp/fw-extract/usr/lib/firmware/intel/iwlwifi/iwlwifi-bz-b0-hr-b0-93.ucode /lib/firmware/
sudo cp /tmp/fw-extract/usr/lib/firmware/intel/iwlwifi/iwlwifi-bz-b0-hr-b0.pnvm /lib/firmware/
# 重载驱动
sudo modprobe -r iwlwifi
sudo modprobe iwlwifi
修复验证
bash
$ dmesg | grep iwl | tail -10
iwlwifi: loaded firmware version 93.26a2cb89.0 bz-b0-hr-b0-93.ucode op_mode iwlmvm
iwlwifi: Detected RF HR B3, rfid=0x10a100
iwlwifi: base HW address: f8:cf:52:bc:41:ed
wlp0s20f3: renamed from wlan0
iwlwifi: Registered PHC clock: iwlwifi-PTP, with index: 0
$ nmcli device status
DEVICE TYPE STATE CONNECTION
enx0a10d7dd5f41 ethernet 已连接 有线连接 1
wlp0s20f3 wifi 已断开 -- # ← WiFi 接口出现!
p2p-dev-wlp0s20f3 wifi-p2p 已断开 --
lo loopback 未托管 --
WiFi 根因分析
┌─────────────────────────────────────────────────────┐
│ Intel AX201 网卡有 3 种 RF 模块变体: │
│ │
│ FM (FM Radio) → iwlwifi-bz-b0-fm-c0-*.ucode │
│ GF (Gale Force) → iwlwifi-bz-b0-gf-a0-*.ucode │
│ HR (Harrison Peak) → iwlwifi-bz-b0-hr-b0-*.ucode ← 这台机器 │
│ │
│ 不同 RF 变体固件互不兼容(硬件射频前端不同) │
└─────────────────────────────────────────────────────┘
| 层级 | 问题 |
|---|---|
| 直接原因 | 硬盘上没有 iwlwifi-bz-b0-hr-b0-*.ucode 固件文件 |
| 为什么其它 AX201 机器没问题 | 大多数 AX201 使用 FM 或 GF 射频模块,Ubuntu 22.04 的 linux-firmware 包含这些变体,但没包含 HR 变体 |
| 根本原因 | 自行升级的 6.12 主线内核需要新版固件(API v90+),Ubuntu 22.04 官方 linux-firmware 包版本为 2022 年 3 月,太旧且缺 HR 变体 |
WiFi 固件命名规则解读
以 iwlwifi-bz-b0-hr-b0-93.ucode 为例:
| 字段 | 含义 |
|---|---|
iwlwifi |
Intel WiFi 固件前缀 |
bz |
平台代号:Bz (Bazaar),对应 AX201/AX211 系列 |
b0 |
硅晶片步进版本 B0 |
hr |
RF 射频模块类型:HR = Harrison Peak |
b0 |
RF 模块步进版本 B0 |
93 |
固件 API 版本号 |
二、声卡修复:SOF 固件缺失 (Arrow Lake)
故障现象
- 系统设置中无声音输出/输入设备
- PulseAudio 只有
auto_null(伪输出),没有真实声卡 aplay -l/arecord -l报 "找不到音效卡"cat /proc/asound/cards显示 "--- no soundcards ---"
排查过程
1. 确认硬件存在
bash
$ lspci -nn | grep audio
00:1f.3 Multimedia audio controller [0401]: Intel Corporation Device [8086:7728]
设备存在,PCI ID 为 8086:7728。
2. 检查驱动状态
bash
$ lsmod | grep sof
snd_sof_pci_intel_mtl 40960 0 # SOF 驱动已加载但 0 用户
snd_sof_intel_hda_generic 36864 1
...
snd_hda_intel 65536 0 # HDA 传统驱动也是 0 用户
SOF 和 HDA 驱动都已加载但未绑定到设备。
3. 查看内核日志(关键!)
bash
$ sudo dmesg | grep -i sof
输出关键信息:
sof-audio-pci-intel-mtl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if 0x040100
sof-audio-pci-intel-mtl 0000:00:1f.3: DMICs detected in NHLT tables: 2
sof-audio-pci-intel-mtl 0000:00:1f.3: SOF firmware and/or topology file not found.
sof-audio-pci-intel-mtl 0000:00:1f.3: Supported default profiles
sof-audio-pci-intel-mtl 0000:00:1f.3: - ipc type 1 (Requested):
sof-audio-pci-intel-mtl 0000:00:1f.3: Firmware file: intel/sof-ipc4/arl/sof-arl.ri
sof-audio-pci-intel-mtl 0000:00:1f.3: Topology file: intel/sof-ace-tplg/sof-hda-generic-2ch.tplg
sof-audio-pci-intel-mtl 0000:00:1f.3: Check if you have 'sof-firmware' package installed.
sof-audio-pci-intel-mtl 0000:00:1f.3: error: sof_probe_work failed err: -2
- 驱动需要
intel/sof-ipc4/arl/sof-arl.ri--- Arrow Lake 固件 - 需要
intel/sof-ace-tplg/sof-hda-generic-2ch.tplg--- 拓扑文件 error: -2=ENOENT(文件不存在)
4. 确认本地固件缺失
bash
$ ls /lib/firmware/intel/sof-ipc4/arl/
ls: 无法访问 '/lib/firmware/intel/sof-ipc4/arl/': 没有那个文件或目录
# 系统只有 MTL (Meteor Lake) 固件,缺 ARL (Arrow Lake)
$ ls /lib/firmware/intel/sof-ipc4/
mtl # 只有 Meteor Lake
$ apt-cache policy firmware-sof-signed
已安装:2.0-1ubuntu4.7 # 2022 年版本,不包含 Arrow Lake
5. 成功方案
ARL 固件实际上就是 MTL 固件 --- Arrow Lake 和 Meteor Lake 共享相同的 DSP 固件二进制。新版 firmware-sof-signed 包的做法是创建符号链接。
bash
# 创建 ARL 固件目录
sudo mkdir -p /lib/firmware/intel/sof-ipc4/arl/{intel-signed,community}
# 创建符号链接到已有 MTL 固件
sudo ln -sf intel-signed/sof-arl.ri /lib/firmware/intel/sof-ipc4/arl/sof-arl.ri
sudo ln -sf ../../mtl/intel-signed/sof-mtl.ri /lib/firmware/intel/sof-ipc4/arl/intel-signed/sof-arl.ri
sudo ln -sf ../../mtl/community/sof-mtl.ri /lib/firmware/intel/sof-ipc4/arl/community/sof-arl.ri
# 重载 SOF 驱动
sudo modprobe -r snd_sof_pci_intel_mtl snd_sof_intel_hda_common snd_sof
sudo modprobe snd_sof_pci_intel_mtl
修复验证
bash
$ cat /proc/asound/cards
0 [sofhdadsp ]: sof-hda-dsp - sof-hda-dsp
LENOVO-83ND-XiaoXinPro16cIAH10-LNVNB161216
$ aplay -l
card 0: sofhdadsp [sof-hda-dsp], device 0: HDA Analog (*) [] # 扬声器
card 0: sofhdadsp [sof-hda-dsp], device 3: HDMI1 (*) [] # HDMI
card 0: sofhdadsp [sof-hda-dsp], device 4: HDMI2 (*) []
card 0: sofhdadsp [sof-hda-dsp], device 5: HDMI3 (*) []
card 0: sofhdadsp [sof-hda-dsp], device 31: Deepbuffer HDA Analog (*) []
$ arecord -l
card 0: sofhdadsp [sof-hda-dsp], device 0: HDA Analog (*) [] # 模拟麦克风
card 0: sofhdadsp [sof-hda-dsp], device 6: DMIC Raw (*) [] # 数字麦克风
dmesg 确认:
sof-audio-pci-intel-mtl: Loaded firmware library: ADSPFW, version: 2.8.1.1
sof-audio-pci-intel-mtl: Booted firmware version: 2.8.1.1
snd_hda_codec_conexant ehdaudio0D0: SN6140: BIOS auto-probing.
snd_hda_codec_conexant ehdaudio0D0: autoconfig for SN6140:
line_outs=1 (0x17/...) type:speaker
hp_outs=1 (0x16/...) # 耳机
inputs: Mic=0x19 # 麦克风
声卡根因分析
| 层级 | 问题 |
|---|---|
| 直接原因 | /lib/firmware/intel/sof-ipc4/arl/ 目录不存在 |
| 为什么其他 Meteor Lake 机器没问题 | MTL 固件存在,且 ARL 固件就是 MTL 的符号链接 |
| 根本原因 | 内核 6.12 的 SOF 驱动根据 PCI ID (8086:7728) 判定为 Arrow Lake 平台,需要 arl/ 路径的固件;Ubuntu 22.04 的 firmware-sof-signed (v2.0) 不包含 Arrow Lake 目录 |
SOF 固件目录结构
/lib/firmware/intel/sof-ipc4/
├── mtl/ # Meteor Lake(已有)
│ ├── sof-mtl.ri → intel-signed/sof-mtl.ri
│ ├── intel-signed/
│ │ └── sof-mtl.ri # 实际固件二进制 (879KB)
│ └── community/
│ └── sof-mtl.ri
│
└── arl/ # Arrow Lake(需创建)
├── sof-arl.ri → intel-signed/sof-arl.ri
├── intel-signed/
│ └── sof-arl.ri → ../../mtl/intel-signed/sof-mtl.ri # → MTL 固件
└── community/
└── sof-arl.ri → ../../mtl/community/sof-mtl.ri
关键经验
通用原则
-
升级主线内核后必须同步升级固件:新驱动需要新版固件,旧发行版的固件包往往不匹配
-
Ubuntu 22.04 的固件包普遍偏旧(均为 2022 年版本):
linux-firmware→20220329firmware-sof-signed→2.0
对于 2023+ 的 Intel 硬件平台,需要从 Debian testing 获取更新固件
-
Debian 的拆分固件包是更好的下载源:
firmware-iwlwifi(23MB)vs 整个linux-firmwarerepo(>1GB)firmware-sof-signed(2MB)包含完整的 SOF 固件
-
排查固件问题的标准流程:
bash# 1. 确认硬件 lspci -nn | grep -iE "network|audio" # 2. 看内核日志(关键!) sudo dmesg | grep -iE "iwlwifi|sof|firmware" # 3. 对比固件文件 ls /lib/firmware/iwlwifi-* # WiFi ls /lib/firmware/intel/sof-ipc4/*/ # 声卡 # 4. 检查固件包版本 apt-cache policy linux-firmware firmware-sof-signed
WiFi 专项
- RF 变体必须完全匹配 :
fm-c0/gf-a0/hr-b0是不同射频硬件,固件不通用 - WiFi 固件命名格式:
iwlwifi-{平台}-{芯片步进}-{RF类型}-{RF步进}-{API版本}.ucode
声卡专项
- SOF 固件跨平台共享:Arrow Lake 和 Meteor Lake 使用相同 DSP 固件,通过符号链接即可
- 声卡固件路径:
intel/sof-ipc4/{平台}/sof-{平台}.ri+ 拓扑文件intel/sof-ace-tplg/sof-hda-generic-*.tplg
一键修复脚本
见 fix-firmware.sh,可自动诊断并修复常见的固件缺失问题。
bash
chmod +x fix-firmware.sh
sudo ./fix-firmware.sh
脚本内容:
#!/bin/bash
#=============================================================================
# fix-firmware.sh --- 一键诊断并修复 Intel WiFi / 声卡固件缺失问题
#
# 适用场景:
# - Ubuntu/Debian 系统,自行升级了主线内核
# - WiFi 消失(iwlwifi 固件缺失)
# - 声卡消失(SOF 固件缺失)
#
# 用法:
# sudo ./fix-firmware.sh # 自动诊断并修复
# sudo ./fix-firmware.sh --dry-run # 仅诊断,不修复
# sudo ./fix-firmware.sh --wifi # 仅修复 WiFi
# sudo ./fix-firmware.sh --audio # 仅修复声卡
#=============================================================================
set -euo pipefail
# --- 颜色定义 ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# --- 配置 ---
DEBIAN_MIRROR="${DEBIAN_MIRROR:-https://mirrors.tuna.tsinghua.edu.cn/debian}"
FIRMWARE_IWLWIFI_URL="${DEBIAN_MIRROR}/pool/non-free-firmware/f/firmware-nonfree/firmware-iwlwifi_20260519-1_all.deb"
FIRMWARE_SOF_URL="${DEBIAN_MIRROR}/pool/non-free-firmware/f/firmware-sof/firmware-sof-signed_2025.12.2-2_all.deb"
TEMP_DIR=$(mktemp -d)
DRY_RUN=false
FIX_WIFI=true
FIX_AUDIO=true
FOUND_ISSUES=0
FIXED_ISSUES=0
# --- 辅助函数 ---
cleanup() {
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
log_section() { echo -e "\n${BOLD}${CYAN}═══ $* ═══${NC}"; }
check_root() {
if [ "$(id -u)" -ne 0 ]; then
log_error "请用 sudo 运行此脚本:sudo $0 $*"
exit 1
fi
}
need_download() {
# 检查系统是否能联网下载
if ! command -v curl &>/dev/null && ! command -v wget &>/dev/null; then
log_warn "未找到 curl 或 wget,将跳过需要下载的操作"
return 1
fi
return 0
}
download() {
local url="$1" output="$2"
if command -v curl &>/dev/null; then
curl -sL --max-time 120 "$url" -o "$output"
elif command -v wget &>/dev/null; then
wget -q --timeout=120 "$url" -O "$output"
fi
}
# --- WiFi 诊断与修复 ---
diagnose_wifi() {
log_section "WiFi 固件诊断"
# 1. 找出所有 Intel WiFi PCI 设备
local wifi_devs
wifi_devs=$(lspci -nn 2>/dev/null | grep -i "Network controller.*Intel" || true)
if [ -z "$wifi_devs" ]; then
log_info "未检测到 Intel WiFi 硬件,跳过 WiFi 诊断"
return 0
fi
echo "$wifi_devs" | while read -r line; do
echo -e " ${line}"
done
# 2. 快速检查:WiFi 接口是否已存在?
# 如果接口已经正常工作,就不需要看历史 dmesg(旧日志可能误报)
if ip link show 2>/dev/null | grep -q "wl"; then
local wl_iface
wl_iface=$(ip link show 2>/dev/null | grep -oP 'wl[^ :]+' | head -1)
log_ok "WiFi 接口已存在 ($wl_iface),驱动工作正常,跳过"
return 0
fi
# 3. WiFi 接口不存在 → 检查 iwlwifi 模块
if ! lsmod | grep -q iwlwifi; then
log_info "iwlwifi 模块未加载,尝试加载..."
modprobe iwlwifi 2>/dev/null || true
sleep 2
fi
# 4. 从 dmesg 提取缺失的固件文件名
# 用本次启动后产生的日志(取最后出现的错误,避免旧日志干扰)
local missing_fw
missing_fw=$(dmesg 2>/dev/null | grep "iwlwifi.*Direct firmware load for.*failed" \
| grep -oP 'iwlwifi-[^ ]+\.ucode' | sort -u || true)
if [ -z "$missing_fw" ]; then
# 也检查 /var/log/syslog,只取最近的启动日志
missing_fw=$(grep "iwlwifi.*Direct firmware load for.*failed" /var/log/syslog 2>/dev/null \
| grep "$(uname -r)" | grep -oP 'iwlwifi-[^ ]+\.ucode' | sort -u || true)
fi
# 5. 对于找到的 "缺失" 固件,检查是否已经存在且只是 API 版本不同
# 例如 dmesg 说缺 -93,但 -96 已存在且驱动支持
if [ -n "$missing_fw" ]; then
local actually_missing=""
for fw in $missing_fw; do
# 检查这个文件是否现在已存在
if [ -f "/lib/firmware/$fw" ]; then
log_info "固件 $fw 已存在(可能已修复),跳过"
continue
fi
# 检查同前缀的其他版本是否存在
local fw_prefix fw_count
fw_prefix=$(echo "$fw" | sed -E 's/-[0-9]+\.ucode$//')
fw_count=$(ls "/lib/firmware/${fw_prefix}-"*.ucode 2>/dev/null | wc -l)
if [ "$fw_count" -gt 0 ]; then
log_info "固件 $fw 不存在,但有同系列其他版本,跳过"
continue
fi
actually_missing="$actually_missing $fw"
done
missing_fw=$(echo "$actually_missing" | xargs -r echo)
fi
# 6. 也检查 "no suitable firmware found" 错误
if [ -z "$missing_fw" ]; then
local no_suitable
no_suitable=$(dmesg 2>/dev/null | grep "iwlwifi.*no suitable firmware" | tail -1 || true)
if [ -n "$no_suitable" ]; then
log_warn "iwlwifi 报告 'no suitable firmware found'"
local max_ver
max_ver=$(dmesg 2>/dev/null | grep "maximum version supported:" | grep -oP 'iwlwifi-[^ ]+' | head -1 || true)
if [ -n "$max_ver" ] && [ ! -f "/lib/firmware/$max_ver" ]; then
missing_fw="$max_ver"
log_info "需要固件: $missing_fw"
fi
fi
fi
if [ -z "$missing_fw" ]; then
# 可能是模块重载后已修复,再检查一次 WiFi 接口
if ip link show 2>/dev/null | grep -q "wl"; then
log_ok "WiFi 接口已出现,修复成功"
return 0
fi
log_info "未检测到明确的 WiFi 固件缺失,跳过"
return 0
fi
echo -e "\n${YELLOW}检测到缺失的 WiFi 固件文件:${NC}"
for fw in $missing_fw; do
echo -e " ${RED}✗${NC} $fw"
done
FOUND_ISSUES=$((FOUND_ISSUES + 1))
# 提取固件前缀(去除版本号),确定需要的 pnvm 文件
local fw_prefix
fw_prefix=$(echo "$missing_fw" | head -1 | sed -E 's/-[0-9]+\.ucode$//')
echo -e "\n${YELLOW}将修复以下固件文件:${NC}"
echo " → ${fw_prefix}-*.ucode 系列"
echo " → ${fw_prefix}.pnvm (射频配置)"
if [ "$DRY_RUN" = true ]; then
log_info "[DRY RUN] 将下载 firmware-iwlwifi 包并安装缺失的固件"
return 0
fi
if ! need_download; then
log_warn "无法联网下载,跳过 WiFi 固件修复"
return 1
fi
# 下载 firmware-iwlwifi Debian 包
log_info "下载 firmware-iwlwifi 包 (~23MB)..."
local deb_file="$TEMP_DIR/firmware-iwlwifi.deb"
if ! download "$FIRMWARE_IWLWIFI_URL" "$deb_file"; then
log_error "下载失败,请检查网络连接"
return 1
fi
log_ok "下载完成 ($(du -h "$deb_file" | cut -f1))"
# 提取并安装固件
log_info "提取并安装固件..."
local extract_dir="$TEMP_DIR/iwlwifi-extract"
mkdir -p "$extract_dir"
dpkg-deb -x "$deb_file" "$extract_dir" 2>/dev/null
# 查找需要的固件文件
local installed=0
local fw_base
fw_base=$(echo "$missing_fw" | head -1)
# 先查找所有匹配的 .ucode 文件
local found_files
found_files=$(find "$extract_dir" -name "${fw_prefix}*.ucode" -o -name "${fw_prefix}*.pnvm" 2>/dev/null || true)
if [ -z "$found_files" ]; then
log_warn "下载的包中未找到 ${fw_prefix}* 固件,尝试查找最接近的版本..."
# 显示包里有什么
find "$extract_dir" -name "iwlwifi-*${fw_prefix##iwlwifi-}*" 2>/dev/null | head -10 || true
log_info "可用的 hr/gf/fm 变体:"
find "$extract_dir" -name "iwlwifi-*" 2>/dev/null | grep -oP 'iwlwifi-[^-]+-[^-]+-[^-]+-[^-]+' | sort -u | head -20
fi
for fw_file in $found_files; do
local fname
fname=$(basename "$fw_file")
cp "$fw_file" "/lib/firmware/$fname"
log_ok "已安装: $fname"
installed=$((installed + 1))
done
if [ "$installed" -eq 0 ]; then
log_error "未找到匹配的固件文件"
log_info "请手动从以下地址下载:"
log_info " https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git"
return 1
fi
# 重载 iwlwifi 模块
log_info "重载 iwlwifi 模块..."
modprobe -r iwlwifi 2>/dev/null || true
sleep 1
modprobe iwlwifi 2>/dev/null || true
sleep 3
# 验证
if ip link show 2>/dev/null | grep -q "wl"; then
local wl_iface
wl_iface=$(ip link show 2>/dev/null | grep -oP 'wl[^ :]+' | head -1)
log_ok "WiFi 接口已出现: $wl_iface"
FIXED_ISSUES=$((FIXED_ISSUES + 1))
else
log_warn "WiFi 接口尚未出现,可能需要重启"
log_info "新的固件文件已安装:"
ls -la /lib/firmware/${fw_prefix}* 2>/dev/null
dmesg 2>/dev/null | grep -i iwl | tail -5
fi
}
# --- 声卡诊断与修复 ---
diagnose_audio() {
log_section "声卡固件诊断"
# 1. 找出 Intel 音频 PCI 设备
local audio_devs
audio_devs=$(lspci -nn 2>/dev/null | grep -i "Audio.*Intel" || true)
if [ -z "$audio_devs" ]; then
log_info "未检测到 Intel 音频硬件,跳过声卡诊断"
return 0
fi
echo "$audio_devs" | while read -r line; do
echo -e " ${line}"
done
# 2. 检查声卡是否存在
if [ -f /proc/asound/cards ] && grep -q "\[.*\]" /proc/asound/cards 2>/dev/null; then
local card_count
card_count=$(grep -c "\[" /proc/asound/cards 2>/dev/null || echo 0)
log_ok "已有 $card_count 张声卡在工作,跳过"
cat /proc/asound/cards 2>/dev/null | while read -r l; do echo " $l"; done
return 0
fi
# 3. 从 dmesg 检查 SOF 固件错误
local sof_err
sof_err=$(dmesg 2>/dev/null | grep "SOF firmware and/or topology file not found" || true)
if [ -z "$sof_err" ]; then
sof_err=$(grep "SOF firmware and/or topology file not found" /var/log/syslog 2>/dev/null || true)
fi
if [ -z "$sof_err" ]; then
log_info "未检测到 SOF 固件错误,跳过"
return 0
fi
FOUND_ISSUES=$((FOUND_ISSUES + 1))
# 4. 提取需要的固件路径
local fw_path tplg_path fw_dir ipc_type
fw_path=$(dmesg 2>/dev/null | grep "Firmware file:" | grep sof | tail -1 | grep -oP 'intel/[^ ]+' || true)
tplg_path=$(dmesg 2>/dev/null | grep "Topology file:" | grep sof | tail -1 | grep -oP 'intel/[^ ]+' || true)
if [ -z "$fw_path" ]; then
fw_path=$(grep "Firmware file:" /var/log/syslog 2>/dev/null | grep sof | tail -1 | grep -oP 'intel/[^ ]+' || true)
fi
echo -e "\n${YELLOW}检测到 SOF 固件缺失:${NC}"
echo -e " ${RED}✗${NC} Firmware: $fw_path"
echo -e " ${YELLOW}?${NC} Topology: $tplg_path"
if [ -z "$fw_path" ]; then
log_warn "无法从 dmesg 提取固件路径"
return 1
fi
# 5. 分析固件路径,确定需要的平台
# 典型路径: intel/sof-ipc4/arl/sof-arl.ri
local platform fw_dir_name fw_file_name
fw_dir_name=$(dirname "/lib/firmware/$fw_path")
fw_file_name=$(basename "$fw_path")
platform=$(echo "$fw_path" | grep -oP 'sof-ipc4/\K[^/]+' || echo "unknown")
echo -e "\n${YELLOW}分析:${NC}"
echo " 平台: $platform"
echo " 目标路径: $fw_dir_name/"
echo " 固件文件: $fw_file_name"
# 6. 检查系统中是否有对应 IPC4 的其他平台固件可复用
local existing_dirs
existing_dirs=$(ls -d /lib/firmware/intel/sof-ipc4/*/ 2>/dev/null | grep -v "$platform" || true)
if [ -z "$existing_dirs" ]; then
log_warn "没有其他平台的 SOF 固件可复用"
if need_download; then
log_info "尝试从 Debian 下载 firmware-sof-signed..."
if [ "$DRY_RUN" = false ]; then
local deb_file="$TEMP_DIR/firmware-sof.deb"
if download "$FIRMWARE_SOF_URL" "$deb_file"; then
log_ok "下载完成 ($(du -h "$deb_file" | cut -f1))"
local sofe_dir="$TEMP_DIR/sof-extract"
mkdir -p "$sofe_dir"
dpkg-deb -x "$deb_file" "$sofe_dir" 2>/dev/null
# 复制整个 sof-ipc4 和 sof-ace-tplg 目录
if [ -d "$sofe_dir/usr/lib/firmware/intel/sof-ipc4" ]; then
cp -rn "$sofe_dir/usr/lib/firmware/intel/sof-ipc4/"* /lib/firmware/intel/sof-ipc4/ 2>/dev/null || true
log_ok "SOF IPC4 固件已安装"
fi
if [ -d "$sofe_dir/usr/lib/firmware/intel/sof-ipc4-tplg" ]; then
cp -rn "$sofe_dir/usr/lib/firmware/intel/sof-ipc4-tplg/"* /lib/firmware/intel/sof-ace-tplg/ 2>/dev/null || true
log_ok "SOF 拓扑文件已安装"
fi
else
log_error "下载失败,尝试手动修复..."
fi
fi
fi
fi
# 7. 检查是否可以通过创建符号链接修复
# SOF 的设计:同一代平台的 DSP 固件通常相同,新平台通过符号链接指向已有固件
local target_dir="/lib/firmware/intel/sof-ipc4/$platform"
if [ -d "$target_dir" ]; then
log_ok "目标目录已存在: $target_dir"
else
log_info "创建 $target_dir 目录..."
if [ "$DRY_RUN" = true ]; then
log_info "[DRY RUN] 将创建符号链接到已有 MTL 固件"
return 0
fi
# 找到一个已存在的参考平台(通常是 mtl)
local ref_platform=""
for ref in mtl lnl ptl; do
if [ -d "/lib/firmware/intel/sof-ipc4/$ref/intel-signed" ]; then
ref_platform="$ref"
break
fi
done
if [ -z "$ref_platform" ]; then
log_error "找不到参考平台固件,请手动安装 firmware-sof-signed 包"
return 1
fi
log_info "使用 $ref_platform 固件作为 $platform 的参考"
mkdir -p "$target_dir/intel-signed" "$target_dir/community"
# 创建符号链接
ln -sf "../../$ref_platform/intel-signed/sof-$ref_platform.ri" \
"$target_dir/intel-signed/sof-$platform.ri"
ln -sf "../../$ref_platform/community/sof-$ref_platform.ri" \
"$target_dir/community/sof-$platform.ri"
ln -sf "intel-signed/sof-$platform.ri" \
"$target_dir/sof-$platform.ri"
log_ok "已创建 $platform 固件符号链接 → $ref_platform"
# 显示目录结构
find "$target_dir" -type l -ls 2>/dev/null | while read -r l; do
echo " $l"
done
fi
# 重载 SOF 驱动
log_info "重载 SOF 驱动..."
for mod in snd_sof_pci_intel_mtl snd_sof_intel_hda_generic \
snd_sof_intel_hda_common snd_sof_intel_hda \
snd_sof_pci snd_sof snd_sof_utils snd_sof_intel_hda_mlink; do
modprobe -r "$mod" 2>/dev/null || true
done
sleep 1
modprobe snd_sof_pci_intel_mtl 2>/dev/null || true
sleep 3
# 验证
if [ -f /proc/asound/cards ] && grep -q "\[.*\]" /proc/asound/cards 2>/dev/null; then
log_ok "声卡已出现!"
cat /proc/asound/cards 2>/dev/null | while read -r l; do echo " $l"; done
aplay -l 2>&1 | grep -E "card|device" | head -10 | while read -r l; do echo " $l"; done
FIXED_ISSUES=$((FIXED_ISSUES + 1))
else
log_warn "声卡尚未出现,请检查 dmesg:"
dmesg 2>/dev/null | grep -iE "sof|snd.*audio" | tail -10 | while read -r l; do echo " $l"; done
fi
}
# --- 主流程 ---
main() {
echo -e "${BOLD}${CYAN}"
echo "╔══════════════════════════════════════════╗"
echo "║ Intel WiFi / 声卡 固件诊断修复工具 ║"
echo "║ fix-firmware.sh v1.0 ║"
echo "╚══════════════════════════════════════════╝"
echo -e "${NC}"
# 解析参数
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=true ;;
--wifi) FIX_AUDIO=false ;;
--audio) FIX_WIFI=false ;;
-h|--help)
echo "用法: sudo $0 [选项]"
echo ""
echo "选项:"
echo " --dry-run 仅诊断,不修复"
echo " --wifi 仅检查/修复 WiFi"
echo " --audio 仅检查/修复声卡"
echo " -h, --help 显示帮助"
exit 0
;;
*) log_error "未知参数: $1"; exit 1 ;;
esac
shift
done
check_root
if [ "$DRY_RUN" = true ]; then
echo -e "${YELLOW}[DRY RUN 模式] 仅诊断,不做任何修改${NC}\n"
fi
# 系统信息
echo -e "${BOLD}系统信息:${NC}"
echo " 发行版: $(lsb_release -ds 2>/dev/null || echo 'Unknown')"
echo " 内核: $(uname -r)"
echo " 架构: $(uname -m)"
echo ""
# 确保 /lib/firmware 存在
mkdir -p /lib/firmware/intel/sof-ipc4
mkdir -p /lib/firmware/intel/sof-ace-tplg
# 诊断
[ "$FIX_WIFI" = true ] && diagnose_wifi
[ "$FIX_AUDIO" = true ] && diagnose_audio
# 总结
log_section "诊断总结"
echo " 发现问题: $FOUND_ISSUES 个"
if [ "$DRY_RUN" = false ]; then
echo " 已修复: $FIXED_ISSUES 个"
fi
if [ "$FOUND_ISSUES" -eq 0 ]; then
log_ok "未发现固件问题,系统状态正常"
elif [ "$FIXED_ISSUES" -eq "$FOUND_ISSUES" ]; then
log_ok "所有问题已修复!"
echo ""
echo -e "${GREEN}${BOLD}建议重启系统以确保所有更改生效:${NC}"
echo " sudo reboot"
else
echo ""
echo -e "${YELLOW}部分问题未能自动修复,请查看上述日志${NC}"
echo ""
echo "手动修复参考:"
echo " 1. 安装更新的固件包:"
echo " sudo apt install linux-firmware firmware-sof-signed"
echo " 2. 或从 Debian 仓库下载手动安装:"
echo " $DEBIAN_MIRROR"
echo " 3. 或从 kernel.org 下载:"
echo " https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git"
fi
echo ""
}
main "$@"
修复日期:2026-07-07