must be called at DISPATCH_LEVEL IRQL or lower.
Listing 9.4 Wdm2 PnpDefaultHandler
NTSTATUS PnpDefaultHandler(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
DebugPrintMsg('PnpDefaultHandler');
PWDM2_DEVICE_EXTENSI0N dx=(PWDM2_DEVICE_EXTENSION)fdo->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(dx->NextStackDevice, Irp);
}
Before continuing with the rest of the PnP implementation, it is worth looking again at the Plug and Play message and state diagram that was shown in the last chapter.
Figure 9.1 shows the main theoretical device states that a device can be in and the messages that are sent to change between these states. As mentioned before, a message such as START_DEVICE in this diagram corresponds to a PnP IRP with a minor code of IRP_MN_START_ DEVICE.
Note that I said 'theoretical' device states. There are no visible flags in the kernel device structure that say which state a device is in. Wdm2 has to maintain its own state variables.
Another important point to note is that your code should be prepared to accept more-or-less any message from any state. The DDK documentation says in at least two places that an unexpected message may occasionally be sent when in one particular state.
Figure 9.1 Plug and Play device states and messages
The device extension for Wdm2 device objects is shown in Listing 9.5. Four state flags are used to ensure that I/O requests are only begun when the device is in the
Paused | Device has a remove pending or stop pending |
GotResources | Device running normally or paused (i.e., not stopped) |
IODisabled | Paused or stopped |
Stopping | Device is in process of being removed or stopped |
The
The Paused flag is set when the device is in the
The
The
In the
Some devices may want to have an
Listing 9.5 Wdm2 device extension
typedef struct _WDM2_DEVICE_EXTENSION {
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice;
UNICODE_STRING ifSymLinkName;
bool GotResources; // Not stopped
bool Paused; // Stop or remove pending
bool IODisabled; // Paused or stopped
LONG OpenHandleCount; // Count of open handles
LONG UsageCount; // Pending I/O Count
bool Stopping; // In process of stopping
KEVENT StoppingEvent; // Set when all pending I/O complete
DEVICE_POWER_STATE PowerState; // Our device power state
PULONG PowerIdleCounter; // Device idle counter
// Resource allocations
bool GotPortOrMemory;
bool PortInIOSpace;
bool PortNeedsMapping;
PUCHAR PortBase;
PHYSICAL_ADDRESS PortStartAddress;
ULONG PortLength;
bool GotInterrupt;
ULONG Vector;
KIRQL Irql;
KINTERRUPT_MODE Mode;
KAFFINITY Affinity;
PKINTERRUPT InterruptObject;
} WDM2_DEVICE_EXTENSION, *PWDM2_DEVICE_EXTENSION;
The
The
The
if (dx->IODisabled) return CompleteIrp(Irp, STATUS_DEVICE_NOT_CONNECTED, 0);
To recap, three flags in the Wdm2 device extension are used to ensure that normal I/O requests are permitted only when the Wdm2 device is fully started. In fact, there will be very few times in the life of a Wdm2 device when I/O requests are not permitted. (Strictly speaking, I could have combined the Paused and