DPAM_widget_roue_path

DPAM是什么?

1)DAPM是Dynamic Audio Power的缩写,直译过来就是动态音频电源管理的意思。
2)DAPM是为了急于Linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下。
3)DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都工作在ASoc Core中完成。
4)DAPM根据当前激活的音频流(playback/capture)和声卡中的mixer等的配置来决定那些音频控件的电源开关被打开或者关闭。
5)DPAM包括route,path和widget。

LINPUT

123
说明:
如红色框所示,需要经过一个开关,一个放大器,一个开关和混合器。

简化图

在这里插入图片描述
说明:要使用LINPUT1的录音功能,需要打开如红色框所示的开关。

wdiget

wdiget

场景需求:
在打开LINPUT1 Switch开关时,同时打开Left Boost Mixer,便产生了widget这个功能。
说明:
1)mixer有多个输入源,只要其中的某个开关使能,顺便把mixer也使能。
2)使用一个widget来表示上图的结构,则widget组成如下:
一个mixer和3个开关;开关用kcontrol表示,kcontrol中的put函数不仅设置开关的reg,顺便设置mixer的reg。
代码如下:

 271 SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,                     
 272                    wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)),

 224 static const struct snd_kcontrol_new wm8960_lin_boost[] = {                     
 225 SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0),                     
 226 SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0),                     
 227 SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0),                     
 228 };

说明:
1)就是图中的3个LINPUT Switch和Left Boost Mixer组成一个widget。
2)普通的snd_kcontrol_new通过SOC_SINGLE声明;DPAM的snd_kcontrol_new通过SOC_DAPM_SINGLE声明。

route

场景:
当LINPUT1 switch打开时,LINPUT1应该打开,Left Boost Mixer也应该打开,LINPUT1怎么知道左右连接了那些widget?这时候就需要route,驱动定义一个snd_soc_route结构数组,数组的条目描述了目的widget和源widget的名称,以及这个kcontrol的名称。

route
说明:
1)蓝色框LINPUT1 Switch是kcontrol,红色框是两个 wdiget,绿色框是一个route.
2)route的格式:
{sink,kcontrol,source}

 261 static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = {               
 262 SND_SOC_DAPM_INPUT("LINPUT1"),                                                                                                                  
                                             
 268                                                                                 
 269 SND_SOC_DAPM_MICBIAS("MICB", WM8960_POWER1, 1, 0),                              
 270                                                                                 
 271 SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,                     
 272                    wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)), 


 224 static const struct snd_kcontrol_new wm8960_lin_boost[] = {                     
 225 SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0),                     
 226 SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0),                     
 227 SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0),                                                                                     
 228 };

 323 static const struct snd_soc_dapm_route audio_paths[] = {                        
 324         { "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" }, 
 .....
 }

说明:代码如上,结合图,LINPUT1,LINPUT1 Switch和Left Boost Mixer组成一个root。

path的创建

1)widget没有连接,wdiget之间使用snd_soc_path结构进行连接的,驱动 使用snd_soc_dapm_add_routes来注册连接信息。
2)根据route中各个name,创建path。
sound/soc/codecs/wm8960.c中

 386 static int wm8960_add_widgets(struct snd_soc_codec *codec)                      
 387 {                                                                               
 388         struct wm8960_data *pdata = codec->dev->platform_data;                  
 389         struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);          
 390         struct snd_soc_dapm_context *dapm = &codec->dapm;                       
 391         struct snd_soc_dapm_widget *w;                                          
 392                                                                                 
 393         snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,                    
 394                                   ARRAY_SIZE(wm8960_dapm_widgets));             
 395                                                                                 
 396         snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
 }

1810 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,                  
1811                             const struct snd_soc_dapm_route *route, int num)    
1812 {                                                                               
1813         int i, ret;                                                             
1814                                                                                 
1815         for (i = 0; i < num; i++) {                                             
1816                 ret = snd_soc_dapm_add_route(dapm, route);                      
1817                 if (ret < 0) {                                                  
1818                         dev_err(dapm->dev, "Failed to add route %s->%s\n",      
1819                                 route->source, route->sink);                    
1820                         return ret;                                             
1821                 }                                                               
1822                 route++;                                                        
1823         }                                                                                                                                       
1824                                                                                 
1825         return 0;                                                               
1826 }  

