ImageVerifierCode 换一换
格式:DOCX , 页数:99 ,大小:303.67KB ,
资源ID:3786810      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/3786810.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(ALSA声卡驱动详解.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

ALSA声卡驱动详解.docx

1、ALSA声卡驱动详解ALSA声卡驱动详解1.ALSA声卡驱动中的DAPM详解之一:kcontrolDAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下。DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都在ASoc core中完成。用户空间的应用程序无需对代码做出修改,也无需重新编译,DAPM根据当前激活的音频流(playback/capture)和声卡中的mixer等的配置来决定那些音频控件的电源开关被打开或关闭。/*/声明:本博内

2、容均由/*/DAPM控件是由普通的soc音频控件演变而来的,所以本章的内容我们先从普通的soc音频控件开始。snd_kcontrol_new结构在正式讨论DAPM之前,我们需要先搞清楚ASoc中的一个重要的概念:kcontrol,不熟悉的读者需要浏览一下我之前的文章:Linux ALSA声卡驱动之四:Control设备的创建。通常,一个kcontrol代表着一个mixer(混音器),或者是一个mux(多路开关),又或者是一个音量控制器等等。 从上述文章中我们知道,定义一个kcontrol主要就是定义一个snd_kcontrol_new结构,为了方便讨论,这里再次给出它的定义:cppview p

3、laincopystructsnd_kcontrol_newsnd_ctl_elem_iface_tiface;/*interfaceidentifier*/unsignedintdevice;/*device/clientnumber*/unsignedintsubdevice;/*subdevice(substream)number*/constunsignedchar*name;/*ASCIInameofitem*/unsignedintindex;/*indexofitem*/unsignedintaccess;/*accessrights*/unsignedintcount;/*co

4、untofsameelements*/snd_kcontrol_info_t*info;snd_kcontrol_get_t*get;snd_kcontrol_put_t*put;unionsnd_kcontrol_tlv_rw_t*c;max-ucontrol-value.integer.value1;return0;上述代码一目了然,从private_value字段取出soc_mixer_control结构,利用该结构的信息,访问对应的寄存器,返回相应的值。SOC_SINGLE_TLV SOC_SINGLE_TLV是SOC_SINGLE的一种扩展,主要用于定义那些有增益控制的控件,例如音量

5、控制器,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_READWRITE,.tlv.p=(tlv_array),.info=snd_soc_info_volsw,.get=snd_soc_get_volsw,.put=snd_soc_put_volsw,.priv

6、ate_value=SOC_SINGLE_VALUE(reg,shift,max,invert)从他的定义可以看出,用于设定寄存器信息的private_value字段的定义和SOC_SINGLE是一样的,甚至put、get回调函数也是使用同一套,唯一不同的是增加了一个tlv_array参数,并把它赋值给了tlv.p字段。关于tlv,已经在Linux ALSA声卡驱动之四:Control设备的创建中进行了阐述。用户空间可以通过对声卡的control设备发起以下两种ioctl来访问tlv字段所指向的数组: SNDRV_CTL_IOCTL_TLV_READ SNDRV_CTL_IOCTL_TLV_W

7、RITE SNDRV_CTL_IOCTL_TLV_COMMAND通常,tlv_array用来描述寄存器的设定值与它所代表的实际意义之间的映射关系,最常用的就是用于音量控件时,设定值与对应的dB值之间的映射关系,请看以下例子:cppview plaincopystaticconstDECLARE_TLV_DB_SCALE(mixin_boost_tlv,0,900,0);staticconststructsnd_kcontrol_newwm1811_snd_controls=SOC_SINGLE_TLV(MIXINLIN1LPBoostVolume,WM8994_INPUT_MIXER_1,7,

8、1,0,mixin_boost_tlv),SOC_SINGLE_TLV(MIXINLIN1RPBoostVolume,WM8994_INPUT_MIXER_1,8,1,0,mixin_boost_tlv),;DECLARE_TLV_DB_SCALE用于定义一个dB值映射的tlv_array,上述的例子表明,该tlv的类型是SNDRV_CTL_TLVT_DB_SCALE,寄存器的最小值对应是0dB,寄存器每增加一个单位值,对应的dB数增加是9dB(0.01dB*900),而由接下来的两组SOC_SINGLE_TLV定义可以看出,我们定义了两个boost控件,寄存器的地址都是WM8994_INPU

9、T_MIXER_1,控制位分别是第7bit和第8bit,最大值是1,所以,该控件只能设定两个数值0和1,对应的dB值就是0dB和9dB。SOC_DOUBLE 与SOC_SINGLE相对应,区别是SOC_SINGLE只控制一个变量,而SOC_DOUBLE则可以同时在一个寄存器中控制两个相似的变量,最常用的就是用于一些立体声的控件,我们需要同时对左右声道进行控制,因为多了一个声道,参数也就相应地多了一个shift位移值,cppview plaincopy#defineSOC_DOUBLE(xname,reg,shift_left,shift_right,max,invert).iface=SNDR

10、V_CTL_ELEM_IFACE_MIXER,.name=(xname),.info=snd_soc_info_volsw,.get=snd_soc_get_volsw,.put=snd_soc_put_volsw,.private_value=SOC_DOUBLE_VALUE(reg,shift_left,shift_right,max,invert)SOC_DOUBLE_R 与SOC_DOUBLE类似,对于左右声道的控制寄存器不一样的情况,使用SOC_DOUBLE_R来定义,参数中需要指定两个寄存器地址。SOC_DOUBLE_TLV 与SOC_SINGLE_TLV对应的立体声版本,通常用于

11、立体声音量控件的定义。SOC_DOUBLE_R_TLV 左右声道有独立寄存器控制的SOC_DOUBLE_TLV版本Mixer控件Mixer控件用于音频通道的路由控制,由多个输入和一个输出组成,多个输入可以自由地混合在一起,形成混合后的输出: 图1 Mixer混音器对于Mixer控件,我们可以认为是多个简单控件的组合,通常,我们会为mixer的每个输入端都单独定义一个简单控件来控制该路输入的开启和关闭,反应在代码上,就是定义一个soc_kcontrol_new数组:cppview plaincopystaticconststructsnd_kcontrol_newleft_speaker_mix

12、er=SOC_SINGLE(InputSwitch,WM8993_SPEAKER_MIXER,7,1,0),SOC_SINGLE(IN1LPSwitch,WM8993_SPEAKER_MIXER,5,1,0),SOC_SINGLE(OutputSwitch,WM8993_SPEAKER_MIXER,3,1,0),SOC_SINGLE(DACSwitch,WM8993_SPEAKER_MIXER,6,1,0),;以上这个mixer使用寄存器WM8993_SPEAKER_MIXER的第3,5,6,7位来分别控制4个输入端的开启和关闭。Mux控件mux控件与mixer控件类似,也是多个输入端和一个输

13、出端的组合控件,与mixer控件不同的是,mux控件的多个输入端同时只能有一个被选中。因此,mux控件所对应的寄存器,通常可以设定一段连续的数值,每个不同的数值对应不同的输入端被打开,与上述的mixer控件不同,ASoc用soc_enum结构来描述mux控件的寄存器信息:cppview plaincopy/*enumeratedkcontrol*/structsoc_enumunsignedshortreg;unsignedshortreg2;unsignedcharshift_l;unsignedcharshift_r;unsignedintmax;unsignedintmask;const

14、char*const*texts;constunsignedint*values;两个寄存器地址和位移字段:reg,reg2,shift_l,shift_r,用于描述左右声道的控制寄存器信息。字符串数组指针用于描述每个输入端对应的名字,value字段则指向一个数组,该数组定义了寄存器可以选择的值,每个值对应一个输入端,如果value是一组连续的值,通常我们可以忽略values参数。下面我们先看看如何定义一个mux控件:第一步,定义字符串和values数组,以下的例子因为values是连续的,所以不用定义:cppview plaincopystaticconstchar*drc_path_tex

15、t=ADC,DAC;第二步,利用ASoc提供的辅助宏定义soc_enum结构,用于描述寄存器:cppview plaincopystaticconststructsoc_enumdrc_path=SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1,14,2,drc_path_text);第三步,利痛ASoc提供的辅助宏,定义soc_kcontrol_new结构,该结构最后用于注册该mux控件:cppview plaincopystaticconststructsnd_kcontrol_newwm8993_snd_controls=SOC_DOUBLE_TLV(.),.SO

