        NAME    msx55x
; File MSX55X.ASM
; Kermit system dependent module for Sanyo MBC-55x
; Sanyo mods by Robert W. Babcock and Joseph H. White
; For version which replaces the BIOS keycode translation table,
;  use -dMODIFIED flag to MASM.
; Edit History
; Last edit 16 Oct. 1988, only call pcwtst on first serini call
; 1 Jan 1988 version 2.30
; 24 Dec 1987 Revise selection of COM1 to use COM1 name but COM2 addresses
;  if base address of 02f8 (COM2) is found in 40:00h and display notice.
;  Restore state of IRQ interrupt line when finished with serial port. [jrd]
; 31 Oct 1987 Add terminal type Tek4010, with Tek submode Tekflg. [jrd]
; 24 Oct 1987 Enhance clrbuf to empty any intermediate (net) buffers. [jrd]
; 19 Oct 1987 Fix stray tab-set at column 32. [jrd]
; 2 Oct 1987 Add PCjr baud rate table, from Ted Medin. [jrd]
; 6 Sept 1987 Allow serial port serint to send xoff when buffer fills even
;  though user may have sent xoff by hand. [jrd]
; 27 Aug 1987 Skip timeout test in OUTCHR if receive timeout is zero. [jrd]
; 23 August 1987 Add vtemu.vtflgop to hold runtime terminal settings so that
;  a reset command restores them to the Setup values, vtemu.vtflgst. Show
;  displays the vtemu.vtflgop operational values. [jrd]
; 17 August 1987 Make timing adjustments for Token Passing and single buffered
;  network adapter boards. Byte netdbfr indicates presence of double buffering;
;  it is set in chknet as a vendor option. To test your boards force dbl buf
;  then look for missing 256 byte parts of long packets sent out; missing parts
;  mean new material overwrote not-yet-sent old == single buffering. [jrd]
; 8 August 1987 Add interrupt chaining in serint. [jrd]
; 23 July 1987 Clear xofsnt and xofrcv xon/xoff flags in ihost(s/r). [jrd]
; 9 July 1987 Cure confusion about COM1/2 for IBM PCjr (address of regular
;  COM2 in 40:0h slot for COM1) with info from John Neufeld. [jrd]
; 2 July 1987 Route NetBios cancels through separate scb for systems, such
;  as Novell NetWare, which object to having active scbs touched. [jrd]
; 25 June 1987 Add trapping of Int 14H (Bios RS232 procedure) to allow
;  CTTY command to function without too much inteference from DOS. [jrd]
; 17 June 1987 Enlarge tab setting to full 132 columns at all times. [jrd]
; 11 June 1987 Add Set Term Roll on/off to control auto roll back of screen
;  when new characters are displayed; default is off (no unwinding). [jrd]
; 20 May 1987 Remove rejection of NULL and DEL chars, let callers do it. [jrd]
; 16 May 1987 Add distinction between user typed and receiver threshold
;  controlled sending of XOFF. User level overrides buffer control.[jrd]
;  Add COM3 and COM4 support: examine memory 40:00h->40:07h for selected
;  port COM1..4, resp. If word is null then set flags.comflg to 0 to say
;  undefined port. Otherwise, use that word in seg 40h as base of UART i/o
;  ports. Assume IRQ4 for COM1 and COM3 (same except for port addresses)
;  and IRQ4 for  COM2 and COM4 (again, same except for port addresses).
;  Serial port info sturcture (not values) assumed identical for all ports.
; 25 April 1987 Add Netbios compatible local area network support. [jrd]
;  Set Port command expanded to syntax SET PORT NET nodename. Use nodename
;  if acting as a client to named remote node, leave blank if running in
;  Server mode. Byte 'ttyact' is controlled by msster.asm to indicate Connect
;  mode is being used. Byte 'netdone' (stored in mssker.asm) holds offset of
;  network hangup procedure 'netclose' to be done when leaving Kermit. Hangup
;  command extended to to network hangup as well. Network uses IBM Netbios
;  standard calls (Int 5Ch) and allows for extensions of AT&T STARLAN for
;  longer node names via Int 2Bh (the later is tested before use). Virtual
;  circuits are employed. The Redirector is not necessary. Kermit can operate
;  as either a terminal (does a CALL at Connect mode startup), a file receiver
;  (does a CALL at startup), or a Kermit server (does an anonomous LISTEN at
;  startup, hence no nodename). Clients should Set Timer Off.
; 16 April 1987 Add measurement and correction of software timer pcwait. [jrd]
; 5 April 1987 Keep DTR & RTS low for 1/2 second in serhng, suggested by
;  Jack Bryans. [jrd]
; 28 March 1987 Reference screen coord wrt low_rgt from msyibm, let number
;  of tabs be full screen width. [jrd]
; 22 March 1987 Fix bug in pcwait code, from Stefan Vogel. [jrd]
; 6 March 1987 Make PCWAIT a global procedure, add SENDBL to send Long
;  Break. [jrd]
; 21 Feb 1987 Merge operations for semi-clone machines (those identical to
;  IBM PC's except the serial port must be accessed via the Bios rather than
;  from the real UART hardware). Ports automatically checked for 8250. [jrd]
; 1 Oct 1986 Version 2.29a
; 30 Sept 1986 Reject DEL char at serial port reception level to avoid
;  problems when DEL is used as a filler char (by Emacs). [jrd]
; 4 Sept 1986 Add Bob Goeke's change to move comms port table to a system
;  dependent module (typ msx---) to allow 3+ ports and localized idents. [jrd]
; 26 August 1986 Use parity mask when testing for nulls & Xon/Xoff in serial
;  port interrupt routine. [jrd]
; 16 August 1986 Use observed screen attributes for mode line. [jrd]
; 9 August 1986 Revise SERINT to insert control-G for overrun chars, give
;  faster return of interrupts to system, remove use of BP in code. [jrd]
; 17 July 1986 Minor clean up of Terminal Status display routine. [jrd]
; 22 June 1986 Leave 8250 UART signal OUT1 low to avoid resetting Hayes
;  1200B modems (thanks to Neil Rickert). [jrd]
;  Skip sending null byte in ihosts and ihostr (thanks to Skip Russell). [jrd]
; 22 May 1986 Rewrite serial port interrupt procedure and proc prtchr
;  to avoid lockups with interrupts disabled, buffer corruption, and to
;  minimize lost clock interrupts. Flow control not needed at 9600 baud,
;  slow screen refresh, VT102 emulation, on a 4.77 MHz IBM PC clone.
;  Added buffer low water mark to give more xon/xoff hysterisis. [jrd]
; [2.29] code frozen on 6 May 1986 [jrd]
; Note -
; When the Bios is used for serial port i/o the modem signals DSR and CTS
; must be asserted low before the Bios will access the hardware. Jumpers
; from pin 20 (DTR) to pin 6 (DSR) and from pin 4 (RTS) to pin 5 (CTS)
; will probably be necessary.
;       From Glenn Everhart (who suggested using the Bios alternative)
;
        public  serini, serrst, clrbuf, outchr, coms, vts, vtstat
        public  dodel, ctlu, cmblnk, locate, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep, termtb, shomodem
        public  count, xofsnt, puthlp, putmod, clrmod, poscur
        public  sendbr, sendbl, machnam, setktab, setkhlp, lclini, showkey
        public  ihosts, ihostr, dtrlow, serhng, comptab, pcwait
        public  perrcnt         ; for debugging -- [jhw]
        include mssdef.h

