IO Request Formatting


I/O Request Formatting

Before your driver can send an I/O request, it usually must format the request. Formatting prepares the underlying IRP for delivery to an I/O target by setting up the I/O stack locations and filling in any other required information, such as an I/O request completion callback.

When to Format a Request

A driver must format the request in the following situations:

  • The driver changes the format of a request it receives from the framework and then sends the request to an I/O target.

    "Changing the format of a request" means making any modification to the parameters that the driver received in the request. Common examples include changing a buffer offset or modifying the length or content of the data.

  • The driver sends a driver-created I/O request to an I/O target.

  • The driver sets an I/O completion callback for the request.

Essentially, a driver must format every request except for requests that the driver receives from the framework and subsequently sends to the default I/O target unchanged and without an I/O completion callback. Such requests can be sent as described in "Send and Forget Option" later in this chapter.

How to Format a Request

A driver formats a request by calling WDF formatting methods. The frameworks provide methods that:

  • Format an unchanged request for the default I/O target.

  • Format a driver-created request or reformat a framework-presented request.

  • Format and send synchronous requests. (KMDF only)

If a driver formats an I/O request, it must also set a completion callback for the request.

How to Format an Unchanged Request for the Default I/O Target

If the driver sets an I/O completion callback, the driver must format the request before sending it to the default I/O target even if the driver does not change any of the parameters in the request. To format such a request, a driver uses a formatting method that is implemented on the WDF request object:

  • A UMDF driver calls IWDFRequest::FormatUsingCurrentType.

  • A KMDF driver calls WdfRequestFormatRequestUsingCurrentType.

These two methods take an existing WDF I/O request object and set up the I/O stack location in the underlying IRP for the next lower driver without changing the IRP in any other way. These methods are the WDF equivalent of IoCopyCurrentIrpStackLocationToNext, which WDM drivers use when sending IRPs.

If the driver does not require a callback when the request has completed, the driver is not required to format the request.

How to Format Changed or Driver-Created Requests

If your driver creates the I/O request object or changes the format of an I/O request object that the driver receives from the framework, the driver must format the request by using a formatting method on the I/O target object.

UMDF Formatting Methods for I/O Requests

 UMDF  UMDF drivers call the following formatting methods on the framework I/O target object:

  • IWDFIoTarget::FormatRequestForIoctl

    Formats a device I/O control request for any I/O target.

  • IWDFIoTarget::FormatRequestForRead

    Formats a read request for any I/O target.

  • IWDFIoTarget::FormatRequestForWrite

    Formats a write request for any I/O target.

KMDF Formatting Methods for I/O Requests

 KMDF  KMDF drivers use the following formatting methods:

  • WdfIoTargetFormatRequestForInternalIoctl

    Formats an internal device I/O control request for any I/O target.

  • WdfIoTargetFormatRequestForInternalIoctlOthers

    Formats an internal device I/O control request that requires nonstandard parameters for any I/O target.

  • WdfIoTargetFormatRequestForIoctl

    Formats a device I/O control request for any I/O target.

  • WdfIoTargetFormatRequestForRead

    Formats a read request for any I/O target.

  • WdfIoTargetFormatRequestForWrite

    Formats a write request for any I/O target.

KMDF also provides methods that format and send synchronous I/O requests in a single call. See "How to Send an I/O Request" later in this chapter for more information.

Parameters for the Formatting Methods

The KMDF and UMDF methods that are implemented on the I/O target objects take one or more of the following parameters, depending on the type of request:

Request

Identifies the I/O request object to format; required for all requests.

IoctlCode

Specifies the I/O control code; used only for device I/O control requests.

InputMemory

Identifies the WDF memory object that provides the input buffer; used for write and IOCTL requests.

InputMemoryOffset

Points to a WDFMEMORY_OFFSET structure that supplies an offset into the input buffer and a length; used for write and IOCTL requests.

OutputMemory

Identifies the WDF memory object that provides the output buffer; used for read and IOCTL requests.

