Share via


處理IRP_MN_SURPRISE_REMOVAL要求

Windows 2000 和更新版本的 PnP 管理員會傳送此 IRP 來通知驅動程式裝置已無法用於 I/O 作業,而且可能已意外從電腦中移除 (「意外移除」) 。

PnP 管理員會基於下列原因傳送 IRP_MN_SURPRISE_REMOVAL 要求:

  • 如果匯流排有熱插即用通知,它會通知裝置的父匯流排驅動程式裝置已消失。 匯流排驅動程式會呼叫 IoInvalidateDeviceRelations。 回應中,PnP 管理員會查詢匯流排驅動程式的子系 (IRP_MN_QUERY_DEVICE_RELATIONS BusRelations) 。 PnP 管理員會判斷裝置不在新的子系列表中,並起始裝置的意外移除作業。

  • 由於另一個原因而列舉公車,且意外移除的裝置不會包含在子系列表中。 PnP 管理員會起始其意外移除作業。

  • 裝置的函式驅動程式會判斷裝置已不存在 (,例如,其要求會重複逾時) 。 匯流排可能是可列舉的,但沒有熱插即用通知。 在此情況下,函式驅動程式會呼叫 IoInvalidateDeviceState。 回應中,PnP 管理員會將 IRP_MN_QUERY_PNP_DEVICE_STATE 要求傳送至裝置堆疊。 函式驅動程式會在PNP_DEVICE_STATE位元遮罩中設定 PNP_DEVICE_FAILED 旗標,指出裝置失敗。

  • 驅動程式堆疊成功完成 IRP_MN_STOP_DEVICE 要求,但後續 IRP_MN_START_DEVICE 要求失敗。 在這種情況下,裝置可能仍然已連線。

所有 PnP 驅動程式都必須處理此 IRP,而且必須將 Irp-IoStatus.Status > 設定為 STATUS_SUCCESS。 呼叫驅動程式AddDevice常式之後,必須準備好隨時處理 PnP 裝置的驅動程式IRP_MN_SURPRISE_REMOVAL。 正確處理 IRP 可讓驅動程式和 PnP 管理員:

  1. 停用裝置,以防仍然連線。

    如果驅動程式堆疊成功完成 IRP_MN_STOP_DEVICE 要求,但基於某些原因,後續 IRP_MN_START_DEVICE 要求失敗,則必須停用裝置。

  2. 釋放指派給裝置的硬體資源,並將其提供給另一部裝置使用。

    一旦裝置不再可用,就應該釋出其硬體資源。 接著,PnP 管理員可以將資源重新指派給另一部裝置,包括使用者可能會熱插回機器的相同裝置。

  3. 將資料遺失和系統中斷的風險降至最低。

    支援熱插即用的裝置及其驅動程式應該設計為處理意外移除。 使用者預期能夠隨時移除支援熱插即用的裝置。

PnP 管理員會在 IRQL = PASSIVE_LEVEL在系統執行緒的內容中傳送IRP_MN_SURPRISE_REMOVAL。

PnP 管理員會先將此 IRP 傳送給驅動程式,再通知使用者模式應用程式和其他核心模式元件。 IRP 完成之後,PnP 管理員會傳送 EventCategoryTargetDeviceChange 通知,並將GUID_TARGET_DEVICE_REMOVE_COMPLETE傳送至在裝置上註冊這類通知的核心模式元件。

IRP_MN_SURPRISE_REMOVAL IRP 會先由裝置堆疊中的頂端驅動程式處理,然後再由每個下一個較低的驅動程式處理。

