日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

WINCE Driver 心得总结

發(fā)布時間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WINCE Driver 心得总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一. Windows CE的驅(qū)動程序的區(qū)分

1.從加載以及接口方式來區(qū)分

可以分為本機設(shè)備驅(qū)動(Built-In Driver)、可加載驅(qū)動(Loadable Driver)以及混合型驅(qū)動。

1)本機設(shè)備驅(qū)動

本機設(shè)備驅(qū)動即Native Device Drivers。這些驅(qū)動程序在系統(tǒng)啟動時,在GWES的進程空間內(nèi)被加載,因此它們不是以獨立的DLL形式存在。這些驅(qū)動對應(yīng)的設(shè)備通常在系統(tǒng)啟動時就被要求加載,如果沒有串口,也沒有LCD的話,整個系統(tǒng)就不能和用戶信息交流。另外,流驅(qū)動程序也能作為本機設(shè)備驅(qū)動而存在。

2)可加載驅(qū)動

也被稱為流驅(qū)動。

這些驅(qū)動可以在系統(tǒng)啟動時或者和啟動后的任何時候由設(shè)備管理器動態(tài)加載。通常它們以DLL動態(tài)鏈接庫的形式存在,系統(tǒng)加載它們后,這些驅(qū)動程序也只是以用戶態(tài)的角色運行。可加載驅(qū)動程序通過文件操作API來從設(shè)備管理器和應(yīng)用程序獲得命令。

Windows CE中典型的可加載驅(qū)動有以下各類:

n???? PCMCIA driver(PCMCIA.dll)

n???? Serial driver(SERIAL.dll)

n???? ATAFLASH driver(ATA.dll)

n???? Ethernet driver(NE2000.dll,SMSC100FD.dll)

3)混合型驅(qū)動

這類驅(qū)動綜合了前兩種驅(qū)動的特性。它同時使用了stream接口和custom-purpose接口。

混合型驅(qū)動主要是提供custom-purpose 接口,但是由于需要和系統(tǒng)中只允許使用stream接口的那些模塊進行交互,因此也必須提供stream接口。例如,PC card socket驅(qū)動同時擁有兩套接口。

2.從驅(qū)動層次上分

可以分為獨立驅(qū)動和層次型驅(qū)動,下圖是這兩種驅(qū)動在系統(tǒng)中的位置。

?

1)獨立驅(qū)動程序

可以將驅(qū)動程序編寫成同時包含MDDPDD層的獨立驅(qū)動。獨立驅(qū)動的代碼應(yīng)當(dāng)包括中斷服務(wù)例程和平臺相關(guān)處理函數(shù)。使用獨立驅(qū)動的好處在于可以省去MDDPDD層驅(qū)動之間的信息傳遞,這一點在實時處理中非常重要。另外,如果設(shè)備的操作和MDD驅(qū)動層的接口描述相吻合,可以使用獨立驅(qū)動程序提高處理性能。

2)層次型驅(qū)動

層次型驅(qū)動分為兩層,較上層的Model Device DriverMDD)和比較下層的Platform Dependent DriverPDD)。MDD實現(xiàn)的是和平臺無關(guān)的功能,它描述了一個通用的驅(qū)動程序框架。而PDD是和硬件以及平臺相關(guān)的代碼組成。MDD調(diào)用PDD中特定的接口來獲取硬件相關(guān)的信息。當(dāng)使用層次型驅(qū)動的時候,一般只需要基于相近的樣列驅(qū)動程序,針對特定的硬件修改PDD程序,MDD建立的框架可繼續(xù)使用。由于層次間接口的層層調(diào)用以及消息的傳遞,使得處理速度相對獨立驅(qū)動程序要慢,因此在時間要求苛刻的環(huán)境下,層次型驅(qū)動顯得不是很適合。

?

一般MDD將完成以下任務(wù)。

n????連接PDD層,并且定義它要使用到的Device Driver Service Provider Interface(DDSI)函數(shù)集;

n???? 向設(shè)備管理器提供Device Driver Interface(DDI)接口集;

n???? 處理復(fù)雜的事件,如中斷等等。

每一種MDD驅(qū)動都處理不同種類的設(shè)備。DDI是由MDD層驅(qū)動以及獨立型驅(qū)動提供給設(shè)備管理器的一組接口集。DDSI是由PDDMDD層提供的接口集。公司的設(shè)備可以用同樣的DDI

在開發(fā)過程中,MDD層驅(qū)動是不需要被修改的。微軟公司不保證被修改的MDD能在系統(tǒng)中正確運行的。和MDD層驅(qū)動不同的是,PDD層驅(qū)動必須被修改成和特定硬件相匹配的代碼。程序員可以自己開發(fā)一個PDD程序,多數(shù)情況下建議開發(fā)者在Platform Builder提供的樣例驅(qū)動程序上進行修改。例如,Platform Builder提供了Wavedev驅(qū)動程序,它的代碼位于%WINCEROOT%\public\common\oak\drivers\WAVEDEV下,這是一個容易理解的流接口層次型驅(qū)動程序。此樣例audio驅(qū)動程序僅提供了播放及錄音功能,只提供播放功能的結(jié)構(gòu)框架,播放功能和音頻設(shè)備的交互還需要 PDD層來解決。

?

二.????????? ?Audio Driver 架構(gòu):

WINCE Audio Driver 架構(gòu)支持兩種驅(qū)動模式

即獨立型的unified audio model (UAM)驅(qū)動和分層式的MDD and PDD mode驅(qū)動,(不論是UAM或者MDD/PDD都是流接口驅(qū)動)

其架構(gòu)還支持的audio compression manager (ACM)驅(qū)動,例如codecs, converters, and filters等器件

1)???????? UAM

UAM支持標(biāo)準(zhǔn)波形驅(qū)動接口(standard wave driver interfaces),過去的波形驅(qū)動和采樣驅(qū)動是由MDDPDD模型組成。MDD模型執(zhí)行了驅(qū)動的獨立硬件部分以及輸出到驅(qū)動接口的中間設(shè)備。PDD模型提供了驅(qū)動依賴硬件的執(zhí)行部分

The following illustration shows the UAM stack.

Using MDD and PDD, the previous model had the following limitations:

·??????????? No support for multiple streams

·??????????? No multiple devices on one driver

·??????????? No reliable support for looping

·??????????? Poor support for streaming

OEM商可以圍繞這些限制來移植自己的MDD或者寫入他們自己的完整驅(qū)動來輸出到合適的接口到中間設(shè)備

UAM實現(xiàn)了對WAVMicrosoft DirectSound®音頻API的高效支持。它還使得編寫一個能有效支持WAVDirectSound的驅(qū)動程序成為可能。

?

在我們的WM8753 音頻Driver中即使用了UAM這種驅(qū)動模式,它也是一種流接口驅(qū)動,故只需編寫驅(qū)動中WAVEMIXER這兩部分,然后使用流接口函數(shù)調(diào)用即可。

?

2).音頻MDDPDD

?

編寫音頻驅(qū)動我們可以選擇UAM架構(gòu),或者直接執(zhí)行流接口(stream interface),我們使用由微軟提供的MDD庫-Wavemdd.lib。這個庫通過DDSI來執(zhí)行流接口功能。如果使用了Wavemdd.lib,則必須一個PDD庫來執(zhí)行音頻DDSI的功能。這個庫被稱為Wavepdd,lib, 這兩個庫編譯連接后就形成了我們的音頻驅(qū)動,通常被為Wavedev,dll

在系統(tǒng)程序文件中可能缺少器件的功能導(dǎo)致音頻器件的很多功能無法被使用,為了解決這個問題DeviceIOControl

PDD和MDD都依靠調(diào)用DDSI函數(shù)來實現(xiàn)相互通信,所以若采用分層式來編寫驅(qū)動,只需找到微軟提供的MDD,然后根據(jù)其DDSI來編寫PDD層即可。

?

三.????????? 流接口驅(qū)動

不論是UAM或者PDD/MDD的架構(gòu),它們都是流接口驅(qū)動

流接口驅(qū)動有一套標(biāo)準(zhǔn)的接口,這和本機驅(qū)動是不一樣的。

n???? 對于I/O設(shè)備來說是非常適合的。????????????????????????????????????

n???? 操作接口和文件系統(tǒng)API十分類似,比如ReadFile,IOControl等。

n???? 應(yīng)用程序可以和流接口驅(qū)動進行交互,并且可以把流驅(qū)動當(dāng)成文件來操作。

流驅(qū)動與驅(qū)動接口、提供設(shè)備的種類無關(guān),因為這組接口有統(tǒng)一的接口規(guī)范。對于需要數(shù)據(jù)流的設(shè)備來說,這種驅(qū)動是十分適合的,如串口就是個典型的例子。可以把使用流驅(qū)動的設(shè)備近似地看作是文件,這樣可以通過文件系統(tǒng)API來操作設(shè)備,如ReadFileIOControl。由于采用了文件系統(tǒng)的API,使得驅(qū)動程序能通過文件系統(tǒng)進行訪問,這點和獨立驅(qū)動程序是不同的。

下圖是流驅(qū)動程序在整個系統(tǒng)中的結(jié)構(gòu)示意圖。

?

上圖顯示了作為本機驅(qū)動而存在的流驅(qū)動程序,在啟動時被設(shè)備管理器所加載。一般本機驅(qū)動是指custom接口的驅(qū)動程序,但是流驅(qū)動也可以成為本機驅(qū)動,例如串口。

流驅(qū)動通過文件系統(tǒng)API來和應(yīng)用程序交互,同時又通過流接口接受設(shè)備管理器的管理。無論流驅(qū)動管理的是本機設(shè)備還是動態(tài)加載的設(shè)備,它們自身是在啟動時被加載還是啟動后由設(shè)備管理器動態(tài)加載,這和系統(tǒng)中其他模塊的交互模型是一樣的。

實現(xiàn)流驅(qū)動程序大致需要完成以下步驟。

1)選擇代表設(shè)備的文件名前綴;

2)實現(xiàn)驅(qū)動的各個入口點;

3)建立.DEF文件;

4)在注冊表中為驅(qū)動程序建立表項。

?

以下是創(chuàng)建流驅(qū)動的具體步驟。

1)首先確定設(shè)備名的前綴。前綴非常重要,設(shè)備管理器在注冊表中通過前綴來識別設(shè)備。同時,在流接口命名時,也將這個前綴作為入口點函數(shù)的前綴,如果設(shè)備前綴為XXX,那么流接口對應(yīng)為XXX_CloseXXX_Init等。

2)實現(xiàn)流接口的各個入口點。所謂入口點是指提供給設(shè)備管理器的標(biāo)準(zhǔn)文件I/O接口。

下表是對這些接口的介紹:

? ?

功能描述

XXX_Close

關(guān)閉hOpenContext參數(shù)指定的設(shè)備上下文

XXX_Deinit

通知設(shè)備管理器回收設(shè)備初始化時分配的資源

XXX_Init

通知設(shè)備管理器為設(shè)備初始化時分配資源

XXX_Open

打開設(shè)備,這個接口可以由應(yīng)用程序直接調(diào)用createfile,然后通過文件系統(tǒng)映射為XXX_Open

XXX_IOControl

I/O控制指令

XXX_PowerUp

設(shè)備加電時,此接口會被自動調(diào)用,可以在這里分配資源等

XXX_PowerDown

如果設(shè)備能由軟件控制斷電,則在設(shè)備斷電前,設(shè)備管理器會調(diào)用這個接口做些安全性檢查

XX_Read

從打開的設(shè)備文件中讀取數(shù)據(jù)

XXX_Seek

文件定位,如果設(shè)備支持的話

XXX_Write

寫數(shù)據(jù)到設(shè)備文件


對于流驅(qū)動,×××_Open/×××_Close/×××_IoControl等就是ddi;如果不是流驅(qū)動,它的ddi不具有上述形式;

?

以我們的driver為例,在程序中,我們可以在C:\WINCE500\PLATFORM\C340\Src\Drivers\audio\IIS\wm8753\wavemain.cpp中找到以下對應(yīng)點

Programming element

Description

WAV_IOControl

This function is the device I/O control routine for the WAV I/O device.

WAV_Init

This function initializes the WAV I/O device.

WAV_Deinit

This function deinitializes the WAV I/O device.

WAV_Open

This function opens the WAV I/O device.

WAV_Close

This function closes the WAV I/O device.

WAV_Read

This function is the read routine for the WAV I/O device driver.

WAV_Write

This function is the write routine for the WAV I/O device.

WAV_Seek

This function is the seek routine for the WAV I/O device.

WAV_PowerUp

This function notifies the WAV I/O device that the system is leaving the suspend state.

WAV_PowerDown

This function turns off the WAV I/O device

?

在注冊表中還要建立驅(qū)動程序的入口點,這樣設(shè)備管理器才能識別和管理這個驅(qū)動

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Audio]

?? "Prefix"="WAV"

?"Dll"="s3c2440a_iis_wm8753.dll"

?? "Index"=dword:1

?? "Order"=dword:0

此外,注冊表還能儲存額外的信息,這些信息可以在驅(qū)動運行之后被使用到,DLL項是設(shè)備管理器在加載驅(qū)動時需要的DLL名稱;Prefix代表了設(shè)備前綴;Order是驅(qū)動程序被加載的順序

?

以下詳細(xì)說明下流接口函數(shù)的各入口

Streams入口:OpenClose

1XXX_Open入口

用于讀/寫打開一個設(shè)備文件。當(dāng)應(yīng)用程序調(diào)用CreateFile的時候,文件系統(tǒng)會自動調(diào)用本接口,打開一個已經(jīng)存在的設(shè)備文件。當(dāng)這個接口被調(diào)用的時候,設(shè)備驅(qū)動可以向設(shè)備管理器申請分配資源,并且為讀/寫文件做好準(zhǔn)備。

下面是接口的原形:

DWORD XXX_Open( DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode );

參數(shù)解釋:

hDeviceContext

指向XXX_Init返回的設(shè)備句柄(上下文)。

AccessCode

打開設(shè)備的權(quán)限描述符,這些權(quán)限包括讀設(shè)備、寫設(shè)備、讀 /寫等。

所謂的設(shè)備上下文指的是代表圖形設(shè)備接口graphics device interfaceGDI)的數(shù)據(jù)結(jié)構(gòu)。它包含了在特定區(qū)域內(nèi)設(shè)備顯示圖象的信息。設(shè)備上下文包含了圖形對象(例如penbrush、字體等),不斷地修改和調(diào)用它們,從而達(dá)到顯示不同圖象的效果。

2XXX_Close入口

在關(guān)閉設(shè)備的時候被操作系統(tǒng)調(diào)用。對應(yīng)于CloseHandle接口。

BOOL XXX_Close( DWORD hOpenContext );

參數(shù)解釋:

hOpenContext

指向XXX_Open返回的已經(jīng)打開的設(shè)備句柄(上下文)。

應(yīng)用程序可以調(diào)用CloseHandle來關(guān)閉正在使用的流驅(qū)動程序,然后設(shè)備管理器會相應(yīng)地調(diào)用本接口來關(guān)閉設(shè)備,當(dāng)設(shè)備關(guān)閉后hOpenContext描述的設(shè)備句柄將不再有效。

Streams入口:Init and Deinit

1XXX_Init入口

XXX_Init要完成以下任務(wù)。

n???? 在驅(qū)動被系統(tǒng)加載時,本接口被調(diào)用;

n???? 初始化需要的資源在本接口處理中被分配;

n???? 創(chuàng)建內(nèi)存映射。

下面是接口的原型:

DWORD XXX_Init( DWORD dwContext );

參數(shù)解釋:

n???? dwContext

指向一個字符串,它描述了注冊表中的一個流設(shè)備接口。

當(dāng)調(diào)用設(shè)備ActivateDeviceEx函數(shù)后,設(shè)備管理器自動調(diào)用這個函數(shù)。當(dāng)用戶激活一個新的設(shè)備時,如插入USB設(shè)備后,當(dāng)總線自檢時,設(shè)備就會被激活,這個接口就會被調(diào)用,這個接口是不允許應(yīng)用程序直接調(diào)用的。

當(dāng)這個接口的處理結(jié)果返回時,設(shè)備管理器就在注冊表中尋找驅(qū)動的Ioctl子鍵。如果這個子鍵存在,設(shè)備管理器將調(diào)用XXX_IOControl接口將dwCode參數(shù)傳入驅(qū)動入口點。

2XXX_Deinit入口

在驅(qū)動被系統(tǒng)卸載的時候,本接口將被調(diào)用,它將釋放所有占用的阻援,并且停止IST

下面是接口的原型:

BOOL XXX_Deinit( DWORD hDeviceContext );

參數(shù)解釋:

hDeviceContext

指向設(shè)備上下文的句柄。這個句柄應(yīng)該是由XXX_Init返回的。

當(dāng)程序調(diào)用DeactivateDevice時,設(shè)備管理器將自動調(diào)用本接口。流接口將釋放全部它申請的資源,并且停止設(shè)備的運行。

Streams入口:ReadWriteSeek

1XXX_Read入口

當(dāng)應(yīng)用程序直接調(diào)用ReadFile函數(shù)時,設(shè)備管理器將調(diào)用這個接口。

下面是接口的原型:

DWORD XXX_Read( DWORD hOpenContext, LPVOID pBuffer, DWORD Count );

參數(shù)解釋:

hOpenContext

指向XXX_Open接口返回的設(shè)備上下文。

pBuffer

指向緩沖區(qū),這個緩沖區(qū)將用來存放從設(shè)備中讀出的數(shù)據(jù),以字節(jié)為單位。

Count

指定要從設(shè)備讀取多少字節(jié)的數(shù)據(jù)存入pBuffer指向的緩沖區(qū)中。

這個從指定的設(shè)備中讀取指定數(shù)量的字節(jié)數(shù)據(jù),它對應(yīng)的應(yīng)用層APIReadFileReadFile函數(shù)的參數(shù)hFile是指向設(shè)備的句柄,ReadFile函數(shù)的參數(shù)hFile將被填寫到count參數(shù)中,ReadFile中的pSizeRead將存放實際讀取數(shù)據(jù)的字節(jié)數(shù)。本接口的返回值是pSizeRead中填充的數(shù)值,若返回-1,代表發(fā)生了錯誤。

2XXX_Write入口

當(dāng)應(yīng)用程序調(diào)用WriteFile的時候,設(shè)備管理器將調(diào)用本接口。

下面是接口的原型:

DWORD XXX_Write( DWORD hOpenContext, LPCVOID pBuffer, DWORD Count );

參數(shù)解釋:

hOpenContext

指向XXX_Open接口返回的設(shè)備上下文。

pBuffer

指向緩沖區(qū),這個緩沖區(qū)將用來存放要向設(shè)備中寫入的數(shù)據(jù),以字節(jié)為單位。

Count

指定要從pBuffer指向的緩沖區(qū)向設(shè)備讀取寫入多少字節(jié)的數(shù)據(jù)。

3XXX_Seek入口

在定位I/O指針的時候被調(diào)用。

下面是接口的原型:

DWORD XXX_Seek( DWORD hOpenContext, long Amount, WORD Type );

參數(shù)解釋:

hOpenContext

指向XXX_Open接口返回的設(shè)備上下文。

Amount

指定指針要移動多少距離,以字節(jié)為單位。正值代表向文件尾端移動,負(fù)值則相反。

Type

描述了起始點的位置。當(dāng)應(yīng)用程序調(diào)用了SetFilePointer函數(shù)后,設(shè)備管理器就會調(diào)用本接口。

如果設(shè)備是可以重復(fù)打開的,本接口用到的指針只是針對hOpenContext的。

Streams入口:PowerUpPowerDown

1XXX_PowerDown入口

這個接口是在停止對設(shè)備供應(yīng)電源時被調(diào)用。下面是接口的原型:

void XXX_PowerDown( DWORD hDeviceContext );

參數(shù)解釋:

hDeviceContext

指向由XXX_Init返回的設(shè)備上下文。

這個函數(shù)應(yīng)當(dāng)執(zhí)行停止設(shè)備供電的操作,此設(shè)備必須支持軟關(guān)電的功能。在I/O control接口中,如果I/O命令字為IOCTL_POWER_XXX,那么就應(yīng)該調(diào)用本接口。這個接口是對應(yīng)與應(yīng)用程序的,系統(tǒng)電源管理并不會用到這個接口。

設(shè)備管理器在將設(shè)備設(shè)置成節(jié)電模式之前將調(diào)用本接口,本接口將盡可能避免引起阻塞的操作,并盡快返回。

2XXX_PowerUp入口

恢復(fù)了設(shè)備的供電。

下面是接口的原型:

void XXX_PowerUp( DWORD hDeviceContext );

參數(shù)解釋:

hDeviceContext

指向XXX_Open接口建立并且返回的設(shè)備上下文。

這個接口在需要恢復(fù)設(shè)備電源供應(yīng)時被調(diào)用。在I/O control接口中,如果I/O命令字為IOCTL_POWER_XXX,那么就應(yīng)該調(diào)用本接口。這個接口是對應(yīng)與應(yīng)用程序的,系統(tǒng)電源管理并不會用到這個接口。本接口應(yīng)盡可能避免引起阻塞的操作,將盡快返回,并設(shè)置全局變量來表明電源已經(jīng)被恢復(fù),可以進行后續(xù)操作。

?

Streams入口:IOControl

XXX_IOControl入口

允許應(yīng)用程序進行非文件的操作。

I/O控制字可以用來識別命令類別,普通的讀寫操作通常是不能完全滿足程序要求的,I/O控制字是和設(shè)備相關(guān)的。

下面是接口的原型:

BOOL XXX_IOControl( DWORD hOpenContext, DWORD dwCode, PBYTE

pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD

pdwActualOut );

參數(shù)解釋:

hOpenContext

指向XXX_Open接口建立并且返回的設(shè)備上下文。

dwCode

指定驅(qū)動程序要操作的I/O操作的標(biāo)識碼。這是由設(shè)備特定的,一般在頭文件中有I/O操作的標(biāo)識碼的定義。

pBufIn

指向存放要向設(shè)備傳輸?shù)臄?shù)據(jù)的緩沖區(qū)。

dwLenIn

指定要從pBufIn指向的緩沖區(qū)向設(shè)備讀取寫入多少字節(jié)的數(shù)據(jù)。

pBufOut

指向緩沖區(qū),這個緩沖區(qū)將用來存放從設(shè)備中讀出的數(shù)據(jù),以字節(jié)為單位。

dwLenOut

指定要從設(shè)備讀取多少字節(jié)的數(shù)據(jù)存入pBuffer指向的緩沖區(qū)中。

pdwActualOut

DWORD型指針,指向的內(nèi)容反映了從設(shè)備中讀取的實際字節(jié)數(shù)。

這個接口主要是傳遞了包括讀寫在內(nèi)的I/O控制命令給設(shè)備。和Windows桌面平臺類似,應(yīng)用程序可以通過直接調(diào)用DeviceIOControl函數(shù)使設(shè)備管理器激活本接口。dwCode參數(shù)指定了命令的類型,這些命令類型是由驅(qū)動程序指定的,并且通過頭文件的形式提供給應(yīng)用程序,在音頻驅(qū)動中就有IOCTL_WAV_MESSAGE, IOCTL_DSDVR_MESSAGE, and IOCTL_MIX_MESSAGE.等。

如果注冊表中有HKEY_LOCAL_MACHINE\Drivers\BuiltIn\YourDevice\Ioctl鍵,設(shè)備管理器在加載驅(qū)動的時候就會調(diào)用本接口,并且使用注冊表中相應(yīng)項的值作為dwCode的值,把NULL填寫入pBufInpBufOut中。驅(qū)動程序可以在這個時候加載其他模塊以及其他不適合在XXX_Init出現(xiàn)的功能,在設(shè)備交互的過程中,以上各個接口基本遵循如下的調(diào)用順序:XXX_InitXXX_Open,XXX_IOControlXXX_CloseXXX_Open接口是要獲得設(shè)備句柄所必須的操作,XXX_Close是釋放資源所必須的操作。

?

上層調(diào)用I/O CONTROL函數(shù)后,I/O CONTROL便會使用消息或者結(jié)構(gòu)體發(fā)送到各個子Driver

?

下表中的結(jié)構(gòu)體包含了器件的擴展信息

Programming element

Description

MMDRV_MESSAGE_PARAMS

Passed to the WAV_IOControl function.

WAVEOPENDESC

Contains information needed by waveform input and output drivers.

WAVEOUTEXTCAPS

Contains extended device caps information.

下表中列出了各個輸入driver消息

Programming element

Description

WIDM_ADDBUFFER

This message is used to request a waveform input driver to add an empty input buffer to its input buffer queue.

WIDM_CLOSE

This message is used to request a waveform input driver to close a specified device instance previously opened with WIDM_OPEN.
?

?

WIDM_GETDEVCAPS

This message is used to request a waveform input driver to return the capabilities of a specified device.

WIDM_GETNUMDEVS

This message is used to request a waveform input driver to return the number of devices that it supports.

WIDM_GETPOS

This message is used to request a stream input driver to return the current input position within a waveform. The input position is relative to the first recorded sample of the waveform.

WIDM_OPEN

This message is used to request a waveform input driver to open a stream of a specified device.

WIDM_PREPARE

This message is used to request a waveform input driver to prepare a system-exclusive data buffer for input.

WIDM_RESET

This message is used to request a waveform input driver to stop recording and return all buffers in the input queue to the caller.

WIDM_START

This message is used to request a waveform input driver to begin recording.

WIDM_STOP

This message is used to request a waveform input driver to stop recording.

WIDM_UNPREPARE

This message is used to request a waveform input driver to undo the buffer preparation that was performed in response to a WIDM_PREPARE message.

下表中列出了各個輸出driver消息

Programming element

Description

WODM_BREAKLOOP

This message is used to request a waveform output driver to break an output loop that was created with a WODM_WRITE message.

WODM_CLOSE

This message is used to request a waveform output driver to close a specified stream that was previously opened with a WODM_OPEN message.

WODM_GETDEVCAPS

This message is used to request a waveform output driver to return the capabilities of a specified device.

WODM_GETNUMDEVS

This message is used to request a waveform output driver to return the number of device instances that it supports.

WODM_GETPITCH

This message is used to request a waveform output driver to return the specified device's current pitch multiplier value.

WODM_GETPLAYBACKRATE

This message is to request a waveform output driver to return the current playback rate multiplier value for the specified device.

WODM_GETPOS

This message is used to return the current position within a stream. The position is relative to the beginning of the waveform.

WODM_GETVOLUME

This message is used to request a waveform output driver to return the current volume level setting for the specified device or stream.

WODM_OPEN

This message is used to request a waveform output driver to open a stream on the specified device.

WODM_PAUSE

This message is used to request a waveform output driver to pause playback of a waveform.

WODM_PREPARE

This message is used to request a waveform output driver to prepare a system-exclusive data buffer for output.

WODM_RESET

This message is used to request a waveform output driver to stop sending output data and return all output buffers to the list.

WODM_RESTART

This message is used to request a waveform output driver to continue playback of a waveform after playback has been paused with WODM_PAUSE.

WODM_SETPITCH

This message is used to request a waveform output driver to set the specified device's pitch multiplier value.

WODM_SETPLAYBACKRATE

This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.

WODM_SETVOLUME

This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.

WODM_UNPREPARE

This message is used to request a waveform output driver to remove the buffer preparation performed in response to WODM_PREPARE.

WODM_WRITE

This message is used to request a waveform output driver to write a waveform data block to the specified device.

?

以我們的WM8753音頻Driver 為例,整個驅(qū)動里包含了以下重要功能的子驅(qū)動:

Devctxt.cpp

器件關(guān)聯(lián)——包含了音頻流的創(chuàng)造,刪除,打開,關(guān)閉,格式等功能

Hwctxt.cpp

硬件關(guān)聯(lián)——包含了基本的硬件功能在各個狀態(tài)的全局配置

I2citf.cpp

I2C傳輸配置

I2S.cpp

I2S傳輸配置

Input.cpp

負(fù)責(zé)輸入音頻流

Output.cpp

負(fù)責(zé)輸出音頻流

Midinote.cpp

負(fù)責(zé)輸出MIDI

Midistrm.cpp

負(fù)責(zé)MIDI的開關(guān)以及控制

Mixerdrv.cpp

系統(tǒng)軟件混音

RTcodecComm.cpp

Wm8753的所有功能配置,以及初始化設(shè)置

Strmctxt.cpp

負(fù)責(zé)所有音頻流的增益,buffer請求等功能以及對Devctxt的控制

Wavemain.cpp

包含了所有的流接口函數(shù)

?

?

按照UAM的定義, wm8753driver主要由mixerwave兩部分組成;

由于mixer只實現(xiàn)一些基本的混音功能,其主要由Mixerdrv.cpp承擔(dān),還包括Midistrm.cppInput.cppOutput.cpp的部分功能。而其他基本都是wave功能

Wavemain.cpp基于整個驅(qū)動的最上層,其中,流接口函數(shù)做到了以下控制:

?

Wav_init ——> hwctxt??? RTcodecComm

?????????????????????? I2citf.,

I2S

?

Wav_deinit?????????????? devctxt???????????????????

Wav_Powerup??????????? hwctxt

Wav_powerdown????????? mixerdrv

??????????????????????? strmctxt

?

Wav_IOControl——> Wav_open/close——> 所有??

若要移植一個音頻驅(qū)動到另一個器件,一般只需更改Hwctxt.cppI2citf.cppI2S.cppRTcodecComm.cpp 即可

?

四.以下是WM8753WAV_IOControl調(diào)用說明:

? extern "C" BOOL WAV_IOControl(DWORD? dwOpenData,

?????????????????? DWORD? dwCode,

?????????????????? PBYTE? pBufIn,

?????????????????? DWORD? dwLenIn,

?????????????????? PBYTE? pBufOut,

DWORD? dwLenOut,

?????????????????? PDWORD pdwActualOut)

{

?

?

??? _try

??? {

?? switch (dwCode)

?????? {

??????? case IOCTL_MIX_MESSAGE:

??????? return HandleMixerMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);//調(diào)用混音消息

?

??????? case IOCTL_WAV_MESSAGE:

???????? return HandleWaveMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);//調(diào)用音頻消息

???????????

??????? //以下為電源管理功能

??????? case IOCTL_POWER_CAPABILITIES:

??????? case IOCTL_POWER_SET:

??????? case IOCTL_POWER_GET:

??????????? return g_pHWContext->IOControl

??????????? (dwOpenData, dwCode, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut);

???????????????????????????????

?????

??????? }

?

??? }

?

BOOL HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams, DWORD *pdwResult) //管理音頻消息

{

??? //? set the error code to be no error first

??? SetLastError(MMSYSERR_NOERROR);

?

??? UINT uMsg = pParams->uMsg;

??? UINT uDeviceId = pParams->uDeviceId;

??? DWORD dwParam1 = pParams->dwParam1;

??? DWORD dwParam2 = pParams->dwParam2;

??? DWORD dwUser?? = pParams->dwUser;

??? StreamContext *pStreamContext = (StreamContext *)dwUser;

?

??? DWORD dwRet;

?

??? g_pHWContext->Lock();

?

????? // catch exceptions inside device lock, otherwise device will remain locked!

??? _try

??? {

??? ??

??? switch (uMsg)

??? {

??? case WODM_GETNUMDEVS: //This message is used to request a waveform output driver to return the capabilities of a specified device.

??????? {

??????????? dwRet = g_pHWContext->GetNumOutputDevices();

??????????? break;

??????? }

?

??? case WIDM_GETNUMDEVS:// This message is used to request a waveform input driver to return the number of devices that it supports.

??????? {

??????????? dwRet = g_pHWContext->GetNumInputDevices();

??????????? break;

??????? }

?

??? case WODM_GETDEVCAPS:// This message is used to request a waveform output driver to return the capabilities of a specified device.

??????? {

??????????? DeviceContext *pDeviceContext;

??????????? UINT NumDevs = g_pHWContext->GetNumOutputDevices();

?

??????????? if (pStreamContext)

??????????? {

??????????????? pDeviceContext=pStreamContext->GetDeviceContext();

??????????? }

??????????? else

??????????? {

??????????????? pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

??????????? }

?

??????????? dwRet = pDeviceContext->GetDevCaps((PVOID)dwParam1,dwParam2);

??????????? break;

??????? }

?

?

??? case WIDM_GETDEVCAPS:// This message is used to request a waveform input driver to return the capabilities of a specified device.

??????? {

???????????

DeviceContext *pDeviceContext;

???????? ???UINT NumDevs = g_pHWContext->GetNumInputDevices();

?

??????????? if (pStreamContext)

??????????? {

??????????????? pDeviceContext=pStreamContext->GetDeviceContext();

??????????? }

??????????? else

??????????? {

??????????????? pDeviceContext = g_pHWContext->GetInputDeviceContext(uDeviceId);

??????????? }

?

??????????? dwRet = pDeviceContext->GetDevCaps((PVOID)dwParam1,dwParam2);

??????????? break;

??????? }

?

??? case WODM_GETEXTDEVCAPS:

??????? {

??????????? DeviceContext *pDeviceContext;

??????????? UINT NumDevs = g_pHWContext->GetNumOutputDevices();

?

??????????? if (pStreamContext)

??????????? {

??????????????? pDeviceContext=pStreamContext->GetDeviceContext();

??????????? }

??????????? else

??????????? {

??????????????? pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

??????????? }

?

??????????? dwRet = pDeviceContext->GetExtDevCaps((PVOID)dwParam1,dwParam2);

??????????? break;

??????? }

?

??? case WODM_OPEN:// This message is used to request a waveform output driver to open a stream on the specified device.

??????? {

??????????? // DEBUGMSG(1, (TEXT("WODM_OPEN\r\n"));

??????????? DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

??????????? dwRet = pDeviceContext->OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)dwUser);

??????????? break;

??????? }

?

??? case WIDM_OPEN:// This message is used to request a waveform input driver to open a stream of a specified device.

??????? {

??????????? // DEBUGMSG(1, (TEXT("WIDM_OPEN\r\n"));

??????????? DeviceContext *pDeviceContext = g_pHWContext->GetInputDeviceContext(uDeviceId);

??????????? dwRet = pDeviceContext->OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)dwUser);

??????????? break;

??????? }

?

??? case WODM_CLOSE:

??? case WIDM_CLOSE:

??????? {

??????????? // DEBUGMSG(1, (TEXT("WIDM_CLOSE/WODM_CLOSE\r\n"));

??????????? dwRet = pStreamContext->Close();

?

??????????? // Release stream context here, rather than inside StreamContext::Close, so that if someone

??????????? // (like CMidiStream) has subclassed Close there's no chance that the object will get released

??????????? // out from under them.

??????????? if (dwRet==MMSYSERR_NOERROR)

??????????? {

??????????????? pStreamContext->Release();

???????????}

??????????? break;

??????? }

?

?? ?case WODM_RESTART:

??? case WIDM_START:

??????? {

??????????? dwRet = pStreamContext->Run();

??????????? break;

??????? }

?

??? case WODM_PAUSE:

??? case WIDM_STOP:

??????? {

??????????? dwRet = pStreamContext->Stop();

??????????? break;

??????? }

?

??? case WODM_GETPOS:

??? case WIDM_GETPOS:

??????? {

??????????? dwRet = pStreamContext->GetPos((PMMTIME)dwParam1);

??????????? break;

??????? }

?

??? case WODM_RESET:

??? case WIDM_RESET:

??????? {

??????????? dwRet = pStreamContext->Reset();

??????????? break;

??????? }

?

??? case WODM_WRITE:

??? case WIDM_ADDBUFFER:

??????? {

??????????? // DEBUGMSG(1, (TEXT("WODM_WRITE/WIDM_ADDBUFFER, Buffer=0x%x\r\n"),dwParam1);

??????????? dwRet = pStreamContext->QueueBuffer((LPWAVEHDR)dwParam1);

??????????? break;

??????? }

?

??? case WODM_GETVOLUME:// This message is used to request a waveform output driver to return the current volume level setting for the specified device or stream.

??????? {

??????????? PULONG pdwGain = (PULONG)dwParam1;

?

??????????? if (pStreamContext)

? ??????????{

??????????????? *pdwGain = pStreamContext->GetGain();

??????????? }

??????????? else

??????????? {

#ifdef USE_HW_GAIN_WODM_SETGETVOLUME

??????????????? // Handle device gain in hardware

??????????????? *pdwGain = g_pHWContext->GetOutputGain();

#else

??????????????? // Handle device gain in software

??????????????? DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

??????????????? *pdwGain = pDeviceContext->GetGain();

#endif

??????????? }

??????????? dwRet = MMSYSERR_NOERROR;

??????????? break;

??????? }

?

??? case WODM_SETVOLUME:// This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.

??????? {

??????????? LONG dwGain = dwParam1;

??????????? if (pStreamContext)

??????????? {

??????????????? dwRet = pStreamContext->SetGain(dwGain);

??????????? }

??????????? else

??????????? {

#ifdef USE_HW_GAIN_WODM_SETGETVOLUME

??????????????? // Handle device gain in hardware

??????????????? dwRet = g_pHWContext->SetOutputGain(dwGain);

#else

???????????????// Handle device gain in software

??????????????? DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

??????????????? dwRet = pDeviceContext->SetGain(dwGain);

#endif

??????????? }

?? ?????????break;

??????? }

?

??? case WODM_BREAKLOOP:// This message is used to request a waveform output driver to break an output loop that was created with a WODM_WRITE message.

??????? {

??????????? dwRet = pStreamContext->BreakLoop();

??????????? break;

??????? }

?

??? case WODM_SETPLAYBACKRATE:// This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device. ??????? {

??????????? WaveStreamContext *pWaveStream = (WaveStreamContext *)dwUser;

?? ?????????dwRet = pWaveStream->SetRate(dwParam1);

??????????? break;

??????? }

?

??? case WODM_GETPLAYBACKRATE:// This message is to request a waveform output driver to return the current playback rate multiplier value for the specified device.

??????? {

?? ?????????WaveStreamContext *pWaveStream = (WaveStreamContext *)dwUser;

??????????? dwRet = pWaveStream->GetRate((DWORD *)dwParam1);

??????????? break;

??????? }

?

??? case MM_WOM_SETSECONDARYGAINCLASS:

??????? {

??????????? dwRet = pStreamContext->SetSecondaryGainClass(dwParam1);

??????????? break;

??????? }

?

??? case MM_WOM_SETSECONDARYGAINLIMIT:

??????? {

??????????? DeviceContext *pDeviceContext;

??????????? if (pStreamContext)

??????????? {

??????????????? pDeviceContext = pStreamContext->GetDeviceContext();

??????????? }

??????????? else

??????????? {

??????????????? pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

??????????? }

??????????? dwRet = pDeviceContext->SetSecondaryGainLimit(dwParam1,dwParam2);

??????????? break;

??????? }

?

? ??case MM_MOM_MIDIMESSAGE:

??????? {

??????????? CMidiStream *pMidiStream = (CMidiStream *)dwUser;

??????????? dwRet = pMidiStream->MidiMessage(dwParam1);

??????????? break;

??????? }

?

??????? ?? // For Debug Register

??? case WPDM_PRIVATE_WRITE_CODEC:

??? case WPDM_PRIVATE_READ_CODEC:

??? ?? ? //{

?????????? //??? dwRet=g_pHWContext->Private_AudioMessage(pParams->uMsg, pParams->dwParam1, pParams->dwParam2);

?????????? //???? break;

?? ??????????? //}

?

// unsupported messages

??? case WODM_GETPITCH:

??? case WODM_SETPITCH:

??? case WODM_PREPARE:

??? case WODM_UNPREPARE:

??? case WIDM_PREPARE:

??? case WIDM_UNPREPARE:

??? default:
?????? dwRet? = MMSYSERR_NOTSUPPORTED;

??????? break;

??? }

???

??? }

??? _except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)

??? {

??????? ERRORMSG(1, (TEXT("Access violation in HandleWaveMessage!!!!\r\n")));

??????? SetLastError(E_FAIL);

??? }???

???

??? g_pHWContext->Unlock();

?

??? // Pass the return code back via pBufOut

??? if (pdwResult)

??? {

??????? *pdwResult = dwRet;

??? }

?

??? return(TRUE);

}??

?????????????????





?

總結(jié)

以上是生活随笔為你收集整理的WINCE Driver 心得总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。