        NAME    msxsee
; File MSXSEE.ASM
;
; This module is derived from MSXCLO.ASM, which was in turn derived from
; MSXIBM.ASM and is intended for the Seequa Chameleon, which differs from the
; IBM in its serial I/O, and uses the 8274 sio chip at 30.  The idea is to use
; the VT100 emulation (which will work) but use special code for the Seequa's
; serial I/O.  This module differs from MSXCLO.ASM in that it uses direct,
; interrupt-driven I/O to the Seequa's port (fast), rather than only BIOS
; calls (slow).
;
;	Glenn Everhart
;
;	Based on MS Kermit 2.29, June 1986
;
; Kermit system dependent module for IBM-PC
; Edit History
; [2.29] code frozen on 6 May 1986 [jrd]
; Remove module VTS since mssset now selects terminal emulation type.
; Add Topview support for some screen handling functions and call smarter
; screen routines in module msyibm.
; Revise Putmod to not advance cursor to last column to avoid unwanted
; cursor wraparound on some machines (Compaq).
; Add DOS keyboard reading if running under IBM PC Netbios (pcnet != 0).
; Move all terminal Set and Status routines to this system dependent file.
; Add Global entry point vtstat to invoke local Status display.
; Remove Autowrap (H-19) as a separate item; a terminals now use Wrap.
; Add Set Term Color for terminal emulation; as a default the system uses
; colors in existence when Kermit is started. [jrd]
; Add extra code to SERINI & SERRST to assert 8250 Uart signals OUT1 and OUT2.
; Normally OUT2 is used to enable recoginition of IRQ3/4 and OUT1 is unused.
; Add code at end of SERRST to clear modem's delta line status bits and
; to reassert DTR, RTS, and OUT1/2.
; Add control of screen refresh as Set Term Color 0 for regular IBM CGA,
; waits for retrace before updating screen, and Set Color 10 for other systems
; not needing to wait. Default is to wait (no snow).
; Add global procedures IHOSTS and IHOSTR to handle host initialization
; when packets are to be sent or received by us,resp. 24 March 1986
; Add global procedure DTRLOW (and worker serhng) to drop DTR and RTS and
;  thus hangup the phone. 29 March 1986 [jrd]
; Revise Set Term Tab ... to use codes of set/clear/not-modified in tmptab
; buffer and hence set/clear individual tabs cleanly. 1 April 1986
; In proc Outchr add override of xon from chkxon sending routine.
;  This makes a hand typed Xoff supress the xon flow control character sent
;  automatically as the receiver buffer empties. 20 April 1986 [jrd]
; Add save reg si in proc puthlp to help avoid lost cursor.
; Add test for IBM PC jr and if machine is a PC jr then set port 2 as the
;  default. 23 April 1986 [jrd]
; Revise Puthlp procedure to use manual cursor movement while writing help
;  text. Hope is to avoid screen problems on Compaq's. 1 May 1986 [jrd]
; Revise Poscur to not do Topview notification. Should cure video controller
;  problems on early IBM/Compaq PC's. 5 May 1986 [jrd]
;
; [2.28 jrd/2]
; Modified procedure serini to flush input char before allowing interrupts,
; to stop interrupts from occurring during the procedure body, to stop
; interrupts from occurring due to TX holding buffer becoming empty, and to
; speed our exit from the procedure before an interrupt can occur.
; Modified procedure serrst to do quicker exit before interrupts occur.
; Modified procedure serint to remove unnecessary start-interrupts in proc
; body (it's an interrupt routine folks) and send 8259 end-of-interrupt
; code just before exiting procedure (less exposure time). [jrd]
; Joe R. Doupnik 22 Dec 1985.
; Make keywords mixed case for reading ease. 26 Dec 85 [jrd]
;
;  Make break be 275 ms, DT 5:51pm  Thursday, 6 December 1984

        public  serini, serrst, clrbuf, outchr, coms, vts, vtstat
        public  dodel, ctlu, cmblnk, locate, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep
        public  count, xofsnt, puthlp, putmod, clrmod, poscur
        public  sendbr, machnam, setktab, setkhlp, lclini, showkey
        public  ihosts, ihostr, dtrlow                          ; [jrd]
	PUBLIC SERIALIO
        include mssdef.h

false   equ     0
true    equ     1
mntrgh  equ     bufsiz*3/4      ; High point = 3/4 of buffer full.

; constants used by serial port handler

ASYIO   EQU     14H		; Interrupt for com1: device via bios.
BRKBIT  EQU     040H            ; Send-break bit.
TIMER   EQU     40H             ; Use to issue short beep.
PORT_B  EQU     61H             ; Port B address.
MCONF   EQU     11H             ; Machine configuration.
KEYB    EQU     16H
BIOS    EQU     10H

MDMDAT1 EQU     03F8H           ; Address of modem port (data). [19b]
MDMSTS1 EQU     03FDH           ; Address of modem port status. [19b]
MDMCOM1 EQU     03FBH           ; Address of modem port command. [19b]
MDMDAT2 EQU     02F8H           ; Port 2 address. [19b]
MDMSTS2 EQU     02FDH           ; Port 2 status. [19b]
MDMCOM2 EQU     02FBH           ; Port 2 command. [19b]
MDMINP  EQU     1               ; Input ready bit.

MDMINTV EQU     0030H           ; Address of modem port interrupt vector.
MDINTV2 EQU     002CH           ; Address for port 2. [19b]
MDMINTO EQU     0EFH            ; Mask to enable interrupt for modem port.
MDINTO2 EQU     0F7H            ; Enable interrupt level 3. [19b]
MDMINTC EQU     010H            ; Bit to set to disable interrupts for modem.
MDINTC2 EQU     008H            ; Disable IRQ3. [19b]

INTCONT EQU     0021H           ; Address of 8259 interrupt controller ICW2-3.
INTCON1 EQU     0020H           ; Address of 8259 ICW1.
EOICOM  EQU     0064H           ; End of interrupt.
EOICOM2 EQU     0063H           ; End of interrupt for COM2. [19b]
;
; Serial I/O equates:
EOI	EQU	20H	; End of interrupt command
FALSE	EQU	0	; Flag value
LF	EQU	0AH	; Line feed
RX_AVIL	EQU	100H
SERIAL	EQU	30H	; Asynchronous Communications $8274
TRUE	EQU	NOT FALSE;Flag value
TX_EMTY	EQU	2000H
TIMEOUT	EQU	8000H
TIMER	EQU	40H	; Timer addr
WR0	EQU	3
 NUL	EQU	0
 RESET_TX_ERR	EQU	0C0H
WR1	EQU	1
WR2	EQU	2
WR3	EQU	3
 RX_ENAB	EQU	1
 RX_7_BIT	EQU	40H
 AUTO_ENAB	EQU	20H
WR4	EQU	4
 CLK_X_16	EQU	40H
WR5	EQU	5
 DTR		EQU	80H
 TX_ENAB	EQU	8
 RTS		EQU	2
;
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
;    or port2)
; port1, port2 - portinfo structures for the corresponding ports

; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
;    not implemented)
; setkhlp - help for setktab.

; SEGMENT FOR SERIAL BUFFERS

DABUF	SEGMENT PUBLIC 'DABUF'
BUFFERS	DB	4096 DUP (?)	; SERIAL BUFFERS, PAGE ALIGNED
	DB	4 DUP (?)	; SAFETY
DABUF	ENDS

datas   segment public 'datas'
        extrn   drives:byte,flags:byte, trans:byte
        extrn   portval:word, port1:byte, port2:byte
        extrn   pcnet:byte, refresh:byte
        extrn   vtemu:byte                                      ; [jrd]

; structure for status information table sttab.
stent   struc
sttyp   dw      ?               ; type (actually routine to call)
msg     dw      ?               ; message to print
val2    dw      ?               ; needed value: another message, or tbl addr
tstcel  dw      ?               ; address of cell to test, in data segment
basval  dw      0               ; base value, if non-zero
stent   ends

setktab db      12
        mkeyw   'BackSpace',0eh
        mkeyw   'F1',3bh
        mkeyw   'F2',3ch
        mkeyw   'F3',3dh
        mkeyw   'F4',3eh
        mkeyw   'F5',3fh
        mkeyw   'F6',40h
        mkeyw   'F7',41h
        mkeyw   'F8',42h
        mkeyw   'F9',43h
        mkeyw   'F10',44h
        mkeyw   'scan',-1

setkhlp db      cr,lf,'Keyname: "BackSpace", F1, ... F10, or "scan" follwed by '
        db      'decimal scan code$'
brkval  db      0               ; What to send for a break.
brkadr  dw      0               ; Where to send it.
modem   mdminfo <MDMDAT1,MDMSTS1,MDMCOM1,MDMINTO,MDMINTC,EOICOM,MDMINTV>
hngmsg  db      cr,lf,' The phone should have hungup.',cr,lf,'$' ; [jrd]
hnghlp  db      cr,lf,' The modem control lines DTR and RTS for the current'
        db      ' port are forced low (off)'
        db      cr,lf,' to hangup the phone. Normally, Kermit leaves them'
        db      ' high (on) when it exits.'
        db      cr,lf,'$'                                       ; [jrd]
erms20  db      cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40  db      cr,lf,'?Warning: Unrecognized baud rate$'
badbd   db      cr,lf,'Unimplemented baud rate$'
prterr  db      '?Unrecognized value$'                  ; [jrd]
machnam db      'Seequa Chameleon$'
crlf    db      cr,lf,'$'
delstr  db      BS,BS,'  ',BS,BS,'$'    ; Delete string. [21d]
clrlin  db      cr,'$'                  ; Clear line (just the cr part).
onmsg   db      'on$'                   ; [jrd]
offmsg  db      'off$'
savsci  dw      ?               ; Save for serial port interrupt vector. [14]
savscs  dw      ?               ; Ditto.  [14]
savbr1  dw      ?               ; "Break" interrupt vector. [25]
savbr2  dw      ?               ; Ditto. [25]
portin  db      0               ; Has comm port been initialized. [21c]
xofsnt  db      0               ; Say if we sent an XOFF.
xofrcv  db      0               ; Say if we received an XOFF.
tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.
rdbuf   db      80 dup (?)      ; temporary storage. [jrd]
ASYMD	DW	0		; STORE BAUD RATE SETTING
ASYPR	DB	0		; ASYNCH PORT 0 OR 1
                                        ; begin Terminal emulator data set

termtb  db      tttypes                 ; entries for Status, not Set
        mkeyw   'Heath-19',ttheath
        mkeyw   'none',ttgenrc
        mkeyw   'VT102',ttvt100
        mkeyw   'VT52',ttvt52           ; [jrd]

vttbl   db      13                      ; fourteen entries.
        mkeyw   'Character-set',chaval
        mkeyw   'Color',200H            ; screen fore/back colors; 200H=marker
        mkeyw   'Cursor-style',curval
        mkeyw   'Heath-19',ttheath+100H ; note 100H flag for decoding here
        mkeyw   'Keyclick',keyval
        mkeyw   'Margin-bell',marval
        mkeyw   'None',ttgenrc+100H
        mkeyw   'Newline',newval
        mkeyw   'Screen-background',scrval
        mkeyw   'Tabstops',tabval
        mkeyw   'VT102',ttvt100+100H
        mkeyw   'VT52',ttvt52+100H              ; [jrd]
        mkeyw   'Wrap',wraval

scrtab  db      02H                     ; screen attributes
        mkeyw   'normal',00H
        mkeyw   'reverse',01H

curtab  db      02H                     ; cursor attributes
        mkeyw   'block',00H
        mkeyw   'underline',01H

chatab  db      02H                     ; character set (pound sign choice)
        mkeyw   'UK-ascii',01H
        mkeyw   'US-ascii',00H          ; US ASCII is default (0).

tabtab  db      02H                     ; label says it all!
        mkeyw   'at',0FFH               ; For setting tab stops.
        mkeyw   'Clear',00H             ; For clearing tab stops.

alltab  db      02H                     ; more tab command decoding
        mkeyw   'all',00H
        mkeyw   'at',01H

vtable  dw      ontab, curtab, chatab, ontab, ontab, ontab, scrtab, 0

vtsflg equ      this byte               ; define small digits xxxval
newval  equ     $-vtsflg                ; and mask for bit in byte
        db      vsnewline
curval  equ     $-vtsflg
        db      vscursor
chaval  equ     $-vtsflg
        db      vsshift3
keyval  equ     $-vtsflg
        db      vskeyclick
wraval  equ     $-vtsflg
        db      vswrap
marval  equ     $-vtsflg
        db      vsmarginbell
scrval  equ     $-vtsflg
        db      vsscreen
numflgs equ     $-vtsflg
tabval  equ     $-vtsflg
        db      0
vtrtns  dw      numflgs dup (flgset), tabset ; dispatch table for vtsflg

clrset  db      ?                       ; Temp for SET Term Tabstops xxx
tmptabs db      80D dup (?)             ; Temporary for unconfirmed tabs.

vthlp   db      ' one of the following:',cr,lf
        db '  terminal types of:  None, Heath-19, VT52, or VT102',cr,lf
        db '  Newline-mode    Cursor-style        Character-set (US UK)',cr,lf
        db '  Keyclick        Margin-bell         Screen-background',cr,lf
        db '  Tabstops        Wrap (long lines)   Color (fore & background)'
        db '$'

wrpst   db      'Autowrap (Heath-19): $'

clrhlp  db      ' one of the following:'
        db      cr,lf,'  AT  #s  (to set tabs at column #s)'
        db      cr,lf,'  Clear AT #s  or  Clear ALL  (to clear tabstops)'
        db      cr,lf,'  Ex: Set Term Tab at 10, 20, 34        sets tabs'
        db      cr,lf,'  Ex: Set Term Tab Clear at 9, 17, 65   clears tabs$'
allhlp  db      ' one of the following:'
        db      cr,lf,'  AT #s (to clear at specific columns)'
        db      cr,lf,'  ALL   (to clear all tabstops)$'
tbshlp  db      '  column number of tab stop to set, 1-79$'
tbchlp  db      '  column number of tab stop to clear, 1-79$'
tbserr  db      cr,lf,'?Column number is not in range 1-79$'
colhlp  db      cr,lf,'  Set Term Color  value, value, value, ...'
        db      '    commas are optional.'
        db      cr,lf,'   0 selects normal white on black and'
        db      ' no-snow mode on an IBM CGA (default).'
        db      cr,lf,'   1 for high intensity foreground.'
        db      cr,lf,'  10 for fast screen updating.'
        db      cr,lf,'  Foreground color (30-37) = 30 + colors'
        db      cr,lf,'  Background color (40-47) = 40 + colors'
        db      cr,lf,'    where colors are  1 = red, 2 = green, 4 = blue.'
        db      cr,lf,'  Ex: 0, 1, 34, 47   IBM CGA(0), bright(1) blue(34)'
        db      ' chars on a white(47) field.'
        db      cr,lf,'  Attributes are applied in order of appearance.$'
colerr  db      cr,lf,'?Value not in range of 0, 1, 10, 30-37, or 40-47$'
vtwrap  db      'Term wrap-lines: $'    ; 1st item has two spaces from STAT0
vtbell  db      'Term margin-bell: $'   ; this is also on same line as wrap.
vtnewln db      '  Term newline: $'
vtcur   db      '  Term cursor-style: $'
vtcset  db      '  Term character-set: $'
vtclik  db      '  Term key-click: $'
vtscrn  db      '  Term screen-background: $'
colst1  db      '  Term color  foreground:3$'
colst2  db      ' background:4$'
                                                        ; terminal emulator
vtstbl  stent   <srchkb,vtwrap,ontab,,vtsflg+wraval>    ; VT100 line wrap
        stent   <srchkb,vtbell,ontab,,vtsflg+marval>    ; VT100 margin bell
        stent   <srchkb,vtcur,curtab,,vtsflg+curval>    ; VT100 cursor type
        stent   <srchkb,vtnewln,ontab,,vtsflg+newval>   ; VT100 newline
        stent   <srchkb,vtscrn,scrtab,,vtsflg+scrval>   ; VT100 screen
        stent   <srchkb,vtcset,chatab,,vtsflg+chaval>   ; VT100 character set
        stent   <srchkb,vtclik,ontab,,vtsflg+keyval>    ; VT100 keyclick
        stent   <colstat>                               ; VT100 colors
        stent   <tabstat>       ; VT100 tab status - needs one whole line
        dw      0               ; end of table
                                                ; end of Terminal data set


ontab   db      02H             ; Two entries.
        db      03H,'off$'      ; Should be alphabetized.  [19a]
        dw      00H
        db      02H,'on$'
        dw      01H

comptab db      04H
        db      01H,'1$'
        dw      01H
        db      01H,'2$'
        dw      00H
        db      04H,'COM1$'
        dw      01H
        db      04H,'COM2$'
        dw      00H

; this table is indexed by the baud rate definitions given in
; pcdefs.  Unsupported baud rates should contain FF.
bddat   label   word
        dw      0FFH            ; 45.5 baud  -- Not supported.
        dw      0FFH            ; 50 baud
        dw      0FFH            ; 75 baud
        dw      000H            ; 110 baud
        dw      0FFH            ; 134.5 baud
        dw      0FFH            ; 150 baud
        dw      002H            ; 300 baud
        dw      0FFH            ; 600 baud
        dw      004H             ; 1200 baud
        dw      0FFH             ; 1800 baud
        dw      0FFH             ; 2000 baud
        dw      005H             ; 2400 baud
        dw      006H             ; 4800 baud
        dw      007H             ; 9600 baud
        dw      001H             ; 19200 baud
        dw      003H             ; 38400 baud
; NOTE THESE ARE JIGGERED FOR USE BY SET BAUD - NOT AS IN REAL IBM PC VERSION
ASYBD	DW	003H	; 110 BAUD REPORT
	DW	00EH	; 19200
	DW	006H	; 300
	DW	00FH	; 38400
	DW	008H	; 1200
	DW	00BH	; 2400
	DW	00CH	; 4800
	DW	00DH	; 9600 BAUD REPORT VALUE

; variables for serial interrupt handler

source  db      bufsiz DUP(?)   ; Buffer for data from port.
srcpnt  dw      0               ; Pointer in buffer (DI).
count   dw      0               ; Number of chars in int buffer.
savesi  dw      0               ; Save SI register here.
telflg  db      0               ; Are we acting as a terminal.
mst     dw      0               ; Modem status address.
mdat    dw      0               ; Modem data address.
mdeoi   db      0               ; End-of-Interrupt value.

rbtrn   db      7fH             ; rubout

shkbuf  db      300 dup (?)     ; room for definition
shkmsg  db      '  Scan code: '
shkmln  equ     $-shkmsg
shkms1  db      cr,lf,'  Definition: '
shkm1ln equ     $-shkms1
;
; Data declarations for serial I/O pieces
	PUBLIC TXBUFFSTRT,TXBUFFEND,RXBUFFSTRT,RXBUFFEND
	PUBLIC TXBUFFSEG,RXBUFFSEG,TXLENGTH,RXLENGTH
	PUBLIC SERSTAT,SERMASK,SRINIT

TXBUFFSTRT   DW ?	; Start of tx buff
TXBUFFEND    DW ?	; End of tx buff
RXBUFFSTRT   DW ?	; Start of RX buff
RXBUFFEND    DW ?	; End if RX buff
RXBUFFSEG    DW ?	; Segment of RX buff
TXBUFFSEG    DW ?	; Segment of TX buff
TXLENGTH     DW ?       ; TX buffer length
RXLENGTH     DW ?       ; RX buffer length
SERSTAT	     DW	?	; Serial port status
SRINIT       DW ?	; serial port initialization word
PORT	     DW ?	; port B (asynchronous) or port A (synchronous)
SERMASK      DB	?	; Mask char for serial port
;	------- Baud rate look up table
SBAUD	DW	710		; 110 baud
	DW	4		; 19200 (was 150 baud entry...)
	DW	260		; 300
	DW	2		; 38400 (NOT 600)
	DW	65		; 1200
	DW	32		; 2400
	DW	16		; 4800
	DW	8		; 9600
	DW	4		;19200	; (not really used)
	DW	2		;38400	; (not really used)
;	------- Command dispatch
SERJMP	DW	OFFSET SERINZ	; Serial initialization
	DW	OFFSET SERPUT	; Transmit serially
	DW	OFFSET SERGET	; Receive serially
	DW	OFFSET SERSTS	; Get serial status
	DW	OFFSET SEREND	; Close port communications
;	------- Interupt dispatch
INTTBL	DW	OFFSET XMITT
	DW	OFFSET STATCHG
	DW	OFFSET RECEIVE
	DW	OFFSET STATCHG
datas   ends

code    segment public 'code'
        extrn   comnd:near, dopar:near, defkey:near, gss:near, lclyini:near
        extrn   sleep:near, atsclr:near, scrseg:near,scrloc:near, scrsync:near
        extrn   atoi:near, strlen:near, prtscr:near, scroff:near, scron:near
        assume  cs:code,ds:datas

;
;********************************************************************;
;********************************************************************;
;********************************************************************;
;
;		Serial port drivers for the 8274 chip at 30
;		Written by : Bob Depelteau
;		Edit date : 9/21/83 , 2/21/84
;
;********************************************************************;
;********************************************************************;
;********************************************************************;
;-----------------------------------------------;
; SERIALIO Asynchronous/Synchronous Communications
;	(AH)=0 Initialize a communications port
;	 (SRINIT)= Parameters for initialization
;
;	BITS:
;
;	PORT
;	8
;	0 - port B
;	1 - port A
;
;	BAUD RATE    PARITY   STOPBIT WORDLENGTH
;	765	    43	       2      01
;	000 - 110   00 - None  0 - 1  00 = 5 BIT
;	001 - 19.2K 01 - Odd   1 - 2  01 = 7 BIT
;	010 - 300   11 - Even	      10 = 6 BIT
;	011 - 38.4K		      11 = 8 BIT
;	100 - 1200
;	101 - 2400
;	110 - 4800
;	111 - 9600
;
;	 (BX)= Length of transmit buffer
;	 (CX)= Length of receive buffer 
;	       ( Maxium size of any buffer is 64K or hex 0000 )
;	       ( Length assumed to be on 16 byte boundry )
;	       ( No check is made for out of memory )
;	 (ES)= Starting Segment to use for buffers
;	       Public variables:
;	              RXBUFFSEG	DW ?	; Segment of reciver buffer
;		      TXBUFFSEG DW ?    ; Segment of transmitter buffer 
;
;	NOTE:
;	  Buffer are flushed and all information is lost upon initialization
;
;	(AH)=1 Queue up a character in buffer to transmitt
;		Updates tramsmitter buffer pointers
;		PUBLIC VARIABLES
;			TXBUFFSTRT  DW   ; Offset start of buffer
;			TXBUFFEND   DW   ; Offset end of buffer
;			TXLENGTH    DW   ; Length of buffer
;
;	(AH)=2 Get a character from buffer into (AL)
;		Updates Reciver buffer pointers
;		PUBLIC VARIABLES
;			RXBUFFSTRT  DW   ; Offset start of buffer
;			RXBUFFEND   DW   ; Offset end of buffer
;			RXLENGTH    DW   ; Length of buffer
;
;	(AH)=3 Get port status into (AX)
;
;	   AH = 7 6 5 4 3 2 1 0
;		| | | | | | | | 
;		| | | | | | |  --- RECIVER BUFFER NOT EMPTY
;		| | | | | |  ----- OVERRUN ERROR
;		| | | | |  ------- PARITY ERROR
;		| | | |  --------- FRAMING ERROR
;		| | |  ----------- BREAK DETECT
;		| |  ------------- TRANS BUFFER FULL
;		|  --------------- TRANS BUFFER EMPTY
;		 ----------------- BUFFER OVERFLOW OR TIMEOUT
;	   AL = 7 6 5 4 3 2 1 0   
;		| | | | | | | | 
;		| | | | | | |  ---
;		| | | | | |  ----- 
;		| | | | |  ------- 
;		| | | |  --------- DATA CARRIER DETECT
;		| | |  ----------- CLEAR TO SEND
;		| |  ------------- DATA SET READY
;		|  ---------------
;		 -----------------
;
;	(AH)=4 Close port communication 
;	       (Must be done before exiting program)
;	
;	USED ON ALL 
;	ON EXIT
;		(AH)= Status of port as returned by function 3
;		      No other regs are affected
;
;-----------------------------------------------;


SERIALIO PROC	FAR
	STI
	PUSH	BX		;
	PUSH	CX		;
	PUSH	DX		;
	PUSH	DI		;
	PUSH	SI		;
	PUSH	DS		;
	PUSH	ES		;
	CLD
	CMP	AH,4		; If illegal function
	JA	SERROR		; then error
	PUSH	AX		; Save
	MOV	AX,SEG DATAS	; Set DS to DATA SEG
	MOV	DS,AX		; 
	ASSUME	DS:DATAS
	POP	AX		;
	PUSH	AX		;
	MOV	AL,AH		; Function
	SHL	AL,1		; Words 2 bytes
	CBW			; Word
	MOV	SI,AX		; Index
	POP	AX		; Restore
	CALL	DS:WORD PTR SERJMP[SI]; Branch indirectly
SERROR:
SERETN:
	POP	ES
	POP	DS		; Restore
	POP	SI		;
	POP	DI		;
	POP	DX		;
	POP	CX		;
	POP	BX		;
	RET
SERIALIO ENDP

; local initialization

lclini  proc    near
        mov     ax,0eH          ; scan code for arrow key
        mov     si,offset rbtrn ; translate to rubout
        mov     cx,1            ; one char translation
        call    defkey
        call    model           ; get model of IBM machine. [jrd]
	MOV	ASYPR,0	; SET COM1 INITIALLY
        mov     brkval,BRKBIT   ; What to send for a break.
        mov     ax,modem.mdcom  ; Where to send it.
        mov     brkadr,ax
        call    lclyini         ; let other modules initialize too...
        ret
lclini  endp

; this is called by Kermit initialization.  It checks the
; number of disks on the system, sets the drives variable
; appropriately.  Returns normally.

DODISK  PROC    NEAR
        int mconf                       ; Get equipment configuration.
        mov ah,al                       ; Store AL value for a bit.
        and al,01H                      ; First, look at bit 0.
        jz dodsk0                       ; No disk drives -- forget it.
        mov al,ah                       ; Get back original value.
        mov cl,6                        ; Shift over bits 6 and 7.
        shr al,cl                       ; To positions 0 and 1.
        inc al                          ; Want 1 thru 4 (not 0 thru 3).
        mov drives,al                   ; Remember how many.
        ret
dodsk0: mov ah,prstr                    ; Print a warning message.
        mov dx,offset erms20            ; I'm not sure if things will
        int dos                         ; work with only a cassette.
        mov drives,0                    ; Say there aren't any drives.
        ret
DODISK  ENDP

model   proc    near            ; Get IBM model, set port 2 for PC jr. [jrd]
        push    es
        push    ax                      ; get IBM model code at F000:FFFE
        mov     ax,0f000h               ; address ROM
        mov     es,ax
        mov     al,byte ptr es:[0fffeh] ; get model id byte
        cmp     al,0fdh                 ; PC jr?
        jne     modelx                  ; ne = no
        mov     flags.comflg,0          ; say not using port 1.
        call    coms0                   ; set port 2 for PC jr, in proc COMS
modelx: pop     ax
        pop     es
        ret
model   endp

; show the definition of a key.  The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Revised to also run under IBM PC Netbios (lose some scan codes by doing
; DOS keyboard reads rather than Bios. Non-Network reads use Bios). [jrd]
; Returns normally.
showkey proc    near
        push    es
        push    ax              ; save the ptr
        mov     bx,ds
        mov     es,bx           ; address data segment
        cld
showk1: cmp     pcnet,0         ; running under Netbios? (0 = no)
        je      showk3          ; e = no.
        xor     bx,bx           ; say shift state is none
        mov     dl,0ffh         ; Network. keyboard input, via DOS
        mov     ah,conin        ; get a char into al
        int     dos
        xor     ah,ah           ; assume no scan code
        cmp     al,0            ; special char?
        jne     showk4          ; ne = no
        mov     ah,conin        ; get second byte, pseudo-scan-code
        int     dos
        xor     ah,ah           ; clear effective shift state
        jmp     showk4          ; and carry on regardless.

showk3: xor     ah,ah           ; Non-Netbios. Bios keyboard input.
        int     keyb            ; read a char
        push    ax              ; save the character
        call    gss             ; get shift state
        pop     bx
        mov     ah,al           ; shift state to ah
        mov     al,bh           ; scan code to al
showk4: push    ax              ; remember scan code
        mov     di,offset shkbuf
        mov     si,offset shkmsg
        mov     cx,shkmln
        rep     movsb           ; copy in initial message
        call    nout            ; write out scan code
        mov     si,offset shkms1
        mov     cx,shkm1ln      ; second message
        rep     movsb
        pop     ax              ; get scan code back
        pop     bx              ; and terminal arg block
        mov     cx,[bx].klen    ; and length
        jcxz    showk2          ; no table, not defined
        push    di              ; remember output ptr
        mov     di,[bx].ktab    ; get key table
        repne   scasw           ; search for a definition for this
        mov     si,di           ; remember result ptr
        pop     di              ; get output ptr back
        jne     showk2          ; not defined, forget it
        sub     si,[bx].ktab    ; compute offset from beginning
        sub     si,2            ; minus 2 for pre-increment
        add     si,[bx].krpl    ; get index into replacement table
        mov     si,[si]         ; pick up replacement
        mov     cl,[si]         ; get length
        mov     ch,0
        inc     si
        rep     movsb           ; copy into buffer
showk2: mov     ax,offset shkbuf ; this is buffer
        mov     cx,di
        sub     cx,ax           ; length
        pop     es
        ret                     ; and return
showkey endp

; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer.  This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.

CLRBUF  PROC    NEAR
        cli
        mov ax,offset source
        mov srcpnt,ax
        mov savesi,ax
        mov count,0
        sti
        ret
CLRBUF  ENDP

; Clear to the end of the current line.  Returns normally.
; Upgraded for Topview compatibility. [jrd]
CLEARL  PROC    NEAR
        push    ax
        push    bx
        push    dx
        mov ah,3                ; Clear to end of line.
        mov bh,0
        int bios                ; Get current cursor position into dx
        mov     ax,dx           ; Topview compatible clear line
        mov     bh,ah           ; same row
        mov     bl,79           ; last column
        call    atsclr          ; clear from ax to bx, screen coord
        pop     dx
        pop     bx
        pop     ax
        ret
CLEARL  ENDP

; Put the char in AH to the serial port.  This assumes the
; port has been initialized.  Should honor xon/xoff.  Skip returns on
; success, returns normally if the character cannot be written.

outchr:
outch2: push dx                 ; Save register.
	PUSH	AX
        sub cx,cx
        mov al,ah               ; Parity routine works on AL.
        call dopar              ; Set parity appropriately.
	MOV	AH,1	; FLAG WRITE A CHAR FROM AL
;	MOV	DX,ASYPR	;SET COM1 OR COM2 PORT
	PUSH	ES
	PUSH	BX	;
	PUSH	CX
;
	MOV	BX,SEG DABUF
	MOV	ES,BX
	MOV	BX,2048
	MOV	CX,BX
	CALL	SERIALIO ; VIA INT SYSTEM
; AH GETS 1 BIT SET IF CHAR THERE
	POP	CX
	POP	BX
	POP	ES
;	INT	ASYIO	; LET INT 14 DO IT FOR US
; AH RETURNS WITH STATUS BYTE.
	AND	AH,80H
	CMP	AH,80H	; DID WE GET IT SENT?
	JZ	OUTCH5	; IF EQUAL NO, FAILED, RETURN.
; CAN'T TIME OUT REALLY... BIOS BETTER KEEP UP.
	POP	DX
	POP	AX
        jmp rskp
outch5: pop dx
	POP	AX
        ret

; This routine blanks the screen.  Returns normally.
; Upgraded to Topview compatiblity. [jrd]
CMBLNK  PROC    NEAR
        push    ax
        push    bx
        xor     ax,ax           ; from screen loc 0,0
        mov     bx,184fH        ; to 24,79
        call    atsclr          ; do Topview compatible clear, in msyibm
        pop     bx
        pop     ax
        ret
CMBLNK  ENDP

; Locate: homes the cursor.  Returns normally.

LOCATE  PROC    NEAR
        mov dx,0                ; Go to top left corner of screen.
        jmp poscur
LOCATE  ENDP

; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $.  Returns normally.
putmod  proc    near
        push    ax              ; save regs. [jrd]
        push    bx
        push    cx
        push    dx              ; preserve message
        mov     cx,1800h
        mov     dx,184fh
        mov     ax,600h         ; scroll to clear the line
        mov     bh,70h          ; inverse video
        int     bios
        mov     dx,1800h        ; now address line 24
        call    poscur
        pop     si              ; get message back
        mov     cx,1            ; only one char at a time
        xor     bh,bh           ; page 0
putmo1: lodsb                   ; get a byte
        cmp     al,'$'          ; end of string?
        je      putmo2
        push    si              ; save si
        push    ax              ; and the char
        call    poscur
        inc     dl              ; increment for next write
        pop     ax              ; recover char
        mov     ah,9            ; try this
        mov     bx,0070h        ; inverse video, page 0
        int     bios
        pop     si              ; recover pointer
        jmp     putmo1
putmo2: pop     cx              ; [jrd]
        pop     bx
        pop     ax
        ret
putmod  endp

; clear the mode line written by putmod.  Returns normally.
clrmod  proc    near
        push    ax              ; save regs. [jrd]
        push    bx
        push    cx
        push    dx
        mov     cx,1800h
        mov     dx,184fh
        mov     ax,600h
        mov     bh,7h
        int     bios
        pop     dx              ; [jrd]
        pop     cx
        pop     bx
        pop     ax
        ret
clrmod  endp

; put a help message on the screen.  This one uses reverse video...
; pass the message in ax, terminated by a null.  Returns normally.
puthlp  proc    near
        push    bx              ; save regs. [jrd]
        push    cx
        push    dx
        push    si
        push    ax              ; preserve this
        cld
        mov     si,ax           ; point to it
        mov     dh,1            ; init counter
puthl1: lodsb                   ; get a byte
        cmp     al,lf           ; linefeed?
        jne     puthl2          ; no, keep going
        inc     dh              ; count it
        jmp     puthl1          ; and keep looping
puthl2: cmp     al,0            ; end of string?
        jne     puthl1          ; no, keep going
        mov     ax,600h         ; scroll to clear window
        xor     cx,cx           ; from top left
        mov     dl,4fh          ; to bottom right of needed piece
        mov     bh,70h          ; inverse video
        int     bios
        call    locate          ; home cursor
        mov     bx,0070h        ; bh = page 0, bl = inverse video
        mov     cx,1            ; one char at a time
        cld                     ; scan direction is forward [jrd]
        pop     si              ; point to string again
puthl3: lodsb                   ; get a byte
        cmp     al,0            ; end of string?
        je      puthl4          ; yes, stop
        push    si              ; save around bios call [jrd]
        cmp     al,' '          ; printable?
        jb      puth21          ; b = no
        mov     ah,9            ; write char at current cursor position [jrd]
        int     bios            ; do the Bios int 10h call
        inc     dl              ; point to next column
        jmp     puth23          ; move cursor there
puth21: cmp     al,cr           ; carriage return?
        jne     puth22          ; ne = no
        xor     dl,dl           ; set to column zero
        jmp     puth23
puth22: cmp     al,lf           ; line feed?
        jne     puth23
        inc     dh              ; go to next line
puth23: mov     ah,2            ; set cursor position to dx
        int     bios
        pop     si              ; restore pointer [jrd]
        jmp     puthl3          ; and keep going
puthl4: mov     dx,24 * 100H    ; go to last line
        call    poscur          ; position cursor
        pop     si              ; [jrd]
        pop     dx
        pop     cx
        pop     bx
        ret
puthlp  endp

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.

DOBAUD  PROC    NEAR
        push    ax              ; save some regs. [jrd]
        push    bx              ; [jrd]
        push    dx              ; [jrd]
        push    bp              ; [jrd]
        mov bp,portval
        mov temp1,ax            ; Don't overwrite previous rate. [25]
        mov ax,ds:[bp].baud     ; Check if new rate is valid. [25]
        mov tmp,2
        mul tmp                 ; Get index into baud table.
        mov bx,offset bddat     ; Start of table.
        add bx,ax
        mov ax,[bx]             ; The data to output to port.
        cmp ax,0FFH             ; Unimplemented baud rate.
        jne dobd0
        mov ax,temp1            ; Get back orginal value.
        mov ds:[bp].baud,ax     ; Leave baud rate as is.
        mov ah,prstr
        mov dx,offset badbd     ; Give an error message.
        int dos
        jmp     dobd1           ; [jrd]
dobd0:  mov temp1,ax            ; Remember value to output. [25]
; WE JIGGER THE BAUD TBL FROM 0 TO 7 NOW...
	PUSH	DX
;	MOV	DX,ASYPR	; SET PORT 0 OR 1
	MOV	ASYMD,AX	; SAVE BAUD RATE SETTING AS JUST 0-7
	SHL	AX,1
	SHL	AX,1	; SHIFT INTO PLACE
	SHL	AX,1
	SHL	AX,1
	SHL	AX,1
	AND	AX,0E0H	; MASK ANY EXTRA JUNK SO ONLY BAUD RATE REMAINS
	OR	AX,3	; SET 8 BIT CHARS NO PARITY
;	MOV	AH,0	; ENSURE HI BYTE ZERO TO FLAG SETUP
	MOV	AH,ASYPR	; SET PORT 0 OR 1
	MOV	SRINIT,AX	;STASH AWAY INITIALIZING PARAMS
	PUSH	ES
	MOV	BX,SEG DABUF
	MOV	ES,BX		; SET ES TO BUFFER
	MOV	AH,0
	MOV	BX,2048		;TRANSMIT BUFFER 
	PUSH	CX
	MOV	CX,BX		; RCV BUFF SIZE
	CALL  SERIALIO	; INIT THE PORT
;	INT	ASYIO	; GET BIOS TO SET BAUD
	POP	CX
	POP	ES	; RESTORE BUFFER'S ES
	POP	DX	; RESTORE DX REG NOW
dobd1:  pop     bp              ; restore regs [jrd]
        pop     dx              ; [jrd]
        pop     bx              ; [jrd]
        pop     ax              ; [jrd]
        ret
DOBAUD  ENDP

; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.  Returns normally.
; This is used during initialization.

GETBAUD PROC    NEAR
	PUSH	BP
        push    cx              ; [jrd]
; SKIP THIS FOR NOW
; SINCE BIOS WON'T RETURN CURRENT BAUD RATE, JUST USE SAVED RATE WE SAVE
; WHENEVER WE SET IT AND HOPE (PRAY?) IT'S RIGHT. BAUD RATE REALLY
; OUGHT TO BE SET PRIOR TO ENTRY WITH MODE COMMAND.
;
	MOV	CX,ASYMD	; GET LAST-SET BAUD RATE.
	mov	cx,srinit
	shr	cx,1
	shr	cx,1		; shift baud rate down
	shr	cx,1
	shr	cx,1
	shr	cx,1
	and	cx,07h		; mask off all but baud rate pat'n
	MOV	BP,OFFSET ASYBD	; GET OUR BAUD RATE TABLE
; CX HAS JUST A VALUE 0-7 WHICH WAS USED IN OUR LAST SET RATE
; JUST GET DISPLAY VALUE NOW IN 0-15 RANGE.
; ASYBD IS CONVERSION FROM SET BAUD RATE TO DISPLAY VALUE
	ADD	CX,CX		; DOUBLE CX FOR WORD OFFSET
	ADD	BP,CX
	MOV CX,DS:[BP]		; NOW GET TABLE VALUE OUT OF THERE
        mov bp,portval
        mov ds:[bp].baud,cx     ; Set baud rate.
        pop     cx              ; [jrd]
	POP	BP
        ret
GETBAUD ENDP

; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR  PROC    NEAR
; SINCE BIOS READ IS SYNCHRONOUS WE HAVE TO CALL IT TWICE, ONCE TO
; SEE IF ANYTHING'S THERE, AND AGAIN IF SO TO GET THE CHARACTER.
;
	PUSH	BX
	MOV	AH,3		; EXAMINE STATUS FUNCTION
	PUSH	DX
;	MOV	DX,ASYPR		; COM1 OR COM2
	PUSH	ES
	PUSH	BX	;
	PUSH	CX
;
	MOV	BX,SEG DABUF
	MOV	ES,BX
	MOV	BX,2048
	MOV	CX,BX
	CALL	SERIALIO ; VIA INT SYSTEM
; AH GETS 1 BIT SET IF CHAR THERE
	POP	CX
	POP	BX
	POP	ES
	POP	DX
	AND	AH,1		; LOOK AT DATA READY BIT
	CMP	AH,1		; IS IT ON?
	JZ	PRTCH1		; IF ZERO YES
	POP	BX
	JMP	RSKP		; NOTHING THERE ... SKIP RETURN
PRTCH1:	MOV	AH,2		; CHAR THERE ... READ IT (SYNCHRONOUSLY)
	PUSH	DX
;	MOV	DX,ASYPR		; SET COM1 OR COM2
	PUSH	ES
	PUSH	BX	;
	PUSH	CX
;
	MOV	BX,SEG DABUF
	MOV	ES,BX
	MOV	BX,2048
; GET 1 CHAR
	MOV	CX,BX
	CALL	SERIALIO	; VIA INT SYSTEM
; AH GETS 1 BIT SET IF CHAR THERE
	POP	CX
	POP	BX
	POP	ES
	POP	DX
	POP	BX
	RET
PRTCHR  ENDP

; local routine to see if we have to transmit an xon
chkxon  proc    near
;        push    bx
;        mov     bx,portval
;        cmp     [bx].floflg,0   ; doing flow control?
;        je      chkxo1          ; no, skip all this
;        cmp     xofsnt,false    ; have we sent an xoff?
;        je      chkxo1          ; no, forget it
;        cmp     count,mntrgh    ; below trigger?
;        jae     chkxo1          ; no, forget it
;        mov     ax,[bx].flowc   ; ah gets xon
;        call    outchr          ; send it
;        nop
;        nop
;        nop                     ; in case it skips
;        mov     xofsnt,false    ; remember we've sent the xon.
;chkxo1: pop     bx              ; restore register
        ret                     ; and return
chkxon  endp

; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the
; cycle of clear input buffer, wait 1 second, test if buffer empty then exit
; else repeat cycle. Requires that the port be initialized before hand.
; Ihosts is used by the local send-file routine just after initializing
; the serial port.
; 22 March 1986 [jrd]

IHOSTS  PROC    NEAR
        push    ax              ; save the registers
        push    bx
        push    cx
        push    dx
        mov     bx,portval      ; port indicator
        mov     ax,[bx].flowc   ; put Go-ahead flow control char in ah
        call    outchr          ; send it (release Host's output queue)
         nop                    ; outchr can do skip return
         nop
         nop
ihosts1:call    clrbuf          ; clear out interrupt buffer
        mov     ax,1            ; sleep for 1 second
        call    sleep           ; procedure sleep is in msscom.asm
        call    prtchr          ; check for char at port
         jmp    ihosts1         ; have a char in al, repeat wait/read cycle
         nop                    ; prtchr does skip return on empty buffer
        pop     dx              ; empty buffer. we are done here.
        pop     cx
        pop     bx
        pop     ax
        ret
IHOSTS  ENDP

; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port.         22 March 1986 [jrd]
IHOSTR  PROC    NEAR
        push    ax              ; save regs
        push    bx
        push    cx
        mov     bx,portval      ; port indicator
        mov     ax,[bx].flowc   ; put Go-ahead flow control char in ah
        call    outchr          ; send it (release Host's output queue)
         nop                    ; outchr can do skip return
         nop
         nop
        pop     cx
        pop     bx
        pop     ax
        ret
IHOSTR  ENDP

; Send a break out the current serial port.  Returns normally.
SENDBR  PROC    NEAR
;
; CAN'T SEND BREAK VIA BIOS SO SKIP THIS
;
        ret                     ; And return.
SENDBR  ENDP

; Wait for the # of milliseconds in ax
; Thanks to Bernie Eiben for this one.
pcwait  proc    near
        mov     cx,240          ; inner loop counter for 1 millisecond
pcwai1: sub     cx,1            ; inner loop takes 20 clock cycles
        jnz     pcwai1
        dec     ax              ; outer loop counter
        jnz     pcwait          ; wait another millisecond
        ret
pcwait  endp

; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.
POSCUR  PROC    NEAR
        push    ax
        push    bx
        mov     ah,2            ; Position cursor.
        mov     bh,0            ; page 0
        int     bios
        pop     bx
        pop     ax
        ret
POSCUR  ENDP

; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.

DODEL   PROC    NEAR
        mov ah,prstr
        mov dx,offset delstr    ; Erase weird character.
        int dos
        ret
DODEL   ENDP

; Move the cursor to the left margin, then clear to end of line.
; Returns normally.

CTLU    PROC    NEAR
        mov ah,prstr
        mov dx,offset clrlin
        int dos
        call clearl
        ret
CTLU    ENDP

; set the current port.

COMS    PROC    NEAR
        mov dx,offset comptab
        mov bx,0
	MOV	ASYPR,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp comx               ;  Didn't get a confirm.
         nop
        pop bx
        mov flags.comflg,bl     ; Set the comm port flag.
        cmp flags.comflg,1      ; Using Com 1?
        jne coms0               ; Nope.
	MOV	ASYPR,0		; SET PORT 1
        mov ax,offset port1
        mov portval,ax
        mov modem.mddat,MDMDAT1 ; Set COM1 defaults.
        mov modem.mdstat,MDMSTS1
        mov modem.mdcom,MDMCOM1
        mov modem.mddis,MDMINTC
        mov modem.mden,MDMINTO
        mov modem.mdmeoi,EOICOM
        mov modem.mdintv,MDMINTV
        mov brkadr,MDMCOM1
        ret
coms0:  mov ax,offset port2
	MOV	ASYPR,1		; SET PORT 2
        mov portval,ax
        mov modem.mddat,MDMDAT2 ; Set COM2 defaults.
        mov modem.mdstat,MDMSTS2
        mov modem.mdcom,MDMCOM2
        mov modem.mddis,MDINTC2
        mov modem.mden,MDINTO2
        mov modem.mdmeoi,EOICOM2
        mov modem.mdintv,MDINTV2
        mov brkadr,MDMCOM2
        ret
comx:   pop bx
        ret
COMS    ENDP


                                        ; begin Terminal set & status code

; SET Term parameters, especially for use with VT100 emulator. [jrd]
; Taken from work done originally by James Harvey IUPUI.
; VTS is called only by mssset to set terminal type and characteristics.

VTS     proc    near                    ; SET TERM whatever
        mov     ah,cmkey                ; Parse another keyword.
        mov     bx,offset vthlp         ; Use this help
        mov     dx,offset vttbl         ; Use this table
        call    comnd
         jmp    r                       ; Vsetup always returns +1.
        cmp     bx,100H                 ; marker for terminal type?
        jb      vsetu1                  ; b = no.
        cmp     bx,200h                 ; marker for set term color?
        je      vsetu2                  ; e = yes
        push bx                         ; yes
        mov ah,cmcfm
        call comnd                      ; Get a confirm.
         jmp vsetu0                     ; Didn't get a confirm.
         nop
        pop bx
        mov flags.vtflg,bl              ; Set the terminal emulation type
        ret                             ; in standard global byte.
vsetu0: pop bx
        ret

vsetu1: sal     bx,1                    ; Make bx a word index.
        call    vtrtns[bx]              ; Dispatch.
         jmp    r                       ; Vsetup always returns +1.
        jmp     r                       ; Vsetup always returns +1.

                                ; Set Term Color foreground, background
vsetu2: mov     ah,cmtxt                ; get number(s) after set term color
        mov     dx,offset colhlp        ; use this help
        mov     bx,offset rdbuf         ; temp buffer
        mov     byte ptr [bx],0         ; clear the buffer
        call    comnd
         jmp    r
        cmp     ah,0                    ; anything given?
        jne     vsetu2a                 ; ne = yes.
        jmp     r                       ; else give not confirmed msg
vsetu2a:mov     ah,cmcfm                ; Parse confirm
        mov     bx,0                    ; Use default help.
        call    comnd
         jmp    r                       ; not confirmed, complain.
        mov     si,offset rdbuf         ; si = place where atoi wants text
vsetu2c:mov     dx,si
        call    strlen                  ; current length of text
        jcxz    vsetu2x                 ; nothing left
        mov     ah,cl                   ; put length where Atoi wants it
        call    atoi                    ; convert text to numeric in ax
         jmp    colbad                  ; no value available
        cmp     ax,0                    ; reset all? regular IBM CGA refresh
        je      vsetu2j                 ; e = yes
        cmp     ax,1                    ; high intensity?
        je      vsetu2k                 ; e = yes
        cmp     ax,10                   ; fast refresh?
        je      vsetu2l                 ; e = yes
        cmp     ax,30                   ; check range
        jb      colbad                  ; b = too small. complain
        cmp     ax,37
        jna     vsetu2b                 ; 30-37 is foreground color
        cmp     ax,40
        jb      colbad
        cmp     ax,47                   ; Compare as unsigned.
        jna     vsetu2b                 ; 40-47 is background
        jmp     colbad                  ; else error
vsetu2x:jmp     rskp                    ; and return normally.

vsetu2b:push    bx
        mov     bx,vtemu.att_ptr        ; Get address of attributes byte
        cmp     al,40                   ; background (40-47)?
        jnb     vsetu2f                 ; nb = yes
        sub     al,30                   ; remove foreground bias
        and     byte ptr [bx],not 07H   ; clear foreground bits
        test    al,1                    ; ANSI red?
        jz      vsetu2d                 ; z = no
        or      byte ptr [bx],4         ; set IBM foreground red
vsetu2d:test    al,2                    ; ANSI & IBM green?
        jz      vsetu2e                 ; z = no
        or      byte ptr [bx],2         ; set green foreground
vsetu2e:test    al,4                    ; ANSI Blue?
        jz      vsetu2i                 ; z = no
        or      byte ptr [bx],1         ; set IBM blue
        jmp     vsetu2i                 ; done with foreground settings
vsetu2f:sub     al,40                   ; remove background bias
        and     byte ptr [bx],not 70H   ; clear background attributes
        test    al,1                    ; ANSI red?
        jz      vsetu2g                 ; z = no
        or      byte ptr [bx],40h       ; set IBM background red
vsetu2g:test    al,2                    ; ANSI & IBM green?
        jz      vsetu2h                 ; z = no
        or      byte ptr [bx],20h       ; set green background
vsetu2h:test    al,4                    ; ANSI Blue?
        jz      vsetu2i                 ; z = no
        or      byte ptr [bx],10h       ; set IBM blue
vsetu2i:pop     bx
        jmp     vsetu2c                 ; get any next value
vsetu2j:mov     refresh,0               ; Regular (slow) screen refresh
        mov     bx,vtemu.att_ptr        ; Get address of attributes byte
        mov     byte ptr [bx],07h       ; clear all, set white on black.
        jmp     vsetu2c                 ; get next value
vsetu2k:mov     bx,vtemu.att_ptr        ; Get address of attributes byte
        or      byte ptr [bx],08h       ; set high intensity
        jmp     vsetu2c                 ; get next value
vsetu2l:mov     refresh,1               ; Fast screen refresh
        jmp     vsetu2c

colbad: mov     ah,prstr                ; Not in range - complain and exit.
        mov     dx,offset colerr
        int     dos
        jmp     rskp

; SET Term flags. These are the (near) equivalent of VT100 Setup mode values.

flgset: push    bx                      ; Save bx for a second.
        mov     ah,cmkey                ; Another keyword.
        mov     dx,vtable[bx]           ; The table to use.
        mov     bx,0                    ; Use default help.
        call    comnd
         jmp    flgse3
        push    bx                      ; Save switch value.
        mov     ah,cmcfm                ; Confirm it.
        call    comnd
         jmp    flgse2
        pop     dx                      ; Restore switch value.
        pop     bx                      ; And index.
        sar     bx,1                    ; Make it a byte index.
        mov     al,vtsflg[bx]           ; Get the flag.
        cmp     dx,0                    ; Set or clear?
        je      flgse1                  ; Go clear it.
        or      vtemu.vtflgst,al        ; Set the flag.
        jmp     rskp                    ; Give good return.

flgse1: not     al                      ; Complement
        and     vtemu.vtflgst,al        ; Clear the indicated flag.
        jmp     rskp                    ; Give good return.
flgse2: pop     bx                      ; error exits
flgse3: pop     bx
        ret

;       SET Term Tabstops Clear ALL
;       SET Term Tabstops Clear AT n1, n2, ..., nx
;       SET Term Tabstops At n1, n2, ..., nx

tabset: cld                             ; Make sure this is clear.
        mov     di,offset tmptabs       ; clear our temp work area here.
        mov     cx,80                   ; 80 columns
        mov     al,0                    ; set "not touched" indicator
        rep     stosb                   ; in all tmptabs slots
        mov     ah,cmkey                ; Parse keyword.
        mov     bx,offset clrhlp        ; Use this help text.
        mov     dx,offset tabtab        ; This table.
        call    comnd
         jmp    r
        mov     clrset,2                ; code for set a tab
        cmp     bl,0                    ; Was it set or clear?
        jne     tabse1                  ; SET - go parse column number(s).
        mov     clrset,1                ; code for clear at/all tab(s)
        mov     ah,cmkey                ; CLEAR - parse ALL or AT
        mov     bx,offset allhlp        ; Use this help text.
        mov     dx,offset alltab        ; Parse ALL or AT.
        call    comnd
         jmp    r
        cmp     bx,0                    ; ALL?
        jne     tabse1                  ; ne = AT, clear at specific places.
        mov     al,1                    ; ALL, means clear all tab stops.
        mov     cx,80D
        mov     di,offset tmptabs
        rep     stosb
        mov     ah,cmcfm                ; Confirm it.
        call    comnd
         jmp    r
        jmp     tabcpy                  ; update active & coldstart tabs

tabse1: mov     dx,offset tbshlp        ; Tell them we want a column number.
        cmp     clrset,1                ; Clearing?
        jne     tabse2                  ; ne = Set. we guessed right on help.
        mov     dx,offset tbchlp        ; Yes - use this help instead.
tabse2: mov     ah,cmtxt                ; get text w/o white space
        mov     bx,offset rdbuf         ; temp buffer
        call    comnd
         jmp    r
        cmp     ah,0                    ; anything given?
        jne     tabse4                  ; ne = yes.
        jmp     r                       ; else give not confirmed msg
tabse4: mov     ah,cmcfm                ; Parse confirm
        mov     bx,0                    ; Use default help.
        call    comnd
         jmp    r                       ; not confirmed, complain.
        mov     si,offset rdbuf         ; si = place where atoi wants text
tabse5: mov     dx,si
        call    strlen                  ; current length of text
        mov     ah,cl                   ; put length where Atoi wants it
        jcxz    tabcpy                  ; nothing left
        call    atoi                    ; convert text to numeric in ax
         nop
         nop
         nop
        mov     bx,ax                   ; for subscripting in code below
        dec     bx                      ; Put column in range 0-79
        cmp     bx,0                    ; check range (1-80 --> 0-79)
        jl      tbsbad                  ; l = too small. complain
        cmp     bx,79                   ; Compare as unsigned.
        jna     tabse3
tbsbad: mov     ah,prstr                ; Not in range - complain and exit.
        mov     dx,offset tbserr
        int     dos
        jmp     rskp

tabse3: mov     al,clrset               ; Get value for setting or clearing.
        mov     tmptabs[bx],al          ; store in tabs temp work array
        jmp     tabse5                  ; look for more

tabcpy: mov     cx,80                   ; update 80 tab stops
        mov     si,vtemu.vttbst         ; in terminal emulator's active buffer
        mov     di,vtemu.vttbs          ; and in the cold-start buffer.
        mov     bx,0                    ; subscript
tabcpy1:mov     al,byte ptr tmptabs [bx] ; get a table entry into al
        or      al,al                   ; what is the code?
        jz      tabcpy3                 ; z = do not touch
        cmp     al,2                    ; set a tab?
        je      tabcpy2                 ; e = set the tab
        mov     byte ptr [bx+si],0      ; clear the tab
        mov     byte ptr [bx+di],0      ; clear the tab
        jmp     tabcpy3
tabcpy2:mov     byte ptr [bx+si],0ffh   ; set the tab
        mov     byte ptr [bx+di],0ffh   ; set the tab
tabcpy3:inc     bx                      ; inc subscript
        loop    tabcpy1
        jmp     rskp                    ; Give good return.

VTS     endp                            ; end of Set Term things.

                ; Terminal Status display, called within STAT0: in MSSSET.[jrd]
VTSTAT  proc    near    ;enter with di within sttbuf, save bx, di
        push    bx
        push    di
        mov     bx,ds
        mov     es,bx
        cld
        mov     bx,offset vtstbl        ; table of things to show
        xor     cx,cx
vtsta1: cmp     word ptr [bx],0         ; end of table?
        je      vtstax                  ; e = yes
        push    bx
        call    [bx].sttyp              ; call appropriate routine
        pop     bx                      ; cx incremented by output count
        cmp     cx,37                   ; place for second display
        jbe     vtsta2                  ; le = only half full
        mov     dx,offset crlf          ; over half full. send cr/lf
        mov     ah,prstr
        int     dos
        xor     cx,cx                   ; say line is empty now
        jmp     vtsta4
vtsta2: push    cx
        mov     cx,37                   ; where we want to be next time
        pop     ax
        sub     cx,ax                   ; compute number of filler spaces
        jcxz    vtsta4                  ; nothing to do
        mov     ah,conout
        mov     dl,' '
vtsta3: int     dos                     ; fill with spaces
        loop    vtsta3                  ; do cx times
        mov     cx,37                   ; current column number
vtsta4:add      bx,size stent           ; look at next entry
        jmp     vtsta1                  ; and do it
vtstax: pop     di
        pop     bx
        add     di,40                   ; say we used a lot of buffer space
        ret                             ; return to STAT0: in MSSSET.

                                        ; foreground/background color status
colstat proc    near
        mov     dx,offset colst1
        mov     ah,prstr
        int     dos                     ; print first part of msg
        xor     ax,ax
        mov     bx,vtemu.att_ptr        ; pointer to attributes byte
        test    byte ptr [bx],1         ; IBM blue foregound?
        jz      colsta1                 ; z = no
        or      al,4                    ; set blue bit
colsta1:test    byte ptr [bx],2         ; IBM green foreground?
        jz      colsta2
        or      al,2
colsta2:test    byte ptr [bx],4         ; IBM red foreground?
        jz      colsta3
        or      al,1
colsta3:add     al,'0'                  ; add ascii bias
        mov     dl,al                   ; move to DOS place
        mov     ah,conout
        int     dos                     ; print the last digit
        mov     dx,offset colst2        ; now do background
        mov     ah,prstr
        int     dos                     ; print second part of msg
        xor     ax,ax
        test    byte ptr [bx],10h       ; IBM blue background?
        jz      colsta4                 ; z = no
        or      al,4                    ; set blue bit
colsta4:test    byte ptr [bx],20h       ; IBM green background?
        jz      colsta5
        or      al,2                    ; set green bit
colsta5:test    byte ptr [bx],40h       ; IBM red background?
        jz      colsta6
        or      al,1                    ; set red bit
colsta6:add     al,'0'                  ; add ascii bias
        mov     dl,al                   ; move to DOS place
        mov     ah,conout
        int     dos
        add     cx,45                   ; about the # columns we used
        ret
colstat endp
                                        ; Tabs Status display
tabstat proc    near                    ; display tabs ruler for Status
        push    dx
        jcxz    tabsta0                 ; empty line, as it should be
        xor     cx,cx                   ; used line, empty it
        mov     dx,offset crlf          ; cr, lf
        mov     ah,prstr
        int     dos
tabsta0:mov     si,vtemu.vttbst         ; active tabs address, not shadow
        mov     cx,79                   ; loop 79 times
        dec     si                      ; dec for inc below
        xor     ax,ax                   ; tens counter
tabsta1:mov     dl,'.'                  ; default position symbol
        inc     si                      ; start with position 1
        inc     al
        cmp     al,10                   ; time to roll over?
        jb      tabsta2                 ; b = not yet
        mov     al,0                    ; modulo 10
        inc     ah
        mov     dl,ah                   ; display a tens-digit
        add     dl,'0'
tabsta2:cmp     byte ptr [si],0         ; is tab set?
        je      tabsta3                 ; e = no
        mov     dl,'T'                  ; yes, display a 'T'
tabsta3:push    ax
        mov     ah,conout               ; console output
        int     dos
        pop     ax
        loop    tabsta1                 ; loop til done (cx has count)
        pop     dx
        mov     cx,79                   ; say line is full
        ret
tabstat endp

; handler routines for status. All are called with bx/ stat ptr.

onoff   proc    near
        call    stmsg           ; print the message
        mov     si,[bx].basval  ; get base value
        cmp     si,0            ; any there?
        je      onoff1          ; e = no
        mov     si,[si]         ; yes, use as base address
onoff1: add     si,[bx].tstcel  ; add offset of test cell
        mov     al,[si]
        mov     dx,offset onmsg ;
        add     cx,2            ; assume two byte on message
        or      al,al           ; test value
        jnz     onoff2          ; nz = on
        mov     dx,offset offmsg
        inc     cx              ; three byte message
onoff2: mov     ah,prstr        ; display the message
        int     dos
        ret
onoff   endp

; search a keyword table for a bit value, print that value. [jrd]
srchkb  proc    near
        call    stmsg           ; first print message
        call    stbval          ; get bit set or reset
        mov     ah,0            ; al has 0/1, high order is 0
        mov     bx,[bx].val2    ; this is table address
        jmp     prttab          ; and look in table.
srchkb  endp

; get address of test value in stent.  Returns address in si. [jrd]
stbval  proc    near
        mov     si,[bx].basval  ; get address of test value
        cmp     si,0            ; any there?
        je      stbva1          ; no, quit with no match
        mov     al,byte ptr [si]; get byte value
        mov     ah,0
        test    al,vtemu.vtflgst ; bit test value against emulator flags byte
        jz      stbva1          ; z = they don't match
        mov     al,1            ;  match
        ret
stbva1: mov     al,0            ; no match
        ret                     ; and return it
stbval  endp

; get address of test value in stent.  Returns address in si
stval   proc    near
        mov     si,[bx].basval  ; get base value
        cmp     si,0            ; any there?
        je      stva1           ; no, keep going
        mov     si,[si]         ; yes, use as base address
stva1:  add     si,[bx].tstcel  ; add offset of test cell
        ret                     ; and return it
stval   endp

; copy the message to the screen
stmsg   proc    near
        mov     si,[bx].msg     ; get message address
stms1:  lodsb                   ; get a byte
        cmp     al,'$'          ; end of message?
        je      stms2           ; e = yes
        mov     dl,al           ; display the character
        mov     ah,conout
        int     dos
        inc     cx              ; count output chars
        jmp     stms1
stms2:  ret
stmsg   endp

; Print value from table.  BX/address of table, AL/value of variable.
prttab: push    cx              ; save column count
        mov cl,[bx]             ; Number of entries in our table.
        inc bx                  ; Point to the data.
prtt0:  mov dl,[bx]             ; Length of keyword.
        inc bx                  ; Point to keyword.
        mov dh,0
        inc dx                  ; Account for "$" in table.
        mov si,dx               ; Put to index register.
        cmp ax,[bx+si]          ; Is this the one?
        je prtt1
        add bx,dx               ; Go to end of keyword.
        add bx,2                ; Point to next keyword.
        dec cl                  ; Any more keywords to check?
        jnz prtt0               ; Yes, go to it.
        mov bx,offset prterr
prtt1:  mov si,bx
        pop     cx              ; recover column count
        jmp stms1               ; copy in message
        ret                     ; and return
VTSTAT  endp                    ; end of Terminal set & status code


; Initialization for using serial port.  This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
;
; Revised slightly by Joe R. Doupnik 22 Dec 1985 to prevent interrupts
; being enabled until we're done, to stop interrupts from occurring when
; TX holding buffer becomes empty (a useless interrupt for us), and to
; shorten the time between enabling interrupts and our exit. [jrd]
; Returns normally.

SERINI  PROC    NEAR
        cmp portin,0            ; Did we initialize port already? [21c]
        jne serin0              ; Yes, so just leave. [21c]
; INIT WITH 1200 BAUD, 8 BITS, NO PARITY
	PUSH	DX
	MOV	PORTIN,1	; SET INIT'D ALREADY...
	PUSH	ES
	PUSH	AX
	PUSH	BX
	PUSH	CX
; SAVE REGS WE USE
	MOV	AX,SEG DABUF	; BUFFER SEGMENT
	MOV	ES,AX		; STORE IN ES
;
	mov	ax,srinit	; get old baud rate if any
	MOV	AH,ASYPR	; SET PORT UP
	MOV	ASYMD,4		; SET ASYNCH BAUD RATE SAVE
	cmp	srinit,0	; got a baud rate setup yet?
	jnz	serin8		; if nonzero assume yes, leave it there.
	MOV	AL,083H		; INIT PATTERN FOR 1200 BAUD, 8 BITS, NO PARITY
serin8:	MOV	BX,2048
	MOV	CX,BX		; BUFFERS 2048 LONG
	MOV	SRINIT,AX	; SET SRINIT WORD FOR BAUD RATE
	MOV	AH,0		; SET INIT
	CALL	SERIALIO	; DO THE WORK
	POP	CX
	POP	BX
	POP	AX
	POP	ES		; FIX STACK & REGS
;	INT	ASYIO
	POP	DX		; BIOS INITS BAUD RATE ETC.
serin0: ret                     ; We're done. [jrd]
SERINI  ENDP

; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
; Moved push/pop es code to do quicker exit before interrupts enabled. [jrd]
; Returns normally.

SERRST  PROC    NEAR
; NOTHING REALLY TO DO HERE
	PUSH	AX
	PUSH	DX
	MOV	AH,4
	CALL	SERIALIO	; CLOSE SERIAL I/O
	POP	DX
	POP	AX
srst1:  ret                     ; All done.
SERRST  ENDP

DTRLOW  PROC    NEAR            ; Global proc to Hangup the Phone by making
; CAN'T DO THIS... IGNORE
        jmp rskp
DTRLOW  ENDP

; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; Returns normally.

serhng  proc    near    ; clear modem's delta status bits and lower DTR & RTS
        ret
serhng  endp


; Produce a short beep.  The PC DOS bell is long enough to cause a loss
; of data at the port.  Returns normally.

BEEP    PROC    NEAR
        mov al,10110110B        ; Gen a short beep (long one losses data.)
        out timer+3,al          ; Code snarfed from Technical Reference.
        mov ax,533H
        out timer+2,al
        mov al,ah
        out timer+2,al
        in al,port_b
        mov ah,al
        or al,03
        out port_b,al
        sub cx,cx
        mov bl,1
beep0:  loop beep0
        dec bl
        jnz beep0
        mov al,ah
        out port_b,al
        ret
BEEP    ENDP

; put the number in ax into the buffer pointed to by di.  Di is updated
nout    proc    near
        mov     dx,0            ; high order is always 0.
        mov     bx,10
        div     bx              ; divide to get digit
        push    dx              ; save remainder digit
        or      ax,ax           ; test quotient
        jz      nout1           ; zero, no more of number
        call    nout            ; else call for rest of number
nout1:  pop     ax              ; get digit back
        add     al,'0'          ; make printable
        stosb                   ; drop it off
        ret                     ; and return
nout    endp

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop bp
        add bp,3
        push bp
        ret
RSKP    ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

	PAGE

;-----------------------------------------------;
; Initialize the communication port using (DX)
;	(srinit) bits:
;		8    Port
;		7-5  Baud rate
;		4-3  Parity
;		 2   Stop bits
;		1-0  Data length
;-----------------------------------------------;
SERINZ	PROC	NEAR
;	------- Set up buffer pointers
	ASSUME DS:DATAS
	MOV	RXLENGTH,CX
	MOV	TXLENGTH,BX
	MOV	TXBUFFSEG,ES
	MOV	RXBUFFSEG,ES
	MOV	CL,4
	SHR	BX,CL
	ADD	RXBUFFSEG,BX
	MOV	RXBUFFSTRT,0
	MOV	RXBUFFEND,0
	MOV	TXBUFFSTRT,0
	MOV	TXBUFFEND,0
	MOV	PORT,1		; default to port B
	MOV	AX,SRINIT	; load parameters
	TEST	AX,256		; port B (0) or port A (1)
	JZ	SER1
	MOV	PORT,0
SER1:
;	------- Set up serial port interrupt vector
	PUSH	AX
	CLI			;
	XOR	BX,BX		;
	MOV	ES,BX		;
	MOV	BX,0BH*4	;
	MOV	AX,OFFSET SERINT;
	MOV	ES:[BX],AX	;
	MOV	AX,CS		;
	ADD	BX,2		;
	MOV	ES:[BX],AX	;
;	------- Enable interrupt controller
	IN	AL,21H		;
	AND	AL,0F7H		; Mask port bit
	OUT	21H,AL		; enabled
	STI
;	------- Do a chanel reset
	MOV	DX,SERIAL+2	; Point to command port
	ADD	DX,PORT		; offset for PORT A or PORT B
	MOV	AL,18H		; Command
	OUT	DX,AL		; Send
	NOP			; Wait
	NOP			; Wait
	NOP			; Wait
	NOP			; Wait
	NOP			; Wait
	NOP			; Wait
	NOP			; Wait
	OUT	DX,AL		; Send
;	------- Initiate baud timer
	POP	AX
	PUSH	AX		; Save
	MOV	BL,40H		; Assume port 1
	TEST	PORT,1
	JNZ	SER3
	SHL	BL,1		; adjust for A port timer
SER3:
	OR	BL,36H		; Add mode3 and read/load data
	MOV	CL,4		; Shift count
	SHR	AL,CL		; Adjust baud
	AND	AL,0EH		; Mask off unwanted bits
	MOV	AH,0		; Zero
	MOV	SI,AX		; Index
	MOV	CX,WORD PTR DS:SBAUD[SI]; Baud rate
	MOV	AL,BL		; Get Timer parameters
	OUT	TIMER+3,AL	; Timer command
	MOV	AL,CL		; Baud rate
	MOV	DX,TIMER+2	; ----Port A
	SUB	DX,PORT		;  make adjustment for Port B
	OUT	DX,AL		; Timer LSB
	MOV	AL,CH		; then
	OUT	DX,AL		; Timer MSB
;	------- Set WR2 CHAN A
	MOV	AL,WR2		; WR2
	OUT	SERIAL+2,AL	; Set
	MOV	AL,14H		; System configuration
	OUT	SERIAL+2,AL	; Sent
;	------- Set WR2 CHAN B
	MOV	DX,SERIAL+3	; Point to command port
	MOV	AL,WR2		; WR2
	OUT	DX,AL		; Set
	MOV	AL,NUL		; WR2
	OUT	DX,AL		; Sent
	POP	AX		; Retreive parameters
;	------- Set WR4 (parity, stop, clock)
	MOV	DX,SERIAL+2
	ADD	DX,PORT		; point to command port
	MOV	BX,AX		; Save parameters
	MOV	AL,BL		; Parameters
	MOV	CL,3		; Count
	SHR	AL,CL		; Shift bits
	AND	AL,3		; Mask out
	MOV	AH,AL		; Parity
	MOV	AL,BL		; Get parameters again
	SHL	AL,1		; 
	AND	AL,8		; Mask
	OR	AL,4		; Assume 7 bits
	OR	AH,AL		; Add to parity
	OR	AH,CLK_X_16	; Add in clock X 16
	MOV	AL,WR4		; WR4
	OUT	DX,AL		; Set
	MOV	AL,AH		; Value
	OUT	DX,AL		; Sent
;	------- Set WR3
	MOV	AL,WR3		; WR3
	OUT	DX,AL		; Set
	MOV	AL,BL		; Parameters
	AND	AL,3		; Mask out
	ROR	AL,1		; Adjust
	ROR	AL,1		;
	OR	AL,RX_ENAB	; Enable reciver
	OUT	DX,AL		; Send WR3
;	------- Set up mask for reciver
	MOV	AH,0FFH		; 
	MOV	BH,BL		;
	AND	BH,3		;
	CMP	BH,3		;
	JE	SERI08		;
	CMP	BH,2		;
	JE	SERI06		;
	CMP	BH,1		;
	JE	SERI07		;
	SHR	AH,1		;
SERI06:	SHR	AH,1		;
SERI07: SHR	AH,1		;
SERI08:
	MOV	SERMASK,AH	; Initalize mask char
;	------- Set WR5
	SHR	AL,1		; Shift bit
	AND	AL,60H		; Remove unwanted bits
	OR	AL,DTR+TX_ENAB+RTS; Set TX enable, DTR and RTS
	MOV	AH,AL		; Save
	MOV	AL,WR5		; WR5
	OUT	DX,AL		; Set
	MOV	AL,AH		; Restore
	OUT	DX,AL		; Send value
;	------- Reset WR0 error flags
	MOV	AL,0
	OUT	DX,AL
	MOV	AL,10H		; EXT Status
	OUT	DX,AL
;	------- Set WR1
	MOV	AL,WR1		; WR1
	OUT	DX,AL		; Set
	MOV	AL,1FH		; EXT INT ENAB,STAT AFF VECT,ALL RX CHAR
	OUT	DX,AL		; Sent
;	------- Reset WR0 error flags
	MOV	AL,0
	OUT	DX,AL
	MOV	AL,20H		; Enab RX INT
	OUT	DX,AL
	MOV	AL,28H		; TX INT Pend
	OUT	DX,AL
	MOV	AL,38H		; EOI
	OUT	SERIAL+2,AL
;	------- Get the status of port
	CALL	UPDATESTAT	;
	CALL	STATCHG		;
	MOV	AX,SERSTAT	; Get the status
;	------- End		; return them to the user
	RET
SERINZ	ENDP
	PAGE
;-----------------------------------------------;
; Buffer up the character in (AL)
;-----------------------------------------------;
SERPUT	PROC	NEAR
	CLI			; Do not allow interrupts
	MOV	DI,TXBUFFEND	; End of buffer
	PUSH	DS		; Save ds
	MOV	DS, TXBUFFSEG	; see of buffer
	MOV	[DI],AL		; Store character
	POP	DS		;
	INC	DI		; Increment pointer
	CMP	TXLENGTH,0	; 
	JE	TXBUFFOK	;
	CMP	DI,TXLENGTH	; See if at end of buffer
	JNE	TXBUFFOK	; If not go
	XOR	DI,DI		; Else zero buffer
TXBUFFOK:
	MOV	TXBUFFEND,DI	;
	PUSH	AX
	STI			; Interrupts back on
	CALL	STRTXMITT	;
	MOV	AX,SERSTAT	; Get the status
	POP	BX		;
	MOV	AL,BL		; Retrieve old al
	RET
SERPUT	ENDP
	PAGE

;-----------------------------------------------;
; Transmit a character from Buffer
;-----------------------------------------------;
STRTXMITT:
	MOV	DX,SERIAL+2
	ADD	DX,PORT		; select port A or port B
	IN	AL,DX	
	TEST	AL,4		; See if transmitter empty
	JNZ	XMITT		;   
	JMP	SHORT XMITRET	;

XMITT	PROC	NEAR
	MOV	SI,TXBUFFSTRT	; Start of buffer
	CMP	TXBUFFEND,SI	; See if any thing to transmit
	JE	XMITTRET	; If not then split
	PUSH	DS		; Save SEG
	MOV	DS,TXBUFFSEG	; Get buffer SEG
	MOV	AL,[SI]		; Get a char
	POP	DS		; retrieve
	INC	SI		; Update pointer
	CMP	TXLENGTH,0	;
	JE	NOXWRAP		;
	CMP	SI,TXLENGTH	; Check for wrap
	JNE	NOXWRAP		;
	XOR	SI,SI		;
NOXWRAP:
	MOV	TXBUFFSTRT,SI	; Save new pointer
	MOV	DX,SERIAL
	ADD	DX,PORT
	OUT	DX,AL		; Send character
	JMP	SHORT XMITRET	;

XMITTRET:
	MOV	AL,28H
	MOV	DX,SERIAL+2
	ADD	DX,PORT
	OUT	DX,AL		; Reset TX int pending
XMITRET:
	CALL	UPDATESTAT	; Update the status of port
	RET
XMITT	ENDP
	PAGE

;-----------------------------------------------;
; Get a character from Buffer
;-----------------------------------------------;
SERGET	PROC	NEAR
	CLI
	MOV	SI,RXBUFFSTRT	; Start of buffer
	MOV	AL,0		; Assume null char
	CMP	SI,RXBUFFEND	; Check for buffer empty
	JE	GETRET		; If so split
	PUSH	DS		; Save
	MOV	DS,RXBUFFSEG	; Receiver buffer see
	MOV	AL,[SI]		; Get a char
	POP	DS		; Retrive
	INC	SI		; Update buffer pointer
	CMP	RXLENGTH,0	;
	JE	NORWRAP		;
	CMP	SI,RXLENGTH	; Check for buffer wrap
	JNE	NORWRAP		;
	XOR	SI,SI		;
NORWRAP:
	MOV	RXBUFFSTRT,SI	;
	STI			;
	PUSH	AX		;
	CALL	UPDATESTAT	; Update the current statuses
	POP	AX		;
	MOV	BX,SERSTAT	; Get the status
	MOV	AH,BH		; Put it where it goes and split
GETRET:
	STI
	RET
SERGET	ENDP

;-----------------------------------------------;
; Receive a character into Buffer
;-----------------------------------------------;
RECEIVE	PROC	NEAR
	MOV	DX,SERIAL
	ADD	DX,PORT		; offset for port A or port B
	IN	AL,DX		; Get a char from port
	AND	AL,SERMASK	; Mask off unwanted bits
	MOV	DI,RXBUFFEND	;
	MOV	ES,RXBUFFSEG	;
	MOV	ES:[DI],AL	; Store char in buffer
	INC	DI		; Update pointer
	CMP	RXLENGTH,0	;
	JE	RXBUFFOK	;
	CMP	DI,RXLENGTH	;
	JNE	RXBUFFOK	;
	XOR	DI,DI		;
RXBUFFOK:
	MOV	RXBUFFEND,DI	; Save pointer
	CALL	UPDATESTAT	;
	RET
RECEIVE	ENDP
	PAGE

;-----------------------------------------------;
; Get Status Condition into (AX)
;-----------------------------------------------;
SERSTS	PROC	NEAR
	MOV	AX,SERSTAT
	AND	SERSTAT,61FFH	; Clear errors and stuff
	RET
SERSTS	ENDP

;-----------------------------------------------;
; Close out the serial port 
;-----------------------------------------------;
SEREND	PROC	NEAR
	IN	AL,21H
	OR	AL,8
	OUT	21H,AL
	MOV	AL,18H
	MOV	DX,SERIAL+2
	ADD	DX,PORT
	OUT	DX,AL
	RET
SEREND	ENDP
	PAGE

;-----------------------------------------------;
; Update the current statuses of the buffer 
;-----------------------------------------------;
UPDATESTAT PROC NEAR
	PUSH	AX
	PUSH	BX
	MOV	AX,SERSTAT	; Get the current status
	AND	AX,9EFFH	; Mask out buffer stats saving errors
	MOV	BX,RXBUFFEND	; Check receiver status
	CMP	BX,RXBUFFSTRT	;
	JE	UP105		; If equal then buffer empty
	OR	AH,1		; Set flag if not empty
	INC	BX		; Check for buffer overflow
	CMP	RXLENGTH,0	; 
	JE	UP100		;
	CMP	BX,RXLENGTH	;
	JNE	UP100		;
	XOR	BX,BX		;
;	------- Check for over flow
UP100:
	CMP	BX,RXBUFFSTRT	; If equal Then next char will overflow
	JNE	UP105		;
	OR	AH,80H		; So report error now
;	------- Do transmitter
UP105:
	MOV	BX,TXBUFFEND	; Check xmitter
	CMP	BX,TXBUFFSTRT	; If equal then buffer empty
	JNE	UP110		; 
	OR	AH,40H		; Report buffer empty
	JMP	SHORT UP130	; And GO
;	------- Check for full
UP110:
	INC	BX		; Check for buffer full
	CMP	TXLENGTH,0	;
	JE	UP120		;
	CMP	BX,TXLENGTH	;
	JNE	UP120		;
	XOR	BX,BX		;
UP120:
	CMP	BX,TXBUFFSTRT	;
	JNE	UP130		; If not equal then not full
	OR	AH,20H		;
UP130:
	MOV	SERSTAT,AX	; Put in the new status
	POP	BX
	POP	AX
	RET
UPDATESTAT ENDP
	PAGE

;-----------------------------------------------;
; Report any change in port status
;-----------------------------------------------;
STATCHG	PROC	NEAR
	MOV	DX,SERIAL+2
	ADD	DX,PORT
	IN	AL,DX
	MOV	BX,SERSTAT	;
	AND	BX,0FF00H	; Clear port status
	TEST	AL,8		; Data carrier detect
	JZ	STAT100		;
	OR	BL,8		;
	MOV	AL,1		;
STAT100:
	TEST	AL,20H		; Clear to send
	JZ	STAT110		;
	OR	BL,10H		;
STAT110:
	MOV	AL,1		; WR1
	OUT	dx,AL
	IN	AL,dx
	TEST	AL,10H		; Parity error
	JZ	STAT120		;
	OR	BH,4		;
STAT120:
	TEST	AL,20H		; Over run error
	JZ	STAT130		;
	OR	BH,2		;
STAT130:
	TEST	AL,40H		; Framing error
	JZ	STAT140		;
	OR	BH,8		;
STAT140:
	MOV	AL,0F0H
	OUT	dx,AL		; Reset error pend
	MOV	AL,10H		; Reset ext stats
	OUT	dx,AL		;
	RET
STATCHG ENDP
	PAGE

;-----------------------------------------------;
; Serial port interrupt handler
;-----------------------------------------------;
SERINT	PROC	FAR
	STI
	PUSH	AX		;
	PUSH	BX		;
	PUSH	CX		;
	PUSH	DX		;
	PUSH	DI		;
	PUSH	SI		;
	PUSH	DS		;
	PUSH	ES		;
	MOV	AX,SEG DATAS	; Set DS to DATA SEG
	MOV	DS,AX		; 
	ASSUME	DS:DATAS
	MOV	AL,2		;
	OUT	SERIAL+3,AL	; Set up to RR2
	IN	AL,SERIAL+3	; 
	AND	AL,3		; Mask off unwanted bits
	SHL	AL,1		; Justify for call
	CBW			; Convert to word
	MOV	SI,AX		; 
	CALL	DS:WORD PTR INTTBL[SI]; Branch indirectly
SERIAB:
	MOV	AL,20H		; Send an EOI command
	OUT	20H,AL		; To interrupt controller
;	------- Send an EOI to port A because INTEL is strange
	MOV	AL,38H		; EOI to serial port
	OUT	SERIAL+2,AL	;
	POP	ES		;
	POP	DS		; Restore
	POP	SI		;
	POP	DI		;
	POP	DX		;
	POP	CX		;
	POP	BX		;
	POP	AX		;
	IRET
SERINT	ENDP

CODE	ENDS
	END
