Alsa驅動分析(轉)


1.????Abstract

2.????Introduction

3.????音頻驅動框架介紹

3.1??????音頻設備的注冊

3.2?????音頻驅動的注冊

3.2.1???????Probe函數的調用

3.2.2???????Soc_probe函數

4.????通常的使用流程的分析

4.1.1???????open過程介紹

4.1.2???????snd_pcm_hw_params流程分析

4.1.3???????prepare流程分析

4.1.4???????write的流程

4.1.5???????使用流程的總結t

5.????Amixer調用的相關邏輯

5.1.1???????Amixer調用的上層邏輯

5.1.2???????Amixer的內核流程

6.????總結

7.????未討論

1.???????????????Abstract

主要是講2.6.21內核里面的alsa驅動的架構,以及在我們的平臺上需要注意的東西。.

2.???????????????Introduction

分成幾個部分:

驅動整體框架,一個簡單的播放流程介紹,以及我們的平臺需要注意的地方;

3.???????????????音頻驅動框架介紹

3.1???????????????音頻設備的注冊

Alsa驅動分析(轉) - wilson - Wilsons blog

這就是設備的注冊了,設備本身非常簡單,復雜的是這個設備的drvdatadrvdata里面包含了三部分,關于machine的,關于platform的,關于codec的,從大體上說machine主要是關于cpu這邊的也可以說是關于ssp本身設置的,而platform是關于平臺級別的,就是說這個平臺本身實現相關的,而codec就是與我們所用的音頻codec相關的;基本上這里就可以看出整個音頻驅動的架構特點,就是從alsa層進入——>內核alsa層接口->core層,這里再調用上面說的三個方面的函數來處理,先是cpu級別的,再是platform的,再是codec級別的,這幾層做完了,工作也就做得差不多了,后面會詳細講講,當然這個執行順序不是固定的(不知道是不是marvel寫代碼不專業導致的),但多半都包括了這三部分的工作;

3.2????????????音頻驅動的注冊

3.2.1??????????Probe函數的調用??????

??????????????????Alsa驅動分析(轉) - wilson - Wilsons blog

???????????????????前面講了設備的注冊,里面的設備的名字就是”soc-audio”,而這里的driver的注冊時名字也是?soc-audio”,對于platform的設備匹配的原則是根據名字的,所以將會匹配成功,成功后就會執行audio驅動提供的probe函數soc_probe;

3.2.2??????????Soc_probe函數

這個函數本身架構很簡單,和前面說的邏輯一樣,先調用了cpu級別的probe,再是codec級別的,最后是platform的(這里三個的順序就不一樣),但是因為cpu級別的和platform級別的都為空,最后都調用了codec級別的probe函數,也就是micco_soc_probe,這個函數基本上就完成了所有應該完成的音頻驅動的初始化了;簡單的劃分,分成兩部分,對上和對下:對上主要是注冊設備節點,以及這些設備節點對應的流的創建;對下主要是讀寫函數的設置,codec本身的dai設置,初始化寄存器的設置,最重要的就是后面的control的創建和門的創建了,如下圖所示:

Alsa驅動分析(轉) - wilson - Wilsons blog這里面的第一部分就是負責初始化的;

?

第二部分就是創建卡和流,對于alsa驅動來說,是先分成卡0,卡1…,然后對于每一個卡的每一個cpu支持的daidigit audio interface)也就是pcm接口?或者i2S接口等都要建立對應的流,一個dai有可能包含兩個流,一個是錄的一個是play的,但在我們的平臺上對于i2Sdai是沒有錄音功能的,所以我們的平臺只有一個卡,三個流,pcm的錄和playi2Splay;流的創建還是更多的考慮為上層服務的,它所提供的接口都是soc層的,這里非常重要的地方在于驅動的一個典型做法那就是如何把關鍵的內核數據結構和export到外部的/dev下的設備節點實現關聯,比如:

?

關鍵數據結構struct snd_pcm,是根據cpu所固有的dai創建的,而對于每一個struct??snd_pcm又可能用到兩個substream(它們實現具體的流的播放等),它們之間的鏈接是通過它的內部數據成員struct snd_pcm_str streams[2];來連接的,而這個snd_pcm類型的指針是在函數snd_device_new里面通過device_data放到設備里面的,這個設備會在snd_device_register_all

的時候注冊到/dev下面,并且調用dev_set_drvdata(preg->dev, private_data);來把這個指針放到設備的私有數據里面;而在需要使用的時候通過snd_pcm_playback_open里面的snd_lookup_minor_data函數取得其私有數據并返回的,這樣就實現了設備節點和對應的驅動的數據結構的關聯,這是一種非常普遍的做法;有了這個數據結構它就可以根據一定的原則取得對應于這個需求的substream,于是一切的操作都可以交給這個substream

?

第三部分就是control的創建,這個函數比較簡單,就是把表micco_snd_controls里面已經定義好的controls模板創建controls,然后加入到cardcontrols列表中去;本身功能很清晰,但是對于我們平臺來說,需要非常小心,因為這里決定了各個controls的序號,而這個序號是audio_controller訪問硬件的索引,所以千萬要小心盡量要維持目前的controls的序號,如果要額外添加新的controls一定要記得要放在micco_add_widgets后面來做,這樣可以做到兼容,否則audio_controller的工作量就大了

?

第四部分就是門的創建了,這個函數也是很清楚,就是把codec對應的門都加入到codec->dapm_widgets列表中去(這里的門的概念可以簡單的理解為水管與水管之間的連接的地方,聲音數據像水一樣從水管里面流出來,源頭可以是CPU了,也可以是modem,然后通過不同的門,流向不同的地方,比如speaker,比如藍牙耳機等等),然后根據micco_audio_map把所有可能連在一起的門連接起來,這個表micco_audio_map的意思是{目的名字,控制點名字,源頭名字},然后函數snd_soc_dapm_connect_input會根據這些名字去查表codec->dapm_widgets(先前已經把所有的門都加入了)找到它們再根據不同的類型做不同的連接,比如是mux之間的連接,muxpga之間的連接等等,注意這里的連接其實只不過是說找到連接的可能性,它對于不同的門,找到其可能的sourcesink,加入到對應的列表中去,具體細節如下:

首先,掃描整個codec所擁有的所有的門,如果它的名字和傳入的sink的名字相同,則認為它就是這個路徑的sink,如果它的名字和傳入的source名字相同,則認為它是這個路徑的source,如果源頭或者sink沒有找到都返回錯誤;然后分配一個struct snd_soc_dapm_path,這個數據結構的主要成分包括名字,source門,sink門,這條路徑的control,這個源頭和sink是否已經連接,是否已經走過(用在后面),這個數據結構會被掛在三個鏈表里面,一個是source的就是這個門會在很多的路徑中,把它在這個路徑中做sourcepath都連在一起,一個是sink的就是把這個門在所有這些由它做sinkpath都連接在一起,一個是把所有的路徑都需要連接在一起的這個是通過codecdapm_paths來訪問的;

list_add(&path->list, &codec->dapm_paths);

list_add(&path->list_sink, &wsink->sources);

list_add(&path->list_source, &wsource->sinks);

需要注意的時候,這里把路徑的list_sink加入到了wsink門的sources列表里面,而把路徑的list_source加入到wsourcesinks列表里面,所以當訪問的時候從wsink門的sources出發就可以找到連接這個門作為sink的所有的路徑,而從wsourcesinks列表出發就可以找到所有以這個門作為source的路徑;

第三步就是為這個數據結構賦值:sourcesink,初始化三個鏈表;第四步:如果control為空則把這個路徑加入到相應的三個鏈表中去,并且路徑設為已經連接,并返回;第五步:否則,根據sink的類型,如果是adcdacinputoutputmicbiasvmidprepost,則把路徑加入到三個鏈表,設置已經連接的標志;如果是snd_soc_dapm_mux則調用dapm_connect_mux來處理;如果是mixerswitch則調用dapm_connect_mixer來處理,如果是hpmiclinespk,則把path加入到三個鏈表中去,但是設置成為連接的狀態

大約就是這樣的了。

也許您要問,為什么要這么做呢?

這個,我也有想過,甚至我認為在門比較少的時候,確實沒什么必要,但是這么做的好處在于當要播放音樂的時候,它可以實現自動的尋找路徑并且自動poweron那些門,不需要上層做任何的控制,因為它真的到達目的地的所有的路徑,這樣它可以自己選擇走哪條路;如果不這么連接起來的話,就需要提供給上層連接的接口,完全由上層來決定該連接哪些門,也必須由上層來負責poweronoff這些門;

第五部分就是注冊了,這里就是向 /dev 注冊設備節點,因為這些設備節點會由 alsa 層來訪問的,這些設備節點和驅動的連接我前面已經說了,主要是提供了對上的 alsa 接口,給 alsa 層調用。 ??

4.???????????????通常的使用流程的分析

通常使用alsalib來播放聲音包括以下幾個步驟:

1,???open,這個和oss相同,對應于alsa就是snd_pcm_open

2,???param設置,這個就是snd_pcm_hw_params;

3,???上層的alsa在設置param的成功以后或者出錯的時候恢復都需要調用snd_pcm_prepare;

4,???write函數;

現在一個個的來看;

4.1.1??????????open過程介紹

如下圖所示:Alsa驅動分析(轉) - wilson - Wilsons blog

?????????就是我先前說的分成三部分,先是cpu級別的,包括clockenabe,中斷的申請,空間的申請;

?????????然后就是平臺級別的包括DMA所需要的空間的分配等;

?????????不過這里codec級別的沒有提供相關的函數,由machine提供了一些函數主要是設置channel,格式,頻率范圍等等;

4.1.2??????????snd_pcm_hw_params流程分析

Alsa驅動分析(轉) - wilson - Wilsons blog

?????????流程就是這樣,至于里面做的具體的事情,我覺得只需要對照spec看看就知道了,具體的寄存器設置下面有一點講解,主要是格式的設置(采樣率的設置會留到prepare的時候),至于中斷上來的時候那個更新hw_ptr函數很有用,這樣上層就可以知道數據到底寫了多少或者說還有多少空間可以寫;

?

4.1.3??????????prepare流程分析

?

alsa層調用snd_pcm_prepare的時候會觸發驅動對應的prepare的函數執行,如下:

Alsa驅動分析(轉) - wilson - Wilsons blog可以看出基本上還是分為了三段,一段是cpu級別的,主要是對于ssp port的設置,具體設置如下:

對于voice通道,littleton_micco_voice_prepare的設置:

the sscr0 0xc0163f,sscr1 0xf01dc0,sspsp 0x800085

其中對于pcmssp地址是:

#define SSCR0_P4????????__REG(0x41A00000)??/* SSP Port 4 Control Register 0 */

#define SSCR1_P4????????__REG(0x41A00004)??/* SSP Port 4 Control Register 1 */

#define SSPSP_P4????????__REG(0x41A0002C)??/* SSP Port 4 Programmable Serial Protocol */

所以結果就相當于:

?SSCR0_P4 0x41A000000xc0163f ——00000000110000000001011000111111

對于這個地址高8位為0

31?MOD-0:普通模式;30ACS-0:時鐘選擇是由NCSECS位絕決定,看后面;

29FPCKE-0FIFO packing mode disabled28()-0reserved

2752MM-013mbps模式;2624FRDC-0:每幀的時隙數

23TIM->1:表示禁止傳輸fifo underrun中斷;22RIM-1:表示禁止接收fifo overrun中斷

21NCS->0:表示時鐘選擇由ECS決定;20EDSS-0:表示前面填充DSS來達到8-16

198SCR-0x16:決定串口bit率,=sspx clock/(scr+1)???;7SSE-0:表示disable port

6ECS-0:表示片內的時鐘用來計算serial clock rate54FRF-0b11:表示psp模式用來模擬I2S協議

30DSS-0b1111:表示16bit數據(EDSS0

?

SSCR1_P4 0x41A00004:??0xf01dc0——00000000111100000001110111000000

對于這個地址高8位也為0

31TTELP-0:表示最后一個bit傳輸(LSB)傳完后有半個時鐘處于高阻(三態)狀態;

30(TTE)-0:表示傳輸信號不是三態的;29EBCEI-0bit傳輸錯誤不產生中斷

28SCFR-0:表示SSPSCLK的時鐘信號需要連續的工作,主模式ignore27ECRA-0:表示禁止其它ssp向它發起始終請求

26ECRB-0:表示同2725SCLKDIR-0:表示主模式,SSP端口,驅動SSPSCLK

24SFRMDIR-0:表示主模式,SSP端口,驅動SSPSFRM信號;

23RWOT-1:表示只接收不傳輸???;22TRAIL-1:表示trailing bytes?dma burst來處理;

21TSRE-1:表示傳輸DMA sevice request?enabled20RSRE-1:表示接收DMA service request允許

19TINTE-0:表示接收超時中斷disable18PINTE-0:表示外設trail byte?中斷disable

17:保留;16IFS->0:表示幀的極性由PSP的極性位決定;

15STRF-0:表示傳輸FIFO(讀,寫)由SSDR_X來決定;14EFWR-0:表示FIFO讀寫特別函數disable

1310RFT-0b0111:表示到達什么級別rxfifo斷言中斷;96TFT-0111:表示TXFIFO斷言中斷級別

5:保留;4SPH-0:表示在每一個幀開始之前要等一個時鐘,結束后要等0.5個時鐘;

3SPO-0:表示SSPSCLKinactive的時候是低電平;2LBM-0:表示非循環模式

1RIE-0:表示RXFIFO門檻到達的中斷disable0RIE)->0:表示接收FIFO門檻到達中斷disable

?

?

SSPSP_P4 0x41A0002C:??0x800085-00000000100000000000000010000101

這個地址的高8位為0

31reverved3028EDMYSTOP-0extended dummy stop

2726EDMYSTART-0extended dummy start25FSRT-0:下一幀的開始由前面的擴展STOP決定;

2423DMYSTOP-0b01:表示最后一bit傳輸完畢后保持activeclock1clock的延遲;22:保留

2116SFRMWDTH-0:表示最小位幀寬度;159SFRMDLY-0serial frame dealy

87DMYSTRT-0b01:表示1clock的延遲在開始的時候;64STRTDLY-0start delay

3ETDS-0:表示結束時的傳輸狀態為low2SFRMP-1serial frame的極性;

10SCMODE-0b01data driven?上升沿,數據采樣下降沿,idle狀態,低;

?

對于littleton_micco_hifi_prepare的設置:

?The sscr0 e1c0003f,sscr1 701dc0,sspsp 40200004,sstsa 3,ssrsa 3,ssacd 60,ssacdd 6590040

其中對于I2sspp地址是:

#define SSCR0_P3??__REG(0x41900000)??/* SSP Port 3 Control Register 0 */

#define SSCR1_P3??__REG(0x41900004)??/* SSP Port 3 Control Register 1 */

#define SSPSP_P3??__REG(0x4190002C)??/* SSP Port 3 Programmable Serial Protocol */

#define SSTSA_P3??__REG(0x41900030)??/* SSP Port 3 Tx Timeslot Active */

#define SSRSA_P3??__REG(0x41900034)??/* SSP Port 3 Rx Timeslot Active */

#define SSACD_P3?__REG(0x4190003C)??/* SSP Port 3 Audio Clock Divider */

#define?????SSACDD_P3???__REG(0x41900040)??/* SSP Port 3 Audio Clock Dither Divider Register */

?

SSCR0_P3==__REG(0x41900000):e1c0003f——11100001110000000000000000111111

31?MOD-1:網絡模式;30ACS-1:時鐘選擇是audio clockaudio clock divider決定,由ssacd寄存器決定;

29FPCKE-1FIFO packing mode enabled28()-0reserved

2752MM-013mbps模式;2624FRDC-1:每幀的時隙數

23TIM->1:表示禁止傳輸fifo underrun中斷;22RIM-1:表示禁止接收fifo overrun中斷

21NCS->0:這里ignore,由ACS決定了(為1);20EDSS-0:表示前面填充DSS來達到8-16

198SCR-0:ACS那里決定;7SSE-0:表示disable port,工作時應為1

6ECS-0:表示片內的時鐘用來計算serial clock rate54FRF-0b11:表示psp模式用來模擬I2S協議

30DSS-0b1111:表示16bit數據(EDSS0

?

SSCR1_P3==__REG(0x41900004):701dc0——00000000011100000001110111000000

31TTELP-0:表示最后一個bit傳輸(LSB)傳完后有半個時鐘處于高阻(三態)狀態;

30(TTE)-0:表示傳輸信號不是三態的;29EBCEI-0bit傳輸錯誤不產生中斷

28SCFR-0:表示SSPSCLK的時鐘信號需要連續的工作,主模式ignore27ECRA-0:表示禁止其它ssp向它發起始終請求

26ECRB-0:表示同2725SCLKDIR-0:表示主模式,SSP端口,驅動SSPSCLK

24SFRMDIR-0:表示主模式,SSP端口,驅動SSPSFRM信號;

23RWOT-0:接收和傳輸都可以;22TRAIL-1:表示trailing bytes?dma burst來處理;

21TSRE-1:表示傳輸DMA sevice request?enabled20RSRE-1:表示接收DMA service request允許

19TINTE-0:表示接收超時中斷disable18PINTE-0:表示外設trail byte?中斷disable

17:保留;16IFS->0:表示幀的極性由PSP的極性位決定;

15STRF-0:表示傳輸FIFO(讀,寫)由SSDR_X來決定;14EFWR-0:表示FIFO讀寫特別函數disable

1310RFT-0b0111:表示到達什么級別rxfifo斷言中斷;96TFT-0111:表示TXFIFO斷言中斷級別

5:保留;4SPH-0:表示在每一個幀開始之前要等一個時鐘,結束后要等0.5個時鐘;

3SPO-0:表示SSPSCLKinactive的時候是低電平;2LBM-0:表示非循環模式

1RIE-0:表示RXFIFO門檻到達的中斷disable0RIE)->0:表示接收FIFO門檻到達中斷disable

?

SSPSP_P3==__REG(0x4190002C):40200004——01000000001000000000000000000100

31reverved3028EDMYSTOP-4extended dummy stop

2726EDMYSTART-0extended dummy start25FSRT-0:下一幀的開始由前面的擴展STOP決定;

2423DMYSTOP-0b00:表示最后一bit傳輸完畢后保持activeclock數的延遲;22:保留

2116SFRMWDTH-0b20:表示最小位幀寬度;159SFRMDLY-0serial frame dealy

87DMYSTRT-0b00:表示0clock的延遲在開始的時候;64STRTDLY-0start delay

3ETDS-0:表示結束時的傳輸狀態為low2SFRMP-1serial frame的極性;

10SCMODE-0b00data driven?下降沿,數據采樣上升沿,idle狀態,低;

?

SSTSA_P3==__REG(0x41900030):3——0011

318->0:reserved;7:0TTSA->0b0011:表示在那個time slot里面是傳輸數據的0,不傳輸,1傳輸;

SSRSA_P3==__REG(0x41900034):3——0011

318?reserved70RTSA-0:表示在那個slot里面接收數據,0,不接受,1?接收;

SSACD_P3==__REG(0x4190003C):60——01100000

318reserved7SCDX8-0sysclk/4產生內部audio clock1sysclk/8產生audio clock

64ACPS-0b110:PLL輸出時鐘由Audio clock dither Divider register value決定;

3SCDB-0:如果SCDX80scdx8決定,為1,則sysclk不分頻;

20ACDS-0:表示clock divider select?/1

SSACDD_P3==__REG(0x41900040):6590040——00000110010110010000000001000000

31reserved3016NUM-1625;除數(0x659

1512reserved110DEN-64:被除數

比如我們的板子上是這樣計算這些值的:

比如,在我們的機子上的一個實例是這樣的,

那么第一步取得采樣率:48K,它也就是Sync clock

第二步球的bit率:48X64=3.072M

第三步求的sysclk:這個根據scdx8決定是X4還是X8,在我們的例子中是4,所以:3.072X4=12.288

第四步求得我們要的dither divider y,公式為:

624*(y)/2=12.288

算出y=0.039384615384615384615384615384615

所以查可能的分子和分母表,得出,分子是:

64,分母是1625

如下圖所示:

Alsa驅動分析(轉) - wilson - Wilsons blog

當然更加詳細的請參閱spec

?

第二段是平臺級別的,主要是對于DMA的初始化;

第三段是codec級別的,這里主要是對codec本身的設置,通過i2c接口對codec的寄存器操作,比如采樣率等等;

最后面還有一個poweron的函數,這個函數前面有提到,但是沒有詳細分析,這里分析一下:

首先根據事件類型,決定是關閉門序列,還是啟動門序列,我只分析啟動過程;

得到啟動序列,就開始遍歷整個序列,對于這個序列的每一個類型,查找所有的門的序列,直到有一個門的類型和當前啟動序列的類型相同,然后再根據不同的類型做不同的檢查和power

1,如果是snd_soc_dapm_vmid則繼續,不做任何處理;

2

A)如果是snd_soc_dapm_adc,并且其active1,這個active在上一步已經分析過了,必須要包含這個流的名字的sname的門才會被激活,假設我們現在討論的是用pcm通道播放聲音,那么流的名字就是“Voice Playback”,所以,將dac3active被設成1,這樣就避免了power on dac1dac2,和adc了。如果這兩個條件都滿足,那么必然是“Voice Capture”了,因為只有這時候,我們才會用到adc,現在看看,如果用了adc將會啟動什么,于是調用函數is_connected_input_ep,這是一個通用遞歸函數,從名字上來說就是看是否是已經連接了輸入的門,我們只考慮adc的情況,其余的情況待會再討論,對于adc,在is_connected_input_ep函數里面,是通過遍歷所有以這個門作為sinksource門(list_for_each_entry(path, &widget->sources, list_sink),可以看到,這里的最后一個參數是list_sink,而第二個參數卻是widget->sources,這個原因我在門連接分析頁里面已經分析過了,總之sources就表示這個門的sources列表,而sinks就是這個門的sink列表),通過遞歸調用is_connected_input_ep來查看這些source門是否其中有一個是連通的,返回的是所有是否連通的和(聯通為1,否則為0),所以返回的結果可能是大于1的數,表示不只一個源是聯通的。

B)如果這個函數返回為真則表示此adc是聯通的,于是調用dapm_update_bits來處理,這個函數過對mux(它的reg<0)inputoutputmichplinespk,不做任何處理就返回了;過了這一關,開始查是否menrevert為真,如果為真,則把power取反,原來為真現在變假,于是調用snd_soc_readmicco_soc_read)開始讀這個寄存器的值(注意,這里讀的值是可能和物理上的這個寄存器的值不一樣的,這里讀的值是cache里面的值),讀出來后強制把1<<shift后的位置為1,比較新舊值是否有變化,如果有,則調用snd_soc_write(codec, widget->reg, new)把值寫到cache里面(實際負責寫的是micco_soc_write,而且,它對于0x70+0x15以下包含0x15的值是直接寫到寄存器的地址的,否則只是些到數組cache里面去)好對于adc的情況我們就分析完了。

3

A)如果此類型是snd_soc_dapm_dac并且active1,則調用is_connected_output_ep來取得是否要power,下面來看看函數is_connected_output_ep,這也是一個通用的判斷是否有連接到輸出的遞歸函數,我們只分析dac的情況,list_for_each_entry(path, &widget->sinks, list_source),上面已經講過,這里實際上查的是這個門的所有的sink列表,通過遞歸調用is_connected_output_ep來看是否它的sink是聯通的,只要有一條路是聯通的,則power為真。

B)返回后調用dapm_update_bits來處理,上面已經分析過了,這個函數就是判斷是否需要設置此門的寄存器的1<<shift位。

4,如果此類型是snd_soc_dapm_pga,則調用is_connected_input_ep來判斷是否聯通輸入,再調用is_connected_output_ep判斷是否聯通輸出,對于pga is_connected_input_ep函數的處理和adc是一樣的,對于is_connected_output_epdac的處理是一樣的,接著調用dapm_set_pga,根據power的值決定是mute pga還是啟用pga,但是就我打印的結果來看,基本上這個函數所起的作用為0,因為對于pga的門似乎都沒有設置相應的control,最后調用dapm_update_bits,設置power?位。

5,對于other widget,這里在我們的平臺上多半是指mux,首先調用is_connected_input_ep判斷是否連接輸入,再調用is_connected_output_ep判斷是否有輸出,調用dapm_update_bits位設置power?位,最后調用w->eventdo_post_event)來進行后期處理,這里主要就是對mux進行寄存器設置,因為mux的寄存器的地址都是大于0x70+0x15的,所以它們的地址需要轉化,這個函數就是根據mux的類型,訪問不同的寄存器。

?

基本上prepare后,一切就都就緒了,只等一個trigger;而trigger的執行會在上層的alsalib調用write的函數觸發;

4.1.4??????????write的流程

?

Alsa驅動分析(轉) - wilson - Wilsons blog

用戶層的write到內核里面都是通過ioctl來做的,這里面會觸發trigger函數的執行,等trigger執行完以后,才會真正調用函數把用戶層的東西copydma分配的空間;

這里面基本上只是畫了最簡單的邏輯,其實里面非常的復雜特別是函snd_pcm_lib_write1,這里面有同步的操作,也就是要等到有空余的空間的時候才允許寫,否則就要等待,喚醒是通過函數snd_pcm_update_hw_ptr_post來做的,這個函數會在DMA傳輸完一幀的中斷到來的時候被調用,用來更新緩沖區指針;

?

其中trigger的邏輯如下:

Alsa驅動分析(轉) - wilson - Wilsons blog

?

簡單的說就是啟動DMAenable ssp口;

4.1.5??????????使用流程的總結t

?????????簡單總結一下,用戶的使用流程;

?????????A,調用snd_pcm_open打開設備節點對應的pcm流的substream也就是錄音或者play

B,調用snd_pcm_hw_params設置硬件參數,包括格式,通道,采樣率,DMA空間的分配,中斷的申請等等,這里面會調用prepare函數使硬件準備好硬件,包括codec的寄存器設置,各種路徑的建立,門的power on等;

C,調用write函數實現把數據寫到設備里面去,這里會觸發trigger函數也就是DMA的啟動,SSP端口的啟動等。

5.???????????????Amixer調用的相關邏輯

我們的audio controller所調用的驅動的接口都是amixer?csetcget,所以有必要分析一下它的邏輯:

5.1.1??????????Amixer調用的上層邏輯

Alsa驅動分析(轉) - wilson - Wilsons blog

????也就是說通過/dev下面的設備節點調用相應的ioctl,然后進入到內核的范圍;

5.1.2??????????Amixer的內核流程?????

Alsa驅動分析(轉) - wilson - Wilsons blog

這里只分析了控制函數為snd_soc_dapm_put_enum_double的處理邏輯,其它的都類似,而具體的應該是哪個處理函數來處理是在controlnew的時候就已經確立了的,對于我們的平臺其實在表micco_dapm_widgets建立的時候就已經確立了;

為了方便后來者的調試,我這里把各個numid的對應的控制函數都列出來了,如下:

numid=112snd_soc_put_volsw

