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
                                    -♦-