zoukankan      html  css  js  c++  java
  • Android音频(2)——ALSA声卡驱动——ASoC

    一、ASoC简介

      ASoC(Alsa System on Chaip),也称为移动设备中的ALSA。是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。ASoC不能单独存在,他只是建立在标准ALSA驱动上的一个它必须和标准的ALSA驱动框架相结合才能工作。


    二、ASoC硬件架构

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

    Machine:是指某款单板,包含特定的外设,为CPU、Codec提供了一个载体,Machine驱动几乎是不可重用的。

    Platform:一般是指某一个SoC平台,可以理解为某款Soc,具有I2S,AC97音频接口等,内部有时钟,DMA单元用于传输音频数据。

    Codec:音频编解码器,Codec里面包含了I2S接口、D/A、A/D、Mixer、PA(功放),通常包含多种输入(Mic、Line-in、I2S、PCM)和多个输出(耳机、喇叭、听筒,Line-out),一般Soc可通过I2C来控制codec芯片。

    三、ASoC软件架构

      对应于硬件,软件驱动上也分Machine驱动、Platform驱动、Codec驱动三大部分,其中Platform驱动用于驱动Soc端的音频相关模块,Codec驱动用于驱动音频编解码器,的Machine驱动负责Platform驱动和Codec驱动之间的耦合以及部分和设备或板子特定的代码。

    Platform驱动:

      只与特定的Soc有关,实现Soc的音频DMA驱动和Soc端的dai接口驱动,注册的所有platform驱动都会挂载在全局platform_list链表上。注册的Soc端的cpu_dai接口驱动挂载在全局dai_list上。只要指定了SoC,就会有一个对应的Platform,它只与SoC相关,与Machine无关,这样我们就可以把Platform抽象出来,使得同一款SoC不用做
    任何的改动,就可以用在不同的Machine中。

    Codec驱动:

      只与Codec编解码器驱动有关,与Soc和Machine无关。所有注册的Codec驱动都会挂载在全局codec_list链表上,注册的Codec端的dai接口驱动挂载在全局dai_list上。Codec和Platform一样,要实现为可重用的部件,同一个Codec可以被不同的Machine使用。嵌入式Codec驱动通常通过I2C对编解码芯片进行控制。

    Machine驱动:

       用于将Platform驱动和Codec驱动关联在一起,通过snd_soc_dai_link中的名字指定使用哪个Platform驱动,使用哪个Soc端的dai接口,使用哪个Codec驱动,使用Codec上的哪个dai接口。同时也做一些特定于单板的操作。只要是与Soc和Codec驱动无关的操作,都应该放在Machine驱动中。Machine驱动中注册的and_codec_card放在全局card_list链表上。ASoC的一切都从Machine驱动开始,包括声卡的注册,绑定Platform和Codec驱动等等。


    涉及的三个驱动中涉及的全局链表

    //soc-core.c中
    struct list_head card_list;     /*Machine驱动注册的snd_codec_card放在这个链表上*/
    struct list_head dai_list;         /*soundsocsamsungI2s.c中使用snd_soc_register_dai注册的cpu_dai会放在这上面,codec中注册的codec端的dai也会挂在这上面*/
    struct list_head platform_list; /*注册的Soc的platform驱动在这个链表上*/
    struct list_head codec_list;     /*音频编解码芯片驱动注册的codec挂载在这个链表上*/

    snd_soc_card是整个ASoc的核心结构体。

    四、ASoC架构中的Machine驱动

    1.核心结构体
    snd_soc_dai_link
    snd_soc_card
    
    2.注册
    //设备端:
    struct snd_soc_dai_link tiny4412_wm8960_dai_link;
    struct snd_soc_card myalsa_card;
    
    tiny4412_wm8960_init
        platform_set_drvdata(&asoc_dev, &myalsa_card);
    
    //驱动端:
    soc_probe(struct platform_device *pdev) //soc-core.c
        snd_soc_register_card(card);

      Machine驱动负责处理单板特有的一些控件和音频事件。单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。snd_soc_dai_link则负责关联Platform和Codec。

      snd_soc_card代表着Machine驱动中要注册的声卡设备,(也就是tiny4412_wm8960.c,它只是平台设备的设备端,在设备端构造snd_soc_card,在驱动端
    注册这个card,驱动端是soc-core.c)

      snd_soc_dai_link中,指定了Platform、Codec、codec_dai、cpu_dai的名字,稍后Machine驱动将会利用这些名字去匹配已经在系统中注册的platform,codec,dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义的,这样看来,Machine驱动的设备初始化代码无非就是选择合适Platform和Codec以及dai,用他们填充以上几个数据结构,然后注册Platform设备即可。当然还要实现连接Platform和Codec的dai_link对应的ops实现。

      通过snd_soc_register_card,为snd_soc_pcm_runtime数组申请内存,每一个dai_link对应snd_soc_pcm_runtime数组的一个单元,然后把snd_soc_card中的dai_link配置复制到相应的snd_soc_pcm_runtime中,最后,大部分的工作都在snd_soc_instantiate_card中实现,包括调用soc_bind_dai_link()来解析struct snd_soc_dai_link来关联各个设备。

      Machine驱动的初始化,codec和dai的注册,都会调用snd_soc_instantiate_cards()进行一次声卡和codec,dai,platform的匹配绑定过程,这里所说的绑定,正如Machine驱动一文中所描述,就是通过3个全局链表,按名字进行匹配,把匹配的codec,dai和platform实例赋值给声卡中用于描述每组关联关系的snd_soc_pcm_runtime结构中。一旦通过Machine驱动将Codec、Platform绑定成功,就会依次调用各个组件的probe()回调函数,调用关系依次是:
      CPU dai接口的:snd_soc_dai_driver.probe()
      Codec驱动的:snd_soc_codec_driver.probe()
      Platform驱动的:snd_soc_platform_driver.probe()
      Codec dai接口的:snd_soc_dai_driver.probe()
    详细调用过程见soc_probe_dai_link()

    snd_soc_instantiate_card(struct snd_soc_card *card)
        //通过snd_soc_dai_link中的name构建关联关系
        soc_bind_dai_link(card, i);
        //对每一条链路调用各个组件的probe()
        soc_probe_dai_link(struct snd_soc_card *card, int num)
        //如果codec驱动有多个codec_conf配置,machine驱动可以通过snd_soc_card选择一个
        //走上了ALSA的老路了
        snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, card->owner, 0, &card->snd_card);
        //若Machine驱动中指定了card的probe()则调用
        card->probe(card);
        snd_soc_add_controls
        snd_soc_dapm_add_routes
        snd_card_register

    五、ASoC架构中的Codec驱动

    1.核心结构体
    snd_soc_codec
    snd_soc_codec_driver
    snd_soc_dai
    snd_soc_dai_driver
    
    2.注册
    //wm8960.c
    snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8960, &wm8960_dai, 1);

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

    所有的Codec驱动都要提供以下特性:
      Codec DAI 和 PCM的配置信息;
      Codec的IO控制方式(I2C,SPI等);
      Mixer和其他的音频控件;
      Codec的ALSA音频操作接口;
    必要时,也可以提供以下功能:
      DAPM描述信息;
      DAPM事件处理程序;
      DAC数字静音控制

    snd_soc_codec/snd_soc_codec_driver代表了Codec驱动(也就是wm8960.c),snd_soc_register_codec()同时注册了codec和codec端的dai。

    六、ASoC架构中的Platform驱动

    1.核心结构体
    snd_soc_platform
    snd_soc_platform_driver
    snd_soc_dai
    snd_soc_dai_driver
    
    2.注册
    注册platform驱动:
    //dma.c
    snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
    注册cpu_dai驱动:
    //i2s.c
    i2s_alloc_dai(pdev, false);
    snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);

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

      Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DAI)把音频数据传送给Codec进行处理,最终由Codec输出驱动耳机或者是喇叭的音信信号。

      在具体实现上,ASoC有把Platform驱动分为两个部分:snd_soc_platform_driver和snd_soc_dai_driver。其中,platform_driver负责管理音频数据,把音频数据通过dma或其他操作传送至cpu dai中,dai_driver则主要完成cpu一侧的dai的参数配置,同时也会通过一定的途径把必要的dma等参数与snd_soc_platform_driver进行交互。

      CPU端的dai驱动通常对应Soc的一个或几个I2S/PCM接口的驱动

    七、总结

      注意各个驱动的分工,就大致知道每个模块需要提供哪些钩子函数,这钩子函数应该由谁调用。比如Codec应该提供自己的各个控制接口给Machine驱动程序调用,Platform驱动也应该提供自己的驱动接口给Machine驱动调用。

      自己编写驱动的时候需要提供Machine驱动的设备端,若Codec驱动还没有,则还需要提供codec的驱动。一般platform驱动是Soc厂商已经提供好的,Codec驱动是音频编解码芯片供应商提供好的。因此,我们的工作就是编写Machine驱动和适配Codec芯片到我们的单板上。

    参考:

    Linux ALSA声卡驱动之五:移动设备中的ALSA: https://blog.csdn.net/michaelcao1980/article/details/78228630
    Linux ALSA声卡驱动之六:ASoC架构中的Machine: https://blog.csdn.net/droidphone/article/details/7231605
    Linux ALSA声卡驱动之七:ASoC架构中的Codec: https://blog.csdn.net/DroidPhone/article/details/7283833
    Linux ALSA声卡驱动之八:ASoC架构中的Platform: https://blog.csdn.net/droidphone/article/details/7316061

  • 相关阅读:
    WPF 自定义ComboBox样式,自定义多选控件
    .net core 的网站
    grpc详细入门
    如何遍历所有程序集中的成员、类
    【C#】IDispose接口的应用
    redis集群简介
    What’s your most controversial programming opinion?
    初学PHP——欲得生受用,须下死功夫!
    Great OOP
    博客园背景特效粒子鼠标跟踪吸附
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10918742.html
Copyright © 2011-2022 走看看