前面几章分析了Codec、Platform、Machine驱动的组成部分及其注册过程,这三者都是物理设备相关的,大家应该对音频物理链路有了一定的认知。接着分析音频驱动的中间层,由于这些并不是真正的物理设备,故我们称之为逻辑设备。
PCM逻辑设备,我们又习惯称之为PCM中间层或pcm native,起着承上启下的作用:往上是与用户态接口的交互,实现音频数据在用户态和内核态之间的拷贝;往下是触发codec、platform、machine的操作函数,实现音频数据在dma_buffer<-> cpu_dai <-> codec之间的传输。
后面章节将会对这个过程详细分析,这里还是先从声卡的注册谈起。
声卡驱动中,一般挂载着多个逻辑设备,看看我们计算机的声卡驱动有几个逻辑设备:
$ cat /proc/asound/devices
1: : sequencer
2: [ 0- 7]: digital audio playback
3: [ 0- 3]: digital audio playback
4: [ 0- 2]: digital audio capture
5: [ 0- 0]: digital audio playback
6: [ 0- 0]: digital audio capture
7: [ 0- 3]: hardware dependent
8: [ 0- 0]: hardware dependent
9: [ 0] : control
33: : timer
· digital audio playback:用于回放的PCM设备
· digital audio capture:用于录制的PCM设备
· control:用于声卡控制的CTL设备,如通路控制、音量调整等
· timer:定时器设备
· sequencer:音序器设备
嵌入式系统中,通常我们更关心PCM和CTL这两种设备。
设备节点如下:
$ ll /dev/snd
drwxr-xr-x 3 root root 260 Feb 26 13:59 ./
drwxr-xr-x 16 root root 4300 Mar 6 17:07 ../
drwxr-xr-x 2 root root 60 Feb 26 13:59 by-path/
crw-rw---T+ 1 root audio 116, 9 Feb 26 13:59 controlC0
crw-rw---T+ 1 root audio 116, 8 Feb 26 13:59 hwC0D0
crw-rw---T+ 1 root audio 116, 7 Feb 26 13:59 hwC0D3
crw-rw---T+ 1 root audio 116, 6 Feb 26 13:59 pcmC0D0c
crw-rw---T+ 1 root audio 116, 5 Mar 6 19:08 pcmC0D0p
crw-rw---T+ 1 root audio 116, 4 Feb 26 13:59 pcmC0D2c
crw-rw---T+ 1 root audio 116, 3 Feb 26 13:59 pcmC0D3p
crw-rw---T+ 1 root audio 116, 2 Feb 26 13:59 pcmC0D7p
crw-rw---T+ 1 root audio 116, 1 Feb 26 13:59 seq
crw-rw---T+ 1 root audio 116, 33 Feb 26 13:59 timer
可以看到这些设备节点的Major=116,Minor则与/proc/asound/devices所列的对应起来,都是字符设备。上层可以通过open/close/read/write/ioctl等系统调用来操作声卡设备,和其他字符设备类似,但一般情况下我们使用已封装好的用户接口库如tinyalsa、alsa-lib。
6.1. 声卡结构概述
回顾下ASoC是如何注册声卡的,详细请参考章节5.ASoC machine driver,这里仅简单陈述下:
· Machine驱动初始化时,name="soc-audio"的platform_device与platform_driver匹配成功,触发soc_probe()调用;
· 继而调用snd_soc_register_card(),该函数做的事情很多:
1. 为每个音频物理链路找到对应的codec、codec_dai、cpu_dai、platform设备实例,完成dai_link的绑定;
2. 调用snd_card_create()创建声卡;
3. 依次回调cpu_dai、codec、platform的probe()函数,完成物理设备的初始化;
· 随后调用soc_new_pcm()创建pcm逻辑设备:
1. 设置pcm native中要使用的pcm操作函数,这些函数用于操作音频物理设备,包括machine、codec_dai、cpu_dai、platform;
2. 调用snd_pcm_new()创建pcm设备,回放子流实例和录制子流实例都在这里创建;
3. 回调platform驱动的pcm_new(),完成音频dma设备初始化和dma buffer内存分配;
· 最后调用snd_card_register()注册声卡。
关于音频物理设备部分(Codec/Platform/Machine)不再累述,下面详细分析声卡和PCM逻辑设备的注册过程。
上面提到声卡驱动上挂着多个逻辑子设备,有pcm(音频数据流)、control(混音器控制)、midi(迷笛)、timerÿ