目录

1. DAPM的基本单元:widget(struct  snd_soc_dapm_widget)

2. widget的种类

3. widget之间的连接器:path(struct snd_soc_dapm_path)

4. widget的连接关系:route(struct snd_soc_dapm_route)


上一篇文章中,我们介绍了音频驱动中对基本控制单元的封装:kcontrol。利用kcontrol,我们可以完成对音频系统中的mixer,mux,音量控制,音效控制,以及各种开关量的控制,通过对各种kcontrol的控制,使得音频硬件能够按照我们预想的结果进行工作。同时我们可以看到,kcontrol还是有以下几点不足:

(1)只能描述自身,无法描述各个kcontrol之间的连接关系;
(2)没有相应的电源管理机制;
(3)没有相应的时间处理机制来响应播放、停止、上电、下电等音频事件;
(4)为了防止pop-pop声,需要用户程序关注各个kcontrol上电和下电的顺序;
(5)当一个音频路径不再有效时,不能自动关闭该路径上的所有的kcontrol;

为此,DAPM框架正是为了要解决以上这些问题而诞生的,DAPM目前已经是ASoc中的重要组成部分,让我们先从DAPM的数据结构开始,了解它的设计思想和工作原理。

1. DAPM的基本单元:widget(struct  snd_soc_dapm_widget)

文章的开头,我们说明了一下目前kcontrol的一些不足,而DAPM框架为了解决这些问题,引入了widget这一概念,所谓widget,其实可以理解为是kcontrol的进一步升级和封装,她同样是指音频系统中的某个部件,比如mixer,mux,输入输出引脚,电源供应器等等,甚至,我们可以定义虚拟的widget,例如playback stream widget。widget把kcontrol和动态电源管理进行了有机的结合,同时还具备音频路径的连结功能,一个widget可以与它相邻的widget有某种动态的连结关系。在DAPM框架中,widget用结构体snd_soc_dapm_widget来描述:

/* dapm widget */
struct snd_soc_dapm_widget {enum snd_soc_dapm_type id;const char *name;     /* widget name */const char *sname; /* stream name */struct list_head list;struct snd_soc_dapm_context *dapm;void *priv;                /* widget specific data */struct regulator *regulator;      /* attached regulator */const struct snd_soc_pcm_stream *params; /* params for dai links */unsigned int num_params; /* number of params for dai links */unsigned int params_select; /* currently selected param for dai link *//* dapm control */int reg;               /* negative reg = no direct dapm */unsigned char shift;            /* bits to shift */unsigned int mask;           /* non-shifted mask */unsigned int on_val;          /* on state value */unsigned int off_val;           /* off state value */unsigned char power:1;         /* block power status */unsigned char active:1;         /* active stream on DAC, ADC's */unsigned char connected:1;        /* connected codec pin */unsigned char new:1;           /* cnew complete */unsigned char force:1;           /* force state */unsigned char ignore_suspend:1;         /* kept enabled over suspend */unsigned char new_power:1;      /* power from this run */unsigned char power_checked:1;     /* power checked this run */unsigned char is_supply:1;      /* Widget is a supply type widget */unsigned char is_ep:2;          /* Widget is a endpoint type widget */int subseq;               /* sort within widget type */int (*power_check)(struct snd_soc_dapm_widget *w);/* external events */unsigned short event_flags;     /* flags to specify event types */int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);/* kcontrols that relate to this widget */int num_kcontrols;const struct snd_kcontrol_new *kcontrol_news;struct snd_kcontrol **kcontrols;struct snd_soc_dobj dobj;/* widget input and output edges */struct list_head edges[2];/* used during DAPM updates */struct list_head work_list;struct list_head power_list;struct list_head dirty;int endpoints[2];struct clk *clk;
};

snd_soc_dapm_widget结构比较大,为了简洁一些,这里我没有列出该结构体的完整字段,不过不用担心,下面我会说明每个字段的意义:

id    该widget的类型值,比如snd_soc_dapm_output,snd_soc_dapm_mixer等等。

*name    该widget的名字

