Übergeben von Power IRPs

Power IRPs müssen auf dem gesamten Gerätestapel an die PDO übergeben werden, um sicherzustellen, dass Energieübergänge sauber verwaltet werden. Treiber verarbeiten ein IRP, das die Geräteleistung reduziert, während das IRP den Gerätestapel hinunter bewegt. Treiber verarbeiten ein IRP, das Geräteleistung in IoCompletion-Routinen anwendet, während das IRP den Gerätestapel zurück nach oben bewegt.

Die folgende Abbildung zeigt die Schritte, die Treiber ausführen müssen, um eine Energie-IRP in einem Gerätestapel in Windows 7 und Windows Vista zu übergeben.

Diagramm zur Veranschaulichung des Übergebens eines Power-Irp in Windows Vista.

Wie in der vorherigen Abbildung gezeigt, muss ein Treiber in Windows 7 und Windows Vista folgendes tun:

  1. Rufen Sie IoCopyCurrentIrpStackLocationToNext auf, wenn Sie eine IoCompletion-Routine festlegen, oder IoSkipCurrentIrpStackLocation , wenn sie keine IoCompletion-Routine festlegen.

    Diese beiden Routinen legen den IRP-Stapelspeicherort für den nächstniedrigen Treiber fest. Durch das Kopieren des aktuellen Stapelspeicherorts wird sichergestellt, dass der IRP-Stapelzeiger auf den richtigen Speicherort festgelegt ist, wenn die IoCompletion-Routine ausgeführt wird.

    Wenn ein falsch geschriebener Treiber den Fehler macht , IoSkipCurrentIrpStackLocation aufzurufen und dann eine Vervollständigungsroutine festzulegen, überschreibt dieser Treiber möglicherweise eine vervollständigungsroutine, die vom Treiber darunter festgelegt wird.

  2. Rufen Sie IoSetCompletionRoutine auf, um eine IoCompletion-Routine festzulegen, wenn eine vollständige Routine erforderlich ist.

  3. Rufen Sie IoCallDriver auf, um den IRP an den nächstniedrigen Treiber im Stapel zu übergeben.

Die folgende Abbildung zeigt die Schritte, die Treiber ausführen müssen, um eine Energie-IRP in einem Gerätestapel in Windows Server 2003, Windows XP und Windows 2000 zu übergeben.

Übergeben eines Power Irp (Windows Server 2003, Windows XP und Windows 2000).

Wie in der vorherigen Abbildung gezeigt, muss ein Treiber folgendes tun:

  1. Rufen Sie je nach Treibertyp möglicherweise PoStartNextPowerIrp auf. Weitere Informationen finden Sie unter Aufrufen von PoStartNextPowerIrp.

  2. Rufen Sie IoCopyCurrentIrpStackLocationToNext auf, wenn Sie eine IoCompletion-Routine festlegen, oder IoSkipCurrentIrpStackLocation , wenn sie keine IoCompletion-Routine festlegen.

    Diese beiden Routinen legen den IRP-Stapelspeicherort für den nächstniedrigen Treiber fest. Durch das Kopieren des aktuellen Stapelspeicherorts wird sichergestellt, dass der IRP-Stapelzeiger auf den richtigen Speicherort festgelegt ist, wenn die IoCompletion-Routine ausgeführt wird.

  3. Rufen Sie IoSetCompletionRoutine auf, um eine IoCompletion-Routine festzulegen. In der IoCompletion-Routine rufen die meisten Treiber PoStartNextPowerIrp auf, um anzugeben, dass sie bereit ist, die nächste Energie-IRP zu verarbeiten.

  4. Rufen Sie PoCallDriver auf, um den IRP an den nächstniedrigen Treiber im Stapel zu übergeben.

    Treiber müssen PoCallDriver anstelle von IoCallDriver (wie bei anderen IRPs) verwenden, um sicherzustellen, dass das System Power IRPs ordnungsgemäß synchronisiert. Weitere Informationen finden Sie unter Calling IoCallDriver vs. Calling PoCallDriver.For more information, see Calling IoCallDriver vs. Calling PoCallDriver.

Denken Sie daran, dass IoCompletion-Routinen unter IRQL = DISPATCH_LEVEL aufgerufen werden können. Wenn ein Treiber eine zusätzliche Verarbeitung unter IRQL = PASSIVE_LEVEL erfordert, nachdem treiber der niedrigeren Ebene das IRP abgeschlossen haben, sollte die Vervollständigungsroutine des Treibers ein Arbeitselement in die Warteschlange stellen und dann STATUS_MORE_PROCESSING_REQUIRED zurückgeben. Der Workerthread muss den IRP abschließen.

In Windows 98/Me müssen Treiber Energie-IRPs unter IRQL = PASSIVE_LEVEL abschließen.

Die Funktionscodes in einem Power-IRP nicht ändern

Zusätzlich zu den üblichen Regeln, die die Verarbeitung von IRPs regeln, haben IRP_MJ_POWER IRPs die folgende besondere Anforderung: Ein Treiber, der eine Leistungs-IRP empfängt, darf die Haupt- und Nebenfunktionscodes in allen E/A-Stapelspeicherorten im IRP nicht ändern, die vom Power Manager oder von treibern höherer Ebene festgelegt wurden. Der Energie-Manager basiert darauf, dass diese Funktionscodes unverändert bleiben, bis die IRP abgeschlossen ist. Verstöße gegen diese Regel können probleme verursachen, die schwer zu debuggen sind. Beispielsweise kann das Betriebssystem nicht mehr reagieren oder "hängen".

Während der Behandlung einer Power-IRP nicht blockieren

Treiber dürfen bei der Behandlung von Power IRPs keine langen Verzögerungen verursachen.

Wenn ein Power-IRP übergeben wird, sollte ein Treiber so bald wie möglich von seiner DispatchPower-Routine zurückkehren, nachdem er IoCallDriver (in Windows 7 und Windows Vista) oder PoCallDriver (in Windows Server 2003, Windows XP und Windows 2000) aufgerufen hat. Ein Treiber darf nicht auf ein Kernelereignis oder anderweitige Verzögerung warten, bevor er zurückgegeben wird. Wenn ein Treiber einen Energie-IRP nicht in kurzer Zeit verarbeiten kann, sollte er STATUS_PENDING zurückgeben und alle eingehenden IRPs in die Warteschlange stellen, bis der Energie-IRP abgeschlossen ist. (Beachten Sie, dass sich dieses Verhalten von PnP-IRPs und DispatchPnP-Routinen unterscheidet, die blockiert werden dürfen.)

Wenn der Treiber auf eine Energieaktion durch einen anderen Treiber weiter unten im Gerätestapel warten muss, sollte er STATUS_PENDING aus seiner DispatchPower-Routine zurückgeben und eine IoCompletion-Routine für die Energie-IRP festlegen. Der Treiber kann alle aufgaben ausführen, die er in der IoCompletion-Routine erfordert, und dann PoStartNextPowerIrp (nur Windows Server 2003, Windows XP und Windows 2000) und IoCompleteRequest aufrufen.

Beispielsweise sendet der Besitzer der Energierichtlinie für ein Gerät in der Regel eine Geräteleistungs-IRP, während ein Systemleistungs-IRP gespeichert wird, um den gerätegerechten Energiezustand für den angeforderten Systemstromzustand festzulegen.

In diesem Fall sollte der Besitzer der Energierichtlinie eine IoCompletion-Routine in der Systemleistungs-IRP festlegen, den Systemleistungs-IRP an den nächstniedrigen Treiber übergeben und STATUS_PENDING aus seiner DispatchPower-Routine zurückgeben.

In der IoCompletion-Routine ruft sie PoRequestPowerIrp auf, um die Energie-IRP des Geräts zu senden und einen Zeiger auf eine Rückrufroutine in der Anforderung zu übergeben. Die IoCompletion-Routine sollte STATUS_MORE_PROCESSING_REQUIRED zurückgeben.

Schließlich übergibt der Treiber die System-IRP aus der Rückrufroutine. Der Treiber darf nicht auf ein Kernelereignis in seiner DispatchPower-Routine warten und mit der IoCompletion-Routine für das IRP signalisieren, das er derzeit verarbeitet. Es kann zu einem System-Deadlock kommen. Weitere Informationen finden Sie unter Handling a System Set-Power IRP in a Device Power Policy Owner.For more information, see Handling a System Set-Power IRP in a Device Power Policy Owner.For more information, see Handling a System Set-Power IRP in a Device Power Policy Owner.

In einer ähnlichen Situation, wenn das System in den Standbymodus wechselt, muss ein Besitzer der Energierichtlinie möglicherweise einige ausstehende E/A-Vorgänge ausführen, bevor er die IRP des Geräts sendet, um das Gerät herunterzuschalten. Anstatt ein Ereignis zu signalisieren, wenn die E/A abgeschlossen ist und in seiner DispatchPower-Routine wartet, sollte der Treiber ein Arbeitselement in die Warteschlange stellen und STATUS_PENDING aus der DispatchPower-Routine zurückgeben. Im Workerthread wartet er auf den Abschluss der E/A und sendet dann die IRP für die Geräteleistung. Weitere Informationen finden Sie unter IoAllocateWorkItem.