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_从零编写之框架_学习笔记的更多相关文章

  1. ALSA声卡10_从零编写之数据传输_学习笔记

    1.引言 (1)应用程序使用声卡的时候,数据流程是:应用程序把数据发送给驱动,驱动把数据发送给硬件声卡,声卡把数据转换成声音数据播放出去. (2)可以使用两种方式发送数据 第一种:app发数据,等驱动 ...

  2. ALSA声卡11_从零编写之调试——学习笔记

    1.调试 (1)把程序拷贝到服务器上进行编译 (2)把程序放到内核上面去 重新配置内核,吧原来的声卡驱动程序去掉 a. 修改语法错误 11th_myalsa b. 配置内核去掉原来的声卡驱动 -> ...

  3. ALSA声卡12_从零编写之添加音量控制_学习笔记

    1.设置音量时应用程序的调用过程 (1)strace分析: amixer cset numid=1 30 (设置音量) /dev/snd/controlC0 open SNDRV_CTL_IOCTL_ ...

  4. ALSA声卡09_从零编写之参数设置_学习笔记

    1.参数设置分析 (1)open: soc_pcm_open 依次调用cpu_dai, dma, codec_dai, machine的open或startup函数 只在dma的open函数里添加参数 ...

  5. go微服务框架kratos学习笔记八 (kratos的依赖注入)

    目录 go微服务框架kratos学习笔记八(kratos的依赖注入) 什么是依赖注入 google wire kratos中的wire Providers injector(注入器) Binding ...

  6. jfinal框架教程-学习笔记

    jfinal框架教程-学习笔记 JFinal  是基于 Java  语言的极速  WEB  + ORM  开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restfu ...

  7. Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)

    在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...

  8. Mina框架的学习笔记——Android客户端的实现

    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...

  9. golang日志框架--logrus学习笔记

    golang日志框架--logrus学习笔记 golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数,对于更精细的日志级别.日志文件分割以及日志分发等方面并没有提供 ...

随机推荐

  1. Eclipse下配置Maven

    1.修改maven根目录下的conf/setting.xml文件,主要修改localRepository属性,用于管理maven下载的jar文件存放的位置. 2.修改eclipse的maven配置,w ...

  2. RTP协议学习

    RTP协议是承载在UDP协议之上的应用协议 http://blog.csdn.net/chen495810242/article/details/39207305 http://blog.51cto. ...

  3. macOS 下安装SDKMAN 软件开发工具包管理器

    SDKMAN 软件开发工具包管理器的安装非常简单,只需要打开终端,执行: $ curl -s "https://get.sdkman.io" | bash 就OK了,输出类似如下: ...

  4. 前端自动化之sass实时编译及自动刷新浏览器

    gulp livereload实现sass实时编译及浏览器自动刷新 首先gulp是基于Node的,所以确保你已经安装 node.js,在Nodejs官方网站下载跟自己操作系统相对应的安装包. 先说一下 ...

  5. python中封装

    封装 引子 从封装的本身意思去理解,封装就是用一个袋子,把买的水果.书.水杯一起装进袋子里,然后再把袋子的口给封上,照这样的理解来说,封装=隐藏,但是,这种理解是片面的 ## 如何封装 在python ...

  6. fedora 27

    安装 U盘安装,感谢学长的U盘 配置 安装外来软件的时候,需要输入root密码 软件 软件安装是个麻烦事儿啊 详情 [新手指南: 在 Ubuntu 和 Fedora 上安装软件包] Fedora 中文 ...

  7. ICCS 会议 Latex 压缩文件提交主要事项

    cd papers/conf latex main... check that the are no error messages ...zip -r mypaper.zip * 说明:必须在Linu ...

  8. 网站部署,网站要求需要支持mb_substring

    如果没有这个函数,php可能会出现中文乱码,处理方法如下: # yum install php-mbstring   //安装 之后在/etc/php.ini中添加extension=mbstring ...

  9. BZOJ1563 NOI2009 诗人小G【决策单调性优化DP】

    LINK 因为是图片题就懒得挂了 简要题意:有n个串,拼接两个串需要加一个空格,给你l和p,问你拼接后每个串的总长减l的绝对值的p次方的最小值 首先打表发现一下这题是决策单调的对于所有数据都成立就当他 ...

  10. 使用poi进行excel导入并解析插入数据库

    前言 最近还得写excel的导入导出,结果还是得百度,虽然都能看懂,但是还是想记录下来这些东西 正文 1. 导入jar包 <dependency> <groupId>org.a ...