9.2.3 Points to Consider in Implementing a DpcForIsr or CustomDpc Routine
Keep the following points in mind when implementing a DpcForIsr or CustomDpc routine:
·A DpcForIsr or CustomDpc routine must synchronize its access to a physical device and to any shared state information or resources that the driver maintains in the device extension with the driver’s other routines that access the same device or memory location.
If the DpcForIsr or CustomDpc shares the device or state with the ISR, it must call KeSynchronizeExecution with a driver-supplied SynchCritSection routine to program the device or to access the shared state.
If the DpcForIsr or CustomDpc shares state or resources, such as an interlocked queue or a timer object, with routines other than the ISR, it must protect the shared state or resources with a driver-initialized executive spin lock for which the driver provides resident storage.
·DpcForIsr or CustomDpc routines run at IRQL DISPATCH_LEVEL, which restricts the set of support routines they can call.
For example, a DpcForIsr or CustomDpc routine can neither access nor allocate pageable memory, and it cannot wait on a dispatcher object. On the other hand, a DpcForIsr or CustomDpc routine can acquire and release a driver’s executive spin lock with KeAcquireSpinLockAtDpcLevel and KeReleaseSpinLockFromDpcLevel, which run faster than KeAcquireSpinLock and KeReleaseSpinLock.
·A DpcForIsr or CustomDpc routine is responsible for starting the next I/O operation on the device.
For device drivers that use direct I/O, this responsibility can include using a SynchCritSection routine to program the device to transfer more data in order to satisfy the current IRP before the driver calls IoStartNextPacket.
·If a device driver sets up a controller object in its DriverEntry routine to synchronize I/O operations through the controller to attached devices, its DpcForIsr or CustomDpc routine is responsible for releasing the controller object with IoFreeController before it completes the current IRP and returns control.
·If the driver uses DMA and its AdapterControl routine returns KeepObject or DeallocateObjectKeepRegisters (thereby retaining the system DMA controller channel or busmaster adapter for additional transfer operations), the driver’s DpcForIsr or CustomDpc routine is responsible for releasing the adapter object or map registers with IoFreeAdapterChannel or IoFreeMapRegisters before it completes the current IRP and returns control.
·A DpcForIsr or CustomDpc routine is generally responsible for logging any device errors that occurred during the processing of a given request, retrying the current request if necessary (and also possible), and for setting the I/O status block and calling IoCompleteRequest with the current IRP.
·The DpcForIsr or CustomDpc of a driver that overlaps operations on its device cannot rely on a one-to-one correspondence between requests input to the StartIo routine and the ISR’s calls to IoRequestDpc or KeInsertQueueDpc. In other words, such a driver’s DpcForIsr or CustomDpc cannot necessarily use the input pointers to the IRP and ISR-supplied context, nor the CurrentIrp pointer in the target device object, to complete only that IRP.
At any given moment, the same DPC object cannot be queued twice. If the ISR of such a driver calls IoRequestDpc or KeInsertQueueDpc more than once before the corresponding DpcForIsr or CustomDpc executes, only one instantiation of that DPC routine is run as soon as the IRQL on a processor falls below DISPATCH_LEVEL. On the other hand, if the ISR calls IoRequestDpc or KeInsertQueueDpc while the corresponding DpcForIsr or CustomDpc is running on another processor, two instantiations of that DPC routine can run concurrently.
Therefore, any NT driver that overlaps interrupt-driven I/O operations on its device must have the following functionality:
·A DpcForIsr or CustomDpc that can complete some driver-maintained count of outstanding requests when it is called
·An ISR that never overwrites its saved context for an interrupt-driven I/O operation until the DpcForIsr or CustomDpc has consumed that context information and completed the IRP for which the context was saved
·A SynchCritSection routine that accesses the ISR’s context area on behalf of the DpcForIsr or CustomDpc routine
For more information about SynchCritSection routines, see Chapter 10. For more information about ControllerControl and AdapterControl routines, see Chapter 11. For more information about any particular support routine mentioned in this section, see the Kernel-mode Driver Reference.