11.3 ControllerControl Routine Requirements

As its name implies, a ControllerControl routine is associated with an NT 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:

1.Updates or initializes whatever context the driver maintains in the device extension of the target device object and in the controller extension

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- or device-imposed limitations on the size of each DMA transfer. In these circumstances, the ControllerControl routine also is responsible for calling IoAllocateAdapterChannel if the driver has an AdapterControl routine.

If the driver uses PIO, its ControllerControl routine also is responsible for splitting large transfer requests, if its hardware requires it, into partial-transfer ranges and for calling MmGetSystemAddressForMdl with the MDL at Irp->MdlAddress.

2.Programs its hardware for the requested I/O operation

If the device or controller extension can be accessed from the ISR, the ControllerControl routine must call KeSynchronizeExecution with a SynchCritSection routine, described in Chapter 10, to program the hardware or to set up context shared with the ISR.

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 cancelled, and do either of the following:

·If Irp->Cancel is set to TRUE, the ControllerControl routine must do the following:

1.Set STATUS_CANCELLED for Status and zero for Information in the I/O status block of the IRP.

2.Call IoFreeController to release the controller object so the next device operation can be started promptly.

3.Call IoStartNextPacket or dequeue the next IRP if the driver manages its own queueing.

4.Complete the cancelled IRP with IoCompleteRequest and return control.

·Otherwise, the ControllerControl routine must do the following:

1.Call IoSetCancelRoutine to reset the Cancel routine entry point for the IRP to NULL. Acquire the cancel spin lock for this call if the driver uses the I/O-manager-supplied device queue in the device object.

2.Call KeSynchronizeExecution with a driver-supplied SynchCritSection routine to program the hardware for the requested I/O operation.

For more information about Cancel routines and handling cancelable IRPs, see Chapter 12.

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.