Share via


Behandeln einer IRP_MN_SURPRISE_REMOVAL-Anforderung

Der PnP-Manager von Windows 2000 und höher sendet diese IRP, um Treiber zu benachrichtigen, dass ein Gerät nicht mehr für E/A-Vorgänge verfügbar ist und wahrscheinlich unerwartet vom Computer entfernt wurde ("Überraschungsentfernung").

Der PnP-Manager sendet aus den folgenden Gründen eine IRP_MN_SURPRISE_REMOVAL-Anforderung :

  • Wenn der Bus über eine Hot-Plug-Benachrichtigung verfügt, benachrichtigt er den übergeordneten Bustreiber des Geräts, dass das Gerät nicht mehr vorhanden ist. Der Bustreiber ruft IoInvalidateDeviceRelations auf. Als Antwort fragt der PnP-Manager den Bustreiber nach seinen untergeordneten Elementen ab (IRP_MN_QUERY_DEVICE_RELATIONS für BusRelations). Der PnP-Manager ermittelt, dass das Gerät nicht in der neuen Liste der untergeordneten Elemente enthalten ist, und leitet die Vorgänge zum Entfernen von Überraschungen für das Gerät ein.

  • Der Bus wird aus einem anderen Grund aufgelistet, und das überraschend entfernte Gerät ist nicht in der Liste der Kinder enthalten. Der PnP-Manager initiiert seine Überraschungsentfernungsvorgänge.

  • Der Funktionstreiber für das Gerät bestimmt, dass das Gerät nicht mehr vorhanden ist (da z. B. die Anforderungen wiederholt ein Timeout haben). Der Bus kann aufzählbar sein, verfügt aber nicht über eine Hot-Plug-Benachrichtigung. In diesem Fall ruft der Funktionstreiber IoInvalidateDeviceState auf. Als Antwort sendet der PnP-Manager eine IRP_MN_QUERY_PNP_DEVICE_STATE-Anforderung an den Gerätestapel. Der Funktionstreiber legt das PNP_DEVICE_FAILED-Flag in der PNP_DEVICE_STATE Bitmaske fest, was angibt, dass das Gerät ausgefallen ist.

  • Der Treiberstapel schließt eine IRP_MN_STOP_DEVICE-Anforderung erfolgreich ab, schlägt dann aber eine nachfolgende IRP_MN_START_DEVICE-Anforderung fehl. In solchen Fällen ist das Gerät wahrscheinlich noch verbunden.

Alle PnP-Treiber müssen diese IRP verarbeiten und Irp-IoStatus.Status> auf STATUS_SUCCESS festlegen. Ein Treiber für ein PnP-Gerät muss jederzeit darauf vorbereitet sein , IRP_MN_SURPRISE_REMOVAL zu verarbeiten, nachdem die AddDevice-Routine des Treibers aufgerufen wurde. Die ordnungsgemäße Behandlung des IRP ermöglicht es den Treibern und dem PnP-Manager, Folgendes zu:

  1. Deaktivieren Sie das Gerät, falls es noch verbunden ist.

    Wenn der Treiberstapel eine IRP_MN_STOP_DEVICE Anforderung erfolgreich abgeschlossen hat, aber dann aus irgendeinem Grund eine nachfolgende IRP_MN_START_DEVICE-Anforderung fehlgeschlagen ist, muss das Gerät deaktiviert werden.

  2. Geben Sie hardwareressourcen frei, die dem Gerät zugewiesen sind, und stellen Sie sie für ein anderes Gerät zur Verfügung.

    Sobald ein Gerät nicht mehr verfügbar ist, sollten seine Hardwareressourcen freigegeben werden. Der PnP-Manager kann dann die Ressourcen einem anderen Gerät neu zuweisen, einschließlich desselben Geräts, das ein Benutzer möglicherweise wieder in den Computer einstecken kann.

  3. Minimieren Sie das Risiko von Datenverlusten und Systemunterbrechungen.

    Geräte, die Hot-Plugging unterstützen, und deren Treiber sollten für das Entfernen von Überraschungen konzipiert sein. Benutzer erwarten, dass Geräte, die Hot-Plugging unterstützen, jederzeit entfernt werden können.

Der PnP-Manager sendet eine IRP_MN_SURPRISE_REMOVAL unter IRQL = PASSIVE_LEVEL im Kontext eines Systemthreads.

Der PnP-Manager sendet diese IRP an Treiber, bevor Benutzermodusanwendungen und andere Kernelmoduskomponenten benachrichtigt werden. Nach Abschluss des IRP sendet der PnP-Manager eine EventCategoryTargetDeviceChange-Benachrichtigung mit GUID_TARGET_DEVICE_REMOVE_COMPLETE an Komponenten im Kernelmodus, die für diese Benachrichtigung auf dem Gerät registriert sind.

Die IRP_MN_SURPRISE_REMOVAL IRP wird zuerst vom obersten Treiber im Gerätestapel und dann von jedem nächstniedrigten Treiber verarbeitet.

Als Reaktion auf IRP_MN_SURPRISE_REMOVAL muss ein Treiber die folgenden Schritte in der aufgeführten Reihenfolge ausführen:

  1. Ermitteln Sie, ob das Gerät entfernt wurde.

    Der Treiber muss immer versuchen, zu ermitteln, ob das Gerät noch verbunden ist. Wenn dies der Fehler ist, muss der Treiber versuchen, das Gerät zu beenden und zu deaktivieren.

  2. Geben Sie die Hardwareressourcen des Geräts (Interrupts, E/A-Ports, Speicherregister und DMA-Kanäle) frei.

  3. Schalten Sie in einem übergeordneten Bustreiber den Bussteckplatz aus, wenn der Treiber dazu in der Lage ist. Rufen Sie PoSetPowerState auf, um den Power Manager zu benachrichtigen. Weitere Informationen finden Sie unter Energieverwaltung.

  4. Verhindern Sie neue E/A-Vorgänge auf dem Gerät.

    Ein Treiber sollte nachfolgende IRP_MJ_CLEANUP, IRP_MJ_CLOSE, IRP_MJ_POWER und IRP_MJ_PNP Anforderungen verarbeiten, aber der Treiber muss neue E/A-Vorgänge verhindern. Ein Treiber muss bei allen nachfolgenden IRPs fehlschlagen, die der Treiber verarbeitet hätte, wenn das Gerät vorhanden wäre, neben close, sauber-up und PnP IRPs.

    Ein Treiber kann ein Bit in der Geräteerweiterung festlegen, um anzugeben, dass das Gerät überraschend entfernt wurde. Die Dispatchroutinen des Treibers sollten dieses Bit überprüfen.

  5. Ausstehende E/A-Anforderungen auf dem Gerät schlagen fehl.

  6. Übergeben Sie weiterhin alle IRPs, die der Treiber nicht für das Gerät verarbeitet.

  7. Deaktivieren sie Geräteschnittstellen mit IoSetDeviceInterfaceState.

  8. Bereinigen Sie gerätespezifische Zuordnungen, Arbeitsspeicher, Ereignisse oder andere Systemressourcen.

    Ein Treiber kann solche sauber aufschieben, bis er die nachfolgende IRP_MN_REMOVE_DEVICE-Anforderung empfängt. Wenn eine Legacykomponente jedoch über ein geöffnetes Handle verfügt, das nicht geschlossen werden kann, wird das Remove-IRP nie gesendet.

  9. Lassen Sie das Geräteobjekt an den Gerätestapel angefügt.

    Trennen und löschen Sie das Geräteobjekt erst nach der nachfolgenden IRP_MN_REMOVE_DEVICE-Anforderung .

  10. Beenden Sie die IRP.

    In einem Funktions- oder Filtertreiber:

    • Legen Sie Irp-IoStatus.Status> auf STATUS_SUCCESS fest.

    • Richten Sie den nächsten Stapelspeicherort mit IoSkipCurrentIrpStackLocation ein, und übergeben Sie den IRP mit IoCallDriver an den nächstniedrigen Treiber.

    • Geben Sie den status von IoCallDriver als Rückgabe status aus der DispatchPnP-Routine weiter.

    • Schließen Sie die IRP nicht ab.

    In einem Bustreiber (der diese IRP für eine untergeordnete PDO behandelt):

    • Legen Sie Irp-IoStatus.Status> auf STATUS_SUCCESS fest.

    • Schließen Sie IRP (IoCompleteRequest) mit IO_NO_INCREMENT ab.

    • Rückgabe aus der DispatchPnP-Routine .