numid=1320snd_soc_dapm_put_enum_double

?

?

.

6.???????????????總結

Alsa驅動的架構主要是分成對上為alsalib提供接口,對下實現硬件的管理,對上的內容基本都是在sound/core目錄里面的文件來完成,而設計硬件的操作分成兩部分一部分相關與cpu這邊的是由sound/soc/pxa目錄里面的文件來完成的,另外一部分設計codec是由sound/soc/codec來完成的,這部分主要就是對codec這邊的寄存器的設置;簡單示意如下:

Alsa驅動分析(轉) - wilson - Wilsons blog

它復雜的地方在于用戶態的alsa lib

7.???????????????未討論

還有一些地方沒有討論到,比如timer,不過留到以后補充吧

備注:

??????????????內核版本:2.6.21+marvel patch

?????? ? ? ? ???硬件平臺:pxa310+9034codec

?作者:wylhistory

轉載請注明出處!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/253369.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253369.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253369.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

bzoj2744[HEOI2012]朋友圈

題目鏈接&#xff1a;bzoj2744 題目大意&#xff1a; 兩個國家看成是AB兩國&#xff0c;現在是兩個國家的描述&#xff1a; 1.A國&#xff1a;每個人都有一個友善值&#xff0c;當兩個A國人的友善值a、b&#xff0c;如果a xor b mod 21&#xff0c;那么這兩個人都是朋友&#x…

Linux之父為過去的言行道歉,宣布離開社區反思

9月17日&#xff0c;Linux 4.19-rc4發布&#xff0c;成為Linux 4.19最新的開發測試內核。這是現階段一個相當常規的內核更新&#xff0c;但令人震驚的是&#xff0c;Linux之父Linus Torvalds宣布將暫時離開內核維護社區&#xff0c;Greg Kroah-Hartman將接管接下來的Linux 4.19…

[BZOJ] 1620: [Usaco2008 Nov]Time Management 時間管理

1620: [Usaco2008 Nov]Time Management 時間管理 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 850 Solved: 539[Submit][Status][Discuss]Description Ever the maturing businessman, Farmer John realizes that he must manage his time effectively. He has N jobs con…

面試-接口和純虛類的區別

相關資料&#xff1a;1.https://zhidao.baidu.com/question/91157279.html 純虛類:1.一個子類只能繼承一個抽象類&#xff08;虛類&#xff09;。2.一個抽象類可以有構造方法。 3.一個抽象類中的方法不一定是抽象方法&#xff0c;即其中的方法可以有實現&#xff08;有方法體&a…

TCP研究

tcp協議本身是可靠的,并不等于應用程序用tcp發送數據就一定是可靠的.不管是否阻塞,send發送的大小,并不代表對端recv到多少的數據 在阻塞模式下, send函數的過程是將應用程序請求發送的數據拷貝到發送緩存中發送并得到確認后再返回.但由于發送緩存的存在,表現為:如果發送緩存大…

DDR工作原理

DDR SDRAM全稱為Double Data Rate SDRAM&#xff0c;中文名為“雙倍數據流SDRAM”。DDR SDRAM在原有的SDRAM的基礎上改進而來。也正因為如此&#xff0c;DDR能夠憑借著轉產成本優勢來打敗昔日的對手RDRAM&#xff0c;成為當今的主流。本文只著重講講DDR的原理和DDR SDRAM相對于…

8.1 文件查找local;find使用

文件查找&#xff1a; 在文件系統上查找符合條件的文件。 文件查找&#xff1a;locate, find 非實時查找(數據庫查找)&#xff1a;locate實時查找&#xff1a;find locate 1 查詢系統上預建的文件索引數據庫 /var/lib/mlocate/mlocate.db2 依賴于事先構建的索引 索引的構建是在…

hdu 5273 Dylans loves sequence 逆序數 區間dp

點擊打開鏈接 題意&#xff1a;給n個數&#xff0c;q次詢問&#xff0c;&#xff08;L&#xff0c;R&#xff09;區間內的逆序數。 思路&#xff1a; 區間dp 代碼一&#xff1a; 1 #include <bits/stdc.h>2 using namespace std;3 typedef long long ll;4 const int maxn…

python第三天習題

# 1. 文件a.txt內容&#xff1a;每一行內容分別為商品名字&#xff0c;價錢&#xff0c;個數&#xff0c;求出本次購物花費的總錢數# apple 10 3# tesla 100000 1# mac 3000 2# lenovo 30000 3# chicken 10 3## 2. 修改文件內容&#xff0c;把文件中的alex都替換成SB# with ope…

智能故事機方案簡介

智能故事機&#xff0c;又叫WiFi故事機&#xff0c;AI故事機&#xff0c;通過WiFi聯網&#xff0c;用戶語音就可以跟它進行問答、點歌等互動&#xff1b;由于聯網所以可以播放云端海量的兒童音頻內容&#xff1b;手機端在微信公眾號或者專屬APP上操作&#xff0c;可以點播相應內…

使用setsockopt()接口,設置TCP的接收與發送超時,Invalid argument錯誤問題

使用TCP套接字時&#xff0c;當無網絡連接時&#xff0c;還會繼續send&#xff0c;繼續recv阻塞&#xff0c;知道TCP自己協議機制判斷斷開連接時才會停止發送和接收&#xff0c;時間需要幾分鐘之久。解決的辦法是&#xff0c;自己設置接收超時時間&#xff0c;當超時后重新發送…

關于SpringCloud、SpringBoot 希望這是說得最詳細的

幾年前&#xff0c;沒幾個jar沖突一下都不叫搭框架 —— java面試必修 什么是Spring Boot 用我的話來理解&#xff0c;Spring Boot就是整合了框架的框架&#xff0c;它讓一切依賴都變得有序簡單&#xff0c;你不用操心A.jar是什么版本&#xff0c;又依賴哪些版本的jar&#xff…

weui-switch開關控件,表單提交后如何取值

最近在學習weui這個框架&#xff0c;做了一些小的試驗&#xff0c;發現weui-switch控件直接提交不能獲取到表單信息&#xff0c;在segmentfault上發現也有人提了這個問題&#xff0c;有人說可以設置一個隱含標簽來捕獲開關的狀態&#xff0c;試了一下&#xff0c;確實可以&…

麥克風設計指導與選型參考

隨著語音識別技術的成熟&#xff0c;智能音箱類產品的火爆&#xff0c;越來越多的產品可以升級為語音交互產品&#xff1b; 下面簡單介紹下此類產品的語音前端--麥克風陣列設計相關注意事項&#xff1a; 線性四麥陣列構型&#xff1a;如上圖所示&#xff0c;麥克風直線等距擺…

[BZOJ1419] Red is good(期望DP)

傳送門 逆推 只不過順序還是順著的&#xff0c;思想是逆著的 f[i][j]表示還剩下i張紅牌&#xff0c;j張黑牌的期望值 那么邊界是 f[i][0]i&#xff0c;因為只剩i張紅牌 f[0][j]0&#xff0c;只剩黑牌&#xff0c;顯然直接停止最優 f[i][j] max(0,i/(ij)*f[i-1][j]j/(ij)*f[i][…

Linux下高性能網絡編程中的幾個TCP/IP選項_SO_REUSEADDR、SO_RECVBUF、SO_SNDBUF、SO_KEEPALIVE、SO_LINGER、TCP_CORK、TCP_NODE

最近在新的平臺上測試程序&#xff0c;以前一些沒有注意到的問題都成為了性能瓶頸&#xff0c;通過設置一些TCP/IP選項能夠解決一部分問題&#xff0c;當然根本的解決方法是重構代碼&#xff0c;重新設計服務器框架。先列出幾個TCP/IP選項&#xff1a; 選項 man 7 socket: SO_R…

云計算在未來一定是不可或缺的

2019獨角獸企業重金招聘Python工程師標準>>> 在2018京東云合作伙伴大會上&#xff0c;京東云總裁申元慶表示&#xff0c;技術發展的大趨勢是“分久必合&#xff0c;合久必分”循環往復的波動&#xff0c;近十年來云計算的發展將算力、存儲、帶寬全部集中在中央部分&…

智能音箱 之 音頻通路質量--測試與參數

一、概述 當將語音識別算法接入到設備時&#xff0c;務必要保證設備的音頻通路具有足夠的質量。因此對設備進行音頻測試&#xff0c;以評估能夠影響語音識別性能的音頻前端的音頻參數。如下要點對語音識別至關重要&#xff1a; 自然聲音合適的增益良好的信噪比一致的響應&…

關于Linux路由表的route命令

轉自&#xff1a;http://www.cnblogs.com/gunl/archive/2010/09/14/1826234.html 查看 Linux 內核路由表 使用下面的 route 命令可以查看 Linux 內核路由表。 # route Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.0.0 * …

Python學習 - 常用模塊(二)

目錄 一. 常用模塊 - hashlib 二. 常用模塊 - hmac 三. 常用模塊 - logging 四. 常用模塊 - re 五. 常用模塊 - requests 六. 常用模塊 - paramiko 一. 常用模塊 - hashlib hash: 一種算法, 3.x里代替了md5模塊和sha模塊, 主要提供 SHA1, SHA224, SHA256, SHA384, SHA512, MD5 …