ALSA学习笔记 (4)Control
1. 如何创建一个control
1.1 定义一个snd_kcontrol_new结构体
static struct snd_kcontrol_new my_control __devinitdata = {
.face = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = “PCM Playback Switch”,
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = 0xffff,
.info = my_control_info,
.get = my_control_get,
.put = my_control_put
};
iface 表示control的类型,用SNDRV_CTL_ELEM_IFACE_XXX来定义。例如: CARD, MIXER, PCM等
name 表示control的名字,用户层可以通过这个名字访问这个control
index 存放这个 control 的索引号
access 访问权限的控制,READ,WRITE,READWRITE等
private_value 特定control的私有数据,例如可以存放寄存器地址信息
1.2 回调函数
1.2.1 info 函数
用于得到对应control的详细信息,需要把信息存入snd_ctl_elem_info 对象中。
struct snd_ctl_elem_info {
struct snd_ctl_elem_id id; /* W: element ID */
snd_ctl_elem_type_t type; /* R: value type - SNDRV_CTL_ELEM_TYPE_* */
unsigned int access; /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */
unsigned int count; /* count of values */
__kernel_pid_t owner; /* owner's PID of this control */
union {
struct {
long min; /* R: minimum value */
long max; /* R: maximum value */
long step; /* R: step (0 variable) */
} integer;
struct {
long long min; /* R: minimum value */
long long max; /* R: maximum value */
long long step; /* R: step (0 variable) */
} integer64;
struct {
unsigned int items; /* R: number of items */
unsigned int item; /* W: item number */
char name[64]; /* R: value name */
__u64 names_ptr; /* W: names list (ELEM_ADD only) */
unsigned int names_length;
} enumerated;
unsigned char reserved[128];
} value;
union {
unsigned short d[4]; /* dimensions */
unsigned short *d_ptr; /* indirect - obsoleted */
} dimen;
unsigned char reserved[64-4*sizeof(unsigned short)];
};
其中value的值是一个共用体,根据control的类型,确定值的类型:
包括BOOLEAN,INTEGER,ENUMERATED,BYTES等类型,下面以BOOLEAN和ENUMRATED为例定义info回调函数。
static int snd_myctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
Static int snd_myctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static char *texts[4] ={
“First”,“Second”,“Third”,“Fourth”
};
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMRATED;
uinfo->count = 1;
uinfo->value.enumerated.item = 3;
strcpy(uinfo->value.enumerated.name,texts[uinfo->value.enumerated.item]);
return 0;
}
1.2.2 get 函数
这个函数用来读取当前 control 的值并返回到用户空间
需要把值放在snd_ctl_elem_value结构体中,与info结构体类似,value字段是一个共用体,与类型相关。
如果value的cont大于1, 需要把值全部放入到 value[]数组中。
static int snd_myctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct mychip *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = get_some_value(chip);
return 0;
}
1.2.3 put 函数
主要是从用户空间写一个值
static int snd_myctrl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct mychip *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
if (chip->current_value != ucontrol->value.integer.value[0]){
change_current_value(chip,ucontrol->value.integer.value[0]);
changed = 1;
}
return changed;
}
1.3 创建并添加一个 snd_kcontrol
snd_ctl_new1用于分配一个snd_kcontrol实例,把snd_kcontrol_new中的成员赋值给snd_kcontrol实例,另外需要传入private_data 的指针
snd_ctl_add 把给定的 control 组件添加到 card 里面
if ((err = snd_ctl_add(card, snd_ctl_new1(&my_control, chip))) < 0)
return err;