linux 音频驱动的流程,Intel平台下Linux音频驱动流程分析
【软件框架】
在对要做的事情一无所知的时候,从全局看看系统的拓扑图对我们认识新事物有很大的帮助。Audio 部分的驱动程序框架如下图所示:
这幅图明显地分为 3 级。
上方蓝色系的 ALSA Kernel 整体属于Linux Kernel,是原生Linux 操作系统的一部分,其中又分出 ASoC Core 和 PCM Core 两级,和她们相关的代码都可以直接在 Linux 源码中找到。
中间淡红色的部分看名字就知道和驱动相关,分为左右 2 条支线。需要注意的是左侧支线由 ASoC 派生而来,而 ASoC 虽本质上属于 ALSA,但在代码上将各部分驱动进行分离设计,也就是这里看到的 Platform Driver、Machine Driver、Codec Driver,分别对应 CPU 驱动、板驱动、编解码芯片驱动。这种架构增强了 CPU 芯片驱动和编解码芯片驱动的可移植性,让我们在开发音频驱动时只需要重新编写电路板相关的板驱动即可。进一步分析,紧接 Platform Driver 后面是 SST Driver,这个 SST 即 Smart Sound Technology,是 Intel 自研的技术,所以这部分结构不一定适用于其它 CPU 芯片,但一旁的 DMA Driver 却是所有 CPU 驱动都必须包含的,因为音频的实质是数据;Codec Driver 之后是 I2C 驱动,对于编解码芯片寄存器的读写都是通过 I2C 总线实现。右侧支线从 PCM Core 引出,这部分我目前还不熟悉,从框图和字面意思上看是和高清音频接口相关的,直接通过 ALSA 的 PCM 机制进行操作并且在硬件上使用专门的 HDMI 控制器而非编解码芯片。
下方灰色一级是最底层的硬件部分,依次为 CPU 内嵌的 DSP 模块、独立的编解码芯片、独立的 HDMI 控制器。在 DSP 与 Codec 之间存在音频数据传输,虽然在图中没有注明,但我们知道这是通过 I2S 总线实现的。在我的实际项目中,DSP 模块集成在编解码芯片中。
无疑,编解码芯片驱动,也即 Codec Driver 部分是我们编写音频驱动的核心。负责对内驱动芯片实现设备/驱动正常注册,对外沟通 DSP 进行音频数据交换。所以下文以此为中心进行代码分析。
【源码文件架构】
按照 ASoC 框架的设计理念,源码文件应该分为 3 个部分,分别是 Platform Driver、Machine Driver、Codec Driver,这 3 者为并行关系,各对应一份源码。其中,Platform Driver 相关的源码主要实现 DMA 功能和 DAI,即 DSP 模块的 I2S 数据传输功能,并导出相应变量或操作函数接口;Codec Driver 相关的源码主要实现 I/O 控制、DAPM 和 PCM 配置,并导出相应变量或操作函数接口;Machine Driver 相关的源码则将前 2 个文件中导出的接口绑定在一起。内核启动后,以模块的形式加载 3 个驱动。
在我的实际项目中,文件 rt5677.c 中是 Codec Driver 部分的源码,文件 cht_rt5677.c 中则为 Machine Driver 部分的源码。前者实现编解码芯片的寄存器配置、设备/驱动创建与注册,后者实现将 Machine 与 Platform 绑定。
【Machine Driver 代码分析】
既然驱动是以模块的形式载入的,那么我们就从模块初始化函数开始阅读代码。
模块初始化函数部分的代码为 late_initcall(snd_cht_driver_init);
查看 snd_cht_driver_init() 函数:
static int __init snd_cht_driver_init(void)
{
…
return platform_driver_register(&snd_cht_mc_driver);
}
原来是注册 platform 驱动,接下来的流程应该就比较熟悉了。
结构体snd_cht_mc_driver 的定义如下:
static struct platform_driver snd_cht_mc_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "cht_rt5677",
.pm = &snd_cht_mc_pm_ops,
},
.probe = snd_cht_mc_probe, // 绑定 probe() 函数
.remove = snd_cht_mc_remove,
.shutdown = snd_cht_mc_shutdown,
};
这里的 probe 函数 snd_cht_mc_probe() 会在平台驱动注册过程中被调用。查看该函数代码:
static int snd_cht_mc_probe(struct platform_device *pdev)
{
…
/* register the soc card */
snd_soc_card_cht.dev = &pdev->dev;
ret_val = snd_soc_register_card(&snd_soc_card_cht); // 注册声卡
…
platform_set_drvdata(pdev,&snd_soc_card_cht); // 设定声卡信息
codec = cht_get_codec(&snd_soc_card_cht);
// use gpio GPIO_SPK_EN to enable/disable ext boost pa
gpio_request(GPIO_SPK_EN, "speaker boost pa ctl");
gpio_direction_output(GPIO_SPK_EN, 0);
…
return ret_val;
}
其中 snd_soc_register_card() 是ASoC Core 中的函数,由Linux 内核实现,功能是创建和注册一个声卡设备。而函数 platform_set_drvdata() 的功能是将预设的声卡结构体值配置到 machine driver。追踪 snd_soc_card_cht 这个结构体,其定义如下:
/* SoCcard */
static struct snd_soc_card snd_soc_card_cht = {
.name = "cherrytrailaud",
.dai_link = cht_dailink, // 绑定 dai_link
.num_links = ARRAY_SIZE(cht_dailink),
.set_bias_level = cht_set_bias_level,
.dapm_widgets = cht_dapm_widgets, // 绑定 dapm_widgets
.num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
.dapm_routes = cht_audio_map,
.num_dapm_routes = ARRAY_SIZE(cht_audio_map),
.controls = cht_mc_controls, // 绑定 controls
.num_controls = ARRAY_SIZE(cht_mc_controls),
};
在这里我们看到了 cht_dailink 数组、cht_dapm_widgets() 数组、cht_mc_controls 数组。后 2 者主要实现 DAPM 相关操作,我们重点查看 cht_dailink,该数组核心部分代码如下:
static struct snd_soc_dai_link cht_dailink[] = {
[CHT_DPCM_AUDIO] = {
.name = "Cherrytrail Audio Port",
.stream_name = "Cherrytrail Audio",
.cpu_dai_name = "Headset-cpu-dai",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "sst-platform",
.init = cht_audio_init, // 绑定 init() 函数
.ignore_suspend = 1,
.dynamic = 1,
.ops = &cht_aif1_ops,
.dpcm_playback = 1,
},
…
};
初始化函数 cht_audio_init() 在第 1 个 cht_dailink 元素中被绑定。至此,Machine Driver 相关代码的分析就完成了。
linux 音频驱动的流程,Intel平台下Linux音频驱动流程分析相关推荐
- linux程序卸载动态库,Intel平台下linux中ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载...
在 IBM Bluemix 云平台上开发并部署您的下一个应用. 相信读者已经看过了 Intel平台下Linux中ELF文件动态链接的加载.解析及实例分析(一): 加载的内容了,了解了ELF文件被加载的 ...
- 三星 arm9 linux,基于arm9内核三星s3c2410平台下linux四键按键驱动程序
#ifndef __kernel__ #define __kernel__ #endif #ifndef module #define module #endif#include #include # ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的I2C驱动架构分析
PowerPC + Linux2.6.25平台下的I2C驱动架构分析 Sailor_forever sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的SPI驱动架构分析
PowerPC + Linux2.6.25平台下的SPI驱动架构分析 Sailor_forever sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...
- linux sybase 自动备份,Linux平台下Sybase数据库备份方法分析.doc
Linux平台下Sybase数据库备份方法分析 Linux平台下Sybase数据库备份方法分析 摘 要:对于从事信息系统管理的人员来说,掌握数据库的备份方法在工作中尤为重要.当本地数据出错或者磁盘损坏 ...
- Ubuntu 16.04安装Intel显卡驱动(解决Intel HD Graphics 630显卡驱动问题)
一般Ubuntu都默认包含了Intel显卡的驱动,如果没有,那么先确定是不是显卡太高,比如I7第7代的CPU核显在Ubuntu 16.04中是没有的,导致画面会很卡,原因是Linux 4.4内核不包含 ...
- linux NAND驱动之三:6410平台上的NAND驱动加载
1,platform_driver 的定义和注册 在s3c_nand.c中, static struct platform_driver s3c6410_nand_driver = { ...
- 【个人总结】基于项目的AI Studio平台下Linux深度学习环境配置心得
更新一下:现在AI Studio应该已经不能用其他深度学习框架了,用一会儿就会中断 前言 PS:本部分主要是对本周工作的总结,标题对应的内容可以跳过本部分 上周主要的工作是研究了一下项目utils文件 ...
- FreeScale mpc8xxx + vxWorks平台下spi flash驱动开发三步走
最近在弄PowerPC平台上的spi flash的驱动程序,总体比较简单,在借鉴了U-Boot中的相关源码后,花了两周左右的时间搞定了,对于spi总线之前一直都有了解,但未能实际接触,这次在vxWor ...
最新文章
- automaticallyAdjustsScrollViewInsets
- 2013 年最不可思议的 10 个硬件开源项目
- centos7 下进行数据库自动备份
- 关于python文件_关于python文件操作
- 一休和尚 小布偶 晴天娃娃
- 泛型中的模糊继承,解析T的意义
- CRC校验算法的解析,暨对网上的CRC详解的补充
- oracle按照指定顺序读取,oracle按照指定顺序进行排序
- python中set index_python中set基础应用
- 节点name在graph中无法展示_图节点分类与消息传递
- 男性玩家占78.8%、90后玩家占近50%、最多人选择中国风链游……《2019链游玩家需求调研报告》重磅发布!...
- NSGA2算法中文版详细介绍
- 保存网页文章为PDF文件
- Pwn-2018_HITB_CTF-gundam
- 使用PS去掉、添加、复制图片中的文字
- python中度数怎么表示_python中如何将华氏温度转换为摄氏温度?
- fiddler更新后证书导出和报错的坑(The root certificate could not be located.)
- Java学习从这里开始
- 雪球结构定价与风险深度分析
- 程序员如何使正确卖出自己的程序但是不想被人知道代码的具体实现?