2019/8/31LinuxALSA声卡驱动原理分析-设备打开过程和数据流程2019/8/31目录一、导读二、ALSA架构简介三、准备工作四、设备打开过程和数据流程i.整体分析ii.设备驱动程序insmod流程图iii.应用程序主流程图iv.声卡打开流程图v.数据写入流程图五、ALSA其它形式的数据写入方法流程图2019/8/31目录一、导读二、ALSA架构简介三、准备工作四、设备打开过程和数据流程i.整体分析ii.设备驱动程序insmod流程图iii.应用程序主流程图iv.声卡打开流程图v.数据写入流程图五、ALSA其它形式的数据写入方法流程图2019/8/31一、导读本文主要针对ALSA声卡硬件驱动,从应用程序的角度展示了从用户层到内核层再到硬件驱动程序控制声卡硬件的过程。主要包括insmod、声卡打开、数据写入三个流程。rmmod和声卡关闭的流程与insmod、声卡打开类似,本文没有描述。ALSA的其他部分如控制、录音等,不在本文叙述范围内。其中的insmod是系统初始化时或手动加载,不需要具体的应用程序参与。具体到硬件,使用的是ENS1371芯片,关于最小化的ENS1371芯片驱动程序,可以参考《LinuxALSA声卡驱动开发最佳实践.pptx》。2019/8/31目录一、导读二、ALSA架构简介三、准备工作四、设备打开过程和数据流程i.整体分析ii.设备驱动程序insmod流程图iii.应用程序主流程图iv.声卡打开流程图v.数据写入流程图五、ALSA其它形式的数据写入方法流程图2019/8/31二、ALSA架构简介1.ALSA是AdvancedLinuxSoundArchitecture,高级Linux声音架构的简称,它在Linux操作系统上提供了音频和MIDI(MusicalInstrumentDigitalInterface,音乐设备数字化接口)的支持。它包含API库和工具、内核驱动集合,对Linux声音进行支持。ALSA包含一系列内核驱动对不同的声卡进行支持,还提供了libasound的API库。用这些进行写程序不需要打开设备等操作,所以编程人员在写程序的时候不会被底层的东西困扰。2.ALSA自带的应用程序是alsa-utils工具包,包括aplay、alsamixer等。aplay用于在ASLA上播放音频。alsamixer用于改变音频信号的音量。3.alsa-lib是用户空间的函数库,提供了libasound.so给应用程序使用,应用程序应包含头文件asoundlib.h。这个库通过提供封装函数(ALSA-API),使ALSA应用程序不需要涉及具体硬件,编写起来更容易。alsa-lib中有control,timer,dmix,pcm等,都是以插件(plugin)的形式存在的。alsa-lib通过硬件访问层的系统调用与内核层进行交互。4.alsa-driver是音频设备的alsa内核部分的驱动。集成在内核里面,大多是以模块的方式存在。可分为三层。(1)最底层是硬件操控层,负责实现硬件操纵访问的功能,这也是声卡驱动程序中用户需实现的主要部分;(2)中间层是ASLA驱动的核心部分,它由各种功能的音频设备组件构成,为用户提供了一些预定义组件(如PCM、AC97、音序器和控制器等),另外用户也可以自行定义设备组件;(3)驱动的最上层是声卡对象描述层,它是声卡硬件的抽象描述,内核通过这些描述可以得知该声卡硬件的功能、设备组件和操作方法等。2019/8/31二、ALSA架构简介左图是从代码的角度体现了alsa-lib和alsa-driver及hardware的交互关系。用户层的alsa-lib通过操作alsa-driver创建的设备文件/dev/snd/pcmC0D0p等对内核层进行访问。内核层的alsa-drivier驱动再经由soundcore对硬件声卡芯片进行访问。从而实现了appalsa-libalsa-driverhardware的操作。图中右上角OSS相关部分是为了兼容OSS驱动模型而存在的。不是本实践的相关部分。2019/8/31目录一、导读二、ALSA架构简介三、准备工作四、设备打开过程和数据流程i.整体分析ii.设备驱动程序insmod流程图iii.应用程序主流程图iv.声卡打开流程图v.数据写入流程图五、ALSA其它形式的数据写入方法流程图2019/8/31三、准备工作为了更有效的跟踪ALSA的流程,需要在开始前进行一些准备工作,这包括用户层ALSA-lib库的调试方法和文档生成。alsa-driver的调试方法参见《Linux基础培训(2)-驱动开发最佳实践-1.pptx》。对调用流程和数据流程进行分析时,这部分内容起到辅助作用。1.ALSA-lib调试方法alsa-utils中的aplay程序可以进行应用程序和lib库的调试。操作如下:(1)复制alsa-utils和alsa-lib到linux文件系统下,如:#cp-rfalsa-utils-1.0.16/opt/#cp-rfalsa-lib-1.0.16/opt/※红色文字表示shell中输入的命令,具体命令要根据具体环境自己修改。alsa-utils-1.0.16和alsa-lib-1.0.16从网上下,也可以在光盘debian-506-source-DVD-1.iso中的pool/main/a/文件夹下找到。(2).复制音频文件,如复制test_files文件夹到/opt下,#cp-rftest_files/opt/(3).在alsa-lib-1.0.16中依次执行如下:#cd/opt/alsa-lib-1.0.16#./configure#make#makeinstall※系统需要安装gcc等工具。(4).在alsa-utils-1.0.16中中依次执行如下:#cd/opt/alsa-utils-1.0.16#./configure#cdaplay#make就会生成执行文件aplay。(5).执行aplay文件播放.wav声音文件。如:#./aplay/opt/test_files/pcm.wav注意命令前面的”./”如果不加,而系统中又安装了alsa-utils工具,就会执行/usr/bin/aplay,注意不要混了。(6).通过gdb可以对alsa-utils的aplay和alsa-lib的libsound.so进行本地调试。#gdbaplay(gdb)setargs/opt/test_files/pcm.wav(gdb)bmain(gdb)r……...…2019/8/31三、准备工作2.ALSA-lib调试方法示例。图中红色表示为在shell中输入的命令,具体命令要根据具体环境自己修改。跟踪代码时可以在gdb中使用bt(backtrace)指令跟踪调用栈查看函数调用关系。2019/8/31三、准备工作3.生成alsa-lib文档alsa-lib中可以用文档生成工具doxygen生成API及相关说明文档。在alsa-lib-1.0.16中依次执行如下:#cd/opt/alsa-lib-1.0.16#cddoc#doxygendoxygen.cfg在新生成的文件夹doxygen/html中就会有网页形式的文档,首页为index.html2019/8/31三、准备工作4.流程图结构说明(1)图示为函数的调用关系,向下为同一级调用,向右为函数内部的子函数调用。(2)绿色文字函数名(如function2)表示该函数是调用流程中比较关键的点。(3)红底白字的函数名(如function…)表示和其它层(如app和lib、lib和driver、alsa-driver和device-driver)的接口函数或kernel的回调函数。(4)蓝色双虚线为函数实参等形式的输出值或函数返回值(如sun_function…有输出值到function1)。注释主函数()function1()function2()sub_function1()......()sun_function...()function...()…………()function...()2019/8/31目录一、导读二、ALSA架构简介三、准备工作四、设备打开过程和数据流程i.整体分析ii.设备驱动程序insmod流程图iii.应用程序主流程图iv.声卡打开流程图v.数据写入流程图五、ALSA其它形式的数据写入方法流程图2019/8/31四、设备打开过程和数据流程i.整体分析userspacekernelspace……app1appnALSA应用程序ALSA-libpcmdmixcontroltimer…ALSA-driver内核API设备驱动hardwareens13711.声卡芯片的硬件驱动程序实际上是alsa-driver的一部分,但是在本文档中,为了明示层次关系,将这两个分开对待。将硬件驱动程序叫做device-driver(设备驱动),alsa-driver的其它部分叫做alsa-driver(alsa驱动)。2.硬件驱动被insmod后,应用程序就可以调用ALSA-lib的API函数播放声音。左图是从应用程序开始,到我们的编写设备驱动程序的调用过程。从应用程序角度看,ASLA的操作分为两部分,打开及关闭是一部分,写入数据是另一部分。3.当声卡name使用”default”时,pcm作为dmix的从设备存在,应用程序直接和dmix的相关函数打交道。dmix混合数据后,直接写到mmap映射的地址中。4.关于1371的驱动ens1371-playback.ko,参见《LinuxALSA声卡驱动开发最佳实践.pptx》。从设备驱动程序角度看,声卡核心驱动可以分为三个主要部分:(1)模块初始化和退出部分。(2)播放以及停止部分。(3)中断处理部分。而从应用程序的角度向下看,这三部分分别在insmod、打开声卡和写入数据时被关联。2019/8/31目录一、导读二、ALSA架构简介三、准备工作四、设备打开过程和数据流程i.整体分析ii.设备驱动程序insmod流程图iii.应用程序主流程图iv.声卡打开流程图v.数据写入流程图五、ALSA其它形式的数据写入方法流程图2019/8/31ii.设备驱动程序insmod流程图insmodens1371-playback时,除了snd_ensoniq_chip_init()设置了硬件寄存器使硬件初始化外,其他的都是为了alsa-driver的架构而进行的工作,因为pci总线是层次式结构的,所以insmod设备是pcicarddevicepcm(substream)一层层细化的,使用inl()/outl()函数读/写内存映射方式的32位寄存器。关于snd_ensoniq_chip_init()时的硬件寄存器配置,参见《ES1371datasheet.pdf》。例如要使能dac1,根据手册第16页内容,就知道应该设置Interrupt/ChipSelectControlRegister第6位(从0位开始),该寄存器的偏移量为0,假设原寄存器内容为ctrl,pci映射的端口为port,则可以用如下的代码实现:ctrl|=(16);outl(ctrl,port+0x00);1.pci_register_driver():注册一个pci设备。linux-source-2.6.26/include/linux/pci.h:6562.snd_card_new():createandinitializeasoundcardstructure.linux-source-2.6.26/sound/core/init.c:1283.对pci设备进行设置,这些函数分别是:pci_enable_device():Initializedevicebeforeit'susedbyadriver.linux-source-2.6.26/drivers/pci/pci.c:787pci_request_regions():ReservedPCII/Oandmemor