snd_soc_new_pcms
==> soc_new_pcm(socdev, &machine->dai_link[i], i);
/* create the pcms */
for(i = 0; i < machine->num_links; i++) {
ret = soc_new_pcm(socdev, &machine->dai_link[i], i); // 创建soc-pcm实例,一个实例对应cpu_dai和codec_dai这样一个组合.
if (ret < 0) {
printk(KERN_ERR "asoc: can't create pcm %s\n",
machine->dai_link[i].stream_name);
mutex_unlock(&codec->mutex);
return ret;
}
}
==> snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, capture, &pcm); // 执行真正的创建[luther.gliethttp]
==> snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count) // 创建playback_count个放音stream,每个pcm可以有多个放音stream声音流通道,但我这里就1个
snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count) // 创建capture_count个录音stream,每个pcm可以有多个录音stream声音流通道,但我这里就1个[luther.gliethttp]
/**
* snd_pcm_new_stream - create a new PCM stream
* @pcm: the pcm instance
* @stream: the stream direction, SNDRV_PCM_STREAM_XXX
* @substream_count: the number of substreams
*
* Creates a new stream for the pcm.
* The corresponding stream on the pcm must have been empty before
* calling this, i.e. zero must be given to the argument of
* snd_pcm_new().
*
* Returns zero if successful, or a negative error code on failure.
*/
int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
{
int idx, err; // 为该pcm一次性创建出所有该pcm包含的stream声音流:放音和录音[luther.gliethttp]
struct snd_pcm_str *pstr = &pcm->streams[stream]; // stream有2种值:
struct snd_pcm_substream *substream, *prev; // 1.SNDRV_PCM_STREAM_PLAYBACK放音
// 2.SNDRV_PCM_STREAM_CAPTURE录音
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
mutex_init(&pstr->oss.setup_mutex);
#endif
pstr->stream = stream; // pstr为stream对应的录音或放音流的head头,后面将为该head一次性
pstr->pcm = pcm; // 追加上所有该pcm包含的相应stream声音流结构体[luther.gliethttp]
pstr->substream_count = substream_count; // 该pcm一共包含substream_count个放音或录音流
if (substream_count > 0) {
err = snd_pcm_stream_proc_init(pstr); // 创建pcm0p和pcm0c等目录
/*
luther@gliethttp:/proc/asound/card0$ tree pcm0p/
pcm0p/
|-- info
|-- oss
`-- sub0
|-- hw_params
|-- info
|-- prealloc
|-- prealloc_max
|-- status
`-- sw_params
1 directory, 8 files
*/
if (err < 0) {
snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
return err;
}
}
prev = NULL;
for (idx = 0, prev = NULL; idx < substream_count; idx++) {
substream = kzalloc(sizeof(*substream), GFP_KERNEL);// 为substream创建一块新内存空间[luther.gliethttp]
if (substream == NULL) {
snd_printk(KERN_ERR "Cannot allocate PCM substream\n");
return -ENOMEM;
}
substream->pcm = pcm; // 该substream所归属的pcm
substream->pstr = pstr; // 该substream所归属的head头
substream->number = idx; // 该substream位于head链表中的id索引值number,用来锁定本substream.
substream->stream = stream;
sprintf(substream->name, "subdevice #%i", idx);
snprintf(substream->latency_id, sizeof(substream->latency_id),
"ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
(stream ? 'c' : 'p'), idx); // 因为该函数snd_pcm_new_stream会一次性为该pcm创建所有stream,
substream->buffer_bytes_max = UINT_MAX; // 所以如果prev等于NULL,那么该substream将作为head链表的头部
if (prev == NULL) // 元素,之后substream_count-1个substream都将依次以next方式
pstr->substream = substream; // prev->next = substream;
else // prev = substream;这样该pcm的所有放音流或者录音流都将顺序链
prev->next = substream; // 接到放音pstr和录音pstr中[luther.gliethttp].
err = snd_pcm_substream_proc_init(substream); // 创建/proc/asound/card0/pcm0p/sub0目录和下面具体的文件
if (err < 0) {
snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
if (prev == NULL)
pstr->substream = NULL;
else
prev->next = NULL;
kfree(substream);
return err;
}
substream->group = &substream->self_group;
spin_lock_init(&substream->self_group.lock);
INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams);
spin_lock_init(&substream->timer_lock);
atomic_set(&substream->mmap_count, 0);
prev = substream; // 该substream作为prev,等待prev->next单向链接下一个subsystem.
}
return 0;
}