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;