向驱动程序堆栈的下层传递 IRP

当驱动程序的调度例程收到 IRP 时,它必须调用 IoGetCurrentIrpStackLocation,以便它可以检查自己的 I/O 堆栈位置,并确定任何参数都有效。 如果驱动程序无法满足并完成请求本身,它可以执行以下操作之一:

  • 传递 IRP,供较低级别的驱动程序进一步处理。

  • 创建一个或多个新 IRP,并将其向下传递给较低级别的驱动程序。

较高级别的驱动程序应将 I/O 请求传递到下一个较低级别的驱动程序,如下所示:

  1. 如果驱动程序将输入 IRP 传递到下一个较低级别的驱动程序,则调度例程应调用 IoSkipCurrentIrpStackLocationIoCopyCurrentIrpStackLocationToNext 来设置下一个较低级别的驱动程序的 I/O 堆栈位置。

    如果驱动程序调用 IoAllocateIrp 为较低级别的驱动程序分配一个或多个额外的 IRP,则调度例程必须按照 在 Intermediate-Level 驱动程序中处理 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_READ 或IRP_MJ_WRITE),驱动程序通常会返回 STATUS_PENDING

    • 调用 IoCallDriver 的结果

      如果输入 IRP 是同步请求(例如IRP_MJ_CREATE),驱动程序通常会返回对 IoCallDriver 的调用结果。

最低级别的设备驱动程序将在其调度例程中无法完成的任何 IRP 传递给其他驱动程序例程,如下所示:

  1. 使用输入 IRP 调用 IoMarkIrpPending

  2. 调用 IoStartPacket 将 IRP 传递到驱动程序的 StartIo 例程或排队,除非驱动程序管理自己的内部 IRP 队列,如 驱动程序管理的 IRP 队列中所述。

    如果驱动程序没有 StartIo 例程,但处理可取消的 IRP,则必须注册 取消 例程或实现 取消安全 IRP 队列。 有关 取消 例程的详细信息,请参阅 取消 IRP

  3. 返回STATUS_PENDING。