off     equ     0
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

MCONF   EQU     11H             ; Bios Machine configuration s/ware interrupt.
KEYB    EQU     16H             ; Bios keyboard software interrupt
VIDEO   EQU     10H             ; Bios Video display software interrupt
RS232   EQU     14H             ; Bios RS232 serial port s/ware interrupt

; constants used by serial port handler
MDMINP  equ     1       ; BIOS data ready mask flag

; 8251A serial communications device
BUF8251 EQU     028h            ; I/O address of 8251 in/out buffer
CMD8251 EQU     02Ah            ; I/O address of 8251A command buffer
STS8251 EQU     02Ah            ; I/O address of 8251A status buffer
VEC8251 EQU     0FAh            ; 8251A interrupt vector number
INT8251 EQU     0FBh            ; 8259A interrupt enable mask (int 2)
; 8251A Command instruction formats
TxEN    EQU     1               ; transmit enable
DTR     EQU     2               ; data terminal ready
RxEN    EQU     4               ; receiver enable
SBRK    EQU     8               ; send break
ERRESET EQU     10h             ; error reset
RTS     EQU     20h             ; request to send
INTRLRS EQU     40h             ; internal reset
; 8251A Status read formats
TxRDY   EQU     1               ; transmitter ready
RxRDY   EQU     2               ; receiver ready
TxEMPTY EQU     4               ; transmit buffer empty
PARERR  EQU     8               ; parity error
OVRRUN  EQU     10h             ; overrun error
FRAMERR EQU     20h             ; framing error
BRKDET  EQU     40h             ; break detect
DSR     EQU     80h             ; data set ready
; 8253 timer device
TIMER0DATA EQU  20h             ; I/O address of counter #0
TIMER1DATA EQU  22h             ; I/O address of counter #1
TIMER2DATA EQU  24h             ; I/O address of counter #2
CMD8253 EQU     26h             ; I/O address of counter control
; 8259A interrupt controller
CMA8259 EQU     0               ; I/O address of command buff 1
CMB8259 EQU     2               ; I/O address of command buff 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 (only port1) [rwb]
; port1 - portinfo structures for the port [rwb]
; low_rgt - low byte = last column (typ 79), high byte = last text row
;  (typ 23) in screen coordinates (start at 0), set by msyibm.

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

datas   segment public 'datas'
        extrn   drives:byte, flags:byte, trans:byte, ttyact:byte
        extrn   portval:word, port1:byte, port2:byte, port3:byte, port4:byte
        extrn   netdone:word, pcnet:byte
        extrn   refresh:byte, scbattr:byte, low_rgt:word, vtemu:byte
        extrn   vtroll:byte, tekflg:byte
        extrn   crt_mode:byte                           ; [jhw]

; 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      0               ; superceded by msuibm code, return 0 here
setkhlp db      '$'             ; and add empty help string

savsci  dd      ?               ; old serial port interrupt vector.
sav232  dd      ?               ; Original Bios Int 14H address, in Code seg.
savirq  db      ?               ; Original Interrupt mask for IRQ
hngmsg  db      cr,lf,' The phone should have hungup.'
        db      cr,lf,'$'
nohngmsg db     cr,lf,' Command ineffective on this port.',cr,lf,'$'
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.',cr,lf
        db      '$'
erms40  db      cr,lf,'?Warning: Unrecognized baud rate',cr,lf,'$'
badbd   db      cr,lf,'Unimplemented baud rate$'
prterr  db      '?Unrecognized value$'
msmsg1  db      cr,lf,' Modem is not ready: DSR is off$'
msmsg2  db      cr,lf,' Modem is ready:     DSR is on$'

machnam db      'Sanyo 55x'
ifdef MODIFIED
        db      ' (Modifies BIOS keycodes)'
endif
        db      '$'
crlf    db      cr,lf,'$'
delstr  db      BS,BS,'  ',BS,BS,'$'    ; Delete string
clrlin  db      cr,'$'                  ; Clear line (just the cr part).
onmsg   db      'on$'
offmsg  db      'off$'
portin  db      0               ; Has comm port been initialized
xofsnt  db      0               ; Say if we sent an XOFF.
xofrcv  db      0               ; Say if we received an XOFF.
parmsk  db      ?               ; parity mask, 0ffh for no parity, 07fh with.
flowoff db      ?               ; flow-off char, Xoff or null (if no flow)
flowon  db      ?               ; flow-on char, Xon or null
overrun db      ?               ; holds status of receiver overrun
pcwcnt  dw      240             ; number of loops for 1 millisec in pcwait
temp    dw      0
tempsci dw      0               ; temp storage for serint
tempdum dw      0               ; temp storage for serdum
rdbuf   db      80 dup (?)      ; temporary storage
                                        ; begin Terminal emulator data set
termtb  db      tttypes                 ; entries for Status, not Set
        mkeyw   'Heath-19',ttheath
        mkeyw   'none',ttgenrc
        mkeyw   'Tek4010',tttek
        mkeyw   'VT102',ttvt100
        mkeyw   'VT52',ttvt52

