Structure of a Kernel-Mode Driver

< BACK  NEXT >
[oR]

A kernel-mode driver looks very different from conventional applications. In general, a driver is just a collection of routines that are called by operating system software (usually the I/O Manager). Flow charts don't provide much benefit when diagramming control paths of a device driver. The routines of the driver sit passively until they are invoked by routines of the I/O Manager.

Depending on the driver, the I/O Manager might call a driver routine in any of the following situations:

  • When a driver is loaded

  • When a driver is unloaded or the system is shutting down

  • When a device is inserted or removed

  • When a user-mode program issues an I/O system service call

  • When a shared hardware resource becomes available for driver use

  • At various points during an actual device operation

The remainder of this section briefly describes the major categories of routines that make up a kernel-mode driver. The details of each of these kinds of driver routines are discussed in subsequent chapters.

Driver Initialization and Cleanup Routines

When a driver loads into the system, various tasks must be performed. Similarly, drivers need to clean up before they are unloaded. There are several routines that a driver may supply to perform these operations.

DriverEntry ROUTINE

The I/O Manager calls this routine when a driver is first loaded, perhaps as early as boot time, but drivers may be dynamically loaded at any time. The DriverEntry routine performs all first-time initialization tasks, such as announcing the addresses of all other driver routines. It locates hardware that it will control, allocates or confirms hardware resource usage (ports, interrupts, DMA), and provides a device name visible to the rest of the system for each hardware device discovered. For WDM drivers participating in Plug and Play, this hardware allocation step is deferred to a later time and routine, the AddDevice function.

REINITIALIZE ROUTINE

Some drivers may not be able to complete their initialization during DriverEntry. This could occur if the driver was dependent on another driver that had yet to load, or if the driver needed more support from the operating system than had booted at the time DriverEntry was initially called. These kinds of drivers can ask that their initialization be deferred by supplying a Reinitialize routine during DriverEntry.

UNLOAD ROUTINE

The I/O Manager calls the Unload routine of a driver when a driver is unloaded dynamically. It must reverse every action that DriverEntry performed, leaving behind no allocated resource. This includes removing the system-wide device name supplied during initialization for all controlled devices. For WDM drivers, device resources (and names) are removed as each device is removed, during RemoveDevice.

SHUTDOWN ROUTINE

Surprisingly, the Unload routine is not invoked during a system shutdown. Since the system is "going away" anyway, a perfect cleanup is not required. Instead, the I/O Manager invokes a driver's Shutdown routine to provide an opportunity to place hardware into a quiescent state.

BUGCHECK CALLBACK ROUTINE

If a driver needs to gain control in the event of a system crash, it can provide a Bugcheck routine. This routine, when properly registered, is called by the kernel during an orderly "crash" process (truly an oxymoronic phrase).

I/O System Service Dispatch Routines

When the I/O Manager receives a request from a user-mode application, the type of request (read, write, etc.) is converted into a function code. The I/O Manager identifies the appropriate driver to handle the request, then calls one of several Dispatch routines in the driver. There is one Dispatch routine per function code supported by a driver.

The driver's appropriate Dispatch routine verifies the request and, if necessary, requests that the I/O Manager queue a device request to perform the real work. It then returns to the I/O Manager, marking the request as pending.

OPEN AND CLOSE OPERATIONS

All drivers must provide a CreateDispatch routine that handles the Win32 CreateFile request. Drivers that must perform cleanup on the Win32 CloseHandle call must supply a CloseDispatch routine.

DEVICE OPERATIONS

Depending on the device, a driver may have individual Dispatch routines for handling data transfers and control operations. The Win32 functions ReadFile, WriteFile, and DeviceIoControl are dispatched to supplied routines in the driver by the I/O Manager. Again, a driver need only supply routines for those operations it supports.

If a user program makes a request of an I/O device for which the driver does not supply a Dispatch routine, the program receives an error indicating that the requested function is not supported.

Data Transfer Routines

Device operations involve a number of different driver routines, depending on the nature and complexity of the device.

START I/O ROUTINE

The I/O Manager calls the driver's Start I/O routine each time a device should begin the start of a data transfer. The request is generated by the I/O Manager each time an outstanding I/O request completes and another request is waiting in the queue. In other words, the I/O Manager (by default) queues and serializes all I/O requests, restarting the affected device only after the previous request completes. (Complex devices capable of dealing with simultaneous requests may choose not to utilize this serialized approach.)

The start I/O routine, supplied by the driver, allocates resources needed to process the requested I/O and sets the device in motion.

INTERRUPT SERVICE ROUTINE (ISR)

