- 論壇徽章:
- 0
|
第六章
控制接口
翻譯:creator
sz111@126.com
概要
控制接口非常廣泛的應(yīng)用在許多轉(zhuǎn)換,變調(diào)等場合,可以從用戶空間進(jìn)行控制;煲羝鹘涌谑且粋(gè)最重要的接口。換句話說,在ALSA0.9.x版本,所有的混音器的工作都是通過控制接口API實(shí)現(xiàn)的(在0.5.x版本混音器內(nèi)核API是獨(dú)立出來的)。
ALSA有一個(gè)定義很好的AC97的控制模塊。如果你的聲卡僅僅支持AC97,你可以忽略這章。
控制接口定義
為了創(chuàng)建一個(gè)新的控制接口,需要定義三個(gè)函數(shù):info,get和put。然后定義一個(gè)snd_kcontrol_new類型的記錄,例如:
Example6-1.定義一個(gè)控制接口
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
};
大部分情況是通過snd_ctl_new1()來創(chuàng)建control,這種情況下,你可以像上面一樣,在定義的前面加上__devinitdata前綴.
iface字段表示control的類型,如:SNDRV_CTL_ELEM_IFACE_XXX,通常情況都是MIXER。CARD表示一個(gè)全局控制,而不是混音器的一部分。假如control和聲卡設(shè)備聯(lián)系的非常緊密,如HWDEP,RAMDIDI,TIMER或SEQUENCER,需要特別通過device和subdevice字段標(biāo)識出。
name字段是表示名稱的標(biāo)識符。在ALSA0.9.X,控制單元名字是非常重要的,因?yàn)榈慕巧褪峭ㄟ^它的名字進(jìn)行分類。有一些預(yù)定義的標(biāo)準(zhǔn)的control名字。詳細(xì)描述請參考下節(jié)的“控制單元名字”。
index字段存放這個(gè)control的索引號。假如一個(gè)名字下面有多個(gè)不同的control,就要通過index(索引)來區(qū)分了。這是當(dāng)一個(gè)聲卡擁有多個(gè)解碼的時(shí)候才會用到。加入索引設(shè)定為零,就可以忽略定義。
access字段包括了控制接口的存取控制。提供了一些位的組合,如:SNDRV_CTL_ELEM_XXX。詳細(xì)描述請參考“接口標(biāo)志位”一節(jié)。
private_value字段這個(gè)記錄的一個(gè)專有的的長整型變量。當(dāng)調(diào)用info,get和put函數(shù)的時(shí)候,可以通過這個(gè)字段傳遞一些參數(shù)值。如果參數(shù)都是些很小的數(shù),可以把它們通過移位來組合,也可以存放一個(gè)指向一個(gè)記錄的指針(因?yàn)樗情L整型的)。
另外三個(gè)在回調(diào)函數(shù)一節(jié)介紹。
控制接口名字
有一些control名字的標(biāo)準(zhǔn)。一個(gè)control通常根據(jù)“源,方向,功能”三部分來命名。
首先,SOURCE定義了control的源,是一個(gè)字符串,如:“Master”,“PCM”,“CD”,“Line”。已經(jīng)有很多預(yù)定義好的“源”了。
第二,“方向”則為“Playbck”,“Capture”,“Bypass
Playback”,“Bypass
Capture”;蛘,它如果省略,那就表示播放和錄音雙向。
第三個(gè),“功能”。根據(jù)控制接口的功能不同有下面三個(gè):“Switch”,“volume”,“route”。
一些控制接口名字的范例如下:“Master
Capture Switch”,“PCM
Playback Volume”.
也有一些不是采用“源,方向,功能”三部分來命名方式:
全局錄音和播放
“Capture
Source”,“Capture
Switch”和“Capture
Volume”用來做全局錄音(輸入)源,開關(guān),和音量的控制!癙layback
Switch”和“Playback
Volume”用來做全局的輸出開關(guān)和音量控制。
音調(diào)控制
音調(diào)開關(guān)和音量名稱形式為“Tone
Control-XXX”。如:“Tone
Control-Switch”,“Tone
Control – Bass”,“Tone
Control – Center”。
3D控制
3D控制開關(guān)和音量命名形式為“3D
Control – XXX”。如:“3D
Control – Switch”,“3D
Control – Switch”,“3D
Control – Center”,“3D Control – Space”。
麥克風(fēng)增益
麥克風(fēng)增益命名如“Mic
Boost”或“Mic
Boost(6dB)”。
更精確的信息請參考文檔(Documentation/sound/alsa/ControlNames.txt)
存取標(biāo)志
存取標(biāo)志是一個(gè)位標(biāo)志,主要是區(qū)分給定的control的存取類型。缺省的存取類型是SNDRV_CTL_ELEM_ACCESS_READWRITE,意思是允許對control進(jìn)行讀寫控制。當(dāng)這個(gè)標(biāo)志位被忽略的時(shí)候(為0),被認(rèn)為是缺省讀寫(READWRITE)。
當(dāng)這個(gè)control是只讀的時(shí)候,需要傳遞SNDRV_CTL_ELEM_ACCESS_READ。這時(shí)候,可以不定義put函數(shù)。類似的,如果control是只寫的話(雖然這種可能性很低),要設(shè)定為WRITE標(biāo)志,也可以不必定義get函數(shù)。
加入control的值是經(jīng)常改變的,應(yīng)該加上VOLATILE標(biāo)志,這意味著control可以不用顯式通知就可以改變。應(yīng)用程序應(yīng)經(jīng)常查詢control。
當(dāng)一個(gè)control是不活動(dòng)的話,設(shè)定INACTIVE標(biāo)志。還有LOCK和OWNER標(biāo)志用來改變寫權(quán)限。
回調(diào)函數(shù)
info函數(shù)
info函數(shù)可以得到對應(yīng)control的詳細(xì)信息。它必須存到一個(gè)給定的snd_ctl_elem_info對象中。例如,對于一個(gè)擁有一個(gè)元素的布爾型control的如下:
Example6-2.info函數(shù)示例
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;
}
type字段表示control的類型。有如下幾種:布爾型,整形,枚舉型,BYTES型,IEC958,64位整形。count字段表示這個(gè)control里面的元素的數(shù)量。如:一個(gè)立體聲音量擁有的count為2。value字段是一個(gè)union(聯(lián)合)類型。value的存儲依賴于類型。布爾型和整形是一樣的。
枚舉型和其他類型有一點(diǎn)不同,需要為當(dāng)前給定的索引項(xiàng)設(shè)定字符串。
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.items
= 4;
if
(uinfo->value.enumerated.item > 3)
uinfo->value.enumerated.item
= 3;
strcpy(
uinfo->value.enumerated.name,texts[
uinfo->value.enumerated.item]);
return
0;
}
get函數(shù)
這個(gè)函數(shù)用來讀取當(dāng)前control的值并返回到用戶空間。
例如:
Example6-3.get函數(shù)示例
static int
snd_myctl_get(struct snd_kcontrol *kcontrol,
struct
snd_ctl_ctl_elem_value *ucontrol)
{
struct
mychip *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0]
= get_some_value(chip);
return 0;
}
value字段和control類型有關(guān),這點(diǎn)和info類似。例如,子驅(qū)動(dòng)和用這個(gè)字段來存儲一些寄存器的偏移,位的屏蔽。private_value設(shè)定如下:
.private_value
= reg | (shift
可以通過以下函數(shù)重新得到:
static int
snd_sbmixer_get_single(struct snd_kcontrol *kcontrol,
struct
snd_ctl_elem_value *ucontrol)
{
int reg
= kcontrol->private_value & 0xff;
int
shift = (kcontrol->private_value >> 16) & 0xff;
int mask
= (kcontrol->private_value >> 24) & 0xff;
....
}
在get函數(shù)中,加入control擁有超過一個(gè)的元素。如count大于1,就必須填充所有的元素。上面的例子中,因?yàn)槲覀兗俣╟ount為1,所以我們僅僅填充了一個(gè)元素(value.integer.value[0])。
put函數(shù)
這個(gè)函數(shù)主要是從用戶空間寫一個(gè)值
例如:
Example6-4.put函數(shù)示例
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;
}
如上,假如value被改變要返回1,沒有改變返回0。假如有錯(cuò)誤發(fā)生,通常返回一個(gè)帶錯(cuò)誤碼的負(fù)數(shù)。
像get函數(shù)一樣,如果control擁有超過一個(gè)的元素,在put函數(shù)中所有的元素都要比較一下。
回調(diào)函數(shù)不是原子的。
所有上面的3個(gè)回調(diào)函數(shù)都是非原子的。
構(gòu)造器
當(dāng)所有事情都準(zhǔn)備好的時(shí)候,我們就可以創(chuàng)建一個(gè)新的control了。為了創(chuàng)建它,首先要調(diào)用兩個(gè)函數(shù),snd_ctl_new1()和snd_ctl_add()。
一個(gè)簡單的方式如下:
if ((err =
snd_ctl_add(card, snd_ctl_new1(&my_control, chip)))
return
err;
my_control是前面定義好的snd_kcontrol_new類型的對象,chip是一個(gè)指向kcontrol->private_data的指針,可以被回調(diào)函數(shù)調(diào)用。
snd_ctl_new1()分配了一個(gè)新的snd_kcontrol實(shí)例(這也是為何my_control可以帶有__devinitdata前綴的原因了),snd_ctl_add會把給定的control組件添加到card里面。
更改通知
假如你需要在中斷程序中改變或更新一個(gè)control,你需要調(diào)用snd_ctl_notify()。
例如:
snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE,id_pointer);
這個(gè)函數(shù)需要card指針,event_mask,和control
id指針作為參數(shù)。event-mask表示notification的類型,如上述示例,是通知改變control的值。id指針是指向一個(gè)snd_ctl_elem_id的結(jié)構(gòu)體。在es1938.c或es1968.c中關(guān)于硬件的卷的中斷部分有相關(guān)示例。
本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u1/49088/showart_1018357.html |
|