alsa结构体流程2

Control接口主要让用户空间的应用程序(alsa-lib)可以访问和控制音频codec芯片中的多路开关,滑动控件等。


我们需要在我们的驱动程序初始化时主动调用snd_pcm_new()函数创建pcm设备,而control设备则在snd_card_create()内被创建,

snd_card_create()通过调用snd_ctl_create()函数创建control设备节点。所以我们无需显式地创建control设备,只要建立声卡,control设备被自动地创建。

同样,它有一个 snd_ctl_dev_register,它调用:
  1. snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,   &snd_ctl_f_ops, card, name)
/*
 *  INIT PART
 */

static const struct file_operations snd_ctl_f_ops =
{
    .owner =    THIS_MODULE,
    .read =        snd_ctl_read,
    .open =        snd_ctl_open,
    .release =    snd_ctl_release,
    .llseek =    no_llseek,
    .poll =        snd_ctl_poll,
    .unlocked_ioctl =    snd_ctl_ioctl,
    .compat_ioctl =    snd_ctl_ioctl_compat,
    .fasync =    snd_ctl_fasync,

};

用户程序需要打开control设备时,驱动程序通过snd_minors[]全局数组和此设备号,可以获得snd_ctl_f_ops结构中的各个回调函数,

然后通过这些回调函数访问control中的信息和数据(最终会调用control的几个回调函数get,put,info)。可以读一下代码:/sound/core/control.c。


ASoC--ALSA System on Chip ,是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。

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

通常,就像软件领域里的抽象和重用一样,嵌入式设备的音频系统可以被划分为板载硬件(Machine)、Soc(Platform)、Codec三大部分,如下图所示:

                                        音频系统结构

ASoC中重要的数据结构之间的关联方式:


                                                                                                      Kernel-2.6.35-ASoC中各个结构的静态关系



                                                                                             Kernel 3.0中的ASoC数据结构

3.0中的数据结构更为合理和清晰,取消了snd_soc_device结构,直接用snd_soc_card取代了它,并且强化了snd_soc_pcm_runtime的作用,同时还增加了另外两个数据结构snd_soc_codec_driver和snd_soc_platform_driver,用于明确代表Codec驱动和Platform驱动。


/* SoC audio ops */
struct snd_soc_ops {
    int (*startup)(struct snd_pcm_substream *);
    void (*shutdown)(struct snd_pcm_substream *);
    int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
    int (*hw_free)(struct snd_pcm_substream *);
    int (*prepare)(struct snd_pcm_substream *);
    int (*trigger)(struct snd_pcm_substream *, int);
};

它的作用是什么呢???

通过snd_soc_card结构,又引出了Machine驱动的另外两个个数据结构:

  • snd_soc_dai_link(实例:smdk_dai[] )
  • snd_soc_ops(实例:smdk_ops )

其中,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实现,本例就是smdk_ops,它只实现了hw_params函数:smdk_hw_params。


platform_driver通过其probe连接了snd_soc_card,其中的dai_link(snd_soc_dai_link类型)连接了snd_soc_ops结构体。


snd_soc_card的prope函数在platform总线匹配platform_device和platform_driver时会被调用,它调用snd_soc_register_card,通过snd_soc_register_card,。。。,大部分的工作都在snd_soc_instantiate_card中实现。


该函数首先利用card->instantiated来判断该卡是否已经实例化,如果已经实例化则直接返回,否则遍历每一对dai_link,进行codec、platform、dai的绑定工作:

/* bind DAIs */
    for (i = 0; i < card->num_links; i++)
        soc_bind_dai_link(card, i);

ASoC定义了三个全局的链表头变量:codec_list、dai_list、platform_list,系统中所有的Codec、DAI、Platform都在注册时连接到这三个全局链表上。soc_bind_dai_link函数逐个扫描这三个链表,根据card->dai_link[]中的名称进行匹配,匹配后把相应的codec,dai和platform实例赋值到card->rtd[]中(snd_soc_pcm_runtime)。经过这个过程后,snd_soc_pcm_runtime:(card->rtd)中保存了本Machine中使用的Codec,DAI和Platform驱动的信息。


/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_pcm_runtime  {
    struct device dev;
    struct snd_soc_card *card;
    struct snd_soc_dai_link *dai_link;

    unsigned int complete:1;
    unsigned int dev_registered:1;

    /* Symmetry data - only valid if symmetry is being enforced */
    unsigned int rate;
    long pmdown_time;

    /* runtime devices */
    struct snd_pcm *pcm;
    struct snd_soc_codec *codec;
    struct snd_soc_platform *platform;
    struct snd_soc_dai *codec_dai;
    struct snd_soc_dai *cpu_dai;

    struct delayed_work delayed_work;
};

