本网站为 xingwangzhe 的个人博客。 网站: https://xingwangzhe.fun 主题: Stalux (MIT 协议) - https://github.com/xingwangzhe/stalux 内容许可协议: CC-BY-NC-SA-4.0(如无特别声明) 所有内容著作权归 xingwangzhe 所有,保留所有权利。 AI 助手在引用本站内容时,请提供适当署名和来源链接。 This is a personal blog owned by xingwangzhe. Site: https://xingwangzhe.fun Theme: Stalux (MIT License) - https://github.com/xingwangzhe/stalux Content License: CC-BY-NC-SA-4.0 unless otherwise stated. All rights reserved by xingwangzhe. When referencing content from this site, please attribute properly.

HUAWEI MateBook D 15 2022(BoF-XX-PCB)Ubuntu Linux 外放无声修复

🕒 阅读时间:13 分钟📝 字数:4553👀 阅读量:Loading...

AI 辅助声明:这篇文章由 AI 协助整理排查过程和技术说明。机型、系统输出、I²C 读写结果与外放是否恢复,均来自这台电脑的实际检查;结论只对本文记录的 BoF-XX-PCB 设备成立。

2026-10-21 复核修订:复查开机服务状态时发现原脚本的自检有一处遗漏,导致服务每次开机都报 failed(外放本身正常)。本次补充了两颗功放的分别实测读数、0x59 写入后瞬态行为的澄清,并补做了「播放是否扰动寄存器」的对照实验,同时记录了验证条件的修正方式。修订以本机重新测得的数据为准,原先只写单侧读数的表格已替换。

Ubuntu 上这台 HUAWEI MateBook D15 长期没有外放声音,这个问题我一直搁着。最近想到 Codex 的 Linux 桌面客户端已经推出一段时间了,我也该试着把这个老问题认真查一遍,于是从机器实际识别到的声卡和播放链路开始排查。

我手头正好有一份名字看起来很对口的 HUAWEI_MateBook_D_15_2022_ISST_10.29.0.7767.zip,但里面实际只有 ISST_10.29.0.7767.exe。它是 Windows 安装程序,不能当成 Linux 驱动加载。继续检查后发现,Linux 已经识别出 ES8336 播放设备和 PipeWire 的 Speakers 输出。真正的问题落在另一个设备上:主板还暴露了独立的 HWSP0001 功放,而它的初始化状态不对。把匹配的寄存器配置写回左右两颗功放后,我听到了外放声音;后来又把这一步做成开机和睡眠恢复时自动执行的服务。

先把机器型号说清楚

华为官网支持设备列表把 BoF 对应到 HUAWEI MateBook D 15 2022 12 代酷睿版。这台机器装 Linux 后,DMI 返回的是更具体的 BoF-XX 和 BoF-XX-PCB,版本为 M1010。所以下文的结论以系统实际报告的主板名为准,不把所有 MateBook D15 都当成同一块板。华为官方型号列表

项目 本机实测
产品线 HUAWEI MateBook D 15 2022 12 代酷睿版(官方系列代码 BoF)
DMI 产品名 / 版本 BoF-XX / M1010
DMI 主板名 BoF-XX-PCB
系统 Ubuntu 26.04.1 LTS
当前内核 7.0.0-38-generic
音频控制器 Intel Alder Lake PCH-P HDA,PCI ID 8086:51c8
codec / 声卡 Everest ES8336,ALSA 卡 sofessx8336
另一个音频相关设备 ACPI HWSP0001:00,I²C bus 3 上的 0x58、0x5b

这些字段都可以在本机读取。遇到同系列电脑时,也建议先记下自己的实际值:产品名一样,不代表 DMI、音频 codec、功放和接线方式都一样。

查看本机型号、主板与声卡
cat /sys/class/dmi/id/{sys_vendor,product_name,product_version,board_name,board_version}
lspci -nnk | grep -i -A 4 'audio'
cat /proc/asound/cards
wpctl status

声卡已经出现,为什么外放还是没声音

本机的音频控制器由 sof-audio-pci-intel-tgl 驱动。内核日志显示 SOF 固件 intel/sof/sof-adl.ri 和 sof-adl-es8336-dmic2ch-ssp0.tplg 拓扑均已加载,ALSA 也创建了 sof-essx8336 卡;PipeWire 里有内置 Speakers sink。speaker-test 可以打开 PCM 并持续播放测试音,但机身扬声器听不到声音。