16、C_ENUM(DRCPath,drc_path),.以上几步定义了一个叫DRC PATH的mux控件,该控件具有两个输入选择,分别是来自ADC和DAC,用寄存器WM8993_DRC_CONTROL_1控制。其中,soc_enum结构使用了辅助宏SOC_ENUM_SINGLE来定义,该宏的声明如下:cppview plaincopy#defineSOC_ENUM_DOUBLE(xreg,xshift_l,xshift_r,xmax,xtexts).reg=xreg,.shift_l=xshift_l,.shift_r=xshift_r,.max=xmax,.texts=xtexts,.mask=

17、xmax?roundup_pow_of_two(xmax)-1:0#defineSOC_ENUM_SINGLE(xreg,xshift,xmax,xtexts)SOC_ENUM_DOUBLE(xreg,xshift,xshift,xmax,xtexts)定义soc_kcontrol_new结构时使用了SOC_ENUM,列出它的定义如下:cppview plaincopy#defineSOC_ENUM(xname,xenum).iface=SNDRV_CTL_ELEM_IFACE_MIXER,.name=xname,.info=snd_soc_info_enum_double,.get=snd_

18、soc_get_enum_double,.put=snd_soc_put_enum_double,.private_value=(unsignedlong)&xenum思想如此统一,依然是使用private_value字段记录soc_enum结构,不过几个回调函数变了,我们看看get回调对应的snd_soc_get_enum_double函数:cppview plaincopyintsnd_soc_get_enum_double(structsnd_kcontrol*kcontrol,structsnd_ctl_elem_value*ucontrol)structsnd_soc_codec*c

