Completing I/O Requests
Every framework-based driver must eventually complete every I/O request that it receives from the framework. Drivers complete requests by calling the request object's WdfRequestComplete, WdfRequestCompleteWithInformation, or WdfRequestCompleteWithPriorityBoost method.
When to Complete a Request
A driver must complete a request when it determines that one of the following cases is true:
-
The requested I/O operation has finished successfully.
-
The requested I/O operation was started but failed before it finished.
-
The requested I/O operation is not supported, or was not valid at the time it was received, and could not be started.
-
The requested I/O operation was canceled.
If the driver services the I/O request by creating I/O activity on the device, the driver typically calls WdfRequestComplete from its EvtInterruptDpc or EvtDpcFunc callback function.
If the driver receives an unsupported or otherwise invalid request, it typically calls WdfRequestComplete from the request handler that received the request.
If the I/O operation was canceled, the driver typically calls WdfRequestComplete from its EvtRequestCancel callback function.
If the driver forwards the I/O request to an I/O target, the driver completes the request after the I/O target completes the request, as follows:
-
If your driver forwards the I/O request synchronously to the I/O target, the driver's call to the I/O target returns only after a lower-level driver has completed the request (unless an error occurs). After the I/O target returns, your driver must call WdfRequestComplete.
-
If your driver forwards the I/O request asynchronously, you will want your driver to be notified when a lower-level driver completes the request. If your driver registers a CompletionRoutine callback function, the framework calls this callback function after the I/O target completes the request. The CompletionRoutine callback function typically calls WdfRequestComplete.
To register a CompletionRoutine callback function, the driver must call WdfRequestSetCompletionRoutine before it forwards the I/O request to an I/O target.
If your driver does not need to be notified when an I/O target completes an asynchronously forwarded I/O request, the driver does not have to register a CompletionRoutine callback function. Instead, the driver can set the WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag when calling WdfRequestSend. In this case the driver does not call WdfRequestComplete.
A driver does not complete an I/O request that it has created by calling WdfRequestCreate or WdfRequestCreateFromIrp. Instead, the driver must call WdfObjectDelete to delete the request object, typically after an I/O target has completed the request.
For example, a driver might receive a read or write request for an amount of data that is larger than the driver's I/O targets can handle at one time. The driver must divide the data into several smaller requests and send these smaller requests to one or more I/O targets. Techniques for handling this situation include:
-
Calling WdfRequestCreate to create a single additional request object that represents a smaller request.
The driver can send this request synchronously to an I/O target. The smaller request's CompletionRoutine callback function can call WdfRequestReuse so that the driver can reuse the request and send it to the I/O target again. After the I/O target completes the last of the smaller requests, the CompletionRoutine callback function can call WdfObjectDelete to delete the driver-created request object and the driver can call WdfRequestComplete to complete the original request.
-
Calling WdfRequestCreate to create several additional request objects that represent the smaller requests.
The driver's I/O targets can process these multiple smaller requests asynchronously. The driver can register a CompletionRoutine callback function for each of the smaller requests. Each time that the CompletionRoutine callback function is called, it can call WdfObjectDelete to delete a driver-created request object. After the I/O target completes all of the smaller requests, the driver can call WdfRequestComplete to complete the original request.
Providing Completion Information
When a driver completes a request, it can optionally provide some additional information that other drivers can access. For example, a driver might provide the number of bytes that were transferred for a read or write request. To provide this information, the driver can do either of the following:
-
Call WdfRequestSetInformation before calling WdfRequestComplete.
Obtaining Completion Information
To obtain information about an I/O request that another driver has completed, a driver can:
-
Call WdfRequestGetStatus to obtain the completion status value that the lower-level driver specified when it called WdfRequestComplete.
-
Call WdfRequestGetCompletionParams to obtain a WDF_REQUEST_COMPLETION_PARAMS structure that contains additional information about the completed request, such as handles to memory objects that represent the request's buffers, or bus-specific information.
A driver can call WdfRequestGetCompletionParams only after it calls WdfRequestSend to send the I/O request synchronously or asynchronously to an I/O target. The driver must not call WdfRequestGetCompletionParams after it calls one of the methods that send I/O requests to I/O targets only synchronously (such as WdfIoTargetSendReadSynchronously).
-
Call WdfRequestGetInformation to obtain additional I/O completion information that the lower-level driver specified when it called WdfRequestSetInformation or WdfRequestCompleteWithInformation, if drivers in the driver stack provide such information.
If a driver sends an I/O request synchronously, it typically calls WdfRequestGetStatus, WdfRequestGetCompletionParams, and WdfRequestGetInformation after the synchronous call returns. If a driver sends an I/O request asynchronously, it typically calls these methods from within a CompletionRoutine callback function.
For more information about completing I/O requests, see Synchronizing Cancel and Completion Code.