第一篇:海思HI35XX之---音頻模塊使用總結
海思HI35XX之---音頻模塊使用總結
AUDIO 模塊包括音頻輸入、音頻輸出、音頻編碼、音頻解碼四個子模塊。音頻輸入和
輸出模塊通過對 Hi35xx 芯片 SIO 接口的控制實現(xiàn)音頻輸入輸出功能。音頻編碼和解碼模塊提供對 G711、G726、ADPCM 格式的音頻編解碼功能,并支持錄制和播放 LPCM格式的原始音頻文件。
音頻輸入輸出接口 SIO(Sonic Input/Output),用于和 Audio Codec 對接,完成聲音的錄制和播放。
對每個 SIO 接口的音頻輸入和音頻輸出功能,軟件分別用 AI 和 AO 兩個模塊來管理,稱之為 AI 設備和 AO 設備,并按照 SIO 序號為其編號。例如與 SIO0 接口對應的軟件設備分別為 AiDev0 和 AoDev0。
HI3518錄音和播放原理:
錄音:原始音頻信號以模擬信號的形式給出后,通過 Audio Codec,按一定采樣率和采樣精度轉換為數字信號。Audio Codec 以 I2S 時序或 PCM 時序的方式,將數字信號傳輸給SIO 接口,SIO 支持多路復用的接收模式。Hi35xx 芯片利用 DMAC 將 SIO 接口中的音頻數據保存到內存中,完成錄音操作。
播放:Hi35xx 芯片利用 DMAC 將內存中的數據傳輸到 SIO 接口。SIO 接口通過 I2S 時序或 PCM 時序向 Audio CODEC 發(fā)送數據。Audio Codec 完成數字信號到模擬信號的轉換過程,并輸出模擬信號。
Hi35xx音頻部分的編碼類型 G711、G726、ADPCM_DVI4 與 ADPCM_ORG_DVI4是使用硬編碼,ADPCM_IMA 是使用 CPU 軟件解碼,其中
Hi3518/Hi3516C 芯片沒有硬件編碼模塊,所有的編碼方式都使用軟件編碼;而所有的解碼功能基于獨立封裝的海思音頻編解碼庫,核心解碼器工作在用戶態(tài),使用 CPU 軟件解碼。SDK 支持通過 SYS模塊的綁定接口,將一個 AI 通道綁定到 AENC 通道,實現(xiàn)錄音編碼功能;也可以將一個 ADEC 通道綁定到 AO 通道,實現(xiàn)解碼播放功能。
使用海思語音編解碼庫進行 G711、G726、ADPCM 格式的編碼,編碼后的碼流遵循以下表格中描述的幀結構,即在每幀碼流數據的凈荷數據之前填充有 4 個字節(jié)的幀頭;使用語音編解碼庫進行以上格式的解碼時,需要讀取相應的幀頭信息。
這4個字節(jié)的幀頭內容即為如下數組中的值:
static char aryHeard[4] = {0,1,160,0};//hisi audio header
利用ACODEC庫進行音頻解碼播放時,每發(fā)送一包音頻數據到解碼通道前,都必須先把這個數組中的內容組合到包的頭部位置,否則解碼出錯。
G711、G726、ADPCM編碼協(xié)議的采樣率均為8KHz。
其中,Hi3518/Hi3516C 使用內部 audio codec。Hi3518A/Hi3516C 支持雙聲道,左右聲道輸入,左右聲道輸出。Hi3518C 只支持單聲道,左聲道輸入、左聲道輸出。
音頻 AI 和 AO 支持的最大通道數為 16 通道(其中 Hi3518/Hi3516C 芯片受內置 codec 限制,只支持 2 通道),且配置 AI 和 AO 設備時需要將通道配置為偶數。
Hi3518/Hi3516C 只支持 16bit 位寬。
Hi3518A/Hi3518C/Hi3516C 提供一個內置的 Audio Codec,并在芯片內部對接到 SIO0接口,即 SIO0 接口只能通過內置的 Audio Codec 完成聲音的播放及錄制。因為 AudioCodec 不能發(fā)送同步時鐘,所以 SIO0 接口只能配置為 I2S 時序的主模式(MASTER)。用戶需要正確配置 SIO0 和 Audio Codec 對接時序才可接收或發(fā)送音頻數據。
Audio Codec 分為模擬部分和數字部分。模擬部分可以通過模擬混音(MICPGA)選擇由麥克風輸入(MICIN)或線性輸入(LINEIN),模擬混音支持增益調節(jié)。數字部分有 ADC 和 DAC,完成模擬信號和數字信號之間的轉換,并且可分別調節(jié)音量。用戶在進行音量調節(jié)時,可綜合模擬部分和數字部分的音量調節(jié),建議優(yōu)先調節(jié)模擬部分音量。
Audio Codec 支持去加重濾波、pop 音抑制和高通濾波,并默認開啟這些功能。
Audio Codec 的用戶態(tài)接口以 ioctl 形式體現(xiàn),其形式如下:
int ioctl(int fd,unsigned long cmd,……);
該函數是 Linux 標準接口,具備可變參數特性。但在 Audio Codec 中,實際只需要 3 個參數。因此,其語法形式等同于:
int ioctl(int fd,unsigned long cmd,CMD_DATA_TYPE *cmddata);
其中,CMD_DATA_TYPE 隨參數 cmd 的變化而變化。
綜上所述,HI3518C音頻子系統(tǒng)初始化時應該作以下軟件配置:
音頻編碼錄制流程:
1、音頻輸入屬性(見AIO_ATTR_S結構體);
2、配置音頻編碼、解碼模塊(ACODEC);
3、設置AI設備屬性;啟用AI設備;啟用AI通道;(啟用AI噪聲抑制、啟用AI重采樣,此兩項可選。);
4、根據音頻編碼協(xié)議創(chuàng)建音頻編碼通道;
5、綁定音頻編碼通道到音頻輸入通道;
6、HI_MPI_AENC_GetFd(AENC_CHN AeChn)獲取音頻編碼通道的Fd;
7、HI_MPI_AENC_GetStream從編碼通道獲取編碼之后的音頻數據;
8、用戶保存或者轉發(fā)此數據。
音頻解碼播放流程:
1、音頻輸出屬性(見AIO_ATTR_S結構體)初始化;
2、配置音頻編碼、解碼模塊(ACODEC);
3、根據音頻編碼協(xié)議創(chuàng)建音頻解碼通道;
4、設置AO設備屬性;啟用AO設備;啟用 AO通道(啟用AO重采樣,此項可選);
5、綁定音頻輸出通道到音頻解碼通道;
6、向每包待發(fā)送的音頻數據頭添加4字節(jié)的海思音頻協(xié)議頭;
7、HI_MPI_ADEC_SendStream向音頻解碼通道發(fā)送組合之后的音頻數據包;
8、播放聲音。
Hi35xx SIO 支持擴展的多路接收的 I2S 及 PCM 接口時序,對接 CODEC 的時序模式選擇、同步時鐘、采樣位寬等配置必須與 Hi35xx SIO 的配置保持一致,否則可能采集不到正確的數據。上面代碼中AUDIO_POINT_NUM = 320,則通過調用口HI_MPI_AENC_GetStream從音頻編碼通道獲取到的每包音頻數據大小都為324字節(jié)(320字節(jié)的凈荷數據+4字節(jié)海思音頻數據頭),使用ACODEC進行解碼播放時,每次調用HI_MPI_ADEC_SendStream將音頻數據發(fā)往音頻解碼通道時,數據長度也必須是324字節(jié)(320字節(jié)的凈荷數據+4字節(jié)海思音頻數據頭)。
在音頻初始化配置完畢后,需要首先對ACODEC模塊進行配置,在配置ACODEC模塊時,注意:
1、要把MICIN靜音(MUTE)功能關閉。
2、輸入設備選用LINEIN。
此處我有一點疑惑,設備的輸入明明接的是MIC,我一開始也是未加思索就選擇MICIN來進行配置ACODEC的,但是音頻編碼流程完畢后獲取到的音頻數據播放時只有“沙沙沙”的背景音,聽不到話筒端的說話聲音,糾結了兩天,其它各項參數確定沒有問題了,嘗試著把MICIN改為LINEIN,聲音OK,無語。。。
目前聽到的采集到的聲音和解碼播放的聲音都很清晰,只是有點小,后續(xù)再嘗試通過ioctl及相應的ACODEC模塊給出的各種增益調節(jié)命令來調整音頻監(jiān)聽與對講的音量大小。。。
第二篇:alsa音頻總結
Linux音頻驅動總結
參考文章:http://blog.csdn.net/droidphone/
http://blog.chinaunix.net/uid/22917448.html
分析只列出部分重要代碼,具體請參考linux3.0內核代碼。
Alsa架構整體來說十分復雜,但對于驅動移植來說我們僅僅只需要關心ASOC就足夠了。在學習asoc之前我們先了解一些專業(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控制器和便攜音頻解碼器上的三個主要數字音頻接口,即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是一種個人電腦聲卡上常見的五線接口?,F(xiàn)在在很多便攜設備中也很流行。這個數字音頻接口有一個復位線,分時在SDATA_OUT(回放)和SDATA_IN(捕獲)線上傳送數據。位時鐘常由解碼器驅動(通常是12.288MHz).幀時鐘(通常48kHz)總是由控制器驅動。每個AC97幀21uS,并分為13個時間槽。
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是一個4線數字音頻接口,常用于HiFi,STB便攜設備。Tx 和Rx信號線用于音頻傳輸。而位時鐘和左右時鐘(LRC)用于同步鏈接。I2S具有靈活性,因為控制器和解碼器都可以控制位時鐘和左右時鐘。位時鐘因采樣率和主系統(tǒng)時鐘而有不同。LRCLK與采樣率相同。少數設備支持獨立的ADC和DAC的LRCLK。這使在不同采樣率情況下同步捕獲和回放成為可能。
I2S has several different operating modes:-I2S有幾個不同的操作模式:
o I2SMSB is transmitted on transition of LRC.左對齊模式:MSB在LRC傳送時傳送。
o Right JustifiedMSB is transmitted on falling edge of first BCLK after FRAME/SYNC.模式A-MSB在FRAME/SYNC后第一個BCLK的下降沿傳送。
o Mode Busing I2C, 3 Wire(SPI)or both APIs 3)Mixers and audio controls 4)Codec audio operations 1)解碼器數字音頻接口和PCM配置。
2)解碼器控制IO-使用I2C,3總線(SPI)或兩個都有。3)混音器和音頻控制。4)解碼器音頻操作。
Optionally, codec drivers can also provide:-解碼器驅動可以選擇性提供:
5)DAPM description.6)DAPM event handler.7)DAC Digital mute control.5)動態(tài)音頻電源管理描述。6)動態(tài)音頻電源管理事件控制。7)數模轉換數字消音控制。SoC DAI Drivers 板級DAI驅動 ===============
Each SoC DAI driver must provide the following features:-每個SoC DAI驅動都必須提供如下性能:
1)Digital audio interface(DAI)description 1)數字音頻接口描述
2)Digital audio interface configuration 2)數字音頻接口配置 3)PCM's description 3)PCM描述
4)SYSCLK configuration 4)系統(tǒng)時鐘配置
5)Suspend and resume(optional)5)掛起和恢復(可選的)
以上由君子翻譯,本人實在沒辦法比他描述的更好了,所以把重要的部分提取出來直接copy。在這里對君子表示由衷感謝,賦上君子注。君子注:
您現(xiàn)在所閱讀的,是君子閱讀Linux音頻SoC驅動時,寫下的文檔譯文。
君子寫些譯文,一方面是作為自己的筆記,幫助記憶,另一方面也希望能對他人有所幫助。如果您能于君子的譯文中有所收獲,則吾心甚慰
現(xiàn)在我們開始分析ASOC:
ASoC被分為Machine、Platform和Codec三大部分。其中的Machine驅動負責Platform和Codec之間的耦合和設備或板子特定的代碼。
看起來挺復雜,其實需要我們做的事情并不多,大部分內核已經完成。下面我們分析哪些是我們需要自己做的:
codec驅動:負責音頻解碼。這部分代碼完全無平臺無關,設備原廠提供,我們只需要把它加進內核編譯就好了。platform驅動:與處理器芯片相關,這部分代碼在該芯片商用之前方案產商提供的demo板已完全確定了,也就是說我們只需要使用就可以了。
machine驅動:好了,到了最關鍵的地方了,machine驅動是耦合platform和codec驅動,同時與上層交互的代碼。由于上層是標準的alsa架構,所以下層接口肯定要做了統(tǒng)一,所以我很負責的告訴你,這部分由machine本身的platform驅動和platform設備組成(請跟asoc的platform驅動區(qū)別),platform驅動內核幫我們完成了,所以你無須過多的關心你的驅動怎么跟上層alsa怎么衍接的問題,我們只需要注冊一個machine的platform設備以及完成platform和codec耦合就ok
asoc的關系圖如下:(以下適應于linux3.0。linux2.6會有所不同)
上圖把asoc架構顯示的淋漓盡致,如果你分析了asoc你就會發(fā)現(xiàn)上圖描述的結構以及函數真的一個都跑不了。
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結構,又引出了Machine驅動的另外兩個個數據結構:
? ? snd_soc_dai_link(實例:smdk_dai[])snd_soc_ops(實例:smdk_ops)
snd_soc_dai_link看名字就知道,很明顯它是起耦合鏈接作用的。它指定了Platform、Codec、codec_dai、cpu_dai的名字,稍后Machine驅動將會利用這些名字去匹配已經在系統(tǒng)中注冊的platform,codec,dai。
snd_soc_ops連接Platform和Codec的dai_link對應的ops操作函數,本例就是smdk_ops,它只實現(xiàn)了hw_params函數:smdk_hw_params。
到此為止,最主要的部分machine的平臺設備注冊我們完成了。
下面我們關注machine平臺驅動部分(這部分內核不需要我們實現(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”, //確保你注冊machine平臺設備和它保持一致 5..owner = THIS_MODULE, 6..pm = &soc_pm_ops, 7.},8..probe = soc_probe, 9..remove = soc_remove, 10.};
初始化入口soc_probe()
soc_probe函數本身很簡單,它先從platform_device參數中取出snd_soc_card,然后調用snd_soc_register_card,通過snd_soc_register_card,為snd_soc_pcm_runtime數組申請內存,每一個dai_link對應snd_soc_pcm_runtime數組的一個單元,然后把snd_soc_card中的dai_link配置復制到相應的snd_soc_pcm_runtime中,最后,大部分的工作都在snd_soc_instantiate_card中實現(xiàn),下面就看看snd_soc_instantiate_card做了些什么: 該函數首先利用card->instantiated來判斷該卡是否已經實例化,如果已經實例化則直接返回,否則遍歷每一對dai_link,進行codec、platform、dai的綁定工作,下只是代碼的部分選節(jié),詳細的代碼請直接參考完整的代碼樹。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);//注冊............}
下面我們看snd_soc_register_card()函數:
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數組申請內存,每一個dai_link對應一個snd_soc_pcm_runtime數組單元。。。。
for(i = 0;i < card->num_links;i++)
card->rtd[i].dai_link = &card->dai_link[i];//把snd_soc_card中的dai_link復制到相應的snd_soc_pcm_runtime。。。。
snd_soc_instantiate_cards();//將調用snd_soc_instantiate_card()//最為重要 }
下面我們分析snd_soc_instantiate_card()函數:
static void snd_soc_instantiate_card(struct snd_soc_card *card){
。。。。
if(card->instantiated){ //判斷該卡是否已經實例化,如果是就返回
mutex_unlock(&card->mutex);
return;
}
/* bind DAIs */
for(i = 0;i < card->num_links;i++)//否則遍例每一對dai_link,進行codec,flatrom,dai的綁定工作
soc_bind_dai_link(card, i);/* ******************************************************************************************************************************************************************
ASoC定義了三個全局的鏈表頭變量:codec_list、dai_list、platform_list,系統(tǒng)中所有的Codec、DAI、Platform都在注冊時連接到這三個全局鏈表上。soc_bind_dai_link函數逐個掃描這三個鏈表,根據card->dai_link[]中的名稱進行匹配,匹配后把相應的codec,dai和platform實例賦值到card->rtd[]中(snd_soc_pcm_runtime)。經過這個過程后,snd_soc_pcm_runtime:(card->rtd)中保存了本Machine中使用的Codec,DAI和Platform驅動的信息。
*****************************************************************************************************************************************************************/
/* 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)建聲卡實例
。。。。。。。//下面是最重要的probe匹配工作
if(card->probe){
ret = card->probe(card);
if(ret < 0)
goto card_probe_error;
}
。。。。。
ret = soc_probe_dai_link(card, i, order);//主要的耦合鏈接工作在此函數完成。。。。。
ret = soc_probe_aux_dev(card, i)。。。。。
if(card->late_probe){//最后的聲卡初始化工作,ret = card->late_probe(card);
}
。。。。。
ret = snd_card_register(card->snd_card);//然后調用標準的alsa驅動的聲卡函數進行聲卡注冊
。。。。。
}
到這里聲卡已經注冊好了,聲卡可以正常工作了,我們再分析最后一個函數,也就是它們是怎么匹配的 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)建標準的alsa的pcm邏輯設備
。。。。。
}
好了,到此為止我們最主要的部分machine部分分析完成了。接著是codec驅動部分:
Codec簡介
在移動設備中,Codec的作用可以歸結為4種,分別是:
? ? 對PCM等信號進行D/A轉換,把數字的音頻信號轉換為模擬信號
對Mic、Linein或者其他輸入源的模擬信號進行A/D轉換,把模擬的聲音信號轉變CPU能夠處理的數字信號
? 對音頻通路進行控制,比如播放音樂,收聽調頻收音機,又或者接聽電話時,音頻信號在codec內的流通路線是不一樣的
? 對音頻信號做出相應的處理,例如音量控制,功率放大,EQ控制等等
ASoC對Codec的這些功能都定義好了一些列相應的接口,以方便地對Codec進行控制。ASoC對Codec驅動的一個基本要求是:驅動程序的代碼必須要做到平臺無關性,以方便同一個Codec的代碼不經修改即可用在不同的平臺上。以下的討論基于wolfson的Codec芯片WM8994,kernel的版本3.3.x。
描述Codec的最主要的幾個數據結構分別是:snd_soc_codec,snd_soc_codec_driver,snd_soc_dai,snd_soc_dai_driver,其中的snd_soc_dai和snd_soc_dai_driver在ASoC的Platform驅動中也會使用到,Platform和Codec的DAI通過snd_soc_dai_link結構,在Machine驅動中進行綁定連接。
Codec的注冊
因為Codec驅動的代碼要做到平臺無關性,要使得Machine驅動能夠使用該Codec,Codec驅動的首要任務就是確定snd_soc_codec和snd_soc_dai的實例,并把它們注冊到系統(tǒng)中,注冊后的codec和dai才能為Machine驅動所用。以WM8994為例,對應的代碼位置:/sound/soc/codecs/wm8994.c,模塊的入口函數注冊了一個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,必定會有相應的platform device,platform device其實在我們之前講過的machine device注冊時已經引入了。
[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個dai,這里只列出第一個):
[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驅動的第一個步驟就是定義snd_soc_codec_driver和snd_soc_dai_driver的實例,然后調用snd_soc_register_codec函數對Codec進行注冊。
snd_soc_register_codec()函數是machine driver提供的,只要注冊成功后codec提供的操作函數就能正常提供給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驅動定義的snd_soc_dai_link中會指定每個link的codec和dai的名字,進行匹配綁定時就是通過和這里的名字比較,從而找到該Codec的 */
// 然后初始化它的各個字段,多數字段的值來自上面定義的snd_soc_codec_driver的實例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函數對本Codec的dai進行注冊 if(ret < 0)goto fail;}
mutex_lock(&client_mutex);list_add(&codec->list, &codec_list);/*最后,它把codec實例鏈接到全局鏈表codec_list中,并且調用snd_soc_instantiate_cards是函數觸發(fā)Machine驅動進行一次匹配綁定操作 */
snd_soc_instantiate_cards();mutex_unlock(&client_mutex)。。。。。}
好了,在這里我們的codec驅動也分析完了,其實這部分都是與平臺無關代碼,一般也不需要改動,這部分我們從設備原廠拿到代碼后丟上去就可以了,只是我們在寫machine device的時候要注意和這里的名字匹配。接下來是asoc的platform驅動:
Platform驅動的主要作用是完成音頻數據的管理,最終通過CPU的數字音頻接口(DAI)把音頻數據傳送給Codec進行處理,最終由Codec輸出驅動耳機或者是喇叭的音信信號。在具體實現(xiàn)上,ASoC有把Platform驅動分為兩個部分:snd_soc_platform_driver和snd_soc_dai_driver。其中,platform_driver負責管理音頻數據,把音頻數據通過dma或其他操作傳送至cpu dai中,dai_driver則主要完成cpu一側的dai的參數配置,同時也會通過一定的途徑把必要的dma等參數與snd_soc_platform_driver進行交互。
snd_soc_platform_driver的注冊
通常,ASoC把snd_soc_platform_driver注冊為一個系統(tǒng)的platform_driver,不要被這兩個想像的術語所迷惑,前者只是針對ASoC子系統(tǒng)的,后者是來自Linux的設備驅動模型。我們要做的就是:
? ? 定義一個snd_soc_platform_driver結構的實例;
在platform_driver的probe回調中利用ASoC的API:snd_soc_register_platform()注冊上面定義的實例;
? 實現(xiàn)snd_soc_platform_driver中的各個回調函數;
以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()該函數用于注冊一個snd_soc_platform,只有注冊以后,它才可以被Machine驅動使用。它的代碼已經清晰地表達了它的實現(xiàn)過程:
? ? ? ? ? 為snd_soc_platform實例申請內存;
從platform_device中獲得它的名字,用于Machine驅動的匹配工作; 初始化snd_soc_platform的字段;
把snd_soc_platform實例連接到全局鏈表platform_list中;
調用snd_soc_instantiate_cards,觸發(fā)聲卡的machine、platform、codec、dai等的匹配工作;
cpu的snd_soc_dai driver驅動的注冊
dai驅動通常對應cpu的一個或幾個I2S/PCM接口,與snd_soc_platform一樣,dai驅動也是實現(xiàn)為一個platform driver,實現(xiàn)一個dai驅動大致可以分為以下幾個步驟:
? ? 定義一個snd_soc_dai_driver結構的實例;
在對應的platform_driver中的probe回調中通過API:snd_soc_register_dai或者snd_soc_register_dais,注冊snd_soc_dai實例;
? ? 實現(xiàn)snd_soc_dai_driver結構中的probe、suspend等回調;
實現(xiàn)snd_soc_dai_driver結構中的snd_soc_dai_ops字段中的回調函數;
snd_soc_register_dai 這個函數在上一篇介紹codec驅動的博文中已有介紹
具體不再分析,這個驅動也不需要用戶做任務修改,所以只要知道它的作用就已經夠了。就像電話機一樣,我們只要知道電話怎么打就夠了,至于它怎么連接我們并不太需要關心。
第三篇:心得體會袁思海
視導員培訓的啟示
匯川區(qū)婁山關紅軍小學:袁思海
2018年9月28日至9月29日,我有幸參加了匯川區(qū)中小學責任督學、視導員專業(yè)化發(fā)展研修班學習,在這兩天的學習期間,聆聽了李國德、梁祝、周學文幾位專家的講座,真正懂得了督導對學校的重要性。督導,顧名思義即監(jiān)督、指導。教育督導的“督”具有監(jiān)督、督促、檢查和評估的職能;“導”具有指導、幫助、服務和咨詢的職能。雖然為期很短,但受益非淺。我領悟到作為一名新時期的校長應有的新理念、新思想,如何配合督學工作,讓學校的管理上臺階,是我需要思考的問題。
一、思想上要轉變。
中小學校實行責任督學掛牌督導制度,是國家教育治理和教育督導改革的重大制度創(chuàng)新,是對督學責任區(qū)建設的深化和完善。責任督學掛牌亮相,依法依規(guī)入校督導,及時發(fā)現(xiàn)解決教育教學實際問題,促進學校全面實施素質教育,得到教育行政部門、學校、家長及社會的廣泛認可,為提高教育質量、促進教育公平、辦人民滿意的教育發(fā)揮了重要作用,教育現(xiàn)狀,需要責任區(qū)督學工作的創(chuàng)新。聽了李國德督學的講座,讓我深深明白,我原來的想法是錯誤的,我原來曾想,這些督學一天沒事,就到學校來指手畫腳,作為一間村級小學,本身人手就不夠,你們還來添亂,我還真有抵觸的情緒,但是現(xiàn)在說真的,沒有了,我茅塞頓開,這些督學都是一線退下來的,在學校的方方面面,都是高手和行家,他一眼看下來,就知道學校的管理漏洞,就知道問題出在哪里。他們是來幫助學校發(fā)展的,是來給學校解決問題的,隨著掛牌督學創(chuàng)新區(qū)的成立,我想這僅僅是個好的開始。
二、行動上加緊。
每位督學是深入學校教育教學管理最直接的監(jiān)督員,責任區(qū)督學掛牌督導是各地人民政府教育督導部門,對區(qū)域內每一所學校設置責任督學。在一定程度上增強了教育督導工作的開放性和透明度。根據工作需要,我今后一定會組織本校的一些老教師、教研組長和中層干部和督學一起對學校工作進行內部督導。開展校內教育督導工作,推動學校工作向前發(fā)展,使學校工作目標更明確,實施時更有計劃性,使學校工作走上正規(guī)化、法制化的道路。同時有利于各部門創(chuàng)造性地工作,并能及時總結經驗,在工作中加以推廣和應用。
通過對教育教學活動全過程進行監(jiān)督、檢查與評價,掌握情況,經驗,發(fā)現(xiàn)問題,及時進行分析,從而不斷優(yōu)化教育教學過程,提高教學管理水平和教學質量,逐步形成了一套利于學校發(fā)展、推動學校素質教育實施的教育督導評估模式與機制,取得較為理想的成效。
三、認真自查,及時改進
通過自查自糾,及時調整方法,讓學校的工作持續(xù)健康發(fā)展,認真聽取督學的建議,邀請督學一起給學校把脈問診,把學校的工作推上一個臺階。
第四篇:7《海思》教案
7、《海思》教案
教學目標 :
1.理清文章結構,學會用自己的話概括文章的主要內容。
2.理解作者由海而產生的獨特的聯(lián)想和深邃的思考。
3.體會文中富有哲理的語言。
4.探究作者思想的廣度和深度。
教學重難點 :
重點:學會編寫閱讀提要。品讀語言,有感情地朗讀課文。
難點:作者思維的廣度和深度。
課時安排 :
兩課時
第一課時
教學過程:
一、預習:
①.讀課文,表段序,勾劃出文中出現(xiàn)的生字詞。(注意讀音及寫法)②.讀單元提示,明確學習內容和學習目標。③.完成學案“基礎訓練”部分。給下列加點字注音:
Wanyan
qì
pú
piaomiao
muyu
juanlian 蜿 蜒
休憩
返璞歸真
縹緲
沐浴
眷戀 2.作者簡介:
梁衡,1946年出生,1968年畢業(yè)于中人民大學。山西霍州人。當代作家。曾長期任新聞記者,歷任新聞出版署副署長?,F(xiàn)任人民日報副總編輯、中國人民大學新聞學院博士生導師、中國作家協(xié)會全委會委員、中國記者協(xié)會全委會常務理事、人教版中小學教材總顧問。是著名的新聞理論家、散文家、科普作家和政論家。曾榮獲全國青年文學獎、趙樹理文學獎、全國優(yōu)秀科普作品獎和中宣部“五個一”工程獎等多種榮譽稱號。
二、問題導學:
1.思考:課文那幾個段落集中描寫了大海的壯麗圖景?那幾個段落集中描寫了作者對大海的聯(lián)想與思考?文章中哪些句段完成了內容的轉換? ①第三段 ②第四段最后一句
2.作者眼前的海是怎樣的?讓作者產生了哪些聯(lián)想與思考?作者心中的海是怎樣的?
作者眼前的海是壯麗的大海(洶涌澎湃 波瀾起伏
海天一色);作者心中的大海的形象——海的博大精深、海的包容一切、海給人類心靈的慰藉。3.作者圍繞海所做的思考是為了表達什么感情?
引導學生看議論抒情句,讓學生全面把握作者愛海的博大精深,愛海的包容一切,海給人類心靈的慰藉。
4.由此引導學生理清文章脈絡,把文章分成三個部分,全班各自據此編寫閱讀提要,并分小組交流,然后再進行全班交流。
完成能力訓練一
第一部分:寫大海的美麗圖景。
或
寫景
眼前之海 第二部分:寫大海引起的聯(lián)想
或
聯(lián)想
聯(lián)想之海 第三部分:寫面對大海的沉思
或
沉思
沉思之海
三、自學探究
1.學情預設:學生對“心中的?!崩斫饪赡苡悬c困難,另外課文的概括是重點,教師重點點撥。
2.個人能力不能完成的問題,小組合作完成。
四、展示點評
1.展示方式:個別回答,小組代表上臺演板。2.點評方式:學生糾錯,教師結合學法點評。
五、拓展延伸
面對壯麗的大海,你會做怎樣的聯(lián)想與思考,而作者又做了怎么樣的聯(lián)想與思考?
他為什么會有這種思考? ①聯(lián)想奇特
②大散文觀”
第二課時
教學過程:
一、復習
1.作者眼前的海是什么樣子的?面對這樣的海他做了怎么樣的聯(lián)想與思考?他為什
么會有這種思考?
2.回顧在學上篇課文中學到的品析語言表達效果的方法:
品析語言我們可以從運用的方式、具體闡述、闡述的特點內容歐、情感意圖這四步來組織語言。
二、問題導學
1.研讀第二自然段:作者眼前之海是神么樣子的呢?給人什么感受?作者是從哪幾個方面著手描寫的呢?我們可以從哪幾個方面去品讀呢?你準備怎么樣去
朗讀它呢?
學生完成能力訓練二 小組合作、交流。
方式:回憶《說幾句愛海的孩子氣的話》中介紹的方法: 四步法:運用的方式
具體闡述
特點 內容
情感意圖 示例:、“極目望去??棉朵”
——運用了排比,比喻的修辭手法。把遠處的浪花比作大軍與棉朵,從聲勢、顏色的角度,生動形象的寫出了海的博大壯闊。2.學生讀:學生按剛才的品析去試著設計朗讀。
3.學生小組合作活動結尾“海啊,你在我的心里”還表達了作者什么樣的感情? 含蓄地表達了作者對大海深沉的愛。
三、自學探究
1.學情預設:語言品析是重點,估計部分同學回答會不規(guī)范,不全面,教師重點點撥。
2.朗讀設計一定發(fā)揮全體同學的積極性。
四、展示點評
1.展示方式:個別回答,小組代表上臺演板。2.點評方式:學生糾錯,教師結合學法點評。
五、拓展延伸
1.《海思》是一篇寫景抒情類的散文,課文中所體現(xiàn)的作者充滿智慧的思考令人嘆服。同學們寫作文若果單純寫景,會不會是一篇好作文? 一篇好作文,除了寫景,還必須寫出作者的思考。聯(lián)想的流暢,思考的有深度,才能算是一篇好作文。2.借助具體物象,培養(yǎng)學生的想像力。
①金錢確實可以買到許多東西,但它不是萬能的,如金錢能買床鋪,不能買甜蜜的夢;
能買書,不能買到知識??請你聯(lián)想它的作用和局限,越多越好。
②有位作家寫了一首詩《0的斷想》:
0是謙虛者的起點,驕傲者的終點;0的負擔最輕,但任務最重;0是一面鏡子,讓你重新認識自己;
0是一只救生圈,讓弱者隨波逐流;
請你運用發(fā)散思維續(xù)寫下去。
創(chuàng)新提示:
①能買藥物,不能買健康;能買娛樂,不能買幸福;能買房屋,不 能買家庭;能買選票,不能買人心??
②0是一塊空地,可種五谷;是煙圈,虛度年華;是鐵環(huán),組成堅韌;是戰(zhàn)鼓,激人奮進??
第五篇:海之韻誦讀社團總結
贛榆區(qū)華杰雙語學校小學部2014——2015學第一學期
海之韻誦讀社團工作總結
剛接手社團的我是迷茫的:沒有教材,學生來自各個學段,所有的一切仿佛都是處于混亂之中,沒辦法,只能靠我這張嘴了。于是在開課之前,我就去找張曉老師討教方法。她非??犊亟o我講了怎樣開展誦讀社團。在前人的經驗教導和我逐步的摸索下,我也慢慢累積了經驗。細細地回想了與孩子們相處得時光,覺得有收獲也有遺憾。
我收獲了以下幾個方面: 一. 全員鞏固了系統(tǒng)的理論知識
作為一名語文教師,我知道誦讀是一項技能,不過這對于我好像是與生俱來的能力。在我的印象中,誰都應該會誦讀,這個還用教嗎?想象總是比現(xiàn)實美好。第一節(jié)課,為了能夠掌握這個社團的基本狀況,我給社團成員5分鐘時間,讓他們準備一篇文章上臺進行誦讀表演。結果讓我目瞪口呆呀!朗讀沒感情,節(jié)奏雜亂,唱讀,拖讀,各種各樣問題。當讓也有幾個資質不錯的成員,聲音如百靈般的動聽。于是我決定從頭教起,首先我準備系統(tǒng)的誦讀知識,每節(jié)課講一個知識點,并伴隨相應的練習訓練。一學期下來,學生明白了原來誦讀還有許多理論要學習,而且也能掌握這些理論,并將這些理論運用于實踐。在教授的過程中我也重新溫習了這些理論知識。大家都在共同的進步。
二.收獲了師生情
剛開始帶這個社團的時候,雖然已經將社團的規(guī)章制度宣讀給孩子們聽,但他們所表現(xiàn)的遵守能力不同。有一天,當我剛踏進社團專用教室時,有一個小女孩跑過來跟我說反映我的社團成員翻別人桌洞,胡亂拿別人東西。當時我就心酸了,那種心情就好像一個母親聽著別人說自家孩子的不是。我當時站在門口理了理失望的思緒,并決定利用上課的時間重點強調一下,發(fā)生過的事情不能挽回,但是不能讓同樣的過錯再次發(fā)生。于是我在班里進行了一番說教,并進行了相應的措施??赡芩麄兏惺艿搅宋业年P懷,每次見到我就會跟在我的旁邊,感覺我又收獲了一份滿滿的感情。
有收獲的同時也會有些遺憾:雖然每個人都有進步,但是進步幅度不大,他們還要在這條路上走很長時間。這學期的社團紀律稍有松懈,為社團教室的主人們帶來了不便。
我希望下學期的社團成員們都不斷進步,不斷努力。
劉昶
2014年1月8日