【基于Linux4.19.X内核】Linux ALSA-ASoC驱动框架(一、Machine驱动框架及部分数据结构)

一、一般规定

  • 一般的platform\codec驱动通常是可重用的,Machine驱动不行,Machine驱动通常包含了如耳机检测、gpio控功放等。
  • DAPM:Dynamic Audio Power Management,Linux ALSA 音频子系统的动态音频电源管理,用于音频通路自动开关、省电。

二、Machine驱动职责一般包含以下内容

  • 使用适当的CPU和codec DAI填充struct snd_soc_dai_link结构体。
  • codec编解码器时钟设置(如果有的话),编解码器codec主从配置,一般放在.hw_params回调里。

  • DAPM:Dynamic Audio Power Management 动态音频电源管理。
  • 将运行时的采样频率传输到codec驱动程序。
c 复制代码
//这里只是举例了一些常用或必要的结构体成员
struct snd_soc_dai_link {
	//1.必选
	/* Codec name */
	const char *name; //任意设置			
	/* Stream name */
	const char *stream_name;  //该链接的流名称		
	/* You MUST specify the DAI name within the codec */
	const char *codec_dai_name; //必须与codec驱动中struct snd_soc_dai_driver下的.name字段相匹配!!!	
	//2.可选
	/* machine stream operations */
	const struct snd_soc_ops *ops;	
	/*
	 * You MUST specify the link's codec, either by device name, or by
	 * DT/OF node, but not both.
	 */
	const char *codec_name;	 //一般是struct platform_driver下.driver.name或
	i2c_driver下.driver.name
	/* This DAI link can route to other DAI links at runtime (Frontend)*/
	unsigned int dynamic:1;	
	/* pmdown_time is ignored at stop */
	unsigned int ignore_pmdown_time:1;	
	/* DPCM capture and Playback support */
	unsigned int dpcm_capture:1;
	unsigned int dpcm_playback:1;
	/*
	 * You MAY specify the link's platform/PCM/DMA driver, either by
	 * device name, or by DT/OF node, but not both. Some forms of link
	 * do not need a platform.
	 */
	const char *platform_name;	
	/* Do not create a PCM for this DAI link (Backend link) */
	unsigned int no_pcm:1;	
	/* optional hw_params re-writing for BE and FE sync */
	int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
			struct snd_pcm_hw_params *params);	
	//3.可不需要
	/*
	 * You MAY specify the DAI name of the CPU DAI. If this information is
	 * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
	 * only, which only works well when that device exposes a single DAI.
	 */
	const char *cpu_dai_name;	//	必须和platform驱动中struct snd_soc_dai_driver下的.name字段相匹配(可以都不填充)!!!
	/* codec/machine specific init - e.g. add machine controls */
	int (*init)(struct snd_soc_pcm_runtime *rtd);	//DAI链接初始化回调函数
}

四、struct snd_soc_card 声卡数据结构

c 复制代码
/* SoC card */
struct snd_soc_card {
	const char *name; //声卡名
	struct module *owner; //一般填写THIS_MODULE
	/* CPU <--> Codec DAI links  */
	struct snd_soc_dai_link *dai_link;	//组成此声卡的DAI链接的数组,如"imx_wm8960_dai"
	int num_links; //组成此声卡的DAI链接的数组的大小
	const struct snd_kcontrol_new *controls; //数组,机器驱动程序设置的控件(在IMX6ULL上没有设置)
	int num_controls; // 机器驱动程序设置的控件的大小
	/*
	 * Card-specific routes and widgets.
	 * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
	 */
	const struct snd_soc_dapm_widget *dapm_widgets;	 // 数组,动态音频电源管理,如"imx_wm8960_dapm_widgets"
	int num_dapm_widgets; //动态音频电源管理数组大小
	struct device *dev; // device,代表声卡对应的设备
	const struct snd_soc_dapm_route *of_dapm_routes; //对应信息在设备树"audio-routing"中,对应成员"sink"和"source"
	int num_of_dapm_routes;	//以IMX6ULL为例,为"audio-routing"的匹配对数
	...
}

声卡名填充

snd_soc_of_parse_card_name(&data->card, "model")使用封装好的该函数,解析dts中的model属性作为声卡名:

Machine驱动下的注册声卡

  • int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) 使用该函数进行声卡注册,该函数在Machine驱动中的"probe"函数中执行
  • 在注册 Machine驱动声卡时,会匹配和调用platform\codec驱动下的"probe"函数。
  • 为成功探测到的DAI链接创建一个新的PCM设备。