将 IRP 调度到 I/O 队列
[适用于 KMDF 和 UMDF]
基于框架的驱动程序可以动态指定传入 IRP 的目标队列。 若要将 IRP 调度到特定队列,驱动程序必须调用 WdfDeviceWdmDispatchIrpToIoQueue 方法。
通常,驱动程序从其 EvtDeviceWdmIrpPrepPreprocess 或 EvtDeviceWdmIrpDispatch 回调函数调用 WdfDeviceWdmDispatchIrpToIoQueue。 为了获得最佳性能,大多数驱动程序不提供这两个回调函数。
注意 UMDF 驱动程序可以提供 EvtDeviceWdmIrpDispatch 回调函数,但只有 KMDF 驱动程序可以提供 EvtDeviceWdmIrpPreprocess。
如果驱动程序已提供 EvtDeviceWdmIrpPrepPreprocess,则可以使用它来动态选择队列。 如果没有,请提供 EvtDeviceWdmIrpDispatch ,并从该回调函数中调用 WdfDeviceWdmDispatchIrpToIoQueue 。
此外,还应注意以下事项:
将 IRP 调度到 I/O 队列的另一种方法是 创建默认队列 ,然后从队列的处理程序中调用 WdfRequestForwardToIoQueue。 此方法从 KMDF 1.0 开始可用,但不适用于 前进进度队列 ,并且通常速度较慢。 请考虑改用 WdfDeviceWdmDispatchIrpToIoQueue 。
调用 WdfDeviceConfigureWdmIrpDispatchCallback 以注册 EvtDeviceWdmIrpDispatch 回调函数时,驱动程序必须将 MajorFunction 参数设置为下列参数之一:IRP_MJ_DEVICE_CONTROL、IRP_MJ_INTERNAL_DEVICE_CONTROL、IRP_MJ_READ、IRP_MJ_WRITE。 虽然此要求不适用于 EvtDeviceWdmIrpPreprocess,但只能将这些类型的 IRP 动态调度到指定的队列。
转到 EvtDeviceWdmIrpPreprocess 的 IRP 具有额外的堆栈位置。 转到 EvtDeviceWdmIrpDispatch (且没有以前调用 EvtDeviceWdmIrpPreprocess) 的 IRP 不会。
EvtDeviceWdmIrpPreprocess 不便于发送驱动程序定义的上下文信息,而 EvtDeviceWdmIrpDispatch 则有助于发送。
调度未预处理的 IRP
若要从驱动程序的 EvtDeviceWdmIrpDispatch 回调函数调度 IRP,请使用以下过程:
从其 EvtDriverDeviceAdd 回调函数中,驱动程序调用 WdfDeviceConfigureWdmIrpDispatchCallback 来注册 EvtDeviceWdmIrpDispatch 回调函数。
如果目标是父设备的 I/O 队列,KMDF 驱动程序必须先调用 WdfPdoInitAllowForwardingRequestToParent ,然后才能调用 WdfDeviceCreate。 如果 KMDF 驱动程序还提供了 EvtDeviceWdmIrpPreprocess 回调函数,则框架会在 IRP 到达时首先调用该函数。 回调函数预处理请求后,它会调用 WdfDeviceWdmDispatchPreprocessedIrp 将 IRP 返回到框架。
框架调用驱动程序的 EvtDeviceWdmIrpDispatch 回调函数。
在 EvtDeviceWdmIrpDispatch 中,驱动程序可以调用 WdfDeviceWdmDispatchIrpToIoQueue 或 WdfDeviceWdmDispatchIrp,但不能同时调用两者。 KMDF 驱动程序具有其他选项,即不调用这两种方法,而是完成 IRP 或将其标记为挂起。
如果 KMDF 驱动程序已设置WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK标志,并且尚未为目标 I/O 队列启用有保证的向前进度,则框架会调用驱动程序的 EvtIoInCallerContext(如果提供)。 预处理请求后,回调函数必须通过调用 WdfDeviceEnqueueRequest 将其排队,或通过调用 WdfRequestComplete 完成该请求。
调度预处理的 IRP
若要将驱动程序的 EvtDeviceWdmIrpPreprocess 回调函数中的 IRP 调度到特定的 I/O 队列,请使用以下过程:
- 驱动程序通过调用 WdfDeviceInitAssignWdmIrpPreprocessCallback 来注册 EvtDeviceWdmIrpPreprocess 回调函数。
- 如果目标是父设备的 I/O 队列,驱动程序将调用 WdfPdoInitAllowForwardingRequestToParent 。
- 在 EvtDeviceWdmIrpPreprocess 中,调用 WdfDeviceWdmDispatchIrpToIoQueue , 标志 设置为 WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP。
- 如果驱动程序已设置WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK标志,并且尚未为目标 I/O 队列启用有保证的向前进度,则框架会调用驱动程序的 EvtIoInCallerContext(如果提供)。 回调函数完成对请求的预处理后,必须通过调用 WdfDeviceEnqueueRequest 将其 排队,或通过调用 WdfRequestComplete 完成该请求。