ALSA 驱动抽象:ASoc 理解与分析

简介: 最近一直在研究 ALSA 驱动,停了一段时间,突然发现Asla 驱动不是一天两天能讲清楚的。

1. ASoC 概述


ASoC (ALSA System on Chip) ,是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。在ASoc出现之前,内核对于SoC中的音频已经有部分的支持,不过会有一些局限性:


  • Codec驱动与SoC CPU的底层耦合过于紧密,这种不理想会导致代码的重复。
  • 音频事件没有标准的方法来通知用户,例如耳机、麦克风的插拔和检测,这些事件在移动设备中是非常普通的,而且通常都需要特定于机器的代码重新对音频路劲进行配置。


  • 当进行播放或录音时,驱动会让整个codec处于上电状态,这对于PC没问题,但对于移动设备来说,这意味着浪费大量的电量。同时也不支持通过改变过取样频率和偏置电流来达到省电的目的。


ASoC正是为了解决上述种种问题而提出的,目前已经被整合至内核的代码树中:sound/soc。ASoC不能单独存在,他只是建立在标准ALSA驱动上的一个它必须和标准的ALSA驱动框架相结合才能工作。


2. 硬件架构


嵌入式设备的音频系统可以被划分为板载硬件(Machine)、Soc(Platform)、Codec三大部分,如下图所示:


image.png


  • Machine :是指某一款机器,可以是某款设备,某款开发板,由此可以看出Machine几乎是不可重用的,每个Machine上的硬件实现可能都不一样,CPU不一样,Codec不一样,音频的输入、输出设备也不一样,Machine为CPU、Codec、输入输出设备提供了一个载体。


  • Platform:一般是指某一个SoC平台,比如s3cxxxx,与音频相关的通常包含该SoC中的时钟、DMA、I2S、PCM等等,只要指定了SoC,那么我们可以认为它会有一个对应的Platform,它只与SoC相关,与Machine无关,这样我们就可以把Platform抽象出来,使得同一款SoC不用做任何的改动,就可以用在不同的Machine中。实际上,把Platform认为是某个SoC更好理解。


  • Codec:字面上的意思就是编解码器,Codec里面包含了I2S接口、D/A、A/D、Mixer、PA(功放),通常包含多种输入(Mic、Line-in、I2S、PCM)和多个输出(耳机、喇叭、听筒,Line-out),Codec和Platform一样,是可重用的部件,同一个Codec可以被不同的Machine使用。嵌入式Codec通常通过I2C对内部的寄存器进行控制。


注释:对于现在的很多嵌入式平台,内部集成了codec,我们在分析时也可以将其划分到codec 上,不同的Soc 内部Codec 有所不同,同时亦可兼容内部codec 和 外部Codec。


3. 软件架构


在软件层面,ASoC也把嵌入式设备的音频系统同样分为3大部分,Machine,Platform和Codec。


  • Machine: Machine 驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个放大器);单独的Platform 和 Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。


  • Platform:它包含了该SoC平台的音频 DMA 和音频接口的配置和控制(I2S,PCM,AC97等等);它也不能包含任何与板子或机器相关的代码。


  • Codec : ASoC 中的一个重要设计原则就是要求Codec驱动是平台无关的,它包含了一些音频的控件(Controls),音频接口,DAMP(动态音频电源管理)的定义和某些Codec IO功能。为了保证硬件无关性,任何特定于平台和机器的代码都要移到 Platform 和Machine驱动中。所有的Codec驱动都要提供以下特性:


Codec DAI 和 PCM的配置信息;Codec的IO控制方式(I2C,SPI等);Mixer和其他的音频控件;Codec的ALSA音频操作接口;


必要时,也可以提供以下功能:


  • DAPM描述信息;


  • DAPM事件处理程序;


  • DAC数字静音控制


4. ASOC 分析


4.1 硬件抽象


通常一个声卡设备,大概包含以下几个物理设备或者外设:


  • Codec:音频编解码控制器,可以是内部Codec(soc 集成),也可以是外部Codec. Codec 通过支持音频编解码,包括模拟麦或者spk, 有的甚至支持数字麦。


  • AMIC/SPK/DMIC:纯硬件电路。麦克风或者spk,软件无需干预。


  • DMA:对于硬件设备的数据量,大多数情况都是通过dma 搬运来提高效率。


  • cpu:整个soc 平台,主要提供音频通信接口来实现和codec 传输。比如(I2S/PDM等)


  • DAI:音频接口,抽象概念,比如I2S等。


  • Card:抽象概念,声卡。


  • Capture:抽象概念,表示录音设备


  • Playback:抽象概念,表示软件设备


对于大多数平台,dma 和 i2s/pdm 等集成在一个soc 上,有些甚至集成了Codec。


image.png


4.2 音频数据流


音频数据的数据流,大致如下。我们可以看到,不同的硬件平台,其声卡设备的硬件逻辑和数据流大致一致,故抽象ASoc 很有必要。


image.png


4.3 ASoc 软件抽象


如下是笔者根据自己理解划分 Alsa 声卡驱动各个部分:


  • Machine:驱动顶层和入口,处理声卡操作。包括声卡创建,音频流的传输与控制。


  • platform:主要负责Soc 平台的DMA 和 CPU_DAI 操作。


  • Codec:主要负责Codec driver 和 Codec_dai 操作。


