machine driver
terminology
硬件特性:所谓的硬件特性指:DAIs 之间的链结;通过某个 GPIO 打开 Amplifier;通过某个 GPIO 检测耳机插拔;使用某个时钟如 MCLK/External OSC 作为 I2S、CODEC 模块的基准时钟源等等
移植性:platform 和 CODEC 驱动一般是可以重用的,而 Machine 有它特定的硬件特性,几乎是不可重用的。
overview
仅有 codec、platform 驱动是不能工作的,需要一个角色把 codec、codec_dai、cpu_dai、pcm_dma 给链结起来才能构成一个完整的音频回路,这个角色就由
machine_drv 承担了。
顺带引入kernel 对应的参考文献可自行了解 目录:Document/sound/alsa/soc/machine.txt
功能特性
链结platform和codec载体
作为一个链结,如上构成音频链路,所需 struct snd_soc_dai_link.承担媒介的作用。对应codec有的codec_name,codec_dai_name成员.对应platform 有platform_name,platform_dai_name成员。
struct snd_soc_dai_link { {
/* config - must be set by machine driver */
const char *name; ; /* Codec name */
const char *stream_name; ; /* Stream name */
const char *codec_name; ; /* for multi-codec */
const struct device_node *codec_of_node ;
const char *platform_name ; /* for multi-platform */
const struct device_node *platform_of_node ;
const char *cpu_dai_name ;
const struct device_node *cpu_dai_of_node ;
const char *codec_dai_name ;
unsigned int dai_fmt ; /* format to set on init */
/* Keep DAI active over suspend */
unsigned int ignore_suspend;
/* Symmetry requirements */
unsigned int symmetric_rates;
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time;
/* codec/machine specific init - e.g. add machine controls */
int (*init )(struct snd_soc_pcm_runtime *rtd );
/* machine stream operations */
struct snd_soc_ops *ops ;
};
个人理解:成员ignore_suspend 以及 ignore_pmdown_time 是针对Android的睡眠唤醒机制,expect snd_soc_dai_link,machine drv可以加入音频控件,音频事件,例如耳机插拔,外部功放的开关,正因有如上(两个成员的支持)可以实现实现在Android浅睡眠(early suspend)的状态下,对插拔的检测。
声卡注册
流程浅析:
在soc_probe中,或许平台私有数据,里面存有snd_soc_card实例,代码如下
static int soc_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
/*
* no card, so machine driver should be registering card
* we should not be here in that case so ret error
*/
if (!card)
return -EINVAL;
dev_warn(&pdev->dev,
"ASoC: machine %s should use snd_soc_register_card()\n",
card->name);
/* Bodge while we unpick instantiation */
card->dev = &pdev->dev;
return snd_soc_register_card(card);
}
snd_soc_register_card()为每个 dai_link 分配一个 snd_soc_pcm_runtime 实例,别忘了之前提过 snd_soc_pcm_runtime是 ASoC 的桥梁,保存着 codec、codec_dai、platform、cpu_dai、pcm_dma 等 runtime devices。每个 snd_soc_pcm_runtime都对应着各自的 dai_link;
随后的工作都在 snd_soc_instantiate_card()进行:
遍历 dai_list、codec_list、platform_list 链表,为每个音频链路匹配 cpu_dai、codec_dai、codec、platform;找到的 cpu_dai、codec_dai、codec、platform 实例保存到 dai_link 对应的 snd_soc_pcm_runtime 中,完成 dai_link 的 runtime devices 绑定工作;
初始化 codec 的寄存器缓存,调用 snd_card_create()创建声卡实例;
soc_probe_dai_link()依次回调 cpu_dai、codec、platform、codec_dai 的 probe()函数,完成各个子设备的初始化,随后调用 **soc_new_pcm()**创建 pcm 实例;
最后调用 snd_card_register()注册声卡。
参考资料:
http://blog.csdn.net/sepnic