平台 os版本 内核
MT6765 Android 9.0 kernel-4.9
audio驱动相关结构体 注释
snd_soc_component 当底层驱动注册platform、codec+codec dai、cpu dai时, 核心层都会创建一个对应的snd_soc_component,并且会挂到component_list 链表中
snd_soc_component_driver 底层驱动需要填充该结构体, 然后向ASoC核心层注册

|snd_soc_dai_driver | 这个结构体用来表示能够传输哪些格式的音频数据,并且提供了设置这些格式的函数|

cpu_dai

cpu_dai 驱动通常对应cpu的一个或者几个 I2S/PCM 接口。用来连接platformmachine

不同的声卡有不同的cpu_dai,但最终都是通过 snd_soc_register_component() 这个函数来注册cpu_dai的。cpu_dai的抽象出来的结构体是mtk_dai_stub_dai

下面我们以mtk_dai_stub_init为入口函数分析一下某一个具体cpu_dai的注册流程。

入口函数所在文件:
./kernel-4.9/sound/soc/mediatek/common_int/mtk-soc-dai-stub.c

module_init(mtk_dai_stub_init);static int __init mtk_dai_stub_init(void)
{pr_warn("%s:\n", __func__);
#ifndef CONFIG_OFint ret;/* #define MT_SOC_DAI_NAME  "mt-soc-dai-driver" */soc_mtk_dai_dev = platform_device_alloc(MT_SOC_DAI_NAME, -1);if (!soc_mtk_dai_dev)return -ENOMEM;ret = platform_device_add(soc_mtk_dai_dev);if (ret != 0) {platform_device_put(soc_mtk_dai_dev);return ret;}
#endif/* 注册platform_driver  */return platform_driver_register(&mtk_dai_stub_driver);
}
#ifdef CONFIG_OF
static const struct of_device_id mt_soc_dai_stub_of_ids[] = {{.compatible = "mediatek,mt_soc_dai_stub",},{} };
#endifstatic struct platform_driver mtk_dai_stub_driver = {.probe  = mtk_dai_stub_dev_probe,.remove = mtk_dai_stub_dev_remove,.driver = {.name = MT_SOC_DAI_NAME,.owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = mt_soc_dai_stub_of_ids,
#endif},
};

of_match_table与设备树匹配的节点是"mediatek,mt_soc_pcm_capture",它与文件./kernel-4.9/arch/arm/boot/dts/mt6765.dts

mt_soc_dai_name {compatible = "mediatek,mt_soc_dai_stub";
};

匹配成功才会调用到mtk_dai_stub_dev_probe函数。

probe函数所在文件:
./kernel-4.9/sound/soc/mediatek/common_int/mtk-soc-dai-stub.c

static int mtk_dai_stub_dev_probe(struct platform_device *pdev)
{int rc = 0;pr_warn("mtk_dai_stub_dev_probe  name %s\n", dev_name(&pdev->dev));pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);if (pdev->dev.dma_mask == NULL)pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;if (pdev->dev.of_node)dev_set_name(&pdev->dev, "%s", MT_SOC_DAI_NAME);pr_warn("%s: dev name %s\n", __func__, dev_name(&pdev->dev));rc = snd_soc_register_component(&pdev->dev, &mt_dai_component,mtk_dai_stub_dai, ARRAY_SIZE(mtk_dai_stub_dai));pr_warn("%s: rc  = %d\n", __func__, rc);return rc;
}

cpu dai 通过 snd_soc_register_component 进行注册,将数组 mtk_dai_stub_dai[] 传入,再通过 snd_soc_register_dais 将所有的 PCM(platform)(如播放、录音、通话等)循环加入 dai list 里面。

cpu_dai注册函数所在文件:
./kernel-4.9/sound/soc/mediatek/common_int/mtk-soc-dai-stub.c

