       NAME    msxap3
       Page    60,132

; Last edit: 14 March 1988
; NEC APCIII Edit History

;       RFGoeke, MIT Center for Space Research, 627-253-1910
;       Goeke @ SPACE.MIT.EDU

; 14 March 1988				Rev. a for V2.30
;	Minor patches to get compatible with released IBM V2.30
;	Major shuffle to get text lined up with msxibm so diff will work
;	Change "esc" to "escape"; add shomodem and termtb; add vtemu.vtflgop
; 6 October 1987                             Rev.  F
;       Recreate SERRST to turn off all ports; called by mssker when exiting;
;       keeps incoming characters on unwatched line from bombing system.
;       NB this is also called by mssrcv, mssscp, ssssen, and msster !!!
;       so one has to keep the modem status lines ON at all times.
;       Also increased Hangup DTR drop to 2 seconds; recalibrated pcwait.
; 8 July 1987                                Rev.  E
;       Minor fix ups to keep pace with v/2.29C development; recalibrated
;       timer code in pcwait.
; 5 November 1986                            Rev.  D
;       Major bug in serini fixed (characters in unaddressed ports were
;       coming through and corrupting DOS
; 14 October 1986                            Rev.  B
;       Modified to work with [2.29a] code.
; 21 August 1986                             Rev.  N
;       Modified from the [2.29] code for msxibm
;       with help from the RAL Version 2.0.

; General considerations:
;       The presence of ANSI.SYS in the booted CONFIG.SYS file is assumed.
;       If ports 2 or 3 are to be used, OPTRS232.SYS is required in CONFIG.SYS
;       References to modems have also been deleted.

; Bugs found:
;       The NEC BIOS call to the screen (19H) tends to wipe out the SI
;               register; a lot of push/pops have been added for this reason.
;       The RS232 BIOS call miscalculates the end of the circular receive
;               buffer by 20 bytes (see comments in SERINI).

; (The following comments are from msxibm.asm; not all apply here!)
; 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
        include mssdef.h

false   equ     0
true    equ     1

; the following sets the text attributes                        RFG

att_low_mask    equ     1FH             ; Various attribute-related equates
att_overline    equ     01H             ; this is all NEC version stuff RFG
att_blink       equ     02H
att_rev_video   equ     04H
att_underline   equ     08H
att_intensity   equ     att_rev_video

nec_black       equ     00H             ; This table gives colors       RFG
nec_blue        equ     20H             ; (only bits 8,7,6 count)
nec_red         equ     40H
nec_magenta     equ     60H
nec_green       equ     80H
nec_cyan        equ     0A0H
nec_yellow      equ     0C0H
nec_white       equ     0E0H

; constants used by serial port handler

KEYB    EQU     18H             ;       RFG
BIOS    EQU     19H             ;       RFG
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
;    or port2)
; port1, port2 - portinfo structures for the corresponding ports
; 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

; 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
; brkval  db      BRKBIT          ; What to send for a break.
brkadr  dw      0               ; Where to send it.
modem   mdminfo <>
hngmsg  db      cr,lf,' The phone or network connection 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      ' For networks, the active session is terminated.',cr,lf,'$'
erms40  db      cr,lf,'?Warning: Unrecognized baud rate',cr,lf,'$'
badbd   db      cr,lf,'Unimplemented baud rate$'
prterr  db      '?Unrecognized value$'
badprt  db      cr,lf,' Serial port COM$'
badprt2 db      ' is not available.$'
badprt3 db      cr,lf,' Notice: Port COM1 uses hardware addresses of COM2'
        db      ' (safe).',cr,lf,'$'
biosmsg db      cr,lf,'This port operates through the Bios',cr,lf,'$'
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$'

;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NEC Specific data follows
machnam db      'NEC APC III (a)$'
First   db      true            ; used in getbaud
source  db      20 DUP(?)       ; Buffer for data from port; see comments
        db      bufsiz DUP(?)   ;    in serini for why this must be bufsiz+20
