news 2026/3/24 0:54:08

dai link代码分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
dai link代码分析

dai link代码分析

  1. snd_soc_dapm_link_dai_widgets 函数连接 codec 的 widget 与其他的 widget。
// msm_tx_cdc_dma_be_dai_links(sun.c)staticstructsnd_soc_dai_linkmsm_rx_tx_cdc_dma_be_dai_links[]={{.name=LPASS_BE_TX_CDC_DMA_TX_4,// "CODEC_DMA-LPAIF_RXTX-TX-4".stream_name=LPASS_BE_TX_CDC_DMA_TX_4,// "CODEC_DMA-LPAIF_RXTX-TX-4".capture_only=1,.trigger={SND_SOC_DPCM_TRIGGER_POST,SND_SOC_DPCM_TRIGGER_POST},.ignore_suspend=1,.ops=&msm_common_be_ops,SND_SOC_DAILINK_REG(tx_dma_tx4),},}SND_SOC_DAILINK_DEFS(tx_dma_tx4,DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")),DAILINK_COMP_ARRAY(COMP_CODEC("lpass-cdc","tx_macro_tx2"),COMP_CODEC("wcd937x_codec","wcd937x_cdc"),COMP_CODEC("wcd938x_codec","wcd938x_cdc"),COMP_CODEC("wcd939x_codec","wcd939x_cdc"),COMP_CODEC("swr-dmic.01","swr_dmic_tx0"),COMP_CODEC("swr-dmic.02","swr_dmic_tx1"),COMP_CODEC("swr-dmic.03","swr_dmic_tx2"),COMP_CODEC("swr-dmic.04","swr_dmic_tx3")),DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy")));staticstructsnd_soc_dai_driverdummy_dai={.name="snd-soc-dummy-dai",.playback={.stream_name="Playback",.channels_min=1,.channels_max=384,.rates=STUB_RATES,.formats=STUB_FORMATS,},.capture={.stream_name="Capture",.channels_min=1,.channels_max=384,.rates=STUB_RATES,.formats=STUB_FORMATS,},.ops=&dummy_dai_ops,};// 最终会创建一个 name和sname 都为 "TX_AIF2 Capture" 的widget// 具体代码可查看 snd_soc_dapm_new_dai_widgets() 函数staticstructsnd_soc_dai_driverlpass_cdc_tx_macro_dai[]={{.name="tx_macro_tx2",.id=LPASS_CDC_TX_MACRO_AIF2_CAP,.capture={.stream_name="TX_AIF2 Capture",.rates=LPASS_CDC_TX_MACRO_RATES,.formats=LPASS_CDC_TX_MACRO_FORMATS,.rate_max=192000,.rate_min=8000,.channels_min=1,.channels_max=8,},.ops=&lpass_cdc_tx_macro_dai_ops,},}staticconststructsnd_soc_dapm_widgetlpass_cdc_tx_macro_dapm_widgets[]={SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP","TX_AIF1 Capture",0,SND_SOC_NOPM,LPASS_CDC_TX_MACRO_AIF1_CAP,0),SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP","TX_AIF2 Capture",0,SND_SOC_NOPM,LPASS_CDC_TX_MACRO_AIF2_CAP,0),}// 创建dai widgetsoc_probe_component()for_each_component_dais()snd_soc_dapm_new_dai_widgets()// 连接dai widget与其他的 widget(根据sname)snd_soc_dapm_link_dai_widgets()

简单梳理下流程:

  • 在调用 snd_soc_bind_card 函数之前,会调用 populate_snd_card_dailinks 填充所有要使用的 dai link。
  • soc_probe_component 函数会遍历 component 中的 dai,为每个 dai 创建对应的 widget,widget 的 name 与 sname 是 dai 中 stream 的 name
  • snd_soc_dapm_link_dai_widgets 函数会根据 sname 连接 dai widget 与普通的 widget。