為了回應 IRP_MN_SURPRISE_REMOVAL,驅動程式必須依照列出的循序執行下列動作:

  1. 判斷裝置是否已移除。

    驅動程式必須一律嘗試判斷裝置是否仍在連線。 如果是,驅動程式必須嘗試停止裝置並加以停用。

  2. (中斷、I/O 埠、記憶體暫存器和 DMA 通道) 釋出裝置的硬體資源。

  3. 在父匯流排驅動程式中,如果驅動程式能夠這麼做,請關閉匯流排插槽。 呼叫 PoSetPowerState 以通知電源管理員。 如需詳細資訊,請參閱 電源管理

  4. 防止裝置上的任何新 I/O 作業。

    驅動程式應該處理後續 IRP_MJ_CLEANUPIRP_MJ_CLOSEIRP_MJ_POWERIRP_MJ_PNP 要求,但驅動程式必須防止任何新的 I/O 作業。 除了關閉、清除和 PnP IRP 之外,驅動程式在裝置存在時,驅動程式必須處理的任何後續 IRP 失敗。

    驅動程式可以在裝置擴充功能中設定一個位,以指出裝置已意外移除。 驅動程式的分派常式應該檢查此位。

  5. 在裝置上失敗未處理的 I/O 要求。

  6. 繼續關閉驅動程式未處理裝置的任何 IRP。

  7. 使用 IoSetDeviceInterfaceState停用裝置介面。

  8. 清除任何裝置特定的配置、記憶體、事件或其他系統資源。

    驅動程式可以延後這類清除,直到收到後續 IRP_MN_REMOVE_DEVICE 要求為止,但如果舊版元件有無法關閉的開啟控制碼,則永遠不會傳送移除 IRP。

  9. 讓裝置物件保持連結至裝置堆疊。

    在後續 IRP_MN_REMOVE_DEVICE 要求之前,請勿卸離並刪除裝置物件。

  10. 完成 IRP。

    在函式或篩選驅動程式中:

    • [Irp-IoStatus.Status > ] 設定為 [STATUS_SUCCESS]。

    • 使用 IoSkipCurrentIrpStackLocation 設定下一個堆疊位置,並使用 IoCallDriver將 IRP 傳遞至下一個較低的驅動程式。

    • 狀態從 IoCallDriver 傳播為 DispatchPnP 常式的傳回狀態。

    • 請勿完成 IRP。

    在匯流排驅動程式 (中,正在處理子 PDO) 的 IRP:

    • [Irp-IoStatus.Status > ] 設定為 [STATUS_SUCCESS]。

    • 使用 IO_NO_INCREMENT 完成 IRP (IoCompleteRequest) 。

    • DispatchPnP 常式傳回。

當此 IRP 成功且裝置的所有開啟控制碼都關閉之後,PnP 管理員會將 IRP_MN_REMOVE_DEVICE 要求傳送至裝置堆疊。 為了回應移除 IRP,驅動程式會將其裝置物件從堆疊中斷連結,並加以刪除。 如果舊版元件已開啟裝置的控制碼,而且即使 I/O 失敗,該控制碼仍會保持開啟狀態,則 PnP 管理員永遠不會傳送移除的 IRP。

所有驅動程式都應該處理此 IRP,並注意裝置已從機器實際移除。 不過,如果某些驅動程式未處理 IRP,則不會造成不良結果。 例如,不取用任何系統硬體資源的裝置,且位於以通訊協定為基礎的匯流排上,例如 USB 或 1394,無法系結硬體資源,因為它不會耗用任何資源。 驅動程式在移除裝置之後嘗試存取裝置並沒有任何風險,因為函式和篩選驅動程式只會透過父匯流排驅動程式存取裝置。 因為匯流排支援移除通知,所以當裝置消失時,父匯流排驅動程式會收到通知,而匯流排驅動程式會失敗所有後續嘗試存取裝置。

在 Windows 98/Me 上,PnP 管理員不會傳送此 IRP。 如果使用者移除裝置而不先使用適當的使用者介面,PnP 管理員只會傳送 IRP_MN_REMOVE_DEVICE 要求給裝置的驅動程式。 所有 WDM 驅動程式都必須同時處理 IRP_MN_SURPRISE_REMOVALIRP_MN_REMOVE_DEVICEIRP_MN_REMOVE_DEVICE的程式碼應該檢查驅動程式是否收到先前的意外移除 IRP,而且應該處理這兩種情況。

使用GUID_REENUMERATE_SELF_INTERFACE_STANDARD

GUID_REENUMERATE_SELF_INTERFACE_STANDARD介面可讓驅動程式要求其裝置繼續執行。

