control的主要用于mixer。它能被用户空间存取,从而读写CODEC相关寄存器,可以控制amix指令,它用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 */
const 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的类型,alsa定义了几种类型(SNDDRV_CTL_ELEM_IFACE_XXX),常用的类型是MIXER,当然也可以定义属于全局的CARD类型,也可以定义属于某类设备的类型,
#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */
#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */
#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */
#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */
#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */
#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */
#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */
#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
name字段是该control的名字,从ALSA 0.9.x开始,control的名字是变得比较重要,因为control的作用是按名字来归类的。ALSA已经预定义了一些control的名字,我们再Control Name一节详细讨论。
control的名字需要遵循一些标准,通常可以分成3部分来定义control的名字:源--方向--功能。
源,可以理解为该control的输入端,alsa已经预定义了一些常用的源,例如:Master,PCM,CD,Line等等。
方向,代表该control的数据流向,例如:Playback,Capture,Bypass,Bypass Capture等等,也可以不定义方向,这时表示该Control是双向的(playback和capture)。
功能,根据control的功能,可以是以下字符串:Switch,Volume,Route等等
index字段用于保存该control的在该卡中的编号。如果声卡中有不止一个codec,每个codec中有相同名字的control,这时我们可以通过index来区分这些controls。当index为0时,则可以忽略这种区分策略。
access字段包含了该control的访问类型。每一个bit代表一种访问类型,这些访问类型可以多个“或”运算组合在一起。
Access字段是一个bitmask,它保存了改control的访问类型。默认的访问类型是:SNDDRV_CTL_ELEM_ACCESS_READWRITE,表明该control支持读和写 *** 作。如果access字段没有定义(.access==0),此时也认为是READWRITE类型。
如果是一个只读control,access应该设置为:SNDDRV_CTL_ELEM_ACCESS_READ,这时,我们不必定义put回调函数。类似地,如果是只写control,access应该设置为:SNDDRV_CTL_ELEM_ACCESS_WRITE,这时,我们不必定义get回调函数。
如果control的值会频繁地改变(例如:电平表),我们可以使用VOLATILE类型,这意味着该control会在没有通知的情况下改变,应用程序应该定时地查询该control的值。
#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */
#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */
#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */
#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */
#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */
#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* kernel use a TLV callback */
#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */
private_value字段包含了一个任意的长整数类型值。该值可以通过info,get,put这几个回调函数访问。你可以自己决定如何使用该字段,例如可以把它拆分成多个位域,又或者是一个指针,指向某一个数据结构。
tlv字段为该control提供元数据
.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_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) }
/*
* DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
*/
static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0);
相关的回调函数
info回调函数用于获取control的详细信息。
get回调函数用于读取control的当前值,并返回给用户空间的应用程序。
put回调函数用于把应用程序的控制值设置到control中。
元数据
这里指的是.tlv.p = (tlv_array), 也就是如下函数
DECLARE_TLV_DB_SCALE宏定义的mixer control,它所代表的值按一个固定的dB值的步长变化。该宏的第一个参数是要定义变量的名字,第二个参数是最小值,以0.01dB为单位。第三个参数是变化的步长
DECLARE_TLV_DB_LINEAR宏定义的mixer control,它的输出随值的变化而线性变化。 该宏的第一个参数是要定义变量的名字,第二个参数是最小值,以0.01dB为单位。第二个参数是最大值
#define TLV_DB_SCALE_MASK 0xffff
#define TLV_DB_SCALE_MUTE 0x10000
#define TLV_DB_SCALE_ITEM(min, step, mute) \
TLV_ITEM(SNDRV_CTL_TLVT_DB_SCALE, \
(min), \
((step) & TLV_DB_SCALE_MASK) | \
((mute) ? TLV_DB_SCALE_MUTE : 0))
#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
/* linear volume between min_dB and max_dB (.01dB unit) */
#define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \
TLV_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB))
#define DECLARE_TLV_DB_LINEAR(name, min_dB, max_dB) \
unsigned int name[] = { TLV_DB_LINEAR_ITEM(min_dB, max_dB) }
代码调用
snd_soc_init
--》platform_driver_register
--》soc_probe
--》snd_soc_register_card
--》snd_soc_instantiate_card
--》snd_card_new create and initialize a soundcard structure
--》 snd_ctl_create create control core:
--》snd_soc_add_card_controls add an array of controls to a SoC card.
--》snd_soc_add_controls
--》 snd_soc_cnew
--》snd_ctl_new1 create a control instance from the template
--》 snd_ctl_add add the control instance to the card
snd_soc_add_platform_controls Add an array of controls to a component.
--》snd_soc_add_controls
--》 snd_soc_cnew
--》snd_ctl_new1 create a control instance from the template
--》 snd_ctl_add add the control instance to the card
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)