Dispatching IRPs to I/O Queues
[Applies to KMDF and UMDF]
A framework-based driver can dynamically specify a target queue for an incoming IRP. To dispatch an IRP to a specific queue, a driver must call the WdfDeviceWdmDispatchIrpToIoQueue method.
Typically, a driver calls WdfDeviceWdmDispatchIrpToIoQueue from either its EvtDeviceWdmIrpPreprocess or EvtDeviceWdmIrpDispatch callback function. For best performance, most drivers do not provide both callback functions.
Note A UMDF driver can supply a EvtDeviceWdmIrpDispatch callback function, but only KMDF drivers can provide EvtDeviceWdmIrpPreprocess.
If your driver already provides EvtDeviceWdmIrpPreprocess, you can use it to dynamically select a queue. If not, provide EvtDeviceWdmIrpDispatch and call WdfDeviceWdmDispatchIrpToIoQueue from within that callback function.
In addition, you should be aware of the following:
An alternate method for dispatching an IRP to an I/O queue is to create a default queue and then from within the queue's handler, call WdfRequestForwardToIoQueue. This technique is available starting in KMDF 1.0 but does not work well with forward progress queues and is in general slower. Consider using WdfDeviceWdmDispatchIrpToIoQueue instead.
When calling WdfDeviceConfigureWdmIrpDispatchCallback to register a EvtDeviceWdmIrpDispatch callback function, the driver must set the MajorFunction parameter to one of the following: IRP_MJ_DEVICE_CONTROL, IRP_MJ_INTERNAL_DEVICE_CONTROL, IRP_MJ_READ, IRP_MJ_WRITE. While this requirement does not apply to EvtDeviceWdmIrpPreprocess, only IRPs of these types can be dynamically dispatched to specified queues.
IRPs that go to EvtDeviceWdmIrpPreprocess have an additional stack location. IRPs that go to EvtDeviceWdmIrpDispatch (without a previous invocation of EvtDeviceWdmIrpPreprocess) do not.
EvtDeviceWdmIrpPreprocess does not facilitate sending driver-defined context information, whereas EvtDeviceWdmIrpDispatch does.
Dispatching Non-Preprocessed IRPs
To dispatch IRPs from a driver's EvtDeviceWdmIrpDispatch callback function, use the following procedure:
From its EvtDriverDeviceAdd callback function, the driver calls WdfDeviceConfigureWdmIrpDispatchCallback to register a EvtDeviceWdmIrpDispatch callback function.
If the target is the parent device's I/O queue, a KMDF driver must call WdfPdoInitAllowForwardingRequestToParent before it calls WdfDeviceCreate. If a KMDF driver has also provided a EvtDeviceWdmIrpPreprocess callback function, the framework calls that function first when an IRP arrives. After the callback function preprocesses the request, it calls WdfDeviceWdmDispatchPreprocessedIrp to return the IRP to the framework.
The framework calls the driver's EvtDeviceWdmIrpDispatch callback function.
From within EvtDeviceWdmIrpDispatch, the driver can call either WdfDeviceWdmDispatchIrpToIoQueue or WdfDeviceWdmDispatchIrp, but not both. A KMDF driver has the additional option of calling neither of these methods, and instead completing the IRP or marking it pending.
If a KMDF driver has set the WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK flag and has not enabled guaranteed forward progress for the target I/O queue, the framework then calls the driver's EvtIoInCallerContext, if provided. After preprocessing the request, the callback function must either queue it by calling WdfDeviceEnqueueRequest or complete it by calling WdfRequestComplete.
Dispatching Preprocessed IRPs
To dispatch IRPs from a driver's EvtDeviceWdmIrpPreprocess callback function to a specific I/O queue, use the following procedure:
- The driver registers a EvtDeviceWdmIrpPreprocess callback function by calling WdfDeviceInitAssignWdmIrpPreprocessCallback.
- The driver calls WdfPdoInitAllowForwardingRequestToParent if the target is the parent device's I/O queue.
- From EvtDeviceWdmIrpPreprocess, call WdfDeviceWdmDispatchIrpToIoQueue with Flags set to WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP.
- If the driver has set the WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK flag and has not enabled guaranteed forward progress for the target I/O queue, the framework then calls the driver's EvtIoInCallerContext, if provided. After the callback function has finished preprocessing the request, it must either queue it by calling WdfDeviceEnqueueRequest or complete it by calling WdfRequestComplete.