杂记asla-lib库函数snd_pcm_open打开流程
浅析ac97声卡intel8x0的DMA内存substream->dma_buffer什么时候被赋值
浅析ac97声卡intel8x0的runtime->dma_area是怎么获取的
浅析ac97声卡intel8x0的pci总线DMA物理地址填充和音频数据发送流程
aplay.c
==> main
==> snd_pcm_open(&handle, pcm_name, stream, open_mode); // 打开一路pcm,刷新config配置
如果是"default",同时type等于SND_CONFIG_TYPE_COMPOUND那么这里对应"empty"
static const char *const build_in_pcms[] = {
"adpcm", "alaw", "copy", "dmix", "file", "hooks", "hw", "ladspa", "lfloat",
"linear", "meter", "mulaw", "multi", "null", "empty", "plug", "rate", "route", "share",
"shm", "dsnoop", "dshare", "asym", "iec958", "softvol", "mmap_emul",
NULL
};
_snd_pcm_empty_open和snd_pcm_open_named_slave
==> snd_pcm_open_conf(pcmp, name, root, conf, stream, mode);
==> open_func = snd_dlobj_cache_lookup(open_name);将获得lib库中_snd_pcm_empty_open函数
所以open_func将等于_snd_pcm_empty_open
_snd_pcm_empty_open
_snd_pcm_asym_open
_snd_pcm_plug_open
_snd_pcm_softvol_open
_snd_pcm_dmix_open
_snd_pcm_hw_open
==> snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
mode | (nonblock ? SND_PCM_NONBLOCK : 0),
0, sync_ptr_ioctl);
==> snd_ctl_hw_open
filename等于"/dev/snd/controlC0"
==> snd_open_device(filename, fmode);
ctl->ops = &snd_ctl_hw_ops;
ctl->private_data = hw;
ctl->poll_fd = fd;
*handle = ctl;
filename等于"/dev/snd/pcmC0D0p"
==> fd = snd_open_device(filename, fmode);
==> return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl);
==> snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode);
pcm->ops = &snd_pcm_hw_ops;
pcm->fast_ops = &snd_pcm_hw_fast_ops;
static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private_data;
void *ptr;
int err;
if (hw->sync_ptr == NULL) { // 如果还没有mmap,那么执行mmap映射内核空间驱动使用的声音缓冲区
ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_control)),
PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
if (ptr == MAP_FAILED || ptr == NULL) {
err = -errno;
SYSMSG("control mmap failed");
return err;
}
hw->mmap_control = ptr; // 声卡驱动头部填充了一个结构体sndrv_pcm_mmap_control,类似qvfb显示原理.
// struct sndrv_pcm_mmap_control {
// sndrv_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */
// sndrv_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */
// };
} else {
hw->mmap_control->avail_min = 1;
}
snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
return 0;
}
snd_pcm_mmap
switch (i->type) {
case SND_PCM_AREA_MMAP: // 表示为数据区分配驱动内存,在snd_pcm_hw_channel_info中设置了type
ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
/*
mmap
==> snd_pcm_mmap_data
==> snd_pcm_default_mmap
// mmap the DMA buffer on RAM
static int snd_pcm_default_mmap(struct snd_