Removing a Device in a Function Driver
When removing a device, a function driver must undo any operations it performed to add and start the device. This discussion includes function drivers for peripheral devices and function drivers for bus devices.
A function driver removes a device using a procedure such as the following in its DispatchPnP routine:
Is this a function driver for a bus device?
If so, possibly delete any outstanding child PDOs for devices on the bus.
If the bus driver handled a previous IRP_MN_SURPRISE_REMOVAL request for the child device, but the driver has not yet received the subsequent IRP_MN_REMOVE_DEVICE request, the bus driver leaves the child PDO intact. At some later time, when all handles to the child device are closed, the PnP manager will send the remove IRP for the child device and the bus driver deletes the child PDO at that time.
If the bus driver handled a previous IRP_MN_REMOVE_DEVICE request for the device, and there has been no subsequent IRP_MN_SURPRISE_REMOVAL request, then the bus driver deletes the child PDO. In this case, the PnP manager ensures that any function and filter drivers have been removed from the child device (FDO and filter DOs have been deleted) before it sends a remove IRP to the parent bus device. The child PDO might still be present, so the bus driver must delete the child PDO before it removes the bus device.
Has the driver already handled a previous IRP_MN_SURPRISE_REMOVAL request for this FDO?
If so, perform any remaining clean-up and skip to step 8, IoCallDriver.
A driver typically maintains a flag in the device extension that indicates whether the driver has handled an IRP_MN_SURPRISE_REMOVAL request for the device.
If the driver previously enabled the device for wake-up, cancel the IRP_MN_WAIT_WAKE request.
Ensure that the device is inactive.
If the device is not already inactive in response to a prior IRP_MN_QUERY_REMOVE_DEVICE, the driver must mark the device as not accepting new requests and must complete any requests queued in this driver. The driver must fail any outstanding requests that require access to the device.
A driver can use the IoXxxRemoveLockXxx routines to count outstanding I/O and to set an event indicating that remove processing can continue.
Perform any power-down operations.
Each driver for the device performs its power-down operations, if any, when it receives the IRP_MN_REMOVE_DEVICE request. The power policy owner for the device, typically the function driver, does not send a separate IRP_MN_SET_POWER request to set the device power state to D3. The parent bus driver typically powers down the slot and notifies the power manager with PoSetPowerState when the bus driver gets the remove IRP. For additional information, see Power Management.
Disable any device interfaces by calling IoSetDeviceInterfaceState.
Free any hardware resources for the device in use by the driver.
The exact operations depend on the device and the driver but can include disconnecting an interrupt with IoDisconnectInterrupt, freeing physical address ranges with MmUnmapIoSpace, and freeing I/O ports.
Pass the IRP_MN_REMOVE_DEVICE request down to the next driver.
Set up the IRP stack location for the next lower driver with IoSkipCurrentIrpStackLocation and pass the IRP to the next driver with IoCallDriver.
A driver is not required to wait for underlying drivers to finish their remove operations before continuing with its remove activities.
Remove the device object from the device stack with IoDetachDevice.
Specify a pointer to the next lower device object as the TargetDevice parameter. The driver receives such a pointer from the call to IoAttachDeviceToDeviceStack in the driver's AddDevice routine.
Clean up any device-specific allocations, memory, events, and so forth.
Free the FDO with IoDeleteDevice.
Return from the DispatchPnP routine, propagating the return status from IoCallDriver.
A function driver does not specify an IoCompletion routine for a remove IRP, nor does it complete the IRP. Remove IRPs are completed by the parent bus driver.