说明:
在396行中,进入snd_soc_dapm_add_routes中,在1816行进入snd_soc_dapm_add_route

1656 static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,            
1657                                   const struct snd_soc_dapm_route *route)       
1658 {                                                                               
1659         struct snd_soc_dapm_path *path;                                         
1660         struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;          
1661         struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;                                                                            
1662         const char *sink;                                                       
1663         const char *control = route->control;                                   
1664         const char *source;                                                     
1665         char prefixed_sink[80];                                                 
1666         char prefixed_source[80];                                               
1667         int ret = 0;                                                            
1668                                                                                 
1669         if (dapm->codec && dapm->codec->name_prefix) {                          
1670                 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",         
1671                          dapm->codec->name_prefix, route->sink);                
1672                 sink = prefixed_sink;                                           
1673                 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",     
1674                          dapm->codec->name_prefix, route->source);              
1675                 source = prefixed_source;                                       
1676         } else {                                                                
1677                 sink = route->sink;                                             
1678                 source = route->source;                                         
1679         }                                                                       
1680                                                                                 
1681         /*                                                                      
1682          * find src and dest widgets over all widgets but favor a widget from   
1683          * current DAPM context            
.....
           1778         case snd_soc_dapm_hp:                                                   
1779         case snd_soc_dapm_mic:                                                  
1780         case snd_soc_dapm_line:                                                 
1781         case snd_soc_dapm_spk:                                                  
1782                 list_add(&path->list, &dapm->card->paths);                      
1783                 list_add(&path->list_sink, &wsink->sources);                    
1784                 list_add(&path->list_source, &wsource->sinks);                  
1785                 path->connect = 0;                                              
1786                 return 0;                                                       
1787         }                                                                       
1788         return 0;                                                               
1789                                                                                 
1790 err:                                                                            
1791         dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",       
1792                  source, control, sink);                                        
1793         kfree(path);                                                            
1794         return ret;                                                                                                                             
1795 }                             

说明:创建struct snd_soc_dapm_path指针,然后把audio里面的sink,kcontrol和source创建route。
结构体的定义:

420 struct snd_soc_dapm_path {                                                      
421         char *name;                                                             
422         char *long_name;                                                        
423                                                                                 
424         /* source (input) and sink (output) widgets */                          
425         struct snd_soc_dapm_widget *source;                                     
426         struct snd_soc_dapm_widget *sink;                                       
427         struct snd_kcontrol *kcontrol;                                                                                                           
428                                                                                 
429         /* status */                                                            
430         u32 connect:1;  /* source and sink widgets are connected */             
431         u32 walked:1;   /* path has been walked */                              
432                                                                                 
433         int (*connected)(struct snd_soc_dapm_widget *source,                    
434                          struct snd_soc_dapm_widget *sink);                     
435                                                                                 
436         struct list_head list_source;                                           
437         struct list_head list_sink;                                             
438         struct list_head list;                                                  
439 }; 

结构体snd_soc_dapm_path定义如下:

419 /* dapm audio path between two widgets */                                       
420 struct snd_soc_dapm_path {                                                      
421         char *name;                                                             
422         char *long_name;                                                        
423                                                                                 
424         /* source (input) and sink (output) widgets */                          
425         struct snd_soc_dapm_widget *source;                                     
426         struct snd_soc_dapm_widget *sink;                                       
427         struct snd_kcontrol *kcontrol;                                                                                                           
428                                                                                 
429         /* status */                                                            
430         u32 connect:1;  /* source and sink widgets are connected */             
431         u32 walked:1;   /* path has been walked */                              
432                                                                                 
433         int (*connected)(struct snd_soc_dapm_widget *source,                    
434                          struct snd_soc_dapm_widget *sink);                     
435                                                                                 
436         struct list_head list_source;                                           
437         struct list_head list_sink;                                             
438         struct list_head list;                                                  
439 }; 

kcontrol的put函数的动作

