;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
; 
;****************************************************************************
;*
;* dprintf - this routine displays information on the debug terminal. it
;*	     provides limited formatting, which is a subset of c's printf
;*	     function
;*
;*	calling sequence:	push selector for insert 'n'
;*				push offset for insert 'n'
;*				push selector for 'n-1'
;*				push offset for 'n-1'
;*				   ...
;*				push selector for second insert
;*				push offset for second insert
;*				push selector for first insert
;*				push offset for first insert
;*				push selector raw string
;*				push offset for raw string
;*				call dprintf
;*				add sp,4 + ('n' * 4)
;*
;*			for "%w", just push one word containing the data to
;*				  be displayed. make sure that the "add sp"
;*				  cleans the stack correctly.
;*
;*			for "%z", just the repeat count, then the selector
;*				  of the area to display, and then the offset.
;*				  make sure that the "add sp" cleans the stack
;*				  correctly.
;*
;*	formatting:	prior to being displayed, the raw string is formatted
;*			by scanning it for format control sequences. as each
;*			format control sequence is encountered, it is replaced
;*			by appropriately formatted text obtained from the
;*			corresponding pointer
;*
;*			the following format control sequences are supported:
;*
;*			%c -  the corresponding far ptr points to a byte
;*			      which replaces the "%c"
;*
;*			%u -  the corresponding far ptr points to a word
;*			      which is displayed as an unsigned decimal
;*			      integer, replacing the "%u"
;*
;*			%x -  the corresponding far ptr points to a word
;*			      which is displayed as upper case hex,
;*			      replacing the "%X"
;*
;*			%lx - the corresponding far ptr points to a double
;*			      word which is displayed as upper case hex,
;*			      replacing the "%X"
;*
;*			%s -  the corresponding far ptr points to a null
;*			      terminated string which is displayed unchanged,
;*			      replacing the "%s"
;*
;*			%p -  the corresponding far ptr is displayed as upper
;*			      case hex in the format "ssss:oooo"
;*
;*			%w -  the corresponding word is displayed as upper
;*			      case hex replacing the "%w". note that in this
;*			      case, only one word is pushed onto the stack
;*			      for the %w insert
;*
;*			%z -  using the corresponding repeat count and far
;*			      pointer, a memory dump is produced. note that
;*			      in this case the stack contains a repeat count
;*			      and a far pointer to the area to dump
;*
;*			%% -  the character "%" is displayed, replacing the
;*			      "%%"
;*
;*


.286p


COM1_PORT	EQU	03f8h
COM2_PORT	EQU	02f8h


DEFAULT_PORT	EQU	COM1_PORT

CAR_RET 	EQU	0DH
LINE_FEED	EQU	0AH
BELL		EQU	07H
COM_LSR 	EQU	05H
COM_DAT 	EQU	00H



s_frame 	struc

s_bp		dw	?		; callers bp.
s_ptr_delta	dw	?		; delta (in bytes) to current pointer
					; from first pointer.
s_ret		dw	?		; callers ip.
s_string	dd	?		; far pointer to raw string.
s_ptrs		dd	?		; pointer to first variable.

s_frame 	ends

;word_10000	 dw	 10000
;word_1000	 dw	 1000
;word_100	 dw	 100
;word_10	 dw	 10


_DATA           segment dword public 'DATA'

                extrn  _ComPort:word

_DATA           ends


_TEXT	segment dword public 'code'
	assume	cs:_TEXT,ds:_DATA

_dprintf	proc	near
		public	_dprintf


		push	0		; zero the delta to current pointer.

		push	bp		; save our callers bp register.
		mov	bp,sp		; point to our stack frame.

		push	ds		; save our callers ds register.
		push	es		; save our callers es register.
		pusha			; save all other caller registers.
		pushf
		cli

		lds	si,ss:[bp+s_string] ; point to the raw string.

dprintf_loop:	lodsb			; pick up a byte of the string.

		or	al,al		; is it the end of the string?
		jnz	dprintf_more	; no, go check for format control.

		popf
		popa			; restore all other caller registers.
		pop	es		; restore our callers es register.
		pop	ds		; restore our callers ds register.
		pop	bp		; restore our callers bp register.
		add	sp,2		; unstack s_ptr_delta.

		ret			; return to our caller.

