電源の設定要求の処理
中間ドライバーは、動作状態 (ネットワーク デバイスの電源状態が D0) とスリープ状態 (ネットワーク デバイスの電源状態が D1、D2、D3) に電源を設定する要求を処理する必要があります。 中間ドライバーは、電源状態変数とスタンバイ フラグも維持する必要があります。 これらの問題について、このトピックでさらに説明します。
中間ドライバーの電源管理の例については、GitHub の Windows ドライバー サンプル リポジトリの「NDIS MUX 中間ドライバーと通知オブジェクト ドライバーのサンプル」を参照してください。
スリープ状態への電源の設定要求の処理
中間ドライバーが、スリープ状態への電源の設定要求を処理する必要があるのは、次の 2 つのケースです:
NDIS は、中間ドライバーの仮想ミニポート上位エッジをスリープ状態にするよう要求します。
中間ドライバー プロトコル下位エッジは、プラグ アンド プレイ (PnP) イベント通知を受け取ったときに、基になるミニポート ドライバーのスリープ状態への移行を処理します。
これらのイベントは任意の順序で発生することがあり、1 つのイベントが必ずしも他のイベントに付随するとは限りません。
中間ドライバーの仮想ミニポート上位エッジがスリープ状態への電源の設定要求を受信すると、次の流れでその要求を処理します:
NDIS は、仮想ミニポートにバインドされている各プロトコル ドライバーの ProtocolNetPnPEvent 関数を呼び出します。 ProtocolNetPnPEvent の呼び出しでは、スリープ状態の NetEventSetPower イベントを指定します。 中間ドライバーにバインドされているプロトコル ドライバーは、ネットワーク データの送信を停止し、中間ドライバーの仮想ミニポートに OID 要求を行います。 中間ドライバーのプロトコル下位エッジは、基になるミニポート ドライバーがスリープ状態への移行を行っていることを NDIS が示すまで、ネットワーク データと要求を送信し続けることができます。
NDIS は、NetEventSetPower イベントを発行した後、基になるドライバーを、続いて仮想ミニポートを一時停止します。 一時停止の理由は、低電力状態への移行です。 仮想ミニポートの一時停止の詳細については、「アダプターの一時停止」を参照してください。
メモ 低電力状態にある間は、OID_PNP_SET_POWER を除いて、OID 要求を仮想ミニポートに送信できません。
NDIS は、中間ドライバーの仮想ミニポートに OID_PNP_SET_POWER 要求を発行します。 中間ドライバーは、NDIS_STATUS_SUCCESS を返して要求を受け入れます。 中間ドライバーは、基になるミニポート ドライバーに OID_PNP_SET_POWER 要求を伝達できません。 中間ドライバーがこの要求を完了した後は、たとえ基になるミニポート・ドライバーからネッ トワーク データやステータスの指示を受信し続けたとしても、それ以上受信したネットワーク データを表示したり、ステータスを表示したりすることはできません。
中間ドライバーのプロトコル下位エッジが、基になるミニポート ドライバーをスリープ状態に移行する場合、次の流れでその移行を処理します:
NDIS は、中間ドライバー プロトコル下位エッジの ProtocolNetPnPEvent 関数を呼び出します。 ProtocolNetPnPEvent の呼び出しでは、スリープ状態の NetEventSetPower イベントを指定します。 中間ドライバーは、ネットワーク データの送信と、基になるミニポート ドライバーへの OID 要求を停止する必要があります。 未処理の要求または送信がある場合、中間ドライバーは ProtocolNetPnPEvent への呼び出しから、NDIS_STATUS_PENDING を返す必要があります。 中間ドライバーは、NdisCompleteNetPnPEvent を呼び出して ProtocolNetPnPEvent への呼び出しを完了します。 中間ドライバーのプロトコル エッジは、基になるミニポート ドライバーから受信したパケットとステータスの表示を引き続き取得できます。 受信したネットワーク データは無視できます。 中間ドライバーの実装が基になるミニポート ドライバーのステータスの監視に依存している場合は、ステータス表示の監視を続ける必要があります。
NDIS 中間ドライバーのプロトコルの端を一時停止し、NetEventSetPower イベントを発行した後、基になるミニポート アダプターを一時停止します。 一時停止の理由は、低電力状態への移行です。 プロトコル バインドの一時停止の詳細については、「バインディングの一時停止」を参照してください。
メモ 低電力状態にある間は、OID_PNP_SET_POWER を除いて、OID 要求を基になるミニポート アダプターに送信できません。
NDIS は、基になるミニポート ドライバーに OID_PNP_SET_POWER 要求を発行します。 ただし、基になるミニポート ドライバーが電源管理をサポートしていない場合、それは停止されます。 この場合、NDIS は、基になるミニポート ドライバーを停止しますが、中間ドライバー プロトコルが基になるミニポート ドライバーと NIC からバインドを解除することを要求しません。 基になるミニポート ドライバーが OID の処理を正常に完了した (またはミニポート ドライバーが停止した) 後は、それ以上のネットワーク データまたはステータスは表示されません。
動作状態への電源の設定要求の処理
中間ドライバーが、動作状態への電源の設定要求を処理するのは、次の 2 つのケースです:
NDIS は、中間ドライバーの仮想ミニポート上位エッジを動作状態にするよう要求します。
中間ドライバー プロトコル下位エッジは、プラグ アンド プレイ (PnP) イベント通知を受け取ったときに、基になるミニポート ドライバーの動作状態への移行を処理します。
これらのイベントは任意の順序で発生することがあり、1 つのイベントが必ずしも他のイベントに付随するとは限りません。
中間ドライバーの仮想ミニポート上位エッジが動作状態への電源の設定要求を受信すると、次の流れでその要求を処理します:
NDIS は、中間ドライバーの仮想ミニポートに OID_PNP_SET_POWER を発行します。 中間ドライバーは、電源の設定要求に NDIS_STATUS_SUCCESS を返します。 中間ドライバーは、基になるミニポート ドライバーに OID_PNP_SET_POWER 要求を伝達できません。
NDIS は、仮想ミニポートを再起動してから、電源設定 OID の発行後に、基になるドライバーを再起動します。 仮想ミニポートの再起動の詳細については、「アダプターの起動」を参照してください。
NDIS は、基になるプロトコル ドライバーの ProtocolNetPnPEvent 関数を呼び出します。 ProtocolNetPnPEvent の呼び出しでは、動作状態 (D0) を設定する NetEventSetPower イベントを指定します。 バインドされたプロトコル ドライバーは、中間ドライバーの仮想ミニポートへのネットワーク データの送信を開始できます。
中間ドライバーのプロトコル下位エッジが基になるミニポート ドライバーを動作状態に移行する場合、次の流れでその移行を処理します:
NDIS は、基になるミニポート ドライバーに OID_PNP_SET_POWER を発行するか、基になるミニポート ドライバーが停止した場合は、その MiniportInitializeEx ハンドラーを呼び出します。
NDIS は、OID を発行した後、基になるミニポート ドライバーを、続いて中間 NDIS のプロトコルエッジと基になるミニポート アダプターを再起動します。 プロトコル バインドの一時停止の詳細については、「バインディングの再起動」を参照してください。
NDIS は、中間ドライバーの ProtocolNetPnPEvent 関数を呼び出します。 ProtocolNetPnPEvent の呼び出しでは、動作状態 (D0) を設定する NetEventSetPower イベントを指定します。 中間ドライバーは、基になるミニポート ドライバーへのネットワーク データの送信を開始できます。
電源状態とスタンバイ フラグ
中間ドライバーは、各仮想ミニポート インスタンスと、ドライバーがバインドされている、それぞれの基になるミニポート ドライバーに対して、個別の電源状態変数を保持している必要があります。 中間ドライバーは、以下の各仮想ミニポートの StandingBy フラグも維持する必要があります:
仮想ミニポートか基になるミニポート ドライバーの電源状態が D0 から離れると TRUE に設定されるもの。
仮想ミニポートか基になるミニポート・ドライバーの電源状態が D0 に戻ると FALSE に設定されるもの。
メモ MUX 中間ドライバーの場合は、基になるミニポート ドライバーに関連付けられている複数の仮想ミニポート、または各仮想ミニポートに関連付けられている複数の基になるミニポートがあります。 いずれかのミニポート アダプターの電源状態が変更されると、関連付けられているすべてのミニポートの動作も影響を受けます。 動作がどのように影響を受けるかは実装によって異なります。 たとえば、ロード バランシング フェールオーバー (LBFO) ソリューションを実装するドライバーは、基になる 1 つのミニポート ドライバーが非アクティブ化されるときに、仮想ミニポートを非アクティブ化しないことがあります。 ただし、基になるすべてのミニポート ドライバーに依存するドライバーの実装では、いずれかの基になるミニポート ドライバーが非アクティブ化されるときに、仮想ミニポートの非アクティブ化が必要になります。
中間ドライバーは、次のように要求を処理するときに、StandingBy フラグと電源状態変数を使用する必要があります。
仮想ミニポートとその基になるミニポート アダプターの両方が D0 に存在しない限り、ドライバーの MiniportSendNetBufferLists 関数は失敗します。
ドライバーが後続の OID_PNP_SET_POWER 要求を確実に受け取れるように、ドライバーの MiniportOidRequest 関数は常に OID_PNP_QUERY_POWER を成功させる必要があります。
仮想ミニポートが D0 にない場合、または StandingBy が TRUE の場合、ドライバーの MiniportOidRequest 関数は失敗します。 それ以外の場合は、基になるミニポート ドライバーが D0 になければ、1 つの要求をキューに入れます。 基になるミニポート ドライバーの状態が D0 になったときに、キューに入った要求を処理する必要があります。
中間ドライバーの仮想ミニポートは、基になるミニポート ドライバーと仮想ミニポートの両方が D0 にある場合にのみ、ステータスを報告する必要があります。