5. WDF Object Model
In the WDF object model:
Objects work as
building blocks for the driver. A driver modifies these objects through
well-defined interfaces. The objects themselves have well-defined life
A set of
events can affect each type of object. The framework defines default
behavior for each event. To support device-specific behavior, the driver
includes callback routines that override the defaults.
The model defines a
set of objects that represents common driver constructs, such as
devices, queues, I/O requests, and the driver itself. The objects have
properties, methods, and events:
describe characteristics of the object. Each property is associated
with methods that get and (if relevant) set the value of the property.
Methods perform actions on the objects.
are conditions for which a driver might need to take action. WDF
identifies possible events for each object and defines default actions
for most of them. The driver includes code to handle only the events for
which the default actions are inappropriate or inadequate for its
device. When the event occurs, WDF invokes the related callback.
The WDF driver creates
instances of the objects that it requires to service its device and
customizes those instances to suit its requirements. For each instance,
the driver provides callbacks for the events that require actions other
than the WDF defaults. The callbacks call methods on the object to
perform any additional actions.
Objects are organized
hierarchically. The WDF driver object is the root object; all other
objects are subordinate to it. For most types, a driver can specify the
parent when it creates the object. If the driver does not specify a
parent at object creation, the framework sets the parent to the WDF
driver object by default. Some object types, however, have predefined
parents that cannot be changed at creation. For example, I/O queue
objects are children of the device object. Each child object is deleted
when its parent object is deleted.
Although the object model
applies to both the KMDF and UMDF, WDF objects themselves are
implemented differently in the two frameworks.
5.1. Kernel Mode Objects
objects are structures that are opaque to the driver. Drivers never
directly access instances of KMDF objects. Instead, they reference
object instances by handles. To read, write, or perform an action on an
object, a driver calls a method on the object and passes the handle.
The KMDF defines more than 20 types of objects. Table 2 lists some of the most commonly used.
Table 2. Commonly Used KMDF Object Types
|Object Type Name||Usage|
|WDFDRIVER||Represents the driver object|
|WDFDEVICE||Represents a device object|
|WDFQUEUE||Represents a queue of I/O request|
|WDFINTERRUPT||Represents an interrupt resource|
|WDFREQUEST||Describes an I/O request|
|WDFMEMORY||Describes a buffer for an I/O request|
|WDFDMANENABLE||Describes the characteristic of all DMA transfers for a device|
|WDFDMATRANSACTION||Manages operations for an individual DMA request|
|WDFIOTARGET||Represents the driver that is the target of an I/O request|
KMDF objects are unique to
the framework. They are not managed by the Windows object manager and
therefore cannot be manipulated by using the system’s ObXxx functions. Only the framework and WDF drivers can create and manipulate them.
events are not related to the kernel dispatcher events that Windows uses
as synchronization mechanisms. A driver cannot create, manipulate, or
wait on a WDF event. Instead, the driver registers a callback for the
event and WDF calls the driver when the event occurs.
5.2. User Mode Objects
UMDF objects are based on
the component object model (COM). The UMDF uses a small subset of COM
for query-interface and reference counting features. In User Mode
Drivers, both the driver and the framework implement
and expose COM-style interfaces. Handles are not required because the
interfaces are abstract base classes and thus identify the object.
The UMDF defines fewer
objects than the KMDF because User Mode Drivers cannot directly access
hardware and therefore do not perform direct memory access (DMA) or
handle interrupts. Table 3 lists the interfaces that expose the UMDF object types.
Table 3. Interfaces for UMDF Object Types
|Object Interface Name||Usage|
|IWDFObject||Defines the base WDF object type|
|IWDFDriver||Represents the driver object|
|IWDFDevice||Represents a device object|
|IWDFFile||Represents a file object|
|IWDFIoQueue||Represents a queue of I/O requests|
|IWDFIoRequest||Describes an I/O request|
|IWDFIoTarget||Represents the driver that is the target of an I/O request|
|IWDFMemory||Provides access to an area of memory|
6. Plug and Play and Power Management Support
support for Plug and Play and power management and making it available
in both kernel mode and user mode were primary design goals for WDF.
Seamless handling of Plug and Play and power events is critically
important to system reliability and a good user experience, but is
exceedingly complex to implement correctly.
Much of this
complexity occurs because drivers must determine the correct way to
handle each Plug and Play or power management request. Proper handling
depends on the driver’s position, the device stack, the current state of
its device, the current state of the operating system, and sometimes
the nature of an impending state change for the device or system. Such
support typically requires thousands of lines of code to handle tricky,
state-dependent situations. Most drivers require code to handle requests
that they don’t even support.
concentrates the state-tracking and decision-making logic in the
frameworks, instead of requiring it in each driver. WDF support for Plug
and Play and power management is based on the following principles:
The driver should
not be required to interpret or respond to every uninteresting request.
Instead, the driver should be able to “opt in” and handle only the
requests that are relevant to its device.
frameworks should provide default behavior for a rich set of Plug and
Play and power features, including device stop, device removal, device
ejection, fast resume, low run-time power usage, and device wake-up by
WDF actions at each point must be well-defined and predictable; in effect, a “contract” applies to each driver callback.
Plug and Play and power management should be thoroughly integrated with other parts of the frameworks, such as queue management.
The frameworks must support both simple and complex hardware and driver designs.
A driver should be able to override any framework-supplied defaults.
6.1. Plug and Play/Power Management State Machine
implements Plug and Play and power management as a state machine. Both
the KMDF and UMDF use the same state machine. A driver includes
callbacks so that it can perform device-specific actions at individual
states in the machine. For example, a driver can provide a callback that
is called immediately after its device enters the working state.
At each state transition, a
predetermined set of events is valid for each type of object, and the
framework invokes the driver’s callbacks for these events in a defined
order. Thus, a driver can assume that both the system and its device are
in a particular state whenever it is asked to perform a Plug and Play
or power management action.
The complicated logic that
tracks system and device state is incorporated into the framework, not
into the driver. This approach vastly reduces the amount of required
decision-making in the driver—especially during power transitions—and
eliminates much redundant code. Instead, the framework defines a
state-related event and the driver optionally supplies a
corresponding callback. As a result, a WDF driver includes code to
handle only those events for which it requires device-specific support.
All other events can be handled by WDF defaults.
Furthermore, Plug and
Play and power management support are integrated throughout the
framework so that other aspects of the driver operate properly when
state transitions occur. For example, a driver can configure its I/O
queues so that the framework stops dispatching requests while the device
is in a low-power state.
7. Integrated I/O Queuing and Cancellation
WDF integrates Plug and
Play and power management support with the queuing of I/O requests and,
in turn, integrates queuing with request cancellation.
Both the KMDF and UMDF provide
configurable I/O queues. The driver creates the queues and configures
them for specific I/O request, power management characteristics, and
dispatching requirements. The framework queues and dispatches requests
according to the driver’s specifications: sequentially (one at a time),
in parallel (as soon as they arrive), or manually (at the driver’s
explicit request). When Plug and Play or power management events affect
queuing, WDF can start, stop, or resume queuing as appropriate,
depending on how the driver configured the queue.
I/O is inherently asynchronous, handling the cancellation of an I/O
request is often complex. The driver must cope with several potential
race conditions and one or more locks, and the required code is
typically scattered among several driver routines.
WDF relieves drivers of much of
this burden by managing the locks for the I/O queues and by canceling
queued requests without driver intervention. (A driver can, however,
register for notification when a request is canceled.) By default,
requests that are in a queue can be canceled. Requests that have been
removed from a queue and dispatched to a driver cannot be canceled
unless the driver specifically marks them so. WDF drivers that use these
defaults typically require little if any cancellation code.
Managing concurrent operations is another challenge in writing a Windows driver. Because Windows is a pre-emptive, multitasking operating
system, multiple threads can concurrently try to access shared data
structures or resources, and multiple driver routines can run
concurrently. To ensure data integrity, drivers must synchronize access
to shared data structures.
synchronization by implementing several internal synchronization
mechanisms and by holding any required locks. In addition, WDF
synchronization scope is a configurable object-based mechanism for
specifying the degree of concurrency. (Synchronization scope is called
the locking constraint in the UMDF.) An object’s synchronization scope
determines whether WDF invokes multiple event callbacks on the object
concurrently. Drivers that use the KMDF can specify synchronization
scope for driver, device, and file objects. In the UMDF, synchronization
scope applies only to device objects.
WDF defines the following synchronization scopes:
WDF does not call certain I/O event callbacks concurrently for an
individual device object or any file objects or queue objects that are
These I/O callbacks are not called concurrently on a per-queue basis.
If a Kernel Mode Driver specifies queue scope for a device object, these
callbacks can run concurrently for multiple queues. However, multiple
callbacks for an individual queue object will not be called
concurrently. The initial UMDF release does not support queue scope.
No scope— WDF does not acquire any locks and can call any event callback concurrently with any other event callback.
By default, the KMDF uses no
scope. A Kernel Mode Driver must “opt in” to synchronization for its
objects by setting device scope or queue scope when it creates an
object. The UMDF uses device scope by default.
For Kernel Mode Drivers, the
KMDF also enables driver writers to constrain the interrupt request
level (IRQL) at which the callbacks can be invoked.
7.2. I/O Model
In Windows, the I/O request
packet (IRP) does more than just present traditional I/O requests (read,
write, create, and so forth) to drivers. It works as a general
packet-based communication mechanism between the operating
system and drivers, and between drivers themselves. The Windows I/O
manager sends IRPs to notify drivers of Plug and Play requests, power
management requests, changes in device status, and queries about device
and driver resources (among other purposes) in addition to passing I/O
requests. Therefore, the WDF I/O model encompasses more than just data
transfers to and from a device.
For WDF drivers, the
framework manages the mechanics of dispatching, queuing, completing, and
canceling IRPs on behalf of its drivers. The framework calls the
driver’s event callback routines to notify it of significant events such
as requests that the driver must handle.
After receiving a
request, the framework records information about the request, creates a
WDF object to represent the request (if necessary), and calls one or
more of the driver’s event callbacks to handle the request as
appropriate. WDF queue objects help drivers to manage the arrival of I/O
requests. A driver can create one or more such queues and configure
each to receive specific types of requests. Depending on the dispatch
mechanism that the driver has designed for each queue, the framework
either delivers the request to the driver immediately or queues it for
The framework keeps track of
every I/O request, whereas the driver “owns” the request—that is, until
the request has been canceled, completed, or passed to another target.
Because the framework is aware of all the active requests, it can call
the appropriate driver callbacks in case of IRP cancellation, power
state changes, hardware removal, and so forth.
7.3. I/O Request Flow
Both the KMDF and UMDF use the
same I/O model, although it is implemented by different components.
Within this model, I/O request flow is as shown in Figure 1.