dprintf_more:	cmp	al,'%'          ; no, is it the start of a format
					; control sequence?
		je	dprintf_type	; yes, go see what type of sequence.
		jmp	dprintf_put_ch	; no, go display character and return.

dprintf_type:	lodsb			; pick up a byte of the string.
		cmp	al,'%'          ; is caller trying to display "%"?

		jne	dprintf_try_c	; no, go see if it is a "c".

		mov	al,'%'          ; yes, go display it
		jmp	dprintf_put_ch	; and exit.

dprintf_try_c:	cmp	al,'c'          ; is it a string display?
		jne	dprintf_try_s	; no, go see if it is a "s".

		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding
		les	bx,ss:[bx]	       ; pointer.
		add	ss:[bp+s_ptr_delta],4  ; move down to next pointer.

		mov	al,es:[bx]	; pick up a byte.
		jmp	dprintf_put_ch	; go display character and return.

dprintf_try_s:	cmp	al,'s'          ; is it a string display?
		jne	dprintf_try_u	; no, go see if it is a "u".

		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding
		les	bx,ss:[bx]	       ; pointer.
		add	ss:[bp+s_ptr_delta],4  ; move down to next pointer.

dprintf_next_s: mov	al,es:[bx]	; pick up a byte.

		or	al,al		; is it the end of the string?
		jz	dprintf_loop	; yes, go do next raw string byte.

		call	put_char	; no, display the character.

		inc	bx		; move down to the next character
		jmp	dprintf_next_s	; and go round again.

dprintf_try_u:	cmp	al,'u'          ; is it an unsigned short display?
		jne	dprintf_try_x	; no, go see if it is a "X".

		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding
		les	bx,ss:[bx]	       ; pointer.
		add	ss:[bp+s_ptr_delta],4  ; move down to next pointer.

		mov	ax,es:[bx]	; pick up the word to display.

		xor	dx,dx		; convert the
		mov	cx, 10000
		div	cx		; ten thousands
;		div	word_10000	; ten thousands
		or	al,'0'          ; digit and
		call	put_char	; display it.

		mov	ax,dx		; convert the
		xor	dx,dx		; thousands
		mov	cx, 1000
		div	cx		; digit
;		div	word_1000	; digit
		or	al,'0'          ; and
		call	put_char	; display it.

		mov	ax,dx		; convert the
		xor	dx,dx		; hundreds
		mov	cx, 100
		div	cx		; digit
;		div	word_100	; digit
		or	al,'0'          ; and
		call	put_char	; display it.

		mov	ax,dx		; convert the
		xor	dx,dx		; tens
		mov	cx, 10
		div	cx		; digit
;		div	word_10 	; digit
		or	al,'0'          ; and
		call	put_char	; display it.

		mov	al,dl		; convert the units digit
		or	al,'0'          ; and go display it
		jmp	dprintf_put_ch	; and return.

dprintf_try_x:	cmp	al,'x'          ; is it an unsigned short hex display?
		jne	dprintf_try_lx	; no, go see if it is a "lX".

		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding
		les	bx,ss:[bx]	       ; pointer.
		add	ss:[bp+s_ptr_delta],4  ; move down to next pointer.

		call	put_hex_word	; convert and display the word.

		jmp	dprintf_loop	; go do next raw string byte.

dprintf_try_lx: cmp	al,'l'          ; is it an unsigned long hex display?
		jne	dprintf_try_p	; no, go see if it is a "p".
		lodsb			; maybe, pick up a byte of the string.
		cmp	al,'x'          ; is the second byte correct?
		je	dprintf_do_lx	; no, go report
		jmp	dprintf_error	; the error.

dprintf_do_lx:	lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding
		les	bx,ss:[bx]	       ; pointer.
		add	ss:[bp+s_ptr_delta],4  ; move down to next pointer.

		add	bx,2		; move down to the second word.
		call	put_hex_word	; convert and display the second word.
		sub	bx,2		; move back to the first word.
		call	put_hex_word	; convert and display the first word.

		jmp	dprintf_loop	; go do next raw string byte.

dprintf_try_p:	cmp	al,'p'          ; is it a far pointer display?
		jne	dprintf_try_w	; no, go see if it is a "w".

		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding pointer.
		add	ss:[bp+s_ptr_delta],4  ; move down to next pointer.

		push	es		; save the callers data selector.

		push	ss		; set up the proper
		pop	es		; selector.

		add	bx,2		; move down to the second word.
		call	put_hex_word	; convert and display the selector.
		mov	al,':'          ; display
		call	put_char	; the ":".
		sub	bx,2		; move back to the first word.
		call	put_hex_word	; convert and display the offset.

		mov	al,' '          ; display
		call	put_char	; a couple
		mov	al,' '          ; of
		call	put_char	; spaces.

		pop	es		; recover the callers data selector.

		jmp	dprintf_loop	; go do next raw string byte.

dprintf_try_w:	cmp	al,'w'          ; is it an immediate word display?
		jne	dprintf_try_z	; no, go see if it is a "z".

		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding pointer.
		add	ss:[bp+s_ptr_delta],2  ; move down to next pointer.

		push	es		; save the callers data selector.

		push	ss		; set up the proper
		pop	es		; selector.

		call	put_hex_word	; convert and display the word.

		pop	es		; recover the callers data selector.

		jmp	dprintf_loop	; go do next raw string byte.

dprintf_try_z:	cmp	al,'z'          ; is it a memory dump display?
		je	dprintf_do_z	; no, go report
		jmp	dprintf_error	; the error.

dprintf_do_z:
		lea	bx,[bp]+s_ptrs	       ; yes, pick up the
		add	bx,ss:[bp+s_ptr_delta] ; corresponding pointer.
		add	ss:[bp+s_ptr_delta],6  ; move down to next pointer.

		mov	cx,ss:[bx+4]	; pick up the repeat count.

		push	es		; save the callers data selector.

		les	bx,ss:[bx]	; point to the area to display.

dprintf_z_a:	mov	ax,es		; pick up the selector to display.
		xchg	ah,al		; set up to process the first byte.
		call	put_left_nib	; display the first byte
		call	put_right_nib	; of the selector.
		xchg	ah,al		; set up to process the second byte.
		call	put_left_nib	; display the second byte
		call	put_right_nib	; of the selector.

		mov	al,':'          ; display a
		call	put_char	; colon.

		mov	ax,bx		; pick up the offset to display.
		xchg	ah,al		; set up to process the first byte.
		call	put_left_nib	; display the first byte
		call	put_right_nib	; of the offset.
		xchg	ah,al		; set up to process the second byte.
		call	put_left_nib	; display the second byte
		call	put_right_nib	; of the offset.

		mov	al,' '          ; display
		call	put_char	; two
		mov	al,' '          ; seperating
		call	put_char	; spaces.

		push	cx		; save the repeat count for later.

		mov	dx,16*3+1	; initialize the fill count.

		cmp	cx,16		; are there more than 16 bytes left?
		jbe	dprintf_z_b	; yes, limit it to 16 bytes
		mov	cx,16		; for this line.

dprintf_z_b:	push	bx		; save offset and display count
		push	cx		; for the character display.

dprintf_z_c:	mov	al,es:[bx]	; pick up a byte to display.
		call	put_hex_byte	; display it in hex.

		mov	al,' '          ; set up to display a space.
		cmp	dx,9*3+1	; should it be a dash?
		jne	dprintf_z_e	; no, bypass changing it.
		mov	al,'-'          ; yes, set up to display a dash.
dprintf_z_e:	call	put_char	; display the dash or space.

		sub	dx,3		; down the fill count by one position.

		inc	bx		; move down to the next byte.

		loop	dprintf_z_c	; more to do? yes, go round again?

		mov	cx,dx		; no, pick up remaining fill count.

dprintf_z_g:	mov	al,' '          ; display a
		call	put_char	; space.

		loop	dprintf_z_g	; more to do? yes, go round again.

		pop	cx		; recover the offset and
		pop	bx		; display count.

dprintf_z_i:	mov	al,'.'          ; set up to display a dot.

		mov	ah,es:[bx]	; does the byte
		cmp	ah,20h		; contain a
		jb	dprintf_z_k	; valid ascii
		cmp	ah,7fh		; code?
		ja	dprintf_z_k	; no, go display the dot.

		xchg	al,ah		; yes, set up to do byte's contents.

dprintf_z_k:	call	put_char	; display a dot or the byte contents.

		inc	bx		; move down to the next byte.

		loop	dprintf_z_i	; more to do on this line?
					; yes, go round again.

		pop	cx		; no, recover the repeat count.

		sub	cx,16		; down the repeat count by one line.

		jle	dprintf_z_z	; more to do? no, go exit.

		mov	al,CAR_RET	; perform
		call	put_char	; a
		mov	al,LINE_FEED	; new line
		call	put_char	; operation.

		jmp	dprintf_z_a	; go round and display another line.

dprintf_z_z:	pop	es		; recover the callers data selector.

		jmp	dprintf_loop	; go do next raw string byte.

dprintf_error:	mov	ah,al		; display
		mov	al,'?'          ; an
		call	put_char	; eye
		mov	al,'\'          ; catching
		call	put_char	; "invalid
		mov	al,ah		; format
		call	put_char	; control"
		mov	al,'\'          ; message
		call	put_char	; and
		mov	al,BELL 	; beep.

dprintf_put_ch: call	put_char	; display the character.
		jmp	dprintf_loop	; go process next raw string byte.

_dprintf	endp

put_left_nib	proc	near

		push	ax		; save the callers ax register.

		shr	al,4		; convert the
		add	al,'0'          ; left nibble
		cmp	al,'9'          ; to an ascii
		jbe	put_left_nib_a	; hex
		add	al,'A'-'9'-1    ; representation.
put_left_nib_a: call	put_char	; display the character.

		pop	ax		; restore the callers ax register.

		ret			; return to our caller.

put_left_nib	endp

put_right_nib	proc	near

		push	ax		; save the callers ax register.

		and	al,0fh		; convert the
		add	al,'0'          ; right nibble
		cmp	al,'9'          ; to an
		jbe	put_rght_nib_a	; ascii hex
		add	al,'A'-'9'-1    ; representation.
put_rght_nib_a: call	put_char	; display the character.

		pop	ax		; restore the callers ax register.

		ret			; return to our caller

put_right_nib	endp

put_hex_byte	proc	near

		mov	al,es:[bx]	; display the left nibble
		call	put_left_nib	; in ascii hex.

		mov	al,es:[bx]	; display the right nibble
		call	put_right_nib	; in ascii hex.

		ret			; return to our caller.

put_hex_byte	endp


put_hex_word	proc	near

		inc	bx		; set up to process second byte first.

		call	put_hex_byte	; display the byte in hex.

		dec	bx		; move back to the first byte.

		call	put_hex_byte	; display the byte in hex.

		ret			; return to our caller.

put_hex_word	endp


;		 public  portadr
;portadr	 dw	 DEFAULT_PORT	 ; change config.h to change this.
					; use: com2=02f8H, com1=03f8H

IODelay Macro
    local a
    jmp a
a:
endm

PollC	PROC	NEAR
	public	PollC

;	mov	dx, cs:PortAdr
	mov	dx, _ComPort
	add	dx, COM_LSR

	in	al,dx			; get input status
;	IODelay

	and	al,1			; is there a char in RECV buffer?
	jz	plc1			; no, go return empty

;	mov	dx, cs:PortAdr
	mov	dx, _ComPort
	add	dx, COM_DAT

	in	al,dx			;      char out of buffer
;	IODelay

	and	al,07fh 		; strip off        parity crap
plc1:	ret
PollC	ENDP


;**	PUTC - output a single char to COM2 handling ^S


put_char	proc	near
		public	put_char

	push	dx
	push	ax

;	See if ^S

	call	PollC		    ; is there a char at input
	jz	pc2		    ; no, go output our char
	cmp	al,'S' - 'A' + 1    ; is it ^S?
	jnz	pc2		    ; no, go output our char

;	Saw ^S.  Wait for and eat next char.

pc1:	call	PollC		    ; look for next char
	jz	pc1		    ; no char, go look again
	cmp	al,'S' - 'A' + 1    ; is it ^S again?
	jz	pc1		    ; yes, go look for something else

;pc2:	 mov	 dx, cs:PortAdr
pc2:	mov	dx, _ComPort
	add	dx, COM_LSR
	in	al,dx
;	IODelay
	test	al,020h
	jz	pc2

;	ready.	crank it out!

;	mov	dx, cs:PortAdr
	mov	dx, _ComPort
	add	dx, COM_DAT
	pop	ax
	out	dx,al

		pop	dx		; restore the callers dx register.

	ret

put_char	endp

_TEXT	ends
	end