vttbl   db      15                      ; number of 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   'Rollback',400h         ; note 400H flag for decoding
        mkeyw   'Screen-background',scrval
        mkeyw   'Tabstops',tabval
        mkeyw   'Tek4010',tttek+100H
        mkeyw   'VT102',ttvt100+100H
        mkeyw   'VT52',ttvt52+100H
        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, VT102, or Tek4010',cr,lf
        db '  Newline-mode    Cursor-style        Character-set (US UK)',cr,lf
        db '  Keyclick        Margin-bell         Screen-background'
        db      ' (normal, reverse)',cr,lf
        db '  Tabstops        Wrap (long lines)   Color (fore & background)'
        db cr,lf,'  Roll (undo screen roll back before writing new chars,'
        db      ' default=off)$'

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,'   2 for monochrome mode'
        db      cr,lf,'   3 for color mode'
        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: $'
vtbell  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  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      2                       ; Two entries.
        mkeyw   'off',0                 ; Should be alphabetized
        mkeyw   'on',1

comptab db      2
        mkeyw   '1',1
        mkeyw   'COM1',1
        mkeyw   '   ',0                 ; port is not present, for Status

; this table is indexed by the baud rate definitions given in
; pcdefs.  Unsupported baud rates should contain FF.
; Baud rates above 4800 may be sufficiently inaccurate to cause problems. [rwb]
; The 8251 must be run in 16x mode for reliable reception, which leads [rwb]
; to small divisors and large errors.  The baud rate divisor is [rwb]
; calculated by 1,789,773 / (16 * baud rate). [rwb]
; Odd baud rates have not been tested [rwb]
bddat   label   word
        dw      2458            ; 45.5 baud
        dw      2337            ; 50 baud
        dw      1491            ; 75 baud
        dw      1017            ; 110 baud
        dw      832             ; 134.5 baud
        dw      746             ; 150 baud
        dw      373             ; 300 baud
        dw      186             ; 600 baud
                                ; actual baud rates in parentheses
        dw      93              ; 1200 baud (1202.8)
        dw      62              ; 1800 baud (1804.2)
        dw      56              ; 2000 baud (1997.5)
        dw      47              ; 2400 baud (2380.0)
        dw      23              ; 4800 baud (4863.5)
        dw      12              ; 9600 baud (9321.7)
        dw      6               ; 19200 baud (18643.5)
        dw      0FFh            ; 38400 baud -- not supported, exceeds
                                ;               chip spec of 19.2K max
        dw      0FFh            ; 56800 baud -- not supported
        dw      0FFh            ; 113600 baud -- not supported
baudlen equ     ($-bddat)/2     ; number of entries above

; variables for serial interrupt handler

source  db      bufsiz+2 DUP(?) ; Buffer for data from port (+ 2 guard bytes).
srcpnt  dw      source          ; Pointer in buffer (DI).
count   dw      0               ; Number of chars in int buffer.
perrcnt dw      0               ; count - missed interrupts dur. protocol xfer

datas   ends

code    segment public 'code'
        extrn   comnd:near, dopar:near, defkey: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
        extrn   prompt:near
        extrn   vtsound:near    ; [rwb]
ifdef MODIFIED
        extrn   rbtabl:near     ; [jhw]
endif
        assume  cs:code,ds:datas

; local initialization

lclini  proc    near
        mov     flags.comflg,1  ; assume COM1 for communications port
        mov     ax,8            ; set default 1200 baud [rwb]
        mov     bp,portval      ; [rwb]
        mov     ds:[bp].baud,ax ; [rwb]
        call    dobaud          ; programm default baud rate [rwb]
        call    model           ; get model of IBM machine
        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.
; following lines commented out because Sanyo [rwb]
; VB BIOS reports no disk drives present [rwb]
;;      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).
dodsk0: mov     drives,al               ; Remember how many.
        ret
DODISK  ENDP

model   proc    near            ; no model info, just return [rwb]
        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.
; Returns normally. Obsolete, name here for external reference only.
showkey proc    near
        ret                             ; return
showkey endp

; SHOW MODEM, displays current status of DSR (CD and CTS are not known)
shomodem proc   near
        mov     ah,cmcfm                ; get a confirm
        call    comnd
         jmp    r                       ; no confirm
         nop
        call    serini                  ; activate port to get status
        call    serrst                  ; turn off port again
        mov     ah,prstr
        in      al,STS8251      ; get status
        test    al,DSR          ; is DSR asserted?
        jz      shomd1                  ; z = no
        mov     dx,offset msmsg2        ; say not asserted
shomd1: int     dos
        jmp     rskp
shomodem 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     srcpnt,offset source    ; receive circular buffer
        mov     count,0                 ; receive circular buffer
        sti
        call    prtchr                  ; empty any intermediate (net) buffers
         nop                            ; got a char, clear again
         nop
         nop
        cli
        mov     srcpnt,offset source    ; receive circular buffer
        mov     count,0                 ; receive circular buffer
        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     video                   ; Get current cursor position into dx
        mov     ax,dx                   ; Topview compatible clear line
        mov     bh,ah                   ; same row
        mov     bl,byte ptr low_rgt     ; last column
        call    atsclr                  ; clear from ax to bx, screen coord
        pop     dx
        pop     bx
        pop     ax
        ret
CLEARL  ENDP

; 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,low_rgt      ; to end of text screen (lower right corner)
        inc     bh                      ; include status line
        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

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


BEEP    PROC    NEAR
        push    bx              ; [rwb]
        push    di              ; [rwb]
        mov     bx,3            ; [rwb]
        mov     di,8            ; [rwb]
        call    vtsound         ; in msz55x [rwb]
        pop     di              ; [rwb]
        pop     bx              ; [rwb]
        ret
