Code Example: Catching Device Timeouts

< BACK  NEXT >
[oR]

This example shows the addition of timeout support to the simple parallel port driver developed in previous chapters.

Device Extension Additions

The Device Extension is modified to include the timeout counter. A counter value of -1 signifies that timeouts are to be ignored.

 typedef struct _DEVICE_EXTENSION {      ...      LONG timeRemaining;  // timeout counter - seconds      ... } DEVICE_EXTENSION, *PDEVICE_EXTENSION; 

AddDevice Additions

AddDevice is changed to initialize the I/O Timer for the device. The counter value does not need to be initialized until the timer is actually started.

 NTSTATUS AddDevice(IN PDRIVER_OBJECT pDriverObject,                    IN PDEVICE_OBJECT pdo) {      PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)            pDevObj->DeviceExtension; ... // Near the end of the function, after IoCreateDevice //  has been called.... // // Create the I/O Timer      IoInitializeTimer( pdo, IoTimer, pDevExt); ... } 

Create Dispatch Routine Changes

When the device is "opened" from user-mode (via the Win32 CreateFile call), the I/O Timer is started. It continues to tick so long as the handle remains open. Since the time is ticking, the timeout counter must be initialized to show that at present the ticks should be ignored.

 NTSTATUS DispatchCreate( IN PDEVICE_OBJECT pDevObj,                          IN PIRP pIrp ) {      PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)           pDevObj->DeviceExtension;      ...      // Near the end of the function, the timeout      //   counter is initialized and the I/O Timer      //   is started.      pDevExt->timeRemaining = -1;      IoStartTimer( pDevObj );      ... } 

StartIo Changes

Each time the physical device is started and an interrupt becomes expected, the maximum number of seconds to wait for the interrupt must be set into the timeout counter. An operational counter must be synchronized with all code paths to ensure it does not become corrupted. The ISR and I/O Timer callback routines, running as interrupting code paths, also read and write the counter.

The use of InterlockedExchange assures that the 32-bit timeout counter is stored atomically.

 VOID StartIo( IN PDEVICE_OBJECT pDevObj,                IN PIRP pIrp ) {      PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)           pDevObj->DeviceExtension;      ...      // Before physically starting the device, the      // timeout counter must be set. Remember to      // account for all forms of device latency,      // including device power/spin-up, etc.      InterlockedExchange( pDevExt->timeRemaining,                           INTERRUPT_TIMEOUT );      //      // Now start the device:      CallTransmitBytes( pDevObj, pIrp );      ... } 

ISR Changes

The Interupt Service Routine is modified so that each time an expected interrupt arrives, the I/O Timeout wait period is either canceled or reset. If the ISR starts another device operation, a fresh timeout period is established. If there are no more pending transfer operations, the timeout is canceled (set to -1).

 BOOLEAN Isr( IN PKINTERRUPT pInterruptObj,           IN PVOID pServiceContext ) {      PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)           pServiceContext;      ...      // If there are more bytes to send,      //    reset the timeout counter to a fresh start      if (TransmitBytes( pDevExt )           InterlockedExchange(&pDevExt->timeRemaining,                             INTERRUPT_TIMEOUT );      // If no more bytes to send, clear the timeout      else           InterlockedExchange(&pDevExt->timeRemaining,                          -1 );      ... 

I/O Timer Callback Routine

Finally, the Timer Callback routine itself is presented. If the routine detects that the timeout has expired, it uses the driver's DprForIsr routine to fail the IRP.

 VOID IoTimer( IN PDEVICE_OBJECT pDevObj,                IN PVOID pContext ) {      PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)           pContext;      // Check the timeout value      if (InterlockedCompareExchange(           &pDevExt->timeRemaining, -1, -1) < 0)           return;    // timer not active      // Since the timer is active, decrement it      if (InterlockedDecrement(&devExt->timeRemaining)                 == 0) {           // timeout has expired - fail the IRP           InterlockedExchange(&pDevExt->timeRemaining,                             -1 );           DpcForIsr( NULL, pDevObj,                    pDevObj->CurrentIrp, pDevExt );       }       return; } 

There is a small window of interest between the check to see if the timer is active and the decrementing of the timer. Between the two calls, the ISR could execute, setting the (formerly) active timer counter to -1. When theIoTimer routine regains control, it decrements the -1 to -2. The code accounts for this window by comparing the timeRemaining value to any negative value.

< 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