uart    db      01001110B        ; set up various parameters....
;                | | | |
;                | | | +--- Clock 10 x16, 11 x64
;                | | +----- Word Length 00 5, 01 6,10 7, 11 8
;                | +------- Parity 00 None, 01 Odd, 11 Even
;                +--------- Stop Bits 01 1, 10 1.5, 11 2
stnorm  db      00100111B       ; This will be CL for serini, normally  RFG
stbrk   db      00101111B       ; This will send a break from serini    RFG
stdtr   db      00000101B       ; This will drop the DTR and RTS line   RFG
stoff   db      00100010B       ; This kills send and receive enable    RFG
;                ||||||+--- Send enable
;                |||||+---- DTR on
;                ||||+----- Receive enable
;                |||+------ Force spacing on output (for break)
;                ||+------- Error request
;                |+-------- Request to send
;                +--------- Interrrupt reset
saybr   db      escape,'[25;0H'
        db      escape,'[35mBreak sent. . .',escape,'[0m$'
initfail db     cr,lf,escape,'[31mSerial port could not be initialized',escape,'[m$'
outfail db      cr,lf,escape,'[31mTime out on send via serial port',escape,'[m$'
intfail db      cr,lf,escape,'[31mTime out on receive via serial port',escape,'[m$'
inbfail db      cr,lf,escape,'[31mSerial port receive buffer overflow',escape,'[m$'
mlcurat db      ?               ; used for the mode line cursor attributes
clreol  db      escape,'[0K$'      ; Clear to end of line.......
blank   db      escape,'[H',escape,'[J$' ; Home cursor, then Clear screen....
;;;;;;;;;;;;;;;;;;;;;;;;;;;; End of NEC specific stuff

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$'
clone   db      0               ; clone flag (0 = real, 'B' = system Bios,
                                ;  'N' = NetBios/network)
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      13                      ; twelve 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	; NEC can't do internally
        mkeyw   'Margin-bell',marval
        mkeyw   'None',ttgenrc+100H
        mkeyw   'Newline',newval
        mkeyw   'Rollback',400h         ; note 400H flag for decoding
;        mkeyw   'Screen-background',scrval    ; NEC keep black back
        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      132 dup (?)             ; Temporary for unconfirmed tabs.

vthlp   db      ' one of the following:',cr,lf
        db '  terminal types of:  None, Heath-19, Tek4010,'
        db  ' VT52, or VT102',cr,lf
        db '  Newline-mode    Cursor-style        Character-set (US UK)',cr,lf
        db '  Tabstops        Wrap (long lines)   Color (of connect screen)'
        db cr,lf,'  Roll (undo screen roll back before writing new chars,'
        db      ' default=off)',cr,lf
        db '  Margin-bell'
        db '$'

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 to screen width-1$'
tbchlp  db      '  column number of tab stop to clear, 1 to screen width-1$'
tbserr  db      cr,lf,'?Column number is not in range 1 to screen width-1$'

;;;;;;;;;;;;;;;;;;;; modified for the realities of the APC III
colhlp  db      cr,lf,'  Color of:  '
        db      escape,'[34mblue  '
        db      escape,'[31mred  '
        db      escape,'[35mmagenta  '
        db      escape,'[32mgreen  '
        db      escape,'[36mcyan  '
        db      escape,'[33myellow  '
        db      escape,'[37mwhite'
        db      escape,'[0m$'
colltb  db      7                       ; 7 entries
        mkeyw   'Blue',nec_blue
        mkeyw   'Cyan',nec_cyan
        mkeyw   'Green',nec_green
        mkeyw   'Magenta',nec_magenta
        mkeyw   'Red',nec_red
        mkeyw   'White',nec_white
        mkeyw   'Yellow',nec_yellow
;;;;;;;;;;;;;;;;;;;; end of NEC colors
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      6               ; six entries for NEC
        mkeyw   '1',1
        mkeyw   '2',2
        mkeyw   '3',3
        mkeyw   'AUX',1
        mkeyw   'AUX2',2
        mkeyw   'AUX3',3

; this table is indexed by the baud rate definitions given in
; pcdefs.  Unsupported baud rates should contain FF.

baudtab db      0FFH            ; 45.5
        db      0FFH            ; 50
        db      0               ; 75
        db      0FFH            ; 110
        db      0FFH            ; 134.5
        db      1               ; 150
        db      2               ; 300
        db      3               ; 600
        db      4               ; 1200
        db      0FFH            ; 1800
        db      0FFH            ; 2000
        db      5               ; 2400
        db      6               ; 4800
        db      7               ; 9600
        db      0FFH            ; 19.2k
        db      0FFh            ; 38.4k
        db      0FFh            ; 57.6k
        db      0FFh            ; 115.2k
nbaud   equ     $-baudtab

; variables for serial interrupt handler
                                ; BIOS handles the buffer; count not used  RFG
count   dw      0               ; Number of chars in int buffer.
mdstreg db      0               ; Modem status register, current.

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   anstat:near             ; RFG
        assume  cs:code,ds:datas

int_rs232 macro                         ; this is necessary since we need to
        local   rs1,rs2                 ; to use the 1A interrupt if we have
        cmp     flags.comflg,1          ; only one port, and 1E if we have more
        je      rs1
        push    si              ; a necessary save
        push    bx              ; a short save
        mov     bh,0
        mov     bl,flags.comflg ; get the port number
        sub     bl,1            ; put it into NEC terms
        mov     si,bx           ; then into the right place
        pop     bx              ; and restore
        int     1EH             ; now the multi-choice interrupt
        pop     si              ; and restore
        jmp     rs2
rs1:    int     1AH
rs2:    nop
        endm

; local initialization

lclini  proc    near
        mov     flags.comflg,1  ; assume COM1 for communications port
;        call    coms2           ; setup serial port modem.info for COM1  RFG
;        call    model           ; get model of IBM machine  RFG
        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.
; From RAL Version 2.0                          RFG

DODISK  PROC    NEAR
        mov	ah,gcurdsk		; Current disk value to AL.
        int	dos
        mov	dl,al			; Put current disk in DL.
        mov	ah,seldsk		; Select current disk.
        int	dos			; Get number of drives in AL.
dodsk0: mov     drives,al               ; Remember how many.
        ret
DODISK  ENDP

; Returns normally. Obsolete, name here for external reference only.
showkey proc    near
        ret                             ; return
showkey endp

; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdstreg, the modem line status register. [jrd]
shomodem proc   near
        mov     ah,cmcfm                ; get a confirm
        call    comnd
         jmp    r                       ; no confirm
         nop
	mov	ah,6			; status request - NEC code follows
	int_rs232			; go get the answer
	and	ch,80h			; CH bit 7	Data set ready
	xor	cl,0FFh			; CL bit 6	Clear to Send = 0
	and	cl,60h			;        5	Carrier detect = 0
	or	ch,cl			; lump the answer together
	mov	mdstreg,ch		; and save it
        mov     ah,prstr
        mov     dx,offset msmsg1        ; modem ready msg
        test    mdstreg,80h             ; is DSR asserted?
        jz      shomd1                  ; z = no
        mov     dx,offset msmsg2        ; say not asserted
shomd1: int     dos
        mov     dx,offset msmsg3        ; CD asserted msg
        test    mdstreg,20h             ; CD asserted?
        jz      shomd2                  ; z = no
        mov     dx,offset msmsg4        ; say not asserted
shomd2: int     dos
        mov     dx,offset msmsg5        ; CTS asserted msg
        test    mdstreg,40h             ; CTS asserted?
        jz      shomd3                  ; z = no
        mov     dx,offset msmsg6        ; say not asserted
shomd3: 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.
; On the NEC, where the buffer is (really) managed by the BIOS, we could
; clear it by calling serini or blindly reading everything out,  RFG

CLRBUF  PROC    NEAR
clrb2:  mov     ah,2            ; Get data length in CX...Page SE-12
        int_rs232               ; Call APC ROM BIOS
clrb4:  or      ch,cl           ; check for zero in both halfs of CX
        cmp     ch,0            ; is CH 0?
        je      clrb1           ; If zero then buffer is clear else
        mov     ah,4            ; Receive Character...by way of NEC BIOS
        int_rs232
        jmp     clrb2
clrb1:
        ret
CLRBUF  ENDP

; Clear to the end of the current line.  Returns normally.      RFG

CLEARL  PROC    NEAR
        push    ax
        push    dx
        mov dx,offset clreol
        mov ah,prstr
        int dos
        pop     dx
        pop     ax
        ret
CLEARL  ENDP

; This routine blanks the screen.  Returns normally.

CMBLNK  PROC    NEAR
        mov ah,prstr
        mov dx,offset blank
        int dos
        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
        push    si		; NEC
        mov     ah,2            ; Position cursor.
        mov     bh,0            ; page 0
        int     bios
        pop     si		; NEC
        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
        ret


BEEP    PROC    NEAR			; NEC version
        mov dl,bell
        mov ah,conout
        int dos
        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.
; This is only used for the send/receive mode lines.            RFG

putmod  proc    near
        push    ax              ; save regs
        push    bx
        push    cx
        push    dx              ; preserve message
	call    anstat          ; get the screen attributes   RPG
        mov     bh,ah           ; mlbattr returned in ah
        mov     mlcurat,ah      ; and put it in mlcurat
        mov     cx,1800h        ; from line 24, column 0
        mov     dx,184fh        ; to line 24, column 79
        mov     ax,600h         ; do a scroll up
        int     bios

        mov     dx,1800h        ; now address line 24
        call    poscur
        pop     si              ; get message back (from dx push)
        mov     cx,1            ; only one char at a time
        xor     bh,bh           ; page 0
putmo1: lodsb                   ; get a byte
        cmp     al,'$'          ; end of string?
        je      putmo2
        push    si              ; save si
        push    ax              ; and the char
        call    poscur
        inc     dl              ; increment for next write
        pop     ax              ; recover char
        mov     ah,9            ; try this
        mov     bl,mlcurat      ; page 0, inverse video
        mov     bh,0
        int     bios
        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.
; separate out the text attributes                      RFG
clrmod  proc    near
        push    ax
        push    bx
        push    cx
        push    dx
        call    anstat          ; get the screen attributes   RPG
        mov     bh,al           ; scbattr returned in al
        mov     cx,1800h        ; from line 24, column 0
        mov     dx,184fh        ; to line 24, column 79
        mov     ax,600h         ; do a scroll up
        int     bios
        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.
; separate out text attributes
puthlp  proc    near
        push    bx              ; save regs. [jrd]
        push    cx
        push    dx
        push    si
        push    ax              ; preserve this
        cld
        mov     si,ax           ; point to it
        mov     dh,1            ; init counter
puthl1: lodsb                   ; get a byte
        cmp     al,lf           ; linefeed?
        jne     puthl2          ; no, keep going
        inc     dh              ; count it
        jmp     puthl1          ; and keep looping
puthl2: cmp     al,0            ; end of string?
        jne     puthl1          ; no, keep going;
        call    anstat          ; get screen attributes     RPG
        mov     bh,ah           ; mlbattr returned in ah
        mov     mlcurat,ah      ; and save it
        mov     ax,600h         ; scroll to clear window
        xor     cx,cx           ; from top left
        mov     dl,4fh          ; to bottom right of needed piece
        int     bios
        call    locate          ; home cursor
        mov     bh,0            ; Page 0
        mov     bl,mlcurat
        mov     cx,1            ; one char at a time
        cld                     ; scan direction is forward [jrd]
        pop     si              ; point to string again
puthl3: lodsb                   ; get a byte
        cmp     al,0            ; end of string?
        je      puthl4          ; yes, stop
        push    si              ; save around bios call
        cmp     al,' '          ; printable?
        jb      puth21          ; b = no
        mov     ah,9            ; write char at current cursor position [jrd]
        int     bios            ; do the Bios int 10h call
        inc     dl              ; point to next column
        jmp     puth23          ; move cursor there
puth21: cmp     al,cr           ; carriage return?
        jne     puth22          ; ne = no
        xor     dl,dl           ; set to column zero
        jmp     puth23
puth22: cmp     al,lf           ; line feed?
        jne     puth23
        inc     dh              ; go to next line
puth23: mov     ah,2            ; set cursor position to dx
        int     bios
        pop     si              ; restore pointer [jrd]
        jmp     puthl3          ; and keep going
puthl4: mov     dx,24 * 100H    ; go to last line
        call    poscur          ; position cursor
        pop     si              ; [jrd]
        pop     dx
        pop     cx
        pop     bx
        ret
puthlp  endp

                                        ; 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,cmkey                ; COLOR - get value
        mov     bx,offset colhlp        ; use this help text
        mov     dx,offset colltb        ; parse by this table
        call    comnd
          jmp   r
        push    bx                      ; save it
        cmp     ah,0                    ; any response
        jne     vsetu2a                 ; ne = yes
        jmp     vsetux                  ; else give not confirmed msg
vsetu2a:
        pop     ax                      ; get value
        mov     bx,vtemu.att_ptr        ; address of attributes byte
        mov     byte ptr [bx],al        ; put the color in (plain, otherwise)
        jmp     rskp
vsetux: pop     bx                      ; throw away
        jmp     r                       ; and exit complaining

; 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

        mov     bx,vtemu.att_ptr        ; pointer to attributes byte
        mov     al,byte ptr [bx]
        and     al,0E0H                 ; color bits only, please
        mov     ah,0
        mov     bx,offset colltb
        call    prttab
        add     cx,18                   ; 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,0F9H                 ; default position symbol ( mid-dot )
        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

; Wait for the # of milliseconds in ax
; Thanks to Bernie Eiben for this one.
; Recalibrated for 8 MHz clock on NEC -- RFG
pcwait  proc    near
        mov     cx,300          ; inner loop counter for 1 millisecond
				; was 240 for IBM PC
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.
; modified to use all 3 ports                   RFG

COMS    PROC    NEAR
        mov dx,offset comptab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp comx               ;  Didn't get a confirm.
         nop
        pop bx
        mov flags.comflg,bl     ; Set the comm port flag.
        cmp flags.comflg,1      ; Using Com 1?
        jne coms0               ; Nope.
        mov ax,offset port1
        mov portval,ax
        ret
coms0:
        cmp flags.comflg,2      ; Using Com 2?
        jne coms1               ; Nope.
        mov ax,offset port2
        mov portval,ax
        ret
coms1:
        cmp flags.comflg,3      ; Using Com 3?
        jne comx                ; this can't be!
        mov ax,offset port3
        mov portval,ax
        ret
comx:   pop bx
        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
chkport endp

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.
; lifted from the RAL version 2.0                               RFG

; This routine should set the baud rate for the current port but it
; is actually done in SERINI.
dobaud  proc    near
        push si                 ; [jrd]
        push bx
        mov bx,portval
        mov si,[bx].baud        ; get baud rate index pointer..
        pop bx
        mov al,baudtab[si]      ; load up baud rate.........
        pop si                  ; [jrd]
        cmp al,0FFH             ; Is Baud Rate Possible??
        je badbaud
        call    serini          ; Simply re-init port with new baud rate
dbret:  ret
BadBaud: mov ah,prstr           ; MS-DOS Print String...
        mov dx,offset badbd     ; point at message
        int DOS
        jmp dbret
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.

; lifted from RAL version 2.0                           RFG
;* RAL..This routine appears to be called every time a status is done.
;* I will set baud rate first time, and simply return from then on.
;*
;*  Page SA-2 APC III Programmer Reference Manual

GETBAUD PROC    NEAR
        push    ax      ; addition to fix (bug) in msster       RFG
        push    bx

        mov     al,First    ; Check to see if this is the first time....
        cmp     al,false
        je      GBRET        ; Quit if baud rate already known.....

        mov     First,False ; Flip Flag...
        mov     bx,portval
        mov     [bx].baud,0Dh ; Default to 9600 Baud.....
        call    serini     ; Set up port........
