ALSA SOC架构关键点
关于ALSA(Advanced Linux Sound Architecture)中文资料真的很少,可能是国人很少真的从零开始做驱动开发的原因。毕竟像wolfson或者realtek这样的公司多还是老外在做开发。ALSA 对SOC支持,更是ALSA在嵌入式领域的应用,也是后来才加入到ALSA中的,那资料更是少了。我花了一个星期也几乎没有任何发现,而后通过零星资料的蛛丝马迹,终于对ALSA有感觉了。对今后的继续学习是非常有帮助的。
按通常的三层分类方式,从下到上,依次是ALSA driver、ALSA lib、ALSA application。
ALSA application包括aplay、arecord,他们属于ALSA utils的工具。这些工具用于测试驱动非常的好。
ALSA lib提供诸如打开,关闭,播放的函数库
ALSA driver是后来才加入了对SOC的支持,并且将hardware audio codec的控制抽象出来,放在sound/soc/codecs的目录里。而和SOC硬件相关的代码抽象出来放在omap目录里(加入SOC是omap)。这种分离式的设计使得一个codec的代码,在不做任何修改的情况下,可以对应很多的SOC。(把通用的代码尽量抽象出来是驱动程序架构设计一直追求的目标)
ALSA的SOC中的一个大家伙,就是DAPM (Dynamic Audio Power Management),它将电源划分为4个域:
- Codec domain - VREF, VMID (core codec and audio power) Usually controlled at codec probe/remove and suspend/resume, although can be set at stream time if power is not needed for sidetone, etc.
- Platform/Machine domain - physically connected inputs and outputs Is platform/machine and user action specific, is configured by the machine driver and responds to asynchronous events e.g when HP are inserted
- Path domain - audio susbsystem signal paths Automatically set when mixer and mux settings are changed by the user. e.g. alsamixer, amixer.
- Stream domain - DACs and ADCs. Enabled and disabled when stream playback/capture is started and stopped respectively. e.g. aplay, arecord.
对于codec domain,它位于sound/soc/codecs目录下,例如wm9713.c。
对于Platform/Machine domain,他放在machine名字的目录里,如sound/soc/s3c24xx目录下neo1973_wm9753.c,以机器名和codec的名字同时命名。
在定义codec的audio path的时候,你需要知道这样的背景知识,DAPM在概念上分为以下部件,
- Mixer - Mixes several analog signals into a single analog signal.
- Mux - An analog switch that outputs only one of many inputs.
- PGA - A programmable gain amplifier or attenuation widget.
- ADC - Analog to Digital Converter
- DAC - Digital to Analog Converter
- Switch - An analog switch
- Input - A codec input pin
- Output - A codec output pin
- Headphone - Headphone (and optional Jack)
- Mic - Mic (and optional Jack)
- Line - Line Input/Output (and optional Jack)
- Speaker - Speaker
- Pre - Special PRE widget (exec before all others)
- Post - Special POST widget (exec after all others)
可以看出这些部件主要也是抽象了codec内部的硬件构件。audio path是路径,所以有输入,输出的概念。除了path的终点,每个部件都包含输入口,和输出口。
对于path上输入的开始端点,它只需要输出到下一个部件就好。同理对于path上输出的端点,它只需要从前一个部件输入就好。path的头尾端点就是用SND_SOC_DAPM_INPUT或者SND_SOC_DAPM_OUTPUT定义这个部件。
codec中都有混音器,它总是把多个输入加和为一个输出信号,他就由SND_SOC_DAPM_MIXER定义。
同样,codec中也会有一些多路开关,他是有多个输入,但是只有一个输入可以和输出接通,这样的部件由SND_SOC_DAPM_MUX定义。
PGA就如它在硬件中的名字,一般就是一个输入,和一个输出。用SND_SOC_DAPM_PGA定义
OK,你的codec代码中将所有可能的path全部连接起来,问题来了,对于每一个audio path都有一个头,和一个尾。但是这条path中间可以走的路那就很多了,也不是一定的。尤其对于手机里的场景中audio path,可以有speaker路径,headphone路径,A2DP路径,GSM phone路径或者MIC路径,很多了,我要根据需要打开或者关闭这些路径。我被这个问题困惑了很久,ALSA的设计中到底由哪个部分负责。一开始我还怀疑是不是codec的audio path没有定义完整?或者ALSA有切换这种场景的函数?再或者由machine代码来定义这样的路径?
后来我的猜想都不正确。Audio Codec中有许多部件,并且可以是任意的名字,ALSA怎么可能知道该如何操作这些部件来切换到你想要的路径,即时ALSA lib也不会关心这部分内容,这些细微的切换又ALSA application以上来完成,ALSA lib也最多提供各种操作mixer或者Mux的函数,如果切换是你应用的事情。
对部件的操作函数是snd_mixer_selem_set_enum_item(),alsamixer也是通过这个函数达到切换的目的