Asoc dapm(一) - kcontrol

转自:http://blog.csdn.net/luckywang1103/article/details/49095655

 

目录(?)[-]

  1. struct snd_kcontrol_new
  2. 一些构造snd_kcontrol_new结构体的宏
    1. SOC_SINGLE
    2. SOC_SINGLE_TLV
    3. SOC_ENUM
    4. SOC_ENUM_EXT
    5. SOC_VALUE_ENUM
    6. SOC_DOUBLE
    7. SOC_DOUBLE_R
    8. SOC_DOUBLE_TLV
    9. SOC_DOUBLE_R_TLV
    10. 其他
  3. 参考文章

接下来准备写几篇和asoc dapm相关的文章
1. kcontrol宏
2. kcontrol的注册与使用
3. dapm widgets & dapm kcontrol & dapm route
4. dapm_widget & dapm_route注册
5. dapm route的更新


struct snd_kcontrol_new

<code class="hljs objectivec has-numbering"><span class="hljs-keyword">struct</span> snd_kcontrol_new {
    snd_ctl_elem_iface_t iface; <span class="hljs-comment">/* interface identifier */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> device;        <span class="hljs-comment">/* device/client number */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> subdevice;     <span class="hljs-comment">/* subdevice (substream) number */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *name;        <span class="hljs-comment">/* ASCII name of item */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> index;     <span class="hljs-comment">/* index of item */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> access;        <span class="hljs-comment">/* access rights */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> count;     <span class="hljs-comment">/* count of same elements */</span>
    snd_kcontrol_info_t *info;
    snd_kcontrol_get_t *get;
    snd_kcontrol_put_t *put;
    <span class="hljs-keyword">union</span> {
        snd_kcontrol_tlv_rw_t *c;
        <span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *p;
    } tlv;
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> private_value;
};</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul>

iface:control类型,通常是SNDRV_CTL_ELEM_IFACE_MIXER
name:kcontrol的名字,名字的命名规则遵循”源-方向-功能”
源可理解为control的输入端,如Master, PCM, CD, line等
方向代表kcontrol的数据流向,如Playback, Capture, Bypass, 也可以不定义,这时是双向的
功能,如Switch, Volume, Route等

通常会借助include/sound/soc.h文件中的宏来定义这个结构体,比如SOC_SINGLE等。
另外info, get, put三个字段是一些回调函数,常常使用sound/soc/soc-core.c文件提供的函数,而不用自己去实现。

kcontrol与dapm kcontrol区别
kcontrol通常用于控件的音量等控制,而dapm kcontrol相关的kcontrol则是用于widget电源管理的开关。


一些构造snd_kcontrol_new结构体的宏

SOC_SINGLE

<code class="hljs avrasm has-numbering"><span class="hljs-preprocessor">#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \</span>
    ((unsigned long)&(struct soc_mixer_control) \
    {<span class="hljs-preprocessor">.reg</span> = xreg, <span class="hljs-preprocessor">.shift</span> = xshift, <span class="hljs-preprocessor">.rshift</span> = xshift, <span class="hljs-preprocessor">.max</span> = xmax, \
    <span class="hljs-preprocessor">.invert</span> = xinvert})
