IO Target Creation and Management


I/O Target Creation and Management

To get access to the default I/O target, a driver simply calls a framework method on the device object. Before a driver can use a remote I/O target, however, it must create and open a WDF object that represents the I/O target object and associate that I/O target object with a device object.

Default I/O Target Retrieval

The framework creates and opens the default I/O target object when the framework creates the device object.

 UMDF  A UMDF driver can access the default I/O target through the IWDFIoTarget interface; it gets a pointer to this interface by calling the IWDFDevice::GetDefaultIoTarget method.

 KMDF  A KMDF driver gets a handle to the default I/O target by calling the WdfDeviceGetIoTarget method, passing the handle to the device object.

Remote I/O Target Creation in KMDF Drivers

Before a KMDF driver can send an I/O request to a remote I/O target, the driver must create and open the I/O target.

To create a remote I/O target, the driver calls WdfIoTargetCreate. This method takes three parameters: a handle to the device object that will send I/O requests to the target, an optional pointer to a WDF_OBJECT_ATTRIBUTES structure, and a location in which the framework returns a handle to the created I/O target object. By default, the I/O target object is a child of the specified device object.

When the I/O target object is created, it is not associated with a particular I/O target. The driver must call WdfIoTargetOpen to associate the object with another device object, device stack, or file. The input parameters to WdfIoTargetOpen are the handle to the I/O target object and a pointer to a WDF_IO_TARGET_OPEN_PARAMS structure, which supplies numerous parameters for the I/O target.

A driver can later close the I/O target and use the WDFIOTARGET object with a different target by calling WdfIoTargetOpen again with different values in the WDF_IO_TARGET_ OPEN_PARAMS structure.

Initialization Functions for the I/O Target Parameters Structure

The I/O target parameters structure provides information that the framework requires to open the I/O target, such as the name of the target device and the callbacks that your driver implements for certain I/O target events.

KMDF includes several WDF_IO_TARGET_OPEN_PARAMS_INIT_XXX initialization functions that fill in various fields of the target parameters structure, depending on the type of object to open. Choose one of the following initialization functions, based on how your driver opens the target:

If your driver

Use

Identifies the target by the name of the device, device interface, or file, and you want the framework to create a new file

The CREATE_BY_NAME version of the initialization function, and supply an access mask in the Desired-Access parameter that specifies the access rights that your driver requires.

Identifies the target by name, and you want the framework to fail the open request if the specified target does not exist

The OPEN_BY_NAME version of the initialization function, and supply an access mask in the Desired-Access parameter that specifies the access rights that your driver requires.

Supplies a pointer to a WDM DEVICE_OBJECT

The EXISTING_DEVICE version of the initialization function. By using this initialization function, a driver that has a pointer to a WDM device object for another device stack can use that stack as a remote I/O target.

The initialization functions fill in the fields of the structure that specify whether to open the target by name or by device object, a name or device object pointer that identifies the target, and the access rights that the driver requires. The CREATE_BY_NAME version is the most common way to open a remote I/O target.

Depending on the specific version, the WDF_IO_TARGET_OPEN_PARAMS_INIT_XXX initialization function requires one or more of the following parameters:

  • I/O Target Name or Device Object Pointer

    To identify the I/O target, the driver supplies either a Unicode string or a device object pointer.

    The Unicode string represents a Windows object name, which uniquely specifies a device, a file, a symbolic link name, or a device interface. If your driver uses the OPEN_BY_NAME version of the initialization function, the call to WdfIoTargetOpen fails if the target device object or interface does not exist.

     Tip  See "Object Names" in the WDK for more information-online at http://go.microsoft.com/fwlink/?LinkId=80615.

  • Desired Access

    The WDK defines several constants that describe common sets of access rights. Access rights are enforced on file system device stacks but are not relevant for many drivers.

    The following are the most commonly used access rights for an I/O target object:

    • STANDARD_RIGHTS_READ provides read access to the target.

    • STANDARD_RIGHTS_WRITE provides write access to the target.

    • STANDARD_RIGHTS_ALL provides read, write, and delete access to the target.

     Tip  See "ACCESS_MASK" in the WDK for a complete list of possible access rights-online at http://go.microsoft.com/fwlink/?LinkId=80616.