BEEP    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
        push    bx
        push    cx
        push    dx              ; preserve message
        mov     bl,scbattr      ; screen attributes at Kermit init time
        and     bl,77h          ; get colors, omit bright and blink
        rol     bl,1            ; interchange fore and background
        rol     bl,1
        rol     bl,1
        rol     bl,1
        mov     bh,0            ; preset page 0
        mov     temp,bx         ; temp = page 0, reverse video
        mov     dx,low_rgt      ; ending location is lower right corner
        inc     dh              ;  of status line
        mov     cx,dx           ; start is status left side
        xor     cl,cl           ; left side
        mov     ax,600h         ; scroll to clear the line
        mov     bh,byte ptr temp ; set inverse video attributes
        int     video
        mov     dx,low_rgt      ; last text line
        inc     dh              ; status line
        xor     dl,dl           ; left side
        call    poscur
        pop     si              ; get message back
        mov     cx,1            ; only one char at a time
        xor     bh,bh           ; page 0
        cld
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,temp         ; page 0, inverse video
        int     video
        pop     si              ; recover pointer
        jmp     putmo1
putmo2: pop     cx
        pop     bx
        pop     ax
        ret
putmod  endp

; clear the mode line written by putmod.  Returns normally.
clrmod  proc    near
        push    ax              ; save regs
        push    bx
        push    cx
        push    dx
        mov     ax,600h         ; do a scroll up
        mov     dx,low_rgt      ; ending location is lower right corner
        inc     dh              ;  of status line
        mov     cx,dx           ; start is status left side
        xor     cl,cl           ; left side
        mov     bh,scbattr      ; use screen attributes at Kermit init time
        int     video
        pop     dx
        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
        push    cx
        push    dx
        push    si
        push    ax              ; preserve this
        cld
        mov     bl,scbattr      ; screen attributes at Kermit init time
        and     bl,77h          ; get colors, omit bright and blink
        rol     bl,1            ; interchange fore and background
        rol     bl,1
        rol     bl,1
        rol     bl,1
        mov     bh,0            ; preset page 0
        mov     temp,bx         ; temp = page 0, reverse video

        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
        mov     bh,bl           ; inverse video
        int     video
        call    locate          ; home cursor
        mov     bx,0070h        ; bh = page 0, bl = inverse video
        mov     bx,temp
        mov     cx,1            ; one char at a time
        cld                     ; scan direction is forward
        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
        cmp     al,' '          ; printable?
        jb      puth21          ; b = no
        mov     ah,9            ; write char at current cursor position
        int     video           ; 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     video
        pop     si              ; restore pointer
        jmp     puthl3          ; and keep going
puthl4: mov     dh,byte ptr low_rgt+1   ; go to last line
        inc     dh
        xor     dl,dl
        call    poscur          ; position cursor
        pop     si
        pop     dx
        pop     cx
        pop     bx
        ret
puthlp  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     bh,1H                   ; marker for terminal type?
        je      vsetu0a                 ; e = yes
        cmp     bh,4h                   ; marker for roll back control?
        je      vsetu3                  ; e = yes
        cmp     bh,2h                   ; marker for set term color?
        je      vsetu2                  ; e = yes
        jmp     short vsetu1            ; else dispatch on bl
vsetu0a: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
        mov     tekflg,0                ; clear Tek sub mode
        ret
vsetu0: pop bx
        ret

vsetu3: mov     ah,cmkey                ; Set Term Roll On/Off, auto roll back
        mov     bx,0                    ; Use on/off table as help
        mov     dx,offset ontab         ; Use on/off table
        call    comnd
         jmp    r                       ; bad keyword
        push    bx
        mov     ah,cmcfm                ; get a confirm
        call    comnd
         jmp    vsetu0                  ; did not get a confirm
         nop
        pop     bx
        mov     vtroll,bl               ; set roll state (0=no auto rollback)
        jmp     rskp                    ; return successfully

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
        jne     vse2cd                  ; cond. jmps modified to correct
                                        ;   'out-of-range' errors      [jhw]
        jmp     vsetu2j                 ; e = yes
vse2cd: cmp     ax,1                    ; high intensity?
        jne     vse2cc
        jmp     vsetu2k                 ; e = yes
vse2cc: cmp     ax,2                    ; set to mono mode (Sanyo)      [jhw]
        jne     vse2ca                  ;                               [jhw]
        jmp     vsetu2m                 ; e = yes                       [jhw]
vse2ca: cmp     ax,3                    ; set to color mode (Sanyo)     [jhw]
        jne     vse2cb                  ;                               [jhw]
        jmp     vsetu2m                 ; e = yes                       [jhw]
vse2cb: cmp     ax,10                   ; fast refresh?
        cmp     ax,1                    ; high intensity?
        je      vsetu2k                 ; e = yes
        cmp     ax,10                   ; fast refresh?
        je      vsetu2l                 ; e = yes
        cmp     ax,30                   ; check range
        jb      clbad                   ; b = too small. complain       [jhw]
        cmp     ax,37
        jna     vsetu2b                 ; 30-37 is foreground color
        cmp     ax,40
        jb      clbad                   ;                               [jhw]
        cmp     ax,47                   ; Compare as unsigned.
        jna     vsetu2b                 ; 40-47 is background
clbad:  jmp     colbad                  ; else error                    [jhw]
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
vsetu2m:                                ; Set screen mode (color/mono)  [jhw]
        mov     crt_mode,al             ; remember the mode             [jhw]
        int     video                   ; AX contained 2 or 3 already   [jhw]
        jmp     vsetu2c                 ;                               [jhw]
;

colbad: cmp     byte ptr [si],0         ; at end of text?
        je      colbad1                 ; e = yes, not an error
        mov     ah,prstr                ; Not in range - complain and exit.
        mov     dx,offset colerr
        int     dos
colbad1: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.
        or      vtemu.vtflgop,al        ; in runtime flags too
        jmp     rskp                    ; Give good return.

flgse1: not     al                      ; Complement
        and     vtemu.vtflgst,al        ; Clear the indicated setup flag.
        and     vtemu.vtflgop,al        ; Clear the indicated runtime 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,132                  ; 132 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,132                  ; use 132 columns
        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
         jmp    tabcpy                  ;  no number available
        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     bl,132-1                ; more than the right most column?
        jna     tabse3                  ; na = no, is ok
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     short tabse5            ; look for more

tabcpy: mov     cx,132                  ; update all active 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     short 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,38                   ; 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     short vtsta4
vtsta2: mov     ax,cx
        mov     cx,38                   ; where we want to be next time
        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,38                   ; current column number
