IRP_MN_QUERY_DEVICE_RELATIONS

PnP マネージャーは、デバイス間の特定の関係を決定するためにこの要求を送信します。 次の種類のドライバーがこの要求を処理します。

  • バス ドライバーは、アダプターまたはコントローラー (バス FDO) の BusRelations 要求を処理する必要があります。 フィルター ドライバーは、BusRelations 要求を処理する場合があります。

  • バス ドライバーは、子デバイス (子 PDO) の TargetDeviceRelation 要求を処理する必要があります。

  • 関数ドライバーとフィルター ドライバーは、RemovalRelations および PowerRelations 要求を処理する場合があります。

  • バス ドライバーは、子デバイス (子 PDO) の EjectionRelations を処理する場合があります。

0x07

主要なコード

IRP_MJ_PNP

送信時

PnP マネージャーは、指定されたデバイスとの関係を持つデバイスに関する情報を収集するために、この IRP を送信します。

PnP マネージャーは、デバイスが列挙されている場合や、デバイスがアクティブな間にデバイスの BusRelations (子デバイス) を照会します。たとえば、ドライバーが IoInvalidateDeviceRelations ルーチンを呼び出して、子デバイスが追加されたか取り外されたかを示す場合などです。

PnP マネージャーは、デバイスのドライバーを削除する前に、デバイスの RemovalRelations を照会します。 PnP マネージャーは、デバイスを取り出す前に、RemovalRelationsEjectRelations を照会します。

PnP マネージャーは、ドライバーまたはユーザー モード アプリケーションがデバイス上の EventCategoryTargetDeviceChange の PnP 通知を登録するときに、デバイスの TargetDeviceRelation を照会します。 PnP マネージャーは、特定のファイル オブジェクトに関連付けられているデバイスを照会します。 IRP_MN_QUERY_DEVICE_RELATIONS は、有効なファイル オブジェクト パラメーターを持つ唯一の PnP IRP です。 ドライバーは、TargetDeviceRelation についてデバイス スタックを照会することができます。 ドライバーは、TargetDeviceRelation クエリを送信するときにファイル オブジェクトを指定する必要はありません。

PnP マネージャーは、デバイスのドライバーが IoInvalidateDeviceRelations を呼び出すと、デバイスの PowerRelations を照会し、このデバイスが暗黙的な電源管理のリレーションシップを持つデバイスのセットが変更されたことを示します。 PowerRelations 要求は、Windows 7 以降でサポートされています。

BusRelationsRemovalRelationsEjectionRelation、および PowerRelations 要求の場合、PnP マネージャーは、システム スレッドのコンテキストで IRQL = PASSIVE_LEVELで IRP_MN_QUERY_DEVICE_RELATIONSを送信します。

TargetDeviceRelation 要求の場合、PnP マネージャーは、任意のスレッド コンテキストで IRQL = PASSIVE_LEVEL でこの IRP を送信します。

入力パラメーター

IO_STACK_LOCATION 構造体の Parameters.QueryDeviceRelations.Type メンバーは、照会されているリレーションの種類を指定します。 指定できる値は、BusRelationsEjectionRelationsRemovalRelationsTargetDeviceRelationPowerRelations です。

現在の IO_STACK_LOCATION 構造体の FileObject メンバーは、Parameters.QueryDeviceRelations.TypeTargetDeviceRelation の場合にのみ有効なファイル オブジェクトを指します。

出力パラメーター

I/O 状態ブロックで返されます。

I/O 状態ブロック

ドライバーは、Irp->IoStatus.Status を STATUS_SUCCESS または STATUS_INSUFFICIENT_RESOURCES などのエラー状態に設定します。

成功した場合、ドライバーは Irp->IoStatus.Information を、要求されたリレーション情報を指す PDEVICE_RELATIONS ポインターに設定します。 DEVICE_RELATIONS 構造体は、次のように定義されています。

typedef struct _DEVICE_RELATIONS {
  ULONG  Count;
  PDEVICE_OBJECT  Objects[1];  // variable length
} DEVICE_RELATIONS, *PDEVICE_RELATIONS;

操作

ドライバーがこのIRP_MN_QUERY_DEVICE_RELATIONS に応答してリレーションを返す場合、ドライバーは、カウントとデバイス オブジェクト ポインターの適切な数を含むページングされたメモリから DEVICE_RELATIONS 構造体を割り当てます。 不要になると、PnP マネージャーは構造体を解放します。 ドライバーが、別のドライバーが割り当てた DEVICE_RELATIONS 構造体を置き換える場合、ドライバーは前の構造体を解放する必要があります。

ドライバーは、この IRP (ObReferenceObject) で報告するすべてのデバイスの PDO を参照する必要があります。 PnP マネージャーは、必要に応じて参照を削除します。

関数またはフィルター ドライバーは、デバイスに対して AddDevice ルーチンが完了した後、いつでもデバイスに対するこの IRP を処理できるように準備する必要があります。 バス ドライバーは、デバイスが列挙された直後に BusRelations のクエリを処理するように準備する必要があります。

プラグ アンド プレイ マイナー IRP の処理に関する一般的な規則については、「プラグ アンド プレイ」を参照してください。

次のサブセクションでは、さまざまなクエリを処理するための特定のアクションについて説明します。

BusRelations 要求

PnP マネージャーがアダプターまたはコントローラーのバス リレーション (子デバイス) を照会したときに、バス ドライバーは、バス上に物理的に存在するすべてのデバイスの PDO へのポインターの一覧を返す必要があります。 バス ドライバーは、起動されているかどうかに関係なく、すべてのデバイスを報告します。 バス ドライバーは、どの子が存在するかを判断するために、バス デバイスの電源を入れる必要がある場合があります。

警告 PnP マネージャーがオブジェクトのデバイス ノード (devnode) を作成するまで、PDO を引数として受け取るルーチンにデバイス オブジェクトを渡すことはできません。 (ドライバーがデバイス オブジェクトを渡した場合、システムはバグ チェック 0xCA: PNP_DETECTED_FATAL_ERROR でバグ チェックを実行します。) PnP マネージャーは、IRP_MN_QUERY_DEVICE_RELATIONS 要求に応答して devnode を作成します。 ドライバーでは、IRP_MN_QUERY_RESOURCE_REQUIREMENTS 要求の受信時に、PDO の devnode が作成されていると想定することができます。

この IRP に応答するバス ドライバーは、アダプターまたはコントローラーが接続されているバスの親バス ドライバーではなく、バス アダプターまたはコントローラーのファンクション ドライバーです。 バス以外のデバイスのファンクション ドライバーは、このクエリを処理しません。 このようなドライバーは、次の下位ドライバーに IRP を渡すだけです。 (下図を参照)。フィルター ドライバーは通常、このクエリを処理しません。

Windows Vista 以降のオペレーティング システムでは、ドライバーは常に IRP_MN_QUERY_DEVICE_RELATIONS IRP を保留にし、後でその処理を完了することをお勧めします。 この順序により、システムはバス リレーションのクエリを非同期的に処理できます。 (Windows Vista より前のオペレーティング システムでは、ドライバーはディスパッチ ルーチンから STATUS_PENDING を安全に返すことができますが、PnP マネージャーはバス リレーションのクエリを他の操作と重複させません。)

次の図は、ドライバーがバス リレーションのクエリを処理する方法を示しています。

diagram illustrating drivers handling a query for bus relations.

