設定和使用裝置佇列

驅動程式會在驅動程式或裝置初始化上呼叫 KeInitializeDeviceQueue 來設定裝置佇列物件。 啟動其裝置 () 之後,驅動程式會呼叫 KeInsertDeviceQueueKeInsertByKeyDeviceQueue,將 IRP 插入此佇列。 下圖說明這些呼叫。

設定和使用裝置佇列。

如圖所示,驅動程式必須提供裝置佇列物件的儲存體,該物件必須位於其中。 設定裝置佇列物件的驅動程式通常會在驅動程式所建立 裝置物件的裝置延伸模組 中提供必要的儲存空間,但如果驅動程式使用 控制器物件 或驅動程式所配置的非分頁集區,則存放裝置可以在控制器擴充功能中。

如果驅動程式在裝置擴充功能中提供裝置佇列物件的儲存體,它會在建立裝置物件之後和啟動裝置之前呼叫 KeInitializeDeviceQueue 。 換句話說,驅動程式可以從其 AddDevice 常式或處理 PnP IRP_MN_START_DEVICE 要求時初始化佇列。 在 對 KeInitializeDeviceQueue的呼叫中,驅動程式會將指標傳遞給它提供給裝置佇列物件的儲存體。

啟動其裝置 () 之後,驅動程式可以呼叫 KeInsertDeviceQueue將 IRP 插入其裝置佇列中,這會將 IRP 放在佇列結尾,或 KeInsertByKeyDeviceQueue,這會根據驅動程式決定的 SortKey 值將 IRP 放入佇列中,如下圖所示。

每個支援常式都會傳回布林值,指出是否已將 IRP 插入佇列中。 如果佇列目前是空的,則這些呼叫也會將裝置佇列物件的狀態設定為 Busy (Not-Busy) 。 不過,如果佇列是空的 (非忙碌) , 則 KeInsertXxxDeviceQueue 常式都不會將 IRP 插入佇列。 相反地,它會將裝置佇列物件的狀態設定為 Busy,並傳回 FALSE。 因為 IRP 尚未排入佇列,所以驅動程式必須將它傳遞給另一個驅動程式常式,以便進一步處理。

設定補充裝置佇列時,請遵循此實作指導方針:

呼叫 KeInsertXxxDeviceQueue 傳回 FALSE時,呼叫端必須傳遞它嘗試排入佇列的 IRP,以便進一步處理至另一個驅動程式常式。 不過, 呼叫 KeInsertXxxDeviceQueue 會將裝置佇列物件的狀態變更為 Busy,因此除非驅動程式先呼叫 KeRemoveXxxDeviceQueue ,否則要傳入的下一個 IRP 會插入佇列中。

當裝置佇列物件的狀態設定為 [忙碌] 時,驅動程式可以藉由呼叫下列其中一個支援常式,將 IRP 清除佇列,以便進一步處理或將狀態重設為Not-Busy:

呼叫上述任一常式,從空白但忙碌的裝置佇列中移除專案,將佇列狀態變更為「不忙碌」。

每個裝置佇列物件都會受到內建的執行微調鎖定保護, (未顯示在 [使用裝置佇列物件 ] 圖) 中。 因此,驅動程式可以將 IRP 插入佇列中,並以多處理器安全的方式從執行小於或等於 IRQL = DISPATCH_LEVEL 的任何驅動程式常式中移除它們。 由於此 IRQL 限制,驅動程式無法從在 DIRQL 執行的 ISR 或SynchCritSection常式呼叫任何KeXxxDeviceQueue常式。

如需詳細資訊,請參閱 管理硬體優先順序微調鎖定 。 如需特定支援常式的 IRQL 需求,請參閱常式的參考頁面。