<span class="hljs-preprocessor">#define SOC_SINGLE(xname, reg, shift, max, invert) \</span>
{   <span class="hljs-preprocessor">.iface</span> = SNDRV_CTL_ELEM_IFACE_MIXER, <span class="hljs-preprocessor">.name</span> = xname, \
    <span class="hljs-preprocessor">.info</span> = snd_soc_info_volsw, <span class="hljs-preprocessor">.get</span> = snd_soc_get_volsw,\
    <span class="hljs-preprocessor">.put</span> = snd_soc_put_volsw, \
    <span class="hljs-preprocessor">.private</span>_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

SOC_SINGLE定义最简单的控件,这种控件只有一个控制量,比如一个开关,或者是数值的变化(比如codec中的某个频率,FIFO大小等)
参数:xname(该控件的名字),reg(该控件对应的寄存器的地址),shift(控制位在寄存器中的位移),max(控件可设置的最大值),invert(设定值是否取反)

SOC_SINGLE_VALUE宏定义private_value字段,目的主要是为了填充struct soc_mixer_control结构体
当上层调用info, get, put函数的时候可以将kcontrol->private_value强制转换为struct soc_mixer_control类型,然后使用这个结构体中的reg, shift, max等数据。


SOC_SINGLE_TLV

<code class="hljs avrasm has-numbering"><span class="hljs-preprocessor">#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \</span>
    ((unsigned long)&(struct soc_mixer_control) \
    {<span class="hljs-preprocessor">.reg</span> = xreg, <span class="hljs-preprocessor">.shift</span> = xshift, <span class="hljs-preprocessor">.rshift</span> = xshift, <span class="hljs-preprocessor">.max</span> = xmax, \
    <span class="hljs-preprocessor">.invert</span> = xinvert})
<span class="hljs-preprocessor">#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \</span>
{   <span class="hljs-preprocessor">.iface</span> = SNDRV_CTL_ELEM_IFACE_MIXER, <span class="hljs-preprocessor">.name</span> = xname, \
    <span class="hljs-preprocessor">.access</span> = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
         SNDRV_CTL_ELEM_ACCESS_READWRITE,\
    <span class="hljs-preprocessor">.tlv</span><span class="hljs-preprocessor">.p</span> = (tlv_array), \
    <span class="hljs-preprocessor">.info</span> = snd_soc_info_volsw, <span class="hljs-preprocessor">.get</span> = snd_soc_get_volsw,\
    <span class="hljs-preprocessor">.put</span> = snd_soc_put_volsw, \
    <span class="hljs-preprocessor">.private</span>_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

该宏和SOC_SINGLE类似,唯一不同的是增加了tlv.p字段,适用于那些以dB为单位的kcontrol。

DECLARE_TLV_DB_SCALE(name, min, step, mute)宏来构造变量tlv_array。
参数name是变量的名字,min是最小值,step是步进值,如果mute=1,当该kcontrol处于最小值时会mute。

来看一个实例:

<code class="hljs r has-numbering">/* from <span class="hljs-number">0</span> to <span class="hljs-number">30</span> dB <span class="hljs-keyword">in</span> <span class="hljs-number">2</span> dB steps */
static DECLARE_TLV_DB_SCALE(vga_tlv, <span class="hljs-number">0</span>, <span class="hljs-number">200</span>, <span class="hljs-number">0</span>);

static const struct snd_kcontrol_new uda1380_snd_controls[] = {
<span class="hljs-keyword">...</span>
SOC_SINGLE_TLV(<span class="hljs-string">"Mic Capture Volume"</span>, UDA1380_ADC, <span class="hljs-number">8</span>, <span class="hljs-number">15</span>, <span class="hljs-number">0</span>, vga_tlv),   /* VGA_CTRL */
}</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

寄存器UDA1380_ADC的偏移8bit处定义了”Mic Capture Volume”,寄存器最大值为15,对应到dB的最小值是0dB,步进值是200*0.01dB=2dB,最大值是15*2dB=30dB
如上这样,寄存器的值与实际增益控制就有一个映射关系了。


SOC_ENUM

<code class="hljs avrasm has-numbering"><span class="hljs-preprocessor">#define SOC_ENUM(xname, xenum) \</span>
{   <span class="hljs-preprocessor">.iface</span> = SNDRV_CTL_ELEM_IFACE_MIXER, <span class="hljs-preprocessor">.name</span> = xname,\
    <span class="hljs-preprocessor">.info</span> = snd_soc_info_enum_double, \
    <span class="hljs-preprocessor">.get</span> = snd_soc_get_enum_double, <span class="hljs-preprocessor">.put</span> = snd_soc_put_enum_double, \
    <span class="hljs-preprocessor">.private</span>_value = (unsigned long)&xenum }

<span class="hljs-preprocessor">#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \</span>
{   <span class="hljs-preprocessor">.reg</span> = xreg, <span class="hljs-preprocessor">.shift</span>_l = xshift_l, <span class="hljs-preprocessor">.shift</span>_r = xshift_r, \
    <span class="hljs-preprocessor">.max</span> = xmax, <span class="hljs-preprocessor">.texts</span> = xtexts }
<span class="hljs-preprocessor">#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \</span>
    SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
//xtexts就是mux或者mixer多个输入源的名字,是字符串数组</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

SOC_ENUM可以用来定义mux, mixer等有多个输入的控件。
SOC_ENUM_SINGLE或SOC_ENUM_DOUBLE用来构造SOC_ENUM中的private_value字段。当info、get、put函数被调用时,会将这个private_value转化成struct soc_enum结构体类型来对数据进行处理。

对于mixer

<code class="hljs cs has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *uda134x_dsp_setting[] = {<span class="hljs-string">"Flat"</span>, <span class="hljs-string">"Minimum1"</span>, <span class="hljs-string">"Minimum2"</span>, <span class="hljs-string">"Maximum"</span>};
<span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *uda134x_deemph[] = {<span class="hljs-string">"None"</span>, <span class="hljs-string">"32Khz"</span>, <span class="hljs-string">"44.1Khz"</span>, <span class="hljs-string">"48Khz"</span>};
<span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *uda134x_mixmode[] = {<span class="hljs-string">"Differential"</span>, <span class="hljs-string">"Analog1"</span>, <span class="hljs-string">"Analog2"</span>, <span class="hljs-string">"Both"</span>};

<span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> soc_enum uda134x_mixer_enum[] = {
SOC_ENUM_SINGLE(UDA134X_DATA010, <span class="hljs-number">0</span>, <span class="hljs-number">0x04</span>, uda134x_dsp_setting),
SOC_ENUM_SINGLE(UDA134X_DATA010, <span class="hljs-number">3</span>, <span class="hljs-number">0x04</span>, uda134x_deemph),
SOC_ENUM_SINGLE(UDA134X_EA010, <span class="hljs-number">0</span>, <span class="hljs-number">0x04</span>, uda134x_mixmode),
};

<span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> snd_kcontrol_new uda1341_snd_controls[] = {
...
SOC_ENUM(<span class="hljs-string">"Sound Processing Filter"</span>, uda134x_mixer_enum[<span class="hljs-number">0</span>]),
SOC_ENUM(<span class="hljs-string">"PCM Playback De-emphasis"</span>, uda134x_mixer_enum[<span class="hljs-number">1</span>]),
SOC_ENUM(<span class="hljs-string">"Input Mux"</span>, uda134x_mixer_enum[<span class="hljs-number">2</span>]),
}</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>

通过SOC_ENUM(“Sound Processing Filter”, uda134x_mixer_enum[0])定义了名为“Sound processing Filter”的mixer控件
从SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting)看出通过配置寄存器UDA134X_DATA010可以控制这个mixer控件的四个输入源”Flat”, “Minimum1”, “Minimum2”, “Maximum”,输入源可以选择其中的一个或者多个。

对于mux
对于mux也类似,如SOC_ENUM(“Input Mux”, uda134x_mixer_enum[2]),只不过mux一个时候只能有一个输入源,即”Differential”, “Analog1”, “Analog2”, “Both”中只能选择一个。


SOC_ENUM_EXT

<code class="hljs avrasm has-numbering"><span class="hljs-preprocessor">#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \</span>
{   <span class="hljs-preprocessor">.max</span> = xmax, <span class="hljs-preprocessor">.texts</span> = xtexts }
<span class="hljs-preprocessor">#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \</span>
{   <span class="hljs-preprocessor">.iface</span> = SNDRV_CTL_ELEM_IFACE_MIXER, <span class="hljs-preprocessor">.name</span> = xname, \
    <span class="hljs-preprocessor">.info</span> = snd_soc_info_enum_ext, \
    <span class="hljs-preprocessor">.get</span> = xhandler_get, <span class="hljs-preprocessor">.put</span> = xhandler_put, \
    <span class="hljs-preprocessor">.private</span>_value = (unsigned long)&xenum }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

SOC_ENUM_EXT与SOC_ENUM宏很类似,但是,SOC_ENUM中构造private_value字段使用SOC_ENUM_SINGLE或者SOC_ENUM_DOUBLE,这两个宏构造的时候都和具体寄存器的某个或者某两个bit相关,而SOC_ENUM_EXT中构造private_value字段使用SOC_ENUM_SINGLE_EXT,这个宏构造的时候只要初始化字符串数组就行了。

<code class="hljs cs has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *rt5659_micbias2_power_mode[] = {
    <span class="hljs-string">"Disable"</span>, <span class="hljs-string">"Enable"</span>
};

