将 IRP 调度到 I/O 队列

[适用于 KMDF 和 UMDF]

基于框架的驱动程序可以动态指定传入 IRP 的目标队列。 若要将 IRP 调度到特定队列,驱动程序必须调用 WdfDeviceWdmDispatchIrpToIoQueue 方法。

通常,驱动程序从其 EvtDeviceWdmIrpPrepPreprocess 或 EvtDeviceWdmIrpDispatch 回调函数调用 WdfDeviceWdmDispatchIrpToIoQueue 为了获得最佳性能,大多数驱动程序不提供这两个回调函数。

注意 UMDF 驱动程序可以提供 EvtDeviceWdmIrpDispatch 回调函数,但只有 KMDF 驱动程序可以提供 EvtDeviceWdmIrpPreprocess

如果驱动程序已提供 EvtDeviceWdmIrpPrepPreprocess,则可以使用它来动态选择队列。 如果没有,请提供 EvtDeviceWdmIrpDispatch ,并从该回调函数中调用 WdfDeviceWdmDispatchIrpToIoQueue

此外,还应注意以下事项:

调度未预处理的 IRP

若要从驱动程序的 EvtDeviceWdmIrpDispatch 回调函数调度 IRP,请使用以下过程:

  1. 从其 EvtDriverDeviceAdd 回调函数中,驱动程序调用 WdfDeviceConfigureWdmIrpDispatchCallback 来注册 EvtDeviceWdmIrpDispatch 回调函数。

    如果目标是父设备的 I/O 队列,KMDF 驱动程序必须先调用 WdfPdoInitAllowForwardingRequestToParent ,然后才能调用 WdfDeviceCreate。 如果 KMDF 驱动程序还提供了 EvtDeviceWdmIrpPreprocess 回调函数,则框架会在 IRP 到达时首先调用该函数。 回调函数预处理请求后,它会调用 WdfDeviceWdmDispatchPreprocessedIrp 将 IRP 返回到框架。

  2. 框架调用驱动程序的 EvtDeviceWdmIrpDispatch 回调函数。

  3. EvtDeviceWdmIrpDispatch 中,驱动程序可以调用 WdfDeviceWdmDispatchIrpToIoQueueWdfDeviceWdmDispatchIrp,但不能同时调用两者。 KMDF 驱动程序具有其他选项,即不调用这两种方法,而是完成 IRP 或将其标记为挂起。

  4. 如果 KMDF 驱动程序已设置WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK标志,并且尚未为目标 I/O 队列启用有保证的向前进度,则框架会调用驱动程序的 EvtIoInCallerContext(如果提供)。 预处理请求后,回调函数必须通过调用 WdfDeviceEnqueueRequest 将其排队,或通过调用 WdfRequestComplete 完成该请求。

调度预处理的 IRP

若要将驱动程序的 EvtDeviceWdmIrpPreprocess 回调函数中的 IRP 调度到特定的 I/O 队列,请使用以下过程:

  1. 驱动程序通过调用 WdfDeviceInitAssignWdmIrpPreprocessCallback 来注册 EvtDeviceWdmIrpPreprocess 回调函数。
  2. 如果目标是父设备的 I/O 队列,驱动程序将调用 WdfPdoInitAllowForwardingRequestToParent
  3. EvtDeviceWdmIrpPreprocess 中,调用 WdfDeviceWdmDispatchIrpToIoQueue标志 设置为 WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP。
  4. 如果驱动程序已设置WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK标志,并且尚未为目标 I/O 队列启用有保证的向前进度,则框架会调用驱动程序的 EvtIoInCallerContext(如果提供)。 回调函数完成对请求的预处理后,必须通过调用 WdfDeviceEnqueueRequest 将其 排队,或通过调用 WdfRequestComplete 完成该请求。