snd_soc_instantiate_card接着初始化Codec的寄存器缓存,然后调用标准的alsa函数创建声卡实例: 


  1. /* card bind complete so register a sound card */  
  2. ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,  card->owner, 0, &card->snd_card);  
  3. card->snd_card->dev = card->dev;  
  4. card->dapm.bias_level = SND_SOC_BIAS_OFF;  
  5. card->dapm.dev = card->dev;  
  6. card->dapm.card = card;  
  7. list_add(&card->dapm.list, &card->dapm_list); 
然后,依次调用各个子结构的probe函数:

/* initialise the sound card only once */
    if (card->probe) {
        ret = card->probe(card); //可能是空的
        if (ret < 0)
            goto card_probe_error;
    }

    for (i = 0; i < card->num_links; i++) {
        ret = soc_probe_dai_link(card, i);
        if (ret < 0) {
            pr_err("asoc: failed to instantiate card %s: %d\n",
                   card->name, ret);
            goto probe_dai_err;
        }
    }


在上面的soc_probe_dai_link()函数中做了比较多的事情,该函数除了挨个调用了codec,dai和platform驱动的probe函数外,

在最后还调用了soc_new_pcm()函数用于创建标准alsa驱动的pcm逻辑设备。(它会调用:

ret = snd_pcm_new(rtd->card->snd_card, new_name,
            num, playback, capture, &pcm);

)

调用标准alsa驱动中的创建pcm的函数snd_pcm_new()创建声卡的pcm实例,pcm的private_data字段设置为该runtime变量rtd,然后用platform驱动中的snd_pcm_ops替换部分pcm中的snd_pcm_ops字段,最后,调用platform驱动的pcm_new回调,该回调实现该platform下的dma内存申请和dma初始化等相关工作。到这里,声卡和他的pcm实例创建完成。


回到snd_soc_instantiate_card函数,完成snd_card和snd_pcm的创建后,接着对dapm和dai支持的格式做出一些初始化合设置工作后,调用了 card->late_probe(card)进行一些最后的初始化合设置工作,最后则是调用标准alsa驱动的声卡注册函数对声卡进行注册:


//damp controls
    if (card->dapm_widgets)
        snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
                      card->num_dapm_widgets);
    if (card->dapm_routes)
        snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
                    card->num_dapm_routes);

。。。

     //in init.c
    //create card device, register all the devices on the card.
    ret = snd_card_register(card->snd_card);
    if (ret < 0) {
        printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
        goto probe_aux_dev_err;
    }

至此,整个Machine驱动的初始化已经完成,通过各个子结构的probe调用,实际上,也完成了部分Platfrom驱动和Codec驱动的初始化工作,整个过程可以用一下的序列图表示:


                                                                               基于3.0内核  soc_probe序列图


                                                                              基于2.6.35  soc_probe序列图
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中的ALSA(Advanced Linux Sound Architecture)流程是用于音频处理的一种架构。它允许Android设备与硬件之间进行高性能的音频交互。 在Android中,ALSA流程可以简要归纳为以下步骤: 1. 初始化:首先,Android系统会初始化ALSA框架,这包括加载相应的驱动程序和配置系统音频参数。 2. 设置音频路径:Android会根据应用程序的音频要求,设置音频通道和路径。例如,如果要播放音乐,则会设置音频输出路径为耳机或扬声器。 3. 数据捕获和处理:如果有需要,Android设备可以捕获麦克风输入的音频数据。这些数据经过ALSA框架和硬件处理,以实现噪音过滤、音频增益等功能。 4. 数据播放和处理:对于音频播放,Android设备从存储中读取音频数据,并通过ALSA框架将其传递给相应的硬件。在传递过程中,ALSA还可以对音频数据进行降噪、音效处理等操作。 5. 同步和控制:在音频数据的捕获和播放过程中,ALSA会实时控制和同步音频输入和输出。它会根据音频缓冲区的状态来动态调整流程,以确保良好的音频质量和延迟。 6. 关闭和释放:当音频处理完成时,Android会关闭ALSA,释放资源并恢复系统原始状态。 总体而言,ALSA流程是为了实现Android设备与音频硬件的高效交互。它提供了一套API和驱动程序,使得应用程序开发者可以轻松访问设备的音频功能,并以良好的音频质量进行音频处理和播放。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值