	PAGE 60,132
;---------------------------------------------------------------------------+
;	Replacment CON device driver - traps and translates ANSI escape
;	sequences for HOME and cursor positioning to what ever the terminal
;	on serial port A expects (via a translation table)
;
;	SLICER MSDOS BIOS    January 30, 1985    Vers 1.0
;	(c) Copyright Slicer Computers Inc., 1985
;
;       David Daney, 1985
;
;----------------------------------------------------------------------------+
w		equ	word ptr
b		equ	byte ptr 
false		equ	0
true		equ	not false
;
;
;  Select type of translation.
;
input_xlat	equ	true
output_xlat	equ	true
;
;	E Q U A T E S
;
; READ/WRITE
;
request_header	struc
r_h_length  	db	?
unit_code   	db	?
command_code	db	?
status		dw	?
		db	8 dup (?)
request_header	ends

init_command	struc
		db	13 dup (?)
number_of_units	db	?
end_address	dd	?
bpb_ptr1	dd	?
init_command	ends

input_cmd	struc
		db	13 dup (?)
media_desc_inp	db	?
inp_buffer	dd	?
inp_count	dw	?
inp_start	dw	?
input_cmd	ends

output_cmd	struc
		db	13 dup (?)
media_desc_out	db	?
out_buffer	dd	?
out_count	dw	?
out_start	dw	?
output_cmd	ends

non_d_input_cmd	struc
		db	13 dup (?)
inp_byte	db	?
non_d_input_cmd	ends

;
;
;
;
stat_error	equ	08000h
stat_done	equ	0100h
stat_busy	equ	0200h
unknown_unit	equ	stat_error+1
not_ready	equ	stat_error+2
unknown_cmd	equ	stat_error+3
crc_error	equ	stat_error+4
bdrsl		equ	stat_error+5
seek_error	equ	stat_error+6
unknown_media	equ	stat_error+7
sector_not_fnd	equ	stat_error+8
write_fault	equ	stat_error+10
read_fault	equ	stat_error+11
failure		equ	stat_error+12
;
function_call	equ	251
;
const		equ	1
conin		equ	2
conout		equ	3
;
code		segment
		assume	cs:code
;
;
;*********************************************
;                                            *
;       con driver for the slicer            *
;       (c) 1984,  Slicer                    *
;                                            *
;*********************************************
con_driver	dw	-1
		dw	-1
attribute	dw	1000000000000011b	;charecter, stdio, special con
		dw	offset strategy
		dw	offset	con_interupt
name1		db	'CON     '
rh_off		dd	?
head		dw	0
tail		dw	0
buffer		dw	16 dup (0)
temp_char	db	?
esc_flag	db	0
con_funtab	label	word
		dw	init
		dw	exit		;media check
		dw	exit		;build bpb
		dw	illegal_cmd	;ioctl read
		dw	con_input
		dw	con_inp_no_wait	;input no wait
		dw	con_inp_status	;input status
		dw	con_input_flush	;input flush
		dw	con_output
		dw	con_output    	;output verify
		dw	exit		;output status
		dw	exit		;output flush
		dw	illegal_cmd	;ioctl write
;
; S T R A T E G Y
;
strategy	proc	far
		mov	w cs:rh_off+2,es
		mov	w cs:rh_off,bx
		ret
strategy	endp
;
; I N T E R U P T
;
con_interupt	proc	far
		push	di
		cld
		push	ds
		push	es
		push	dx
		push	ax
		push	bx
		push	cx
		push	si
		les	bx,cs:rh_off
		mov	al,es:[bx].command_code
		cmp	al,13
		jl	cont
		mov	al,3		;make al bad command (ioctl)
cont:		rol	al,1
		xor	ah,ah
		mov	di,ax
		jmp	con_funtab[di]
exit:		les	bx,rh_off
		or	es:[bx].status,stat_done
		pop	si
		pop	cx
		pop	bx
		pop	ax
		pop	dx
		pop	es
		pop	ds
		pop	di
		ret
con_interupt	endp
;
; I L L E G A L   C O M M A N D
;
illegal_cmd	proc	near
		mov	es:[bx].status,unknown_cmd
		jmp	exit
illegal_cmd	endp
;
; I N P U T   N O   W A I T
;
con_stat_call	db	0
;
con_inp_no_wait	proc	near
		mov	con_stat_call,0
		jmp	short cinw1
con_inp_status:
		mov	con_stat_call,0ffh
cinw1:
		mov	al,temp_char
		or	al,al
		jnz	c_have_t
		push	bx
		call	get_char1_50
		pop	bx
		jnz	c_have_t
c_inw_busy:	or	es:[bx].status,stat_busy
c_have_t:	test	con_stat_call,0ffh
		jnz	exit
	 	mov	es:[bx].inp_byte,al
		jmp	exit
con_inp_no_wait	endp
;
; I N P U T   F L U S H 
;
con_input_flush	proc	near
		call	get_char1_50
		jz	c_if_end
		call	get_char1
		jmp	con_input_flush
c_if_end:	mov	temp_char,0
		jmp	exit
con_hNput_flush	endp
;
; I N P U T
;
con_input	proc	near
		mov	cx,es:[bx].inp_count
		jcxz	con_in_done
		les	di,es:[bx].inp_buffer
con_in_loop:	push	di

		xor	ax,ax
		xchg	al,temp_char
		or	al,al
		jnz	gc_end
		call	get_char1
		or	ax,ax
		jz	gc_end
		or	al,al
		jnz	gc_end
		mov	temp_char,ah
gc_end:
		pop	di
		stosb
		loop	con_in_loop
con_in_done:
		jmp	exit
con_input	endp



;
; O U T P U T
;
con_output	proc	near
		mov	cx,es:[bx].out_count
		jcxz	con_out_done
		lds	si,es:[bx].out_buffer
con_out_loop:	lodsb
;***********************************************************************
;  Can be patched here from debug to call outchr instead of ansiout    *
;  to disable output translation.				       *
;***********************************************************************
		if	output_xlat
		push	cx
		call	ansiout		;output a charecter
		pop	cx
		else
		call	outchr
		endif
		loop	con_out_loop
con_out_done:	jmp	exit
con_output	endp


		
get_char1	proc	near		
get_char1_10:	call	getc1
		mov	si,tail
		cmp	si,head
		jz	get_char1_10
;
		mov	ax,buffer[si]
		add	si,2
		and	si,01fh		;circular buffer
		mov	tail,si
;
		ret
;
get_char1_50:				;set z-flag if char avail.
		call	getc1
		mov	si,tail
		cmp	si,head
		mov	ax,buffer[si] ;getchar
;
		ret
;
get_char1	endp
				   
getc1		proc	near
		mov	ax,tail
		add	ax,2
		and	ax,01fh
		cmp	ax,head
		je	getc1_ret	;internal buffer is full;
		mov	bl,const
		int	function_call
		jnz	getc1_cont
getc1_ret:	ret
getc1_cont:
		mov	bl,conin
		int	function_call
		xor	ah,ah
;*****************************************************************************
;									     *
;Can be patched here from debug to jmp getc1_7 to disable input translation. *
;									     *
;*****************************************************************************
		if	input_xlat
		test	esc_flag,0ffh
		jnz	getc1_8
		cmp	al,1bh         ;esc function key leadin
		je	getc1_cont1
		jmp	getc1_7
getc1_cont1:	mov	esc_flag,0ffh
		ret
getc1_8:
;
;
;
;
;    The following code converts escape sequences from the
;    terminal into IBM function key sequences(esc. A  -> 0 72 ).  Currently
;    it is set up for a VT 52 terminal, but is easily
;    changed.
;
;
;
		mov	esc_flag,0
		cmp	al,'A'
		jne	chk_nxt1
		mov	ah,72			;up
		mov	al,0
		jmp	getc1_7
chk_nxt1:	cmp	al,'B'
		jne	chk_nxt2
		mov	ah,80			;down
		mov	al,0
		jmp	getc1_7
chk_nxt2:	cmp	al,'C'
		jne	chk_nxt3
		mov	ah,77			;right
		mov	al,0
		jmp	getc1_7
chk_nxt3:	cmp	al,'D'
		jne	chk_nxt4
		mov	ah,75			;left
		mov	al,0
		jmp	getc1_7
chk_nxt4:	cmp	al,'P'
		jne	chk_nxt5
		mov	ah,59			;f1
		mov	al,0
		jmp	getc1_7
chk_nxt5:	cmp	al,'Q'
		jne	chk_nxt6
		mov	ah,60			;f2
		mov	al,0
		jmp	getc1_7
chk_nxt6:	cmp	al,'R'
		jne	chk_nxt7
		mov	ah,61			;f3
		mov	al,0
		jmp	getc1_7
chk_nxt7:			;not found leave as esc.
		endif

;
getc1_7:	mov	si,head
		mov	buffer[si],ax
		add	si,2
		and	si,01fh
		mov	head,si
		ret
getc1		endp


		if	output_xlat
;
;	actual terminal escape sequences for cursor control and erasure
;	(currently set up for a Visual 50)
;
esc	equ	01Bh
dohm	db	esc,'H',0,0		;cursor home
doup	db	esc,'A',0,0		;cursor up
dodn	db	esc,'B',0,0		;cursor down
dofd	db	esc,'C',0,0		;cursor forward
dobk	db	esc,'D',0,0			;cursor back
doepg	db	esc,'J',0,0		;erase from cursor to end of page
dobpg	db	0,0,0,0			;erase from begin of page to cursor
doeln	db	esc,'K',0,0		;erase from cursor to end of line
dobln	db	0,0,0,0			;erase from begin of line to cursor
doln	db	esc,'t',0,0		;erase entire line
dobrv	db	esc,'j',0,0		;begin reverse video
doerv	db	esc,'W',0,0		;exit reverse video
dosav	db	0,0,0,0			;save cursor position
dorst	db	0,0,0,0			;restore cursor to saved postion
;
dopos1	db	esc,'Y',0,0		;cursor position lead in
dopos2	db	0,0,0,0			;chars between line + col #s
dopos3	db	0,0,0,0			;chars after line + col #s
doposfm	db	0			;the line # comes first
					;if bit 0=1 then the line # goes 2cd
doposl	db	31			;32 is first line
doposc	db	31			;32 is first col
	endif
;
outchr	proc	near			;OUTPUT a character to the console
	push	bx
	mov	bx,conout
	int	function_call
	pop	bx
	ret
outchr	endp
	if	output_xlat
;
;
; ANSI INFO and routines. ANSI driver implemented as a finite state automata
; This ANSI driver translates the ANSI standard escape sequences into the
; 
; This is not a full implementation of ANSI, but rather a minimal 
; implementation which implements all of the necessary ANSI functions.
; To wit:
;		cursor up
;		cursor down
;		cursor forward
;		cursor back
;		direct cursor positioning (both varieties)
;		erase parts of lines and pages
;		save / restore cursor position
;		start / exit revers video
;
STATE   DW      ST1             ;Current ANSI character state.
PRMPNT  DW      PARMS           ;Current parameter pointer.
PARMS   DB      0,0,0,0,0,0,0   ;Allow for up to eight parameters.
LASTPRM DB      0               ;With this being the eight one.

CMDTABL DB      'A'             ;Cursor up.  "esc","[",#,"A"
        DW      offset CUU
        DB      'B'             ;Cursor down. "esc","[",#,"B"
        DW      offset CUD
        DB      'C'             ;Cursor forward. "esc","[",#,"C"
        DW      offset CUF
        DB      'D'             ;Cursor back. "esc","[",#,"D"
        DW      offset CUB
        DB      'H'             ;Direct cursor posit. "esc","[",x,y,"H"
        DW      offset CUP
        DB      'J'             ;Erase. "esc","[",code,"J"
        DW      offset ED
        DB      'K'             ;Erase in line. "esc","[",code,"K"
        DW      offset EL
        DB      'f'             ;Direct cursor posit. "esc","[",x,y,"f"
        DW      offset CUP
        DB      'm'             ;Special video mode. "esc","[",code,"m"
        DW      offset SGR
        DB      's'             ;Save cursor posit. "esc","[","s"
        DW      offset PSCP
        DB      'u'             ;Move cursor to saved. "esc","[","u"
        DW      offset PRCP
        DB      00              ;End of table.
;
; ANSI console output driver.
;
ANSIOUT	PROC	NEAR
	push	cs
	pop	ds
	assume	ds:code
	MOV     DI,OFFSET STATE ;Retrieve current ansi state.
        JMP     [DI]            ;Jump to it.
;
; State one (1).
;   Looks for an Escape character.
;
ST1:    CMP     AL,ESC          ;See if this the first character is ESC.
        JNZ     OUTCHR          ;No, treat as regular character output.
        MOV     WORD PTR [DI],OFFSET ST2        ;Yes, setup state two.
        RET
;
; State two (2).
;   Looks for the "[" character.
;
ST2:	MOV     WORD PTR [DI],OFFSET ST1 ;Setup for state one just in
	CMP     AL,'['          	;case not a valid state two.
        JNZ     OUTCHR          	;No, treat as regular charcter
        MOV     BX,OFFSET PARMS 	;Yes, get parameter pointer.
        MOV     WORD PTR [PRMPNT],BX    ;Setup in pointer index.
        MOV     WORD PTR [BX],0 	;Clear first entry.
        MOV     WORD PTR [DI],OFFSET ST3 ;Setup for state three.
        RET
;
; State three (3).
;   Entered one or more times for parameter passing.
;
ST3:    CMP     AL,';'          ;Look for decimal # seperator.
        JNZ     ST3A            ;No check phase A.
        INC     WORD PTR [PRMPNT]       ;Yes, incr. pointer to next param.
        MOV     AX,OFFSET LASTPRM       ;Check for outside parameter list.
        CMP     [PRMPNT],AX
        JBE     RETST3          ;Yes, proceed with next parameter.
        MOV     [PRMPNT],AX     ;No, treat as extentsion to old.
RETST3: MOV     DI,[PRMPNT]     ;Setup for next parameter.
        MOV     BYTE PTR [DI],0 ;Pre-Initialize it to zero.
        RET
;
; State three A (3A).
;   Check for an ascii digit.
;
ST3A:   CMP     AL,'0'          ;Check for ASCII digit.
        JB      ST3B            ;No, check for seconday command character.
        CMP     AL,'9'          ;Still checking for ASCII digit.
        JA      ST3B            ;No, it must be a secondary.
        SUB     AL,'0'          ;Convert to binary.
        MOV     DI,[PRMPNT]     ;Get the current parameter pointer.
        XCHG    [DI],AL         ;Get existing #.
        MOV     AH,10           ;Scale by 10.
        MUL     AH
        ADD     [DI],AL         ;Add to new digit.
        RET
;
; State three B (3B).
;   Wasn't a ascii digit, so check for secondary command.
;
ST3B:   MOV     [DI],OFFSET ST1         ;Preset STATE to state 1 just in case.
        MOV     DI,OFFSET PARMS-1       ;Get pointer to start of parameters.
        MOV     [PRMPNT],DI             ;Save it in Parameter pointer.
        MOV     DI,OFFSET CMDTABL-3     ;Get start of Secondary command table.

ST3B1:  ADD     DI,3            ;Update Command table pointer.
        CMP     BYTE PTR [DI],0 ;Check for end of table.
        JNZ     ST3B2           ;No, continue processing.
        JMP     OUTCHR          ;Yes, treat as regular character.
ST3B2:  CMP     AL,[DI]         ;Check for valid. command.
        JNZ     ST3B1           ;No, keep checking.
        JMP     [DI+1]          ;Yes, transfer to that secondary command.
;
; Get binary parameter from storage and return a one if = 0
;
GETONE: CALL    GETPARM         ;Get parameter form list.
        OR      AL,AL           ;Verify for non-zero.
        JNZ     GETRET          ;Good, then return to caller.
        INC     AL              ;Bad, make it at least a one.
GETRET: CBW                     ;Sign extend AL.
        MOV     CX,AX           ;Copy of it to CX.
        RET

GETPARM:INC     WORD PTR [PRMPNT]       ;Increment parameter pointer.
GOTPARM:MOV     DI,[PRMPNT]     ;Get parameter pointer.
        MOV     AL,[DI]         ;Get parameter value.
        RET
;
; Send character sequence addressed by ds:si, that is no more than
;	4 characters long and zero terminated if 3 characters or less
;
OUTSEQ: PUSH	SI
	push	cx
	mov	cx,4
outslp: lodsb
	or	al,al
	jz	dnsq
        CALL    OUTCHR
	loop	outslp
dnsq:	pop	cx
	POP	SI
	ret

;
; Cursor Positioning routines.
;

CUU:    MOV     si,offset doup	;Cursor up.
        JMP     SHORT CURPOS
CUD:    mov	si,offset dodn	;Cursor down.
        JMP     SHORT CURPOS
CUF:    mov	si,offset dofd	;Cursor forward.
        JMP     SHORT CURPOS
CUB:	mov	si,offset dobk	;Cursor back

CURPOS: CALL    GETONE          ;Get number of positions to move into CX.
MOVCUR: CALL    OUTSEQ          ;Send escape, command characters.
        LOOP    MOVCUR          ;Keep moving until done.
        RET
;
; Direct cursor positioning routine.
;
CUP:    MOV	SI,OFFSET DOPOS1
	CALL	OUTSEQ
	CALL    GETONE          ;Get LINE position.
        MOV     BL,AL           ;Save in BX.
        CALL    GETONE          ;Get COLUMN position.
	MOV	AL,[DOPOSL]	;CONVERT BINARY NUMBER
	ADD	BL,AL
	MOV	AL,[DOPOSC]
	ADD	CL,AL
	TEST	[DOPOSFM],01H
	JZ	OKLC
	XCHG	CX,BX		;if column comes first xchg regs
OKLC:	MOV	AL,BL		;output 1st position #
	CALL	OUTCHR
	mov	si,offset dopos2
	CALL	OUTSEQ
	MOV	AL,CL		;output 2cd position #
	CALL	OUTCHR
	MOV	SI,OFFSET DOPOS3
	JMP	OUTSEQ
;
; Erase all/part of screen.
;
ED:     CALL    GETPARM         ;Get trinary command type.
	inc	al
        mov	si,offset doepg
        DEC     AL              ;See if erase to end of screen.
        JZ      ED1             ;Yes, perform ZDS function.
        mov	si,offset dobpg
        DEC     AL              ;See if erase from beginning of screen.
        JZ      ED1             ;Yes, perform ZDS function.
        mov	si,offset dohm	;Now we assume erase whole screen.
	call	outseq
	mov	si,offset doepg
ED1:    JMP     OUTSEQ
;
; Erase all/part of a line.
;
EL:     CALL    GETPARM         ;Get trinary command type.
	inc	al
	mov	si,offset doeln
        DEC     AL              ;See if erase to end of line.
        JZ      EL1             ;Yes, perform ZDS function.
        mov	si,offset dobln
        DEC     AL              ;See if erase from beginning of line
        JZ      EL1             ;Yes, perform ZDS function.
        mov	si,offset doln	;Now we assume erase to end of line.
EL1:    JMP     OUTSEQ
;
; Special video modes.
;
SGR:    CALL    GETPARM         ;Get trinary command type.
        mov	si,offset dobrv
        CMP     AL,7            ;See if enter reverse video mode.
        JZ      SGR2            ;Yes, perform ZDS function.
        mov	si,offset doerv
        OR      AL,AL           ;See if exit reverse video mode.
        JNZ     SGR3            ;No, ignore.
SGR2:   JMP	OUTSEQ
SGR3:   RET
;
; Save / restore cursor position.
;
PSCP:   mov	si,offset dosav	;Set save cursor posit. mode.
        JMP     OUTSEQ

PRCP:   MOV	SI,OFFSET DORST	;Restore last cursor save.
        JMP     OUTSEQ
ANSIOUT	ENDP
	endif
;				     
;
; I N I T
;
con_end		label	byte
init		proc	near
		mov	es:w [bx].end_address,offset con_end
		mov	es:w [bx].end_address+2,cs
		jmp	exit
init		endp
code		ends
		end