For most I/O targets, the WDF_IO_TARGET_OPEN_PARAMS_INIT_XXX initialization function fills in all of the fields that the driver requires, other than the event callback pointers. The driver must separately fill in the callback pointers. Table 9-1 lists all of the possible fields of the I/O target parameters structure.

Table 9-1: Fields in the WDF_IO_TARGET_OPEN_PARAMS Structure
Open table as spreadsheet

Field name

Description

Type

One of the following values of the WDF_IO_TARGET_OPEN_TYPE enumeration:

WdfIoTargetOpenUseExistingDevice

WdfIoTargetOpenByName

WdfIoTargetOpenReopen

Filled in for the driver by the initialization functions.

EvtIoTargetQueryRemove

Pointer to the EvtIoTargetQueryRemove callback.

EvtIoTargetRemoveCanceled

Pointer to the EvtIoTargetRemoveCanceled callback.

EvtIoTargetRemoveComplete

Pointer to the EvtIoTargetRemoveComplete callback.

TargetDeviceObject

Pointer to a WDM DEVICE_OBJECT; filled in as required by the initialization function;

required for EXISTING_DEVICE version.

TargetFileObject

Pointer to a FILE_OBJECT;

used only for WdfIoTargetOpenUseExistingDevice.

TargetDeviceName

Unicode string that identifies the I/O target by name;

filled in as required by the initialization function;

required for OPEN_BY_NAME version.

DesiredAccess

Value of type ACCESS_MASK;

filled in as required by the initialization function.

ShareAccess

A bit mask that contains zero or more of the following flags:

FILE_SHARE_READ,

FILE_SHARE_WRITE, or

FILE_SHARE_DELETE.

FileAttributes

A bit mask of FILE_ATTRIBUTE_Xxxx flags, typically FILE_ATTRIBUTE_NORMAL;

filled in as required by the initialization functions.

CreateDisposition

Constant that defines system actions for file creation.

CreateOptions

A bit mask of file option flags;

filled in as required by the initialization functions.

EaBuffer

An extended attributes buffer for file creation.

EaBufferLength

Length of the extended attributes buffer.

AllocationSize

Initial size to allocate if the target is a file.

FileInformation

Status information returned if WdfIoTargetOpen creates a file.

If the target is a file and the driver opens it by name, the driver can also fill in fields that commonly apply to file creation, such as FileAttributes and CreateOptions. Most drivers, however, do not supply values for these fields because the initialization function fills in the appropriate values on the driver's behalf. These fields rarely apply if the target is not a file.

 Tip  See ZwCreateFile in the WDK for details about the file creation options-online at http://go.microsoft.com/fwlink/?LinkId=80617.

KMDF Example: Create and Open a Remote I/O Target

Listing 9-1 shows how the Toastmon sample creates and opens a remote I/O target. This driver creates an I/O target for each Toaster device in the system. The sample code is from the Toastmon.c file.

Listing 9-1: Creating and opening a remote I/O target in a KMDF driver

