ドライバー スタックへの IRP の受け渡し

ドライバーのディスパッチ ルーチンは、IRP を受信したとき、自身の I/O スタックの場所を確認できるように、またあらゆるパラメーターが有効であると判断できるように IoGetCurrentIrpStackLocation を呼び出す必要があります。 要求そのものをドライバーが満たして完了できない場合は、次のいずれかを実行できます。

  • 自身より下位のドライバーで詳しく処理するために、そのドライバーに IRP を渡します。

  • 1 つ以上の新しい IRP を作成して、下位ドライバーに渡します。

上位ドライバーから次の下位ドライバーへ I/O 要求を受け渡し

  1. ドライバーから次の下位ドライバーに入力 IRP が渡される場合、ディスパッチ ルーチンは IoSkipCurrentIrpStackLocation または IoCopyCurrentIrpStackLocationToNext を呼び出して、その下位ドライバーの I/O スタックの場所を設定する必要があります。

    ドライバーが IoAllocateIrp を呼び出して下位ドライバーに 1 つ以上の追加 IRP を割り当てる場合、ディスパッチ ルーチンは、「中間レベル ドライバーでの IRP の処理」の説明にある手順に従い、その下位ドライバーの I/O スタックの場所を初期化する必要があります。

    そのディスパッチ ルーチンは、特定の要求に対して、次の下位ドライバーの I/O スタックの場所でパラメーターの一部を変更できます。 たとえば、基になるデバイスの転送容量に既知の制限がある場合、上位ドライバーは、IRP を再利用して基になるデバイス ドライバーに転送要求を部分的に送信できるように、大規模な転送要求のパラメーターを変更できます。

  2. IoSetCompletionRoutine を呼び出します。

    ディスパッチ ルーチンが受信した IRP を次の下位ドライバーに渡す場合、IoCompletion ルーチンの設定は任意ですが有用です。このようなタスクを、この要求を下位ドライバーがどのように完了したかを判断する処理、部分的な転送で IRP を再利用する処理、IRP を追跡している場合はドライバーが維持している状態を更新する処理、エラーが返された要求を再試行する処理で構成されているとして、このルーチンで実行できるからです。

    ディスパッチ ルーチンが新しい IRP を割り当てた場合は、IoCompletion ルーチンを設定する必要があります。下位のドライバーが要求を完了した後で該当の IRP を解放する必要があるからです。

    IoCompletion ルーチンの詳細については「IRP の完了」を参照してください。

  3. 下位ドライバーで処理する各 IRP を指定して IoCallDriver を呼び出します。

  4. 次のような適切な NTSTATUS 値を返します。

    • STATUS_PENDING

      入力 IRP が IRP_MJ_READIRP_MJ_WRITE などの非同期要求である場合、通常、ドライバーは STATUS_PENDING を返します。

    • IoCallDriver 呼び出しの結果

      入力 IRP が IRP_MJ_CREATE などの同期要求である場合、ドライバーは IoCallDriver 呼び出しの結果を頻繁に返します。

最下位のデバイス ドライバーは、ディスパッチ ルーチンで完了できない IRP を他のドライバー ルーチンへ受け渡し

  1. 入力 IRP を指定して IoMarkIrpPending を呼び出します。

  2. ドライバーによって管理される IRP キュー」の説明にあるようにドライバーが自身の内部 IRP キューを管理していない場合は、IoStartPacket を呼び出して IRP をドライバーの StartIo ルーチンに渡すかキューに置きます。

    StartIo ルーチンがないドライバーであっても、取り消し可能な IRP を扱っている場合、そのドライバーはキャンセル ルーチンを登録するか、キャンセルセーフな IRP キューを実装する必要があります。 キャンセル ルーチンの詳細については「IRP のキャンセル」を参照してください。

  3. STATUS_PENDING を返します。