*sname    代表该widget所在stream的名字,比如对于snd_soc_dapm_dai_in类型的widget,会使用该字段。

*codec *platform    指向该widget所属的codec和platform。

list    所有注册到系统中的widget都会通过该list,链接到代表声卡的snd_soc_card结构的widgets链表头字段中。

*dapm    snd_soc_dapm_context结构指针,ASoc把系统划分为多个dapm域,每个widget属于某个dapm域,同一个域代表着同样的偏置电压供电策略,比如,同一个codec中的widget通常位于同一个dapm域,而平台上的widget可能又会位于另外一个platform域中。

*priv    有些widget可能需要一些专有的数据,可以使用该字段来保存,像snd_soc_dapm_dai_in类型的widget,会使用该字段来记住与之相关联的snd_soc_dai结构指针。

*regulator    对于snd_soc_dapm_regulator_supply类型的widget,该字段指向与之相关的regulator结构指针。

*params    目前对于snd_soc_dapm_dai_link类型的widget,指向该dai的配置信息的snd_soc_pcm_stream结构。

reg shift mask     这3个字段用来控制该widget的电源状态,分别对应控制信息所在的寄存器地址,位移值和屏蔽值。

value  on_val  off_val    电源状态的当前只,开启时和关闭时所对应的值。

power invert    用于指示该widget当前是否处于上电状态,invert则用于表明power字段是否需要逻辑反转。

active connected    分别表示该widget是否处于激活状态和连接状态,当和相邻的widget有连接关系时,connected位会被置1,否则置0。

new   我们定义好的widget(snd_soc_dapm_widget结构),在注册到声卡中时需要进行实例化,该字段用来表示该widget是否已经被实例化。

ext    表示该widget当前是否有外部连接,比如连接mic,耳机,喇叭等等。

force    该位被设置后,将会不管widget当前的状态,强制更新至新的电源状态。

ignore_suspend new_power power_checked    这些电源管理相关的字段。

subseq    该widget目前在上电或下电队列中的排序编号,为了防止在上下电的过程中出现pop-pop声,DAPM会给每个widget分配合理的上下电顺序。

*power_check    用于检查该widget是否应该上电或下电的回调函数指针。
event_flags    该字段是一个位或字段,每个位代表该widget会关注某个DAPM事件通知。只有被关注的通知事件会被发送到widget的事件处理回调函数中。
*event    DAPM事件处理回调函数指针。
num_kcontrols *kcontrol_news **kcontrols    这3个字段用来描述与该widget所包含的kcontrol控件,例如一个mixer控件或者是一个mux控件。

sources sinks    两个链表字段,两个widget如果有连接关系,会通过一个snd_soc_dapm_path结构进行连接,sources链表用于链接所有的输入path,sinks链表用于链接所有的输出path。

power_list    每次更新整个dapm的电源状态时,会根据一定的算法扫描所有的widget,然后把需要变更电源状态的widget利用该字段链接到一个上电或下电的链表中,扫描完毕后,dapm系统会遍历这两个链表执行相应的上电或下电操作。
dirty    链表字段,widget的状态变更后,dapm系统会利用该字段,把该widget加入到一个dirty链表中,稍后会对dirty链表进行扫描,以执行整个路径的更新。
inputs    该widget的所有有效路径中,连接到输入端的路径数量。
outputs    该widget的所有有效路径中,连接到输出端的路径数量。
*clk    对于snd_soc_dapm_clock_supply类型的widget,指向相关联的clk结构指针。

以上我们对snd_soc_dapm_widget结构的各个字段所代表的意义一一做出了说明,这里只是让大家现有个概念,至于每个字段的详细作用,我们会在以后相关的章节中提及。

2. widget的种类

在DAPM框架中,把各种不同的widget划分为不同的种类,snd_soc_dapm_widget结构中的id字段用来表示该widget的种类,可选的种类都定义在一个枚举中:

/* dapm widget types */
enum snd_soc_dapm_type {......}