GBRET:
        pop     bx
        pop     ax
        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]

; partially taken from RAL version 2.0
; use call for all 3 RS232 ports                        RFG

PRTCHR  PROC    NEAR
        push    cx
        push    bx

        mov     ah,2            ; Get data length in CX...Page SE-12
        int_rs232               ; Call APC ROM BIOS
        or      ch,cl           ; check for zero in both halfs of CX
        cmp     ch,0            ; is CH 0?
        je      prtcn           ; give up if no characters........

        mov     ah,4            ; Receive Character...by way of NEC BIOS
        int_rs232
        cmp     ah,0            ; check return status
        je      prtc1           ; 0 = everything normal
                                ; 1 = port not initialized
                                ; 2 = (receive) buffer overflow
                                ; 3 = timed out
        call    beep            ; say something
        cmp     ah,2
        je      prtc2
        mov     ah,prstr        ; say timed out
        mov     dx,offset intfail
        int     dos
        jmp     prtcx
prtc2:  mov     ah,prstr        ; say buffer overflow
        mov     dx,offset inbfail
        int     dos
        jmp     prtcx
prtc1:
        mov     al,ch           ; Character is returned in CH....

prtcx:  pop     bx
        pop     cx
        ret
prtcn:                          ; no characters in queue, check console
        pop     bx
        pop     cx
        jmp rskp
PRTCHR  ENDP

; Network Receive packet routine. Request a net packet with no-wait option.
; Return carry clear if success. If failure, reset serial port (Server mode
; reinits serial port) and return carry set. No entry setup needed.
RECEIVE PROC    NEAR                    ; receive network session pkt
RECEIVE ENDP

; Network Receive post processing interrupt routine.
; Copy chars from rcvbuf to circular buffer source, act on xon/xoff,
; clear rposted interlock flag. At entry, CS is our code segment,
; es:bx points to scb, netbios stack, interrupts are off.
RPOST   PROC    FAR             ; network receive post interrupt routine
RPOST   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]

; XON/XOFF is handled by the BIOS an NEC                RFG

OUTCHR  PROC    NEAR
        push    dx
        push    bx
        mov     al,ah           ; parity works on AH
        call    dopar           ; do parity work before sending
        mov     ah,3            ; NEC ROM BIOS send character in AL
        int_rs232               ; Call ROM BIOS send character in AL
        cmp     ah,0            ; check return status
        je      outc1           ; 0 = everything normal
                                ; 1 = port not initialized
                                ; 2 = (receive) buffer overflow
                                ; 3 = timed out
        call    beep            ; say something
        mov     ah,prstr
        mov     dx,offset outfail
        int     dos
        pop     bx
        pop     dx
        ret                     ; and return (abnormally?)
outc1:
        pop     bx
        pop     dx
        jmp     rskp
OUTCHR  ENDP

; Network Send packet routine. Send xmt scb with no-wait option. Waits
; up to 6 seconds for current Send to complete before emitting new Send.
; Failure to Send resets serial port (Server mode allows reiniting of serial
; port). Returns carry clear for success, carry set for failure.
; Enter with xmtcnt holding length of data in xmtbuf to be sent.
SEND    PROC    NEAR                    ; Network. Send session packet
SEND    ENDP

; Network Send packet completion interrupt routine. At entry CS is our
; code segment, es:bx points to scb, netbios stack, interrupts are off.
SPOST   PROC    NEAR                    ; post routine for Send packets
SPOST   ENDP

; dispatch prebuilt network session scb, enter with bx pointing to scb.
; returns status in al (and ah too). Allows STARLAN Int 2ah for netint.
SESSION PROC    NEAR
SESSION ENDP

; Make a virtual circuit Session, given preset scb's from proc chknet.
; For Server mode, does a Listen to '*', otherwise does a Call to indicated
; remote node. Updates vcid number in scb's. Shows success or fail msg.
; Updates network status byte pcnet to 2 if session is established.
; Does nothing if a session is active upon entry; otherwise, does a network
; hangup first to clear old session material from adapter board. This is
; the second procedure to call in initializing the network for usage.
SETNET  PROC    NEAR                    ; Network, make a connection
SETNET  ENDP

