Some PnP and power IRPs must be processed first by the parent bus driver for a device and then by each next-higher driver in the device stack. For example, the parent bus driver must be the first driver to perform its start operations for a device (IRP_MN_START_DEVICE), followed by each next-higher driver. For such an IRP, function and filter drivers must set an I/O completion routine, pass the IRP to the next-lower driver, and postpone any activities to process the IRP until the lower drivers have finished with the IRP.
An IoCompletion routine can be called at IRQL DISPATCH_LEVEL, but a function or filter driver might need to process the IRP at IRQL PASSIVE_LEVEL. To return to passive IRQL from an IoCompletion routine, a driver can use a kernel event. The driver registers an IoCompletion routine that sets a kernel-mode event and then the driver waits on the event in its DispatchPnP routine. When the event is set, lower drivers have completed the IRP and the driver is allowed to process the IRP.
Note that a driver must not use this technique to wait for lower drivers to finish a power IRP (IRP_MJ_POWER). Waiting on an event in the DispatchPower routine that is set in the IoCompletion routine can cause a deadlock. See Passing Power IRPs for more information.
The following two figures show an example of how a driver waits for lower drivers to complete a PnP IRP. The example shows what the function and bus drivers must do, plus how they interact with the PnP Manager and the I/O Manager.

Postponing PnP IRP Handling — Part 1
The following notes correspond to the circled numbers in the previous figure:
The function driver can use IoCopyCurrentIrpStackLocationToNext to set up the stack location.
In the call to IoSetCompletionRoutine, the function driver sets InvokeOnSuccess, InvokeOnError, and InvokeOnCancel to TRUE and passes the kernel-mode event as part of the context parameter.
If the bus driver calls other driver routines or sends I/O to the device in order to start it, the bus driver does not complete the PnP IRP in its DispatchPnP routine. Instead, it must mark the IRP pending with IoMarkIrpPending and return STATUS_PENDING from its DIspatchPnP routine. The driver later calls IoCompleteRequest from another driver routine, possibly a DPC routine.
The following figure shows the second part of the example, where the higher drivers in the device stack resume their postponed IRP processing.

Postponing PnP IRP Handling — Part 2
The following notes correspond to the circled numbers in the previous figure:
The IoCompletion routine must return STATUS_MORE_PROCESSING_REQUIRED to prevent the I/O Manager from calling IoCompletion routines set by higher drivers at this time. The IoCompletion routine uses this status to forestall completion so its driver's DispatchPnP routine can regain control. The I/O Manager will resume calling higher drivers' IoCompletion routines for this IRP when this driver's DispatchPnI routine completes the IRP.
If IoCallDriver returns STATUS_PENDING, the DispatchPnP routine has resumed execution before its IoCompletion routine has been called. The DispatchPnP routine, therefore, must wait for the kernel event to be signaled by its IoCompletion routine. This ensures that the DispatchPnP routine will not continue processing the IRP until all lower drivers have completed it.
If Irp->IoStatus.Status is set to an error, a lower driver has failed the IRP and the function driver must not continue handling the IRP (except for any necessary cleanup).
For IRPs being handled first by the parent bus driver, the bus driver typically sets a successful status in Irp->IoStatus.Status and optionally sets a value in Irp->IoStatus.Information. Function and filter drivers leave the values in IoStatus as is unless they fail the IRP.
The function driver's DispatchPnP routine calls IoCompleteRequest to complete the IRP. The I/O Manager resumes I/O completion processing. In this example, there are no filter drivers above the function driver, and thus no more IoCompletion routines to call. When IoCompleteRequest returns control to the function driver DispatchPnP routine, the DispatchPnP routine returns status.
For some IRPs, if a function or filter driver fails the IRP on its way back up the device stack, the PnP Manager informs the lower drivers. For example, if a function or filter driver fails an IRP_MN_START_DEVICE, the PnP Manager sends an IRP_MN_REMOVE_DEVICE to the device stack.