Dispatching IRPs to I/O Queues
[Applies to KMDF only]
Starting with KMDF 1.11, 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.
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.
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, the driver must call WdfPdoInitAllowForwardingRequestToParent before it calls WdfDeviceCreate.
- If the 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. Alternatively, the driver can call neither of these methods, opting instead to complete the IRP or mark it pending.
- If the driver has set the WDF_FORWARD_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.
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_FORWARD_IRP_TO_IO_QUEUE_PREPROCESSED_IRP.
- If the driver has set the WDF_FORWARD_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.