ALSA声卡驱动详解(4)

2019-08-31 00:43

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之间的连接,具体的连接代码分析,我们留到以后的章节中讨论。

1.ALSA声卡驱动中的DAPM详解之三:如何定义各种widget 上一节中,介绍了DAPM框架中几个重要的数据结构:snd_soc_dapm_widget,snd_soc_dapm_path,snd_soc_dapm_route。其中snd_soc_dapm_path无需我们自己定义,它会在注册snd_soc_dapm_route时动态地生成,但是对于系统中的widget和route,我们是需要自己进行定义的,另外,widget所包含的kcontrol与普通的kcontrol有所不同,它们的定义方法与标准的kcontrol也有所不同。本节的内容我将会介绍如何使用DAPM系统提供的一些辅助宏定义来定义各种类型的widget和它所用到的kcontrol。

/*****************************************************************************************************/

声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!

/*****************************************************************************************************/ 定义widget

和普通的kcontrol一样,DAPM框架为我们提供了大量的辅助宏用来定义各种各样的widget控件,这些宏定义根据widget的类型,按照它们的电源所在的域,被分为了几个域,他们分别是:

codec域 比如VREF和VMID等提供参考电压的widget,这些widget通常在codec的probe/remove回调中进行控制,当然,在工作中如果没有音频流时,也可以适当地进行控制它们的开启与关闭。

16

platform域 位于该域上的widget通常是针对平台或板子的一些需要物理连接的输入/输出接口,例如耳机、扬声器、麦克风,因为这些接口在每块板子上都可能不一样,所以通常它们是在machine驱动中进行定义和控制,并且也可以由用户空间的应用程序通过某种方式来控制它们的打开和关闭。

音频路径域 一般是指codec内部的mixer、mux等控制音频路径的widget,这些widget可以根据用户空间的设定连接关系,自动设定他们的电源状态。

音频数据流域 是指那些需要处理音频数据流的widget,例如ADC、DAC等等。 codec域widget的定义

目前,DAPM框架只提供了定义一个codec域widget的辅助宏: [cpp] view plaincopy

#define SND_SOC_DAPM_VMID(wname) \\

{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0}

platform域widget的定义

DAPM框架为我们提供了多种platform域widget的辅助定义宏: [cpp] view plaincopy

#define SND_SOC_DAPM_SIGGEN(wname) \\

{ .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_INPUT(wname) \\

{ .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_OUTPUT(wname) \\

{ .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_MIC(wname, wevent) \\

{ .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \\

.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}

#define SND_SOC_DAPM_HP(wname, wevent) \\

{ .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \\

17

.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}

#define SND_SOC_DAPM_SPK(wname, wevent) \\

{ .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \\

.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}

#define SND_SOC_DAPM_LINE(wname, wevent) \\

{ .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \\

.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \\

.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}

以上这些widget分别对应信号发生器,输入引脚,输出引脚,麦克风,耳机,扬声器,线路输入接口。其中的reg字段被设置为SND_SOC_NOPM(-1),表明这些widget是没有寄存器控制位来控制widget的电源状态的。麦克风,耳机,扬声器,线路输入接口这几种widget,还可以定义一个dapm事件回调函数wevent,从event_flags字段的设置可以看出,他们只会响应

SND_SOC_DAPM_POST_PMU(上电后)和SND_SOC_DAPM_PMD(下电前)事件,这几个widget通常会在machine驱动中定义,而

SND_SOC_DAPM_INPUT和SND_SOC_DAPM_OUTPUT则用来定义codec芯片的输出输入脚,通常在codec驱动中定义,最后,在machine驱动中增加相应的route,把麦克风和耳机等widget与相应的codec输入输出引脚的widget连接起来。

音频路径(path)域widget的定义

这种widget通常是对普通kcontrols控件的再封装,增加音频路径和电源管理功能,所以这种widget会包含一个或多个kcontrol,普通kcontrol的定义方法我们在ALSA声卡驱动中的DAPM详解之一:kcontrol中已经介绍过,不过这些被包含的kcontrol不能使用这种方法定义,它们需要使用dapm框架提供的定义宏来定义,详细的讨论我们后面有介绍。这里先列出这些widget的定义宏: [cpp] view plaincopy

#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\\ wcontrols, wncontrols) \\

{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}

#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\\ wcontrols, wncontrols) \\

18

{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}

#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \\ wcontrols, wncontrols)\\

{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}

#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \\

wcontrols, wncontrols)\\

{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \\

.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \\

.num_kcontrols = wncontrols}

#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \\ { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}

#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \\

{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}

#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \\

{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}

#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \\

{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \\

.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}

#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \\

{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \\

19

.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \\

.num_kcontrols = 1}

可以看出,这些widget的reg和shift字段是需要赋值的,说明这些widget是有相应的电源控制寄存器的,DAPM框架在扫描和更新音频路径时,会利用这些寄存器来控制widget的电源状态,使得它们的供电状态是按需分配的,需要的时候(在有效的音频路径上)上电,不需要的时候(不再有效的音频路径上)下电。这些widget需要完成和之前介绍的mixer、mux等控件同样的功能,实际上,这是通过它们包含的kcontrol控件来完成的,这些kcontrol我们需要在定义widget前先定义好,然后通过wcontrols和num_kcontrols参数传递给这些辅助定义宏。 如果需要自定义这些widget的dapm事件处理回调函数,也可以使用下面这些带“_E”后缀的版本:

SND_SOC_DAPM_PGA_E

SND_SOC_DAPM_OUT_DRV_E SND_SOC_DAPM_MIXER_E

SND_SOC_DAPM_MIXER_NAMED_CTL_E SND_SOC_DAPM_SWITCH_E SND_SOC_DAPM_MUX_E

SND_SOC_DAPM_VIRT_MUX_E

音频数据流(stream)域widget的定义

这些widget主要包含音频输入/输出接口,ADC/DAC等等: [cpp] view plaincopy

#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \\

{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \\

.reg = wreg, .shift = wshift, .invert = winvert }

#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \\

wevent, wflags) \\

{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \\

.reg = wreg, .shift = wshift, .invert = winvert, \\ .event = wevent, .event_flags = wflags }

#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \\

{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \\

.reg = wreg, .shift = wshift, .invert = winvert }

#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \\

wevent, wflags) \\

20


ALSA声卡驱动详解(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:龙虎山风景区上清镇水生态文明自主创建项目实施方案 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: