実行中システムへの PnP デバイスの追加
このセクションでは、実行中のコンピューターにユーザーが追加した PnP デバイスをシステムが構成するときに発生するイベントのシーケンスについて説明します。 この説明では、PnP マネージャー、バス ドライバー、および新しいデバイスの列挙と構成における関数ドライバーとフィルター ドライバーの役割について説明します。
この説明のほとんどは、マシンの起動時に存在する PnP デバイスの構成にも関連しています。 具体的には、INFファイルでドライバがSERVICE_DEMAND_STARTとマークされている デバイスは、そのデバイスが動的に追加される場合でも、起動時に存在する 場合でも、基本的に同じ方法で設定される。
次の図は、ユーザーがハードウェアをコンピューターに接続したときから始めて、デバイスを構成する最初の手順を示しています。
次の注釈は、前の図の丸数字に対応しています。
ユーザーが PnP バス上の空きスロットに PnP デバイスを接続します。
この例では、ユーザーは PnP USB ジョイスティックを USB ホスト コントローラー上のハブに接続します。 子デバイスを接続できるため、USB ハブは PnP バス デバイスです。
バス デバイスの関数ドライバーは、新しいデバイスがバス上にあることを判断します。
ドライバーがこれを判断する方法は、バス アーキテクチャによって異なります。 一部のバスの場合、バス関数ドライバーは、新しいデバイスのホット プラグ通知を受け取ります。 バスがホット プラグ通知をサポートしていない場合、ユーザーはコントロール パネルで適切なアクションを実行して、バスを列挙する必要があります。
この例では、USB バスはホット プラグ通知をサポートしているため、USB バスの関数ドライバーには、その子が変更されたことを通知します。
バス デバイスの関数ドライバーは、子デバイスのセットが変更されたことを PnP マネージャーに通知します。
関数ドライバーは、 BusRelations の タイプ を使用して IoInvalidateDeviceRelations を呼び出すことによって PnP マネージャーに通知します。
PnP マネージャーは、バス上のデバイスの現在の一覧のバスのドライバーに対してクエリを実行します。
PnP マネージャーは、バスのデバイス スタックに IRP_MN_QUERY_DEVICE_RELATIONS 要求を送信します。 Parameters.QueryDeviceRelations.Type 値は BusRelations であり、PnP マネージャーがバス上に存在するデバイスの現在のリスト (バス関係) を要求していることを示します。
PnP マネージャーは、バスのデバイス スタックの最上位ドライバーに IRP を送信します。 PnP IRP の規則に従って、スタック内の各ドライバーは、必要に応じて IRP を処理し、IRP を次のドライバーに渡します。
バス デバイスの関数ドライバーは、IRP を処理します。
この IRP の処理の詳細については、 IRP_MN_QUERY_DEVICE_RELATIONS の参考ページを参照してください。
この例では、USB ハブ ドライバーは、ハブ FDO のこの IRP を処理します。 ハブ ドライバーは、ジョイスティック デバイスの PDO を作成し、IRP で返される子デバイスの一覧にジョイスティック PDO への参照ポインターを含めます。
USBハブの親バスドライバー(USBホストコントローラクラス/ミニクラスドライバーのペア)がIRPを完了すると、IRPはハブドライバーによって登録された IoCompletion ルーチンによってデバイススタックに戻されます。
バス関数ドライバーは、PnP マネージャーが子デバイスの一覧のクエリ実行を要求することによって、子の一覧の変更を報告することに注意してください。 結果として得られる IRP_MN_QUERY_DEVICE_RELATIONS 要求は、バス デバイスのすべてのドライバーによって確認されます。 通常、バス関数ドライバーは、IRP を処理し、子を報告する唯一のドライバーです。 一部のデバイス スタックでは、バス フィルター ドライバーが存在し、バスの関係の一覧の構築に参加します。 例として、ACPI デバイスのバス フィルター ドライバーとして接続する ACPIが挙げられます。 一部のデバイス スタックでは、非バスフィルター ドライバーが IRP_MN_QUERY_DEVICE_RELATIONS 要求を処理しますが、これは一般的ではありません。
この時点で、PnP マネージャーには、バス上のデバイスの現在の一覧があります。 PnP マネージャーはその後、デバイスが新しく到着したか、削除されたかを判断します。 この例では、1 つの新しいデバイスがあります。 次の図は、新しいデバイスの開発ノードを作成し、デバイスの構成を開始する PnP マネージャーを示しています。
次の注釈は、前の図の丸数字に対応しています。
PnP マネージャーは、バス上の新しい子デバイスの devnode を作成します。
PnP マネージャーは、現在 PnP デバイス ツリーに記録されているバスの子の一覧と IRP_MN_QUERY_DEVICE_RELATIONS IRP で返されるバスの関係の一覧を比較します。 PnP マネージャーは、新しいデバイスごとに devnode を作成し、削除されたすべてのデバイスの削除処理を開始します。
この例では、1 つの新しいデバイス (ジョイスティック) があるため、PnP マネージャーはジョイスティック用の devnode を作成します。 この時点で、ジョイスティック用に構成されているドライバーは、ジョイスティックの PDO を作成した親 USBハブ バスドライバーだけです。 オプションのバスフィルター ドライバーもデバイススタックに存在しますが、この例では、わかりやすくするためにバスフィルター ドライバーを省略しています。
前の図の 2 つの開発ノード間の幅の矢印は、ジョイスティック devnode が USB ハブ devnode の子であることを示しています。
PnP マネージャーは新しいデバイスに関する情報を収集し、デバイスの構成を開始します。
PnP マネージャーは、デバイスに関する情報を収集するデバイス スタックに IRP のシーケンスを送信します。 この時点でデバイス スタックは、デバイスの親バス ドライバーによって作成された PDO と、オプションのバス フィルター ドライバーのフィルター DOs のみで構成されます。 そのため、バス ドライバーとバス フィルター ドライバーは、これらの IRP に応答する唯一のドライバーです。 この例では、ジョイスティック デバイス スタック内の唯一のドライバーは親バス ドライバーである、USB ハブ ドライバーです。
PnP マネージャーはデバイス スタックに IRP を送信することによって、新しいデバイスに関する情報を収集します。 これらのIRPには、次が含まれます。
IRP_MN_QUERY_ID、次の種類のハードウェア ID ごとの個別の IRP:
BusQueryDeviceID
BusQueryInstanceID
BusQueryHardwareIDs
BusQueryCompatibleIDs
BusQueryContainerID
IRP_MN_QUERY_DEVICE_TEXT、次の項目ごとの個別の IRP:
DeviceTextDescription
DeviceTextLocationInformation
PnP マネージャーは、新しい PnP デバイスの処理のこの段階で上記の IRP を送信しますが、必ずしも一覧に記載されている順序ではないので、IRP が送信される順序について想定しないでください。 また、PnP マネージャーが上記の IRP のみを送信すると想定しないでください。
PnP マネージャーはレジストリを確認して、デバイスがこのマシンに以前にインストールされていたかどうかを確認します。 PnPマネージャは、 Enum 枝の下にあるデバイスの <enumerator>\<deviceID> サブキーを確認します。 この例では、デバイスは新規であり、「一から」構成する必要があります。
PnP マネージャーは、レジストリにデバイスに関する情報を格納します。
レジストリの Enum ブランチはオペレーティング システム コンポーネントで使用するために予約されており、そのレイアウトは変更される可能性があります。 ドライバーライターは、システム ルーチンを使用して、ドライバーに関連する情報を抽出する必要があります。 ドライバーから直接 Enum ブランチにアクセスしないでください。 次の Enum 情報は、デバッグ目的でのみ一覧表示されます。
PnP マネージャーは、デバイスの列挙子のキーの下に、デバイスのサブキーを作成します。
PnP マネージャーは、 HKLM\System\CurrentControlSet\Enum\<enumerator>\<deviceID> という名前のサブキーを作成します。 <列挙子> サブキーが存在していなければ作成されます。
列挙子 は、PnP ハードウェア標準に基づいて PnP デバイスを検出するコンポーネントです。 列挙子のタスクは、PnP マネージャーと連携して PnP バス ドライバーによって実行されます。 デバイスは通常、PCI や PCMCIA バスドライバーなどの親バスドライバーによって列挙されます。 一部のデバイスは、ACPI ドライバーなどのバスフィルタードライバーによって列挙されます。
PnP マネージャーは、デバイスのこのインスタンスのサブキーを作成します。
IRP_MN_QUERY_CAPABILITIESの Capabilities.UniqueID が TRUE として返された場合、デバイスの一意の ID はシステム全体で一意です。 そうでない場合、PnP マネージャーは、システム全体で一意になるように ID を変更します。
PnP マネージャーは、 HKLM\System\CurrentControlSet\Enum\<enumerator>\<deviceID>\<instanceID> という名前のサブキーを作成します。
PnP マネージャーは、デバイス インスタンスのサブキーにデバイスに関する情報を書き込みます。
PnP マネージャーは、デバイスに提供された場合、次のような情報を格納します。
DeviceDesc — IRP_MN_QUERY_DEVICE_TEXTから
場所 - IRP_MN_QUERY_DEVICE_TEXTから
機能 — IRP_MN_QUERY_CAPABILITIESからのフラグ
UINumber — IRP_MN_QUERY_CAPABILITIESから
HardwareID — IRP_MN_QUERY_IDから
CompatibleIDs — IRP_MN_QUERY_IDから
ContainerID — IRP_MN_QUERY_IDから
LogConf\BootConfig — IRP_MN_QUERY_RESOURCESから
LogConf\BasicConfigVector — IRP_MN_QUERY_RESOURCE_REQUIREMENTSから
この時点で、PnP マネージャーは、デバイスの関数ドライバーとフィルタードライバー (存在する場合) を検索する準備ができています。 (次の図を参照してください)。
次の注釈は、前の図の丸数字に対応しています。
カーネル モード PnP マネージャーは、ユーザー モード PnP マネージャーとユーザー モードセットアップ コンポーネントと連携して、デバイスの関数ドライバーとフィルター ドライバー (存在する場合) を見つけます。
カーネル モードの PnP マネージャーは、ユーザー モード PnP マネージャーにイベントをキューに登録し、インストールする必要があるデバイスを識別します。 特権ユーザーがログインすると、ユーザー モード コンポーネントはドライバーの検索に進みます。 セットアップ コンポーネントとデバイスのインストールにおける役割については、 デバイスのインストール概要 を参照してください。
ユーザー モードセットアップ コンポーネントは、カーネル モード PnP マネージャーに関数とフィルター ドライバーを読み込むよう指示します。
ユーザー モード コンポーネントはカーネル モードを呼び戻してドライバーを読み込み、 AddDevice ルーチンを呼び出します。
次の図は、ドライバーの読み込み (必要な場合)、 AddDevice ルーチンの呼び出し、デバイスの起動をドライバーに指示する PnP マネージャーを示しています。
次の注釈は、前の図の丸数字に対応しています。
下位フィルタードライバー
ファンクション ドライバーがデバイス スタックにアタッチされる前に、PnP マネージャーは下位フィルタードライバーを処理します。 ドライバーがまだ読み込まれていない場合、下位フィルター ドライバーごとに、PnP マネージャーはドライバーの DriverEntry ルーチンを呼び出します。 PnP マネージャーは次に、フィルター ドライバーの AddDevice ルーチンを呼び出します。 その AddDevice ルーチンで、フィルター ドライバーは、フィルター デバイス オブジェクト (フィルター DO) を作成し、デバイス スタック (IoAttachDeviceToDeviceStack) にアタッチします。 デバイス オブジェクトをデバイス スタックにアタッチすると、ドライバーはデバイスのドライバーとしてエンゲージされます。
USB ジョイスティックの例では、デバイス用の下位フィルター ドライバーが 1 つあります。
関数ドライバー
下位フィルターがアタッチされると、PnP マネージャーは関数ドライバーを処理します。 ドライバーがまだ読み込まれていない場合、PnP マネージャーは関数ドライバーの DriverEntry ルーチンを呼び出し、関数ドライバーの AddDevice ルーチンを呼び出します。 関数ドライバーは関数デバイス オブジェクト (FDO) を作成し、デバイス スタックにアタッチします。
この例では、USB ジョイスティックの関数ドライバーは実際はHID クラス ドライバーと HID ミニクラス ドライバーのドライバーのペアです。 2 つのドライバーが連携して、関数ドライバーとして機能します。 ドライバーのペアは、FDO を 1 つだけ作成し、デバイス スタックにアタッチします。
上位フィルタードライバー
関数ドライバーがアタッチされると、PnP マネージャーは上位フィルター ドライバーを処理します。
この例では、デバイス用の上位フィルター ドライバーが 1 つあります。
リソースの割り当てとデバイスの起動
PnP マネージャーは必要に応じて、デバイスにリソースを割り当て、デバイスを起動する IRP を発行します。
リソースの割り当て
構成プロセスの早い段階で、PnP マネージャーはデバイスの親バス ドライバーからデバイスのハードウェア リソース要件を収集しました。 デバイス用にドライバーの完全なセットが読み込まれた後、PnP マネージャーはデバイス スタックに IRP_MN_FILTER_RESOURCE_REQUIREMENTS 要求を送信します。 スタック内のすべてのドライバーには、この IRP を処理し、必要に応じてデバイスのリソース要件の一覧を変更する機会があります。
PnP マネージャーはデバイスの要件と現在使用可能なリソースに基づいて、デバイスに必要な場合はデバイスにリソースを割り当てます。
PnP マネージャーは、新しいデバイスのニーズを満たすために、既存のデバイスのリソース割り当てを再配置する必要がある場合があります。 このリソースの再割り当ては、「再調整」と言います。既存のデバイスのドライバーは、再調整中に一連の停止 IRP と開始 IRP を受け取りますが、再調整はユーザーに対して透過的である必要があります。
USB ジョイスティックの例では、USB デバイスはハードウェア リソースを必要としないため、PnP マネージャーはリソース 一覧を NULL に設定します。
デバイスの起動 (IRP_MN_START_DEVICE)
PnP マネージャーは、デバイスにリソースを割り当てると、 IRP_MN_START_DEVICE をデバイス スタックに送信して、ドライバーがデバイスを起動するように指示します。
デバイスの起動後、PnP マネージャーは、デバイスのドライバーにさらに 3 つの IRP を送信します。
-
開始 IRP が正常に完了すると、PnP マネージャーはデバイス スタックに別の IRP_MN_QUERY_CAPABILITIES IRP を送信します。 デバイスのすべてのドライバーには、IRP を処理するオプションがあります。 PnP マネージャーは機能またはフィルター ドライバーが機能情報を収集するためにデバイスにアクセスする必要がある場合があるため、すべてのドライバーが接続され、デバイスが起動した後の時点でこの IRP を送信します。
-
この IRP は、例えばデバイス マネージャーや Hotplug プログラムなどのユーザー インターフェイスにデバイスを表示しないことを報告する機会をドライバーに与えます。 これは、システム上に存在するが、現在の構成では使用できないデバイス (ノート PC のドッキング解除時に使用できないノート PC のゲーム ポートなど) に役立ちます。
バス関係のIRP_MN_QUERY_DEVICE_RELATIONS
PnP マネージャーは、デバイスに子デバイスがあるかどうかを判断するためにこの IRP を送信します。 その場合、PnP マネージャーは各子デバイスを構成します。
GUID_PNP_LOCATION_INTERFACEの使用
GUID_PNP_LOCATION_INTERFACE インターフェイスは、デバイスのSPDRP_LOCATION_PATHS プラグ アンド プレイ (PnP) デバイス プロパティを提供します。
ドライバーでこのインターフェイスを実装するには、InterfaceType = GUID_PNP_LOCATION_INTERFACE でIRP_MN_QUERY_INTERFACE IRP を処理します。 インターフェイスの個々のルーチンへのポインターを記述した PNP_LOCATION_INTERFACE 構造体へのポインターがドライバーから提供されます。 PnpGetLocationString ルーチン は、デバイスのSPDRP_LOCATION_PATHS プロパティのデバイス固有の部分を提供します。