9.2.2 Using Direct I/O

Any device driver that transfers data using direct I/O might have to split up a large transfer request into several transfer operations to suit the capabilities of its device or, for a slave DMA device, of the system DMA controller. Consequently, such a driver’s DpcForIsr routine might have to reprogram the device for more than one transfer operation in order to satisfy a given read/write request and complete that IRP.

Because a DpcForIsr or CustomDpc routine runs at IRQL DISPATCH_LEVEL, it must call KeSynchronizeExecution with a SynchCritSection routine to update any state, such as the set of device registers, that is shared with the driver’s ISR.

NT device drivers that use direct I/O can be requested to transfer large amounts of data. The locked-down buffer described by the MDL in IRPs passed to such a driver’s DispatchRead and/or DispatchWrite routine(s) can be larger than the system-defined PAGE_SIZE. Moreover, the MDL at Irp->MdlAddress can describe a buffer backed by several discontiguous physical pages in system memory.

In addition, the device through which such a driver transfers the requested data can have transfer limitations of its own. For example, the system “AT” disk driver, described in Chapter 2, must split up any transfer request for more than 256 sectors due to the disk controller’s limitations.

When such a device driver’s StartIo, AdapterControl, or ControllerControl routine is called with a request to transfer more data than the physical device can handle, it can set up its device to transfer only as much data as that device allows. After the driver’s ISR has handled the interrupt(s) for a maximum device transfer, the DpcForIsr (or CustomDpc) must set up the device again, possibly more than once, to transfer the remaining data necessary to satisfy the IRP.