int snd_soc_register_component(struct device *dev,const struct snd_soc_component_driver *cmpnt_drv,struct snd_soc_dai_driver *dai_drv,int num_dai)
{struct snd_soc_component *cmpnt;int ret;/* 为定义的snd_soc_component结构体申请一块内存 */cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL);if (!cmpnt) {dev_err(dev, "ASoC: Failed to allocate memory\n");return -ENOMEM;}/* 将上面分配了内存的cmpnt初始化,并把cmpnt_drv和dev赋值给cmpnt */ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev);if (ret)goto err_free;cmpnt->ignore_pmdown_time = true;cmpnt->registered_as_component = true;/****************************************************************** 函数的主要功能:* 1. 初始化snd_soc_component,并把cmpnt_drv和dev赋值到cmpnt;* 2. dai_drv(也就是mtk_dai_stub_dai) 执行for循环逐一取出snd_soc_dai_driver结构体;* 3. 创建新的snd_soc_dai并且添加到component->dai_list*****************************************************************/ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);if (ret < 0) {dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);goto err_cleanup;}/************************************************** 实际上是对snd_soc_component_add_unlocked()的封装,* 作用是将cmpnt添加到component_list; *************************************************/snd_soc_component_add(cmpnt);return 0;err_cleanup:snd_soc_component_cleanup(cmpnt);
err_free:kfree(cmpnt);return ret;
}

我们可以发现snd_soc_register_component也调用到了snd_soc_component_add_unlocked这个函数,这个函数的主要作用就是把platform->component添加到component_list,而platform->componentsnd_soc_component的结构体,component_list则是一个链表。

所以,snd_soc_register_component的作用就是把mtk_dai_stub_dai相应的配置设置给snd_soc_component,然后再把设置好的snd_soc_component添加到链表component_list中。

mtk_dai_stub_dai数组元素被转换成一个个snd_soc_dai_driver结构体,通过snd_soc_dai.list全面添加到snd_soc_component.dai_listsnd_soc_component.list通过snd_soc_component_add把自己添加到全局链表component_list

结构体所在文件:
./kernel-4.9/sound/soc/mediatek/common_int/mtk-soc-dai-stub.c

static struct snd_soc_dai_driver mtk_dai_stub_dai[] = {...... /* 省略部分相关代码 */{.capture = {/* #define MT_SOC_BTCVSD_CAPTURE_STREAM_NAME "BTCVSD_Capture" */.stream_name =MT_SOC_BTCVSD_CAPTURE_STREAM_NAME,.rates = SNDRV_PCM_RATE_8000_48000,.formats = SND_SOC_ADV_MT_FMTS,.channels_min = 1,.channels_max = 2,.rate_min = 8000,.rate_max = 48000,},.name = MT_SOC_BTCVSD_RX_DAI_NAME,.ops = &mtk_dai_stub_ops,},{.playback = {/* #define MT_SOC_BTCVSD_PLAYBACK_STREAM_NAME "BTCVSD_Playback" */.stream_name =MT_SOC_BTCVSD_PLAYBACK_STREAM_NAME, .rates = SNDRV_PCM_RATE_8000_48000,.formats = SND_SOC_ADV_MT_FMTS,.channels_min = 1,.channels_max = 2,.rate_min = 8000,.rate_max = 48000,},.name = MT_SOC_BTCVSD_TX_DAI_NAME,.ops = &mtk_dai_stub_ops,},{.playback = {.stream_name =MT_SOC_BTCVSD_PLAYBACK_STREAM_NAME,.rates = SNDRV_PCM_RATE_8000_48000,.formats = SND_SOC_ADV_MT_FMTS,.channels_min = 1,.channels_max = 2,.rate_min = 8000,.rate_max = 48000,},.capture = {.stream_name =MT_SOC_BTCVSD_CAPTURE_STREAM_NAME,.rates = SNDRV_PCM_RATE_8000_48000,.formats = SND_SOC_ADV_MT_FMTS,.channels_min = 1,.channels_max = 2,.rate_min = 8000,.rate_max = 48000,},.name = MT_SOC_BTCVSD_DAI_NAME,.ops = &mtk_dai_stub_ops,},...... /* 省略部分代码 */
}

mtk_dai_stub_dai是一个 数组,每一个元素都是一个snd_soc_dai_driver结构体,在这里对每一个元素都进行了赋值操作,由此可以看出cpu_dai的驱动中包含这针对不同PCM的cpu_dai

上面填充的数组元素实际大部分是对snd_soc_dai_driver中的snd_soc_pcm_stream这个结构体的成员变量进行填充的。

结构体定义的所在文件:
./kernel-4.9/include/sound/soc.h

