Device Driver Basics
█▌Overview▐█
An installable device driver is a specially-formatted program that is
loaded into memory via a DEVICE= or DEVICEHIGH= command in CONFIG.SYS.
The first part of the file must be an 18-byte Device Header structure.
The first four bytes are modified by DOS upon installation. The file is
installed into a chain of device drivers:
╔══════ Device Header ════════╗
╓───┬───┬┬┬┬┬┬┬───────────────╥─ - - - - - - - - - - - - - ─┐
╔═══════nextDev│ │N U L ║ code and data of NUL device │
║ ╙─┴─┴─┴─┴┴┴┴┴┴┴─┴─┴─┴─┴─┴─┴─┴─╨─ - - - - - - - - - - - - - ─┘
║ ╔═══►╓───┬───┬┬┬┬┬┬┬───────────────╥─ - - - - - - - - - - - - - - - ─┐
║ ║ ╔═══nextDev│ │C O N ║ code+data of standard CON device│
║ ║ ║ ╙─┴─┴─┴─┴┴┴┴┴┴┴─┴─┴─┴─┴─┴─┴─┴─╨─ - - - - - - - - - - - - - - - ─┘
║ ║ ╚═►╓───┬───┬┬┬┬┬┬┬───────────────╖
║ ║ ╔═══nextDev│ │L P T 1 ║
║ ║ ╚═►╟─┴─┴─┴─┼┴┴┴┴┴┴─┴─┴─┴─┴─┴─┴─┴─╫─ - - - - - - - - - - - ──┐
║ ║ ║ ffff│ │L P T 2 ║ code+data of LPTn devices│
║ ║ ╙─┴─┴─┴─┴┴┴┴┴┴┴─┴─┴─┴─┴─┴─┴─┴─╨─ - - - - - - - - - - - ──┘
╚═════►╓───┬───┬┬┬┬┬┬┬───────────────╥─ - - - - - - - - - - - - - - - ─┐
╚═════nextDev│ │C O N ║ code+data of ANSI.SYS CON device│
╙─┴─┴─┴─┴┴┴┴┴┴┴─┴─┴─┴─┴─┴─┴─┴─╨─ - - - - - - - - - - - - - - - ─┘
When installing, DOS points nextDev of the NUL device to the new driver
(e.g., ANSI.SYS above) and stores whatever was in the NUL device's nextDev
into ANSI.SYS's nextDev field.
This process inserts the driver near the start of the chain. In the
example, any access to the device name of CON is satisfied by the
installed driver, rather than the original.
The device driver file is a binary image file. After assembling the
source code, use EXE2BIN to convert to a binary file (or link it as a
"tiny model" program). Unlike a COM-format file, do not include an
ORG 100H at the start of the code and do not assume that a PSP or
environment has been prepared for you.
Note: It is possible to use the EXE file format for a device driver.
The trick it to put the device header at the very start of your
data segment.
However, some older versions of IBM's OEM version (PC-DOS) cannot
load an EXE file via the DEVICE= command.
█▌Strategy and Interrupt▐█
Two of the fields in the device header are 16-bit pointers to within the
device driver code segment--the Strategy routine and the Interrupt
routine.
When an application uses a DOS function (such as INT 21H services) which
require action of a device, DOS makes two calls to the driver. First, it
calls the Strategy routine, passing it information about the requested
action. It then calls the Interrupt routine.
■ When DOS calls the Strategy routine, it sets ES:BX to the address of a
Device Request information structure. The "request packet" always
begins with a 13-byte DevRequestHdrRec, followed by 0 or more bytes of
data that varies, depending upon the request command code.
The device driver should simply save the address passed in ES:BX, for
later use by the Interrupt routine.
■ Then DOS calls the Interrupt routine, passing no parameters. The
Interrupt routine inspects the data passed to the Strategy routine and
takes the requested action.
Upon completion of a request, the driver should set the DevStatusWord
in the request structure to indicate completion (and any errors), then
return to DOS via a FAR return.
This two-call system was designed as a way for a "smart device" to enqueue
requests, with the idea of perhaps improving performance by acting on them
in a different order than originally requested. To my knowledge, no DOS
device driver does this. It is probably valid to assume that a call to
the Strategy routine will be followed immediately by a call to the
Interrupt routine.
See Also: Device Requests
Installable Device Drivers
-♦-