The Kernel's interrupt dispatcher calls a driver's Interrupt Service routine each time the device generates an interrupt. The ISR is responsible for complete servicing of the hardware interrupt. By the time the ISR returns, the interrupt should be dismissed from a hardware perspective.

As described earlier, only the most minimal of servicing should be performed within the ISR itself. If additional, time-consuming activities are required as a result of servicing the interrupt, a DPC should be scheduled within the ISR. The remaining work of the ISR can then be completed at an IRQL below DIRQL.

DPC ROUTINES

A driver can supply zero or more DPC routines that perform or complete routine device operations. This might include the release of system resources (such as a DMA page descriptor), reporting error conditions, marking I/O requests as complete, and starting the next device operation, as necessary.

If only one DPC is required for completion of interrupt servicing, the I/O Manager supports a simplified mechanism called a DpcForIsr routine. However, some drivers may wish to provide many DPCs for varied purposes. Perhaps two different DPCs, one that completes a write operation and one that completes a read operation, is convenient. DPCs can be scheduled simply to perform work at an IRQL of DISPATCH_LEVEL. A driver can have any number of custom DPC routines.

Resource Synchronization Callbacks

Recalling the design goals of Windows 2000, all kernel-mode code (including device driver code) must be reentrant. Driver code must consider that multiple threads in one or more processes may make simultaneous I/O requests. Contention issues between the two simultaneous requests must be handled safely and correctly by the reentrant driver code.

The I/O Manager provides several synchronization services to deal with the issue of shared resources among simultaneous requests. These synchronization routines operate differently than those provided to Win32 programmers. In particular, the Win32 model assumes that if a resource is unavailable due to its use by another thread, it is perfectly acceptable to block the execution of the second requester. In kernel mode, it is completely unacceptable to block the execution of an arbitrary thread. A caller must be guaranteed that a return will be prompt, even if the request must be queued for later completion.

The technique employed to synchronize within kernel-mode code is to supply the address of a callback routine dedicated to synchronization of a specific resource. When a driver needs access to a shared resource, it queues a request for that resource with the assistance of the I/O Manager. When the resource becomes available, the I/O Manager invokes the driver-supplied callback routine associated with the request. Of course, this means that multiple requests for the resource are serialized and that at any given time, only one thread context may "own" the resource.

There are three types of synchronization callback routines supported by the I/O Manager. These are discussed in the following sections.

ControllerControl ROUTINE

Sometimes a single controller (card) supports more than one function. Further, the functions may share a single set of controller registers. Thus, only one function on such cards may be in operation at a time. Typically, the Start I/O routine requests exclusive ownership of the controller. When granted, the ControllerControl callback routine executes. When the I/O completes, the driver releases the controller, usually within a DpcForIsr routine.

AdapterControl ROUTINE

DMA hardware is another shared resource that must be passed from driver to driver. Before performing DMA, the driver requests exclusive ownership of the proper DMA hardware typically a DMA channel. When ownership is granted, the AdapterControl callback routine executes.

SynchCritSection ROUTINES

Interrupt service occurs at a device-specific DIRQL while remaining driver code operates at DISPATCH_LEVEL or below. If the lower IRQL sections of code ever touch resources used by the ISR, that operation must execute inside of a SynchCritSection routine. Resources in this category include all device control registers and any other context or state information shared with the Interrupt Service routine.

SynchCritSection routines operate somewhat differently than other synchronization techniques. Once the callback occurs, the IRQL level is raised to the device's DIRQL level. Thus, lower IRQL sections of code temporarily operate at device DIRQL, preventing interruption by the ISR. When the SynchCritSection completes, the IRQL is restored to its original value.

Other Driver Routines

In addition to the basic set of routines just described, a driver may contain any of the following additional functions.

Timer routines.

Drivers that need to keep track of time passage can do so using either an I/O Timer or a CustomTimerDpc routine. Chapter 11 describes both mechanisms.

I/O completion routines.

A higher-level driver within layers of drivers may wish to be notified when a request sent to a lower-level driver completes. The higher-level driver may register an I/O Completion routine for this purpose. Chapter 15 discusses the details of this process.

Cancel I/O routines.

Drivers must consider the possibility that a device request may be canceled by the requester. This could happen during a long device operation (or because an unanticipated device error leaves the driver in a waiting state). The driver may provide a Cancel I/O routine that is called by the I/O Manager when the requester "gives up."

< BACK  NEXT >


The Windows 2000 Device Driver Book(c) A Guide for Programmers
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
ISBN: 0130204315
EAN: 2147483647
Year: 2000
Pages: 156

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