DAPM-1 Kcontrol
- 控制部件之kcontrol
- snd_kcontrol_new 结构体
- 如何定义snd_kcontrol_new?
- 如何使用snd_kcontrol?
- 添加kcontrol代码分析
课程:韦东山音频专题
内核:Kernel 3.5
但是我用的实例和课程不同,以防止编程记流水账
控制部件之kcontrol
Kcontrol的核心点:
(1) 一个声卡有多个kcontrol
(2) 一个kcontrol对应一个功能,如调音量,开关录音等
(3) kcontrol中有函数来设置功能
代码分析:
课程实例:
wm8960.c sound\soc\codecs 28499 2019/7/20 459
博客实例:
uda134x.c sound\soc\codecs 16565 2019/7/20 344
snd_kcontrol_new 结构体
#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) }
static const struct snd_kcontrol_new uda1341_snd_controls[] = {
SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
struct snd_kcontrol_new {
...
snd_kcontrol_info_t *info;
snd_kcontrol_get_t *get;
snd_kcontrol_put_t *put;
...
unsigned long private_value;
};
从snd_kcontrol_new 结构体中成员变量:
.info
: 获取kcontrol的信息.get
: 获取kcontrol的值.set
: 设置kcontrol的值.private_value
: 供info, get, set三个函数使用,也许会有寄存器地址以及位偏移信息。
如何定义snd_kcontrol_new?
include\sound\soc.h中有定义了宏来方便定义:
#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("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
#define UDA134X_DATA000 10
如何使用snd_kcontrol?
上层通过ioctl调用kcontrol的file operation函数。
APP: open("/dev/snd/controlC0")
ioctrl -- > snd_ctl_ioctl
case SNDRV_CTL_IOCTL_ELEM_READ:
snd_ctl_elem_read_user(card, argp);
snd_ctl_elem_read(card, control);
kctl = snd_ctl_find_id(card, &control->id); //找到对应的kctrol
result = kctl->get(kctl, control); // .get函数在定义kcontrol时定义
添加kcontrol代码分析
搜索uda1341_snd_controls
看到有在probe()函数中调用。
uda134x_soc_probe(struct snd_soc_codec *codec)
snd_soc_add_codec_controls(codec, uda1341_snd_controls,...)
snd_soc_add_controls()
//snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
snd_ctl_add(card, snd_soc_cnew(control, data, control->name, prefix));
list_add_tail(&kcontrol->list, &card->controls);
snd_soc_cnew(control, data, control->name, prefix)
将 snd_kcontrol_new 构造成 snd_kcontrol,下面来看下这个函数:
snd_soc_cnew(control, data, control->name, prefix)
kcontrol = snd_ctl_new1(&template, data); //create a control instance from the template
snd_ctl_new(&kctl, access); //struct snd_kcontrol kctl;
kctl->vd[idx].access = access;
return kctl;
看来是分配了一个struct snd_kcontrol kctl,然后把snd_kcontrol_new 信息填充进去。