alsa声卡分析alsa-utils调用过程(二)-tinymixer

时间:2022-05-06
本文章向大家介绍alsa声卡分析alsa-utils调用过程(二)-tinymixer,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

继上一篇文章:http://www.cnblogs.com/linhaostudy/p/8515277.html

三、tinymixer调用分析:(tinymixer.log搜索节点:/dev/snd/controlCx)

还是一样,系统调用从应用层到kernel层,都要通过VFS来到file_operations;

我们使用tinymixer "SEC_MI2S_RX Audio Mixer MultiMedia1" 1打开通道看一下相应的流程;

log中的open("/dev/snd_controlCx")中对应的file_operations中:

 1 /*
 2  *  INIT PART
 3  */
 4 
 5 static const struct file_operations snd_ctl_f_ops =
 6 {
 7     .owner =    THIS_MODULE,
 8     .read =        snd_ctl_read,
 9     .open =        snd_ctl_open,
10     .release =    snd_ctl_release,
11     .llseek =    no_llseek,
12     .poll =        snd_ctl_poll,
13     .unlocked_ioctl =    snd_ctl_ioctl,
14     .compat_ioctl =    snd_ctl_ioctl_compat,
15     .fasync =    snd_ctl_fasync,
16 };

 tinymixer首先先调用open操作函数集;也就是snd_ctl_open打开control逻辑设备;

我们主要分析ioctl函数,由file_operations来到snd_ctl_ioctl函数中来:

 1 static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 2 {
 3     struct snd_ctl_file *ctl;
 4     struct snd_card *card;
 5     struct snd_kctl_ioctl *p;
 6     void __user *argp = (void __user *)arg;
 7     int __user *ip = argp;
 8     int err;
 9 
10     ctl = file->private_data;
11     card = ctl->card;
12     if (snd_BUG_ON(!card))
13         return -ENXIO;
14     switch (cmd) {
15     case SNDRV_CTL_IOCTL_PVERSION:
16         return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
17     case SNDRV_CTL_IOCTL_CARD_INFO:
18         return snd_ctl_card_info(card, ctl, cmd, argp);
19     case SNDRV_CTL_IOCTL_ELEM_LIST:
20         return snd_ctl_elem_list(card, argp);
21     case SNDRV_CTL_IOCTL_ELEM_INFO:
22         return snd_ctl_elem_info_user(ctl, argp);
23     case SNDRV_CTL_IOCTL_ELEM_READ:
24         return snd_ctl_elem_read_user(card, argp);
25     case SNDRV_CTL_IOCTL_ELEM_WRITE:
26         return snd_ctl_elem_write_user(ctl, argp);
27     case SNDRV_CTL_IOCTL_ELEM_LOCK:
28         return snd_ctl_elem_lock(ctl, argp);
29     case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
30         return snd_ctl_elem_unlock(ctl, argp);
31     case SNDRV_CTL_IOCTL_ELEM_ADD:
32         return snd_ctl_elem_add_user(ctl, argp, 0);
33     case SNDRV_CTL_IOCTL_ELEM_REPLACE:
34         return snd_ctl_elem_add_user(ctl, argp, 1);
35     case SNDRV_CTL_IOCTL_ELEM_REMOVE:
36         return snd_ctl_elem_remove(ctl, argp);
37     case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
38         return snd_ctl_subscribe_events(ctl, ip);
39     case SNDRV_CTL_IOCTL_TLV_READ:
40         return snd_ctl_tlv_ioctl(ctl, argp, 0);
41     case SNDRV_CTL_IOCTL_TLV_WRITE:
42         return snd_ctl_tlv_ioctl(ctl, argp, 1);
43     case SNDRV_CTL_IOCTL_TLV_COMMAND:
44         return snd_ctl_tlv_ioctl(ctl, argp, -1);
45     case SNDRV_CTL_IOCTL_POWER:
46         return -ENOPROTOOPT;
47     case SNDRV_CTL_IOCTL_POWER_STATE:
48 #ifdef CONFIG_PM
49         return put_user(card->power_state, ip) ? -EFAULT : 0;
50 #else
51         return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
52 #endif
53     }
54     down_read(&snd_ioctl_rwsem);
55     list_for_each_entry(p, &snd_control_ioctls, list) {
56         err = p->fioctl(card, ctl, cmd, arg);
57         if (err != -ENOIOCTLCMD) {
58             up_read(&snd_ioctl_rwsem);
59             return err;
60         }
61     }
62     up_read(&snd_ioctl_rwsem);
63     snd_printdd("unknown ioctl = 0x%xn", cmd);
64     return -ENOTTY;
65 }

通过tinymixer.log搜索ioctl可以看到,进入:

1 case SNDRV_CTL_IOCTL_ELEM_WRITE:
2         return snd_ctl_elem_write_user(ctl, argp);

相应流程如下:

|->snd_ctl_ioctl  
   |->snd_ctl_elem_write_user  
     |->snd_ctl_elem_wirte  
       |->kctl->put  
          |=snd_soc_dapm_put_volsw  
            |->snd_soc_dapm_mixer_update_power//找到使用这个kcontrol的path,根据该kcontrol的值来更新path的connect状态  
               //更新path->connect状态

kcontrol、dapm widget、route/path创建与注册和它们之间的关系可以见: