	NAME	msxz10
; File MSXZ10.ASM
	include mssdef.h
;       Copyright (C) 1982,1991, Trustees of Columbia University in the
;       City of New York.  Permission is granted to any individual or
;       institution to use, copy, or redistribute this software as long as
;       it is not sold for profit and this copyright notice is retained.
; Kermit system dependent module for Heath/Zenith Z100
; Edit history
; 2 March 1991 version 3.10
; Last change:	3 November 1990.
; 
; OUTCH2 defined as far label.
; Replay code in PRTCHR modified per ibm pc version and call serrst added at
; label coms0.	These two last changes are for version 3.02.
; New code for VTS and VTSTAT added and under revision but not active.	These
; two routines and corresponding data really belong in msy but the routines
; and some of their data are kept here to make msy small enough to assemble
; with MASM 4.	DUMPSCR moved to msyz10.asm.
; A number of calls to SPRTCH added in order to allow windowing for the non
; interupt driven S-100 modem ports COM3/COM4.	Some very limited success at
; 1200 baud would indicate that it might work at 300 (untested).
; SERISR optimized and performance improved for COM1/COM2.  However, there are
; still some problems from 19200 baud and up, in particular with windowing.
; OUTCHR significantly rewritten.  Modified CHKXON (COM1/2) and CHKXOF (COM3/4)
; to call OUTCH5 and OUTCH2 respectively rather than OUTCHAR.
; SERISR significantly modified to improve flow control for COM1/2 and SPRTCH
; fixed to ignore flow control for COM3/4 if not called for.
; Minor correction to WAIT01.  CLEARL and CTLU merged.
; PUTHLP display routine improved and replay command implemented.
; Increased size of buffilen and buffolen.  Added register save to BEEP.
; Added routines ENA_WRP and DIS_WRP and several calls to these to make serial
; display behave.  Help message for 'set port' improved.
; Various cosmetic changes.
;
; First version of this file for MS-Kermit 3.0:	 8 May 1990.
; Bo Gedda
;
; Support for 2 US Robotics S-100 modems at ports 20H (com3) and 2EH (com4).
; com1 (1 in status list) means serial port B.
; com2 (2 in status list) means serial port A.
; com3 (3 in status list) means S-100 port 1 (20H).
; com4 (4 in status list) means S-100 port 2 (2EH).
; 
	public	getbaud, serini, serrst, clrbuf, outchr, coms, vts, vtstat
	public	ctlu, cmblnk, locate, prtchr, baudst, clearl, bdtab, dodel
	public	beep, sprtch, klen, ktab, krpl, getivec, setivec, dupflg
	public	count, xofsnt, puthlp, putmod, clrmod, poscur, pcwait
	public	sendbr, sendbl, machnam, lclini, outch2, dis_scan
	public	ihosts, ihostr, dtrlow, mdmhand, shomodem, getmodem
	public	portval, port1, port2, port3, port4, serhng, ena_scan
	public	flowon, flowoff, sescur, sesdisp, setnbios, peekcom, parmsk

off	equ	0
false	equ	0
true	equ	1
bufon	equ	1		; buffer level xon/xoff on-state control flag
usron	equ	2		; user level xon/xoff on-state control flag
mntrgh	equ	bufsiz*3/4	; High point = 3/4 of buffer full
mntrgl	equ	bufsiz/4	; Low point = 1/4 buffer full
xoftime equ	15		; 15 seconds time out for xoff, see timer

; constants used by serial port handler

; Z-100 standard serial ports A (J1) and B (J2), called COM2 and COM1 here.
; Note that A=J1=COM2=2 and B=J2=COM1=1.  Port B is the standard modem port
; similar to an IBM PC port.  Thats why.
; serial port information
TSRE	EQU	004H
THBE	EQU	001H
DTR	EQU	002H
DTROFF	EQU	0fdH
RTS	EQU	020H
RTSOFF	EQU	0dfH
DCD	EQU	040H
DSR	EQU	080H
RDA	EQU	002H
J1_ADDR EQU	0e8H
J2_ADDR EQU	0ecH
PDATA	EQU	0
PSTATUS EQU	1
PMODE	EQU	2
PCOMM	EQU	3
TXON	EQU	001H
TXOFF	EQU	0feH
RXON	EQU	004H
RXOFF	EQU	0fbH
MODE1	EQU	04dH
MODE2	EQU	030H	;  must be ORed with appropriate baud rate
Z8259	EQU	0f2H
EOI	EQU	020H
J1INT	EQU	68
J2INT	EQU	69
BUFILEN EQU	bufsiz
BUFOLEN EQU	bufsiz/2

BRKBIT	EQU	048H		; Send-break bit.

mdmdat1 equ	J2_ADDR		; Address of serial port B (J2)
mdmcom1 equ	J2_ADDR + PCOMM ; Address of serial port B command
mdmdat2 equ	J1_ADDR		; Address of serial port A (J1)
mdmcom2 equ	J1_ADDR + PCOMM ; Address of serial port A command

;US Robotics S-100 modem using 8251A USART data
mdmdat3 equ	020h		; Address of USR S-100 port 1
mdmcom3 equ	mdmdat3 + 1	; Address of USR S-100 command port
mdmdat4 equ	02eh		; Address of USR S-100 port 2
mdmcom4 equ	mdmdat4 + 1	; Address of USR S-100 command port
modsndb equ	1h		; Bit to test for send S-100 modem
modrcvb equ	2h		; Bit to test for receive S-100 modem
modperb equ	8h		; Parity error detect bit S-100 modem
modorub	equ	10h		; Overrun error detect bit
moddcdb equ	80h		; Carrier detect bit S-100 modem

COLUMNS EQU	80		; Characters per screen line.
ROWS	EQU	24		; Text lines per screen
VID_CMD EQU	0d8h		; Video-memory control port.
PAR_GRN EQU	0e000h		; Green video plane segment address.

; external variables used:
; 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,
;    port2, port3 or port4 )
; port1, port2, port3, port4 - portinfo structures for the corresponding ports
; monmode - color/monochrome mode of monitor
; dmpname - file name for screen dump file

; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.

BIOS_SEG SEGMENT AT 40H		; Define segment where BIOS really is
	ORG	1*3
BIOS_STATUS	LABEL FAR	; Console input status
	ORG	2*3
BIOS_CONIN	LABEL FAR	; Console input
	ORG	3*3
BIOS_CONOUT	LABEL FAR	; Console output
	ORG	4*3
BIOS_PRINT	LABEL FAR	; Printer output
	ORG	6*3
BIOS_AUXOUT	LABEL FAR	; AUX output routine
	ORG	25*3
BIOS_PRNFUNC	LABEL FAR	; PRN: FUNCTION
	ORG	26*3
BIOS_AUXFUNC	LABEL FAR	; AUX: function
	ORG	27*3
BIOS_CONFUNC	LABEL FAR	; CON: function
BIOS_SEG ENDS

;  Define functions of BIOS_CONFUNC, BIOS_PRNFUNC, and BIOS_AUXFUNC
CHR_WRITE	EQU 0		; Write function
CHR_READ	EQU CHR_WRITE+1 ; Read function
CHR_STATUS	EQU CHR_READ+1	; Status function
  CHR_SFGS	  EQU 0		  ; Get status subfunction
    CHRS_WA	    EQU 00000001B   ; <ETX> sent, waiting for <ACK>
    CHRS_WD	    EQU 00000010B   ; <DC3> seen, waiting for <DC1>
    CHRS_SN	    EQU 00000100B   ; Sending nulls
    CHRS_TXR	    EQU 10000000B   ; Transmitter ready to send data
    CHRS_RXR	    EQU 01000000B   ; Receiver has data 
    CHRS_RXOF	    EQU 00100000B   ; Receiver queue overflow
    CHRS_RXE	    EQU 00010000B   ; Other type of reciver error
    CHRS_TXE	    EQU 00001000B   ; Transmitter error
  CHR_SFGC	  EQU CHR_SFGS+1  ; Get configuration info subfunction
CHR_CONTROL	EQU CHR_STATUS+1 ; Control function
  CHR_CFSU	  EQU 0		  ; Setup new configuration parms subfunction
  CHR_CFCI	  EQU CHR_CFSU+1  ; Clear input subfunction
  CHR_CFCO	  EQU CHR_CFCI+1  ; Clear output subfunction
CHR_LOOK	EQU CHR_CONTROL+1; Nondestructive read function
CHR_FMAX	EQU CHR_LOOK	; Maximum function number

; storage for port configuration
cfginfo struc
cfclass db	0
cfattr	db	0
cfport	dw	0
cfbaud	db	0
cfhshk	db	0
cfbctl	db	0
cfecnt	db	0
cfncnt	db	0
cfnchr	db	0
cfres	db	6 dup(?)
cfsize	db	0
cfginfo ends

; 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

data	segment
	extrn	flags:byte, trans:byte, taklev:byte, verident:byte
	extrn	comptab:byte, termtb:byte, ontab:byte, scrtab:byte
	extrn	cntltab:byte, beltab:byte, curtab:byte, chatab:byte
	extrn	kpamtab:byte, dirtab:byte, doscol:byte
	extrn	lclsusp:word, lclrest:word, lclexit:word, dosflg:byte
	extrn	dosflg1:byte, repflg:byte, diskio:byte, kstatus:byte
	extrn	holdscr:byte, vtemu:word, lincur:word
	extrn	belltype:byte, vtroll:byte

oldoff	dw	0
oldseg	dw	0
sescur	dw	0
dupflg	db	0		; full (0) or half (1) duplex on port
brkval	db	0		; What to send for a break.
brkdur	dw	0		; Length of break in centiseconds
badbd	db	cr,lf,'Unimplemented baud rate$'
noimp	db	cr,lf,'Not implemented$'
coms0msg db	cr,lf,'No US Robotics S-100 modem detected at this port!'
	db	cr,lf,'$'
comsmsg db	' One of the following:'
	db	cr,lf,'  1  2  3  4  COM1  COM2  COM3  COM4  A  B  J1  J2'
	db	cr,lf,lf,'Where'
	db	cr,lf,'  1 = COM1 = Serial Port B = J2'
	db	cr,lf,'  2 = COM2 = Serial Port A = J1'
	db	cr,lf,'  3 = COM3 = US Robotics S-100 modem at port 20H'
	db	cr,lf,'  4 = COM4 = US Robotics S-100 modem at port 2EH$'
vtsmsg	db	cr,lf,'The Z-100 terminal has inherent HEATH-19 support.'
	db	cr,lf,' Set terminal none activates native Heath-19 '
	db	'properties.',cr,lf
	db	' This deactivates key mapping and scan codes.$' 
msmsg0	db	cr,lf,'  Modem may be ready: DSR is unknown$'
msmsg1	db	cr,lf,'  Modem is not ready: DSR is off$'
msmsg2	db	cr,lf,'  Modem is ready:     DSR is on$'
msmsg3	db	cr,lf,'  no Carrier Detect:  CD  is off$'
msmsg4	db	cr,lf,'  Carrier Detect:     CD  is on$'
msmsg5	db	cr,lf,'  no Clear To Send:   CTS is off$'
msmsg6	db	cr,lf,'  Clear To Send:      CTS is on$'
msmsg7	db	cr,lf,'  Modem is not used by the Network$'
not_z	db	'Sorry, wrong software!',cr,lf
	db	'This Kermit will only run on the Z-100 -- a non '
	db	'IBM PC compatible',cr,lf,lf
machnam db	'Heath-Zenith_Z-100$'
com3ms	db	'Carrier detected at S-100 Port 20H, COM3',cr,lf,'$'
com4ms	db	'Carrier detected at S-100 Port 2EH, COM4',cr,lf,'$'
com3ms1 db	'Modem   detected at S-100 Port 20H, COM3',cr,lf,'$'
com4ms1 db	'Modem   detected at S-100 Port 2EH, COM4'
crlf	db	cr,lf,'$'
infmsg	db	'S-100 MODEM INITIALIZATION FAILURE',cr,lf,'$'
wmsg	db	cr,lf,' CARRIER detected  --  disconnecting',cr,lf,'$'
dscmsg	db	cr,lf,' DISCONNECTED',cr,lf,'$'
ndscmsg db	cr,lf,' !!!  WARNING  >>>  NOT DISCONNECTED  !!!',cr,lf,'$'
hngstr	db	'+++$'
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,lf,' The USR S-100 modem is hung up using "+++".'
	db	cr,lf,'$'				       
rdbuf	db	80 dup (?)	; temp buf [jrd]
delstr	db	BS,BS,'  ',BS,BS,'$'	; Delete string
clrlin	db	BS,BS,'  ',cr,'$'	; Clear line (just the cr part)
home	db	ESCAPE,'H$'	; Home cursor
clrstr	db	ESCAPE,'E$'	; Home cursor and erase entire display
eeolstr db	ESCAPE,'K$'	; Erase to end of line
enamod	db	ESCAPE,'x1$'	; Enable 25th line
dismod	db	ESCAPE,'y1$'	; Disable 25th line
enascan db	ESCAPE,'y?$'	; Enable scan codes, disable key expansion
disscan db	ESCAPE,'x?$'	; Disable scan codes, enable key expansion
begrev	db	ESCAPE,'p$'	; Enter reverse video
endrev	db	ESCAPE,'q$'	; Exit reverse video
lin25	db	ESCAPE,'Y8 $'	; Column 1 row 25
savcur	db	ESCAPE,'j$'	; Save current cursor position
precur	db	ESCAPE,'k$'	; Restore cursor to previous position
monstr	db	ESCAPE,'i0$'	; Return montior information
portin	db	-1		; Has comm port been initialized?
				; -1=has not used, 1=is used, 0=has been used
xofsnt	db	0		; Say if we sent an XOFF
xofrcv	db	0		; Say if we received an XOFF
parmsk	db	0ffh		; parity mask, 0ffh for no parity, 07fh with
flowoff db	0		; flow-off char, Xoff or null (if no flow)
flowon	db	0		; flow-on char, Xon or null
tmp	db	0,'$'
temp	dw	0		; Temporary storage.
mddat0	dw	0		; Storage for modem data port
mdstat0 dw	0		; Storage for modem status port
savedi	dw	offset source	; Temporary storage for di
srcpnt	dw	offset source	; where to read next serial port byte
source	db	bufsiz dup(0)	; S-100 port input buffer
timer	db	0
timer0	db	0
				; begin Terminal emulator data set
portmax equ	4		; number of predefined ports

port1	prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
port2	prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
port3	prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
port4	prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
	rept	portmax-4
	prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
	endm
portval dw	port1		; Default is to use port 1

bdtab	db	16		; 16 entries
	mkeyw	'45.5',0
	mkeyw	'50 ',1
	mkeyw	'75 ',2
	mkeyw	'110 ',3
	mkeyw	'134.5',4
	mkeyw	'150',5
	mkeyw	'300',6
	mkeyw	'600',7
	mkeyw	'1200',8
	mkeyw	'1800',9
	mkeyw	'2000',10
	mkeyw	'2400',11
	mkeyw	'4800',12
	mkeyw	'9600',13
	mkeyw	'19200',14
	mkeyw	'38400',15

bdtab12 db	16		; 16 (yes 16) entries for com1 and com2 
	mkeyw	'45.5',0
	mkeyw	'50 ',1
	mkeyw	'75 ',2
	mkeyw	'110 ',3
lbdtab12  equ	$-bdtab12	; length of table


bdtab34 db	4		; 4 entries for com3 and com4, s-100 modem 
	mkeyw	'150 ',0
	mkeyw	'300',1
	mkeyw	'600',2
	mkeyw	'1200',3

; this table is indexed by the baud rate definitions given in
; bdtab.  Unsupported baud rates should contain 0FFH.
bddat	label	word
	dw	0		; 45.5 baud
	dw	1		; 50 baud
	dw	2		; 75 baud
	dw	3		; 110 baud
	dw	4		; 134.5 baud
	dw	5		; 150 baud
	dw	6		; 300 baud
	dw	7		; 600 baud
	dw	8		; 1200 baud
	dw	9		; 1800 baud
	dw	10		; 2000 baud
	dw	11		; 2400 baud
	dw	12		; 4800 baud
	dw	13		; 9600 baud
	dw	14		; 19200 baud
	dw	15		; 38400 baud
lbddat	equ	$-bddat		; length of table

bddat12 label	word		; for com1 and com2 
	dw	0		; 45.5 baud
	dw	1		; 50 baud
	dw	2		; 75 baud
	dw	3		; 110 baud
	dw	4		; 134.5 baud
	dw	5		; 150 baud
	dw	6		; 300 baud
	dw	7		; 600 baud
	dw	8		; 1200 baud
	dw	9		; 1800 baud
	dw	10		; 2000 baud
	dw	11		; 2400 baud
	dw	12		; 4800 baud
	dw	13		; 9600 baud
	dw	14		; 19200 baud
	dw	15		; 38400 baud

bddat34 label	word		; for com3 and com4, s-100 modem
	dw	0		; 150 baud
	dw	1		; 300 baud
	dw	2		; 600 baud
	dw	3		; 1200 baud
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 
	dw	0ffh 

; baud rate data for S-100 modem
bd150	db	4fh		; Low speed mode byte	 (150/300)   
	db	17h		; Low speed command byte (150/600)
bd300	db	4fh		; Low speed mode byte	 (150/300)
	db	37h		; High speed command byte(300/1200)
bd600	db	4eh		; High speed mode byte	 (600/1200)
	db	17h		; Low speed command byte (150/600)
bd1200	db	4eh		; High speed mode byte	 (300/1200)
	db	37h		; High speed command byte(300/1200)

; S-100 COM3/COM4 default baud rate: 0=150, 1=300, 2=600, 3=1200 baud
bds100	equ	3		; Set to 0, 1, 2, or 3
 
; S-100 modem set up string
; echo commands, use extended result codes, do not answer call
set_str db	'ATE1X1S0=0',cr,'$'

auxconf cfginfo <>

; variables for serial interrupt handler

count	dw	0		; Number of chars in int buffer.
buffin	db	BUFILEN+2 dup(?)  ; input buffer
bufibeg dw	0
bufiend dw	0
buffout db	BUFOLEN+2 dup(?)  ; output buffer
bufobeg dw	0
bufoend dw	0
portadr dw	0
intin	db	0		; port int installed flag
mdmhand db	0		; Modem status


ourarg	termarg <>

klen	dw	?		; length of key redefinition table
ktab	dw	?		; address of key redefinition table
krpl	dw	?		; address of key replacement table

colortb	db	0,4,2,6,1,5,3,7		; color reversed-bit setting bytes
clrset	db	?			; Temp for SET Term Tabstops xxx

; This is data for the extended set terminal parameters.  It was put here
; in order to keep the size of msyz10.asm within limits for assembly by
; MASM 4.  The corresponding code is conatained in VTS and VTSTAT below.
erms41	db	cr,lf,'?More parameters are needed$'
vthlp	db	' one of the following:',cr,lf
	db '  terminal types of: None, Heath-19, VT52, VT102, VT320,'
	db	' or Tek4010',cr,lf
	db '  Newline-mode    Cursor-style        Character-set'
	db 	cr,lf
	db '  Keyclick        Margin-bell         Screen-background'
	db	' (normal, reverse)',cr,lf
	db '  Tabstops        Wrap (long lines)   Color (fore & background)'
	db	cr,lf,'  Bell  audible or visual'
	db	cr,lf,'  Clear-screen  (clears old startup screen)'
	db	cr,lf,'  Controls 7-bit or 8-bit  (permits VT320 to use'
	db	' 8-bit control sequences (C1))'
	db	cr,lf,'  Direction Left-to-right or Right-to-left'
	db	' (screen writing direction)'
	db	cr,lf,'  Graphics  (type of display adapter when in Tek4010'
	db	' mode)'
	db	cr,lf,'  Keypad numeric (normal) or application mode'
	db 	cr,lf,'  Replay filespec (display a file through the emulator)'
	db	cr,lf,'  Rollback  (undo screen roll back before writing new'
	db	' chars, default=off)$'
clrhlp	db	' one of the following:'
	db	cr,lf,'  AT #s  (to set tabs at column #s)    or'
	db	' AT start-column:spacing'
	db	cr,lf,'  Clear AT #s (clears individual tabs) or'
	db	' AT start-column:spacing'
	db	cr,lf,'  Clear ALL  (to clear all tabstops)'
	db	cr,lf,'  Ex: Set term tab at 10, 20, 34        sets tabs'
	db	cr,lf,'  Ex: Set term tab at 1:8        sets tabs at 1, 9,'
	db	cr,lf,'  Ex: Set term tab clear at 9, 17, 65   clears tabs'
	db	cr,lf,'  Ex: Set term tab clear at 1:8  clears tabs at 1, 9,'
	db	' 17,...$'
tbserr	db	cr,lf,'?Column number is not in range 1 to screen width-1$'
colhlp	db	cr,lf,'  Set Term Color  value, value, value, ...'
	db	cr,lf,'   0 no-snow mode on an IBM CGA and white on black'
	db	cr,lf,'   1 for high intensity foreground'
	db	cr,lf,'  10 for fast CGA screen updating (may cause snow)'
	db	cr,lf,'  Foreground color (30-37) = 30 + sum of colors'
	db	cr,lf,'  Background color (40-47) = 40 + sum of colors'
	db	cr,lf,'    where colors are  1 = red, 2 = green, 4 = blue'
	db	cr,lf,'  Ex: 0, 1, 37, 44   IBM CGA(0), bright(1) white(37)'
	db	' chars on a blue(44) 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: $'
vtbellm	db	'Term margin-bell: $'
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  foregnd:3$'
colst2	db	' backgnd:4$'
vtrolst	db	'Term rollback: $'
vtdir	db	'Term direction: $'
vtcntst	db	'Term controls: $'
vtkpst	db	'Term keypad: $'
vtbset	db	'Term bell: $'
vtgchst	db	'Term graph char: $'
						; terminal emulator
vtstbl	stent	<srchkw,vtcset,chatab,vtemu.vtchset>		; char set
	stent	<srchkb,vtclik,ontab,vskeyclick,vtemu.vtflgop>	; keyclick
	stent	<srchkb,vtwrap,ontab,vswrap,vtemu.vtflgop>	; line wrap
	stent	<srchkb,vtcntst,cntltab,vscntl,vtemu.vtflgop>	; controls
	stent	<srchkb,vtbellm,ontab,vsmarginbell,vtemu.vtflgop>;margin bell
	stent	<srchkb,vtcur,curtab,vscursor,vtemu.vtflgop>	; cursor type
	stent	<srchkw,vtbset,beltab,belltype>			; bell
 	stent	<srchkb,vtdir,dirtab,vswdir,vtemu.vtflgop>	; write direct
	stent	<srchkb,vtnewln,ontab,vsnewline,vtemu.vtflgop>	; newline
	stent	<srchkw,vtrolst,ontab,vtroll>			; rollback
	stent	<srchkb,vtkpst,kpamtab,deckpam,vtemu.vtflgop>	; keypad
	stent	<srchkb,vtscrn,scrtab,vsscreen,vtemu.vtflgop>	; screen 
	dw	0		; end of table
						; end of Terminal data set

vttbl	db	19			; number of entries
	mkeyw	'Bell',8800h		; note 8800 flag for decoding
	mkeyw	'Character-set',chaval+8300h
	mkeyw	'Clear-screen',8500h	; 8500h = marker here
	mkeyw	'Color',8200H		; screen fore/back colors; 200H=marker
	mkeyw	'Controls',cntlval
	mkeyw	'Cursor-style',curval
	mkeyw	'Direction',dirval
	mkeyw	'Graphics',8600h	; Tek graphics board, 800h=marker
	mkeyw	'Heath-19',ttheath+8100H; note 8100H flag for decoding here
	mkeyw	'Keyclick',keyval
	mkeyw	'Keypad',kpamval
	mkeyw	'Margin-bell',marval
	mkeyw	'None',ttgenrc+8100H
	mkeyw	'Newline',newval
	mkeyw	'Replay',8700h		; note 8700H flag for file replaying
	mkeyw	'Rollback',8400h	; note 8400H flag for decoding
	mkeyw	'Screen-background',scrval
	mkeyw	'Tabstops',tabval
	mkeyw	'Wrap',wraval

vtsflg equ	this word		; define small digits xxxval
newval	equ	$-vtsflg		; 0   and mask for bit in byte
	dw	vsnewline		;  1
wraval	equ	$-vtsflg		; 2
	dw	vswrap			;  2
chaval	equ	$-vtsflg		; 4
	dw	vsnrcm			;  4
dirval	equ	$-vtsflg		; 6
	dw	vswdir			;  8
keyval	equ	$-vtsflg		; 8
	dw	vskeyclick		;  10h
marval	equ	$-vtsflg		; 10
	dw	vsmarginbell		;  20h
curval	equ	$-vtsflg		; 12
	dw	vscursor		;  40h
scrval	equ	$-vtsflg		; 14
	dw	vsscreen		;  80h
cntlval	equ	$-vtsflg		; 16
	dw	vscntl			;  100h
kpamval	equ	$-vtsflg		; 18
	dw	deckpam			;  400h
numflgs equ	($-vtsflg)/2		;  10
tabval	equ	$-vtsflg		; 20
	dw	0
;vtrtns	dw	numflgs dup (flgset), tabmod ; dispatch table for vtsflg

data	ends

code	segment public
	extrn	comnd:near, dopar:near, defkey:near, getpos:near, atsclr:near
	extrn	lclyini:near, setcol:near, srchkb:near, srchkw:near
	extrn	csrtype:near
	assume	cs:code, ds:data, es:nothing

; local initialization
LCLINI	proc	near
	jmp	lclini1			; Bypass the exit code
not_z10:mov	ah,prstr
	mov	dx,offset not_z		; This is not a Z-100, IBM PC maybe?
	int	dos			; This program is for
	mov	dx,offset verident	; display version header
	int	dos
	mov	ah,4ch			; terminate process
	int	dos
; Find out if this is a Z-100
; We are doing that by looking for 0E9H at locations 0040:0000H
; and 0040:0003H which are in the Z-100 bios jump table.
lclini1:mov	bx,BIOS_SEG	; The segment at 40h		
	mov	ax,es		; Save es
	mov	es,bx		; Set up the extra segment
	cmp	byte ptr es:0,0e9h ; Z-100?
	jnz	not_z10		; No, it's probably IBM compatible
	cmp	byte ptr es:3,0e9h ;Z-100?
	jnz	not_z10		; No, it's probably IBM compatible
	mov	es,ax		; Restore es
;
	mov	flags.vtflg,ttheath ; Set Heath-19 emulation mode, allows macs
	mov	brkval,BRKBIT	; What to send for a break
	in	al,mdmcom4	; Check this port
	and	al,modperb	; Is it there?
	jnz	lclini3		; No, skip
	mov	dx,offset com4ms1
	mov	ah,prstr	; Tell user it is there
	int	dos
	in	al,mdmcom4	; Check again	
	and	al,moddcdb	; Carrier?
	jz	lclini3		; No, skip
	mov	flags.comflg,4	; Indicate s-100 port 2 for now
	mov	portval,offset port4
	mov	mddat0,mdmdat4
	mov	mdstat0,mdmcom4
	mov	ah,prstr	; Tell user
	mov	dx,offset com4ms
	int	dos
lclini3:in	al,mdmcom3	; Check this port
	and	al,modperb	; Is it there?
	jnz	lclini4		; No, skip
	mov	dx,offset com3ms1
	mov	ah,prstr	; Tell user it is there
	int	dos
	in	al,mdmcom3	; Check again	
	and	al,moddcdb	; Carrier?
	jz	lclini4		; No, skip
	mov	flags.comflg,3	; Indicate s-100 port 1
	mov	portval,offset port3
	mov	mddat0,mdmdat3
	mov	mdstat0,mdmcom3
	mov	ah,prstr	; Tell user
	mov	dx,offset com3ms
	int	dos
lclini4:
	call	getbaud		; Which port of COM1/COM2 is default?
				; Get baud rate from UARTs for this
	call	baudref		; Set up baud rate references bdtab, bddat
	mov	port3.baud,bds100  ; and put in default baud rate
	mov	port4.baud,bds100  ; and put in default baud rate
	mov	lclsusp,offset suspend ; call this when suspending to DOS
	mov	lclrest,offset restore ; call this when returning from DOS
	mov	lclexit,offset finexit ; call this when exiting Kermit
 	call	ena_wrp		; Make terminal wrap to next line at line end
	call	lclyini		; let other modules initialize too...
	ret			; We are all done with lclini
;
baudref:push	di		; Rearrange bdtab and bddat
	push	si
	push	es
	mov	ax,ds		; Set up
	mov	es,ax		;  pointers
	mov	di,offset bddat ;  to move baud
	mov	si,offset bddat12 ; rate selection
	mov	cx,lbddat	;  length of table
	cmp	flags.comflg,2	; Ports 1/2
	jle	lclini5		;  or ports 3/4?
	mov	si,offset bddat34 ;Port 4! 
lclini5:cld			
	rep	movsb		; Move array
	mov	di,offset bdtab ; This too
	mov	si,offset bdtab12
	mov	cx,lbdtab12	; Length of table 
	cmp	flags.comflg,2	; Ports 1/2
	jle	lclini6		;  or ports 3/4?
	mov	si,offset bdtab34 ;Port 4! 
lclini6:rep	movsb		; Move array
	pop	es		; Restore registers
	pop	si
	pop	di
	ret			; We're done
LCLINI	endp

; Call these routines when suspending Kermit to go to DOS
suspend proc	near
	call	ihosts		; suspend the host
	call	serrst
	call	dis_scan	; disable scan code generation
	call	dis_wrp		; disable sreen line wrap around
	ret
suspend endp

; Call these routines when returning to Kermit from DOS
restore proc	near
	call	serini		; reinit serial port
	call	ihostr		; resume the host
	call	ena_wrp		; enable screen line wrap around
	ret
restore endp

; Call these routines when doing final exit of Kermit
finexit proc	near
	call	serrst		; reset serial port
	call	dis_scan	; disable scan code generation
	call	dis_wrp		; disable sreen line wrap around
	ret
finexit endp

; This routine, ena_scan, enables Z-100 scan code generation.  It also
; disables extended key code generation.  Modifies ax.
ENA_SCAN PROC	NEAR
	push	dx
	mov	ah,prstr
	mov	dx,offset enascan
	int	dos 
	or	dosflg1,1		; say scan codes enabled
	pop	dx
	ret
ENA_SCAN ENDP

; This routine, dis_scan, disables Z-100 scan code generation.	It also
; enables extended key code generatin.	Modifies ax.
DIS_SCAN PROC	NEAR
	push	dx
	mov	ah,prstr
	mov	dx,offset disscan
	int	dos 
	and	dosflg1,0feh		; say scan codes disabled
	pop	dx
	ret
DIS_SCAN ENDP

; This routine, ena_wrp, enables wrap around at end of line.
; Modifies ax.
ENA_WRP PROC NEAR
	push	dx
	mov	ah,conout
	mov	dl,ESCAPE
	int	dos
	mov	dl,'v'
	int	dos
	pop	dx
	ret
ENA_WRP ENDP

; This routine, dis_wrp, disables wrap around at end of line.
; Modifies ax.
DIS_WRP PROC NEAR
	push	dx
	mov	ah,conout
	mov	dl,ESCAPE
	int	dos
	mov	dl,'w'
	int	dos
	pop	dx
	ret
DIS_WRP ENDP

; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdmhand, the modem line status register. [jrd]
shomodem proc	near
	mov	ah,cmeol		; get a confirm
	call	comnd
	jc	shomd5			; c = failure
	mov	dx,offset msmsg7	; no modem status for network
	call	getmodem		; get modem status
	mov	ah,prstr
	cmp	flags.comflg,2		; port 1 or 2
	jle	shomd0			; yes, jump
	mov	dx,offset msmsg0	; not supported function
	jmp	shomd1
shomd0: mov	dx,offset msmsg1	; modem not ready msg
	test	mdmhand,20h		; is DSR asserted?
	jz	shomd1			; z = not ready
	mov	dx,offset msmsg2	; modem ready msg
shomd1: int	dos
	mov	dx,offset msmsg3	; CD not asserted msg
	test	mdmhand,80h		; CD asserted?
	jz	shomd2			; z = not asserted
	mov	dx,offset msmsg4	; CD asserted msg
shomd2: int	dos
	clc
shomd5: ret
shomodem endp

; Get modem status and set global byte mdmhand. Preserve all registers but dx.
; Returns with byte mdmhand in al, ah=0.
getmodem proc	near		; gets modem status upon request
	cmp	flags.comflg,2	; COM1 or COM2?
	jna	getmodem2	; na = yes, jump to handle these
	mov	dx,mdstat0	; Port address
	in	al,dx		; Get status
	and	al,moddcdb	; Carrier?
	mov	mdmhand,0	; Everything off
	jz	getmodem1	; z = yes, no carrier, done
	mov	mdmhand,80h	; No, carrier detected
getmodem1:jmp	getmodem4	; Done with COM3/COM4
getmodem2:mov	dx,portadr
	add	dx,PSTATUS
	in	al,dx
	mov	mdmhand,0	; Everything off
	test	al,DSR		; DSR indicated?
	jz	getmodem3	; z = no, go on
	mov	mdmhand,20h	; Indicate DSR
getmodem3:test	al,DCD		; CD indicated?
	jz	getmodem4	; z = no, go on
	or	mdmhand,80h	; Indicate CD, don't touch DSR
getmodem4:mov	al,mdmhand	; Promised it here
	xor	ah,ah		; A promise too
	clc			; Success
	ret
getmodem 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.
CLRBUF	PROC	NEAR
	cmp	flags.comflg,2	; Ports 1/2?
	jg	clrbuf1		; g = no, do S-100 stuff
	cli
	push	bx
	xor	bx,bx
	mov	bufoend,bx
	mov	bufobeg,bx
	mov	bufiend,bx
	mov	bufibeg,bx
	pop	bx
	mov	count,0
	sti	
	ret
clrbuf1:push	ax			; First empty port
	push	dx
	mov	dx,mddat0		; Get possible
	in	al,dx			;  character
	pop	dx
	pop	ax			;  then do it
	mov	count,0			; Nothing in buffer
	mov	srcpnt,offset source	; Reset buffer
	mov	savedi,offset source	;  pointers
	ret
CLRBUF	ENDP

; Put the char in AH to the serial port, assumimg the port is active.
; Returns carry clear if success, else carry set.
; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to
; prevent confusion of flow control logic at top of outchr; used by receiver
; buffer high/low water mark flow control code. [jrd]
; 14 September 1990 add entry point OUTCH5 for priority sending of xon;
; used by CHKXON and SERISR.
OUTCHR	PROC	NEAR
	cmp	flowoff,0		; Are we doing flow control
	je	outch2			; No, just continue
	cmp	ah,flowoff		; sending xoff?
	jne	outch1			; ne = no
	mov	xofsnt,usron		; indicate user level xoff being sent
	jmp	outch12
outch1:and	xofsnt,not usron	; cancel user level xoff
	cmp	ah,flowon		; user sending xon?
	jne	outch12			; ne = no
	mov	xofsnt,off	; say an xon has been sent (cancels xoff)
outch12:mov	timer,xoftime+1	; Set delay to xoftime minimum, maximum+1 sec
outch14:cmp	xofrcv,true	; Are we being held (xoff received)?
	jnz	outch2		; no - it's OK to go on
	cmp	flags.comflg,2	; Check if S-100 ports
	push	ax		; Save regs
	push	bx
	push	cx
	push	dx
	jle	outch16		; No, make it simple
	push	es
	mov	cx,1		; No delay for sprtch
	call	sprtch		; Get possible char at port com3/4
	pop	es
outch16:mov	ah,gettim	; Get time function
	int	dos
	cmp	dl,timer0	; Normally 0
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	jnz	outch14		; No, go loop
	xor	timer0,50	; Yes, move target 1/2 second
	cmp	timer0,0	; This is only true every second
	jnz	outch14		; No, continue looping
	dec	timer		; Yes, one second has passed (unless 1st time)
	jnz	outch14		; No, have more seconds left, try again
	mov	xofrcv,off	; Timed out, force it off and fall thru.
OUTCH2	LABEL	NEAR   		; outch2 entry point without flow control
	mov	al,ah		; Routine works on AL.
	call	dopar		; Set parity appropriately.
	cmp	repflg,0	; Doing REPLAY from a file?
	je	outch24		; e = no
	and	al,7fh		; Strip parity
	cmp	al,'C'-40h	; Control-C? (to exit playback mode)
	je	outch22		; e = yes, return failure
	clc			; Return success, send nothing
	ret
outch22:stc			; Return failure to exit playback mode
	ret
;
outch24:push	bx
	push	dx
	cmp	flags.comflg,2	; Ports J1/J2
	jle	outch4		; Yes, go handle J1/J2
	mov	bl,al		; No, do S-100, save byte to send
	push	cx
	xor	cx,cx		; Set loop counter
outch26:push	bx		; Check on input
	push	cx
	push	es
	mov	cx,1		; No delay
	call	sprtch		; Get char from port if any
	pop	es
	pop	cx
	pop	bx
	mov	dx,mdstat0
	in	al,dx		; Check this port
	and	al,modsndb	;  for ready
	jnz	outch28		; Ready, continue
	loop	outch26		; Not ready, loop until ready or timeout
	jmp	short outch44	; Timed out, return with carry set
outch28:pop	cx
	mov	al,bl		; Get back byte to send
	mov	dx,mddat0
	out	dx,al		; Send it out
	jmp	outch8		; All done S-100 modem	
;
outch4: push	cx
	xor	cx,cx		; Set loop counter
outch40:mov	bx,bufobeg	; get pointer to beginning of que
	sub	bx,bufoend	; where are we?
	jnl	outch42		; we did not wrap
	add	bx,BUFOLEN	; we have wrapped
outch42:cmp	bx,BUFOLEN-2	; we have bx char in buffer; is it full?
	jnae	outch53		; no, go on
	loop	outch40		; yes, loop until there is space or timeout
outch44:pop	cx		; timed out
	pop	dx
	pop	bx
	stc
	ret
;
outch5: push	bx		; OUTCH5 entry for SERISR and CHKXON
	push	dx		;  ah will contain xon or xoff only
	push	cx
	xor	cx,cx		; Set loop counter
outch50:mov	bx,bufobeg	; get pointer to beginning of que
	sub	bx,bufoend	; where are we?
	jnl	outch51		; we did not wrap
	add	bx,BUFOLEN	; we have wrapped
outch51:cmp	bx,BUFOLEN	; we have bx char in buffer; is it full?
	jne	outch52		; no, go on
	loop	outch50		; yes, loop until there is space or timeout
	jmp	short outch44	; timed out, no space
outch52:mov	al,ah		; Routine works on AL.
	call	dopar		; Set parity appropriately.
	pop	cx
	jmp	short outch54
				;
outch53:pop	cx		; restore stack
	cmp	bx,0		; buffer empty?
	jz	outch58		; yes, skip
	cmp	flowoff,0	; Are we doing flow control
	je	outch58		; No, skip
	cmp	al,flowoff	; Is it xoff?
	je	outch54		; Yes, this is priority, expedite
	cmp	al,flowon 	; Is it xon?
	jne	outch58		; No, skip
				;
outch54:cli
	mov	bx,bufobeg	; beginning of que
	dec	bx		; we want space in between, bx still >= 0
	jae	outch56		; yes, go on
 	mov	bx,BUFOLEN	; wrap
outch56:mov	bufobeg,bx	; new beginning
	mov	byte ptr buffout[bx],al	 ; put char in it
	sti
	jmp	short outch6

outch58:mov	bx,bufoend
	mov	byte ptr buffout[bx],al	 ; put char in it
	inc	bx		; point to next spot in que
	cmp	bx,BUFOLEN	; looking at end of que ?
	jne	outch6		; no, OK
	xor	bx,bx		; yes, reset pointer
outch6: mov	bufoend,bx	; store new value
	mov	dx,portadr
	add	dx,PCOMM
	cli
	in	al,dx
	test	al,TXON		; TX already on ?
	jnz	outch7		; yes, OK
	or	al,TXON		; no, turn it on
	out	dx,al		;   it's on
outch7: sti			; done with 2661
outch8: pop	dx
	pop	bx
	clc			; success, return with carry cleared
	ret
OUTCHR	ENDP

; Move the cursor to the left margin, then clear to end of line.
CTLU	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset clrlin
	int	dos

; Clear to the end of the current line
CLEARL	PROC	NEAR
	push	ax
	push	dx
	mov	ah,prstr
	mov	dx,offset eeolstr	; Erase to end of line
	int	dos
	pop	dx
	pop	ax
	ret
CLEARL	ENDP
CTLU	ENDP

; This routine blanks the screen and homes the cursor.	Uses ax and dx.
CMBLNK	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset clrstr	; Home cursor, blank screen
	int	dos
	ret
CMBLNK	ENDP

; Locate: homes the cursor.  Uses ax and dx.
LOCATE	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset home		; Go to top left corner of screen.
	int	dos
LOCATE	ENDP

; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $.
PUTMOD	PROC	NEAR
	push	ax		; save regs
	push	dx		; preserve message
	mov	ah,prstr
	mov	dx,offset savcur
	int	dos
	mov	dx,offset enamod
	int	dos
	mov	dx,offset lin25
	int	dos
	mov	dx,offset begrev
	int	dos
	pop	dx		; get message back
	int	dos		; write it out
	mov	dx,offset endrev
	int	dos
	mov	dx,offset precur
	int	dos
	pop	ax
	ret			; and return
PUTMOD	ENDP

; clear the mode line written by putmod.
CLRMOD	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset dismod
	int	dos
	ret
CLRMOD	ENDP

BEEP	PROC	NEAR
	push	ax		; save regs
	push	dx		; preserve message
	mov	ah,conout
	mov	dl,BELL		; ASCII BEL
	int	dos		; Ring it
	pop	dx
	pop	ax
	clc
	ret
BEEP	ENDP

; Put a help message on the screen.  This one uses reverse video...
; pass the message in ax, terminated by a null.	 Messes up ax, bx, cx, dx.
PUTHLP	PROC	NEAR
	push	si
	push	ax		; preserve this
	mov	dx,offset crlf
	int	dos
	pop	si		; point to string again
	jmp	short puthl3	; assume message begins with cr and lf
puthl2:	call	getpos		; get cursor pos into dx
	mov	ax,dx		; from row ah, col al
	mov	bx,dx
	mov	bl,COLUMNS	;  to row bh, col bl
	mov	dx,word ptr doscol ; dos color reversed
	call	setcol		; set this color
	call	atsclr		;  and clear the line
puthl3: mov	cx,COLUMNS - 1	; characters on a line less one (starts at 0)
puthl4: lodsb			; get a byte
	mov	ah,conout	; print char
	cmp	al,0		; end of string?
	je	puthl5		; yes, stop
	cmp	al,lf		; lf ?
	je	puthl7 		; end of line, do new one
	cmp	cx,0		; last column
	je	puthl6		; no more space on line, get new one
	mov	dl,al		; else, print char
	int	dos
	jmp	short puthl3	; get next char
puthl5: pop	si
	ret
puthl6: mov	dl,cr
	int	dos
puthl7: mov	dl,lf
	int	dos
	jmp	short puthl2

PUTHLP	ENDP

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns carry clear.
BAUDST	PROC	NEAR
	mov	dx,offset bdtab		; baud rate table, ascii
	xor	bx,bx			; help is the table itself
	mov	ah,cmkey		; get keyword
	call	comnd
	jc	baudst1			; c = failure
	push	bx			; save result
	mov	ah,cmeol		; get confirmation
	call	comnd
	pop	bx
	jc	baudst1			; c = failure
	push	si
	mov	si,portval
	mov	ax,[si].baud		; remember original value
	mov	[si].baud,bx		; set the baud rate
	pop	si
	call	dobaud			; use common code
	clc
baudst1:ret
BAUDST	ENDP

DOBAUD	PROC	NEAR
	push	ax			; save some regs
	push	bx
	push	cx
	push	dx
	mov	bp,portval	; Pointer to port data structure
	mov	temp,ax		; Don't overwrite previous rate
	mov	ax,ds:[bp].baud ; Check if new rate is valid
	shl	ax,1		; 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,temp		; 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
	stc			; Failure
	jmp	dobd2
dobd0:	mov	ds:[bp].baud,ax ; Put in new baud rate
	cmp	flags.comflg,2	; is it J1/J2?
	jle	dobd1		; yes, go do J1/J2 stuff
	call	serini		; go set rate in S-100 modem

	jmp	dobd2
dobd1:	mov	dx,portadr	; get addr to send it
	add	dx,PMODE
	push	ax		; save baud
	mov	al,MODE1
	cli			; none while setting 2661
	out	dx,al		; mode reg 1/2
	pop	ax		; get baud back
	and	al,0fH		; make sure it's clean
	or	al,MODE2	; make complete mode 2/2 command
	out	dx,al		; set mode reg 2/2
	sti			; done with 2661
	clc			; Success
dobd2:	pop	dx		; restore regs
	pop	cx
	pop	bx
	pop	ax
	ret
DOBAUD	ENDP

; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.
; Also finds out which serial port, A (COM2) or B (COM1), is defined
; as default by Zenith Configur.
; This is used during initialization.
GETBAUD PROC	NEAR
	cmp	flags.comflg,2	; J1/J2?
	jg	getbau3		; No, all done
	
	push	ax
	push	bx
	push	dx
	push	di
	cmp	portadr,0	; Just started Kermit?
	jnz	getbau2		; No, skip this
	mov	bx,ds		; Set up pointer to config info
	mov	es,bx
	mov	bx,offset auxconf
	mov	ah,chr_status
	mov	al,chr_sfgc	; Get current config info
	call	bios_auxfunc
	cmp	auxconf.cfport,mdmdat1 ; Is it B?
	jne	getbau1		; ne = no
	mov	flags.comflg,1	; Set flag to indicate port B
	mov	portval,offset port1
	mov	mddat0,mdmdat1
	mov	portadr,mdmdat1
	mov	mdstat0,mdmcom1
	jmp	getbau2
getbau1:mov	flags.comflg,2	; Set flag to indicate port A
	mov	portval,offset port2
	mov	mddat0,mdmdat2
	mov	portadr,mdmdat2
	mov	mdstat0,mdmcom2	       
getbau2:mov	dx,portadr	; Get addr to retrieve mode from
	add	dx,PMODE
	in	al,dx		; Read and discard mode 1/2
	in	al,dx		; mode 2/2 has baud rate
	and	ax,000fH	; Clean it up
	mov	bp,portval
	mov	ds:[bp].baud,ax ; Put it in portinfo struct
	pop	di
	pop	dx
	pop	bx
	pop	ax
getbau3:ret
GETBAUD ENDP

; Get Char from serial port buffer.
; returns carry set if no character available at port, otherwise prtchr
; returns carry clear with char in al, # of chars in buffer in dx and count.
PRTCHR	PROC	NEAR
	cmp	flags.comflg,2	; check if S-100 ports
	jg	prtch4		; Yes, go do S-100 stuff
	call	chkxon		; see if we need to xon
	cmp	repflg,0	; REPLAY?
	je	prtch0		; e = no
 	jmp	prtch30		; yes, do replay file reading
prtch0: cli			; dont let intterrupts touch buffers
	mov	dx,bufiend	; compute number of chars in
	sub	dx,bufibeg	;   input que
	jge	prtch1		; is it wrapped around
	add	dx,BUFILEN	; yes, make it +
prtch1: cmp	dx,0		; anything in there ?
	jne	prtch2		; ne = yes. [jrd]
	mov	count,dx
	sti
	stc			; no
	ret
prtch2: mov	bx,bufibeg	; yes, get the char, get the position
	mov	al,byte ptr buffin[bx]	; get the char
	inc	bx		; bump the position ptr
	cmp	bx,BUFILEN	; wrap it ?
	jne	prtch3
	xor	bx,bx		; yes, reset pointer
prtch3: mov	bufibeg,bx	; store new value
	dec	dx		; we took one char out
	mov	count,dx	; save
	sti
	clc			; yes, got it
	ret
prtch4: 
	push	ax		; First check port for possible input
	push	bx
	push	cx
	push	es
	mov	cx,1		; Parameter for sprtch, cx=1 means don't loop
	call	sprtch		; Read port
	pop	es
	pop	cx
	pop	bx
	pop	ax
	cmp	repflg,0	; REPLAY?
	je	prtch41		; e = no
 	jmp	prtch30		; yes, do replay file reading
prtch41:cmp	count,0		; Buffer empty?
	jne	prtch5		; ne = no, get char
	mov	dx,0		; Nothing there		Is this needed?
	stc			; Got nothing
	ret
prtch5: push	si		; Don't mess up, used by spack
	mov	si,srcpnt	; Point to next character in que
	cld
	lodsb			; Get the next one
	cmp	si,offset source + bufsiz ; Bigger than buffer?
	jb	prtch6		; No, keep going
	mov	si,offset source ; Yes, wrap around
prtch6: dec	count
	mov	dx,count
	mov	srcpnt,si
	pop	si		; Left in good shape
	clc			; Yes, got it
	ret
prtch30:cmp	repflg,2		; at EOF already?
	jne	prtch31			; ne = no
	stc				; yes, return with no char
	ret
prtch31:push	bx			; REPLAY, read char from a file
	push	cx
	xor	dx,dx
	test	xofsnt,usron		; user level xoff sent?
	jz	prtch32			; z = no
	pop	cx			; suppress reading here
	pop	bx
	stc				; return with no char
	ret
prtch32:mov	ax,100
	mov	bx,1
	jmp	$+2			; flush lookahead buffer
	div	bx			; burn some cpu cycles
	div	bx			; because a 1 ms wait is too long
	div	bx
	div	bx
	mov	ah,readf2
	mov	bx,diskio.handle	; file handle
	mov	cx,1			; read one char
	mov	dx,offset rdbuf		; to this buffer
	int	dos
	jc	prtch34			; c = read failure
	cmp	ax,cx			; read the byte?
	jne	prtch34			; ne = no
	pop	cx
	pop	bx
	mov	al,rdbuf		; get the char into al
	mov	dx,1			; external char count
	clc
	ret				; return it
prtch34:call	beep
	mov	ax,40			; wait 40 millisec
	call	pcwait
	call	beep
	mov	repflg,2		; say at EOF
	pop	cx
	pop	bx
	stc				; say no char
	ret
PRTCHR	ENDP

; Examine incoming communications stream for a packet SOP character.
; Return CX= count of bytes starting at the SOP character (includes SOP)
; and carry clear. Return CX = 0 and carry set if SOP is not present.
; Destroys AL.
peekcom proc far
	mov	cx,count		; qty in circular buffer
	cmp	cx,6			; basic NAK
	jb	peekc4			; b = two few chars, get more
	push	bx
	cli		; interrupts off, to keep srcpnt & count consistent
	mov	bx,srcpnt	    ; address of next available slot in buffer
	sub	bx,cx		    ; minus number of unread chars in buffer
	cmp	bx,offset source	; located before start of buf?
	jae	peekc1			; ae = no
	add	bx,bufsiz		; else do arithmetic modulo bufsiz
peekc1:	mov	al,[bx]
	cmp	al,trans.rsoh		; packet receive SOP?
	je	peekc3			; e = yes
	inc	bx
	cmp	bx,offset source+bufsiz ; beyond end of buffer?
	jb	peekc2			; b = no
	mov	bx,offset source	; wrap around
peekc2:	loop	peekc1			; keep looking
	sti
	pop	bx
	stc				; set carry for no SOP
	ret
peekc3:	sti				; interrupts back on now
	pop	bx
	inc	cx			; include SOP in count
	clc				; say SOP found
	ret				; CX has count remaining
	
peekc4:	xor	cx,cx			; return count of zero
	stc				; say no data
	ret
peekcom endp


; local routine to see if we have to transmit an xon when com1/2
chkxon	proc	near
	cmp	xofsnt,false	; have we sent an xoff?
	je	chkxo1		; no, forget it
	cmp	flowoff,0	; Are wo doing flow control?
	je	chkxo1		; no, skip all this
	test	xofsnt,usron	; did user send an xoff?
	jnz	chkxo1		; nz = yes, don't contradict it here
	test	xofsnt,bufon	; have we sent a buffer level xoff?
	jz	chkxo1		; z = no, forget it
	cmp	count,mntrgl	; below trigger?
	jae	chkxo1		; no, forget it
	mov	ah,flowon	; xon
	call	outch5		; send it
	jc	chkxo1		; failure
	and	xofsnt,false	; remember we've sent the xon.
chkxo1: ret			; and return
chkxon	endp

; Local routine to see if we have to transmit an xoff or xon when com3/4
; this is probably overdoing it
; called by sprtch
chkxof	proc	near
	cmp	flowoff,0	; Are wo doing flow control?
	je	chkxof1		; no, skip all this
	test	xofsnt,usron	; did user send an xoff?
	jnz	chkxof1		; nz = yes, don't contradict it here
	test	xofsnt,bufon	; have we sent a buffer level xoff?
	jz	chkxof1		; z = no, forget it
	cmp	count,mntrgh	; Buffer filling up?
	jb	chkxof3		; no, go check that xon sent
	cmp	xofsnt,true	; yes, have we sent an xoff?
	je	chkxof1		; yes, all done
	mov	ah,flowoff	; xoff
	mov	xofsnt,true	; remember we've sent the xoff.
	jmp	short chkxof2	; go send xoff
chkxof3:cmp	count,mntrgl	; below trigger
	jae	chkxof1		; no, forget it
	cmp	xofsnt,false	; xon sent?
	je	chkxof1		; all done
	mov	ah,flowon	; xon
chkxof2:call	outch2		; send it
chkxof1:ret			; and return
chkxof	endp

; Read the serial port for the S-100 modem and put input in buffer.
; Call with delay loop count in cx, c = 1 means no delay.
; Input stream is monitored for xon/xoff.
; Called by outchr, prtchr and outtty.
; Destroys ax, bx, cx, dx, es
SPRTCH	PROC	NEAR
	mov	bx,ds		; Point to data segment
	mov	es,bx
	mov	dx,mdstat0	; Check 
	in	al,dx		;  status
	and	al,modrcvb	; Character at port?
	jnz	sprtch2		; Yes, go get it
	call	chkxof
	loop	sprtch0		; Keep checking port if cx not=1
	ret			; No data 

sprtch0:push	cx
	xor	cx,cx		; This is a delay loop to expand the delay for
	mov	cl,trans.rtime	;  screen escape sequencies and capture.
	or	cx,cx		; avoid 0, it will loop for ever
	jnz	sprtch1
	inc	cx
sprtch1:loop	sprtch1		;  The delay time is controlled through the
	pop	cx		;   receive timeout setting.
	jmp	sprtch

sprtch2:mov	dx,mddat0	; Get
	in	al,dx		;  character
	mov	ah,al		; Make working copy
	and	ah,parmsk	; Strip parity
	mov	bx,portval
	cmp	[bx].floflg,0	; Are we doing flow control.
	jz	sprtch4		; No, skip
	mov	dx,[bx].flowc
	cmp	ah,dh		; xon?
	jne	sprtch3		; No, check xoff
	mov	xofrcv,off	; Set flag to indicate xoff not received (xon)
	jmp	short sprtch6	; Get the next char

sprtch3:cmp	ah,dl		; xoff?
	jne	sprtch4		; No, go do normal buffer handling
	mov	xofrcv,true	; Set flag to indicatae xoff received
	jmp	short sprtch6	; Get the next char

sprtch4:push	di
	mov	di,savedi	; Point to last received char
	cld
	stosb			; Save the next one
	cmp	di,offset source + bufsiz ; Bigger than buffer?
	jb	sprtch5		; No, keep going
	mov	di,offset source ; Yes, wrap around
sprtch5:inc	count
	mov	savedi,di
	pop	di
sprtch6:call	chkxof
	loop	sprtch0		; Keep checking port if cx not=0
	ret
SPRTCH	ENDP

; IHOSTS - Initialize the host by sending XOFF, or equivalent.
; Requires that the port be initialized before hand.
; Do not send flow control if doing half duplex.
IHOSTS	PROC	NEAR
	push	ax		; save the registers
	push	cx
	push	dx
	mov	xofrcv,off	; clear old xoff received flag
	mov	xofsnt,off	; and old xoff sent flag
	mov	ah,flowoff	; put wait flow control char in ah
	or	ah,ah		; check for null char
	jz	ihosts1		; z = null, don't send it
	cmp	dupflg,0	; full duplex?
	jne	ihosts1		; ne = no, half
	call	outchr		; send it
ihosts1:call	clrbuf		; clear out interrupt buffer
	pop	dx		; empty buffer. we are done here
	pop	cx
	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
	or	ah,ah		; check for null char
	jz	ihostr1		; z = null, don't send it
	call	outchr		; send it (release Host's output queue)
ihostr1:pop	cx
	pop	bx
	pop	ax
	ret
IHOSTR	ENDP


; Global proc to Hangup the Phone or Network by making DTR and
; RTS low (phone).
DTRLOW	PROC	NEAR
	mov	ah,cmline	; allow text, to be able to display help
	mov	bx,offset rdbuf		; dummy buffer
	mov	dx,offset hnghlp	; help message
	call	comnd			; get a confirm
	jc	dtrlow3			; c = failure
	cmp	flags.comflg,'0'	; Bios?
	jb	dtrlow1			; b = no, UART
	cmp	flags.comflg,'4'	; Bios?
	jbe	dtrlow2			; be = yes, can't access modem lines
dtrlow1:call	serhng			; drop DTR and RTS
	cmp	taklev,0		; in a Take file or macro?
	jne	dtrlow2			; ne = yes, no message
	mov	ah,prstr		; give a nice message
	mov	dx,offset hngmsg
	int	dos
dtrlow2:clc				; success
dtrlow3:ret
DTRLOW	ENDP

; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. (com1 and com2)
; The USR S-100 modem will not respond to dropping of DTR.  Instead the +++
; sequence must be sent.
; Calling this twice without intervening calls to serini should be harmless.
SERHNG	PROC	NEAR
	cmp	flags.comflg,2	; Which port?
	jg	serhng1
	cli
	call	porton		; Insure that DTR and RTS are high
	sti
	mov	dx,portadr
	add	dx,PCOMM
	in	al,dx
	xor	al,DTR		; Drop DTR
	xor	al,RTS		; Drop RTS 
	out	dx,al
	mov	ax,500		; 500 millisec, for pcwait
	call	pcwait		; keep lines low for at least 500 millisec
	clc
	ret
serhng1:mov	dx,mdstat0	; Port address.	 [19b]
	in	al,dx		; Get status
	and	al,moddcdb	; Carrier?
	jz	serhng4		; No, tell user
	mov	ah,prstr	; Yes, tell user to wait
	mov	dx,offset wmsg
	int	dos
	mov	ax,1100		; 1100 milliseconds
	call	pcwait		; Wait before sending '+++'
	push	si
	mov	si,offset hngstr  ; Point to '+++'
	cld
	lodsb			; Get the first byte of string
serhng2:push	ax		; We need the loaded byte later
	mov	dx,mdstat0	; The status port
serhng3:in	al,dx		; Get status
	and	al,modsndb	; Mask for ready
	jz	serhng3		; No, go on
	pop	ax		; Get byte back
	mov	dx,mddat0	; The data port
	out	dx,al		; Send it out
	lodsb			; Load next byte
	cmp	al,'$'		; Finished?
	jnz	serhng2		; No, process next
	pop	si
	mov	ax,1100		; 1100 milliseconds
	call	pcwait		; Wait after sending '+++'
	mov	dx,mdstat0	; Port address.	 [19b]
	in	al,dx		; Get status
	and	al,moddcdb	; Carrier?
serhng4:mov	ah,prstr
	mov	dx,offset dscmsg ; Point to message
	clc
	jz	serhng5		; Yes, no carrier, go tell user
	inc	cl		; No, carrier detected
	cmp	cl,3		; Try three times
	jnz	serhng1		; No, go try again
	mov	dx,offset ndscmsg ; Warn user
serhng5:int	dos		;  all done 
	ret
SERHNG	ENDP

; Send a break out the current serial port.
SENDBR	PROC	NEAR
	mov	brkdur,28	    ; Normal break 280ms
	jmp	sendbr1
sendbl: mov	brkdur,180	    ; Long break 1800ms
	jmp	sendbr1
sendbr1:push	cx
	push	dx
	push	ax
	mov	dx,mdstat0	; Port address
	cmp	flags.comflg,2	; Which port?
	jg	sendbr3	     
	in	al,dx		; Get current setting
	or	al,brkval	; Set send-break bit(s)
	out	dx,al		; Start the break
	mov	bx,brkdur	; wait this long
	call	wait01		; hold break for desired interval
	xor	al,brkval	; Clear send-break bit(s)
	out	dx,al		; Stop the break
sendbr2:pop	ax
	pop	dx
	pop	cx
	ret
sendbr3:call	pickspd		; Point to speed
	mov	al,[bx+1]	; Command byte
	sub	al,8h		; Break byte 8h lower (1fh and 3fh)
	cmp	al,1fh
	je	sendbr4
	mov	al,3fh	    
sendbr4:out	dx,al
	mov	bx,brkdur	; wait this long
	call	wait01
	call	initmod
	jmp	sendbr2
SENDBR	ENDP

; Position the cursor according to contents of DX:
; DH contains row, DL contains column.
POSCUR	PROC	NEAR
	push	ax
	push	dx
	cmp	flags.comflg,2	; Ports 1/2
	jna	poscur1		; Yes, skip this
	push	bx		; No, check input port
	push	cx
	push	es
	mov	cx,1		; No delay
	call	sprtch		; Get char from port if any
	pop	es
	pop	cx
	pop	bx
poscur1:mov	ah,conout
	mov	dl,ESCAPE
	int	dos
	mov	dl,'Y'
	int	dos
	pop	dx
	push	dx
	mov	dl,dh
	add	dl,' '
	int	dos
	pop	dx
	add	dl,' '
	int	dos
	pop	ax
	ret
POSCUR	ENDP


; Delete a character from the terminal.	 This works by printing
; backspaces and spaces.
DODEL	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset delstr ; Erase weird character.
	int	dos
	ret
DODEL	ENDP

; select port to be current.  Returns with carry clear if success.
COMS	PROC	NEAR
;	mov	kstatus,0		; global status, success
	mov	dx,offset comptab	; table of legal comms ports
	mov	bx,offset comsmsg	; point to comsmsg
	mov	ah,cmkey		; parse key word
	call	comnd
	jnc	coms0			; nc = success
	ret				; failure
coms0:	call	serrst			; uninstall interrupt
	call	comstrt
	jnc	coms1
	mov	ah,prstr
	mov	dx,offset coms0msg	; Point to no S-100 modem msg
	int	dos
coms1:	clc
	ret

comstrt:mov	al,flags.comflg
	mov	tmp,al			; Save the old one in case
	mov	flags.comflg,bl		; Set the comm port flag.
	cmp	bl,1			; COM1 (port B)?
	je	coms2			; Yes
	cmp	bl,2			; COM2 (port A)?
	je	coms3			; Yes		
	cmp	bl,3			; COM3 (S-100 modem port 1)
	je	coms4			; Yes
	in	al,mdmcom4		; Check this port
	and	al,modperb		; Is it there?
	jnz	coms6			; No, skip
	mov	portval,offset port4	; Must be COM4
	mov	mddat0,mdmdat4
	mov	mdstat0,mdmcom4
	jmp	coms5	
coms4:	in	al,mdmcom3		; Check this port
	and	al,modperb		; Is it there?
	jnz	coms6			; No, skip
	mov	portval,offset port3
	mov	mddat0,mdmdat3
	mov	mdstat0,mdmcom3
	jmp	coms5		
coms2:	mov	mdstat0,mdmcom1		; Set break address for B
	mov	portadr,mdmdat1		; Set address for B
	mov	portval,offset port1	; Point to portinfo for B
	jmp	coms5
coms3:	mov	mdstat0,mdmcom2		; Set break address for A
	mov	portadr,mdmdat2		; Set address for A
	mov	portval,offset port2	; Point to portinfo for A
coms5:	call	baudref			; Set up bdtab and bddat
	call	getbaud			; See what is in the port now set
	clc				; Success
	ret	
coms6:	mov	al,tmp
	mov	flags.comflg,al		; Get the old one back
	stc				; Failure
	ret
COMS	ENDP

; Set heath emulation on/off.
; 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.
; Enter via direct jmp. Exit ret with carry set for failure, else carry
; cleared.
VTS	proc	near			; SET TERM whatever
	mov	dx,offset termtb	; terminal table, ascii
	xor	bx,bx			; help is the table itself
	mov	ah,cmkey		; get keyword
	call	comnd
	jnc	vset1			; nc = success
	ret				; failure
vset1:	mov	flags.vtflg,bx		; Set the Heath emulation flag
	and	bx,bx			; emulating?
	mov	dosflg,0ffh		; set the flag, disable scan codes
	mov	flags.xltkbd,0		; key translation disabled
	jz	vset2			; nz=yes
	mov	dosflg,0		; clear the flag, enable scan codes
	mov	flags.xltkbd,1		; key translation enabled
vset2:	mov	dx,offset vtsmsg
	mov	ah,prstr
	int	dos
	clc				; success
	ret
VTS	ENDP

VTSTAT	PROC	NEAR		; For Status display [jrd]
	ret			; no emulator status to display
VTSTAT	ENDP


; simple routine to insure that the port has RXON and DTR high
;  assumes int are off
porton	proc	near
	push	dx
	push	ax
	mov	dx,portadr
	add	dx,PCOMM
	in	al,dx
	or	al,RXON
	or	al,DTR
	or	al,RTS
	out	dx,al
	pop	ax
	pop	dx
	ret
porton	endp

; routine to retrieve current int vector
;  inputs:  al = int number
;  outputs: cx = seg for current isr
;	    dx = offset for current isr
getivec proc	near
	push	es		; save registers
	push	bx
	mov	ah,35H		; Int 21H, function 35H = Get Vector.
	int	dos		; get vector in es:bx
	mov	cx,es		; addr of org vector (seg)
	mov	dx,bx		;   and offset
	pop	bx
	pop	es
	ret
getivec endp

; routine to set int vector
;  inputs:  al = int number
;	    cx = seg for isr
;	    dx = offset for isr
setivec proc	near
	push	ds		; save ds around next DOS call.
	mov	ds,cx
	mov	ah,25H		; set interrupt address from ds:dx
	int	dos
	pop	ds
	ret
setivec endp


; 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.
SERINI	PROC	NEAR
	cmp	portin,0	; did we initialize port already?
	je	serin1		; e = yes
	jl	serin0		; l = no, not yet
	jmp	serin2
serin0: mov	bl,flags.comflg ; pass current port ident
	call	comstrt		; do SET PORT now
	jnc	serin1		; nc = success
	ret			; failed, exit now
serin1: cmp	flags.comflg,2	; COM1 or COM2?
	jle	serini1		; Go do COM1/COM2 stuff
serin2: cmp	flags.comflg,2	; COM1 or COM2?
	jg	serini2		; Go do COM3/COM4 stuff
	jmp	serini3		; Update flow and leave
initmod:			; The S-100 modem set up routine
serini2:call	pickspd		; Select baud and speed info
	xor	al,al		; Use this to reset modem
	mov	dx,mdstat0	; Status port
	out	dx,al		; Send to port
	jmp	$+2		; Wait a little
	out	dx,al
	jmp	$+2		; Wait a little
	out	dx,al
	jmp	$+2		; Wait a little
	mov	al,40h
	out	dx,al
	jmp	$+2		; Wait a little
	mov	al,[bx]
	out	dx,al
	jmp	$+2		; Wait a little
	mov	al,[bx+1]
	out	dx,al
	jmp	$+2
	in	al,dx		; Check port
	and	al,moddcdb	;  for carrier
	jnz	serini0		; Yes, don't do AT stuff
	mov	bx,10		; Wait 10/100 seconds
	call	wait01		; Call wait routine
	push	si
	mov	si,offset set_str;ATE1X1S0=0 sets up modem: echo commands, use
	cld			;  extended response codes, don't answer
	lodsb			; Get the first byte of string
serini5:push	ax		; We need the loaded byte later
serini6:xor	cx,cx		; Reset loop counter.  Loop to avoid hanging
	mov	dx,mdstat0	; The status port
serini7:in	al,dx		; Get status
	and	al,modsndb	; Mask for ready
	jnz	serini8		; Yes, go on
	inc	cx		; No 
	or	cx,cx		; Run out?
	jnz	serini7		; No, try again
	mov	ah,prstr	; Yes, tell user failure in initialization
	mov	dx,offset infmsg; Tell user init failed
	int	dos
	pop	ax		; Restore stack
	pop	si
	stc			; Failure
	ret
serini8:pop	ax		; Get byte back
	mov	dx,mddat0	; The data port
	out	dx,al		; Send it out
	lodsb			; Load next byte
	cmp	al,'$'		; Finished?
	jnz	serini5		; No, process next
	pop	si		; Left in good order
	mov	bx,25		; Wait 25/100 seconds
	call	wait01		; Call wait routine
	call	prtchr		; Purge modem
	jmp	serini3		; Success

serini1:mov	ax,portval
	cmp	ax,offset port2
	je	seri2		; setup for J1
	cmp	intin,2
	jne	seri0
serini0:clc			; Success
	ret			; J2 (com3, com4) already set up
seri0:	cmp	intin,1
	jne	seri1		; J1 currently installed
	call	serrst		; de-install current int
seri1:	mov	al,J2INT
	call	getivec
	mov	oldseg,cx
	mov	oldoff,dx
	mov	cx,cs
	mov	dx,offset serisr
	mov	al,J2INT
	call	setivec
	mov	portadr,J2_ADDR
	call	clrbuf
	call	porton
	mov	intin,2		; show J2 installed
	jmp	serini3		; Success
seri2:	cmp	intin,1
	jne	seri3
	clc			; Success
	ret			; J1 already set up
seri3:	cmp	intin,2
	jne	seri4		; J2 currently installed
	call	serrst		; de-install current int
seri4:	mov	al,J1INT
	call	getivec
	mov	oldseg,cx
	mov	oldoff,dx
	mov	cx,cs
	mov	dx,offset serisr
	mov	al,J1INT
	call	setivec
	mov	portadr,J1_ADDR
	call	clrbuf
	call	porton
	mov	intin,1		; show J1 installed

serini3:push	bx
	mov	bx,portval		; get port data structure
	mov	[bx].portrdy,1		; say the comms port is ready
	mov	parmsk,0ffh		; parity mask, assume parity is None
	cmp	[bx].parflg,parnon	; is it None?
	je	serini3a		; e = yes
	mov	parmsk,07fh		; no, pass lower 7 bits as data
serini3a:xor	ax,ax
	cmp	[bx].floflg,0		; flow control is off?
	je	serini3b		; e = yes
	mov	ax,[bx].flowc		; get flow control chars
serini3b:mov	flowoff,al		; xoff or null
	mov	flowon,ah		; xon or null
	mov	xofrcv,off		; clear xoff received flag
	pop	bx
	mov	portin,1		; say initialized
	clc				; carry clear for success
	ret				; We're done

pickspd:mov	bp,portval	; Get speed for S-100 modem 'from' portval
	cmp	ds:[bp].baud,0	; 150 baud?
	mov	bx,offset bd150
	jz	serini4
	cmp	ds:[bp].baud,1	; 300 baud?
	mov	bx,offset bd300
	jz	serini4
	cmp	ds:[bp].baud,2	; 600 baud?
	mov	bx,offset bd600
	jz	serini4
	mov	bx,offset bd1200; Default to 1200 baud
serini4:ret
SERINI	ENDP

; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
SERRST	PROC	NEAR
	cmp	portin,0	; Reset already? 
	jg	serr0		; g = no
	clc
	ret			; e = yes, l=not used yet, just leave
serr0:	push	dx
	cmp	intin,0		; is any isr installed
	je	serr2		; no, all done
	push	cx
	push	ax
	mov	ax,J2INT	; guess it's J2
	cmp	intin,2		; yes,
	je	serr1		;   reset it
	mov	ax,J1INT	; no, must be J1
serr1:	mov	cx,oldseg	; original isr
	mov	dx,oldoff	;   address
	call	setivec		; do it
	mov	intin,0		; show nothing installed
	call	porton		; Insure that DTR and RTS are high
	pop	ax
	pop	cx
serr2:	pop	dx
	mov	portin,0		; reset flag
	push	bx
	mov	bx,portval		; port data structure
	mov	[bx].portrdy,0		; say port is not ready
	pop	bx
	clc
	ret
SERRST	ENDP

; the serial port interrupt service routine
;  this routine does int driven input and output
;   once installed, it displaces the Z-100 serial isr
serisr: push	ax			; Save regs
	push	bx
	push	cx
	push	dx
	push	ds			; Save data seg
	mov	ax,seg data		; Set our
	mov	ds,ax			;  data seg
					;
	mov	dx,portadr		; Get the port address
	mov	cx,dx			;  and save a copy
	add	dx,PSTATUS
	in	al,dx	  	      	; Get port status
	mov	ah,al			; Save it
	test	ah,RDA	       		; Check for data available
	jz	isr5			; No, nothing to receive, go send
					;
	mov	dx,cx			; Port address
	in	al,dx			; Get the data
	cmp	flowoff,0		; Are wo doing flow control?
	jz	isr2   			; No, skip
					;
 	mov	ch,al			; Make working copy of data
	and	ch,parmsk		; Strip parity, if any
	cmp	ch,flowon 		; xon?
	jne	isr1			; No, check xoff
	mov	xofrcv,false		; Indicate xoff not received (xon)
   	     				; Done with receiver
	jmp	short isr5		;  there should be time for send
isr1:	cmp	ch,flowoff		; xoff?
	mov	ch,0			; We need this later in cx
	jnz	isr2			; No, put regular char in buffer
  	cmp	xofsnt,true 		; Did we send an outstanding xoff?
  	jz 	isr5 		       	; Yes, ignore (possible echo), go send
	mov	xofrcv,true		; Set flag to indicatae xoff received
   	     				; Done with receiver
	jmp	short isr5		;  there should still be time for send
isr2:	mov	bx,bufiend		; Get where to put it
	cmp	count,BUFILEN		; Buffer full?
	jne	isr3			; No, jump
	dec	bx			; Don't overwrite que
	mov	byte ptr buffin[bx],bell; Put Ctrl-G in the que as marker
	jmp	short isr5		; We missed it anyway
isr3:	mov	byte ptr buffin[bx],al 	; Stick it in the que
	inc	bx			; Bump que pointer
	inc	count			; One more in que
	cmp	bx,BUFILEN		; Pointing to end of que?
	jne	isr4 			; No, go on
	xor	bx,bx			; Reset pointer
isr4:	mov	bufiend,bx		; Store new pointer
;	jmp	short isr12	; Pick	; We won't take time to send now
	jmp	short isr5	;  one	; There should still be time for send
					;
isr5:	test	ah,TSRE+THBE		; Ready to send?
	jz	isr12		 	; No, almost done
	mov	bx,bufobeg		; Pointer to beginning of output buffer
	cmp	count,mntrgh		; Past the high trigger point?
	jnae	isr6			;  no, make it simple
	cmp	flowoff,0		; Are we doing flow control?
	jz	isr6			;  no, make it simple
	cmp	xofsnt,true 		; Did we send an xoff already?
	jz	isr6			;  yes, make it simple
	mov	al,flowoff		; xoff
	or	al,al			; Null?
	jz	isr6			; Don't send null
	call	dopar
	mov	dx,cx			; Port address
	out	dx,al			; Send the xoff out
	mov	xofsnt,true		; Remember
	cmp	bx,bufoend		; Buffer empty?
	jz	isr11		 	; Yes, turn transmitter off
	jmp	short isr12	       	; We have used transmitter already,
					;  so we need to go
isr6:	cmp	bx,bufoend		; Buffer empty?
	jz	isr11		 	; Yes, turn transmitter off
	mov	al,byte ptr buffout[bx] ; Get char to send
	cmp	flowoff,0		; Are we doing flow control?
	jz	isr7			; No, just go on
	mov	ah,al			; Working copy
	and	ah,parmsk		; Strip parity
	cmp	ah,flowoff		; xoff?
	jz	isr7			; Just send it
	cmp	ah,flowon 		; xon?
	jz	isr7			; Just send it
	cmp 	xofrcv,true		; Being held?
	jz 	isr12  			; Yes, don't send
isr7:	mov	dx,cx			; Port address
	out	dx,al			; Send it
	inc	bx			; Point to next char to send
	cmp	bx,BUFOLEN		; Pointing to end of que?
	jne	isr10
	xor	bx,bx		 	; Reset pointer
isr10:	mov	bufobeg,bx		; Save it
	jmp	short isr12		; Almost done
					;
isr11:	mov	dx,cx			; Port address
	add	dx,PCOMM
	in	al,dx			; Get current mode
	and	al,TXOFF		; Turn xmitter off
	out	dx,al			; Do it.
					;
isr12:	mov	al,EOI			; Tell interrupt controller
	out	Z8259,al		;   that interrupt serviced
					;
	pop	ds			; Restore regs
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	iret
  
;; Wait for the # of milliseconds in ax, for non-IBM compatibles.
pcwait	proc	near
	cmp	ax,0
	jz	pcwait2		; no wait
	push	bx
	push	cx
	push	dx
	xor	dx,dx
	mov	cx,10		; we can not make it finer than 10ms
	div	cx
	cmp	ax,0
	jnz	pcwait1
	inc	ax		; make it 10ms for 1 to 9
pcwait1:mov	bx,ax		; and 10ms for 10 to 19, 20ms for 20 to 29
	call	wait01		; 10ms => 10 to 20ms by wait01
	pop	dx		; 20ms => 20 to 30ms by wait01
	pop	cx
	pop	bx
pcwait2:ret
pcwait	endp

; Wait for the # of hundredths seconds in bx. Range 1 to 0ffffh.
; Accuracy within 10ms due to use of system clock.
; This uses dos calls and is compatible with all msdos systems.
; Preserves all registers.
wait01	proc	near
	push	ax
	push	cx
	push	dx
	push	di
	mov	ah,gettim	; Get time function
	int	dos
wait011:mov	di,dx		; Preset/reset di
wait012:int	dos
	cmp	dx,di		; Changed?
	je	wait012		; Yes, continue
	dec	bx		; 1/100 second passed
	jnz	wait011		; Did not time out, keep waiting
	pop	di		; Timed out
	pop	dx
	pop	cx
	pop	ax
	ret
wait01	endp

; Service SET NETBIOS-NAME name   command at Kermit prompt level
setnbios proc	near
	ret
setnbios endp
sesdisp	proc	near
	ret
sesdisp	endp
code	ends
	end