snd_soc_dapm_input     该widget对应一个输入引脚。
snd_soc_dapm_output    该widget对应一个输出引脚。
snd_soc_dapm_mux    该widget对应一个mux控件。
snd_soc_dapm_virt_mux    该widget对应一个虚拟的mux控件。
snd_soc_dapm_value_mux    该widget对应一个value类型的mux控件。
snd_soc_dapm_mixer    该widget对应一个mixer控件。
snd_soc_dapm_mixer_named_ctl    该widget对应一个mixer控件,但是对应的kcontrol的名字不会加入widget的名字作为前缀。
snd_soc_dapm_pga    该widget对应一个pga控件(可编程增益控件)。
snd_soc_dapm_out_drv    该widget对应一个输出驱动控件
snd_soc_dapm_adc    该widget对应一个ADC 
snd_soc_dapm_dac    该widget对应一个DAC 
snd_soc_dapm_micbias    该widget对应一个麦克风偏置电压控件
snd_soc_dapm_mic    该widget对应一个麦克风。
snd_soc_dapm_hp    该widget对应一个耳机。
snd_soc_dapm_spk    该widget对应一个扬声器。
snd_soc_dapm_line     该widget对应一个线路输入。
snd_soc_dapm_switch       该widget对应一个模拟开关。
snd_soc_dapm_vmid      该widget对应一个codec的vmid偏置电压。
snd_soc_dapm_pre      machine级别的专用widget,会先于其它widget执行检查操作。
snd_soc_dapm_post    machine级别的专用widget,会后于其它widget执行检查操作。
snd_soc_dapm_supply           对应一个电源或是时钟源。
snd_soc_dapm_regulator_supply  对应一个外部regulator稳压器。
snd_soc_dapm_clock_supply      对应一个外部时钟源。
snd_soc_dapm_aif_in            对应一个数字音频输入接口,比如I2S接口的输入端。
snd_soc_dapm_aif_out          对应一个数字音频输出接口,比如I2S接口的输出端。
snd_soc_dapm_siggen            对应一个信号发生器。
snd_soc_dapm_dai_in           对应一个platform或codec域的输入DAI结构。
snd_soc_dapm_dai_out        对应一个platform或codec域的输出DAI结构。
snd_soc_dapm_dai_link         用于链接一对输入/输出DAI结构。

我们从es8316.c中挑选一个看一下:

static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {SND_SOC_DAPM_SUPPLY("Bias", ES8316_SYS_PDN, 3, 1, NULL, 0),SND_SOC_DAPM_SUPPLY("Analog power", ES8316_SYS_PDN, 4, 1, NULL, 0),SND_SOC_DAPM_SUPPLY("Mic Bias", ES8316_SYS_PDN, 5, 1, NULL, 0),.......
}

3. widget之间的连接器:path(struct snd_soc_dapm_path)

之前已经提到,一个widget是有输入和输出的,而且widget之间是可以动态地进行连接的,那它们是用什么来连接两个widget的呢?DAPM为我们提出了path这一概念,path相当于电路中的一根跳线,它把一个widget的输出端和另一个widget的输入端连接在一起,path用snd_soc_dapm_path结构来描述:

/* dapm audio path between two widgets */
struct snd_soc_dapm_path {const char *name;/** source (input) and sink (output) widgets* The union is for convience, since it is a lot nicer to type* p->source, rather than p->node[SND_SOC_DAPM_DIR_IN]*/union {struct {struct snd_soc_dapm_widget *source;struct snd_soc_dapm_widget *sink;};struct snd_soc_dapm_widget *node[2];};/* status */u32 connect:1;  /* source and sink widgets are connected */u32 walking:1;  /* path is in the process of being walked */u32 weak:1;  /* path ignored for power management */u32 is_supply:1; /* At least one of the connected widgets is a supply */int (*connected)(struct snd_soc_dapm_widget *source,struct snd_soc_dapm_widget *sink);struct list_head list_node[2];struct list_head list_kcontrol;struct list_head list;
};

