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;