在WinCE.net中,最簡單的一個驅動程式莫過於一個內置(Built-in)設備的流介面驅動。對於一個不支援熱拔插的設備,最快捷的方法就是為其實現一個內置的流介面的驅動。

對於這樣一類驅動程式,我們只需要按一種特定的規則實現一個動態庫,其中實現對所有的硬體功能的調用,再將這個動態庫加入系統中,然後設置相關的登錄機碼,使得在系統啟動時裝置管理員能識別並且載入這個設備即可。

1. 實現動態連結程式庫
此動態連結程式庫與應用程式層所用的庫並不很大差別,原始檔案可以是C、C++、甚至彙編,只是它要實現以下函數。

DllEntry(HINSTANCE DllInstance, INT Reason, LPVOID Reserved )

這個函數是動態連結程式庫的入口,每個動態連結程式庫都需要輸出這個函數,它只在動態庫被載入和卸載時被調用,也就是裝置管理員調用LoadLibrary而引起它被裝入記憶體和調用UnloadLibrary將其從記憶體釋放時被調用,因而它是每個動態連結程式庫最早被調用的函數,一般用它做一些全域變數的初始化。

參數:

DllInstance:DLL的控制碼,與一個EXE檔的控制碼功能類似,一般可以通過它在得到DLL中的一些資源,例如對話方塊,除此之外一般沒什麼用處。

Reason:

一般我們只關心兩個值:DLL_PROCESS_ATTACH與DLL_PROCESS_DETACH,Reason等於前者是動態庫被載入,等於後者是動態庫被釋放。

所以,我們可以在Reason等於前者是初始化一些資源,等於後者時將其釋放。

DWORD XXX_Init( LPCTSTR pCoNtext, LPCVOID lpvBusCoNtext);
它是驅動程式的動態庫被成功裝載以後第一個被調用的函數。其調用時間僅次與DllEntry,而且,當一個庫用來生成多於一個的驅動程式實例時僅調用一次DllEntry,而xxx_Init會被調用多次。驅動程式應當在這個函數中初始化硬體,如果初始化成功,就分配一個自已的記憶體空間(通常用結構體表示),將自已的狀態保存起來,並且將此區塊的位址做為一個DWORD值返回給上層。裝置管理員就會用在調用XXX_Open時將此控制碼傳回,我們就能訪問自已的狀態。如果初始化失敗,則返回0以通知這個驅動程式沒有成功載入,先前所分配的系統資源應該全部釋放,此程式的生命即告終至。
當這個函數成功返回,裝置管理員對這個程式就不做進一步處理,除非它設置了更多的特性。至此一個各為XXX的設備就已經載入成功,當使用者程式調用CreateFile來打開這個設備時,裝置管理員就會調XXX_Open函數。
參數:
pCoNtext:系統傳入的註冊表鍵,通過它可以講到我們在註冊表中設置的配置資訊。
lpvBusCoNtext:一般不用。
實際上,很多程式中將這個函數寫成了DWORD XXX_Init( DWORD pCoNtext ),我們只需要將pCoNtext轉化成LPCTSTR即可。
DWORD XXX_Open(DWORD hDeviceCoNtext,DWORD dwAccess, DWORD dwShareMode);
當使用者程式調用CreateFile打開這個設備時,裝置管理員就會調用此驅動程式的XXX_Open函數。
參數:
hDeviceCoNtext XXX_Init 返回給上層的值,也就是我們在XXX_Init中分配的用來記錄驅動程式資訊的那個結構體的指標,我們可以在這個函數中直接將其轉化成所定義的結構,從而獲取驅動程式的資訊。
dwAccess 上層所要求的訪問方式,可以是讀或者寫,或者是0,即不讀也不寫。
dwShareMode 上層程式所請求的共用模式,可以是共用讀、共用寫這兩個值的邏輯或,或者是0,即獨佔式訪問。
系統層對設備檔的存取許可權及共用方法已經做了處理,所以在驅動程式中對這兩個參數一般可以不用理會。
這個函數一般不用做太多處理,可以直接返回hDeviceCoNtext表示成功,對於一個不支援多個使用者的硬體,在設備已經打開後,應該總是返回0以至失敗,則CreateFile調用不成功。
DWORD XXX_Close(  DWORD hDeviceCoNtext );
當使用者程式調用CloseHandle關閉這個設備控制碼時,這個函數就會被裝置管理員調用。
參數:
hDeviceCoNtext 為XXX_Open返回給上層的那個值。
這個函數應該做與XXX_Open相反的事情,具體包括:釋放XXX_Open分配的記憶體,將驅動程式被打開的記數減少等。
DWORD XXX_Deinit( DWORD hDeviceCoNtext );
這個函數在設備被卸載時被調用,它應該實現與XXX_Init相反的操作,主要為釋放前者佔用的所有系統資源。
參數:
hDeviceCoNtext XXX_Init函數返回給上層的那個控制碼
void XXX_PowerUp( DWORD hDeviceCoNtext );
void XXX_PowerDown(DWORD hDeviceCoNtext );
正如其名稱中體現的那樣,這兩個函數在系統PowerUp與PowerDown時被調用,這兩個函數中不能使用任何可能引起執行緒切換的函數,否則會引起系統死機。所以,在這兩個函數中,實際上幾乎是什麼做不了,一般在PowerDown時做一個標誌,讓驅動程式知道自已曾經被Power Down過。在Power Down/On的過程中硬體可能會掉電,所以,儘管Power On以後,原來的IO操作仍然會從接著執行,但可能會失敗。這時,當我們發現一次IO操作失敗是因為程式曾經進入過Power Down狀態,就重新初始化一次硬體,再做同樣的IO操作。
BOOL XXX_IOControl(
DWORD hDeviceCoNtext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
);
幾乎可以說一個驅動程式的所有功能都可以在這個函數中實現。對於一類CE自身已經支援的設備,它們已經被定義了一套IO操作定,我們只需按照各類設備已經定義的內容去實現所有的IO操作。但當我們實現一個自訂的設備時,我們就可以隨心所欲定義我們自已的IO操作。
參數:
hDeviceCoNtext XXX_Open返回給上層的那個控制碼,即我們自已定義的,用來存放程式所有資訊的一個結構。
dwCode IO操作碼,如果是CE已經支援的設備類,就用它已經定義好碼值,否則就可以自已定義。
pBufIn 傳入的Buffer,每個IO操作碼都會定義自已的Buffer結構
dwLenIn pBufIn以位元組記的大小
pBufOut,dwLenOut分別為傳出的Buffer,及其以位元組記的大小
pdwActualOut 驅動程式實際在pBufOut中填入的資料以位元組記的大小
其中,前兩個參數是必須的,其它的任何一個都有可能是Null或0。所以,當給pdwActualOut賦值時應該先判斷它是否為一個有效的位址。
2. 註冊表的設置
系統啟動時啟動裝置管理程式,裝置管理程式讀取HKEY_LOCAL_MACHINE/Drivers/BuiltIn鍵的內容並載入已列出的流介面驅動程式。因此註冊表對於驅動的載入有著關鍵作用。下面我們以設備名是「STR」來舉一個例子:

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/STR]
"Prefix"="STR"
"Dll"="MyDev.Dll"
"Order"=dword:1
其中 "Prefix"="STR" 表示流介面的首碼,我們以後可以通過Creatfile 函數來實現對這個流介面的操作,實現如下:HANDLE hStr = CreateFile(TEXT("str1:"), GENERIC_READ | GENERIC_WRITE, 0, Null, OPEN_EXISTING, 0, 0) 。其中「str1:」中的表示設備好「1」是必需的,不管你的設備當中是不是剛好只有一個,不然的話會出現打開不了這個設備的情況。

"Dll"="MyDev.Dll" 指的是「STR」設備調用的驅動程式 DLL。

HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SampleDev 表示該註冊表存在於CE系統登錄的 HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SampleDev 目錄下。

3. 創建Makefile和Sources和.def檔
這三個檔主要是來控制編譯的,Makefile 和 .def 檔實現比較簡單,Sources 檔相對比較複雜。

Makefile 只需要這樣一行!INCLUDE $(_MAKEENVROOT)/makefile.def ,具體的實現什麼任務還不知道。

.def 檔定義需要輸出的函數,這些函數能夠被其它代碼用動態載入的方法調用。

Sources 這個檔很重要,內容也多,最基本的一個檔該有如下內容。

TARGETNAME=MyDev(指定要生成的動態庫的名稱)
TARGETTYPE=DYNLINK(指定要生成的是一個動態庫)
TARGETLIBS=$(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/coredll.lib /
        $(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/ceddk.lib

(下面兩項指定需要與哪些動態庫連結,一般要第一項就足夠了)
DLLENTRY=DllEntry(指定動態庫的入口函數)
SOURCES= (請在這寫上你所有原始檔案的名字,它們將會被編譯)
創作者介紹

資訊園

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()