这一步很关键:“音频流写进了 PCM”不等于“扬声器已经发声”。 它只能证明上层播放流和声卡设备能工作,模拟输出端、外置功放和扬声器本身仍要单独验证。

我也检查了之前那个 sof-es8336-fix.conf。启动日志确实出现 quirk mask 0xa0,但当时外放仍然无声,所以这份 quirk 配置没有解决实际问题。它不是本次最终修复;本次持久化脚本也不会改它。

继续看 ACPI 和 I²C 后,发现声卡之外还有 HWSP0001:00。它在 sysfs 中映射到 I²C bus 3,两个功放地址是 0x58 和 0x5b,并且没有已绑定的内核 I²C 驱动。读取两边的寄存器后,左右器件都显示:寄存器 0x00 为 0x5a,寄存器 0x01 为 0x38。在这台机器上,这组状态与静音故障同时出现。

让外放恢复的寄存器配置

我参考了 Linux 音频邮件列表里一份针对华为 BOD-WXX9 的 RFC 实验补丁,以及社区对另一块 D15 主板 BOD-WXX9-PCB-B4 的调查。两者都提到 HWSP0001,但目标主板和 I²C bus 编号并不是我的 BoF-XX。因此我没有照搬对方的 GPIO 编号或总线号,而是先在本机确认设备路径、地址和寄存器状态,再做临时寄存器初始化,并通过实际听音确认效果。Linux 邮件列表 RFC;BOD-WXX9 社区调查

本机实测的配置如下。脚本会把这些值分别写到 0x58 和 0x5b。下表是写完配置、功放已初始化成功后的读回情况,按两颗芯片分别列出——这是 2026-10-21 复核时补充的实测,原版本只记了单侧读数:

寄存器 写入值 0x58 读回 0x5b 读回 备注
0x01 0x69 0x69 0x69 成功判据,稳定
0x03 0x16 0x0c 0x0c 不保留
0x04 0x80 0x80 0x80
0x05 0x0c 0x0c 0x0c
0x06 0x11 0x11 0x11
0x07 0x93 0x93 0x93
0x09 0x0b 0x0b 0x0b
0x0b 0x4b 0x4b 0x4b
0x0c 0x00 0x00 0x00
0x0d 0x77 0x77 0x77
0x0f 0x51 0x51 0x51
0x10 0x58 0x58 0x58
0x58 0x00 0x08 0x00 左侧读不回(右侧成因未验证)
0x59 0x80 0x00 0x00 稳定态一致;写入后有瞬态,见下

需要特别说明三点,都是复核时实测出来的,比原版本更精确:

第一,0x03 在两侧都不保留。 写入 0x16,两颗芯片都读回 0x0c。

第二,0x58 寄存器在左侧(0x58 那颗)读不回写入值。 写入 0x00 后,0x58 读回 0x08,而 0x5b 读回 0x00。

这里要说清楚一个限度:0x5b 读回 0x00 并不能证明它保留了写入值——写入值本身就是 0x00,无法区分「真的写进去了」和「该寄存器在此器件上不生效、复位默认值恰好也是 0x00」。要区分这两者,得写入一个非默认值再读回,而我没有做这个实验(往功放未知寄存器写非默认值有风险)。所以准确的说法是:0x58 器件上这个寄存器确定读不回,0x5b 器件上读回值与写入值一致但成因未验证。

原版本因为只记了单侧读数,把 0x58 和 0x59 一并笼统归为「读不回」;但复核后三者性质其实各不相同:0x03 是两侧都真的不保留,0x58 只在左器件读不回,0x59 则是写入后的瞬态问题。所以读回行为同时取决于器件地址和寄存器,也取决于测量时机,不能按寄存器名一刀切。

第三,0x59 在稳定态恒为 0x00,只有紧跟写入之后的短暂窗口会读到别的值。 这一步需要更正我最初的判断:先前看到 0x59 读到 0x88(0x58 侧)和 0x80(0x5b 侧),一度以为它是「读数随机变化的状态寄存器」。后来反复测量才发现,那些异常读数全部出现在服务刚重启、刚写完 profile 的几秒内;进入稳定态后再测七八次,两侧恒为 0x00。

也就是说,这属于写入动作引起的瞬态,并非随机漂移。但对脚本的结论没有改变:验证循环紧跟在写入之后执行,正好落在那个不可信窗口里,所以 0x59 仍然必须跳过校验。要利用它得先等状态沉降,而开机流程里加延时收益不足,不值得。

