As its name implies, a ControllerControl routine is associated with a controller object. When the ControllerControl routine executes, the hardware represented by the controller object is free and the controller extension generally is not being accessed by another driver routine unless the controller extension contains context that is shared with the driver’s ISR.
Usually, a ControllerControl routine does at least the following:
If the driver uses DMA, its ControllerControl routine usually is responsible for determining whether a given transfer request must be split up into partial transfers due to any system-imposed or device-imposed limitations on the size of each DMA transfer. In these circumstances, the ControllerControl routine also is responsible for calling AllocateAdapterChannel if the driver has an AdapterControl routine.
If the driver uses PIO, its ControllerControl routine also is responsible for splitting transfer requests, if its hardware requires it, into partial-transfer ranges and for calling MmGetSystemAddressForMdlSafe with the MDL at Irp->MdlAddress.
If the device or controller extension can be accessed from the ISR, the ControllerControl routine must use a SynchCritSection routine that is invoked by calling KeSynchronizeExecution. For more information, see Using Critical Sections.
If the driver has a Cancel routine, its ControllerControl routine also must check the Irp->Cancel field to determine whether the current IRP should be canceled, and do either of the following:
If Irp->Cancel is set to TRUE, the ControllerControl routine must do the following:
If Irp->Cancel is not set to TRUE, the ControllerControl routine instead must do the following:
For more information about handling cancelable IRPs, see Canceling IRPs.
For most interrupt-driven I/O operations except overlapped operations on different devices attached to the physical controller/adapter, a ControllerControl routine should return KeepObject because the DpcForIsr or CustomDpc routine completes the operation and the IRP.
As soon as the I/O operation(s) to satisfy the current request are done, the routine that will complete the IRP should call IoFreeController and IoStartNextPacket so that the next request can be processed as quickly as possible.
If the ControllerControl routine itself completes an IRP or if it can set up an operation, such as a disk seek, for one target device object (disk) that could be overlapped with an operation for another device object, the ControllerControl routine should return DeallocateObject.