资源预览内容
第1页 / 共90页
第2页 / 共90页
第3页 / 共90页
第4页 / 共90页
第5页 / 共90页
第6页 / 共90页
第7页 / 共90页
第8页 / 共90页
第9页 / 共90页
第10页 / 共90页
亲,该文档总共90页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
1.ALSA声卡驱动中的DAPM详解之一:kcontrolDAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下。DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都在ASoc core中完成。用户空间的应用程序无需对代码做出修改,也无需重新编译,DAPM根据当前激活的音频流playback/capture和声卡中的mixer等的配置来决定那些音频控件的电源开关被翻开或关闭。/*/声明:本博容均由原创,请注明出处,!/*/DAPM控件是由普通的soc音频控件演变而来的,所以本章的容我们先从普通的soc音频控件开场。snd_kcontrol_new结构在正式讨论DAPM之前,我们需要先搞清楚ASoc中的一个重要的概念:kcontrol,不熟悉的读者需要浏览一下我之前的文章:Linux ALSA声卡驱动之四:Control设备的创立。通常,一个kcontrol代表着一个mixer混音器,或者是一个mux多路开关,又或者是一个音量控制器等等。从上述文章中我们知道,定义一个kcontrol主要就是定义一个snd_kcontrol_new结构,为了方便讨论,这里再次给出它的定义:cppview plaincopystructsnd_kcontrol_newsnd_ctl_elem_iface_tiface;/*interfaceidentifier*/unsignedintdevice;/*device/clientnumber*/unsignedintsubdevice;/*subdevice(substream)number*/constunsignedchar*name;/*ASCIInameofitem*/unsignedintindex;/*indexofitem*/unsignedintaccess;/*accessrights*/unsignedintcount;/*countofsameelements*/snd_kcontrol_info_t*info;snd_kcontrol_get_t*get;snd_kcontrol_put_t*put;unionsnd_kcontrol_tlv_rw_t*c;constunsignedint*p;tlv;unsignedlongprivate_value;回到Linux ALSA声卡驱动之四:Control设备的创立中,我们知道,对于每个控件,我们需要定义一个和他对应的snd_kcontrol_new结构,这些snd_kcontrol_new结构会在声卡的初始化阶段,通过snd_soc_add_codec_controls函数注册到系统中,用户空间就可以通过amixer或alsamixer等工具查看和设定这些控件的状态。snd_kcontrol_new结构中,几个主要的字段是get,put,private_value,get回调函数用于获取该控件当前的状态值,而put回调函数那么用于设置控件的状态值,而private_value字段那么根据不同的控件类型有不同的意义,比方对于普通的控件,private_value字段可以用来定义该控件所对应的存放器的地址以与对应的控制位在存放器中的位置信息。值得庆幸的是,ASoc系统已经为我们准备了大量的宏定义,用于定义常用的控件,这些宏定义位于include/sound/soc.h中。下面我们分别讨论一下如何用这些预设的宏定义来定义一些常用的控件。简单型的控件SOC_SINGLE SOC_SINGLE应该算是最简单的控件了,这种控件只有一个控制量,比方一个开关,或者是一个数值变量比方Codec中某个频率,FIFO大小等等。我们看看这个宏是如何定义的:cppview plaincopy#defineSOC_SINGLE(xname,reg,shift,max,invert).iface=SNDRV_CTL_ELEM_IFACE_MIXER,.name=xname,.info=snd_soc_info_volsw,.get=snd_soc_get_volsw,.put=snd_soc_put_volsw,.private_value=SOC_SINGLE_VALUE(reg,shift,max,invert)宏定义的参数分别是:xname该控件的名字,reg该控件对应的存放器的地址,shift控制位在存放器中的位移,max控件可设置的最大值,invert设定值是否逻辑取反。这里又使用了一个宏来定义private_value字段:SOC_SINGLE_VALUE,我们看看它的定义:cppview plaincopy#defineSOC_DOUBLE_VALUE(xreg,shift_left,shift_right,xmax,xinvert)(unsignedlong)&(structsoc_mixer_control).reg=xreg,.rreg=xreg,.shift=shift_left,.rshift=shift_right,.max=xmax,.platform_max=xmax,.invert=xinvert)#defineSOC_SINGLE_VALUE(xreg,xshift,xmax,xinvert)SOC_DOUBLE_VALUE(xreg,xshift,xshift,xmax,xinvert)这里实际上是定义了一个soc_mixer_control结构,然后把该结构的地址赋值给了private_value字段,soc_mixer_control结构是这样的:cppview plaincopy/*mixercontrol*/structsoc_mixer_controlintmin,max,platform_max;unsignedintreg,rreg,shift,rshift,invert;看来soc_mixer_control是控件特征的真正描述者,它确定了该控件对应存放器的地址,位移值,最大值和是否逻辑取反等特性,控件的put回调函数和get回调函数需要借助该结构来访问实际的存放器。我们看看这get回调函数的定义:cppview plaincopyintsnd_soc_get_volsw(structsnd_kcontrol*kcontrol,structsnd_ctl_elem_value*ucontrol)structsoc_mixer_control*mc=(structsoc_mixer_control*)kcontrol-private_value;structsnd_soc_codec*codec=snd_kcontrol_chip(kcontrol);unsignedintreg=mc-reg;unsignedintreg2=mc-rreg;unsignedintshift=mc-shift;unsignedintrshift=mc-rshift;intmax=mc-max;unsignedintmask=(1invert;(snd_soc_read(codec,reg)shift)&mask;if(invert)if(snd_soc_volsw_is_stereo(mc)if(reg=reg2)(snd_soc_read(codec,reg)rshift)&mask;else(snd_soc_read(codec,reg2)shift)&mask;if(invert)return0;上述代码一目了然,从private_value字段取出soc_mixer_control结构,利用该结构的信息,访问对应的存放器,返回相应的值。SOC_SINGLE_TLV SOC_SINGLE_TLV是SOC_SINGLE的一种扩展,主要用于定义那些有增益控制的控件,例如音量控制器,EQ均衡器等等。cppview plaincopy#defineSOC_SINGLE_TLV(xname,reg,shift,max,invert,tlv_array).iface=SNDRV_CTL_ELEM_IFACE_MIXER,.name=xname,.access=SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_READ
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号