動的な列挙

動的列挙とは、システムの実行中にシステムに接続されているデバイスの数と種類の変更を検出して報告できる、ドライバーの機能です。

親デバイスに接続されているデバイスの数または種類がシステムの構成に依存する場合、バス ドライバーは動的列挙を使用する必要があります。 これらのデバイスの中には、常時システムに接続されているデバイスもあれば、システムの実行中に電源に接続されたり取り外されたりするものもあります。

たとえば、システムの PCI バスに接続されているデバイスの数と種類はシステムに依存しますが、ユーザーが電源をオフにしてケースを開き、ドライバーを使用してデバイスを追加または削除しない限り、それらは永続的です。 一方、ユーザーは、システムの実行中にケーブルを接続または取り外すことによって、USB デバイスを追加または取り外すことができます。

動的子リスト

フレームワークにより、フレームワークの子リスト オブジェクトを提供することで、ドライバーで動的列挙をサポートできます。 各子リストは、親デバイスに接続されている子デバイスの一覧を表します。 親デバイスのバス ドライバーは、親の子デバイスを識別し、親デバイスの子リストに追加し、各子デバイスの物理デバイス オブジェクト (PDO) を作成する必要があります。

デバイスの FDO を表すフレームワーク デバイス オブジェクトをドライバーが作成するたびに、フレームワークは、デバイスの空の既定の子リストを作成します。 ドライバーは、WdfFdoGetDefaultChildList を呼び出すことによって、デバイスの既定の子リストへのハンドルを取得できます。 通常、デバイスの子を列挙するバス ドライバーを作成する場合、ドライバーは既定の子リストに子を追加できます。 追加の子リストを作成する必要がある場合、ドライバーは WdfChildListCreate を呼び出すことができます。

ドライバーは、子リストを使用する前に、WDF_CHILD_LIST_CONFIG 構造体を初期化し、その構造体を既定の子リストの場合 WdfFdoInitSetDefaultChildListConfig、または追加の子リストの場合 WdfChildListCreate に渡すことによって、子リスト オブジェクトを構成する必要があります。

動的な子記述

バス ドライバーは、子デバイスを識別するたびに、子デバイス記述を子リストに追加する必要があります。 子記述は、必要な ID 記述とオプションのアドレス記述で構成されます。

識別記述 識別記述は、ドライバが列挙する各デバイスを一意に識別する情報を含む構造体です。 ドライバーはこの構造体を定義しますが、最初のメンバーは WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER 構造体である必要があります。

通常、識別記述には、デバイスの デバイス識別文字列、場合によってはシリアル番号、およびスロット番号など、バス上のデバイスの場所に関する情報が含まれます。

ドライバーは、次のコールバック関数のセットを提供できます。これにより、フレームワークは識別記述の情報を操作できます。

通常、ドライバーの識別記述構造体に、動的に割り当てられたバッファーへのポインターが含まれている場合は、これらのコールバック関数を指定する必要があります。 これらのコールバック関数の目的の詳細については、参照ページを参照してください。

アドレス記述 アドレス記述は、デバイスが接続されている間に情報が変更される可能性がある場合に、ドライバーがバス上のデバイスにアクセスできるように、ドライバーが必要とする情報を含む構造体です。 ドライバーはこの構造体を定義しますが、最初のメンバーは WDF_CHILD_ADDRESS_DESCRIPTION_HEADER 構造体である必要があります。

アドレス記述は省略可能です。 デバイスのアドレス情報が、デバイスが接続されてから取り外された時刻の間で変更できない場合は、デバイスのすべてのアドレス情報を識別記述に格納できます。 たとえば USB コントローラーは、デバイスが接続されているときにデバイスにアドレスを割り当て、これらのアドレスは変更されません。

一方、一部のバスでは、変更可能なアドレス指定情報が使用されます。 たとえば、IEEE 1394 バスでは、発生したバス リセットの数である「世代数」が使用されます。 IEEE 1394 デバイスに対する各非同期 I/O 要求には、生成カウントを含める必要があります。 このアドレス情報は変更される可能性があるため、ドライバーはアドレス記述に格納する必要があります。

ドライバーは、アドレス記述の情報を操作するコールバック関数の次のセットを提供できます。

通常、ドライバーのアドレス記述構造体に、動的に割り当てられたバッファーへのポインターが含まれている場合は、これらのコールバック関数を指定する必要があります。 これらのコールバック関数の目的の詳細については、参照ページを参照してください。

動的子リストへのデバイスの追加

フレームワークがバス ドライバーの EvtDriverDeviceAdd コールバック関数を呼び出す場合、コールバック関数は WdfDeviceCreate を呼び出して親デバイスの FDO を作成する必要があります。これは通常、バス アダプターです。 FDO の作成の詳細については、「ファンクション ドライバーでのデバイス オブジェクトの作成」を参照してください。 ドライバーは次に、親デバイスの子を列挙し、子リストに子を追加する必要があります。

必要に応じて、ドライバーは WdfDeviceSetBusInformationForChildren を呼び出して、バスに関する情報をフレームワークに提供できます。 そうすることにより子デバイスとアプリがバスを識別しやすくなるため、推奨されます。

子リストに子を追加するために、ドライバーは、検出された各子デバイスに対して WdfChildListAddOrUpdateChildDescriptionAsPresent を呼び出す必要があります。 この呼び出しは、ドライバーが親デバイスに接続されている子デバイスを検出したことをフレームワークに通知します。 ドライバーが WdfChildListAddOrUpdateChildDescriptionAsPresent を呼び出すと、ID の説明と、必要に応じてアドレスの説明が提供されます。

ドライバーが WdfChildListAddOrUpdateChildDescriptionAsPresent を呼び出して新しいデバイスを報告した後、フレームワークは新しいデバイスが存在することを PnP マネージャーに通知します。 その後、PnP マネージャーは、新しいデバイスのデバイス スタックとドライバー スタックをビルドします。 このプロセスの一環として、フレームワークはバス ドライバーの EvtChildListCreateDevice コールバック関数を呼び出します。 このコールバック関数は、新しいデバイスの PDO を作成するために WdfDeviceCreate を呼び出す必要があります。

通常、複数の子デバイスが親に接続されているため、バス ドライバーは WdfChildListAddOrUpdateChildDescriptionAsPresent を複数回呼び出す必要があります。 これを行う最も効率的な方法は次のとおりです。

  1. WdfChildListBeginScan を呼び出します。

  2. 各子デバイスに対して WdfChildListAddOrUpdateChildDescriptionAsPresent を呼び出します。

  3. WdfChildListEndScan を呼び出します。

WdfChildListBeginScanWdfChildListEndScan の呼び出しでドライバーの動的列挙体を囲むと、フレームワークは子リストに対するすべての変更を格納し、ドライバーが WdfChildListEndScan を呼び出すときに PnP マネージャーに変更を通知します。 後で、フレームワークは、子リスト内の各デバイスに対してバス ドライバーの EvtChildListCreateDevice コールバック関数を呼び出します。 このコールバック関数は、各新しいデバイスの PDO を作成するために WdfDeviceCreate を呼び出します。

ドライバーが WdfChildListBeginScan を呼び出すと、フレームワークは、以前に報告されたすべてのデバイスに、存在しなくなったとマークします。 そのため、ドライバーは、新しく検出された子だけでなく、ドライバーが検出できるすべての子に対して WdfChildListAddOrUpdateChildDescriptionAsPresent を呼び出す必要があります。 子リストに 1 つの子を追加するには、ドライバーで最初に WdfChildListBeginScan を呼び出さずに、 WdfChildListUpdateAllChildDescriptionsAsPresent を 1 回呼び出すことができます。

動的子リストの更新

動的な子リストの情報を更新するには、次の 2 つの一般的な方法があります。

  1. 親デバイスが子の到着または削除を示す割り込みを受信すると、ドライバーの EvtInterruptDpc コールバック関数は、デバイスが接続された場合は WdfChildListAddOrUpdateChildDescriptionAsPresent を呼び出し、デバイスが取り外された場合は WdfChildListUpdateChildDescriptionAsMissing を呼び出します。

  2. ドライバーは、親デバイスが動作 (D0) 状態になるたびにフレームワークが呼び出す EvtChildListScanForChildren コールバック関数を提供できます。 このコールバック関数は、WdfChildListBeginScanWdfChildListAddOrUpdateChildDescriptionAsPresent (または WdfChildListUpdateAllChildDescriptionsAsPresent)、および WdfChildListEndScan を呼び出すことによって、すべての子デバイスを列挙する必要があります。

ドライバーでは、これらの手法の 1 つまたは両方を使用できます。

動的子リストの走査

ドライバーで子リストの内容を確認する場合は、次のいずれかの手法を使用してリストを走査できます。

  • ドライバーは、各子デバイス記述の内容を一度に 1 つずつ取得するために、次のことができます。

    1. WdfChildListBeginIteration を呼び出します。
    2. 必要な回数、WdfChildListRetrieveNextDevice を呼び出します。
    3. WdfChildListEndIteration を呼び出します。

    WdfChildListBeginIteration を呼び出すとき、ドライバーは、フレームワークがすべてのデバイス記述を取得するか、サブセットのみを取得するかを示す WDF_RETRIEVE_CHILD_FLAGS 型のフラグを指定します。 WdfChildListRetrieveNextDevice は、一致を検出すると、子デバイスの識別とアドレスの記述にくわえて、そのデバイス オブジェクトへのハンドルを取得します。

  • 子デバイス記述に現在含まれているアドレス記述を取得する必要がある場合、ドライバーは、識別記述を指定して WdfChildListRetrieveAddressDescription を呼び出すことができます。 フレームワークは、一致する識別記述を持つ子デバイスが見つかるまで子リストを走査し、次にアドレス記述を取得します。

  • 特定の子デバイスに関連付けられているフレームワーク デバイス オブジェクトのハンドルを取得する必要がある場合、ドライバーは WdfChildListRetrievePdo を呼び出すことができます。 フレームワークは、一致する識別記述を持つ子デバイスが見つかるまで子リストを走査し、次にデバイス オブジェクト ハンドルを返します。 呼び出しを WdfChildListBeginIterationWdfChildListEndIteration でラップして、別のスレッドでの PDO の突然の PnP 取り出しから、呼び出し元を保護してください。

PDO の識別およびアドレスの記述へのアクセス

ドライバーは、PDO の識別記述またはアドレス記述にアクセスするために、次のメソッドを呼び出すことができます。

再列挙要求の処理

動的列挙をサポートするフレームワークベースのバス ドライバーは、REENUMERATE_SELF_INTERFACE_STANDARD インターフェイスを介して特定の子デバイスを再び有効にする要求を受け取ることができます。 詳細については、「列挙要求の処理」を参照してください。