您当前的位置: 首页 >  linux
  • 3浏览

    0关注

    417博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

08.音频系统:第003课_Linux音频驱动程序:第004节_声卡控制之kcontrol

江南才尽,年少无知! 发布时间:2019-04-16 18:16:39 ,浏览量:3

一个芯片之中有多个寄存器,一个寄存器里,某些位用来表示某个功能。如下,那我们要分析的kcontrol是表示一个功能,还是表示一个寄存器呢?当然使用kcontrol表示一个功能比较好,如下: 在这里插入图片描述 在打开某个功能的时候,我们去操作某个kcontrol就可以了。显然我们找到了kcontrol的核心,寄存器的某些位来表示一个功能,其可能是一个位,也可能是多个位,显然这些位的读写函数都是各不相同。kcontrol中有自己的读写函数。如上图我们做些简单的总接: 1.一个声卡有多个kcontrol 2.一个kcontrol对应一个功能,如:音量,开关,录音。 3.kcontrol中有函数设置功能 下面我们开始分析代码,打开rt5651.c文件,找到:

static const struct snd_kcontrol_new rt5651_snd_controls[] = {
	//后续进行粘贴
	......
	......
};

可以发现该结构体rt5651_snd_controls,被snd_soc_codec_driver结构体的controls成员所指向:

static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
	.controls = rt5651_snd_controls,
	.num_controls = ARRAY_SIZE(rt5651_snd_controls),
}
snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,rt5651_dai, ARRAY_SIZE(rt5651_dai));
	/*通过machine最终导致snd_soc_register_card被调用*/
	ret = snd_soc_register_card(card);
		/*在该函数内,会做很多工作,如绑定dai等等*/
		ret = snd_soc_instantiate_card(card);
			snd_soc_add_card_controls(card, card->controls, card->num_controls);
				snd_soc_add_controls(card, soc_card->dev, controls, num_controls,NULL, soc_card);
					const struct snd_kcontrol_new *control = &controls[i];
					snd_ctl_add(card, snd_soc_cnew(control, data,control->name, prefix));
						list_add_tail(&kcontrol->list, &card->controls);
						

可以知道soc_codec_dev_rt5651会被snd_soc_register_codec函数注册。最终被添加到&kcontrol->list列表之中,这个列表挂载着一堆snd_kcontrol *kcontrol,如下: 在这里插入图片描述 我们看看snd_kcontrol 结构体存在什么东西:

struct snd_ctl_elem_id {
	unsigned int numid;		/* numeric identifier, zero = invalid */
	snd_ctl_elem_iface_t iface;	/* interface identifier */
	unsigned int device;		/* device/client number */
	unsigned int subdevice;		/* subdevice (substream) number */
	unsigned char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];		/* ASCII name of item */
	unsigned int index;		/* index of item */
};
struct snd_kcontrol {
	struct snd_ctl_elem_id id;
	unsigned int count;		/* count of same elements:相同元素个数 */
	snd_kcontrol_info_t *info;//获得kcontrol的信息
	snd_kcontrol_get_t *get//获得kcontrol的值(寄存器的一些值)
	snd_kcontrol_put_t *put;//设置kcontrol的值(寄存器的值)
	unsigned long private_value;//该值为给上面3个函数使用
	void *private_data;//该值为给上面3个函数使用(如指定寄存器的那些未等等)
}

那么以上的值,如struct snd_ctl_elem_id id,寄存器等等都是由我们芯片的驱动程序提供: 在这里插入图片描述 芯片驱动中有一系列的snd_kcontrol_new,用他们构造snd_kcontrol,然后添加到声卡之中。每个snd_kcontrol_new都存在snd_kcontrol_info_t *info,snd_kcontrol_get_t *get,snd_kcontrol_put_t *put;等等。 我了我们编写的方便,其提供了多个类似于SOC_DOUBLE_TLV,SOC_DOUBLE,SOC_DOUBLE等宏。

static const struct snd_kcontrol_new rt5651_snd_controls[] = {
	/* Headphone Output Volume */
	SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL,
		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
	/* OUTPUT Control */
	SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1,
		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),

	/* DAC Digital Volume */
	SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL,
		RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1),
	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL,
			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
			175, 0, dac_vol_tlv),
	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
			175, 0, dac_vol_tlv),
	/* IN1/IN2 Control */
	SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
		RT5651_BST_SFT1, 8, 0, bst_tlv),
	SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
		RT5651_BST_SFT2, 8, 0, bst_tlv),
	/* INL/INR Volume Control */
	SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
			RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
			31, 1, in_vol_tlv),
	/* ADC Digital Volume Control */
	SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL,
		RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1),
	SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL,
			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
			127, 0, adc_vol_tlv),
	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA,
			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
			127, 0, adc_vol_tlv),
	/* ADC Boost Volume Control */
	SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL,
			RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT,
			3, 0, adc_bst_tlv),

	/* RT5651 ASRC Switch */
	SOC_ENUM_EXT("RT5651 ASRC Switch", rt5651_asrc_enum,
		     rt5651_asrc_get, rt5651_asrc_put),
	/* ASRC */
	SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1,
		RT5651_STO1_T_SFT, 1, 0),
	SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1,
		RT5651_STO2_T_SFT, 1, 0),
	SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1,
		RT5651_DMIC_1_M_SFT, 1, 0),

	SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum),
	SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum),
};

我们进入SOC_DOUBLE_TLV宏:

#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
	.tlv.p = (tlv_array), \
	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
	.put = snd_soc_put_volsw, \
	.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
					  max, invert, 0) }

这个宏会帮我们实现info,put ,以及private_value函数,以及私有数据的构造,其私有数据存放的是SOC_DOUBLE_VALUE,其为一个结构体,如下:

#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \
	((unsigned long)&(struct soc_mixer_control) \
	{.reg = xreg, .rreg = xreg, .shift = shift_left, \
	.rshift = shift_right, .max = xmax, .platform_max = xmax, \
	.invert = xinvert, .autodisable = xautodisable})

其指定了: reg :寄存开始,,rreg :寄存器结束,,shift_left:从哪一位开始shift_right:从那一位结束,xmax:用几位来表示 等等信息,这是一个简单的例子。 在开发板上执行tinymix,其会列举出所有的: 在这里插入图片描述

可以看到第一个"HP Playback Volume"与驱动程序的

SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL,RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),

相对应,其他的也是一样,依次如此。我们可以用过其序列,也可以通过其名字,其做控制。如: tinymix “OUT Playback Volume” 得到: OUT Playback Volume: 31 31 (range 0->39) 执行: tinymix “OUT Playback Volume” 10 可以把其设置为10,然后再执行 tinymix “OUT Playback Volume” 可以把名字换成序列,即1,2,3,4,5等等。

前面提到snd_kcontrol 中存成员unsigned int count,代表有多少个元素,也就是说可以存在多个snd_ctl_elem_id,如果第一个snd_kcontrol 的snd_ctl_elem_id为1,count为3,name第二个snd_kcontrol 的snd_ctl_elem_id就要从3开始。

下面我们做一些总结: 在这里插入图片描述

关注
打赏
1592542134
查看更多评论
立即登录/注册

微信扫码登录

0.0956s