/* SoC PCM stream information */
struct snd_soc_pcm_stream {const char *stream_name;u64 formats; //这个格式定义在pcm.h SNDRV_PCM_FMTBITxxxx     /* SNDRV_PCM_FMTBIT_* */unsigned int rates;  //采样率 我们常说16k 48k  /* SNDRV_PCM_RATE_* */unsigned int rate_min;    //最小采样率 /* min rate */unsigned int rate_max;    //最大采样率 /* max rate */unsigned int channels_min;    //最小通道数,单声道1/* min channels */unsigned int channels_max; //最大通道数  立体声道2/* max channels */unsigned int sig_bits;  //位数 8  还是16    /* number of bits of content */
};
static struct snd_soc_dai_ops mtk_dai_stub_ops = {.startup = multimedia_startup,
}

函数所在文件:
./kernel-4.9/sound/soc/soc-core.c

static int snd_soc_component_initialize(struct snd_soc_component *component,const struct snd_soc_component_driver *driver, struct device *dev)
{/* 定义了一个动态音频电源管理指针变量dapm */struct snd_soc_dapm_context *dapm;/* component->name由系统生成 */component->name = fmt_single_name(dev, &component->id);if (!component->name) {dev_err(dev, "ASoC: Failed to allocate name\n");return -ENOMEM;}component->dev = dev;component->driver = driver;component->probe = component->driver->probe;component->remove = component->driver->remove;dapm = &component->dapm;dapm->dev = dev;dapm->component = component;dapm->bias_level = SND_SOC_BIAS_OFF;dapm->idle_bias_off = true;if (driver->seq_notifier)dapm->seq_notifier = snd_soc_component_seq_notifier;if (driver->stream_event)dapm->stream_event = snd_soc_component_stream_event;component->controls = driver->controls;component->num_controls = driver->num_controls;component->dapm_widgets = driver->dapm_widgets;component->num_dapm_widgets = driver->num_dapm_widgets;component->dapm_routes = driver->dapm_routes;component->num_dapm_routes = driver->num_dapm_routes;INIT_LIST_HEAD(&component->dai_list);mutex_init(&component->io_mutex);return 0;
}

函数所在文件:
./kernel-4.9/sound/soc/soc-core.c

static int snd_soc_register_dais(struct snd_soc_component *component,struct snd_soc_dai_driver *dai_drv, size_t count,bool legacy_dai_naming)
{struct device *dev = component->dev;struct snd_soc_dai *dai;unsigned int i;int ret;dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);/* 把 snd_soc_dai_driver 添加到 snd_soc_component */component->dai_drv = dai_drv;for (i = 0; i < count; i++) {dai = soc_add_dai(component, dai_drv + i,count == 1 && legacy_dai_naming);if (dai == NULL) {ret = -ENOMEM;goto err;}}return 0;err:snd_soc_unregister_dais(component);return ret;
}

函数所在文件:
./kernel-4.9/sound/soc/soc-core.c

/* Create a DAI and add it to the component's DAI list */
static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,struct snd_soc_dai_driver *dai_drv,bool legacy_dai_naming)
{struct device *dev = component->dev;struct snd_soc_dai *dai;dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);if (dai == NULL)return NULL;/** Back in the old days when we still had component-less DAIs,* instead of having a static name, component-less DAIs would* inherit the name of the parent device so it is possible to* register multiple instances of the DAI. We still need to keep* the same naming style even though those DAIs are not* component-less anymore.*/if (legacy_dai_naming &&(dai_drv->id == 0 || dai_drv->name == NULL)) {dai->name = fmt_single_name(dev, &dai->id);} else {dai->name = fmt_multiple_name(dev, dai_drv);if (dai_drv->id)dai->id = dai_drv->id;elsedai->id = component->num_dai;}if (dai->name == NULL) {kfree(dai);return NULL;}/* 创建新的 snd_soc_dai 并且挂在 component->dai_list */dai->component = component;dai->dev = dev;dai->driver = dai_drv;/************************************ ops 由dai_drv赋值的,* cpu dai 是:mtk_dai_stub_dai * codec dai 是:mtk_6357_dai_codecs***********************************/if (!dai->driver->ops)dai->driver->ops = &null_dai_ops;list_add(&dai->list, &component->dai_list);component->num_dai++;dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);return dai;
}

函数所在文件:
./kernel-4.9/sound/soc/soc-core.c

static void snd_soc_component_add(struct snd_soc_component *component)
{mutex_lock(&client_mutex);/* 该函数在audio的platform驱动注册的时候同样被调用了 */snd_soc_component_add_unlocked(component);mutex_unlock(&client_mutex);
}

