5.1.2 DriverEntry's Additional Responsibilites
Depending on the position of a particular driver in a chain of layered NT drivers, on the nature of the underlying device, and on the design of the driver, its DriverEntry routine also can be responsible for doing following:
·In a lowest-level NT driver, the DriverEntry routine initializes the physical device.
·In a higher-level NT driver, the DriverEntry routine layers the driver over the next-lower-level driver(s), using one of the following techniques:
·To establish a connection between paired class/port drivers, the class driver calls IoGetDeviceObjectPointer with the name of the port driver's (primary) device object(s).
For example, a SCSI class driver calls IoGetDeviceObjectPointer repeatedly, passing an updated Unicode name string \Device\ScsiPortDigit where Digit is a count enumerating the SCSI HBAs in the machine. Then, the class driver uses the returned device object pointers to send get-configuration requests to the NT SCSI port driver, in order to determine which HBAs control a bus with attached devices of the class driver's type. (For more information about initializing SCSI drivers, see also Appendix A.)
A successful call to IoGetDeviceObjectPointer returns pointers to both the lower driver's device object and the file object associated with that device object. A higher-level driver must save the returned device object pointer so it can pass this device object pointer to IoCallDriver when it passes IRPs on for processing by lower drivers.
Few higher-level NT drivers except FSDs have any use for the returned pointer to the file object. However, a higher-level NT driver should save this returned pointer to the file object if it might break its connection to the lower driver later, for example when being unloaded. To break such a connection, higher-level drivers call ObDereferenceObject to release the file object pointer returned by IoGetDeviceObjectPointer.
For more information about driver Unload routines, see Chapter 15.
·To establish a connection between an NT intermediate or highest-level driver and a lower-level driver, the DriverEntry routine creates a device object and calls IoAttachDevice with a pointer to its newly created device object and a pointer to the name of the lower driver's device object.
Calling IoAttachDevice successfully allows a higher-level NT driver to intercept requests bound for the lower driver's device by aliasing the target device object to its own device object. Note that the device object created by the higher-level driver is not required to have a name, because the lower driver's device object is still the named target for I/O requests.
·Since the system itself can boot from an NT driver's floppy or CD-ROM device, the DriverEntry routine of such a driver must create a symbolic link between each possible boot device (the driver's named device object that represents a floppy or CD-ROM drive) and the corresponding ARC device by calling IoAssignArcName. For more information about the ARC firmware and the corresponding functionality in x86-based Windows NT platforms, see Chapter 16. For disk device drivers, the system sets up these symbolic links automatically.
·If an NT device or intermediate driver has a device-dedicated thread, its DriverEntry routine can call PsCreateSystemThread with the entry point for the driver's thread.
If a highest-level NT driver uses executive worker threads, as many NT file system drivers do, it must have a callback routine of type WORKER_THREAD_ROUTINE, which takes a single input PVOID Parameter.
·If a driver has an optional Reinitialize routine, its DriverEntry routine calls IoRegisterDriverReinitialization once if and only if the DriverEntry routine will return STATUS_SUCCESS. The driver can call IoRegisterDriverReinitialization as many times as the Reinitialize routine should be run. Usually, a driver with a Reinitialize routine is a higher-level NT driver. For more information about Reinitialize routines, see Section 5.3.
Providing Storage for System Resources
An NT driver must provide storage, usually in the device extension of a device object, for any Kernel-defined objects and executive spin locks it uses. NT drivers also must provide storage for pointers to certain objects obtained from the HAL or I/O Manager, as explained in Chapter 3.
Most device and intermediate drivers provide storage in their device or controller extensions for every NT object and system resource they use to process I/O requests. Their DriverEntry routines initialize certain resources, such as any Kernel-defined object stored in the device (or controller) extension, that the driver uses thereafter.
However, an NT driver designer might decide to allocate additional system-space memory for the driver's needs, such as for long-term I/O buffers or a zone buffer. If so, the DriverEntry routine can call one (or more) of the following routines:
·ExAllocatePool for paged or nonpaged system-space memory
·MmAllocateNonCachedMemory or MmAllocateContiguousMemory for cache-aligned nonpaged system-space memory (used for I/O buffers)
·HalAllocateCommonBuffer for drivers of devices that use continuous DMA
For more information about using memory, see Chapter 16. For more information about using common buffers for DMA, see the section on adapter objects in Chapter 3.