第一篇:高通音頻增益調(diào)試總結(jié)
高通音頻調(diào)試總結(jié)
1、綜述
該文檔主要描述了手機(jī)打開免提通話的時(shí)候,如何解決固話端出現(xiàn)的嘯音、噪音問題。
2、環(huán)境 項(xiàng)目:xxx 硬件平臺(tái):MSM7X27A 軟件版本:android2.3.5, AMSS11452302
3、調(diào)試流程
(1)咨詢高通FAE,明確哪些參數(shù)需要調(diào)整
FAE給出的建議是:針對(duì)嘯音,調(diào)整codec_rx_gain、codec_tx_gain參數(shù);針對(duì)雜音,調(diào)整rx_agc_static_gain、rx_agc_exp_thres、rx_agc_compr_thres、tx_agc_exp_thres、tx_agc_compr_thres參數(shù);(2)使用QACT工具,對(duì)上述參數(shù)進(jìn)行調(diào)試 QACT是高通提供的音頻校準(zhǔn)工具,可以使用該工具直接在線修改各類音頻參數(shù),調(diào)試十分方便(使用方法詳見安裝文件目錄下的文檔《80-VM407-1_E_Audio_Calibration_Tool_User_Guide.pdf》)。
使用該工具在線調(diào)試的基本思路是:適當(dāng)降低增益(codec_rx_gain、codec_tx_gain),并調(diào)整AGC的門限值以及靜態(tài)增益(rx_agc_exp_thres、rx_agc_compr_thres、tx_agc_exp_thres、tx_agc_compr_thres、rx_agc_static_gain參數(shù)),以達(dá)到消除嘯音、噪音的目的。在線調(diào)試完成后,還可以用這個(gè)工具將調(diào)好的audio_cal.xml文件直接生成代碼,具體也請(qǐng)參考上述文檔。(3)修改代碼 代碼路徑:modem_proc/multimedia/audio/vocoder/src/voccal.c 在結(jié)構(gòu)體voc_pcm_on_chip_speaker_cal_umts_qrd中,分別修改各個(gè)參數(shù),代碼如下:
CAL_MEMORY voc_pcm_path_cal_type voc_pcm_on_chip_speaker_cal_umts_qrd = {
VOC_EC_VER_ECNS,/* ec_version */
VOC_EC_AEC,/* ec_mode */
VOC_NS_ON,/* ns_enable */
0x656e,/* tx_gain */ 0x1000,/* dtmf_tx_gain */ // codec_tx_gain由0x71cf修改為0x2328 0x2328, /* codec_tx_gain */ // codec_rx_gain由0xb460修改為0x1770
0x1770,/* codec_rx_gain */ 0x0000,/* codec_st_gain */ …… ……
#ifdef FEATURE_AUDIO_AGC /* agc_param */ /* rx_agc_static_gain由0x8000修改為0x4000,rx_agc_exp_thres由0x1b00修改為0xe42,rx_agc_compr_thres由0x2000修改為0x1f40,tx_agc_exp_thres由0xf86修改為0x09c4,tx_agc_compr_thres由0x1bde修改為0x1964 */ { 0x4000, 0x0000, 0xe42, 0xffb0, 0x1f40, 0xffff, 0x0000, 0x0000, 0x2000, 0x0000, 0x09c4, 0xffc0, 0x1964, 0xffff }, voc_cal_adv_agc_param,voc_cal_avc_param,#endif /* FEATURE_AUDIO_AGC */ …… …… };
第二篇:高通音頻調(diào)試總結(jié)
高通音頻調(diào)試總結(jié)
----夏珊珊
之前會(huì)議電話項(xiàng)目我們?cè)O(shè)計(jì)的方案是:外部的codec內(nèi)帶音頻處理dsp接6270模塊工作。外部codec+6270與高通的codec+dsp工作方式大致相同。所以調(diào)節(jié)音頻的工作原理可以以高通內(nèi)部的原理來(lái)作依據(jù)。
在調(diào)節(jié)會(huì)議電話的時(shí)候我們遇到了一個(gè)很大的問題,底噪。我們?cè)谶@個(gè)問題上糾結(jié)了很久。調(diào)節(jié)了mic的濾波電路,高通的AGC參數(shù),TX,RX filter 參數(shù),都沒有明顯的改善,后來(lái)我們把mic斷開接地,發(fā)現(xiàn)tx端還是有很大的噪音,截取輸入到高通的音頻噪音比較明顯,從而我們確定了這個(gè)噪音是由外部的codec所引入的。調(diào)整音頻的時(shí)候分析噪音來(lái)源比較重要,這樣相應(yīng)調(diào)整各部分增益來(lái)使噪音源影響盡量減小。
對(duì)于噪音處理,發(fā)現(xiàn)不管使用高通的AGC壓制噪音還是使用外部CODEC帶的DSP處理噪音都對(duì)音質(zhì)有很大的損傷。所以建議在調(diào)整音頻之前先最大限度的保證結(jié)構(gòu)和硬件設(shè)計(jì)的優(yōu)化性,畢竟軟件可以對(duì)數(shù)字噪音處理比較理想,但是對(duì)于模擬噪音就不是萬(wàn)能的了。具體對(duì)于噪音的處理后續(xù)會(huì)在文檔中提到。
高通音頻通道及調(diào)整
基本概念
回音:Near end 端不說(shuō)話,far end說(shuō)話了后經(jīng)過上圖的path,經(jīng)過喇叭播放后在空中回蕩,又被mic收回去,在far-end聽到了自己的聲音。
Echo path:從Echo Canceller出來(lái),經(jīng)過gain、a/d轉(zhuǎn)換 到speaker 經(jīng)外面的環(huán)境,然后又被mic收回,通過一系列的通道到Echo Canceller。
Acoustic echo path:從speaker 出來(lái),在環(huán)境中回蕩后再進(jìn)mic
從上圖可以看到:
如果TX進(jìn)來(lái)的ECHO跟我們估測(cè)的ECHO相近,Ataptive filter相減TX進(jìn)來(lái)的echo可以消除回音。
Ataptive filter:用于模擬echo。
PCD(Path Change Detect):當(dāng)使用者在移動(dòng),acoustic echo path也會(huì)改變。SPDET:用于檢測(cè)是far end speaker講話或者near end speaker,防止near end speaker講話的時(shí)候被抑制掉
理想的狀態(tài)是TX進(jìn)來(lái)的echo,跟我們估測(cè)echo相近,相減就為0,但是實(shí)際上不可能,所以需要一個(gè)DENS消除非線性的回音,我們選擇0~4KHZ是因?yàn)檫@個(gè)范圍的聲音是人聲范圍。
調(diào)整順序:
設(shè)置音量等級(jí)和AGC gain→EC gain和 limit→codec和mic的gain→Ec parameter。高通的default volume 基本上可以使用于各個(gè)普通的場(chǎng)合。
AGC gain 我們首先調(diào)整外圍的gain,比如tx agc、txvolume,AGC處理噪音比較有效,但是會(huì)相應(yīng)的犧牲tx端的音質(zhì)及音量大小。如果這個(gè)噪音會(huì)隨著Rx_Volume變化,在拔出手柄或者靜音Rx_CODEC_GAIN(0x0000),噪音明顯減弱,那么這個(gè)噪音是數(shù)字噪音,可以使用RxAGC減弱,具體的操作方法是:
? 設(shè)置Rx AGC工作在靜態(tài)增益模式(compFlinkAIGFlag=0x0000);? 減弱‘rx_agc_static_gain’為0dB(compFlinkStaticGain=0x2000);? 增加‘rx_agc_exp_thres’ 到-40dBm0mu(expFlinkThreshold=0x1180).同樣TX端的數(shù)字噪音也可以調(diào)整TX AGC 消除,調(diào)整的方式于RX AGC相同。在音頻通路上,建議調(diào)整增益的地方是codectxgain 和txvolume,這樣做的目的是防止送入codec處理的音頻信號(hào)太大出現(xiàn)削頂失真,使EC無(wú)法很好的模擬回音并處理掉回音。所以我們盡量在EC處理完畢后對(duì)信號(hào)進(jìn)行放大。
EC gain和limit 外圍的gain調(diào)整完畢后調(diào)整EC block gain(input gain、output gain)在調(diào)整的時(shí)候,rx volume 是調(diào)整到最大處理,這樣做為了避免rx 方向上聲音太小,揚(yáng)聲器聲音不夠大,不易于測(cè)試回音。
Nlpp limit:當(dāng)input太大的時(shí)候,rx收到的聲音特別大聲,但是spk不總是這么大聲,這樣使ECHO收到的東西太多失真,設(shè)置limit的話使突強(qiáng)的時(shí)候使進(jìn)入EC的echo不要太多。AF limit:控制TX方向的,EC 無(wú)法收斂,或者收斂的速度太慢,收到的東西突強(qiáng)太多,這樣使用limit 解決,用于限制突然大聲的信號(hào)。
Codec及mic的gain 隨后設(shè)置codec和mic的gain,文章開端曾提到若模塊有噪音,噪音的來(lái)源必須找到,并相對(duì)于此來(lái)設(shè)置codec及mic的gain。我們的應(yīng)用噪音是來(lái)自于codec芯片本身,所以對(duì)于mic增益的降低對(duì)噪音是沒有益處的,因?yàn)樵胍魰?huì)隨著ADC的放大而放大,衰減而減弱。Mic增益小,相對(duì)的ADCgain必須放大才能讓tx端聽到清晰的聲音,這樣反而把噪音放大了。所以為了讓產(chǎn)生的噪音最小,我們嘗試把mic的增益放大,ADC gain衰減來(lái)減弱噪音,達(dá)到比較好的效果。所以調(diào)整這部分的增益需要根據(jù)具體的情況,具體的模塊相應(yīng)調(diào)整。
Ec parameters 對(duì)回音來(lái)說(shuō),結(jié)構(gòu)及材料也有很大的影響因素。我們?cè)谠O(shè)計(jì)的時(shí)候必須要考慮到這些因素才能更好的實(shí)現(xiàn)音質(zhì)效果。比如SPK與mic必須盡量的拉開距離;mic腔體不能太大,mic使用專門的泡膜包起來(lái);機(jī)殼的材質(zhì)最好使用吸引的材料,防止大聲音播放的時(shí)候機(jī)殼震動(dòng)影響mic等等,這些在前期的時(shí)候最好設(shè)計(jì)考慮到。
關(guān)于EC參數(shù),高通有幾組默認(rèn)的回音參數(shù),從Speaker phone 到bluetooth 幾個(gè)等級(jí)。通常嘗試的時(shí)候從普通的模式到aggressive嘗試,ECHO canceller的肯定會(huì)傷害到double talk的能力,所以可以不用不壓抑太多就不要壓抑太多。如果嘗試模式的參數(shù)沒有echo,就選擇壓制的比較小的那組參數(shù)。總之是在Double talk 和echo canceller取得一個(gè)平衡。
細(xì)調(diào)
如果使用aggressive那組參數(shù),echo還是沒有消除,那么查找echo path delay Echo會(huì)隨著echo path改變,echo path有長(zhǎng)短。當(dāng)echo path delay設(shè)置不好,會(huì)使echo收斂不好。
如果不知道要設(shè)置多少的話就先設(shè)置為0,然后慢慢向上調(diào)整。
調(diào)整進(jìn)入AF的參數(shù)
調(diào)整進(jìn)入AF的兩個(gè)進(jìn)入EC的input的大小,他們的大小關(guān)系必須在一定的范圍,AF才能正常的收斂。
X[K]> Z[K],AF才能正常的收斂。從網(wǎng)路端送來(lái)的信號(hào),ECHO是從環(huán)境處理后的聲音,肯定是稍微有點(diǎn)小,但是如果經(jīng)過codec處理后就可能比X大,那么就使用Inputgain降低,然后增大OutputGain。
EC已經(jīng)收斂了,如果有非線性的echo無(wú)法消除,通過設(shè)置 DENS_tail_portion: DENS_tail_alpha: DENS_NL_atteu:
這幾個(gè)參數(shù)設(shè)置越大,echo 消除能力越好,但是影響double talk 高通給出的參數(shù)適用于大部分的場(chǎng)合,只需要在默認(rèn)參數(shù)的基礎(chǔ)上微調(diào)就可以了。這些參數(shù)的調(diào)整如果使用工具調(diào)整就比較方便了。下面就講講音頻調(diào)試工具。
音頻調(diào)試工具
音頻調(diào)試工具的比較(這個(gè)是引用了鐘明同學(xué)的文檔,他的高通文檔講解的比較清晰了,我對(duì)其引用補(bǔ)充下吧 O(^_^)O)
AT Command: 引用了6100的使用的AT命令作個(gè)簡(jiǎn)要的介紹。設(shè)置回音的ECHO命令A(yù)T+ECHO和AT+ECHO1可以設(shè)置回音的28個(gè)參數(shù)。
AT+CLVL: 音量級(jí)別設(shè)置 AT+RXVOL: RX端音量設(shè)置 AT+CMUT:靜音設(shè)置 AT+CMIC: mic音量設(shè)置 AT+SIDET:側(cè)邊音設(shè)置
AT+ECHO:設(shè)置手持與免提模式下的回聲各個(gè)參數(shù) AT+ECHO1:設(shè)置藍(lán)牙耳機(jī)與普通耳機(jī)的回聲參數(shù)
QACT 需要導(dǎo)入正確的audio_cal.xml,通常這個(gè)文件在工程里帶有 使用步驟
1.配置QPST,使使端口出現(xiàn)在active Phones tab。
如果設(shè)備沒有連接上或者XML文件導(dǎo)入錯(cuò)誤,在QACT v1.x的版本會(huì)彈出這個(gè)窗口。表示只能在PC上調(diào)整,而無(wú)法在線的把數(shù)據(jù)導(dǎo)入到模塊。
導(dǎo)入正確的xml文件
如果連接成功,可以看到以下圖片,選擇“否”,也就是不把XML 中默認(rèn)的結(jié)果導(dǎo)到模塊里面去。(我們這里只是調(diào)試,不要導(dǎo)入.XML 中默認(rèn)的值)
我們?cè)诶锩鏁?huì)調(diào)整的比較多的是: 調(diào)整codec的gains
Graphical拉AGC 參數(shù),從Data獲取參數(shù)
拉TX,RX filter 曲線
選擇對(duì)應(yīng)的path,device,拉出曲線后可見右邊的7個(gè)參數(shù),對(duì)應(yīng)于代碼里voc_pcm_path_cal_type結(jié)構(gòu)體中的tx_iir_filter。
QACT在線調(diào)試必須通話掛機(jī)后才生效。而且拉TX,RX filter無(wú)法模擬模塊里原來(lái)的聲音曲線,調(diào)節(jié)音質(zhì)曲線個(gè)人比較傾向于使用Qfilt。
QFILT 使用音頻分析儀器獲取未處理的(TX/RX filter全部設(shè)置為0)頻響曲線。把這個(gè)曲線數(shù)據(jù)保存為*.EXP格式。
之前在龍旗做測(cè)試的時(shí)候發(fā)現(xiàn)使用儀器獲取曲線數(shù)據(jù)無(wú)法直接保存為.EXP格式,保存為.ASM格式,將保存的數(shù)據(jù)去掉100之前及4000之后的數(shù)據(jù),加上固定的格式如下:
# 09-27-06 15:32:32.49 Hz dBPa/V 100 0.239521 105.83 0.174744 112 0.105024 118.322 0.0793721 125 0.0562545 132.288 0.0526554 140 0.0522274 149.666 0.0886258 160 0.144394 169.706 0.17004 180 0.128156 189.737 0.0954074 ???? 3768.29 0.286294 4000 FAIL 保存為.EXP格式,紅色的是RX的首尾固定格式,Tx的首尾固定格式如下:
# 09-29-06 15:05:11.04 Hz dBV/Pa ?? FAIL 使用QFILT導(dǎo)入對(duì)應(yīng)的RX或者TX數(shù)據(jù),導(dǎo)入數(shù)據(jù)之前必須配置右邊的相關(guān)設(shè)置。選擇Test Mode,Test Class,Test Path及Filter Type 0.676438
導(dǎo)入文件后的初始化曲線,這個(gè)曲線跟使用儀器測(cè)出來(lái)的頻響曲線一致。
通過調(diào)整濾波曲線后的圖如下:綠色是調(diào)整后的曲線,黃色的是原始的曲線,紅色的濾波器的調(diào)整曲線。我們調(diào)整曲線的目的是確保調(diào)整后曲線在兩條白色的曲線之間,且比較平滑。
調(diào)整到合適的曲線則點(diǎn)擊Get Cofficients 獲取調(diào)整的參數(shù)
在實(shí)際測(cè)試的時(shí)候如果把這個(gè)參數(shù)寫入程序然后編譯下載效率太慢了,這個(gè)時(shí)候可以直接使用QDV把這些實(shí)時(shí)的數(shù)據(jù)寫入到模塊,在通話的過程中實(shí)時(shí)生效,使用測(cè)試儀器測(cè)試使用調(diào)整后的參數(shù)曲線是否能通過測(cè)試。
QDV QDV使用需要導(dǎo)入正確的rpt文件。這個(gè)文件可以跟高通提SR獲取。
之前遇到使用了錯(cuò)誤的rpt文件導(dǎo)致有些參數(shù)設(shè)置不正確,所以一定要確保使用正確的文件。
啟動(dòng)QDV,首先看到以下的界面:
MEMA , MEMB , MEMC , MEMI值一定要設(shè)置正確,這個(gè)值可以通過查看代碼獲取。設(shè)置完成后進(jìn)入以下界面
它的工具條如下所示
選擇導(dǎo)入.rpt文件。
選擇完.rpt文件后 點(diǎn)擊 打開一個(gè)Text view 界面,右擊選擇需要修改的參數(shù)。
選擇new可以導(dǎo)入一個(gè)新的參數(shù)。
導(dǎo)入后如圖,選中變量后點(diǎn)擊
可以修改變量值。
調(diào)整EC block中參數(shù),配置完成后,必須寫ecParametersUpdated使回音參數(shù)生效。如下圖,設(shè)定了Echo參數(shù)后需要設(shè)置ecParametersUpdated為FFFF使其生效,設(shè)置完成后它會(huì)自動(dòng)跳變?yōu)?000.同樣,對(duì)于TX filtr和RX filter也需要寫一個(gè)load參數(shù)(txPcmFiltLoad和rxPcmFiltLoad)FFFF使寫入的參數(shù)生效,同樣這個(gè)參數(shù)生效后會(huì)自動(dòng)跳回0000。
第三篇:高通平臺(tái)常用調(diào)試Tool介紹1
高通平臺(tái)的常用的調(diào)試tool: QPST, QRCT, QXDM, Trace32(use JTAG)2013年09月07日 ? 綜合 ? 共 4410字 ? 字號(hào) 小 中 大 ? 評(píng)論關(guān)閉 OverView:
QPST 綜合工具, 傳輸文件, 查看device的EFS文件系統(tǒng), 代碼燒錄 QRCT 測(cè)試RF QXDM 看log JTAG trace32調(diào)試
QPST,QXDM的使用說(shuō)明,具體的可以看我上傳到csdn的資源文件,我都是看它,看了那個(gè)user guide就完全會(huì)了,很簡(jiǎn)單的
QPST是一個(gè)針對(duì)高通芯片開發(fā)的傳輸軟件。簡(jiǎn)單的說(shuō)就是用高通處理芯片的手機(jī)理論上都可以用QPST傳輸文件,可以修改C網(wǎng)機(jī)器內(nèi)部參數(shù)的軟件。一次可以track多臺(tái)電腦 QPST還可進(jìn)行代碼燒入 包括:
5個(gè) client applications ? QPST Configuration monitor the status of: Active phones Available serial ports Active clients To start QPST Configuration, from the Start menu, select Programs → QPST → QPST Configuration.? Service Programming provide service programming for CDMA phones that contain Qualcomm ASICs.With it, you can save SP data to a file, then download the data in that file to multiple phones.The SP application accesses settings regardless of the phone’s internal memory implementation.It is feature-aware and displays settings pages appropriate to the phone being programmed.To start SP, from the Start menu, select Programs → QPST → Service Programming.? Software Download ? RF NV Item Manager ? EFS Explorer The EFS Explorer application lets you navigate the embedded file system(EFS)of phones that support EFS.It is similar in function to the Windows Explorer program on a PC.To start EFS Explorer, from the Start menu, select Programs → QPST → EFS Explorer.When EFS Explorer launches, it displays a Phone Selection dialog that lists the phones currently being monitored by the QPST server, as shown in Figure Creating a new directory ? When you create a directory in the phone’s EFS, the directory is created on the phone and the file structure list is refreshed.To create a directory: 1.Navigate to the location where you want to create a new directory.2.From the File menu, select New → Directory.The Create Directory dialog, as shown in Figure below 3.Type a name for the file in the field.4.Click OK.Two standalone utilities,--QCNView--Roaming List Editor, complete the QPST tool set.QRCT
? QRCT is a Windows toolkit designed to control a QUALCOMM phone such as a Form Factor Accurate(FFA)for testing RF in three system modes – CDMA 2000, GSM, and WCDMA.? This application requires Advanced Mode Subscriber Software(AMSS)software with FTM built into it.The FTM mode must be enabled before using the CDMA 2000, GSM, and WCDMA RF controls.? FTM is a mode of operation that allows a user to perform diagnostic or design verification functionality by exposing functions not discretely available to the user in AMSS mode.FTM does not provide the ability to make phone calls and is not driven by the AMSS Call Processing State Machine.? QRCT uses the Qualcomm Manufacturing Support Library(QMSL)for all communication with the phone.It is possible to determine the exact function calls by monitoring the QMSL Text Log.The user can then replicate any QRCT sequence by calling QMSL in their own program.QXDM是監(jiān)視手機(jī)狀態(tài)的,還有一些簡(jiǎn)單的控制功能
? The QUALCOMM? Extensible Diagnostic Monitor(QXDM)provides a diagnostic client for Dual-Mode Subscriber Station(DMSS)and newer User Equipment(UE)software, Advanced Mobile Subscriber Software(AMSS).? QXDM was developed to provide a rapid prototyping platform for new diagnostic clients and diagnostic protocol packets.It provides a Graphical User Interface(GUI)that displays data transmitted to and from the DMSS.Options menu on QXDM: QXDM communications menu: ? Lists all the available ports on the system and their properties ? Ports listed in this are those that have been added in the QPST Configuration tool for monitoring Traces on the QXDM: JTAG
? Joint Test Action Group(JTAG)is the common name for what was later standardized as the IEEE 1149.1 Standard Test Access Port and Boundary-Scan Architecture.It was initially devised for testing printed circuit boards using boundary scan and is still widely used for this application.? Today JTAG is also widely used for IC debug ports.In the embedded processor market, essentially all modern processors support JTAG when they have enough pins.Embedded systems development relies on debuggers talking to chips with JTAG to perform operations like single stepping and break pointing.Digital electronics products such as cell phones or a wireless access point generally have no other debug or test interfaces ? Used for debugging & storing firmware.
第四篇:alsa音頻總結(jié)
Linux音頻驅(qū)動(dòng)總結(jié)
參考文章:http://blog.csdn.net/droidphone/
http://blog.chinaunix.net/uid/22917448.html
分析只列出部分重要代碼,具體請(qǐng)參考linux3.0內(nèi)核代碼。
Alsa架構(gòu)整體來(lái)說(shuō)十分復(fù)雜,但對(duì)于驅(qū)動(dòng)移植來(lái)說(shuō)我們僅僅只需要關(guān)心ASOC就足夠了。在學(xué)習(xí)asoc之前我們先了解一些專業(yè)術(shù)語(yǔ):
ASoC currently supports the three main Digital Audio Interfaces(DAI)found on SoC controllers and portable audio CODECs today, namely AC97, I2S and PCM.ASoC現(xiàn)在支持如今的SoC控制器和便攜音頻解碼器上的三個(gè)主要數(shù)字音頻接口,即AC97,I2S,PCM(與pcm音頻格式注意區(qū)分,前者是一種音頻接口,后者是一種輸入聲卡的音頻格式)。
AC97 AC97 ====
AC97 is a five wire interface commonly found on many PC sound cards.It is now also popular in many portable devices.This DAI has a reset line and time multiplexes its data on its SDATA_OUT(playback)and SDATA_IN(capture)lines.The bit clock(BCLK)is always driven by the CODEC(usually 12.288MHz)and the frame(FRAME)(usually 48kHz)is always driven by the controller.Each AC97 frame is 21uS long and is divided into 13 time slots.AC97是一種個(gè)人電腦聲卡上常見的五線接口?,F(xiàn)在在很多便攜設(shè)備中也很流行。這個(gè)數(shù)字音頻接口有一個(gè)復(fù)位線,分時(shí)在SDATA_OUT(回放)和SDATA_IN(捕獲)線上傳送數(shù)據(jù)。位時(shí)鐘常由解碼器驅(qū)動(dòng)(通常是12.288MHz).幀時(shí)鐘(通常48kHz)總是由控制器驅(qū)動(dòng)。每個(gè)AC97幀21uS,并分為13個(gè)時(shí)間槽。
I2S I2S ===
I2S is a common 4 wire DAI used in HiFi, STB and portable devices.The Tx and Rx lines are used for audio transmission, whilst the bit clock(BCLK)and left/right clock(LRC)synchronise the link.I2S is flexible in that either the controller or CODEC can drive(master)the BCLK and LRC clock lines.Bit clock usually varies depending on the sample rate and the master system clock(SYSCLK).LRCLK is the same as the sample rate.A few devices support separate ADC and DAC LRCLKs, this allows for simultaneous capture and playback at different sample rates.I2S是一個(gè)4線數(shù)字音頻接口,常用于HiFi,STB便攜設(shè)備。Tx 和Rx信號(hào)線用于音頻傳輸。而位時(shí)鐘和左右時(shí)鐘(LRC)用于同步鏈接。I2S具有靈活性,因?yàn)榭刂破骱徒獯a器都可以控制位時(shí)鐘和左右時(shí)鐘。位時(shí)鐘因采樣率和主系統(tǒng)時(shí)鐘而有不同。LRCLK與采樣率相同。少數(shù)設(shè)備支持獨(dú)立的ADC和DAC的LRCLK。這使在不同采樣率情況下同步捕獲和回放成為可能。
I2S has several different operating modes:-I2S有幾個(gè)不同的操作模式:
o I2SMSB is transmitted on transition of LRC.左對(duì)齊模式:MSB在LRC傳送時(shí)傳送。
o Right JustifiedMSB is transmitted on falling edge of first BCLK after FRAME/SYNC.模式A-MSB在FRAME/SYNC后第一個(gè)BCLK的下降沿傳送。
o Mode Busing I2C, 3 Wire(SPI)or both APIs 3)Mixers and audio controls 4)Codec audio operations 1)解碼器數(shù)字音頻接口和PCM配置。
2)解碼器控制IO-使用I2C,3總線(SPI)或兩個(gè)都有。3)混音器和音頻控制。4)解碼器音頻操作。
Optionally, codec drivers can also provide:-解碼器驅(qū)動(dòng)可以選擇性提供:
5)DAPM description.6)DAPM event handler.7)DAC Digital mute control.5)動(dòng)態(tài)音頻電源管理描述。6)動(dòng)態(tài)音頻電源管理事件控制。7)數(shù)模轉(zhuǎn)換數(shù)字消音控制。SoC DAI Drivers 板級(jí)DAI驅(qū)動(dòng) ===============
Each SoC DAI driver must provide the following features:-每個(gè)SoC DAI驅(qū)動(dòng)都必須提供如下性能:
1)Digital audio interface(DAI)description 1)數(shù)字音頻接口描述
2)Digital audio interface configuration 2)數(shù)字音頻接口配置 3)PCM's description 3)PCM描述
4)SYSCLK configuration 4)系統(tǒng)時(shí)鐘配置
5)Suspend and resume(optional)5)掛起和恢復(fù)(可選的)
以上由君子翻譯,本人實(shí)在沒辦法比他描述的更好了,所以把重要的部分提取出來(lái)直接copy。在這里對(duì)君子表示由衷感謝,賦上君子注。君子注:
您現(xiàn)在所閱讀的,是君子閱讀Linux音頻SoC驅(qū)動(dòng)時(shí),寫下的文檔譯文。
君子寫些譯文,一方面是作為自己的筆記,幫助記憶,另一方面也希望能對(duì)他人有所幫助。如果您能于君子的譯文中有所收獲,則吾心甚慰
現(xiàn)在我們開始分析ASOC:
ASoC被分為Machine、Platform和Codec三大部分。其中的Machine驅(qū)動(dòng)負(fù)責(zé)Platform和Codec之間的耦合和設(shè)備或板子特定的代碼。
看起來(lái)挺復(fù)雜,其實(shí)需要我們做的事情并不多,大部分內(nèi)核已經(jīng)完成。下面我們分析哪些是我們需要自己做的:
codec驅(qū)動(dòng):負(fù)責(zé)音頻解碼。這部分代碼完全無(wú)平臺(tái)無(wú)關(guān),設(shè)備原廠提供,我們只需要把它加進(jìn)內(nèi)核編譯就好了。platform驅(qū)動(dòng):與處理器芯片相關(guān),這部分代碼在該芯片商用之前方案產(chǎn)商提供的demo板已完全確定了,也就是說(shuō)我們只需要使用就可以了。
machine驅(qū)動(dòng):好了,到了最關(guān)鍵的地方了,machine驅(qū)動(dòng)是耦合platform和codec驅(qū)動(dòng),同時(shí)與上層交互的代碼。由于上層是標(biāo)準(zhǔn)的alsa架構(gòu),所以下層接口肯定要做了統(tǒng)一,所以我很負(fù)責(zé)的告訴你,這部分由machine本身的platform驅(qū)動(dòng)和platform設(shè)備組成(請(qǐng)跟asoc的platform驅(qū)動(dòng)區(qū)別),platform驅(qū)動(dòng)內(nèi)核幫我們完成了,所以你無(wú)須過多的關(guān)心你的驅(qū)動(dòng)怎么跟上層alsa怎么衍接的問題,我們只需要注冊(cè)一個(gè)machine的platform設(shè)備以及完成platform和codec耦合就ok
asoc的關(guān)系圖如下:(以下適應(yīng)于linux3.0。linux2.6會(huì)有所不同)
上圖把a(bǔ)soc架構(gòu)顯示的淋漓盡致,如果你分析了asoc你就會(huì)發(fā)現(xiàn)上圖描述的結(jié)構(gòu)以及函數(shù)真的一個(gè)都跑不了。
Machie:
Machine platform device:(~/sound/soc/samsung/smdk_wm8994.c)
1.smdk_snd_device = platform_device_alloc(“soc-audio”,-1);2.if(!smdk_snd_device)3.return-ENOMEM;4.5.platform_set_drvdata(smdk_snd_device, &smdk);6.7.ret = platform_device_add(smdk_snd_device);
1.static struct snd_soc_dai_link smdk_dai[] = { 2.{ /* Primary DAI i/f */
3..name = “WM8994 AIF1”, 4..stream_name = “Pri_Dai”, 5..cpu_dai_name = “samsung-i2s.0”, 6..codec_dai_name = “wm8994-aif1”, 7..platform_name = “samsung-audio”, 8..codec_name = “wm8994-codec”, 9..init = smdk_wm8994_init_paiftx, 10..ops = &smdk_ops, 11.}, { /* Sec_Fifo Playback i/f */
12..name = “Sec_FIFO TX”, 13..stream_name = “Sec_Dai”, 14..cpu_dai_name = “samsung-i2s.4”, 15..codec_dai_name = “wm8994-aif1”, 16..platform_name = “samsung-audio”, 17..codec_name = “wm8994-codec”, 18..ops = &smdk_ops, 19.}, 20.};21.22.static struct snd_soc_card smdk = { 23..name = “SMDK-I2S”, 24..owner = THIS_MODULE, 25..dai_link = smdk_dai,26..num_links = ARRAY_SIZE(smdk_dai), 27.};
通過snd_soc_card結(jié)構(gòu),又引出了Machine驅(qū)動(dòng)的另外兩個(gè)個(gè)數(shù)據(jù)結(jié)構(gòu):
? ? snd_soc_dai_link(實(shí)例:smdk_dai[])snd_soc_ops(實(shí)例:smdk_ops)
snd_soc_dai_link看名字就知道,很明顯它是起耦合鏈接作用的。它指定了Platform、Codec、codec_dai、cpu_dai的名字,稍后Machine驅(qū)動(dòng)將會(huì)利用這些名字去匹配已經(jīng)在系統(tǒng)中注冊(cè)的platform,codec,dai。
snd_soc_ops連接Platform和Codec的dai_link對(duì)應(yīng)的ops操作函數(shù),本例就是smdk_ops,它只實(shí)現(xiàn)了hw_params函數(shù):smdk_hw_params。
到此為止,最主要的部分machine的平臺(tái)設(shè)備注冊(cè)我們完成了。
下面我們關(guān)注machine平臺(tái)驅(qū)動(dòng)部分(這部分內(nèi)核不需要我們實(shí)現(xiàn),但我們需要知道它是怎么工作的)
ASoC的platform_driver在以下文件中定義:sound/soc/soc-core.c。還是先從模塊的入口看起:
[cpp] view plaincopy 1.static int __init snd_soc_init(void)2.{ 3.......4.return platform_driver_register(&soc_driver);5.}
soc_driver的定義如下:
[cpp] view plaincopy
1./* ASoC platform driver */
2.static struct platform_driver soc_driver = { 3..driver = {
4..name = “soc-audio”, //確保你注冊(cè)machine平臺(tái)設(shè)備和它保持一致 5..owner = THIS_MODULE, 6..pm = &soc_pm_ops, 7.},8..probe = soc_probe, 9..remove = soc_remove, 10.};
初始化入口soc_probe()
soc_probe函數(shù)本身很簡(jiǎn)單,它先從platform_device參數(shù)中取出snd_soc_card,然后調(diào)用snd_soc_register_card,通過snd_soc_register_card,為snd_soc_pcm_runtime數(shù)組申請(qǐng)內(nèi)存,每一個(gè)dai_link對(duì)應(yīng)snd_soc_pcm_runtime數(shù)組的一個(gè)單元,然后把snd_soc_card中的dai_link配置復(fù)制到相應(yīng)的snd_soc_pcm_runtime中,最后,大部分的工作都在snd_soc_instantiate_card中實(shí)現(xiàn),下面就看看snd_soc_instantiate_card做了些什么: 該函數(shù)首先利用card->instantiated來(lái)判斷該卡是否已經(jīng)實(shí)例化,如果已經(jīng)實(shí)例化則直接返回,否則遍歷每一對(duì)dai_link,進(jìn)行codec、platform、dai的綁定工作,下只是代碼的部分選節(jié),詳細(xì)的代碼請(qǐng)直接參考完整的代碼樹。static int soc_probe(struct platform_device *pdev){
struct snd_soc_card *card = platform_get_drvdata(pdev);//別忘記了machine的platform_set_drvdata //取出snd_soc_card
.............ret = snd_soc_register_card(card);//注冊(cè)............}
下面我們看snd_soc_register_card()函數(shù):
int snd_soc_register_card(struct snd_soc_card *card){
。。。。
card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime)*
(card->num_links + card->num_aux_devs),GFP_KERNEL);//為snd_soc_pcm_runtime數(shù)組申請(qǐng)內(nèi)存,每一個(gè)dai_link對(duì)應(yīng)一個(gè)snd_soc_pcm_runtime數(shù)組單元。。。。
for(i = 0;i < card->num_links;i++)
card->rtd[i].dai_link = &card->dai_link[i];//把snd_soc_card中的dai_link復(fù)制到相應(yīng)的snd_soc_pcm_runtime。。。。
snd_soc_instantiate_cards();//將調(diào)用snd_soc_instantiate_card()//最為重要 }
下面我們分析snd_soc_instantiate_card()函數(shù):
static void snd_soc_instantiate_card(struct snd_soc_card *card){
。。。。
if(card->instantiated){ //判斷該卡是否已經(jīng)實(shí)例化,如果是就返回
mutex_unlock(&card->mutex);
return;
}
/* bind DAIs */
for(i = 0;i < card->num_links;i++)//否則遍例每一對(duì)dai_link,進(jìn)行codec,flatrom,dai的綁定工作
soc_bind_dai_link(card, i);/* ******************************************************************************************************************************************************************
ASoC定義了三個(gè)全局的鏈表頭變量:codec_list、dai_list、platform_list,系統(tǒng)中所有的Codec、DAI、Platform都在注冊(cè)時(shí)連接到這三個(gè)全局鏈表上。soc_bind_dai_link函數(shù)逐個(gè)掃描這三個(gè)鏈表,根據(jù)card->dai_link[]中的名稱進(jìn)行匹配,匹配后把相應(yīng)的codec,dai和platform實(shí)例賦值到card->rtd[]中(snd_soc_pcm_runtime)。經(jīng)過這個(gè)過程后,snd_soc_pcm_runtime:(card->rtd)中保存了本Machine中使用的Codec,DAI和Platform驅(qū)動(dòng)的信息。
*****************************************************************************************************************************************************************/
/* bind completed ? */
if(card->num_rtd!= card->num_links){
mutex_unlock(&card->mutex);
return;
}
。。。。。
/* card bind complete so register a sound card */
ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,card->owner, 0, &card->snd_card)。。。。。
card->snd_card->dev = card->dev;
card->dapm.bias_level = SND_SOC_BIAS_OFF;
card->dapm.dev = card->dev;
card->dapm.card = card;
list_add(&card->dapm.list, &card->dapm_list);//初始化codec緩存,創(chuàng)建聲卡實(shí)例
。。。。。。。//下面是最重要的probe匹配工作
if(card->probe){
ret = card->probe(card);
if(ret < 0)
goto card_probe_error;
}
。。。。。
ret = soc_probe_dai_link(card, i, order);//主要的耦合鏈接工作在此函數(shù)完成。。。。。
ret = soc_probe_aux_dev(card, i)。。。。。
if(card->late_probe){//最后的聲卡初始化工作,ret = card->late_probe(card);
}
。。。。。
ret = snd_card_register(card->snd_card);//然后調(diào)用標(biāo)準(zhǔn)的alsa驅(qū)動(dòng)的聲卡函數(shù)進(jìn)行聲卡注冊(cè)
。。。。。
}
到這里聲卡已經(jīng)注冊(cè)好了,聲卡可以正常工作了,我們?cè)俜治鲎詈笠粋€(gè)函數(shù),也就是它們是怎么匹配的 soc_probe_dai_link():
static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order){
。。。。。
/* probe the cpu_dai */
if(!cpu_dai->probed &&
cpu_dai->driver->probe_order == order){
if(!try_module_get(cpu_dai->dev->driver->owner))
return-ENODEV;
if(cpu_dai->driver->probe){
ret = cpu_dai->driver->probe(cpu_dai);
if(ret < 0){
printk(KERN_ERR “asoc: failed to probe CPU DAI %sn”, cpu_dai->name);
module_put(cpu_dai->dev->driver->owner);
return ret;
}
}
cpu_dai->probed = 1;
/* mark cpu_dai as probed and add to card dai list */
list_add(&cpu_dai->card_list, &card->dai_dev_list);
}
/* probe the CODEC */
if(!codec->probed &&
codec->driver->probe_order == order){
ret = soc_probe_codec(card, codec);
if(ret < 0)
return ret;
}
/* probe the platform */
if(!platform->probed &&
platform->driver->probe_order == order){
ret = soc_probe_platform(card, platform);
if(ret < 0)
return ret;
}
/* probe the CODEC DAI */
if(!codec_dai->probed && codec_dai->driver->probe_order == order){
if(codec_dai->driver->probe){
ret = codec_dai->driver->probe(codec_dai);
if(ret < 0){
printk(KERN_ERR “asoc: failed to probe CODEC DAI %sn”, codec_dai->name);
return ret;
}
}
/* mark codec_dai as probed and add to card dai list */
codec_dai->probed = 1;
list_add(&codec_dai->card_list, &card->dai_dev_list);
}
/* complete DAI probe during last probe */
if(order!= SND_SOC_COMP_ORDER_LAST)return 0;
。。。。。
/* create the pcm */
ret = soc_new_pcm(rtd, num);//如果上面都匹配成功將創(chuàng)建標(biāo)準(zhǔn)的alsa的pcm邏輯設(shè)備
。。。。。
}
好了,到此為止我們最主要的部分machine部分分析完成了。接著是codec驅(qū)動(dòng)部分:
Codec簡(jiǎn)介
在移動(dòng)設(shè)備中,Codec的作用可以歸結(jié)為4種,分別是:
? ? 對(duì)PCM等信號(hào)進(jìn)行D/A轉(zhuǎn)換,把數(shù)字的音頻信號(hào)轉(zhuǎn)換為模擬信號(hào)
對(duì)Mic、Linein或者其他輸入源的模擬信號(hào)進(jìn)行A/D轉(zhuǎn)換,把模擬的聲音信號(hào)轉(zhuǎn)變CPU能夠處理的數(shù)字信號(hào)
? 對(duì)音頻通路進(jìn)行控制,比如播放音樂,收聽調(diào)頻收音機(jī),又或者接聽電話時(shí),音頻信號(hào)在codec內(nèi)的流通路線是不一樣的
? 對(duì)音頻信號(hào)做出相應(yīng)的處理,例如音量控制,功率放大,EQ控制等等
ASoC對(duì)Codec的這些功能都定義好了一些列相應(yīng)的接口,以方便地對(duì)Codec進(jìn)行控制。ASoC對(duì)Codec驅(qū)動(dòng)的一個(gè)基本要求是:驅(qū)動(dòng)程序的代碼必須要做到平臺(tái)無(wú)關(guān)性,以方便同一個(gè)Codec的代碼不經(jīng)修改即可用在不同的平臺(tái)上。以下的討論基于wolfson的Codec芯片WM8994,kernel的版本3.3.x。
描述Codec的最主要的幾個(gè)數(shù)據(jù)結(jié)構(gòu)分別是:snd_soc_codec,snd_soc_codec_driver,snd_soc_dai,snd_soc_dai_driver,其中的snd_soc_dai和snd_soc_dai_driver在ASoC的Platform驅(qū)動(dòng)中也會(huì)使用到,Platform和Codec的DAI通過snd_soc_dai_link結(jié)構(gòu),在Machine驅(qū)動(dòng)中進(jìn)行綁定連接。
Codec的注冊(cè)
因?yàn)镃odec驅(qū)動(dòng)的代碼要做到平臺(tái)無(wú)關(guān)性,要使得Machine驅(qū)動(dòng)能夠使用該Codec,Codec驅(qū)動(dòng)的首要任務(wù)就是確定snd_soc_codec和snd_soc_dai的實(shí)例,并把它們注冊(cè)到系統(tǒng)中,注冊(cè)后的codec和dai才能為Machine驅(qū)動(dòng)所用。以WM8994為例,對(duì)應(yīng)的代碼位置:/sound/soc/codecs/wm8994.c,模塊的入口函數(shù)注冊(cè)了一個(gè)platform driver:
[html] view plaincopy
1.static struct platform_driver wm8994_codec_driver = { 2..driver = { 3..name = “wm8994-codec”, //注意machine device里面和這里保持一致 4..owner = THIS_MODULE, 5.}, 6..probe = wm8994_probe, 7..remove = __devexit_p(wm8994_remove), 8.};9.10.module_platform_driver(wm8994_codec_driver);有platform driver,必定會(huì)有相應(yīng)的platform device,platform device其實(shí)在我們之前講過的machine device注冊(cè)時(shí)已經(jīng)引入了。
[html] view plaincopy
1.static int __devinit wm8994_probe(struct platform_device *pdev)2.{
3.return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, 4.wm8994_dai, ARRAY_SIZE(wm8994_dai));5.}
其中,soc_codec_dev_wm8994和wm8994_dai的定義如下(代碼中定義了3個(gè)dai,這里只列出第一個(gè)):
[html] view plaincopy
1.static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { 2..probe = wm8994_codec_probe, 3..remove = wm8994_codec_remove, 4..suspend = wm8994_suspend, 5..resume = wm8994_resume,6..set_bias_level = wm8994_set_bias_level, 7..reg_cache_size = WM8994_MAX_REGISTER, 8..volatile_register = wm8994_soc_volatile, 9.};
[html] view plaincopy
1.static struct snd_soc_dai_driver wm8994_dai[] = { 2.{
3..name = “wm8994-aif1”, 4..id = 1, 5..playback = {
6..stream_name = “AIF1 Playback”, 7..channels_min = 1, 8..channels_max = 2, 9..rates = WM8994_RATES, 10..formats = WM8994_FORMATS, 11.},12..capture = {
13..stream_name = “AIF1 Capture”, 14..channels_min = 1, 15..channels_max = 2, 16..rates = WM8994_RATES, 17..formats = WM8994_FORMATS, 18.},19..ops = &wm8994_aif1_dai_ops, 20.}, 21.......22.}
可見,Codec驅(qū)動(dòng)的第一個(gè)步驟就是定義snd_soc_codec_driver和snd_soc_dai_driver的實(shí)例,然后調(diào)用snd_soc_register_codec函數(shù)對(duì)Codec進(jìn)行注冊(cè)。
snd_soc_register_codec()函數(shù)是machine driver提供的,只要注冊(cè)成功后codec提供的操作函數(shù)就能正常提供給machine driver使用了。int snd_soc_register_codec(struct device *dev,const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai){ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)。。。。。。
/* create CODEC component name */ codec->name = fmt_single_name(dev, &codec->id);/*Machine驅(qū)動(dòng)定義的snd_soc_dai_link中會(huì)指定每個(gè)link的codec和dai的名字,進(jìn)行匹配綁定時(shí)就是通過和這里的名字比較,從而找到該Codec的 */
// 然后初始化它的各個(gè)字段,多數(shù)字段的值來(lái)自上面定義的snd_soc_codec_driver的實(shí)例soc_codec_dev_wm8994: codec->write = codec_drv->write;codec->read = codec_drv->read;codec->volatile_register = codec_drv->volatile_register;codec->readable_register = codec_drv->readable_register;codec->writable_register = codec_drv->writable_register;codec->dapm.bias_level = SND_SOC_BIAS_OFF;codec->dapm.dev = dev;codec->dapm.codec = codec;codec->dapm.seq_notifier = codec_drv->seq_notifier;codec->dev = dev;codec->driver = codec_drv;codec->num_dai = num_dai;mutex_init(&codec->mutex);
/* allocate CODEC register cache */ if(codec_drv->reg_cache_size && codec_drv->reg_word_size){ reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;codec->reg_size = reg_size;/* it is necessary to make a copy of the default register cache
* because in the case of using a compression type that requires
* the default register cache to be marked as __devinitconst the
* kernel might have freed the array by the time we initialize
* the cache.*/ if(codec_drv->reg_cache_default){ codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,reg_size, GFP_KERNEL);if(!codec->reg_def_copy){ ret =-ENOMEM;goto fail;} } }
。。。。。。/* register any DAIs */ if(num_dai){ ret = snd_soc_register_dais(dev, dai_drv, num_dai);//通過snd_soc_register_dais函數(shù)對(duì)本Codec的dai進(jìn)行注冊(cè) if(ret < 0)goto fail;}
mutex_lock(&client_mutex);list_add(&codec->list, &codec_list);/*最后,它把codec實(shí)例鏈接到全局鏈表codec_list中,并且調(diào)用snd_soc_instantiate_cards是函數(shù)觸發(fā)Machine驅(qū)動(dòng)進(jìn)行一次匹配綁定操作 */
snd_soc_instantiate_cards();mutex_unlock(&client_mutex)。。。。。}
好了,在這里我們的codec驅(qū)動(dòng)也分析完了,其實(shí)這部分都是與平臺(tái)無(wú)關(guān)代碼,一般也不需要改動(dòng),這部分我們從設(shè)備原廠拿到代碼后丟上去就可以了,只是我們?cè)趯憁achine device的時(shí)候要注意和這里的名字匹配。接下來(lái)是asoc的platform驅(qū)動(dòng):
Platform驅(qū)動(dòng)的主要作用是完成音頻數(shù)據(jù)的管理,最終通過CPU的數(shù)字音頻接口(DAI)把音頻數(shù)據(jù)傳送給Codec進(jìn)行處理,最終由Codec輸出驅(qū)動(dòng)耳機(jī)或者是喇叭的音信信號(hào)。在具體實(shí)現(xiàn)上,ASoC有把Platform驅(qū)動(dòng)分為兩個(gè)部分:snd_soc_platform_driver和snd_soc_dai_driver。其中,platform_driver負(fù)責(zé)管理音頻數(shù)據(jù),把音頻數(shù)據(jù)通過dma或其他操作傳送至cpu dai中,dai_driver則主要完成cpu一側(cè)的dai的參數(shù)配置,同時(shí)也會(huì)通過一定的途徑把必要的dma等參數(shù)與snd_soc_platform_driver進(jìn)行交互。
snd_soc_platform_driver的注冊(cè)
通常,ASoC把snd_soc_platform_driver注冊(cè)為一個(gè)系統(tǒng)的platform_driver,不要被這兩個(gè)想像的術(shù)語(yǔ)所迷惑,前者只是針對(duì)ASoC子系統(tǒng)的,后者是來(lái)自Linux的設(shè)備驅(qū)動(dòng)模型。我們要做的就是:
? ? 定義一個(gè)snd_soc_platform_driver結(jié)構(gòu)的實(shí)例;
在platform_driver的probe回調(diào)中利用ASoC的API:snd_soc_register_platform()注冊(cè)上面定義的實(shí)例;
? 實(shí)現(xiàn)snd_soc_platform_driver中的各個(gè)回調(diào)函數(shù);
以kernel3.3中的/sound/soc/samsung/dma.c為例:
[cpp] view plaincopy
1.static struct snd_soc_platform_driver samsung_asoc_platform = { 2..ops = &dma_ops, 3..pcm_new = dma_new, 4..pcm_free = dma_free_dma_buffers, 5.};6.7.static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)8.{ 9.return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);10.} 11.12.static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev)13.{ 14.snd_soc_unregister_platform(&pdev->dev);15.return 0;16.} 17.18.static struct platform_driver asoc_dma_driver = { 19..driver = { 20..name = “samsung-audio”, 21..owner = THIS_MODULE, 22.}, 23.24..probe = samsung_asoc_platform_probe, 25..remove = __devexit_p(samsung_asoc_platform_remove), 26.};27.28.module_platform_driver(asoc_dma_driver);snd_soc_register_platform()該函數(shù)用于注冊(cè)一個(gè)snd_soc_platform,只有注冊(cè)以后,它才可以被Machine驅(qū)動(dòng)使用。它的代碼已經(jīng)清晰地表達(dá)了它的實(shí)現(xiàn)過程:
? ? ? ? ? 為snd_soc_platform實(shí)例申請(qǐng)內(nèi)存;
從platform_device中獲得它的名字,用于Machine驅(qū)動(dòng)的匹配工作; 初始化snd_soc_platform的字段;
把snd_soc_platform實(shí)例連接到全局鏈表platform_list中;
調(diào)用snd_soc_instantiate_cards,觸發(fā)聲卡的machine、platform、codec、dai等的匹配工作;
cpu的snd_soc_dai driver驅(qū)動(dòng)的注冊(cè)
dai驅(qū)動(dòng)通常對(duì)應(yīng)cpu的一個(gè)或幾個(gè)I2S/PCM接口,與snd_soc_platform一樣,dai驅(qū)動(dòng)也是實(shí)現(xiàn)為一個(gè)platform driver,實(shí)現(xiàn)一個(gè)dai驅(qū)動(dòng)大致可以分為以下幾個(gè)步驟:
? ? 定義一個(gè)snd_soc_dai_driver結(jié)構(gòu)的實(shí)例;
在對(duì)應(yīng)的platform_driver中的probe回調(diào)中通過API:snd_soc_register_dai或者snd_soc_register_dais,注冊(cè)snd_soc_dai實(shí)例;
? ? 實(shí)現(xiàn)snd_soc_dai_driver結(jié)構(gòu)中的probe、suspend等回調(diào);
實(shí)現(xiàn)snd_soc_dai_driver結(jié)構(gòu)中的snd_soc_dai_ops字段中的回調(diào)函數(shù);
snd_soc_register_dai 這個(gè)函數(shù)在上一篇介紹codec驅(qū)動(dòng)的博文中已有介紹
具體不再分析,這個(gè)驅(qū)動(dòng)也不需要用戶做任務(wù)修改,所以只要知道它的作用就已經(jīng)夠了。就像電話機(jī)一樣,我們只要知道電話怎么打就夠了,至于它怎么連接我們并不太需要關(guān)心。
第五篇:調(diào)試總結(jié)
調(diào)試總結(jié)
來(lái)到海南昌江項(xiàng)目部電氣隊(duì)已經(jīng)有50多天了,我有幸加入到調(diào)試隊(duì)。聽?zhēng)煾祩冋f(shuō):“調(diào)試現(xiàn)在改新模式了,我們是第一批加入進(jìn)來(lái)的,機(jī)會(huì)真是千載難逢,要我們務(wù)必抓住這次機(jī)會(huì)!”聽后我激動(dòng)異常,暗暗下決心機(jī)會(huì)是留給有準(zhǔn)備的人的,現(xiàn)在機(jī)會(huì)就放在我面前,我若不抓住,豈不是白白浪費(fèi)?所以,努力與學(xué)習(xí)以及實(shí)踐與理論都將為此而進(jìn)行。
調(diào)試是一門技術(shù)活,彭師傅說(shuō)過:“干調(diào)試要多問,多看,少動(dòng)手。”說(shuō)實(shí)話,剛聽到這我就想“不是應(yīng)該多動(dòng)手嗎?這樣才能更加的熟練技能?!焙髞?lái),我明白了“少動(dòng)手”的意思是不要亂動(dòng)、亂摸,調(diào)試不僅危險(xiǎn)高壓電,而且一旦產(chǎn)生事故十分嚴(yán)重,那些儀器儀表十分昂貴。一定要熟悉弄懂后才按規(guī)定操作,這也就要坐到前面說(shuō)的“多問、多看。”
最近我們干的活主要是環(huán)吊、門吊、半門吊,具體就是一些接線,打磨,放電纜、裝網(wǎng)架等等。在此過程中我深深明白四個(gè)字:眼高手低。這也是在學(xué)校時(shí),實(shí)習(xí)老師常常教導(dǎo)我們的“干活最容易犯的是眼高手低,一個(gè)很簡(jiǎn)單的活看起來(lái)很容易,一旦動(dòng)手,你就發(fā)現(xiàn)不是那么回事?!爆F(xiàn)在回想起來(lái),才明白老師的淳淳教導(dǎo)。就在前幾天,郭師傅跟牛師傅交給我一個(gè)任務(wù),讓我協(xié)助焊工把角鋼焊上,再把網(wǎng)架固定在上面,結(jié)果我沒把角鋼扶正,導(dǎo)致角鋼向兩邊偏了整整5cm。事后,牛師傅嚴(yán)厲的批評(píng)了我,我無(wú)言以對(duì),默默的思索自己錯(cuò)在了什么地方。最后,我用磨光機(jī)把角鋼切下來(lái),重新再安裝上去。就是這一次,我真正懂得了“眼高手低?!碑?dāng)然了,這段時(shí)間,我也發(fā)生了許多別的失誤。例如:常常忘記一些該辦的要緊事、有些方面操作不當(dāng)以及把螺絲弄丟等等。這些都不一一列舉了。總之,干這些活,我明白了許多,也成熟了許多,我會(huì)盡自己的努力做好自己的工作。
這兩個(gè)星期也感覺挺忙的,周一周三延點(diǎn)、周二周四培訓(xùn)、周六加班。彭師傅曾問我:“晚上培訓(xùn)精力上沒問題吧?對(duì)這個(gè)培訓(xùn)有什么看法?”我說(shuō):“精力上當(dāng)然沒問題,就是培訓(xùn)的有點(diǎn)快,有很多不是太懂,希望能講的慢一些,細(xì)一些?!迸韼煾祵?duì)此跟我詳細(xì)的說(shuō):“培訓(xùn)其實(shí)并不是都全部教懂,因?yàn)橛行〇|西是需要接觸,進(jìn)行具體的操作時(shí)才能真正的懂,培訓(xùn)的主要目的是把調(diào)試的主要內(nèi)容,具體方向,大多方面講一些,讓我們?cè)跇I(yè)余有個(gè)學(xué)習(xí)的方向,這個(gè)主要靠的就是自己本身的努力。”聽后,我豁然開朗,明白了自己的努力方向。對(duì)調(diào)試的其他建議,說(shuō)實(shí)話,還真不知道說(shuō)什么,因?yàn)槲覀儾沤佑|這個(gè)調(diào)試,還處于懵懵懂懂之中,只有在遇到實(shí)際的問題時(shí),我們才會(huì)具體的提出來(lái),所以建議問題還是留到現(xiàn)學(xué)現(xiàn)問吧。
最后,想起了李師傅給我們的寄語(yǔ):書山有路勤為徑、學(xué)海無(wú)涯苦作舟。是啊,學(xué)習(xí)如逆水推舟,不進(jìn)則退,獲得成功的途徑只有努力與付出。在此,在調(diào)試隊(duì)我要踐行我的誓言:人生難得一回闖,且看失敗與成長(zhǎng)。
趙直2012年08月26日