OutputMemoryOffset

Points to a WDFMEMORY_OFFSET structure that supplies an offset into the output buffer and a length; used for read and IOCTL requests.

DeviceOffset

Specifies an offset into the device at which to start the transfer; used only for read and write requests.

 KMDF  The KMDF methods also require a handle to the I/O target to which the request will be sent. The UMDF methods require no such information because they are implemented on the I/O target object.

UMDF Example: Format a Write Request

Listing 9-7 shows how a UMDF driver formats a write request. This example is based on code in the Queue.cpp file in the Usb\Echo_driver sample.

Listing 9-7: Formatting a write request in a UMDF driver

image from book
 STDMETHODIMP_ (void) CMyQueue::OnWrite(         /* [in] */ IWDFIoQueue *pWdfQueue,         /* [in] */ IWDFIoRequest *pWdfRequest,         /* [in] */ SIZE_T BytesToWrite          ) {     HRESULT hr = S_OK;     IWDFMemory * pInputMemory = NULL;     IWDFUsbTargetPipe * pOutputPipe = m_Parent->GetOutputPipe();     pWdfRequest->GetInputMemory(&pInputMemory);     hr = pOutputPipe->FormatRequestForWrite( pWdfRequest,                                              NULL, //pFile                                              pInputMemory,                                              NULL, //Memory offset                                              NULL  //DeviceOffset);     if (FAILED(hr)) {         pWdfRequest->Complete(hr);     } else {         ForwardFormattedRequest(pWdfRequest, pOutputPipe);     }     SAFE_RELEASE(pInputMemory);     return; } 
image from book

The sample code shows the IQueueCallbackWrite::OnWrite method on the Echo_driver's I/O queue. The framework calls this method with pointers to the IWDFQueue interface on the queue object and the IWDFIoRequest interface on the request object. The driver retrieves the WDF memory object from the incoming request object and passes it to the FormatRequestForWrite method on a USB target pipe to format the write request for the I/O target.

KMDF Example: Format a Read Request

Listing 9-8 shows how a KMDF driver formats a read request. The example is based on code in the Toastmon.c file in the Toastmon sample.

Listing 9-8: Formatting a read request in a KMDF driver

image from book
 status = WdfMemoryCreate( &attributes,                           NonPagedPool,                           DRIVER_TAG,                           READ_BUF_SIZE,                           &memory,                           NULL); // buffer pointer if (!NT_SUCCESS(status)) {     return status; } status = WdfIoTargetFormatRequestForRead( IoTarget,                                           request,                                           memory,                                           NULL, // Output buffer offset                                           NULL); // Device offset 
image from book

By the time the code in Listing 9-8 runs, the sample driver has already created both the I/O request object and the I/O target object and has initialized an object attributes structure. The listing shows how the driver creates a WDF memory object for the read request's output buffer and then formats the request to use this object.

First, the driver creates a WDF memory object by calling WdfMemoryCreate. The memory object uses a buffer that is READ_BUF_SIZE bytes long and is allocated from the nonpaged pool. To format the request, the driver calls WdfIoTargetFormatRequestForRead, passing the handles to the I/O target object, the I/O request object, and the memory object. The driver specifies NULL for both the output buffer offset and the device offset.

I/O Completion Callbacks

By default, WDF sends I/O requests asynchronously. Typically a driver sets an I/O completion callback to be notified when an asynchronous request is complete. The framework invokes the callback after the I/O completion callbacks of all lower drivers in the stack have run.

A driver should set an I/O completion callback for every asynchronous request, unless the driver sets the send-and-forget flag as described in "Send and Forget Option" later in this chapter.

  • A UMDF driver calls IWDFIoRequest::SetCompletionCallback and passes a pointer to the IRequestCallbackRequestCompletion interface for the request callback object along with a pointer to a driver-defined context area.

  • A KMDF driver calls WdfRequestSetCompletionRoutine and passes a pointer to a CompletionRoutine and a pointer to a driver-defined context area.

Processing in the I/O Completion Callback

In the I/O completion callback, the driver does any additional processing that it requires for the completed request. Such processing involves checking the completion status of the request and retrieving any data that it requires from the I/O buffers in the request.

If the driver created the request, the driver must not complete the request in the completion callback. The request has already "unwound" all the way back to the driver.

If the driver sent to an I/O target a request that the framework previously delivered, the driver must call the framework to complete the request either during its I/O completion callback or sometime afterward. The easiest way to think about this is that requests start and end at the same layer in the device stack. If your driver receives a request, your driver can complete that request because it came from a higher layer. A driver should never complete a request that it created, because the request did not come from a higher layer.

If the driver created the I/O request object and has finished using it and any child memory objects, the driver can delete the I/O request object. However, if the driver sets the parent appropriately, the driver can avoid explicitly deleting the I/O request object.

 KMDF  A KMDF driver can reuse the I/O request objects that it created instead of deleting them. After a KMDF driver retrieves all of the status information and I/O results from the request, it can prepare the request object for reuse, as described in "How to Reuse an I/O Request Object in a KMDF Driver" later in this chapter.

 Parameters for I/ O completion callbacks  Both UMDF and KMDF completion callbacks have the following four parameters:

Request

UMDF value: Pointer to the IWDFIoRequest interface for the completed I/O request.

KMDF value: Handle to the completed WDFREQUEST object.

Target

UMDF value: Pointer to the IWDFIoTarget interface for the I/O target.

KMDF value: Handle to the WDFIOTARGET object.

Params

UMDF value: Pointer to the IWDFRequestCompletionParams interface for the completed I/O request parameters.

KMDF value: Pointer to a WDF_REQUEST_COMPLETION_PARAMS structure that contains the completion parameters for the request.

Context

Both: Pointer to a driver-defined context area that the driver supplied when it registered the callback.

The Context parameter can contain a pointer to any information that the driver might need when it completes the request. Consider using the Context parameter instead of the I/O request object's context area if the information has a different lifetime from the I/O request object or is shared between the request and another object.

image from book
When to Complete a Request in a WDF Driver

If you're familiar with WDM drivers, the WDF requirement to complete framework-delivered I/O requests in the I/O completion callback probably surprises you. Remember, however, that the framework sets its own completion routine that regains ownership of the IRP on behalf of the driver-the equivalent of returning STATUS_MORE_PROCESSING_REQUIRED in a WDM driver. The WDF driver calls a framework request-completion method to indicate that the driver has completed processing the WDF request, so the framework can continue completion of the IRP.

image from book

Retrieving Completion Status and Information

To get the completion status and number of transferred bytes, a driver uses the information in the Params parameter as follows:

  •  UMDF  A UMDF driver calls methods on the IWDFRequestCompletionParams interface on the I/O request object to get the completion status and number of transferred bytes.

    The framework passes a pointer to this interface as an input parameter to the I/O completion callback. The driver can query the interface for a pointer to the IWDFIoRequestCompletionParams interface, which supports methods that return the buffers for read, write, and device I/O control requests. These two interfaces are organized hierarchically, so IWDFIoRequestCompletionParams derives from IWDFRequestCompletionParams.

  •  KMDF  A KMDF driver uses the pointer to the WDF_REQUEST_COMPLETION_PARAMS structure or calls WdfRequestGetCompletionParams to get a pointer to the structure.

    This structure contains all of the parameters to the request.

The completion parameters are valid until the request has been completed by the current driver, deleted, reused, or reformatted. After any of those actions have occurred, the pointer is no longer valid.

Tip 

You might wonder how request completion parameters-sent as a parameter to your I/O completion callback-differ from request parameters. Request parameters represent the parameters that came to your driver with the request, and the completion parameters represent the parameters that your driver sent with the request to the I/O target. In fact, if you do not make any changes to the request, completion parameters are not available. In this case, the request parameters serve as the completion parameters as well.




Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net