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.