workbuddy弄了三个小时,终于有声音了
一、症状
● 系统里能识别声卡 chtrt5645,aplay -l 也能列出来
● 播放任何东西都没声音,音量拉满、取消静音都无效
● 内核日志关键报错 :
ASoC: no backend DAIs enabled for Audio Port (-2 2)
CrOS 的音频栈是 CRAS(不是 PulseAudio/PipeWire),它认为自己正常工作了、hw_ptr 也在一路前进,但耳朵里什么都没有。这一点很迷惑人:"播放成功"不等于"出声 音"。
二、根因(两层,缺 一不可)
第一层:DAPM 图里 FE → BE 断链
ASoC 的音频路径是一张 DAP M 有向图:
PCM(前端 FE) → 平台 mixer → 后端 BE → I2S2 → RT564 5 codec
Cherry Trail 的 SST 平台驱动(snd_soc_sst_atom_hifi2_platform)里挂了 102 条 DAPM 路由,其中约 80 条是带 kcontrol 名字的 mixer 路由(上游宏 SST_SBA_MIXER_GRAPH_MAP 展开的那批)。
在这颗 ChromiumOS 定制内核上,这批带控件的 mixer 路由 全部注册失败 ,而且是静默失败:
● dmes g 里一条错误都没有
● 但 debugfs 里 dump 出的 DAPM 图,这些 widget 之间的连接根本不存在
● 结果 media0_out 收不到任何输入 → 后端 DAI 一个都没被使能 → -22 (EINVAL)
机器驱动 cht_rt5645.ko 自己那 6 条 ssp2_aif1_map 路由是能注册成功的(有验证),说明内核机制本身没坏,坏的是 SST 平台驱动那张表在这 个内核 ABI 下对不上。
第二层:数字链路通了,但 co dec 的模拟输出级是关着的
把第一层绕过之后,hw_ptr 会正常前进、CRAS 报告播放成功,但依然一点声音都没有。因为 RT5645 的模拟输出链还全是 off:
DAC1 → DAC1 MIX → Stereo DAC MIX → SPK MIX → SPKVOL → Ext Spk → 扬声器
↑ 全在这一段断掉
实测 Stereo DAC MIXL DAC L1 Switch / Stereo DAC MIXR DAC R1 Switch 都是 off,信号过了 DAC 就没了。所以必须再补 一套完整的 cod ec 混音初始化。
三、实现思路
1 . 给机器驱动打二进制补丁(绕过第一层)
不能改 SST 平台驱动(改不动那 80 条静默失败的路由),所以换个方向:在机器驱动里补 4 条"静态"(不带 kcontrol) 桥接路由,把 FE 和 BE 直接缝起来。
原版 ssp2_aif1_ma p 只有 6 条路由,扩到 10 条,新增:
media0 _out mix 0 ← media1_in
media 0_out mix 0 ← media3_in
co dec_out0 mix 0 ← pcm0_in
pcm1_out mix 0 ← codec_i n0
静态路由在内核上注册是成功的,链 路立刻通。
打补丁时的几个硬坑(想复现的话注意):
● 这是 ChromiumOS 内核,不是上游内核:struct snd_soc_dapm_route 在这里是 0x60 = 96 字节,不是上游的 24 字节。路由数组必须按 0x60 步长解码,否则全是垃圾。
● 模块是 relocatable 的,路由表里全是待重定位的指针。得从 .rela.ro data / .rela.data 反推每条路由的真实指向。
● 数组要扩容,就得把 .rodata 和 .rela.rodata 整体搬到文件末尾再追加,同时补 20 条 R_X86_64_64 重定位、修正 .rela.text 里的 add end、把 .text 里的路由条数立即数从 6 改成 10。
● insmod 前必须过 modu le version magic 校验,所以只能对同版本内核用。
结果:模块从 32448 字节变成 47008 字节,md5 4132556a0b5f92a74dada5520275 c39e。
2. 移植 kmyers 的混音序列(解决第二层)
kmyers 的 GPD Pocket ChromiumOS 项目 里有份 HiFi.conf,它的 EnableSequence 就是这台机器的正确初始化序列。把里面所有 cset 抽出来做成一个纯 amixer 脚本,共 92 条,覆盖:
● media 通路(media1_in / media0_out / pc m0_in / codec_out0 各级 Switch 和 Gain)
● codec 输入输出(codec_out0 mi x 0 pcm0_in、pcm1_out mix 0 codec_in0)
● 输出配置整段(DAC1 Mux / DAC1 MIX / Stereo DAC MIX / Mono DAC MIX / HPO M IX / SPK MIX / SPOL·SPOR MIX / SPKV OL)
● 设备级(Speaker / Headphone / Mic)
关键:HiFi.conf 里 # Output Configuration 那一段(我漏过一次)必须抄全,它就是第二层根因。 漏了它,你会得到"hw_ ptr 在跑、CRAS 说成功、耳朵里没声"的诡异状态。
3. 开机自动应用
Fy deOS 用的是 upstart(不是 systemd,没有 systemctl):
# /etc/init/g pd-audio -fix.conf
start on started cras
task
exec /usr/local/gpd-audio-fix.sh
start on started cras 而不是 s tartup —— 太早跑 amixer 会找不到声卡,全部静默失败。脚 本内部还加了两道保险:
● 等 /proc/asound/card0 出现(最多 90s)
● 等 pcm0p 进入 RUNNING(CR AS 真正把流开起来)再打 cset,失败自动重试
4. amixer 的一个引号陷阱(踩了很久)
#
整串包成单参数 → amixer: Wrong control identifier
amixer -c chtrt5645 cset “name= ‘Ext Spk Switch’ on”
#
只给 name= 那个词加引号,on 独立成参
amixer -c chtrt5645 cset ‘name=Ext Spk Switch’ on
加上 >/de v/null 2>&1 之后,错误全被吞掉,看起来像"没生 效",其实一条都没设上。调试时一定要把 stderr 放出来。
5. 别把"音量 调太小"当成故障(我自己又踩了一次)
修完第二天用户报"又没声音了"。折腾一圈发现:是他自己把音量调低了(嫌太大声)。
原 因是这台机器的内部扬声器有双重衰减:
● 软音量:CRAS 的 node volume(0-100),在 DSP 里做增益
● 硬音量:Sp eaker Playback Volume(0-39,RT5645 模拟增益),CRAS 会按 node volume 自动同步写
实测映射(cras_ test_client --dump_se rver_info 里 INTERNAL_SPEAKE R 的 Vol 列 ↔ 硬件音量):
n ode vol
硬件 Spea ker Vol
约合 dB
听感
16
11
-30 d B
基本听不见(软音量再叠一层)
30
15
-2 4 dB
很轻
40
19
-18 dB
偏小
60
26
-7.5 dB
正常
70+
29~31
0 dB
偏大
所以音量低于 25 左右就等于静音,不是驱动又挂了。以后遇到"突然没声",先看这一行:
cras_test_client --dump_server_info | gr ep ‘7:1’ # INTERN AL_SPEAKER 的 Vol
四、使用方法
安装(两步)
把安装器拷进设备(U 盘 / SSH / 下载都行),然后:
sudo cp gpd-audio-fix-installer.sh /usr/local/
sudo sh /usr/ local/gpd-audio-fix-installer.sh
装完立刻有声,重启自动生效。
为什么要先 cp 到 /us r/local?
ChromeOS 的 sh 拒绝执行 noexec 挂载点上的脚本(/tmp 就是 noexec),会报
Refusing to exec … fro m noexec m ount,连 sh -s < file 也会被拦。
临时用一次可以走管道:ca t gpd-audio-fix-installer.s h | sudo sh(但不 能带参数)。
卸载
sudo sh /usr/local/gpd- audio-fix-inst aller.sh --uninstall
会把原 版模块还原回去、删掉混音脚本 和开机作业。
安装器做了什么
步骤
内容
1
校验内核版本(不匹配 会警告)
2
备份原版模块到 /usr/local/cht_rt5 645.ko.b ak
3
写入补丁版驱动并校验 md5
4
写入混音脚本( 92 条 cset )
5
写入 upstart 开机作业
6
rootfs 回只读 → 重启 CRAS → 重载驱动 → 应用混音 → 播放自检
安装后自检
c at /tmp/gpd-audio-fix.log # 应看到 OK try=0
amixer -c chtrt5645 cget name=‘SPK MIXL DAC L1 Switch’ # 应为 on
amixer -c chtrt5645 cget name=‘Ext Spk Switch’ # 应为 on
amixer -c chtrt5645 c get name=‘Speak er Channel Switch’ # 应为 on,on
在 CrOS 上测音频,别用 aplay
CRAS 独占 PCM。调试期间 CRAS 挂过几次,会把 PCM 泄漏在 R UNNING 状态,这时 aplay hw: 只会报 Device or resource busy,而且只有重启才能恢复。正确姿势:
cras_test_client --pla yback_file /tmp/test. wav
五、验证记录
项目
结果
补丁后 DAP M 图
m edia0_out mix 0 ← media1_in + media 3_in ![]()
完整链路
Headset Playback → medi a1_in → media0_out → pcm0_in → codec_out0 → ssp2 Tx → AIF1 全 On ![]()
CRAS 播放
返回 0 , hw_ptr 前进,耳朵能听到 ![]()
开机自动执行
OK try=0 ,首次即成功 ![]()
重启 E2E
6 个关键开关全 on ,播放后不回退 ![]()
安装 → 卸载 → 再安装
模块 md5 双向还原正确,最终有声 ![]()
六、限制
● 只对同一内核 有效:5.10 .110-15808-ge5740beba59b-dirty。系统升级内核后模块 version magic 不匹配,必须重新打补丁( 打补丁脚本在项目里,思路见上)。
● 需要开发者模式:要 mount -o remount rw / 写 rootfs。LoadPin 只拦 非 rootfs 路径,所以模块必须落在 /lib/modules/… 下,放 /tmp 加载不了。
● 这套东西是绕过,不是修复。真正的修法应该是让 SST 平台驱动那 80 条 mixer 路由在这个内核 ABI 下正确注册,但那需要重编内核模块 —— 如果哪天有新内核 + 对齐的 struct 定义,值得重做一遍。
七、致谢
● kmyers 的 GPD Pocket ChromiumOS 项目:HiFi.conf 的混音序列是这台机器能出声的直接依据
● 内核侧参考:sound/soc/soc-dapm.c、sound/soc/intel/atom/sst/sst_atom_hifi2.c
gpd-audio-fix-kit.zip (24.3 KB)