図に示す例では、PnP マネージャーは、USB ハブ デバイスのドライバーに BusRelationsIRP_MN_QUERY_DEVICE_RELATIONS を送信します。 PnP マネージャーは、ハブ デバイスの子の一覧を要求しています。

  1. すべての PnP IRP と同様に、PnP マネージャーは、デバイスのデバイス スタックの最上位のドライバーに IRP を送信します。

  2. オプションのフィルター ドライバーがスタックの最上位のドライバーである場合もあります。 フィルター ドライバーは、通常、この IRP を処理せずに、IRP をスタックに渡します。 フィルター ドライバーでは、たとえば、ドライバーがバス上の列挙不可能なデバイスを公開する場合、この IRP を処理する可能性があります。

  3. USB ハブのバス ドライバーが、IRP を処理します。

    USB ハブ バス ドライバー:

    • まだ PDO を持っていない子デバイスに対して PDO を作成します。

    • バスに存在しなくなったすべてのデバイスに対して PDO を非アクティブとしてマークします。 バス ドライバーは、このような PDO を削除しません。PDO を削除するタイミングの詳細については、「デバイスの削除」を参照してください。

    • バス上に存在するすべての子デバイスを報告します。

      子デバイスごとに、バス ドライバーは PDO を参照し、DEVICE_RELATIONS 構造体の PDO にポインターを向けます。

      この例には、ジョイスティック デバイス用とキーボード デバイス用の 2 つの PDO があります。

      バス ドライバーは、別のドライバーがこの IRP の DEVICE_RELATIONS 構造をすでに作成しているかどうかをチェックする必要があります。 すでに作成されている場合、バス ドライバーは既存の情報に追加する必要があります。

      バスに子デバイスが存在しない場合、ドライバーは、DEVICE_RELATIONS 構造体でカウントを 0 に設定し、成功を返します。

    • I/O 状態ブロック内で適切な値を設定し、IRP を次の下位ドライバーに渡します。 アダプターまたはコントローラーのバス ドライバーは IRP を完了しません。

  4. オプションの下位フィルター (存在する場合) は、通常、この IRP を処理しません。 このようなフィルター ドライバーは、スタックの下に IRP を渡します。 下位フィルター ドライバーがこの IRP を処理する場合は、子デバイスの一覧に PDO を追加できますが、他のドライバーによって作成された PDO は削除することができません。

  5. 親バス ドライバーは、デバイス スタック内の唯一のドライバー (デバイスが未加工モード) でない限り、この IRP を処理しません。 すべての PnP IRP と同様に、親バス ドライバーは IoCompleteRequest で IRP を完了します。

    デバイス スタックに 1 つ以上のバス フィルター ドライバーがある場合、このようなドライバーは、バス ドライバーへの途中で、または IRP がデバイス スタックに戻る途中で (IoCompletion ルーチンがある場合) IRP を処理する可能性があります。 PnP IRP の規則に従って、このようなドライバーは、スタックを下っていく途中で IRP に PDO を追加したり、IRP が (IoCompletion ルーチンで) スタックに戻る途中でリレーション リストを変更したりできます。

EjectionRelations 要求

ドライバーは、指定したデバイスが取り出されたときにシステムから物理的に削除される可能性があるデバイスの PDO へのポインターを返します。 デバイスの子の PDO を報告しないでください。PnP マネージャーは常に、親デバイスより先に子デバイスを削除するよう要求します。

PnP マネージャーは、取り出されているデバイスに IRP_MN_EJECT IRP を送信します。 このようなデバイスのドライバーでも、IRP の削除を受信します。 デバイスの取り出しのリレーションは、(IRP_MN_EJECT IRP ではなく) IRP_MN_REMOVE_DEVICE IRP を受信します。

親バス ドライバーのみが、その子デバイスの 1 つに対する、DirectiveRelations クエリに応答できます。 ファンクション ドライバーとフィルター ドライバーは、これをデバイス スタック内の次の下位ドライバーに渡す必要があります。 バス ドライバーは、アダプターまたはコント ローラーのファンクション ドライバーとしてこの IRP を受け取る場合、バス ドライバーは、ファンクション ドライバーのタスクを実行し、次の下位ドライバーに IRP を渡す必要があります。

PowerRelations 要求

Windows 7 以降では、PowerRelations クエリを使用すると、ドライバーは、PnP 列挙をサポートする親バスと、バス上の列挙された子デバイスとの間の従来のリレーションシップの外部で、電源管理のリレーションを指定できます。 たとえば、バス ドライバーがバス上の子デバイスを列挙できない場合、またはデバイスが複数のバスの子である場合、PowerRelations クエリでは、子デバイスとバスまたはバスの電源のリレーションを記述することができます。

PnP マネージャーは、デバイスのドライバーが IoInvalidateDeviceRelations ルーチンを呼び出し、PowerRelationsパラメーター値を指定するときに、デバイスの PowerRelations クエリを発行します。

このクエリに応答して、ターゲット デバイス (つまり、クエリの対象であるデバイス) のドライバーは、ターゲット デバイスがオンになる前に電源マネージャーによってオンになる必要がある他のデバイスの PDO へのポインターを含む DEVICE_RELATIONS 構造体を提供します。 逆に、これらの他のデバイスは、ターゲット デバイスがオフになった後でのみオフになる必要があります。 電源マネージャーは、クエリの情報を使用して、これらのデバイスが正しい順序でオンまたはオフになっていることを保証します。

