浅析alsa声卡放音模式时s3c24xx处理器DMA中断如何建立和处理
《浅析uda134x声卡驱动probe的精简步骤》《浅析打开/dev/dsp设备节点代码流程》《浅析放音模式--向/dev/dsp设备write写入音频数据的代码流》1.登记soc_pcm_ops中的soc_pcm_hw_params到substream->ops中
static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
.card = &snd_soc_s3c24xx_uda134x,
.codec_dev = &soc_codec_dev_uda134x, // 核心在于执行它的uda134x_soc_probe
.codec_data = &s3c24xx_uda134x,
};
struct snd_soc_codec_device soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.remove = uda134x_soc_remove,
.suspend = uda134x_soc_suspend,
.resume = uda134x_soc_resume,
};
==> uda134x_soc_probe
==> snd_soc_new_pcms
==> soc_new_pcm
==> 设置substream->ops = soc_pcm_ops;
/* 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,
};
2.引用soc_pcm_hw_params
static const struct file_operations snd_pcm_oss_f_reg =
{
.owner = THIS_MODULE,
.read = snd_pcm_oss_read,
.write = snd_pcm_oss_write,
.open = snd_pcm_oss_open,
.release = snd_pcm_oss_release,
.poll = snd_pcm_oss_poll,
.unlocked_ioctl = snd_pcm_oss_ioctl,
.compat_ioctl = snd_pcm_oss_ioctl_compat,
.mmap = snd_pcm_oss_mmap,
};
snd_pcm_oss_f_reg
==> snd_pcm_oss_write
==> snd_pcm_oss_write1
==> snd_pcm_oss_make_ready
《浅析alsa声卡驱动snd_pcm_oss_make_ready函数》==> snd_pcm_oss_change_params
《浅析alsa声卡驱动snd_pcm_oss_change_params函数》==> snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams) // 执行硬件参数配置函数
《浅析alsa声卡驱动snd_pcm_kernel_ioctl函数》==> snd_pcm_playback_ioctl1或者snd_pcm_capture_ioctl1
==> snd_pcm_common_ioctl1
case SNDRV_PCM_IOCTL_HW_PARAMS:
return snd_pcm_hw_params_user(substream, arg);
==> snd_pcm_hw_params_user
==> snd_pcm_hw_params
==> snd_pcm_hw_params
==> substream->ops->hw_params(substream, params);即soc_pcm_ops的soc_pcm_hw_params
==> soc_pcm_hw_params
==> platform->pcm_ops->hw_params(substream, params);即s3c24xx_pcm_hw_params
struct snd_soc_platform s3c24xx_soc_platform = {
.name = "s3c24xx-audio",
.pcm_ops = &s3c24xx_pcm_ops,
.pcm_new = s3c24xx_pcm_new,
.pcm_free = s3c24xx_pcm_free_dma_buffers,
};
s3c24xx_pcm_ops
static struct snd_pcm_ops s3c24xx_pcm_ops = {
.open = s3c24xx_pcm_open,
.close = s3c24xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = s3c24xx_pcm_hw_params,
.hw_free = s3c24xx_pcm_hw_free,
.prepare = s3c24xx_pcm_prepare,
.trigger = s3c24xx_pcm_trigger,
.pointer = s3c24xx_pcm_pointer,
.mmap = s3c24xx_pcm_mmap,
};
==> s3c24xx_pcm_hw_params
==> s3c2410_dma_request(prtd->params->channel, prtd->params->client, NULL);
设置dma完成之后的函数为s3c24xx_audio_buffdone
s3c2410_dma_set_buffdone_fn(prtd->params->channel, s3c24xx_audio_buffdone);
==> request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
client->name, (void *)chan);
登记注册dma数据传输完毕的irq中断函数s3c2410_dma_irq
s3c2410_dma_irq
==> s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
static inline void
s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
enum s3c2410_dma_buffresult result)
{
#if 0
pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
chan->callback_fn, buf, buf->id, buf->size, result);
#endif
if (chan->callback_fn != NULL) {
(chan->callback_fn)(chan, buf->id, buf->size, result); // 执行s3c24xx_audio_buffdone完成audio音频数据发送工作
}
}