; --------------------------------------- ;
; DRIVERS.ASM                             ;
;                                         ;
; Version 1.0                             ;
;                                         ;
; IC v2.0+ Installable Command            ;
;                                         ;
; Display installed device drivers list.  ;
;                                         ;
; Copyright (C) 1992, Geoff Friesen B.Sc. ;
; All rights reserved.                    ;
;                                         ;
; Developed with: Borland TASM 2.5        ;
; --------------------------------------- ;

_TEXT           SEGMENT BYTE PUBLIC 'CODE'
		ASSUME  cs:_TEXT, ds:_TEXT, es:_TEXT, ss:_TEXT
		ORG     100h

CR              EQU     13
LF              EQU     10

CLINE		EQU	10ah
; HEXW		EQU	10ch
STDINIT		EQU	10eh

_drivers:
		lea     dx, msg
		mov     ah, 9
		int     21h
		int     20h

msg             DB      "NONCOM$"

code_entry      DW      _code
help_entry      DW      _help
byline_entry    DW      _byline
setup_entry     DW      _setup
cleanup_entry   DW      _cleanup

DBUFSIZ		EQU	18
OBUFSIZ		EQU	66

_device		STRUC
 _next_dev	DD	?
 _attribute	DW	?
 _strategy	DW	?
 _interrupt	DW	?
 _name		DB	8 DUP (?)
_device		ENDS

_block		DB	"BLOC"
_char		DB	"CHAR"
_dashes		DB	"--------"
_dbuffer	_device	<>
_obuffer	DB	OBUFSIZ DUP (?), CR, LF
_title		DB	"Name        Type    Units    Attrib    Address"
		DB	"      Strat    Intrp"
		DB	CR, LF
		DB	"----        ----    -----    ------    -------"
		DB	"      -----    -----"
		DB	CR, LF
		DB	'$'

_code           PROC    NEAR
		push	cs
		pop	ds

		lea	dx, _title	; Display title.
		mov	ah, 9
		int	21h

		mov	ah, 52h		; Get DOS list of lists address.
		int	21h

		add	bx, 22h		; Point to NUL driver header.
_code1:
		call	_display	; Display driver information.

		mov	ax, es:[bx]	; Check for end of driver chain.
		cmp	ax, 0ffffh
		jz	_code2		; Branch if end.

		push	es:[bx]		; Point to next driver.
		push	es:[bx+2]

		pop	es
		pop	bx

		jmp	SHORT _code1	; Continue.
_code2:
		ret
_code           ENDP

; ------------------------------------------- ;
; DISPLAY: Display device driver information. ;
;                                             ;
; Entry: ES:BX - address of driver header     ;
;                                             ;
; Exit: AX, CX, SI, and DI destroyed          ;
; ------------------------------------------- ;

_display	PROC	NEAR
		push	bx
		push	ds
		push	es
		push	bp
		mov	bp, sp

		mov	ax, ds		; Swap DS and ES.
		mov	cx, es
		mov	es, ax
		mov	ds, cx

		mov	si, bx		; Copy driver data to local buffer.
		lea	di, _dbuffer
		mov	cx, DBUFSIZ
		rep	movsb

		push	cs		; Point DS back to our segment.
		pop	ds

		lea	di, _obuffer	; Set output buffer to all spaces.
		mov	cx, OBUFSIZ
		mov	al, ' '
		rep	stosb

		lea	si, _dashes

		test	_dbuffer._attribute, 8000h ; Character device?
		jz	_display1	; No, branch.

		lea	si, _dbuffer._name
_display1:
		mov	cx, 8
		lea	di, _obuffer

		rep	movsb		; Copy name or dashes.

		lea	si, _block	; Assume block device.

		test	_dbuffer._attribute, 8000h ; Character device?
		jz	_display2	; No, branch.

		lea	si, _char
_display2:
		mov	cx, 4
		add	di, 4

		rep	movsb

		lea	si, _dbuffer
		add	si, 10
		lodsb			; Get block device units.

		test	_dbuffer._attribute, 8000h ; Character device?
		jz	_display3	; No, branch.

		mov	al, 1
_display3:
		add	di, 4
		call	hexb

		mov	ax, _dbuffer._attribute
		add	di, 7
		call	hexw

		mov	ax, [bp+2]
		add	di, 6
		call	hexw

		mov	al, ':'
		stosb

		mov	ax, [bp+6]
		call	hexw

		mov	ax, _dbuffer._strategy
		add	di, 4
		call	hexw

		mov	ax, _dbuffer._interrupt
		add	di, 5
		call	hexw

		mov	ah, 40h		; Send output buffer to STDOUT.
		mov	bx, 1
		mov	cx, OBUFSIZ+2
		lea	dx, _obuffer
		int	21h

		pop	bp
		pop	es
		pop	ds
		pop	bx

		ret
_display	ENDP

; ----------------------------------------- ;
; HEXW: Display word in hexadecimal format. ;
;                                           ;
; Entry: AX - word to be displayed          ;
;                                           ;
; Exit: AX, and CX destroyed                ;
; ----------------------------------------- ;

hexw            PROC    NEAR
		push    bx

		push	ax

		mov     al, ah          ; Display most-significant byte.
		call    hexb

		pop     ax

		call    hexb            ; Display least-significant byte.

		pop     bx

		ret
hexw            ENDP

; ----------------------------------------- ;
; HEXB: Display byte in hexadecimal format. ;
;                                           ;
; Entry: AL - byte to be displayed          ;
;                                           ;
; Exit: AX and CX destroyed                 ;
; ----------------------------------------- ;

hexb            PROC    NEAR
		mov     ch, al
		mov     cl, 4
		shr     al, cl

		call    hexb1

		mov     al, ch
		and     al, 0fh
hexb1:
		mov     cl, '0'

		cmp     al, 9
		jbe     hexb2

		mov     cl, 37h
hexb2:
		add     al, cl
		stosb

		ret
hexb            ENDP

_help           DB      CR, LF
		DB      "DRIVERS: Display list of installed device drivers"
		DB      CR, LF
		DB	CR, LF
		DB	"Syntax: DRIVERS"
		DB	CR, LF
		DB	CR, LF
		DB	"The DRIVERS command generates a listing of every"
		DB	CR, LF
		DB	"installed device driver.  The name of the driver"
		DB	CR, LF
		DB	"is displayed in the leftmost column (unless this"
		DB	CR, LF
		DB	"driver is a block device in which cases 8 dashes"
		DB	CR, LF
		DB	"are displayed).  The listing is routed to STDOUT"
		DB	CR, LF
		DB	"which can be redirected (ex: drivers >listing)."
		DB	CR, LF
		DB	'$'

_byline         DB      "DRIVERS  - display installed device drivers list"
		DB      CR, LF
		DB      '$'

smsg		DB	CR, LF
		DB	"drivers: setting up"
		DB	CR, LF
		DB	'$'

_setup          PROC    NEAR
		lea	dx, smsg
		mov	ah, 9
		int	21h

		ret
_setup          ENDP

cmsg		DB	CR, LF
		DB	"drivers: cleaning up"
		DB	CR, LF
		DB	'$'

_cleanup        PROC    NEAR
		lea	dx, cmsg
		mov	ah, 9
		int	21h

		ret
_cleanup        ENDP

_TEXT           ENDS
		END     _drivers