1968 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,                       
1969         struct snd_ctl_elem_value *ucontrol)                                    
1970 {                                                                               
1971         struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);                                                                   
1972         struct snd_soc_dapm_widget *widget = wlist->widgets[0];                 
1973         struct snd_soc_codec *codec = widget->codec;                            
1974         struct soc_mixer_control *mc =                                          
1975                 (struct soc_mixer_control *)kcontrol->private_value;            
1976         unsigned int reg = mc->reg;                                             
1977         unsigned int shift = mc->shift;                                         
1978         int max = mc->max;                                                      
1979         unsigned int mask = (1 << fls(max)) - 1;                                
1980         unsigned int invert = mc->invert;                                       
1981         unsigned int val;                                                       
1982         int connect, change;                                                    
1983         struct snd_soc_dapm_update update;                                      
1984         int wi;                                                                 
1985                                                                                 
1986         val = (ucontrol->value.integer.value[0] & mask);                        
1987                                                                                 
1988         if (invert)                                                             
1989                 val = max - val;                                                
1990         mask = mask << shift;                                                   
1991         val = val << shift;                                                     
1992                                                                                 
1993         if (val)        
 1994                 /* new connection */                                            
1995                 connect = invert ? 0 : 1;                                       
1996         else                                                                    
1997                 /* old connection must be powered down */                       
1998                 connect = invert ? 1 : 0;                                       
1999                                                                                 
2000         mutex_lock(&codec->mutex);                                              
2001                                                                                 
2002         change = snd_soc_test_bits(widget->codec, reg, mask, val);              
2003         if (change) {                                                           
2004                 for (wi = 0; wi < wlist->num_widgets; wi++) {                   
2005                         widget = wlist->widgets[wi];                            
2006                                                                                 
2007                         widget->value = val;                                    
2008                                                                                 
2009                         update.kcontrol = kcontrol;                             
2010                         update.widget = widget;                                 
2011                         update.reg = reg;                                       
2012                         update.mask = mask;                                     
2013                         update.val = val;                                       
2014                         widget->dapm->update = &update;                         
2015                                                                                                                                                 
2016                         dapm_mixer_update_power(widget, kcontrol, connect);     
2017                                                                                 
2018                         widget->dapm->update = NULL;                            
2019                 }                                                               
2020         }            

1470 static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,          
1471                                    struct snd_kcontrol *kcontrol, int connect)  
1472 {                                                                               
1473         struct snd_soc_dapm_path *path;                                         
1474         int found = 0;                                                          
1475                                                                                 
1476         if (widget->id != snd_soc_dapm_mixer &&                                 
1477             widget->id != snd_soc_dapm_mixer_named_ctl &&                       
1478             widget->id != snd_soc_dapm_switch)                                  
1479                 return -ENODEV;                                                 
1480                                                                                 
1481         /* find dapm widget path assoc with kcontrol */                         
1482         list_for_each_entry(path, &widget->dapm->card->paths, list) {           
1483                 if (path->kcontrol != kcontrol)                                 
1484                         continue;                                               
1485                                                                                 
1486                 /* found, now check type */                                     
1487                 found = 1;                                                      
1488                 path->connect = connect;                                        
1489                 break;                                                          
1490         }                                                                       
1491                                                                                                                                                 
1492         if (found)                                                              
1493                 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);      
1494                                                                                 
1495         return 0;                                                               
1496 }

                                                                                                      

1
kcontrol的put函数的作用:
1)在1995行设置connected
2)在1493行使用dapm_power_widgets函数进行设置。
a. 无人使用声卡,不设置,不启动任何寄存器。
b. 有app使用声卡,也许会设置寄存器。

总结

总结:
a. tinymix设置普通的kcontrol:会直接设置寄存器
b. tinymix设置DAPM的kcontrol:设置所在path的connect,
调用dapm_power_widgets(widget>dpam,SND_SOC_DAPM_STREAM_NOP);
c. tinyplay,tinycap在传输数据之前,调用dapm_power_widgets(dapm,event)
d. dapm_power_widgets在有app使用声卡的前提下会找出complete_path,
设置上面的所有widget。

说明:tinymix命令没有使用声卡,tinyplay和tinycap使用声卡。

complete path

complete path
说明:
1)如上图所示,path1,path2和path3组成一个complete path。
2)complete path上各个path都是connect状态,并且有app使用声卡,才会启动所涉及的寄存器或者叫widget。

3)complete path上各个path都是connect状态,并且有app使用声卡,才会启动所涉及的寄存器或者叫widget。

录音步骤

  1. 使用tinymix打开LINPUT1 Switch和Boost Switch开关。
  2. 然后使用tinycap录音,tiny会打开complete路上的widget。

说明:
需要集合更多实验例子,才能说明流程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值