デバイス電源状態についての IRP_MN_QUERY_POWER の処理

単一のデバイスの状態の変化に関するデバイス クエリ電源 IRP クエリは、デバイスのスタック内のすべてのドライバーに送信されます。 このような IRP は、I/O スタックの場所の Power.Type メンバーで DevicePowerState を指定します。

ドライバーは、スタックの下に移動するクエリ電源 IRP を処理します。

ファンクションまたはフィルター ドライバーは、以下のいずれかに該当する 場合、IRP_MN_QUERY_POWER 要求を失敗させることができます。

  • デバイスでウェイクアップが有効になっており、要求された電源状態が、デバイスがシステムをウェイクアップできる状態を下回っています。 たとえば、D2 からシステムをウェイクアップできるが、D3 からはウェイクアップできないデバイスでは、D3 のクエリには失敗しますが、D2 のクエリには成功します。

  • 要求された状態に入ると、ドライバーは、開いているモデム接続などのデータを失う操作を破棄する必要があります。 このような理由から、ドライバーがクエリに失敗することはめったにありません。ほとんどの状況では、アプリケーションがそのようなケースを処理します。

IRP_MN_QUERY_POWER 要求を失敗させるため、ドライバーは以下の手順を実行します。

  1. PoStartNextPowerIrp を呼び出し、ドライバーが次の電源 IRP を処理する準備ができていることを示します。 (Windows Server 2003、Windows XP、および Windows 2000 のみ)。

  2. Irp->IoStatus.Status をエラー ステータスに設定し、IO_NO_INCREMENT を指定して IoCompleteRequest を呼び出します。 ドライバーは、デバイス スタックのさらに下に IRP を渡しません。

  3. DispatchPower ルーチンからエラー ステータスを返します。

ドライバーがクエリ電源 IRP に成功した場合、操作を開始したり、クエリ対象の電源状態に対する後続の IRP_MN_SET_POWER 要求の正常な完了を妨げる他のアクションを実行したりすることはできません。

IRP に成功したドライバーは、以下のように、クエリ対象の状態の設定電源 IRP を準備し、クエリ IRP を渡す必要があります。

  1. 未処理の I/O 操作を完了します。

  2. 受信 I/O 要求をキューに入れます。

  3. 指定された電源状態への移行を妨げる他の新しいアクティビティは開始しないでください。 ただし、ドライバーは、デバイス コンテキストを保存したり、シャットダウンに向けて他の手順を実行したりしてはなりません。

  4. IoCopyCurrentIrpStackLocationToNext を呼び出し、次の下位ドライバーの IRP スタックの場所を設定します。

  5. IoCompletion ルーチンを設定します。 IoCompletion ルーチンで、PoStartNextPowerIrp (Windows Server 2003、Windows XP、Windows 2000 のみ) を呼び出して、次の電源 IRP を処理するドライバーの準備状態を示します。

  6. IoCallDriver (Windows 7 と Windows Vista の場合) を呼び出すか、PoCallDriver (Windows Server 2003、Windows XP、Windows 2000 の場合) を呼び出し、クエリ IRP を次の下位ドライバーに渡します。 IRP は完了させません。

  7. STATUS_PENDING を返します。 ドライバーは Irp->IoStatus.Status の値を変更してはなりません。

クエリ電源 IRP がバス ドライバーに到達すると、バス ドライバーは PoStartNextPowerIrp (Windows Server 2003、Windows XP、Windows 2000 のみ) を呼び出します。ドライバーが指定された電源状態に変更できる場合は Irp->IoStatus.Status を STATUS_SUCCESS に設定します。変更できない場合は、失敗ステータスを設定します。 その後、バス ドライバーは IoCompleteRequest を呼び出し、IO_NO_INCREMENT を指定します。

一般的なデバイス スタックのドライバーは、以下のようにデバイス クエリ電源 IRP を処理します。

  • ほとんどのフィルター ドライバーは、そのまま次の下位ドライバーに IRP を渡し (「電源 IRP の受け渡し」を参照) し、STATUS_PENDING を返す必要があります。 ただし、フィルター ドライバーによっては、受信 IRP のキューやデバイス電源状態の保存など、デバイス固有のタスクを最初に実行する必要があります。

  • ファンクション ドライバーは、デバイス固有のタスク (保留中の I/O 要求の完了、受信 I/O 要求のキュー、デバイス コンテキストの保存、デバイスの電源変更など) を実行し、必要に応じて IoCompletion ルーチンを設定して、デバイスの電源 IRP を次の下位ドライバーに渡します (「電源の IRP の受け渡し」を参照)。 DispatchPower ルーチンから STATUS_PENDING を返します。

  • バス ドライバーは、PoStartNextPowerIrp (Windows Server 2003、Windows XP、Windows 2000 のみ) を呼び出して、次の電源 IRP を開始します。 その後、IO_NO_INCREMENT を指定して IRP を完了します。 ドライバーがすぐに IRP を完了できない場合、IoMarkIrpPending を呼び出し、DispatchPower ルーチンから STATUS_PENDING を返して、後で IRP を完了します。

ターゲット デバイスが既にクエリ対象の電源状態にある場合でも、各ファンクションまたはフィルター ドライバーは I/O をキューに入れ、IRP を次の下位ドライバーに渡す必要があります。 IRP は、デバイス スタックから (IRP を完了する) バス ドライバーまで移動する必要があります。

IRP_MN_QUERY_POWER 要求の処理時、ドライバーはできる限りすばやく DispatchPower ルーチンから戻る必要があります。 ドライバーは、同じ IRP を処理するコードによって通知されるカーネル イベントの DispatchPower ルーチンで待機してはなりません。 電源 IRP はシステム全体で同期されるため、デッドロックが発生する可能性があります。