可以看到一个ALSA 声卡驱动是十分复杂的,包含了各种复杂驱动。


  • codec driver:音频配置和传输


  • dma:dma 处理


  • dai:i2s等接口配置


  • pcm:和上层应用交互的中间层


  • control:和上层应用交互的中间层


  • 其他:比如i2c/spi ,codec 控制操作。


image.png


4.4 ASoc 驱动分析


我们以 linux-kernel-4.4.94 为例子来分析 ASoc 驱动。限于篇幅,我们只分析 Machine 驱动框架,对于Codec 驱动和其他设备驱动,有时间再分析。


ASoc Machine 驱动调用如下:


image.png


/* ASoC platform driver */
static struct platform_driver soc_driver = {
        .driver         = {  
                .name           = "soc-audio",
                .pm             = &snd_soc_pm_ops,
        },
        .probe          = soc_probe,        .remove         = soc_remove,
};


最顶层入口是soc_probe,位于 sound/soc/soc-core.c,不同的Machine 位置可能不同。大部分在soc/xxx/下。


/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
        struct snd_soc_card *card = platform_get_drvdata(pdev);
        /*
        ¦* no card, so machine driver should be registering card
        ¦* we should not be here in that case so ret error
        ¦*/
        if (!card)
                return -EINVAL;
        dev_warn(&pdev->dev,
                ¦"ASoC: machine %s should use snd_soc_register_card()\n",
                ¦card->name);
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
        return snd_soc_register_card(card);
}


最关键的就是 snd_soc_register_card 这个函数了。详细分析看上图uml 时许图。


4.5 ASoc 数据结构


image.png


  • ASoc 数据结构如上图。最顶层我们构建了snd_soc_card。贯穿整个驱动生命周期中,snd_soc_pcm_runtime,至关重要。


  • dai_link 关联着dai_driver 和 compoent_driver


  • snd_soc_codec:codec 相关


  • snd_soc_paltform:platform 相关


  • snd_soc_dai:cpu_dai 和 codec_dai 相关操作


  • snd_soc_component:关联dai_driver 和 component_driver。关联platform_driver 和 component_driver


  • snd_soc_ops/snd_soc_dai_ops/snd_pcm_ops:比较关键的几个ops


对于刚开始学习ASLA 驱动时,我们先关注这几个结构体就行。后续将从音频流和控制两大块,详细分析整个数据流和控制的调用过程。


5. 总结


本文详细的介绍了ALSA 驱动最关键的一环ASoC ,理解了ASoc 顶层设计框架对于我们后续深入学习ASLA 驱动至关重要。


当我们熟悉了一个平台的驱动框架后,再去看另外一个平台就知道哪些是我们需要关注的,哪些是linux 内核已经实现的,从而达到事半功倍的作用

希望本文,对读者朋友学习理解Alsa 驱动有所帮助!

相关文章
|
4月前
|
存储 传感器 编解码
【Camera基础(二)】摄像头驱动原理和开发&&V4L2子系统驱动架构
【Camera基础(二)】摄像头驱动原理和开发&&V4L2子系统驱动架构
|
5月前
|
Unix Linux 编译器
Linux驱动设计(一):驱动是什么?
Linux驱动设计(一):驱动是什么?
51 0
|
Linux Android开发
Linux misc子系统框架驱动4412蜂鸣器
Linux misc子系统框架驱动4412蜂鸣器
89 0
Linux misc子系统框架驱动4412蜂鸣器
|
Linux
Linux驱动入门(5)LED驱动---驱动分层和分离,平台总线模型
Linux驱动入门(5)LED驱动---驱动分层和分离,平台总线模型
108 0
|
缓存 Linux API
Linux驱动分析之Uart驱动架构
UART设备驱动可以使用tty驱动的框架来实现,但是因为串口之间有共性,所以Linux在tty接口上封装了一层(serial core)。后面我们再拿一篇文章来解释tty驱动,tty其实就是各种终端设备,串口其实也是终端设备。
Linux驱动分析之Uart驱动架构
|
Ubuntu Linux 开发者
韦东山Linux驱动入门实验班(2)hello驱动---驱动层与应用层通讯,以及自动产生设备节点
韦东山Linux驱动入门实验班(2)hello驱动---驱动层与应用层通讯,以及自动产生设备节点
158 0
|
Linux API
Linux驱动分析之SPI驱动架构
Linux驱动分析之SPI驱动架构
|
Linux API
Linux驱动之I2C驱动架构
Linux驱动之I2C驱动架构
|
Linux API
Linux驱动分析之MMC子系统框架
Linux内核中,MMC不仅是一个驱动,而是一个子系统。内核把mmc, sd以及sdio三者的驱动代码整合在一起,俗称MMC子系统。源码位于drivers/mmc下。mmc目录下有core和host两个文件夹(以前的版本可能还有card目录,现在已经和core目录合并了)。
|
IDE 前端开发 数据可视化
ZenUML与服务驱动设计
ZenUML与服务驱动设计
ZenUML与服务驱动设计