13.1.3 Allocating IRPs for Lower Drivers

An NT highest-level or intermediate driver’s DispatchRead and/or DispatchWrite routine is most likely to set an IoCompletion routine in an IRP because transfer requests must be handled asynchronously by lower-level drivers, as discussed in Chapter 6. To allocate an IRP for an asynchronous request, which will be processed in an arbitrary thread context by lower drivers, such a DispatchReadWrite routine can call one of the following support routines:

A higher-level driver’s DispatchDeviceControl routine can allocate an IRP with IoBuildDeviceIoControlRequest. It can set up an IoCompletion routine for such an IRP but is unlikely to do this. If the driver allocates resident storage for and initializes an event object, its DispatchDeviceControl routine can wait on an event when it sends on driver-allocated IRPs for inherently synchronous device control requests, as mentioned in Chapter 6.

Usually, a higher-level driver would not set its IoCompletion routine in an IRP allocated with IoBuildSynchronousFsdRequest for the same reason. For more information about restrictions on calls to this support routine from Dispatch routines, see also Chapter 6.

Each higher-level NT driver sets up any driver-allocated (and reused) IRPs for lower drivers in such a way that it is immaterial to the underlying device driver whether a given request comes from an NT intermediate driver or originates from any other source, such as an NT file system or user-mode application.