比如上述的过程就会根据lpass_cdc_tx_macro_dai创建一个名为TX_AIF2 Capture的dai widget,并根据它的sname连接TX_AIF2 CAP这个widget。

  1. 函数 snd_soc_dapm_connect_dai_link_widgets 负责连接 cpu dai 与 codec dai。

    snd_soc_bind_card()soc_probe_link_components()soc_probe_link_dais()// 以下的两个函数都在前面函数的调用之后,因为前面两个函数会将对应的widget注册到声卡之中,没有注册后面的连接就无法进行snd_soc_dapm_link_dai_widgets()// 连接codec dai widget与 普通的 widgetsnd_soc_dapm_connect_dai_link_widgets()// 连接cpu dai widget与codec dai widget
  2. 每个dai link会对应一个pcm runtime,通过下面的调用在声卡中注册对应的pcm设备

    snd_soc_bind_card()for_each_card_rtds(card,rtd)soc_init_pcm_runtime(card,rtd);// 自动寻找空闲的次设备号,然后设置对应的snd_card_register中使用的回调函数soc_new_pcm()snd_card_register()// 创建一个名为 "CODEC_DMA-LPAIF_RXTX-TX-4" 的 rtdsoc_new_pcm_runtime()dev=kzalloc(sizeof(structdevice),GFP_KERNEL);// 这里会创建一个名为"CODEC_DMA-LPAIF_RXTX-TX-4"的devicedev_set_name(dev,"%s",dai_link->name);// 注册设备ret=device_register(dev);// 创建pcm设备,并添加到card的device中的详细调用栈如下:for_each_card_rtds(card,rtd)// 这个函数会将rtd中的pcm初始化,包括各种操作函数soc_init_pcm_runtime(card,rtd)soc_new_pcm()soc_create_pcm()snd_pcm_new()_snd_pcm_new()// 将创建的pcm设备添加到card的device链表之中snd_device_new()

