Asoc dapm(一) - kcontrol
来源:互联网 发布:印度经济 知乎 编辑:程序博客网 时间:2024/06/05 23:52
- Asoc dapm(一) - kcontrol
- Asoc dapm(二) - kcontrol注册与使用
- Asoc dapm(三) - dapm widgets & dapm kcontrol & dapm route
- Asoc dapm(四) - dapm widgets & dapm route注册
- Asoc dapm(五) - dapm widget链表更新
struct snd_kcontrol_new
struct snd_kcontrol_new { snd_ctl_elem_iface_t iface; /* interface identifier */ unsigned int device; /* device/client number */ unsigned int subdevice; /* subdevice (substream) number */ unsigned char *name; /* ASCII name of item */ unsigned int index; /* index of item */ unsigned int access; /* access rights */ unsigned int count; /* count of same elements */ snd_kcontrol_info_t *info; snd_kcontrol_get_t *get; snd_kcontrol_put_t *put; union { snd_kcontrol_tlv_rw_t *c; const unsigned int *p; } tlv; unsigned long private_value;};
iface:control类型,通常是SNDRV_CTL_ELEM_IFACE_MIXER
name:kcontrol的名字,名字的命名规则遵循”源-方向-功能”
源可理解为control的输入端,如Master, PCM, CD, line等
方向代表kcontrol的数据流向,如Playback, Capture, Bypass, 也可以不定义,这时是双向的
功能,如Switch, Volume, Route等
通常会借助include/sound/soc.h文件中的宏来定义这个结构体,比如SOC_SINGLE等。
另外info, get, put三个字段是一些回调函数,常常使用sound/soc/soc-core.c文件提供的函数,而不用自己去实现。
kcontrol与dapm kcontrol区别
kcontrol通常用于控件的音量等控制,而dapm kcontrol相关的kcontrol则是用于widget电源管理的开关。
一些构造snd_kcontrol_new结构体的宏
SOC_SINGLE
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ .invert = xinvert})#define SOC_SINGLE(xname, reg, shift, max, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .put = snd_soc_put_volsw, \ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
SOC_SINGLE定义最简单的控件,这种控件只有一个控制量,比如一个开关,或者是数值的变化(比如codec中的某个频率,FIFO大小等)
参数:xname(该控件的名字),reg(该控件对应的寄存器的地址),shift(控制位在寄存器中的位移),max(控件可设置的最大值),invert(设定值是否取反)
SOC_SINGLE_VALUE宏定义private_value字段,目的主要是为了填充struct soc_mixer_control结构体
当上层调用info, get, put函数的时候可以将kcontrol->private_value强制转换为struct soc_mixer_control类型,然后使用这个结构体中的reg, shift, max等数据。
SOC_SINGLE_TLV
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ .invert = xinvert})#define SOC_SINGLE_TLV(xname, reg, shift, 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_SINGLE_VALUE(reg, shift, max, invert) }
该宏和SOC_SINGLE类似,唯一不同的是增加了tlv.p字段,适用于那些以dB为单位的kcontrol。
DECLARE_TLV_DB_SCALE(name, min, step, mute)宏来构造变量tlv_array。
参数name是变量的名字,min是最小值,step是步进值,如果mute=1,当该kcontrol处于最小值时会mute。
来看一个实例:
/* from 0 to 30 dB in 2 dB steps */static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0);static const struct snd_kcontrol_new uda1380_snd_controls[] = {...SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */}
寄存器UDA1380_ADC的偏移8bit处定义了”Mic Capture Volume”,寄存器最大值为15,对应到dB的最小值是0dB,步进值是200*0.01dB=2dB,最大值是15*2dB=30dB
如上这样,寄存器的值与实际增益控制就有一个映射关系了。
SOC_ENUM
#define SOC_ENUM(xname, xenum) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ .info = snd_soc_info_enum_double, \ .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ .private_value = (unsigned long)&xenum }#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ .max = xmax, .texts = xtexts }#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \ SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)//xtexts就是mux或者mixer多个输入源的名字,是字符串数组
SOC_ENUM可以用来定义mux, mixer等有多个输入的控件。
SOC_ENUM_SINGLE或SOC_ENUM_DOUBLE用来构造SOC_ENUM中的private_value字段。当info、get、put函数被调用时,会将这个private_value转化成struct soc_enum结构体类型来对数据进行处理。
对于mixer
static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", "Minimum2", "Maximum"};static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};static const char *uda134x_mixmode[] = {"Differential", "Analog1", "Analog2", "Both"};static const struct soc_enum uda134x_mixer_enum[] = {SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),};static const struct snd_kcontrol_new uda1341_snd_controls[] = {...SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),}
通过SOC_ENUM(“Sound Processing Filter”, uda134x_mixer_enum[0])定义了名为“Sound processing Filter”的mixer控件
从SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting)看出通过配置寄存器UDA134X_DATA010可以控制这个mixer控件的四个输入源”Flat”, “Minimum1”, “Minimum2”, “Maximum”,输入源可以选择其中的一个或者多个。
对于mux
对于mux也类似,如SOC_ENUM(“Input Mux”, uda134x_mixer_enum[2]),只不过mux一个时候只能有一个输入源,即”Differential”, “Analog1”, “Analog2”, “Both”中只能选择一个。
SOC_ENUM_EXT
#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \{ .max = xmax, .texts = xtexts }#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_ext, \ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&xenum }
SOC_ENUM_EXT与SOC_ENUM宏很类似,但是,SOC_ENUM中构造private_value字段使用SOC_ENUM_SINGLE或者SOC_ENUM_DOUBLE,这两个宏构造的时候都和具体寄存器的某个或者某两个bit相关,而SOC_ENUM_EXT中构造private_value字段使用SOC_ENUM_SINGLE_EXT,这个宏构造的时候只要初始化字符串数组就行了。
static const char *rt5659_micbias2_power_mode[] = { "Disable", "Enable"};static const struct soc_enum rt5659_micbias2_power_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rt5659_micbias2_power_mode), rt5659_micbias2_power_mode);static int rt5659_micbias2_power_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int pwr = snd_soc_read(codec, RT5659_PWR_ANLG_2); if (pwr & 0x0400) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; return 0;}static int rt5659_micbias2_power_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int pwr = ucontrol->value.integer.value[0]; if (pwr == 1) { snd_soc_update_bits(codec, RT5659_PWR_ANLG_3, 0x0002, 0x0002); snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, 0x0200, 0x0200); snd_soc_update_bits(codec, RT5659_PWR_ANLG_2, 0x0400, 0x0400); dev_info(codec->dev, "enable micbias2 power\n"); } else { snd_soc_update_bits(codec, RT5659_PWR_ANLG_3, 0x0002, 0x0000); snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, 0x0200, 0x0000); snd_soc_update_bits(codec, RT5659_PWR_ANLG_2, 0x0400, 0x0000); dev_info(codec->dev, "disable micbias2 power\n"); } return 0;}SOC_ENUM_EXT("micbias2 power", rt5659_micbias2_power_enum, rt5659_micbias2_power_get, rt5659_micbias2_power_put),
SOC_VALUE_ENUM
SOC_VALUE_ENUM 用于定义带values字段的snd_kcontrol_new结构体
SOC_VALUE_ENUM_SINGLE和SOC_VALUE_ENUM_DOUBLE 用于定义带values字段的soc_enum结构体
SOC_DOUBLE
SOC_SINGLE在寄存器中只控制一个变量,通常用于单声道;而SOC_DOUBLE可以同时在一个寄存器中控制两个相似的变量,通常是对左右声道的控制,用于立体声。
SOC_DOUBLE_R
与SOC_DOUBLE类似,用于左右声道的控制不在一个寄存器中的情况,参数中指定两个寄存器地址
SOC_DOUBLE_TLV
SOC_DOUBLE_R_TLV
其他
下面这些带EXT的宏需要我们自己定义get, put函数
SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert, xhandler_get, xhandler_put)
SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert, xhandler_get, xhandler_put)
SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert, xhandler_get, xhandler_put, tlv_array)
SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, xhandler_get, xhandler_put, tlv_array)
SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, xhandler_get, xhandler_put, tlv_array)
SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put)
参考文章
- ALSA声卡驱动中的DAPM详解之一:kcontrol
- Asoc dapm(一) - kcontrol
- Asoc dapm(一) - kcontrol
- Asoc dapm(三) - dapm widgets & dapm kcontrol & dapm route
- Asoc dapm(二) - kcontrol注册与使用
- asoc dapm相关
- Asoc dapm(四) - dapm widgets & dapm route注册
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- DAPM之二:audio paths与dapm kcontrol
- google支付接口被刷以及解决方案
- mysqldump: Couldn't execute 'SET OPTION SQL_QUOTE_SHOW_CREATE=1'
- 【c#笔记】网页数据抓取
- SpringMVC Ajax例子
- 我的职业观
- Asoc dapm(一) - kcontrol
- flume+kafka+smart数据接入实施手册
- C#+Jquery实现省地市三级联动下拉
- Yarn HA解决方案
- spark1.5 scala.collection.mutable.WrappedArray$ofRef cannot be cast to ...解决办法
- maven 项目异地导如出错,pom文件报错,jar文件无法下载
- C++ 用户自定义类型
- Android编译系统
- jsp页面 上传图片预览 的处理