image from book
 NTSTATUS Toastmon_OpenDevice(     WDFDEVICE Device,     PUNICODE_STRING SymbolicLink,     WDFIOTARGET *Target     ) {     NTSTATUS                    status = STATUS_SUCCESS;     WDF_IO_TARGET_OPEN_PARAMS   openParams;     WDFIOTARGET                 ioTarget;     WDF_OBJECT_ATTRIBUTES       attributes;     // [1]     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TARGET_DEVICE_INFO);     // [2]     status = WdfIoTargetCreate(deviceExtension->WdfDevice, &attributes, &ioTarget);     if (!NT_SUCCESS(status)) {         return status;     }     . . .  //Code to set up timers omitted     // [3]     WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&openParams,                                                 SymbolicLink,                                                 STANDARD_RIGHTS_ALL);     // [4]     openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ;     // [5]     openParams.EvtIoTargetQueryRemove = ToastMon_EvtIoTargetQueryRemove;     openParams.EvtIoTargetRemoveCanceled = ToastMon_EvtIoTargetRemoveCanceled;     openParams.EvtIoTargetRemoveComplete = ToastMon_EvtIoTargetRemoveComplete;     // [6]     status = WdfIoTargetOpen(ioTarget, &openParams);     if (!NT_SUCCESS(status)) {         WdfObjectDelete(ioTarget);         return status;     }     . . .  //More code omitted     return status; } 
image from book

In Listing 9-1 the driver creates a context area for the I/O target object, creates the I/O target object, and opens the target by name. It also creates a timer that periodically sends I/O requests to the target device. Listing 9-1 does not show the code that creates the timer or sends the I/O requests. The following explanation is keyed to the numbers in the listing.

  1. To initialize the context area and the object attributes for the I/O target object, the driver calls WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE with a pointer to an WDF_OBJECT_ATTRIBUTES structure and the context type. The context type is defined in the Toastmon.h header file.

  2. The driver creates the I/O target object by calling WdfIoTargetCreate. This method takes as input a handle to the device object and a pointer to the initialized attributes structure, and returns a handle to the newly created I/O target object.

  3. The driver initializes a WDF_IO_TARGET_OPEN_PARAMS structure with information that describes how the framework should open the target. The WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME function fills in the required information. The driver passes to the function a pointer to the WDF_IO_TARGET_OPEN_PARAMS structure, the name of the device to open, and the constant STANDARD_RIGHTS_ALL, which specifies read, write, and delete access.

  4. The driver sets up the ShareAccess field of the WDF_IO_TARGET_OPEN_PARAMS structure and registers callback functions for the I/O target object. The ShareAccess field indicates whether the driver requires exclusive access to the target. The driver can share read and write access, so it supplies the union of these two values.

  5. The sample driver registers callback functions for the EvtIoTargetQueryRemove, EvtIoTargetRemoveCanceled, and EvtIoTargetRemoveComplete events. These callbacks enable the driver to perform special processing when the device is removed, when it is about to be removed, and when removal is canceled. The sample driver uses its timer to periodically send a request to the I/O target. If the target is removed or query-removed, the driver shuts off the timer, and if removal is canceled, the driver restarts the timer.

    By default, the framework stops the I/O target when the device is removed or query-removed and restarts the target if removal is canceled. The defaults provide all of the processing that many drivers require. A driver can implement callbacks to override these defaults; if the driver does so, the framework does not perform any of the default tasks and the driver must implement all of the code itself.

  6. The driver opens the object by calling WdfIoTargetOpen with the handle of the I/O target and a pointer to the configuration structure.

I/O Target State Management

A big advantage of I/O targets over simple device object pointers is the driver's ability to query and manage the state of the target. The I/O target object tracks queued and sent requests and can cancel them if changes occur in the state of either the target device or the WDF driver that sent the request.

If the I/O target is in a stopped state when a driver sends a request, the framework can queue the request for processing after the target returns to the working state. From the driver's perspective, the I/O target object behaves like a cancel-safe queue that retains sent requests until the framework can deliver them. The framework does not free the I/O target object until all of the I/O requests that have been sent to the target are complete.

Table 9-2 describes the possible states of an I/O target.

Table 9-2: I/O Target States
Open table as spreadsheet

State

Description

Started

The I/O target is operating and can process I/O requests.

Stopped

The I/O target has been stopped.

Stopped for query-remove

The I/O target has been stopped temporarily because removal of its device is pending. If the device is eventually removed, the target enters the Deleted state. If the device is not removed, the target typically returns to the Started state.

Closed

A remote I/O target has been closed because the driver called a close method.

Deleted

The I/O target's device has been removed. The framework cancels all I/O requests that have been queued for the I/O target.

By default, the frameworks send I/O requests only when the I/O target is in the Started state. However, a driver can also specify that the framework ignore the state of the target and send the request even if the target is in the Stopped state.

Methods for Managing I/O Target State

WDF provides methods that a driver can call to start and stop the I/O target, close or remove it if the target device is removed, and remove the target synchronously and query its current state:

  • UMDF drivers call methods in the IWDFIoTargetStateManagement interface, which is implemented on the I/O target object.

  • KMDF drivers call WdfIoTargetXxx methods.

Table 9-3 summarizes the methods that a driver can call to manage the state of an I/O target. KMDF supports additional methods for formatting and sending requests to I/O targets and for querying the properties of remote I/O targets.

Table 9-3: Methods to Manage I/O Target State
Open table as spreadsheet

Task

UMDF IWDFIoTargetState-Management method

KMDF method

Return the current state of the I/O target.

GetState

WdfIoTargetGetState

Open a remote I/O target.

None

WdfIoTargetOpen

Close a remote target.

None

WdfIoTargetClose

Remove an I/O target object.

Remove

None

Start sending requests to an I/O target object.

Start

WdfIoTargetStart

Stop sending I/O requests to an I/O target.

Stop

WdfIoTargetStop

Close an I/O target temporarily during a query-remove operation.

None

WdfIoTargetCloseForQuery-Remove

I/O Target Callbacks for KMDF Drivers

By default, if the device that is associated with a remote I/O target is removed, KMDF stops and closes the I/O target object but does not notify the driver. However, a driver can register one or more event callback functions so that it can receive notification when a remote I/O target is stopped, stopped for query-remove, or removed.

If the driver must perform any special processing of I/O requests that it sent to the I/O target, it should register one or more of the EvtIoTargetXxx callbacks, as described in Table 9-4. When the removal of the target device is queried, canceled, or completed, KMDF calls the corresponding callback function and then processes the target state changes. A driver can fail a query-remove request by implementing EvtIoTargetQueryRemove and returning a failure status.

Table 9-4: I/O Target Event Callbacks
Open table as spreadsheet

Callback

Description

EvtIoTargetQueryRemove

Called when removal of the I/O target device is queried. To allow the removal, the function must call WdfIoTargetCloseForQueryRemove and return STATUS_SUCCESS. To veto the removal, the function must return a failure status such as STATUS_UNSUCCESSFUL or STATUS_INVALID_DEVICE_REQUEST.

EvtIoTargetRemoveCanceled

Called after a query-remove operation for the target device has been canceled. This function should reopen the I/O target that EvtIoTargetQueryRemove temporarily stopped by calling WdfIoTargetOpen with the WDF_IO_TARGET_OPEN_TYPE WdfIoTargetOpenReopen. This function should always return STATUS_SUCCESS.

EvtIoTargetRemoveComplete

Called when I/O target device removal is complete. This function should always return STATUS_SUCCESS.

For default I/O targets, no such callbacks are defined. The WDF driver and the target device are in the same device stack, so the driver is notified of device-removal requests through its Plug and Play and power management callbacks.

When an I/O target is deleted, KMDF by default cancels all I/O requests that have been sent to the target and waits for all the requests to complete before it deletes the I/O target object. If the default behavior is not appropriate, a driver can provide custom cleanup by registering an EvtObjectCleanup callback for the I/O target object. Before the framework performs its own cleanup processing, it invokes the cleanup callback. For example, some drivers might block new requests and wait for the pending I/O to complete instead of allowing the framework to cancel them. In this case, EvtObjectCleanup would call WdfIoTargetStop with the stop action WdfIoTargetWaitForSentIoToComplete.

KMDF Example: EvtIoTargetQueryRemove Callback

Listing 9-2 shows the Toastmon driver's EvtIoTargetQueryRemove callback function. The framework calls this function as part of the query-removal sequence. In the sample driver, this callback stops the timer and temporarily closes the handle to the I/O target object.

Listing 9-2: EvtIoTargetQueryRemove callback in a KMDF driver

image from book
 NTSTATUS ToastMon_EvtIoTargetQueryRemove(     WDFIOTARGET IoTarget ) {     PAGED_CODE();     . . .  //Timer code omitted     WdfIoTargetCloseForQueryRemove(IoTarget);     return STATUS_SUCCESS; } 
image from book

To prevent target removal, EvtIoTargetQueryRemove returns an error code, typically either STATUS_UNSUCCESSFUL or STATUS_INVALID_DEVICE_REQUEST.

If the driver's EvtIoTargetQueryRemove callback returns STATUS_SUCCESS to allow target removal, the callback must call WdfIoTargetCloseForQueryRemove. WdfIoTargetCloseForQueryRemove closes the I/O target handle temporarily but does not delete the I/O target object.

If the device removal actually occurs, the framework calls the driver's EvtIoTargetRemoveComplete callback, which flushes any pending requests that the timer sent and deletes the I/O target object. If the removal is canceled, the framework instead calls the EvtIoTargetRemoveCanceled callback, which reopens the target and restarts the timer. In this callback, the driver once again calls WdfIoTargetOpen to open the target, but uses the WDF_IO_TARGET_OPEN_ PARAMS_INIT_REOPEN function to initialize the parameters. This function fills in the parameters structure with the same values that the driver used when it first opened the I/O target.




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