1,初始化函数:
snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
ARRAY_SIZE(wm9713_snd_ac97_controls));
首先wm9713_snd_ac97_controls结构体数组的实力化,这个过程是在编译的时候就决定的。是使用宏定义完成的。
(1)涉及到两个结构体,一个是snd_kcontrol_new,另外一个是soc_mixer_control。这两个结构体中涉及的内容就是接下来通过宏定义来初始化的对象。
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;
};
/* mixer control */
struct soc_mixer_control {
int min, max, platform_max;
unsigned int reg, rreg, shift, rshift, invert;
};
(2)宏定义原型:
#define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, 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 = (unsigned long)&(struct soc_mixer_control)
{
.reg = xreg,
.shift = shift_left,
.rshift = shift_right,
.max = xmax,
.platform_max = xmax,
.invert = xinvert
}
}
static const unsigned int out_tlv[] = {
TLV_DB_RANGE_HEAD(2),
/* 0000000 - 0101111 = "Analogue mute" */
0,
48,
TLV_DB_SCALE_ITEM(-25500, 0, 0),
48,
127,
TLV_DB_SCALE_ITEM(-7300, 100, 0),
};
(3)具体实现:
取数组中的第一个成员,具体是怎么替代并且初始化:
SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv)
变形为:
.ifa = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = Speaker Playback Volume,
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ|
SNDRV_CTL_ELEM_ACCESS_READWRITE,
.tlv.p = out_tlv,
.info = snd_soc_info_volsw,
.get = snd_soc_get_volsw,
.put = snd_soc_put_volsw,
.private_value= (unsigned long)&(struct soc_mixer_control)
{
.reg = AC97_MASTER,
.shift = 8,
.rshift = 0,
.max = 1,
.platform_max = 1,
.invert = 31
}
2,初始化过程:
/**
* snd_soc_add_controls - add an array of controls to a codec.
* Convienience function to add a list of controls. Many codecs were
* duplicating this code.
*
* @codec: codec to add controls to
* @controls: array of controls to add
* @num_controls: number of elements in the array
*
* Return 0 for success, else error.
*/
int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls)
参数codec 这个结构体指针是上级传下来的,主要用来找到card这个结构体。
参数controls 指针就是全局定义的wm9713_snd_ac97_controls。
参数num_controls 是数组中实际的数组个数。
其实英语的注释中已经写的很清楚了这里只是简单的翻译一下,在后续分析中还会不断介绍到各自的作用。
函数内容for循环遍历说有的数组中的每一个成员,完成相应的操作。在这个for循环中使用的是:err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
前面介绍了很多snd_kcontrol_new,这段代码中引入了snd_kcontrol。是这个结果在add函数中被使用。snd_soc_cnew这个函数就是分配一下内存空间,这个空间的对象就是snd_kcontrol,而后要注意的是在cardlist中链表中的结构是snd_kcontrol。函数中有这样的一句表述:list_add_tail(&kcontrol->list, &card->controls)。还有三个函数指针同样也要被初始化:
.info = snd_soc_info_volsw,
.get = snd_soc_get_volsw,
.put = snd_soc_put_volsw,
这样的函数作用就是和底层的硬件打交道,通过这些函数实现硬件的操作。其实在这层次中的函数还是进行了封装,目的就是参数再进一步提炼,到了最后调用read write等函数进行读写硬件的寄存器。同时再列出相同功能属性的操作函数:
.info = snd_soc_info_volsw_2r,
.get = snd_soc_get_volsw_2r,
.put = snd_soc_put_volsw_2r,
和
.info = snd_soc_info_volsw_s8,
.get = snd_soc_get_volsw_s8,
.put = snd_soc_put_volsw_s8,
这样的函数操作集很多类型,针对不同的寄存器变量有不同的实现。