DAPM
概要
设计dapm的主要目的之一,就是希望声卡上的各种部件的电源按需分配,需要的就上电,不需要的就下电,使得整个音频系统总是处于最小的耗电状态,最主要的就是,这一切对用户空间的应用程序是透明的,也就是说,用户空间的应用程序无需关心那个部件何时需要电源,它只要按需要设定好音频路径,播放音频数据,暂停或停止,dapm框架会根据音频路径,完美地对各种部件的电源进行控制,而且精确地按某种顺序进行,防止上下电过程中产生不必要的pop-pop声。
DAPM core API
snd_soc_dapm_new_controls()创建和注册widgets到snd_soc_card的widgets链表字段。
snd_soc_dapm_add_routes()注册音频路由表。音频路由信息用 snd_soc_dapm_route结构数组定义。其注册有两种方法,这两种方法最终通过snd_soc_dapm_add_routes()注册到DAPM core。
- 通过snd_soc_codec_driver/snd_soc_platform_drivers/snd_soc_card结构体里的dapm_routes和num_dapm_routes字段注册。
- 在codec、platform的probe回调中主动注册音频路由,machine驱动中通过snd_soc_dai_link结构的init回调函数主动注册音频路由。
snd_soc_dapm_new_widgets() 创建widget所需要的dapm kcontrols。 dapm kcontol的状态变化,代表着音频路径的变化,从而影响着音频路径上各个widget的电源状态。不同类型widget创建其dapm kcontrol入口不同,如下:
只有上面类型widget有相关dapm kcontrol定义,其它类型没有定义。mixer类型有多个kcontrol定义,mux类型只有一个kcontrol定义。mixer widget有多个输入端,每个输入端由一个kcontrol控制其开启和关闭。widget之间通过snd_soc_dapm_path实例连接起来。
dapm_new_mixer
snd_soc_dapm_switch、snd_soc_dapm_mixer类型的kcontrol,注册的name是widget name 加上 kcontrol name。
snd_soc_dapm_mixer_named_ctl、snd_soc_dapm_mux类型的kcontrol,注册的name是 kcontrol name。
DAPM widgets
定义一个widget,我们需要指定两个很重要的内容:一个是用于控制widget的电源状态的reg/shift等寄存器信息,另一个是用于控制音频路径切换的dapm kcontrol信息,这些dapm kcontrol有它们自己的reg/shift寄存器信息用于切换widget的路径连接方式。
创建DAI widgets
soc_probe_component()函数里,会遍历componet所属的所有DAI实例,然后调用snd_soc_dapm_new_dai_widgets()创建 DAI widgets。
DAPM path
dapm paths描述了widget之间的连接关系。把这个连接关系称为audio path路由表。
在音频驱动里,通过snd_soc_dapm_route结构数组来定义路由表,数组每一项描述了目的widget、源widget、以及控制连接的kcontrol名称。dapm core会把snd_soc_dapm_route结构转化为内部使用的snd_soc_dapm_path结构。
注册接口snd_soc_dapm_add_routes,snd_soc_dapm_add_path()添加一条path实例。
snd_soc_dapm_add_path
snd_soc_dapm_check_dynamic_path(),检查一条path是否是动态连接。如果一条path定义了kcontrol即连接信息,那么目的widget必须是以下类型:
或者源widget必须是以下类型:
否则报错认为定义的path是不合法,继续下一个path注册。
如果一个path没有定义kontrol,这个path默认为connect状态。
path->list_node[in]链表元素挂载到源widget的edges[in]链表头,path->list_node[out]链表元素挂载到目的widget的edges[out]链表头。
也就是说通过widget的edges[in]链表头可以找到这个widget作为源widget的所有path实例。edges[out]链表头可以找到这个widget作为目的widget的所有path实例。
dapm_set_path_status函数是初始化widget输入端对应的path状态。实现过程是读取kcontrol实际寄存器的值,根据寄存器的值来初始化这个path是否处于连接状态。
端点widgets
一条完整的dapm音频路径,必然有起点和终点,我们把位于这些起点和终点的widget称之为端点widget。
当声卡上的其中一个widget的状态发生改变时,从这个widget开始,dapm框架会向前和向后遍历路径上的所有widget,判断每个widget的状态是否需要跟着变更,到达这些端点widget就会认为它是一条完整音频路径的开始和结束,从而结束一次扫描动作。
有以下端点widgets: