alsa 驱动介绍及user层到hw层文件ioctl操作流程分析

 

 

Machine


以装配有CS4270的1款android 智能电视为例


/sound/soc/samsung/exynos.c




Platform


以Samsung cpu exynos4412为例


/sound/soc/samsung/




Codec


以wolfson的Codec芯片cs4270为例


/sound/soc/codecs/cs4270.c




ALSA 框架介绍



Alsa 太多太杂,很难整理的规整,只能看到哪里写到哪里


 

ASoC被分为Machine,Platform和Codec3大部件,Platform驱动的主要作用是完成音频数据的管理,终究通过CPU的数字音频接口(DAI)把音频数据传送

给Codec进行处理,终究由Codec输出驱动耳机或是喇叭的音信信号。在具体实现上,ASoC有把Platform驱动分为两个部份:snd_soc_platform_driver

和snd_soc_dai_driver。其中,platform_driver负责管理音频数据,把音频数据通过dma或其他操作传送至cpu dai中,dai_driver则主要完成cpu 1侧的

dai的参数配置,同时也会通过1定的途径把必要的dma等参数与snd_soc_platform_driver进行交互。

Machine  是指某1款机器,可以是某款装备,某款开发板,又或是某款智能手机,由此可以看出Machine几近是不可重用的,每一个Machine上的硬件实

现可能都不1样,CPU不1样,Codec不1样,音频的输入、输出装备也不1样,Machine为CPU、Codec、输入输出装备提供了1个载体。

Platform  1般是指某1个SoC平台,比如pxaxxx,s3cxxxx,omapxxx等等,与音频相干的通常包括该SoC中的时钟、DMA、I2S、PCM等等,只要指定了SoC,那么我们可以认为它会有1个对应的Platform,它只与SoC相干,与

Machine无关,这样我们就能够把Platform抽象出来,使得同1款SoC不用做任何的改动,就能够用在不同的Machine中。实际上,把Platform认为是某个SoC更好理解。

Codec  字面上的意思就是编解码器,Codec里面包括了I2S接口、D/A、A/D、Mixer、PA(功放),通常包括多种输入(Mic、Line-in、I2S、PCM)和多个

输出(耳机、喇叭、听筒,Line-out),Codec和Platform 1样,是可重用的部件,同1个Codec可以被不同的Machine使用。嵌入式Codec通常通过I2C对
内部的寄存器进行控制。

 

Machine驱动的初始化,codec和dai的注册,都会调用snd_soc_instantiate_cards()进行1次声卡和codec,dai,platform的匹配绑定进程,这里所说的
绑定,正如Machine驱动1文中所描写,就是通过3个全局链表,按名字进行匹配,把匹配的codec,dai和platform实例赋值给声卡每对dai的snd_soc_pcm_runtime变量中。1旦绑定成功,将会使得codec和dai驱动的probe回调被调用。alsa架构的数据交互,是通过对PCM装备的操作来完成的, PCM装备分成playback和capture两个stream, 每一个stream底下有N个substream
alsa驱动最底层需要调试的有3块: DMA部份,IIS驱动部份,codec部份

 

 

 

 

IIS介绍



A)I2S有4根线,


1.串行时钟SCLK,也叫位时钟(BCLK),即对应数字音频的每位数据,SCLK都有1个脉冲。SCLK的频率=2×采样频率×采样位数。


2. 帧时钟LRCK,(也称WS),用于切换左右声道的数据。LRCK为“1”表示正在传输的是右声道的数据,为“0”则表示正在传输的是左声道的数据。LRCK


的频率等于采样频率。


3.串行数据SDATA,就是用2进制补码表示的音频数据。


4.有时为了使系统间能够更好地同步,还需要另外传输1个信号MCLK,称为主时钟,也叫系统时钟(Sys Clock),是采样频率的256倍或384倍。

 

B)声音数据DAT 1般在CLK的上升沿进行采样,有些DAC也是可以调的。每一个声道里面可以容纳的CLK数必须多于数据的位数,多出来的时钟和数据DAC会丢弃不用,比如16bit采样的声音数据当1个声道是32个CLK且left-justify的时候,后面106个时钟的数据会被DAC丢掉,不影响的。



C)I2S数据的格式分I2S, Left-justify, Right-justify。3种格式的区分在于声音数据与WS的对应关系:


1 .  I2S模式DAT的MSB在WS变化后的第2个上升沿开始传输


2.  Left-justify模式DAT的MSB在WS变化后的第1个上升沿开始传输


3.   Right-justify模式DAT的LSB在WS行将变换到下1声道前的最后1个时钟传输




I2S部份触及的几个频率:


  * 输出采样频率 fs = 44.1KHz.  (也有其它fs的音源, 但加了resampler后, 都变成44.1KHz输出了). 这是个关键频率.


  * LRCLK, 就等于fs. (L/R声道信号)


  * BCLK = 32倍fs = 1411.2KHz = 1.4112MHz. (bit clock). 2声道16bit, 故32倍fs. 若2声道24bit, 则48倍fs.


  * MCLK是全部audio模块的工作频率, 通常选fs的256, 384, 512倍. 比如: 256倍fs = 11289.6KHz = 11.2896MHz.



从频率设置来讲, MCLK是个主要频率, 它是全部audio模块的工作频率.



那末, 从软件来讲要设置两个方面的寄存器: 1是该PLL从晶振频率如何得到PLLout频率(比如P/M/S/k). 2是PLLout如何分频得到audio部份的MCLK.




IIS驱动部份最重要的就是注册以下钩子函数,挂到了alsa驱动上

static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {

.trigger = i2s_trigger,

.hw_params = i2s_hw_params,

.set_fmt = i2s_set_fmt,

.set_clkdiv = i2s_set_clkdiv,

.set_sysclk = i2s_set_sysclk,

.startup = i2s_startup,

.shutdown = i2s_shutdown,

.delay = i2s_delay,

};




codec芯片介绍


cs4270的驱动要设置的参数有:
静音,传输模式,比特位长度,时钟主从模式,音量大小
cs4270驱动里面定义了snd_soc_dai_driver结构成员,里面定义了playback和capture两个substream,同时也挂了1个snd_soc_dai_ops结构体,里面全是操作函数指针。
alsa上面1层层的终究会调用到这些指针

static const struct snd_soc_dai_ops cs4270_dai_ops = {

.hw_params = cs4270_hw_params,

.set_sysclk = cs4270_set_dai_sysclk,

.set_fmt = cs4270_set_dai_fmt,

.digital_mute = cs4270_dai_mute,

};

static struct snd_soc_dai_driver cs4270_dai = {

.name = "cs4270-hifi",

.playback = {

.stream_name = "Playback",

.channels_min = 1,

.channels_max = 2,

.rates = SNDRV_PCM_RATE_CONTINUOUS,

.rate_min = 4000,

.rate_max = 216000,

.formats = CS4270_FORMATS,

},

.capture = {

.stream_name = "Capture",

.channels_min = 1,

.channels_max = 2,

.rates = SNDRV_PCM_RATE_CONTINUOUS,

.rate_min = 4000,

.rate_max = 216000, .

formats = CS4270_FORMATS,

},

.ops = &cs4270_dai_ops,

};





DMA介绍



IIS总线是慢速总线,相对CPU来讲,太慢。所以采取DMA的方式最能节省CPU性能。


PCM playback的时候,DMA目的地址是IIS FIFO寄存器。源地址是寄存PCM数据的内存。


DMA的驱动采取了linux pl330的驱动架构,采取中断的方式来触发后续DMA。


IIS中通过DMA的方式写入FIFO寄存器,在DMA的驱动中挂接了1个回调函数audio_buffdone。DMA完成后,回函数调用,刷新alsa的环,便于下1次DMA


DMA的目的地址,就是IIS发送寄存器的地址。源地址,就是申请的DMA buffer,只不过DMAbuffer被映照成了1个环


 

static void dma_enqueue(struct snd_pcm_substream *substream)

{

      struct runtime_data *prtd = substream->runtime->private_data;

     dma_addr_t pos = prtd->dma_pos;

     unsigned int limit;

     struct samsung_dma_prep dma_info;

     pr_debug("Entered %s\n", __func__);

     limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;

     pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit);

     dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);

     dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);

    dma_info.fp = audio_buffdone; //回调函数

    dma_info.fp_param = substream;

    dma_info.period = prtd->dma_period;

    dma_info.len = prtd->dma_period*limit;

     while (prtd->dma_loaded < limit) {

                 pr_debug("dma_loaded: %d\n", prtd->dma_loaded);

                 if ((pos + dma_info.period) > prtd->dma_end) {

                                             dma_info.period = prtd->dma_end - pos;

                                             pr_debug("%s: corrected dma len %ld\n", __func__, dma_info.period);

                   }

                                                           dma_info.buf = pos;

                                                           prtd->params->ops->prepare(prtd->params->ch, &dma_info); //DMA注册

                                                          prtd->dma_loaded++;

                                                          pos += prtd->dma_period;

                                                          if (pos >= prtd->dma_end) pos = prtd->dma_start;

      }

                                           prtd->dma_pos = pos;

}

 

static void audio_buffdone(void *data)

{

      struct snd_pcm_substream *substream = data;

      struct runtime_data *prtd = substream->runtime->private_data;

      pr_debug("Entered %s\n", __func__);

      if (prtd->state & ST_RUNNING) {

           prtd->dma_pos += prtd->dma_period;

           if (prtd->dma_pos >= prtd->dma_end)

                    prtd->dma_pos = prtd->dma_start;

           if (substream)

                  snd_pcm_period_elapsed(substream);

          spin_lock(&prtd->lock);

          if (!samsung_dma_has_circular()) {

                  prtd->dma_loaded--;

                  dma_enqueue(substream);

            } spin_unlock(&prtd->lock);

      }

}


DMA部份主要通过注册以下钩子函数来挂到alsa驱动里面


 

static struct snd_pcm_ops dma_ops = {

 .open = dma_open,

 .close = dma_close,

 .ioctl = snd_pcm_lib_ioctl,

 .hw_params = dma_hw_params,

 .hw_free = dma_hw_free,

 .prepare = dma_prepare,

 .trigger = dma_trigger,

 .pointer = dma_pointer,

 .mmap = dma_mmap,

};


alsa数据读写简介

A/CC寄存haokan.nx4738.info/Article/1109-111100.HtmK/k++后续

A/CC寄存haokan.jn9013.info/Article/1109-111113.HtmK/k++后续

A/CC寄存haokan.kc2296.info/Article/1109-688886.HtmK/k++后续

A/CC寄存haokan.cd9296.info/Article/1109-555777.HtmK/k++后续

A/CC寄存haokan.ti9926.info/Article/1109-355355.HtmK/k++后续

A/CC寄存haokan.xh8190.info/Article/1109-900102.HtmK/k++后续

A/CC寄存haokan.ex2597.info/Article/1109-664655.HtmK/k++后续

A/CC寄存haokan.dk4007.info/Article/1109-088891.HtmK/k++后续

A/CC寄存haokan.ef3522.info/Article/1109-224644.HtmK/k++后续

A/CC寄存haokan.ef4462.info/Article/1109-788886.HtmK/k++后续

A/CC寄存haokan.it5387.info/Article/1109-333334.HtmK/k++后续

A/CC寄存haokan.fs7219.info/Article/1109-888799.HtmK/k++后续

A/CC寄存haokan.wt3667.info/Article/1109-111133.HtmK/k++后续

A/CC寄存haokan.yz8343.info/Article/1109-446665.HtmK/k++后续

A/CC寄存haokan.ew5883.info/Article/1109-113224.HtmK/k++后续

A/CC寄存haokan.tr7328.info/Article/1109-546666.HtmK/k++后续

A/CC寄存haokan.jk0241.info/Article/1109-866887.HtmK/k++后续

A/CC寄存haokan.wf9924.info/Article/1109-221153.HtmK/k++后续

A/CC寄存haokan.zr3966.info/Article/1109-468877.HtmK/k++后续

A/CC寄存haokan.xc3175.info/Article/1109-000200.HtmK/k++后续

A/CC寄存haokan.jm9292.info/Article/1109-335355.HtmK/k++后续

A/CC寄存haokan.fy1534.info/Article/1109-668878.HtmK/k++后续

A/CC寄存haokan.yc2123.info/Article/1109-991100.HtmK/k++后续

A/CC寄存haokan.fi3099.info/Article/1109-024223.HtmK/k++后续

A/CC寄存haokan.xh7514.info/Article/1109-002001.HtmK/k++后续

A/CC寄存haokan.tx7245.info/Article/1109-453355.HtmK/k++后续

A/CC寄存haokan.zk6504.info/Article/1109-776666.HtmK/k++后续

A/CC寄存haokan.jf9007.info/Article/1109-980008.HtmK/k++后续

A/CC寄存haokan.kb5162.info/Article/1109-880023.HtmK/k++后续

A/CC寄存haokan.wt6288.info/Article/1109-111133.HtmK/k++后续

A/CC寄存haokan.ch8617.info/Article/1109-553355.HtmK/k++后续

A/CC寄存haokan.nd4716.info/Article/1109-355557.HtmK/k++后续

A/CC寄存haokan.yj5978.info/Article/1109-757556.HtmK/k++后续

A/CC寄存haokan.fa9309.info/Article/1109-777999.HtmK/k++后续

A/CC寄存haokan.bf9343.info/Article/1109-999888.HtmK/k++后续

A/CC寄存haokan.ka8973.info/Article/1109-222111.HtmK/k++后续

A/CC寄存haokan.hc4097.info/Article/1109-042244.HtmK/k++后续

A/CC寄存haokan.ft3103.info/Article/1109-322242.HtmK/k++后续

A/CC寄存haokan.mz2762.info/Article/1109-113354.HtmK/k++后续

A/CC寄存haokan.ds6551.info/Article/1109-533545.HtmK/k++后续

A/CC寄存haokan.ea5660.info/Article/1109-999910.HtmK/k++后续

A/CC寄存haokan.wr6454.info/Article/1109-980088.HtmK/k++后续

A/CC寄存haokan.ws7888.info/Article/1109-889110.HtmK/k++后续

A/CC寄存haokan.mt4520.info/Article/1109-664669.HtmK/k++后续

A/CC寄存haokan.kk6938.info/Article/1109-787791.HtmK/k++后续

A/CC寄存haokan.hn0768.info/Article/1109-133244.HtmK/k++后续

A/CC寄存haokan.mp4043.info/Article/1109-991110.HtmK/k++后续

A/CC寄存haokan.nz8589.info/Article/1109-799088.HtmK/k++后续

A/CC寄存haokan.ed6309.info/Article/1109-646657.HtmK/k++后续

A/CC寄存haokan.bn9204.info/Article/1109-443553.HtmK/k++后续

A/CC寄存haokan.ce8184.info/Article/1109-324246.HtmK/k++后续

A/CC寄存haokan.xa6085.info/Article/1109-579900.HtmK/k++后续

A/CC寄存haokan.sd2713.info/Article/1109-787779.HtmK/k++后续

A/CC寄存haokan.dz8132.info/Article/1109-982022.HtmK/k++后续

A/CC寄存haokan.dr3184.info/Article/1109-221433.HtmK/k++后续

A/CC寄存haokan.sh0309.info/Article/1109-980081.HtmK/k++后续

A/CC寄存haokan.ys0851.info/Article/1109-655557.HtmK/k++后续

A/CC寄存haokan.hr3242.info/Article/1109-687778.HtmK/k++后续

A/CC寄存haokan.iy8268.info/Article/1109-656775.HtmK/k++后续

A/CC寄存haokan.if0303.info/Article/1109-544666.HtmK/k++后续

A/CC寄存haokan.ii3885.info/Article/1109-555345.HtmK/k++后续

A/CC寄存haokan.cm2967.info/Article/1109-442466.HtmK/k++后续

A/CC寄存haokan.ca2345.info/Article/1109-990344.HtmK/k++后续

A/CC寄存haokan.xi1167.info/Article/1109-666888.HtmK/k++后续

A/CC寄存haokan.wy7792.info/Article/1109-557755.HtmK/k++后续

A/CC寄存haokan.ah3774.info/Article/1109-534444.HtmK/k++后续

A/CC寄存haokan.hk3165.info/Article/1109-334242.HtmK/k++后续

A/CC寄存haokan.bs6582.info/Article/1109-344535.HtmK/k++后续

A/CC寄存haokan.wp8971.info/Article/1109-112324.HtmK/k++后续

A/CC寄存haokan.dp0923.info/Article/1109-111002.HtmK/k++后续

A/CC寄存haokan.wp2607.info/Article/1109-900800.HtmK/k++后续

A/CC寄存haokan.mw7921.info/Article/1109-887797.HtmK/k++后续

A/CC寄存haokan.pe7846.info/Article/1109-665777.HtmK/k++后续

A/CC寄存haokan.nr3477.info/Article/1109-443335.HtmK/k++后续

A/CC寄存haokan.ed8387.info/Article/1109-446575.HtmK/k++后续

A/CC寄存haokan.xe5002.info/Article/1109-555444.HtmK/k++后续

A/CC寄存haokan.iy2250.info/Article/1109-113123.HtmK/k++后续

A/CC寄存haokan.jc9250.info/Article/1109-911100.HtmK/k++后续

A/CC寄存haokan.ch3371.info/Article/1109-557779.HtmK/k++后续

A/CC寄存haokan.zz0340.info/Article/1109-345535.HtmK/k++后续

A/CC寄存haokan.fp5848.info/Article/1109-222133.HtmK/k++后续

A/CC寄存haokan.yn9497.info/Article/1109-678880.HtmK/k++后续

A/CC寄存haokan.cz2516.info/Article/1109-444664.HtmK/k++后续

A/CC寄存haokan.ds2632.info/Article/1109-333122.HtmK/k++后续

A/CC寄存haokan.zt3161.info/Article/1109-667991.HtmK/k++后续

A/CC寄存haokan.bd4666.info/Article/1109-224426.HtmK/k++后续

A/CC寄存haokan.ct1905.info/Article/1109-111000.HtmK/k++后续

A/CC寄存haokan.wh1847.info/Article/1109-777997.HtmK/k++后续

A/CC寄存haokan.bz3110.info/Article/1109-442344.HtmK/k++后续

A/CC寄存haokan.nx3556.info/Article/1109-991100.HtmK/k++后续

A/CC寄存haokan.hb2699.info/Article/1109-446656.HtmK/k++后续

A/CC寄存haokan.bx1978.info/Article/1109-911132.HtmK/k++后续

A/CC寄存haokan.cw4201.info/Article/1109-666686.HtmK/k++后续

A/CC寄存haokan.za6685.info/Article/1109-135335.HtmK/k++后续

A/CC寄存haokan.kx3116.info/Article/1109-999808.HtmK/k++后续

A/CC寄存haokan.kb1056.info/Article/1109-322243.HtmK/k++后续

A/CC寄存haokan.by9567.i

内容概要:本文围绕“基于纳什博弈的多微网主体电热双共享策略”展开研究,通过构建电热联合系统的双优化模型,结合纳什博弈理论实现多个微网主体间的能量共享与利益分配。上采用博弈论优化各微网的能源交互策略,下考虑电、热负荷的耦合关系与设备运行约束,实现系统整体经济性与能效的提升。研究通过Matlab代码实现仿真验证,复现SCI论文中的核心算法与建模思路,涵盖YALMIP工具包调用、优化模型搭建与求解流程,具有较强的可操作性与科研参考价值。; 适合人群:电力系统、能源互联网、微电网优化等领域的研究生、科研人【SCI复现】基于纳什博弈的多微网主体电热双共享策略研究(Matlab代码实现)员及具备一定Matlab编程基础的工程技术人员;熟悉优化建模与博弈论者更佳。; 使用场景及目标:①学习并复现SCI级多微网协同优化论文的核心方法;②掌握基于纳什博弈的双优化建模技巧;③深入理解电热综合能源系统的协同调度机制与数学建模过程;④借助提供的代码资源开展二次开发或对比实验。; 阅读建议:建议结合文档中提供的网盘资源(含YALMIP-develop.zip等工具包与完整代码)同步运行与调试,按照目录顺序逐步学习,重点关注模型构建逻辑与Matlab实现细节,同时可延伸至其他优化问题如储能配置、需求响应等方向的应用拓展。
在软件工程领域,自动化测试技术已成为保障产品稳定性的关键环节。面对日益提升的质量标准,各类自动化测试解决方案正被广泛部署于企业级开发流程中。针对Windows平台桌面软件的特殊性,我们构建了一套结合Python编程环境与Windows应用程序驱动技术的界面自动化测试体系。 该测试架构采用Python作为核心编程语言,其语法简洁性与模块化特性显著提升了测试代码的可维护性。配合微软研发的应用程序自动化驱动组件,该系统能够完整模拟用户对桌面程序的操作行为。值得注意的是,该驱动组件不仅兼容传统Win32应用程序,还全面支持通用Windows平台应用,并通过标准化通信协议与主流Web测试工具实现无缝对接。 测试体系的核心价值体现在三个维度:首先,通过预置的控件识别引擎,可精准定位按钮、输入框、导航菜单及数据列表等界面元素;其次,基于行为模拟库实现了完整的用户交互流程自动化;最后,模块化的测试用例管理机制支持快速构建测试场景。 技术文档作为该体系的重要组成部分,系统阐述了环境配置流程、功能模块解析及测试用例编写规范。其中特别提供了针对典型业务场景的测试范例,包括数据验证流程、界面响应测试及异常处理机制。辅助资料包内含架构概览指南与扩展资源索引,完整示例工程则展示了实际项目中的最佳实践方案。 该解决方案显著降低了企业级应用的测试复杂度,通过标准化测试流程提升了缺陷检出效率。对于需要持续迭代的桌面软件产品,这种自动化测试模式能够有效保障版本发布质量,特别适合金融、医疗等对软件稳定性要求严格的行业领域。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值