デバイスの電源切断 IRP の処理

デバイスの電源オフ IRP は、マイナー関数コード IRP_MN_SET_POWER と、現在のデバイス電源状態以下のデバイス電源状態 (PowerDeviceD0PowerDeviceD1PowerDeviceD2、または PowerDeviceD3) を指定します。 IRP がデバイス スタックを移動すると、ドライバーは電源オフ IRP を処理する必要があります。 上位レベルのドライバーは、下位レベルのドライバーの前に IRP を処理する必要があります。 実行するデバイス固有のタスクがないドライバーは、すぐに次の下位ドライバーに IRP を渡す必要があります。

次の図は、このような IRP の処理に関連する手順を示しています。

diagram illustrating handling a device power-down request.

IRP で PowerDeviceD3 が指定されている場合、ファンクション ドライバーは通常、以下のタスクを実行する必要があります。

  • IoAcquireRemoveLock を呼び出し、現在の IRP を渡して、電源 IRP の処理中にドライバーが PnP IRP_MN_REMOVE_DEVICE 要求を受け取らないようにします。

    IoAcquireRemoveLock が失敗ステータスを返した場合、ドライバーは IRP の処理を続行すべきではありません。 代わりに、Windows Vista 以降では、ドライバーは IoCompleteRequest を呼び出して IRP を完了し、エラー ステータスを返す必要があります。 Windows Server 2003、Windows XP、Windows 2000 では、ドライバーは IoCompleteRequest を呼び出して IRP を完了し、PoStartNextPowerIrp を呼び出して次の電源 IRP を起動した後、失敗ステータスを返す必要があります。

  • デバイスを閉じる、保留中の I/O を完了またはフラッシュする、割り込みを無効にする、後続の受信 IRP をキューに入れる、デバイスを復元または再初期化するデバイス コンテキストを保存するなど、デバイス電源を切断する前に実行する必要があるデバイス固有のタスクを実行します。

    ドライバーは、IRP の処理中に長い遅延 (たとえば、ユーザーがこの種類のデバイスを不適切と判断する可能性がある遅延) を発生させるべきではありません。

    ドライバーは、デバイスが動作状態に戻るまで、受信 I/O 要求をキューに入れる必要があります。

  • 可能であれば、Parameters.Power.ShutdownType の値をチェックします。 システムの設定電源 IRP がアクティブな場合、ShutdownType はシステム IRP に関する情報を提供します。 この値について詳しくは、「システム電源操作」をご覧ください。

    休止状態のパス上にあるデバイスのドライバーは、この値を検査する必要があります。 ShutdownTypePowerActionHibernate の場合、ドライバーは、デバイスを復元するのに必要なコンテキストを保存する必要がありますが、デバイスの電源をオフにしてはなりません。

  • ドライバーがこれを行うことができる場合や、変更が適切な場合、デバイスの物理的な電源状態を変更します。

  • PoSetPowerState を呼び出し、新しいデバイスの電源状態を電源マネージャーに通知します。

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

  • ドライバーが次の電源 IRP を処理する準備ができていることを示す PoStartNextPowerIrp を呼び出す IoCompletion ルーチンを設定します。 この手順は、Windows 7 および Windows Vista では必要ありません。

  • IoCallDriver (Windows 7 と Windows Vista の場合) を呼び出すか、PoCallDriver (Windows Server 2003、Windows XP、Windows 2000 の場合) を呼び出し、IRP を次の下位ドライバーに渡します。 IRP は、IRP を完了するバス ドライバーに渡す必要があります。

  • IoReleaseRemoveLock を呼び出し、以前に取得したロックを解放します。

  • STATUS_PENDING を返します。

ドライバーは、デバイス コンテキスト情報を保存し、IRP を転送する前に新しい電源状態を設定する必要があります。 コンテキスト情報には、少なくとも、要求された新しい電源状態が含まれている必要があります。 さらに、電源投入時にドライバーが必要とする追加情報も含める必要があります。 IRP が完了し、デバイスの電源がオフになると、ドライバーはデバイスにアクセスできなくなり、デバイス コンテキストを使用できなくなります。

各ドライバーは、次の下位ドライバーに IRP を渡す必要があります。 IRP がバス ドライバーに到達すると、バス ドライバーはデバイスの電源をオフにし (これが可能な場合)、PoSetPowerState を呼び出して電源マネージャーに通知し、IRP を完了します。

ただし、バス ドライバーが休止状態デバイスを提供する場合、IRP の ShutdownType の値が PowerSystemHibernate であるかどうかをチェックする必要があります。 その場合、バス ドライバーは PoSetPowerState を呼び出して PowerDeviceD3 を報告する必要がありますが、デバイスの電源をオフにしてはなりません。 休止状態のファイルが保存されると、デバイスはシステムの残りの部分と共に電源がオフになります。

すべての子デバイスの電源がオフになったら、バス ドライバーはバスの電源もオフにすることができます。 この動作はデバイスに依存しています。

IRP が他の状態 (D0、D1、または D2) を指定する場合、必要なドライバー アクションはデバイスに依存します。 通常、これらの状態をサポートするデバイスは、I/O 要求が到着したら、すぐに動作状態に戻ることができます。 このようなデバイスのドライバーは、保留中の I/O 要求を完了して、新しい要求をキューに入れ、IRP を次の下位ドライバーに転送する前に必要なすべてのコンテキストを保存する必要があります。 IRP がバス ドライバーに到達すると、ハードウェアが要求された状態に設定されます。 ドライバーは、スリープ状態の間デバイスにアクセスできません。

状況によっては、デバイスが既に D0 状態にある場合、ファンクションまたはフィルター ドライバーが、PowerDeviceD0 を指定するデバイスの電源 IRP を受け取る可能性があります。 ドライバーは、他の設定電源 IRP と同様、この IRP を処理する必要があります。保留中の I/O 要求を完了して、受信 I/O 要求をキューに入れ、IoCompletion ルーチンを設定し、IRP を次の下位ドライバーに渡します。 ただし、ドライバーはデバイスのハードウェア設定を変更しないでください。 バス ドライバーは、IRP を受信したら、そのまま IRP を完了する必要があります。 IRP が完了したら、ファンクション ドライバーとフィルター ドライバーは、キューに登録された要求を処理できます。 IRP が完了するまで I/O をキューに登録すると、上位のドライバーが I/O を試みている間に下位のドライバーがデバイス レジスタを変更しようとする可能性がなくなります。