A driver registers a DpcForIsr routine for a device object by calling IoInitializeDpcRequest after it has created the device object. The driver can make this call from its AddDevice routine, or from DispatchPnP code that handles IRP_MN_START_DEVICE requests.
To queue the DpcForIsr routine for execution, the driver's ISR calls IoRequestDpc just before it returns. The following figure illustrates calls to these routines.

Using a DPC Object for a DpcForIsr Routine
As the previous figure shows, calling IoInitializeDpcRequest associates a DPC object with a driver-supplied DpcForIsr routine and a driver-created device object. The I/O Manager allocates memory for the DPC object and calls KeInitializeDpc on the driver's behalf.
When the ISR is called to handle a device interrupt at DIRQL, it should return control to the system as soon as possible for better overall system and driver performance. Usually, an ISR merely clears the interrupt, gathers whatever context information the DpcForIsr routine needs to complete the operation that caused the interrupt, calls IoRequestDpc, and returns.
When the ISR calls IoRequestDpc, it passes a pointer to the device object, a pointer to the DeviceObject->CurrentIrp, and a pointer to a driver-determined context. The I/O Manager calls KeInsertQueueDpc on the driver's behalf, which queues the DPC object. When IRQL falls below DISPATCH_LEVEL on a processor, the kernel dequeues the DPC object and runs the driver's DpcForIsr routine on that processor at IRQL DISPATCH_LEVEL.
The DpcForIsr routine is responsible for doing whatever is necessary to complete the I/O requested in the current IRP. On entry, the routine receives a pointer to the DPC object, along with pointers to the device object, IRP, and context area, which were passed in the ISR's call to IoRequestDpc. The context area must be in resident memory, and is usually in the device extension. Alternatively, it can be in nonpaged pool allocated by the driver, or in a controller extension if the driver uses a controller object.
Because ISR and DpcForIsr routines can run concurrently on SMP machines, you must follow these guidelines:
Otherwise, the driver's StartIo (or queue-management routines) might start another I/O operation that overwrites the shared context area before the DpcForIsr routine can complete the current operation. This is because the ISR can be called again if the device interrupts while or before the DpcForIsr routine executes (assuming interrupts are still enabled).
Even on a uniprocessor machine, the ISR could be called again if the device interrupts while or before the DpcForIsr routine is run. If this occurs, the DpcForIsr routine is run only once. In other words, there is no one-to-one correspondence between an ISR's calls to IoRequestDpc and instantiations of the DpcForIsr routine if a driver overlaps I/O operations for its target device objects.