vtsta4: add     bx,size stent           ; look at next entry
        jmp     vtsta1                  ; and do it
vtstax: pop     di
        pop     bx
        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     cl,byte ptr low_rgt     ; loop screen width-1 times
        xor     ch,ch                   ; clear high byte
        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'
        cmp     dl,'9'                  ; larger than 90?
        jbe     tabsta2                 ; be = no
        sub     dl,10                   ; roll over to 0, 1, etc
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,38                   ; say line is used
        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.vtflgop ; 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

; Compute number of iterations needed in procedure pcwait inner loop
; to do one millisecond delay increments. Uses Intel 8253 timer chip
; (timer #2) to measure elapsed time assuming 1.78977 MHz clock.
; Called by serini below. For Sanyo 55x this is the baud rate generator,
; so call dobaud to reset the baud rate.
; Regs preserved. 16 April 87 [jrd]
pcwtst  proc    near
        push    ax
        push    cx
        push    dx
; 10 = timer 2, 11 = load low byte then high byte, 010 = mode 2, 0 = binary
        mov     al,10110100B    ; command byte
        out     CMD8253,al      ; timer command port
        xor     al,al   ; clear initial count for count-down
        out     TIMER2DATA,al   ; low order byte of count preset
        out     TIMER2DATA,al   ; high order byte, to the same place
        mov     ax,8    ; wait 8 millisec
        call    pcwait  ; call the software timer
; 10 = timer 2, 00 = latching command, 0000 = don't cares
        mov     al,10000000B    ; command byte
        out     CMD8253,al
        in      al,timer2data   ; read count down value
        xchg    al,ah           ; save low order byte
        in      al,timer2data   ; get high order byte
        xchg    ah,al           ; put in correct sequence
        neg     ax              ; subtract from zero to get elapsed tics
        add     ax,1789-2       ; round up
        xor     dx,dx           ; clear high order divisor
        mov     cx,1789 ; tics per millisec
        div     cx              ; count / 1193 yields millisecs, quo=ax
        push    ax              ; retain whole number of milliseconds
        mov     ax,pcwcnt       ; get current pcwait inner loop count
        mov     cl,3
        shl     ax,cl           ; current counter times 8 loops
        pop     cx              ; recover millisec for the 8 loop test
        xor     dx,dx           ; clear high order field for division
        div     cx              ; divide by observed milliseconds
        mov     pcwcnt,ax       ; store quotient as new inner loop counter
        call    dobaud  ; fix the baud rate we messed up
        pop     dx
        pop     cx
        pop     ax
        ret
pcwtst  endp

;; Wait for the # of milliseconds in ax, for non-IBM compatibles.
;; Thanks to Bernie Eiben for this one. Modified to use adjustable
; inner loop counter (pcwcnt, adjusted by proc pcwtst) by [jrd].
pcwait  proc    near
        mov     cx,pcwcnt       ; inner loop counter for 1 ms (240 @ 4.77 MHz)
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

; set the current port (only port 1 available on Sanyo)

COMS    PROC    NEAR
        mov     portval,offset port1
        clc                             ; return success
        ret
COMS    ENDP

; Test presently selected serial port for having a real 8250 UART.
; Return carry clear and clone = 0 if 8250 present,
;  else carry set and clone = 'B' for system Bios or
;  carry set and clone = 'N' for network.
; Method is to check UART's Interrupt Identification Register for high
; five bits being zero; IBM does it this way. Assumes port structure
; has been initialized with addresses of UART.  21 Feb 1987 [jrd]
; 29 May 1987 Add double check by reading Line Status Register. [jrd]

chkport proc    near
        clc                             ; clear carry (say 8250)
        ret
chkport 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
        push    bx
        push    dx
        mov     bx,portval              ; pointer to port data structure
        mov     temp,ax                 ; Don't overwrite previous rate
        mov     ax,[bx].baud            ; Check if new rate is valid
        shl     ax,1                    ; make a word index
        mov     bx,offset bddat         ; Start of table.
dobd0a: add     bx,ax
        mov     ax,[bx]                 ; The data to output to port.
        cmp     ax,0FFH                 ; Unimplemented baud rate.
        jne dobd2
        mov     ah,prstr
        mov     dx,offset badbd         ; Give an error message.
        int     dos
        jmp     dobd1

dobd2:  mov temp,ax             ; Remember value to output. [25]
        out TIMER2DATA,al       ; [rwb]
        mov al,ah               ; [rwb]
        out TIMER2DATA,al       ; [rwb]
dobd1:  pop     dx                      ; restore regs
        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.  Returns normally.
; This is used during initialization.
; This function is not possible with the Sanyo hardware, so just return. [rwb]

GETBAUD PROC    NEAR
        ret
GETBAUD ENDP

; Get Char from serial port buffer.
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
; Revised 22 May 1986, and again slightly 2 August 1986 by [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 25 April 1987 Add Netbios support, remove test for NUL and DEL. [jrd]
PRTCHR  PROC    NEAR
        call    chkxon                  ; see if we need to xon
ifdef DEBUG
        jmp     prtc00                  ; dummy jump to be changed by debug
prtc00:
endif
        in      al,cmd8251              ; get port status
        test    al,rxrdy                ; is character in 8251?
        jz      prtc01                  ; no, go on
        cli                             ; yes, hold interrupts and
        int     0fah                    ; call the interrupt service routine
        sti                             ; re-enable interrupts
        inc     perrcnt                 ; count the errors
prtc01:

        cmp     count,0                 ; any characters available?
        jnz     prtch1                  ; nz = yes, get one
prtch0: mov     dx,0                    ; return count of zero
        jmp     rskp                    ; No data - check console.
prtch1: push    si                      ; save si
        cli             ; interrupts off, to keep srcpnt & count consistent
        mov     si,srcpnt           ; address of next available slot in buffer
        sub     si,count            ; minus number of unread chars in buffer
        cmp     si,offset source        ; located before start of buf?
        jae     prtch2                  ; ae = no
        add     si,bufsiz               ; else do arithmetic modulo bufsiz
prtch2: mov     al,byte ptr [si]        ; get a character into al
        dec     count                   ; one less unread char now
        sti                             ; interrupts back on now.
        pop     si
        mov     dx,count                ; return # of chars in buffer
        ret
PRTCHR  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.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 25 April 1987 Add Netbios support [jrd]
; 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]
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     outch1b
outch1: cmp     ah,flowon               ; user sending xon?
        jne     outch1b                 ; ne = no
        mov     xofsnt,off           ; say an xon has been sent (cancels xoff)
outch1b:cmp     xofrcv,off              ; Are we being held (xoff received)?
        je      outch2                  ; e = no - it's OK to go on.
        cmp     flags.timflg,0          ; is timer off?
        je      outch2                  ; e = yes, no timeout period
        push    cx                      ; save reg
        mov     cl,trans.rtime          ; receive timeout interval
        mov     ch,0
        jcxz    outch1c                 ; z = no timeout wanted.
outch1a:cmp     xofrcv,off              ; Are we being held (xoff received)?
        je      outch1c                 ; e = no - it's OK to go on.
        mov     al,1                    ; else sleep for a second
        call    sleep
        loop    outch1a                 ; and try it again
        mov     xofrcv,off              ; timed out, force it off and fall thru
outch1c:pop     cx                      ; end of flow control section
                     ; OUTCH2 is entry point for sending without flow control
OUTCH2: mov     al,ah                   ; Parity routine works on AL.
        call    dopar                   ; Set parity appropriately.
        mov     ah,al                   ; Don't overwrite character with status
outch3a:push    cx                      ; Save registers
        push    dx
        sub     cx,cx
outch3b: in al,STS8251          ; get status [rwb]
        test al,TxEMPTY         ; Transmitter ready? [rwb]
        jnz     outch4                  ; Yes
        jmp     $+2                     ; use time, prevent overdriving UART
        jmp     $+2
        loop    outch3b
         jmp    outch5                  ; Timeout
outch4: cli                     ; can't tolerate receiver ints here
        mov al,(TxEN+DTR+RxEN+ERRESET+RTS) ; enable transmit [rwb]
        out CMD8251,al          ; [rwb]
        jmp $+2                 ; waste some time [rwb]
        mov al,ah               ; Now send it out [rwb]
        out BUF8251,al          ; [rwb]
        jmp $+2                 ; waste some time [rwb]
        mov al,(DTR+RxEN+ERRESET+RTS) ; back to receive-only mode [rwb]
        out CMD8251,al          ; [rwb]
        sti
        pop     dx                      ; exit success
        pop     cx
        jmp     rskp
outch5: pop     dx                      ; exit failure
        pop     cx
        ret
OUTCHR  ENDP


hexout  proc    near                    ; display byte in al as hex value
        push    ax                      ; all regs preserved
        push    cx
        push    dx
        mov     cx,2                    ; two nibbles
hexout1:push    cx                      ; save counter
        mov     cl,4                    ; high nibble
        ror     al,cl                   ; put in low order field
        mov     dl,al
        xchg    ch,al                   ; save al byte in ch
        and     dl,0fh                  ; four bits
        cmp     dl,9                    ; too big?
        jbe     hexout2                 ; be = no
        add     dl,'A'-'9'-1            ; bump up to A-F
hexout2:add     dl,'0'
        mov     ah,conout
        int     dos
        xchg    ch,al                   ; recover data byte
        pop     cx
        loop    hexout1                 ; do second nibble
        mov     dl,'H'                  ; add a final hex ident
        int     dos
        pop     ax
        pop     cx
        pop     dx
        ret
hexout  endp

; local routine to see if we have to transmit an xon
chkxon  proc    near
        cmp     flowon,0                ; 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 (low water mark) trigger?
        jae     chkxo1                  ; no, forget it
        mov     ah,flowon               ; ah gets xon
        and     xofsnt,off              ; remember we've sent the xon.
        call    outch2              ; send via non-flow controlled entry point
         nop
         nop
         nop                            ; in case it skips
chkxo1: ret
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]
; 22 June 1986 Don't send null char if not using flow control. [jrd]

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,flowon       ; put Go-ahead flow control char in ah
        or      ah,ah           ; check for null char
        jz      ihosts1         ; z = null, don't send it.
        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     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]
