DSP

open("/dev/dsp")函数调用流程 --OSS接口

2019-07-13 10:25发布

open("/dev/dsp")
==> sys_open
==> soundcore_open (所有的fops以iminor为索引放在全局static struct sound_unit *chains[SOUND_STEP];中)
==> snd_pcm_oss_f_reg.snd_pcm_oss_open
/*
 * 下面是内核对soc_pcm_open函数的简短描述
 * Called by ALSA when a PCM substream is opened, the runtime->hw record is
 * then initialized and any private data can be allocated. This also calls
 * startup for the cpu DAI, platform, machine and codec DAI.
 */
==> substream->ops->open(substream)     即soc_pcm_ops.soc_pcm_open
==> cpu_dai->ops.startup(substream)     即cpu内部音频控制单元初始化,比如i2s和ssp控制器等
==> platform->pcm_ops->open(substream)  即ep93xx_soc_platform.ep93xx_pcm_ops.ep93xx_pcm_open比如申请dma等
==> codec_dai->ops.startup(substream)   即和cpu链接的外部codec音频芯片初始化,我的codec只提供了prepare和shutdown[luther.gliethttp].
==> machine->ops->startup(substream)    这里*machine = rtd->dai;在soc_new_pcm()中pcm->private_data = rtd;
                                        同时rtd->dai = dai_link;这个dai_link就是machine->dai_link[i];即下面的snd_soc_machine_TLG
                                        因为一个snd_soc_dai_link将最终生成一个pcm实例
                                        即machine->ops->startup(substream)就是一个pcm对应的ops下的startup初始化,就表示pcm实例启动[luther.gliethttp]
/* machine stream operations */
static struct snd_soc_ops TLG_machine_ops[] = {
{
    .startup = TLG_xxxx_hifi_startup,
    .prepare = TLG_xxxx_hifi_prepare,
    .shutdown = TLG_xxxx_hifi_shutdown,
},
{
    .startup = TLG_xxxx_voice_startup,
    .prepare = TLG_xxxx_voice_prepare,
    .shutdown = TLG_xxxx_voice_shutdown,
}
};

static struct snd_soc_dai_link TLG_dai[] = {
{
    .name = "I2S",
    .stream_name = "I2S HiFi",
    .cpu_dai = &ep93xx_ssp_dai[I2S_SSP_PORT-1],
    .codec_dai = &xxxx_dai[0],
    .ops = &TLG_machine_ops[0],
    .init = TLG_xxxx_init,
},
{
    .name = "PCM",
    .stream_name = "PCM Voice",
    .cpu_dai = &ep93xx_ssp_dai[PCM_SSP_PORT-1],
    .codec_dai = &xxxx_dai[1],
    .ops = &TLG_machine_ops[1],
    .init = TLG_xxxx_init,
}
};

struct snd_pcm_ops ep93xx_pcm_ops = {
    .open        = ep93xx_pcm_open,
    .close        = ep93xx_pcm_close,
    .ioctl        = snd_pcm_lib_ioctl,
    .hw_params    = ep93xx_pcm_hw_params,
    .hw_free    = ep93xx_pcm_hw_free,
    .prepare    = ep93xx_pcm_prepare,
    .trigger    = ep93xx_pcm_trigger,
    .pointer    = ep93xx_pcm_pointer,
    .mmap        = ep93xx_pcm_mmap,
};

/* TLG audio machine driver */
static struct snd_soc_machine snd_soc_machine_TLG = {
    .name = "TLG",
    .dai_link = TLG_dai,
    .num_links = ARRAY_SIZE(TLG_dai),
};

struct snd_soc_platform ep93xx_soc_platform = {
    .name        = "ep93xx-audio",
    .pcm_ops     = &ep93xx_pcm_ops,
    .pcm_new    = ep93xx_pcm_new,
    .pcm_free    = ep93xx_pcm_free_dma_buffers,
};
在soc_new_pcm函数中对soc_pcm_ops操作方法内容进行了如下丰富操作.
/* create a new pcm */
static int soc_new_pcm(struct snd_soc_device *socdev,
    struct snd_soc_dai_link *dai_link, int num)

/* ASoC PCM operations */
static struct snd_pcm_ops soc_pcm_ops = {
    .open        = soc_pcm_open,
    .close        = soc_codec_close,
    .hw_params    = soc_pcm_hw_params,
    .hw_free    = soc_pcm_hw_free,
    .prepare    = soc_pcm_prepare,
    .trigger    = soc_pcm_trigger,
};
    soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;         // 开发板自己的mmap方法
    soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
    soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl;       // 开发板自己的ioctl方法
    soc_pcm_ops.copy = socdev->platform->pcm_ops->copy;
    soc_pcm_ops.silence = socdev->platform->pcm_ops->silence;
    soc_pcm_ops.ack = socdev->platform->pcm_ops->ack;
    soc_pcm_ops.page = socdev->platform->pcm_ops->page;