5. 创建声卡

 代码位置 sound/soc/generic/simple-card.c

static int asoc_simple_card_probe(struct platform_device *pdev)
{
    ...

    ret = devm_snd_soc_register_card(dev, card);
 
    ...
}

 asoc_simple_card_probe -> devm_snd_soc_register_card -> snd_soc_register_card

int snd_soc_register_card(struct snd_soc_card *card)
{
    int i, ret;
    struct snd_soc_pcm_runtime *rtd;

    if (!card->name || !card->dev)
        return -EINVAL;

    for (i = 0; i < card->num_links; i++) {
        struct snd_soc_dai_link *link = &card->dai_link[i];

        ret = soc_init_dai_link(card, link);
        if (ret) {
            dev_err(card->dev, "ASoC: failed to init link %s\n",
                link->name);
            return ret;
        }
    }
    ...
}

soc_init_dai_link执行后,会出现下面红框内的链接

 继续分析

asoc_simple_card_probe -> devm_snd_soc_register_card -> snd_soc_register_card -> snd_soc_instantiate_card -> soc_bind_dai_link

int snd_soc_register_card(struct snd_soc_card *card)
{
       ...
    dev_set_drvdata(card->dev, card);
    snd_soc_initialize_card_lists(card);
    INIT_LIST_HEAD(&card->dai_link_list);
    card->num_dai_links = 0;

    INIT_LIST_HEAD(&card->rtd_list);
    card->num_rtd = 0;

    INIT_LIST_HEAD(&card->dapm_dirty);
    INIT_LIST_HEAD(&card->dobj_list);
    card->instantiated = 0;
    mutex_init(&card->mutex);
    mutex_init(&card->dapm_mutex);

    ret = snd_soc_instantiate_card(card);
       ...
    }
}

static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
    struct snd_soc_pcm_runtime *rtd;
    struct snd_soc_dai_link *dai_link;
    int ret, i, order;

    mutex_lock(&client_mutex);
    mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);

    /* check whether any platform is ignore machine FE and using topology */
    soc_check_tplg_fes(card);

    /* bind DAIs */
    for (i = 0; i < card->num_links; i++) {
        ret = soc_bind_dai_link(card, &card->dai_link[i]);
        if (ret != 0)
            goto base_error;
    }
    
    ...
}

static int soc_bind_dai_link(struct snd_soc_card *card,
    struct snd_soc_dai_link *dai_link)
{
    struct snd_soc_pcm_runtime *rtd;
    struct snd_soc_dai_link_component *codecs = dai_link->codecs;
    struct snd_soc_dai_link_component cpu_dai_component;
    struct snd_soc_component *component;
    struct snd_soc_dai **codec_dais;
    struct device_node *platform_of_node;
    const char *platform_name;
    int i;

    if (dai_link->ignore)
        return 0;

    dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);

    if (soc_is_dai_link_bound(card, dai_link)) {
        dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
            dai_link->name);
        return 0;
    }

    /* 创建rtd */
    rtd = soc_new_pcm_runtime(card, dai_link);
    if (!rtd)
        return -ENOMEM;

    cpu_dai_component.name = dai_link->cpu_name;
    cpu_dai_component.of_node = dai_link->cpu_of_node;
    cpu_dai_component.dai_name = dai_link->cpu_dai_name;
    rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
    if (!rtd->cpu_dai) {
        dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
             dai_link->cpu_dai_name);
        goto _err_defer;
    }
    
    /* 关联cpu */
    snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
    rtd->num_codecs = dai_link->num_codecs;

    /* Find CODEC from registered CODECs */
    codec_dais = rtd->codec_dais;
    for (i = 0; i < rtd->num_codecs; i++) {
        codec_dais[i] = snd_soc_find_dai(&codecs[i]);
        if (!codec_dais[i]) {
            dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
                codecs[i].dai_name);
            goto _err_defer;
        }
        snd_soc_rtdcom_add(rtd, codec_dais[i]->component);
    }

    /* Single codec links expect codec and codec_dai in runtime data */
    rtd->codec_dai = codec_dais[0];

    /* if there's no platform we match on the empty platform */
    platform_name = dai_link->platform_name;
    if (!platform_name && !dai_link->platform_of_node)
        platform_name = "snd-soc-dummy";

    /* find one from the set of registered platforms */
    list_for_each_entry(component, &component_list, list) {
        platform_of_node = component->dev->of_node;
        if (!platform_of_node && component->dev->parent->of_node)
            platform_of_node = component->dev->parent->of_node;

        if (dai_link->platform_of_node) {
            if (platform_of_node != dai_link->platform_of_node)
                continue;
        } else {
            if (strcmp(component->name, platform_name))
                continue;
        }
        /* 关联codec*/
        snd_soc_rtdcom_add(rtd, component);
    }

    soc_add_pcm_runtime(card, rtd);
    return 0;

_err_defer:
    soc_free_pcm_runtime(rtd);
    return  -EPROBE_DEFER;
}

asoc_simple_card_probe -> devm_snd_soc_register_card -> snd_soc_register_card -> snd_soc_instantiate_card -> snd_soc_add_dai_link

 

static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
    /* add predefined DAI links to the list */
    for (i = 0; i < card->num_links; i++) 
        snd_soc_add_dai_link(card, card->dai_link+i);
    ...
}

主要是将dai_link挂载到card的dai_link上面,上图已经连接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
创建虚拟声 c 是为了在计算机中模拟一个虚拟的音频设备,使得计算机可以像使用真实的声一样进行音频输入输出。 首先,在操作系统层面上,需要编写相关的驱动程序或者使用现有的虚拟声驱动程序,使操作系统能够识别虚拟声 c,并将其作为一种可用的音频设备。这样,在操作系统的声音设置中,就可以选择虚拟声 c 作为默认的输入输出设备。 其次,在应用程序层面上,需要编写相应的代码来使用虚拟声 c 进行音频的输入输出。在音频输入方面,可以通过调用虚拟声 c 提供的接口函数,从外部音频源(如麦克风或其他音频设备)获取音频信号,并传输给计算机。在音频输出方面,可以通过调用虚拟声 c 提供的接口函数,将计算机处理后的音频数据输出到音频播放设备(如扬声器或其他音频输出设备)。 此外,虚拟声 c 还可以支持一些特殊功能,如音频混音、音频格式转换等。通过调用相应的接口函数,可以实现将多路音频信号混合为一路输出,或者将音频信号转换为不同的格式以适应不同的音频设备。 总之,创建虚拟声 c 是通过编写相应的驱动程序和应用程序代码,在操作系统和应用程序中模拟一个虚拟的音频设备,并使其能够进行音频的输入输出。这样,就可以方便地实现音频数据的处理和传输,满足用户对音频功能的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值