ALSA声卡08_从零编写之框架_学习笔记

发布者:诗意世界最新更新时间:2024-07-16 来源: elecfans关键字:框架  s3c2440 手机看文章 扫描二维码
随时随地手机看文章

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编写

/* 参考soundsocsamsungs3c24xx_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函数)


两个核心结构体


/* 参考 soundsoccodecsuda134x.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)


/* 参考soundsocsamsungs3c24xx-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)


/* 参考 soundsocsamsungdma.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、总结


关键字:框架  s3c2440 引用地址:ALSA声卡08_从零编写之框架_学习笔记

上一篇:mini2440内核大于2M烧写方法
下一篇:ALSA声卡09_从零编写之参数设置_学习笔记

推荐阅读最新更新时间:2026-03-13 08:26

ALSA声卡笔记2---ASoC驱动框架
1、简单了解一下ASOC 在嵌入式系统里面的声卡驱动为ASOC(ALSA System on Chip) ,它是在ALSA 驱动程序上封装的一层 分为3大部分,Machine,Platform和Codec ,三部分的关系如下图所示:其中Machine是指我们的开发板,Platform是指Soc,而Codec是指编解码器(如uda1341) (1)machine:单板相关内容,开发板所用的主芯片(Platform是指Soc)、编解码芯片(codec)是哪一个。主芯片里的IIS接口(DAI(全称Digital Audio Interface)接口)接到哪里去.CPU DAI是哪一个,codec DAI是哪一个,DMA是哪个
[单片机]
<font color='red'>ALSA</font><font color='red'>声卡</font>笔记2---ASoC驱动<font color='red'>框架</font>
迅为恩智浦IMX6Q开发板Buildroot 文件系统 alsa 声卡工具测试
耳机设置常用命令如下: 设置音量(最大为 127):amixer sset Headphone 101,101 左声道开启设置:amixer sset 'Left Output Mixer PCM' on 右声道开启设置:amixer sset 'Right Output Mixer PCM' on 使用命令“aplay -l”查看当前查看播放音频设备: 如下图所示,使用命令 amixer sset Headphone 101,101 设置音量大小。 如下图所示,使用命令 amixer sset 'Left Output Mixer PCM' on 开启左声道。 如下图所示,使
[单片机]
迅为恩智浦IMX6Q开发板Buildroot 文件系统 <font color='red'>alsa</font> <font color='red'>声卡</font>工具测试
ALSA声卡12_从零编写之添加音量控制_学习笔记
1、设置音量时应用程序的调用过程 (1)strace分析: amixer cset numid=1 30 (设置音量) /dev/snd/controlC0 open SNDRV_CTL_IOCTL_CARD_INFO SNDRV_CTL_IOCTL_PVERSION SNDRV_CTL_IOCTL_ELEM_INFO SNDRV_CTL_IOCTL_ELEM_READ SNDRV_CTL_IOCTL_ELEM_WRITE : snd_ctl_elem_write_user (2)应用程序调用SNDRV_CTL_IOCTL_ELEM_WRITE时,驱动程序调用snd_ctl_elem_write_user函数,这个函数从用户空间把
[单片机]
<font color='red'>ALSA</font><font color='red'>声卡</font>12_从零编写之添加音量控制_学习笔记
S3C2440 块设备驱动之框架详细分析(二十)
本节目的: 通过分析2.6内核下的块设备驱动框架,知道如何来写驱动 1、之前我们学的都是字符设备驱动,先来回忆一下 字符设备驱动: 当我们的应用层读写(read()/write())字符设备驱动时,是按字节/字符来读写数据的,期间没有任何缓存区,因为数据量小,不能随机读取数据,例如:按键、LED、鼠标、键盘等。 2、接下来本届开始学习块设备驱动 块设备: 块设备是i/o设备中的一类,当我们的应用层对该设备读写时,是按扇区大小来读写数据,若读写的数据小于扇区的大小,就会需要缓存区,可以随机读写设备的任意位置处的数据,例如 普通文件(*txt,*.c等),硬盘,U盘,SD卡 3、块设备结构: 段(
[单片机]
PSA 认证开启安全框架新纪元,GlobalPlatform将接管
摘编自Arm官方博客 从边缘人工智能到城市、工厂与家庭的关键基础设施,塑造未来的数字系统都依赖一个安全起点 —— 信任根(Root of Trust, RoT)。正因如此,2019 年 Arm 联合六家顶尖安全评估实验室发起 PSA 认证(PSA Certified),这个全球安全框架旨在帮助生态系统构建并验证可信互联产品。 如今,PSA 认证在新的管理架构下迈入发展新阶段:全球公认的开放安全标准机构 GlobalPlatform 将接管其治理权,确保该框架持续成功、保持中立,并与不断演变的全球法规保持一致。这不仅是一个里程碑,更标志着Arm构想的生态系统已扎根落地,准备进一步规模化扩展。 基于信任的基石:PSA 认证
[物联网]
一个使用传统DAS和深度强化学习融合的自动驾驶框架
增强学习是最近几年中机器学习领域的最新进展。增强学习依靠与环境交互学习,在相应的观测中采取最优行为。行为的好坏可以通过环境给予的奖励来确定。不同的环境有不同的观测和奖励。例如,驾驶中环境观测是摄像头和激光雷达采集到的周围环境的图像和点云,以及其他的传感器的输出,例如行驶速度、GPS定位、行驶方向。驾驶中的环境的奖励根据任务的不同,可以通过到达终点的速度、舒适度和安全性等指标确定。增强学习和传统机器学习的最大区别是增强学习是一个闭环学习的系统,增强学习算法选取的行为会直接影响到环境,进而影响到该算法之后从环境中得到的观测。 增强学习在无人驾驶中的应用 关于安全自主驾驶的研究可以分为两种方法:一是传统的感知,规划和控制框架,另一种
[嵌入式]
一个使用传统DAS和深度强化学习融合的自动驾驶<font color='red'>框架</font>
无人驾驶的基本框架你了解吗
将无人车理解为机器人并且使用机器人开发的思维处理无人车系统是目前工业界的共识,但也不乏一些单纯使用人工智能或者是智能体来完成无人驾驶的案例。其中基于深度学习的端到端无人驾驶和基于强化学习的驾驶智能体是目前的研究热点。 无人驾驶系统的核心可以概述为三个部分:感知(Perception),规划(Planning)和控制(Control),这些部分的交互以及其与车辆硬件、其他车辆的交互可以用下图表示: 感知是指无人驾驶系统从环境中收集信息并从中提取相关知识的能力。其中,环境感知(Environmental Perception)特指对于环境的场景理解能力,例如障碍物的位置,道路标志/标记的检测,行人车辆的检测等数据的语义分类。一
[嵌入式]
无人驾驶的基本<font color='red'>框架</font>你了解吗
利用验证框架 JAIST揭示开源自动驾驶系统的安全漏洞
据外媒报道,日本先进科学技术研究所(JAIST)研究人员利用新开发的验证框架,揭示了开源自动驾驶系统在高速行驶和突然切入车辆时的安全限制,这引发了人们对其实际部署的担忧。 图片来源: JAIST 在这项研究中,JAIST的研究助理教授Duong Dinh Tran及其团队(包括JAIST的Takashi Tomita副教授和Toshiaki Aoki教授)决定对开源自动驾驶系统Autoware进行严格的验证框架测试,以揭示其在关键交通情况下的潜在安全限制。 为了彻底检验Autoware的安全性,研究人员构建了一个特殊的虚拟测试系统。该系统相关论文发表在期刊《IEEE Transactions on Reliabili
[汽车电子]
利用验证<font color='red'>框架</font> JAIST揭示开源自动驾驶系统的安全漏洞
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved