Stripping the above down, you have this:
PFDO_DATA FdoData = NULL;
if (ulStatusW != 0) { //Write Complete
...
}
else {
if (ulStatusR != 0) { //Read Complete
...
else {
...
WdfInterruptQueueDpcForIsr(Interrupt);
return FALSE;
}
}
return TRUE;
There are a few issues here. First of all, if two interrupts occur very near to each other time wise (like may happen if you are running read and write at the same time), Windows may queue the occurrences into a single ISR call. What this can mean is that your code could miss the fact that the 'read' is complete as you are checking 'write' first and only checking 'read' if it wasn't 'write'. What you need to do is check *both* in each interrupt call.
Secondly, you pointer FdoData which is initialised to point to NULL. Then in later lines you start writing to this without updating it to point to some place - this is VERY VERY VERY bad, and I'm surprised it didn't cause a blue screen. You are basically trying to read/write values from uninitialized memory.
You are also writing to a variable LastPtr which doesn't appear to exist? In which case the only conclusion I can draw is that this is declared as a global variable, which should *not* be done in a KMDF driver. You should be storing everything in the device extension. Now while a pointer to your device extension isn't passed as a parameter in the ISR, you can get it by other means, you simply add these two lines to the top of your ISR:
PDEVICE_EXTENSION devExt;
devExt = DriverGetDeviceContext(WdfInterruptGetDevice(Interrupt));
//Note: DriverGetDeviceContext should be replaced by whatever you put in your:
//WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, DriverGetDeviceContext)
The third issue with your code is more a misunderstanding of KMDF. If it wasn't read or write, you call WdfInterruptQueueDpcForIsr(), and then return FALSE. Returning FALSE instructs the KDMF framework that the interrupt is either not recognised, or not handled by the ISR - in which case you should *not* be handling it in a DPC - because you don't recognise it.
Basically your ISR should be as succinct as possible, something along these lines:
BOOLEAN PCIeEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageID)
{
PDEVICE_EXTENSION devExt; //DO NOT USE GLOBAL VARIABLES, put anything you need to be global in your DEVICE_EXTENSION...
devExt = DriverGetDeviceContext(WdfInterruptGetDevice(Interrupt));
//Note: DriverGetDeviceContext should be replaced by whatever you put in your:
//WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, DriverGetDeviceContext)
//(1) Check if this is a message ID you are expecting. If you only have one IRQ source (one MSI interrupt), this will *always* be 0
if (MessageID != 0) {
return FALSE; //Unknown source. This ISR will not handle it so let KMDF deal with the problem...
}
//(2) Do the *bare minimum* required to check the Write status flags
BOOL writeDone = ...;
...;
//(3) Do the *bear minimum* required to check the Read status flags
BOOL readDone = ...;
...;
//(4) Queue DPC to do the rest.
if (writeDone || readDone) {
WdfInterruptQueueDpcForIsr(Interrupt); //processing
}
return TRUE; //We recognised the message ID and did everything we needed to handle it - even if that didn't involve queuing a DPC!
}