Share via


デバイス電源状態についての IRP_MN_QUERY_POWER または IRP_MN_SET_POWER の送信

デバイス電源ポリシーの所有者は、下位ドライバーがデバイス電源状態の変更に対応できるかどうかを判断するためにデバイスクエリ電源IRP (IRP_MN_QUERY_POWER) を送信し、デバイス電源状態を変更するためにデバイス電源の設定IRP (IRP_MN_SET_POWER) を送信します。 (このドライバーは、外部信号に応答してデバイスがウェイクアップできるようにするために、待機/ウェイクIRPを送信することもできます。詳細については、 ウェイクアップ機能を持つデバイスのサポート を参照してください。)

ドライバーは、以下のいずれかがtrueであるとき、 IRP_MN_QUERY_POWER 要求を送る必要があります:

  • ドライバーがシステムクエリ電源IRPを受信します。

  • ドライバーがアイドルデバイスをスリープ状態にする準備をしているため、下位のドライバーに問い合わせて、スリープ状態にすることが可能かどうかを調べる必要があります。

ドライバーは、以下のいずれかがtrueである場合、 IRP_MN_SET_POWER 要求を送信する必要があります:

  • ドライバーは、デバイスがアイドル状態であって、スリープ状態にすることができると判断しました。

  • デバイスがスリープ状態であって、待機中のI/Oを処理するために、動作状態を再入力する必要があります。

  • ドライバーがシステム電源の設定IRPを受信します。

ドライバーは、それ自身の電源IRPを割り当ててはなりません。電源マネージャは、この目的のために PoRequestPowerIrp ルーチンを提供します。 Rules for Handling Power IRPs が説明するように、 PoRequestPowerIrp はIRPを割り当てて送信し、 IoCallDriver (Windows 7 および Windows Vista の場合)、または PoCallDriver (Windows Server 2003、Windows XP、および Windows 2000 の場合)と組み合わせて、すべての電源要求が適切に同期されるようにします。 PoRequestPowerIrp の呼び出し元は、IRQL <= DISPATCH_LEVELで実行されている必要があります。

以下は、このルーチンのプロトタイプです:

NTSTATUS
PoRequestPowerIrp (
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR MinorFunction,
    IN POWER_STATE PowerState,
    IN PREQUEST_POWER_COMPLETE CompletionFunction,
    IN PVOID Context,
    OUT PIRP *Irp OPTIONAL
    );

IRPを送信するには、ドライバーは PoRequestPowerIrpを呼び出し、 DeviceObjectにターゲットデバイスオブジェクトへのポインタを、 MinorFunctionにマイナーIRPコードIRP_MN_SET_POWERまたはIRP_MN_QUERY_POWERを、 PowerState.タイプに値 DevicePowerStatePowerState.状態にデバイスの電源状態を指定します。 Windows 98/Meでは、 DeviceObject は基礎となるデバイスのPDOを指定する必要があります。Windows 2000以降のWindowsでは、この値は同じデバイススタック内のドライバーのPDOまたはFDOのいずれかを指すことができます。

他のすべてのドライバーが IRP を完了した後に、ドライバーが追加のタスクを実行する必要がある場合、 CompletionFunctionの電源完了機能へポインターを渡す必要があります。 I/Oマネージャは、IRPをスタックに渡すときにドライバーによって設定されたすべての IoCompletion ルーチンを呼び出した後に、 CompletionFunction を呼び出します。

デバイス パワー ポリシー オーナーがデバイス パワー クエリ IRP を送信するときは常に、 PoRequestPowerIrpの呼び出しで指定したコールバック ルーチン(CompletionFunction) からデバイス電源の設定IRPを送信する必要があります。 クエリが成功した場合、電源設定IRPはクエリされた電源状態を指定します。 クエリが失敗した場合は、電源設定IRPは現在のデバイスの電源状態を再アサートします。 現在の状態を再アサートすることは、ドライバーがクエリに応答してI/Oをキューに入れるため重要です。ポリシー所有者は、キューに入れられたI/O要求の処理を開始するようにデバイススタック内のドライバーに通知するために、電源設定IRPを送信する必要があります。

デバイスのポリシー所有者は、デバイスの電源IRPを送信するだけでなく、デバイススタックに渡されるIRPも処理することに注意してください。 したがって、そのようなドライバーは、特にデバイスの電源投入時に、IRP処理コードの一部として IoCompletion ルーチンを設定することがよくあります ( IoSetCompletionRoutine)。 IoCompletion ルーチンは、他のドライバーによって設定された IoCompletion ルーチンの順番で、 CompletionFunctionの前に呼び出されます。 詳細については、 IoCompletion Routines for Device Power IRPsを参照してください。

CompletionFunction が呼び出された時点で IRP はすべてのドライバーによって完了しているため、 CompletionFunction は、 IoCallDriverPoCallDriver、または PoStartNextPowerIrp を、その IRP が発生した状態で呼び出してはなりません。 (ただし、別の電源IRPに対してこれらのルーチンを呼び出す場合があります。)代わりに、このルーチンは、IRP を発生させたドライバーが必要とする追加のアクションを実行します。 ドライバーがシステムIRPに応答してデバイスIRPを送信した場合、 CompletionFunction はシステムIRPを完了する場合があります。 詳細については、 デバイス電源ポリシー所有者におけるシステム電源設定IRPの処理を参照してください。

PoRequestPowerIrpの呼び出しに応答して、電源マネージャは電源IRPを割り当て、デバイスのデバイススタックの最上位に送信します。 電源マネージャーは、割り当てられたIRPへのポインターを返します。

エラーが発生しなければ、 PoRequestPowerIrp はSTATUS_PENDINGを返します。 この状態は、IRPが正常に送信され、完了待ちであることを意味します。 電源マネージャーがIRPを割り当てることができないか、呼び出し元が無効なマイナー電源IRPコードを指定した場合、呼び出しは失敗します。

デバイスの電源投入要求は、まず、デバイスの基盤になるバスドライバーによって処理され、次にスタック内で連続して上位の各ドライバーによって処理される必要があります。 したがって、 PowerDeviceD0 要求を送信する場合、ドライバーは、IRP が完了し、デバイスが電源投入された後、 CompletionFunction が必要なタスクを実行するようにしなければなりません。

デバイスの電源を切る (PowerDeviceD3)場合、デバイススタック内の各ドライバーは、次の下位ドライバーにIRPを送信する前に、必要なコンテキストをすべて保存し、必要なクリーンアップを行わなければなりません。 コンテキスト情報とクリーンアップの範囲は、ドライバーの種類により異なります。 ファンクションドライバーは、ハードウェアコンテキストを必ず保存する必要がありますが、フィルタードライバーは、独自のソフトウェアコンテキストを保存する必要がある場合があります。 この状況で設定された CompletionFunction は、完了した電源IRPに関連するアクションを取ることができますが、ドライバーはデバイスにアクセスできません。