第十四部分 snd_pcm
1.pcm结构体
struct snd_pcm {
struct snd_card *card; //声卡
struct list_head list;
int device; //设备号
unsigned int info_flags;
unsigned short dev_class;
unsigned short dev_subclass;
char id[64]; //id字串
char name[80]; //名字
struct snd_pcm_str streams[2]; //pcm流数组 0-回放 1-捕捉
struct mutex open_mutex;
wait_queue_head_t open_wait; //PCM打开等待队列
void *private_data;
void (*private_free) (struct snd_pcm *pcm); //(soc_new_pcm函数)platform->driver->pcm_free
struct device *dev; //设备文件
};
2.pcm流
struct snd_pcm_str {
int stream; //流类型
struct snd_pcm *pcm; //捆绑的pcm结构体
/* -- substreams -- */
unsigned int substream_count; //子流个数
unsigned int substream_opened; //子流打开标志
struct snd_pcm_substream *substream; //pcm子流
#ifdef CONFIG_SND_VERBOSE_PROCFS
struct snd_info_entry *proc_root;
struct snd_info_entry *proc_info_entry;
#endif
};
3.pcm子流
struct snd_pcm_substream {
struct snd_pcm *pcm; //捆绑pcm结构体
struct snd_pcm_str *pstr; //捆绑的pcm流
void *private_data; /* copied from pcm->private_data */
int number;
char name[32]; //子流名
int stream; //流类型
struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
size_t buffer_bytes_max; /* limit ring buffer size */
struct snd_dma_buffer dma_buffer;
unsigned int dma_buf_id;
size_t dma_max;
/* -- hardware operations -- */
struct snd_pcm_ops *ops; //pcm操作函数集
/* -- runtime information -- */
struct snd_pcm_runtime *runtime; //pcm runtime
/* -- timer section -- */
struct snd_timer *timer; //声卡定时器
unsigned timer_running: 1; /* time is running */
/* -- next substream -- */
struct snd_pcm_substream *next; //下一个pcm子流
/* -- linked substreams -- */
struct list_head link_list; /* linked list member */
struct snd_pcm_group self_group; /* fake group for non linked substream (with substream lock inside) */
struct snd_pcm_group *group; /* pointer to current group */
/* -- assigned files -- */
void *file; //指向 snd_pcm_file结构体
int ref_count;
atomic_t mmap_count;
unsigned int f_flags;
void (*pcm_release)(struct snd_pcm_substream *);
struct pid *pid;
#ifdef CONFIG_SND_VERBOSE_PROCFS
struct snd_info_entry *proc_root;
struct snd_info_entry *proc_info_entry;
struct snd_info_entry *proc_hw_params_entry;
struct snd_info_entry *proc_sw_params_entry;
struct snd_info_entry *proc_status_entry;
struct snd_info_entry *proc_prealloc_entry;
struct snd_info_entry *proc_prealloc_max_entry;
#endif
/* misc flags */
unsigned int hw_opened: 1;
};
4.snd_pcm_new 创建PCM设备
int snd_pcm_new(struct snd_card *card, const char *id, int device,int playback_count, int capture_count,struct snd_pcm ** rpcm)
{
struct snd_pcm *pcm;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free, //释放
.dev_register = snd_pcm_dev_register, //注册
.dev_disconnect = snd_pcm_dev_disconnect, //断开连接
};
if (snd_BUG_ON(!card))
return -ENXIO;
if (rpcm)
*rpcm = NULL;
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); //分配snd_pcm内存
if (pcm == NULL) {
snd_printk(KERN_ERR "Cannot allocate PCM\n");
return -ENOMEM;
}
pcm->card = card; //捆绑声卡
pcm->device = device; //设备号
if (id) //id识别字串
strlcpy(pcm->id, id, sizeof(pcm->id)); //填充pcm结构体id字串
if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { //回放 SNDRV_PCM_STREAM_PLAYBACK=0
snd_pcm_free(pcm);
return err;
}
if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) { //捕捉 SNDRV_PCM_STREAM_CAPTURE=1
snd_pcm_free(pcm);
return err;
}
mutex_init(&pcm->open_mutex);
init_waitqueue_head(&pcm->open_wait); //初始化PCM打开等待队列
if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { //创建声卡设备,声卡设备的device_data指向snd_pcm结构体对象
snd_pcm_free(pcm);
return err;
}
if (rpcm)
*rpcm = pcm;
return 0;
}
EXPORT_SYMBOL(snd_pcm_new);
5.创建pcm子流
int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
{
int idx, err;
struct snd_pcm_str *pstr = &pcm->streams[stream]; //获取pcm流
struct snd_pcm_substream *substream, *prev;
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
mutex_init(&pstr->oss.setup_mutex);
#endif
pstr->stream = stream; //获取流类型 0:回放 1:捕捉
pstr->pcm = pcm; //捆绑pcm设备
pstr->substream_count = substream_count; //子流个数
if (substream_count > 0) {
err = snd_pcm_stream_proc_init(pstr); //proc接口
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); //分配子流内存
if (substream == NULL) {
snd_printk(KERN_ERR "Cannot allocate PCM substream\n");
return -ENOMEM;
}
substream->pcm = pcm; //捆绑pcm设备
substream->pstr = pstr; //捆绑pcm子流
substream->number = idx; //索引号
substream->stream = stream; //子流类型 0:回放 1:捕捉
sprintf(substream->name, "subdevice #%i", idx); //子流名
substream->buffer_bytes_max = UINT_MAX;
if (prev == NULL) //处理第一个pcm子流时走的分支
pstr->substream = substream; //pcm流捆绑子流
else //前一个子流的next指针指向当前子流,也就是串成一串(0->next--1->next-->2...)
prev->next = substream;
err = snd_pcm_substream_proc_init(substream); //proc接口
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);
atomic_set(&substream->mmap_count, 0);
prev = substream; //prev指向当前substream
}
return 0;
}
EXPORT_SYMBOL(snd_pcm_new_stream);
6 注册方法snd_pcm_dev_register
static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
struct snd_pcm_substream *substream;
struct snd_pcm_notify *notify;
char str[16];
struct snd_pcm *pcm;
struct device *dev;
if (snd_BUG_ON(!device || !device->device_data))
return -ENXIO;
pcm = device->device_data; //声卡设备的私有数据中获取snd_pcm对象
mutex_lock(®ister_mutex);
err = snd_pcm_add(pcm); //添加snd_pcm对象到全局snd_pcm_devices链表
if (err) {
mutex_unlock(®ister_mutex);
return err;
}
for (