当widget之间发生连接关系时,snd_soc_dapm_path作为连接者,它的source字段会指向该连接的起始端widget,而它的sink字段会指向该连接的到达端widget,还记得前面snd_soc_dapm_widget结构中的两个链表头字段:sources和sinks么?widget的输入端和输出端可能连接着多个path,所有输入端的snd_soc_dapm_path结构通过list_sink字段挂在widget的souces链表中,同样,所有输出端的snd_soc_dapm_path结构通过list_source字段挂在widget的sinks链表中。这里可能大家会被搞得晕呼呼的,一会source,一会sink,不要紧,只要记住,连接的路径是这样的:起始端widget的输出-->path的输入-->path的输出-->到达端widget输入。

图1    widget通过path进行连接

另外,snd_soc_dapm_path结构的list字段用于把所有的path注册到声卡中,其实就是挂在snd_soc_card结构的paths链表头字段中。如果你要自己定义方法来检查path的当前连接状态,你可以提供自己的connected回调函数指针。

connect,walked,walking,weak是几个辅助字段,用于帮助所有path的遍历。

4. widget的连接关系:route(struct snd_soc_dapm_route)

通过上一节的内容,我们知道,一个路径的连接至少包含以下几个元素:起始端widget,跳线path,到达端widget,在DAPM中,用snd_soc_dapm_route结构来描述这样一个连接关系:

struct snd_soc_dapm_route {const char *sink;const char *control;const char *source;int (*connected)(struct snd_soc_dapm_widget *source,struct snd_soc_dapm_widget *sink);
};

sink指向到达端widget的名字字符串,source指向起始端widget的名字字符串,control指向负责控制该连接所对应的kcontrol名字字符串,connected回调则定义了上一节所提到的自定义连接检查回调函数。该结构的意义很明显就是:source通过一个kcontrol,和sink连接在一起,现在是否处于连接状态,请调用connected回调函数检查。
      这里直接使用名字字符串来描述连接关系,所有定义好的route,最后都要注册到dapm系统中,dapm会根据这些名字找出相应的widget,并动态地生成所需要的snd_soc_dapm_path结构,正确地处理各个链表和指针的关系,实现两个widget之间的连接,具体的连接代码分析,我们留到以后的章节中讨论。

static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {.dapm_routes = rt5651_dapm_routes,
}
snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,rt5651_dai, ARRAY_SIZE(rt5651_dai));/*machin之后最终导致该函数被调用*/static int snd_soc_instantiate_card(struct snd_soc_card *card)soc_probe_link_components(card, i, order);soc_probe_component(card, component);snd_soc_dapm_add_routes(dapm, component->dapm_routes,component->num_dapm_routes);snd_soc_dapm_add_route(dapm, route);   /*创建一个path*/snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,route->connected);

参考文章:08.音频系统:第003课_Linux音频驱动程序:第005节_DAPM_widget_route_path_江南才尽,年少无知!的博客-CSDN博客