Nachdem diese IRP erfolgreich war und alle geöffneten Handles für das Gerät geschlossen wurden, sendet der PnP-Manager eine IRP_MN_REMOVE_DEVICE-Anforderung an den Gerätestapel. Als Reaktion auf das Entfernen von IRP trennen Treiber ihre Geräteobjekte vom Stapel und löschen sie. Wenn eine Legacykomponente über ein für das Gerät geöffnetes Handle verfügt und das Handle trotz E/A-Fehlern geöffnet bleibt, sendet der PnP-Manager niemals die Remove-IRP.

Alle Treiber sollten diese IRP verarbeiten und beachten, dass das Gerät physisch vom Computer entfernt wurde. Einige Treiber führen jedoch nicht zu negativen Ergebnissen, wenn sie die IRP nicht verarbeiten. Beispielsweise kann ein Gerät, das keine Systemhardwareressourcen verbraucht und sich in einem protokollbasierten Bus wie USB oder 1394 befindet, keine Hardwareressourcen binden, da es keine verbraucht. Es besteht kein Risiko, dass Treiber versuchen, auf das Gerät zuzugreifen, nachdem es entfernt wurde, da die Funktions- und Filtertreiber nur über den übergeordneten Bustreiber auf das Gerät zugreifen. Da der Bus entfernungsbenachrichtigungen unterstützt, wird der übergeordnete Bustreiber benachrichtigt, wenn das Gerät verschwindet und der Bustreiber bei allen nachfolgenden Versuchen, auf das Gerät zuzugreifen, fehlschlägt.

Unter Windows 98/Me sendet der PnP-Manager diese IRP nicht. Wenn ein Benutzer ein Gerät entfernt, ohne zuvor die entsprechende Benutzeroberfläche zu verwenden, sendet der PnP-Manager nur eine IRP_MN_REMOVE_DEVICE Anforderung an die Treiber für das Gerät. Alle WDM-Treiber müssen sowohl IRP_MN_SURPRISE_REMOVAL als auch IRP_MN_REMOVE_DEVICE verarbeiten. Der Code für IRP_MN_REMOVE_DEVICE sollte überprüfen, ob der Treiber zuvor eine Überraschungs-Entfernungs-IRP erhalten hat, und sollte beide Fälle behandeln.

Verwenden von GUID_REENUMERATE_SELF_INTERFACE_STANDARD

Die GUID_REENUMERATE_SELF_INTERFACE_STANDARD-Schnittstelle ermöglicht es einem Treiber, anzufordern, dass sein Gerät erneut aufgezählt wird.

Um diese Schnittstelle zu verwenden, senden Sie eine IRP_MN_QUERY_INTERFACE IRP mit InterfaceType = GUID_REENUMERATE_SELF_INTERFACE_STANDARD an Ihren Bustreiber. Der Bustreiber stellt einen Zeiger auf eine REENUMERATE_SELF_INTERFACE_STANDARD-Struktur bereit, die Zeiger auf die einzelnen Routinen der Schnittstelle enthält. Eine ReenumerateSelf-Routine fordert an, dass ein Bustreiber ein untergeordnetes Gerät erneut aufzählt.

Informationen zu PNP_DEVICE_STATE

Der PNP_DEVICE_STATE Typs ist eine Bitmaske, die den PnP-Zustand eines Geräts beschreibt. Ein Treiber gibt als Antwort auf eine IRP_MN_QUERY_PNP_DEVICE_STATE-Anforderung einen Wert dieses Typs zurück.

typedef ULONG PNP_DEVICE_STATE, *PPNP_DEVICE_STATE;

Die Flagbits in einem PNP_DEVICE_STATE-Wert werden wie folgt definiert.

Flag-Bit BESCHREIBUNG
PNP_DEVICE_DISABLED

Das Gerät ist physisch vorhanden, aber in der Hardware deaktiviert.

PNP_DEVICE_DONT_DISPLAY_IN_UI

Zeigen Sie das Gerät nicht auf der Benutzeroberfläche an. Wird für ein Gerät festgelegt, das physisch vorhanden ist, aber in der aktuellen Konfiguration nicht verwendet werden kann, z. B. einen Spielport auf einem Laptop, der nicht verwendet werden kann, wenn der Laptop abgedockt wird. (Siehe auch das NoDisplayInUI-Flag in der DEVICE_CAPABILITIES-Struktur .)

PNP_DEVICE_FAILED

Das Gerät ist vorhanden, funktioniert aber nicht ordnungsgemäß.

Wenn sowohl dieses Flag als auch PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED festgelegt sind, muss das Gerät beendet werden, bevor der PnP-Manager neue Hardwareressourcen zuweist (ein ununterbrochener Ausgleich wird für das Gerät nicht unterstützt).

PNP_DEVICE_NOT_DISABLEABLE

Das Gerät ist erforderlich, wenn der Computer gestartet wird. Ein solches Gerät darf nicht deaktiviert werden.

Ein Treiber legt dieses Bit für ein Gerät fest, das für den ordnungsgemäßen Systembetrieb erforderlich ist. Wenn ein Treiber beispielsweise eine Benachrichtigung erhält, dass sich ein Gerät im Auslagerungspfad befindet (IRP_MN_DEVICE_USAGE_NOTIFICATION für DeviceUsageTypePaging), ruft der Treiber IoInvalidateDeviceState auf und legt dieses Flag in der resultierenden IRP_MN_QUERY_PNP_DEVICE_STATE-Anforderung fest.

Wenn dieses Bit für ein Gerät festgelegt ist, gibt der PnP-Manager diese Einstellung an das übergeordnete Gerät des Geräts, das übergeordnete Gerät des übergeordneten Geräts des Geräts usw. weiter.

Wenn dieses Bit für ein Mit Stammverzeichnis aufgelistetes Gerät festgelegt ist, kann das Gerät nicht deaktiviert oder deinstalliert werden.

PNP_DEVICE_REMOVED

Das Gerät wurde physisch entfernt.

PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED

Die Ressourcenanforderungen für das Gerät wurden geändert.

In der Regel legt ein Bustreiber dieses Flag fest, wenn er festgestellt hat, dass er seine Ressourcenanforderungen erweitern muss, um ein neues untergeordnetes Gerät aufzulisten.

PNP_DEVICE_DISCONNECTED

Der Gerätetreiber wird geladen, aber dieser Treiber hat erkannt, dass das Gerät nicht mehr mit dem Computer verbunden ist. In der Regel wird dieses Flag für Funktionstreiber verwendet, die mit drahtlosen Geräten kommunizieren. Das Flag wird beispielsweise festgelegt, wenn sich das Gerät außerhalb des Bereichs bewegt, und wird gelöscht, nachdem sich das Gerät wieder in den Bereich bewegt und erneut verbunden wird.

Ein Bustreiber legt dieses Flag normalerweise nicht fest. Der Bustreiber sollte stattdessen das Aufzählen des untergeordneten Geräts beenden, wenn das Gerät nicht mehr verbunden ist. Dieses Flag wird nur verwendet, wenn der Funktionstreiber die Verbindung verwaltet.

Der einzige Zweck dieses Flags besteht darin, Clients mitzuteilen, ob das Gerät verbunden ist. Das Festlegen des Flags wirkt sich nicht darauf aus, ob der Treiber geladen wird.

Der PnP-Manager fragt die PNP_DEVICE_STATE eines Geräts direkt nach dem Starten des Geräts ab, indem er eine IRP_MN_QUERY_PNP_DEVICE_STATE Anforderung an den Gerätestapel sendet. Als Reaktion auf diese IRP setzen die Treiber für das Gerät die entsprechenden Flags in PNP_DEVICE_STATE.

Wenn sich eines der Zustandsmerkmale nach der ersten Abfrage ändert, benachrichtigt ein Treiber den PnP-Manager, indem er IoInvalidateDeviceState aufruft. Als Reaktion auf einen Aufruf von IoInvalidateDeviceState fragt der PnP-Manager die PNP_DEVICE_STATE des Geräts erneut ab.

Wenn ein Gerät PNP_DEVICE_NOT_DISABLEABLE markiert ist, zeigt der Debugger ein DNUF_NOT_DISABLEABLE Benutzerflag für den Devnode an. Der Debugger zeigt auch einen DisableableDepends-Wert an, der die Anzahl der Gründe zählt, aus denen das Gerät nicht deaktiviert werden kann. Dieser Wert ist die Summe von X+Y, wobei X eins ist, wenn das Gerät nicht deaktiviert werden kann, und Y die Anzahl der untergeordneten Geräte des Geräts, die nicht deaktiviert werden können.