linux-alsa详解7 ASOC-machine
前面的内容我们提到,ASoC被分为Machine、Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的代码,再次引用上一节的内容:Machine驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个放大器);单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作.
以WM8994的一款Samsung的开发板SMDK为例子做说明,WM8994是一颗Wolfson生产的多功能Codec芯片.
代码位于:/sound/soc/samsung/smdk_wm8994.c
1 注册platfrom_driver
1 static struct platform_driver smdk_audio_driver = { 2 .driver = { 3 .name = "smdk-audio-wm8994", 4 .of_match_table = of_match_ptr(samsung_wm8994_of_match), 5 .pm = &snd_soc_pm_ops, 6 }, 7 .probe = smdk_audio_probe, 8 }; 9 10 module_platform_driver(smdk_audio_driver);
2 probe函数
1 static int smdk_audio_probe(struct platform_device *pdev) 2 { 3 int ret; 4 struct device_node *np = pdev->dev.of_node; 5 struct snd_soc_card *card = &smdk;//给声卡赋值 6 struct smdk_wm8994_data *board; 7 const struct of_device_id *id; 8 9 card->dev = &pdev->dev; 10 11 board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL); 12 if (!board) 13 return -ENOMEM; 14 15 if (np) { 16 smdk_dai[0].cpu_dai_name = NULL; 17 smdk_dai[0].cpu_of_node = of_parse_phandle(np, 18 "samsung,i2s-controller", 0); 19 if (!smdk_dai[0].cpu_of_node) { 20 dev_err(&pdev->dev, 21 "Property 'samsung,i2s-controller' missing or invalid\n"); 22 ret = -EINVAL; 23 } 24 25 smdk_dai[0].platform_name = NULL; 26 smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; 27 } 28 29 id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev); 30 if (id) 31 *board = *((struct smdk_wm8994_data *)id->data); 32 33 platform_set_drvdata(pdev, board); 34 35 ret = devm_snd_soc_register_card(&pdev->dev, card); 36 37 if (ret) 38 dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); 39 40 return ret; 41 }
3 smdk的定义初始化
1 static struct snd_soc_card smdk = { 2 .name = "SMDK-I2S", 3 .owner = THIS_MODULE, 4 .dai_link = smdk_dai, 5 .num_links = ARRAY_SIZE(smdk_dai), 6 }
初始化snd_soc_dai_link
1 static struct snd_soc_dai_link smdk_dai[] = { 2 { /* Primary DAI i/f */ 3 .name = "WM8994 AIF1", 4 .stream_name = "Pri_Dai", 5 .cpu_dai_name = "samsung-i2s.0", 6 .codec_dai_name = "wm8994-aif1", 7 .platform_name = "samsung-i2s.0", 8 .codec_name = "wm8994-codec", 9 .init = smdk_wm8994_init_paiftx, 10 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 11 SND_SOC_DAIFMT_CBM_CFM, 12 .ops = &smdk_ops, 13 }, { /* Sec_Fifo Playback i/f */ 14 .name = "Sec_FIFO TX", 15 .stream_name = "Sec_Dai", 16 .cpu_dai_name = "samsung-i2s-sec", 17 .codec_dai_name = "wm8994-aif1", 18 .platform_name = "samsung-i2s-sec", 19 .codec_name = "wm8994-codec", 20 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 21 SND_SOC_DAIFMT_CBM_CFM, 22 .ops = &smdk_ops, 23 }, 24 }
通过snd_soc_card结构,又引出了Machine驱动的另外两个个数据结构:
snd_soc_dai_link(实例:smdk_dai[] )
snd_soc_ops(实例:smdk_ops )
其中,snd_soc_dai_link中,指定了Platform、Codec、codec_dai、cpu_dai的名字,稍后Machine驱动将会利用这些名字去匹配已经在系统中注册的platform,codec,dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义的,这样看来,Machine驱动的设备初始化代码无非就是选择合适Platform和Codec以及dai,用他们填充以上几个数据结构,然后注册Platform设备即可.当然还要实现连接Platform和Codec的dai_link对应的ops实现,本例就是smdk_ops,它只实现了hw_params函数:smdk_hw_params.
4 函数devm_snd_soc_register_card
probe调用此函数注册声卡
定义位于:sound\soc\soc-devres.c
1 /** 2 * devm_snd_soc_register_card - resource managed card registration 3 * @dev: Device used to manage card 4 * @card: Card to register 5 * 6 * Register a card with automatic unregistration when the device is 7 * unregistered. 8 */ 9 int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) 10 { 11 struct snd_soc_card **ptr; 12 int ret; 13 14 ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL); 15 if (!ptr) 16 return -ENOMEM; 17 18 ret = snd_soc_register_card(card); 19 if (ret == 0) { 20 *ptr = card; 21 devres_add(dev, ptr); 22 } else { 23 devres_free(ptr); 24 } 25 26 return ret; 27 }
5 函数snd_soc_register_card
调用snd_soc_register_card,通过snd_soc_register_card,为snd_soc_pcm_runtime数组申请内存,每一个dai_link对应snd_soc_pcm_runtime数组的一个单元,然后把snd_soc_card中的dai_link配置复制到相应的snd_soc_pcm_runtime中,最后,大部分的工作都在snd_soc_instantiate_card中实现。
1 /** 2 * snd_soc_register_card - Register a card with the ASoC core 3 * 4 * @card: Card to register 5 * 6 */ 7 int snd_soc_register_card(struct snd_soc_card *card) 8 { 9 int i, ret; 10 struct snd_soc_pcm_runtime *rtd; 11 12 if (!card->name || !card->dev) 13 return -EINVAL; 14 15 for (i = 0; i < card->num_links; i++) {//循环查找声卡中的dai_link 16 struct snd_soc_dai_link *link = &card->dai_link[i];//定义dai_link,逐个拿到声卡中的dai_link 17 18 ret = soc_init_dai_link(card, link);//检查确认dai->link中的codec/platform 信息 19 if (ret) { 20 dev_err(card->dev, "ASoC: failed to init link %s\n", 21 link->name); 22 return ret; 23 } 24 } 25 26 dev_set_drvdata(card->dev, card); 27 /*以下是初始化card中的一系列链表*/ 28 snd_soc_initialize_card_lists(card); 29 /*初始化card中的链表*/ 30 INIT_LIST_HEAD(&card->dai_link_list); 31 card->num_dai_links = 0; 32 33 INIT_LIST_HEAD(&card->rtd_list); 34 card->num_rtd = 0; 35 36 INIT_LIST_HEAD(&card->dapm_dirty); 37 INIT_LIST_HEAD(&card->dobj_list); 38 card->instantiated = 0;//card中的初始化标志 39 mutex_init(&card->mutex); 40 mutex_init(&card->dapm_mutex); 41 42 ret = snd_soc_instantiate_card(card);//初始化card的重要函数 43 if (ret != 0) 44 return ret; 45 46 /* deactivate pins to sleep state */ 47 list_for_each_entry(rtd, &card->rtd_list, list) { 48 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 49 int j; 50 51 for (j = 0; j < rtd->num_codecs; j++) { 52 struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; 53 if (!codec_dai->active) 54 pinctrl_pm_select_sleep_state(codec_dai->dev); 55 } 56 57 if (!cpu_dai->active) 58 pinctrl_pm_select_sleep_state(cpu_dai->dev); 59 } 60 61 return ret; 62 }
5.1 函数soc_init_dai_link
1 static int soc_init_dai_link(struct snd_soc_card *card, 2 struct snd_soc_dai_link *link) 3 { 4 int i, ret; 5 6 ret = snd_soc_init_multicodec(card, link);//用card->codec给声卡中codecs赋值 7 if (ret) { 8 dev_err(card->dev, "ASoC: failed to init multicodec\n"); 9 return ret; 10 } 11 12 for (i = 0; i < link->num_codecs; i++) { 13 /* 14 * Codec must be specified by 1 of name or OF node, 15 * not both or neither. 16 */ 17 if (!!link->codecs[i].name == 18 !!link->codecs[i].of_node) { 19 dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", 20 link->name); 21 return -EINVAL; 22 } 23 /* Codec DAI name must be specified */ 24 if (!link->codecs[i].dai_name) { 25 dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", 26 link->name); 27 return -EINVAL; 28 } 29 } 30 31 /* 32 * Platform may be specified by either name or OF node, but 33 * can be left unspecified, and a dummy platform will be used. 34 */ 35 if (link->platform_name && link->platform_of_node) { 36 dev_err(card->dev, 37 "ASoC: Both platform name/of_node are set for %s\n", 38 link->name); 39 return -EINVAL; 40 } 41 42 /* 43 * CPU device may be specified by either name or OF node, but 44 * can be left unspecified, and will be matched based on DAI 45 * name alone.. 46 */ 47 if (link->cpu_name && link->cpu_of_node) { 48 dev_err(card->dev, 49 "ASoC: Neither/both cpu name/of_node are set for %s\n", 50 link->name); 51 return -EINVAL; 52 } 53 /* 54 * At least one of CPU DAI name or CPU device name/node must be 55 * specified 56 */ 57 if (!link->cpu_dai_name && 58 !(link->cpu_name || link->cpu_of_node)) { 59 dev_err(card->dev, 60 "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", 61 link->name); 62 return -EINVAL; 63 } 64 65 return 0; 66 }
5.2 结构体soc_init_dai_link
定义位于:linux-4.9.73\include\sound\soc.h
snd_soc_dai_link中,指定了Platform、Codec、codec_dai、cpu_dai的名字,Machine驱动将会利用这些名字去匹配已经在系统中注册的platform、codec和dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义,最后会赋值给结构体snd_soc_pcm_runtime 中。
6 snd_soc_instantiate_card
snd_soc_instantiate_card主要作用四方面:
作用1:遍历每一对dai_link,进行codec、platform、dai的绑定工作。
1)ASoC定义了三个全局的链表头变量:codec_list、dai_list、platform_list,系统中所有的Codec、DAI、Platform都在注册时连接到这三个全局链表上,soc_bind_dai_link函数逐个扫描这三个链表。
2)根据card->dai_link[]中的名称进行匹配,匹配后把相应的codec,dai和platform实例赋值到card->rtd[]中(snd_soc_pcm_runtime)。经过这个过程后,snd_soc_pcm_runtime:(card->rtd)中保存了本Machine中使用的Codec,DAI和Platform驱动的信息。
3)之后将snd_soc_pcm_runtime加入card的链表中。
作用2:snd_soc_instantiate_card接着初始化Codec的寄存器缓存,然后调用标准的alsa函数snd_card_new创建声卡实例。
作用3:调用machine 、codec和platform的probe函数
作用4:注册声卡snd_card_register(card->snd_card);
1 static int snd_soc_instantiate_card(struct snd_soc_card *card) 2 { 3 struct snd_soc_codec *codec; 4 struct snd_soc_pcm_runtime *rtd;//建立snd_soc_pcm_runtime结构体,很重要的一个结构体 5 struct snd_soc_dai_link *dai_link; 6 int ret, i, order; 7 8 mutex_lock(&client_mutex); 9 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); 10 11 /* bind DAIs */ 12 for (i = 0; i < card->num_links; i++) { 13 ret = soc_bind_dai_link(card, &card->dai_link[i]);//初始化rtd 14 if (ret != 0) 15 goto base_error; 16 } 17 18 /* bind aux_devs too */ 19 for (i = 0; i < card->num_aux_devs; i++) { 20 ret = soc_bind_aux_dev(card, i); 21 if (ret != 0) 22 goto base_error; 23 } 24 25 /* add predefined DAI links to the list */ 26 for (i = 0; i < card->num_links; i++) 27 snd_soc_add_dai_link(card, card->dai_link+i); 28 29 /* initialize the register cache for each available codec */ 30 list_for_each_entry(codec, &codec_list, list) { 31 if (codec->cache_init) 32 continue; 33 ret = snd_soc_init_codec_cache(codec); 34 if (ret < 0) 35 goto base_error; 36 } 37 38 /* card bind complete so register a sound card */ 39 ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,//建立声卡设备snd_card,生成声卡设备节点。snd_soc_instantiate_card函数作用2 40 card->owner, 0, &card->snd_card); 41 if (ret < 0) { 42 dev_err(card->dev, 43 "ASoC: can't create sound card for card %s: %d\n", 44 card->name, ret); 45 goto base_error; 46 } 47 48 soc_init_card_debugfs(card); 49 50 card->dapm.bias_level = SND_SOC_BIAS_OFF; 51 card->dapm.dev = card->dev; 52 card->dapm.card = card; 53 list_add(&card->dapm.list, &card->dapm_list); 54 55 #ifdef CONFIG_DEBUG_FS 56 snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); 57 #endif 58 59 #ifdef CONFIG_PM_SLEEP 60 /* deferred resume work */ 61 INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); 62 #endif 63 64 if (card->dapm_widgets) 65 snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, 66 card->num_dapm_widgets); 67 68 if (card->of_dapm_widgets) 69 snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, 70 card->num_of_dapm_widgets); 71 /*依次调用各个子结构的probe函数*/ 72 /* initialise the sound card only once */ 73 if (card->probe) { machine的probe函数 74 ret = card->probe(card); 75 if (ret < 0) 76 goto card_probe_error; 77 } 78 79 /* probe all components used by DAI links on this card */ 80 for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; 81 order++) { 82 list_for_each_entry(rtd, &card->rtd_list, list) { 83 ret = soc_probe_link_components(card, rtd, order);//调用codec和plafform的probe函数 84 if (ret < 0) { 85 dev_err(card->dev, 86 "ASoC: failed to instantiate card %d\n", 87 ret); 88 goto probe_dai_err; 89 } 90 } 91 } 92 93 /* probe auxiliary components */ 94 ret = soc_probe_aux_devices(card); 95 if (ret < 0) 96 goto probe_dai_err; 97 98 /* Find new DAI links added during probing components and bind them. 99 * Components with topology may bring new DAIs and DAI links. 100 */ 101 list_for_each_entry(dai_link, &card->dai_link_list, list) { 102 if (soc_is_dai_link_bound(card, dai_link)) 103 continue; 104 105 ret = soc_init_dai_link(card, dai_link); 106 if (ret) 107 goto probe_dai_err; 108 ret = soc_bind_dai_link(card, dai_link); 109 if (ret) 110 goto probe_dai_err; 111 } 112 113 /* probe all DAI links on this card */ 114 for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; 115 order++) { 116 list_for_each_entry(rtd, &card->rtd_list, list) { 117 ret = soc_probe_link_dais(card, rtd, order); 118 if (ret < 0) { 119 dev_err(card->dev, 120 "ASoC: failed to instantiate card %d\n", 121 ret); 122 goto probe_dai_err; 123 } 124 } 125 } 126 127 snd_soc_dapm_link_dai_widgets(card); 128 snd_soc_dapm_connect_dai_link_widgets(card); 129 130 if (card->controls) 131 snd_soc_add_card_controls(card, card->controls, card->num_controls); 132 133 if (card->dapm_routes) 134 snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, 135 card->num_dapm_routes); 136 137 if (card->of_dapm_routes) 138 snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, 139 card->num_of_dapm_routes); 140 141 snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), 142 "%s", card->name); 143 snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), 144 "%s", card->long_name ? card->long_name : card->name); 145 snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), 146 "%s", card->driver_name ? card->driver_name : card->name); 147 for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) { 148 switch (card->snd_card->driver[i]) { 149 case '_': 150 case '-': 151 case '\0': 152 break; 153 default: 154 if (!isalnum(card->snd_card->driver[i])) 155 card->snd_card->driver[i] = '_'; 156 break; 157 } 158 } 159 160 if (card->late_probe) { 161 ret = card->late_probe(card); 162 if (ret < 0) { 163 dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", 164 card->name, ret); 165 goto probe_aux_dev_err; 166 } 167 } 168 169 snd_soc_dapm_new_widgets(card); 170 171 ret = snd_card_register(card->snd_card);//注册声卡snd_card,即snd_soc_instantiate_card函数作用4 172 if (ret < 0) { 173 dev_err(card->dev, "ASoC: failed to register soundcard %d\n", 174 ret); 175 goto probe_aux_dev_err; 176 } 177 178 card->instantiated = 1;//给声卡初始化标志位置1标志已初始化 179 snd_soc_dapm_sync(&card->dapm); 180 mutex_unlock(&card->mutex); 181 mutex_unlock(&client_mutex); 182 183 return 0; 184 185 probe_aux_dev_err: 186 soc_remove_aux_devices(card); 187 188 probe_dai_err: 189 soc_remove_dai_links(card); 190 191 card_probe_error: 192 if (card->remove) 193 card->remove(card); 194 195 snd_soc_dapm_free(&card->dapm); 196 soc_cleanup_card_debugfs(card); 197 snd_card_free(card->snd_card); 198 199 base_error: 200 soc_remove_pcm_runtimes(card); 201 mutex_unlock(&card->mutex); 202 mutex_unlock(&client_mutex); 203 204 return ret; 205 }
6.1 函数soc_bind_dai_link
即snd_soc_instantiate_card的作用1:遍历每一对dai_link,进行codec、platform、dai的绑定工作。
作用:(1)ASoC定义了三个全局的链表头变量:codec_list、dai_list、platform_list,系统中所有的Codec、DAI、Platform都在注册时连接到这三个全局链表上
(2)函数逐个扫描这三个链表,根据card->dai_link[]中的名称进行匹配,匹配后把相应的codec,dai和platform实例赋值到card->rtd[]中(snd_soc_pcm_runtime).经过这个过程后,snd_soc_pcm_runtime:(card->rtd)中保存了本Machine中使用的Codec,DAI和Platform驱动的信息
1 static int soc_bind_dai_link(struct snd_soc_card *card, 2 struct snd_soc_dai_link *dai_link) 3 { 4 struct snd_soc_pcm_runtime *rtd; 5 struct snd_soc_dai_link_component *codecs = dai_link->codecs; 6 struct snd_soc_dai_link_component cpu_dai_component; 7 struct snd_soc_dai **codec_dais; 8 struct snd_soc_platform *platform; 9 const char *platform_name; 10 int i; 11 12 dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); 13 14 if (soc_is_dai_link_bound(card, dai_link)) {//确认card->dai_link和rtd->dai_link信息一致
15 dev_dbg(card->dev, "ASoC: dai link %s already bound\n", 16 dai_link->name); 17 return 0; 18 } 19 20 rtd = soc_new_pcm_runtime(card, dai_link);//分配rtd结构体并初始化部分成员 21 if (!rtd) 22 return -ENOMEM; 23 /*用dai_link中信息给dai component赋值*/ 24 cpu_dai_component.name = dai_link->cpu_name; 25 cpu_dai_component.of_node = dai_link->cpu_of_node; 26 cpu_dai_component.dai_name = dai_link->cpu_dai_name; 27 rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);//查找已注册的dai,拿到cpu_dai信息给rtd赋值。实参就是dai_link中的platform的dai信息 28 if (!rtd->cpu_dai) { 29 dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", 30 dai_link->cpu_dai_name); 31 goto _err_defer; 32 } 33 /*用card中的codec 给rtd赋值*/ 34 rtd->num_codecs = dai_link->num_codecs;//codec的个数 35 36 /* Find CODEC from registered CODECs */ 37 codec_dais = rtd->codec_dais; 38 for (i = 0; i < rtd->num_codecs; i++) { 39 codec_dais[i] = snd_soc_find_dai(&codecs[i]);//实参codecs就是dai_link信息,拿到codec dai信息 40 if (!codec_dais[i]) { 41 dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", 42 codecs[i].dai_name); 43 goto _err_defer; 44 } 45 } 46 /*将查找到的codec dai信息赋给rtd*/ 47 /* Single codec links expect codec and codec_dai in runtime data */ 48 rtd->codec_dai = codec_dais[0]; 49 rtd->codec = rtd->codec_dai->codec; 50 51 /* if there's no platform we match on the empty platform */ 52 platform_name = dai_link->platform_name; 53 if (!platform_name && !dai_link->platform_of_node) 54 platform_name = "snd-soc-dummy"; 55 56 /* find one from the set of registered platforms */ 57 list_for_each_entry(platform, &platform_list, list) { 58 if (dai_link->platform_of_node) { 59 if (platform->dev->of_node != 60 dai_link->platform_of_node) 61 continue; 62 } else { 63 if (strcmp(platform->component.name, platform_name)) 64 continue; 65 } 66 67 rtd->platform = platform; 68 } 69 if (!rtd->platform) { 70 dev_err(card->dev, "ASoC: platform %s not registered\n", 71 dai_link->platform_name); 72 goto _err_defer; 73 } 74 75 soc_add_pcm_runtime(card, rtd);//将上述赋值好的rtd,见到card中的rtd链表中 76 return 0; 77 78 _err_defer: 79 soc_free_pcm_runtime(rtd); 80 return -EPROBE_DEFER; 81 }
6.2 函数snd_soc_find_dai
根据dai_link已经注册的dai信息查找,返回snd_soc_dai
1 /** 2 * snd_soc_find_dai - Find a registered DAI 3 * 4 * @dlc: name of the DAI and optional component info to match 5 * 6 * This function will search all regsitered components and their DAIs to 7 * find the DAI of the same name. The component's of_node and name 8 * should also match if being specified. 9 * 10 * Return: pointer of DAI, or NULL if not found. 11 */ 12 struct snd_soc_dai *snd_soc_find_dai( 13 const struct snd_soc_dai_link_component *dlc) 14 { 15 struct snd_soc_component *component; 16 struct snd_soc_dai *dai; 17 struct device_node *component_of_node; 18 19 lockdep_assert_held(&client_mutex); 20 21 /* Find CPU DAI from registered DAIs*/ 22 list_for_each_entry(component, &component_list, list) { 23 component_of_node = component->dev->of_node; 24 if (!component_of_node && component->dev->parent) 25 component_of_node = component->dev->parent->of_node; 26 27 if (dlc->of_node && component_of_node != dlc->of_node) 28 continue; 29 if (dlc->name && strcmp(component->name, dlc->name)) 30 continue; 31 list_for_each_entry(dai, &component->dai_list, list) { 32 if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) 33 continue; 34 35 return dai; 36 } 37 } 38 39 return NULL; 40 }
6.3 函数soc_add_pcm_runtime
将上述赋值好的rtd,见到card中的rtd链表中
1 static void soc_add_pcm_runtime(struct snd_soc_card *card, 2 struct snd_soc_pcm_runtime *rtd) 3 { 4 list_add_tail(&rtd->list, &card->rtd_list); 5 rtd->num = card->num_rtd; 6 card->num_rtd++; 7 }
7 snd_soc_instantiate_card函数作用3
调用machine 、codec和platform的probe函数
1 static int snd_soc_instantiate_card(struct snd_soc_card *card) 2 { 3 ... 4 5 /* initialise the sound card only once */ 6 if (card->probe) {//machine对应的probe函数 7 ret = card->probe(card); 8 if (ret < 0) 9 goto card_probe_error; 10 } 11 12 /* probe all components used by DAI links on this card */ 13 for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; 14 order++) { 15 list_for_each_entry(rtd, &card->rtd_list, list) { 16 ret = soc_probe_link_components(card, rtd, order); 17 if (ret < 0) { 18 dev_err(card->dev, 19 "ASoC: failed to instantiate card %d\n", 20 ret); 21 goto probe_dai_err; 22 } 23 } 24 } 25 26 /* probe auxiliary components */ 27 ret = soc_probe_aux_devices(card); 28 if (ret < 0) 29 goto probe_dai_err; 30 31 ... 32 /* probe all DAI links on this card */ 33 for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; 34 order++) { 35 list_for_each_entry(rtd, &card->rtd_list, list) { 36 ret = soc_probe_link_dais(card, rtd, order); 37 if (ret < 0) { 38 dev_err(card->dev, 39 "ASoC: failed to instantiate card %d\n", 40 ret); 41 goto probe_dai_err; 42 } 43 } 44 } 45 46 ... 47 48 if (card->late_probe) { 49 ret = card->late_probe(card); 50 if (ret < 0) { 51 dev_err(card->dev, "ASoC: %s late_probe() 52 ... 53 }
7.1 machine的probe函数
也就是struct snd_soc_card card->probe函数
struct snd_soc_card card是从\sound\soc\samsung\smdk_wm8994.c的smdk_audio_probe函数中定义初始化card,然后传下去的,没有发现card->probe函数的定义。定义的地方不知道在哪里???待分析
7.2 函数soc_probe_link_components
1 static int soc_probe_link_components(struct snd_soc_card *card, 2 struct snd_soc_pcm_runtime *rtd, 3 int order) 4 { 5 struct snd_soc_platform *platform = rtd->platform; 6 struct snd_soc_component *component; 7 int i, ret; 8 9 /* probe the CPU-side component, if it is a CODEC */ 10 component = rtd->cpu_dai->component;//找到 cpu component 11 if (component->driver->probe_order == order) { 12 ret = soc_probe_component(card, component); 13 if (ret < 0) 14 return ret; 15 } 16 17 /* probe the CODEC-side components */ 18 for (i = 0; i < rtd->num_codecs; i++) {//获取codec component 19 component = rtd->codec_dais[i]->component; 20 if (component->driver->probe_order == order) { 21 ret = soc_probe_component(card, component); 22 if (ret < 0) 23 return ret; 24 } 25 } 26 27 /* probe the platform */ 28 if (platform->component.driver->probe_order == order) {//获取 platform component 29 ret = soc_probe_component(card, &platform->component); 30 if (ret < 0) 31 return ret; 32 } 33 34 return 0; 35 }
7.3 函数soc_probe_component
根据cpu component /codec component/platform component调用对应的probe函数
1 static int soc_probe_component(struct snd_soc_card *card, 2 struct snd_soc_component *component) 3 { 4 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 5 struct snd_soc_dai *dai; 6 int ret; 7 8 if (!strcmp(component->name, "snd-soc-dummy")) 9 return 0; 10 11 if (component->card) { 12 if (component->card != card) { 13 dev_err(component->dev, 14 "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", 15 card->name, component->card->name); 16 return -ENODEV; 17 } 18 return 0; 19 } 20 21 if (!try_module_get(component->dev->driver->owner)) 22 return -ENODEV; 23 24 component->card = card; 25 dapm->card = card; 26 soc_set_name_prefix(card, component); 27 28 soc_init_component_debugfs(component); 29 30 if (component->dapm_widgets) { 31 ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, 32 component->num_dapm_widgets); 33 34 if (ret != 0) { 35 dev_err(component->dev, 36 "Failed to create new controls %d\n", ret); 37 goto err_probe; 38 } 39 } 40 41 list_for_each_entry(dai, &component->dai_list, list) { 42 ret = snd_soc_dapm_new_dai_widgets(dapm, dai); 43 if (ret != 0) { 44 dev_err(component->dev, 45 "Failed to create DAI widgets %d\n", ret); 46 goto err_probe; 47 } 48 } 49 50 if (component->probe) { 51 ret = component->probe(component);//调用probe函数 52 if (ret < 0) { 53 dev_err(component->dev, 54 "ASoC: failed to probe component %d\n", ret); 55 goto err_probe; 56 } 57 58 WARN(dapm->idle_bias_off && 59 dapm->bias_level != SND_SOC_BIAS_OFF, 60 "codec %s can not start from non-off bias with idle_bias_off==1\n", 61 component->name); 62 } 63 64 /* machine specific init */ 65 if (component->init) { 66 ret = component->init(component); 67 if (ret < 0) { 68 dev_err(component->dev, 69 "Failed to do machine specific init %d\n", ret); 70 goto err_probe; 71 } 72 } 73 74 if (component->controls) 75 snd_soc_add_component_controls(component, component->controls, 76 component->num_controls); 77 if (component->dapm_routes) 78 snd_soc_dapm_add_routes(dapm, component->dapm_routes, 79 component->num_dapm_routes); 80 81 list_add(&dapm->list, &card->dapm_list); 82 83 /* This is a HACK and will be removed soon */ 84 if (component->codec) 85 list_add(&component->codec->card_list, &card->codec_dev_list); 86 87 return 0; 88 89 err_probe: 90 soc_cleanup_component_debugfs(component); 91 component->card = NULL; 92 module_put(component->dev->driver->owner); 93 94 return ret; 95 }
7.3 codec probe来源
7.3.1 codec driver 的probe函数赋值
1 static int wm8994_probe(struct platform_device *pdev) 2 { 3 ... 4 5 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, 6 wm8994_dai, ARRAY_SIZE(wm8994_dai)); 7 }
调用函数snd_soc_register_codec的实参snd_soc_codec_driver定义了probe函数
1 static const struct snd_soc_codec_driver soc_codec_dev_wm8994 = { 2 .probe = wm8994_codec_probe, 3 .remove = wm8994_codec_remove, 4 .suspend = wm8994_codec_suspend, 5 .resume = wm8994_codec_resume, 6 .get_regmap = wm8994_get_regmap, 7 .set_bias_level = wm8994_set_bias_level, 8 };
函数wm8994_codec_probe完成codec的初始化,如linux-alsa详解6 asoc-codec中第5节所述。
7.3.2 获取codec driver的probe函数
在codec 注册过程中
1 int snd_soc_register_codec(struct device *dev, 2 const struct snd_soc_codec_driver *codec_drv, 3 struct snd_soc_dai_driver *dai_drv, 4 int num_dai) 5 { 6 ... 7 8 if (codec_drv->probe) 9 codec->component.probe = snd_soc_codec_drv_probe; 10 if (codec_drv->remove) 11 codec->component.remove = snd_soc_codec_drv_remove; 12 if (codec_drv->write) 13 codec->component.write = snd_soc_codec_drv_write; 14 if (codec_drv->read) 15 codec->component.read = snd_soc_codec_drv_read; 16 codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; 17 18 ... 19 }
函数snd_soc_codec_drv_probe
根据codec的component获取到结构体codec,然后找到codec driver。codec driver中probe已在上述过程中初始化。
至此codec的probe函数已完美找到。
1 static int snd_soc_codec_drv_probe(struct snd_soc_component *component) 2 { 3 struct snd_soc_codec *codec = snd_soc_component_to_codec(component); 4 5 return codec->driver->probe(codec); 6 }
7.4 platform probe来源
1 int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, 2 const struct snd_soc_platform_driver *platform_drv) 3 { 4 int ret; 5 6 ret = snd_soc_component_initialize(&platform->component, 7 &platform_drv->component_driver, dev); 8 if (ret) 9 return ret; 10 11 platform->dev = dev; 12 platform->driver = platform_drv; 13 14 if (platform_drv->probe) 15 platform->component.probe = snd_soc_platform_drv_probe; 16 if (platform_drv->remove) 17 platform->component.remove = snd_soc_platform_drv_remove; 18 19 ... 20 }
继续追踪函数snd_soc_platform_drv_probe
根据platform->component获取到对应的platform结构体,然后调用platform->driver中的probe
1 static int snd_soc_platform_drv_probe(struct snd_soc_component *component) 2 { 3 struct snd_soc_platform *platform = snd_soc_component_to_platform(component); 4 5 return platform->driver->probe(platform); 6 }
platform->driver中的probe就是结构体snd_soc_platform_driver中的probe的函数,但是在platform注册过程中没有找到其probe函数的定义,待分析???
7.5 cpu probe来源
待追踪???
8 machine/platform/codec数据结构体总结
(1)machine所用的数据结构体:
snd_soc_card
snd_soc_dai_link
snd_soc_ops
snd_soc_pcm_runtime
全局list:codec_list、component_list、platform_list;dai_list(是挂在component中)
(2)platform所用结构体:
snd_soc_platform和snd_soc_platform_driver
(3)codec所用结构体:
snd_soc_codec,snd_soc_codec_driver;
snd_soc_dai_ops;
(4)都用到的结构体:
snd_soc_component,snd_soc_component_driver;
snd_soc_dai,snd_soc_dai_driver;

参考博文:https://www.cnblogs.com/jason-lu/archive/2013/06/07/3123978.html
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号