;
; A device driver utility
; prints the chain of DOS device drivers
;
; by Raymond Michels
;
;
cseg    segment

        assume cs:cseg,ds:cseg

        org     100h

ddhead  struc
next_dd         dd      0       ;
attrib          dw      0       ;
strat_ptr       dw      0       ;
int_ptr         dw      0       ;
dev_name        db      8 dup (0);
ddhead  ends



begin:
        mov     ax,es           ;get PSP segment for return
        mov     cs:psp_seg,ax
        mov     ax,cs
        mov     ds,ax           ;set DS to our CS
        mov     ss,ax
        mov     sp,offset ourstk
;
        mov     ah,52h          ;get dos variables
        int     21h
                                ;es:bx -> vars
        add     bx,22h          ;get to nul device

        mov     dx,offset crlf  ;print headers
        call    string_out
        mov     dx,offset head0
        call    string_out

loop1:
        call    prt_dd          ;print device driver info
        cmp     word ptr es:[bx],0FFFFh ;check if last driver in chain
        je      exit            ;yes - so exit
        les     bx,es:[bx]      ;get address of next driver
        jmp     short loop1

exit:
        mov     ax,cs:psp_seg
        mov     ds,ax
        mov     es,ax
        mov     ah,0            ;exit to dos
        int     21h


prt_dd  proc    near
;Print pertinent field of device driver header
;Input: ES:BX points to device driver header
;Output: None

        push    ax              ;save registers
        push    bx
        push    cx
        push    dx
        push    si

        mov     dx,es           ;segment of device driver
        call    hex_to_ascii
        mov     al,':'
        call    char_out

        mov     dx,bx           ;offset of device driver
        call    hex_to_ascii
        mov     al,' '
        call    char_out
        mov     al,' '
        call    char_out

        mov     dx,es:[bx.attrib]       ;attribute
        call    hex_to_ascii
        mov     al,' '
        call    char_out
        mov     al,' '
        call    char_out

        mov     dx,es           ;Print SEG:OFS of Strategy
        call    hex_to_ascii
        mov     al,':'
        call    char_out
        mov     dx,es:[bx.strat_ptr]
        call    hex_to_ascii
        mov     al,' '
        call    char_out

        mov     dx,es           ;Print SEG:OFS of Interrupt
        call    hex_to_ascii
        mov     al,':'
        call    char_out
        mov     dx,es:[bx.int_ptr]
        call    hex_to_ascii

        mov     al,' '
        call    char_out
        mov     al,' '
        call    char_out

        mov     ax,es:[bx.attrib];Print BLOCK or CHAR
        and     ax,0f000h
        test    ax,8000h
        jnz     is_char         ;Has Character Attribute

        mov     dx,offset block ;Print Out Block Info
        call    string_out
        mov     al,' '
        call    char_out

        mov     al,es:[bx+10]
        add     al,48
        call    char_out
        jmp     prt_dd1

is_char:mov     dx,offset char  ;Print Out Character Info
        call    string_out
        mov     al,' '
        call    char_out
        mov     si,bx
        add     si,10
        mov     cx,8

is_char_loop:                   ;Print Out Character Device Name
        mov     al,es:[si]
        inc     si
        call    char_out
        loopnz  is_char_loop

prt_dd1:
        mov     dx,offset crlf
        call    string_out

        pop     si              ;restore registers
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
prt_dd  endp

char_out proc near  ;output character in al
        push    dx
        mov     dl,al
        mov     ah,2
        int     21h
        pop     dx
        ret
char_out        endp


hex_to_ascii    proc    near    ;output hex word in dx
        push    cx
        push    ax
        mov     cx,4
hex1:
        push    cx
        mov     cl,4
        rol     dx,cl
        mov     al,dl
        and     al,0fh
        daa
        add     al,0f0h
        adc     al,040h
        call    char_out
        pop     cx
        loop    hex1

        pop     ax
        pop     cx
        ret
hex_to_ascii    endp

string_out      proc    near    ;print a string pointed to by DS:DX
                                ;first byte of string is length

        push    ax
        push    bx
        push    cx
        push    dx
        mov     ah,40h
        mov     bx,dx
        inc     dx      ;point to string
        mov     cl,[bx] ;get length
        mov     bx,1    ;standard output
        int     21h
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
string_out      endp

;
;data
;

head0   db      162,'     D E V I C E    D R I V E R    C H A I N      ',13,10
        db          'Drv Addrs  Atrb  Strategy  Interrupt  Type  Name/Unit',13,10
        db          '---------  ----  --------- ---------  ----- ---------',13,10
block   db      5,'Block'
char    db      5,'Char '
crlf    db      2,13,10
;
psp_seg dw      0

        align 4
        db      40 dup ('STACK   ')
ourstk  dw      ?

cseg    ends
end     begin


