ALSA声卡驱动中的DAPM详解之二:widget-具备路径和电源管理信息的kcontrol
上一篇文章中,我们介绍了音频驱动中对基本控制单元的封装:kcontrol。利用kcontrol,我们可以完成对音频系统中的mixer,mux,音量控制,音效控制,以及各种开关量的控制,通过对各种kcontrol的控制,使得音频硬件能够按照我们预想的结果进行工作。同时我们可以看到,kcontrol还是有以下几点不足:
- 只能描述自身,无法描述各个kcontrol之间的连接关系;
- 没有相应的电源管理机制;
- 没有相应的时间处理机制来响应播放、停止、上电、下电等音频事件;
- 为了防止pop-pop声,需要用户程序关注各个kcontrol上电和下电的顺序;
- 当一个音频路径不再有效时,不能自动关闭该路径上的所有的kcontrol;
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
为此,DAPM框架正是为了要解决以上这些问题而诞生的,DAPM目前已经是ASoc中的重要组成部分,让我们先从DAPM的数据结构开始,了解它的设计思想和工作原理。
DAPM的基本单元:widget
文章的开头,我们说明了一下目前kcontrol的一些不足,而DAPM框架为了解决这些问题,引入了widget这一概念,所谓widget,其实可以理解为是kcontrol的进一步升级和封装,她同样是指音频系统中的某个部件,比如mixer,mux,输入输出引脚,电源供应器等等,甚至,我们可以定义虚拟的widget,例如playback stream widget。widget把kcontrol和动态电源管理进行了有机的结合,同时还具备音频路径的连结功能,一个widget可以与它相邻的widget有某种动态的连结关系。在DAPM框架中,widget用结构体snd_soc_dapm_widget来描述:
- struct snd_soc_dapm_widget {
- enum snd_soc_dapm_type id;
- const char *name; /* widget name */
- ......
- /* dapm control */
- int reg; /* negative reg = no direct dapm */
- unsigned char shift; /* bits to shift */
- unsigned int value; /* widget current value */
- unsigned int mask; /* non-shifted mask */
- ......
- int (*power_check)(struct snd_soc_dapm_widget *w);
- 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;
- /* widget input and outputs */
- struct list_head sources;
- struct list_head sinks;
- ......
- };
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结构的各个字段所代表的意义一一做出了说明,这里只是让大家现有个概念,至于每个字段的详细作用,我们会在以后相关的章节中提及。
widget的种类
在DAPM框架中,把各种不同的widget划分为不同的种类,snd_soc_dapm_widget结构中的id字段用来表示该widget的种类,可选的种类都定义在一个枚举中:
- /* dapm widget types */
- enum snd_soc_dapm_type {......}
下面我们逐个解释一下这些widget的种类:
- 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结构。
widget之间的连接器:path
之前已经提到,一个widget是有输入和输出的,而且widget之间是可以动态地进行连接的,那它们是用什么来连接两个widget的呢?DAPM为我们提出了path这一概念,path相当于电路中的一根跳线,它把一个widget的输出端和另一个widget的输入端连接在一起,path用snd_soc_dapm_path结构来描述:
- struct snd_soc_dapm_path {
- const char *name;
- /* source (input) and sink (output) widgets */
- struct snd_soc_dapm_widget *source;
- struct snd_soc_dapm_widget *sink;
- struct snd_kcontrol *kcontrol;
- /* status */
- u32 connect:1; /* source and sink widgets are connected */
- u32 walked:1; /* path has been walked */
- u32 walking:1; /* path is in the process of being walked */
- u32 weak:1; /* path ignored for power management */
- int (*connected)(struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink);
- struct list_head list_source;
- struct list_head list_sink;
- 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的遍历。
widget的连接关系: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之间的连接,具体的连接代码分析,我们留到以后的章节中讨论。
ALSA声卡驱动中的DAPM详解之二:widget-具备路径和电源管理信息的kcontrol的更多相关文章
- ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)
前面的六篇文章,我们已经讨论了dapm关于动态电源管理的有关知识,包括widget的创建和初始化,widget之间的连接以及widget的上下电顺序等等.本章我们准备讨论dapm框架中的另一个机制:事 ...
- ALSA声卡驱动中的DAPM详解之六:精髓所在,牵一发而动全身
设计dapm的主要目的之一,就是希望声卡上的各种部件的电源按需分配,需要的就上电,不需要的就下电,使得整个音频系统总是处于最小的耗电状态,最主要的就是,这一切对用户空间的应用程序是透明的,也就是说,用 ...
- ALSA声卡驱动中的DAPM详解之四:在驱动程序中初始化并注册widget和route
前几篇文章我们从dapm的数据结构入手,了解了代表音频控件的widget,代表连接路径的route以及用于连接两个widget的path.之前都是一些概念的讲解以及对数据结构中各个字段的说明,从本章开 ...
- ALSA声卡驱动中的DAPM详解之三:如何定义各种widget
上一节中,介绍了DAPM框架中几个重要的数据结构:snd_soc_dapm_widget,snd_soc_dapm_path,snd_soc_dapm_route.其中snd_soc_dapm_pat ...
- ALSA声卡驱动中的DAPM详解之五:建立widget之间的连接关系
前面我们主要着重于codec.platform.machine驱动程序中如何使用和建立dapm所需要的widget,route,这些是音频驱动开发人员必须要了解的内容,经过前几章的介绍,我们应该知道如 ...
- ALSA声卡驱动中的DAPM详解之一:kcontrol
DAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态 ...
- 「翻译」Unity中的AssetBundle详解(二)
为AssetBundles准备资源 使用AssetBundles时,您可以随意将任何Asset分配给所需的任何Bundle.但是,在设置Bundles时,需要考虑一些策略.这些分组策略可以使用到任何你 ...
- C/C++中函数参数传递详解(二)
昨天看了内存管理的有关内容,有一点了解,但不是很深入,发现之前写代码时有很多细节问题没有注意到,只知道这样做可以实现功能,却不知道为什么可以这样,对于采用自己的方法造成的隐患也未知,更不晓得还有其他方 ...
- 线程Thread中的方法详解(二)
1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...
随机推荐
- 在eclipse里如何快速定位到某一行?
使用快捷键ctrl+L讲每一行的行号显示出来:在eclipse的某一行的最左边,右键——show Line Numbers就可以将行数都显示出来.
- Codeforces_761_E_(dfs)
E. Dasha and Puzzle time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- 扩增子分析解读6进化树 Alpha Beta多样性
分析前准备 # 进入工作目录 cd example_PE250 上一节回顾:我们的OTU获得了物种注释,并学习OTU表的各种操作————添加信息,格式转换,筛选信息. 接下来我们学习对OTU序列的 ...
- JavaScipt30(第四个案例)(主要知识点:数组原型链上的一些方法)
承接上文,下面是第四个案例 附上项目链接: https://github.com/wesbos/JavaScript30 const inventors = [ { first: 'Albert', ...
- Python自学-2-python解释器
写python源文件,以.py为后缀名 用python解释器去执行.py文件 python解释器 CPython:官方版本,由C语言开发的,下载默认就是这个,使用最广的解释器. 用>> ...
- 洛谷——P3919 【模板】可持久化数组(可持久化线段树/平衡树)
P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...
- buf.writeUInt8()函数详解
buf.writeUInt8(value, offset[, noAssert]) value {Number} 需要被写入到 Buffer 的字节 offset {Number} 0 <= o ...
- 2.5.5 基本的 I/0 重定向
标准输入/输出(standard I/O)可能是软件设计原则里最重要的概念了.这个概念就是:程序应该有数据的来源端.数据的目的端以及报告问题的地方,它们分别被称为标准输入(standard i ...
- vb 运行ppt示例代码
来源:http://support.microsoft.com/kb/222929 通过使用 PowerPoint 中的自动运行功能,您可以以编程方式打印.显示幻灯片及执行以交互式执行的大多数事情.按 ...
- 桦仔------分享一下我研究SQLSERVER以来收集的笔记
http://www.cnblogs.com/lyhabc/p/3219117.html