Driver Initialization and Cleanup

< BACK  NEXT >
[oR]

Programmed I/O device drivers must perform extra initialization during DriverEntry (or AddDevice for WDM drivers). Similarly, the driver's Unload routine must be extended to remove the additional resources allocated.

Initializing the Start I/O Entry Point

If a driver has a Start I/O routine, it must be announced during DriverEntry. This is done by storing the address of the Start I/O routine into the DriverStartIo field of the driver object, as in the following code fragment.

 NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject,                       IN PUNICODE_STRING pRegistryPath ) {     :     // Export other driver entry points     //     pDriverObject->DriverStartIo = StartIo;     pDriverObject->DriverUnload = DriverUnload;     pDriverObject->MajorFunction[ IRP_MJ_CREATE ] =               DispatchOpenClose;     : } 

An unitialized DriverStartIo field within the driver object results in an access violation (and blue screen crash) when the Dispatch routines invoke IoStartPacket.

Initializing a DpcForIsr Routine

The I/O Manager provides a simplified version of the DPC mechanism for use with standard interrupt processing. One special DPC object may be associated with each device object, DpcForIsr. To utilize this mechanism, a driver must call IoInitializeDpcRequest to associate the DpcForIsr routine with the Device object (typically from DriverEntry or AddDevice). During the actual interrupt service (ISR), the driver schedules the DPC by invoking IoRequestDpc.

Of course, this simplified mechanism is quite restrictive. Some drivers require multiple DPCs for different circumstances. A subsequent chapter explains the process of creating custom DPCs for multiple purposes.

Connecting to an Interrupt Source

All interrupts are initially handled by the kernel of Windows 2000. As explained in chapter 1, this is done so that portability to multiple platforms can be easily achieved. The kernel dispatches interrupts to a driver's ISR by creation of and then connection to an interrupt object. These steps are accomplished by the I/O Manger's IoConnectInterrupt function, described in Table 8.3. The driver's ISR address is passed (along with nine other input parameters) to this function so that the kernel associates a specific hardware interrupt with it.

IoConnectInterrupt returns a pointer to an interrupt object (via the first argument). This pointer should be saved in the Device or Controller Extension since it will be needed to ultimately disconnect from the interrupt source or to execute any SynchCritSection routines.

Table 8.3. Function Prototype for IoConnectInterrupt
NTSTATUS IoConnectInterrupt IRQL == PASSIVE_LEVEL
Parameter Description
OUT PKINTERRUPT *pInterruptObject Address of pointer to receive pointer to interrupt object
IN PKSERVICE_ROUTINE ServiceRoutine ISR that handles the interrupt
IN PVOID pServiceContext Context argument passed to ISR; usually the device extension
IN PKSPIN_LOCK pSpinLock Initialized spin lock (see below)
IN ULONG Vector Translated interrupt vector value
IN KIRQL Irql DIRQL value for device
IN KIRQL SynchronizeIrql Usually same as DIRQL (see below)
IN KINTERRUPT_MODE InterruptMode LevelSensitive
Latched
IN BOOLEAN ShareVector If TRUE, interrupt vector is sharable
IN KAFFINITY ProcessorEnableMask Set of CPUs which can take interrupt
IN BOOLEAN FloatingSave If TRUE, save the state of the FPU during an interrupt
Return Value STATUS_SUCCESS
STATUS_INVALID_PARAMETER
STATUS_INSUFFICIENT_ RESOURCES

The use of interrupt objects requires care in several areas. First, if an ISR handles more than one interrupt vector, or if a driver has more than one ISR, a spin lock must be supplied to prevent collisions over the ISR's ServiceContext.

Second, if the ISR manages more than one interrupt vector, or a driver has more than one ISR, ensure that the value specified for SynchronizeIrql is the highest DIRQL value of any of the vectors used.

Finally, a driver's Interrupt Service routine must be ready to run as soon as IoConnectInterrupt is called. Clearly, interrupts at the IRQL specified may preempt any additional initialization attempted by a driver, and the ISR must be able to handle these interrupts correctly. In general, the following sequence should be used:

  1. Call IoInitializeDpcRequest to initialize the device object's DPC and perform any initialization needed to make the DpcForIsr routine execute properly.

  2. Disable interrupts from the device by setting appropriate bits and the device's control registers.

  3. Perform any driver initialization required by the ISR in order for it to run properly.

  4. Call IoConnectInterrupt to attach the ISR to an interrupt source and store the address of the Interrupt object in the Device Extension.

  5. Use a SyncCritSection routine to put the device into a known initial state and to enable device interrupts.

Disconnecting from an Interrupt Source

If a driver is capable of being unloaded, it needs to detach its Interrupt Service routine from the kernel's list of interrupt handlers before the driver is removed from memory. If the device generates an interrupt after the driver is unloaded, the kernel will try to call the address in nonpaged pool where the ISR used to live. This results in a system crash.

Disconnecting from an interrupt is a two-step procedure. First, use KeSyncrhonizeExecution and a SynchCritSection routine to disable the device and prevent it from generating any further interrupts. Second, remove the ISR from the kernel's list of handlers by passing the device's interrupt object to IoDisconnectInterrupt.

< 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