; Called only when Kermit exits. Name passed to mssker by proc chknet
; in word netdone.
NETCLOSE PROC   NEAR                    ; close entire network connection
NETCLOSE ENDP

; Start connection process to network. Obtains Network board local name
; and appends '.K' to form Kermit's local name (removed when Kermit exits).
; If no local name is present then use name 'mskermit.K'.
; Sets local name in scb's for xmt, rcv, lsn. (Does not need DOS 3.x)
; Sets NETDONE pointer to procedure netclose for Kermit exit.
; Verifies existance of interrupt 5ch support, verifies vendor specific
; support for BREAK and other features, sets network type bit in nettype,
; sets BREAK support in nsbrk, hangsup old session if new node name given,
; fills in local and remote node names and name number in scbs (including ISN
; names for STARLAN), and sets network status byte pcnet to 0 (no net) or
; to 1 (net ready). This is the first procedure called to init network usage.
; Byte count of new host name is in temp from COMS.
chknet  proc    near
chknet  endp

; local routine to see if we have to transmit an xon
; its handled by the hardware on the NEC                        RFG
chkxon  proc    near
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    bx
        push    cx
        push    dx
        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)
         nop                    ; outchr can do skip return
         nop
         nop
ihosts1:call    clrbuf          ; clear out interrupt buffer
        mov     ax,1            ; sleep for 1 second
        call    sleep           ; procedure sleep is in msscom.asm
        call    prtchr          ; check for char at port
         jmp    ihosts1         ; have a char in al, repeat wait/read cycle
         nop                    ; prtchr does skip return on empty buffer
        pop     dx              ; empty buffer. we are done here.
        pop     cx
        pop     bx
        pop     ax
        ret
IHOSTS  ENDP

; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port.         22 March 1986 [jrd]
IHOSTR  PROC    NEAR
        push    ax              ; save regs
        push    bx
        push    cx
        mov     bx,portval      ; port indicator
        mov     ax,[bx].flowc   ; put Go-ahead flow control char in ah
        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     bx
        pop     ax
        ret
IHOSTR  ENDP

; Send a break out the current serial port.  Returns normally.
; an APC specific version                               RFG

SENDBR  PROC    NEAR
        push    dx
        push    cx
        push    ax

        mov     ah,prstr                ; tell the user on the status line
        mov     dx,offset saybr         ;   that we're sending it
        int     dos

        mov     ah,5            ; set the break bit
        mov     al,stbrk
        int_rs232
        mov     ax,275          ; # of ms to wait
        call    pcwait          ; hold break for desired interval
        mov     ah,5            ; and clear the break bit
        mov     al,stnorm
        int_rs232

        pop     ax
        pop     cx
        pop     dx
        ret
SENDBR  ENDP
SENDBL  PROC    NEAR                    ; Send a long break
        push    dx
        push    cx
        push    ax

        mov     ah,prstr                ; tell the user on the status line
        mov     dx,offset saybr         ;   that we're sending it
        int     dos

        mov     ah,5            ; set the break bit
        mov     al,stbrk
        int_rs232
        mov     ax,1800          ; # of ms to wait
        call    pcwait          ; hold break for desired interval
        mov     ah,5            ; and clear the break bit
        mov     al,stnorm
        int_rs232

        pop     ax
        pop     cx
        pop     dx
        ret
SENDBL  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.

;************* RAL *****************************************************
;* Page SE-10 MS-DOS Programmers Manual
;* Performs Serial Port Initialization.............
;***********************************************************************

; Various mods to allow 3 ports and setting timeout parameters so that we
;       won't hang forever if the line dies.                    RFG

SERINI  PROC    NEAR
	call serrst		; Turn off the unused ports to avoid
				; characters coming in and causing a
				; d.e.l.a.y.e.d CRASH

        push es
        push di
        push    si              ; additional save               RFG

        mov AX,datas            ; point at start of this segement?
        mov ES,AX
        mov DI,offset source    ; Point at Serial Buffer....

        mov bx,portval
        mov parmsk,0ffh         ; parity mask, assume parity is None. [jrd]
        cmp [bx].parflg,parnon  ; is it None?
        je serin3               ; e = yes
        mov parmsk,07fh         ; no, pass lower 7 bits as data
serin3:
        mov si,[bx].baud        ; get baud rate index pointer..
        mov ah,[bx].floflg

        mov al,baudtab[si]      ; load up baud rate.........

                                ; AH = 1 XON/XOFF flow control
                                ; AH = 0 No Flow control
                                ; Page SE-10 NEC Programmer Ref manual

        cmp     AH,0            ; doing flow control?
        je      NoFlow          ; 0 if not flow control

        mov ah,1                ; Init with Xon/Xoff

NoFlow:
        mov ch,uart             ; set up various UART parameters

        mov dx,bufsiz           ; load with Buffer Size...bufsiz in mssdef.h
                                ;    (currently 2048 bytes)
                                ; NB that since the BIOS uses 1 word per char,
                                ;    this means the buffer is really only
                                ;    bufsiz/2 long. (1 sec at 9600 baud)
                                ; Due to a bug in the BIOS, the size is
                                ;    miscalculated by the 20 bytes used at
                                ;    the front by the BIOS for pointers, etc.;
                                ;    without the pad put into the 'source'
                                ;    definition, the handler would simply
                                ;    overwrite the following data area.
                                ; This is a circular buffer managed entirely
                                ;    by the BIOS with XON set at 3/4 DX and
                                ;    XOFF set at 1/4 DX.


        mov bh,2                ; time out on send is this number *500 ms
                                ;       0 = infinity                    RFG
                                ; this should /not/ affect waiting for XON
                                ;       from the host (handled in BIOS again)
        mov bl,4                ; time out on receive is this number *500 ms
                                ;       0 = infinity                    RFG
                                ; since we're checking buffer before we read
                                ;       (see prtchr), shouldn't be necessary.

        mov CL,stnorm           ; see NEC Ref Guide, Page SE-11     RFG
        mov CH,uart             ; set up various parameters....   again

        int_rs232               ; Call NEC Rom

        cmp ah,0                ; Did everything go ok??
        je serinx               ; continue if so...
        call    beep            ; otherwise, notify the authorities
        mov     ah,prstr
        mov     dx,offset initfail
        int     dos
serinx:
        pop     si              ; additional restore            RFG
        pop di
        pop es
        ret                     ; We're done. [21c]
SERINI  ENDP

; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
; in NEC land, we simply turn everyone OFF.        RFG

SERRST  PROC    NEAR

        push es
        push di
        push si

        mov AX,datas            ; point at start of this segement?
        mov ES,AX
        mov DI,offset source    ; Point at Serial Buffer....

	mov ch,uart		; just as a formality
        mov cl,stoff            ; now we turn unused ports dead off 'cause
                                ; if we don't, and come characters come in,
                                ; we get a d.e.l.a.y.e.d crash!
        mov ah,0                ; initialize port mode
        mov al,0                ; baud probably irrelevant
        mov dx,bufsiz           ; just to give it a valid number
        mov bh,0                ; zip to the high byte
        mov bl,0                ; turn port 1 off
        mov si,bx
        int 1EH                 ; could have used 1AH here
	mov ch,uart
        mov cl,stoff
        mov ah,0
        mov al,0
        mov dx,bufsiz
        mov bh,0
        mov bl,1                ; turn port 2 off
        mov si,bx
        int 1EH
	mov ch,uart
        mov cl,stoff
        mov ah,0
        mov al,0
        mov dx,bufsiz
        mov bh,0
        mov bl,2                ; turn port 3 off
        mov si,bx
        int 1EH

        pop si
        pop di
        pop es

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

; 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
        push    ax
        mov     ah,5            ; direct to the UART
        mov     al,stdtr        ; lower the boom
        int_rs232               ; drop the DTR
        mov     ax,500         ; hold it low for a bit
        call    pcwait
        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
