声卡控制之kcontrol

硬件原理图

mic连接
说明:mic连接的是WM8960的LINPUT1脚。

2. kcontrol是什么

kcontrol代表一个功能,使用一个寄存器里某些位;kcontrol有R/W函数。

3. kcontrol特性

1)一个声卡有多个kcontrol
2)一个kcontrol对应一个功能
比如: 音量、开/关、录音

4. snd_kcontrol结构体

 62 struct snd_kcontrol {                                                           
 63         struct list_head list;          /* list of controls */                  
 64         struct snd_ctl_elem_id id;                                              
 65         unsigned int count;             /* count of same elements */            
 66         snd_kcontrol_info_t *info;                                              
 67         snd_kcontrol_get_t *get;                                                
 68         snd_kcontrol_put_t *put;                                                
 69         union {                                                                 
 70                 snd_kcontrol_tlv_rw_t *c;                                       
 71                 const unsigned int *p;                                          
 72         } tlv;                                                                  
 73         unsigned long private_value;                                            
 74         void *private_data;                                                     
 75         void (*private_free)(struct snd_kcontrol *kcontrol);                    
 76         struct snd_kcontrol_volatile vd[0];     /* volatile data */             
 77 };

769 struct snd_ctl_elem_id {                                                                                                                                                                                      
770         unsigned int numid;             /* numeric identifier, zero = invalid */
771         snd_ctl_elem_iface_t iface;     /* interface identifier */              
772         unsigned int device;            /* device/client number */              
773         unsigned int subdevice;         /* subdevice (substream) number */      
774         unsigned char name[44];         /* ASCII name of item */                
775         unsigned int index;             /* index of item */                     
776 };

说明:
1)函数说明
info //获得kcontrol信息
get //获得kcontrol的值
put //设置kcontrol的值
2) private_value、private_data
提供 info/put/get使用
也许含有reg Addr和那些位

3)snd_ctl_elem_id中的numid和count
numid和count是对应的
有两个snd_kcontrol
第一个snd_kcontrol是count=3,则numid=1
第二个snd_kcontrol是count=1,则numid=4

一个numid对应着一个snd_kcontrol。
tinymix可以通过numid或者name,操作相应的kcontrol。

4. 构造kcontrol变量

4.1 声明snd_kcontrol_new结构变量

163 static const struct snd_kcontrol_new wm8960_snd_controls[] = {                  
 164 SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,                
 165                  0, 63, 0, adc_tlv),                                            
 166 SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,          
 167         6, 1, 0),                                                               
 168 SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,                    
 169         7, 1, 0),        
 ......
 }                                     

wm8960_snd_controls传递给函数snd_soc_add_controls

 978         snd_soc_add_controls(codec, wm8960_snd_controls,                                                                                                          
 979                                      ARRAY_SIZE(wm8960_snd_controls)); 

snd_soc_add_controls

2501 int snd_soc_add_controls(struct snd_soc_codec *codec,                           
2502         const struct snd_kcontrol_new *controls, int num_controls)              
2503 {                                                                               
2504         struct snd_card *card = codec->card->snd_card;                          
2505         int err, i;                                                             
2506                                                                                 
2507         for (i = 0; i < num_controls; i++) {                                    
2508                 const struct snd_kcontrol_new *control = &controls[i];          
2509                 err = snd_ctl_add(card, snd_soc_cnew(control, codec,                                                                                              
2510                                                      control->name,             
2511                                                      codec->name_prefix));      
2512                 if (err < 0) {                                                  
2513                         dev_err(codec->dev, "%s: Failed to add %s: %d\n",       
2514                                 codec->name, control->name, err);               
2515                         return err;                                             
2516                 }                                                               
2517         }                                                                       
2518                                                                                 
2519         return 0;                                                               
2520 }  

说明:使用函数snd_soc_cnew把snd_kcontrol_new结构转换成snd_kcontrol结构。

5. 存放kcontrol变量