; 22 June 1986 Don't send null char if not using flow control. [jrd]
IHOSTR  PROC    NEAR
        push    ax              ; save regs
        push    cx
        mov     xofrcv,off      ; clear old xoff received flag
        mov     xofsnt,off      ; and old xoff sent flag
        mov     ah,flowon       ; 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)
         nop                    ; outchr can do skip return
         nop
         nop
ihostr1:pop     cx
        pop     ax
        ret
IHOSTR  ENDP

; Send a break out the current serial port.  Returns normally.
; Do both regular and long Break. 6 March 1987 [jrd]

SENDBR  PROC    NEAR
        push    cx              ; Regular Break entry point
        mov     cx,275          ; 275 milliseconds in regular Break
        call    sendbw          ; call worker routine to do it
        pop     cx
        clc                     ; don't exit Connect mode
        ret
SENDBL: push    cx              ; Long Break entry point
        mov     cx,1800         ; 1.8 second long break
        call    sendbw          ; call worker routine to do it
        pop     cx
        clc                     ; don't exit Connect mode
        ret
                                ; worker - send Break for cx millisec
sendbw:
        push ax
        mov al,(TxEN+DTR+RxEN+RTS)      ; [rwb]
        out CMD8251,al                  ; [rwb]
        mov al,(TxEN+DTR+RxEN+SBRK+RTS) ; [rwb]
        out CMD8251,al                  ; [rwb]
        mov ax,cx                       ; # of ms to wait
        call pcwait                     ; hold break for desired interval
        mov al,(TxEN+DTR+RxEN+RTS)      ; [rwb]
        out CMD8251,al                  ; [rwb]
        mov al,(DTR+RxEN+ERRESET+RTS)   ; [rwb]
        out CMD8251,al                  ; [rwb]
        pop ax
        ret
SENDBR  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.
;
; 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.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 24 April 1987 Add PCnet support calls [jrd]
; 17 May 1987 Redo for COM3/4 support. [jrd]
SERINI  PROC    NEAR
        cmp     portin,0                ; Did we initialize port already?
        je      serin0                  ; e = no, not yet
        ret                             ; Yes, so just leave