component probe函数调用

  1. 注册component(以wcd938x.c为例子)

    staticstructsnd_soc_component_driversoc_codec_dev_wcd938x={.name=WCD938X_DRV_NAME,.probe=wcd938x_soc_codec_probe,.remove=wcd938x_soc_codec_remove,.controls=wcd938x_snd_controls,.num_controls=ARRAY_SIZE(wcd938x_snd_controls),.dapm_widgets=wcd938x_dapm_widgets,.num_dapm_widgets=ARRAY_SIZE(wcd938x_dapm_widgets),.dapm_routes=wcd938x_audio_map,.num_dapm_routes=ARRAY_SIZE(wcd938x_audio_map),.suspend=wcd938x_soc_codec_suspend,.resume=wcd938x_soc_codec_resume,};wcd938x_bind(){// 注册component到全局的component_list链表之中snd_soc_register_component(dev,&soc_codec_dev_wcd938x,wcd938x_dai,ARRAY_SIZE(wcd938x_dai))}
  2. 寻找component

    populate_snd_card_dailinks(){// 拷贝dai—link数据到msm_kalama_dai_links数组中memcpy(msm_kalama_dai_links+total_links,msm_rx_tx_cdc_dma_be_dai_links,sizeof(msm_rx_tx_cdc_dma_be_dai_links));}// 遍历msm_kalama_dai_links数组,创建对应的pcm_runtime结构for_each_card_prelinks(card,i,dai_link)// 里面会找cpu、codec、platform对应的dai和component,然后添加到rtd的components数组中snd_soc_add_pcm_runtime(card,dai_link);// 根据dai link中的dai link component找到对应的component,然后找到component对应的daisnd_soc_find_dai()
  3. 调用component 的 probe函数: 一般的功能就是注册widget,比如tfa9874这个smart pa的中定义的widget,将其注册到声卡之中。

    // 调用component driver中的probe函数soc_probe_link_components()snd_soc_component_probe()// 调用component driver中的probe函数staticintsoc_probe_link_components(structsnd_soc_card*card){structsnd_soc_component*component;structsnd_soc_pcm_runtime*rtd;inti,ret,order;for_each_comp_order(order){for_each_card_rtds(card,rtd){for_each_rtd_components(rtd,i,component){// 按照顺序执行probe函数if(component->driver->probe_order!=order)continue;// 根据rtd得到对应的componentret=soc_probe_component(card,component);if(ret<0)returnret;}}}return0;}soc_probe_link_dais()// 根据rtd中的dai,调用对应的dai probe函数snd_soc_pcm_dai_probe()intsnd_soc_pcm_dai_probe(structsnd_soc_pcm_runtime*rtd,intorder){structsnd_soc_dai*dai;inti;for_each_rtd_dais(rtd,i,dai){if(dai->driver->probe_order!=order)continue;// 现在已经改版为dai->driver->ops->probeif(dai->driver->probe){intret=dai->driver->probe(dai);if(ret<0)returnsoc_dai_ret(dai,ret);}dai->probed=1;}return0;}
  4. 为什么component的probe函数还需要在声卡注册阶段主动的调用,而不是直接驱动自动触发的probe调用

    • 他也会注册为平台设备,但是平台设备的probe函数的功能是去注册component组件。后续由声卡从component_list中找到组件,然后进行调用

      • 第一次probe,平台设备驱动的probe函数,它负责注册component到compnent_list中
      • 第二次probe,声卡的驱动程序从component_list中找到对应的数据,调用其component driver的probe函数与dai driver的probe函数
      staticconststructdev_pm_opswcd938x_dev_pm_ops={.suspend_late=wcd938x_suspend,.resume_early=wcd938x_resume,};#endifstaticstructplatform_driverwcd938x_codec_driver={.probe=wcd938x_probe,.remove=wcd938x_remove,.driver={.name="wcd938x_codec",.owner=THIS_MODULE,.of_match_table=of_match_ptr(wcd938x_dt_match),#ifdefCONFIG_PM_SLEEP.pm=&wcd938x_dev_pm_ops,#endif.suppress_bind_attrs=true,},};staticconststructof_device_idwcd938x_dt_match[]={{.compatible="qcom,wcd938x-codec",.data="wcd938x"},{}};// 注册为平台设备驱动程序module_platform_driver(wcd938x_codec_driver);// 平台驱动对应的probe函数wcd938x_probe()wcd938x_bind()snd_soc_register_component(dev,&soc_codec_dev_wcd938x,wcd938x_dai,ARRAY_SIZE(wcd938x_dai));
    • 声卡注册为平台设备,声卡的驱动程序在匹配到对应的设备时,就会自动调用probe函数。后续的component的probe与dai的probe函数都是在声卡驱动程序中调用的。如下:

      staticconststructof_device_idkalama_asoc_machine_of_match[]={{.compatible="qcom,kalama-asoc-snd",.data="codec"},{.compatible="qcom,kalama-asoc-snd-stub",.data="stub_codec"},{},};staticstructplatform_driverkalama_asoc_machine_driver={.driver={.name=DRV_NAME,.owner=THIS_MODULE,.pm=&snd_soc_pm_ops,.of_match_table=kalama_asoc_machine_of_match,.suppress_bind_attrs=true,},.probe=msm_asoc_machine_probe,.remove=msm_asoc_machine_remove,};staticint__initmsm_asoc_machine_init(void){snd_card_sysfs_init();returnplatform_driver_register(&kalama_asoc_machine_driver);}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/17 3:48:35

2024终极指南:三步让老旧Mac重获新生完整流程

2024终极指南&#xff1a;三步让老旧Mac重获新生完整流程 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 您是否曾因苹果官方的硬件限制&#xff0c;被迫放弃为心爱的老旧…

作者头像 李华
网站建设 2026/3/23 19:21:53

Layui多选下拉框插件终极指南:快速掌握formSelects完整使用方案

Layui多选下拉框插件终极指南&#xff1a;快速掌握formSelects完整使用方案 【免费下载链接】layui-formSelects Layui select多选小插件 项目地址: https://gitcode.com/gh_mirrors/la/layui-formSelects 还在为表单中的复杂选择需求而头疼吗&#xff1f;Layui多选下拉…

作者头像 李华
网站建设 2026/3/15 10:45:05

鸿蒙阅读革命:开源阅读应用如何重塑你的数字书房体验

鸿蒙阅读革命&#xff1a;开源阅读应用如何重塑你的数字书房体验 【免费下载链接】legado-Harmony 开源阅读鸿蒙版仓库 项目地址: https://gitcode.com/gh_mirrors/le/legado-Harmony 还在为碎片化阅读和信息过载而烦恼吗&#xff1f;开源阅读鸿蒙版为你带来前所未有的纯…

作者头像 李华
网站建设 2026/3/22 14:52:36

VSCode审查元素进阶指南:3步定位并修复页面异常渲染问题

第一章&#xff1a;VSCode审查元素进阶指南概述 在现代前端开发中&#xff0c;快速定位并调试界面问题至关重要。虽然浏览器内置的开发者工具提供了强大的“审查元素”功能&#xff0c;但 Visual Studio Code&#xff08;VSCode&#xff09;通过扩展与集成能力&#xff0c;也能…

作者头像 李华
网站建设 2026/3/23 23:39:23

VSCode组织级智能体落地难?这7个坑90%的企业都踩过

第一章&#xff1a;VSCode组织级智能体落地难&#xff1f;这7个坑90%的企业都踩过在企业级开发环境中&#xff0c;VSCode凭借其轻量、可扩展和强大的插件生态成为主流编辑器。然而&#xff0c;当尝试将VSCode与AI智能体&#xff08;如GitHub Copilot、自研代码助手&#xff09;…

作者头像 李华
网站建设 2026/3/19 20:07:53

快速上手WPS文档预览:Vue项目集成完整教程

快速上手WPS文档预览&#xff1a;Vue项目集成完整教程 【免费下载链接】wps-view-vue wps在线编辑、预览前端vue项目&#xff0c;基于es6 项目地址: https://gitcode.com/gh_mirrors/wp/wps-view-vue 在当今数字化办公环境中&#xff0c;WPS文档在线预览已成为提升团队协…

作者头像 李华