ALSA声卡08_从零编写之框架_学习笔记
1、整体框架
(1)图示((DAI(全称Digital Audio Interface)接口))
在嵌入式系统里面,声卡驱动是ASOC,是在ALSA驱动上封装的一层,包括以下三大块
(2)程序框架
machine:s3c2440_uda1341.c
codec: UDA1341,WM8976
platform:IIS ,DMA
2、s3c2440_uda1341.c(参考s3c24xx_uda134x.c)
(1)分配一个平台为soc-audio的平台设备,
在这平台设备里面有一个核心结构体snd_soc_s3c24xx_uda134x设置到私有数据里面
snd_soc_s3c24xx_uda134x结构体是snd_soc_card类型的,里面有dai_link(我们需要重点关注的),dai_link确定了声卡各部分所对应的驱动程序
(2)名为soc-audio的平台设备,注册后会跟内核里面soc-core.c文件注册的同名driver匹配,最后调用probe,进行一系列的声卡注册。
3、s3c2440_uda1341.c编写
/* 参考sound\soc\samsung\s3c24xx_uda134x.c
*/
/*
* 1. 分配注册一个名为soc-audio的平台设备
* 2. 这个平台设备有一个私有数据 snd_soc_card(结构体)
* snd_soc_card里有一项snd_soc_dai_link(结构体)
* snd_soc_dai_link被用来决定ASOC各部分的驱动
*/
static struct snd_soc_ops s3c2440_uda1341_ops = {
//.hw_params = s3c24xx_uda134x_hw_params,//设置参数
};
static struct snd_soc_dai_link s3c2440_uda1341_dai_link = {
.name = "100ask_UDA1341",//结构体的名字
.stream_name = "100ask_UDA1341",//
.codec_name = "uda1341-codec",//使用哪一个编解码芯片
.codec_dai_name = "uda1341-iis",//编解码芯片里面哪一个DAI
.cpu_dai_name = "s3c2440-iis",//2440的DAI(平台部分的)
.ops = &s3c2440_uda1341_ops,//操作函数
.platform_name= "s3c2440-dma", //平台的名字
};
static struct snd_soc_card myalsa_card = {
.name = "S3C2440_UDA1341",//结构体的名字
.owner = THIS_MODULE,
.dai_link = &s3c2440_uda1341_dai_link,
.num_links = 1,
};
static void asoc_release(struct device * dev)
{
}
//定义一个名为soc-audio的平台设备
static struct platform_device asoc_dev = {
.name = "soc-audio",
.id = -1,
.dev = {
.release = asoc_release, //release函数必须要写,否则有警告信息
},
};
//入口函数
static int s3c2440_uda1341_init(void)
{
platform_set_drvdata(&asoc_dev, &myalsa_card);//把snd_soc_card结构体当做平台设备的私有数据
platform_device_register(&asoc_dev); //注册平台设备
return 0;
}
//出口函数
static void s3c2440_uda1341_exit(void)
{
platform_device_unregister(&asoc_dev);//卸载平台设备
}
4、uda1341.c(codec)
小技巧:本来想在初始化的函数里调用snd_soc_register_codec函数,但是这个函数里有device参数。所以要自己构建一个平台设备和平台驱动。
int snd_soc_register_codec(struct device *dev,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
通过注册平台设备、平台驱动来实现对snd_soc_register_codec的调用(通过平台设备和平台驱动匹配后调用probe函数)
两个核心结构体
/* 参考 sound\soc\codecs\uda134x.c
*/
/*
* 1. 构造一个snd_soc_dai_driver(结构体)
* 2. 构造一个snd_soc_codec_driver(结构体)
* 3. 注册它们
*/
static struct snd_soc_codec_driver soc_codec_dev_uda1341 = {
.probe = uda1341_soc_probe,
};
static const struct snd_soc_dai_ops uda1341_dai_ops = {
.hw_params = uda1341_hw_params,
};
static struct snd_soc_dai_driver uda1341_dai = {
.name = "uda1341-iis",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体,编解码芯片里面哪一个DAI
根据编解码芯片的数据手册确定的
/* 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 = &uda1341_dai_ops,
};
/* 通过注册平台设备、平台驱动来实现对snd_soc_register_codec的调用(通过平台设备和平台驱动匹配后调用probe函数)
*
*/
static void uda1341_dev_release(struct device * dev)
{
}
//probe函数
static int uda1341_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, //注册结构体snd_soc_dai_driver 和snd_soc_codec_driver,用哪一个codec,哪一个DAI
&soc_codec_dev_uda1341, &uda1341_dai, 1);
}
//remove函数
static int uda1341_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
//平台设备
static struct platform_device uda1341_dev = {
.name = "uda1341-codec",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体
.id = -1,
.dev = {
.release = uda1341_dev_release,
},
};
//平台驱动
struct platform_driveruda1341_drv = {
.probe=
uda1341_probe,//probe函数
.remove=
uda1341_remove,
.driver=
{
.name=
"uda1341-codec",
}
};
static int uda1341_init(void)
{
platform_device_register(&uda1341_dev);//注册平台设备
platform_driver_register(&uda1341_drv);//注册平台驱动
return 0;
}
static void uda1341_exit(void)
{
platform_device_unregister(&uda1341_dev);//卸载平台设备
platform_driver_unregister(&uda1341_drv);//卸载平台驱动
}
5、s3c2440_iis.c(Platform)
/* 参考sound\soc\samsung\s3c24xx-i2s.c
*/
//操作函数相关的结构体
static const struct snd_soc_dai_ops s3c2440_i2s_dai_ops = {
.hw_params = s3c2440_i2s_hw_params,//设置参数
.trigger = s3c2440_i2s_trigger,//触发传输
};
//我们的dai_driver没有名字,而我们的machine怎么知道使用哪一个CPU DAI,没有名字,名字在注册的时候从平台设备哦继承而来snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);
表示能够支持的属性
static struct snd_soc_dai_driver s3c2440_i2s_dai = {
.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 = &s3c2440_i2s_dai_ops,//操作函数相关的结构体
};
//probe函数(注册)
static int s3c2440_iis_probe(struct platform_device *pdev)
{
return snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);//注册cpu dai
}
remove函数(卸载)
static int s3c2440_iis_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&pdev->dev);
return 0;
}
static void s3c2440_iis_release(struct device * dev)
{
}
//注册平台设备
static struct platform_device s3c2440_iis_dev = {
.name = "s3c2440-iis",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体
.id = -1,
.dev = {
.release = s3c2440_iis_release,
},
};
//注册平台驱动
struct platform_driver s3c2440_iis_drv = {
.probe=
s3c2440_iis_probe,
.remove=
s3c2440_iis_remove,
.driver=
{
.name=
"s3c2440-iis",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体
}
};
//入口函数
static int s3c2440_iis_init(void)
{
platform_device_register(&s3c2440_iis_dev);//注册平台设备
platform_driver_register(&s3c2440_iis_drv);//注册平台驱动
return 0;
}
//出口函数
static void s3c2440_iis_exit(void)
{
platform_device_unregister(&s3c2440_iis_dev);//卸载平台设备
platform_driver_unregister(&s3c2440_iis_drv);//卸载平台驱动
}
6、s3c2440_dma.c(Platform)
/* 参考 sound\soc\samsung\dma.c
*/
/* 1. 分配DMA BUFFER
* 2. 从BUFFER取出period
* 3. 启动DMA传输
* 4. 传输完毕,更新状态(hw_ptr)
* 2,3,4这部分主要有: request_irq, 触发DMA传输, 中断处理
*/
//操作函数相关的结构体
static struct snd_pcm_ops s3c2440_dma_ops = {
.open= s3c2440_dma_open,
.close = s3c2440_dma_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = s3c2440_dma_hw_params,
.prepare = s3c2440_dma_prepare,
.trigger = s3c2440_dma_trigger,
.pointer = s3c2440_dma_pointer,
};
static struct snd_soc_platform_driver s3c2440_dma_platform = {
.ops= &s3c2440_dma_ops,//操作函数相关的结构体
.pcm_new = s3c2440_dma_new,
.pcm_free = s3c2440_dma_free,
};
//probe 函数
static int s3c2440_dma_probe(struct platform_device *pdev)
{
return snd_soc_register_platform(&pdev->dev, &s3c2440_dma_platform);//注册平台结构体,//我们的s3c2440_dma_platform没有名字,而我们的machine怎么知道使用哪一个CPU DAI,没有名字,名字在注册的时候从平台设备哦继承而来snd_soc_register_platform(&pdev->dev,
&s3c2440_dma_platform);
}
static int s3c2440_dma_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
static void s3c2440_dma_release(struct device * dev)
{
}
//平台设备
static struct platform_device s3c2440_dma_dev = {
.name = "s3c2440-dma",
.id = -1,
.dev = {
.release = s3c2440_dma_release,
},
};
//平台驱动
struct platform_drivers3c2440_dma_drv = {
.probe=
s3c2440_dma_probe,//probe函数
.remove=
s3c2440_dma_remove,
.driver=
{
.name=
"s3c2440-dma",
}
};
static int s3c2440_dma_init(void)
{
platform_device_register(&s3c2440_dma_dev);/注册平台设备
platform_driver_register(&s3c2440_dma_drv);//注册平台驱动
return 0;
}
static void s3c2440_dma_exit(void)
{
platform_device_unregister(&s3c2440_dma_dev);
platform_driver_unregister(&s3c2440_dma_drv);
iounmap(dma_regs);
}
7、总结
ALSA声卡08_从零编写之框架_学习笔记的更多相关文章
- ALSA声卡10_从零编写之数据传输_学习笔记
1.引言 (1)应用程序使用声卡的时候,数据流程是:应用程序把数据发送给驱动,驱动把数据发送给硬件声卡,声卡把数据转换成声音数据播放出去. (2)可以使用两种方式发送数据 第一种:app发数据,等驱动 ...
- ALSA声卡11_从零编写之调试——学习笔记
1.调试 (1)把程序拷贝到服务器上进行编译 (2)把程序放到内核上面去 重新配置内核,吧原来的声卡驱动程序去掉 a. 修改语法错误 11th_myalsa b. 配置内核去掉原来的声卡驱动 -> ...
- ALSA声卡12_从零编写之添加音量控制_学习笔记
1.设置音量时应用程序的调用过程 (1)strace分析: amixer cset numid=1 30 (设置音量) /dev/snd/controlC0 open SNDRV_CTL_IOCTL_ ...
- ALSA声卡09_从零编写之参数设置_学习笔记
1.参数设置分析 (1)open: soc_pcm_open 依次调用cpu_dai, dma, codec_dai, machine的open或startup函数 只在dma的open函数里添加参数 ...
- go微服务框架kratos学习笔记八 (kratos的依赖注入)
目录 go微服务框架kratos学习笔记八(kratos的依赖注入) 什么是依赖注入 google wire kratos中的wire Providers injector(注入器) Binding ...
- jfinal框架教程-学习笔记
jfinal框架教程-学习笔记 JFinal 是基于 Java 语言的极速 WEB + ORM 开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restfu ...
- Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)
在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...
- Mina框架的学习笔记——Android客户端的实现
Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...
- golang日志框架--logrus学习笔记
golang日志框架--logrus学习笔记 golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数,对于更精细的日志级别.日志文件分割以及日志分发等方面并没有提供 ...
随机推荐
- StringUtils.isEmpty和StringUtils.isBlank的区别
两个方法都是判断字符是否为空的.前者是要求没有任何字符,即str==null 或 str.length()==0:后者要求是空白字符,即无意义字符.其实isBlank判断的空字符是包括了isEmpty ...
- 如何使用fiddller跟踪windows进程发送的请求20140911
总结点:如何使用fiddller跟踪windows进程发送的请求 案例如下: 需求:运维工具提出需求,对每个插件的配置文件,同步到运维中心时先加密,然后传输到运维中心解密,存储到数据库 测试分析:这个 ...
- awk结合正则匹配
利用awk分析data.csv中label列各取值的分布. 在终端执行head data.csv查看数据: name,business,label,label_name 沧州光松房屋拆迁有限公司,旧房 ...
- 安装hadoop 2.2.0
安装环境为 CentOS 64位系统, 大概分下面几个步奏, 0. 安装JDK1. 配置SSH2. 配置/etc/hosts3. 拷贝hadoop包到没台机器上4. 修改hadoop配置文件5. 关闭 ...
- ExpressCache
ExpressCache 非联想.等品牌电脑使用的ExpressCache(带破解文件). (原始安装文件+patch+说明).注意,执行eccmd命令时,需要管理员权限.否则报错. http://a ...
- 十天学会单片机Day6 学会看数据手册 (IIC总线PCF859芯片( A/D D/A)应用)
1.实际电路 2.引脚图 3.地址 高四位为固定地址1001,A2A1A0可编程地址,通过观察实际电路,可知A2A1A0 为000.最低位为读写为,1为读,0为写. 4.控制字 控制寄存器的高半字节用 ...
- Codeforces 1012C Hills【DP】*
Codeforces 1012C Hills Welcome to Innopolis city. Throughout the whole year, Innopolis citizens suff ...
- BZOJ2565 最长双回文串 【Manacher】
BZOJ2565 最长双回文串 Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"c ...
- git 第一次提交至仓库
可以打开Idea 的 terminal直接进行命令操作 1.git init 2.git add src(这个src意思是添加src目录下的所有文件,有些会说add .. 那就是提交工程下的所有 ...
- mix deps HEX_HTTP_CONCURRENCY=1 HEX_HTTP_TIMEOUT=120 timeout
mix deps.get timeout 问题: If this happens consistently, adjust your concurrency and timeout setting ...