9.7 Device-Driver Initialization

MS-DOS loads and initializes installable device drivers in the order in which their corresponding device or devicehigh commands appear in the CONFIG.SYS file. When loading a driver, MS-DOS does not create a program segment prefix (PSP) or an environment block. Instead, it allocates enough memory to load the contents of the driver file and copies the contents from disk, placing the device-driver header at the beginning of the allocated memory. MS-DOS then calls the strategy and interrupt routines with a request packet for Init (Device-Driver Function 00h). The form of this request packet corresponds to an INITREQUEST structure:

INITREQUEST STRUC

irLength db ? ;length of record, in bytes

irUnit db ? ;not used

irFunction db 00h ;function number

irStatus dw ? ;status

irReserved db 8 dup(?) ;reserved

irUnits db ? ;OUTPUT: number of units

irEndAddress dd ? ;INPUT: end available driver memory

;OUTPUT: end resident code

irParamAddress dd ? ;INPUT: addr CONFIG.SYS device= line

;OUTPUT: addr BPB pointer array

irDriveNumber db ? ;INPUT: first drive number

irMessageFlag dw ? ;OUTPUT: error-message flag

INITREQUEST ENDS

For a full description of the INITREQUEST structure, see Init (Device-Driver Function 00h).

When processing the Init function, the interrupt routine should carry out any initialization required, such as processing arguments specified on the device or devicehigh command line. Note that only a few MS-DOS system functions are available during initialization (Interrupt 21h Functions 01h through 0Ch, 25h, 30h, and 35h). In general, the interrupt routine can display messages at the standard output device, but it cannot open files or allocate additional memory.

Initially, the irEndAddress value in the request packet contains the segment address of the next memory block after the driver, regardless of whether the device driver is loaded using the device or devicehigh command. The driver can use the memory up to this address. If the devicehigh command is used to load a driver into the upper memory area, the driver's code- and data-segment addresses may be greater than A000h, and the address space immediately following the driver may contain ROM or memory-mapped devices and not necessarily RAM.

To complete the initialization, the interrupt routine must copy the address of the end of the driver to the irEndAddress field in the request packet. Block-device drivers must also copy the number of units they support and the address of an array of BIOS parameter blocks (BPBs) to corresponding fields in the request packet. Finally, the interrupt routine must set the done bit (bit 8) in the irStatus field and return.

If a driver cannot be initialized, it must set both the error bit (bit 15) and the done bit (bit 8) in the irStatus field. It must also set the irUnits field to zero and set irEndAddress the driver's starting address. MS-DOS then discards the driver and frees its memory for use by the next driver.

MS-DOS initializes a driver only once. This means the interrupt routine should free the memory containing its initialization code and data. The driver cannot free memory directly, but MS-DOS frees it for the driver when the driver specifies its ending address in the request packet. MS-DOS uses this ending addess to reallocate the memory block containing the driver. If the initialization code and data are at the end of the driver and the driver sets the irEndAddress field properly, MS-DOS frees their memory when reallocating the block.

An installable device driver that has the same logical-device name as an existing character-device driver effectively replaces the existing driver. The old driver remains in memory, however, and its strategy and interrupt routines can be called by the new driver to access the given device. This is one way a new driver can extend the capabilities of an existing driver.

The new driver can retrieve the addresses of the old driver's strategy and interrupt routines by searching the driver chain for device-driver headers that have matching logical-device names. (The new driver is at the top of the driver chain, and the dhLink field in its device-driver header contains the address of the next driver in the chain. For the last driver in the chain, the dhLink field contains 0FFFFh.) The old driver's address can be retrieved only after the new driver has completed its initialization.