;From: bobs@access.digex.net (Bob Smith)
;Newsgroups: alt.lang.asm
;Subject: Re: Assembling to SYS

comment ^
In fact it is possible to have a device driver in .COM format (meaning that
the first two bytes are not 'MZ') which can execute from the DOS command
line as well.  For the sake of completeness, I'll explain how, but I suspect
you won't want to use this approach.

Note that the first four bytes of a device driver header are used as a link
field to the next device driver in sequence.  However, DOS doesn't examine
these bytes until the DD returns from its initialization call, so they can
be set initially to whatever you like just as long as they are valid after
the initialization call.  Of course, unless you have a nested DD, the first
word should be set to -1.

Thus the first few bytes of the DD header can be a near (three byte) or
short (two byte) jump over the rest of the DD header.  The disadvantage
(and it's not a small one) of this combination is that all immediate
displacement data references in the DD part of the file must be
artificially reduced by 100h (the difference between the two file format's
origins).  This makes it awkward (but not impossible) to share code between
the two file formats (.COM file and DD).  Because of this complication,
this mixed format beast is pretty much relegated to being written in
assembler language.  All in all, it's much easier to write a mixed format
program as an .EXE file.  So what if it won't run on DOS 2.x?

At the risk of overlengthening this message (and boring the socks off you),
here's some sample code which creates a combination .COM file and device
driver:
==================================================^
.286

DD_STR  struc

DD_NEXT  dd     -1              ; Pointer to next device drive in chain
DD_ATTR  dw     ?               ; Attributes
DD_STRA  dw     ?               ; Offset of strategy routine
DD_INTR  dw     ?               ; Offset of interrupt routine
DD_NAME  db     '        '      ; Char device[0-7] = name,
                                ; Block device[0] = # units,
                                ;             [1-7] = undefined

DD_STR   ends


SRH_STR  struc                  ; Status request header

SRH_LEN  db     ?               ; 00-00:  Length
SRH_UCD  db     ?               ; 01-01:  Unit code
SRH_CCD  db     ?               ; 02-02:  Command code
SRH_STA  dw     ?               ; 03-04:  Status
SRH_RES  db     8 dup (?)       ; 05-0C:  Reserved area

SRH_STR  ends


VECTOR   struc

VOFF     dw      ?              ; Offset
VSEG     dw      ?              ; Segment

VECTOR   ends



CODE    segment dword public 'code'
        assume  cs:CODE,ds:CODE

        org     100h
START:
DRV_ATTR_CHAR equ     8000h     ; Character device
DDHDR   DD_STR  <, DRV_ATTR_CHAR, \
                ENTER_STRA-100h,  \
                ENTER_INTR-100h,  \
                'FOO'>
L1:
        org     START

        jmp     short L1

        org     L1

; Put .COM file entry point code here.




        ret                     ; Return to DOS


        align   4
RH_VEC  VECTOR  <>

        assume  ds:nothing
ENTER_STRA:

; Put DD strategy entry point code here.
; For the DD code, all immediate displacement data references must
; be reduced by 100h as demonstrated by the next two instructions.

        mov     RH_VEC.VSEG-100h,es ; Save for later use
        mov     RH_VEC.VOFF-100h,bx ; ...

        retf                    ; Return to caller


ENTER_INTR:
        assume  ds:nothing

; Put DD interrupt entry point code here.

        pusha                   ; Save for a moment
        push    es              ; ...

        les     bx,RH_VEC-100h  ; ES:BX ==> request header
        assume  es:nothing      ; Tell the assembler about it

        cmp     es:[bx].SRH_CCD,0 ; Izit initialization time?
        jne     short XINIT     ; Jump if not

        mov     DDHDR.DD_NEXT.VOFF-100h,-1 ; Set to non-nested value
        mov     DDHDR.DD_NEXT.VSEG-100h,-1 ; ...

; Put DD initialization code here.




        jmp     EXIT

XINIT:

; Put DD non-initialization code here.




EXIT:
        pop     es              ; Restore
        popa                    ; ...

        retf                    ; Return to caller

CODE    ends

        end     START


