Книга: Writing Windows WDM Device Drivers
Interrupt Handler
Interrupt Handler
Listing 17.3 shows the interrupt service routine for WdmIo, InterruptHandler. Remember that this is a general-purpose service routine. If the user mode controlling application has set up its control fields or commands wrongly, things could go horribly wrong.
An interrupt handler should complete its job as quickly as possible. It is run at Device IRQL (DIRQL), so do not make DebugPrint calls. Remember that your device could interrupt at any time, not just when you have started a write request.
The first job of an interrupt handler is to see if the interrupt was generated by the correct device. If it was not, the routine should return FALSE as quickly as possible to let any other chained interrupt service routines have their go. Otherwise it should process the interrupt (at the very least, stop the device from interrupting) and return TRUE.
InterruptHandler reads the device register at InterruptReg. As described in Chapter 15, it then ANDs this value with InterruptRegMask and compares it with InterruptRegValue. If they are equal, the interrupt is valid and the handler can continue.
If the device extension Timeout flag is –1, no transfer is in progress and so TRUE is returned straight away. If your device requires further processing to cancel such "spurious" interrupts, you need to amend WdmIo so that it does what you want.
Next, WdmIo's interrupt handler gets the current IRP for this device. I double-check that there is a current IRP and then see if the I/O Manager has signalled that it should be cancelled by setting its Cancel flag.
If the IRP is still in progress, the TxIsWrite flag indicates whether the Read or Write stored commands should be run. The RunWriteCmdsSynch and RunReadCmdsSynch routines return TRUE if the transfer is now complete (i.e., if all the bytes have been transferred or there has been some error).
If the transfer is now complete, this is remembered by setting Timeout to –1. Interrupt routines run at Device IRQL and so cannot complete IRPs. Completing an IRP also takes some time, so this job ought not to be done in the interrupt handler, anyway. The driver model uses Deferred Procedure Calls (DPCs) to solve these problems, as described in the next section. InterruptHandler calls IoRequestDpc to request that the WdmIo DPC be run.
Listing 17.3 WdmIo Interrupt Handler
BOOLEAN InterruptHandler(IN PKINTERRUPT Interrupt, IN PWDMIO_DEVICE_EXTENSION dx) {
// See if interrupt is ours
dx->TxLastIntReg = ReadByte(dx, dx->InterruptReg);
if ((dx->TxLastIntReg&dx->InterruptRegMask) != dx->InterruptRegValue) return FALSE;
// If no transfer in progress then no further processing required
if (dx->Timeout==-1) return TRUE;
// See if current IRP being cancelled
PDEVICE_OBJECT fdo = dx->fdo;
PIRP Irp = fdo->CurrentIrp;
if (Irp==NULL) return TRUE;
BOOLEAN TxComplete = Irp->Cancel;
if (!TxComplete) {
// Run relevant set of commands
if (dx->TxIsWrite) TxComplete = RunWriteCmdsSynch(dx);
else TxComplete = RunReadCmdsSynch(dx);
}
// If all done, in error or being cancelled then call DPC to complete IRP
if (TxComplete) {
dx->Timeout = –1;
IoRequestDpc(fdo, Irp, dx);
}
return TRUE;
}
- 9.2.4. Traps, Exceptions, and Interrupts
- 10.4 A Closer Look at Exceptions and Interrupts
- 10.5.1 Installing Exception Handlers
- 10.5.3 Loading and Invoking Exception Handlers
- 10.5.5 Exception Handlers
- Shared Interrupt Mappings
- Interrupt Handling
- Chapter 17 Interrupt-Driven I
- Exception Handler Syntax
- 17.4.5. Interrupt Off Timing
- 17.4.6. Interrupt Off History
- 1.3.6 Interrupts