4. DAPM Route定义:source / control / sink 的含义
DAPM(Dynamic Audio Power Management)路由的核心是 snd_soc_dapm_route 结构体。该结构体用于描述音频数据在 Codec、CPU DAI、DMA 以及外部连接器之间的流动路径。理解 source、control 和 sink 三个字段的含义,是进行 DAPM 路由调试的基础。
4.1 snd_soc_dapm_route 结构体解析
在 Linux 内核源码 include/sound/soc-dapm.h 中,该结构体定义如下:
struct snd_soc_dapm_route {
const char *sink; /* 路径终点 widget 名称 */
const char *control; /* 可选:控制该路径的 mixer/mux 控件名称,NULL 表示直连 */
const char *source; /* 路径起点 widget 名称 */
/* 注:实际内核中还有后续字段,但驱动开发中最常用的是以上三个 */
};
三个字段构成了一个有向边:音频数据从 source 流出,经过可选的 control 开关,最终流入 sink。
4.2 三字段含义详解
| 字段 | 含义 | 典型值举例 | 说明 |
|---|---|---|---|
| source | 音频路径的起点 Widget | "DAC", "DMIC", "I2S Input" |
数据生产者,可以是 ADC、DMA 缓冲区、外部引脚输入等 |
| control | 路径上的开关/混音器控件 | "Left Mixer", "Mux Select", NULL |
若为 NULL 表示直连;若指定控件名,则路径通断受该控件状态控制 |
| sink | 音频路径的终点 Widget | "HP Out", "Speaker", "ADC" |
数据消费者,可以是耳机放大器、扬声器、ADC 输入等 |
snd_soc_dapm_widget 定义中的 .name 字段完全匹配(包括大小写)。control 字段对应 mixer 或 mux 类型的 widget 名称,用于实现条件路由。
4.3 路由方向与数据流
DAPM 路由是有向的。数据流方向固定为:
source → [control] → sink
在音频回放(playback)路径中,source 通常是 DAC 或 AIF,sink 是输出引脚。在录音(capture)路径中,source 是输入引脚或 MIC,sink 是 ADC 或 AIF。驱动开发者必须按照实际硬件信号流向填写路由表。
"HP Out" 作为 source,"DAC" 作为 sink,这会导致音频路径无法建立。
4.4 路由定义示例:三字段组合
以下是一个典型 Codec 的路由表片段,展示了三种常见组合:
static const struct snd_soc_dapm_route audio_paths[] = {
/* 1. 直连路径:control = NULL */
{ "HP Out", NULL, "HP Amp" },
/* 2. 受 mixer 控件控制的路径 */
{ "Left Mixer", "Left DAC Switch", "Left DAC" },
/* 3. 受 mux 控件控制的路径 */
{ "ADC Mux", "DMIC Select", "DMIC" },
};
| 行号 | source | control | sink | 含义 |
|---|---|---|---|---|
| 1 | "HP Amp" |
NULL |
"HP Out" |
HP Amp 直连到 HP Out,只要 HP Amp 上电,路径即通 |
| 2 | "Left DAC" |
"Left DAC Switch" |
"Left Mixer" |
Left DAC 通过 Left DAC Switch 控件连接到 Left Mixer,控件值为 1 时路径导通 |
| 3 | "DMIC" |
"DMIC Select" |
"ADC Mux" |
DMIC 通过 DMIC Select mux 控件连接到 ADC Mux,mux 选择 DMIC 时路径导通 |
4.5 路由与 DAPM 上电/下电的关系
DAPM 引擎在构建完整音频路径时,会遍历所有注册的路由表。只有当一条路径上的所有 widget 都处于上电状态,且 control 控件处于开启状态时,该路径才被认为是激活的。DAPM 会沿着激活路径递归上电所有涉及的 widget。
/sys/kernel/debug/asoc/<card>/dapm 可以查看当前所有 widget 的状态和连接关系。
4.6 路由定义中的 control 字段深入
control 字段并非任意字符串,它必须对应一个已注册的 mixer 或 mux 控件的名称。具体规则如下:
- Mixer 控件: control 字符串必须与 mixer widget 中
snd_kcontrol_new定义的.name一致。例如"Left DAC Switch"对应一个开关型 mixer 控件。 - Mux 控件: control 字符串必须与 mux widget 中
snd_kcontrol_new定义的.name一致。例如"DMIC Select"对应一个枚举型 mux 控件。 - NULL: 表示无控制条件,路径始终跟随 source widget 的上电状态。
当 control 不为 NULL 时,DAPM 会在运行时检查该控件的当前值。对于 mixer,值为非零时路径导通;对于 mux,值等于该路由对应的枚举索引时路径导通。
4.7 路由定义与 DAPM 图的关系
下图展示了一个简化的 Codec 内部路由拓扑,标注了 source、control、sink 三字段在 DAPM 图中的位置:
4.8 路由注册与调试检查点
路由表通过 snd_soc_dapm_add_routes() 函数注册到 DAPM 核心:
static int my_codec_probe(struct snd_soc_component *component) {
struct snd_soc_card *card = component->card;
snd_soc_dapm_add_routes(card, audio_paths, ARRAY_SIZE(audio_paths));
return 0;
}
调试时,可以通过以下方法验证路由是否正确注册:
- debugfs 检查: 查看
/sys/kernel/debug/asoc/<card>/dapm中每个 widget 的connected状态。 - dmesg 日志: 开启 DAPM 调试日志
# echo 'file sound/soc/soc-dapm.c +p' > /sys/kernel/debug/dynamic_debug/control,观察路由查找过程。 - 控件值验证: 使用
amixer cget检查 control 字段对应的 mixer/mux 控件当前值是否符合预期。