serin0:
        call pcwtst             ; calibrate timer (only on first call)
serin2a:push    bx
        push    es
        mov al,VEC8251          ; serial interrupt vector
        mov     ah,35H                  ; Int 21H, function 35H = Get Vector.
        int     dos                     ; get vector in es:bx
        mov     word ptr savsci,bx    ; save offset address of original vector
        mov     word ptr savsci+2,es    ;  and its segment.
        mov al,VEC8251          ; serial interrupt vector
        mov     dx,offset serint        ; offset of our interrupt routine
        push    ds                      ; save ds around next DOS call.
        mov     bx,seg serint           ; compose full address of our routine.
        mov     ds,bx                   ; segment is the code segment.
        mov     ah,25H                  ; set interrupt address from ds:dx
        int     dos
        pop     ds
        mov     al,rs232                ; interrupt number for Bios serial port
        mov     ah,35H                  ; get vector into es:bx
        int     dos
        mov     word ptr sav232,bx      ; save offset
        mov     word ptr sav232+2,es    ; save segment
        mov     dx,offset serdum        ; offset of our interrupt routine
        push    ds                      ; save ds around next DOS call.
        mov     bx,seg serdum           ; compose full address of our routine.
        mov     ds,bx                   ; segment is the code segment.
        mov     ah,25H                  ; set interrupt address from ds:dx
        int     dos
        pop     ds
        pop     es
        pop     bx
        mov     portin,1                ; Remember port has been initialized.
        cli                             ; Disable interrupts
        cld                             ; Do increments in string operations
        mov al,INTRLRS          ; 8251 reset command [rwb]
        out CMD8251,al          ; [rwb]
        jmp $+2                 ; waste some time [rwb]
        mov al,04Eh             ; 8-bit, no parity, 1 stop, 16x clock [rwb]
        out CMD8251,al          ; [rwb]
        jmp $+2                 ; waste time again [rwb]
        mov al,(DTR+RxEN+ERRESET+RTS)  ; enable receive [rwb]
        out CMD8251,al          ; [rwb]
        in al,CMB8259           ; get interrupt mask [rwb]
        and al,INT8251          ; enable RS-232 interrupt [rwb]
        out CMB8259,al          ; [rwb]
        sti                       ; Allow interrupts (AFTER next instr)

serin4: push    bx
        mov     bx,portval              ; get port
        mov     parmsk,0ffh             ; parity mask, assume parity is None.
        cmp     [bx].parflg,parnon      ; is it None?
        je      serin1                  ; e = yes
        mov     parmsk,07fh             ; no, pass lower 7 bits as data
serin1: mov     bx,[bx].flowc           ; get flow control chars
        mov     flowoff,bl              ; xoff or null
        mov     flowon,bh               ; xon or null
        mov     xofrcv,off              ; clear xoff received flag
        pop     bx
        mov     portin,1                ; say initialized
        ret                             ; We're done
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.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 17 May 1987 Redo for COM3/4 support [jrd]
SERRST  PROC    NEAR
        cmp     portin,0        ; Reset already?
        je      srst1           ; Yes, just leave.
        cli                     ; Disable interrupts
