In Chapter 5, "The I/O Request Packet," I explained the mechanics of passing IRPs down the driver stack in two situations: one in which you care about the result and therefore need a completion routine, and the other in which you don't care about the result and therefore don't install a completion routine. Many of the PnP requests fit into the second of these categories—you're receiving the IRP and passing it down, but you don't care what happens to it afterward. To begin with, then, I suggest writing a helper function that you can use to pass a request down in the "don't care" scenario—see the code below.
NTSTATUS DefaultPnpHandler(PDEVICE_OBJECT fdo, PIRP Irp) { IoSkipCurrentIrpStackLocation(Irp); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; return IoCallDriver(pdx->LowerDeviceObject, Irp); } |
A simplified version of the dispatch function for IRP_MJ_PNP might look like the following:
1 2 3 4 5 |
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) { PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG fcn = stack->MinorFunction; static NTSTATUS (*fcntab[])(PDEVICE_OBJECT, PIRP) = { HandleStartDevice, // IRP_MN_START_DEVICE HandleQueryRemove, // IRP_MN_QUERY_REMOVE_DEVICE <etc.>, }; if (fcn >= arraysize(fcntab)) return DefaultPnpHandler(fdo, Irp); return (*fcntab[fcn])(fdo, Irp); } |