<span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> soc_enum rt5659_micbias2_power_enum = 
    SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rt5659_micbias2_power_mode),
                rt5659_micbias2_power_mode);

<span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> rt5659_micbias2_power_get(<span class="hljs-keyword">struct</span> snd_kcontrol *kcontrol,
        <span class="hljs-keyword">struct</span> snd_ctl_elem_value *ucontrol)
{
    <span class="hljs-keyword">struct</span> snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
    <span class="hljs-keyword">int</span> pwr = snd_soc_read(codec, RT5659_PWR_ANLG_2);

    <span class="hljs-keyword">if</span> (pwr & <span class="hljs-number">0x0400</span>)
        ucontrol-><span class="hljs-keyword">value</span>.integer.<span class="hljs-keyword">value</span>[<span class="hljs-number">0</span>] = <span class="hljs-number">1</span>;
    <span class="hljs-keyword">else</span>
        ucontrol-><span class="hljs-keyword">value</span>.integer.<span class="hljs-keyword">value</span>[<span class="hljs-number">0</span>] = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> rt5659_micbias2_power_put(<span class="hljs-keyword">struct</span> snd_kcontrol *kcontrol,
        <span class="hljs-keyword">struct</span> snd_ctl_elem_value *ucontrol)
{
    <span class="hljs-keyword">struct</span> snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
    <span class="hljs-keyword">int</span> pwr = ucontrol-><span class="hljs-keyword">value</span>.integer.<span class="hljs-keyword">value</span>[<span class="hljs-number">0</span>];

    <span class="hljs-keyword">if</span> (pwr == <span class="hljs-number">1</span>) {
        snd_soc_update_bits(codec, RT5659_PWR_ANLG_3, <span class="hljs-number">0x0002</span>, <span class="hljs-number">0x0002</span>);
        snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, <span class="hljs-number">0x0200</span>, <span class="hljs-number">0x0200</span>);
        snd_soc_update_bits(codec, RT5659_PWR_ANLG_2, <span class="hljs-number">0x0400</span>, <span class="hljs-number">0x0400</span>);
        dev_info(codec->dev, <span class="hljs-string">"enable micbias2 power\n"</span>);
    } <span class="hljs-keyword">else</span> {
        snd_soc_update_bits(codec, RT5659_PWR_ANLG_3, <span class="hljs-number">0x0002</span>, <span class="hljs-number">0x0000</span>);
        snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, <span class="hljs-number">0x0200</span>, <span class="hljs-number">0x0000</span>);
        snd_soc_update_bits(codec, RT5659_PWR_ANLG_2, <span class="hljs-number">0x0400</span>, <span class="hljs-number">0x0000</span>);
        dev_info(codec->dev, <span class="hljs-string">"disable micbias2 power\n"</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}

SOC_ENUM_EXT(<span class="hljs-string">"micbias2 power"</span>, rt5659_micbias2_power_enum,
        rt5659_micbias2_power_get, rt5659_micbias2_power_put),</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li></ul>

SOC_VALUE_ENUM

SOC_VALUE_ENUM 用于定义带values字段的snd_kcontrol_new结构体
SOC_VALUE_ENUM_SINGLE和SOC_VALUE_ENUM_DOUBLE 用于定义带values字段的soc_enum结构体


SOC_DOUBLE

SOC_SINGLE在寄存器中只控制一个变量,通常用于单声道;而SOC_DOUBLE可以同时在一个寄存器中控制两个相似的变量,通常是对左右声道的控制,用于立体声。


SOC_DOUBLE_R

与SOC_DOUBLE类似,用于左右声道的控制不在一个寄存器中的情况,参数中指定两个寄存器地址


SOC_DOUBLE_TLV

SOC_DOUBLE_R_TLV


其他

下面这些带EXT的宏需要我们自己定义get, put函数
SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert, xhandler_get, xhandler_put)
SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert, xhandler_get, xhandler_put)
SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert, xhandler_get, xhandler_put, tlv_array)
SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, xhandler_get, xhandler_put, tlv_array)
SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, xhandler_get, xhandler_put, tlv_array)
SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put)


参考文章

  1. ALSA声卡驱动中的DAPM详解之一:kcontrol

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值