この順序保証は、S1、S2、S3 (スリープ)、S4 (休止状態)、および S5 (シャットダウン) のシステムの電源状態間の遷移を含む、グローバルなシステム スリープ状態遷移にのみ適用されます。 PowerRelations の順序保証は、ダイレクト ランタイム電源管理 (DFx) 遷移の場合を除き、システムが S0 (実行中) のシステム状態のままである間、Dx デバイスの電源状態遷移には適用されません。

ターゲット デバイスが特殊なファイル (ページング ファイル、休止状態ファイル、クラッシュ ダンプ ファイルなど) のデバイス パス上にある場合、ターゲット デバイスのドライバーは、InPathTRUE である IRP_MN_DEVICE_USAGE_NOTIFICATION IRP を処理するときに追加の手順を実行する必要があります。 このドライバーは、PowerRelations クエリ用に PDO が提供されているデバイスが、特殊なファイルのデバイス パス内であることもサポートできるようにする必要があります。 このサポートを確認するには、ターゲット デバイスのドライバーは、最初にこれらの各デバイスに IRP_MN_DEVICE_USAGE_NOTIFICATION IRP を送信する必要があり、この IRP は、ターゲット デバイスと同じ UsageNotification.Type を指定する必要があります。 この IRP を受け取るすべてのデバイスが成功の状態コードで IRP を完了した場合にのみ、ターゲット デバイスのドライバーは、IRP_MN_DEVICE_USAGE_NOTIFICATION IRP を正常に完了できます。 それ以外の場合、このドライバーは、エラーの状態コードでこの IRP を完了する必要があります。

この同じドライバーが、InPathFALSE である IRP_MN_DEVICE_USAGE_NOTIFICATION IRP を処理する場合、ドライバーは、InPathTRUE の場合と同じ一連の依存デバイスに IRP_MN_DEVICE_USAGE_NOTIFICATION IRP を送信する必要があります。 ただし、InPathFALSE の場合、ドライバーはエラーの状態コードでこの IRP を完了しない必要があります。

PowerRelations クエリに応答するドライバーは、PowerRelations クエリに PDO が提供されているすべてのデバイスについてのターゲット デバイス変更通知に登録する必要があります。 これらの通知に登録するには、ドライバーは IoRegisterPlugPlayNotification ルーチンを呼び出し、EventCategoryTargetDeviceChangeEventCategory パラメーター値を指定できます。

RemovalRelations 要求

ドライバーは、指定したデバイスのドライバーが削除されたときにドライバーを削除する必要があるすべてのデバイスの PDO へのポインターを返します。 デバイスの子の PDO を報告しないでください。PnP マネージャーは、デバイスを削除する前に、子デバイスの削除をすでに要求しています。

削除リレーションが削除される順序は定義されていません。

デバイス スタック内のすべてのドライバーは、この種類のリレーション クエリを処理することができます。 ファンクションまたはフィルター ドライバーは、IRP を次の下位ドライバーに渡す前にこれを処理します。 バス ドライバーは、IRP を処理し、完了します。

TargetDeviceRelation 要求

TargetDeviceRelation クエリを使用すると、PnP マネージャーは、ハードウェアを制御する PnP デバイス スタック内の PDO の、PnP 以外のデバイス スタックに対してクエリを実行できます。

一般に、ドライバーは、IRP が特定のデバイス スタックの下部に達するまで、IRP_MN_QUERY_DEVICE_RELATIONS IRP をスタックに転送します。 PnP 以外のスタックの下部にあるドライバーは、関連する PnP スタックに IRP を転送または再発行します。 たとえば、PnP マネージャーは、PnP 以外のスタックであるファイル システム スタックの上部にあるデバイス オブジェクトに TargetDeviceRelation クエリを送信する可能性があります。 ファイル システム スタック内の各デバイス オブジェクトは、クエリがスタックの下部にあるデバイス オブジェクトに到達するまで、下にあるデバイス オブジェクトにクエリを渡します。 スタック内の最下位のデバイス オブジェクトは、PnP ストレージ ボリューム スタックの上部にあるデバイス オブジェクトに TargetDeviceRelation クエリを転送または再発行し、その後、そのクエリはストレージ ボリューム スタックの下部にある PDO に渡されます。