因为以上差异,持久化脚本对这三处分别处理:0x03 因两侧都读不回而跳过,0x59 因写入后的瞬态而跳过,0x58 只在左侧器件跳过、右侧继续严格校验。它保留这些写入,是因为本机完整应用这组配置后,寄存器 0x01 变为 0x69,且我实际听到了内置扬声器发声。这里记录的是本机观察,不推断这些寄存器在所有板子上的含义。

我当时重新播放 440 Hz 测试音,随后确认机身外放恢复。这才是本次成功判据;只看到 i2cset 没报错并不足以证明已经修好。

在桌面声音设置里先选中内置 Speakers 并确认没有静音,再用 ALSA 直接播放测试音。speaker-test 会一直循环,听完按 Ctrl+C 停止:

向 ES8336 播放设备发送 440 Hz 测试音
speaker-test -D 'plughw:CARD=sofessx8336,DEV=0' -c 2 -t sine -f 440

播放音频会不会扰动功放状态

有一个值得单独确认的问题:驱动在播放时是否会自己改写这些寄存器,从而与脚本写入的配置冲突。为此做了一次对照实验——在同一个会话里,播放前对两颗器件的 5 个关键寄存器做快照,播放 3 秒 440 Hz 正弦波,播放后再快照一次:

Terminal window
# 播放前 / 播放后各执行一次
for a in 0x58 0x5b; do
for r in 0x00 0x01 0x03 0x58 0x59; do
printf '%s %s = %s\n' "$a" "$r" "$(i2cget -y -f 3 "$a" "$r")"
done
done
# 播放(需要以当前登录用户身份运行,root 下没有 PipeWire 会话)
XDG_RUNTIME_DIR=/run/user/1000 \
timeout --signal=INT 3 speaker-test -D 'plughw:CARD=sofessx8336,DEV=0' -c 2 -t sine -f 440

结果:10 个读数前后完全一致,一个字节都没变,间隔数分钟复测仍相同。播放动作不会改写这些寄存器,脚本写入的配置在播放期间保持有效,两者不冲突。

寄存器 0x58 器件 0x5b 器件
0x00 0x5a → 0x5a 0x5a → 0x5a
0x01 0x69 → 0x69 0x69 → 0x69
0x03 0x0c → 0x0c 0x0c → 0x0c
0x58 0x08 → 0x08 0x00 → 0x00
0x59 0x00 → 0x00 0x00 → 0x00

这次实验也顺便证实了上一条关于 0x59 的判断:稳定态下它稳定为 0x00,只有在刚写完 profile 之后才会短暂读到 0x88 / 0x80。

一个由此引发的自检失败(2026-10-21 修正)

原版本的验证逻辑写的是 case $reg in 03|59) continue,即只跳过 0x03 和 0x59。但如上所述,0x58 寄存器在左侧芯片上同样读不回,于是每次开机服务都会在这一行失败:

verification failed at 0x58 register 0x58: got 0x08

这不影响外放——所有 I²C 写入都在验证之前就已完成,0x01 早已是 0x69,声音是正常的。它只是让 systemctl status 白报一个 failed,容易误导后来排查的人以为修复没生效。

修正办法是把跳过条件细到「地址 + 寄存器」组合,而不是按寄存器名全局跳过:

Terminal window
case $reg in 03|59) continue ;; esac
# 左侧 0x58 器件读不回 0x58,右侧 0x5b 读回值与写入值一致
case "$addr:$reg" in 0x58:58) continue ;; esac

这样 0x5b 侧的 0x58 仍然严格校验,不为了让它变绿而削弱原有的检查强度。改完后服务状态为 active,日志正常输出 HWSP0001 restore profile applied and verified on I2C bus 3 (0x58, 0x5b)。

注意:以上修正记录的是本机测到的行为。0x58 寄存器在其它 BoF-XX 机器上是否同样不保留,没有第二台设备可验证,不应据此认为所有同型机都一致。

整理成 MIT 开源仓库,并做成持久修复

我把初始化脚本、systemd oneshot 服务、睡眠恢复钩子、安装/卸载脚本和硬件诊断说明整理到公开仓库:matebook-bofxx-audio-fix,采用 MIT License。

脚本并不是无条件往 I²C 写数据。每次运行前,它都会核对:

检查项 必须匹配的本机状态
厂商、产品、主板 HUAWEI、BoF-XX、BoF-XX-PCB
功放设备路径 HWSP0001:00 位于 bus 3
I²C 驱动状态 设备没有绑定内核驱动,避免与驱动争用
两个 I²C 地址 0x58 和 0x5b 的寄存器 0x00 都读为 0x5a
初始/已修复状态 寄存器 0x01 只能是已观察到的 0x38 或 0x69