Linux内核4.14版本——alsa框架分析(11)——DAPM(2)——widget、route和path的概念相关推荐

  1. Linux内核4.14版本——alsa框架分析(1)—alsa简介

    目录 一,ALSA声音编程介绍 二,ALSA历史 三,数字音频基础 四,ALSA基础 五,ALSA体系结构 六,设备命名 七,声音缓存和数据传输 八,Over and Under Run 九,一个典型 ...

  2. Linux内核4.14版本——alsa框架分析(8)-ASoC(Codec)

    1. 概述 ASOC的出现是为了让Codec独立于CPU,减少和CPU之间的耦合,这样同一个Codec驱动无需修 改就可以适用任何一款平台.还是以下图做参考例子: 在Machine中已经知道,snd_ ...

  3. Linux内核4.14版本——drm框架分析(1)——drm简介

    目录 1. DRM简介(Direct Rendering Manager) 1.1 DRM发展历史 1.2 DRM架构对比FB架构优势 1.3 DRM图形显示框架 1.4 DRM图形显示框架涉及元素 ...

  4. Linux内核4.14版本——mmc框架_软件总体架构

    目录 1. 前言 2. 软件架构 3. 工作流程 4. mmc设备 4.1 mmc type card 4.2 sd type card 4.3 sdio type card 5. mmc协议 5.1 ...

  5. Linux内核4.14版本:ARM64的内核启动过程(二)——start_kernel

    目录 1. rest_init 2. init 进程(kernel_init) 2.1 kernel_init_freeable 2.1.1 do_basic_setup 2.1.2 prepare_ ...

  6. Linux内核4.14版本——watchdog看门狗框架分析

    目录 0 简介 1. 设备的注册 1.1 dw_wdt_drv_probe 1.2 watchdog_register_device 1.3 __watchdog_register_device 1. ...

  7. Linux内核4.14版本——DMA Engine框架分析(6)-实战(测试dma驱动)

    1. dw-axi-dmac驱动 2. dma的测试程序 2.1 内核程序 2.2 用户测试程序 1. dw-axi-dmac驱动 dw-axi-dmac驱动4.14版本没有,是从5.4版本移植的,基 ...

  8. Linux内核4.14版本——Nand子系统(1)——hisi504_nand.c分析

    1. 简介 2. DTS 3. hisi_nfc_probe函数 3.1 获取dts中的资源 3.2 设置nand-chip结构体中必要的字段 3.3 nand_scan_ident扫描识别nand控 ...

  9. Linux内核4.14版本——DMA Engine框架分析(2)_功能介绍及解接口分析(slave client driver)

    1 前言 2  Slave-DMA API和Async TX API 3 dma engine的使用步骤 3.1 申请DMA channel 3.2 配置DMA channel的参数 3.3 获取传输 ...

最新文章

  1. 【ubuntu】ubuntu14.04、16.04、18.04 LTS版本支持时间
  2. 曾被无视多年,却成就19世纪最伟大的一场革命,影响了整个世界!
  3. C++文件输入和输出
  4. 基于ECI+FaaS构建游戏战斗结算服最佳实践
  5. UML分析AsyncDisplayKit框架-ASMuplexImageNode异步下载时序图。
  6. [转]IaaS、PaaS、SaaS、CaaS、MaaS五者的区别
  7. 如何将C语言翻译成汇编语言,如何把汇编语言转换成C语言
  8. Linux下安装informix11.5数据库
  9. windows查看linux文件工具,「实用工具」介绍几款Windows系统与Linux服务器传递文件的工具...
  10. 【SDOI 2009】学校食堂 Dining
  11. 插个“USB”就能无线投影,DispalyTen想借传屏切入企业级会议市场
  12. 各地级市-国内及外汇旅游收入(1995-2020)
  13. linux设置家目录,usermod更改用户家目录
  14. 【光纤传输特性】图文并茂,你该了解这些
  15. Pytorch文本分类
  16. LaTex关于数学公式的使用(7)--- 函数单边大括号
  17. secoclient报错接收返回码超时,Windows 无法验证此设备所需的驱动程序的数字签名。某软件或硬件最近有所更改,可能安装了签名错误或损毁的文件,或者安装的文件可能是来路不明的恶意软件。
  18. WebGL 3D 数百个 HTML5 例子学习 HT 图形组件
  19. 如何区分漫威军团与灭霸军团--支持向量机(小白篇)
  20. MATLAB信号处理——信号与系统的分析基础(5)

热门文章

  1. 油滴获取配置失败还原更改请勿关闭计算机,配置Windows Update,补丁更新
  2. 一周AI回顾 | 南沙设立人工智能视觉图像研发中心,旷视科技C轮筹资4.6亿美元
  3. 如何学习HTML5?
  4. swiper+vue3 水平带左右箭头切换
  5. 莱昂纳多(Leonardo)方程求解计算国土面积 (matlab程序答案)
  6. 涿州阳光计算机学校学历,涿州职教中心计算机专业高考班人才培养方案.pdf
  7. 小程序制作预算_做一个小程序的大概预算是多少?做一个小程序大概多少钱?...
  8. common prep
  9. 什么是LORA无线远传智能水表?
  10. 数据产品经理一天日程曝光,网友表示:是我本人!