继上一篇文章: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%x\n", 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创建与注册和它们之间的关系可以见: