WDM驅動程式設計之設計開發篇 (轉)
WDM驅動程式設計之設計開發篇 (轉)[@more@]
(作者:蘇金國 2000年11月09日 13:26)
透過DDK和相應的開發,我們構造好了WDM的開發環境。接著,我們就要深入進行設計與開發工作了。
■WDM 驅動程式的運作流程
WDM本身的PNP管理器被抽象地提升到了的地位。PNP管理器負責所有的匯流排驅動程式的載入。匯流排驅動程式則負責遍歷所有位於匯流排上的裝置,並且為每個裝置建立相應的裝置。當PNP管理器發現一個裝置物件,就查詢該物件對應的。並該Driver的ADD DEVICE例程。如果Driver不在中,就先載入,然後呼叫ADD DEVICE例程。
當然,匯流排本身並沒有發出任何訊號告訴PNP管理器自己的存在,所以,匯流排Driver是在NT的安裝時設定的。而ISA裝置並沒有規範,因為需要KMD自己檢查存在及狀態,所以它是老式KMD存在的惟一理由。這也是極力在新規範裡取消ISA匯流排的理由之一。WDM支援PNP和PM協議,而且實現時僅僅需要在MAJOR FUNCTION里加入一些對PNP和PM事件響應的例程即可。
■驅動
設計一個裝置驅動程式,應該支援和其他相同型別裝置的NT驅動程式相同的IRP_MJ_XXX和IOCTL請求程式碼。如果設計一箇中間層NT驅動程式,應該首先確認下層驅動程式所管理的裝置,因為一個高層的驅動程式必須具有低層驅動程式絕大多數IRP_MJ_XXX例程入口。高層驅動程式在接到I/O請求時,在確定自身IRP當前堆疊單元引數有效的前提下 ,設定好IRP中下一個低層驅動程式的堆疊單元,然後再呼叫IoCallDriver將請求傳遞給下層驅動程式處理。一旦決定好了驅動程式應該處理哪些IRP_MJ_XXX,就可以開始確定驅動程式應該有多少個Dispatch例程。當然也可以考慮把某些RP_MJ_XXX處理的例程合併為同一例程處理。例如在ChangerDisk和VDisk裡,對IRP_MJ_CREATE和IRP_MJ_CLOSE處理的例程就是同一。
一個驅動程式必須為它所管理的每個可能成為I/O請求的目標的物理和邏輯裝置建立一個Device物件。一些低層的驅動程式還可能要建立一些不確定數目的Device物件。例如一個驅動程式必須為每一個物理硬碟建立一個Device物件,同時還必須為每個物理上的每個邏輯分割槽建立一個Device物件。
一個高層驅動程式必須為它所代表的虛擬裝置建立一個Device物件,這樣更高層的驅動程式才能連線它們的Device物件到這個驅動程式的Device物件。另外,一個高層驅動程式通常為它低層驅動程式所建立的Device物件建立一系列的虛擬或邏輯Device物件。
儘管可以分階段來設計驅動程式,從而使一個處在開發階段的驅動程式不必一開始就建立出所有它將要處理的所有Device物件,但從一開始就確定好最終要建立的所有Device物件將有助於設計者所要解決的任何同步問題。另外,確定所要建立的Device物件還有助於定義Device物件的Device Extension的內容和資料結構。
■驅動程式開發
驅動程式的開發是一個從粗到細逐步求精的過程。NT DDK的src目錄下有一個龐大的模板程式碼,幾乎覆蓋了所有型別的裝置驅動程式、高層驅動程式和過濾器驅動程式。在開始開發驅動程式之前,應該先在這個樣板庫下面尋找是否有和所要開發的類似型別的例程。
例如若要開發光碟塔驅動程式,雖然DDK對光碟塔沒有任何描述,但光碟塔是符合-Ⅱ規範的SCSI裝置,可以在srcstorageclass目錄中發現很多和SCSI裝置有關的驅動程式,例如SCSI Tape、SCSI Disk、SCSI CDROM等驅動程式開發時,可以參考類似驅動程式,從而減化開發難度。
下面筆者將進一步介紹開發驅動程式的基本步驟:
l.編寫驅動程式
(1)首先編寫一個DriverEntry例程,並在該例程裡呼叫IoCreateDevice來建立一個Device物件。
(2)寫一個處理IRP_MJ_CREATE請求的Dispatch例程的基本框架。如果驅動程式建立了多於一個的Device物件,則必須為IRP_MJ_CLOSE請求寫一個例程,該例程通常情況下可以和DispatchCreate共用一個例程。
(3) 編譯連線驅動程式。
2.測試驅動程式
(1)首先在中安裝好驅動程式,具體編譯安裝驅動程式請見下版的《編譯安裝篇》。
(2)為NT邏輯裝置名稱和目標Device物件名稱之間建立起符號連線,在前面已經知道Device物件名稱對是不可見的,是不能直接透過來訪問的,Win32 API只能訪問NT邏輯裝置名稱。可以透過修改登錄檔來建立這兩種名稱之間的符號連線。執行Regedt32.exe在HKEY_LOCAL_MACHINE System CurrentControlSet Control Session Manager DDevices下建立起符號連線,這種符號連線也可以在驅動程式裡呼叫函式IoCreateSymbolicLink來建立。
(3)完成以上所有的設定並檢查無誤後,我們必須重新啟動系統。
(4)編寫一個簡單的測試程式呼叫Win32 API中的CreateFile函式,並以剛才命名的NT邏輯裝置名開啟這個裝置。如果開啟成功,則成功地寫出了一個最簡單的驅動程式了。支援更多的裝置I/O請求,例如驅動程式可能需要對IRP_MJ_READ請求做出響應(完成後可用ReadFile 函式進行測試)。如果驅動程式需要能夠手工解除安裝,那麼還必須對IRP_MJ_CLOSE做出響應。為所需要處理的IRP_MJ_XXX寫好處理例程,並在DriverEntry裡面初始化好這些例程入口。一個低層的驅動程式需要一個StartIo、ISR和DpcForIsr例程,可能還需要一個SynchCritSection例程,如果裝置使用了DMA,那麼可能還需要一個AdapterControl例程。
對於高層驅動程式可能需要一個或多個IoCompletion例程,最起碼完成檢查I/O狀態塊然後呼叫IoCompleteRequest的工作。如果需要,還要對Device Extension資料結構和內容做些修改。有一點必須很清楚的,就是程式碼執行級別的問題,即IRQL,最常見的級別是PASSIVE_LEVEL、APC_LEVEL、DISPATCH_LEVEL和DIRQL。
在看NT DDK HELP中的函式說明的時候,要注意函式的可執行級別,比如有的函式只能在PASSIVE_LEVEL下執行,有的函式則可以在DISPATCH_LEVEL以下級別執行,級別越高的時候,對程式碼的要求就越嚴格,比如在DISPATCH_LEVEL的時候,就不能使用分頁記憶體。通常情況下應該儘可能讓程式碼在低執行級別如PASSIVE_LEVEL下執行,在高階別下執行過長時間將導致系統降低、影響系統響應的實時性。但有時候自己無法控制執行的級別,例如在呼叫低層Driver時使用IoCallDriver,低層Driver響應完畢後會completion例程,該例程執行的級別就是由低層Driver來決定。因此在編寫completion例程時,應儘量將這個函式設計成能在DISPATCH_LEVEL級別執行。
依照以上開發步驟,我們可以設計出全新的WDM裝置驅動程式。
(作者:蘇金國 2000年11月09日 13:26)
透過DDK和相應的開發,我們構造好了WDM的開發環境。接著,我們就要深入進行設計與開發工作了。
■WDM 驅動程式的運作流程
WDM本身的PNP管理器被抽象地提升到了的地位。PNP管理器負責所有的匯流排驅動程式的載入。匯流排驅動程式則負責遍歷所有位於匯流排上的裝置,並且為每個裝置建立相應的裝置。當PNP管理器發現一個裝置物件,就查詢該物件對應的。並該Driver的ADD DEVICE例程。如果Driver不在中,就先載入,然後呼叫ADD DEVICE例程。
當然,匯流排本身並沒有發出任何訊號告訴PNP管理器自己的存在,所以,匯流排Driver是在NT的安裝時設定的。而ISA裝置並沒有規範,因為需要KMD自己檢查存在及狀態,所以它是老式KMD存在的惟一理由。這也是極力在新規範裡取消ISA匯流排的理由之一。WDM支援PNP和PM協議,而且實現時僅僅需要在MAJOR FUNCTION里加入一些對PNP和PM事件響應的例程即可。
■驅動
設計一個裝置驅動程式,應該支援和其他相同型別裝置的NT驅動程式相同的IRP_MJ_XXX和IOCTL請求程式碼。如果設計一箇中間層NT驅動程式,應該首先確認下層驅動程式所管理的裝置,因為一個高層的驅動程式必須具有低層驅動程式絕大多數IRP_MJ_XXX例程入口。高層驅動程式在接到I/O請求時,在確定自身IRP當前堆疊單元引數有效的前提下 ,設定好IRP中下一個低層驅動程式的堆疊單元,然後再呼叫IoCallDriver將請求傳遞給下層驅動程式處理。一旦決定好了驅動程式應該處理哪些IRP_MJ_XXX,就可以開始確定驅動程式應該有多少個Dispatch例程。當然也可以考慮把某些RP_MJ_XXX處理的例程合併為同一例程處理。例如在ChangerDisk和VDisk裡,對IRP_MJ_CREATE和IRP_MJ_CLOSE處理的例程就是同一。
一個驅動程式必須為它所管理的每個可能成為I/O請求的目標的物理和邏輯裝置建立一個Device物件。一些低層的驅動程式還可能要建立一些不確定數目的Device物件。例如一個驅動程式必須為每一個物理硬碟建立一個Device物件,同時還必須為每個物理上的每個邏輯分割槽建立一個Device物件。
一個高層驅動程式必須為它所代表的虛擬裝置建立一個Device物件,這樣更高層的驅動程式才能連線它們的Device物件到這個驅動程式的Device物件。另外,一個高層驅動程式通常為它低層驅動程式所建立的Device物件建立一系列的虛擬或邏輯Device物件。
儘管可以分階段來設計驅動程式,從而使一個處在開發階段的驅動程式不必一開始就建立出所有它將要處理的所有Device物件,但從一開始就確定好最終要建立的所有Device物件將有助於設計者所要解決的任何同步問題。另外,確定所要建立的Device物件還有助於定義Device物件的Device Extension的內容和資料結構。
■驅動程式開發
驅動程式的開發是一個從粗到細逐步求精的過程。NT DDK的src目錄下有一個龐大的模板程式碼,幾乎覆蓋了所有型別的裝置驅動程式、高層驅動程式和過濾器驅動程式。在開始開發驅動程式之前,應該先在這個樣板庫下面尋找是否有和所要開發的類似型別的例程。
例如若要開發光碟塔驅動程式,雖然DDK對光碟塔沒有任何描述,但光碟塔是符合-Ⅱ規範的SCSI裝置,可以在srcstorageclass目錄中發現很多和SCSI裝置有關的驅動程式,例如SCSI Tape、SCSI Disk、SCSI CDROM等驅動程式開發時,可以參考類似驅動程式,從而減化開發難度。
下面筆者將進一步介紹開發驅動程式的基本步驟:
l.編寫驅動程式
(1)首先編寫一個DriverEntry例程,並在該例程裡呼叫IoCreateDevice來建立一個Device物件。
(2)寫一個處理IRP_MJ_CREATE請求的Dispatch例程的基本框架。如果驅動程式建立了多於一個的Device物件,則必須為IRP_MJ_CLOSE請求寫一個例程,該例程通常情況下可以和DispatchCreate共用一個例程。
(3) 編譯連線驅動程式。
2.測試驅動程式
(1)首先在中安裝好驅動程式,具體編譯安裝驅動程式請見下版的《編譯安裝篇》。
(2)為NT邏輯裝置名稱和目標Device物件名稱之間建立起符號連線,在前面已經知道Device物件名稱對是不可見的,是不能直接透過來訪問的,Win32 API只能訪問NT邏輯裝置名稱。可以透過修改登錄檔來建立這兩種名稱之間的符號連線。執行Regedt32.exe在HKEY_LOCAL_MACHINE System CurrentControlSet Control Session Manager DDevices下建立起符號連線,這種符號連線也可以在驅動程式裡呼叫函式IoCreateSymbolicLink來建立。
(3)完成以上所有的設定並檢查無誤後,我們必須重新啟動系統。
(4)編寫一個簡單的測試程式呼叫Win32 API中的CreateFile函式,並以剛才命名的NT邏輯裝置名開啟這個裝置。如果開啟成功,則成功地寫出了一個最簡單的驅動程式了。支援更多的裝置I/O請求,例如驅動程式可能需要對IRP_MJ_READ請求做出響應(完成後可用ReadFile 函式進行測試)。如果驅動程式需要能夠手工解除安裝,那麼還必須對IRP_MJ_CLOSE做出響應。為所需要處理的IRP_MJ_XXX寫好處理例程,並在DriverEntry裡面初始化好這些例程入口。一個低層的驅動程式需要一個StartIo、ISR和DpcForIsr例程,可能還需要一個SynchCritSection例程,如果裝置使用了DMA,那麼可能還需要一個AdapterControl例程。
對於高層驅動程式可能需要一個或多個IoCompletion例程,最起碼完成檢查I/O狀態塊然後呼叫IoCompleteRequest的工作。如果需要,還要對Device Extension資料結構和內容做些修改。有一點必須很清楚的,就是程式碼執行級別的問題,即IRQL,最常見的級別是PASSIVE_LEVEL、APC_LEVEL、DISPATCH_LEVEL和DIRQL。
在看NT DDK HELP中的函式說明的時候,要注意函式的可執行級別,比如有的函式只能在PASSIVE_LEVEL下執行,有的函式則可以在DISPATCH_LEVEL以下級別執行,級別越高的時候,對程式碼的要求就越嚴格,比如在DISPATCH_LEVEL的時候,就不能使用分頁記憶體。通常情況下應該儘可能讓程式碼在低執行級別如PASSIVE_LEVEL下執行,在高階別下執行過長時間將導致系統降低、影響系統響應的實時性。但有時候自己無法控制執行的級別,例如在呼叫低層Driver時使用IoCallDriver,低層Driver響應完畢後會completion例程,該例程執行的級別就是由低層Driver來決定。因此在編寫completion例程時,應儘量將這個函式設計成能在DISPATCH_LEVEL級別執行。
依照以上開發步驟,我們可以設計出全新的WDM裝置驅動程式。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987279/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- WDM驅動程式設計之編譯安裝篇 (轉)程式設計編譯
- Delphi之快速設計(程式設計篇) (轉)程式設計
- 驅動篇——核心程式設計基礎程式設計
- linux驅動程式設計(轉)Linux程式設計
- 程式設計模式-表驅動程式設計程式設計設計模式
- 程式設計技巧之-表驅動法程式設計
- 前端開發-領域驅動設計前端
- 事件驅動程式設計事件程式設計
- 模型驅動設計(MDD)之靈活設計模型
- 領域驅動設計與敏捷開發敏捷
- 領域驅動設計最佳實踐--程式碼篇
- Linux裝置驅動程式設計之阻塞與非阻塞(轉)Linux程式設計
- Java開發架構篇《初識領域驅動設計DDD落地》Java架構
- Java開發架構篇:初識領域驅動設計DDD落地Java架構
- Linux 程式設計之Shell程式設計(轉)Linux程式設計
- Java設計模式之開篇Java設計模式
- 系統設計思想之Domain驅動AI
- 領域驅動設計與模型驅動設計的關係模型
- Flutter開發之非同步程式設計Flutter非同步程式設計
- 【程式設計開發】之 OAuth2程式設計OAuth
- 遊戲開發新手入門之Windows程式設計(轉)遊戲開發Windows程式設計
- 建立開發程式設計機制 (轉)程式設計
- 微服務架構設計基礎之領域驅動設計微服務架構
- Android事件驅動程式設計(二)Android事件程式設計
- Android事件驅動程式設計(三)Android事件程式設計
- Android事件驅動程式設計(一)Android事件程式設計
- 玩轉 PHP 網路程式設計之原理篇PHP程式設計
- 【程式設計開發】之開發解決的“坑“程式設計
- 測試開發之自動化篇-自動化測試框架設計框架
- 中文程式設計之思考 (轉)程式設計
- 行為驅動開發(BDD)如何與領域驅動設計(DDD)結合?
- 測試開發之效能篇-效能測試設計
- 極限程式設計 vs 互動式設計 (轉)程式設計
- 虛擬裝置驅動程式的設計與實現 (轉)
- C++Builder5.0呼叫SQLSERVER7.0驅動程式設計 (轉)C++UISQLServer程式設計
- Java 程式設計開發Java程式設計
- Laravel最佳實踐–事件驅動程式設計Laravel事件程式設計
- Laravel 最佳實踐 -- 事件驅動程式設計Laravel事件程式設計