audio驱动之cpu_dai相关推荐

  1. audio驱动之codec和codec_dai

    平台 os版本 内核 MT6765 Android 9.0 kernel-4.9 在嵌入式设备中,codec的作用可以简单的分为4种: 对PCM等信号进行D/A转换,把数字的隐僻信号转换为模拟信号. ...

  2. Waveform Audio 驱动(Wavedev2)之:WAV 驱动解析

    Waveform Audio 驱动(Wavedev2)之:WAV 驱动解析 上篇文章中,我们模拟了WAV API.现在进入我们正在要解析的Wave 驱动的架构.我们了解一个驱动的时候,先不去看具体跟硬 ...

  3. Waveform Audio 驱动(Wavedev2)之:WAV API模拟

    Waveform Audio  驱动(Wavedev2)之:WAV API模拟 Waveform 驱动对Windows Mobile来说是一个非常重要的驱动,控制着所有有关声音的操作,包括喇叭.耳机. ...

  4. MTK 驱动(60)---Audio驱动开发之音频链路

    Audio驱动开发之音频链路 [元器件说明] 本文中使用的 Codec 芯片为 ALC5677. [音频链路模型] 一个常见的音频链路如 图1 所示,包含 音频输入.ADC.DSP.DAC.音频输出 ...

  5. win7(windows7旗舰版)声卡High Definition Audio驱动 (安装失败)解决方法

    win7(windows7旗舰版)声卡High Definition Audio驱动 (安装失败)解决方案 前几天装了一下windows7体验一下,结果声卡驱动安装有问题,这电脑没声音我可没法活啊. ...

  6. 在MTK平台配置一个支持smartPA的audio驱动

    文章目录 smartPA概述 smartPA AW87319概述 smartPA AW87319功能特性 在kernel中添加对smartPA的支持 1. 在配置文件中添加对smartPA的支持 2. ...

  7. Linux Audio驱动系列(技巧篇) - tingmix调试抓Log

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎订阅! 你的喜欢就是我写作的动力! 目录 ...

  8. AUDIO驱动点检表

    AUDIO驱动点检表 备注:以下都以MT6753,ANDROID 5.1版本为基础. 1.驱动配置部分 1.1 耳机部分 配置文件: accdet_custom_def.h 耳机MIC模式配置: 默认 ...

  9. SM8150 Audio驱动分析

    1. TDM硬件接口介绍: I2S只能传2个声道的数据,PCM可以传多达16路数据,采用时分复用的方式,就是TDM. TDM不像I2S有统一的标准,不同的IC厂商在应用TDM时可能略有差异,这些差异表 ...

最新文章

  1. git命令合并分支代码
  2. 通过BeanShell获取UUID并将参数传递给Jmeter
  3. Pyqt5 获取命令行参数sys.argv
  4. oracle所有表相关查询
  5. 即日起更新机器学习相关博客
  6. 重磅!居全国前列!合肥获批建设3个国家战略性新兴产业集群!
  7. 苹果6屏幕多大_苹果12使用高通X55,10亿买下的英特尔基带何时能派上用场
  8. WEB安全基础-Javascrp相关知识点之BOM
  9. ASP.NET生成静态页面的简单实现
  10. Docker的思想来自于集装箱
  11. OLT操作命令集及排障
  12. Pascal基础教程
  13. 算数平均数与几何平均数
  14. [转帖]历史上真实的《勇敢的心》
  15. c++ min/max
  16. 怎么提高图片分辨率?如何改变图片的分辨率?
  17. 文本相似度 Text Similarity
  18. 跟我一起云计算(6)——openAPI
  19. C语言 模拟键盘、鼠标事例
  20. 融合算法性能评价指标

热门文章

  1. 博弈论分析题_微观经原笔记(四)一些关于博弈论的习题
  2. N71005-第四周
  3. HTML5页面的基本框架结构
  4. 服务器硬盘一般用哪种,服务器用哪种硬盘比较好,怎么挑选
  5. 字节跳动(抖音)软件测试月薪23K岗、技术二面面试题最新出炉
  6. Samba共享Nextcloud目录
  7. linux ext4文件系统分析,LinuxEXT4文件系统分析
  8. Python OpenCV 之图像乘除与像素的逻辑运算,图像处理取经之旅第 17 天
  9. 高级驾驶辅助系统(ADAS)——自适应巡航控制系统
  10. [总结]hosts文件妙用