次の一覧に、PnP デバイス スタックの下部にある PDO へのポインターを安全に取得できる状況をまとめています。

  • PnP のデバイス オブジェクト

    PnP デバイス スタック内のデバイス オブジェクトは、デバイスの AddDevice ルーチンが呼び出されたときに、スタックの PDO についての情報を得ます。 ドライバーは、ポインターの使用が、ロックの削除ルーチンを使用して受信 IRP_MN_REMOVE_DEVICE メッセージと正しく同期されている場合は、PDO へのポインターを安全にキャッシュすることができます。

  • PnP 以外のスタック内にあり、スタックの一番下ではないデバイス オブジェクト

    PnP 以外のスタックの下部にないデバイス オブジェクトの場合、ドライバーは TargetDeviceRelation クエリを送信して、対応する PnP デバイス スタックの下部にある PDO へのポインターを取得できます。

  • デバイスのファイル オブジェクト

    デバイスのファイル オブジェクトを指定すると、ドライバーは IoGetRelatedDeviceObject を呼び出してデバイス オブジェクトを取得し、前のリスト項目の指示に従うことができます。

  • デバイス オブジェクトへのハンドル

    デバイス オブジェクトへのハンドルを指定すると、ドライバーは ObReferenceObjectByHandle を呼び出してデバイスのファイル オブジェクトを取得し、前のリスト項目の指示に従うことができます。

親バス ドライバーは、その子デバイスの TargetDeviceRelation リレーション クエリを処理する必要があります。 バス ドライバーは、ObReferenceObject を使用して子デバイスの PDO を参照し、DEVICE_RELATIONS 構造体の PDO へのポインターを返します。 この種類のリレーションの構造体には、1 つの PDO ポインターしかありません。 PnP マネージャーは、ドライバーまたはアプリケーションがデバイス上の通知の登録を解除するときに、PDO への参照を削除します。

親バス ドライバーのみが TargetDeviceRelation クエリに応答します。 ファンクション ドライバーとフィルター ドライバーは、これをデバイス スタック内の次の下位ドライバーに渡す必要があります。 バス ドライバーは、アダプターまたはコント ローラーのファンクション ドライバーとしてこの IRP を受け取る場合、バス ドライバーは、ファンクション ドライバーのタスクを実行し、次の下位ドライバーに IRP を渡す必要があります。

ドライバーが PDO ベースのスタックにない場合、ドライバーは、ドライバーが I/O を実行するファイル ハンドルに関連付けられているデバイス オブジェクトに、新しいターゲットとデバイス間のリレーションのクエリ IRP を送信します。

この IRP の送信

ドライバーは、BusRelations を要求するために IRP_MN_QUERY_DEVICE_RELATIONS を送信することはできません。 ドライバーは、RemovalRelations または DirectiveRelations に対してこの IRP を送信することは制限されていませんが、ドライバーがこれを実行する可能性はあまりありません。

ドライバーは、TargetDeviceRelation についてデバイス スタックを照会することができます。 IRP の送信の詳細については、「IRP の処理」を参照してください。 次の手順は、特にこの IRP に適用されます。

  • IRP の次の I/O スタックの位置の値を設定します。MajorFunctionIRP_MJ_PNP に、MinorFunctionIRP_MN_QUERY_DEVICE_RELATIONS に、Parameters.QueryDeviceRelations.TypeTargetDeviceRelation に設定し、Irp->FileObject を有効なファイル オブジェクトに設定します。

  • IoStatus.Status を STATUS_NOT_SUPPORTED に初期化します。

ドライバーがこの IRP を送信して、ドライバーが受信した TargetDeviceRelationIRP_MN_QUERY_DEVICE_RELATIONS に応答して PDO を報告した場合、ドライバーは PDO を報告し、IRP が完了すると、返されたリレーション構造を解放します。 ドライバーが別の理由でこの IRP を開始した場合、IRP が完了して、PDO が不要になったときに PDO を逆参照すると、ドライバーはリレーションの構造を解放します。

要件

ヘッダー

Wdm.h (Wdm.h、Ntddk.h、Ntifs.h を含む)

関連項目

AddDevice

IoCompleteRequest

IoGetRelatedDeviceObject

IoInvalidateDeviceRelations

IoRegisterPlugPlayNotification

IRP_MJ_PNP

IRP_MN_DEVICE_USAGE_NOTIFICATION

IRP_MN_EJECT

IRP_MN_QUERY_RESOURCE_REQUIREMENTS

IRP_MN_REMOVE_DEVICE

IO_STACK_LOCATION

ObReferenceObject

ObReferenceObjectByHandle