Linux音频驱动-AOSC之Codec
概述
Codec代码分析
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {.name = "UDA134X",.stream_name = "UDA134X",.codec_name = "uda134x-codec",.codec_dai_name = "uda134x-hifi",.cpu_dai_name = "s3c24xx-iis",.ops = &s3c24xx_uda134x_ops,.platform_name = "s3c24xx-iis",
};
在内核中搜索codec_name="uda134x-codec",会在kernel/sound/soc/codec/uda134x.c中发现。
static struct platform_driver uda134x_codec_driver = {.driver = {.name = "uda134x-codec",.owner = THIS_MODULE,},.probe = uda134x_codec_probe,.remove = uda134x_codec_remove,
};
之间查看此platform_driver的probe函数
static int uda134x_codec_probe(struct platform_device *pdev)
{return snd_soc_register_codec(&pdev->dev,&soc_codec_dev_uda134x, &uda134x_dai, 1);
}
此出通过snd_soc_register_codec函数注册了uda134x的codec,同时传入了snd_soc_codec_driver和snd_soc_dai_driver结构。
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,.dapm_widgets = uda134x_dapm_widgets,.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),.dapm_routes = uda134x_dapm_routes,.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
};
snd_soc_dai_driver结构:
static const struct snd_soc_dai_ops uda134x_dai_ops = {.startup = uda134x_startup,.shutdown = uda134x_shutdown,.hw_params = uda134x_hw_params,.digital_mute = uda134x_mute,.set_sysclk = uda134x_set_dai_sysclk,.set_fmt = uda134x_set_dai_fmt,
};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,
};
继续进入snd_soc_register_codec函数分析。
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)return -ENOMEM;codec->component.dapm_ptr = &codec->dapm;
codec->component.codec = codec;
2. 调用snd_soc_component_initialize函数进行component部件的初始化,会根据snd_soc_codec_driver中的struct snd_soc_component_driver结构设置snd_soc_codec中的component组件,详细代码不在贴出。
ret = snd_soc_component_initialize(&codec->component,&codec_drv->component_driver, dev);
3. 根据snd_soc_codec_driver的参数,进行一系列的初始化,
if (codec_drv->controls) {codec->component.controls = codec_drv->controls;codec->component.num_controls = codec_drv->num_controls;
}
if (codec_drv->dapm_widgets) {codec->component.dapm_widgets = codec_drv->dapm_widgets;codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
}
if (codec_drv->dapm_routes) {codec->component.dapm_routes = codec_drv->dapm_routes;codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
}if (codec_drv->probe)codec->component.probe = snd_soc_codec_drv_probe;
if (codec_drv->remove)codec->component.remove = snd_soc_codec_drv_remove;
if (codec_drv->write)codec->component.write = snd_soc_codec_drv_write;
if (codec_drv->read)codec->component.read = snd_soc_codec_drv_read;
codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
if (codec_drv->seq_notifier)codec->dapm.seq_notifier = codec_drv->seq_notifier;
if (codec_drv->set_bias_level)codec->dapm.set_bias_level = snd_soc_codec_set_bias_level;
codec->dev = dev;
codec->driver = codec_drv;
codec->component.val_bytes = codec_drv->reg_word_size;
mutex_init(&codec->mutex);
4. 根据snd_soc_dai_driver中的参数设置Format
for (i = 0; i < num_dai; i++) {fixup_codec_formats(&dai_drv[i].playback);fixup_codec_formats(&dai_drv[i].capture);}
5. 调用snd_soc_register_dais接口注册dai,传入参数有dai的驱动,以及dai的参数,因为一个codec不止一个dai接口。
ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
if (ret < 0) {dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);goto err_cleanup;
}
根据dai的数目,分配snd_soc_dai结构,根据dai的数目设置dai的名字,这是dai的传入参数驱动,然后将此dai加入到component的dai_list中。
for (i = 0; i < count; i++) {dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);if (dai == NULL) {ret = -ENOMEM;goto err;}/** 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 (count == 1 && legacy_dai_naming) {dai->name = fmt_single_name(dev, &dai->id);} else {dai->name = fmt_multiple_name(dev, &dai_drv[i]);if (dai_drv[i].id)dai->id = dai_drv[i].id;elsedai->id = i;}if (dai->name == NULL) {kfree(dai);ret = -ENOMEM;goto err;}dai->component = component;dai->dev = dev;dai->driver = &dai_drv[i];if (!dai->driver->ops)dai->driver->ops = &null_dai_ops;list_add(&dai->list, &component->dai_list);dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
}
6. 根据component的dai_list,对所有的dai设置其所属的codec。
list_for_each_entry(dai, &codec->component.dai_list, list)dai->codec = codec;
7. 将所有的组间加入到component_list中,然后将注册的codec存入codec_list中。
mutex_lock(&client_mutex);
snd_soc_component_add_unlocked(&codec->component);
list_add(&codec->list, &codec_list);
mutex_unlock(&client_mutex);
至此,codec的注册就分析完毕。
总结: 通过调用snd_soc_register_codec函数之后,分配的codec最终放入了codec_list链表中,codec下的component组件全部放入component_list链表中,codec下的dai全部存放入code->component.dai_list中。 可以在上节的Machine中看到,machine匹配codec_dai和cpu_dai也是从code->component.dai_list中获取的。
2. 定义struct snd_soc_codec_driver结构,设置,初始化。
Linux音频驱动-AOSC之Codec相关推荐
- Linux 音频驱动
Linux 音频驱动 硬件介绍 WM8960与IMX6ULL之间有两个通信接口:I2C和I2S 其中I2C用于配置WM8960 I2S用于音频数据传输 修改设备树文件 编写I2C子节点设备树 code ...
- Linux 音频驱动(四) ASoC音频驱动之Machine驱动
目录 1. 基本介绍 2. 源码分析 2.1. Machine数据结构 struct snd_soc_dai_link 3. 声卡 3.1. 数据结构struct snd_soc_card 3.2. ...
- Linux 音频驱动(五) ALSA音频驱动之PCM逻辑设备
目录 1. 前言 2. PCM逻辑设备 2.1. 创建 PCM逻辑设备: 2.2. PCM逻辑设备文件操作函数集:snd_pcm_f_ops[] 2.3. Open PCM逻辑设备 2.4. Writ ...
- STM32MP157驱动开发——Linux 音频驱动
STM32MP157驱动开发--Linux 音频驱动 一.简介 1.CS42L51 简介 2.I2S总线 3.STM32MP1 SAI 总线接口 二.驱动开发 1.音频驱动 1)修改设备树 i2c 接 ...
- Linux音频驱动之二:Control接口的调用
本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记 一. control接口说明 Control接口主要让用户空间的应用程序(alsa-lib)可以访问和控制音频 ...
- 转载:Linux音频驱动-OSS和ALSA声音系统简介及其比较
Linux音频驱动-OSS和ALSA声音系统简介及其比较 概述 昨天想在Ubuntu上用一下HTK工具包来绘制语音信号的频谱图和提取MFCC的结果,但由于前段时间把Ubuntu升级到13.04,系统的 ...
- Linux 音频驱动(二) ASoC音频驱动之Platform驱动
目录 1. 简介 2. 源码分析 2.1. CPU DAI 2.1.1. 数据结构struct snd_soc_dai_driver 2.1.2. 注册CPU DAI:snd_soc_register ...
- linux 音频架构绕过,linux音频驱动架构
1.linux音频驱动架构分为3部分组成:硬件无关层(核心层ALSA).板级音频数字接口层驱动(McASP.McBSP等).外部codes驱动 sound/soc/davinci/ti81xx-etv ...
- linux 音频驱动的流程,Intel平台下Linux音频驱动流程分析
[软件框架] 在对要做的事情一无所知的时候,从全局看看系统的拓扑图对我们认识新事物有很大的帮助.Audio 部分的驱动程序框架如下图所示: 这幅图明显地分为 3 级. 上方蓝色系的 ALSA Kern ...
- Linux音频驱动开发概括
原址 1.嵌入式音频系统硬件连接 下图所示的嵌入式设备使用IIS将音频数据发送给编解码器.对编解码器的I/O寄存器的编程通过IIC总线进行. 2.音频体系结构-ALSA ALSA是Advanced L ...
最新文章
- linux默认shell类型转换,Linux中默认的shell如何切换为其他类型的shell
- 蓄力十年,做一个成就
- 每天学习flash一点(3) flash外部读取xml
- Unity C# namespace 命名空间的使用
- ios 图片居中裁剪_[ iOS Shortcuts / Workflow ] 分享一个给照片批量加「底部居中偏上」水印的捷径,可适应不同水印的尺寸...
- linux杀掉进程后总是重启,Linux监控进程,进程关闭自动重启方案
- 再读《精通css》00
- andriod环境搭建
- 如何拯救美团的“中年危机”?
- java中的龟兔赛跑代码_有关JAVA编写龟兔赛跑的游戏的问题。求助……
- Jmeter设置默认中文页面
- python脚本操作excel
- hbase的region分区
- 基于ssm的记账管理系统设计与实现【毕业设计jsp】
- 最护眼的电脑屏幕颜色是黑色?
- js 仿微信投诉—引入vue.js,拆分组件为单个js
- 在c语言中 if语句后的一对原括号,c语言中if语句后的一对圆括号中
- 浅谈如何做好督查督办工作?
- 成功实现NAS家庭服务器(流媒体播放、文件共享及下载机)
- 高薪运维经典企业版面试题汇总