19、odec=snd_kcontrol_chip(kcontrol);structsoc_enum*e=(structsoc_enum*)kcontrol-private_value;unsignedintval;val=snd_soc_read(codec,e-reg);ucontrol-value.enumerated.item0=(vale-shift_l)&e-mask;if(e-shift_l!=e-shift_r)ucontrol-value.enumerated.item1=(vale-shift_r)&e-mask;return0;通过info回调函数则可以获取某个输入端所对应的名

20、字,其实就是从soc_enum结构的texts数组中获得:cppview plaincopyintsnd_soc_info_enum_double(structsnd_kcontrol*kcontrol,structsnd_ctl_elem_info*uinfo)structsoc_enum*e=(structsoc_enum*)kcontrol-private_value;uinfo-type=SNDRV_CTL_ELEM_TYPE_ENUMERATED;uinfo-count=e-shift_l=e-shift_r?1:2;uinfo-value.enumerated.items=e-ma

21、x;if(uinfo-value.enumerated.iteme-max-1)uinfo-value.enumerated.item=e-max-1;strcpy(uinfo-value.enumerated.name,e-textsuinfo-value.enumerated.item);return0;以下是另外几个常用于定义mux控件的宏:SOC_VALUE_ENUM_SINGLE 用于定义带values字段的soc_enum结构。SOC_VALUE_ENUM_DOUBLE SOC_VALUE_ENUM_SINGLE的立体声版本。SOC_VALUE_ENUM 用于定义带values字段

22、snd_kcontrol_new结构,这个有点特别,我们还是看看它的定义:cppview plaincopy#defineSOC_VALUE_ENUM(xname,xenum).iface=SNDRV_CTL_ELEM_IFACE_MIXER,.name=xname,.info=snd_soc_info_enum_double,.get=snd_soc_get_value_enum_double,.put=snd_soc_put_value_enum_double,.private_value=(unsignedlong)&xenum从定义可以看出来,回调函数被换掉了,我们看看他的get回调:

23、cppview plaincopyintsnd_soc_get_value_enum_double(structsnd_kcontrol*kcontrol,structsnd_ctl_elem_value*ucontrol)structsnd_soc_codec*codec=snd_kcontrol_chip(kcontrol);structsoc_enum*e=(structsoc_enum*)kcontrol-private_value;unsignedintreg_val,val,mux;reg_val=snd_soc_read(codec,e-reg);val=(reg_vale-sh

24、ift_l)&e-mask;for(mux=0;muxmax;mux+)if(val=e-valuesmux)break;ucontrol-value.enumerated.item0=mux;if(e-shift_l!=e-shift_r)val=(reg_vale-shift_r)&e-mask;for(mux=0;muxmax;mux+)if(val=e-valuesmux)break;ucontrol-value.enumerated.item1=mux;return0;与SOC_ENUM定义的mux不同,它没有直接返回寄存器的设定值,而是通过soc_enum结构中的values字段做了一次转换,与values数组中查找和寄存器相等的值,然后返回他在values数组中的索引值,所以,尽管寄存器的值可能是不连续的,但返回的值是连续的。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1