3.2. Object Context Area
Every instance of an object can have one or more
object context areas. The object context area is a driver-defined
storage area for data that is related to that particular instance, such
as a driver-allocated event. The driver determines the size and layout
of the object context area. For a device object, the object context
area is the equivalent of the WDM device extension.
A driver initializes the context area and specifies
its size and type when it creates the object. When KMDF creates the
object, it allocates memory for the context areas from the nonpaged
pool and initializes them according to the driver’s specification. When
KMDF deletes the object, the context areas are deleted along with the
object.
The context area is considered part of the object,
which is opaque to drivers. Therefore, the driver must use an accessor
method to get a pointer to the context area. Each context area has its
own accessor method, and KMDF provides macros to create these methods.
For the driver, defining and initializing a context
area is a multistep process. First, the driver defines a data structure
that describes the context area. This definition typically appears in a
header file.
Next, the driver declares the type of the context area, by using either the WDF_DECLARE_CONTEXT_TYPE or WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro. These macros associate a type with the context area and create a named accessor method that returns a pointer to the context area. WDF_DECLARE_CONTEXT_TYPE_WITH_NAME assigns a driver-specified name to the accessor method. WDF_DECLARE_CONTEXT_TYPE assigns the default name WdfObjectGet_ContextStructure, where ContextStructure is the name of the context structure. This step, too, can be performed in a header file.
Finally, the driver associates the context area with
a specific instance of an object. To do so, the driver initializes the
object attribute structure with information about the context area by
using the WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE or WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE macro. The WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE
macro records information about the context area in an attributes
structure, which the driver later supplies when it creates the object. WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE combines the actions of WDF_OBJECT_ATTRIBUTES_INIT and WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE—that
is, it initializes the attribute structure with settings for
synchronization scope and execution level in addition to information
about the context. The driver passes the resulting attribute structure
when it calls the creation method for the object.
3.3. I/O Queues
KMDF I/O queues manage requests that are targeted at
the driver. A driver typically creates one or more queues, each of
which can accept one or more types of request. A driver can have any
number of queues, and they can all be configured differently. Both KMDF
and the driver itself can queue I/O request.
The most important characteristics of any queue are
the types of requests it accepts, the way in which it dispatches those
requests, and whether KMDF handles power management for it.
A queue can accept one or more types of requests.
For example, a driver might have one queue for read and write request
and another that accepts only device I/O control requests.
The dispatch method determines how many requests the
driver services at a given time. Queues can dispatch requests
sequentially, in parallel, or manually. A sequential queue dispatches
one request at a time. A parallel queue dispatches requests as soon as
they arrive. A manual queue does not dispatch requests automatically; the driver must call a method on the queue each time it is ready to handle another request.
By default, all KMDF I/O queues are power managed,
which means that KMDF handles starting and stopping the queue according
to the power management state of the device and the system. In
addition, KMDF can use an empty queue as a cue to start its idle-device
timer.
The driver uses a WDF_IO_QUEUE_CONFIG structure to configure a queue. For each queue, the driver can specify
The types of I/O requests that are placed in the queue.
The dispatch method for the queue.
The power management options for the queue.
The I/O event callback functions registered to handle I/O requests from the queue.
Whether the queue accepts requests that have a zero-length buffer.
WDF supplies two functions to initialize the WDF_QUEUE_CONFIG structure:
WDF_IO_QUEUE_CONFIG_INIT, which configures a power-managed queue with a driver-specified dispatch method.
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE,
which configures a power-managed queue with a driver-specified dispatch
method and designates it as the driver’s default queue, into which KMDF
places all read, write, and device I/O control requests for which no
other queue is configured.
Like all other objects, queues have attributes. In
many cases, the default attributes are acceptable for queues. A driver
might override the defaults for one of the following reasons:
To create one or more queue-specific context areas in which to save data specific to the queue.
To specify a callback function to be invoked when the queue is deleted.
To specify a parent object for the queue. By default, the parent object is the device object.
3.4. I/O Requests
The WDFREQUEST object represents the IRP sent by the application that initiated the I/O request. Like other KMDF objects, the WDFREQUEST object is opaque to driver writers and is managed by the framework. Most KMDF drivers never directly see the underlying IRP.
When KMDF calls one of the driver’s I/O event callback functions, it passes a handle to a WDFREQUEST object, along with additional information that the driver might require to handle the request. The WDFREQUEST object encapsulates the information passed in the original IRP.
KMDF drivers that support buffered or direct I/O can use the buffer passed by the originator of the I/O request or can use a WDFMEMORY object that represents the output buffer. Using a WDFMEMORY
object is simpler and requires less code because the framework handles
all validation and addressing issues. For example, the handle to the WDFMEMORY object contains the size of the buffer, thus ensuring that buffer overruns do not occur.