Minidrivers、Miniport 驅動程式和驅動程式配對

迷你驅動程式或迷你埠驅動程式可作為驅動程式配對的一半。 (迷你埠、埠) 等驅動程式配對可讓您更輕鬆地開發驅動程式。 在驅動程式配對中,一個驅動程式會處理整個裝置集合通用的一般工作,而其他驅動程式則會處理個別裝置特有的工作。 處理裝置特定工作的驅動程式會依各種名稱排列,包括迷你埠驅動程式、迷你類別驅動程式和minidriver。

Microsoft 提供一般驅動程式,而且通常獨立硬體廠商會提供特定的驅動程式。 閱讀本主題之前,您應該先瞭解 裝置節點和裝置堆疊和I/O 要求封包中呈現的概念。

每個核心模式驅動程式都必須實作名為 DriverEntry 的函式,此函式會在載入驅動程式之後不久呼叫。 DriverEntry 函式會填入DRIVER_OBJECT結構的特定成員,其中包含驅動程式所實作之數個其他函式的指標。 例如,DriverEntry 函式會以驅動程式 Unload 函式的指標填入DRIVER_OBJECT結構的 Unload 成員,如下圖所示。

此圖顯示具有卸除成員的驅動程式對象結構。

DRIVER_OBJECT 結構的 MajorFunction 成員是函式的指標陣列,可處理 I/O 要求封包 (IRPs) ,如下圖所示。 驅動程式通常會填入 MajorFunction 數位的數個成員,其中包含驅動程式) 處理各種IRP之函式 (的指標。

此圖顯示具有 majorfunction 成員的 driver-object 結構。

IRP 可以根據其主要函式程式代碼進行分類,此程式代碼是由常數所識別,例如 IRP_MJ_READIRP_MJ_WRITEIRP_MJ_PNP。 識別主要函式程序代碼的常數,可作為 MajorFunction 陣列中的索引。 例如,假設驅動程式會實作分派函式來處理具有主要函式程序代碼的 IRP IRP_MJ_WRITE。 在此情況下,驅動程式必須使用分派函式的指標填入陣列的 MajorFunction[IRP_MJ_WRITE] 元素。

驅動程式通常會填入 MajorFunction 數位的某些元素,並將其餘元素設定為I/O管理員所提供的預設值。 下列範例示範如何使用 !drvobj 調試程式延伸模組來檢查剖析區驅動程式的函式指標。

0: kd> !drvobj parport 2
Driver object (fffffa80048d9e70) is for:
 \Driver\Parport
DriverEntry:   fffff880065ea070 parport!GsDriverEntry
DriverStartIo: 00000000 
DriverUnload:  fffff880065e131c parport!PptUnload
AddDevice:     fffff880065d2008 parport!P5AddDevice

Dispatch routines:
[00] IRP_MJ_CREATE                      fffff880065d49d0    parport!PptDispatchCreateOpen
[01] IRP_MJ_CREATE_NAMED_PIPE           fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       fffff880065d4a78    parport!PptDispatchClose
[03] IRP_MJ_READ                        fffff880065d4bac    parport!PptDispatchRead
[04] IRP_MJ_WRITE                       fffff880065d4bac    parport!PptDispatchRead
[05] IRP_MJ_QUERY_INFORMATION           fffff880065d4c40    parport!PptDispatchQueryInformation
[06] IRP_MJ_SET_INFORMATION             fffff880065d4ce4    parport!PptDispatchSetInformation
[07] IRP_MJ_QUERY_EA                    fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              fffff880065d4be8    parport!PptDispatchDeviceControl
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff880065d4c24    parport!PptDispatchInternalDeviceControl
[10] IRP_MJ_SHUTDOWN                    fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL                fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP                     fffff880065d4af4    parport!PptDispatchCleanup
[13] IRP_MJ_CREATE_MAILSLOT             fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       fffff880065d491c    parport!PptDispatchPower
[17] IRP_MJ_SYSTEM_CONTROL              fffff880065d4d4c    parport!PptDispatchSystemControl
[18] IRP_MJ_DEVICE_CHANGE               fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   fffff80001b6ecd4    nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         fffff880065d4840    parport!PptDispatchPnp

在調試程序輸出中,您可以看到 parport.sys 實作 GsDriverEntry,這是驅動程式的進入點。 GsDriverEntry 會在建置驅動程式時自動產生,執行一些初始化,然後呼叫驅動程式開發人員所實作的 DriverEntry

您也可以在其 DriverEntry 函式中看到剖析驅動程式 () 提供這些主要函式程式代碼分派函式的指標:

  • IRP_MJ_CREATE
  • IRP_MJ_CLOSE
  • IRP_MJ_READ
  • IRP_MJ_WRITE
  • IRP_MJ_QUERY_INFORMATION
  • IRP_MJ_SET_INFORMATION
  • IRP_MJ_DEVICE_CONTROL
  • IRP_MJ_INTERNAL_DEVICE_CONTROL
  • IRP_MJ_CLEANUP
  • IRP_MJ_POWER
  • IRP_MJ_SYSTEM_CONTROL
  • IRP_MJ_PNP

MajorFunction 數位列的其餘元素會保留預設分派函式 nt 的指標!IopInvalidDeviceRequest

在調試程序輸出中,您可以看到剖析區驅動程式提供 UnloadAddDevice 的函式指標,但未提供 StartIo 的函式指標。 AddDevice 函式不尋常,因為它的函式指標不會儲存在 DRIVER_OBJECT 結構中。 相反地,它會儲存在延伸模組的 AddDevice 成員中 ,以DRIVER_OBJECT 結構。 下圖說明剖析器驅動程式在其 DriverEntry 函式中提供的函式指標。 剖析區所提供的函式指標會著色。

driver-object 結構中的函式指標圖表。

使用驅動程式配對讓您更容易使用

一段時間后,隨著 Microsoft 內部和外部的驅動程式開發人員獲得 Windows 驅動程式模型 (WDM) 的經驗,他們瞭解了一些關於分派函式的事項:

  • 分派函式大部分都是重複使用的。 例如,所有驅動程式的分派函式中的大部分程式代碼IRP_MJ_PNP都相同。 它只是 隨插即用 (PnP) 程式代碼的一小部分,這是控制個別硬體片段的個別驅動程式專屬的程式代碼。
  • 分派函式很複雜且難以正確。 實作線程同步處理、IRP 佇列和 IRP 取消等功能相當具挑戰性,而且需要深入瞭解操作系統的運作方式。

為了方便驅動程式開發人員使用,Microsoft 建立了數個技術特定的驅動程式模型。 一目了然,技術特定模型似乎彼此不同,但更仔細地顯示其中許多模型都是以這個範例為基礎:

  • 驅動程式分成兩個部分:一個處理一般處理,另一個處理特定裝置特有的處理。
  • 一般片段是由 Microsoft 撰寫。
  • 特定部分可由 Microsoft 或獨立硬體廠商撰寫。

假設 Proseware 和 Contoso 公司都製作了需要 WDM 驅動程式的 Toy 機器人。 此外,假設 Microsoft 提供名為 GeneralRobot.sys 的一般機器人驅動程式。 Proseware 和 Contoso 可以撰寫小型驅動程式來處理其特定機器人的需求。 例如,Proseware 可以撰寫 ProsewareRobot.sys,而驅動程式配對 (ProsewareRobot.sys,GeneralRobot.sys) 可以合併成單一 WDM 驅動程式。 同樣地,驅動程式配對 (ContosoRobot.sys,GeneralRobot.sys) 可以合併成單一 WDM 驅動程式。 在最常見的形式中,概念是您可以使用 (specific.sys 來建立驅動程式,general.sys) 組。

驅動程式配對中的函式指標

在 (specific.sys general.sys) 組中,Windows 會載入 specific.sys 並呼叫其 DriverEntry 函式。 specific.sys 的 DriverEntry 函式會接收 DRIVER_OBJECT 結構的指標。 一般而言,您會預期 DriverEntry 會填入 MajorFunction 陣列的數個元素,其中包含分派函式的指標。 此外,您還需要 DriverEntry 填入 Unload 成員 (,而且可能是DRIVER_OBJECT結構的StartIo 成員和驅動程式物件延伸模組的 AddDevice 成員) 。 不過,在驅動程式配對模型中, DriverEntry 不一定這麼做。 相反地,specific.sys 的 DriverEntry 函式會將 DRIVER_OBJECT 結構傳遞至 general.sys 所實作的初始化函式。 下列程式代碼範例示範如何在 (ProsewareRobot.sys GeneralRobot.sys) 配對中呼叫初始化函式。

PVOID g_ProsewareRobottCallbacks[3] = {DeviceControlCallback, PnpCallback, PowerCallback};

// DriverEntry function in ProsewareRobot.sys
NTSTATUS DriverEntry (DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath)
{
   // Call the initialization function implemented by GeneralRobot.sys.
   return GeneralRobotInit(DriverObject, RegistryPath, g_ProsewareRobottCallbacks);
}

GeneralRobot.sys 中的初始化函式會將函式指標寫入 DRIVER_OBJECT 結構的適當成員,以及其延伸 () 和 MajorFunction 陣列的適當元素。 概念是,當 I/O 管理員將 IRP 傳送給驅動程式配對時,IRP 會先移至 GeneralRobot.sys 所實作的分派函式。 如果 GeneralRobot.sys 可以自行處理 IRP,則不需要涉及特定驅動程式 ProsewareRobot.sys。 如果 GeneralRobot.sys 可以處理部分但並非所有的 IRP 處理,它會從 ProsewareRobot.sys 實作的其中一個回呼函式取得協助。 GeneralRobot.sys 會在 GeneralRobotInit 呼叫中接收 ProsewareRobot 回呼的指標。

在 DriverEntry 傳回之後的某個時間點,會針對 Proseware 機器人裝置節點建構裝置堆疊。 裝置堆疊看起來可能像這樣。

proseware 機器人裝置節點的圖表,其中顯示裝置堆疊中的三個裝置物件:afterthought.sys (篩選) 、prosewarerobot.sys、fdo generalrobot.sys () ,以及 pci.sys (pdo) 。

如上圖所示,Proseware 機器人的裝置堆疊有三個裝置物件。 頂端裝置物件是與篩選驅動程式相關聯的篩選裝置物件 (Filter DO AfterThought.sys) 。 中間裝置對像是與驅動程式組 (ProsewareRobot.sys 相關聯的功能裝置物件 (FDO) ,GeneralRobot.sys) 。 驅動程式組可作為裝置堆疊的函式驅動程式。 底部裝置物件是與 Pci.sys 相關聯的實體裝置物件 (PDO) 。

請注意,驅動程式組只會佔用裝置堆疊中的一個層級,而且只與一個裝置對象相關聯:FDO。 GeneralRobot.sys 處理 IRP 時,可能會呼叫 ProsewareRobot.sys 以取得協助,但與將要求傳遞至裝置堆疊不同。 驅動程式配對會形成位於裝置堆疊中一層的單一 WDM 驅動程式。 驅動程式配對會完成 IRP,或將其向下傳遞至與 Pci.sys 相關聯的 PDO 堆棧。

驅動程式配對的範例

假設您在膝上型電腦中有無線網路卡,而藉由查看 裝置管理員,即可判斷 netwlv64.sys 是網路卡的驅動程式。 您可以使用 !drvobj 調試程式延伸模組來檢查函式指標是否有 netwlv64.sys。

1: kd> !drvobj netwlv64 2
Driver object (fffffa8002e5f420) is for:
 \Driver\netwlv64
DriverEntry:   fffff8800482f064 netwlv64!GsDriverEntry
DriverStartIo: 00000000 
DriverUnload:  fffff8800195c5f4 ndis!ndisMUnloadEx
AddDevice:     fffff88001940d30 ndis!ndisPnPAddDevice
Dispatch routines:
[00] IRP_MJ_CREATE                      fffff880018b5530 ndis!ndisCreateIrpHandler
[01] IRP_MJ_CREATE_NAMED_PIPE           fffff88001936f00 ndis!ndisDummyIrpHandler
[02] IRP_MJ_CLOSE                       fffff880018b5870 ndis!ndisCloseIrpHandler
[03] IRP_MJ_READ                        fffff88001936f00 ndis!ndisDummyIrpHandler
[04] IRP_MJ_WRITE                       fffff88001936f00 ndis!ndisDummyIrpHandler
[05] IRP_MJ_QUERY_INFORMATION           fffff88001936f00 ndis!ndisDummyIrpHandler
[06] IRP_MJ_SET_INFORMATION             fffff88001936f00 ndis!ndisDummyIrpHandler
[07] IRP_MJ_QUERY_EA                    fffff88001936f00 ndis!ndisDummyIrpHandler
[08] IRP_MJ_SET_EA                      fffff88001936f00 ndis!ndisDummyIrpHandler
[09] IRP_MJ_FLUSH_BUFFERS               fffff88001936f00 ndis!ndisDummyIrpHandler
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff88001936f00 ndis!ndisDummyIrpHandler
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff88001936f00 ndis!ndisDummyIrpHandler
[0c] IRP_MJ_DIRECTORY_CONTROL           fffff88001936f00 ndis!ndisDummyIrpHandler
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff88001936f00 ndis!ndisDummyIrpHandler
[0e] IRP_MJ_DEVICE_CONTROL              fffff8800193696c ndis!ndisDeviceControlIrpHandler
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff880018f9114 ndis!ndisDeviceInternalIrpDispatch
[10] IRP_MJ_SHUTDOWN                    fffff88001936f00 ndis!ndisDummyIrpHandler
[11] IRP_MJ_LOCK_CONTROL                fffff88001936f00 ndis!ndisDummyIrpHandler
[12] IRP_MJ_CLEANUP                     fffff88001936f00 ndis!ndisDummyIrpHandler
[13] IRP_MJ_CREATE_MAILSLOT             fffff88001936f00 ndis!ndisDummyIrpHandler
[14] IRP_MJ_QUERY_SECURITY              fffff88001936f00 ndis!ndisDummyIrpHandler
[15] IRP_MJ_SET_SECURITY                fffff88001936f00 ndis!ndisDummyIrpHandler
[16] IRP_MJ_POWER                       fffff880018c35e8 ndis!ndisPowerDispatch
[17] IRP_MJ_SYSTEM_CONTROL              fffff880019392c8 ndis!ndisWMIDispatch
[18] IRP_MJ_DEVICE_CHANGE               fffff88001936f00 ndis!ndisDummyIrpHandler
[19] IRP_MJ_QUERY_QUOTA                 fffff88001936f00 ndis!ndisDummyIrpHandler
[1a] IRP_MJ_SET_QUOTA                   fffff88001936f00 ndis!ndisDummyIrpHandler
[1b] IRP_MJ_PNP                         fffff8800193e518 ndis!ndisPnPDispatch

在調試程序輸出中,您可以看到 netwlv64.sys 實作 GsDriverEntry,這是驅動程式的進入點。 GsDriverEntry 會在驅動程式建置時自動產生,執行一些初始化,然後呼叫驅動程式開發人員所撰寫的 DriverEntry

在此範例中,netwlv64.sys 實作 DriverEntry,但 ndis.sys 實作 AddDeviceUnload 和數個分派函式。 Netwlv64.sys 稱為 NDIS 迷你埠驅動程式,ndis.sys 稱為 NDIS 連結庫。 這兩個模組會形成 (NDIS 迷你埠、NDIS 連結庫) 組。

此圖顯示無線網路卡的裝置堆疊。 請注意,驅動程式配對 (netwlv64.sys,ndis.sys) 只會佔用裝置堆棧中的一個層級,而且只與一個裝置對象相關聯:FDO。

無線網路卡裝置堆疊的圖表,其中顯示 netwlv64.sys,ndis.sys 為與 fdo 相關聯的驅動程式組,並 pci.sys 與 pdo 相關聯。

可用的驅動程式組

不同的技術特定驅動程式模型會針對驅動程式組的特定和一般片段使用各種名稱。 在許多情況下,配對的特定部分具有前置詞 “mini”。以下是一些可用的特定 (一般) 組:

  • (顯示迷你埠驅動程序、顯示埠驅動程式)
  • (音訊迷你埠驅動程式、音訊埠驅動程式)
  • (記憶體迷你埠驅動程式、記憶體埠驅動程式)
  • (電池迷你類別驅動程式、電池類別驅動程式)
  • (HID 迷你驅動程式、HID 類別驅動程式)
  • (changer miniclass 驅動程式、changer 埠驅動程式)
  • (NDIS 迷你埠驅動程式、NDIS 連結庫)

注意 如您在清單中所見,數個模型會針對驅動程式配對的一般部分使用 類別驅動程式 一詞。 這種類別驅動程式與獨立類別驅動程式不同,與類別篩選驅動程式不同。

適用於所有驅動程式開發人員的概念

裝置節點和裝置堆疊

驅動程式堆疊