home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
extra
/
nyenhuis3.arc
/
MSXIBM.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-16
|
135KB
|
3,933 lines
; File MSXIBM.ASM
; Kermit system dependent module for IBM-PC
include mssdef.h
; Edit History
; Last edit 16 Jan 1990
; 30 Sept 1989 Incorporate Opennet networking material from Fred Richter.
; 30 Sept 1989 Fred Richter (FGR) Intel Corp, Hauppauge NY
; polyof!inthap!fred or fred@polyof.poly.edu
; Added support for Intel Opennet Networking Virtual Terminal Services
; added "set port opennet xxx", also modified (slightly)
; the Netbios code (rpost) to always have the next Netbios receive posted
; as a small efficiency gain. Added error checking for received Netbios
; packets (there was none for async receives), also fix problem when the
; receives are canceled, where the data was being accepted anyway.
; 3 Sept 1989 Add DECnet CTERM and LAT support, plus Novell Int 6Bh.
; 9 July 1989 Add automatic usage of National Semiconductor 16550A UART in
; receiver fifo mode. Thanks to Dan Norstedt, danne@kicki.stacken.kth.se,
; and Campbell Scientific, Logan Utah for urging and supporting information.
; 17 June 1989 Add transparent interrupt driven support for IBM's Extended
; Bios via SET PORT BIOSn.
; 8 June 1989 Add Wyse-700 support from (Mikko Laanti (mjl).
; 6 March 1989 Add SET TERMINAL REPLAY FILESPEC command.
; 21 Jan 1989 Avoid initializing a port until the port is accessed for regular
; use, baud rate setting, or modem status. portin=-1 means unaccessed.
; 2 Dec 1988 Preserve UART parity etc bits in Line Control Reg.
; 30 Nov 1988 Add SET TERM CLEAR screen clear command (uses byte VTCLEAR).
; 26 Nov 1988 Add SET TERM TAB SET/CLEAR AT start-col:spacing notation.
; 21 Nov 1988 Version 2.32
; 25 Oct 1988 Add Ungermann Bass network board status check in proc chkub,
; thanks to Fritz Buetikofer and Rene Rehmann in Switzerland.
; 9 Oct 1988 Add byte vtemu.vtchset to hold choices for VT102 emulator
; character sets (US, UK, or Alternate-ROM). Tnx to Baruch Cochavy. The value
; of vtemu.vtchset must match definitions in emulator file mszibm.asm.
; 5 Oct 1988 Add SET TERMINAL DIRECTION command and status display line.
; 21 August 1988 Move tests for NUL and DEL received chars to prtchr routine
; for uniform application of tests.
; 28 July 1988 Add more UB details from Henrik Levkowetz. Double check serial
; port address for 02f8h with COM1, for PCjr, and shift to COM2 addresses.
; 16 July 1988 Use null interrupt routine, nulint, when resetting serial port
; because setting OUT2 low generates stray ints on some UARTs. [jrd]
; 1 July 1988 Version 2.31
; 12 June 1988 Add small changes to handle network session failures, and
; add carry set if serini fails to init port.
; 29 May 1988 Add Ungermann Bass NetOne NETCI support from Henrik Levkowetz
; [ohl]. Revise same to test for actual network presence and to avoid
; interference with NetBios operations. Use "SET PORT UB-Net1"
; 23 May 1988 Hangup now resets serial port so can be re-inited with DTR high
; 21 May 1988 Tweak serrst to allow stray interrupts while resetting UART,
; clear outstanding network requests when changing ports.
; 6 May 1988 Introduce xmtbufx for explict network double buffering of
; xmitted data.
; 28 April 1988 fix set port bios register problem.
; 18 April 1988 Network: do another READ when char count < low water mark.
; If BIOSn is selected skip test of Bios 40:0h for port presence.
; 3 April 1988 Ignore NUL and DEL at serial port unless DEBUG or TRANSLATE
; INPUT are active, but pass DEL if Tek mode is active. Replace netdone
; with new lclexit global word to shut net when Kermit exits.
; 22 March 1988 Add global byte Tekgraf which forces graphics board type
; 0=auto-sensing, 1=cga, 2=ega, 3=VGA, 5=Hercules, 5=ATT. Tekgraf stored
; and set in this file by Set Term Graphics <board type>. [jrd]
; 6 March 1988 Ignore received XOFF's if we have already sent one. [jrd]
; 27 Feb 1988 Add global routine getmodem to return modem status in al. [jrd]
; 9 Feb 1988 Automaticallly find Interrupt ReQuest level for a port.
; No Modem Status for network. [jrd]
; 25 Jan 1988 Revise outchr waiting on XON to use 4 millisec increments. [jrd]
; 1 Jan 1988 version 2.30
; 24 Dec 1987 Revise selection of COM1 to use COM1 name but COM2 addresses
; if base address of 02f8 (COM2) is found in 40:00h and display notice.
; Restore state of IRQ interrupt line when finished with serial port. [jrd]
; 31 Oct 1987 Add terminal type Tek4010, with Tek submode Tekflg. [jrd]
; 24 Oct 1987 Enhance clrbuf to empty any intermediate (net) buffers. [jrd]
; 19 Oct 1987 Fix stray tab-set at column 32. [jrd]
; 2 Oct 1987 Add PCjr baud rate table, from Ted Medin. [jrd]
; 6 Sept 1987 Allow serial port serint to send xoff when buffer fills even
; though user may have sent xoff by hand. [jrd]
; 27 Aug 1987 Skip timeout test in OUTCHR if receive timeout is zero. [jrd]
; 23 August 1987 Add vtemu.vtflgop to hold runtime terminal settings so that
; a reset command restores them to the Setup values, vtemu.vtflgst. Show
; displays the vtemu.vtflgop operational values. [jrd]
; 17 August 1987 Make timing adjustments for Token Passing and single buffered
; network adapter boards. Byte netdbfr indicates presence of double buffering;
; it is set in chknet as a vendor option. To test your boards force dbl buf
; then look for missing 256 byte parts of long packets sent out; missing parts
; mean new material overwrote not-yet-sent old == single buffering. [jrd]
; 8 August 1987 Add interrupt chaining in serint. [jrd]
; 23 July 1987 Clear xofsnt and xofrcv xon/xoff flags in ihost(s/r). [jrd]
; 9 July 1987 Cure confusion about COM1/2 for IBM PCjr (address of regular
; COM2 in 40:0h slot for COM1) with info from John Neufeld. [jrd]
; 2 July 1987 Route NetBios cancels through separate scb for systems, such
; as Novell NetWare, which object to having active scbs touched. [jrd]
; 25 June 1987 Add trapping of Int 14H (Bios RS232 procedure) to allow
; CTTY command to function without too much inteference from DOS. [jrd]
; 17 June 1987 Enlarge tab setting to full 132 columns at all times. [jrd]
; 11 June 1987 Add Set Term Roll on/off to control auto roll back of screen
; when new characters are displayed; default is off (no unwinding). [jrd]
; 20 May 1987 Remove rejection of NULL and DEL chars, let callers do it. [jrd]
; 16 May 1987 Add distinction between user typed and receiver threshold
; controlled sending of XOFF. User level overrides buffer control.[jrd]
; Add COM3 and COM4 support: examine memory 40:00h->40:07h for selected
; port COM1..4, resp. If word is null then set flags.comflg to 0 to say
; undefined port. Otherwise, use that word in seg 40h as base of UART i/o
; ports. Assume IRQ4 for COM1 and COM3 (same except for port addresses)
; and IRQ4 for COM2 and COM4 (again, same except for port addresses).
; Serial port info sturcture (not values) assumed identical for all ports.
; 25 April 1987 Add Netbios compatible local area network support. [jrd]
; Set Port command expanded to syntax SET PORT NET nodename. Use nodename
; if acting as a client to named remote node, leave blank if running in
; Server mode. Byte 'ttyact' is controlled by msster.asm to indicate Connect
; mode is being used. Byte 'netdone' (stored in mssker.asm) holds offset of
; network hangup procedure 'netclose' to be done when leaving Kermit. Hangup
; command extended to to network hangup as well. Network uses IBM Netbios
; standard calls (Int 5Ch) and allows for extensions of AT&T STARLAN for
; longer node names via Int 2Bh (the later is tested before use). Virtual
; circuits are employed. The Redirector is not necessary. Kermit can operate
; as either a terminal (does a CALL at Connect mode startup), a file receiver
; (does a CALL at startup), or a Kermit server (does an anonomous LISTEN at
; startup, hence no nodename). Clients should Set Timer Off.
; Note -
; When the Bios is used for serial port i/o the modem signals DSR and CTS
; must be asserted low before the Bios will access the hardware. Jumpers
; from pin 20 (DTR) to pin 6 (DSR) and from pin 4 (RTS) to pin 5 (CTS)
; will probably be necessary.
; From Glenn Everhart (who suggested using the Bios alternative)
;
public serini, serrst, clrbuf, outchr, coms
public dodel, ctlu, cmblnk, locate, prtchr, baudst, clearl
public getbaud, beep, shomodem, getmodem, mdmhand
public count, xofsnt, puthlp, putmod, clrmod, poscur, holdscr
public sendbr, sendbl, machnam, setktab, setkhlp, lclini, showkey
public ihosts, ihostr, dtrlow, serhng, comptab, pcwait
public portval, port1, port2, port3, port4, bdtab, ubhold
public dupflg
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
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
;;MDMDAT1 EQU 03F8H ; Address of port com1 (data)
;;MDMCOM1 EQU 03FBH ; Address of port com1 (command)
;;MDMSTS1 EQU 03FDH ; Address of port com1 (status)
;;MDMDAT2 EQU 02F8H ; Port com2 data
;;MDMCOM2 EQU 02FBH ; Port com2 command
;;MDMSTS2 EQU 02FDH ; Port com2 status
MDMINTV EQU 0CH ; IRQ4 com1/3 port interrupt vector
MDINTV2 EQU 0BH ; IRQ3 com2/4 port interrupt vector
MDMINTO EQU 0EFH ; Mask to enable interrupt level IRQ4
MDINTO2 EQU 0F7H ; Mask to enable interrupt level IRQ3
MDMINTC EQU 010H ; Bit to set to disable interrupts for IRQ4
MDINTC2 EQU 008H ; Bit to set to disable interrupts for IRQ3
EOICOM EQU 0064H ; End of interrupt for IRQ4
EOICOM2 EQU 0063H ; End of interrupt for IRQ3
INTCONT EQU 0021H ; Address of 8259 interrupt controller ICW2-3
INTCON1 EQU 0020H ; Address of 8259 ICW1
MDMINP EQU 1 ; Input ready bit
MDMOVER EQU 2 ; Receiver overrun
; external variables used:
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; low_rgt - low byte = last column (typ 79), high byte = last text row
; (typ 23) in screen coordinates (start at 0), set by msyibm.
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
; not implemented)
; setkhlp - help for setktab.
data segment public 'data'
extrn flags:byte, trans:byte, ttyact:byte, comand:byte
extrn lclsusp:word, lclrest:word, lclexit:word, rxtable:byte
extrn rdbuf:byte, taklev:byte, tekflg:byte, scbattr:byte
extrn low_rgt:word, diskio:byte, crt_cols:byte, repflg:byte
; Modem information
mdminfo struc
mddat dw 0 ; data register
mdiir dw 0 ; interrupt identification register
mdstat dw 0 ; line status register
mdcom dw 0
mden db 0
mddis db 0
mdmeoi db 0
mdintv dw 0
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 ? ; old serial port interrupt vector
sav232 dd ? ; Original Bios Int 14H address, in Code seg
savirq db ? ; Original Interrupt mask for IRQ
savlcr db ? ; Original Line Control Reg (3fbh) contents
dupflg db 0 ; full (0) or half (1) duplex on port
brkval db BRKBIT ; What to send for a break
brkadr dw 0 ; Where to send it
intkind db 0 ; cause of serial port interrupt
isps2 db 0 ; non-zero if real IBM PS/2
erms40 db cr,lf,'?Warning: Unrecognized Speed',cr,lf,'$'
badbd db cr,lf,'Unimplemented speed$'
badprt db cr,lf,'?Warning: no hardware for this serial port$'
biosmsg db cr,lf,'?This port will be operated through the Bios as BIOS$'
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$'
hngmsg db cr,lf,' The phone or network connection should have hung up'
db cr,lf,'$'
hnghlp db cr,lf,' The modem control lines DTR and RTS for the current'
db ' port are forced low (off)'
db cr,lf,' to hangup the phone. Normally, Kermit leaves them'
db ' high (on) when it exits.',cr,lf
db ' For networks, the active session is terminated.',cr,lf,'$'
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
xofsnt db 0 ; Say if we sent an XOFF
xofrcv db 0 ; Say if we received an XOFF
parmsk db 0ffh ; parity mask, 0ffh for no parity, 07fh with
flowoff db 0 ; flow-off char, Xoff or null (if no flow)
flowon db 0 ; flow-on char, Xon or null
pcwcnt dw 240 ; 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
comptab db 19 ; communications port options
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
mkeyw '3Com(BAPI)','C' ; 3Com BAPI interface
mkeyw 'DECnet','D' ; DECnet-DOS LAT and CTERM
mkeyw 'NetBios','N' ; Netbios
mkeyw 'Novell(NASI)','W' ; Novell NetWare NASI/NACS
mkeyw 'OpenNET','O' ; Intel OpenNET support (FGR)
mkeyw 'UB-Net1','U' ; Ungermann Bass Net One
mkeyw ' ',0 ; port is not present, for Status
portmax equ 4 ; number of predefined ports
port1 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
port2 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
port3 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
port4 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
rept portmax-4
prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
endm
portval dw port1 ; Default is to use port 1
bdtab db 18 ; 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 '19200',14
mkeyw '38400',15
mkeyw '57600',16
mkeyw '115200',17
; 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 06H ; 19200 baud
dw 03H ; 38400 baud
dw 02h ; 57600 baud
dw 01h ; 115200 baud
baudlen equ ($-bddat)/2 ; number of entries above
jrbddat label word ; Baud rate table for IBM PCjrs [tm]
dw 0FFH ; 45.5 baud -- Not supported
dw 8bfH ; 50 baud
dw 5d3H ; 75 baud
dw 3f9H ; 110 baud
dw 340H ; 134.5 baud
dw 2e9H ; 150 baud
dw 175H ; 300 baud
dw 0baH ; 600 baud
dw 5dH ; 1200 baud
dw 3eH ; 1800 baud
dw 38H ; 2000 baud
dw 2fH ; 2400 baud
dw 18H ; 4800 baud
dw 0CH ; 9600 baud
dw 06H ; 19200 baud
dw 03H ; 38400 baud
dw 02h ; 57600 baud
dw 01h ; 115200 baud
; 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. [jrd]
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 ; 19200 baud
dw 0FFH ; 38400 baud
dw 0FFH ; 57600 baud
dw 0FFH ; 115200 baud
; variables for serial interrupt handler
source db bufsiz+2 DUP(?) ; Buffer for data from port (+ 2 guard bytes)
srcpnt dw source ; Pointer in buffer (DI)
count dw 0 ; Number of chars in int buffer
mst dw 0 ; Modem status address
mdat dw 0 ; Modem data address
miir dw 0 ; modem interrupt ident register
mdeoi db 0 ; End-of-Interrupt value
mdmhand db 0 ; Modem status register, current
; 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
nbuflen equ 256 ; bytes in each network buffer (two of them)
; DEC-LAT requires 259 (256 here + 3 extra)
netbios equ 8000h ; network type bit, using NetBios
starlan equ 1 ; network type bit, AT&T STARLAN
netone equ 02h ; [ohl] type bit, Ungermann-Bass Net/One
;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
bapi equ 10h ; 3Com BAPI, nettype
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
;; 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.
portn prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> ; port struc for PORTN
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 ? ; buffer address, offset
dw data ; and segment
scb_length dw ? ; length of buffer data
scb_rname db '* ' ; remote name, 16 chars space
scb_lname db ' ' ; local name filled
db 0 ; reserved
db 0 ; reserved
scb_post dw ? ; 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
rcv scbst <,,,,rcvbuf,,length rcvbuf,,,,,rpost>; declare scb for rcvr
xmt scbst <,,,,xmtbuf,,length xmtbuf,,,,,spost>; for xmtr
lsn scbst <,,,,xmtbuf,,length xmtbuf,,,,,lpost>; for server listen
can scbst <> ; for cancels
; DECnet material
decneth dw 0 ; session handle
decseg dw 0 ; segment of SCB memory block
decint equ 69h ; CTERM interrupt
decnet equ 4 ; for DECnet/CTERM nettype
declat equ 8 ; for LAT nettype
dpresent equ 100h ; Installation check for CTERM
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
latsrv equ 0d500h ; LAT Get next service name
latopen equ 0d0ffh ; LAT open
latclose equ 0d000h ; LAT close
latsend equ 1 ; LAT send byte
latread equ 2 ; LAT read byte
latstat equ 3 ; LAT status
latbreak equ 0d100h ; LAT send a BREAK
lcbst struc ; LAT control block structure
service db 18 dup (0) ; service
db 18 dup (0) ; node, for future use
db 18 dup (0) ; port, for future use
stopped dd 0 ; session stopped post routine addr
overflow dd 0 ; service table overflow post addr
xnotify dd 0 ; transmit post routine addr
rnotify dd 0 ; receive post routine addr
sstatus dw 0 ; session status
dw 0 ; slot state, LAT driver use
db 0 ; local credits, LAT driver use
dw 0 ; vcb offset, LAT driver use
dw 0 ; vcb segment, LAT driver use
dw 0 ; back slot, LAT driver use
dw 0 ; forward slot, LAT driver use
db 0 ; rem slot id, LAT driver use
db 0 ; loc slot id, LAT driver use
db 0 ; slot byte count, LAT driver use
db 0 ; remote credits, LAT driver use
xdata db 255 dup (0) ; transmitted data slot
slotqty db 2 ; number receive data slots
slotused db 0 ; number occupied slots
slotnr db 0 ; index of next rcv slot to use
slotcur db 0 ; index of current rcv slot
slotptr dw 0 ; ptr to first received char
dw 0 ; ptrs to slots
dw 0
; reuse NetBios buffers xmtbufx, rcvbuf for slot1, slot2, resp.
; init these address in proc chkdec below.
lcbst ends
lat lcbst <> ; LAT data structure
decmsg1 db cr,lf,'Cannot create DECnet session.$'
decmsg3 db ' DECnet Error $'
decmsg4 db cr,lf,'DECnet CTERM session started.$'
decmsg5 db cr,lf,'DECnet LAT session started.$'
; end of DECnet
pcnet db 0 ; Network is functioning
xmtbuf db nbuflen dup (0) ; network buffer for transmitter
xmtcnt dw 0 ; occupancy in current output buffer
xmtbufx db nbuflen+3 dup (0) ; external version of xmtbuf (dbl buffers)
rcvbuf db nbuflen+3 dup (0) ; network buffer for receiver
nambuf db 65 dup (?) ; network long name storage (STARLAN)
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
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
nettype dw 0 ; kind of local area net (vendor bit field)
chkmsg1 db cr,lf,' Cannot construct a local Kermit name, error = $'
chkmsg2 db cr,lf,lf,' Name $'
chkmsg3 db ' is already in use. Please enter another of'
db cr,lf,' 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: $'
nonetmsg db cr,lf,'?The network is not available$'
noname db cr,lf,'?No name exists for the remote host.$'
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$'
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
biosbuf db 20 dup (0) ; IBM EBIOS receive buffer
biosblen equ $-biosbuf ; its length
data ends
code segment public 'code'
extrn comnd:near, prompt:near, dopar:near, lclyini:near, atsclr:near
extrn strcpy:near, strlen:near,decout:near, prtasz:near, prtscr:near
extrn kbsusp:near, kbrest:near ; in msuibm.asm
assume cs:code, ds:data, es:nothing
; local initialization
lclini proc near
mov flags.comflg,1 ; assume COM1 for communications port
;;; call coms2 ; setup serial port modem.info for COM1
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 lclyini ; let other modules initialize too...
ret
lclini endp
; Call these routines when suspending Kermit to go to DOS
suspend proc near
call kbsusp ; DEC LK250 keyboard, set back to DOS mode
call ihosts ; suspend the host
call serrst
ret
suspend endp
; Call these routines when returning to Kermit from DOS
restore proc near
call kbrest ; DEC LK250 keyboard, set back to DEC mode
call serini ; reinit serial port
call ihostr ; resume the host
ret
restore endp
; Call these routines when doing final exit of Kermit
finexit proc near
call netclose ; close network connections
call kbsusp ; DEC LK250 keyboard, set back to DOS mode
call serrst ; reset serial port
ret
finexit endp
; The IBM PC's. If jr then redo IBM baud rate with jr's values. [jrd]
model proc near
mov isps2,0 ; PS/2 present indicator
push es
push ax ; get IBM model code at F000:FFFEh
mov ax,0f000h ; address ROM
mov es,ax
mov al,byte ptr es:[0fffeh] ; get model id byte
cmp al,0fdh ; PC jr?
jne modelx ; ne = no
push ds
pop es ; set es to data segment
mov si,offset bddat ; regular IBM baud rate table
mov di,offset jrbddat ; PCjr baud rate table
mov cl,baudlen ; number of words to copy
xor ch,ch
cld
rep movsw ; copy PCjr values to IBM table
jmp short modelx
mov ah,0ch ; AT and PS/2 configuration call
xor al,al
int 15h ; IBM Bios
jc modelx ; 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 modelx ; ne = no
model3: mov isps2,1 ; say real PS/2 for IRQ setting
modelx: pop ax
pop es
ret
model endp
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally. Obsolete, name here for external reference only.
showkey proc near
ret ; return
showkey endp
; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdmhand, the modem line status register. [jrd]
shomodem proc near
mov ah,cmeol ; get a confirm
call comnd
jc shomd5 ; c = failure
mov dx,offset msmsg7 ; no modem status for network
call getmodem ; get modem status
mov 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 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
cmp rcv.scb_lname,' ' ; have NetBios name yet?
jbe shomd4 ; be = no, skip this part
mov dx,offset netmsg3 ; local name
int dos
mov cx,16
mov di,offset rcv.scb_lname
call prtscr
mov ah,prstr
mov dx,offset netmsg4 ; remote name
int dos
mov cx,16
mov di,offset rcv.scb_rname
call prtscr
shomd4: cmp lat.service,0 ; DECnet name available?
je shomd5 ; e = no
mov ah,prstr
mov dx,offset netmsg5
int dos
mov dx,offset lat.service ; network host name, asciiz
call prtasz
clc
shomd5: ret
shomodem endp
; Get modem status and set global byte mdmhand. Preserve all registers.
getmodem proc near ; gets modem status upon request
cmp portin,-1 ; done any port yet?
jne getmod1 ; ne = 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
mov dx,mst ; hardware
inc dx ; uart status reg
in al,dx
jmp short getmodx
getmod2:cmp flags.comflg,'4' ; above Bios? (networks)
ja getmodx ; a = yes, no status
mov ah,3 ; ask Bios for modem status into al
push dx
mov dl,flags.comflg ; get port id
sub dl,'1' ; remove ascii bias (BIOS1 -> 0)
int rs232
pop dx
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
cli
mov srcpnt,offset source ; receive circular buffer
mov count,0 ; receive circular buffer
sti
call prtchr ; empty any intermediate (net) buffers
cli
mov srcpnt,offset source ; receive circular buffer
mov count,0 ; receive circular buffer
mov xmtcnt,0 ; network output buffer count
sti
clc
cmp flags.comflg,'0' ; using Bios?
jb clrbuf3 ; b = no
cmp flags.comflg,'4' ; using Bios?
ja clrbuf3 ; a = no
call chkbios ; check for IBM EBIOS and set dl
jc clrbuf3 ; c = not present
mov ah,0f9h ; do a Regain Control operation
int rs232
clrbuf1:mov ax,0fd02h ; see if buffer has chars already
int rs232
jcxz clrbuf2 ; z = no, ok to reset buffering
mov ah,0fch ; do receive /nowait to clear buff
int rs232
jmp short clrbuf1 ; repeat til empty
clrbuf2:mov bx,offset biosbuf ; receive buffer for EBIOS
push ds
pop es ; set es:bx to the buffer address
xor cx,cx ; set cx to zero to terminate buffering
mov ax,0ff02h ; reset buffered mode for receiving
int rs232
clrbuf3: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 atsclr ; clear from ax to bx, screen coord
pop dx
pop bx
pop ax
ret
CLEARL ENDP
; This routine blanks the screen. Returns normally.
; Upgraded to Topview compatiblity. [jrd]
CMBLNK PROC NEAR
push ax
push bx
xor ax,ax ; from screen loc 0,0
mov bx,low_rgt ; to end of text screen (lower right corner)
inc bh ; include status line
call atsclr ; do Topview compatible clear, in msyibm
pop bx
pop ax
ret
CMBLNK ENDP
; Locate: homes the cursor. Returns normally.
LOCATE PROC NEAR
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 terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
jmp clearl
CTLU ENDP
BEEP PROC NEAR
push ax
push cx
mov al,10110110B ; Gen a short beep (long one losses data.)
out timercmd,al ; set Timer to 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
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 si
push dx ; preserve message
mov bl,scbattr ; screen attributes at Kermit init time
and bl,77h ; get colors, omit bright and blink
rol bl,1 ; interchange fore and background
rol bl,1
rol bl,1
rol bl,1
xor bh,bh ; preset page 0
mov temp,bx ; temp = page 0, reverse video
mov dx,low_rgt ; ending location is lower right corner
inc dh ; of status line
mov cx,dx ; start is status left side
xor cl,cl ; left side
mov ax,600h ; scroll to clear the line
mov bh,byte ptr temp ; set inverse video attributes
int video
mov dx,low_rgt ; last text line
inc dh ; status line
xor dl,dl ; left side
call poscur
pop si ; get message back
mov cx,1 ; only one char at a time
xor bh,bh ; page 0
cld
putmo1: lodsb ; get a byte
cmp al,'$' ; end of string?
je putmo2
push si ; save si
push ax ; and the char
call poscur
inc dl ; increment for next write
pop ax ; recover char
mov ah,9 ; try this
mov bx,temp ; page 0, inverse video
int video
pop si ; recover pointer
cmp dl,crt_cols ; beyond physical right border?
jb putmo1 ; b = no
putmo2: pop si
pop cx
pop bx
pop ax
ret
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
push ax ; save regs
push bx
push cx
push dx
mov ax,600h ; do a scroll up
mov dx,low_rgt ; ending location is lower right corner
inc dh ; of status line
mov cx,dx ; start is status left side
xor cl,cl ; left side
mov bh,scbattr ; use screen attributes at Kermit init time
int video
pop dx
pop cx
pop bx
pop ax
ret
clrmod endp
; put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push bx ; save regs
push cx
push dx
push si
push ax ; preserve this
cld
mov bl,scbattr ; screen attributes at Kermit init time
and bl,77h ; get colors, omit bright and blink
rol bl,1 ; interchange fore and background
rol bl,1
rol bl,1
rol bl,1
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 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,70h ; inverse video
mov bh,bl ; inverse video
int video
call locate ; home cursor
mov bx,0070h ; bh = page 0, bl = inverse video
mov bx,temp
mov cx,1 ; one char at a time
cld ; scan direction is forward
pop si ; point to string again
puthl3: lodsb ; get a byte
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 puth23 ; move cursor there
puth21: cmp al,cr ; carriage return?
jne puth22 ; ne = no
xor dl,dl ; set to column zero
jmp puth23
puth22: cmp al,lf ; line feed?
jne puth23
inc dh ; go to next line
puth23: mov ah,2 ; set cursor position to dx
int video
pop si ; restore pointer
jmp puthl3 ; and keep going
puthl4: mov dh,byte ptr low_rgt+1 ; go to last line
inc dh
xor dl,dl
call poscur ; position cursor
pop si
pop dx
pop cx
pop bx
ret
puthlp endp
; 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.
; Called by serini below. For IBM PC compatible machines.
; Regs preserved. 16 April 87 [jrd]
pcwtst proc near
push ax
push cx
push dx
mov pcwcnt,256 ; software loop, initial value
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
xor dx,dx ; clear high order divisor
add ax,1193/2 ; round up
adc dx,0 ; for very very slow machines
mov cx,1193 ; tics per millisec
div cx ; count / 1193 yields millisecs, quo=ax
mov cx,ax ; retain whole number of milliseconds
mov ax,pcwcnt ; get current pcwait inner loop count
xor dx,dx ; clear high order field for division
shl ax,1
rcl dx,1
shl ax,1
rcl dx,1
shl ax,1
rcl dx,1 ; dx:ax = current counter times 8 loops
jcxz pcwtst1 ; z = no millisec (super speed machines) use 1
div cx ; divide by observed milliseconds
pcwtst1:mov pcwcnt,ax ; store quotient as new inner loop counter
pop dx
pop cx
pop ax
ret
pcwtst endp
;; Wait for the # of milliseconds in ax, for non-IBM compatibles.
;; Thanks to Bernie Eiben for this one. Modified to use adjustable
; inner loop counter (pcwcnt, adjusted by proc pcwtst) by [jrd].
pcwait proc near
push cx
pcwai0: mov cx,pcwcnt ; inner loop counter for 1 ms (240 @ 4.77 MHz)
pcwai1: sub cx,1 ; inner loop takes 20 clock cycles
jnz pcwai1
dec ax ; outer loop counter
jnz pcwai0 ; wait another millisecond
pop cx
ret
pcwait 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.
; '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: mov temp,bx
cmp bl,'D' ; DECnet?
je comstrt ; e = yes
cmp bl,'N' ; NetBios network?
je comstrt ; yes, get another item for networks
cmp bl,'O' ; Opennet network?
je comstrt ; yes, get another item for networks
cmp bl,'U' ; Ungermann Bass net?
je comstrt ; e = yes
cmp bl,'W' ; Novell NASI net?
je comstrt ; e = yes
mov ah,cmeol ; non-network
call comnd ; Get a confirm
jnc coms0b ; nc = success
ret ; failure
coms0b: mov bx,temp
COMSTRT:mov temp,bx ; port ident is in BL
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,'W' ; Novell NASI?
jne comst5 ; ne = no
jmp comsub
comst5: cmp bl,'C' ; 3Com BAPI?
jne comst5a ; ne = no
jmp comsbapi
comst5a:cmp flags.comflg,'N' ; have been running on NetBios?
je coms1c ; eq = yes
cmp flags.comflg,'O' ; have been running on Opennet?
jne coms2 ; ne = no
; turn off sources of net interrupts
coms1c: mov bx,offset can ; cancel outstanding requests
mov can.scb_cmd,ncancel ; set cancel op code
cmp lposted,1 ; listen outstanding?
jne coms1a ; ne = no
mov can.scb_baddr,offset lsn ; cancel listen
call session
mov lposted,0
coms1a: cmp rposted,1 ; receive outstanding?
mov rposted,0 ; clear interlock flag no matter what
jne coms2 ; ne = no
mov can.scb_baddr,offset rcv ; cancel receive
call session
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 UART port addresses
mov bx,type prtinfo ; size of each portinfo structure
mul bx ; times port number
add ax,offset port1 ; plus start of COM1
mov portval,ax ; points to our current port struct
pop bx ; restore registers
cmp flags.comflg,'1' ; Bios path?
jb coms4 ; b = no, check hardware
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 bx ; save register
push es
mov ax,40h ; look at RS232_base [bx] in Bios area 40:00h
mov es,ax
mov bx,temp ; get desired port
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
pop bx
or ax,ax ; is address zero?
je comsnh ; e = yes, no serial port hardware
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
mov brkadr,ax ; where to send break command
add ax,2 ; increment to status port 03fdh
mov modem.mdstat,ax ; set line-status port address
call chkport ; get type of UART support
jc comsnu ; c = not a real 8250 class UART
call chkint ; find IRQ for the port
jc comsnu ; c = not found, an error condition
ret ; success
comsnh: mov ah,prstr ; no port address for hardware
mov dx,offset badprt
int dos
; no port address or no UART or no IRQ
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
; Opennet Network support (FGR)
comso: mov inettyp,'O' ; remember OpenNet type network
jmp 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 dx,offset rdbuf ; work buffer
mov word ptr rdbuf,0 ; insert terminator
mov bx,offset nethlp ; help message
call comnd ; get the name, ignore errors
xchg ah,al ; put byte count in al
xor ah,ah ; clear junk
mov temp,ax ; save number of chars entered
mov ah,cmeol
call comnd ; get a confirm
jc comsn2 ; c = failure
call serrst ; reset serial port
cmp temp,0 ; any name given?
je comsn1 ; e = no, use current name
mov si,offset rdbuf
mov di,offset nambuf ; copy to here
call strcpy
comsn1: call chknet ; start network usage
cmp pcnet,0 ; is network alive (non-zero)?
jne comsn4 ; ne = yes
comsn2: stc
ret ; failure
comsn4: mov portval,offset portn ; set Network port structure address
mov portn.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
call chkport ; set type of port support
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:push bx
call netclose ; better close NetBios parts NOW!
pop bx
mov portval,offset portn ; set Network port data structure address
mov portn.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
comsd: ; DECnet
mov ah,cmword ; get a word (remote node name)
mov dx,offset rdbuf ; work buffer
mov word ptr rdbuf,0 ; insert terminator
mov bx,offset dnethlp ; help message
call comnd ; get the name
xchg ah,al ; put byte count in al
xor ah,ah ; clear junk
mov temp,ax ; save number of chars entered
mov ah,cmword ; get optional LAT service name
mov dx,offset rdbuf+80 ; work near end of this buffer
mov word ptr rdbuf+80,0 ; insert terminator
mov bx,offset nethlp2 ; help message
mov comand.cmblen,17 ; length of buffer (password = 16 chr)
call comnd ; get the name, ignore if absent
mov ah,cmeol
call comnd ; get a confirm
jnc comsd3
ret ; did not get a confirm
comsd3: cmp temp,0 ; any node name?
je comsd8a ; e = no
mov si,offset rdbuf ; the node name, make upper case
add si,temp ; and add '::' if absent
cmp byte ptr [si],':' ; ended on colon?
jne comsd4 ; ne = no, append them
cmp byte ptr [si-1],':' ; first colon present?
je comsd5 ; e = yes
dec si ; one colon, back up to it
dec temp
comsd4: mov word ptr [si+1],'::'
mov byte ptr [si+3],0 ; terminator
add temp,2 ; include new bytes
comsd5: mov si,offset rdbuf ; match spelling of old and new nodes
mov di,offset lat.service
mov cx,temp
sub cx,2 ; ignore trailing '::' here
cld
comsd6: lodsb ; si = new node name
mov ah,[di] ; di = old node name
inc di
and ax,not 2020h ; move both to upper case
xor ah,al ; compare bytes
loope comsd6 ; repeat while same spelling
je comsd8 ; e = same throughout
mov al,flags.comflg ; save kind of port
call nethangup ; different, clear current connection
mov si,offset rdbuf
mov di,offset lat.service ; copy new name for use by chkdec
call strcpy
comsd8: cmp pcnet,2 ; session active?
jb comsd8a ; b = no
test nettype,decnet+declat ; and of DEC kind?
jz comsd8a
call chknew ; session exists, Resume or start new?
jc comsd8a ; c = resume
cmp rdbuf,0 ; New session?
jne comsd8a ; ne = no, resume current
call nethangup ; hangup current session
comsd8a:call serrst ; reset serial port (not used here)
jmp chkdec ; make DECnet session with host
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 portn ; set Network port data structure address
mov portn.portrdy,1 ; say the comms port is ready
mov 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
COMS ENDP
; SETUP DECNET port. Host name is in lat.service. Try LAT then try CTERM.
; Return carry clear if success, or carry set if failure.
chkdec proc near
cmp pcnet,2 ; net active now?
jb chkde4 ; b = no
test nettype,declat ; LAT support active?
jz chkde9 ; z = not LAT
cmp decneth,0 ; valid LAT handle?
je chkde4 ; e = invalid handle
mov portval,offset portn ; set Network port data structure address
mov flags.comflg,'D' ; set the comm port flag
mov portn.portrdy,1 ; say the comms port is ready
clc
ret ; return to active session
chkde9: cmp decneth,0 ; valid CTERM handle?
jle chkde4 ; le = none, start new session
jmp chkde6 ; resume old session
chkde4: cmp lat.service,0 ; node name present?
jne chkde4a ; ne = yes
mov ah,prstr
mov dx,offset noname ; say host name is required
int dos
stc
ret
chkde4a:xor ax,ax ; status of service not available
mov es,ax ; refer to segment 0
mov si,latint*4 ; LAT 6Ah interrupt location
les si,es:[si] ; get LAT driver entry point
mov ax,es
cmp ax,0 ; undefined interrupt?
je chkde4h ; e = yes
cmp ax,0f000h ; points at ROM Bios?
je chkde4h ; e = yes
cmp word ptr es:[si-3],'AL' ; preceeding 3 bytes spell 'LAT'?
jne chkde4h ; ne = no, so no LAT, try CTERM
cmp byte ptr es:[si-1],'T'
je chkde4i ; e = a match for LAT
chkde4h:jmp chkde4e ; no LAT, try CTERM
chkde4i:push ds
pop es
mov bx,offset lat ; LAT session control block
mov ax,offset xmtbufx ; initialize receive slot pointers
mov [bx].slotptr+2,ax
add ax,4
mov [bx].slotptr,ax
mov ax,offset rcvbuf ; use this as second buffer
mov [bx].slotptr+4,ax
cmp lat.service,'*' ; just show known LAT names?
jne chkde4j ; ne = no
call latlst ; show LAT names
stc ; do not make a connection
ret
chkde4j:mov ax,latopen ; open a LAT session
mov di,offset rdbuf+80 ; optional asciiz LAT password ptr
cmp byte ptr [di],0 ; any name entered?
je chkde4d ; e = no
mov cx,16 ; 16 chars required, blank padded
chkde4b:cmp byte ptr [di],0 ; found terminator?
je chkde4c ; yes, proceed to pad with spaces
inc di ; no, point to next character
loop chkde4b ; and loop
jmp short chkde4g ; in case 16 byte password
chkde4c:mov byte ptr [di],' ' ; insert padding
inc di ; point to next
loop chkde4c ; and loop
chkde4g:mov byte ptr [di],0 ; null terminator
mov di,offset rdbuf+80 ; point es:di to password field
push ds
pop es
and al,0fh ; open as AX = 0d0fh if with password
chkde4d:mov dh,0ffh
int latint
or ah,ah ; status byte
jnz chkde4e ; nz = failure, try CTERM
mov dh,0ffh ; success
mov decneth,dx ; store handle returned in dl
or nettype,declat ; say LAT session is active
mov pcnet,2
mov portval,offset portn ; set Network port data structure address
mov flags.comflg,'D' ; set the comm port flag
mov portn.portrdy,1 ; say the comms port is ready
mov ah,prstr
mov dx,offset decmsg5 ; show status
int dos
clc ; carry clear means status = success
ret
chkde4e:xor ax,ax ; CTERM check
mov es,ax ; refer to segment 0
mov si,decint*4 ; CTERM 69h interrupt location
les si,es:[si] ; get CTERM driver entry point
mov ax,es
cmp ax,0 ; undefined interrupt?
je chkde4f ; e = yes
cmp ax,0f000h ; points at ROM Bios?
je chkde4f ; e = yes
mov ax,dpresent ; CTERM installation call
int decint
cmp al,0ffh ; CTERM installed?
je chkde5 ; e = yes
chkde4f:mov ah,prstr
mov dx,offset decmsg1 ; no CTERM yet
int dos
jmp chkde8 ; exit with no net
chkde5: mov ax,decseg ; scb memory segment, if non-zero
or ax,ax ; allocated already?
jnz chkde5a ; nz = yes, segment is in ax
mov ax,dgetscb ; get CTERM SCB size
int decint
add ax,15 ; round up byte count
shr ax,1 ; bytes to paragraphs
shr ax,1
shr ax,1
shr ax,1
mov bx,ax
mov temp,ax ; save requested paragraphs
mov ah,alloc
int dos ; bx gets # paragraphs allocated
jc chkde8 ; c = failure
mov decseg,ax ; store address of memory block
cmp temp,bx ; wanted vs allocated paragraphs
jb chkde7 ; b = not enough
chkde5a:mov bx,offset lat.service ; ds:bx = node name
mov es,ax
xor dx,dx ; es:dx = SCB address
mov ax,dopen ; open session
int decint
cmp ax,0 ; > 0 means session handle, else error
jle chkde7 ; le = error
mov decneth,ax ; store handle
mov ah,prstr
mov dx,offset decmsg4 ; say CTERM connection is ready
int dos
chkde6: or nettype,decnet ; network type is DECnet
mov pcnet,2 ; say net is present and active
mov portval,offset portn ; set Network port structure address
mov flags.comflg,'D' ; set the comm port flag
mov portn.portrdy,1 ; say the comms port is ready
clc
ret
; CTERM startup failure
chkde7: push ax ; save error number in ax
mov ax,decseg ; allocated memory segment
mov es,ax
mov ah,freemem ; free allocated memory at 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
chkde8: mov pcnet,0 ; no net
stc ; status is error
ret
chkdec endp
; 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 rdbuf+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 rdbuf ; 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
; 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
cmp flags.comflg,2 ; COM1 or COM2?
ja chkin1 ; a = no
jmp chkin2 ; be = yes, use standard IRQ's
chkin1: mov modem.mddis,MDMINTC ; IRQ 4 test. mask to disable IRQ 4
mov modem.mden,MDMINTO ; mask to enable IRQ 4
mov modem.mdmeoi,20h ; use general in case we guess wrong
mov modem.mdintv,MDMINTV ; IRQ 4 interrupt vector (0ch)
mov intkind,0 ; clear interrupt cause
call serini ; setup port for IRQ 4
jc chkint2 ; c = failure
mov dx,modem.mddat
inc dx ; interrupt enable reg (3f9h)
cli
mov al,2 ; set xmtr holding reg empty interrupt
out dx,al
jmp $+2
out dx,al ; again, because first may be missed
sti
mov ax,1 ; wait one millisec for interrupt
call pcwait ; to occur
test intkind,2 ; check cause of interrupt, ours?
jz chkint2 ; z = no, try other IRQ
call serrst ; reset port
mov modem.mdmeoi,EOICOM ; use specific EOI for IRQ4 level
clc ; this setup worked
ret
; IRQ 3 test
chkint2:call serrst ; reset port
mov modem.mddis,MDINTC2 ; mask to disable IRQ 3
mov modem.mden,MDINTO2 ; mask to enable IRQ 3
mov modem.mdmeoi,20h ; use general in case we guess wrong
mov modem.mdintv,MDINTV2 ; IRQ 3 interrupt vector
mov intkind,0 ; clear interrupt cause
call serini ; setup port for IRQ 3
jc chkin2 ; c = failure
mov dx,modem.mddat
inc dx ; interrupt enable reg (3f9h)
cli
mov al,2 ; set xmtr holding reg empty interrupt
out dx,al
jmp $+2
out dx,al ; again, because first may be missed
sti
mov ax,1 ; wait one millisec for interrupt
call pcwait ; to occur
test intkind,2 ; check cause of interrupt, ours?
jz chkin2 ; z = no, so no interrupts for port
call serrst ; reset port
mov modem.mdmeoi,EOICOM2 ; use specific EOI for IRQ 3 level
clc ; this setup worked
ret
chkin2: call serrst ; reset port, auto test did not work
cmp flags.comflg,1 ; COM1?
je chkin4 ; e = yes, use IRQ 4
cmp isps2,0 ; IBM PS/2 Model 50 or above?
jne chkin3 ; ne = yes, other COMs use IRQ 3
cmp flags.comflg,3 ; COM2, COM3, or COM4?
je chkin4 ; e = COM3, use IRQ 4
jmp short chkin3 ; else COM2 or COM4, use IRQ 3
chkin4: cmp modem.mddat,02f8h ; really COM2 material for PCjr?
je chkin3 ; e = yes, use COM2 addresses
mov modem.mdmeoi,EOICOM ; use specific EOI for IRQ4 level
mov modem.mddis,MDMINTC ; IRQ 4 test. mask to disable IRQ 4
mov modem.mden,MDMINTO ; mask to enable IRQ 4
mov modem.mdintv,MDMINTV ; IRQ 4 interrupt vector (0ch)
jmp short chkin5
chkin3: mov modem.mdmeoi,EOICOM2 ; use specific EOI for IRQ 3 level
mov modem.mddis,MDINTC2 ; mask to disable IRQ 3
mov modem.mden,MDINTO2 ; mask to enable IRQ 3
mov modem.mdintv,MDINTV2 ; IRQ 3 interrupt vector
chkin5: clc
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
jmp $+2 ; pause, for chip access timing
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
; Check for presence of IBM EBIOS and set dl to Bios port value
; Returns carry clear if EBIOS present, else carry set
chkbios proc near
xor dx,dx ; assume port 1, find current port
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz chkbios1 ; z = yes, don't access it
and dl,7 ; use low three bits
dec dl ; address ports as 0..3 for Bios
mov ax,0f4ffh ; IBM EBIOS presence check
int rs232
jc chkbios1 ; c = failure
or ax,ax ; returns ax = 0 if present
jnz chkbios1 ; nz = not present
clc
ret
chkbios1:stc ; IBM EBIOS not present, dl = port
ret
chkbios endp
;;;;;;;;;;;;;;;;;;;;;; end of part one of msxibm.asm
;;;;;;;;;;;;;;;;;;;;;; start part two of msxibm.asm
; 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
mov si,portval
mov ax,[si].baud ; remember original value
mov [si].baud,bx ; set the baud rate
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
mov bl,flags.comflg ; pass current port ident
cmp bl,4 ; upper limit on UARTs
ja dobd4 ; a = not a UART, no baud rate
call comstrt ; do SET PORT command now
jnc dobd3 ; nc = success
dobd4: stc
ret ; failure
dobd3: push ax ; save some regs
push bx
push cx
push dx
cmp flags.comflg,'4' ; UART or Bios?
ja dobd1 ; a = no, networks
call chkport ; check port for real 8250 UART
mov bx,portval ; pointer to port data structure
mov temp,ax ; don't overwrite previous rate
mov ax,[bx].baud ; check if new rate is valid
shl ax,1 ; make a word index
mov bx,offset bddat ; start of table
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 ax,0FFH ; Unimplemented baud rate
jne dobd0
mov ah,prstr
mov dx,offset badbd ; give an error message
int dos
jmp dobd1
dobd0: cmp flags.comflg,'0' ; running on a real uart?
jb dobd2 ; b = the real thing
xor dx,dx ; assume port 1, find current port
mov dl,flags.comflg ; get coms port (1..4)
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
xor ah,ah ; set serial port
int rs232 ; Bios: set the parameters
jmp dobd1 ; and exit
dobd2: mov temp,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
mov ax,temp ; set the baud rate divisor, low byte
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
dobd1: pop dx ; restore regs
pop cx
pop bx
pop ax
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 bx
mov bx,portval
mov [bx].baud,0ffh ; set baud rate to unknown
cmp flags.comflg,4 ; UART?
ja getb3 ; a = no, Bios or Networks
cmp portin,-1 ; port unused?
jne getbud ; ne = no, used, go get rate
mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT command now
jnc getbud ; nc = success
getb3: pop bx
ret ; failure
getbud: push ax ; save some regs
push cx
push dx
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
cmp ax,0FFFFH ; Who knows what this is
je getb2
mov bx,offset bddat ; find rate's offset into table
xor cl,cl ; keep track of index
getb0: cmp ax,[bx]
je getb1
inc cl
cmp cl,baudlen ; at the end of the list?
jge getb2 ; ge = yes
add bx,2
jmp getb0
getb1: xor ch,ch
mov bx,portval
mov [bx].baud,cx ; set baud rate
getb2: pop dx ; restore regs
pop cx
pop ax
pop bx
clc
ret
GETBAUD 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 prtch0a ; ne = yes, do not read
call chkxon ; see if we need to xon
cmp repflg,0 ; REPLAY?
je prtchn1 ; e = no
jmp prtch30 ; yes, do replay file reading
prtchn1:mov al,flags.comflg ; get kind of port
cmp al,'0' ; Bios or network?
jb prtch0 ; b = no, UART
cmp al,'4' ; Bios?
jbe prtch6 ; be = yes, else networks
prtchn: cmp count,bufsiz-nbuflen ; room left for more network data?
ja prtch1 ; a = no, read current buffer
cmp al,'U' ; UB network?
je prtchn2
cmp al,'C' ; 3Com BAPI interface?
je prtchn2 ; e = yes
cmp al,'W' ; Novell network?
jne prtchn3 ; ne = no
prtchn2:call ubrecv ; do a UB receive
jmp short prtch0
prtchn3:cmp al,'D' ; DECnet?
jne prtchn4 ; ne = no
jmp decrcv ; DECnet receive char
prtchn4:call receive ; start next NetBios receive (async)
prtch0: cmp count,0 ; any characters available?
jnz prtch1 ; nz = yes, get one
prtch0a:xor dx,dx ; return count of zero
stc ; say no data
ret
prtch1: push si ; save si
cli ; interrupts off, to keep srcpnt & count consistent
mov si,srcpnt ; address of next available slot in buffer
sub si,count ; minus number of unread chars in buffer
cmp si,offset source ; located before start of buf?
jae prtch2 ; ae = no
add si,bufsiz ; else do arithmetic modulo bufsiz
prtch2: mov al,byte ptr [si] ; get a character into al
dec count ; one less unread char now
sti ; interrupts back on now
pop si
mov dx,count ; return # of chars in buffer
jmp prtch12 ; screen delivered characters
prtch6: ; Bios calls
call chkbios ; set dl to port check IBM EBIOS
jc prtch7 ; c = EBIOS not present
mov ah,0fch ; IBM EBIOS receive /no wait
int rs232 ; does line check then char ready chk
test ah,8ch ; timeout, framing error, parity error?
jnz prtch8 ; nz = error, no char
jz prtch9a ; z = success, process char
prtch7: mov ah,3 ; check port status, std Bios calls
int rs232 ; Bios call
test ah,mdminp ; data ready?
jnz prtch9 ; nz = yes, get one
prtch8: xor dx,dx ; return count of zero
stc ; say no data
ret
prtch9: mov ah,2 ; receive a char into al
int rs232 ; Bios call
test ah,8ch ; timeout, framing error, parity error?
jnz prtch8 ; nz = error, no char
prtch9a: ; single char read final filter
cmp al,flowoff ; acting on Xoff?
jne prtch10 ; ne = no, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF?
jne prtch8 ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; set the flag saying XOFF received
jmp prtch8 ; and exit
prtch10:cmp al,flowon ; acting on Xon?
jne prtch12 ; ne = no, go on
mov xofrcv,off ; Clear the XOFF received flag
jmp short prtch8 ; no data to return
prtch12:test flags.debug,logses ; debug mode?
jnz prtch14 ; nz = yes, pass all chars
cmp rxtable+256,0 ; translation turned off?
jne prtch14 ; ne = table is on, pass all chars
cmp al,0 ; NUL?
je prtch13 ; e = yes, ignore it
cmp tekflg,0 ; Tek emulation active?
jne prtch14 ; ne = yes, pass DEL
cmp al,DEL ; DEL char
jne prtch14 ; ne = no, pass char
prtch13:xor dx,dx
stc ; no data
ret
prtch14:clc ; return char in al
ret
prtch30:push bx ; REPLAY, read char from a file
push cx
xor dx,dx
test xofsnt,usron ; user level xoff sent?
jz prtch32 ; z = no
pop cx ; suppress reading here
pop bx
clc ; return with no char
ret
prtch32:cmp tekflg,0 ; doing Tek plots?
jne prtch32a ; ne = yes, do not insert pauses
mov ax,100
mov bx,1
jmp $+2 ; flush lookahead buffer
div bx ; burn some cpu cycles
jmp $+2 ; because a 1 ms wait is too long
div bx
jmp $+2
div bx
prtch32a:mov ah,readf2
mov bx,diskio.handle ; file handle
mov cx,1 ; read one char
mov dx,offset rdbuf ; to this buffer
int dos
jc prtch31 ; c = read failure
cmp ax,cx ; read the byte?
jne prtch31 ; ne = no
pop cx
pop bx
mov al,rdbuf ; get the char into al
mov dx,1 ; external char count
clc
ret ; return it
prtch31:call beep
mov ax,40 ; wait 40 millisec
call pcwait
call beep
mov ah,coninq ; wait for a keystroke
int dos
or al,al ; null?
jnz prtch33 ; nz = no
mov ah,coninq
int dos
prtch33:pop cx
mov bx,portval
mov [bx].portrdy,0 ; say port is not ready
pop bx
xor dx,dx
stc ; say no char
ret
PRTCHR ENDP
; DECnet receive routine
DECRCV PROC NEAR
mov dx,decneth ; DEC handle
test nettype,declat ; LAT interface?
jz decrcv1 ; z = not LAT
test lat.sstatus,08h ; status: stop slot received?
jnz decrcv4 ; nz = yes, no valid session
mov ah,latread ; read char via LAT
int latint
test ah,80h ; char available?
jz decrcv2 ; z = yes
test lat.sstatus,0ch ; status: stop slot or circuit failure
jnz decrcv4 ; nz = yes, no valid session
stc ; return no char
mov count,0
ret
decrcv1:mov ax,dcstat ; CTERM status
int decint
test ah,0c0h ; no session, DECnet error?
jnz decrcv4 ; nz = yes, stop here
; test ah,1 ; data available?
; jz decrcv3 ; z = no
; data available test fails under flow control, maybe a Cterm bug. jrd
mov ax,dread ; read char via CTERM
int decint
test ah,80h ; char received?
jnz decrcv3 ; nz = no
decrcv2:jmp prtch9a ; use common completion code
decrcv3:stc ; return no char
mov count,0
ret
decrcv4:call nethangup
test flags.remflg,dserver ; server mode?
jz decrcv5 ; z = no
call serini ; reinitialize it for new session
decrcv5:stc ; say failure to receive
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) and 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 session
pop bx
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 receiv4 ; 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
call hexout ; show error code
; Error return
receiv3:mov pcnet,1 ; say session is broken
mov rposted,0
call serrst ; reset serial port
test flags.remflg,dserver ; server mode?
jz receiv3a ; z = no
call serini ; reinitialize it for new session
receiv3a:stc ; say failure to receive
ret
receiv4:clc ; carry clear = success
ret
; shared by NetBios, Novell, Opennet, Ungerman Bass, 3ComBAPI
receiv5:push bx ; new packet has been received
push cx ; copy contents to circ buf source
push dx
push si
mov dh,flowon
mov dl,flowoff
mov si,rcv.scb_baddr ; source of text (es:bx is scb ptr)
mov bx,srcpnt ; address of destination buffer slot
receiv6:mov cx,rcv.scb_length ; get remaining returned byte count
jcxz receiv13 ; z = nothing there
mov ax,offset source+bufsiz ; end of destination buffer+1
sub ax,bx ; space remaining at end of buffer
jns receiv7 ; should never be negative
neg ax ; but if so invert
receiv7:cmp ax,cx ; buffer ending vs incoming byte count
jge receiv8 ; ge = enough for this pass
mov cx,ax ; limit this pass to end of the buffer
receiv8:sub rcv.scb_length,cx ; deduct chars done in this pass
add count,cx ; add them to the count
cld ; inner loop "block" transfer
receiv9:lodsb ; get byte from rcvbuf to al
or dx,dx ; doing flow control?
jz receiv11 ; 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 receiv10 ; ne = no
cmp xofsnt,0 ; have we sent an XOFF?
jne receiv12 ; ne = yes, ignore this XOFF char
mov xofrcv,bufon ; set flag saying buffer XOFF received
jmp short receiv12 ; and skip this character
receiv10:cmp ah,dh ; acting on Xon?
jne receiv11 ; ne = no, go on
mov xofrcv,off ; clear the XOFF received flag
jmp short receiv12 ; and skip this character
receiv11:mov [bx],al ; store new char in buffer "source"
inc bx
receiv12:loop receiv9 ; bottom of inner loop
; update buffer pointer for wrapping
cmp bx,offset source+bufsiz ; pointing beyond end of buffer?
jb receiv6 ; b = no, do next pass
mov bx,offset source ; wrap pointer, modulo bufsiz
jmp short receiv6 ; do next pass
receiv13:mov srcpnt,bx ; update pointer to next free slot
cmp count,bufsiz ; count more that buffer size?
jbe receiv14 ; be = no
mov count,bufsiz ; limit to bufsiz (tells the truth)
receiv14:mov rposted,0 ; clear interlock flag
pop si
pop dx
pop cx
pop bx
clc
ret
RECEIVE 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
; Ungermann-Bass NETCI port receive characters routine. Receive one or more
; characters. Calls the receiv5 routine to transfer character to main source
; circular buffer. Return carry clear if success.
UBRECV PROC near
push bx
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 ; 3Com BAPI interface?
jz ubrecv2a ; z = no, Int 6bh kind
mov ah,bapiread
xor dh,dh ; session 0
int bapiint
jmp short ubrecv2b
ubrecv2a:mov ax, nciread ; function 1 (receive) port 0 [ohl]
int netci ; get characters [ohl]
ubrecv2b:stc
jcxz ubrec1 ; cx = z = nothing to do
mov rcv.scb_length, cx ; prepare for rpost call [ohl]
call receiv5 ; process buffer
clc
ubrec1: pop es
pop cx
pop bx
ret
UBRECV ENDP
; Put the char in AH to the serial port, assumimg the port is active.
; Returns carry clear if success, else carry set.
; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to
; prevent confusion of flow control logic at top of outchr; used by receiver
; buffer high/low water mark flow control code. [jrd]
OUTCHR PROC NEAR
cmp flowoff,0 ; Are we doing flow control
je outch2 ; No, just continue
cmp ah,flowoff ; sending xoff?
jne outch1 ; ne = no
mov xofsnt,usron ; indicate user level xoff being sent
jmp outch1b
outch1: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 ; return failure to exit playback mode
ret
outch3: cmp flags.comflg,'0' ; Bios?
jb outch3a ; b = no, UART
cmp flags.comflg,'4' ; Bios?
jbe outch3e ; be = yes
jmp outch8 ; else try networks
outch3e:jmp outch6 ; do Bios routine
outch3a:push cx ; save registers
push dx
outch3b:cmp dupflg,0 ; full duplex?
je outch3d ; e = yes
mov dx,modem.mddat
add dx,4 ; modem control reg 3fch
in al,dx
or al,2 ; set RTS
jmp $+2
out dx,al
add dx,2 ; modem status register 3feh
jmp $+2
in al,dx
test al,20h ; ignore CTS if DSR is not asserted
jz outch3d ; z = DSR not asserted
mov cx,8000 ; ~10 seconds worth of waiting on CTS
outch3c:test al,10h ; is CTS asserted?
jnz outch3d ; nz = yes
push cx
push dx
mov ax,1 ; wait one millisec
call pcwait
pop dx
pop cx
loop outch3c ; test again
call beep ; half duplex timeout, make non-fatal
pop dx
pop cx
clc
ret
outch3d:xor cx,cx
mov dx,modem.mdstat ; get port status
in al,dx
test al,20H ; Transmitter (THRE) ready?
jnz outch4 ; nz = yes
jmp $+2 ; use time, prevent overdriving UART
jmp $+2
loop outch3b
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat ; use a little time
jmp $+2
out dx,al
cmp dupflg,0 ; full duplex?
je outch4a ; e = yes
cmp al,trans.seol ; End of Line char?
jne outch4a ; ne = no
xor cx,cx ; loop counter
outch4b:mov dx,modem.mdstat ; modem line status reg
in al,dx ; read transmitter shift reg empty bit
jmp $+2
jmp $+2
jmp $+2 ; wait for char to be sent
test al,40h ; is it empty?
loopz outch4b ; z = no, not yet
mov dx,modem.mddat
add dx,4 ; modem control reg 3fch
in al,dx
and al,not 2 ; unassert RTS
jmp $+2
out dx,al
outch4a:pop dx ; exit success
pop cx
clc
ret
outch5: call beep
pop dx ; exit failure
pop cx
stc
ret
; finish up for Bios calls
outch6: push cx ; find current port
push dx
xor dx,dx ; assume port 1
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz outch5 ; 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
mov ah,1 ; send char
int rs232 ; bios send
pop dx ; exit success
pop cx
shl ah,1 ; put status high bit into carry
ret ; c set = failure, else success
outch8: ; Network sending, buffered and single char
cmp flags.comflg,'D' ; DECnet?
je outch14 ; e = yes
push bx
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
pop bx
inc xmtcnt ; count of items in this buffer
cmp xmtcnt,length xmtbuf ; is buffer full now?
jae outch9 ; ae = buffer is full, send it now
cmp ah,trans.seol ; end of packet?
je outch9 ; e = yes, send buffer
cmp ah,flowon ; flow control?
je outch9 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je outch9
cmp ttyact,0 ; are we in Connect mode?
je outch10 ; e = no, wait for more before sending
outch9: cmp flags.comflg,'U' ; check for UB port [ohl]
je outch12 ; e = yes [ohl]
cmp flags.comflg,'W' ; Novell network?
je outch12 ; e = yes
cmp flags.comflg,'C' ; 3Com BAPI
je outch12 ; e = yes
call send ; NetBios network send routine
jc outch11 ; c = error
outch10:clc ; good exit
ret
outch11:stc ; bad exit
ret
outch12:jmp ubsend ; UB/Novell network send
outch14:mov dx,decneth ; DECnet, handle
or dl,dl ; legal handle?
jle outch14c ; le = invalid handle
test nettype,declat ; LAT?
jz outch14a ; z = no, use CTERM
mov al,ah
mov ah,latsend ; LAT send byte
int latint
jmp short outch14b ; common completion
outch14a:push bx ; CTERM
mov bl,ah ; char to be sent
mov ax,dsend ; send byte in bl
int decint
pop bx
outch14b:rcl ah,1 ; status 80h bit, did char get sent?
jnc outch15 ; nc = success
outch14c:call nethangup ; failure
stc
outch15:ret
OUTCHR ENDP
; 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
cmp pcnet,1 ; network ready yet?
ja send0b ; a = net is operational
je send0c ; e = net but no session, fail
jmp send3a ; 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 send3a ; 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 bx ; save these regs
push cx
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: jcxz send2a ; z = nothing left to do
rep movsw ; copy the data
send2a: 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 session
pop bx ; recover pointer to scb
; 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 (hex)
call hexout
pop dx
pop ax
; Error return
send3: mov pcnet,1 ; say session is broken
call serrst ; reset serial port
test flags.remflg,dserver ; server mode?
jz send3a ; z = no
call nethangup ; Server: purge old NAKs etc
send3a: call serini ; reinitialize it for new session
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
; Ungermann-Bass NETCI/Novell NASI port send packet routine.
; Enter with xmtcnt holding length of data in xmtbuf to be sent.
ubsend proc near
push ax
push bx
push cx
push es
mov cx, xmtcnt ; number of chars [ohl]
jcxz ubsend1 ; dont send zero chars [ohl]
mov bx, offset xmtbufx ; buffer address in es:bx [ohl]
mov ax, data
mov es, ax
ubsend2:test nettype,bapi ; 3Com BAPI?
jz ubsend2a ; z = no, Int 6bh kind
mov ah,bapiwrit ; 3Com block write
xor dh,dh ; session 0
int bapiint
jmp short ubsend2b
ubsend2a:mov ax, nciwrit ; write function, port 0 [ohl]
int netci
ubsend2b: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]
mov cx,xmtcnt ; need count in cx too
jmp short ubsend2 ; try again to send [ohl]
ubsend1:mov xmtcnt,0
pop es
pop cx
pop bx
pop ax
clc ; success, need failure case too
ret
ubsend endp ; [ohl] ---
; Dispatch prebuilt NetBios session scb, enter with bx pointing to scb.
; Returns status in al (and ah too). Allows STARLAN Int 2ah for netint.
SESSION PROC NEAR
push es ; save es around call
push ds
pop es ; 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
SESSION ENDP
; 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.
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
setne0: ret
; No Session
setne1: call nethangup ; clear old session material
test flags.remflg,dserver ; Server mode?
jz setne2 ; z = no, file xfer or Connect
; Server mode, post a Listen (async)
mov lsn.scb_rname,'*' ; accept anyone
mov ax,500
call pcwait ; 0.5 sec wait
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 session
pop bx
ret
setne2: ; Non-server (Client) mode
test nettype,starlan ; STARLAN?
jz setne2a ; z = 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 session
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
push bx ; save reg
mov bx,offset xmt ; setup scb pointer
call session
pop bx ; restore register
; 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:
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
stc ; set carry for failure
ret
setne5: 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,data ; 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
NETHANGUP PROC NEAR ; disconnect network session, keep names
cmp pcnet,0 ; network started?
je nethang1 ; e = no
mov al,flags.comflg ; get type of port
cmp al, 'U' ; Ungermann-Bass port? [ohl]
je nethang2 ; e = yes [ohl]
cmp al,'W' ; Novell?
je nethang2 ; e = yes
cmp al,'D' ; DECnet?
je nethang3 ; e = yes
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 session
mov can.scb_baddr,offset rcv ; cancel receives
call session
mov rposted,0 ; say no receives posted
mov can.scb_baddr,offset xmt ; cancel sends
call session
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 session
pop bx
mov portn.portrdy,0 ; say the comms port is not ready
mov pcnet,1 ; say network but no session
call serrst ; reset the serial port for reiniting
nethang1:clc
ret
; UB network [ohl] +++
nethang2:call ubclose ; close connection if any [ohl]
mov xmtcnt,0
clc
ret ; [ohl] ---
nethang3:mov dx,decneth ; DECnet handle
test nettype,declat ; DECnet LAT active?
jz nethang4 ; z = no
mov ax,latclose
int latint
and nettype,not declat ; remove net type bit
jmp short nethang5
nethang4:test nettype,decnet ; DEC CTERM active?
jz nethang5 ; z = no
mov ax,dclose ; CTERM close
int decint
and nettype,not decnet ; remove net type bit
nethang5:xor dx,dx ; clear handle
mov decneth,dx
mov portn.portrdy,0 ; say the comms port is not ready
mov pcnet,1 ; say network but no session
call serrst ; reset the serial port for reiniting
clc
ret
NETHANGUP 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 ubclos3 ; 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 portn.portrdy,0 ; say the comms port is not ready
ubclos3:pop cx
pop dx
ret
ubclos4:test nettype,bapi ; 3Com BAPI in use?
jz ubclos3 ; z = no
mov ah,bapieecm ; control Enter Command Mode char
mov al,1 ; enable it
int bapiint
jmp short ubclos3
ubclose endp
; Ungermann Bass/Novell. Put current connection on Hold. Requires keyboard
; verb \kubhold 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 ubhold2
ubhold1:test nettype,bapi ; 3Com BAPI?
jz ubhold2 ; z = no
mov ah,bapiecm ; do Enter Command Mode char
int bapiint
ubhold2:pop cx
pop dx
clc
ret
ubhold endp
; Called when Kermit exits. Name passed to mssker by initialization lclini
; in word lclexit.
NETCLOSE PROC NEAR ; close entire network connection
cmp pcnet,0 ; network ever used?
je netclo1 ; e = no, so don't touch it
call nethangup ; close connections
test nettype,netbios ; NetBios activated?
jz netclo1 ; z = no
push bx
mov bx,offset xmt
mov xmt.scb_cmd,ndelete ; delete our local Kermit name
call session ; from net adapter board
pop bx
mov pcnet,0 ; say no network
mov portn.portrdy,0 ; say comms port is not ready
and nettype,not netbios ; 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 temp,0 ; byte count of new name, if any
je chkneb ; e = none, resume old session
call chknew ; Resume current session?
jc chknex ; c = yes
cmp rdbuf,0 ; New session?
je chkneb ; e = yes
clc
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
push bx
push es ; Test for Netbios presence, IBM way
mov ah,35h ; DOS get interrupt vector
mov al,netint ; the netbios vector
int dos ; returns vector in es:bx
mov ax,es
cmp ax,0f000h ; rom bios segment??
jb chknee ; b = not likely, else Bios has
xor ax,ax ; trapped this vector to dummy iret
xor bx,bx ; fake null vector
chknee: or bx,ax ; is vector present?
pop es
pop bx
jz chknet0 ; z = no
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 session ; execute operation
pop bx
mov al,xmt.scb_err ; get response
cmp xmt.scb_err,3 ; 'illegal function', so adapter is ready
jne chknet0 ; ne = failure
push bx
push es ; Test for Netbios presence, IBM way
mov ah,35h ; DOS get interrupt vector
mov al,2ah ; the netbios vector 2ah
int dos ; returns vector in es:bx
mov ax,es
cmp ax,0f000h ; rom bios segment??
jb chknef ; b = not likely
xor ax,ax
xor bx,bx ; fake null vector
chknef: or bx,ax ; is vector present?
pop es
pop bx
jz chknet0 ; z = no, no NetBios network
or nettype,netbios ; say have NetBios network
; AT&T STARLAN board check (0ddh=magic #)
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 chknet1 ; ne = no
or nettype,starlan ; say using STARLAN, have int 2ah
push bx
push es ; 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 bx,ax ; is vector present?
pop es
pop bx
jz chknet1 ; z = no
mov nsbrk,1 ; network BREAK supported
jmp 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 portn.portrdy,1 ; say the comms port is ready
cmp temp,0 ; byte count of new name, from COMS
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 nethangup ; hangup net to clear old connection
chkne1d: ; start fresh connection
push si
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
test nettype,starlan ; STARLAN?
jz chkne1b ; z = 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 cx,temp ; count of characters in new name
cmp cx,16 ; > 16 chars in remote node name?
ja chkne1a ; a = yes, too long for Netbios
mov al,'/' ; scan for slashes in name
mov di,offset nambuf ; source of text
cld
repne scasb ; look for the slash
jne chkne1b ; ne = none, do regular Netbios name storage
chkne1a: ; STARLAN ISN long remote name support
mov xmt.scb_vrname,offset nambuf ; STARLAN var length name ptr
mov xmt.scb_vrname+2,data ; segment of remote name
mov cx,temp ; get name length again (in cl)
mov xmt.scb_vrlen,cl ; indicate its length
jmp chkne1c ; copy blanks in remote name field
; end STARLAN section
chkne1b:mov cx,temp ; Regular Netbios form, name length
mov si,offset nambuf ; source of text
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
chknet2:cmp pcnet,0 ; started net?
je chknet2c ; e = no
ret ; else quit here
chknet2c:
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 session
pop bx
pop word ptr xmt.scb_rname ; restore remote name first two bytes
chknet2a:
push es ; save registers
push di
push si
push cx
push ds
pop es ; set es:di to data segment
mov si,offset xmtbuf+60 ; where local name is returned (1st entry)
cmp word ptr xmtbuf+58,0 ; is local name empty?
jne chknet2b ; ne = no, use name from table
mov si,offset deflname ; else use default local name
chknet2b:
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
chknet3:cmp byte ptr[si],' ' ; find first space (end of regular node name)
jbe chknet4 ; be = found one (or control code)
movsb ; copy local name to scb
loop chknet3 ; continue though local name
chknet4:cmp word ptr [di-2],'K.' ; is extension '.K' present already?
je chknet4a ; e = yes, nothing to add
cmp word ptr [di-2],'k.' ; check lower case too
je chknet4a ; 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
add cx,2 ; 15th and 16th chars
chknet4a:jcxz chknet5 ; z = nothing to add
mov al,' ' ; space as padding
rep stosb
chknet5: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 cx
pop si
pop di
pop es
push bx ; Put our new local name in NAU
mov xmt.scb_cmd,nadd ; ADD NAME, wait
mov bx,offset xmt
call session
pop bx
mov al,xmt.scb_err ; get error code
or al,al ; success?
jz chknet7 ; z = yes
cmp al,0dh ; duplicate name in local table?
je chknet6a ; e = yes
cmp al,16h ; name used elsewhere?
je chknet6a ; e = yes
cmp al,19h ; name conflict?
je chknet6a ; 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 hexout ; display it (in al)
mov ah,prstr
mov dx,offset crlf
int dos
mov pcnet,0 ; say no connection today
stc ; set carry for failure
ret
chknet6a:
mov ah,prstr ; ask for another name
mov dx,offset chkmsg2 ; prompt message
int dos
mov ah,conout ; show name itself
push cx
mov cx,16 ; 16 bytes in name field
mov si,offset xmt.scb_lname
chknet6c:lodsb ; get name char into al
mov dl,al
int dos
mov byte ptr[si-1],' ' ; clear old name as we go
loop chknet6c
pop cx
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 chknet6b ; c = error
cmp xmtbuf+59,0 ; any bytes read?
je chknet6b ; e = no, exit failure
mov ah,prstr ; say rechecking name
mov dx,offset netmsg1
int dos
jmp chknet2a ; go reinterpret name
chknet6b:
stc ; set carry for failure
ret
chknet7: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 ax
push cx
mov dx,offset netmsg2 ; say net going
mov ah,prstr
int dos
mov si,offset rcv.scb_lname ; display our local name
mov ah,conout
mov cx,16
cld
chknet9:lodsb ; byte from si to al
mov dl,al
int dos ; display it
loop chknet9
mov ah,prstr
mov dx,offset crlf ; add cr/lf
int dos
pop cx
pop ax
clc ; carry clear for success
ret
chknet endp
; Network session exists. Tell user and ask for new node or Resume.
; Returns rdbuf 0 if Resume response.
chknew proc near
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
mov rdbuf,bl ; save keyword action value here
mov ah,cmeol ; get a confirm
call comnd
chknew1: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??? [jrd]
cmp ax,0f000h ; rom bios starts here
jb chkub2 ; b = not likely
xor ax,ax ; yes, say no network
mov es,ax ; fake a null vector
mov bx,ax
chkub2: mov ax,es
or bx,ax ; is vector present?
jz chkub0 ; z = no
mov al,0ffh ; test value (anything non-zero)
mov ah,2 ; function code for testing net board
int netci
or al,al ; al = 0 means board is ok
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 ; [ohl] ----
hexout proc near ; display byte in al as hex value
push ax ; all regs preserved
push cx
push dx
mov cx,2 ; two nibbles
hexout1:push cx ; save counter
mov cl,4 ; high nibble
ror al,cl ; put in low order field
mov dl,al
xchg ch,al ; save al byte in ch
and dl,0fh ; four bits
cmp dl,9 ; too big?
jbe hexout2 ; be = no
add dl,'A'-'9'-1 ; bump up to A-F
hexout2:add dl,'0'
mov ah,conout
int dos
xchg ch,al ; recover data byte
pop cx
loop hexout1 ; do second nibble
mov dl,'H' ; add a final hex ident
int dos
pop ax
pop cx
pop dx
ret
hexout endp
; local routine to see if we have to transmit an xon
chkxon proc near
cmp flowon,0 ; doing flow control?
je chkxo1 ; no, skip all this
test xofsnt,usron ; did user send an xoff?
jnz chkxo1 ; nz = yes, don't contradict it here
test xofsnt,bufon ; have we sent a buffer level xoff?
jz chkxo1 ; z = no, forget it
cmp count,mntrgl ; below (low water mark) trigger?
jae chkxo1 ; no, forget it
mov ah,flowon ; ah gets xon
and xofsnt,off ; remember we've sent the xon
call outch2 ; send via non-flow controlled entry point
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 cx
push dx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowoff ; put wait flow control char in ah
or ah,ah ; check for null char
jz ihosts1 ; z = null, don't send it
cmp dupflg,0 ; full duplex?
jne ihosts1 ; ne = no, half
call outchr ; send it
ihosts1:call clrbuf ; clear out interrupt buffer
pop dx ; empty buffer. we are done here
pop cx
pop ax
ret
IHOSTS ENDP
; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Do not send flow control if doing half duplex.
IHOSTR PROC NEAR
push ax ; save regs
push cx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; check for null char
jz ihostr1 ; z = null, don't send it
cmp dupflg,0 ; full duplex?
jne ihostr1 ; ne = no, half
call outchr ; send it (release Host's output queue)
ihostr1:pop cx
pop ax
ret
IHOSTR ENDP
; Send a break out the current serial port. Returns normally.
; Do both regular and long Break. 6 March 1987 [jrd]
SENDBR PROC NEAR
push cx ; Regular Break entry point
mov cx,275 ; 275 milliseconds in regular Break
call sendbw ; call worker routine to do it
pop cx
clc ; don't exit Connect mode
ret
SENDBL: push cx ; Long Break entry point
mov cx,1800 ; 1.8 second long break
call sendbw ; call worker routine to do it
pop cx
clc ; don't exit Connect mode
ret
; worker - send Break for cx millisec
sendbw: mov al,flags.comflg ; get type of port
cmp al,4 ; running on a UART?
ja sendbw2 ; a = yes
push dx ; UART BREAK
mov dx,brkadr ; port address
in al,dx ; get current setting
push ax ; save setting on the stack
or al,brkval ; 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 ax
ret
sendbw2:cmp al,'N' ; is this a NetBios network port?
jne sendbw5 ; ne = no
cmp nsbrk,0 ; is network able to send a break?
je sendbw4 ; e = no
test nettype,starlan ; STARLAN: network break supported?
jz sendbw4 ; z = 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
sendbw4:ret
sendbw5:cmp al,'4' ; Bios?
ja sendbw6 ; a = no
push ax
push dx
call chkbios ; set dl to port, check IBM EBIOS
jc sendbw5a ; c = not present
mov ah,0fbh ; send BREAK, IBM EBIOS code
int rs232 ; bios send
sendbw5a:pop dx
pop ax
ret
sendbw6:cmp al,'U' ; is it an UB NETCI port? [ohl]
je sendbw6 ; e = yes [ohl]
cmp al,'W' ; Novell network?
jne sendbw7 ; ne = no
push cx ; UB port send break [ohl] +++
mov ax,ncicont + 0 ; call control, use 0 for network port num [ohl]
mov cl,ncibrk ; request break [ohl]
int netci ; Net/One command interface int. (6Bh) [ohl]
pop cx
ret ; [ohl] ---
sendbw7:cmp al,'D' ; DECnet?
jne sendbw9 ; ne = no
test nettype,declat ; LAT?
jz sendbw8 ; z = no, CTERM cannot send a BREAK
mov ax,latbreak ; LAT BREAK command
push dx
mov dx,decneth ; DECnet handle
int latint
pop dx
sendbw8:ret
sendbw9:test nettype,bapi ; 3Com BAPI interface?
jne sendbw8 ; ne = no
mov ah,bapibrk ; BAPI, send BREAK
xor dh,dh ; session id of 0 (external sessions)
int bapiint
ret
SENDBR ENDP
; Initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
;
; Revised slightly by Joe R. Doupnik 22 Dec 1985 to prevent interrupts
; being enabled until we're done, to stop interrupts from occurring when
; TX holding buffer becomes empty (a useless interrupt for us), and to
; shorten the time between enabling interrupts and our exit.
; 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 serin5 ; e = yes
jl serin0 ; l = no, not yet
jmp serin4 ; yes, update flow and leave
serin0: mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT now
jnc serin5 ; nc = success
ret ; failed, exit now
serin5: push bx
mov bx,portval
mov bl,[bx].duplex ; get full/half duplex flag, local cpy
mov dupflg,bl
pop bx
cmp flags.comflg,4 ; UART?
jbe serin2 ; be = yes, real thing
jmp serin3 ; else try other port kinds
serin2: push bx
push es
in al,21H ; Interrupt controller
mov savirq,al ; save state here for restoration
or al,modem.mddis ; Inhibit IRQ 3 or IRQ 4
out 21H,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 4 or IRQ 3
mov dx,offset serint ; offset of our interrupt routine
push ds ; save ds around next DOS call
mov bx,cs ; compose full address of our routine
mov ds,bx ; segment is the code segment
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
mov al,rs232 ; interrupt number for Bios serial port
mov ah,35H ; get vector into es:bx
int dos
mov word ptr sav232,bx ; save offset
mov word ptr sav232+2,es ; save segment
mov dx,offset serdum ; offset of our interrupt routine
push ds ; save ds around next DOS call
mov bx,cs ; compose full address of our routine
mov ds,bx ; segment is the code segment
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
pop es
pop bx
mov portin,1 ; Remember port has been initialized
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
cli ; Disable interrupts
cld ; Do increments in string operations
mov al,modem.mdmeoi
mov mdeoi,al ; Use to signify end-of-interrupt
in al,21H ; Set up 8259 interrupt controller
and al,modem.mden ; Enable INT3 or INT4. (bit=0 means enable)
out 21H,al ; rewrite interrupt mask byte
mov dx,modem.mdcom ; set up serial card Line Control Reg
in al,dx ; get present settings
mov savlcr,al ; save them for restoration
mov al,3 ; 8 data bits. DLAB = 0
out dx,al
mov dx,modem.mdiir ; Interrupt Ident reg (03fah)
mov al,087h ; 8 byte trigger (80), reset fifos (2/4), Rx fifo(1)
out dx,al
jmp $+2
in al,dx ; read back iir
and al,0c0h ; select BOTH fifo bits: 16550A vs 16550 (bad fifo)
cmp al,0c0h ; are both fifo enabled bits set?
je serin2b ; e = yes, rcvr fifo is ok (16550/A)
xor al,al ; else turn off fifo mode (16550/etc)
out dx,al
serin2b: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
mov al,1 ; set up interrupt enable register
out dx,al ; for Data Available only
jmp $+2
add dx,3 ; modem control register 3fch
mov al,0bh ; assert DTR, RTS, not OUT1, and OUT2
cmp dupflg,0 ; full duplex?
je serin2c ; e = yes
mov al,9h ; assert DTR, not RTS, not OUT1, OUT2
serin2c:out dx,al ; OUT2 high turns on interrupt driver chip
sti ; Allow interrupts (AFTER next instr)
jmp short serin4 ; finish up
serin3: cmp flags.comflg,'N' ; NetBios?
je serin3o ; e = yes
cmp flags.comflg,'O' ; Opennet Network? (FGR)
jne serin3a ; ne = no
serin3o:cmp pcnet,2 ; already going?
je serin4 ; e = yes
call setnet ; setup network session and pcnet flag
jnc serin4 ; nc = success
ret ; fail, carry set, leave portin at 0
serin3a:cmp flags.comflg,'4' ; using Bios?
ja serin3b ; a = no
call chkbios ; set dl to port, check IBM EBIOS
jc serin4 ; c = not present
mov ah,0f9h ; do a Regain Control operation
int rs232
mov bx,offset biosbuf ; receive buffer for EBIOS
push ds
pop es ; set es:bx to the buffer address
mov cx,biosblen ; set cx to buffer's length
mov ax,0ff02h ; set buffered mode for receiving
int rs232
mov ax,0fb03h ; set outgoing DTR and RTS leads
int rs232
serin3b:cmp flags.comflg,'D' ; DECnet?
jne serin4 ; ne = no
cmp pcnet,2 ; going already?
je serin4 ; e = yes
call chkdec ; reinit
jnc serin4 ; nc = success
ret ; fail, carry set, leave portin at 0
serin4: 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 serin1 ; e = yes
mov parmsk,07fh ; no, pass lower 7 bits as data
serin1: xor ax,ax
cmp [bx].floflg,0 ; flow control is off?
je serin1a ; e = yes
mov ax,[bx].flowc ; get flow control chars
serin1a:mov flowoff,al ; xoff or null
mov flowon,ah ; xon or null
mov xofrcv,off ; clear xoff received flag
pop bx
mov portin,1 ; say initialized
clc ; carry clear for success
ret ; We're done
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Moved push/pop es code to do quicker exit before interrupts enabled. [jrd]
; Returns normally.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls [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 srst1 ; nz = yes (Bios or Net)
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,cs ; 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
jmp $+2 ; chip access delay
test al,40h ; both xmtr output registers empty?
loopz srst2 ; z = no, wait for them a while
xor al,al
mov dx,modem.mdiir ; modem Interrupt Ident reg (03fah)
out dx,al ; turn off FIFO mode
jmp $+2
dec dx ; point at int enable reg 3f9h
out dx,al ; disable interrupts from this source
jmp $+2 ; let stray interrupts occur now
jmp $+2
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
; clear modem's delta status bits and reassert DTR etc
inc dx ; increment to modem control register 3fch
mov al,03h ; reassert DTR,RTS,but not OUT1 and not OUT2
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
jmp $+2
jmp $+2
jmp $+2 ; wait for char to be sent
test al,40h ; is it empty?
loopz srst2b ; z = no, not yet
pop dx
mov al,1 ; reassert DTR but not RTS, OUT1, OUT2
srst2a: out dx,al ; OUT2 low to turn off interrupt drivers
jmp $+2 ; pause, in case stray interrupt is generated
jmp $+2 ; which is more than likely, hence nulint.
add dx,2 ; modem status register 3feh
in al,dx ; clear status register by reading it
jmp $+2
mov mdmhand,al ; save here for Show Modem
cli ; Disable interrupts
in al,21H ; Interrupt controller
or al,modem.mddis ; Inhibit IRQ 3 or IRQ 4
pop word ptr savsci+2 ; recover original int owner's addr
pop word ptr savsci
sti ; 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,25H ; set interrupt vector
int dos ; replaced
pop ds
mov al,rs232 ; Bios serial port interrupt vector to restore
mov dx,word ptr sav232 ; offset part
push ds
mov bx,word ptr sav232+2 ; segment part
mov ds,bx
mov ah,25h ; set interrupt vector
int dos
pop ds
pop bx
cli
mov ah,savirq ; saved Interrupt state
and ah,modem.mddis ; pick out our IRQ bit
in al,21h ; get current intrpt controller state
jmp $+2
xor al,modem.mddis ; remove our IRQ bit
or al,ah ; set previous state
out 21h,al ; reset IRQ 3 or 4 to original state
sti
; non-UART processes
srst1: cmp flags.comflg,'4' ; using Bios?
ja srst6 ; a = no
call chkbios ; set dl to port, check IBM EBIOS
jc srst6 ; c = not present
mov ah,0f9h ; do a Regain Control operation
int rs232
srst1a: mov ax,0fd02h ; see if buffer has chars already
int rs232
jcxz srst1b ; z = no, ok to reset buffering
mov ah,0fch ; do receive /nowait to clear buff
int rs232
jmp short srst1a ; repeat til empty
srst1b: mov bx,offset biosbuf ; receive buffer for EBIOS
push ds
pop es ; set es:bx to the buffer address
xor cx,cx ; set cx to zero to terminate buffering
mov ax,0ff02h ; reset buffered mode for receiving
int rs232
jmp srst9 ; done
srst6: cmp pcnet,0 ; a network active?
je srst9 ; e = no
cmp flags.comflg,'O' ; Opennet network? (FGR)
je srst7 ; e = yes
cmp flags.comflg,'N' ; NetBios network?
jne srst9 ; ne = no
srst7: cmp rposted,0 ; receive outstanding?
je srst9 ; e = no
mov can.scb_baddr,offset rcv ; cancel receives
push bx
mov bx,offset can
call session
pop bx
mov rposted,0 ; clear interlock flag no matter what
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
clc
ret
SERRST ENDP
; Null interrupt routine, to handle strays
nulint proc near
push ax
push dx
mov al,20h ; general EOI
mov dx,intcon1 ; to 8259 interrupt controller
out dx,al ; clear controller chip
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
cmp dl,al ; referencing same port as Kermit is using?
pop ax ; recover request parameters
jne serdu1 ; ne = no, chain to Bios routine
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
pop tempsci ; save old ds
pop dx ; clean the stack and prepare for ret far
pop ax ; to old int handler (same as a jump there)
push word ptr savsci+2 ; old handler segment
push word ptr savsci ; old handler offset
push tempsci ; recover old ds
pop ds
ret ; do far return (chain to old handler)
srintc: mov al,mdeoi ; allow interrupt controller to run
out intcon1,al ; Send End-of-Interrupt to 8259
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: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
mov dh,al ; dh = working copy. Check null, flow cntl
and dh,parmsk ; strip parity temporarily, if any
cmp flowoff,0 ; flow control active?
je srint2 ; e = no
cmp dh,flowoff ; acting on Xoff?
jne srint1 ; ne = Nope, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF?
jne srint0 ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; Set the flag saying XOFF received
jmp srint0 ; and exit
srint1: cmp dh,flowon ; acting on Xon?
jne srint2 ; ne = no, go on
mov xofrcv,off ; Clear the XOFF received flag
jmp srint0 ; and exit
srint2: push bx ; save register
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 srint2a ; yes, go store real second char
srint4a:pop bx ; restore reg
mov dx,mst ; uart line status register
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
mov al,flowoff ; get the flow off char (Xoff or null)
or al,al ; don't send nul chars
jz retint ; z = null, nothing to send
call dopar ; Set parity appropriately
mov ah,al ; Don't overwrite character with status
push cx ; save reg
xor cx,cx ; loop counter
srint5: mov dx,mst ; Get port status
in al,dx
test al,20H ; Transmitter ready?
jnz srint6 ; nz = yes
jmp $+2 ; use time, prevent overdriving UART
loop srint5 ; else wait loop, cx times
jmp srint7 ; Timeout
srint6: mov al,ah ; Now send out the flow control char
mov dx,modem.mddat
jmp $+2
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
DTRLOW PROC NEAR ; Global proc to Hangup the Phone or Network
; by making DTR and RTS low (phone). [jrd]
mov ah,cmline ; allow text, to be able to display help
mov bx,offset rdbuf ; dummy buffer
mov dx,offset hnghlp ; help message
call comnd ; get a confirm
jc dtrlow3 ; c = failure
cmp flags.comflg,'0' ; Bios?
jb dtrlow1 ; b = no, UART
cmp flags.comflg,'4' ; Bios?
jbe dtrlow2 ; be = yes, can't access modem lines
dtrlow1:call serhng ; drop DTR and RTS
cmp taklev,0 ; in a Take file or macro?
jne dtrlow2 ; ne = yes, no message
mov ah,prstr ; give a nice message
mov dx,offset hngmsg
int dos
dtrlow2:clc ; success
dtrlow3:ret
DTRLOW ENDP
; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; 5 April 1987 Add 500 millisec wait with lines low before returning. [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; If network then call nethangup procedure to hangup the session without
; losing local name information.
; Returns normally.
serhng proc near ; clear modem's delta status bits and lower DTR & RTS
call serini ; init port, if not done already
mov al,flags.comflg ; get kind of port
cmp al,4 ; UART?
jbe shng1 ; be = yes
cmp al,'4' ; Bios?
ja shng2 ; a = no, networks
clc ; else Bios, no hangup
ret
shng2: cmp pcnet,0 ; network operational?
je shng1 ; e = no
call nethangup ; break the session
call serrst ; reset port so can be opened again
clc
ret
shng1: call serrst ; reset port so serini can set DTR
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
jmp $+2
add dx,2 ; increment to modem status register
in al,dx ; Clear Status reg by reading it
sti ; Enable interrupts
mov ax,500 ; 500 millisec, for pcwait
call pcwait ; keep lines low for at least 500 millisec
pop dx
pop ax
clc
ret
serhng endp
code ends
end