Windows_Driver_Model

**視窗驅動程式模型**（**Windows Driver Model**，簡稱 WDM），是微軟視窗作業系統的驅動程式設計架構，包括對於各項裝置（Device）的支援，如鍵盤（Keyboard）、滑鼠（Mouse）、網路卡（Network Driver Interface Specification，Ndis）、通用序列匯流排（Universal Serial Bus，USB）等。WDM 可支援 Windows 98, Windows 98 Second Edition, Windows Me, Windows 2000, Windows XP 以及 Windows Server 2003 在 x86 平台上的建制工作。這個架構分成好幾個管理層面：

* 核心（Kernel）
* 物件管理（Object Manager）
* 執行（Executive）
* 輸入輸出管理（I/O Manager）
* 記憶體管理（Memory Manager）
* 行程服務（Process Service）
* 執行時期函式庫（Run-time Library）
* 電源管理（Power Manager）
* 隨插即用子系統（Plug and Play Subsystem）
* 視窗管理指令（Windows Management Instrumentation，WMI）
* 核心流（Kernel Streaming）
* 硬體抽象層（Hardware Abstraction Layer）

## 種類

驅動程式的種類有匯流排驅動程式（bus driver）、功能驅動程式（function driver）、篩選驅動程式（filter driver）三種：

* 匯流排驅動程式（bus drivers）
  * 虛擬匯流排驅動程式（Virtual bus drivers）：呼叫 IoInvalidateDeviceRelations 通知 PnP Manager。
* 功能驅動程式（function drivers）
  * 微埠型驅動程式（miniport drivers）：屬於 USB, Audio, SCSI 以及 network 的轉換器（adapters）。
  * 虛擬裝置驅動程式（Virtual device drivers）
  * 類型驅動程式（Class drivers）
* 篩選性驅動程式（filter drivers）
  * 上層篩選性驅動程式（upper-filter drivers）
  * 下層篩選性驅動程式（lower-filter drivers）

## 程式進入點

如同許多語言從 main 函式開始，WDM 驅動程式的載入（Loading）乃至於動作，以及其解除安裝（Unload）行為，都有其步驟與規則。WDM 驅動程式可以動態式的載入與解除安裝，當偵測到裝置（Device）插入的時候，依據「PnP Manager」會自動地載入相對應的裝置驅動程式，然後成為「Driver Object」，並呼叫 DriverEntry 函式。所有的 WDM 驅動程式，都必須擁有這個 DriverEntry 常式（routine），而且「此一名稱不可改變」的，所有的驅動程式也是從這裡開始執行的，I/O Manager 首先呼叫驅動程式的 `DriverEntry()`。DriverEntry 在 DDK Compiler 編譯出來的輸出符號表是「`DriverEntry@8`」，原因是微軟的 C 編譯器把 stdcall 函示（例如 VcDCall）的名稱加上「記號」，加上一個＠符號，在附上參數的總位元組個數，8 指此 function 的所有參數所佔的 byte 數。

DriverEntry 函式有兩個參數，其中第一個參數 `PDRIVER_OBJECT DriverObject` 是指向該驅動程式對應的物件指標；`PUNICODE_STRING RegistryPath`，驅動程式的服務主要鍵碼，這個參數的使用時機並不多。以下是一個簡單而標準的 DriverEntry 基本實作：

## IRQL

DriverEntry 運作在 IRQL = PASSIVE\_LEVEL 等級，所以可以使用分頁記憶體。WDM 有數個經常實作的 PASSIVE\_LEVEL 等級如下：

* DriverEntry
* Dispatch Function：DispatchXxx
* Unload：UnloadXxx
* AddDevice: XxxAddDevice
* Reinitialize: XxxReinitialize

另外還有幾個 DISPATCH\_LEVEL 等級的函式如下：

* StartIo
* AdapterControl
* ControllerControl
* IoTimer
* Dpc（延遲程式呼叫，Deferred Procedure Call）

## 派送行程

當 _DriverEntry_ 函式完成物件的初始化與系統註冊之後，接下來的重點便會落在 Dispatch Function 身上。每當 I/O Manager 得到一個請求時（例如按鍵，移動滑鼠），它使用請求的函式代碼（IoControlCode）呼叫驅動程式中幾個 Dispatch 行程。

## 解除安裝

Unload 負責在驅動程式被停止前做一些必要的處理動作，如釋放資源，記錄最後狀態等。

## 編譯

驅動程式的編譯需要使用 DDK（_Device Driver Kit_）中的 build 指令，它是一道命令列程式，一般會在後面加上參數：**-ceZ**。例如：

DDK 可用於建立用於 Windows 2000、Windows XP、Microsoft Windows Server 2003、Vista 的建置環境，但在 Windows 作業系統並非預設的功能，必須另行安裝。安裝完成後你會看到 Build Enviroment，**free 是指 release 版，check 則是 debug 版**。

* Windows XP checked 64 Bit Build Environment
* Windows XP checked Build Environment
* Windows XP free 64 Bit Build Environment
* Windows XP free Build Environment

build 指令一開始呼叫 Build.exe 編譯連結器，從系統「環境變數」（Environment Variable）Include 中得到參照檔案的位址，然後呼叫 **Visual C++** 的編譯連結器 Nmake.exe 進行實際的編譯連結工作。在編譯過程中遇到的錯誤，遇到的警告，會記錄到 buildxxx.log，buildxxx.wrn，buildxxx.err 等檔案中。

## 安裝

安裝過程分成兩個步驟：

* 首先將編譯成的.sys 檔案複製到 Windows NT 的 System32\\Drivers\\ 目錄下；
* 接著在 Registry 的 HKEY\_LOCAL\_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\ 下建立和.sys 檔案同名的鍵，然後在之下建立名為 Start、Type、ErrorControl 的三種 REG\_DWORD 類型的鍵值。

## 範例

Microsoft DDK 提供了大量的 WDM 範例（samples）參考，這些範例隨著 DDK 的安裝，會進駐我們的系統之中（WINDDK\xx00\src）。一般人不大可能從輪子造起一個新的驅動程式，大部份要靠「既有的範例」來改良一個新的驅動程式。

* 1394
* Audio
* AVStream
* filesys
* general
* hid
* input
* ir
* kernel

## 批評

* WDM 學習曲線過長。
* 電源管理（power management）事件與隨插即用（Plug-and-play）差異太大。導致系統的睡眠（sleep）與清醒（wake up）狀態容易產生問題。
* I/O cancellation 幾乎不可能達成。
* 每支驅動程式動輒要撰寫數千行的程式碼。
* 不支援純使用者模式（pure user-mode）驅動程式。

## 相關條目

* Windows Driver Foundation
* Windows Display Driver Model
* VxD

## 外部連結

* Windows Driver Foundation Homepage
* Introducing Windows Driver Framework，written by well-known Windows driver developer, Walter Oney.
* Building and deploying a basic WDF Kernel Mode Driver，CodeProject
* Developing a WDF USB Kernel Mode Driver for the OSR USB FX2，CodeProject
* A simple demo for WDM Driver development

## 參考

* Walter Oney，《Windows Driver Model》