1. Self-Managed I/O
Some drivers have I/O
paths that do not go through queues or are not subject to power
management. UMDF provides self-managed I/O features to support these
requirements.
The self-managed I/O
callbacks correspond directly to Plug and Play and power management
state changes, and the automatic queuing feature in UMDF is built around
the same mechanism. These routines are called with a pointer to the IWDFDevice interface and no other parameters. If a driver implements the IPnpCallbackSelfManagedIo interface, UMDF calls its methods at the designated times so that the driver can perform whatever actions it requires.
Table 1 lists the methods of this interface and indicates when each is called.
Table 1. Self-Managed I/O Methods
Method | When Called |
---|
OnSelfManagedIoCleanup | During device removal, after calling OnSelfManagedIoSuspend |
OnSelfManagedIoFlush | After device removal has completed. |
OnSelfManagedIoInit | During device start-up, after the framework has called the driver’s IPnpCallback::OnDoEntry callback function for the first time. |
OnSelfManagedIoRestart | When the device returns from a low-power state to its working (DO) state; called only if UMDF previously called the driver’s OnSelfManagedIoSuspend method. |
OnSelfManagedIoStop | Not currently called. |
OnSelfManagedIoSuspend | When one of the following is true:
The device is about to enter a low-power state. The device is being removed or was surprise-removed. The Plug and Play manager is preparing to redistribute the system’s hardware resources among system’s attached devices.
|
2. Synchronization Issues
Because Windows is a
preemptive, multitasking operating system, multiple threads can try to
access shared data structures or resources concurrently and multiple
driver routines can run concurrently. To ensure data integrity, all
drivers must synchronize access to shared data structures.
For UMDF drivers, ensuring proper synchronization requires attention to several areas:
The number of concurrently active requests that are dispatched from a particular queue.
The number of concurrently active callbacks for a particular device object.
The driver utility functions that access object-specific data.
The dispatch method for an
I/O queue controls the number of requests from the queue that can
concurrently be active in the driver. Limiting concurrent requests does not, however, resolve all
potential synchronization issues. Concurrently active callbacks on the
same object might require access to shared object-specific data.
Similarly, driver utility functions might share object-specific data
with callbacks. For example, a driver’s cleanup and cancellation methods
often use the same data as its dispatch (read, write, and device I/O
control) callbacks.
UMDF provides configurable concurrency control, called the synchronization model or locking constraint, for the callbacks of several types of objects. An object’s synchronization model determines whether UMDF invokes certain event callbacks on the object concurrently.
UMDF defines two synchronization models that is device scope and no scope.
Device Scope means that UMDF
does not call certain I/O event callbacks concurrently for an individual
device object or any file objects or queues that are children of the
device object. Specifically, device scope applies to the following event
callbacks:
IFileCallbackCleanup::OnCleanupFile
IFileCallbackClose::OnCloseFile
IQueueCallbackCreate::OnCreateFile
IQueueCallbackDefaultIoHandler::OnDefaultIoHandler
IQueueCallbackDeviceIoControl::OnDeviceIoControl
IQueueCallbackIoResume::OnIoResume
IQueueCallbackIoStop::OnIoStop
IQueueCallbackRead::OnRead
IQueueCallbackStateChange::OnStateChange
IQueueCallbackWrite::OnWrite
IRequestCallbackCancel::OnCancel
However,
callbacks for different device objects that were created by the same
driver can be called concurrently. By default, a UMDF uses device scope.
No Scope means that UMDF can
call any event callback concurrently with any other event callback. The
driver must create and acquire all its own locks.
A driver sets the synchronization mode by calling the SetLocking Constraint method of the IWDFDeviceInitialize interface before it creates the device object.
3. Locks
In addition to the
synchronization for the configurable synchronization model, UMDF
provides a lock for each device and I/O queue object. A driver can
acquire and release this lock by using the IWDFObject::AcquireLock and IWDFObject::ReleaseLock methods. These methods are supported for IWDFDevice and IWDFIoQueue, which inherit from IWDFObject.
Driver
code that runs outside an event callback sometimes must synchronize
with code that runs inside an event callback. After acquiring the lock,
the driver can safely access the object and perform other actions that
affect the object. However, to prevent a deadlock, the driver must
release the lock before calling any methods in the framework, such as IWDFRequest::CompleteWithInformation.
4. Plug and Play and Power Management Notification
UMDF implements
integrated Plug and Play and power management support as an internal
state machine. An event is associated with the transition to each state,
and a driver can supply callbacks that are invoked at specific state
changes.
UMDF is designed to work with
drivers on an “opt-in” basis. A UMDF driver implements Plug and Play
callback interfaces for only the events that affect its device. For
example, some devices require intervention immediately after they are
turned on and immediately before they are turned off. The driver for
such a device can implement the IPnpCallbackHardware
interface, which provides methods to be called at those times. If the
device does not require such intervention, its driver does not implement
the interface.
If you are familiar with WDM
driver, you probably remember that any time the system power state
changes, the WDM driver must determine the correct power state for its
device and then issue power management requests to put the device in
that state at the appropriate time. The UMDF state machine automatically
handles the translation of system power events to device power events
and notifies the driver to
UMDF automatically provides
for the correct behavior in device parent/child relationships. If both a
parent and a child device are powered down and the child must power up,
UMDF automatically returns the parent to full power and then powers up
the child.
To accomplish these power transitions, a driver implements the IPnpCallback and IPnpCallbackHardware
interfaces. The methods in these two interfaces are called in a defined
order and each conforms to a “contract” so that both the device and the
system are guaranteed to be in a particular state when the driver is
called to perform an action.
In
addition, requests that the framework has received and not yet delivered
to the device driver can affect the power state of the device. If the
driver has configured a queue for power management, the framework can
automatically restore device power before it delivers the request to the
driver. It can also automatically stop and start the queue in response
to Plug and Play and power events.