329 int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)           
 330 {                                                                               
 331         struct snd_ctl_elem_id id;                                                                                                                                                                           
 332         unsigned int idx;                                                       
 333         int err = -EINVAL;                                                      
 334                                                                                 
 335         if (! kcontrol)                                                         
 336                 return err;                                                     
 337         if (snd_BUG_ON(!card || !kcontrol->info))                               
 338                 goto error;                                                     
 339         id = kcontrol->id;                                                      
 340         down_write(&card->controls_rwsem);                                      
 341         if (snd_ctl_find_id(card, &id)) {                                       
 342                 up_write(&card->controls_rwsem);                                
 343                 snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
 344                                         id.iface,                               
 345                                         id.device,                              
 346                                         id.subdevice,                           
 347                                         id.name,                                
 348                                         id.index);                              
 349                 err = -EBUSY;                                                   
 350                 goto error;                                                     
 351         }                                                                       
 352         if (snd_ctl_find_hole(card, kcontrol->count) < 0) {                     
 353                 up_write(&card->controls_rwsem);                                
 354                 err = -ENOMEM;                                                  
 355                 goto error;                                                     
 356         }                                                                       
 357         list_add_tail(&kcontrol->list, &card->controls);                        
 358         card->controls_count += kcontrol->count;                                
 359         kcontrol->id.numid = card->last_numid + 1;                              
 360         card->last_numid += kcontrol->count;                                    
 361         up_write(&card->controls_rwsem);                                        
 362         for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)     
 363                 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);            
 364         return 0;                                                               
 365                                                                                 
 366  error:                                                                         
 367         snd_ctl_free_one(kcontrol);                                             
 368         return err;                                                             
 369 }  

说明:list_add_tail(&kcontrol->list, &card->controls); 说明kcontrol是挂在链表card->control中。

怎么构造snd_kcontrol_new

参考wm8960.c,读芯片手册,确定reg addr位,使用宏设置结构体。

怎么使用snd_kcontrol

  1. 打开control设备
open("/dev/snd/controlC0")
  1. 通过ioctl控制
    1)在sound/core/control.c中,file_operations的结构
1508 static const struct file_operations snd_ctl_f_ops =                             
1509 {                                                                                                                                                                                                            
1510         .owner =        THIS_MODULE,                                                                     
1511         .read =         snd_ctl_read,                                                                    
1512         .open =         snd_ctl_open,                                                                    
1513         .release =      snd_ctl_release,                                                                 
1514         .llseek =       no_llseek,                                                                       
1515         .poll =         snd_ctl_poll,                                                                    
1516         .unlocked_ioctl =       snd_ctl_ioctl,                                                           
1517         .compat_ioctl = snd_ctl_ioctl_compat,                                                            
1518         .fasync =       snd_ctl_fasync,                                                                  
1519 };  

2)snd_ctl_ioctl函数中:

1272 static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1273 {                                                                               
1274         struct snd_ctl_file *ctl;                                               
1275         struct snd_card *card;                                                  
1276         struct snd_kctl_ioctl *p;                                               
1277         void __user *argp = (void __user *)arg;                                 
1278         int __user *ip = argp;                                                  
1279         int err;                                                                
1280                                                                                 
1281         ctl = file->private_data;                                               
1282         card = ctl->card;                                                       
1283         if (snd_BUG_ON(!card))                                                  
1284                 return -ENXIO;                                                  
1285         switch (cmd) {                                                          
1286         case SNDRV_CTL_IOCTL_PVERSION:                                          
1287                 return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;           
1288         case SNDRV_CTL_IOCTL_CARD_INFO:                                         
1289                 return snd_ctl_card_info(card, ctl, cmd, argp);                 
1290         case SNDRV_CTL_IOCTL_ELEM_LIST:                                         
1291                 return snd_ctl_elem_list(card, argp);                           
1292         case SNDRV_CTL_IOCTL_ELEM_INFO:                                         
1293                 return snd_ctl_elem_info_user(ctl, argp);                       
1294         case SNDRV_CTL_IOCTL_ELEM_READ:                                         
1295                 return snd_ctl_elem_read_user(card, argp);                      
1296         case SNDRV_CTL_IOCTL_ELEM_WRITE:                                        
1297                 return snd_ctl_elem_write_user(ctl, argp);                      
1298         case SNDRV_CTL_IOCTL_ELEM_LOCK:                                         
1299                 return snd_ctl_elem_lock(ctl, argp);                            
1300         case SNDRV_CTL_IOCTL_ELEM_UNLOCK:                                       
1301                 return snd_ctl_elem_unlock(ctl, argp);                          
1302         case SNDRV_CTL_IOCTL_ELEM_ADD:                                          
1303                 return snd_ctl_elem_add_user(ctl, argp, 0);                     
1304         case SNDRV_CTL_IOCTL_ELEM_REPLACE:                                      
1305                 return snd_ctl_elem_add_user(ctl, argp, 1);       
      1306         case SNDRV_CTL_IOCTL_ELEM_REMOVE:                                       
1307                 return snd_ctl_elem_remove(ctl, argp);                          
1308         case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:                                  
1309                 return snd_ctl_subscribe_events(ctl, ip);                       
1310         case SNDRV_CTL_IOCTL_TLV_READ:                                          
1311                 return snd_ctl_tlv_ioctl(ctl, argp, 0);                         
1312         case SNDRV_CTL_IOCTL_TLV_WRITE:                                         
1313                 return snd_ctl_tlv_ioctl(ctl, argp, 1);                         
1314         case SNDRV_CTL_IOCTL_TLV_COMMAND:                                       
1315                 return snd_ctl_tlv_ioctl(ctl, argp, -1);                        
1316         case SNDRV_CTL_IOCTL_POWER:                                             
1317                 return -ENOPROTOOPT;                                            
1318         case SNDRV_CTL_IOCTL_POWER_STATE:                                       
1319 #ifdef CONFIG_PM                                                                
1320                 return put_user(card->power_state, ip) ? -EFAULT : 0;           
1321 #else                                                                           
1322                 return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;          
1323 #endif                                                                          
1324         }                                                                       
1325         down_read(&snd_ioctl_rwsem);                                            
1326         list_for_each_entry(p, &snd_control_ioctls, list) {                     
1327                 err = p->fioctl(card, ctl, cmd, arg);                           
1328                 if (err != -ENOIOCTLCMD) {                                      
1329                         up_read(&snd_ioctl_rwsem);                              
1330                         return err;                                             
1331                 }                                                               
1332         }                                                                       
1333         up_read(&snd_ioctl_rwsem);                                                                                                                                                                           
1334         snd_printdd("unknown ioctl = 0x%x\n", cmd);                             
1335         return -ENOTTY;                                                         
1336 }         

说明:
在1294行的宏对应着snd_ctl_elem_read_use
2)snd_ctl_elem_read_use函数

 852 static int snd_ctl_elem_read_user(struct snd_card *card,                        
 853                                   struct snd_ctl_elem_value __user *_control)   
 854 {                                                                               
 855         struct snd_ctl_elem_value *control;                                     
 856         int result;                                                             
 857                                                                                 
 858         control = memdup_user(_control, sizeof(*control));                      
 859         if (IS_ERR(control))                                                    
 860                 return PTR_ERR(control);                                        
 861                                                                                 
 862         snd_power_lock(card);                                                   
 863         result = snd_power_wait(card, SNDRV_CTL_POWER_D0);                      
 864         if (result >= 0)                                                        
 865                 result = snd_ctl_elem_read(card, control);                      
 866         snd_power_unlock(card);                                                 
 867         if (result >= 0)                                                        
 868                 if (copy_to_user(_control, control, sizeof(*control)))          
 869                         result = -EFAULT;                                       
 870         kfree(control);                                                                                                                                                                                      
 871         return result;                                                          
 872 }  

3)进入865行的snd_ctl_elem_read

 826 static int snd_ctl_elem_read(struct snd_card *card,                                                                                                                                                          
 827                              struct snd_ctl_elem_value *control)                
 828 {                                                                               
 829         struct snd_kcontrol *kctl;                                              
 830         struct snd_kcontrol_volatile *vd;                                       
 831         unsigned int index_offset;                                              
 832         int result;                                                             
 833                                                                                 
 834         down_read(&card->controls_rwsem);                                       
 835         kctl = snd_ctl_find_id(card, &control->id);                             
 836         if (kctl == NULL) {                                                     
 837                 result = -ENOENT;                                               
 838         } else {                                                                
 839                 index_offset = snd_ctl_get_ioff(kctl, &control->id);            
 840                 vd = &kctl->vd[index_offset];                                   
 841                 if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&                
 842                     kctl->get != NULL) {                                        
 843                         snd_ctl_build_ioff(&control->id, kctl, index_offset);   
 844                         result = kctl->get(kctl, control);                      
 845                 } else                                                          
 846                         result = -EPERM;                                        
 847         }                                                                       
 848         up_read(&card->controls_rwsem);                                         
 849         return result;                                                          
 850 }   

说明: 在844行使用kcontrol中的get函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值