Android音频驱动-ASOC之PCM Device创建

前面已经创建了control设备,现在soc_probe_link_dais调用soc_new_pcm创建pcm设备。
1)设置pcm native中要使用的pcm操作函数,这些函数用于操作音频物理设备,包括machine、codec_dai、cpu_dai、platform;
2)调用snd_pcm_new()创建pcm设备,回放子流实例和录制子流实例都在这里创建;
3)回调platform驱动的pcm_new(),完成音频dma设备初始化和dma buffer内存分配;

soc-core.c
    soc_probe
    platform_get_drvdata(pdev)//获取声卡
    snd_soc_register_card
    snd_soc_instantiate_card
    soc_probe_link_dais
soc-pcm.c
    soc_new_pcm

int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)//num为设备编号,递增排序
{
    struct snd_soc_platform *platform = rtd->platform;
    struct snd_soc_dai *codec_dai;
    struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
    struct snd_pcm *pcm;
    char new_name[64];
    int ret = 0, playback = 0, capture = 0;
    int i;

    /* create the PCM */
    if (rtd->dai_link->no_pcm) {
        snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name);
        ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, playback, capture, &pcm);
    } else {
        if (rtd->dai_link->dynamic)
            snprintf(new_name, sizeof(new_name), "%s (*)", rtd->dai_link->stream_name);
        else
            //生成stream的/proc/asound/pcm,分为playback和capture,new_name为stream_name codec_dai_name-num
            snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name,
                (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, num);

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

    rtd->pcm = pcm;
    pcm->private_data = rtd;//保存runtime对象

    /* ASoC PCM operations */
    if (rtd->dai_link->dynamic) {
        rtd->ops.open       = dpcm_fe_dai_open;
        rtd->ops.hw_params  = dpcm_fe_dai_hw_params;
        rtd->ops.prepare    = dpcm_fe_dai_prepare;
        rtd->ops.trigger    = dpcm_fe_dai_trigger;
        rtd->ops.hw_free    = dpcm_fe_dai_hw_free;
        rtd->ops.close      = dpcm_fe_dai_close;
        rtd->ops.pointer    = soc_pcm_pointer;
        rtd->ops.ioctl      = soc_pcm_ioctl;
    } else {
        rtd->ops.open       = soc_pcm_open;
        rtd->ops.hw_params  = soc_pcm_hw_params;
        rtd->ops.prepare    = soc_pcm_prepare;
        rtd->ops.trigger    = soc_pcm_trigger;
        rtd->ops.hw_free    = soc_pcm_hw_free;
        rtd->ops.close      = soc_pcm_close;
        rtd->ops.pointer    = soc_pcm_pointer;
        rtd->ops.ioctl      = soc_pcm_ioctl;
    }

    if (platform->driver->ops) {
        rtd->ops.ack        = platform->driver->ops->ack;
        rtd->ops.copy       = platform->driver->ops->copy;
        rtd->ops.silence    = platform->driver->ops->silence;
        rtd->ops.page       = platform->driver->ops->page;
        rtd->ops.mmap       = platform->driver->ops->mmap;
    }

    if (playback)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);//设置playback的substream->ops

    if (capture)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);//设置capture的substream->ops
    if (platform->driver->pcm_new) {
            ret = platform->driver->pcm_new(rtd);//platform没事具体实现
        if (ret < 0) {
            dev_err(platform->dev,
                "ASoC: pcm constructor failed: %d\n",
                ret);
            return ret;
        }
    }
    return ret;
}
/*设置substream的ops回调函数
void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
             const struct snd_pcm_ops *ops)
{
    struct snd_pcm_str *stream = &pcm->streams[direction];
    struct snd_pcm_substream *substream;
    for (substream = stream->substream; substream != NULL; substream = substream->next)
        substream->ops = ops;
}*/
/*platform driver的回调函数pcm_new
static int mtk_asoc_pcm_I2S0dl1_new(struct snd_soc_pcm_runtime *rtd)
{
    int ret = 0;
    pr_warn("%s\n", __func__);
    return ret;
}*/
int snd_pcm_new(struct snd_card *card, const char *id, int device,
        int playback_count, int capture_count, struct snd_pcm **rpcm)
{
    return _snd_pcm_new(card, id, device, playback_count, capture_count,
            false, rpcm);
}
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
        int playback_count, int capture_count, bool internal,
        struct snd_pcm **rpcm)
{
    struct snd_pcm *pcm;
    int err;
    //参数ops中的dev_register字段指向snd_pcm_dev_register,
    //这个回调函数会在声卡的注册阶段创建pcm设备节点/dev/snd/pcmCxxDxxp和/dev/snd/pcmCxxDxxc
    static struct snd_device_ops ops = {
        .dev_free = snd_pcm_dev_free,
        .dev_register = snd_pcm_dev_register,
        .dev_disconnect = snd_pcm_dev_disconnect,
    };

    pcm = kzalloc(
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值