home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
mskermit.zip
/
msxibm.asm
< prev
next >
Wrap
Assembly Source File
|
1998-05-28
|
268KB
|
8,223 lines
NAME msxibm
; File MSXIBM.ASM
; Kermit system dependent module for IBM-PC
include mssdef.h
; Copyright (C) 1982, 1997, Trustees of Columbia University in the
; City of New York. The MS-DOS Kermit software may not be, in whole
; or in part, licensed or sold for profit as a software product itself,
; nor may it be included in or distributed with commercial products
; or otherwise distributed by commercial concerns to their clients
; or customers without written permission of the Office of Kermit
; Development and Distribution, Columbia University. This copyright
; notice must not be removed, altered, or obscured.
;
; Edit history
; 12 Jan 1995 version 3.14
; Last edit
; 12 Jan 1995
public serini, serrst, clrbuf, outchr, coms, cardet
public dodel, ctlu, cmblnk, locate, prtchr, baudst, clearl
public getbaud, beep, shomodem, getmodem, mdmhand, shownet
public count, xofsnt, puthlp, putmod, clrmod, poscur, holdscr
public sendbr, sendbl, machnam, setktab, setkhlp, lclini, showkey
public ihosts, ihostr, dtrlow, serhng, comptab, pcwait, portval
public bdtab, dupflg, peekcom, tstport, fossil_port, fossilflag
public savexoff, savexlen, parmsk, flowon, flowoff, flowcnt
public isps55 ; [HF] 940130 Japanese IBM PS/55 mode
public ps55mod ; [HF]940206 PS/55 mode line status (0:system)
ifndef no_network
public setnbios, ubhold, ubclose
endif ; no_network
ifndef no_tcp
public tcpstart, tcp_status, sesdisp, seslist, sescur, winupdate
public tcpbtpkind, sestime
endif ; no_tcp
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
nbuflen equ 512 ; bytes in each network buffer (two of them)
; DEC-LAT requires 259 (256 + 3 extra)
BRKBIT EQU 040H ; Send-break bit.
TIMERCMD EQU 43h ; 8253/4 Timer chip command port
TIMER2DATA EQU 42h ; 8253/4 Timer 2 data port
PPI_PORT EQU 61h ; 8255 prog peripheral chip control port
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 ; Input ready bit
MDMOVER EQU 2 ; Receiver overrun
; 1200/75 baud split speed constants
cnt75b equ 47721/3 ; One bit of 75 baud at 1.193 Mhz clock
precomp equ cnt75b/8 ; Precomp 12%, allows 3ms latency w 12% jitter
ifndef no_tcp
_TEXT segment
extrn ktcpopen:far, ktcpclose:far, ktcpswap:far, ktcpcom:far
_TEXT ends
endif ; no_tcp
data segment
extrn flags:byte, trans:byte, ttyact:byte, comand:byte
extrn lclsusp:word, lclrest:word, lclexit:word, rxtable:byte
extrn rdbuf:byte, taklev:byte, scbattr:byte
extrn low_rgt:word, diskio:byte, crt_cols:byte
extrn dosnum:word, portirq:byte, portfifo:byte, dosctty:byte
extrn tv_mode:byte, repflg:byte, decbuf:byte
extrn takadr:word, taklev:byte, vtinited:byte, kbdflg:byte
extrn yflags:byte, apctrap:byte, protlist:byte
extrn vtcpage:word, kstatus:word
extrn domath_ptr:word, domath_cnt:word, domath_msg:word
ifndef no_network
ifndef no_tcp
extrn tcpnewline:byte
extrn tcpaddress:byte, tcpsubnet:byte, tcpdomain:byte
extrn tcpgateway:byte, tcpprimens:byte, tcpsecondns:byte
extrn tcphost:byte, tcpbcast:byte, tcpbtpserver:byte
extrn tcpport:word, tcppdint:word, tcpttbuf:byte
extrn tcpdebug:byte, tcpmode:byte, tcpmss:word
endif ; no_tcp
endif ; no_network
ifndef no_terminal
extrn tekflg:byte, ftogmod:dword
endif ; no_terminal
; Modem information
mdminfo struc
mddat dw 03f8h ; data register, base address (03f8h)
mdiir dw 03fah ; interrupt identification register (03fah)
mdstat dw 03fdh ; line status register (03fdh)
mdcom dw 03fbh ; line control register (03fbh)
mden db not (1 shl 4) ; mask to enable interrupt
mddis db (1 shl 4) ; mask to disable interrupt
mdmeoi db 60h+4 ; specific EOI
mdintv dw 8+4 ; saved interrupt vector (0ch is IRQ 4)
mdmintc dw 20h ; interrupt controller control (20h or 0a0h)
mdfifo db 0 ; non-zero if UART is in FIFO mode
mdminfo ends
modem mdminfo <>
setktab db 0 ; superceded by msuibm code, return 0 here
setkhlp db '$' ; and add empty help string
holdscr db 0 ; Hold-Screen, non-zero to stop reading
savsci dd 0 ; old serial port interrupt vector
sav232 dd 0 ; Original Bios Int 14H address, in Code seg
savirq db 0 ; Original Interrupt mask for IRQ
savier db 0 ; original UART Int enable bits (03f9)
savstat db 0 ; orginal UART control reg (03fch)
savlcr db 0 ; Original Line Control Reg (3fbh) contents
dupflg db 0 ; full (0) or half (1) duplex on port
quechar db 0 ; queued char for outchr (XOFF typically)
intkind db 0 ; cause of serial port interrupt
isps2 db 0 ; non-zero if real IBM PS/2
isps55 db 0 ; [HF] 940130 non-zero if Japanese PS/55 mode
ps55mod db 0, 0 ; [HF] 940202 PS/55 mode line at startup/curr.
reset_clock db 0 ; toggle to reset time of day clock in serini
erms40 db cr,lf,'?Warning: Unrecognized Speed',cr,lf,'$'
badbd db cr,lf,'Unimplemented speed$'
badprt db cr,lf,'?Warning: unknown address for port. Assuming \x0$'
biosmsg db cr,lf,'?Warning: unknown hardware for port.'
db ' Using the Bios as BIOS$'
badirq db cr,lf,'?Warning: unable to verify IRQ. Assuming $'
msmsg1 db cr,lf,' Modem is not ready: DSR is off$'
msmsg2 db cr,lf,' Modem is ready: DSR is on$'
msmsg3 db cr,lf,' no Carrier Detect: CD is off$'
msmsg4 db cr,lf,' Carrier Detect: CD is on$'
msmsg5 db cr,lf,' no Clear To Send: CTS is off$'
msmsg6 db cr,lf,' Clear To Send: CTS is on$'
msmsg7 db cr,lf,' Modem is not used by the Network$'
msmsg8 db cr,lf,' COM1 address: Port \x$'
msmsg9 db ', IRQ $'
msmsg10 db ', 16550A UART FIFO$'
msmsg11 db cr,lf,' Fossil port: $'
msmsg12 db ', disable-on-close: off$'
msmsg13 db ', disable-on-close: on$'
msmsg14 db ', 1 stop bit$'
msmsg20 db ' (Set Carrier is on)$'
msmsg21 db ' (Set Carrier is off)$'
hngmsg db cr,lf,' The phone or network connection should have hung up'
db cr,lf,'$'
machnam db 'IBM-PC$'
crlf db cr,lf,'$'
delstr db BS,BS,' ',BS,BS,'$' ; Delete string
clrlin db BS,BS,' ',cr,'$' ; Clear line (just the cr part)
portin db -1 ; Has comm port been initialized, -1=not used
nettype dw 0 ; kind of local area net (vendor bit field)
xofsnt db 0 ; Say if we sent an XOFF
xofrcv db 0 ; Say if we received an XOFF
pcwcnt dw 800 ; number of loops for 1 millisec in pcwait
temp dw 0
temp2 dw 0
tempsci dw 0 ; temp storage for serint
tempdum dw 0 ; temp storage for serdum
timeract db 0 ; timer in use by a routine, flag
clomsg db ' A communications session may be active;'
db ' exit anyway [Yes/No]? ',0
clotab db 2 ; close net on exit table
mkeyw 'yes',0
mkeyw 'no',1
ifdef no_network
comptab db 25 - 12
else
ifdef no_tcp
comptab db 25 - 1 ; communications port options
else
comptab db 25 ; communications port options
endif ; no_tcp
endif ; no_network
mkeyw 'Bios1','0'+1 ; '0' is to flag value as forced Bios
mkeyw 'Bios2','0'+2
mkeyw 'Bios3','0'+3
mkeyw 'Bios4','0'+4
mkeyw 'COM1',1 ; these go straight to the hardware
mkeyw 'COM2',2
mkeyw 'COM3',3
mkeyw 'COM4',4
mkeyw '1',1 ; straight to the hardware
mkeyw '2',2
mkeyw '3',3
mkeyw '4',4
ifndef no_network
mkeyw '3Com(BAPI)','C' ; 3Com BAPI interface
mkeyw 'BWTCP','b' ; [JRS] Beame & Whiteside TCP
mkeyw 'DECnet','D' ; DECnet-DOS LAT and CTERM
mkeyw 'EBIOS','E' ; IBM/YALE EBIOS Int 14h interceptor
mkeyw 'NetBios','N' ; Netbios
mkeyw 'Novell(NASI)','W' ; Novell NetWare NASI/NACS
mkeyw 'OpenNET','O' ; Intel OpenNET support (FGR)
mkeyw 'SuperLAT','M' ; Meridian SuperLAT
ifndef no_tcp
mkeyw 'TCP/IP','t' ; Telnet, internal
endif ; no_tcp
mkeyw 'TELAPI','T' ; Novell TELAPI
mkeyw 'TES','I' ; TES, Interconnections Inc
mkeyw 'UB-Net1','U' ; Ungermann Bass Net One
endif ; no_network
mkeyw 'Fossil','F' ; Fossil
mkeyw ' ',0 ; port is not present, for Status
; port structure:
; baud rate index, local echo, parity flag, if flow control active (both ways),
; if need handshake after pkts, default handshake char, flow control char pair
; half/full duplex, port ready, send, receive, close procedures
; UART hardware
port1 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,uartsnd,uartrcv,serrst>
port2 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,uartsnd,uartrcv,serrst>
port3 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,uartsnd,uartrcv,serrst>
port4 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,uartsnd,uartrcv,serrst>
; IBM PC Bios and EBIOS
portb1 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,biossnd,biosrcv,serrst>
portb2 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,biossnd,biosrcv,serrst>
portb3 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,biossnd,biosrcv,serrst>
portb4 prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,biossnd,biosrcv,serrst>
portval dw port1 ; Default is to use port 1
bdtab db 21 ; Baud rate table
mkeyw '45.5',0
mkeyw '50',1
mkeyw '75',2
mkeyw '110',3
mkeyw '134.5',4
mkeyw '150',5
mkeyw '300',6
mkeyw '600',7
mkeyw '1200',8
mkeyw '1800',9
mkeyw '2000',10
mkeyw '2400',11
mkeyw '4800',12
mkeyw '9600',13
mkeyw '14400',14
mkeyw '19200',15
mkeyw '28800',16
mkeyw '38400',17
mkeyw '57600',18
mkeyw '115200',19
mkeyw '75/1200',20 ; split speed, use this index for Bsplit
Bsplit equ 20 ; 75/1200 baud, split-speed [pslms]
; this table is indexed by the baud rate definitions given in bdtab.
; Unsupported baud rates should contain 0FFh.
bddat label word
dw 9E4H ; 45.5 baud
dw 900H ; 50 baud
dw 600H ; 75 baud
dw 417H ; 110 baud
dw 359H ; 134.5 baud
dw 300H ; 150 baud
dw 180H ; 300 baud
dw 0C0H ; 600 baud
dw 60H ; 1200 baud
dw 40H ; 1800 baud
dw 3AH ; 2000 baud
dw 30H ; 2400 baud
dw 18H ; 4800 baud
dw 0CH ; 9600 baud
dw 08h ; 14400 baud
dw 06H ; 19200 baud
dw 04h ; 28800 baud
dw 03H ; 38400 baud
dw 02h ; 57600 baud
dw 01h ; 115200 baud
dw 5fh ; Split 75/1200, 1200+1.1 percent error
baudlen equ ($-bddat)/2 ; number of entries above
; this table is indexed by the baud rate definitions given in
; pcdefs. Unsupported baud rates should contain FF.
; Bits are for Bios speed, no parity, 8 data bits.
clbddat label word
dw 0FFH ; 45.5 baud -- Not supported
dw 0FFH ; 50 baud
dw 0FFH ; 75 baud
dw 03H ; 110 baud
dw 0FFH ; 134.5 baud
dw 23H ; 150 baud
dw 43H ; 300 baud
dw 63H ; 600 baud
dw 83H ; 1200 baud
dw 0ffH ; 1800 baud
dw 0FFH ; 2000 baud
dw 0a3H ; 2400 baud
dw 0c3H ; 4800 baud
dw 0e3H ; 9600 baud
dw 0FFH ; 14400 baud
dw 0FFH ; 19200 baud
dw 0FFH ; 28800 baud
dw 0FFH ; 38400 baud
dw 0FFH ; 57600 baud
dw 0FFH ; 115200 baud
dw 0FFh ; Split 75/1200
defcom dw 03f8h,02f8h,03e8h,02e8h ; default COMn port addresses
;;;;;;;;;;;;;; start of per session save area
even
savexoff label word
source db bufsiz+2 DUP(?) ; Buffer for data from port (+ 2 guard bytes)
srcpnt dw source ; Pointer in buffer
count dw 0 ; Number of chars in int buffer
cardet db 0 ; UART Carrier Detect (and network analogue)
parmsk db 0ffh ; parity mask, 0ffh for no parity, 07fh with
flowoff db 0 ; flow-off char, Xoff or null (if no flow)
flowon db 0 ; flow-on char, Xon or null
flowcnt db 0 ; holds flowc (!= 0 using any flow control)
xmtcnt dw 0 ; occupancy in current output buffer
xmtbufx db nbuflen+3 dup (0) ; external version of xmtbuf (dbl buffers)
ifndef no_network
ifndef no_tcp
; TCP/IP Telnet internal
port_tn prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,ubsend,ubrecv,tcpclose>
else
port_tn prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,ubsend,ubrecv,ubclose>
endif ; no_tcp
endif ; no_network
savexlen dw ($-savexoff)
;;;;;;;;;;;;;;; end of per session save
tcp_status dw 0 ; status from msntnd.c
; SUCCESS 0
; NO_DRIVER 1
; NO_LOCAL_IP 2
; NO_SESSION 3
; NO_HOST 4
; BAD_SUBNET_MASK 5
; SESSIONS_EXCEEDED 6
; HOST_UNKNOWN 7
; HOST_UNREACHABLE 8
; CONNECTION_REJECTED 9
tcpbtpkind db 0 ; BOOT kind from msntni.asm
; BOOT_FIXED 0
; BOOT_BOOTP 1
; BOOT_RARP 2
; BOOT_DHCP 3
xmtbuf db nbuflen dup (0) ; network buffer for transmitter
rcvbuf db nbuflen+3 dup (0) ; network buffer for receiver
; variables for serial interrupt handler
mst dw 03fdh ; Modem status address
mdat dw 03f8h ; Modem data address
miir dw 03fah ; modem interrupt ident register
mdeoi db 20h ; End-of-Interrupt value
mdmhand db 0 ; Modem status register, current
mdintc dw 20h ; interrupt control address
fossil_port dw 0 ; Fossil, port number 0..98
fossilflag db 0 ; Fossil, shut port when done if non-zero
fossil_portst equ 3 ; Fossil, port status
fossil_init equ 4 ; Fossil, init port in dx
fossil_done equ 5 ; Fossil, release port in dx
fossil_dtr equ 6 ; Fossil, DTR control
fossil_blkrd equ 18h ; Fossil, block read
fossil_blkwr equ 19h ; Fossil, block write
fossil_flow equ 0fh ; Fossil, set flow control method
ifndef no_network
; Information structures for IBM Netbios compatible Local Area Networks
; network constants
netint equ 5ch ; Netbios interrupt
nadd equ 30h ; Add name
ncall equ 10h ; CALL, open a virtual circuit session
ncancel equ 35h ; Cancel command in scb buffer
ndelete equ 31h ; Delete Name
nhangup equ 12h ; Hangup virtual circuit session
nlisten equ 11h ; Listen for session caller
naustat equ 33h ; Network Adapter Unit, get status of
nreceive equ 15h ; Receive on virtual circuit
nreset equ 32h ; Reset NAU and tables
nsend equ 14h ; Send on virtual circuit
nsestat equ 34h ; Session, get status of
netbrk equ 70h ; STARLAN Int 5bh send Break
nowait equ 80h ; no-wait, command modifier
npending equ 0ffh ; Pending request
exnbios equ 0400h ; Int 2ah exec netbios call, error retry
; nettype word bits
netbios equ 0001h ; NetBios
netone equ 0002h ; Ungermann-Bass Net/One
decnet equ 0004h ; DECnet CTERM
declat equ 0008h ; DECnet LAT
bapi equ 0010h ; 3Com BAPI
ebios equ 0020h ; EBIOS, IBM and YALE
telapi equ 0040h ; TELAPI, Novell
tes equ 0080h ; TES, Interconnections Inc and Novell
tcpnet equ 0100h ; TCP/IP (internal)
acsi equ 0200h ; EBIOS, ACSI direct to NetBios pathway
bwtcp equ 0400h ; [JRS] Beame & Whiteside TCP
;xncall equ 74h ; [ohl] Net/One extended call function
netci equ 6Bh ; [ohl] Net/One command interface interrupt,
; [ohl] used for the following functions:
nciwrit equ 0000h ; [ohl] Net/One write function
nciread equ 0100h ; [ohl] Net/One read function
ncistat equ 0700h ; [ohl] Net/One status function
ncicont equ 0600h ; [ohl] Net/One control function
ncibrk equ 02h ; [ohl] Net/One code for a break
ncidis equ 04h ; [ohl] Net/One code for disconnect
ncihld equ 06h ; [ohl] code for placing a connection on hold
bapiint equ 14h ; 3Com BAPI, interrupt (Bios replacment)
bapicon equ 0a0h ; 3Com BAPI, connect to port
bapidisc equ 0a1h ; 3Com BAPI, disconnect
bapiwrit equ 0a4h ; 3Com BAPI, write block
bapiread equ 0a5h ; 3Com BAPI, read block
bapibrk equ 0a6h ; 3Com BAPI, send short break
bapistat equ 0a7h ; 3Com BAPI, read status (# chars to be read)
bapihere equ 0afh ; 3Com BAPI, presence check
bapieecm equ 0b0h ; 3Com BAPI, enable/disable ECM char
bapiecm equ 0b1h ; 3Com BAPI, trap Enter Command Mode char
bapiping equ 0b2h ; KERMIT BAPI extension, Telnet, Ping host
bapito_3270 equ 0b3h ; KERMIT BAPI extension, byte to 3270
bapinaws equ 0b4h ; KERMIT BAPI extension, send NAWS update
;
telopen equ 0e0h ; TELAPI xtelopen a connection
telclose equ 0e1h ; xtelclose a connection
telread equ 0e2h ; xtelread char(s)
telwrite equ 0e3h ; xtelwrite chars
telioctl equ 0e4h ; xtelioctl, ioctl the port
telreset equ 0e5h ; xtelreset, reset the whole TELAPI package
telunload equ 0e6h ; xtelunload, unload TELAPI TSR
tellist equ 0e7h ; xtellist, list current sessions and status
telattach equ 0e8h ; xtelattach, session to COM port # 0..3
telportosn equ 0e9h ; xtelportosn, return session id for port
telunreac equ -51 ; network is unreachable
telinuse equ -56 ; socket already in use
teltmo equ -60 ; timeout on connection attempt
telrefuse equ -61 ; connection refused
teldwnhost equ -64 ; host is down
telunkhost equ -67 ; unknown host
telfull equ -301 ; all sessions are in use
; TELAPI messages and misc data
telmsg1 db cr,lf,'?Badly constructed Internet address: $'
telmsg2 db cr,lf,'?No connection. Status = -$'
telmsg51 db cr,lf,'?Network is unreachable$'
telmsg56 db cr,lf,'?Socket already in use$'
telmsg60 db cr,lf,'?Timeout on connection attempt$'
telmsg61 db cr,lf,'?Connection refused$'
telmsg64 db cr,lf,'?Host is down$'
telmsg67 db cr,lf,'?Unknown host$'
telmsg301 db cr,lf,'?All sessions are in use$'
telhostid db 2 dup (0) ; TELAPI Telnet internal host session ident
IAC equ 255 ; B&W TCP/IP Telnet Options codes
DONT equ 254
DO equ 253
WONT equ 252
WILL equ 251
SB equ 250
SE equ 240
TELOPT_ECHO equ 1
TELOPT_SGA equ 3
TELOPT_STATUS equ 5
TELOPT_TTYPE equ 24
TELOPT_NAWS equ 31
NTELOPTS equ 24
sgaflg db 0 ; B&W TCP/IP, supress go ahead flag
option1 db 0 ; B&W TCP/IP, Telnet Options byte1
option2 db 0 ; B&W TCP/IP, Telnet Options byte1
optstate db 0 ; B&W TCP/IP, Telnet Options state variable
bwtcpnam db 'TCP-IP10',0 ; [JRS] name of Beame & Whiteside TCP driver
bwhandle dw 0 ; [JRS] handle for Beame & Whiteside TCP driver
;
testalk equ 4 ; TES invoke interactive cmd interpreter
tesbwrite equ 6 ; TES block write
tesbread equ 7 ; TES block read
tesinstal equ 0a0h ; TES installation/status report
teslist equ 0a1h ; TES get list of sessions, with status
tesgets equ 0a2h ; TES get list of server names
tesnews equ 0a3h ; TES start a new session
tesholds equ 0a4h ; TES hold currently active connection
tesresume equ 0a5h ; TES resume a session (1..9)
tesdrop equ 0a6h ; TES drop a session
tesnexts equ 0a7h ; TES skip to next active session
tesexec equ 0a8h ; TES send string to cmd interpreter
tesport dw 0 ; TES low byte = intercepted port
tesquiet db 'ACTION NONE',0 ; TES Stop command prompting
tesses db 0 ; TES session number (1..9 is legal)
tesname db 50 dup (0) ; TES host name asciiz
teshelp db cr,lf,'?Host name or "*" to see available hosts'
db ' or press ENTER to resume a connection$'
tesnlist db cr,lf,' Active TES hosts:$'
tesnhost db cr,lf,'?No existing connection.'
db ' Please select a host with SET PORT TES host$'
latkind db 0 ; non-zero if using TES or Meridian LAT
DEC_LAT equ 0 ; for latkind
MTC_LAT equ 2 ; for latkind
TES_LAT equ 1 ; for latkind
;; pcnet values: 0 no network available at all
;; 1 network board reports itself as present
;; 2 and session is in progress
;; extrn byte pcnet is defined in msster.
; NetBios (StarGROUP and Opennet)
port_nb prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,send,receive,nbclose>
; Ungermann Bass, 3ComBAPI, TELAPI
port_ub prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,ubsend,ubrecv,ubclose>
; DECnet LAT and CTERM and TES-LAT
port_dec prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,decsnd,decrcv,decclose>
; TES
port_tes prtinfo <-1,0,defpar,3,0,defhand,1,floxon,0,0,tessnd,tesrcv,tesclose>
endif ; no_network
scbst struc ; Session (Network) Control Block [PCnet comp]
scb_cmd db 0 ; command code for Netbios Int 5ch
scb_err db 0 ; error return or request is pending
scb_vcid db 0 ; virtual circuit ident number
scb_num db 0 ; local name-number
scb_baddr dw 0 ; buffer address, offset
dw data ; and segment
scb_length dw 0 ; length of buffer data
scb_rname db '* ' ; remote name, 16 chars space
scb_lname db ' ' ; local name filled
db 0 ; Receive timeout (0.5 sec units), want 0
db 0 ; Send timeout (0.5 sec units), want 0
scb_post dw 0 ; interrupt driven post address, offset
dw code ; and segment
db 0 ; LAN_num (adapter #), set to zero for STARLAN
scb_done db 0 ; command complete status
; the 14 bytes below are normally 'reserved'
; STARLAN uses 5 for long/special call names
; together with STARLAN specific Int 5bh
scb_vrname dw 0,0 ; Variable length call name ptr offset,segment
scb_vrlen db 0 ; length of vrname
db 9 dup (0) ; reserved
scbst ends ; 64 bytes overall
ifndef no_network
rcv scbst <,,,,rcvbuf,,length rcvbuf,,,,,rpost>; declare scb for rcvr
else
rcv scbst <,,,,rcvbuf,,length rcvbuf,,,,,> ; declare scb for rcvr
endif ; no_network
ifndef no_network
xmt scbst <,,,,xmtbuf,,length xmtbuf,,,,,spost>; for xmtr
lsn scbst <,,,,xmtbuf,,length xmtbuf,,,,,lpost>; for server listen
can scbst <> ; for cancels
; DECnet material
decint equ 69h ; CTERM interrupt
dpresent equ 100h ; CTERM Installation check
dsend equ 101h ; CTERM send byte
dread equ 102h ; CTERM read byte
dcstat equ 103h ; CTERM status
ddstat equ 104h ; CTERM Decnet status
dopen equ 105h ; CTERM open session
dclose equ 106h ; CTERM close session
dgetscb equ 10ah ; CTERM get SCB size
latint equ 6ah ; LAT interrupt
latsend equ 1 ; LAT send byte
latread equ 2 ; LAT read byte
latstat equ 3 ; LAT status
latsendb equ 4 ; LAT send block (v4)
latreadb equ 5 ; LAT read block (v4)
latinfo equ 6 ; LAT get miscellaneous information
latsrv equ 0d500h ; LAT get next service name
latopen equ 0d0ffh ; LAT open
latclose equ 0d000h ; LAT close
latbreak equ 0d100h ; LAT send a BREAK
latscbget equ 0d800h ; LAT get SCB interior to LAT
latscbfree equ 0d801h ; LAT free SCB interior to LAT
latcpyems equ 0d900h ; LAT copy to/from SCB in EMS or not
decneth dw 0 ; CTERM session handle
decseg dw 0 ; segment of CTERM SCB memory block
lathand dw 0 ; LAT session handle, high byte = 0ffh
latseg dw 0 ; LAT SCB seg in our memory
latversion db 4 ; LAT major version number
latscbptr dd 0,0,0 ; LAT, pointer to SCB
lcbst struc ; LAT control block structure V4
service db 17 dup (0) ; 0 service (number is offset)
db 10 dup (0) ; 17 node, for future use
lat_pwd dd 0 ; 27 password buffer ptr
pwd_len db 0 ; 31 length of the buffer
db 22 dup (0) ; 32 reserved
stopped dd 0 ; 54 session stopped post routine addr
overflow dd 0 ; 58 service table overflow post addr
xnotify dd 0 ; 62 transmit post routine addr
rnotify dd 0 ; 66 receive post routine addr
sstatus dw 0 ; 70 session status
db 270 dup (0) ; 72 reserved
slotqty db 2 ; 342 number receive data slots
slotused db 0 ; 343 number occupied slots
slotnr db 0 ; 344 index of next rcv slot to use
slotcur db 0 ; 345 index of current rcv slot
slotptr dw 0 ; 346 ptr to first received char
slottbl dw 0 ; 348 ptrs to bufs for slot 1
dw 0 ; 350 and for slot 2
slotbf1 db 259 dup (0) ; 352 first receive buffer
slotbf2 db 259 dup (0) ; 611 second receive buffer
lcbst ends ; total of 870 bytes
latservice db 17 dup (0) ; LAT host name
latpwd db 16 dup (0),0 ; LAT password, terminator
decmsg1 db cr,lf,'Cannot create DECnet session.$'
decmsg3 db ' DECnet Error $'
decmsg4 db cr,lf,' CTERM ready$'
decmsg5 db cr,lf,' LAT ready$'
decmsg6 db cr,lf,' Unable to allocate LAT SCB, trying CTERM$'
; end of DECnet and TES-LAT
pcnet db 0 ; Network is functioning
nambuf db 65 dup (0) ; network long name storage (STARLAN)
newnambuf db 0 ; non-zero if new entry into namebuf above
internet db 4 dup (0) ; TELAPI Internet address, binary
telses dw 0 ; TELAPI session number
telport dw 23 ; TELAPI Telnet port (defaults to 23)
sposted db 0 ; send interlock, 0 if no send posted
rposted db 0 ; rcv interlock, 0 if no receive posted
lposted db 0 ; listen outstanding (if non-zero)
netdbfr db 0 ; non-zero if net board is double buffered
lnamestat db 0 ; status of local name 0 = default,
; 1 = specified by user, 2 = locked in
deflname db 'mskermit.K ' ; default local name, 16 bytes
ivt1str db 'iVT1',0 ; FGR - OpenNet VT handshake string
inettyp db 0 ; FGR - network type 'N' or 'O'
nsbrk dw 0 ; net can send Break
starlan db 0 ; non-zero if StarLAN net
chkmsg1 db cr,lf,'?Cannot construct a local Kermit name, error = $'
setnbad db cr,lf,'?Local Kermit NetBIOS name is already fixed.$'
chkmsg2 db cr,lf,lf,' Name $'
chkmsg3 db ' is already in use. Please enter another of',cr,lf
setnbhlp db ' 1 - 14 letters or numbers (or nothing to quit): $'
netmsg1 db cr,lf,' Checking if our node name is unique ...$'
netmsg2 db cr,lf,' The network is active, our name is $'
netmsg3 db cr,lf,' NetBios local name: $'
netmsg4 db ' Remote host: $'
netmsg5 db cr,lf,' DECnet host: $'
netmsg6 db cr,lf,' TELAPI Internet host: $'
netmsg6a db ' port: $'
netmsg7 db cr,lf,' TES host name: $'
netmsg9 db cr,lf,' SuperLAT name: $'
netmsg8 db cr,lf,' EBIOS server port name: $'
nonetmsg db cr,lf,'?The network is not available$'
noname db cr,lf,'?No name exists for the remote host.$'
dnetsrv db cr,lf,' Available LAT service names:',cr,lf,'$'
ngodset db cr,lf,' Connecting to network node: $'
nbadset db bell,cr,lf,'?Cannot reach network node: $'
recmsg db cr,lf,'?Network receive failed, status = $'
sndmsg db cr,lf,'?Network send failed, status = $'
naskpmt db cr,lf,' A network session is active.',cr,lf
db ' Enter RESUME to resume it or NEW to start a new session:',0
nettab db 2
mkeyw 'New',0
mkeyw 'Resume',1
acnop equ 80h ; ACSI nop
; second byte: null (ignored)
acenable equ 81h ; ACSI raise modem leads
; second byte: DTR=01h, RTS=02h
acdisable equ 82h ; ACSI drop all modem leads
; second byte: null (ignored)
acbreak equ 83h ; ACSI send a BREAK
; second byte: null (ignored)
acsetmode equ 84h ; ACSI set port Mode (speed etc)
; second byte: speed=3bits, parity=2bits, stopbits=1bit, databits=2bits
acmodem equ 85h ; ACSI return modem leads state
; second byte: DCD=80h, RI=40h, DSR=20h, CTS=10h
acreqmodem equ 86h ; ACSI request modem leads state
; second byte: DCD=80h, RI=40h, DSR=20h, CTS=10h
acdelay equ 87h ; ACSI pause transmission
; second byte: delay in hundreths of second
acpace equ 88h ; ACSI set flow control or pacing
; second byte: direction send=10h, recv=20h; if pacing send=1, recv=2
acsetxon equ 89h ; ACSI set XON pacing character
; second byte: char to represent resume transmission
acsetxoff equ 8ah ; ACSI set XOFF pacing character
; second byte: char to represent cease transmission
; ACSI general read character status: BREAK detected=10h, framing error=08h,
; parity error=04h, overrun=02h
ebbufset equ 0ffh ; EBIOS set buf mode (1=send, 2=rcv)
ebbufcnt equ 0fdh ; EBIOS get buf count (1=send, 2=rcv)
ebpace equ 0feh ; EBIOS set pacing mode (80h=send)
ebrcv equ 0fch ; EBIOS receive, no wait
ebsend equ 1 ; EBIOS send a char
ebmodem equ 0fbh ; EBIOS set modem leads
ebbreak equ 0fah ; EBIOS send a BREAK
ebcontrol equ 0f9h ; EBIOS regain control
ebredir equ 0f6h ; EBIOS do port redirection
ebquery equ 0f5h ; EBIOS get redirection info
ebpresent equ 0f4h ; EBIOS presence check
ebport dw 0 ; EBIOS equivalent serial port 0..3
ebcoms db 0,0 ; adapter (port), path (80h=network)
db 16 dup (0) ; Call name (host)
db 16 dup (0) ; Listen name (null)
db 16 dup (0) ; local name (null = use lan adapter)
db 0 ; unique name (1 = group name)
ebmsg2 db cr,lf,'?No server port name is known,'
db ' reenter the command with a name.$'
ebmsg3 db cr,lf,'?Unable to contact that port. Error code=$'
ebiostab db 4 ; EBIOS table of local port names
mkeyw '1',1
mkeyw '2',2
mkeyw '3',3
mkeyw '4',4
ifndef no_tcp
tcpadrst db cr,lf,' tcp/ip address: $' ; TCP/IP status msgs
tcpsubst db cr,lf,' tcp/ip subnetmask: $'
tcpdomst db cr,lf,' tcp/ip domain: $'
tcpgatest db cr,lf,' tcp/ip gateway: $'
tcppnsst db cr,lf,' tcp/ip primary-nameserver: $'
tcpsnsst db cr,lf,' tcp/ip secondary-nameserver: $'
tcpbcstst db cr,lf,' tcp/ip broadcast: $'
tcphostst db cr,lf,' tcp/ip host: $'
tcpportst db cr,lf,' tcp/ip port: $'
tcpdebst db cr,lf,' tcp/ip debug-Options: $'
tcpbinst db cr,lf,' telnet mode: $'
tcppdintst db ', Packet-Driver-interrupt: \x$'
tcppdnul db ' (search for it)$'
tcpodi db ' using ODI interface$'
tcpttyst db cr,lf,' telnet term-type: $'
tcpttynul db '(report real terminal type)',0 ; ASCIIZ
tcpnlst db cr,lf,' telnet newline-mode: $'
tcpnlmsg0 db 'off (CR->CR NUL)$'
tcpnlmsg1 db 'on (CR->CR LF)$'
tcpnlmsg2 db 'raw (CR->CR)$'
tcpdeboff db 'off$'
tcpdebon db 'on$'
tcpmodemsg0 db 'NVT-ASCII$'
tcpmodemsg1 db 'Binary$'
tcpbtpbost db ' from BOOTP host: $'
tcpbtpdhst db ' from DHCP host: $'
tcpbtprast db ' from RARP host: $'
tcpmssst db cr,lf,' tcp/ip mss: $'
endif ; no_tcp
badport db cr,lf,'?Port 25 is forbidden, sorry. Using 23 for Telnet.$'
maxsessions equ 6 ; max sessions, also in msntnd.c
seslist db maxsessions dup (-1) ; list of Telnet session idents, -1=dead
seshostlen equ 61 ; length of host name, asciiz
sesname db maxsessions*seshostlen dup (0) ; host names, asciiz.
sesport dw maxsessions dup (23) ; Telnet ports
sestime db maxsessions * 4 dup (0) ; start time dd, hh, mm, ss
sescur dw -1 ; Current session (0..5)
sesheader db cr,lf,' status session port hostname$'
sesinact db cr,lf,' inactive $'
sesactive db cr,lf,' active $'
curmsg db cr,lf,' current > $'
curinact db cr,lf,' inactive > $'
sesnone db cr,lf,' Error, all sessions are in use$'
sesnohost db cr,lf,' Oops, no host name is available$'
seshelp db cr,lf,lf,' choices R return to active session'
db cr,lf,' 1..6 pick a new or existing session'
db cr,lf,' N start a new session (default)'
db cr,lf,' Q quit this command'
db cr,lf
db cr,lf,'Choice> $'
endif ; no_network
data ends
data1 segment
ifndef no_network
nethlp db cr,lf,' node name of remote system,'
db cr,lf,' or press ENTER to use current name,'
db cr,lf,' or press ENTER for server mode (NetBios only).$'
dnethlp db cr,lf,' node name of remote system,'
db cr,lf,' or press ENTER to use current name,'
db cr,lf,' or * to see a list of LAT service names.$'
nethlp2 db cr,lf,' Optional LAT password, if using a LAT connection$'
ebhlp db 'Name of server port$'
setnbhlp2 db ' 1 - 14 letters or numbers (or nothing to quit): $'
telhlp db 'Internet address nnn.nnn.nnn.nnn$'
telhlp2 db 'Optional TCP port (default is 23)$'
ifndef no_tcp
tcphlp db cr,lf,' Host Internet name machine.domain or'
db ' Internet address nnn.nnn.nnn.nnn'
db cr,lf,' or * to become a Telnet server.'
db cr,lf,' Optional TCP port number and NEW or RESUME'
db ' may follow the host name.$'
tcpporthlp db cr,lf,' TCP port on host, 23 is Telnet, or'
tcpnewhlp db cr,lf,' NEW session or RESUME current session$'
endif ; no_tcp
endif ; no_network
fossilhlp db cr,lf,' Fossil port, 1..99. No Fossil checking is done!$'
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,'$'
data1 ends
code1 segment
assume cs:code1
extrn iseof:far, tolowr:far, strcat:far
extern atsclr:near, setpos:near, setatch:near
extrn strcpy:far, strlen:far, prtasz:far, prtscr:far
extrn valout:far, domath:far, decout:far
ifndef no_tcp
ifndef no_terminal
extern termswapin:far, termswapdel:far, termswapout:far
endif ; no_terminal
endif ; no_tcp
fatsclr proc far
call atsclr
ret
fatsclr endp
fsetatch proc far
call setatch
ret
fsetatch endp
fsetpos proc far
call setpos
ret
fsetpos endp
code1 ends
code segment
extrn comnd:near, prompt:near, dopar:near, lclyini:near
extrn crun:near
ifndef no_terminal
extrn kbsusp:near, kbrest:near ; in msuibm.asm
endif ; no_terminal
assume cs:code, ds:data, es:nothing
foutchr proc far
call outchr
ret
foutchr endp
fdopar proc far
call dopar
ret
fdopar endp
; local initialization
lclini proc near
call pcwtst ; calibrate software timer
call pcwtst
mov flags.comflg,1 ; assume COM1 for communications port
call model ; get model of IBM machine
mov lclsusp,offset suspend ; call this when suspending to DOS
mov lclrest,offset restore ; call this when returning from DOS
mov lclexit,offset finexit ; call this when exiting Kermit
call getcodep ; get Code Page ident
call lclyini ; let other modules initialize too...
ret
lclini endp
; Call these routines when suspending Kermit to go to DOS
suspend proc near
ifndef no_terminal
call kbsusp ; DEC LK250 keyboard, set back to DOS mode
endif ; no_terminal
cmp flags.comflg,'t'; doing TCP?
je suspen1 ; e = yes, don't touch port
cmp portin,0 ; port initialized yet?
jle suspen1 ; l = no, e = yes but inactive
call ihosts ; suspend the host
mov ax,20 ; wait 20 millisec for port to finish
call pcwait
call serrst
suspen1:ret
suspend endp
; Call these routines when returning to Kermit from DOS
restore proc near
call getcodep ; reset Code Page ident
ifndef no_terminal
call kbrest ; DEC LK250 keyboard, set back to DEC mode
endif ; no_terminal
cmp flags.comflg,'t'; doing TCP?
je restor1 ; e = yes, don't touch port
cmp portin,0 ; port initialized yet?
jl restor1 ; l = no
call serini ; reinit serial port
call ihostr ; resume the host
restor1:ret
restore endp
; Call these routines when doing final exit of Kermit
finexit proc near
cmp flags.carrier,0 ; be concerned about CD?
je finex4 ; e = no
call testcd ; update cardet byte
test cardet,80h ; is carrier detect still active?
jnz finex3 ; nz = yes
finex4: cmp nettype,0 ; any network connections open?
je finex2 ; e = no, but go through the motions anyway
finex3: cmp flags.exitwarn,0 ; warn about active session?
je finex2 ; e = no, just kill the sessions
mov dx,offset clomsg ; say connection going, ask for permission
call prompt
mov dx,offset clotab ; table of choices
xor bx,bx ; help
mov ah,cmkey ; get keyword
call comnd
jc finex5 ; c = failure
push bx
mov ah,cmeol
call comnd
pop bx
jnc finex1 ; nc = got good response
finex5: ret ; return carry set to say don't close
finex1: or bx,bx ; ok to close
jz finex2 ; e = yes
stc ; carry set to say don't close
ret
finex2: call serrst ; reset serial port
ifndef no_network
call netclose ; close network connections
endif ; no_network
ifndef no_terminal
call kbsusp ; DEC LK250 keyboard, set back to DOS mode
endif ; no_terminal
clc ; return with permission to exit
ret
finexit endp
; The IBM PC's.
model proc near
mov isps2,0 ; PS/2 present indicator
push es
push ax ; get IBM model code
mov al,byte ptr es:[0fffeh] ; get model id byte
mov ah,0ch ; AT and PS/2 configuration call
xor al,al
int 15h ; IBM Bios
jc model4 ; c = no information
cmp word ptr es:[bx+2],040fch ; PS/2 model 50?
je model3 ; e = yes
cmp word ptr es:[bx+2],050fch ; PS/2 model 60?
je model3 ; e = yes
cmp byte ptr es:[bx+2],0f8h ; PS/2 model 80?
jne model4 ; ne = no
model3: mov isps2,1 ; say real PS/2 for IRQ setting
model4:
;;; [HF] 940130 The following section checks Japanese PS/55 mode
;;; [HF] 940130 moved from dvtest in MSYIBM.ASM
mov isps55,0 ; [HF] 940130 assume not PS/55
push ds
mov ax,ds ; preset es:si to start of data seg
mov es,ax ; as saftey factor after test
xor si,si
mov ax,6300h ; get Double Byte Char Set Lead Table
int dos ; returns ptr in ds:si
mov bx,ds ; cannot trust al as return status
mov es,bx
pop ds
mov ax,ds ; current DS
cmp ax,bx ; same seg?
je modelx ; e = yes, test failed
cmp word ptr es:[si],0 ; see if both bytes are also zeros
je modelx ; z = test failed
mov isps55,1 ; [HF] say Japanese PS/55 is active
mov ax,1402h ; [HF]940206 check the modeline status
int 16h ; [HF]940206 Keyboard Bios
mov ps55mod,al ; [HF]940206 save it in current status
mov byte ptr ps55mod+1,al ; [HF]940206 and in startup status
modelx: pop ax
pop es
ret
model endp
; Get the currently active Code Page ident into flags.chrset. User defined
; table overrides DOS report.
getcodep proc near
cmp flags.chrset,1 ; user-defined table in use?
je getcod1 ; e = yes
cmp flags.chrset,866 ; forced CP866 in use?
je getcod1 ; e = yes
mov flags.chrset,437 ; find default global char set
cmp dosnum,0300h+30 ; DOS version 3.30 or higher?
jb getcod1 ; b = no, no Code Pages
mov ax,6601h ; get global Code Page
int dos ; bx=active Code Page, dx=boot CP
jc getcod1
mov flags.chrset,bx ; setup default SET FILE CHAR SET
mov vtcpage,bx ; set terminal Code Page too
getcod1:ret
getcodep 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
code ends
code1 segment
assume cs:code1
ifndef no_tcp
ftcpstats proc far ; TCP/IP status display
mov ah,prstr
mov dx,offset tcpadrst
int dos
mov dx,offset tcpaddress ; tcpaddress string
call prtasz
mov bx,offset tcpbtpserver
cmp byte ptr [bx],0 ; bootp etc host?
je ftcpst4 ; e = no
mov dx,offset tcpbtpbost ; show BOOTP title
cmp tcpbtpkind,1 ; did BOOTP?
je ftcpst4a ; e = yes
mov dx,offset tcpbtpdhst ; show DHCP title
cmp tcpbtpkind,3 ; did DHCP?
je ftcpst4a ; e = yes
mov dx,offset tcpbtprast ; show RARP title
ftcpst4a:int dos
mov dx,bx ; show boot host IP
call prtasz
ftcpst4:mov dx,offset tcpsubst
int dos
mov dx,offset tcpsubnet ; tcp subnetmask string
call prtasz
mov dx,offset tcpdomst
int dos
mov dx,offset tcpdomain ; tcp domain string
call prtasz
mov dx,offset tcpgatest
int dos
mov dx,offset tcpgateway ; tcp gateway string
call prtasz
mov dx,offset tcppnsst
int dos
mov dx,offset tcpprimens ; tcp primary nameserver
call prtasz
mov dx,offset tcpsnsst
int dos
mov dx,offset tcpsecondns ; tcp secondary nameserver
call prtasz
mov dx,offset tcpbcstst
int dos
mov dx,offset tcpbcast ; tcp broadcast address
call prtasz
mov dx,offset tcpportst
int dos
push ax
push bx
push cx
mov bx,offset tcpport ; tcp port
mov ax,[bx]
call decout
mov ax,tcppdint ; Packet Driver interrupt
cmp ax,'DO' ; using ODI?
jne ftcpst3 ; ne = no
mov ah,prstr
mov dx,offset tcpodi ; say using ODI interface
int dos
jmp short ftcpst1
ftcpst3:push ax ; save value
mov ah,prstr
mov dx,offset tcppdintst
int dos
pop ax
mov cx,16
push ax
call valout ; show value as hex
pop ax
or ax,ax ; null?
jnz ftcpst1 ; nz = no, just show value
mov ah,prstr
mov dx,offset tcppdnul ; show search msg
int dos
ftcpst1:pop cx
pop bx
pop ax
mov dx,offset tcpttyst
int dos
mov dx,offset tcpttbuf ; tcp term-type override
push bx
mov bx,dx
cmp byte ptr [bx],0
jne ftcpst2
mov dx,offset tcpttynul ; alternate msg
ftcpst2:pop bx
call prtasz
mov dx,offset tcpnlst ; newline mode msg
int dos
push bx
mov bl,tcpnewline ; tcpnewline value of 0 (off) or 1
mov dx,offset tcpnlmsg1 ; assume on
cmp bl,1 ; on?
pop bx
je ftcpst5 ; e = yes
mov dx,offset tcpnlmsg0 ; assume off
jb ftcpst5 ; b = correct
mov dx,offset tcpnlmsg2 ; then use raw
ftcpst5:
mov ah,prstr
int dos
mov dx,offset tcpbinst ; debug-option
int dos
push bx
mov bl,tcpmode ; tcpmode
mov dx,offset tcpmodemsg0 ; assume NVT-ASCII
or bl,bl ; NVT?
pop bx
jz ftcpst6 ; z = yes, NVT
mov dx,offset tcpmodemsg1 ; say BINARY
ftcpst6:mov ah,prstr
int dos
mov dx,offset tcpmssst ; MSS
int dos
mov ax,tcpmss
call decout ; show value
mov ah,prstr
mov dx,offset tcpdebst ; debug-option
int dos
push bx
mov bl,tcpdebug ; offset of tcpdebug
mov dx,offset tcpdeboff ; assume off
or bl,bl ; off?
pop bx
jz ftcpst7 ; z = yes
mov dx,offset tcpdebon ; say on
ftcpst7:mov ah,prstr
int dos
mov dx,offset tcphostst
int dos
mov dx,offset tcphost ; tcp host IP ident string
call prtasz
ret
ftcpstats endp
endif ; no_tcp
code1 ends
code segment
assume cs:code
; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdmhand, the modem line status register.
shomodem proc near
mov ah,cmeol ; get a confirm
call comnd
jnc shomd1a ; nc = success
ret
shomd1a:cmp flags.comflg,'F' ; Fossil?
je shomd1b ; e = yes
cmp flags.comflg,'4' ; hardware or Bios?
ja shomd3c ; a = no, show nothing
shomd1b:mov dx,offset msmsg7 ; no modem status for network
call getmodem ; get modem status
mov mdmhand,al
mov ah,prstr
mov dx,offset msmsg1 ; modem ready msg
test mdmhand,20h ; 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 mdmhand,80h ; CD asserted?
jz shomd2 ; z = no
mov dx,offset msmsg4 ; say not asserted
shomd2: int dos
mov dx,offset msmsg20 ; CD sensitive
cmp flags.carrier,0 ; be sensitive?
jne shomd2a ; ne = yes
mov dx,offset msmsg21 ; CD insenstive
shomd2a:int dos
mov dx,offset msmsg5 ; CTS asserted msg
test mdmhand,10h ; CTS asserted?
jz shomd3 ; z = no
mov dx,offset msmsg6 ; say not asserted
shomd3: mov ah,prstr
int dos
mov al,flags.comflg
cmp al,'1' ; UART?
jae shomd3c ; ae = no
add al,'0' ; COMnumber
mov msmsg8+7,al ; stuff in msg
mov ah,prstr
mov dx,offset msmsg8 ; show port base address
int dos
mov ax,modem.mddat ; port address
mov cx,16 ; in hex
call valout
mov ah,prstr
mov dx,offset msmsg9 ; and IRQ
int dos
mov ax,modem.mdintv ; interrupt vector
mov cl,al
and ax,7 ; lower three bits of IRQ
cmp cl,60h ; using cascaded 8259?
jb shomd3a ; b = no
add ax,8 ; say IRQ 8..15
shomd3a:call decout ; output as decimal
cmp modem.mdfifo,0 ; UART FIFO active?
je shomd3b ; e = no
mov dx,offset msmsg10 ; FIFO msg
mov ah,prstr
int dos
shomd3b:mov bx,portval
mov al,[bx].stopbits ; number of stop bits (1 or 2)
add al,'0'
mov msmsg14+2,al ; change the visible number
mov dx,offset msmsg14
mov ah,prstr
int dos
clc
ret
shomd3c:cmp flags.comflg,'F' ; Fossil?
jne shomd4 ; ne = no
mov ah,prstr
mov dx,offset msmsg11
int dos
mov ax,fossil_port
inc ax ; count from 1
xor dx,dx
mov cx,10 ; decimal
call valout
mov ah,prstr
mov dx,offset msmsg12
cmp fossilflag,0 ; do not close on done?
je shomd3d ; e = yes
mov dx,offset msmsg13
shomd3d:int dos
shomd4: clc
ret
shomodem endp
; Show status of network connections
shownet proc near
mov ah,cmeol ; get a confirm
call comnd
jnc shonet0 ; nc = success
ret
shonet0:
ifndef no_network
ifndef no_tcp
call ftcpstats ; call TCP/IP FAR worker
endif ; no_tcp
mov dx,offset netmsg3 ; local name
mov ah,prstr
int dos
mov cx,16
mov di,offset deflname ; default Netbios name
call prtscr
cmp rcv.scb_lname,' ' ; have NetBios name yet?
jbe shonet1 ; be = no, skip this part
mov ah,prstr
mov dx,offset netmsg4 ; remote name
int dos
mov cx,16
mov di,offset rcv.scb_rname
call prtscr
shonet1:cmp latservice,0 ; DECnet name available?
je shonet3 ; e = no
mov ah,prstr
mov dx,offset netmsg5
cmp latkind,DEC_LAT ; DEC_LAT?
je shonet2 ; e = yes
mov dx,offset netmsg7 ; TES heading
cmp latkind,TES_LAT ; TES_LAT?
je shonet2 ; e = yes
mov dx,offset netmsg9 ; Meridian SuperLAT
shonet2:int dos
mov dx,offset latservice ; network host name, asciiz
call prtasz
shonet3:cmp word ptr internet,0 ; have TELAPI Internet address?
je shonet6 ; e = no
mov ah,prstr
mov dx,offset netmsg6
int dos
xor bx,bx ; subscript
mov cx,4 ; four fields
shonet4:mov al,internet[bx] ; binary internet address
xor ah,ah
call decout
cmp cx,1 ; doing last field?
je shonet5 ; e = yes, no dot
mov dl,'.'
mov ah,conout
int dos
shonet5:inc bx
loop shonet4
mov dx,offset netmsg6a ; port:
mov ah,prstr
int dos
mov ax,telport ; port
call decout
shonet6:cmp tesname,0 ; have TES name?
je shonet7 ; e = no
mov ah,prstr
mov dx,offset netmsg7
int dos
mov dx,offset tesname ; node name
call prtasz ; show, asciiz
clc
ret
shonet7:cmp ebcoms+2,0 ; have an EBIOS name?
je shonet8 ; e = no
mov ah,prstr
mov dx,offset netmsg8
int dos
mov cx,16
mov di,offset ebcoms+2 ; host port, 16 chars space filled
call prtscr
shonet8:
endif ; no_network
clc
ret
shownet endp
; Get modem status and set global byte mdmhand. Preserve all registers.
getmodem proc near ; gets modem status upon request
cmp portin,1 ; port active?
je getmod1 ; e = yes
mov bl,flags.comflg ; pass current port ident
cmp bl,'4' ; above UART and Bios?
ja getmod1 ; a = yes, do not start the port
call comstrt ; do SET PORT command now
jnc getmod1 ; nc = success
ret ; failed to set port
getmod1:xor al,al ; assume nothing is on
cmp flags.comflg,'1' ; UART?
jae getmod2 ; ae = no
cmp flags.comflg,0 ; null port?
je getmodx ; e = yes, no status
call serini
mov dx,modem.mdstat ; hardware, line status reg
inc dx ; modem status reg
in al,dx
push ax
call serrst
pop ax
jmp short getmodx
getmod2:cmp flags.comflg,'4' ; above Bios? (networks)
ja getmod3 ; a = yes, no status
mov ah,3 ; ask Bios for modem status into al
push dx
xor dh,dh
mov dl,flags.comflg ; get port id
sub dl,'1' ; remove ascii bias (BIOS1 -> 0)
int rs232
pop dx
jmp short getmodx
getmod3:
ifndef no_network
cmp flags.comflg,'E' ; IBM EBIOS?
jne getmodx ; ne = no
mov ah,3 ; get Bios style modem status
push dx
mov dx,ebport ; current EBIOS port
int rs232
pop dx
endif ; no_network
getmodx:xor ah,ah ; return status in al
clc
ret
getmodem endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cmp repflg,0 ; REPLAY?
je clrbuf1 ; e = no
ret
clrbuf1:call prtchr ; read from active comms port
jnc clrbuf1 ; nc = got a char, continue til none
mov ax,10 ; wait 10 ms
call pcwait
call prtchr ; read from active comms port
jnc clrbuf1 ; nc = got a char, continue til none
clc
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
; Upgraded for Topview compatibility.
CLEARL PROC NEAR
push ax
push bx
push dx
mov ah,3 ; Clear to end of line
xor bh,bh
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 fatsclr ; 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.
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)
cmp isps55,0 ; [HF] Japanese PS/55?
je cmblnk1 ; [HF] e = no
cmp ps55mod,0 ; [HF] can access modeline ?
je cmblnk2 ; [HF] e = no, system uses it. Do not access
cmblnk1:inc bh ; include status line
cmblnk2:call fatsclr ; do Topview compatible clear, in msyibm
pop bx
pop ax
ret
CMBLNK ENDP
; Locate: homes the cursor. Returns normally.
LOCATE PROC NEAR
xor dx,dx ; 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
xor bh,bh ; page 0
int video
pop bx
pop ax
ret
POSCUR ENDP
; Delete a character from the screen. This works by printing
; backspaces and spaces.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase character
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
BEEP PROC NEAR
mov timeract,1 ; say timer chip is being used here
push ax
push cx
mov al,10110110B ; Gen a short beep (long one losses data.)
out timercmd,al ; set Timer to mode 3
mov ax,1512 ; divisor, for frequency
out timer2data,al ; send low byte first
mov al,ah
out timer2data,al
in al,ppi_port ; get 8255 Port B setting
or al,3 ; turn on speaker and timer
out ppi_port,al ; start speaker and timer
push ax
mov ax,40 ; 40 millisecond beep, calibrated time
call pcwait
pop ax
in al,ppi_port
and al,0fch ; turn off speaker and timer
out ppi_port,al
pop cx
pop ax
mov timeract,0 ; say timer chip is no longer in use here
clc
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
push si
mov si,dx ; preserve message
mov bl,scbattr ; screen attributes
push bx ; save scbattr
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 scbattr,bl
call clrmod ; clear mode line to inverse video
cmp isps55,0 ; [HF]940209 Japanese PS/55?
je putmo3 ; [HF]940209 e = no
push ax ; [HF]940209
mov ax,1401h ; [HF]940209 disable system modeline
mov ps55mod,al ; [HF]940209 remember it
int 16h ; [HF]940209
pop ax ; [HF]940209
putmo3: mov dx,low_rgt ; lower right corner
inc dh ; of status line
xor dl,dl ; start on left
mov ah,scbattr ; inverse video attribute
cld
putmo1: lodsb ; get a byte
cmp al,'$' ; end of string?
je putmo2
call fsetatch ; write char and attribute
inc dl ; increment for next write
cmp dl,crt_cols ; beyond physical right border?
jb putmo1 ; b = no
putmo2: pop bx
mov scbattr,bl
pop si
pop dx
pop cx
pop bx
pop ax
ret
putmod endp
; clear the mode line written by putmod.
clrmod proc near
cmp isps55,0 ; [HF]940206 is Japanese PS/55?
je clrmod1 ; [HF]940206 e = no, skip next proc.
cmp ps55mod,0 ; [HF]940206 can we use modeline?
jne clrmod1 ; [HF]940206 ne = yes, keep going
push ax ; [HF]940206 no, change the status
mov ax,1401h ; [HF]940208 access to modeline
mov ps55mod,al ; [HF]940208 change the status
int 16h ; [HF]940208
pop ax ; [HF]940208
clrmod1:push ax ; save regs
push bx
mov bx,low_rgt ; ending loc is lower right corner
inc bh ; of status line
mov ah,bh
xor al,al ; column zero
call fatsclr ; clear this region
cmp isps55,0 ; [HF]940206 is Japanese PS/55?
je clrmod2 ; [HF]940206 e = no
mov ah,14h ; [HF]940206
mov al,byte ptr ps55mod+1 ; [HF]940206 return to start value
mov ps55mod,al ; [HF]940206
int 16h ; [HF]940206
clrmod2: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.
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
xor bh,bh ; 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 short puthl1 ; and keep looping
puthl2: or al,al ; end of string?
jnz puthl1 ; nz = 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,bl ; inverse video
int video
call locate ; home cursor
xor bh,bh
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
or al,al ; end of string?
jz puthl4 ; z = 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 short puth23 ; move cursor there
puth21: cmp al,cr ; carriage return?
jne puth22 ; ne = no
xor dl,dl ; set to column zero
jmp short 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 short puthl3 ; and keep going
puthl4: mov dh,byte ptr low_rgt+1 ; go to last line
inc dh
cmp isps55,0 ; [HF]940211 Japanese PS/55?
je puthl5 ; [HF]940211 e = no
cmp ps55mod,0 ; [HF]940211 system uses bottom line?
jne puthl5 ; [HF]940211 ne = no
dec dh ; [HF]940211 do not touch bottom line
puthl5: xor dl,dl
call poscur ; position cursor
pop si
pop dx
pop cx
pop bx
ret
puthlp endp
; set the current port.
; Note: serial port addresses are found by looking in memory at 40:00h and
; following three words for COM1..4, resp. All UARTS are assumed to follow
; std IBM addresses relative to 03f8h for COM1, and actual address are offset
; from value found in segment 40h. Global byte flags.comflg is 1,2,3,4 for
; COM1..4, and is 'N' for NetBios, etc.
; 'O' is for Intel Opennet Network (FGR)
; If address 02f8h is found in 40:00h then name COM1 is retained but COM2
; addressing is used to access the UART and a notice is displayed. IRQ 3
; or IRQ 4 is sensed automatically for any COMx port.
COMS PROC NEAR
mov dx,offset comptab ; table of legal comms ports
xor bx,bx ; no extra help text
mov ah,cmkey ; parse key word
call comnd
jnc coms0a ; nc = success
ret ; failure
coms0a: cmp bl,'4' ; networks?
ja coms0b ; a = yes
mov ah,cmeol ; non-network
push bx
call comnd ; get a confirm
pop bx
jnc coms0b ; nc = success
ret ; failure
coms0b: mov reset_clock,1 ; reset elapsed time clock
COMSTRT:mov temp,bx ; port ident is in BL
cmp bl,'F' ; Fossil?
jne comst12 ; ne = no
jmp comsf
comst12:
ifndef no_network
cmp bl,'N' ; NetBios network?
jne comst2a ; ne = no
jmp comsn ; yes, get another item for networks
comst2a:cmp bl,'O' ; Opennet network?
jne comst2 ; ne = no
jmp comso ; yes, get another item for networks
comst2: cmp bl,'U' ; Ungermann Bass net?
jne comst3 ; ne = no
jmp comsub
comst3: cmp bl,'D' ; DECnet?
jne comst4 ; ne = no
jmp comsd ; do DECnet startup
comst4: cmp bl,'E' ; IBM EBIOS?
jne comst5 ; ne = no
test nettype,acsi ; NetBios without EBIOS.COM?
jz comst4a ; z = no, using EBIOS.COM
mov inettyp,bl ; set type code
jmp comso2 ; do NetBios setup
comst4a:jmp comse ; do EBIOS checkup
comst5: cmp bl,'W' ; Novell NASI?
jne comst6 ; ne = no
jmp comsub
comst6: cmp bl,'C' ; 3Com BAPI?
jne comst7 ; ne = no
jmp comsbapi
comst7: cmp bl,'T' ; Novell TELAPI
jne comst8 ; ne = no
jmp comstelapi
comst8: cmp bl,'I' ; TES?
jne comst9 ; ne = no
jmp comsteslat
comst9: cmp bl,'t' ; Telnet, internal?
jne comst10 ; ne = no
ifndef no_tcp
jmp comstn
endif ; no_tcp
comst10:cmp bl,'M' ; Meridian Superlat?
jne comst11 ; ne = no
jmp comsmedlat
comst11:cmp bl,'b' ; [JRS] Beame & Whiteside TCP?
jne coms1c ; ne = no
jmp comsbw ; setup BW connection
; stop sources of NetBios interrupts
coms1c: call nbclose ; close NetBios session now
endif ; no_network
coms2: call serrst ; close current comms port
mov al,byte ptr temp ; get COMx (1-4)
mov flags.comflg,al ; remember port ident
cmp al,'1' ; Bios?
jb coms2a ; b = no, hardware
sub al,'0' ; remove ascii bias for portinfo
coms2a: dec al
xor ah,ah ; count ports from 0
push bx ; set port structure
mov bx,type prtinfo ; size of each portinfo structure
mul bl ; times port number
pop bx ; restore register
add ax,offset port1 ; plus start of COM1
mov portval,ax ; points to our current port struct
cmp flags.comflg,'1' ; Bios path?
jb coms4 ; b = no, check hardware
add ax,offset portb1-offset port1 ; correct to use Bios ports
mov portval,ax
mov dl,flags.comflg
sub dl,'1' ; port, internal from 0
xor dh,dh ; clear for COMTCP in OS2
mov ah,3 ; check port status, std Bios calls
int rs232 ; Bios call
and al,80h ; get CD bit
mov cardet,al ; preserve as global
clc
ret
coms4: cmp portin,-1 ; serial port touched yet?
jne coms4a ; ne = yes, else avoid init looping
mov portin,0 ; say serial port is being touched
coms4a: push es
mov ax,40h ; look at RS232_base [bx] in Bios area 40:00h
mov es,ax
mov bx,temp ; get desired port number 1..4
xor bh,bh
dec bl ; count com1 as bl = 0, etc
shl bx,1 ; make bx a word index
mov ax,es:[bx] ; get modem base address into ax
pop es
push bx ; save this index
or ax,ax ; is address zero?
jnz comsc ; nz = no, have port address
mov ah,prstr
mov dx,offset badprt ; tell them what we are doing
int dos
mov ax,defcom[bx] ; get default COMn port address
push ax
mov cx,16 ; base 16
call valout ; show port
pop ax
comsc: ; hardware tests
mov modem.mddat,ax ; set base address (also data address) 03f8h
add ax,2
mov modem.mdiir,ax ; interrupt identification reg 03fah
inc ax ; increment to command port 03fbh
mov modem.mdcom,ax ; set line control register address
add ax,2 ; increment to status port 03fdh
mov modem.mdstat,ax ; set line-status port address
call chkport ; get type of UART support
pop bx ; recover port index
jc comsnu ; c = not a real 8250 class UART
mov ax,40h
push es
mov es,ax
mov ax,modem.mddat ; get COMn port address
mov es:[bx],ax ; force into seg 40h
pop es
call chkint ; find IRQ for the port
jnc comsc1 ; nc = found, else error condition
ret
comsc1: call getbaud ; update current baud info for port
clc
ret ; success
; no UART
comsnu: mov ah,prstr ; tell user about Bios pathway
mov dx,offset biosmsg
int dos
mov dl,byte ptr temp ; selected hardware port
add dl,'0' ; map to Bios
mov flags.comflg,dl
mov ah,conout ; say port number
int dos
stc ; say error
ret
ifndef no_network
; Opennet Network support (FGR)
comso: mov inettyp,'O' ; remember OpenNet type network
jmp short comso2 ; do generic network code
; NetBios Network support
comsn: mov inettyp,'N' ; remember Netbios type network
comso2: mov ah,cmword ; get a word (remote node name)
mov bx,offset decbuf ; work buffer
mov word ptr decbuf,0 ; insert terminator
mov dx,offset nethlp ; help message
call comnd ; get the name, ignore errors
mov newnambuf,al ; save number of chars entered
mov ah,cmeol
call comnd ; get a confirm
jc comsn2 ; c = failure
; Enter here from EBIOS when EBIOS.COM is not installed. Use 'E'
; and nettype subident of abios.
comsn3: call serrst ; reset serial port
cmp newnambuf,0 ; any name given?
je comsn1 ; e = no, use current name
mov si,offset decbuf
mov di,offset nambuf ; copy to here
call strcpy
comsn1: call chknet ; start network usage
jc comsn2 ; c = failed
cmp pcnet,0 ; is network alive (non-zero)?
jne comsn4 ; ne = yes
comsn2: stc
ret ; failure
comsn4: mov portval,offset port_nb ; set Network port structure address
mov port_nb.portrdy,1 ; say the comms port is ready
mov al,inettyp ; FGR - get saved network type
mov flags.comflg,al ; set the Netbios port flag
clc ; return success
ret ; End NetBios
; Ungermann-Bass terminal port [ohl +]
comsub: push bx ; save net type U or W
mov ah,cmeol
call comnd ; get a confirm
jc comsub0 ; c = failure
call serrst ; reset serial port
call chkub ; check UB network presence
pop bx ; recover net type U or W
jnc comsub1 ; nc = present
comsub0:ret ; return failure
comsub1:mov portval,offset port_ub ; set Network port data structure addr
mov port_ub.portrdy,1 ; say the comms port is ready
mov flags.comflg,bl ; set the comm port flag
mov pcnet,2 ; network is present and active
clc ; return success
ret ; End Ungermann Bass / Novell NASI
comsmedlat: ; Meridian Superlat
mov latkind,MTC_LAT ; say Meridian
jmp short comsd1
; TES_LAT
comsteslat:
mov latkind,TES_LAT ; say TES over LAT (vs DECnet)
jmp short comsd1 ; common code
; DECnet
comsd: mov latkind,DEC_LAT ; DECnet over LAT or CTERM
comsd1: mov ah,cmword ; get a word (remote node name)
mov bx,offset decbuf ; work buffer
mov word ptr decbuf,0 ; insert terminator
mov dx,offset dnethlp ; help message
call comnd ; get the name
mov temp,ax ; save number of chars entered
mov ah,cmword ; get optional LAT service name
mov bx,offset decbuf+80 ; work near end of this buffer
mov word ptr decbuf+80,0 ; insert terminator
mov dx,offset nethlp2 ; help message
mov comand.cmblen,16 ; length of buffer (password = 16 chr)
call comnd ; get the name, ignore if absent
mov decbuf+79,al ; store byte count in name here
mov comand.cmblen,0 ; length of buffer back to normal
mov ah,cmeol
call comnd ; get a confirm
jnc comsd3
ret ; did not get a confirm
comsd3: call serrst ; close serial port now
cmp temp,0 ; any node name?
je comsd8 ; e = no, assume preestablished
cmp decbuf,'*' ; just show LAT names?
jne comsd4 ; ne = no
call far ptr chkdec ; see if network is available
jc comsd3a ; c = no, no net available
and nettype,not decnet ; remove CTERM indicator
test nettype,declat ; LAT type present?
jz comsd3a ; z = no
call latlst ; show LAT names
and nettype,not declat ; remove this indicator
clc ; success but do not make connection
ret
comsd3a:cmp latkind,DEC_LAT ; doing DEC_LAT?
je comsd3b ; e = yes, DECnet
mov latkind,DEC_LAT ; not this method of TES
jmp comstes1 ; try older TES method
comsd3b:mov ah,prstr
mov dx,offset nonetmsg ; say net is not available
int dos
clc
ret
; put name in uppercase, strip '::'
comsd4: mov si,offset decbuf ; the node name, make upper case
mov cx,temp ; length of node name
add si,cx ; and add '::' if absent
push ds
pop es
cmp byte ptr [si-1],':' ; ended on colon?
jne comsd5 ; ne = no
dec cx ; remove it
cmp byte ptr [si-2],':' ; first colon present?
jne comsd5 ; e = yes
dec cx ; remove it
comsd5: mov si,offset decbuf ; uppercase and copy name
mov di,offset latservice ; to this structure
jcxz comsd7a ; z = empty name
cld
comsd6: lodsb ; si = new node name
cmp al,'a' ; in lower case?
jb comsd7 ; b = no
cmp al,'z' ; in lower case?
ja comsd7 ; a = no
and al,not 20h ; convert to upper case
comsd7: stosb
loop comsd6
comsd7a:mov byte ptr [di],0 ; terminate latservice name
mov si,offset decbuf+80 ; LAT password
mov di,offset latpwd ; where it will reside
mov byte ptr [di],0 ; clear password now
call strcpy ; copy it, asciiz
mov cl,decbuf+79 ; length of name
xor ch,ch
add di,cx ; point to trailer
sub cx,16 ; max chars in password
jle comsd8 ; le = filled now, or no password
mov al,' ' ; make it space filled
push ds
pop es
rep stosb ; fill in spaces
comsd8: call far ptr chkdec ; see if network is available
jc comsd3a ; c = no
mov ah,prstr
test nettype,decnet ; starting CTERM?
jz comsd9a ; z = no
mov dx,offset decmsg4 ; assume CTERM
int dos
comsd9a:test nettype,declat ; LAT too?
jz comsd9b ; z = no
cmp latkind,DEC_LAT ; DEC_LAT?
jne comsd9b ; ne = no, don't say LAT on screen
mov dx,offset decmsg5 ; say LAT connection is ready
int dos
comsd9b:cmp pcnet,2 ; session active?
jb comsd10 ; b = no, start a new one
call chknew ; session exists, Resume or start new?
jc comsd11 ; c = resume
call decclose ; close current session
comsd10:mov portval,offset port_dec ; set Network port data structure addr
mov al,'D' ; assume DECnet
cmp latkind,DEC_LAT ; DEC_LAT?
je comsd10b ; e = yes
mov al,'I' ; TES_LAT
comsd10a:cmp latkind,MTC_LAT ; Meridian LAT?
jne comsd10b ; ne = no
mov al,'M' ; Meridian SuperLAT
comsd10b:mov flags.comflg,al ; set the comm port flag
comsd11:clc
ret ; end of DECnet
comsbapi:mov ah,bapihere ; 3Com BAPI presence check
xor al,al
mov bx,0aaaah ; undocumented magic
int bapiint
cmp ax,0af01h ; signature
jne comsbap1 ; ne = not present
call serrst ; close current port
mov ah,bapieecm ; disable Enter Command Mode char
xor al,al
int bapiint
mov portval,offset port_ub ; set Network port data structure addr
mov port_ub.portrdy,1 ; say the comms port is ready
or nettype,bapi ; indentify network type
mov flags.comflg,'C' ; set the comm port flag
mov pcnet,2 ; network is present and active
clc ; success
ret
comsbap1:mov ah,prstr
mov dx,offset nonetmsg ; say no network
int dos
comsbap3:stc ; say failure
ret ; end 3Com BAPI
comse: mov dx,offset ebiostab ; table of EBIOS ports
xor bx,bx
mov ah,cmkey
call comnd
jnc comse1 ; nc = success
; failure is ok, fails for GETBAUD etc calling comstrt
mov bx,ebport ; use current port
inc bx ; here count from 1
comse1: push bx
mov ah,cmword ; get a word (remote node name)
mov bx,offset decbuf ; work buffer
mov word ptr decbuf,0 ; insert terminator
mov dx,offset ebhlp ; help message
call comnd ; get the name
mov ah,cmeol
call comnd ; get a confirm
pop bx
jnc comse7
ret ; c = failure
comse7: dec bx ; count from 0
mov ebport,bx ; port number 0..3
call chkebios ; EBIOS presence check
jnc comse7a ; nc = success
mov inettyp,'E' ; try NetBios directly (ABIOS)
mov al,decbuf ; indicator of new host name
mov newnambuf,al ; set for NetBios routine
or nettype,acsi ; say doing special subset of NetBios
jmp comsn3 ; setup NetBios connection
comse7a:push es
mov bx,ds
mov es,bx
mov bx,offset ebcoms ; es:bx to ebcoms address
mov dx,ebport ; port number
mov cx,51 ; number of bytes in ebcoms
mov ah,ebquery ; get redirection table info
int rs232
mov ebcoms,0 ; query puts ebport in LANA, clear it
cmp decbuf,0 ; any new name given?
je comse4 ; e = no, presume name exists in EBIOS
mov si,offset decbuf ; user input
mov di,offset ebcoms+2 ; where to store it
mov cx,16 ; 16 char NetBios name
cld
comse2: lodsb ; get a new char
or al,al ; null terminator?
jnz comse3 ; nz = no, use it
mov al,' ' ; replace with space
rep stosb ; do remaining spots
jmp short comse3b ; carry on when done
comse3: stosb ; store it
loop comse2
comse3b:call setnbname ; setup local Netbios name
jc comse4 ; c = failed
mov si,ds
mov es,si
cld
mov ebcoms+2+16,0 ; no Listen required, just a Call
mov cx,8
mov si,offset deflname ; our Netbios name
mov di,offset ebcoms+2+16+16
rep movsw
comse4: mov bx,offset ebcoms ; es:bx to ebcoms structure
mov ebcoms+1,80h ; force a network connection
mov ah,ebredir ; do redirection
xor al,al
mov dx,ebport
int rs232
pop es
or ax,ax ; status
jz comse5 ; z is success
push ax
mov ah,prstr
mov dx,offset ebmsg3 ; cannot open network
int dos
pop ax
xchg ah,al
xor ah,ah
call decout ; show error value
stc
ret
comse5: cmp ebcoms+2,' ' ; do we have a name?
ja comse6 ; a = yes
mov ah,prstr
mov dx,offset ebmsg2 ; say bad command
int dos
stc ; fail
ret
comse6: call serrst ; reset previous port
mov bx,offset portb1 ; use Bios data structure
mov ax,type prtinfo ; portinfo item size
mov cx,ebport ; actual port (0..3)
mul cl ; times port
add bx,ax ; new portb<n> offset
mov portval,bx
mov [bx].portrdy,1 ; say the comms port is ready
mov [bx].sndproc,offset ebisnd ; send processor
mov [bx].rcvproc,offset ebircv ; receive processor
mov [bx].cloproc,offset ebiclose ; close processor
or nettype,ebios ; indentify network type
mov flags.comflg,'E' ; say EBIOS
mov pcnet,1
clc ; success
ret
comsex: mov dx,offset nonetmsg ; say network is not available
mov ah,prstr
int dos
comsex1:stc ; failure
ret
comstelapi: ; Novell TELAPI
mov ah,cmword ; get a word (remote node name)
mov bx,offset decbuf ; work buffer
mov word ptr decbuf,0 ; insert terminator
mov dx,offset telhlp ; help message
call comnd ; get the name
jc comstel9
mov bx,offset decbuf+80+2 ; user text goes here
mov dx,offset telhlp2
mov ah,cmword ; get optional Telnet port
call comnd
jc comstel9
mov word ptr decbuf+80,ax ; store string length here
mov ah,cmeol
call comnd ; get a confirm
jnc comstel1 ; nc = ok so far
comstel9:ret ; did not get a confirm
comstel1:cmp decbuf,0 ; got new address?
jne comstel2 ; ne = yes
cmp word ptr internet,0 ; have we a previous address?
jne comstel6 ; ne = yes, use it instead
jmp short comstel5 ; no address, say illegal
comstel2:
mov domath_ptr,offset decbuf+80+2 ; port number string
mov ax,word ptr decbuf+80 ; length of string
mov domath_cnt,ax
call domath ; convert to number in ax
jc comstel11 ; c = nothing convertable
cmp ax,25 ; verboten?
jne comstel12 ; ne = no
comstel11:mov ax,23 ; use default
comstel12:mov telport,ax ; port number
cmp portin,0 ; inited port yet?
jl comstel8 ; l = no
test nettype,telapi ; already doing TELAPI?
jz comstel7 ; z = no
call chknew ; ask Resume or New
jc comstel6 ; c = Resume
comstel7:call telapiclose ; close that connection
comstel8:xor bx,bx ; convert Internet address to binary
xor dx,dx ; Internet field in dl, as a temp
mov word ptr internet,dx ; clear Internet address
mov word ptr internet+2,dx
mov si,offset decbuf ; fresh text
cld
comstel3:lodsb ; get ascii digit
cmp al,'.' ; separator?
jne comstel4 ; ne = no
inc bx ; next field
cmp bx,3 ; beyond last field
ja comstel5 ; a = yes, error
jmp short comstel3
comstel4:or al,al ; end of information?
jz comstel6 ; z = yes
sub al,'0' ; strip ascii bias
cmp al,9 ; in digits?
ja comstel5 ; a = no
mov dl,internet[bx] ; current field
xor dh,dh
shl dx,1 ; times two
push dx ; save
shl dx,1 ; times four
shl dx,1 ; times eight
pop cx ; recover times two
add dx,cx ; plus two = times ten
add al,dl ; plus current digit
mov internet[bx],al ; save value
jmp short comstel3 ; next character
comstel5:mov ah,prstr ; say bad address construction
mov dx,offset telmsg1
int dos
mov dx,offset decbuf ; show address
call prtasz
stc
ret
comstel6:call serrst ; end previous async session
mov portval,offset port_ub ; set Network port data structure addr
mov bx,portval
mov [bx].cloproc,offset telapiclose
or nettype,telapi ; indentify network type
mov flags.comflg,'T' ; set the comm port flag
clc
ret
comstes1:mov cx,0ffffh ; old TES presence check
mov ah,tesinstal ; installation/status check
call tes_service
jc comstes2 ; c = error of some kind
cmp ax,'TE' ; signature
jne comstes2 ; ne = not present
cmp cx,0ffffh ; should change too
jne comstes3 ; ne = present
comstes2:mov ah,prstr
mov dx,offset nonetmsg ; say no network
int dos
stc ; say failure
ret
comstes3:mov tesport,dx ; remember TES intercepted port
call serrst ; close current port
mov portval,offset port_tes ; set Network port data structure addr
or nettype,tes ; indentify network type
mov flags.comflg,'I' ; set the comm port flag
mov latkind,DEC_LAT ; not LAT kind
cmp decbuf,'*' ; was show-all entered?
jne comstes4 ; ne = no
jmp teshosts ; show known TES hosts
comstes4:mov ax,temp ; length of entered name
or al,tesname ; plus preexisting name, if any
or ax,ax ; anything present?
jz comstes9 ; z = no name, find existing session
cmp decbuf,0 ; anything to copy?
je comstes5 ; e = no, use existing name
call tesclose ; close existing connection
or nettype,tes ; indentify network type
mov si,offset decbuf
mov di,offset tesname
call strcpy ; copy node name
comstes5:clc
ret
comstes9:mov tesses,1 ; search for an active/held session
comstes10:call tesstate ; get state of that session to AH
test ah,2 ; active?
jnz comstes12 ; nz = yes, use it
inc tesses ; next session
cmp tesses,9 ; done all?
jbe comstes10 ; be = no
mov tesses,1 ; try for a held session
comstes11:call tesstate ; get state of that session to AH
test ah,1 ; on hold?
jnz comstes12 ; nz = yes, use it
inc tesses ; next session
cmp tesses,9 ; done all?
jbe comstes11 ; be = no
mov tesses,0 ; say no session
mov ah,prstr
mov dx,offset tesnhost ; give directions
int dos
call teshosts ; show known hosts
comstes12:ret
; TCP/IP Telnet
comstn:
ifndef no_tcp
mov ah,cmword ; get a word (remote node name)
mov comand.cmblen,60 ; set 60 byte limit plus null
mov bx,offset decbuf+1 ; work buffer, 1st byte = count
mov word ptr decbuf,0 ; insert terminator
mov word ptr decbuf+80,0 ; byte count of args
mov dx,offset tcphlp ; help message
call comnd ; get the name
jc comstnx
or al,al ; anything?
jz comstn1 ; z = no
mov decbuf,al ; store byte count
mov ah,cmword ; get optional Port number
mov comand.cmblen,7 ; set 7 byte limit plus null
mov bx,offset decbuf+81 ; far from real node names
mov word ptr decbuf+80,0 ; byte count of args, arg
mov dx,offset tcpporthlp
call comnd
jc comstnx
mov decbuf+80,al ; store arg byte count
mov bx,offset decbuf+82 ; get optional NEW or RESUME
add bx,ax ; plus byte count of above
mov word ptr [bx],0 ; clear count and inital byte
inc bx ; goes into decbuf[84]
push bx
mov ah,cmword ; get optional NEW/RESUME
mov comand.cmblen,7 ; set 7 byte limit plus null
mov dx,offset tcpnewhlp
call comnd
pop bx
jc comstnx
mov [bx-1],al ; store arg byte count
comstn1:mov ah,cmeol
call comnd ; get a confirm
jnc comstn2 ; nc = ok so far
comstnx:mov kstatus,ksgen ; global status for unsuccess
ret ; did not get a confirm
comstn2:call serrst ; close current comms port
call sesmgr ; SESSION MANAGER
jnc comstn3 ; nc = start a session
mov kstatus,ksgen ; global status for unsuccess
ret ; cannot allocate a session, fail
comstn3: mov flags.comflg,'t' ; what we want, may not have yet
mov bx,offset port_tn ; set Network port data structure addr
mov [bx].floflg,0 ; flow control kind, (none)
mov [bx].flowc,0 ; flow control characters (none)
mov portval,bx
mov nsbrk,1 ; network BREAK supported
clc
else
stc
endif ; no_tcp
ret
; Beame & Whiteside TCP/IP
comsbw: mov ah,cmword ; get a word (remote node name)
mov bx,offset decbuf ; work buffer
mov decbuf+80+1,0
mov dx,offset telhlp ; help message
call comnd ; get the name
jc comsbw9 ; c = failure, get eol
mov ah,cmword ; get optional port number
mov bx,offset decbuf+80+2 ; storage spot
mov word ptr decbuf+80,0 ; length of string
mov dx,offset telhlp2 ; help for optional port
mov comand.cmcr,1 ; bare CR's allowed
call comnd
mov word ptr decbuf+80,ax ; string length
comsbw9:mov ah,cmeol
call comnd ; get a confirm
jnc comsbw1 ; nc = ok so far
mov kstatus,ksgen ; global status for unsuccess
ret ; did not get a confirm
comsbw1:cmp decbuf,0 ; got new address?
jne comsbw2 ; ne = yes
cmp word ptr internet,0 ; have we a previous address?
je comsbw5 ; e = no address, say illegal
jmp comsbw6
comsbw2:mov domath_ptr,offset decbuf+80+2 ; port string
mov ax,word ptr decbuf+80 ; length
mov domath_cnt,ax
call domath ; convert to number in ax
jc comsbw2b ; c = nothing convertable
cmp ax,25 ; verboten?
jne comsbw2c ; ne = no
comsbw2b:mov ax,23 ; use default
comsbw2c:mov telport,ax ; port number
cmp portin,0 ; inited port yet?
jl comsbw8 ; l = no
test nettype,bwtcp ; [JRS] already doing BWTCP?
jz comsbw7 ; [JRS] z = no
call chknew ; ask Resume or New
jnc comsbw7 ; nc = New
jmp comsbw6
comsbw7:call bwclose ; close current connection
comsbw8:xor bx,bx ; convert Internet address to binary
xor dx,dx ; Internet field in dx, as a temp
mov word ptr internet,dx ; clear Internet address
mov word ptr internet+2,dx
mov si,offset decbuf ; fresh text
cld
cmp byte ptr [si],'*' ; [JRS] telnet server mode?
jne comsbw3 ; [JRS] ne = no, process IP address
mov word ptr internet,-1 ; [JRS] bogus IP for server mode
mov word ptr internet+2,-1 ; [JRS] bogus IP for server mode
comsbw6:call serrst ; end previous async session
push bx
mov bx,offset port_tn
mov portval,bx
mov [bx].sndproc,offset bwsend ; [JRS] BW send routine
mov [bx].rcvproc,offset bwrecv ; [JRS] BW Receive routine
mov [bx].cloproc,offset bwclose ; [JRS] BW Close routine
pop bx
or nettype,bwtcp ; [JRS] set it to BW-TCP
mov flags.comflg,'b' ; [JRS] set the comm port flag
clc
ret
comsbw3:lodsb ; get ascii digit
cmp al,'.' ; separator?
jne comsbw4 ; ne = no
inc bx ; next field
cmp bx,3 ; beyond last field
ja comsbw5 ; a = yes, error
jmp short comsbw3
comsbw4:or al,al ; end of information?
jz comsbw6 ; z = yes
sub al,'0' ; strip ascii bias
cmp al,9 ; in digits?
ja comsbw5 ; a = no
mov dl,internet[bx] ; current field
xor dh,dh
shl dx,1 ; times two
push dx ; save
shl dx,1 ; times four
shl dx,1 ; times eight
pop cx ; recover times two
add dx,cx ; plus two = times ten
add al,dl ; plus current digit
mov internet[bx],al ; save value
jmp short comsbw3 ; next character
comsbw5:mov ah,prstr ; say bad address construction
mov dx,offset telmsg1
int dos
mov dx,offset decbuf ; show address
call prtasz
stc
ret
endif ; no_network
; Fossil
comsf: mov ah,cmword ; get a word (remote node name)
mov bx,offset decbuf ; work buffer
mov word ptr decbuf,0 ; insert terminator
mov dx,offset fossilhlp ; help message
call comnd ; get the port, optional
push ax ; string length
mov ah,cmeol
call comnd ; get a confirm
pop ax
jnc comsf2 ; nc = ok so far
comsf1: mov kstatus,ksgen ; global status for unsuccess
ret ; did not get a confirm
comsf2: mov domath_ptr,offset decbuf
mov domath_cnt,ax
call domath ; convert to number in ax
jc comsf4 ; c = failure
cmp ax,99 ; largest acceptable value
ja comsf4 ; a = failure
dec ax ; count internally from 0 as F1
js comsf4 ; sign = failure
mov fossil_port,ax ; Fossil port (Fossil1 is value 0)
call serrst ; end previous async session
mov flags.comflg,'F' ; set the comm port flag
mov portval,offset portb1
mov bx,portval
mov [bx].sndproc,offset fossnd
mov [bx].rcvproc,offset fosrcv
mov portin,0 ; say port is selected
clc
ret
comsf4: stc
ret
COMS ENDP
ifndef no_network
teshosts proc near ; TES, show list of hosts
mov ah,prstr
mov dx,offset tesnlist ; show list of hosts
int dos
push es
push si
mov ah,tesgets ; get TES known servers
call tes_service ; cx gets qty
mov dx,offset decbuf ; work buffer
mov word ptr decbuf,' ' ; item spacing
xor di,di ; line length counter
or cx,cx ; any servers?
jnz teshost1 ; nz = some servers
inc cx ; say one for loop
push cx
mov word ptr decbuf+2,'ON' ; prefill with NONE
mov word ptr decbuf+4,'EN'
mov decbuf+6,0 ; asciiz
mov cx,6 ; length of " NONE"
jmp short teshost3 ; show NONE
teshost1:push cx ; count of servers
push si ; save master list pointer
push di
mov si,es:[si] ; get offset of first name
mov di,dx ; decbuf
add di,2 ; move into decbuf+2
teshost2:mov al,es:[si] ; get name char
inc si
mov [di],al ; store name char
inc di
or al,al ; at end?
jnz teshost2 ; nz = no
pop di
pop si ; master list of offsets
add si,2 ; next item in list
call strlen ; get length of name w/spaces
add di,cx ; length of display line with name
cmp di,60 ; time to break line?
jbe teshost3 ; be = no
push dx
mov ah,prstr ; break the screen line
mov dx,offset crlf
int dos
pop dx
xor di,di ; say line is empty
teshost3:add di,cx ; current line length
call prtasz ; show asciiz text at ds:dx
pop cx
loop teshost1 ; do all entries
pop si
pop es
ret
teshosts endp
; Perform TES function given in AH, but tell cmd interpreter to not prompt.
tes_service proc near
push ax
push si
push es
mov ax,ds
mov es,ax
mov si,offset tesquiet ; cmd to say no prompting
xor al,al ; no visible response please
mov ah,tesexec
int rs232
pop es
pop si
pop ax
push ds ; prevent corruption by TES
int rs232 ; do the main request
pop ds
ret
tes_service endp
; TES - start or resume a TES connection
tesstrt proc near
cmp tesses,0 ; session yet?
jne tesstr2 ; ne = yes
cmp tesname,0 ; have a node name?
jne tesstr1 ; ne = yes
jmp tesstr4 ; find an existing connection, if any
tesstr1:push si
mov si,offset tesname ; node name
mov ah,tesnews ; make a new session
call tes_service
pop si
jmp short tesstr4 ; double check on transistions
; have a session, live or held
tesstr2:call tesstate ; get session status
test ah,2 ; active or being made so?
jnz tesstr3 ; nz = yes, connect to it
test ah,1 ; session on hold or being made so?
jz tesstr1 ; z = no, make a new one
mov ah,tesresume ; resume a session
mov al,tesses ; the session number
call tes_service
shl ah,1 ; get status into carry bit
jc tesstr4 ; c = problem, try to recover
tesstr3:cmp tesname,0 ; have name yet?
je tesstr4 ; e = no, get it now
mov pcnet,2 ; have an active session
mov port_tes.portrdy,1 ; say port is ready
clc
ret
tesstr4:push si ; find an active session number
push es
mov temp,0 ; retry counter
mov tesses,1 ; session number
tesstr5:mov ah,teslist ; get TES session pointers
call tes_service ; CX gets quantity of ACTIVE sessions
tesstr6:mov al,es:[si] ; get session status
cmp al,82h ; making a session now?
je tesstr7 ; e = yes, good enough
test al,80h ; in transitional status?
jz tesstr6b ; z = no
mov ah,100
call pcwait ; wait 100 ms
inc temp
cmp temp,10
ja tesstr6a ; a = too many retries, quit
jmp short tesstr5 ; nz = yes, go around again
tesstr6b:mov temp,0 ; clear retry counter
test al,2 ; 0=inactive, 1=on hold, 2=active?
jnz tesstr7 ; nz = active
add si,3 ; skip status byte, name offset
inc tesses ; bump session number
cmp tesses,9 ; done all?
jbe tesstr6 ; be = no
tesstr6a:mov tesses,0 ; no active session
mov port_tes.portrdy,0 ; say the comms port is not ready
mov pcnet,1 ; network is present and inactive
stc ; signal failure
jmp short tesstr8
; set port ready, get host name
tesstr7:mov port_tes.portrdy,1 ; say the comms port is ready
mov pcnet,2 ; network is present and active
mov di,offset tesname ; readback asciiz name
mov byte ptr [di],0 ; clear the name field
mov si,es:[si+1] ; get name ptr offset
or si,si ; check for null pointer
jz tesstr6a ; z = no name, dead session
mov cx,49 ; limit to 48 chars plus null
tesstr7a:mov al,es:[si] ; get a char
inc si
mov [di],al ; store
inc di
or al,al ; null?
jz tesstr7b ; z = yes, stop here
loop tesstr7a ; keep going
tesstr7b:clc ; signal success
tesstr8:pop es
pop si
ret
tesstrt endp
; TES. Return session status in AH for session in tesses. Destroys AX
tesstate proc near
push cx
push si
push es
mov ah,teslist ; get session list
call tes_service
mov ah,0ffh ; set up no session status
mov al,tesses ; our session number, 1..9
dec al ; base on zero here
mov ah,al
shl ah,1
add al,ah
xor ah,ah ; times three
add si,ax ; point to session structure es:[si]
mov ah,es:[si] ; get session status byte
testat1:pop es
pop si
pop cx
ret
tesstate endp
; Start Novell TELAPI session. Internet address is already binary
telstrt proc near
mov dx,word ptr internet ; internet address, high part
mov cx,word ptr internet+2
mov bx,telport ; Telnet port (23 decimal)
push es
push si
xor si,si ; use TELAPI data structures, not ours
mov es,si ; es:si = Telnet state record, theirs
mov di,offset telhostid ; two byte host identifier in ds:di
mov ah,telopen ; open the connection
int rs232
mov telses,ax ; save TELAPI session number
pop si
pop es
or ax,ax ; get status returned in AX
jns telstr1 ; ns = success
cmp ax,telinuse ; socket is already connected? (-56)
jne telstr2 ; ne = no, else attach to it
telstr1:mov port_ub.portrdy,1 ; say the comms port is ready
mov pcnet,2 ; network is present and active
or nettype,telapi
clc
ret
; failure message display section
telstr2:mov dx,offset telmsg51 ; network unreachable
cmp ax,telunreac ; correct?
je telstr3 ; e = yes
mov dx,offset telmsg56 ; socket in use
cmp ax,telinuse
je telstr3
mov dx,offset telmsg60 ; timeout on connection attempt
cmp ax,teltmo
je telstr3
mov dx,offset telmsg61 ; connection refused
cmp ax,telrefuse
je telstr3
mov dx,offset telmsg64 ; host is down
cmp ax,teldwnhost
je telstr3
mov dx,offset telmsg67 ; unknown host
cmp ax,telunkhost
je telstr3
mov dx,offset telmsg301 ; no more space
cmp ax,telfull
je telstr3
push ax ; unknown error, show error value
mov dx,offset telmsg2
mov ah,prstr
int dos
pop ax
neg ax ; make positive number again
call decout ; show error value, for now
jmp short telstr4
telstr3:mov ah,prstr
int dos ; show reason msg
telstr4:mov ax,3000 ; show for three seconds
call pcwait
mov port_ub.portrdy,0 ; say port is not ready
and nettype,not telapi ; clear network use bit
stc ; fail
ret
telstrt endp
; Start Beame & Whiteside TCP connecton. IP address is already binary [JRS]
bwstart proc near ; [JRS]
push bx ; [JRS]
push cx ; [JRS]
push dx ; [JRS]
mov bx,bwhandle ; [JRS] check the file handle
or bx,bx ; [JRS] non-zero is open
jnz bwstrt1 ; [JRS] nz = yes, just continue
mov ax,3d42h ; [JRS] open file shared read/write
mov dx,offset bwtcpnam ; [JRS] "TCP-IP10"
int dos
jc bwstrt2 ; c = failed
mov bwhandle,ax ; [JRS] save file handle
mov bx,ax ; [JRS] copy handle
mov ax,4401h ; [JRS] io/ctl - set dev info
xor cx,cx ; [JRS]
mov dx,60h ; [JRS] data is raw
int dos ; [JRS]
jc bwstrt2 ; c = failed
mov xmtbuf,0 ; [JRS] set up port bind address
push es
mov ax,40h ; Bios work area
mov es,ax
mov ax,es:[6ch] ; low word of Bios tod tics
pop es
mov word ptr xmtbuf+1,ax ; local port
mov ax,4403h ; [JRS] write to device
mov bx,bwhandle ; [JRS] device handle
mov cx,3 ; [JRS] length of data
mov dx,offset xmtbuf ; [JRS] data buffer
int dos ; [JRS]
jc bwstrt2 ; c = failed
mov xmtbuf,1 ; [JRS] set up IP bind address
mov dx,word ptr internet ; [JRS] internet address, high part
mov cx,word ptr internet+2 ; [JRS]
cmp dx,-1 ; [JRS] check for server addr -1
jz bwaccept ; [JRS] z = -1, do accept processing
mov word ptr xmtbuf+1,dx ; [JRS] store address in buffer
mov word ptr xmtbuf+3,cx ; [JRS]
mov ax,telport
mov word ptr xmtbuf+5,ax ; telnet port (23)
mov ax,4403h ; [JRS] write to device
mov bx,bwhandle ; [JRS]
mov cx,7 ; [JRS]
mov dx,offset xmtbuf ; [JRS]
int dos ; [JRS]
jc bwstrt2 ; c = failed
bwstrt0:mov xmtbuf,6 ; [JRS] set up for no read blocking
mov xmtbuf+1,1 ; [JRS] control string is \6\1
mov ax,4403h ; [JRS] write to device
mov bx,bwhandle ; [JRS]
mov cx,2 ; [JRS]
mov dx,offset xmtbuf ; [JRS]
int dos ; [JRS]
jc bwstrt2 ; c = failed
bwstrt1:pop dx ; [JRS] restore registers
pop cx ; [JRS]
pop bx ; [JRS]
mov port_tn.portrdy,1 ; [JRS] say the comms port is ready
mov pcnet,2 ; [JRS] network is present and active
or nettype,bwtcp ; [JRS]
mov optstate,0 ; init Options
mov sgaflg,0 ; assume supresss go aheads in effect
mov option2,TELOPT_SGA
mov ah,DO
call bwsendiac ; say do supress go aheads
clc
ret
bwstrt2:call bwclose ; [JRS] failure, close "file"
pop dx ; [JRS]
pop cx ; [JRS]
pop bx ; [JRS]
stc ; c = failed
ret
bwaccept:mov xmtbuf,2 ; [JRS] set port to accept calls
mov ax,4403h ; [JRS] write to device
mov bx,bwhandle ; [JRS]
mov cx,1 ; [JRS]
mov dx,offset xmtbuf ; [JRS]
int dos ; [JRS]
mov ax,4402h ; [JRS] read from device
mov bx,bwhandle ; [JRS] device handle
mov cx,11 ; [JRS] buffer length
mov dx,offset xmtbuf ; [JRS] buffer
int dos ; [JRS]
bwacpt1:cmp xmtbuf,4 ; [JRS] check response 0 < xmtbuf < 4
jge bwacpt2 ; [JRS] complete
cmp xmtbuf,0 ; [JRS]
je bwacpt2 ; [JRS]
; [JRS] waiting for a connection
mov ax,4402h ; [JRS] read from device
mov bx,bwhandle ; [JRS]
mov cx,11 ; [JRS]
mov dx,offset xmtbuf ; [JRS]
int dos ; [JRS]
jmp short bwacpt1 ; [JRS] got look at response
bwacpt2:cmp xmtbuf,0 ; [JRS] check for response of zero
je bwstrt2 ; [JRS] e=yes, fail
jmp bwstrt0 ; [JRS] success, we have a call
bwstart endp ; [JRS]
endif ; no_network
code ends
code1 segment
assume cs:code1
ifndef no_network
; Check for presence of DECNET. Host name is in latservice.
; Try LAT then try CTERM. Sets nettype for kind found.
; Return carry clear if success, or carry set if failure.
chkdec proc FAR
cmp pcnet,2 ; net active now?
jb chkde2 ; b = no
cmp lathand,0 ; valid LAT handle?
jne chkde1 ; ne = yes
cmp decneth,0 ; valid LAT handle?
je chkde2 ; e = invalid handle
chkde1: clc
ret ; return to active session
chkde2: push es
and nettype,not (declat+decnet) ; clear network type bits
call chklat ; check for LAT
jc chkde3 ; c = not present
mov latversion,4 ; assume DECnet version 4 or later
xor bx,bx
mov es,bx ; clear ES:BX for text below
mov ax,latscbget ; try getting SCB internal to LAT
mov dh,0ffh
int latint
jc chkde2a ; if this kind of failure
or ah,ah ; success?
jnz chkde2a ; nz = no, use v3 SCB in Kermit
push es
push bx
mov ax,latscbfree ; free the SCB
int latint
pop ax ; old ES
pop bx
or ax,bx ; returned address from ES:BX, null?
jnz chkde4 ; nz = no, LAT has internal SCBs
chkde2a:mov latversion,3 ; DECnet version 3 style LAT
jmp short chkde4
; now do CTERM too
chkde3: mov al,decint ; CTERM interrupt 69h
mov ah,35h ; get vector to es:bx
int dos
mov ax,es
or ax,ax ; undefined interrupt?
jz chkde4 ; z = yes
cmp byte ptr es:[bx],0cfh ; points at IRET?
je chkde4 ; e = yes
mov ax,dpresent ; CTERM installation call
int decint
cmp al,0ffh ; CTERM installed?
jne chkde4 ; ne = no
or nettype,decnet ; kind of network is CTERM
chkde4: pop es
test nettype,declat+decnet ; any DEC network found?
jz chkde5 ; z = no
clc ; clear means yes
ret
chkde5: stc ; status is no net
ret
chkdec endp
; Check for LAT interrupt vector, return carry clear if found else carry set.
; Sets latkind to DEC_LAT, TES_LAT or MTC_LAT.
chklat proc near
push es
mov al,latint ; LAT interrupt 6Ah
mov ah,35h ; get vector to es:bx
int dos
mov ax,es
or ax,ax ; undefined interrupt?
jz chklat1 ; z = yes
cmp byte ptr es:[bx],0cfh ; points at IRET?
je chklat1 ; e = yes, not installed
cmp word ptr es:[bx-3],'AL' ; preceeding 3 bytes spell 'LAT'?
jne chklat1 ; ne = no, so no LAT, try CTERM
cmp byte ptr es:[bx-1],'T'
jne chklat1 ; ne = no, fail
or nettype,declat ; kind of network is LAT
mov latkind,TES_LAT ; assume TES LAT
cmp word ptr es:[bx-6],'ET' ; Interconnections Inc "TESLAT"?
je chklat2 ; e = yes
mov latkind,MTC_LAT ; Meridian
cmp word ptr es:[bx-6],'TM' ; Meridian "MTCLAT"?
je chklat2 ; e = yes
mov latkind,DEC_LAT ; say DEC's LAT
chklat2:pop es
clc ; success
ret
chklat1:pop es
stc ; say failure
ret
chklat endp
; Start DECNET link. Host name is in latservice, nettype has LAT or CTERM
; kind bits. Return carry clear if success, or carry set if failure.
decstrt proc FAR
cmp pcnet,2 ; net active now?
jb decst2 ; b = no
cmp lathand,0 ; invalid LAT handle?
jne decst1 ; ne = no, have a connection
cmp decneth,0 ; invalid CTERM handle?
je decst2 ; e = yes, start the net
decst1: mov port_dec.portrdy,1 ; say the comms port is ready
mov al,'D' ; assume DECnet port flag
cmp latkind,DEC_LAT ; DEC_LAT?
je decst1b ; e = yes
mov al,'I' ; TES-LAT
decst1a:cmp latkind,TES_LAT ; TES-LAT?
je decst1b ; e = yes
mov al,'M' ; Meridian SuperLAT
decst1b:mov flags.comflg,al ; set the comm port flag
clc
ret ; return to active session
decst2: push es ; used a lot here
call chkdec ; get net type
jnc decst3 ; nc = have a CTERM or LAT kind
jmp decst16 ; c = net not found
decst3: cmp latservice,0 ; node name present?
jne decst4 ; ne = yes
mov ah,prstr
mov dx,offset noname ; say host name is required
int dos
pop es
stc ; fail
ret
decst4: test nettype,declat ; LAT is available?
jnz decst6 ; nz = yes
jmp decst13 ; z = no, try CTERM
decst6: cmp word ptr latscbptr+2,0 ; any segment allocated now?
jne decst8 ; ne = yes, do not malloc one here
; cmp tv_mode,0 ; running under Windows or DV?
; je decst6a ; e = no, ok to try local SCB
; jmp decst12b ; can't use local so no LAT today
decst6a:mov bx,870+15 ; size of LAT SCB, bytes, rounded up
mov cl,4
shr bx,cl ; bytes to paragraphs
mov temp,bx ; save requested paragraphs
mov ah,alloc ; allocate memory, ax gets segment
int dos ; bx gets # paragraphs allocated
jnc decst7 ; nc = success
jmp decst13 ; fail, go try CTERM
decst7: mov latseg,ax
mov word ptr latscbptr+2,ax ; remember seg of SCB
mov word ptr latscbptr+10,ax ; and on the "To:" side as well
mov es,ax
xor di,di ; es:di is destination
xor ax,ax ; get word of zeros
mov word ptr latscbptr+0,ax ; remember offset (0) of SCB
mov word ptr latscbptr+8,ax ; as above
mov cx,bx ; paragraphs obtained
shl cx,1
shl cx,1
shl cx,1 ; words
cld
rep stosw ; clear the SCB
cmp temp,bx ; wanted vs allocated (bx) paragraphs
jbe decst5 ; be = enough, setup structure
jmp decst12 ; deallocate memory and try CTERM
decst5: and nettype,not declat ; presume failure
cmp latversion,4 ; version 4?
jb decst8 ; b = no, earlier, do our own SCB
cmp latpwd,0 ; password given?
jne decst8 ; ne = yes, must use our SCB
mov ax,latscbget ; get LAT interior SCB addr to es:bx
mov dh,0ffh
int latint
or ah,ah ; success?
jnz decst5a ; nz = no
mov ax,es
mov word ptr latscbptr+6,ax ; address of SCB within LAT
mov word ptr latscbptr+4,bx ; offset part
call decfems ; copy EMS SCB to local SCB
jmp short decst9 ; fill in local info
decst5a:mov ah,prstr
mov dx,offset decmsg6 ; say can't allocate LAT SCB
int dos
jmp decst13 ; try CTERM
decst8: les bx,latscbptr ; allocate data buffers locally
mov es:[bx].slottbl,slotbf1 ; offset of first buffer
mov es:[bx].slottbl+2,slotbf2 ; offset of second buffer
mov es:[bx].slotqty,2 ; say two buffers
decst9: les di,latscbptr ; set es:di to local scb
mov si,offset latservice ; get host name
mov cx,17 ; 17 bytes
cld
rep movsb ; insert host name
mov ax,latopen ; open a LAT session
mov di,offset latpwd ; es:di optional asciiz LAT password
cmp byte ptr [di],0 ; any name entered?
je decst10 ; e = no
and al,0fh ; open as AX = 0d0fh if with password
decst10:mov bx,word ptr latscbptr ; open needs es:bx == SCB
cmp latversion,4 ; LAT version 4?
jb decst11 ; b = no, use version 2
mov al,1 ; v4 form
push ax
mov cx,ds
mov word ptr es:[bx].lat_pwd+2,cx ; set the pointer segment
mov word ptr es:[bx].lat_pwd,di ; address of the password buffer
mov dx,di
call strlen ; password string length to cx
mov es:[bx].pwd_len,cl ; length of the password
or cx,cx ; is there a password?
jnz decst10a ; nz = yes
mov word ptr es:[bx].lat_pwd,cx ; no, clear fields
mov word ptr es:[bx].lat_pwd+2,cx
mov byte ptr es:[bx].pwd_len,cl
decst10a:call dec2ems ; copy local SCB to one in EMS
pop ax
decst11:mov dh,0ffh
cmp latversion,4 ; version 4?
jb decst11a ; b = no, earlier, use our own SCB
les bx,latscbptr+4 ; stuff in lat
decst11a:int latint
or ah,ah ; status byte
jnz decst12 ; nz = failure, clean up, try CTERM
mov dh,0ffh
mov lathand,dx ; handle returned in dl, 0ffh in dh
or nettype,declat ; say LAT session is active
jmp decst17 ; finish startup info
; LAT startup failure
decst12:mov ax,latseg ; stored segment of memory block
or ax,ax ; did we use it?
jz decst12a ; z = no
mov es,ax ; allocated segment, unneed now
mov ah,freemem ; free it again
int dos
jmp short decst12b ; clear pointers
decst12a:cmp word ptr latscbptr+2,0 ; in use as LAT internal perhaps?
je decst12b ; e = no
les bx,latscbptr
mov ax,latscbfree ; free SCB internal to LAT
int latint
decst12b:xor ax,ax
mov latseg,ax ; say not used
mov lathand,ax ; invalidate the handle
mov word ptr latscbptr+0,ax ; clear SCB pointer
mov word ptr latscbptr+2,ax
and nettype,not declat ; fall through to try CTERM
decst13:test nettype,decnet ; is CTERM available?
jz decst16 ; z = no
and nettype,not decnet ; presume failure
mov ax,decseg ; scb memory segment, if non-zero
or ax,ax ; allocated already?
jnz decst14 ; nz = yes, segment is in ax
mov ax,dgetscb ; get CTERM SCB size
int decint
add ax,15 ; round up byte count
mov cl,4
shr ax,cl ; bytes to paragraphs
mov bx,ax
mov temp,ax ; save requested paragraphs
mov ah,alloc ; allocate memory
int dos ; bx gets # paragraphs allocated
jc decst16 ; c = failure
mov decseg,ax ; store address of memory block
cmp temp,bx ; wanted vs allocated paragraphs
jb decst15 ; b = not enough, fail
decst14:mov bx,offset latservice ; ds:bx = node name
mov es,ax ; ax holds scb segment
xor dx,dx ; es:dx = SCB address
mov ax,dopen ; open session
int decint
cmp ax,0 ; > 0 means session handle, else error
jle decst15 ; le = error
mov decneth,ax ; store handle
or nettype,decnet ; network type is DECnet
jmp short decst17 ; success
; CTERM startup failure
decst15:push ax ; save error number in ax
mov ax,decseg ; allocated memory segment
mov es,ax
mov ah,freemem ; free allocated memory segment @ES
int dos ; free the block
mov decseg,0 ; clear remembered segment address
mov ah,prstr
mov dx,offset decmsg1 ; cannot create session
int dos
mov dx,offset decmsg3 ; DEC Error #
int dos
pop ax ; recover error number (negative)
neg ax
call decout ; error number
mov decneth,0 ; invalidate the handle
and nettype,not decnet
decst16:mov pcnet,0 ; no net
mov port_dec.portrdy,0 ; port is not ready
pop es
stc ; status is error
ret
; LAT or CTERM success
decst17:mov pcnet,2 ; say net is present and active
mov al,'D' ; assume DECnet
cmp latkind,DEC_LAT ; DECnet?
je decst18 ; e = yes
mov al,'I' ; TES-LAT
cmp latkind,TES_LAT ; TES_LAT?
je decst18 ; e = yes
mov al,'M'
decst18:mov flags.comflg,al ; set the comm port flag
decst19:mov port_dec.portrdy,1 ; say the comms port is ready
mov ax,100 ; wait 100 ms for DECnet to get ready
call pcwait ; FAR call
pop es
clc
ret
decstrt endp
; Copy LAT scb from local SCB to one in EMS
dec2ems proc near
cmp latversion,4 ; version 4?
jb dec2emsx ; b = no, earlier, do our own SCB
push ax
push bx
push cx
push dx
push es
mov ax,seg latscbptr ; seg where latscbptr is located
mov es,ax ; to es:bx
mov bx,offset latscbptr
mov ax,latcpyems ; copy from local to EMS
mov dh,0ffh ; signature
mov cx,31 ; bytes needed from LAT structure
int latint ; copy local LAT info to EMS version
pop es
pop dx
pop cx
pop bx
pop ax
dec2emsx:ret
dec2ems endp
; Copy LAT SCB from EMS to local SCB
decfems proc near
cmp latversion,4 ; version 4?
jb decfemsx ; b = no, earlier, do our own SCB
push ax
push bx
push cx
push dx
push es
mov ax,seg latscbptr ; seg where latscbptr is located
mov es,ax ; to es:bx
mov bx,offset latscbptr+4 ;local(0),LAT(4),local(8) in latscbptr
mov ax,latcpyems ; copy from EMS to local
mov dh,0ffh ; signature
mov cx,31 ; just enough of LAT structure
int latint
pop es
pop dx
pop cx
pop bx
pop ax
decfemsx:ret
decfems endp
endif ; no_network
code1 ends
code segment
assume cs:code
ifndef no_network
; Display list of LAT service names. Presumes LAT presence checks have passed
latlst proc near
push es
push bx
mov ah,prstr
mov dx,offset dnetsrv ; header
int dos
push ds
pop es
mov si,2 ; chars in line counter
latlst1:mov bx,offset decbuf+2 ; es:bx = temp buffer for a name
mov word ptr [bx-2],' ' ; indent
mov byte ptr [bx],0 ; and a null terminator
mov ax,latsrv ; get next LAT service name
mov dh,0ffh
int latint
or ah,ah ; check status
jnz latlst2 ; nz = done (no more names)
mov dx,offset decbuf ; name ptr is in es:bx (our buffer)
call prtasz ; show asciiz name
call strlen ; get current length
add si,cx ; count chars on this line
cmp si,60 ; enough on line already?
jbe latlst1 ; be = no
mov ah,prstr ; break the screen line
mov dx,offset crlf
int dos
mov si,2 ; reset line count
jmp short latlst1 ; do it again
latlst2:pop bx
pop es
ret
latlst endp
endif ; no_network
; Check which Interrupt ReQuest line the port uses. Technique: allow interrupt
; on transmitter holding register empty, test for that condition first with
; IRQ 4 and then IRQ 3. Returns with IRQ values set and carry clear if success
; or carry set if failure. [jrd]
chkint proc near
call serrst
mov bl,flags.comflg ; port 1..4
dec bl
xor bh,bh
mov al,portirq[bx] ; pre-specified IRQ, if any
or al,al ; IRQ specified already?
jnz chkint20 ; nz = yes
chkint10:test flags.comflg,1 ; COM1/3?
jz chkint13 ; z = no, COM2/4
cmp flags.comflg,1 ; COM1?
je chkint10a ; e = yes, try IRQ 4
cmp isps2,0 ; IBM PS/2 Model 50 or above?
jne chkint11 ; ne = yes, other COM2..4 try IRQ 3
chkint10a:call chkint5 ; test for IRQ 4
jc chkint11 ; c = failed
ret
chkint11:call chkint6 ; else try IRQ 3
jnc chkint12 ; nc = success
jmp chkint7 ; fall back on defaults
chkint12:ret ; carry clear for success
chkint13:call chkint6 ; test for IRQ 3
jc chkint14 ; c = failed
ret
chkint14:call chkint5 ; else try IRQ 4
jnc chkint15 ; nc = success
jmp chkint7 ; fall back on defaults
chkint15:ret ; carry clear for success
; IRQ specified, in AL
chkint20:mov di,sp ; do push sp test for XT vs 286 class
push sp ; XT pushes sp-2, 286's push old sp
pop cx ; recover pushed value, clean stack
sub di,cx ; non-zero if < 80286, no slave 8259
cmp al,2 ; using IRQ 2?
jne chkint1 ; ne = no
or di,di ; cascaded 8259?
jnz chkint1 ; nz = no
add al,7 ; map IRQ 2 to IRQ 9
chkint1:cmp al,15 ; larger than legal IRQ?
ja chkint2 ; a = yes, fail
or di,di ; 286 or above (cascaded 8259)?
jz chkint3 ; z = yes
cmp al,7 ; larger than legal for single 8259?
jbe chkint3 ; be = no
chkint2:stc ; fail
ret
chkint3:mov cl,al ; IRQ 0..15
mov bx,1
shl bx,cl ; bit position of IRQ 0..15
or bl,bh ; copy bit to bl
mov modem.mddis,bl ; mask to disable IRQ
not bl ; 0 means enable
mov modem.mden,bl ; mask to enable IRQ
and al,7 ; IRQ, lower three bits
mov ah,al ; make a copy
add ah,60h ; specific EOI control code
mov modem.mdmeoi,ah ; specific EOI control command
add al,8 ; IRQ 0 starts at Int 8
xor ah,ah
mov modem.mdintv,ax ; Interrupt number
mov modem.mdmintc,20h ; master 8259 control address
or bh,bh ; on cascaded 8259?
jz chkint4 ; z = no
or modem.mdmintc,80h ; slave 8259 control address (0a0h)
add modem.mdintv,70h-8 ; Interrupt number for IRQ 8..15
chkint4:clc
ret
; find IRQ 4 by usage test
chkint5:mov modem.mddis,(1 shl 4) ; IRQ 4 test. mask to disable IRQ 4
mov modem.mden,not (1 shl 4); mask to enable IRQ 4
mov modem.mdmeoi,20h ; use general in case we guess wrong
mov modem.mdintv,8+4 ; IRQ 4 interrupt vector (0ch)
mov modem.mdmintc,20h ; use master 8259 here
call inttest
jc chkint5a ; c = failed
mov modem.mdmeoi,60h+4 ; use specific EOI for IRQ4 level
mov bl,flags.comflg ; port 1..4
dec bl
xor bh,bh
mov portirq[bx],4
clc ; this setup worked
chkint5a:ret
; IRQ 3 test
chkint6:mov modem.mddis,(1 shl 3) ; mask to disable IRQ 3
mov modem.mden,not (1 shl 3); mask to enable IRQ 3
mov modem.mdmeoi,20h ; use general in case we guess wrong
mov modem.mdintv,8+3 ; IRQ 3 interrupt vector
call inttest
jc chkint6a ; c = failed
mov modem.mdmeoi,60h+3 ; use specific EOI for IRQ3 level
mov bl,flags.comflg ; port 1..4
dec bl
xor bh,bh
mov portirq[bx],3
clc ; this setup worked
chkint6a:ret
; auto test did not work
chkint7:mov modem.mdmintc,20h ; use master 8259 Int controller
cmp flags.comflg,1 ; COM1?
je chkint8 ; e = yes, use IRQ 4
cmp isps2,0 ; IBM PS/2 Model 50 or above?
jne chkint9 ; ne = yes, other COMs use IRQ 3
cmp flags.comflg,3 ; COM2, COM3, or COM4?
jne short chkint9 ; ne = COM2 or COM4, use IRQ 3
chkint8:mov modem.mdmeoi,60h+4 ; use specific EOI for IRQ4 level
mov modem.mddis,(1 shl 4) ; IRQ 4 test. mask to disable IRQ 4
mov modem.mden,not (1 shl 4); mask to enable IRQ 4
mov modem.mdintv,8+4 ; IRQ 4 interrupt vector (0ch)
mov bl,flags.comflg ; port 1..4
dec bl
xor bh,bh
mov ax,4 ; IRQ
mov portirq[bx],al
jmp short chkint9a ; show message
chkint9:mov modem.mdmeoi,60h+3 ; use specific EOI for IRQ 3 level
mov modem.mddis,(1 shl 3) ; mask to disable IRQ 3
mov modem.mden,not (1 shl 3); mask to enable IRQ 3
mov modem.mdintv,8+3 ; IRQ 3 interrupt vector
mov bl,flags.comflg ; port 1..4
dec bl
xor bh,bh
mov ax,3 ; IRQ
mov portirq[bx],al
chkint9a:push ax
mov ah,prstr
mov dx,offset badirq ; say assuming an IRQ
int dos
pop ax
mov cx,10 ; decimal
call valout ; show IRQ
clc
ret
inttest:call serini ; setup port for given IRQ
jc inttes2 ; c = failure
mov dx,modem.mddat
inc dx ; interrupt enable reg (3f9h)
cli
mov intkind,0 ; clear interrupt cause
mov al,2 ; set xmtr holding reg empty interrupt
out dx,al
call delay
mov al,2 ; set xmtr holding reg empty interrupt
out dx,al ; again, because first may be missed
sti
call delay ; wait one millisec for interrupt
mov al,intkind ; interrupt kind
push ax
call serrst ; reset port
pop ax
test al,2 ; check cause of interrupt, ours?
jz inttes2 ; z = no, test failed
clc ; this setup worked
ret
inttes2:stc ; failure
ret
chkint endp
; Test presently selected serial port for having a real 8250 UART.
; Return carry clear if 8250 present,
; else carry set and flags.comflg in ascii digits for system Bios or
; carry set 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
cmp flags.comflg,4 ; non-UART port?
ja chkporx ; a = yes
cmp flags.comflg,0 ; undefined port?
je chkporx ; e = yes
push ax
push dx
mov dx,modem.mdiir ; UART Interrupt Ident reg (3FAh/2FAh)
in al,dx ; read UART's IIR
test al,30h ; are these bits set?
jnz chkpor1 ; nz = yes, not an 8250/16450/16550A
mov dx,modem.mdstat ; line status register
in al,dx ; read to clear UART BI, FE, PE, OE bits
call delay
in al,dx ; these bits should be cleared
test al,8eh ; are they cleared?
jnz chkpor1 ; nz = no, not an 8250/16450/16550A
pop dx
pop ax
clc ; clear carry (say 8250/etc)
ret
chkpor1:pop dx
pop ax
add flags.comflg,'0' ; set Bios usage flag (ascii digit)
chkporx:stc ; set carry (say no 8250/etc)
ret
chkport endp
; Test serial hardware port given in BL (1..4). Return carry set if fail.
tstport proc near
push bx
push es
mov ax,40h ; look at RS232_base [bx] in Bios area 40:00h
mov es,ax
xor bh,bh
dec bl ; count com1 as bl = 0, etc
shl bx,1 ; make bx a word index
mov ax,es:[bx] ; get modem base address into ax
pop es
or ax,ax ; is address zero?
jnz tstport1 ; nz = no, have port address
mov ax,defcom[bx] ; get default COMn port address
tstport1: ; hardware tests
push modem.mdiir ; save these values
push modem.mdstat
add ax,2
mov modem.mdiir,ax ; interrupt identification reg 03fah
add ax,3 ; increment to status port 03fdh
mov modem.mdstat,ax ; set line-status port address
call chkport ; get type of UART support
pop modem.mdstat
pop modem.mdiir
pop bx
ret ; return with carry flag from chkport
tstport endp
ifndef no_network
; Check for presence of IBM EBIOS
; Returns carry clear if EBIOS present, else carry set
chkebios proc near
mov dx,ebport ; port 0..3
mov ax,ebpresent*256+0ffh ; IBM EBIOS presence check
int rs232
jc chkebios1 ; c = failure
or ax,ax ; returns ax = 0 if present
jnz chkebios1 ; nz = not present
clc
ret
chkebios1:stc ; IBM EBIOS not present
ret
chkebios endp
endif ; no_network
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns carry clear.
BAUDST PROC NEAR
mov dx,offset bdtab ; baud rate table, ascii
xor bx,bx ; help is the table itself
mov ah,cmkey ; get keyword
call comnd
jc baudst1 ; c = failure
push bx ; save result
mov ah,cmeol ; get confirmation
call comnd
pop bx
jc baudst1 ; c = failure
call dobaud ; use common code
clc
baudst1:ret
BAUDST ENDP
DOBAUD PROC NEAR
cmp portin,-1 ; port used yet?
jne dobd3 ; ne = yes, go get rate
push bx ; save rate index
mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT command now
pop bx
jnc dobd3 ; nc = success
dobd4: stc
ret ; failure
dobd3: push bx ; save baud rate index
mov al,flags.comflg ; comms port
cmp al,'E' ; EBIOS?
je dobd5 ; e = yes
cmp al,'4' ; UART or Bios?
ja dobd1 ; a = no, networks
call chkport ; check port for real 8250 UART
dobd5: pop bx ; baud rate index
push bx ; check if new rate is valid
mov ax,bx
shl ax,1 ; make a word index
mov bx,offset bddat ; start of table
cmp flags.comflg,'0' ; Bios?
jb dobd0a ; b = no, UART
mov bx,offset clbddat ; use Bios speed parameters
dobd0a: add bx,ax
mov ax,[bx] ; data to output to port
cmp al,0FFh ; unimplemented baud rate?
jne dobd0 ; ne = no
mov ah,prstr
mov dx,offset badbd ; give an error message
int dos
jmp dobd1
dobd0: pop bx ; get baud rate index
push bx
mov si,portval
mov [si].baud,bx ; set the baud rate index
mov dl,flags.comflg ; get coms port (1..4, letters)
cmp dl,4 ; running on a real uart?
jbe dobd2 ; be = yes, the real thing
cmp dl,'E' ; EBIOS?
je dobd6 ; e = yes
cmp dl,'4' ; Bios?
ja dobd1 ; a = no, network
or dl,dl ; zero (undefined port)?
jz dobd1 ; z = yes, just exit
and dl,7 ; use lower three bits
dec dl ; count ports as 0..3 for Bios
jmp short dobd7
dobd6:
ifndef no_network
test nettype,acsi ; using EBIOS.COM?
jnz dobd8 ; nz = not using it
mov dx,ebport ; get EBIOS port (0..3)
endif ; no_network
dobd7: xor dh,dh
xor ah,ah ; set serial port
int rs232 ; Bios: set the parameters
jmp short dobd1 ; and exit
ifndef no_network
dobd8: push bx ; ACSI
call send ; send current buffer first
pop bx
shl bx,1 ; index words
mov ax,clbddat[bx] ; Bios speed settings
mov word ptr xmtbufx,4 ; four bytes in packet
mov ah,acsetmode ; ACSI set mode
mov word ptr xmtbufx+2,ax ; Mode setting
call send ; send speed update to host
jmp short dobd1 ; exit
endif ; no_network
dobd2: pushf
cli ; interrupts off
push ax ; UART, remember value to output
mov dx,modem.mdcom ; LCR -- Initialize baud rate
in al,dx ; get it
mov bl,al ; make a copy
or ax,80H ; turn on DLAB bit to access divisor part
out dx,al
mov dx,modem.mddat
pop ax ; set the baud rate divisor
out dx,al
inc dx ; next address for high part
mov al,ah ; set high part of divisor
out dx,al
mov dx,modem.mdcom ; LCR again
mov al,bl ; get original setting from bl
out dx,al ; restore it
popf ; restore interrupt state
dobd1: pop bx ; restore regs
clc
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
push ax
push bx
mov bx,portval
mov al,flags.comflg
cmp al,4 ; UART?
ja getb3 ; a = no, Bios or Networks
cmp portin,-1 ; port unused?
jne getbud ; ne = no, used, go get rate
mov bl,al ; pass current port ident
call comstrt ; do SET PORT command now
jnc getbud ; nc = success
getb3: pop bx
pop ax
ret ; failure
getbud: push cx ; save some regs
push dx
pushf
cli ; interrupts off
mov dx,modem.mdcom ; get current Line Control Register value
in al,dx
mov bl,al ; save it
or ax,80H ; turn on to access baud rate generator
out dx,al
mov dx,modem.mddat ; Divisor latch
inc dx
in al,dx ; get high order byte
mov ah,al ; save here
dec dx
in al,dx ; get low order byte
push ax
mov dx,modem.mdcom ; Line Control Register
mov al,bl ; restore old value
out dx,al
pop ax
popf ; ints back to normal
cmp ax,0FFFFH ; if no port
je getb2 ; e = no port, bus noise
mov bx,offset bddat ; find rate's offset into table
xor cl,cl ; keep track of index
getb0: cmp ax,[bx] ; observed vs table divisor
je getb1 ; e = found a match
inc cl ; next table index
cmp cl,baudlen ; at the end of the list?
jge getb2 ; ge = yes, quit
add bx,2 ; next table entry
jmp short getb0
getb1: xor ch,ch
mov bx,portval
mov [bx].baud,cx ; set baud rate
getb2: pop dx ; restore regs
pop cx
pop bx
pop ax
clc
ret
GETBAUD ENDP
; Examine incoming communications stream for a packet SOP character.
; Return CX= count of bytes starting at the SOP character (includes SOP)
; and carry clear. Return CX = 0 and carry set if SOP is not present.
; Destroys AL.
; Tells a fib about SOP present if using SET CARRIER on serial links
; and cardet says loss of carrier.
peekcom proc far
cmp flags.comflg,'F' ; Fossil?
je peekc8 ; e = yes
cmp flags.comflg,4 ; UART?
ja peekc9 ; a = no
peekc8: cmp flags.carrier,0 ; worry about Carrier Detect?
je peekc9 ; e = no
cmp dupflg,0 ; full duplex?
jne peekc9 ; e = no, half
test cardet,1 ; 1 = "CD was on, is now off"
jz peekc9 ; z = no
mov flags.cxzflg,'C' ; simulate Control-C interrupt
mov cx,6 ; lie that enough bytes to be read
clc ; say enough for SOP
ret ; so cardet is passed upward now
peekc9: mov cx,count ; qty in circular buffer
cmp cx,6 ; basic NAK
jb peekc4 ; b = two few chars, get more
push bx
cli ; interrupts off, to keep srcpnt & count consistent
mov bx,srcpnt ; address of next available slot in buffer
sub bx,cx ; minus number of unread chars in buffer
cmp bx,offset source ; located before start of buf?
jae peekc1 ; ae = no
add bx,bufsiz ; else do arithmetic modulo bufsiz
peekc1: mov al,[bx]
cmp al,trans.rsoh ; packet receive SOP?
je peekc3 ; e = yes
inc bx
cmp bx,offset source+bufsiz ; beyond end of buffer?
jb peekc2 ; b = no
mov bx,offset source ; wrap around
peekc2: loop peekc1 ; keep looking
sti
pop bx
stc ; set carry for no SOP
ret
peekc3: sti ; interrupts back on now
pop bx
inc cx ; include SOP in count
clc ; say SOP found
ret ; CX has count remaining
peekc4: push bx ; read from port, add to buffer
mov bx,portval
push si ; used by packet routines
call [bx].rcvproc ; read routine
pop si
jc peekc7 ; c = nothing available
cmp count,0 ; something put in buffer?
jne peekc7 ; ne = yes, go read from buffer
mov bx,srcpnt ; where next read would be
inc bx ; add to buffer
cmp bx,offset source+bufsiz ; pointing beyond end of buffer?
jb peekc5 ; b = no
mov bx,offset source ; wrap pointer, modulo bufsiz
peekc5: cli
mov [bx],al ; store byte
mov srcpnt,bx ; update pointer to next free slot
inc count
cmp count,bufsiz ; count more that buffer size?
jbe peekc6 ; be = no
mov count,bufsiz ; limit to bufsiz (tells the truth)
peekc6: sti
peekc7: pop bx
cmp count,6 ; enough for basic NAK?
jae peekcom ; ae = yes, repeat examination
xor cx,cx ; return count of zero
stc ; say no data
ret
peekcom endp
; Get Char from serial port buffer.
; returns carry set if no character available at port, otherwise
; returns carry clear with char in al, # of chars in buffer in dx.
prtchr proc near
cmp holdscr,0 ; Holdscreen in effect?
jne prtch3 ; ne = yes, do not read
call chkxon ; see if we need to send XON
cmp repflg,0 ; REPLAY?
je prtch1 ; e = no
jmp prtchrpl ; yes, do replay file reading
prtch1: cmp count,0 ; is buffer empty?
jne prtch4 ; ne = no, read from it
push bx
mov bx,portval
call [bx].rcvproc ; read routine
pop bx ; fall through to grab new char
jc prtch3 ; c = nothing available
cmp count,0 ; something put in buffer?
jne prtch4 ; ne = yes, go read from buffer
prtch2: inc dx
clc ; return single char already in AL
ret
prtch3: xor dx,dx ; return count of zero
stc ; say no data
ret
prtch4: 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 prtch5 ; ae = no
add si,bufsiz ; else do arithmetic modulo bufsiz
prtch5: lodsb ; 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
clc
ret
prtchr endp
uartrcv proc near ; UART receive
cmp flags.carrier,0 ; worry about Carrier Detect?
je uartrcv1 ; e = no
cmp dupflg,0 ; full duplex?
jne uartrcv1 ; e = no, half
push dx
mov dx,modem.mddat
add dx,6 ; modem status reg 3feh
in al,dx ; 03feh, modem status reg
pop dx
and al,80h ; get CD bit
jnz uartrcv2 ; nz = CD is on now
test cardet,80h ; previous CD state
jz uartrcv2 ; z = was off
mov al,01h ; say was ON but is now OFF
mov flags.cxzflg,'C' ; simulate Control-C interrupt
uartrcv2:mov cardet,al ; preserve as global
cmp al,1 ; carrier dropped?
jne uartrcv1 ; ne = no
push bx
mov bx,portval
mov [bx].portrdy,0 ; say port is not ready
pop bx
mov kbdflg,'C' ; exit Connect mode
uartrcv1:stc ; say not returning char in al here
ret ; interrupt driven so no work here
uartrcv endp
biosrcv proc near ; Bios calls
xor dh,dh ; assume port 1, find current port
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz biosrc1 ; z = yes, don't access it
and dl,7 ; use low three bits
dec dl ; address ports as 0..3 for Bios
mov ah,3 ; check port status, std Bios calls
int rs232 ; Bios call
cmp flags.carrier,0 ; worry about Carrier Detect?
je biosrc4 ; e = no
and al,80h ; get CD bit
jnz biosrc3 ; nz = CD is on now
test cardet,80h ; previous CD state
jz biosrc4 ; z = was off
mov al,01h ; say was ON but is now OFF
mov flags.cxzflg,'C' ; simulate Control-C interrupt
biosrc3:mov cardet,al ; preserve as global
biosrc4:test ah,mdminp ; data ready?
jnz biosrc2 ; nz = yes, get one
biosrc1:cmp flags.carrier,0 ; worry about Carrier Detect?
je biosrc5 ; e = no
cmp dupflg,0 ; full duplex?
jne biosrc4 ; e = no, half
test cardet,1 ; 1 = "CD was on, is now off"
jz biosrc5 ; z = no
mov flags.cxzflg,'C' ; simulate Control-C interrupt
push bx
mov bx,portval
mov [bx].portrdy,0
pop bx
mov kbdflg,'C' ; exit Connect mode
biosrc5:stc ; say not returning char in al here
ret
biosrc2:mov ah,2 ; receive a char into al
int rs232 ; Bios call
test ah,8ch ; timeout, framing error, parity error?
jnz biosrc1 ; nz = error, no char
jmp short schrcv ; single char read post processor
biosrcv endp
schrcv proc near ; single char read final filter
test flowcnt,2 ; using input XON/XOFF flow control?
jz schrcv3 ; z = no
mov ah,al ; get copy of character
and ah,parmsk ; strip parity, if any, before testing
cmp ah,flowoff ; acting on XOFF?
jne schrcv2 ; ne = no, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF?
jne schrcv1 ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; set the flag saying XOFF received
schrcv1:stc ; say not returning char in al here
ret
schrcv2:cmp ah,flowon ; acting on XON?
jne schrcv3 ; ne = no, go on
mov xofrcv,off ; clear the XOFF received flag
xor dx,dx
stc
ret ; no data to return
schrcv3:xor ah,ah
clc ; return char in al
ret ; expect count=0
schrcv endp
; Fossil block receive
fosrcv proc near
mov dx,fossil_port ; get port number (1..4)
mov ah,fossil_portst ; check port status, std Bios calls
int rs232 ; Bios call
cmp flags.carrier,0 ; care abour carrier?
je fosrcv4 ; e = no
and al,80h ; get CD bit
jnz fosrcv3 ; nz = CD is on now
test cardet,80h ; previous CD state
jz fosrcv4 ; z = was off
mov al,01h ; say was ON but is now OFF
mov flags.cxzflg,'C' ; simulate Control-C interrupt
fosrcv3:mov cardet,al ; preserve as global
fosrcv4:test ah,mdminp ; data ready?
jnz fosrcv2 ; nz = yes, get one
fosrcv1:cmp flags.carrier,0 ; worry about Carrier Detect?
je fosrcv5 ; e = no
cmp dupflg,0 ; full duplex?
jne fosrcv4 ; e = no, half
test cardet,1 ; 1 = "CD was on, is now off"
jz fosrcv5 ; z = no
fosrcv6:call serrst ; close port
mov kbdflg,'C' ; exit Connect mode
fosrcv5:stc ; say not returning char in al here
ret
fosrcv2:push es
mov ax,seg rcvbuf
mov es,ax
mov cx,nbuflen ; buffer length
mov di,offset rcvbuf
mov ah,fossil_blkrd ; receive block
xor al,al
int rs232 ; Bios call
pop es
or ax,ax ; count received
jz fosrcv1 ; z = no char
cmp ax,0ffffh ; error condition?
je fosrcv6 ; e = yes, shut down port
cmp ax,fossil_blkrd*256 ; complete no-op?
je fosrcv6 ; e = yes
mov rcv.scb_length,ax ; count received
mov rcv.scb_baddr,di ; offset of receive buffer
jmp blkrcv ; block read post processor
fosrcv endp
ifdef no_terminal
; REPLAY, read char from a file
prtchrpl proc near
stc
ret
prtchrpl endp
endif ; no_terminal
ifndef no_terminal
prtchrpl proc near
cmp repflg,2 ; at EOF already?
jne prtchrp1 ; ne = no
stc ; yes, return with no char
ret
prtchrp1:push bx
push cx
xor dx,dx
test xofsnt,usron ; user level xoff sent?
jz prtchrp2 ; z = no
pop cx ; suppress reading here
pop bx
stc ; say not returning char in al here
ret
prtchrp2:test tekflg,tek_active ; doing graphics mode?
jnz prtchrp3 ; nz = yes, do not insert pauses
in al,ppi_port ; delay
in al,ppi_port
in al,ppi_port ; burn some bus cycles
in al,ppi_port ; because a 1 ms wait is too long
in al,ppi_port
prtchrp3:mov ah,readf2
mov bx,diskio.handle ; file handle
mov cx,1 ; read one char
mov dx,offset decbuf ; to this buffer
int dos
jc prtchrp4 ; c = read failure
cmp ax,cx ; read the byte?
jne prtchrp4 ; ne = no
pop cx
pop bx
mov al,decbuf ; get the char into al
clc
ret ; return it
prtchrp4:call beep
mov ax,40 ; wait 40 millisec
call pcwait
call beep
mov repflg,2 ; say at EOF
pop cx
pop bx
stc ; say not returning char in al here
ret
prtchrpl endp
endif ; no_terminal
ifndef no_network
ebircv proc near ; EBIOS calls
mov dx,ebport ; port 0..3
mov ah,ebrcv ; IBM EBIOS receive /no wait
int rs232 ; does line check then char ready chk
test ah,8ch ; timeout, framing error, parity error?
jnz ebircv2 ; nz = error, no char
jmp schrcv ; z = success, process char in AL
ebircv2:stc ; say not returning char in al here
ret
ebircv endp
; DECnet receive routine
DECRCV PROC NEAR
test nettype,declat ; LAT interface?
jz decrcv1 ; z = not LAT
mov dx,lathand
or dx,dx ; invalid handle?
jz decrcv1 ; z = yes, try CTERM
mov cx,bufsiz ; final receiver buffer length
sub cx,count ; minus occupancy
cmp cx,254 ; too big for broken DEC LAT?
jbe decrcv5 ; be = no
mov cx,254 ; limit to byte sized length
decrcv5:push es
mov ax,seg rcvbuf
mov es,ax ; es:bx will point to rcvbuf
mov bx,offset rcvbuf
mov ah,latreadb ; read a block to es:bx, max len cx
mov dx,lathand
int latint
pop es
test ah,80h ; ah is status
jnz decrcv6 ; nz = error of some kind
jcxz decrcv6 ; z = no received bytes, do status
mov rcv.scb_length,cx ; bytes received, setup blkrcv
call blkrcv ; process buffer
stc ; say not returning char in al here
ret
; non-SCB status check, slower and much safer
decrcv6:mov ah,latstat ; get status
mov dx,lathand
int latint
test ah,4 ; session not active?
jnz decrcv3 ; nz = yes, no valid session
stc ; say not returning char in al here
ret
; end alterntive code
; push es
; push bx
; les bx,latscbptr
; test es:[bx].sstatus,18h ; status: stop slot or circuit failure
; pop bx
; pop es
; jnz decrcv4 ; nz = yes, no valid session
; stc ; return no char
; ret
decrcv1:test nettype,decnet ; is CTERM active?
jz decrcv3 ; z = no
mov dx,decneth ; handle
or dx,dx ; legal?
jz decrcv3 ; z = no
mov ax,dcstat ; CTERM status
int decint
test ah,0c0h ; no session, DECnet error?
jnz decrcv3 ; nz = yes, stop here
; test ah,1 ; data available?
; jz decrcv4 ; z = no
; data available test fails under flow control, maybe a Cterm bug.
mov ax,dread ; read char via CTERM
int decint
test ah,80h ; char received?
jnz decrcv4 ; nz = no
decrcv2:jmp schrcv ; use common completion code
decrcv3:call decclose ; close connection
test flags.remflg,dserver ; server mode?
jz decrcv4 ; z = no
call serini ; reinitialize it for new session
decrcv4:stc ; say not returning char in al here
ret
DECRCV ENDP
; NetBios Receive packet routine. If a new packet has been received unpack
; the data and request a new one with no-wait option. If a receive request is
; still outstanding just return with no new data.
; Return carry clear if success. If failure, reset serial port (Server mode
; reinits serial port). Return carry set. No entry setup needed.
RECEIVE PROC NEAR ; receive network session pkt
cmp pcnet,1 ; net ready yet?
jbe receiv3 ; be = no, declare a broken session
cmp rposted,1 ; is a request outstanding now?
je receiv4 ; e = yes (1), don't do another
jb receiv1 ; b = no (0), do one now
call receiv2 ; have new pkt, unpack, do new recv
jnc receiv1 ; nc = success
ret ; else return carry set
receiv1:mov rposted,1 ; say posting a receive now
mov rcv.scb_length,nbuflen ; length of input buffer
mov rcv.scb_cmd,nreceive+nowait ; receive, no wait
push bx
mov bx,offset rcv ; setup pointer to scb
call nbsession
pop bx
stc ; set carry to say no char yet
ret
receiv2:mov al,rcv.scb_err ; returned status
or al,al ; success?
jz receiv5 ; z = yes, get the data
cmp al,npending ; pending receive?
je receiv4 ; e = yes
cmp al,6 ; message incomplete?
je receiv5 ; e = yes, get what we have anyway
cmp al,0bh ; receive cancelled?
je receiv3 ; e = yes
cmp al,18h ; session ended abnormally?
jbe receiv3 ; e = yes, b = other normal errors
mov ah,prstr
mov dx,offset recmsg ; give error message
int dos
mov al,rcv.scb_err ; get error code
xor ah,ah
call decout ; show error code
; Error return
receiv3:mov pcnet,1 ; say session is broken
call serrst ; close the connection
cmp lposted,1 ; Listen posted?
je receiv3a ; e = yes, stay alive
cmp xmt.scb_rname,'*' ; behaving as a Listner?
je receiv3a ; e = yes, stay alive
test flags.remflg,dserver ; server mode?
jz receiv4 ; z = no
receiv3a:call serini ; reinitialize it for new session
receiv4:stc ; say not returning char in al here
ret
receiv5:mov rposted,0 ; clear interlock flag
test nettype,acsi ; ACSI?
jnz receiv6 ; nz = yes
jmp blkrcv ; process block of data
receiv6:jmp acsircv ; process special format block data
RECEIVE ENDP
endif ; no_network
; Block receive transfer and flow control scan routine
; Enter with DS:rcv.scb_baddr pointing at source buffer (rcvbuf),
; and rcv.scb_length holding incoming byte count.
; Destroys reg BX
; Shared by NetBios, Novell, Opennet, Ungerman Bass, 3ComBAPI, TCP/IP, etc
blkrcv proc near
push cx ; new packet has been received
push dx ; copy contents to circ buf source
push si
mov dh,flowon
mov dl,flowoff
mov si,rcv.scb_baddr ; source of text
mov bx,srcpnt ; address of destination buffer slot
blkrcv6:mov cx,rcv.scb_length ; get remaining returned byte count
jcxz blkrcv13 ; z = nothing there
mov ax,offset source+bufsiz ; end of destination buffer+1
sub ax,bx ; space remaining at end of buffer
jns blkrcv7 ; should never be negative
neg ax ; but if so invert
blkrcv7:cmp ax,cx ; buffer ending vs incoming byte count
jge blkrcv8 ; ge = enough for this pass
mov cx,ax ; limit this pass to end of the buffer
blkrcv8:sub rcv.scb_length,cx ; deduct chars done in this pass
add count,cx ; add them to the count
cld ; inner loop "block" transfer
test flowcnt,2 ; doing input XON/XOFF flow control?
jz blkrcv20 ; z = no
blkrcv9:lodsb ; get byte from rcvbuf to al
mov ah,al ; get copy of character
and ah,parmsk ; strip parity, if any, before testing
cmp ah,dl ; acting on Xoff?
jne blkrcv10 ; ne = no
cmp xofsnt,0 ; have we sent an XOFF?
jne blkrcv12 ; ne = yes, ignore this XOFF char
mov xofrcv,bufon ; set flag saying buffer XOFF received
dec count ; uncount flow control
jmp short blkrcv12 ; and skip this character
blkrcv10:cmp ah,dh ; acting on XON?
jne blkrcv11 ; ne = no, go on
mov xofrcv,off ; clear the XOFF received flag
dec count ; uncount flow control
jmp short blkrcv12 ; and skip this character
blkrcv11:mov [bx],al ; store new char in buffer "source"
inc bx
blkrcv12:loop blkrcv9 ; bottom of inner loop
jmp short blkrcv22
blkrcv20:push es ; no flow control, just do copy
push di
mov ax,ds
mov es,ax
mov di,bx ; destination
shr cx,1 ; prep for word moves
jnc blkrcv21 ; nc = even number of bytes
movsb
blkrcv21:rep movsw ; do quick copy
mov bx,di ; update destination pointer
pop di
pop es
; update buffer pointer for wrapping
blkrcv22:cmp bx,offset source+bufsiz ; pointing beyond end of buffer?
jb blkrcv6 ; b = no, do next pass
mov bx,offset source ; wrap pointer, modulo bufsiz
jmp short blkrcv6 ; do next pass
blkrcv13:mov srcpnt,bx ; update pointer to next free slot
cmp count,bufsiz ; count more that buffer size?
jbe blkrcv14 ; be = no
mov count,bufsiz ; limit to bufsiz (tells the truth)
blkrcv14:pop si
pop dx
pop cx
stc ; say no char in al from us
ret
blkrcv endp
ifndef no_network
; ACSI block receive transfer and flow control scan routine
; Enter with DS:rcv.scb_baddr pointing at source buffer (rcvbuf),
; and rcv.scb_length holding incoming byte count.
; Destroys regs AX and BX.
; Format of packet: int count of entire block, then [char, status] byte pairs
acsircv proc near
push cx ; new packet has been received
push dx ; copy contents to circ buf source
push si
mov dh,flowon
mov dl,flowoff
mov bx,srcpnt ; address of destination buffer slot
mov si,rcv.scb_baddr ; source of text
cld
lodsw ; get internal length word
mov cx,rcv.scb_length ; get block length
mov rcv.scb_length,0 ; clear counter
sub cx,2 ; data bytes remaining in block
cmp ax,cx ; internal vs external count
jae acsrcv1 ; ae=internal is gt or equal to ext
mov cx,ax ; use shorter internal count
acsrcv1:shr cx,1 ; count words in block
jcxz acsrcv14 ; z = nothing there
acsrcv9:lodsw ; get char+status bytes from rcvbuf
test ah,80h ; status, is it a command?
jnz acsrcv12 ; nz = yes, ignore the pair
test flowcnt,2 ; using input XON/XOFF flow control?
jz acsrcv11 ; z = no
mov ah,al ; get copy of character
and ah,parmsk ; strip parity, if any, before testing
cmp ah,dl ; acting on Xoff?
jne acsrcv10 ; ne = no
cmp xofsnt,0 ; have we sent an XOFF?
jne acsrcv12 ; ne = yes, ignore this XOFF char
mov xofrcv,bufon ; set flag saying buffer XOFF received
jmp short acsrcv12 ; and skip this character
acsrcv10:cmp ah,dh ; acting on XON?
jne acsrcv11 ; ne = no, go on
mov xofrcv,off ; clear the XOFF received flag
jmp short acsrcv12 ; and skip this character
acsrcv11:mov [bx],al ; store new char in buffer "source"
inc bx
inc count ; add it to the count
cmp bx,offset source+bufsiz ; pointing beyond end of buffer?
jb acsrcv12 ; b = no
mov bx,offset source ; wrap pointer, modulo bufsiz
acsrcv12:loop acsrcv9
acsrcv13:mov srcpnt,bx ; update pointer to next free slot
cmp count,bufsiz ; count more that buffer size?
jbe acsrcv14 ; be = no
mov count,bufsiz ; limit to bufsiz (tells the truth)
acsrcv14:pop si
pop dx
pop cx
stc ; say no char in al from us
ret
acsircv endp
; NetBios Receive post processing interrupt routine.
; Sets rposted interlock flag
RPOST PROC NEAR ; NetBios receive post interrupt routine
push ds
push ax
mov ax,data ; reestablish data segment
mov ds,ax
mov rposted,2 ; set interlock flag to completed
pop ax
pop ds
iret ; return from interrupt
RPOST endp
; TES block mode receive, uses blkrcv to process results
TESRCV proc near
push di
push cx
push dx
push es
mov ax,data
mov es,ax ; es:di will point to rcvbuf
mov di,offset rcvbuf
mov cx,nbuflen ; buffer length
mov dx,tesport ; operational port
mov ah,tesbread ; block read
int rs232
jcxz tesrcv1 ; z = no characters read
mov rcv.scb_length,cx ; prepare for receive call
call blkrcv ; process rcvbuf
jmp short tesrcv2
tesrcv1:call tesstate ; get session status to AH
and ah,7fh ; trim high bit (transition states)
or ah,ah ; session active?
jnz tesrcv2 ; nz = yes, carry on
call tesclose ; close our end
tesrcv2:pop es
pop dx
pop cx
pop di
stc ; say not returning char in al here
ret
TESRCV endp
; Ungermann-Bass NETCI port receive characters routine. Receive one or more
; characters. Calls the blkrcv routine to transfer character to main source
; circular buffer. Return carry clear if success.
UBRECV PROC near
push cx
push es
mov ax,data
mov es,ax ; es:bx will point to rcvbuf
mov bx,offset rcvbuf
mov cx,nbuflen ; buffer length
ubrecv2:test nettype,bapi+tcpnet ; 3Com BAPI or TCP Telnet interface?
jz ubrecv2a ; z = no
mov ah,bapiread
xor dh,dh ; session 0
ifndef no_tcp
test nettype,tcpnet ; TCP/IP Telnet?
jz ubrecv2d ; z = no
call ktcpcom ; Far call Telnet code
jmp short ubrecv2e
endif ; no_tcp
ubrecv2d:int bapiint
ubrecv2e:cmp ah,3 ; status, no session and above
jb ubrecv3 ; b = no, successful?
jmp short ubrecv2b ; broken connection, terminate it
ubrecv2a:test nettype,telapi ; Novell TELAPI?
jz ubrecv2c ; z = no, use Int 6Bh kind
push si
push bx
mov si,bx ; use es:si for buffer address
mov bx,telses ; session number
mov ah,telread
int rs232
pop bx
pop si
xchg ax,cx ; byte count returned in AX
jcxz ubrecv2b ; z = connection broken
or cx,cx
jns ubrecv3 ; ns = no error
cmp cx,-35 ; status of no data?
jne ubrecv2b ; ne = no
xor cx,cx ; mimic no data
jmp short ubrec1
ubrecv2b:call ubclose
jmp short ubrec1
ubrecv2c:test nettype,netone ; UB?
jz ubrec1 ; z = no, do nothing
mov ax, nciread ; function 1 (receive) port 0 [ohl]
int netci ; get characters [ohl]
ubrecv3:jcxz ubrec1 ; cx = z = nothing to do
mov rcv.scb_length,cx ; prepare for rpost call
call blkrcv ; process buffer
ubrec1: pop es
pop cx
stc ; say not returning char in al here
ret
UBRECV ENDP
; Beame & Whiteside TCP receive routine [JRS]
bwrecv proc near ; [JRS]
test nettype,bwtcp ; active?
jnz bwrecv1 ; nz = yes
stc
ret
bwrecv1:push di ; [JRS] save the environment
push si ; [JRS]
push dx ; [JRS]
push cx ; [JRS]
push bx ; [JRS]
mov ah,readf2 ; [JRS] read from "file"
mov bx,bwhandle ; [JRS] device handle
or bx,bx
jz bwrecv4 ; z = invalid handle
mov cx,nbuflen-4 ; number of bytes to read - safety
mov dx,offset rcvbuf ; [JRS] data buffer is DS:DX
int dos ; [JRS] ask dos to get it
jc bwrecv5 ; [JRS] c = no data available
mov cx,ax ; [JRS] get the number of bytes read
jcxz bwrecv4 ; [JRS] no chars read is a hangup
cmp ax,nbuflen-4 ; check on sanity
ja bwrecv5 ; a = error of some kind, ignore
mov si,offset rcvbuf
call bwtnopt ; do options scanning
jmp short bwrecv5
bwrecv4:call bwclose ; read failed, quit
bwrecv5:pop bx ; [JRS] restore environment
pop cx ; [JRS]
pop dx ; [JRS]
pop si ; [JRS]
pop di ; [JRS]
stc ; [JRS] flag no characters read
ret ; [JRS]
bwrecv endp ; [JRS]
; Beame & Whiteside telnet options scanner and processor
; Enter with newly read material in ds:si, of length CX bytes
bwtnopt proc near
or cx,cx
jle bwtnopt1 ; le = nothing to do
cmp optstate,0 ; outside IAC string?
je bwtnopt2 ; e = yes
jmp bwtnopt20 ; do options
bwtnopt1:ret
bwtnopt2:push cx
push es
mov ax,seg rcvbuf ; make es:di the receiver buffer
mov es,ax
mov di,si
mov al,IAC ; IAC
cld
repne scasb ; look for IAC
pop es
pop cx
mov ax,di ; points one byte after break
jne bwtnopt3 ; ne = no IAC
dec ax ; backup to IAC
bwtnopt3:sub ax,si ; minus starting offset
sub cx,ax ; original count - <before IAC>
mov rcv.scb_length,ax ; data length before IAC
mov rcv.scb_baddr,si ; source of text
add si,ax ; starting point for IAC
or ax,ax ; any leading text?
jz bwtnopt4 ; z = nothing to block receive upon
call blkrcv ; dispose of it, saves si and cx
bwtnopt4:or cx,cx ; bytes remaining in buffer
jg bwtnopt5 ; if positive then si == IAC byte
xor cx,cx ; force zero
ret
bwtnopt5:inc si
dec cx ; skip IAC
mov optstate,2 ; read two more chars
jmp bwtnopt ; repeat
bwtnopt20:cmp optstate,2 ; reading 1st char after IAC?
jb bwtnopt23 ; b = no
dec cx ; read the char
lodsb
cmp al,SB ; before legal options?
jae bwtnopt22 ; ae = no
inc si ; recover char
inc cx
mov optstate,0 ; clear Options machine
jmp bwtnopt ; continue
bwtnopt22:mov option1,al ; save first Option byte
mov optstate,1 ; get one more byte
jmp bwtnopt ; get the second Options byte
bwtnopt23:mov optstate,0 ; read second char after IAC
dec cx ; read the char
lodsb
mov option2,al ; second options byte
mov ah,option1
mov bx,portval
mov bl,[bx].ecoflg ; echo status
; decode options and respond
cmp al,TELOPT_ECHO ; Echo?
jne bwtnopt30 ; ne = no
cmp ah,WILL ; remote host will echo?
jne bwtnopt26 ; ne = no
cmp bl,0 ; are we doing local echo?
je bwtnopt29 ; e = no
mov ah,DO ; say please echo
call bwsendiac
xor bl,bl ; say we should not echo
call setecho ; set our echo state
jmp bwtnopt
bwtnopt26:cmp ah,WONT ; remote host won't supply echo?
jne bwtnopt28 ; ne = no
cmp bl,0 ; are we doing local echo?
jne bwtnopt29 ; ne = yes
mov ah,DONT
call bwsendiac
mov bl,lclecho ; do local echoing
call setecho ; set local echoing state
jmp bwtnopt
bwtnopt28:cmp ah,DO ; remote host wants us to echo?
jne bwtnopt29 ; ne = no
mov ah,WONT ; decline
call bwsendiac
bwtnopt29:jmp bwtnopt
bwtnopt30:cmp al,TELOPT_SGA ; SGA?
jne bwtnopt40 ; ne = no
cmp ah,WONT ; host won't do SGAs?
jne bwtnopt33 ; ne = no
cmp sgaflg,0 ; our state is don't too?
jne bwtnopt35 ; ne = yes
inc sgaflg ; change state
mov ah,DONT ; say please don't
call bwsendiac
cmp bl,0 ; doing local echo?
jne bwtnopt35 ; ne = yes
mov bl,lclecho ; change to local echoing
call setecho
jmp bwtnopt ; continue
bwtnopt33:cmp ah,WILL ; host will use Go Aheads?
jne bwtnopt35 ; ne = no
cmp sgaflg,0 ; doing SGAs?
jne bwtnopt35 ; ne = no
mov sgaflg,0 ; change to doing them
mov ah,DO
call bwsendiac
bwtnopt35:jmp bwtnopt
bwtnopt40:cmp ah,WILL ; all other Options
jne bwtnopt41 ; ne = no
mov ah,DONT ; say do not
call bwsendiac ; respond
jmp bwtnopt43 ; continue
bwtnopt41:cmp ah,DO
jne bwtnopt42
mov ah,WONT ; say we won't
call bwsendiac
mov ah,DONT ; and host should not either
call bwsendiac
jmp bwtnopt43 ; continue
bwtnopt42:cmp ah,DONT
jne bwtnopt43
mov ah,WONT ; say we won't
call bwsendiac
bwtnopt43:jmp bwtnopt ; continue
bwtnopt endp
; Beame & Whiteside, send IAC byte1 byte2, where byte 1 is in AH
; and byte 2 is in option2
bwsendiac proc near
push cx
push si
push ax
mov ah,IAC ; send IAC
call outchr
pop ax ; send command byte
call outchr
mov ah,option2 ; send response byte
call outchr
pop si
pop cx
ret
bwsendiac endp
; Update local-echo status from B&W Telnet Options negotiations
; Enter with BL = 0 or lclecho, to clear or set local-echo
setecho proc near
and yflags,not lclecho ; assume no local echo in emulator
or yflags,bl ; set terminal emulator
push si
mov si,portval
mov [si].ecoflg,bl ; set mainline SET echo flag
pop si
ifndef no_terminal
cmp ttyact,0 ; acting as a Terminal?
je setecho1 ; e = no
push cx
push si
call dword ptr ftogmod ; toggle mode line
call dword ptr ftogmod ; and again
pop si
pop cx
endif ; no_terminal
setecho1:ret
setecho endp
endif ; no_network
; Put the char in AH to the serial port, assumimg the port is active.
; Returns carry clear if success, else carry set.
; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to
; prevent confusion of flow control logic at top of outchr; used by receiver
; buffer high/low water mark flow control code. [jrd]
outchr proc near
cmp quechar,0 ; char queued for transmission?
je outch0 ; e = no, no XOFF queued
xchg ah,quechar ; save current char
cmp ah,flowoff ; really XOFF?
jne outch0a ; ne = no
mov xofsnt,bufon ; we are senting XOFF at buffer level
outch0a:call outch2 ; send queued char (XOFF usually)
xor ah,ah ; replacement for queued char, none
xchg ah,quechar ; recover current char, send it
outch0: test flowcnt,1 ; doing output XON/XOFF flow control?
jz outch2 ; z = no, just continue
cmp ah,flowoff ; sending xoff?
jne outch1 ; ne = no
mov xofsnt,usron ; indicate user level xoff being sent
jmp short outch1b
outch1: and xofsnt,not usron ; cancel user level xoff
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
push cx ; save reg
mov ch,15 ; 15 sec timeout interval
xor cl,cl ; convert to 4 millsec increments
outch1a:cmp xofrcv,off ; are we being held (xoff received)?
je outch1c ; e = no - it's OK to go on
push ax
mov ax,4 ; 4 millisec wait loop
call pcwait
pop ax
loop outch1a ; and try it again
mov xofrcv,off ; timed out, force it off
cmp ttyact,0 ; in Connect mode?
je outch1c ; e = no
push ax ; save char around the call
call beep ; let user know we are xoff-ed
pop ax ; but are sending anyway
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
cmp repflg,0 ; doing REPLAY from a file?
je outch3 ; e = no
and al,7fh ; strip parity
cmp al,'C'-40h ; Control-C? (to exit playback mode)
je outch2a ; e = yes, return failure
clc ; return success, send nothing
ret
outch2a:stc ; failure, to exit playback mode
ret
outch3: push bx
mov bx,portval ; output char is in register AH
call [bx].sndproc ; output processing routine
pop bx
ret
outchr endp
uartsnd proc near ; UART send
push cx
push dx
push bx
mov bx,portval
cmp [bx].portrdy,0 ; is port ready?
pop bx
je uartsn8 ; e = no
cmp flags.carrier,0 ; worry about carrier detect?
je uartsn9a ; e = no
cmp dupflg,0 ; full duplex?
jne uartsn1 ; ne = no, half
mov dx,modem.mddat
add dx,6 ; modem status reg 3feh
in al,dx ; 03feh, modem status reg
and al,80h ; get CD bit
jnz uartsn9 ; nz = CD is on now
test cardet,80h ; previous CD state
jz uartsn9 ; z = was off
mov al,01h ; say was ON but is now OFF
mov flags.cxzflg,'C' ; simulate Control-C interrupt
uartsn9:mov cardet,al ; preserve as global
cmp al,1 ; carrier dropped?
je uartsn8 ; e = yes, fail the operation
uartsn9a:test flowcnt,4 ; using RTS to control incoming chars?
jz uartsn3 ; z = no
mov cx,8000 ; ~10 seconds worth of waiting on CTS
jmp short uartsn2 ; do CTS test/waiting
; Half Duplex here
uartsn1:mov dx,modem.mdstat ; 3fdh
dec dx
in al,dx ; modem control reg 3fch
or al,2 ; assert RTS for hardware transmit
push ax
in al,ppi_port ; delay
pop ax
mov dx,modem.mdstat ; 3fdh, waste cycles here
dec dx ; 3fch
out dx,al
add dx,2 ; modem status register 3feh
in al,ppi_port ; delay
in al,ppi_port ; delay
in al,dx ; get DSR status
test al,20h ; ignore CTS if DSR is not asserted
jz uartsn3 ; z = DSR not asserted
mov cx,8000 ; ~10 seconds worth of waiting on CTS
; Half Duplex and RTS/CTS flow cont.
uartsn2:mov dx,modem.mdstat ; 3fdh
inc dx ; 3feh
in al,dx ; wait on CTS (ah has output char)
test al,10h ; is CTS asserted? (dx = 3feh)
jnz uartsn3 ; nz = yes
push ax ; preserve char in ah
mov ax,1 ; wait one millisec
call pcwait
pop ax
loop uartsn2 ; test again
push ax
call beep ; timeout, make non-fatal
pop ax ; continue to send the char
cmp dupflg,0 ; half duplex?
jne uartsn8 ; ne = yes, fail at this point
uartsn3:push bx
mov bx,portval
cmp [bx].baud,Bsplit ; split-speed mode?
pop bx
jne uartsn4 ; ne = no
mov al,ah ; [pslms]
call out75b ; do split speed sending at 75 baud
pop dx
pop cx
ret ; out75b sets/clears carry bit
uartsn4:mov cx,0ffffh ; try counter
uartsn4a:mov dx,modem.mdstat ; get line status
in al,dx
test al,20H ; Transmitter (THRE) ready?
jnz uartsn5 ; nz = yes
in al,ppi_port ; delay
in al,ppi_port ; delay
in al,ppi_port ; delay
loop uartsn4a
jmp short uartsn8 ; Timeout
uartsn5:mov al,ah ; Now send it out
mov dx,modem.mddat ; use a little time
push ax
in al,ppi_port ; delay
pop ax
out dx,al
cmp dupflg,0 ; full duplex?
je uartsn7 ; e = yes
; half duplex
cmp al,trans.seol ; End of Line char?
jne uartsn7 ; ne = no
xor cx,cx ; loop counter
uartsn6:mov dx,modem.mdstat ; modem line status reg
in al,dx ; read transmitter shift reg empty bit
push ax
in al,ppi_port ; delay, wait for char to be sent
in al,ppi_port
in al,ppi_port
in al,ppi_port
pop ax
test al,40h ; is it empty?
loopz uartsn6 ; z = no, not yet
mov dx,modem.mdstat
dec dx ; modem control reg 3fch
in al,dx
and al,not 2 ; unassert RTS (half duplex turn)
push ax
in al,ppi_port ; delay
pop ax
out dx,al
uartsn7:pop dx ; exit success
pop cx
clc
ret
uartsn8:call beep
mov kbdflg,'C' ; exit connect mode
pop dx ; exit failure
pop cx
stc
ret
uartsnd endp
biossnd proc near ; Bios send
push cx ; find current port
mov cx,5 ; retry counter
push dx
xor dh,dh ; assume port 1
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz biossn3 ; z = yes, don't access it
and dl,7 ; use lower three bits
dec dl ; address ports as 0..3 for Bios
mov al,ah ; now send it out
biossn2:push ax ; save char
mov ah,1 ; send char
int rs232 ; bios send
shl ah,1 ; set carry if failure
pop ax ; recover char
jnc biossn4 ; nc = success
push ax
mov ax,60 ; wait 60 ms
call pcwait ; this must preserve cx and dx
pop ax ; recover char
loop biossn2 ; try again
biossn3:push bx
mov bx,portval
mov [bx].portrdy,0 ; say port is not ready
pop bx
mov kbdflg,'C' ; exit Connect mode
stc ; fail through here
biossn4:pop dx
pop cx
ret ; c set = failure, else success
biossnd endp
; Fossil block send
fossnd proc near
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
inc xmtcnt ; count of items in this buffer
and ah,7fh ; strip parity
cmp xmtcnt,length xmtbuf ; is buffer full now?
jae fossnd2 ; ae = buffer is full, send it now
cmp ah,trans.seol ; end of packet?
je fossnd2 ; e = yes, send buffer
test flowcnt,1 ; using output XON/XOFF flow control?
jz fossnd1 ; z = no
cmp ah,flowon ; flow control?
je fossnd2 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je fossnd2
fossnd1:cmp ttyact,0 ; are we in Connect mode?
jne fossnd2 ; ne = yes, send now
clc ; e = no, wait for more before sending
ret
fossnd2:push es
push di
mov di,seg xmtbufx
mov es,di
mov di,offset xmtbufx
fossnd3:cmp xmtcnt,0 ; buffer count
jle fossnd4 ; le = nothing to send
mov ah,fossil_blkwr ; Fossil send block
xor al,al
mov dx,fossil_port ; port
mov cx,xmtcnt ; count
int rs232 ; block send
jc fossnd5 ; c = error
cmp ax,0ffffh ; error condition?
je fossnd5 ; e = yes
cmp ax,fossil_blkwr*256 ; complete no-op?
je fossnd5 ; e = yes
add di,ax ; move buffer pointer
sub xmtcnt,ax ; minus count sent
jnz fossnd3 ; nz = have some more to send
fossnd4:pop di
pop es
clc
ret
fossnd5:pop di
pop es
call serrst ; close port
mov kbdflg,'C' ; exit Connect mode
stc ; say not returning char in al here
ret
fossnd endp
ifndef no_network
ebisnd proc near ; EBIOS block send
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
inc xmtcnt ; count of items in this buffer
and ah,7fh ; strip parity
cmp xmtcnt,length xmtbuf ; is buffer full now?
jae ebisnd2 ; ae = buffer is full, send it now
cmp ah,trans.seol ; end of packet?
je ebisnd2 ; e = yes, send buffer
test flowcnt,1 ; using output XON/XOFF flow control?
jz ebisnd1 ; z = no
cmp ah,flowon ; flow control?
je ebisnd2 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je ebisnd2
ebisnd1:cmp ttyact,0 ; are we in Connect mode?
jne ebisnd2 ; ne = yes, send now
clc ; e = no, wait for more before sending
ret
ebisnd2:push si
mov si,offset xmtbufx
ebisnd3:cmp xmtcnt,0 ; buffer count
jle ebisnd4 ; le = nothing to send
cld
lodsb ; read next byte from buffer
push si
mov ah,ebsend ; EBIOS send char in AL
mov dx,ebport ; port 0..3, do here to waste time
int rs232 ; bios send
pop si
shl ah,1 ; put status high bit into carry
jc ebisnd4 ; c = failure
dec xmtcnt
jmp short ebisnd3
ebisnd4:pop si
ret ; c set = failure, else success
ebisnd endp
decsnd proc near ; DECnet/LAT send processor
test nettype,declat ; LAT?
jz decsnd3 ; z = no, use CTERM
decsnd1:mov dx,lathand ; LAT handle
or dx,dx ; legal handle?
jz decsnd4 ; z = invalid handle
call latblksnd ; send char in ah, and buffer
jc decsnd4 ; c = failure
ret
decsnd3:mov dx,decneth ; DECnet, handle
or dx,dx ; legal handle?
jz decsnd4 ; z = invalid handle
mov bl,ah ; CTERM char to be sent
mov ax,dsend ; send byte in bl
int decint
rcl ah,1 ; status 80h bit, did char get sent?
jc decsnd4 ; c = failure
ret
decsnd4:call decclose ; failure, close connection
stc
ret
decsnd endp
; Special block sending routine for LAT (all vendors)
; DEC's LAT breaks if we send too much at one time, TES LAT breaks much
; more readily, and MTC LAT tolerates the longest bursts. None works
; without a breathing space between block sends which don't fully
; send the block. TES LAT does not support callbacks. We arbitarily
; limit a buffer to 78 bytes to survive the various LAT troubles on
; both ends of the link. Putting DEC's LAT v4.1 in expanded memory
; under DOS 6.2 and NetWare VLM 1.1 shells causes lockups.
; Variable "temp" is borrowed as a retry counter.
latblksnd proc near
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
inc xmtcnt ; count of items in this buffer
cmp xmtcnt,78 ; is buffer full now?
jae latsnd2 ; ae = buffer is full, send it now
and ah,7fh ; strip parity
cmp ah,trans.seol ; end of packet?
je latsnd2 ; e = yes, send buffer
test flowcnt,1 ; using output XON/XOFF flow control?
jz latsnd1 ; z = no
cmp ah,flowon ; flow control?
je latsnd2 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je latsnd2
latsnd1:cmp ttyact,0 ; are we in Connect mode?
jne latsnd2 ; ne = yes, send now
xor ah,ah
clc ; e = no, wait for more before sending
ret
latsnd2:push bx
mov bx,offset xmtbufx
mov temp,0 ; retry counter
mov temp2,10 ; ms time wait when not enough space
cmp latkind,TES_LAT ; TES?
jne latsnd3 ; ne = no
mov temp2,2*55 ; slower for TES
latsnd3:cmp xmtcnt,0 ; buffer count
jle latsnd8 ; le = nothing to send
mov dx,lathand
mov ah,latstat ; get status
int latint
test ah,4 ; session is inactive?
jz latsnd5 ; z = no
pop bx
stc ; inactive, exit failure
ret
latsnd5:mov cx,xmtcnt ; amount to be sent
cmp cx,78 ; apply limits to fragile LATs
jbe latsnd7 ; be = in bounds
mov cx,78 ; so they do not mess up
latsnd7:push es
push bx
mov ax,seg xmtbufx
mov es,ax ; es:bx is send buffer
mov ah,latsendb ; send block
mov dx,lathand
int latint
pop bx
pop es
add bx,cx ; move to next new output byte
sub xmtcnt,cx ; deduct chars sent
jle latsnd8 ; le = all done
or cx,cx ; any chars accepted?
jnz latsnd7a ; nz = yes
inc temp ; retry counter
cmp temp,10 ; exhausted retries?
jbe latsnd7b ; be = no
call decclose ; failure, close connection
pop bx
stc
ret
latsnd7a:mov temp,0 ; reset retry counter
latsnd7b:push bx
mov ax,temp2 ; retry timeout
add temp2,ax ; new timeout (longer)
cmp latkind,TES_LAT ; TES LAT?
jne latsnd7c ; ne = no
add ax,100 ; slower for TES
latsnd7c:inc ax ; zero avoidance
call pcwait ; pause
call decrcv ; do a receive to clear LAT driver
pop bx
jmp latsnd3 ; continue sending remainder
latsnd8:pop bx
clc ; exit success
ret
latblksnd endp
endif ; no_network
; Software uart that generates output rate of 75 baud independently of
; 8250 baudrate; use with V.23 split speed modems.
; This routine outputs a character in 8,<parity>,1 format only.
; To generate good bit timing, latency is to be kept low; now set for max
; 12% bit distortion and 1.2% speed deviation (about the same as the input
; stage of a HW-uart), which requires latency < 3ms (i e the same as 8250
; requires for receive in 9600 baud)
; Creator Dan Norstedt 1987. Implemented 18 Feb 1988 by [pslms].
out75b proc near
mov timeract,1 ; say we are allocating the timer chip
push cx
push dx
xchg ax,bx ; save char to output
mov bh,1 ; prepare output char
mov cx,cnt75b ; maximum end count
out75b1:call read_timer2 ; save previous end count in CX, read timer
; test for timer still decrementing ?
jb out75b1 ; b = yes, wait (for a maximum of 1 bit)
mov al,0b4h ; set up counter 2 to mode 2, load LSB+MSB
out timercmd,al ; set mode 2 = rate generator
jmp $+2
mov ax,cnt75b*4+cnt75b*4+cnt75b*2-precomp ; set start point
out timer2data,al ; output LSB
jmp $+2
xchg cx,ax ; save value in CX for compare in READ_TIMER2
mov al,ch ; output MSB
cli ; timer starts counting on next instr, make
out timer2data,al ; sure it's not to far of from start bit
in al,ppi_port ; get Port B contents
jmp $+2
and al,0fch ; mask speaker and gate 2 bits
inc ax
out ppi_port,al ; set speaker off and gate 2 on
mov al,-1
out timer2data,al ; set counter wraparound to 0FFFFH
jmp $+2
out timer2data,al
mov bp,cnt75b*4+cnt75b*4+cnt75b ; set timer value for next bit
mov dx,modem.mddat ; get com port address
add dx,3 ; address of it's line control register
in al,dx ; get port status
jmp $+2
out75b2:or al,brkbit ; set line to space (by using break bit)
out75b3:out dx,al ; once start bit is out, we may reenable
sti ; without getting extra jitter
out75b4:call read_timer2
jns out75b5 ; ns = timer doesn't seem to run
cmp ax,bp ; time for next bit?
jns out75b4 ; ns = no, wait
sub bp,cnt75b ; yes, step time to next event
in al,dx ; get line control register
and al,0bfh ; remove break bit
shr bx,1 ; carry for mark bit, none for space
jnc out75b2 ; nc = it was a space (we know BX is non-zero)
jnz out75b3 ; mark, and not the last one
jmp $+2
out dx,al ; last, start to send stop bit
pop dx
pop cx
mov timeract,0 ; say we are finished with the timer chip
cmp quechar,0 ; any char queued to be sent?
je out75b6 ; e = no
call outchr ; yes, send it now
out75b6:clc
ret
out75b5:in al,dx ; timer doesn't function properly,
and al,0bfh ; restore com port and return error
out dx,al
mov timeract,0 ; say we are finished with the timer chip
pop dx
pop cx
stc
ret
out75b endp
read_timer2 proc near
mov al,80h ; Freeze timer 2
out timercmd,al
jmp $+2
in al,timer2data ; Get LSB
jmp $+2
mov ah,al
in al,timer2data ; Get MSB
xchg al,ah ; Get LSB and MSB right
cmp ax,cx ; Compare to previous sample
mov cx,ax ; Replace previous sample with current
ret
read_timer2 endp
ifndef no_network
; NetBios 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
mov bx,xmtcnt ; count of chars in buffer
test nettype,acsi ; ACSI?
jz send32 ; z = no
or bx,bx ; at start of buffer?
jnz send31 ; nz = no
mov bx,2 ; include internal count word
mov word ptr xmtbufx,bx
mov xmtcnt,bx
send31: mov xmtbufx[bx+1],0 ; status
inc xmtcnt
add word ptr xmtbufx,2 ; internal count word
send32:
mov xmtbufx[bx],ah ; put char in buffer
inc xmtcnt ; count of items in this buffer
and ah,7fh ; strip parity
cmp xmtcnt,length xmtbuf ; is buffer full now?
jae send22 ; ae = buffer is full, send it now
test nettype,acsi ; ACSI?
jz send33 ; z = no
cmp xmtcnt,512 ; ACSI has hard 512 byte limit
jb send33 ; b = not full yet
mov xmtcnt,512 ; limit buffer
jmp short send22 ; send only this buffer
send33: cmp ah,trans.seol ; end of packet?
je send22 ; e = yes, send buffer
test flowcnt,1 ; using output XON/XOFF flow control?
jz send21 ; z = no
cmp ah,flowon ; flow control?
je send22 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je send22
send21:cmp ttyact,0 ; are we in Connect mode?
jne send22 ; ne = yes, send now
clc ; e = no, wait for more before sending
ret
send22: cmp pcnet,1 ; network ready yet?
ja send0b ; a = net is operational
je send0c ; e = net but no session, fail
jmp send3b ; no net, fail
send0c: jmp send3 ; net but no session
send0b: cmp sposted,0 ; is a send outstanding now?
je send1 ; e = no, go ahead
push cx ; Timed test for old send being done
mov ch,trans.rtime ; receive timeout other side wants
mov cl,80h ; plus half a second
shl cx,1 ; sending timeout * 512
send0: cmp sposted,0 ; is a send outstanding now?
je send0a ; e = no, clean up and do send
push cx ; save cx
push ax ; and ax
mov ax,2 ; wait 2 milliseconds
call pcwait ; between retests
pop ax
pop cx ; loop counter
loop send0 ; repeat test
pop cx ; recover cx
jmp send3b ; get here on timeout, can't send
send0a: pop cx ; recover cx and proceed to send
send1: cmp xmtcnt,0 ; number of items to send
jne send1a ; ne = some
clc ; else don't send null packets
ret
send1a: push cx ; save these regs
push si
push di
push es
push ds
pop es ; set es to data segment
mov si,offset xmtbufx ; external buffer
mov di,offset xmtbuf ; copy for network packets
mov cx,xmtcnt ; buffer length
mov xmt.scb_length,cx ; tell buffer length
shr cx,1 ; divide by two (words), set carry
jnc send2 ; nc = even number of bytes
movsb ; do single move
send2: rep movsw ; copy the data
pop es
pop di
pop si
pop cx
mov xmtcnt,0 ; say xmtbufx is available again
mov xmt.scb_cmd,nsend+nowait ; send, don't wait for completion
mov sposted,1 ; say send posted
mov bx,offset xmt ; set pointer to scb
call nbsession
; success or failure?
cmp xmt.scb_err,0 ; good return?
je send4 ; e = yes
cmp xmt.scb_err,npending ; pending?
je send4 ; e = yes
cmp xmt.scb_err,18h ; session ended abnormally?
jbe send3 ; e = yes, b = other normal errors
push ax
push dx ; another kind of error, show message
mov ah,prstr
mov dx,offset sndmsg ; say send failed
int dos
mov al,xmt.scb_err ; show error code
call decout
pop dx
pop ax
; Error return
send3: mov pcnet,1 ; say session is broken
call serrst ; reset serial port
cmp lposted,1 ; Listen posted?
je receiv3a ; e = yes, stay alive
cmp xmt.scb_rname,'*' ; behaving as a Listner?
je receiv3a ; e = yes, stay alive
cmp lposted,1 ; Listen posted?
je send3a ; e = yes, stay alive
cmp xmt.scb_rname,'*' ; behaving as a Listner?
je send3a ; e = yes, stay alive
test flags.remflg,dserver ; server mode?
jz send3b ; z = no
send3a: call nbclose ; Server: purge old NAKs etc
call serini ; reinitialize it for new session
send3b: stc ; set carry for failure to send
ret
send4: clc
ret
SEND ENDP
; NetBios 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
push ds
push ax
mov ax,data
mov ds,ax
mov sposted,0 ; clear send interlock
pop ax
pop ds
iret
SPOST ENDP
; TES block send. Destroys BX
TESSND proc near
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
inc xmtcnt ; count of items in this buffer
and ah,7fh ; strip parity
cmp xmtcnt,length xmtbuf ; is buffer full now?
jae tessen22 ; ae = buffer is full, send it now
cmp ah,trans.seol ; end of packet?
je tessen22 ; e = yes, send buffer
test flowcnt,1 ; using output XON/XOFF flow control?
jz tessen21 ; z = no
cmp ah,flowon ; flow control?
je tessen22 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je tessen22
tessen21:cmp ttyact,0 ; are we in Connect mode?
jne tessen22 ; ne = yes, send now
clc ; e = no, wait for more before sending
ret
tessen22:push ax
push cx
push dx
push di
push es
mov cx,xmtcnt ; number of chars
jcxz tessnd4 ; don't send zero chars
mov di,offset xmtbufx ; buffer address in es:di
mov ax,data
mov es,ax
tessnd1:mov temp,0 ; retry counter
tessnd2:mov ah,tesbwrite ; block write
mov dx,tesport ; operational port
int rs232
or ax,ax ; number of chars sent, zero?
jnz tessnd3 ; nz = sent some
mov ax,10 ; wait 10ms
call pcwait
inc temp ; count retry
cmp temp,5 ; done all retries?
jb tessnd2 ; b = no
call tesclose ; close sessioin, declare failure
stc
jmp short tessnd5 ; exit failure
tessnd3:cmp ax,cx ; check that all characters were sent
je tessnd4 ; e = yes
add di,ax ; point to remaining chars
sub cx,ax ; count of remaining characters
mov xmtcnt,cx ; need count in xmtcnt too
jmp short tessnd1 ; try again to send
tessnd4:clc ; success, need failure case too
tessnd5:mov xmtcnt,0
pop es
pop di
pop dx
pop cx
pop ax
ret
TESSND endp
; Block send routine shared by many networks.
; Enter with char to be sent in AH. Destroys BX.
ubsend proc near
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
inc xmtcnt ; count of items in this buffer
and ah,parmsk ; strip parity
ifndef no_tcp
test nettype,tcpnet ; TCP/IP Telnet?
jz ubsen24 ; z = no
cmp ah,CR ; carriage return?
jne ubsen24 ; ne = no
cmp xmtcnt,length xmtbuf ; is buffer full?
jb ubsen22 ; b = no, else take special setps
call ubsen28 ; send what we have now
ubsen22:cmp tcpnewline,2 ; newline is RAW?
je ubsen24 ; e = yes, no special steps
mov bx,xmtcnt
mov al,LF ; CR -> CR/LF
cmp tcpnewline,0 ; newline mode is off?
jne ubsend23 ; ne = no, send CR/LF
cmp tcpmode,0 ; NVT-ASCII?
jne ubsen28 ; ne = no, Binary, no CR NUL
xor al,al ; CR -> CR NUL
ubsend23:mov xmtbufx[bx],al ; append this char
inc xmtcnt
jmp short ubsen28 ; send buffer now
endif ; no_tcp
ubsen24:cmp xmtcnt,length xmtbuf ; is buffer full now?
jae ubsen28 ; ae = buffer is full, send it now
cmp ah,trans.seol ; end of packet?
je ubsen28 ; e = yes, send buffer
test flowcnt,1 ; using output XON/XOFF flow control?
jz ubsen25 ; z = no
cmp ah,flowon ; flow control?
je ubsen28 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je ubsen28
ubsen25:cmp ttyact,0 ; are we in Connect mode?
jne ubsen28 ; ne = yes, send now
clc ; e = no, wait for more before sending
ret
ubsen28:push ax
push cx
push es
mov cx,xmtcnt ; number of chars
or cx,cx
jnz ubsen29 ; nz = have something to send
jmp ubsend1 ; z = nothing to send
ubsen29:mov temp,200 ; retry counter for can't send
mov bx,offset xmtbufx ; buffer address in es:bx
ubsend2:mov ax,seg xmtbuf
mov es,ax
test nettype,bapi+tcpnet ; 3Com BAPI or TCP Telnet?
jz ubsend2a ; z = no
mov ah,bapiwrit ; 3Com block write
xor dh,dh ; session 0
ifndef no_tcp
test nettype,tcpnet ; TCP/IP Telnet?
jz ubsend2d ; z = no
push bx
call ktcpcom ; Far call TCP/IP Telnet code
pop bx
jmp short ubsend2e
endif ; no_tcp
ubsend2d:int bapiint
ubsend2e:cmp ah,3 ; status, no session and above
jae ubsend2b ; ae = no session and above, fail
jmp short ubsend3 ; process data
ubsend2a:test nettype,telapi ; Novell TELAPI?
jz ubsend2c ; z = no, Int 6Bh kind
push si
push bx ; preserve buffer offset
mov si,bx ; use es:si for buffer address
mov ah,telwrite
mov bx,telses ; session number
int rs232
pop bx
pop si
mov cx,ax ; TELAPI returns sent count in AX
or ax,ax ; error response (sign bit set)?
jns ubsend3 ; ns = no error
ubsend2b:call ubclose ; failure, close the connection
pop es
pop cx
pop ax
stc ; failure
ret
ubsend2c:test nettype,netone ; UB?
jz ubsend1 ; no, do nothing
mov ax, nciwrit ; write function, port 0 [ohl]
int netci
ubsend3:cmp cx,xmtcnt ; check that all characters sent [ohl]
je ubsend1 ; e = yes [ohl]
add bx,cx ; point to remaining chars [ohl]
sub xmtcnt,cx ; count of remaining characters [ohl]
or cx,cx ; did we send any?
jnz ubsend3a ; nz = yes
push bx ; try to read to pass time of day
mov bx,bufsiz ; size of main rcv buffer
sub bx,count ; minus occupancy
cmp bx,nbuflen ; qty in next full read batch
jb ubsend3b ; b = not enough space
mov bx,portval
call [bx].rcvproc ; read routine
ubsend3b:pop bx ; fall through to grab new char
cmp flags.cxzflg,'C' ; user abort?
je ubsend3c ; e = yes
mov ax,5 ; 5 millisec pause between retries
call pcwait
test nettype,tcpnet ; TCP/IP Telnet?
jnz ubsend3a ; nz = yes
dec temp ; retry counter
jnz ubsend3a ; nz = some retries remaing
ubsend3c:pop es
pop cx
pop ax
stc ; fail but do not close port
ret
ubsend3a:mov cx,xmtcnt ; need count in cx too
jmp ubsend2 ; try again to send [ohl]
ubsend1:mov xmtcnt,0
pop es
pop cx
pop ax
clc ; success, need failure case too
ret
ubsend endp
; Invoke internal TCP/IP NAWS Telnet Option when screen size changes
winupdate proc far
ifndef no_tcp
test nettype,tcpnet ; TCP/IP Telnet?
jz winupda1 ; z = no
push es
mov ax,seg xmtbuf
mov es,ax
mov bx,offset xmtbufx ; buffer address in es:bx
xor cx,cx ; no data bytes to send
mov ah,bapinaws ; window size update request
call ktcpcom ; Far call TCP/IP Telnet code
pop es
cmp ah,3 ; status, no session and above
jae winupda2 ; ae = no session and above, fail
endif ; no_tcp
winupda1:clc ; success
ret
winupda2:call ubclose ; failure, close the connection
stc ; failure
ret
winupdate endp
; Block send routine for Beame & Whiteside TCP
; Enter with char to be sent in AH. Destroys BX. [JRS]
bwsend proc near
test nettype,bwtcp ; active?
jnz bwsend0 ; nz = yes
stc
ret
bwsend0:mov bx,xmtcnt ; [JRS] count of chars in buffer
mov xmtbufx[bx],ah ; [JRS] put char in buffer
inc xmtcnt ; [JRS] count of items in this buffer
and ah,7fh ; [JRS] strip parity
cmp ah,CR ; [JRS] carriage return?
jne bwsend1 ; [JRS] ne = no
inc bx ; [JRS]
xor al,al ; CR -> CR NUL
ifndef no_tcp
cmp tcpnewline,0 ; newline mode is off?
je bwsend0a ; e = yes
mov al,LF ; CR -> CR/LF
endif ; no_tcp
bwsend0a:call dopar ; [JRS] apply parity
mov xmtbufx[bx],al ; [JRS] append this char
inc xmtcnt ; [JRS]
jmp short bwsend2 ; [JRS]
bwsend1:cmp ttyact,0 ; [JRS] are we in Connect mode?
jne bwsend2 ; [JRS] ne = yes, send now
cmp xmtcnt,length xmtbuf-1 ; [JRS] is buffer full? (room for lf)
jb bwsend3 ; [JRS] b = no, else take special step
bwsend2:mov ah,40h ; [JRS] write to device
mov bx,bwhandle ; [JRS] device handle
mov cx,xmtcnt ; [JRS] number of bytes to write
mov dx,offset xmtbufx ; [JRS] data buffer
int dos ; [JRS] ask dos to send it
jc bwsend4 ; c = failed
mov xmtcnt,0 ; [JRS] clear the buffer
bwsend3:clc ; [JRS] e = no, wait for more
ret
bwsend4:call bwclose ; failed to send, quit
stc
ret
bwsend endp
; Dispatch prebuilt NetBios session scb, enter with bx pointing to scb.
; Returns status in al (and ah too). Allows STARLAN Int 2ah for netint.
NBSESSION PROC NEAR
push es ; save es around call
mov ax,ds
mov es,ax ; make es:bx point to scb in data seg
mov ax,exnbios ; funct 4 execute netbios, for Int 2ah
int netint ; use NetBios interrupt
pop es ; saved registers
ret ; exit with status in ax
NBSESSION ENDP
ifndef no_tcp
; Start a TCP/IP Telnet session. Set nettype if successful.
; Uses sescur to determine new (-1) or old (0..MAXSESSIONS-1) session.
; Returns carry clear if success, else carry set.
tcpstart proc near
mov bx,sescur ; current session index for seslist
or bx,bx ; non-negative means active
jns tcpstar1 ; ns = active
mov decbuf,0 ; ensure cmd line is cleared too
mov decbuf+80,0
mov decbuf+82,0
call sesmgr ; init a fresh session
jnc tcpstar0 ; nc = success
mov kstatus,ksgen ; global status for unsuccess
ret ; carry = failure
tcpstar0:mov sescur,bx ; get its index
jmp short tcpstar2 ; start fresh session
tcpstar1:mov al,seslist[bx] ; get the state value
xor ah,ah
or al,al ; is session active now?
jns tcpstar3 ; ns = yes, else start fresh session
tcpstar2:mov vtinited,0 ; MSY terminal emulation
ifndef no_terminal
mov tekflg,0 ; clear all graphics mode material
endif ; no_terminal
mov reset_clock,1 ; new session, set port clock trigger
call clrclock ; clear elapsed time clock
call ktcpopen ; open a new TCP connection
jmp short tcpstar4 ; check status in AX
tcpstar3:call ktcpswap ; switch to Telnet session in AL
tcpstar4:or al,al ; Telnet status, successful?
jns tcpstar5 ; ns = yes
jmp tcpclose ; fail, close this failed session
; started/swapped sessions ok
tcpstar5:mov bx,sescur ; current session, local basis
or bx,bx ; must be 0..5 to be usable
js tcpstar6 ; s = not usable
mov seslist[bx],al ; update local session mgr with status
push ax
push si
push di
mov al,seshostlen ; length of name fields
mul bl ; times number of entries
add ax,offset sesname
mov si,ax ; name of current host
mov di,offset tcphost ; update main table
call strcpy
push bx
shl bx,1 ; address words
mov ax,sesport[bx] ; port
mov tcpport,ax ; tcp port
pop bx
pop di
pop si
pop ax
mov pcnet,2 ; net open and going
or nettype,tcpnet ; say a session is active (ses = BL)
clc ; success
ret
tcpstar6:stc
mov kstatus,ksgen ; global status for unsuccess
ret ; carry = failure
tcpstart endp
; Close/shutdown/terminate a TCP/IP Telnet session. Sescur is session
; number, -1 closes all sessions and TCP/IP.
tcpclose proc near
mov ax,sescur
or ax,ax ; close active (>=0) or all (-1)?
js tcpclo1 ; s = all (-1)
mov bx,ax
ifndef no_terminal
call termswapdel ; delete term save block for ses BX
endif ; no_terminal
mov al,-1 ; session closed marker
xchg al,seslist[bx] ; get tcpident from local list to AL
or al,al ; is this Telnet session active?
jns tcpclo1 ; ns = yes, close it
mov cx,maxsessions ; number session slots
tcpclo0:cmp seslist[bx],0 ; session status, active?
jge tcpclo3a ; ge = yes, make this the active one
inc bx
cmp bx,maxsessions ; time to wrap?
jb tcpclo0a ; b = no
xor bx,bx ; wrap around
tcpclo0a:loop tcpclo0
jmp short tcpclo4 ; no active sessions, quit
tcpclo1:call ktcpclose ; AL = close this particular session
or al,al ; status from ktcpclose
jns tcpclo3 ; ns = have ses, -1 = no more sessions
call ktcpclose ; close TCP/IP as a whole after last
and nettype,not tcpnet ; clear activity flag
mov cx,maxsessions ; clear all local table entries
xor bx,bx
tcpclo2:mov seslist[bx],-1 ; status is inactive
ifndef no_terminal
push ax
call termswapdel ; delete terminal save block
pop ax
endif ; no_terminal
inc bx
loop tcpclo2
tcpclo3:call tcptoses ; convert next tcp ident AL to sescur
tcpclo3a:mov sescur,bx ; next new session
or bx,bx ; closing last session?
js tcpclo4 ; s = yes, no more sessions
ifndef no_terminal
call termswapin ; swap in next session's emulator
endif ; no_terminal
mov portin,0 ; reset the serial port for reiniting
mov port_tn.portrdy,0 ; say the comms port is not ready
mov kbdflg,' ' ; stay in connect mode
stc
ret
tcpclo4:mov al,-1 ; -1 means all sessions and network
call ktcpclose ; close the network
call serrst ; close the port
mov pcnet,0 ; say no network
and nettype,not tcpnet
mov kbdflg,'C' ; quit connect mode
stc
ret
tcpclose endp
endif ; no_TCP
; Make a NetBios 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.
; If success nettype is set to netbios and return is carry clear; else
; if failure nbclose is called to clean up connections and remove the nettype
; bit and return is carry set.
SETNET PROC NEAR ; NetBios, make a connection
cmp lposted,1 ; Listen pending?
je setne0 ; e = yes, exit now
cmp pcnet,1 ; session active?
jbe setne1 ; be = no
clc
setne0: ret
; No Session
setne1: cmp xmt.scb_rname,'*' ; wild card?
je setne1a ; e = yes, do a Listen
test flags.remflg,dserver ; Server mode?
jz setne2 ; z = no, file xfer or Connect
; Server mode, post a Listen (async)
setne1a:mov lsn.scb_rname,'*' ; accept anyone
mov ax,500
call pcwait ; 0.5 sec wait
or nettype,netbios ; set net type
mov lposted,1 ; set listen interlock flag
mov lsn.scb_cmd,nlisten+nowait ; do LISTEN command, no wait
push bx ; save reg
mov bx,offset lsn
call nbsession
pop bx
mov pcnet,2 ; net ready, Listen is active
clc
ret
setne2: ; Non-server (Client) mode
cmp starlan,0 ; STARLAN?
je setne2a ; e = no
cmp xmt.scb_vrlen,0 ; yes, using long name support?
je setne2a ; e = no
push es ; save reg
push ds
pop es ; make es:bx point to xmt scb
push bx ; save reg
mov bx,offset xmt ; use xmt scb for the call
mov xmt.scb_cmd,ncall ; CALL_ISN, vrname + vrlen are ready
int 5bh ; STARLAN CALL Int 5bh, wait
pop bx
pop es ; restore regs
jmp short setne3 ; finish up
; Regular Netbios Call
setne2a:cmp flags.comflg,'O' ; Opennet network? (FGR)
jne setne2b ; ne = no
mov xmt.scb_rname+15,'v' ; fix name to use VT port under nameserver
mov rcv.scb_rname+15,'v'
setne2b:mov xmt.scb_cmd,ncall ; CALL, wait for answer
push bx ; save reg
mov bx,offset xmt ; setup scb pointer
call nbsession
pop bx ; restore register
setne3: ; common Call completion, show status
test xmt.scb_err,0ffh ; is there a non-zero return code?
jnz setne3a ; nz = yes, do bad return
or al,al ; check error return
jnz setne3b ; nz = bad connection
jmp short setne4 ; good connection so far
; We try twice to allow for R1, and R3
; versions of the nameservers
setne3b:cmp flags.comflg,'O' ; Opennet netnork? (FGR)
jne setne3a ; ne = no
mov xmt.scb_rname+15,' ' ; try generic port under nameserver
mov rcv.scb_rname+15,' '
; Regular Netbios Call
mov xmt.scb_cmd,ncall ; CALL, wait for answer
mov bx,offset xmt ; setup scb pointer
call nbsession
; common Call completion, show status
test xmt.scb_err,0ffh ; is there a non-zero return code?
jnz setne3a ; nz = yes, do bad return
or al,al ; check error return
jz setne4 ; z = good connection so far
setne3a:mov dx,offset nbadset ; say can't reach remote node
mov ah,prstr
int dos
call saynode ; show remote host node name
jmp setne4c
; keep results of Call (vcid)
setne4: mov al,xmt.scb_vcid ; local session number
mov rcv.scb_vcid,al ; for receiver too
mov can.scb_vcid,al ; for sending Breaks
mov pcnet,2 ; say session has started
; Here is the real difference between Opennet and generic Netbios.
; The Opennet Virtual Terminal Services exchange a small handshake at connect
; time. After that it is just normal Netbios data transfer between the host
; and Kermit.
cmp flags.comflg,'O' ; Opennet netnork? (FGR)
jne setne4o ; ne = no
push si
push di
mov si,offset ivt1str ; protocol string "iVT1\0"
mov di,offset xmtbufx ; buffer
call strcpy ; copy asciiz string
mov xmtcnt,5 ; length of asciiz string, for send
pop di
pop si
call send ; send signon packet
; Note to Opennet purists: this just sends the handshake string to the host
; system without checking for an appropriate response. Basically, I am just
; very willing to talk to ANY VT server, and do the host response checking
; (if desired) in a Kermit script file (so its optional).
setne4o:cmp flags.comflg,'E' ; ACSI version of EBIOS?
jne setnet4p ; ne = no
mov word ptr xmtbufx,6 ; internal word count
mov xmtcnt,6 ; four bytes
mov word ptr xmtbufx+2,acenable*256+3 ; raise DTR and RTS
mov bx,portval
mov ax,[bx].baud ; get baud rate index
cmp al,0ffh ; unknown baud rate?
jne setnet4pa ; ne = no
mov ax,11 ; 2400,n,8,1
mov [bx].baud,ax ; set index into port info structure
setnet4pa:shl ax,1 ; make a word index
mov bx,ax
mov ax,clbddat[bx] ; Bios style speed setting
cmp al,0ffh ; unimplemented baud rate?
jne setnet4pb ; ne = no
mov bx,portval ; set index into port info structure
mov [bx].baud,3 ; 110 baud -> 19200 for ACSI
mov al,3 ; default to 19200,n,8,1
setnet4pb:mov ah,acsetmode ; ACSI cmd for Mode set
mov word ptr xmtbufx+4,ax ; Mode setting
or nettype,acsi ; set special net operation
call send
setnet4p:
test flags.remflg,dregular+dquiet ; regular or quiet display?
jnz setne4c ; nz = yes, show only no-connect msg
mov dx,offset ngodset ; say good connection
mov ah,prstr
int dos
call saynode ; show remote host name
setne4c:cmp pcnet,1 ; check connection again
ja setne5 ; a = good so far
call nbclose ; shut down NetBios
stc ; set carry for failure
ret
setne5: or nettype,netbios ; set net type
clc ; carry clear for success
ret
SETNET ENDP
saynode proc near ; display node name on screen, si=name ptr
push ax
push cx
push dx
push si
mov ah,conout
mov si,offset nambuf ; remote node string
mov cx,64 ; up to 64 bytes long
saynod1:cld
lodsb ; get remote node name char into al
mov dl,al
int dos ; display it
cmp al,' ' ; was it a space?
jbe saynod2 ; be = yes, quit here
loop saynod1 ; do all chars
saynod2:mov ah,prstr
mov dx,offset crlf
int dos
pop si
pop dx
pop cx
pop ax
ret
saynode endp
LPOST PROC FAR ; Interrupt Post routine for Listen call
push ds ; update vcid and calling node name in scb's
push cx
push es
push si
push di
mov cx,seg lsn ; reestablish data segment
mov ds,cx
mov es,cx
mov si,offset lsn.scb_rname ; copy remote name to rcv and xmt scbs
push si
mov di,offset rcv.scb_rname
mov cx,8 ; 16 byte field
cld
rep movsw
mov cx,8
pop si
push si
mov di,offset xmt.scb_rname
rep movsw
mov cx,8
pop si
mov di,offset nambuf ; and to nambuf for display
rep movsw
mov cl,lsn.scb_vcid ; local session number
mov rcv.scb_vcid,cl
mov xmt.scb_vcid,cl
mov can.scb_vcid,cl
mov lposted,0 ; clear interlock flag
mov pcnet,2 ; say net ready due to a Listen
pop di
pop si
pop es
pop cx
pop ds
iret ; return from interrupt
LPOST ENDP
; Close all network connections
NETHANGUP PROC NEAR ; disconnect network session, keep names
call ubclose ; close Ungermann Bass Int 6Bh class
mov xmtcnt,0
call decclose ; close DECnet connection
call telapiclose ; close Telapi session
ifndef no_tcp
mov sescur,-1 ; say close all sessions, stop TCP/IP
call tcpclose ; close internal TCP/IP sessions
endif ; no_tcp
call ebiclose ; close EBIOS session
call tesclose ; close TES session, ignore failures
call nbclose ; close NetBios and ACSI
call bwclose ; close BW TCP
mov portin,0 ; reset the serial port for reiniting
mov kbdflg,'C' ; quit connect mode
clc
ret
NETHANGUP ENDP
; Close NetBios connection. Clears nettype of netbios
nbclose proc near
test nettype,(netbios+acsi) ; NetBios or ACSI active?
jz nbclose2 ; z = no
cmp pcnet,0 ; network started?
je nbclose2 ; e = no
test nettype,acsi ; ACSI?
jz nbclose1 ; z = no
mov word ptr xmtbufx,4 ; four bytes
mov word ptr xmtbufx+2,acdisable*256 ; drop all modem leads
mov xmtcnt,4 ; four bytes
call send ; tell the server
mov ax,500 ; wait 0.5 sec
call pcwait ; for pkt to reach host
nbclose1:push bx ; NetBios network
mov bx,offset can
mov can.scb_cmd,ncancel ; set cancel op code
mov can.scb_baddr,offset lsn ; cancel listens
mov lposted,0 ; say no listen
call nbsession
mov can.scb_baddr,offset rcv ; cancel receives
call nbsession
mov rposted,0 ; say no receives posted
mov can.scb_baddr,offset xmt ; cancel sends
call nbsession
mov sposted,0 ; say no sends posted
mov xmtcnt,0 ; reset output buffer counter
mov xmt.scb_cmd,nhangup ; hangup, and wait for completion
mov bx,offset xmt
call nbsession
pop bx
and nettype,not (netbios+acsi)
mov pcnet,1 ; net but no connection
mov port_nb.portrdy,0 ; say the comms port is not ready
mov portin,0
mov kbdflg,'C' ; quit connect mode
stc
nbclose2:ret
nbclose endp
decclose proc near
test nettype,declat ; DECnet LAT active?
jz decclos3 ; z = no
mov dx,lathand ; LAT handle
or dx,dx ; invalid handle?
jz decclos2 ; z = yes
mov ax,latclose
int latint
mov ax,latseg ; allocated memory segment
or ax,ax ; was it used?
jz decclos1 ; z = no
push es
mov es,ax
mov ah,freemem ; free allocated memory segment @ES
int dos ; free the block
pop es
mov latseg,0 ; clear remembered segment address
mov word ptr latscbptr+2,0 ; clear this pointer (same as latseg)
decclos1:cmp latversion,4 ; version 4?
jb decclos2 ; b = no
push es
les bx,latscbptr+4 ; address of exterior SCB
mov dx,lathand
mov ax,latscbfree ; free SCB interior to LAT
int latint
mov word ptr latscbptr+2,0
pop es
decclos2:and nettype,not declat ; remove net type bit
mov lathand,0 ; invalidate the handle
decclos3:test nettype,decnet ; DEC CTERM active?
jz decclos4 ; z = no
mov dx,decneth ; DECnet CTERM handle
or dx,dx ; invalid handle?
jz decclos5 ; z = yes
mov ax,dclose ; CTERM close
int decint
mov decneth,0 ; invalidate the handle
mov ax,decseg ; allocated memory segment
or ax,ax ; ever used?
jz decclos4 ; z = no
mov es,ax
mov ah,freemem ; free allocated memory segment @ES
int dos ; free the block
mov decseg,0 ; clear remembered segment address
decclos4:and nettype,not decnet ; remove net type bit
mov port_dec.portrdy,0 ; say port is not ready
mov pcnet,0 ; say no network
mov portin,0
mov kbdflg,'C' ; quit connect mode
stc
decclos5:ret
decclose endp
telapiclose proc near
test nettype,telapi ; Novell TELAPI?
jz telapiclo1 ; e = no
mov xmtcnt,0
push bx
mov bx,telses ; session number
mov ah,telclose ; close session
int rs232
pop bx
and nettype,not telapi ; remove active net type bit
mov portin,0
mov pcnet,1
push bx
mov bx,portval
mov [bx].portrdy,0 ; say port is not ready
pop bx
mov kbdflg,'C' ; quit connect mode
stc
telapiclo1:ret
telapiclose endp
; Close EBIOS communications link
ebiclose proc near
test nettype,ebios ; EBIOS?
jz ebiclos1 ; z = no
mov dx,ebport ; EBIOS
mov ax,ebmodem*256+0 ; reset outgoing DTR and RTS leads
int rs232
push es
mov bx,ds
mov es,bx
mov bx,offset ebcoms ; es:bx is parameter block ebcoms
mov ah,ebredir ; do redirect away from EBIOS
mov ebcoms+1,0 ; set port to hardware
int rs232
mov dx,ebport ; port 0..3
mov bx,offset rcvbuf ; receive buffer for EBIOS
xor cx,cx ; set to zero to stop buffering
mov ax,ebbufset*256+2 ; reset rcvr buffered mode
int rs232
xor cx,cx
mov bx,offset xmtbuf ; EBIOS transmitter work buffer
mov ax,ebbufset*256+1 ; reset xmtr buffered mode
int rs232
pop es
mov bx,offset portb1 ; use Bios data structure
mov ax,type prtinfo ; portinfo item size
mul dl ; times actual port (0..3)
add bx,ax ; new portb<n> offset
mov [bx].portrdy,0 ; say port is not ready
and nettype,not ebios
mov portin,0
mov kbdflg,'C' ; quit connect mode
stc
ebiclos1:ret
ebiclose endp
; TES close session
tesclose proc near
test nettype,tes ; TES?
jz tesclo3 ; z = no
mov temp,0 ; retry counter
call tesstate ; get session state to AH
test ah,2 ; is this session active?
jz tesclo2 ; z = no, but keep held sessions
mov ah,tesdrop ; drop a session
mov al,tesses ; the session
call tes_service
or ah,ah ; status
jz tesclo2 ; z = success
stc ; say failure
ret
tesclo2:and nettype,not tes ; successful hangup
mov tesses,0 ; clear session
mov port_tes.portrdy,0 ; say the comms port is not ready
mov pcnet,1 ; say network but no session
mov portin,0
mov kbdflg,'C' ; quit connect mode
stc
ret
tesclo3:clc
ret
tesclose endp
; Ungermann Bass. Do a disconnect from the current connection.
ubclose proc near
push ax
push cx
test nettype,netone ; UB network has been activated?
jz ubclos4 ; z = no
mov ax,ncistat ; get status [ohl]
int netci
or ch,ch ; check if we have a connection [ohl]
jz ubclos2 ; z = no [ohl]
mov ax,ncicont ; control function [ohl]
mov cx,ncidis ; say disconnect [ohl]
int netci
ubclos1:call ubrecv ; read response from net cmdintpr[ohl]
jnc ubclos1 ; continue till no chars [ohl]
mov ax,ncistat ; get status again
int netci
or ch,ch ; check if we have a connection
jnz ubclos3 ; nz = yes, had more than one
ubclos2:and nettype,not netone ; remove network type
mov pcnet,1 ; net but no connection
mov port_ub.portrdy,0 ; say the comms port is not ready
mov portin,0
mov kbdflg,'C' ; quit connect mode
stc
ubclos3:pop cx
pop ax
ret
ubclos4:test nettype,bapi+tcpnet ; 3Com BAPI or TCP Telnet in use?
jz ubclos6 ; z = no
mov ah,bapieecm ; control Enter Command Mode char
mov al,1 ; enable it
ifndef no_tcp
test nettype,tcpnet ; TCP/IP Telnet?
jz ubclos5 ; z = no
mov bx,sescur ; current session
mov seslist[bx],-1 ; say session is closed
call tcpclose ; tell Telnet manager about closure
jmp short ubclos3
endif ; no_tcp
ubclos5:int bapiint
and nettype,not bapi ; remove BAPI bit
jmp short ubclos3
ubclos6:test nettype,telapi ; Novell TELAPI Int 6Bh interface?
jz ubclos3 ; z = no
call telapiclose
jmp short ubclos3
ubclose endp
; Ungermann Bass/Novell. Put current connection on Hold. Requires keyboard
; verb \knethold to activate. Should return to Connect mode to see NASI. [jrd]
ubhold proc near
push ax
push cx
test nettype,netone ; UB/Novell network active?
jz ubhold1 ; z = no
mov ax,ncistat ; get link status
int netci
or ch,ch ; connection active?
jz ubhold1 ; z = no
mov ax,ncicont ; control command
mov cl,ncihld ; place circuit on HOLD
int netci
jmp short ubhold3
ubhold1:test nettype,bapi ; 3Com BAPI
jz ubhold2 ; z = no
mov ah,bapiecm ; do Enter Command Mode char
ubhold1b:int bapiint
jmp short ubhold3
ubhold2:test nettype,tes ; TES?
jz ubhold3 ; z = no
mov ah,testalk ; TES get command interpreter
mov dx,tesport ; "serial port"
int rs232
ubhold3:pop cx
pop dx
clc
ret
ubhold endp
; Beame & Whiteside TCP close session [JRS]
bwclose proc near ; [JRS]
mov bx,bwhandle ; [JRS] get file handle
or bx,bx ; [JRS] if zero, we're done
jz bwclos1 ; [JRS] z= done
mov ah,close2 ; [JRS] close device
int dos ; [JRS]
mov bwhandle,0 ; [JRS] clear the handle value
bwclos1:and nettype,not bwtcp
mov portin,0 ; say serial port is closed
mov pcnet,0
mov port_tn.portrdy,0 ; say port is not ready
mov kbdflg,'C' ; quit connect mode
clc ; [JRS] flag success
ret
bwclose endp
; Called when Kermit exits. Name passed to mssker by initialization lclini
; in word lclexit.
NETCLOSE PROC NEAR ; close entire network connection
call nethangup ; close connections
push bx
mov bx,offset xmt
cmp xmt.scb_lname,' ' ; any local name?
je netclo2 ; e = none
mov xmt.scb_cmd,ndelete ; delete our local Kermit name
call nbsession ; from net adapter board
mov xmt.scb_lname,' ' ; clear name
netclo2:pop bx
mov pcnet,0 ; say no network
mov lnamestat,0 ; local name not present, inactive
mov port_nb.portrdy,0 ; say comms port is not ready
and nettype,not (netbios+acsi) ; remove network kind
netclo1:clc
ret
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
cmp flags.comflg,'U' ; Ungermann Bass network?
jb chknea ; b = no, (ae includes U and W)
mov pcnet,0 ; force reactivation of UB net
chknea: cmp pcnet,2 ; session active now?
jb chknec ; b = no
cmp newnambuf,0 ; non-zero if new destination name
je chkneb ; e = none, resume old session
call chknew ; Resume current session?
jnc chkneb ; nc = no
chknex: ret ; resume old one
chkneb: jmp chknet1 ; skip presence tests
chknec: ; setup addresses and clear junk in scb's
cmp pcnet,0 ; have we been here already?
je chkned ; e = no
jmp chknet1 ; yes, skip init part
chkned: mov xmtcnt,0 ; say buffer is empty
mov nsbrk,0 ; assume no BREAK across network
and nettype,not netbios ; say no NetBios network yet
mov starlan,0 ; no Starlan yet
call chknetbios ; is Netbios present?
jc chknet0 ; c = not present
or nettype,netbios ; say have NetBios network
call chkstarlan ; is AT&T StarLAN present?
jc chknet1 ; c = no
inc starlan ; say using STARLAN, have int 2ah
mov nsbrk,1 ; network BREAK supported
jmp short chknet1
chknet0:mov pcnet,0 ; no network yet
push dx
mov ah,prstr
mov dx,offset nonetmsg ; say network is not available
int dos
pop dx
stc ; set carry for failure
ret ; and exit now
; net ready to operate
chknet1:mov port_nb.portrdy,1 ; say the comms port is ready
cmp newnambuf,0 ; non-zero if new destination name
jne chkne1e ; ne = new name given
jmp chknet2 ; nothing, so leave names intact
chkne1e:cmp pcnet,2 ; is session active now?
jb chkne1d ; b = no
call nbclose ; close to clear old connection
chkne1d:push si ; start fresh connection
push di
push es
push ds
pop es ; make es:di point to data segment
cld
mov cx,8 ; 16 bytes for a node name
mov ax,' ' ; first, fill with spaces
mov di,offset xmt.scb_rname ; remote name field, clear it
rep stosw
cmp starlan,0 ; STARLAN?
jne chkne1b ; ne = no
; begin STARLAN section
mov xmt.scb_vrname,0 ; STARLAN var length name ptr
mov xmt.scb_vrname+2,0 ; segement of name
mov xmt.scb_vrlen,0 ; and its length
mov di,offset nambuf ; source of text
mov dx,di
call strlen ; length of new name to cx
cmp cx,16 ; > 16 chars in remote node name?
ja chkne1a ; a = yes, too long for Netbios
mov al,'/' ; scan for slashes in name
cld
repne scasb ; look for the slash
jne chkne1b ; ne = none, do regular Netbios name storage
chkne1a: ; STARLAN ISN long remote name support
mov dx,offset nambuf ; STARLAN var length name ptr
mov xmt.scb_vrname,dx
mov xmt.scb_vrname+2,data ; segment of remote name
call strlen ; get name length again (in cx)
mov xmt.scb_vrlen,cl ; indicate its length
jmp short chkne1c ; copy blanks in remote name field
; end STARLAN section
chkne1b: ; Regular Netbios form
mov si,offset nambuf ; source of text
mov dx,si
call strlen ; length to cx
cmp cx,16
jbe chkne1f ; be = in bounds
mov cx,16 ; chop to 16 (prespace filled above)
chkne1f:mov di,offset xmt.scb_rname ; destination is remote name
rep movsb ; copy text to transmitter's scb
chkne1c:mov cx,8 ; 8 words
mov si,offset xmt.scb_rname ; from here
mov di,offset rcv.scb_rname ; to receiver's scb also
rep movsw
pop es
pop di
pop si
mov newnambuf,0 ; say new name is established now
chknet2:cmp pcnet,0 ; started net?
je chknet2c ; e = no
clc
ret ; else quit here
chknet2c:call setnbname ; establish local Netbios name
jnc chknet9 ; nc = success
ret
chknet9:mov pcnet,1 ; network is present (but not active)
mov al,xmt.scb_num ; name number
mov rcv.scb_num,al
mov lsn.scb_num,al
push es
push si
push di
mov si,ds
mov es,si
mov si,offset xmt.scb_lname
mov di,offset rcv.scb_lname ; put in receiver scb too
mov cx,8
rep movsw
mov cx,8
mov si,offset xmt.scb_lname
mov di,offset lsn.scb_lname ; in Listen scb also
rep movsw
pop si
pop di
pop es
clc
ret
chknet endp
; Service SET NETBIOS-NAME name command at Kermit prompt level
setnbios proc near
mov bx,offset decbuf ; work buffer
mov dx,offset setnbhlp2 ; help
mov ah,cmword ; get netbios name
call comnd
jc setnb3 ; c = failure
push ax ; save char count
mov ah,cmeol ; get a confirmation
call comnd
pop ax
jc setnb3 ; c = failure
cmp lnamestat,2 ; is name fixed already?
je setnb2 ; e = yes
mov cx,ax ; char count
jcxz setnb3 ; z = enter no new name
cmp cx,16 ; too long?
jbe setnb1 ; be = no
mov cx,16 ; truncate to 16 chars
setnb1: mov si,offset decbuf ; work buffer
mov di,offset deflname ; default name
push es
mov ax,ds
mov es,ax
cld
rep movsb ; copy the name
mov al,' ' ; pad with spaces
mov cx,offset deflname+16 ; stopping place+1
sub cx,di ; number of spaces to write
rep stosb ; won't do anything if cx == 0
pop es
mov lnamestat,1 ; say have new local name
call setnbname ; do the real NetBios resolution
ret ; returns carry set or clear
setnb2: mov ah,prstr
mov dx,offset setnbad ; say name is fixed already
int dos
setnb3: stc ; failure
ret
setnbios endp
chknetbios proc near ; Test for Netbios presence, IBM way
push es
mov ah,35h ; DOS get interrupt vector
mov al,netint ; the netbios vector
int dos ; returns vector in es:bx
mov ax,es
or ax,ax ; undefined interrupt?
jz chknb2 ; z = yes
cmp byte ptr es:[bx],0cfh ; points at IRET?
je chknb2 ; e = yes
mov xmt.scb_cmd,7fh ; presence test, 7fh is illegal command code
mov xmt.scb_err,0 ; clear response field
push bx
mov bx,offset xmt ; address of the session control block
call nbsession ; execute operation
pop bx
mov al,xmt.scb_err ; get response
cmp al,3 ; 'illegal function', so adapter is ready
je chknb1 ; e = success
or al,al
jnz chknb2 ; nz = not "good response" either
chknb1: pop es
clc ; netbios is present
ret
chknb2: pop es
stc ; netbios is not present
ret
chknetbios endp
chkstarlan proc near ; AT&T STARLAN board check
push es
mov ah,35h ; DOS get interrupt vector
mov al,2ah ; PC net vector 2ah
int dos ; returns vector in es:bx
mov ax,es
or ax,ax ; undefined interrupt?
jz chkstar1 ; z = yes
cmp byte ptr es:[bx],0cfh ; points at IRET?
je chkstar1 ; e = yes
xor ah,ah ; vendor installation check on int 2ah
xor al,al ; do error retry
int 2ah ; session level interrupt
cmp ah,0ddh ; 0ddh = magic number, success?
jne chkstar1 ; ne = no
; Test for vector
mov ah,35h ; DOS get interrupt vector
mov al,5bh ; 5bh = STARLAN netbios ext'd vector
int dos ; returns vector in es:bx
mov ax,es
or ax,ax ; undefined interrupt?
jz chkstar1 ; z = yes
cmp byte ptr es:[bx],0cfh ; points to IRET?
je chkstar1 ; e = yes
pop es
clc ; StarLAN is present
ret
chkstar1:pop es
stc ; StarLAN is not present
ret
chkstarlan endp
; Put a local name into the Netbios name table, ask user if conflicts.
setnbname proc near
cmp lnamestat,2 ; validiated local Netbios name?
jb setnbn1 ; b = no
ret ; else quit here
setnbn1:call chknetbios ; Netbios presence check
jnc setnbn1a ; nc = present
ret
setnbn1a:mov ah,prstr
mov dx,offset netmsg1 ; say checking node name
int dos
push word ptr xmt.scb_rname ; save first two bytes (user spec)
mov byte ptr xmt.scb_rname,'*' ; call to local name
push bx
mov xmt.scb_cmd,naustat ; get Network Adapter Unit status
mov bx,offset xmt
call nbsession
pop bx
pop word ptr xmt.scb_rname ; restore remote name first two bytes
setnbn2:push es
push si
push di
mov si,ds
mov es,si
cld
mov si,offset deflname ; use default local name
mov di,offset xmt.scb_lname ; where to put it in scb
mov cx,14 ; 16 bytes minus extension of '.K'
cld ; append extension of '.K' to loc name
setnbn5:cmp byte ptr[si],' ' ; find first space (end of regular node name)
jbe setnbn6 ; be = found one (or control code)
movsb ; copy local name to scb
loop setnbn5 ; continue though local name
setnbn6:cmp word ptr [di-2],'K.' ; is extension '.K' present already?
je setnbn7 ; e = yes, nothing to add
cmp word ptr [di-2],'k.' ; check lower case too
je setnbn7 ; e = yes, nothing to add
mov word ptr [di],'K.' ; append our extension of '.K'
add di,2 ; step over our new extension
sub cx,2
; complete field with spaces
setnbn7:add cx,2 ; 15th and 16th chars
mov al,' ' ; space as padding
rep stosb
pop di ; clean stack from work above
pop si
pop es
push bx ; Put our new local name in NAU
mov xmt.scb_cmd,nadd ; ADD NAME, wait
mov bx,offset xmt
call nbsession
pop bx
mov al,xmt.scb_err ; get error code
or al,al ; success?
jnz setnbn8 ; nz = no
jmp setnbn12 ; success
setnbn8:cmp al,0dh ; duplicate name in local table?
je setnbn9 ; e = yes
cmp al,16h ; name used elsewhere?
je setnbn9 ; e = yes
cmp al,19h ; name conflict?
je setnbn9 ; e = yes
push ax
mov ah,prstr ; another kind of error
mov dx,offset chkmsg1 ; say can't construct local name
int dos
pop ax
call decout ; display it (in al)
mov ah,prstr
mov dx,offset crlf
int dos
stc ; set carry for failure
ret
setnbn9:mov ah,prstr ; ask for another name
mov dx,offset chkmsg2 ; prompt message
int dos
mov ah,conout ; show name itself
push si
push cx
mov cx,16 ; 16 bytes in name field
mov si,offset xmt.scb_lname
setnbn10:lodsb ; get name char into al
mov dl,al
int dos
mov byte ptr[si-1],' ' ; clear old name as we go
loop setnbn10
pop cx
pop si
mov ah,prstr
mov dx,offset chkmsg3 ; rest of prompt
int dos
mov ah,0ah ; read buffered line from stdin
mov dx,offset xmtbuf+58 ; where to put text (xmtbuf+60=text)
mov xmtbuf+58,15 ; buf capacity, including cr at end
mov xmtbuf+59,0 ; say text in buffer = none
int dos
jc setnbn11 ; c = error
cmp xmtbuf+59,0 ; any bytes read?
je setnbn11 ; e = no, exit failure
mov ah,prstr ; say rechecking name
mov dx,offset netmsg1
int dos
push es
mov si,ds
mov es,si
mov si,offset xmtbuf+60 ; where text went
mov di,offset deflname ; where local name is stored
mov cx,8
cld
rep movsw ; copy 14 chars to deflname
mov byte ptr [di],0 ; null terminator, to be safe
pop es
mov lnamestat,1 ; say local name specified
jmp setnbn2 ; go reinterpret name
setnbn11:stc ; set carry for failure
ret
setnbn12:mov dx,offset netmsg2 ; say net is going
mov ah,prstr
int dos
push si
push di
push es
mov si,ds
mov es,si
mov si,offset xmt.scb_lname ; display our local name
mov di,offset deflname ; local Netbios name
mov ah,conout
mov cx,16
cld
setnbn13:lodsb ; byte from si to al
stosb ; and store in local Netbios name
mov dl,al
int dos ; display it
loop setnbn13
pop es
pop di
pop si
mov lnamestat,2 ; say local name is fixed now
mov ah,prstr
mov dx,offset crlf ; add cr/lf
int dos
clc ; carry clear for success
ret
setnbname endp
; Network session exists. Tell user and ask for new node or Resume.
; Returns carry set if Resume response, else carry clear for New.
chknew proc near
mov ax,takadr ; we could be in a macro or Take file
push ax ; save Take address
mov al,taklev
xor ah,ah
push ax ; and Take level
push dx
mov dx,size takinfo ; bytes for each current Take
mul dx ; times number of active Take/macros
pop dx
sub takadr,ax ; clear Take address as if no
mov taklev,0 ; Take/macro were active so that
mov dx,offset naskpmt ; prompt for New or Resume
call prompt
mov dx,offset nettab ; table of answers
xor bx,bx ; help for the question
mov ah,cmkey ; get answer keyword
mov comand.cmcr,1 ; allow bare CR's
call comnd
mov comand.cmcr,0 ; dis-allow bare CR's
jc chknew1 ; c = failure, means Resume
push bx
mov ah,cmeol ; get a confirm
call comnd
pop bx
jc chknew1 ; c = failure, resume session
or bx,bx ; 0 for new?
jz chknew1 ; z = yes, return carry clear
stc ; set carry for resume
chknew1:pop ax
mov taklev,al ; restore Take level
pop takadr ; restore Take address
ret ; carry may be set
chknew endp
; ; [ohl] ++++
; Verifies existance of interrupt 6Bh support, verifies vendor specific
; support for BREAK and other features, sets network type bit in nettype,
; sets BREAK support in nsbrk and sets network status byte pcnet to 0
; (no net) or to 1 (net ready). This is the first procedure called to
; init Ungermann-Bass NETCI terminal port network usage.
chkub proc near
push bx
push es ; Test for vector
mov ah,35h ; DOS get interrupt vector
mov al,6bh ; 6bh = Net/One command interpreter
; interface, with break support
int dos ; returns vector in es:bx
mov ax,es ; is vector in rom bios?
or ax,ax ; undefined vector?
jz chkub0 ; z = yes
cmp byte ptr es:[bx],0cfh ; points at IRET?
je chkub0 ; e = yes
;some mov al,0ffh ; test value (anything non-zero)
;emulators mov ah,2 ; function code for testing net board
;flunk int netci
;this or al,al ; al = 0 means board is ok
;test jnz chkub0 ; nz = not ok
pop es
pop bx
mov nsbrk,1 ; network BREAK supported
or nettype,netone ; say have Net/One
clc ; return success
ret
chkub0: pop es ; clean stack from above
pop bx
push ax
push dx
mov ah,prstr
mov dx,offset nonetmsg ; say network is not available
int dos
pop dx
pop ax
stc ; set carry for failure
ret ; and exit now
chkub endp
endif ; no_network
; local routine to see if we have to transmit an xon
chkxon proc near
test flowcnt,1+4 ; doing output/RTS flow control?
jz chkxo1 ; z = 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
test flowcnt,4 ; using RTS/CTS kind?
jz chkxo2 ; z = no
cmp flags.comflg,4 ; using uart?
ja chkxo1 ; a = no, ignore situation
push ax
push dx
mov dx,modem.mddat ; serial port base address
add dx,4 ; increment to control register
in al,dx
or al,2 ; assert RTS for flow-on
push ax
in al,ppi_port ; delay
pop ax
out dx,al
and xofsnt,off ; remember we've sent the "xon"
pop dx
pop ax
; do software flow control too
chkxo2: test flowcnt,1 ; using outgoing XON/XOFF kind?
jz chkxo1 ; z = no
mov ah,flowon ; ah gets xon
and xofsnt,off ; remember we've sent the xon
call outch2 ; send via non-flow controlled entry point
chkxo1: ret
chkxon endp
; IHOSTS - Initialize the host by sending XOFF, or equivalent.
; Requires that the port be initialized before hand.
; Do not send flow control if doing half duplex.
IHOSTS PROC NEAR
push ax ; save the registers
push bx
push cx
push dx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
cmp portin,0 ; is a comms port active?
jle ihosts1 ; le = no
mov bx,portval
test flowcnt,4 ; using CTS/RTS?
jnz ihosts2 ; nz = yes
mov ah,byte ptr [bx].flowc ; put wait flow control char in ah
or ah,ah ; check for null char
jz ihosts1 ; z = null, don't send it
cmp dupflg,0 ; full duplex?
jne ihosts1 ; ne = no, half
call outchr ; send it
jmp short ihosts1
ihosts2:cmp flags.comflg,4 ; using uart?
ja ihosts1 ; a = no, ignore situation
mov dx,modem.mddat ; serial port base address
add dx,4 ; increment to control register
in al,dx
and al,not 2 ; clear RTS for flow-off
push ax
in al,ppi_port ; delay
pop ax
out dx,al
or xofsnt,bufon ; remember we've sent the "xoff"
ihosts1:pop dx
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. Do not send flow control if doing half duplex.
IHOSTR PROC NEAR
push ax ; save regs
push bx
push cx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
cmp portin,0 ; is a comms port active?
jle ihostr1 ; le = no
mov bx,portval
test flowcnt,4 ; using CTS/RTS?
jnz ihostr2 ; nz = yes
mov ah,byte ptr [bx].flowc+1; put go-ahead flow control char in ah
or ah,ah ; check for null char
jz ihostr1 ; z = null, don't send it
cmp dupflg,0 ; full duplex?
jne ihostr1 ; ne = no, half
call outchr ; send it (release Host's output queue)
jmp short ihostr1
ihostr2:cmp flags.comflg,4 ; using uart?
ja ihostr1 ; a = no, ignore situation
push dx
mov dx,modem.mddat ; serial port base address
add dx,4 ; increment to control register
in al,dx
or al,2 ; assert RTS for flow-on
push ax
in al,ppi_port ; delay
pop ax
out dx,al
and xofsnt,off ; remember we've sent the "xon"
pop dx
ihostr1:pop cx
pop bx
pop ax
ret
IHOSTR ENDP
; Send a break out the current serial port. Returns normally.
; Do both regular and long Break.
; Networks use flags.comflg so that more than one net can be active
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
mov flags.cxzflg,0 ; clear in case Control-Break
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
mov flags.cxzflg,0 ; clear in case Control-Break
clc ; don't exit Connect mode
ret
; worker - send Break for cx millisec
sendbw: mov al,flags.comflg ; get type of port
cmp al,4 ; running on a UART or network?
ja sendbw2 ; a = network
push dx ; UART BREAK
mov dx,modem.mdcom ; port address
in al,dx ; get current setting
push ax ; save setting on the stack
or al,brkbit ; set send-break bit(s)
out dx,al ; start the break
mov ax,cx ; # of ms to wait
call pcwait ; hold break for desired interval
pop ax ; restore Line Control Register
out dx,al ; stop the break
pop dx
ret
sendbw2:
ifndef no_network
cmp al,'N' ; is this a NetBios network port?
jne sendbw3 ; ne = no
cmp starlan,0 ; STARLAN: network break supported?
jne sendbw2a ; ne = no
push bx
push es ; save es around call
push ds
pop es ; make es:bx point to scb in data segment
mov bx,offset can ; use Cancel control block
mov can.scb_cmd,netbrk ; send net Break command
int 5bh ; use network Break interrupt
pop es ; saved registers
pop bx
sendbw2a:ret
sendbw3:cmp al,'E' ; EBIOS?
jne sendbw6 ; ne = no
test nettype,acsi ; using EBIOS.COM?
jnz sendbw4 ; nz = no
push ax
push dx
mov dx,ebport ; port 0..3
mov ah,ebbreak ; EBIOS send BREAK
int rs232 ; bios send
pop dx
pop ax
ret
sendbw4:call send ; send current buffer first
mov word ptr xmtbufx,4 ; four bytes in packet
mov word ptr xmtbufx+2,acbreak*256+0 ; BREAK cmd, null char
call send ; send the command
ret
sendbw6:cmp al,'U' ; UB NETCI or Novell NASI/NACS?
je sendbw6a ; e = yes
cmp al,'W' ; NASI/NACS?
jne sendbw7 ; ne = no
sendbw6a:push cx ; UB port send break [ohl]
mov ax,ncicont+0 ; call control, use 0 for network port num
mov cl,ncibrk ; request break [ohl]
int netci ; Net/One command interface int. (6Bh) [ohl]
pop cx
ret
sendbw7:cmp al,'M' ; Meridian SuperLAT?
je sendbw7a ; e = yes
cmp al,'D' ; DECnet?
jne sendbw9 ; ne = no
test nettype,declat ; LAT?
jz sendbw9 ; z = no, CTERM cannot send a BREAK
sendbw7a:mov ax,latbreak ; LAT BREAK command
push dx
mov dx,lathand ; LAT handle
int latint
pop dx
ret
sendbw9:cmp al,'C' ; 3Com BAPI or TCP Telnet?
je sendbw9a ; e = yes
cmp al,'t'
jne sendbw10 ; ne = no
sendbw9a:mov ah,bapibrk ; BAPI, send BREAK
xor dh,dh ; session id of 0 (external sessions)
ifndef no_tcp
cmp al,'t' ; TCP/IP Telnet?
jne sendbw9b ; ne = no
call ktcpcom ; Far call TCP/IP Telnet code
ret
endif ; no_tcp
sendbw9b:int bapiint
ret
sendbw10:cmp al,'T' ; Novell TELAPI?
jne sendbw11 ; ne = no
mov ah,255 ; Telnet Interpret As Command char
call outchr ; send it
mov ah,244 ; Telnet Interrupt Process char
call outchr ; send it
ret
sendbw11:cmp al,'I' ; TES?
jne sendbw12 ; ne = no
cmp latkind,TES_LAT ; using LAT?
jne sendbw11a ; ne = no, older TES
mov ax,latbreak ; LAT BREAK command
push dx
mov dx,lathand ; LAT handle
int latint
pop dx
ret
sendbw11a:mov ah,testalk ; get command interpreter
mov dx,tesport
int rs232
ret
sendbw12:mov ax,8000h ; Artisoft Int 14h interceptor
int rs232 ; presence check
cmp al,0ffh ; present?
jne sendbw13 ; ne = no
push bx
push dx
push cx
mov dl,flags.comflg ; get type of port
sub dl,'4' ; Bios port
xor dh,dh
push es
push di
mov di,seg xmtbufx ; temp buf
mov es,di
mov di,offset xmtbufx
mov xmtbufx+37,7 ; default to 9600 bps index value
mov ax,8007h ; Artisoft, Get_Redirected_Port
int rs232 ; info to es:di buffer (c set if failure)
pop di
pop es
xor bx,bx ; no parity (bh) one stop bit (bl)
mov cl,xmtbufx+37 ; returned baud rate index
mov ch,3 ; 8 data bits
mov ax,0400h ; extended init (4), set BREAK condition (0)
int rs232
pop cx
mov ax,cx ; # of ms to wait
call pcwait ; hold break for desired interval
mov dl,flags.comflg ; get type of port
sub dl,'4' ; Bios port
xor dh,dh
xor bx,bx ; no parity (bh) one stop bit (bl)
mov cl,xmtbufx+37 ; returned baud rate index
mov ch,3 ; 8 data bits
mov ax,0401h ; extended init (4), set no BREAK condition (1)
int rs232
pop dx
pop bx
sendbw13:ret
endif ; no_network
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.
; Returns carry clear if success, else carry set.
; 9 July 1989 Add support for 16550/A 14 char receiver fifo.
SERINI PROC NEAR
call pcwtst ; recalibrate pcwait loop timer
cmp portin,0 ; did we initialize port already?
je serin4 ; e = yes
jl serin3 ; l = no, not yet
jmp serin30 ; yes, update flow and leave
serin3: mov bl,flags.comflg ; pass current port ident
mov portin,0 ; say have been here once
call comstrt ; do SET PORT now
jnc serin4 ; nc = success
ret ; failed, exit now
serin4: push bx
mov bx,portval
mov bl,[bx].duplex ; get full/half duplex flag, local cpy
mov dupflg,bl
pop bx
mov cardet,0 ; assume no Carrier is Detected
cmp flags.comflg,4 ; UART?
jbe serin5 ; be = yes, real thing
jmp serin8 ; else try other port kinds
serin5: push bx
push es
mov dx,modem.mdmintc ; interrupt controller
inc dx ; look at interrupt mask
in al,dx ; get interrupt mask
mov savirq,al ; save state here for restoration
or al,modem.mddis ; inhibit our IRQ
out dx,al
mov al,byte ptr modem.mdintv ; desired interrupt vector
mov ah,35H ; Int 21H, function 35H = Get Vector
int dos ; get vector into es:bx
mov word ptr savsci,bx ; save address offset of original vector
mov word ptr savsci+2,es ; and its segment
mov al,byte ptr modem.mdintv ; interrupt number for IRQ
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,setintv ; set interrupt address from ds:dx
int dos
pop ds
mov al,rs232 ; interrupt number for Bios serial port
mov ah,getintv ; 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,setintv ; set interrupt address from ds:dx
int dos
pop ds
pop es
pop bx
mov portin,1 ; Remember port has been initialized
mov ax,modem.mdstat
mov mst,ax ; Use this address for status
mov ax,modem.mddat
mov mdat,ax ; Use this address for data
mov ax,modem.mdiir
mov miir,ax ; uart interrupt ident register
mov al,modem.mdmeoi
mov mdeoi,al ; Use to signify end-of-interrupt
mov ax,modem.mdmintc ; interrupt controller control addr
mov mdintc,ax ;
mov dx,modem.mdstat ; uart line status register, 03fdh
inc dx
in al,dx ; 03feh, modem status reg
mov ah,80h+20h ; CD + DSR bits
and al,ah ; select bits
cmp al,ah ; test CD + DSR bits
je serin5c ; e = both are on, don't reset UART
call delay
mov dx,modem.mdcom
inc dx ; modem control register (3fch)
mov al,0fh ; set DTR, RTS, OUT1, OUT2
out dx,al
call delay
serin5c:mov dx,modem.mdcom ; set up serial card Line Control Reg
in al,dx ; get present settings
mov savlcr,al ; save them for restoration
call delay ; Telepath with this delay removed
mov al,3 ; 8 data bits. DLAB = 0
mov bx,portval
test [bx].parflg,PARHARDWARE ; using hardware parity?
jz serin5h ; z = no
cmp [bx].parflg,PAREVNH ; even parity?
jne serin5e ; ne = no
or al,18h
jmp short serin5h
serin5e:cmp [bx].parflg,PARODDH ; odd parity?
jne serin5f ; ne = no
or al,08h
jmp short serin5h
serin5f:cmp [bx].parflg,PARMRKH ; mark parity?
jne serin5g ; ne = no
or al,20h+18h ; set sticky parity bit (20h)
jmp short serin5h
serin5g:or al,20h+08h ; space parity
serin5h:cmp [bx].stopbits,1 ; one stop bit?
je serin5d ; e = yes
or al,4 ; set bit 2^2 to 1 for two stop bits
serin5d:out dx,al
call delay ; Telepath fails if this is removed
mov dx,modem.mddat
inc dx ; int enable reg (03f9)
in al,dx
mov savier,al ; save for restoration
; drain UART for broken SMC FDC37C665
; UART emulation. Must be before 16550
; testing.
serin5a:mov dx,modem.mdstat ; UART line status reg
in al,dx
call delay
test al,1 ; data ready?
jz serin5b ; z = no
mov dx,modem.mddat ; UART data register
in al,dx ; read the received character into al
call delay
jmp short serin5a ; end SMC broken
serin5b:
mov dx,modem.mdiir ; Interrupt Ident reg (03fah)
in al,dx ; read current setting
call delay ; Telepath fails if this is removed
mov al,087h ; 8 byte trigger (80), reset fifos (2/4), Rx fifo(1)
out dx,al
mov modem.mdfifo,al ; assume FIFO is active
call delay ; Telepath fails if this is removed
in al,dx ; read back iir
and al,0c0h ; select BOTH fifo bits: 16550A vs 16550 (bad fifo)
mov bl,flags.comflg ; get current port ident (1..4)
dec bl ; count from 0
and bx,3 ; stay sane
cmp portfifo[bx],0 ; FIFO mode allowed?
je serin5i ; e = no, shut it off
cmp al,0c0h ; are both fifo enabled bits set?
je serin6 ; e = yes, rcvr fifo is ok (16550/A)
serin5i:call delay ; Telepath fails if this is removed
xor al,al ; else turn off fifo mode (16550/etc)
out dx,al
mov modem.mdfifo,al ; say no FIFO
call delay
serin6: mov dx,modem.mddat ; data and command port, read and flush any
in al,dx ; char in UART's receive buffer
inc dx ; interrupt enable register 3f9h
call delay ; Telepath fails if this is removed
mov al,1 ; set up interrupt enable register
out dx,al ; for Data Available only
call delay ; Telepath fails if this is removed
add dx,3 ; modem control register 3fch
in al,dx ; read original
mov savstat,al ; save original
mov al,0bh ; assert DTR, RTS, not OUT1, and OUT2
cmp dupflg,0 ; full duplex?
je serin7 ; e = yes
mov al,9h ; assert DTR, not RTS, not OUT1, OUT2
serin7: cli
out dx,al ; OUT2 high turns on interrupt driver chip
mov dx,modem.mdiir ; Interrupt Ident reg (03fah)
in al,dx ; read current setting
mov dx,mdintc ; interrupt controller cntl address
inc dx ; access OCW1, interrupt mask byte
in al,dx ; get 8259 interrupt mask
and al,modem.mden ; enable IRQ. (bit=0 means enable)
out dx,al ; rewrite interrupt mask byte
sti
jmp serin30 ; finish up
serin8: mov al,flags.comflg
cmp al,'F' ; Fossil?
jne serin8a ; ne = no
mov dx,fossil_port ; trust not the shabby shells
mov ah,fossil_init ; Fossil, init port in dx
xor bx,bx ; no Control-C nonsense
int rs232
mov ah,fossil_dtr ; Fossil, DTR control
mov al,1 ; raise DTR
mov dx,fossil_port ; port to use
int rs232
push bx
mov bx,portval ; get port data structure
mov al,[bx].floflg ; flow control kind
pop bx
or al,al ; if flow of none
jz serin8c ; z = none
cmp al,2 ; xon/xoff?
jne serin8b ; ne = no
mov al,5 ; Fossil xon/xoff
jmp short serin8c
serin8b:mov al,2 ; RTS/CTS
serin8c:mov ah,fossil_flow
int rs232 ; set flow control
jmp serin30 ; finish up
serin8a:
ifndef no_network
cmp al,'N' ; NetBios?
je serin9 ; e = yes
cmp al,'O' ; Opennet Network? (FGR)
jne serin11 ; ne = no
serin9: mov port_nb.portrdy,0 ; say port is not ready yet
call setnet ; setup network session and pcnet flag
jc serin10 ; c = failed
jmp serin30 ; nc = success
serin10:ret ; fail, carry set, leave portin at 0
serin11:cmp al,'E' ; using EBIOS?
jne serin13 ; ne = no
test nettype,acsi ; using EBIOS.COM?
jnz serin9 ; nz = not using it
mov bx,offset ebcoms ; es:bx to ebcoms structure
mov ebcoms+1,80h ; force a network connection
mov ah,ebredir ; do redirection
xor al,al
mov dx,ebport
int rs232
or ax,ax
jz serin12 ; ax = 0 is success
stc ; fail
ret
serin12:mov dx,ebport ; port 0..3
mov bx,offset rcvbuf ; receive buffer for EBIOS
push es
mov ax,ds
mov es,ax ; set es:bx to the buffer address
mov cx,nbuflen ; set cx to buffer's length
mov ax,ebbufset*256+2 ; set rcvr buffered mode
int rs232
mov cx,nbuflen
mov bx,offset xmtbuf ; EBIOS transmitter work buffer
mov ax,ebbufset*256+1 ; set xmtr buffered mode
int rs232
mov ax,ebmodem*256+3 ; set outgoing DTR and RTS modem leads
int rs232 ; and ignore incoming leads
mov pcnet,1
pop es
jmp serin30
serin13:cmp al,'D' ; DECnet?
jne serin14 ; ne = no
call decstrt ; reinit
jnc serin30 ; nc = success
ret ; fail, carry set, leave portin at 0
serin14:cmp al,'T' ; Novell TELAPI?
jne serin15 ; ne = no
cmp pcnet,2 ; going already?
je serin30 ; e = yes
call telstrt ; start Telnet session
jnc serin30 ; nc = success
call telapiclose ; close session
stc
ret ; fail, leave portin at 0
serin15:cmp al,'M' ; Meridian SuperLAT?
je serin15a ; e = yes
cmp al,'I' ; TES?
jne serin17 ; ne = no
cmp latkind,TES_LAT ; using LAT?
jne serin16 ; ne = no, older style
serin15a:call decstrt ; reinit
jnc serin30 ; nc = success
ret ; fail, carry set, leave portin at 0
serin16:call tesstrt ; start a TES session
jnc serin30 ; nc = success
mov ax,2000 ; pause 2 sec for any msg
call pcwait
stc
ret
serin17:
ifndef no_tcp
cmp al,'t' ; TCP/IP?
jne serin18 ; ne = no
call tcpstart ; start TCP connection
jnc serin30
push bx
mov bx,portval ; get port data structure
mov [bx].portrdy,0 ; say the comms port is not ready
mov portin,0
pop bx
stc
ret ; fail
endif ; no_tcp
serin18:cmp al,'U' ; Ungermann Bass?
je serin20 ; e = yes
cmp al,'C' ; 3Com BAPI?
je serin20 ; e = yes
serin19:cmp al,'b' ; [JRS] Beame & Whiteside TCP
jne serin20 ; [JRS] ne = no
call bwstart ; [JRS] start a Telnet session w/BWTCP
jnc serin30 ; [JRS] nc = success
ret ; [JRS]
serin20:mov bl,al ; preset net type
call comstrt ; start net
jnc serin30
ret ; c = failure
endif ; no_network
serin30:push bx
mov bx,portval ; get port data structure
mov [bx].portrdy,1 ; say the comms port is ready
mov parmsk,0ffh ; parity mask, assume parity is None
cmp [bx].parflg,parnon ; is it None?
je serin31 ; e = yes
mov parmsk,07fh ; no, pass lower 7 bits as data
serin31:xor ax,ax
mov al,[bx].floflg ; flow control kind
mov flowcnt,al ; save here for active use
mov ax,[bx].flowc ; get flow control chars
pop bx
mov flowoff,al ; xoff or null
mov flowon,ah ; xon or null
mov xofrcv,off ; clear xoff received flag
call testcd ; update cardet byte
mov quechar,0 ; clear outchr queued flow control
call clrclock ; clear elapsed time clock if req'd
mov portin,1 ; say initialized
clc ; carry clear for success
ret ; We're done
SERINI ENDP
; Gateway 2000 Telepath internal modem extra delay routine
delay proc near
push ax
mov ax,1 ; 1 millisecond
call pcwait
pop ax
ret
delay endp
; Set session start time of day, if starttime+3 or reset_clock are
; non-zero. Forces both to zero afterward.
clrclock proc near
push bx
mov bx,portval
xor ax,ax
xchg starttime[bx+3],al ; get and clear clock reset byte
xchg reset_clock,ah ; from set port command
or ax,ax ; reset clock?
jz clrclk2 ; z = no
mov ah,gettim ; read DOS tod clock
int dos ; ch=hours, cl=minutes, dh=seconds
mov al,60
mul ch ; hours to minutes in ax
add al,cl ; plus minutes
adc ah,0
mov bl,dh ; save seconds in bx
xor bh,bh
mov cx,60
mul cx ; hh+mm to seconds in dx:ax
add ax,bx ; plus seconds
adc dx,0 ; total seconds in dx:ax
mov bx,portval
cmp flags.comflg,'t' ; doing TCP/IP Telnet?
je clrclk1 ; e = yes
mov word ptr starttime[bx],ax
mov word ptr starttime[bx+2],dx
jmp short clrclk2
clrclk1:
ifndef no_terminal
ifndef no_tcp
mov bx,sescur ; current session ident
js clrclk2 ; s = invalid session
shl bx,1
shl bx,1 ; quad bytes
mov word ptr sestime[bx],ax
mov word ptr sestime[bx+2],dx
endif ; no_tcp
endif ; no_terminal
clrclk2:pop bx
ret
clrclock 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.
; Returns normally.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls [jrd]
; 17 May 1987 Redo for COM3/4 support [jrd]
; 9 July 1989 Accomodate 16550/A receiver fifo mode. [jrd]
SERRST PROC NEAR
cmp portin,0 ; Reset already?
jg srst3 ; g = no
clc
ret ; e = yes, l=not used yet, just leave
srst3: cmp flags.comflg,'0' ; Bios or networks?
jb srst4 ; b = no, real UART
jmp srst6 ; finish up
srst4: push word ptr savsci ; save original interrupt owner
push word ptr savsci+2 ; offset and segment
mov word ptr savsci,offset nulint ; redirect to our null routine
mov ax,seg nulint ; segment of null routine is code
mov word ptr savsci+2,ax
xor cx,cx ; loop counter
srst2: mov dx,modem.mdstat ; status register
in al,dx
call delay ; delay
and al,60h ; Shift Reg Empty & Holding Reg Empty
cmp al,60h ; are both set?
loopne srst2 ; ne = no, wait until so (or timeout)
xor al,al
mov dx,modem.mdiir ; modem Interrupt Ident reg (03fah)
out dx,al ; turn off FIFO mode
call delay
dec dx ; point at int enable reg 3f9h
out dx,al ; disable interrupts from this source
call delay ; delay, let stray ints occur now
add dx,2 ; point at Line Control Register 3fbh
mov al,savlcr ; saved bit pattern
and al,not 80h ; force DLAB bit to 0
out dx,al ; restore line control state
call delay
; clear modem's delta status bits and reassert DTR etc
inc dx ; increment to modem control register 3fch
mov al,savstat ; saved modem control reg (03fch)
or al,3 ; ensure DTR and RTS are asserted
cmp dupflg,0 ; full duplex?
je srst2a ; e = yes
xor cx,cx
push dx ; save dx around test below
srst2b: mov dx,modem.mdstat ; modem line status reg
in al,dx ; read transmitter shift reg empty bit
call delay
test al,40h ; is it empty?
loopz srst2b ; z = no, not yet
pop dx
mov al,savstat ; saved modem control reg
or al,1 ; assert DTR
and al,not 2 ; unassert RTS
srst2a: out dx,al ; restore modem control reg (03fch)
call delay ; pause, in case stray interrupt is generated
add dx,2 ; modem status register 3feh
in al,dx ; clear status register by reading it
mov mdmhand,al ; save here for Show Modem
cli ; Disable interrupts
mov dx,modem.mdmintc
inc dx
in al,dx ; Interrupt controller int mask
or al,modem.mddis ; inhibit our IRQ line
push ax
in al,ppi_port ; delay
pop ax
out dx,al
sti
pop word ptr savsci+2 ; recover original int owner's addr
pop word ptr savsci
; replace original IRQ intrpt vector
push bx
mov al,byte ptr modem.mdintv ; vector number to do
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,setintv ; 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,setintv ; set interrupt vector
int dos
pop ds
pop bx
mov ah,savirq ; saved Interrupt state
and ah,modem.mddis ; pick out our IRQ bit
mov dx,modem.mdmintc ; interrupt controller cntl address
cli
inc dx
in al,dx ; get current intrpt controller state
push ax
in al,ppi_port ; delay
pop ax
and al,modem.mden ; set our bit to zero
or al,ah ; set previous state of our IRQ
out dx,al ; reset IRQ to original state
sti
mov dx,modem.mddat ; base address, 03f8h
inc dx ; Interrupt Enable Reg (03f9h)
mov al,savier ; saved IER
out dx,al ; restore setting
jmp short srst9
; non-UART processes
srst6:
ifndef no_network
cmp pcnet,0 ; a network active?
je srst8 ; e = no
cmp flags.comflg,'O' ; Opennet network? (FGR)
je srst7 ; e = yes
cmp flags.comflg,'N' ; NetBios network?
jne srst8 ; ne = no
srst7: cmp rposted,0 ; receive outstanding?
je srst8 ; e = no
mov can.scb_baddr,offset rcv ; cancel receives
push bx
mov bx,offset can
call nbsession
pop bx
mov rposted,0 ; clear interlock flag no matter what
cmp lposted,0 ; Listen posted?
jne srst8 ; ne = yes, don't post another
call nbclose ; shut down NetBIOS
endif ; no_network
srst8: cmp flags.comflg,'F' ; Fossil?
jne srst9 ; ne = no
cmp fossilflag,0 ; shut down port when done?
je srst9 ; e = no
mov dx,fossil_port ; port
mov ah,fossil_done ; fossil, done with driver
int rs232
srst9: mov portin,0 ; reset flag
push bx
mov bx,portval ; port data structure
mov [bx].portrdy,0 ; say port is not ready
pop bx
mov quechar,0 ; clear any outchr queued char
clc
ret
SERRST ENDP
code ends
code1 segment
assume cs:code1
; Null interrupt routine, to handle strays
nulint proc near
push ax
push dx
push ds
mov ax,data ; set data seg addressibility
mov ds,ax
mov al,mdeoi ; specific EOI
mov dx,mdintc ; interrupt controller control word
out dx,al
test dl,80h ; slave controller?
jz nulint1 ; z = no
mov al,20h ; general EOI
out 20h,al ; EOI to master 8259
nulint1:pop ds
pop dx
pop ax
iret
nulint 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 data ; get our data segment
mov ds,ax
mov al,flags.comflg ; get port id (COM1 = 1, COM2 = 2)
and al,7 ; use lower three bits
dec al ; DOS counts COM1 as 0, etc
mov dosctty,0 ; assume DOS not using our comms line
cmp dl,al ; referencing same port as Kermit is using?
pop ax ; recover request parameters
jne serdu1 ; ne = no, chain to Bios routine
mov dosctty,1 ; say DOS is using our comms line
pop ds
cmp ah,1 ; send char in al?
jb serdu3 ; b = no, init, return dummy status=ok
ja serdu2 ; a = no, other
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
xor ah,ah ; ah = errors (none here)
iret
serdu3: mov ax,60b0h ; dummy status report:xmtr empty, CD,
iret ; DSR, and CTS are on
serdu1: pop tempdum ; save old ds
push word ptr sav232+2 ; push Bios int 14H handler segment
push word ptr sav232 ; push Bios int 14H handler offset
push tempdum ; recover old ds
pop ds
ret ; do a ret far (chain to Bios)
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.
; 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.
; Upgraded to read cause of interrupt from interrupt ident reg (accepts only
; data ready), chain to old interrupt if source is not our device.
; 9 Feb 1988 Add storage of interrupt cause in intkind. [jrd]
; 9 July 1989 Add support for 16550/A 14 char receiver fifo.
SERINT PROC FAR
push ax ; save registers
push dx ;
push ds
mov ax,seg data
mov ds,ax ; address data segment
mov dx,miir ; modem interrupt ident reg
in al,dx ; get interrupt cause
mov intkind,al ; save cause here
test al,1 ; interrupt available if this bit is zero
jz srintc ; z = interrupt is from our source
; temporary item to side step chaining for noisy buses and funny Bios'
; push ds ; preserve data seg addressibility
; pushf ; call the old int handler
; call dword ptr savsci ; via pseudo INT
; pop ds ; recover data seg
and intkind,not 4 ; say not-data-ready, to exit below
srintc: mov al,mdeoi ; specific EOI
mov dx,mdintc ; interrupt controller control word
out dx,al
test dl,80h ; slave controller?
jz srintd ; z = no
mov al,22h ; specific EOI for IRQ 2 (cascade)
out 20h,al ; EOI the master 8259
srintd: test intkind,4 ; data ready?
jnz srint0a ; nz = yes, else ignore
srint0: sti ; else turn on interrupts
jmp retint ; and exit now (common jump point)
srint0a:mov dx,mst ; asynch status port
in al,dx
srint0b:cli ; no interrupts permitted here
and al,mdmover ; select overrun bit
mov ah,al ; save it for later
mov dx,mdat
in al,dx ; read the received character into al
test flowcnt,2 ; incoming XON/XOFF flow control?
jz srint2 ; z = no
mov dh,al ; dh = working copy. Check flow cntl
and dh,parmsk ; strip parity temporarily, if any
cmp dh,flowoff ; acting on Xoff?
jne srint1 ; ne = no, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF?
jne srint4e ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; set the flag saying XOFF received
jmp short srint4e ; and continue the loop
srint1: cmp dh,flowon ; acting on Xon?
jne srint2 ; ne = no, go on
mov xofrcv,off ; clear the XOFF received flag
jmp short srint4e ; and continue the loop
srint2: push bx ; save register
or ah,ah ; overrun?
jz srint2a ; z = no
mov ah,al ; yes, save present char
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 short srint2a ; yes, go store real second char
srint4a:pop bx ; restore reg
srint4e:mov dx,mst ; uart line status register, 03fdh
in al,dx ; get status
test al,1 ; data ready?
jnz srint0b ; nz = yes, and preserve al
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
test flowcnt,4 ; using RTS/CTS flow control?
jz srint4b ; z = no
mov dx,mst ; modem status port (03fdh)
dec dx ; modem control reg (03fch)
in al,dx
and al,not 2 ; reset RTS bit
push ax
in al,ppi_port ; delay
pop ax
out dx,al ; tell the UART to drop RTS
mov xofsnt,bufon ; remember RTS reset at buffer level
jmp short retint
srint4b:test flowcnt,1 ; send outgoing XON/XOFF?
jz retint ; z = no
mov al,flowoff ; get the flow off char (XOFF or null)
push bx
mov bx,portval
cmp [bx].baud,Bsplit ; doing 75/1200 baud stuff?
pop bx
jne srint4c ; ne = no
mov quechar,al ; put char in outchr queue for sending
cmp timeract,0 ; is timer being used at task level?
jne srint4d ; ne = yes, just queue the char
mov ah,al ; put char into ah
call foutchr ; send the char now, non-blocking
srint4d:jmp short retint
srint4c:call fdopar ; set parity appropriately
mov ah,al ; don't overwrite character with status
push cx ; save reg
xor cx,cx ; loop counter
srint5: mov dx,mst ; get port status
in al,dx
test al,20H ; transmitter ready?
jnz srint6 ; nz = yes
in al,ppi_port ; delay
in al,ppi_port ; delay
in al,ppi_port ; delay
loop srint5 ; else wait loop, cx times
jmp short srint7 ; timeout
srint6: mov al,ah ; now send out the flow control char
mov dx,modem.mddat
push ax
in al,ppi_port ; delay
pop ax
out dx,al
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
; Update cardet byte for UART, Bios and Fossil ports
testcd proc far
cmp flags.carrier,0 ; worry about carrier detect?
je testcdx ; e = no
push ax
push dx
mov al,flags.comflg
cmp al,4 ; UART?
jbe testcd1 ; e = yes
cmp al,'4' ; BIOS?
je testcd2 ; e = yes
cmp al,'F' ; Fossil?
je testcd3 ; e = yes
pop dx
pop ax
jmp short testcdx ; can't get CD for the rest
testcd1:mov dx,modem.mddat ; UART
add dx,6 ; modem status reg 3feh
in al,dx ; 03feh, modem status reg
jmp short testcd4
testcd2:mov ah,3 ; check port status, std Bios calls
mov dl,al ; port + bias
sub dl,'1' ; remove bias
int rs232 ; Bios call
jmp short testcd4
testcd3:mov dx,fossil_port ; get port number (1..4)
mov ah,fossil_portst ; check port status, std Bios calls
int rs232 ; Bios call
testcd4:and al,80h ; get CD bit
jnz testcd5 ; nz = CD is on now
test cardet,80h ; previous CD state
jz testcd5 ; z = was off, still is
mov al,01h ; say was ON but is now OFF
mov flags.cxzflg,'C' ; simulate Control-C interrupt
testcd5:mov cardet,al ; preserve as global
pop dx
pop ax
testcdx:ret
testcd endp
code1 ends
code segment
assume cs:code
DTRLOW PROC NEAR ; Global proc to Hangup the Phone or Network
; by making DTR and RTS low (phone).
mov ah,cmword ; allow text, to be able to display help
mov bx,offset rdbuf ; dummy buffer
mov dx,offset hnghlp ; help message
call comnd
jc dtrlow3 ; c = failure
mov ah,cmeol
call comnd ; get a confirm
jc dtrlow3
cmp flags.comflg,'0' ; Bios?
jb dtrlow1 ; b = no, UART
cmp flags.comflg,'4' ; Bios?
jbe dtrlow2 ; be = yes, can't access modem lines
dtrlow1:call serhng ; drop DTR and RTS
cmp taklev,0 ; in a Take file or macro?
jne dtrlow2 ; ne = yes, no message
mov ah,prstr ; give a nice message
mov dx,offset hngmsg
int dos
dtrlow2:clc ; success
dtrlow3:ret
DTRLOW ENDP
; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 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 session close procedure to hangup the session without
; losing local name information; serrst does this.
; Returns normally.
serhng proc near ; clear modem's delta status bits and lower DTR & RTS
cmp apctrap,0 ; APC disable?
je shng1 ; e = no
stc ; fail
ret
shng1: call serrst ; reset port so can be opened again
cmp flags.comflg,'F' ; Fossil?
je shng2 ; e = yes
ifndef no_network
cmp flags.comflg,4 ; UART port?
jbe shng2 ; be = yes
push bx
mov bx,portval
call [bx].cloproc ; close the active network session
pop bx
clc
ret
endif ; no_network
shng2: call serini ; energize, maybe for first time
cmp flags.comflg,'F' ; Fossil?
jne shng3 ; ne = no
push ax
push dx
mov ah,fossil_dtr ; Fossil, DTR control
xor al,al ; lower DTR
mov dx,fossil_port ; port to use
int rs232
call serrst
jmp short shng4
shng3: call serrst ; back to sleep
cli ; Disable interrupts
push ax
push dx
mov dx,modem.mddat ; serial port base address
add dx,4 ; increment to control register
mov al,08h ; reassert OUT2, un-assert DTR,RTS,OUT1
out dx,al
in al,ppi_port ; delay
add dx,2 ; increment to modem status register
in al,dx ; Clear Status reg by reading it
sti ; Enable interrupts
shng4: mov ax,1000 ; 1000 millisec, for pcwait
call pcwait ; keep lines low for at least 500 millisec
pop dx
pop ax
clc
ret
serhng endp
; Compute number of iterations needed in procedure pcwait inner loop
; to do one millisecond delay increments. Uses Intel 8253/8254 timer chip
; (timer #2) to measure elapsed time assuming 1.193182 MHz clock.
; For IBM PC compatible machines.
pcwtst proc near
push cx
mov cx,10 ; number of tests to perform
pcwtst1:call pcwtst2 ; do the test and new pcwcnt calculation
loop pcwtst1 ; repeat several times for convergence
pop cx
ret
pcwtst2:push ax
push bx
push cx
push dx
in al,ppi_port ; 8255 chip port B, 61h
and al,0fch ; speaker off (bit 1), stop timer (bit 0)
out ppi_port,al ; do it
; 10 = timer 2, 11 = load low byte then high byte, 010 = mode 2, 0 = binary
mov al,10110100B ; command byte
out timercmd,al ; timer command port, 43h
xor al,al ; clear initial count for count-down
out timer2data,al ; low order byte of count preset, to port 42h
out timer2data,al ; high order byte, to the same place
in al,ppi_port ; get 8255 setting
mov dl,al ; remember it in dl
and al,0fch ; clear our control bits
or al,1 ; start counter now (Gate = 1, speaker is off)
out ppi_port,al ; do it, OUT goes low
; this is the test loop
mov ax,8 ; wait 8 millisec
call pcwait ; call the software timer
; end test loop
mov al,dl ; restore ppi port, stop timer
out ppi_port,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
mov bx,ax ; save observed tics
mov ax,pcwcnt ; current pcwcnt value
; new pcwcnt= old pcwcnt * [1193(tics/ms) / (observed tics / loops)]
mov cx,8*1193
mul cx
or bx,bx ; zero observed tics?
jz pcwtst3 ; z = yes, divide by one
cmp dx,bx ; overflow?
jb pcwtst4 ; b = not likely
mov ax,pcwcnt
jmp short pcwtst3 ; bypass calculation
pcwtst4:div bx ; divided by observed tics
pcwtst3:mov pcwcnt,ax ; store quotient as new inner loop counter
pop dx
pop cx
pop bx
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 FAR
push cx
push ds
mov cx,data
mov ds,cx
pcwai0: mov cx,pcwcnt ; inner loop counter for 1 ms
pcwai1: push ax
in al,PPI_PORT ; touch bus to deal with fast caches
pop ax
sub cx,1
jnz pcwai1
dec ax ; outer loop counter
jnz pcwai0 ; wait another millisecond
pop ds
pop cx
ret
pcwait endp
ifndef no_tcp
sesdisp proc near
mov ah,cmeol
call comnd
jnc sesdisp1
ret
sesdisp1:call fsesdisp ; located in seg code1
ret
sesdisp endp
endif
code ends
code1 segment
assume cs:code1
ifndef no_tcp
; TCP/IP Telnet session manager.
; Enter with SET PORT TCP/IP command line in buffer decbuf,
; and <byte count> + <port number> + NUL + {NEW, RESUME} in decbuf+80
; Syntax of that line is
; empty - resume current session, error return if none.
; digit - start or resume session digit, with digit being a local number.
; host - ask if resume or new. If resume call ktcpswap, else tcpstart.
; * - server mode
; Returns sescur as index (0..maxsessions-1) for seslist action.
; Successful return is carry clear, else carry set.
sesmgr proc far
ifndef no_terminal
push bx
mov bx,sescur ; current session
call termswapout ; swap out current session's emulator
pop bx
endif ; no_terminal
cmp decbuf,1 ; byte count, anything given?
jb sesmgr24 ; b = no, use tcphost default
ja sesmgr40 ; ja = yes, but more than one char
mov bl,decbuf+1 ; get single char
mov al,bl
and al,not 20h ; upper case, for letters only
jmp short sesmgr13
sesmgr10:cmp sescur,-1 ; any session yet?
je sesmgr22 ; e = no, use command line
call iseof ; are we at EOF, such as from disk?
jc sesmgr28 ; c = yes, fail the command
call fsesdisp ; display the table for guidance, inc help
mov dx,offset seshelp
mov ah,prstr
int dos
mov flags.cxzflg,0 ; clear Control-C flag
mov ax,0c0ah ; clear buffer and read line
mov decbuf+100,80 ; length of our buffer
mov dx,offset decbuf+100 ; start of buffer (len, cnt, data)
int dos
cmp flags.cxzflg,'C' ; Control-C entered?
je sesmgr28 ; e = yes, quit
mov al,decbuf+101 ; number of printables entered
or al,al ; need at least one
jz sesmgr15 ; default is NEW
mov bl,decbuf+102 ; get first byte
mov al,bl
and al,not 20h ; upper case, for letters only
sesmgr13:cmp bl,'*' ; "*" for server mode?
je sesmgr40 ; e = yes, use as host name
sesmgr13a:cmp al,'R' ; RESUME current?
jne sesmgr14 ; ne = no
clc ; resume current session
ret
sesmgr14:cmp al,'Q' ; QUIT?
je sesmgr28 ; e = yes, return failure
cmp al,'N' ; NEW?
jne sesmgr20 ; ne = no
sesmgr15:mov cx,maxsessions ; find an opening for NEW
xor bx,bx
sesmgr16:mov al,seslist[bx]
or al,al ; session in use?
jns sesmgr18 ; ns = yes
mov sescur,bx ; set current session ident
jmp short sesmgr22 ; s = no
sesmgr18:inc bx ; next slot
loop sesmgr16
mov dx,offset sesnone ; say no more sessions available
mov ah,prstr
int dos
stc ; fail out
ret
sesmgr20:xor bh,bh ; ensure high byte is clear
sub bx,'1' ; assume digit 1..6, remove bias
cmp bx,6 ; legal values are 0..5
jae sesmgr10 ; ae = out of range
mov sescur,bx ; return slist index for action
mov al,bl
mov cx,seshostlen ; length of a table entry
mul cl ; skip to correct sesname
cmp decbuf,1 ; host name given on command line?
ja sesmgr22 ; a = yes, use it as host name
mov di,offset tcphost ; update active host name
add ax,offset sesname ; get host name from table
mov si,ax
cmp byte ptr [si],0 ; any name present?
jne sesmgr20a ; ne = yes
xchg si,di ; use current name in tcphost
jmp short sesmgr26 ; use existing tcpport too
sesmgr20a:push bx
shl bx,1 ; address words
mov ax,sesport[bx]
mov tcpport,ax ; set tcpport
pop bx
jmp short sesmgr26 ; and switch terminal configuration
sesmgr22:push bx
mov ax,tcpport ; tcp port
mov bx,sescur ; new session
or bx,bx ; negative, for no session?
jns sesmgr22a ; ns = not negative
xor bx,bx ; start session 0
mov sescur,bx
sesmgr22a:shl bx,1 ; address words
mov sesport[bx],ax ; port
pop bx
mov si,offset decbuf+1 ; name of new host
cmp byte ptr [si-1],0 ; byte count, anything given?
je sesmgr24 ; e = no, use tcphost default
mov di,offset tcphost
call strcpy ; copy new host name
sesmgr24:mov si,offset tcphost ; host name
cmp byte ptr [si],0 ; is this empty too?
je sesmgr27 ; e = yes, no host name, fail
cmp sescur,0 ; inited current session ident?
jge sesmgr25 ; ge = yes
mov sescur,0 ; start with session 0
sesmgr25:mov bx,sescur ; return slist index for action
mov al,bl
mov cx,seshostlen ; length of a table entry
mul cl ; skip to correct sesname
add ax,offset sesname ; destination table
mov di,ax
sesmgr26:call strcpy
push bx
mov ax,tcpport
mov bx,sescur ; new session
shl bx,1
mov sesport[bx],ax
ifndef no_terminal
shr bx,1
call termswapin ; swap in new session's emulator
endif ; no_terminal
pop bx
clc
ret
sesmgr27:mov dx,offset sesnohost ; say have no host name
mov ah,prstr
int dos
sesmgr28:mov kstatus,ksgen ; command failure
stc
ret
; user specified host name
; see if name is already in use
sesmgr40:mov si,offset decbuf+1 ; user string
mov cl,[si-1] ; user string length
xor ch,ch
cld
sesmgr41:lodsb ; read a byte
call tolowr ; to lower case
mov [si-1],al ; store letter
loop sesmgr41
mov si,offset decbuf+81 ; optional port number
mov temp2,si ; where to expect New/Resume
mov al,[si-1] ; byte count
xor ah,ah
mov domath_cnt,ax ; for domath
xor ax,ax ; default port
cmp domath_cnt,0 ; byte count, any port specified?
je sesmgr46 ; e = no, use default
sesmgr44:
mov domath_ptr,si
add si,domath_cnt ; skip over field for next read
mov temp2,si ; where to expect New/Resume
mov domath_msg,1 ; do not complain about letters
call domath ; convert to number in ax
jnc sesmgr45 ; nc = decoded a port number
sub si,domath_cnt
mov temp2,si ; back up for New/Resume
jmp short sesmgr46
sesmgr45:or ax,ax ; any port specified?
jz sesmgr46 ; z = no, use 23
cmp ax,25 ; this one?
jne sesmgr47 ; ne = no
mov ah,prstr
mov dx,offset badport ; say bad port number
int dos
sesmgr46:mov ax,23 ; use official Telnet port
sesmgr47:mov temp,ax ; remember port
mov cx,maxsessions
xor bx,bx ; session subscript, assummed
mov si,offset decbuf ; user len+string
mov di,offset sesname ; session list of host names
cld
sesmgr42:push cx
push si
push di
push es
mov cl,[si] ; length of user string
xor ch,ch
inc si ; skip user string count byte
inc cl ; include null termintors
mov ax,seg sesname
mov es,ax
repe cmpsb ; compare host names
pop es
pop di
pop si
pop cx
jne sesmgr43 ; ne = no match, try next entry
cmp seslist[bx],0 ; is session active?
jl sesmgr43 ; l = no, ignore this entry
shl bx,1 ; address words
mov ax,sesport[bx] ; current port
shr bx,1 ; restore bx
cmp ax,temp ; specified port same?
jne sesmgr43 ; ne = no, not a duplicate session
mov bx,temp2 ; where to expect NEW/RESUME
mov bl,[bx] ; get first byte of NEW/RESUME
or bl,bl ; anything?
jz sesmgr10 ; z = no, show menu and prompt
mov al,bl ; get byte
and al,not 20h ; to upper case, for letters only
jmp sesmgr13a ; decode letter
sesmgr43:add di,seshostlen ; next entry in our table
inc bx ; next session subscript
loop sesmgr42
mov ax,temp
mov tcpport,ax ; set tcpport
jmp sesmgr15 ; start a New session
sesmgr endp
fsesdisp proc far
mov ah,prstr
mov dx,offset sesheader
int dos
push bx
xor bx,bx ; number of sessions
sesdis1:mov al,bl ; get our local counter
mov dl,seshostlen ; length of host name array row
mul dl
add ax,offset sesname ; asciiz host name
mov si,ax ; save host name pointer in cx
cmp byte ptr [si],0 ; ever had a host name?
jz sesdis3 ; z = no, don't display info
mov al,seslist[bx] ; get Telnet session number
mov dx,offset sesinact ; inactive msg
or al,al ; seslist status
jns sesdis4 ; ns = active
cmp bx,sescur ; same as current?
jne sesdis2 ; ne = no
mov dx,offset curinact ; say inactive but current
jmp short sesdis2
sesdis4:mov dx,offset sesactive ; active msg
cmp bx,sescur ; same as current?
jne sesdis2 ; ne = no
mov dx,offset curmsg ; current msg
sesdis2:mov ah,prstr ; show status, ses #, host name
int dos
mov dl,bl ; count local session idents
add dl,'1' ; bias
mov ah,conout
int dos
mov dl,' '
int dos
int dos
int dos
int dos
int dos
int dos
int dos
shl bx,1 ; address words
mov ax,sesport[bx]
shr bx,1 ; restore bx
call decout
mov ah,conout
mov dl,' '
int dos
int dos
mov dx,si
call prtasz ; show host name
sesdis3:inc bx ; next item
cmp bx,maxsessions ; done all?
jb sesdis1 ; b = no
pop bx
ret
fsesdisp endp
; Returns session ident in BX when given a Telnet ident in AL. Also updates
; tcphost from session table.
; Returns -1 if no correspondence
tcptoses proc far
push ax
push cx
mov cx,maxsessions ; number session slots
xor bx,bx
tcptose1:mov ah,seslist[bx] ; session status
or ah,ah ; active?
js tcptose2 ; s = no
cmp ah,al ; same active session?
je tcptose3 ; e = yes, return BX
tcptose2:inc bx
loop tcptose1
mov bx,-1 ; return -1 for failure to find
pop cx
pop ax
ret
tcptose3:push si
push di
mov di,offset tcphost ; host name
mov al,bl
mov cx,seshostlen ; length of a table entry
mul cl ; skip to correct sesname
add ax,offset sesname ; source table
mov si,ax
call strcpy
pop di
pop si
pop cx
pop ax
ret
tcptoses endp
endif ; no_tcp
code1 ends
end