[oR]
Code Example: Driver UnloadIn the Minimal driver, an Unload routine is supplied that undoes the work of DriverEntry. Its work is straightforward, as it must delete each symbolic link and device object that has been created. To perform this work, the Unload routine relies on the fact that the driver object points to a linked list of device objects controlled by the driver. The first device controlled by a driver is pointed to by the field DeviceObject within the driver object. Each device points to the next via the field NextDevice . When examining the Unload routine, remember that the Minimal DEVICE_EXTENSION structure maintains a back pointer to the parent device object.
//++
// Function: DriverUnload
//
// Description:
// Stops & Deletes devices controlled by this driver.
// Stops interrupt processing (if any)
// Releases kernel resources consumed by driver
//
// Arguments:
// pDriverObject - Passed from I/O Manager
//
// Return value:
// None
// -
VOID DriverUnload (
IN PDRIVER_OBJECT pDriverObject ) {
PDEVICE_OBJECT pNextObj;
// Loop through each device controlled by Driver
pNextObj = pDriverObject->DeviceObject;
while (pNextObj != NULL) {
// Dig out the Device Extension from the
// Device Object
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
// This will yield the symbolic link name
UNICODE_STRING pLinkName =
pDevExt->ustrSymLinkName;
// ... which can now be deleted
IoDeleteSymbolicLink(&pLinkName);
// a little trickery...
// we need to delete the device object, BUT
// the Device object is pointed to by pNextObj
// If we delete the device object first,
// we can't traverse to the next Device in the list
// Rather than create another pointer, we can
// use the DeviceExtension's back pointer
// to the device.
// So, first update the next pointer...
pNextObj = pNextObj->NextDevice;
// then delete the device using the Extension
IoDeleteDevice( pDevExt->pDevice );
}
// Finally, hardware that was allocated in DriverEntry
// would be released here using
// IoReportResourceUsage
}
|
[oR]
Writing Shutdown RoutinesIf a driver has special processing to do before the operating system disappears, a driver should supply a Shutdown routine. Execution ContextThe I/O Manager calls a Shutdown routine during a system shutdown. As described in Table 6.5, the Shutdown routine runs at PASSIVE_LEVEL IRQL, which means it has access to paged system resources. Table 6.5. Function Prototype for Shutdown Routine
What a Shutdown Routine DoesThe main purpose of the Shutdown routine is to put the device into a quiescent state and perhaps store some device information into the system Registry. Again, saving the current volume settings from a sound card is a good example of something a Shutdown routine might do. Unlike the driver's Unload routine, Shutdown routines don't have to worry about releasing driver resources because the operating system is about to disappear anyway. Enabling Shutdown NotificationThere is no direct field in the Driver object for announcing the Shutdown routine. Instead, the event of system shutdown is sent as a separate I/O request to a driver. It is handled with an entry inside of the driver's MajorFunction code array. Additionally, the I/O Manager must be notified that a driver is interested in receiving shutdown notifications. This is done by making a call to IoRegisterShutdownNotification . The following code fragment shows how to enable shutdown notifications in a driver.
NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath ) {
:
pDriverObject->MajorFunction[ IRP_MJ_SHUTDOWN ] =
Shutdown;
IoRegisterShutdownNotification( pDriverObject );
:
}
|