目录
1. 前言
前面几章分析了ASoC音频驱动中Codec、Platform、Machine驱动的组成部分及其注册过程,这三者都是物理设备相关的,大家应该对音频物理链路有了一定的认知。接着分析音频驱动的中间层,由于这些并不是真正的物理设备,故我们称之为逻辑设备。
PCM逻辑设备,我们又习惯称之为PCM中间层或pcm native,起着承上启下的作用:
1.往上是与用户态接口的交互,实现音频数据在用户态和内核态之间的拷贝,即user space <-> kernel space;
2.往下是触发codec、platform、machine的操作函数,实现音频数据在dma_buffer<-> cpu_dai <-> codec之间的传输。
2. PCM逻辑设备
Kernel 版本:3.10
内核源码文件:
./kernel-3.10/sound/core/device.c
./kernel-3.10/sound/core/init.c
./kernel-3.10/sound/core/pcm.c
./kernel-3.10/sound/core/pcm_lib.c
./kernel-3.10/sound/core/pcm_native.c
./kernel-3.10/sound/soc/soc-core.c
./kernel-3.10/sound/soc/soc-pcm.c
./kernel-3.10/sound/core/sound.c
Tinyalsa源码文件:
./external/tinyalsa/pcm.c
2.1. 创建 PCM逻辑设备:
在Linux 音频驱动(四) ASoC音频驱动之Machine驱动中我们给出了注册声卡的完整时序图。现在简化该时序图,重点看一下其中创建PCM逻辑设备的过程。
(为了和原时序图保持一致,没有更改本时序图里的时序编号)
snd_register_device_for_dev()创建pcmCxDxp、pcmCxDxc设备节点的过程如下:
- 首先,分配并初始化一个snd_minor结构中的各字段;
type:SNDRV_DEVICE_TYPE_PCM_PLAYBACK/SNDRV_DEVICE_TYPE_PCM_CAPTURE
card:card的编号
device:pcm实例的编号,大多数情况为0
f_ops:pcmCxDxp、pcmCxDxc设备节点的文件操作函数集,为snd_pcm_f_ops[*]
private_data:指向该snd_pcm的实例对象 - 根据type,card和pcm的编号,确定数组的索引值minor,minor也作为pcm设备的次设备号;
- 把该snd_minor结构的地址放入全局数组snd_minors[minor]中;
- 最后,调用device_create创建设备节点。
// ./kernel-3.10/sound/core/sound.c, line 57
static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
// ./kernel-3.10/sound/core/sound.c, line 269
int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops,
void *private_data, const char *name, struct device *device)
{
int minor;
struct snd_minor *preg;
......
preg = kmalloc(sizeof *preg, GFP_KERNEL);
if (preg == NULL)
return -ENOMEM;
preg->type = type;
preg->card = card ? card->number : -1;
preg->device = dev;
preg->f_ops = f_ops;
preg->private_data = private_data;
preg->card_ptr = card;
mutex_lock(&sound_mutex);
......
minor = snd_find_free_minor(type);
......
snd_minors[minor] = preg;
preg->dev = device_create(sound_class, device, MKDEV(major, minor),
private_data, "%s", name);
......
}
注1:C0D0代表的是Card 0 Device 0,即声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。
注2:snd_minors[]非常重要,用于保存声卡下某个逻辑设备的上下文信息,它在逻辑设备建立阶段被填充,在逻辑设备被使用时就可以从该结构体中得到相应的信息。
注3:sound_class 是s