Linux ALSA音效卡驅動之二:音效卡的建立
1. struct snd_card
1.1. snd_card是什麼
snd_card可以說是整個ALSA音訊驅動最頂層的一個結構,整個音效卡的軟體邏輯結構開始於該結構,幾乎所有與聲音相關的邏輯裝置都是在snd_card的管理之下,音效卡驅動的第一個動作通常就是建立一個snd_card結構體。正因為如此,本節中,我們也從 struct cnd_card開始吧。
1.2. snd_card的定義
snd_card的定義位於改標頭檔案中:include/sound/core.h
- struct list_head devices 記錄該音效卡下所有邏輯裝置的連結串列
- struct list_head controls 記錄該音效卡下所有的控制單元的連結串列
- void *private_data 音效卡的私有資料,可以在建立音效卡時通過引數指定資料的大小
2. 音效卡的建立流程
2.1.1. 第一步,建立snd_card的一個例項
- index 一個整數值,該音效卡的編號
- id 字串,音效卡的識別符號
- 第四個引數 該引數決定在建立snd_card例項時,需要同時額外分配的私有資料的大小,該資料的指標最終會賦值給snd_card的private_data資料成員
- card 返回所建立的snd_card例項的指標
2.1.2. 第二步,建立音效卡的晶片專用資料
音效卡的專用資料主要用於存放該音效卡的一些資源資訊,例如中斷資源、io資源、dma資源等。可以有兩種建立方法:
- 通過上一步中snd_card_create()中的第四個引數,讓snd_card_create自己建立
- 自己建立:
然後,把晶片的專有資料註冊為音效卡的一個低階裝置:
註冊為低階裝置主要是為了當音效卡被登出時,晶片專用資料所佔用的記憶體可以被自動地釋放。
2.1.3. 第三步,設定Driver的ID和名字
snd_card的driver欄位儲存著晶片的ID字串,user空間的alsa-lib會使用到該字串,所以必須要保證該ID的唯一性。shortname欄位更多地用於列印資訊,longname欄位則會出現在/proc/asound/cards中。
2.1.4. 第四步,建立音效卡的功能部件(邏輯裝置),例如PCM,Mixer,MIDI等
這時候可以建立音效卡的各種功能部件了,還記得開頭的snd_card結構體的devices欄位嗎?每一種部件的建立最終會呼叫snd_device_new()來生成一個snd_device例項,並把該例項連結到snd_card的devices連結串列中。
通常,alsa-driver的已經提供了一些常用的部件的建立函式,而不必直接呼叫snd_device_new(),比如:
PCM ---- snd_pcm_new()
RAWMIDI -- snd_rawmidi_new()
CONTROL -- snd_ctl_create()
TIMER -- snd_timer_new()
INFO -- snd_card_proc_new()
JACK -- snd_jack_new()
2.1.5. 第五步,註冊音效卡
2.2. 一個實際的例子
我把/sound/arm/pxa2xx-ac97.c的部分程式碼貼上來:
驅動程式通常由probe回撥函式開始,對一下2.1中的步驟,是否有相似之處?
經過以上的建立步驟之後,音效卡的邏輯結構如下圖所示:
圖 2.2.1 音效卡的軟體邏輯結構
下面的章節裡我們分別討論一下snd_card_create()和snd_card_register()這兩個函式。
3. snd_card_create()
snd_card_create()在/sound/core/init.c中定義。
首先,根據extra_size引數的大小分配記憶體,該記憶體區可以作為晶片的專有資料使用(見前面的介紹):
拷貝音效卡的ID字串:
如果傳入的音效卡編號為-1,自動分配一個索引編號:
初始化snd_card結構中必要的欄位:
建立邏輯裝置:Control
建立proc檔案中的info節點:通常就是/proc/asound/card0
把第一步分配的記憶體指標放入private_data欄位中:
4. snd_card_register()
snd_card_create()在/sound/core/init.c中定義。
首先,建立sysfs下的裝置:
其中,sound_class是在/sound/sound_core.c中建立的:
由此可見,音效卡的class將會出現在檔案系統的/sys/class/sound/下面,並且,sound_devnode()也決定了相應的裝置節點也將會出現在/dev/snd/下面。
接下來的步驟,通過snd_device_register_all()註冊所有掛在該音效卡下的邏輯裝置,snd_device_register_all()實際上是通過snd_card的devices連結串列,遍歷所有的snd_device,並且呼叫snd_device的ops->dev_register()來實現各自裝置的註冊的。
最後就是建立一些相應的proc和sysfs下的檔案或屬性節點,程式碼就不貼了。
至此,整個音效卡完成了建立過程。