; Leave receive and transmit enabled (that's how DOS sets them initially) [rwb]
; Also leave interrupt enabled, DOS will handle any interrupts
        mov al,(DTR+RxEN+TxEN+ERRESET+RTS)  ; enable transmit and receive [rwb]
        out CMD8251,al          ; [rwb]
        sti                     ; replace original IRQ interrupt vector
        push    bx
        mov al,VEC8251          ; Restore the serial card int vector
        mov     dx,word ptr savsci ; offset part
        push    ds
        mov     bx,word ptr savsci+2 ; segment part
        mov     ds,bx           ; ds:dx has interrupt vector
        mov     ah,25H          ; set interrupt vector
        int     dos             ; replaced.
        pop     ds
        mov     al,rs232        ; Bios serial port interrupt vector to restore
        mov     dx,word ptr sav232   ; offset part
        push    ds
        mov     bx,word ptr sav232+2 ; segment part
        mov     ds,bx
        mov     ah,25h          ; set interrupt vector
        int     dos
        pop     ds
        pop     bx
srst3:  mov     portin,0        ; Reset flag.
srst1:
ifdef MODIFIED
        call rbtabl             ; make sure BIOS key translation table ptr is
                                ;   reset upon exit.  Didn't know where else to
                                ;   put this in the machine dependent code [jhw]
endif
        ret                     ; All done.
SERRST  ENDP

; Dummy Interrupt 14H to defeat DOS interference with serial port when CTTY
; and Kermit use the port simultaneously. If ports differ then chain DOS to
; original Int 14H Bios code. Else return dummy status=ok reports and
; Backspace for Read, ignore char for Write.
; Entered with AH = function request, AL = char to be sent, DX = com port num
; CS is our code segment, DS is DOS's, SS is ours or DOS's, interrupts off.
; 25 June 1987 [jrd]
SERDUM  PROC    FAR
        push    ds                      ; preserve all registers.
        push    ax
        mov     ax,seg datas            ; get our data segment
        mov     ds,ax
        pop     ax                      ; recover request parameters
        pop     ds
        cmp     ah,0                    ; initialization request?
        je      serdu3                  ; e = yes, return dummy status=ok rpt
        cmp     ah,1                    ; send char in al?
        jne     serdu2                  ; ne = no
        mov     ah,60h                  ; yes, set line status=ok in ah
        iret
serdu2: cmp     ah,2                    ; receive char (and wait for it)?
        jne     serdu3                  ; ne = no, return dummy report
        mov     al,bs                   ; yes, return ascii BS to DOS
        mov     ah,0                    ; ah = errors (none here)
        iret
serdu3: mov     ax,60b0h                ; dummy status report:xmtr empty, CD,
        iret                            ;  DSR, and CTS are on.

SERDUM  ENDP

; serial port interrupt routine.  This is not accessible outside this
; module, handles serial port receiver interrupts.
; Revised on 22 May 1986, again 2 August 1986 to run at 38.4kb on PC's. [jrd]
; Srcpnt holds offset, within buffer Source, where next rcv'd char goes.
; Count is number of chars now in buffer, and oldest char is srcpnt-count
; done modulo size of Source. All pointer management is handled here.
; Control-G char substituted for char(s) lost in overrun condition. [jrd]
; Upgraded to read cause of interrupt from interrupt ident reg (accepts only
;  data ready), chain to old interrupt if source is not our device. [jrd]

SERINT  PROC  FAR
        push    ax                      ; save registers
        push    dx                      ;
        push    ds
        mov     ax,seg datas
        mov     ds,ax                   ; address data segment
; IBM version sends EOI command to 8259 interrupt controller at this [rwb]
; point, but Sanyo normally runs in auto EOI mode, so no EOI is needed [rwb]
        in al,STS8251           ; [rwb]
        test al,RxRDY           ; Data available? [rwb]
        jnz srint0a             ; nz = yes
srint0: sti                             ; else turn on interrupts
        jmp     retint                  ;  and exit now (common jump point)

srint0a:and al,OVRRUN           ; select overrun bit [rwb]
        mov     overrun,al              ; save it for later
        in al,BUF8251           ; [rwb]
        cmp     flowoff,0               ; flow control active?
        je      srint2                  ; e = no
        mov     ah,al              ; ah = working copy. Check null, flow cntl.
        and     ah,parmsk               ; strip parity temporarily, if any.
        jz      srint2                  ; if null skip flow control
        cmp     ah,flowoff              ; acting on Xoff?
        jne     srint1                  ; ne = Nope, go on.
        mov     xofrcv,bufon            ; Set the flag saying XOFF received.
        jmp     srint0                  ;  and exit
srint1: cmp     ah,flowon               ; acting on Xon?
        jne     srint2                  ; ne = no, go on.
        mov     xofrcv,off              ; Clear the XOFF received flag.
        jmp     srint0                  ;  and exit
srint2: push    bx                      ; save register
        mov     ah,overrun              ; get overrun flag
        or      ah,ah                   ; overrun?
        jz      srint2a                 ; z = no
        mov     ah,al                   ; yes, save present char
        mov al,(DTR+RxEN+ERRESET+RTS)  ; [rwb]
        out CMD8251,al          ; clear overrun status in 8251 [rwb]
        mov     al,bell                 ; insert control-G for missing char
srint2a:mov     bx,srcpnt               ; address of buffer storage slot
        mov     byte ptr [bx],al        ; store the new char in buffer "source"
        inc     srcpnt                  ; point to next slot
        inc     bx
        cmp     bx,offset source + bufsiz ; beyond end of buffer?
        jb      srint3                  ; b = not past end
        mov     srcpnt,offset source ; wrap buffer around
srint3: cmp     count,bufsiz            ; filled already?
        jae     srint4                  ; ae = yes
        inc     count                   ; no, add a char
srint4: or      ah,ah                   ; anything in overrun storage?
        jz      srint4a                 ; z = no
        mov     al,ah                   ; recover any recent char from overrun
        xor     ah,ah                   ; clear overrun storage
        jmp     srint2a                 ; yes, go store real second char
srint4a:pop     bx                      ; restore reg
        sti                          ; ok to allow interrupts now, not before
        cmp     count,mntrgh            ; past the high trigger point?
        jbe     retint                  ; be = no, we're within our limit
        test    xofsnt,bufon        ; Has an XOFF been sent by buffer control?
        jnz     retint                  ; nz = Yes.
        mov     al,flowoff              ; get the flow off char (Xoff or null)
        or      al,al                   ; don't send nul chars
        jz      retint                  ; z = null, nothing to send
        call    dopar                   ; Set parity appropriately.
        mov     ah,al                  ; Don't overwrite character with status
        push    cx                      ; save reg
        xor     cx,cx                   ; loop counter
srint5: in al,STS8251           ; Get port status. [rwb]
        test al,TxEMPTY         ; Transmitter ready?
        jnz     srint6                  ; nz = yes
        jmp     $+2                     ; use time, prevent overdriving UART
        loop    srint5                  ; else wait loop, cx times
         jmp    srint7                  ; Timeout
srint6: cli
        mov al,(TxEN+DTR+RxEN+ERRESET+RTS) ; enable output command [rwb]
        out CMD8251,al          ; [rwb]
        mov al,ah               ; Now send out the flow control char
        out BUF8251,al
        push cx                 ; save reg [jrd]
        xor cx,cx               ; loop counter [jrd]
srint6a: in al,STS8251          ; Get port status. [rwb]
        test al,TxEMPTY         ; Transmitter done?
        jnz srint6b             ; nz = yes
        jmp $+2                 ; use time, prevent overdriving UART
        loop srint6a            ; else wait loop, cx times
                                ; on timeout, kill transmitter
srint6b: mov al,(DTR+RxEN+ERRESET+RTS) ; command to enable only receive [rwb]
        out CMD8251,al
        pop cx
        sti                     ; Enable interrupts after next instruct. [jrd]
        mov     xofsnt,bufon       ; Remember we sent an XOFF at buffer level
srint7: pop     cx                      ; restore reg
retint: pop     ds
        pop     dx
        pop     ax
        iret
SERINT  ENDP

DTRLOW  PROC    NEAR            ; Global proc to Hangup the Phone or Network
                                ; by making DTR and RTS low (phone). [jrd]
        mov     ah,cmtxt        ; 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
         jmp    r
        call    serhng                  ; drop DTR and RTS
        mov     ah,prstr                ; give a nice message
        mov     dx,offset hngmsg
        int     dos
        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]
; 5 April 1987 Add 500 millisec wait with lines low before returning. [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; If network then call nethangup procedure to hangup the session without
; losing local name information.
; Returns normally.

serhng  proc    near    ; clear modem's delta status bits and lower DTR & RTS
shng1:  cli                             ; Disable interrupts
        push    ax
        mov al,(RxEN+ERRESET)   ; DTR and RTS low [rwb]
        out CMD8251,al          ; [rwb]
shngx:  sti                             ; Enable interrupts
        mov     ax,500                  ; 500 millisec, for pcwait
        call    pcwait              ; keep lines low for at least 500 millisec
        pop     ax
        ret
serhng  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

code    ends
        end
