Releasing Driver-Allocated Resources
The specifics of how a driver uses the registry, sets up system objects and resources in its device extensions, controller extension, or driver-allocated nonpaged pool varies from driver to driver. However, any Unload routine must release the resources a driver is using in stages.
Any driver's Unload routine must ensure that no other driver routine is currently using or might shortly be using a particular resource before it releases that resource.
In general, an Unload routine releases all driver-allocated resources in the following stages:
If the driver has not already done so, disable interrupts on any physical devices, if possible, and then call IoDisconnectInterrupt as soon as interrupts are disabled.
Ensure that no other driver routine can reference the resources that the Unload routine intends to release.
For example, an Unload routine must call IoStopTimer if the driver's IoTimer routine is currently enabled for a particular device object. It must ensure that no thread is waiting for any of the driver's dispatcher objects and that its timer objects are not queued for calls to its CustomTimerDpc routines before it frees the storage for its dispatcher objects. It must call KeRemoveQueueDpc if it has a CustomDpc routine that the ISR might have queued, and so on.
If the driver called IoQueueWorkItem, it must ensure that the work item has completed. IoQueueWorkItem takes out a reference on the associated device object; the driver cannot be unloaded if any such references remain.
If the driver called PsCreateSystemThread, the Unload routine also must cause the driver-created thread to be run so that the thread itself can call PsTerminateSystemThread before the driver is unloaded. A driver cannot release a driver-created system thread by calling ZwClose with the ThreadHandle returned by PsCreateSystemThread.
Release any device-specific resources that the driver allocated. Doing so might involve calling the following system support routines:
IoDeleteSymbolicLink if the DriverEntry or Reinitialize routine called IoCreateSymbolicLink or IoCreateUnprotectedSymbolicLink, and IoDeassignArcName if the driver called IoAssignArcName.
ExFreePool if DriverEntry or any other driver routine called ExAllocatePoolWithTag and the driver has not yet released the allocated memory.
MmUnmapIoSpace if the DriverEntry or Reinitialize routine called MmMapIoSpace.
MmFreeNonCachedMemory if the DriverEntry or Reinitialize routine called MmAllocateNonCachedMemory.
MmFreeContiguousMemory if the DriverEntry or Reinitialize routine called MmAllocateContiguousMemory.
FreeCommonBuffer if the DriverEntry or Reinitialize routine called AllocateCommonBuffer.
IoAssignResources or IoReportResourceUsage if the DriverEntry or Reinitialize routine called one of these support routines or HalAssignSlotResources to claim hardware resources in the configuration registry for itself and/or for its physical devices individually.
Release system objects and resources that the DriverEntry or Reinitialize routine set up in the device extension of the device objects or in the controller extension of the controller object (if it created one). In particular, the driver must do the following before it attempts to delete the device object (IoDeleteDevice) or controller object (IoDeleteController):
- Call IoDisconnectInterrupt to free the interrupt object pointer stored in the corresponding device or controller extension.
- Call ObDereferenceObject with the pointer to the next-lower driver's file object if it called IoGetDeviceObjectPointer and stored this pointer in a device or controller extension.
- Call IoDetachDevice with the pointer to the lower driver's device object if it called IoAttachDevice or IoAttachDeviceToDeviceStack and stored this pointer in a device or controller extension.
Free the hardware resources that the DriverEntry or Reinitialize routine claimed for the driver's physical devices, if any, in the registry under the \Registry\Machine\Hardware\ResourceMap tree.
Remove any names for its devices that the DriverEntry or Reinitialize routine stored in the registry under the \Registry..\DeviceMap tree, as well.
After the driver has released device, system, and hardware resources, it can delete its device and controller objects, as described in Releasing Device and Controller Objects.