ASOC 音频子系统框架
基于: Mini2440 开发板, Linux 3.4.2 内核
ASOC 简介:
ASoC - ALSA System on Chip,是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中音频 Codec 的一套软件体系。
就像软件领域里的抽象和重用一样,嵌入式设备的音频系统可以被划分为 Machine、Platform、 Codec。
所以,我们可以把 ASOC 的驱动分为 3 个部分,以内核中的文件为例:
Machine:
S3c24xx_uda134x.c (sound\soc\samsung)
Platform:
S3c24xx-i2s.c (sound\soc\samsung)
Dma.c (sound\soc\samsung)
Codec:
Uda134x.c (sound\soc\codecs)
我们以 S3c24xx_uda134x.c 文件中的 s3c24xx_uda134x_probe 函数为起点:
/* 创建并配置一个 snd_soc_card 结构体 */
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
.name = "S3C24XX_UDA134X",
.owner = THIS_MODULE,
.dai_link = &s3c24xx_uda134x_dai_link,
.num_links = 1,
};
/* 申请一个名为 "soc-audio" 的 platform_device */
s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
/* 设置 platform_device 的 drvdata */
platform_set_drvdata(s3c24xx_uda134x_snd_device,
&snd_soc_s3c24xx_uda134x);
/* 将 s3c24xx_uda134x 添加进平台设备,它是 UDA1341 芯片的引脚状态信息 */
platform_device_add_data(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x, sizeof(s3c24xx_uda134x));
/* 添加平台设备 */
ret = platform_device_add(s3c24xx_uda134x_snd_device);
这里的 snd_soc_dai_link 结构尤为重要,在它的内部指定了 Platform、Codec、 codec_dai、 cpu_dai 的名字,稍后 Machine 驱动将会利用这些名字去匹配已经在系统中注册了的 platform、codec、dai,这些注册的接口都是在另外相应的 Platform 驱动和
Codec 驱动的代码文件中定义的。由此可见,Machine 的功能可认为是匹配相应的驱动实现一个完成的音频控制体系。
注册了名为 "soc-audio" 的 platform_device 之后,系统会在内核中找到同名的 driver,随后调用 driver 的 probe 函数,该函数主要是完成声卡的实例化、调用各个子接口的 probe 函数、创建标准 alsa 驱动的 pcm 逻辑设备以及完成声卡的注册。
Uda134x.c 文件
该文件为 ASOC 的 Codec 驱动,主要是完成 Codec 芯片的各种操控,我们以 uda134x_codec_probe 函数为入口:
static struct snd_soc_dai_driver uda134x_dai = {
.name = "uda134x-hifi",
/* playback capabilities */
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = UDA134X_RATES,
.formats = UDA134X_FORMATS,
},
/* capture capabilities */
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = UDA134X_RATES,
.formats = UDA134X_FORMATS,
},
/* pcm operations */
.ops = &uda134x_dai_ops,
};
static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.remove = uda134x_soc_remove,
.suspend = uda134x_soc_suspend,
.resume = uda134x_soc_resume,
.reg_cache_size = sizeof(uda134x_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = uda134x_reg,
.reg_cache_step = 1,
.read = uda134x_read_reg_cache,
.write = uda134x_write,
.set_bias_level = uda134x_set_bias_level,
};
/* 注册 Codec */
snd_soc_register_codec(&pdev->dev, &soc_codec_dev_uda134x, &uda134x_dai, 1);
snd_soc_register_codec 函数的大体步骤:
/* 分配 snd_soc_codec */
1. codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
2. 配置 Codec
/* 注册 dais */
3. snd_soc_register_dais:
/* 分配 snd_soc_dai */
1. dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
2. 配置 Dai
3. 将 Dai 加入到 dai_list
4. 调用 snd_soc_instantiate_cards 函数触发一次匹配绑定操作
4. 将 Codec 加入到 codec_list
5. 调用 snd_soc_instantiate_cards 函数触发一次匹配绑定操作
S3c24xx-i2s.c 与 Dma.c 文件
ASOC 把 Platform 驱动分为两个部分:snd_soc_platform_driver 和
snd_soc_dai_driver。其中,platform_driver 负责管理音频数据,把音频数据通过 dma 或其他操作传送至 cpu dai
中,dai_driver 则主要完成 cpu 一侧的 dai 的参数配置,同时也会通过一定的途径把必要的 dma 等参数与 snd_soc_platform_driver 进行交互。
先来看 Dma.c 中的 samsung_asoc_platform_probe 函数:
static struct snd_pcm_ops dma_ops = {
.open = dma_open,
.close = dma_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = dma_hw_params,
.hw_free = dma_hw_free,
.prepare = dma_prepare,
.trigger = dma_trigger,
.pointer = dma_pointer,
.mmap = dma_mmap,
};
static struct snd_soc_platform_driver samsung_asoc_platform = {
.ops = &dma_ops,
.pcm_new = dma_new,
.pcm_free = dma_free_dma_buffers,
};
/* 注册 soc platform */
snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
snd_soc_register_platform 函数中申请、配置了 snd_soc_platform 结构,并将其加入到了 platform_list,然后调用 snd_soc_instantiate_cards 函数进行绑定。
samsung_asoc_platform 结构中的 pcm_new 主要用来分配一个 buffer,dma 使用它来操作音频数据; pcm_free 用来释放这个 buffer; ops 中为涉及到 dma 操作以及 dma buffer 管理等工作的函数。
S3c24xx-i2s.c 中的 s3c24xx_iis_dev_probe 函数:
static const struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
.trigger = s3c24xx_i2s_trigger,
.hw_params = s3c24xx_i2s_hw_params,
.set_fmt = s3c24xx_i2s_set_fmt,
.set_clkdiv = s3c24xx_i2s_set_clkdiv,
.set_sysclk = s3c24xx_i2s_set_sysclk,
};
static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
.probe = s3c24xx_i2s_probe,
.suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume,
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = S3C24XX_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = S3C24XX_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &s3c24xx_i2s_dai_ops,
};
/* 注册 soc dai */
snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
snd_soc_register_dai 函数中申请、配置了 snd_soc_dai 结构,并将其加入到了 dai_list,然后调用 snd_soc_instantiate_cards 函数进行绑定。
这两个结构中的函数不难理解,主要是为了配置 I2S 的引脚及时钟、dai 数据格式等。
这些函数可能会由 soc-core 或 Machine 驱动中的函数调用。
ASOC 音频子系统框架的更多相关文章
- 【Linux高级驱动】input子系统框架
[1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架? 1) 通过网络搜索 2) 自己想办法跟内核代码! 2.1 定位此驱动是属于哪种类 ...
- 【Linux高级驱动】input子系统框架【转】
转自:http://www.cnblogs.com/lcw/p/3802617.html [1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架? 1) 通过网 ...
- Linux驱动修炼之道-RTC子系统框架与源码分析【转】
转自:http://helloyesyes.iteye.com/blog/1072433 努力成为linux kernel hacker的人李万鹏原创作品,为梦而战.转载请标明出处 http://bl ...
- Linux输入子系统框架分析(1)
在Linux下的输入设备键盘.触摸屏.鼠标等都能够用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层.事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备 ...
- 音频分析框架pyAudioAnalysis文档
“ pyAudioAnalysis是一个非常好用且强大的音频分析开源工具,能实现音频的特征提取.分类和回归模型的训练和执行,以及其他一些实用的功能.此外,本文档并非直译,也有部分比较简略,可以结合源码 ...
- Linux 驱动框架---input子系统框架
前面从具体(Linux 驱动框架---input子系统)的工作过程学习了Linux的input子系统相关的架构知识,但是前面的学习比较实际缺少总结,所以今天就来总结一下输入子系统的架构分层,站到远处来 ...
- alsamixer 在音频子系统的使用
alsamixer是Linux 音频架构ALSA工具的其中一个,用于配置音频的各个参数. alsamixer是基于文本下的图形界面的,可以通过键盘的上下键,左右键等,很方便地设置需要的音量,开关某个s ...
- input子系统框架
废话不多说,直接进入主题.在驱动insmod后,我们应用层对input设备如何操作?以下以全志a64为实例. 在/dev/input/eventX下(X的形成为后续会分析),是内核把接口暴露给应用层, ...
- linux驱动由浅入深系列:tinyalsa(tinymix/tinycap/tinyplay/tinypcminfo)音频子系统之一【转】
本文转载自:http://blog.csdn.net/radianceblau/article/details/64125411 目前linux中主流的音频体系结构是ALSA(Advanced Lin ...
随机推荐
- TensorFlow数据读取
TensorFlow高效读取数据的方法 TF Boys (TensorFlow Boys ) 养成记(二): TensorFlow 数据读取 Tensorflow从文件读取数据 极客学院-数据读取 十 ...
- Axure RP Extension for Chrome 插件安装
描述 我的chmod浏览器上不去谷歌商店,我用的是蓝灯,登上商店后搜索Axure RP Extension for Chrome,下载安装,完成后进入这个插件的详细信息: 使用 打开用axure生成的 ...
- MySQL安装及后续配置
rpm -qa | grep mysql 检查已安装的mysql版本 rpm -e --nodeps mysql-libs-5.1.71 卸载 tar -zxvf MySQL.tar.gz 解压 安 ...
- 别人的Linux私房菜(7)文件与目录管理
- 代表上一个工作目录 ~username代表用户所在的家目录 cd切换目录 配合之上的参数 . .. / ~ ~name (change directory) pwd显 ...
- python 实践项目 强密码检测
需求:写一个函数,它使用正则表达式,确保传入的口令字符串是强口令.强口令的定义是:长度不少于 8 个字符,同时包含大写和小写字符,至少有一位数字.你可能需要用多个正则表达式来测试该字符串,以保证它的强 ...
- http协议基本原理
HTTP(HyperText Transport Protocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP协议的详细内容请参考RFC2616.HTTP协议采用了请求/响应模型 ...
- pop
package com.example.hellopopupwindow; import android.os.Bundle; import android.app.Activity; import ...
- PHP几种加密方式
1.MD5() 2.Sha1() 3.urlencode()方法用于加密,urldecode()方法用于解密 4.base64_encode ( ) 64位加密 base64_decode ( ...
- 【接口时序】8、DDR3驱动原理与FPGA实现(一、DDR的基本原理)
一. 软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:无 3.仿真工具:无 硬件平台: 1. FPGA型号:无 2. DDR3型号:无 二. 存储器的分类 存储器一 ...
- poj1149构图题
引题解: 这道题目的大意是这样的:⦁ 有 M 个猪圈(M ≤ 1000),每个猪圈里初始时有若干头猪.⦁ 一开始所有猪圈都是关闭的.⦁ 依次来了 N 个顾客(N ≤ 100),每个顾客分别会打开指定 ...