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