若要使用此介面,請使用 InterfaceType = GUID_REENUMERATE_SELF_INTERFACE_STANDARD,將IRP_MN_QUERY_INTERFACE IRP 傳送至匯流排驅動程式。 匯流排驅動程式會提供指向REENUMERATE_SELF_INTERFACE_STANDARD結構的指標,其中包含介面個別常式的指標。 ReenumerateSelf 常式會要求匯流排驅動程式繼續子裝置。

關於PNP_DEVICE_STATE

PNP_DEVICE_STATE類型是描述裝置 PnP 狀態的位元遮罩。 驅動程式會傳回這個類型的值,以回應 IRP_MN_QUERY_PNP_DEVICE_STATE 要求。

typedef ULONG PNP_DEVICE_STATE, *PPNP_DEVICE_STATE;

PNP_DEVICE_STATE值中的旗標位定義如下。

旗標位 描述
PNP_DEVICE_DISABLED

裝置實際存在,但在硬體中已停用。

PNP_DEVICE_DONT_DISPLAY_IN_UI

請勿在使用者介面中顯示裝置。 針對實際存在但無法用於目前設定的裝置進行設定,例如膝上型電腦未停駐時無法使用的遊戲連接埠。 (另請參閱DEVICE_CAPABILITIES structure.) 中的NoDisplayInUI旗標

PNP_DEVICE_FAILED

裝置存在,但無法正常運作。

設定此旗標和PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED時,裝置必須在 PnP 管理員指派新的硬體資源之前停止, (裝置) 不支援停止重新平衡。

PNP_DEVICE_NOT_DISABLEABLE

電腦啟動時需要裝置。 這類裝置不得停用。

驅動程式會為適當的系統作業所需的裝置設定此位。 例如,如果驅動程式收到裝置位於DeviceUsageTypePaging) 的分頁路徑 (IRP_MN_DEVICE_USAGE_NOTIFICATION的通知,驅動程式會呼叫IoInvalidateDeviceState,並在產生的IRP_MN_QUERY_PNP_DEVICE_STATE要求中設定此旗標。

如果裝置已設定此位,PnP 管理員會將此設定傳播至裝置的父裝置、其父裝置等。

如果已針對根列舉裝置設定此位,則無法停用或卸載裝置。

PNP_DEVICE_REMOVED

裝置已實際移除。

PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED

裝置的資源需求已變更。

一般而言,當匯流排驅動程式判斷它必須擴充其資源需求,才能列舉新的子裝置時,就會設定此旗標。

PNP_DEVICE_DISCONNECTED

裝置驅動程式已載入,但此驅動程式偵測到裝置已不再連線到電腦。 一般而言,此旗標用於與無線裝置通訊的函式驅動程式。 例如,當裝置移出範圍時,會設定 旗標,並在裝置返回範圍並重新連線之後清除。

匯流排驅動程式通常不會設定此旗標。 如果裝置不再連線,則匯流排驅動程式應該停止列舉子裝置。 只有在函式驅動程式管理連線時,才會使用此旗標。

此旗標的唯一用途是讓用戶端知道裝置是否已連線。 設定旗標不會影響是否載入驅動程式。

PnP 管理員會藉由將IRP_MN_QUERY_PNP_DEVICE_STATE要求傳送至裝置堆疊,在啟動裝置之後立即查詢裝置 的PNP_DEVICE_STATE 。 為了回應此 IRP,裝置的驅動程式會在 PNP_DEVICE_STATE 中設定適當的旗標。

如果初始查詢之後有任何狀態特性變更,驅動程式會呼叫 IoInvalidateDeviceState來通知 PnP 管理員。 為了回應對 IoInvalidateDeviceState的呼叫,PnP 管理員會重新查詢裝置的PNP_DEVICE_STATE。

如果裝置標示PNP_DEVICE_NOT_DISABLEABLE,偵錯工具會顯示 devnode DNUF_NOT_DISABLEABLE使用者旗標。 偵錯工具也會顯示 DisableableDepends 值,這個值會計算裝置無法停用的原因數目。 這個值是 X+Y 的總和,其中如果無法停用裝置,則 X 是一個,而 Y 是無法停用的裝置子裝置計數。