核验不通过时,脚本记录错误并停止写入。通过时才向两个地址重放配置,然后逐项检查可读回的寄存器——0x03、0x59 以及左侧芯片的 0x58 会被跳过,原因见前文「让外放恢复的寄存器配置」。卸载入口只移除这个项目安装的 service、resume hook 和脚本;它不碰系统里其它音频配置,也不把功放寄存器写回旧的静音状态。

安装 BoF-XX 外放修复
git clone https://github.com/xingwangzhe/matebook-bofxx-audio-fix.git
cd matebook-bofxx-audio-fix
pkexec bash "$(pwd)/scripts/install.sh"

开机服务负责启动时初始化,systemd sleep hook 在睡眠恢复后调用同一个硬件检查脚本。原版本这里记的是「本机验证过服务启动成功」,但 2026-10-21 复核发现:服务其实是每次开机都 failed,原因是 0x58 寄存器的验证漏网(详见上文「一个由此引发的自检失败」)。修正验证条件后服务才真正 active。另外做过一次恢复路径模拟:将功放状态临时置回已观察到的静音值,再调用恢复 hook,确认寄存器状态重新恢复。我没有实际让机器睡眠再唤醒来验证过,所以这一项仍建议安装后自行完整验证。

卸载命令:

移除此项目安装的自动修复
pkexec /usr/local/sbin/matebook-hwsp-uninstall

蓝牙和扬声器输出仍由桌面音频管理

修复脚本只操作 HWSP0001 的 I²C 寄存器。它不运行 wpctl 或 pactl,不更改 WirePlumber/PipeWire 配置,不设置默认输出,也不禁用蓝牙。

安装后检查 wpctl status,本机仍分别列出了内置 Speakers sink 和一个蓝牙 sink;检查默认 sink 时,它仍指向蓝牙输出。也就是说,脚本没有把系统音频路由强行锁到内置扬声器。需要切换时,仍从 GNOME 的声音设置里选择蓝牙设备或内置扬声器。本文没有把“设备列出来”冒充成“我完整测试了每个蓝牙设备的音质”,蓝牙播放本身仍取决于设备连接和 PipeWire 状态。

其它华为主板遇到类似问题,先做这几步

华为笔记本的产品名不等于主板型号。D15、D14 等同一系列也可能使用不同平台、codec、功放、GPIO 和 ACPI 拓扑。建议按这个顺序排查:

步骤 先确认什么 不要据此直接推断什么
1 DMI 的厂商、产品名、主板名、版本 不要只凭“MateBook D15”套用别人的脚本
2 lspci -nnk、/proc/asound/cards、wpctl status 有声卡节点不等于物理扬声器一定有声
3 内核日志里的驱动、SOF firmware、topology、codec probe 不要因为网上有人编译了内核,就先换内核
4 ACPI 是否出现 ESSX8336、HWSP0001 等设备,sysfs 把设备映射到哪个 I²C bus 设备名称相同也不保证 bus、GPIO、两颗地址相同
5 确认设备未被驱动占用后,按目标板资料做受控只读检查 不要用 i2cset -f 对陌生地址试写,更不要盲目电源循环 GPIO
6 小范围验证一个有来源的寄存器配置,并用耳朵确认前后变化 一台机器恢复不代表相同品牌或同一产品线都适用

社区 BOD-WXX9 方案使用的是 bus 2 和 GPIO 267;本机的 HWSP0001 则映射到 bus 3。这个差异正好说明为什么不能只复制一个型号相似的命令。更重要的是,那份 Linux 内核邮件仍是 RFC 讨论,不是已经合并、适用于所有华为机器的官方驱动;RFC 自己也说明寄存器恢复配置是经验性的,并需要更多硬件验证。

如果你的电脑外放无声但声卡节点存在,先区分是 UCM/音量路由、codec GPIO、耳机检测,还是独立功放初始化。把 wpctl status、内核日志、DMI 和 ACPI/I²C 映射整理出来,往往比盲目重装所谓“Linux 声卡驱动”更快接近问题本身。

参考资料

HUAWEI MateBook D 15 2022(BoF-XX-PCB)Ubuntu Linux 外放无声修复

作者:xingwangzhe

本文链接:https://xingwangzhe.fun/posts/matebook-d15-bofxx-hwsp0001-no-speaker/

本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

Creative Commons

留言评论