home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
01e
/
msk230s2.zip
/
MSXIBM.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-12
|
152KB
|
3,083 lines
NAME msxibm
; File MSXIBM.ASM
; Kermit system dependent module for IBM-PC
; Edit History
; Last edit: 8 Jan 1988
; 1 Jan 1988 version 2.30
; 24 Dec 1987 Revise selection of COM1 to use COM1 name but COM2 addresses
; if base address of 02f8 (COM2) is found in 40:00h and display notice.
; Restore state of IRQ interrupt line when finished with serial port. [jrd]
; 31 Oct 1987 Add terminal type Tek4010, with Tek submode Tekflg. [jrd]
; 24 Oct 1987 Enhance clrbuf to empty any intermediate (net) buffers. [jrd]
; 19 Oct 1987 Fix stray tab-set at column 32. [jrd]
; 2 Oct 1987 Add PCjr baud rate table, from Ted Medin. [jrd]
; 6 Sept 1987 Allow serial port serint to send xoff when buffer fills even
; though user may have sent xoff by hand. [jrd]
; 27 Aug 1987 Skip timeout test in OUTCHR if receive timeout is zero. [jrd]
; 23 August 1987 Add vtemu.vtflgop to hold runtime terminal settings so that
; a reset command restores them to the Setup values, vtemu.vtflgst. Show
; displays the vtemu.vtflgop operational values. [jrd]
; 17 August 1987 Make timing adjustments for Token Passing and single buffered
; network adapter boards. Byte netdbfr indicates presence of double buffering;
; it is set in chknet as a vendor option. To test your boards force dbl buf
; then look for missing 256 byte parts of long packets sent out; missing parts
; mean new material overwrote not-yet-sent old == single buffering. [jrd]
; 8 August 1987 Add interrupt chaining in serint. [jrd]
; 23 July 1987 Clear xofsnt and xofrcv xon/xoff flags in ihost(s/r). [jrd]
; 9 July 1987 Cure confusion about COM1/2 for IBM PCjr (address of regular
; COM2 in 40:0h slot for COM1) with info from John Neufeld. [jrd]
; 2 July 1987 Route NetBios cancels through separate scb for systems, such
; as Novell NetWare, which object to having active scbs touched. [jrd]
; 25 June 1987 Add trapping of Int 14H (Bios RS232 procedure) to allow
; CTTY command to function without too much inteference from DOS. [jrd]
; 17 June 1987 Enlarge tab setting to full 132 columns at all times. [jrd]
; 11 June 1987 Add Set Term Roll on/off to control auto roll back of screen
; when new characters are displayed; default is off (no unwinding). [jrd]
; 20 May 1987 Remove rejection of NULL and DEL chars, let callers do it. [jrd]
; 16 May 1987 Add distinction between user typed and receiver threshold
; controlled sending of XOFF. User level overrides buffer control.[jrd]
; Add COM3 and COM4 support: examine memory 40:00h->40:07h for selected
; port COM1..4, resp. If word is null then set flags.comflg to 0 to say
; undefined port. Otherwise, use that word in seg 40h as base of UART i/o
; ports. Assume IRQ4 for COM1 and COM3 (same except for port addresses)
; and IRQ4 for COM2 and COM4 (again, same except for port addresses).
; Serial port info sturcture (not values) assumed identical for all ports.
; 25 April 1987 Add Netbios compatible local area network support. [jrd]
; Set Port command expanded to syntax SET PORT NET nodename. Use nodename
; if acting as a client to named remote node, leave blank if running in
; Server mode. Byte 'ttyact' is controlled by msster.asm to indicate Connect
; mode is being used. Byte 'netdone' (stored in mssker.asm) holds offset of
; network hangup procedure 'netclose' to be done when leaving Kermit. Hangup
; command extended to to network hangup as well. Network uses IBM Netbios
; standard calls (Int 5Ch) and allows for extensions of AT&T STARLAN for
; longer node names via Int 2Bh (the later is tested before use). Virtual
; circuits are employed. The Redirector is not necessary. Kermit can operate
; as either a terminal (does a CALL at Connect mode startup), a file receiver
; (does a CALL at startup), or a Kermit server (does an anonomous LISTEN at
; startup, hence no nodename). Clients should Set Timer Off.
; 16 April 1987 Add measurement and correction of software timer pcwait. [jrd]
; 5 April 1987 Keep DTR & RTS low for 1/2 second in serhng, suggested by
; Jack Bryans. [jrd]
; 28 March 1987 Reference screen coord wrt low_rgt from msyibm, let number
; of tabs be full screen width. [jrd]
; 22 March 1987 Fix bug in pcwait code, from Stefan Vogel. [jrd]
; 6 March 1987 Make PCWAIT a global procedure, add SENDBL to send Long
; Break. [jrd]
; 21 Feb 1987 Merge operations for semi-clone machines (those identical to
; IBM PC's except the serial port must be accessed via the Bios rather than
; from the real UART hardware). Ports automatically checked for 8250. [jrd]
; 1 Oct 1986 Version 2.29a
; 30 Sept 1986 Reject DEL char at serial port reception level to avoid
; problems when DEL is used as a filler char (by Emacs). [jrd]
; 4 Sept 1986 Add Bob Goeke's change to move comms port table to a system
; dependent module (typ msx---) to allow 3+ ports and localized idents. [jrd]
; 26 August 1986 Use parity mask when testing for nulls & Xon/Xoff in serial
; port interrupt routine. [jrd]
; 16 August 1986 Use observed screen attributes for mode line. [jrd]
; 9 August 1986 Revise SERINT to insert control-G for overrun chars, give
; faster return of interrupts to system, remove use of BP in code. [jrd]
; 17 July 1986 Minor clean up of Terminal Status display routine. [jrd]
; 22 June 1986 Leave 8250 UART signal OUT1 low to avoid resetting Hayes
; 1200B modems (thanks to Neil Rickert). [jrd]
; Skip sending null byte in ihosts and ihostr (thanks to Skip Russell). [jrd]
; 22 May 1986 Rewrite serial port interrupt procedure and proc prtchr
; to avoid lockups with interrupts disabled, buffer corruption, and to
; minimize lost clock interrupts. Flow control not needed at 9600 baud,
; slow screen refresh, VT102 emulation, on a 4.77 MHz IBM PC clone.
; Added buffer low water mark to give more xon/xoff hysterisis. [jrd]
; [2.29] code frozen on 6 May 1986 [jrd]
; Note -
; When the Bios is used for serial port i/o the modem signals DSR and CTS
; must be asserted low before the Bios will access the hardware. Jumpers
; from pin 20 (DTR) to pin 6 (DSR) and from pin 4 (RTS) to pin 5 (CTS)
; will probably be necessary.
; From Glenn Everhart (who suggested using the Bios alternative)
;
public serini, serrst, clrbuf, outchr, coms, vts, vtstat
public dodel, ctlu, cmblnk, locate, prtchr, dobaud, clearl
public dodisk, getbaud, beep, termtb, shomodem
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, sendbl, machnam, setktab, setkhlp, lclini, showkey
public ihosts, ihostr, dtrlow, serhng, comptab, pcwait
include mssdef.h
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
MCONF EQU 11H ; Bios Machine configuration s/ware interrupt.
KEYB EQU 16H ; Bios keyboard software interrupt
VIDEO EQU 10H ; Bios Video display software interrupt
RS232 EQU 14H ; Bios RS232 serial port s/ware interrupt
; constants used by serial port handler
;;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:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; low_rgt - low byte = last column (typ 79), high byte = last text row
; (typ 23) in screen coordinates (start at 0), set by msyibm.
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
; not implemented)
; setkhlp - help for setktab.
datas segment public 'datas'
extrn drives:byte, flags:byte, trans:byte, ttyact:byte
extrn portval:word, port1:byte, port2:byte, port3:byte, port4:byte
extrn netdone:word, pcnet:byte
extrn refresh:byte, scbattr:byte, low_rgt:word, vtemu:byte
extrn vtroll:byte, tekflg:byte
; structure for status information table sttab.
stent struc
sttyp dw ? ; type (actually routine to call)
msg dw ? ; message to print
val2 dw ? ; needed value: another message, or tbl addr
tstcel dw ? ; address of cell to test, in data segment
basval dw 0 ; base value, if non-zero
stent ends
setktab db 0 ; superceded by msuibm code, return 0 here
setkhlp db '$' ; and add empty help string
savsci dd ? ; old serial port interrupt vector.
sav232 dd ? ; Original Bios Int 14H address, in Code seg.
savirq db ? ; Original Interrupt mask for IRQ
brkval db BRKBIT ; What to send for a break.
brkadr dw 0 ; Where to send it.
modem mdminfo <>
hngmsg db cr,lf,' The phone or network connection should have hungup.'
db cr,lf,'$'
nohngmsg db cr,lf,' Command ineffective on this port.',cr,lf,'$'
hnghlp db cr,lf,' The modem control lines DTR and RTS for the current'
db ' port are forced low (off)'
db cr,lf,' to hangup the phone. Normally, Kermit leaves them'
db ' high (on) when it exits.',cr,lf
db ' For networks, the active session is terminated.',cr,lf,'$'
erms40 db cr,lf,'?Warning: Unrecognized baud rate',cr,lf,'$'
badbd db cr,lf,'Unimplemented baud rate$'
prterr db '?Unrecognized value$'
badprt db cr,lf,' Serial port COM$'
badprt2 db ' is not available.$'
badprt3 db cr,lf,' Notice: Port COM1 uses hardware addresses of COM2'
db ' (safe).',cr,lf,'$'
biosmsg db cr,lf,'This port operates through the Bios',cr,lf,'$'
msmsg1 db cr,lf,' Modem is not ready: DSR is off$'
msmsg2 db cr,lf,' Modem is ready: DSR is on$'
msmsg3 db cr,lf,' no Carrier Detect: CD is off$'
msmsg4 db cr,lf,' Carrier Detect: CD is on$'
msmsg5 db cr,lf,' no Clear To Send: CTS is off$'
msmsg6 db cr,lf,' Clear To Send: CTS is on$'
machnam db 'IBM-PC$'
crlf db cr,lf,'$'
delstr db BS,BS,' ',BS,BS,'$' ; Delete string
clrlin db cr,'$' ; Clear line (just the cr part).
onmsg db 'on$'
offmsg db 'off$'
clone db 0 ; clone flag (0 = real, 'B' = system Bios,
; 'N' = NetBios/network)
portin db 0 ; Has comm port been initialized
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
parmsk db ? ; parity mask, 0ffh for no parity, 07fh with.
flowoff db ? ; flow-off char, Xoff or null (if no flow)
flowon db ? ; flow-on char, Xon or null
overrun db ? ; holds status of receiver overrun
pcwcnt dw 240 ; number of loops for 1 millisec in pcwait
temp dw 0
tempsci dw 0 ; temp storage for serint
tempdum dw 0 ; temp storage for serdum
rdbuf db 80 dup (?) ; temporary storage
; begin Terminal emulator data set
termtb db tttypes ; entries for Status, not Set
mkeyw 'Heath-19',ttheath
mkeyw 'none',ttgenrc
mkeyw 'Tek4010',tttek
mkeyw 'VT102',ttvt100
mkeyw 'VT52',ttvt52
vttbl db 15 ; number of entries.
mkeyw 'Character-set',chaval
mkeyw 'Color',200H ; screen fore/back colors; 200H=marker
mkeyw 'Cursor-style',curval
mkeyw 'Heath-19',ttheath+100H ; note 100H flag for decoding here
mkeyw 'Keyclick',keyval
mkeyw 'Margin-bell',marval
mkeyw 'None',ttgenrc+100H
mkeyw 'Newline',newval
mkeyw 'Rollback',400h ; note 400H flag for decoding
mkeyw 'Screen-background',scrval
mkeyw 'Tabstops',tabval
mkeyw 'Tek4010',tttek+100H
mkeyw 'VT102',ttvt100+100H
mkeyw 'VT52',ttvt52+100H
mkeyw 'Wrap',wraval
scrtab db 02H ; screen attributes
mkeyw 'normal',00H
mkeyw 'reverse',01H
curtab db 02H ; cursor attributes
mkeyw 'block',00H
mkeyw 'underline',01H
chatab db 02H ; character set (pound sign choice)
mkeyw 'UK-ascii',01H
mkeyw 'US-ascii',00H ; US ASCII is default (0).
tabtab db 02H ; label says it all!
mkeyw 'at',0FFH ; For setting tab stops.
mkeyw 'Clear',00H ; For clearing tab stops.
alltab db 02H ; more tab command decoding
mkeyw 'all',00H
mkeyw 'at',01H
vtable dw ontab, curtab, chatab, ontab, ontab, ontab, scrtab, 0
vtsflg equ this byte ; define small digits xxxval
newval equ $-vtsflg ; and mask for bit in byte
db vsnewline
curval equ $-vtsflg
db vscursor
chaval equ $-vtsflg
db vsshift3
keyval equ $-vtsflg
db vskeyclick
wraval equ $-vtsflg
db vswrap
marval equ $-vtsflg
db vsmarginbell
scrval equ $-vtsflg
db vsscreen
numflgs equ $-vtsflg
tabval equ $-vtsflg
db 0
vtrtns dw numflgs dup (flgset), tabset ; dispatch table for vtsflg
clrset db ? ; Temp for SET Term Tabstops xxx
tmptabs db 132 dup (?) ; Temporary for unconfirmed tabs.
vthlp db ' one of the following:',cr,lf
db ' terminal types of: None, Heath-19, VT52, VT102, or Tek4010',cr,lf
db ' Newline-mode Cursor-style Character-set (US UK)',cr,lf
db ' Keyclick Margin-bell Screen-background'
db ' (normal, reverse)',cr,lf
db ' Tabstops Wrap (long lines) Color (fore & background)'
db cr,lf,' Roll (undo screen roll back before writing new chars,'
db ' default=off)$'
clrhlp db ' one of the following:'
db cr,lf,' AT #s (to set tabs at column #s)'
db cr,lf,' Clear AT #s or Clear ALL (to clear tabstops)'
db cr,lf,' Ex: Set Term Tab at 10, 20, 34 sets tabs'
db cr,lf,' Ex: Set Term Tab Clear at 9, 17, 65 clears tabs$'
allhlp db ' one of the following:'
db cr,lf,' AT #s (to clear at specific columns)'
db cr,lf,' ALL (to clear all tabstops)$'
tbshlp db ' column number of tab stop to set, 1 to screen width-1$'
tbchlp db ' column number of tab stop to clear, 1 to screen width-1$'
tbserr db cr,lf,'?Column number is not in range 1 to screen width-1$'
colhlp db cr,lf,' Set Term Color value, value, value, ...'
db ' commas are optional.'
db cr,lf,' 0 selects normal white on black and'
db ' no-snow mode on an IBM CGA (default).'
db cr,lf,' 1 for high intensity foreground.'
db cr,lf,' 10 for fast screen updating.'
db cr,lf,' Foreground color (30-37) = 30 + colors'
db cr,lf,' Background color (40-47) = 40 + colors'
db cr,lf,' where colors are 1 = red, 2 = green, 4 = blue.'
db cr,lf,' Ex: 0, 1, 34, 47 IBM CGA(0), bright(1) blue(34)'
db ' chars on a white(47) field.'
db cr,lf,' Attributes are applied in order of appearance.$'
colerr db cr,lf,'?Value not in range of 0, 1, 10, 30-37, or 40-47$'
vtwrap db ' Term wrap-lines: $'
vtbell db ' Term margin-bell: $'
vtnewln db ' Term newline: $'
vtcur db ' Term cursor-style: $'
vtcset db ' Term character-set: $'
vtclik db ' Term key-click: $'
vtscrn db ' Term screen-background: $'
colst1 db ' Term color foreground:3$'
colst2 db ' background:4$'
; terminal emulator
vtstbl stent <srchkb,vtwrap,ontab,,vtsflg+wraval> ; VT100 line wrap
stent <srchkb,vtbell,ontab,,vtsflg+marval> ; VT100 margin bell
stent <srchkb,vtcur,curtab,,vtsflg+curval> ; VT100 cursor type
stent <srchkb,vtnewln,ontab,,vtsflg+newval> ; VT100 newline
stent <srchkb,vtscrn,scrtab,,vtsflg+scrval> ; VT100 screen
stent <srchkb,vtcset,chatab,,vtsflg+chaval> ; VT100 character set
stent <srchkb,vtclik,ontab,,vtsflg+keyval> ; VT100 keyclick
stent <colstat> ; VT100 colors
stent <tabstat> ; VT100 tab status - needs one whole line
dw 0 ; end of table
; end of Terminal data set
ontab db 2 ; Two entries.
mkeyw 'off',0 ; Should be alphabetized
mkeyw 'on',1
comptab db 10 ; communications port options
mkeyw '1',1
mkeyw '2',2
mkeyw '3',3
mkeyw '4',4
mkeyw 'COM1',1
mkeyw 'COM2',2
mkeyw 'COM3',3
mkeyw 'COM4',4
mkeyw 'NET','N' ; Netbios
mkeyw ' ',0 ; port is not present, for Status
; this table is indexed by the baud rate definitions given in
; pcdefs. Unsupported baud rates should contain FF.
bddat label word
dw 0FFH ; 45.5 baud -- Not supported.
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 ; 56800 baud
dw 01h ; 113600 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.
; Clone: 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 ; 56800 baud
dw 0FFH ; 113600 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.
mdeoi db 0 ; End-of-Interrupt value.
mdstreg 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)
starlan equ 1 ; network type bit, AT&T STARLAN
;; 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> ; 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 datas ; and segment
scb_length dw ? ; length of buffer data
scb_rname db '* ' ; remote name, 16 chars space
scb_lname db 'mskermit ' ; 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
xmtbuf db nbuflen dup (0) ; network buffer for transmitter
xmtcnt dw 0 ; occupancy in current output buffer
rcvbuf db nbuflen 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
netdbfr db 0 ; non-zero if net board is double buffered
deflname db 'mskermit ' ; default local name, 16 bytes
nsbrk dw 0 ; net can send Break
nettype dw 0 ; kind of local area net (vendor bit field)
commsg db cr,lf,' Port NET will not be used.$'
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 $'
nonetmsg db cr,lf,' The network is not available.$'
nethlp db cr,lf,' Enter node name of remote system,'
db cr,lf,' or a carriage return to use current name,'
db cr,lf,' or a carriage return for server mode.$'
ngodset db cr,lf,' Connecting to network node: $'
nbadset db bell,cr,lf,' Cannot reach network node: $'
nbaduc db cr,lf,' Consider trying again with this name in Upper Case.$'
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.'
db cr,lf,'> $'
nettab db 2
mkeyw 'New',0
mkeyw 'Resume',1
datas ends
code segment public 'code'
extrn comnd:near, dopar:near, defkey:near, lclyini:near
extrn sleep:near, atsclr:near, scrseg:near,scrloc:near, scrsync:near
extrn atoi:near, strlen:near, prtscr:near, scroff:near, scron:near
extrn prompt:near
assume cs:code,ds:datas
; 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
call lclyini ; let other modules initialize too...
ret
lclini endp
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. Returns normally.
DODISK PROC NEAR
int mconf ; Get equipment configuration.
mov ah,al ; Store AL value for a bit.
and al,01H ; First, look at bit 0.
jz dodsk0 ; No disk drives -- forget it.
mov al,ah ; Get back original value.
mov cl,6 ; Shift over bits 6 and 7.
shr al,cl ; To positions 0 and 1.
inc al ; Want 1 thru 4 (not 0 thru 3).
dodsk0: mov drives,al ; Remember how many.
ret
DODISK ENDP
; The IBM PCjr. If jr then redo IBM baud rate with jr's values. [jrd]
model proc near
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 datas 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
mov ch,0
cld
rep movsw ; copy PCjr values to IBM table
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 mdstreg, the modem line status register. [jrd]
shomodem proc near
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
call serini ; activate port to get status
call serrst ; turn off port again
mov ah,prstr
mov dx,offset msmsg1 ; modem ready msg
test mdstreg,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 mdstreg,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 mdstreg,10h ; CTS asserted?
jz shomd3 ; z = no
mov dx,offset msmsg6 ; say not asserted
shomd3: int dos
jmp rskp
shomodem endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cli
mov srcpnt,offset source ; receive circular buffer
mov count,0 ; receive circular buffer
sti
call prtchr ; empty any intermediate (net) buffers
nop ; got a char, clear again
nop
nop
cli
mov srcpnt,offset source ; receive circular buffer
mov count,0 ; receive circular buffer
mov xmtcnt,0 ; network output buffer count
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
; Upgraded for Topview compatibility. [jrd]
CLEARL PROC NEAR
push ax
push bx
push dx
mov ah,3 ; Clear to end of line.
mov bh,0
int video ; Get current cursor position into dx
mov ax,dx ; Topview compatible clear line
mov bh,ah ; same row
mov bl,byte ptr low_rgt ; last column
call atsclr ; clear from ax to bx, screen coord
pop dx
pop bx
pop ax
ret
CLEARL ENDP
; This routine blanks the screen. Returns normally.
; Upgraded to Topview compatiblity. [jrd]
CMBLNK PROC NEAR
push ax
push bx
xor ax,ax ; from screen loc 0,0
mov bx,low_rgt ; to end of text screen (lower right corner)
inc bh ; include status line
call atsclr ; do Topview compatible clear, in msyibm
pop bx
pop ax
ret
CMBLNK ENDP
; Locate: homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
push ax
push bx
mov ah,2 ; Position cursor.
mov bh,0 ; page 0
int video
pop bx
pop ax
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
BEEP PROC NEAR
push 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
ret
BEEP ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push ax ; save regs
push bx
push cx
push dx ; preserve message
mov bl,scbattr ; screen attributes at Kermit init time
and bl,77h ; get colors, omit bright and blink
rol bl,1 ; interchange fore and background
rol bl,1
rol bl,1
rol bl,1
mov bh,0 ; preset page 0
mov temp,bx ; temp = page 0, reverse video
mov dx,low_rgt ; ending location is lower right corner
inc dh ; of status line
mov cx,dx ; start is status left side
xor cl,cl ; left side
mov ax,600h ; scroll to clear the line
mov bh,byte ptr temp ; set inverse video attributes
int video
mov dx,low_rgt ; last text line
inc dh ; status line
xor dl,dl ; left side
call poscur
pop si ; get message back
mov cx,1 ; only one char at a time
xor bh,bh ; page 0
cld
putmo1: lodsb ; get a byte
cmp al,'$' ; end of string?
je putmo2
push si ; save si
push ax ; and the char
call poscur
inc dl ; increment for next write
pop ax ; recover char
mov ah,9 ; try this
mov bx,temp ; page 0, inverse video
int video
pop si ; recover pointer
jmp putmo1
putmo2: pop cx
pop bx
pop ax
ret
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
push ax ; save regs
push bx
push cx
push dx
mov ax,600h ; do a scroll up
mov dx,low_rgt ; ending location is lower right corner
inc dh ; of status line
mov cx,dx ; start is status left side
xor cl,cl ; left side
mov bh,scbattr ; use screen attributes at Kermit init time
int video
pop dx
pop cx
pop bx
pop ax
ret
clrmod endp
; put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push bx ; save regs
push cx
push dx
push si
push ax ; preserve this
cld
mov bl,scbattr ; screen attributes at Kermit init time
and bl,77h ; get colors, omit bright and blink
rol bl,1 ; interchange fore and background
rol bl,1
rol bl,1
rol bl,1
mov bh,0 ; preset page 0
mov temp,bx ; temp = page 0, reverse video
mov si,ax ; point to it
mov dh,1 ; init counter
puthl1: lodsb ; get a byte
cmp al,lf ; linefeed?
jne puthl2 ; no, keep going
inc dh ; count it
jmp puthl1 ; and keep looping
puthl2: cmp al,0 ; end of string?
jne puthl1 ; no, keep going
mov ax,600h ; scroll to clear window
xor cx,cx ; from top left
mov dl,4fh ; to bottom right of needed piece
mov bh,70h ; inverse video
mov bh,bl ; inverse video
int video
call locate ; home cursor
mov bx,0070h ; bh = page 0, bl = inverse video
mov bx,temp
mov cx,1 ; one char at a time
cld ; scan direction is forward
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
push si ; save around bios call
cmp al,' ' ; printable?
jb puth21 ; b = no
mov ah,9 ; write char at current cursor position
int video ; do the Bios int 10h call
inc dl ; point to next column
jmp puth23 ; move cursor there
puth21: cmp al,cr ; carriage return?
jne puth22 ; ne = no
xor dl,dl ; set to column zero
jmp puth23
puth22: cmp al,lf ; line feed?
jne puth23
inc dh ; go to next line
puth23: mov ah,2 ; set cursor position to dx
int video
pop si ; restore pointer
jmp puthl3 ; and keep going
puthl4: mov dh,byte ptr low_rgt+1 ; go to last line
inc dh
xor dl,dl
call poscur ; position cursor
pop si
pop dx
pop cx
pop bx
ret
puthlp endp
; begin Terminal set & status code
; SET Term parameters, especially for use with VT100 emulator. [jrd]
; Taken from work done originally by James Harvey IUPUI.
; VTS is called only by mssset to set terminal type and characteristics.
VTS proc near ; SET TERM whatever
mov ah,cmkey ; Parse another keyword.
mov bx,offset vthlp ; Use this help
mov dx,offset vttbl ; Use this table
call comnd
jmp r ; Vsetup always returns +1.
cmp bh,1H ; marker for terminal type?
je vsetu0a ; e = yes
cmp bh,4h ; marker for roll back control?
je vsetu3 ; e = yes
cmp bh,2h ; marker for set term color?
je vsetu2 ; e = yes
jmp short vsetu1 ; else dispatch on bl
vsetu0a:push bx ; yes
mov ah,cmcfm
call comnd ; Get a confirm.
jmp vsetu0 ; Didn't get a confirm.
nop
pop bx
mov flags.vtflg,bl ; Set the terminal emulation type
mov tekflg,0 ; clear Tek sub mode
ret
vsetu0: pop bx
ret
vsetu3: mov ah,cmkey ; Set Term Roll On/Off, auto roll back
mov bx,0 ; Use on/off table as help
mov dx,offset ontab ; Use on/off table
call comnd
jmp r ; bad keyword
push bx
mov ah,cmcfm ; get a confirm
call comnd
jmp vsetu0 ; did not get a confirm
nop
pop bx
mov vtroll,bl ; set roll state (0=no auto rollback)
jmp rskp ; return successfully
vsetu1: sal bx,1 ; Make bx a word index.
call vtrtns[bx] ; Dispatch.
jmp r ; Vsetup always returns +1.
jmp r ; Vsetup always returns +1.
; Set Term Color foreground, background
vsetu2: mov ah,cmtxt ; get number(s) after set term color
mov dx,offset colhlp ; use this help
mov bx,offset rdbuf ; temp buffer
mov byte ptr [bx],0 ; clear the buffer
call comnd
jmp r
cmp ah,0 ; anything given?
jne vsetu2a ; ne = yes.
jmp r ; else give not confirmed msg
vsetu2a:mov ah,cmcfm ; Parse confirm
mov bx,0 ; Use default help.
call comnd
jmp r ; not confirmed, complain.
mov si,offset rdbuf ; si = place where atoi wants text
vsetu2c:mov dx,si
call strlen ; current length of text
jcxz vsetu2x ; nothing left
mov ah,cl ; put length where Atoi wants it
call atoi ; convert text to numeric in ax
jmp colbad ; no value available
cmp ax,0 ; reset all? regular IBM CGA refresh
je vsetu2j ; e = yes
cmp ax,1 ; high intensity?
je vsetu2k ; e = yes
cmp ax,10 ; fast refresh?
je vsetu2l ; e = yes
cmp ax,30 ; check range
jb colbad ; b = too small. complain
cmp ax,37
jna vsetu2b ; 30-37 is foreground color
cmp ax,40
jb colbad
cmp ax,47 ; Compare as unsigned.
jna vsetu2b ; 40-47 is background
jmp colbad ; else error
vsetu2x:jmp rskp ; and return normally.
vsetu2b:push bx
mov bx,vtemu.att_ptr ; Get address of attributes byte
cmp al,40 ; background (40-47)?
jnb vsetu2f ; nb = yes
sub al,30 ; remove foreground bias
and byte ptr [bx],not 07H ; clear foreground bits
test al,1 ; ANSI red?
jz vsetu2d ; z = no
or byte ptr [bx],4 ; set IBM foreground red
vsetu2d:test al,2 ; ANSI & IBM green?
jz vsetu2e ; z = no
or byte ptr [bx],2 ; set green foreground
vsetu2e:test al,4 ; ANSI Blue?
jz vsetu2i ; z = no
or byte ptr [bx],1 ; set IBM blue
jmp vsetu2i ; done with foreground settings
vsetu2f:sub al,40 ; remove background bias
and byte ptr [bx],not 70H ; clear background attributes
test al,1 ; ANSI red?
jz vsetu2g ; z = no
or byte ptr [bx],40h ; set IBM background red
vsetu2g:test al,2 ; ANSI & IBM green?
jz vsetu2h ; z = no
or byte ptr [bx],20h ; set green background
vsetu2h:test al,4 ; ANSI Blue?
jz vsetu2i ; z = no
or byte ptr [bx],10h ; set IBM blue
vsetu2i:pop bx
jmp vsetu2c ; get any next value
vsetu2j:mov refresh,0 ; Regular (slow) screen refresh
mov bx,vtemu.att_ptr ; Get address of attributes byte
mov byte ptr [bx],07h ; clear all, set white on black.
jmp vsetu2c ; get next value
vsetu2k:mov bx,vtemu.att_ptr ; Get address of attributes byte
or byte ptr [bx],08h ; set high intensity
jmp vsetu2c ; get next value
vsetu2l:mov refresh,1 ; Fast screen refresh
jmp vsetu2c
colbad: cmp byte ptr [si],0 ; at end of text?
je colbad1 ; e = yes, not an error
mov ah,prstr ; Not in range - complain and exit.
mov dx,offset colerr
int dos
colbad1:jmp rskp
; SET Term flags. These are the (near) equivalent of VT100 Setup mode values.
flgset: push bx ; Save bx for a second.
mov ah,cmkey ; Another keyword.
mov dx,vtable[bx] ; The table to use.
mov bx,0 ; Use default help.
call comnd
jmp flgse3
push bx ; Save switch value.
mov ah,cmcfm ; Confirm it.
call comnd
jmp flgse2
pop dx ; Restore switch value.
pop bx ; And index.
sar bx,1 ; Make it a byte index.
mov al,vtsflg[bx] ; Get the flag.
cmp dx,0 ; Set or clear?
je flgse1 ; Go clear it.
or vtemu.vtflgst,al ; Set the flag.
or vtemu.vtflgop,al ; in runtime flags too
jmp rskp ; Give good return.
flgse1: not al ; Complement
and vtemu.vtflgst,al ; Clear the indicated setup flag.
and vtemu.vtflgop,al ; Clear the indicated runtime flag.
jmp rskp ; Give good return.
flgse2: pop bx ; error exits
flgse3: pop bx
ret
; SET Term Tabstops Clear ALL
; SET Term Tabstops Clear AT n1, n2, ..., nx
; SET Term Tabstops At n1, n2, ..., nx
tabset: cld ; Make sure this is clear.
mov di,offset tmptabs ; clear our temp work area here.
mov cx,132 ; 132 columns
mov al,0 ; set "not touched" indicator
rep stosb ; in all tmptabs slots
mov ah,cmkey ; Parse keyword.
mov bx,offset clrhlp ; Use this help text.
mov dx,offset tabtab ; This table.
call comnd
jmp r
mov clrset,2 ; code for set a tab
cmp bl,0 ; Was it set or clear?
jne tabse1 ; SET - go parse column number(s).
mov clrset,1 ; code for clear at/all tab(s)
mov ah,cmkey ; CLEAR - parse ALL or AT
mov bx,offset allhlp ; Use this help text.
mov dx,offset alltab ; Parse ALL or AT.
call comnd
jmp r
cmp bx,0 ; ALL?
jne tabse1 ; ne = AT, clear at specific places.
mov al,1 ; ALL, means clear all tab stops.
mov cx,132 ; use 132 columns
mov di,offset tmptabs
rep stosb
mov ah,cmcfm ; Confirm it.
call comnd
jmp r
jmp tabcpy ; update active & coldstart tabs
tabse1: mov dx,offset tbshlp ; Tell them we want a column number.
cmp clrset,1 ; Clearing?
jne tabse2 ; ne = Set. we guessed right on help.
mov dx,offset tbchlp ; Yes - use this help instead.
tabse2: mov ah,cmtxt ; get text w/o white space
mov bx,offset rdbuf ; temp buffer
call comnd
jmp r
cmp ah,0 ; anything given?
jne tabse4 ; ne = yes.
jmp r ; else give not confirmed msg
tabse4: mov ah,cmcfm ; Parse confirm
mov bx,0 ; Use default help.
call comnd
jmp r ; not confirmed, complain.
mov si,offset rdbuf ; si = place where atoi wants text
tabse5: mov dx,si
call strlen ; current length of text
mov ah,cl ; put length where Atoi wants it
jcxz tabcpy ; nothing left
call atoi ; convert text to numeric in ax
jmp tabcpy ; no number available
mov bx,ax ; for subscripting in code below
dec bx ; Put column in range 0-79
cmp bx,0 ; check range (1-80 --> 0-79)
jl tbsbad ; l = too small. complain
cmp bl,132-1 ; more than the right most column?
jna tabse3 ; na = no, is ok
tbsbad: mov ah,prstr ; Not in range - complain and exit.
mov dx,offset tbserr
int dos
jmp rskp
tabse3: mov al,clrset ; Get value for setting or clearing.
mov tmptabs[bx],al ; store in tabs temp work array
jmp short tabse5 ; look for more
tabcpy: mov cx,132 ; update all active tab stops
mov si,vtemu.vttbst ; in terminal emulator's active buffer
mov di,vtemu.vttbs ; and in the cold-start buffer.
mov bx,0 ; subscript
tabcpy1:mov al,byte ptr tmptabs [bx] ; get a table entry into al
or al,al ; what is the code?
jz tabcpy3 ; z = do not touch
cmp al,2 ; set a tab?
je tabcpy2 ; e = set the tab
mov byte ptr [bx+si],0 ; clear the tab
mov byte ptr [bx+di],0 ; clear the tab
jmp short tabcpy3
tabcpy2:mov byte ptr [bx+si],0ffh ; set the tab
mov byte ptr [bx+di],0ffh ; set the tab
tabcpy3:inc bx ; inc subscript
loop tabcpy1
jmp rskp ; Give good return.
VTS endp ; end of Set Term things.
; Terminal Status display, called within STAT0: in MSSSET.[jrd]
VTSTAT proc near ;enter with di within sttbuf, save bx, di
push bx
push di
mov bx,ds
mov es,bx
cld
mov bx,offset vtstbl ; table of things to show
xor cx,cx
vtsta1: cmp word ptr [bx],0 ; end of table?
je vtstax ; e = yes
push bx
call [bx].sttyp ; call appropriate routine
pop bx ; cx incremented by output count
cmp cx,38 ; place for second display
jbe vtsta2 ; le = only half full
mov dx,offset crlf ; over half full. send cr/lf
mov ah,prstr
int dos
xor cx,cx ; say line is empty now
jmp short vtsta4
vtsta2: mov ax,cx
mov cx,38 ; where we want to be next time
sub cx,ax ; compute number of filler spaces
jcxz vtsta4 ; nothing to do
mov ah,conout
mov dl,' '
vtsta3: int dos ; fill with spaces
loop vtsta3 ; do cx times
mov cx,38 ; current column number
vtsta4: add bx,size stent ; look at next entry
jmp vtsta1 ; and do it
vtstax: pop di
pop bx
ret ; return to STAT0: in MSSSET.
; foreground/background color status
colstat proc near
mov dx,offset colst1
mov ah,prstr
int dos ; print first part of msg
xor ax,ax
mov bx,vtemu.att_ptr ; pointer to attributes byte
test byte ptr [bx],1 ; IBM blue foregound?
jz colsta1 ; z = no
or al,4 ; set blue bit
colsta1:test byte ptr [bx],2 ; IBM green foreground?
jz colsta2
or al,2
colsta2:test byte ptr [bx],4 ; IBM red foreground?
jz colsta3
or al,1
colsta3:add al,'0' ; add ascii bias
mov dl,al ; move to DOS place
mov ah,conout
int dos ; print the last digit
mov dx,offset colst2 ; now do background
mov ah,prstr
int dos ; print second part of msg
xor ax,ax
test byte ptr [bx],10h ; IBM blue background?
jz colsta4 ; z = no
or al,4 ; set blue bit
colsta4:test byte ptr [bx],20h ; IBM green background?
jz colsta5
or al,2 ; set green bit
colsta5:test byte ptr [bx],40h ; IBM red background?
jz colsta6
or al,1 ; set red bit
colsta6:add al,'0' ; add ascii bias
mov dl,al ; move to DOS place
mov ah,conout
int dos
add cx,45 ; about the # columns we used
ret
colstat endp
; Tabs Status display
tabstat proc near ; display tabs ruler for Status
push dx
jcxz tabsta0 ; empty line, as it should be
xor cx,cx ; used line, empty it
mov dx,offset crlf ; cr, lf
mov ah,prstr
int dos
tabsta0:mov si,vtemu.vttbst ; active tabs address, not shadow
mov cl,byte ptr low_rgt ; loop screen width-1 times
xor ch,ch ; clear high byte
dec si ; dec for inc below
xor ax,ax ; tens counter
tabsta1:mov dl,'.' ; default position symbol
inc si ; start with position 1
inc al
cmp al,10 ; time to roll over?
jb tabsta2 ; b = not yet
mov al,0 ; modulo 10
inc ah
mov dl,ah ; display a tens-digit
add dl,'0'
cmp dl,'9' ; larger than 90?
jbe tabsta2 ; be = no
sub dl,10 ; roll over to 0, 1, etc
tabsta2:cmp byte ptr [si],0 ; is tab set?
je tabsta3 ; e = no
mov dl,'T' ; yes, display a 'T'
tabsta3:push ax
mov ah,conout ; console output
int dos
pop ax
loop tabsta1 ; loop til done (cx has count)
pop dx
mov cx,38 ; say line is used
ret
tabstat endp
; handler routines for status. All are called with bx/ stat ptr.
onoff proc near
call stmsg ; print the message
mov si,[bx].basval ; get base value
cmp si,0 ; any there?
je onoff1 ; e = no
mov si,[si] ; yes, use as base address
onoff1: add si,[bx].tstcel ; add offset of test cell
mov al,[si]
mov dx,offset onmsg
add cx,2 ; assume two byte on message
or al,al ; test value
jnz onoff2 ; nz = on
mov dx,offset offmsg
inc cx ; three byte message
onoff2: mov ah,prstr ; display the message
int dos
ret
onoff endp
; search a keyword table for a bit value, print that value. [jrd]
srchkb proc near
call stmsg ; first print message
call stbval ; get bit set or reset
mov ah,0 ; al has 0/1, high order is 0
mov bx,[bx].val2 ; this is table address
jmp prttab ; and look in table.
srchkb endp
; get address of test value in stent. Returns address in si. [jrd]
stbval proc near
mov si,[bx].basval ; get address of test value
cmp si,0 ; any there?
je stbva1 ; no, quit with no match
mov al,byte ptr [si] ; get byte value
mov ah,0
test al,vtemu.vtflgop ; bit test value against emulator flags byte
jz stbva1 ; z = they don't match
mov al,1 ; match
ret
stbva1: mov al,0 ; no match
ret ; and return it
stbval endp
; get address of test value in stent. Returns address in si
stval proc near
mov si,[bx].basval ; get base value
cmp si,0 ; any there?
je stva1 ; no, keep going
mov si,[si] ; yes, use as base address
stva1: add si,[bx].tstcel ; add offset of test cell
ret ; and return it
stval endp
; copy the message to the screen
stmsg proc near
mov si,[bx].msg ; get message address
stms1: lodsb ; get a byte
cmp al,'$' ; end of message?
je stms2 ; e = yes
mov dl,al ; display the character
mov ah,conout
int dos
inc cx ; count output chars
jmp stms1
stms2: ret
stmsg endp
; Print value from table. BX/address of table, AL/value of variable.
prttab: push cx ; save column count
mov cl,[bx] ; Number of entries in our table.
inc bx ; Point to the data.
prtt0: mov dl,[bx] ; Length of keyword.
inc bx ; Point to keyword.
mov dh,0
inc dx ; Account for "$" in table.
mov si,dx ; Put to index register.
cmp ax,[bx+si] ; Is this the one?
je prtt1
add bx,dx ; Go to end of keyword.
add bx,2 ; Point to next keyword.
dec cl ; Any more keywords to check?
jnz prtt0 ; Yes, go to it.
mov bx,offset prterr
prtt1: mov si,bx
pop cx ; recover column count
jmp stms1 ; copy in message
ret ; and return
VTSTAT endp ; end of Terminal set & status code
; Compute number of iterations needed in procedure pcwait inner loop
; to do one millisecond delay increments. Uses Intel 8253/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
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
mov ax,8 ; wait 8 millisec
call pcwait ; call the software timer
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
add ax,1193/2 ; round up
xor dx,dx ; clear high order divisor
mov cx,1193 ; tics per millisec
div cx ; count / 1193 yields millisecs, quo=ax
push ax ; retain whole number of milliseconds
mov ax,pcwcnt ; get current pcwait inner loop count
mov cl,3
shl ax,cl ; current counter times 8 loops
pop cx ; recover millisec for the 8 loop test
xor dx,dx ; clear high order field for division
div cx ; divide by observed milliseconds
mov pcwcnt,ax ; store quotient as new inner loop counter
pop dx
pop cx
pop ax
ret
pcwtst endp
;; Wait for the # of milliseconds in ax, for non-IBM compatibles.
;; Thanks to Bernie Eiben for this one. Modified to use adjustable
; inner loop counter (pcwcnt, adjusted by proc pcwtst) by [jrd].
pcwait proc near
mov cx,pcwcnt ; inner loop counter for 1 ms (240 @ 4.77 MHz)
pcwai1: sub cx,1 ; inner loop takes 20 clock cycles
jnz pcwai1
dec ax ; outer loop counter
jnz pcwait ; wait another millisecond
ret
pcwait endp
; set the current port.
; 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. COM1 and COM3 are assumed to use IRQ4,
; COM2 and COM4 IRQ3. Global byte flags.comflg is 1,2,3,4 for COM1..4, and
; is 'N' for Network.
; 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.
COMS PROC NEAR
mov dx,offset comptab ; table of legal comms ports
mov bx,0 ; no extra help text
mov ah,cmkey ; parse key word
call comnd
jmp r ; failed
cmp bl,'N' ; Network?
jne coms1 ; ne = no
jmp comsn ; yes, get another item for networks
coms1: mov temp,bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
mov bx,temp ; get port number/letter
mov flags.comflg,bl ; remember port number
COMS2: ; Entry point to select comms port
xor bh,bh ; clear high byte
mov bl,flags.comflg ; get COMx number (1-4)
push bx ; Set UART port addresses
mov ax,bx ; get COMx (1-4)
dec ax ; count ports from zero
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
push bx ; save register
push es
mov ax,40h ; look at RS232_base [bx] in Bios area 40:00h
mov es,ax
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 comsf ; e = yes, no serial port, use Bios.
cmp bx,1 ; doing com1?
jne comsc ; ne = no
cmp ax,02f8h ; is the address really that for COM2?
jne comsc ; ne = no
mov bl,2 ; Yes! Use port 2 values and COM1 name
push ax
mov ah,prstr
mov dx,offset badprt3 ; Give Notice of addressing scramble
int dos
pop ax
comsc: mov modem.mddat,ax ; set base address (also data address) 03f8h
add ax,3 ; 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
test bl,1 ; even or odd numbered com ?
jz comsd ; z = even numbered (com2, com4)
mov modem.mddis,MDMINTC ; com1, com3. mask to disable IRQ4
mov modem.mden,MDMINTO ; mask to enable IRQ4
mov modem.mdmeoi,EOICOM ; end of interrupt for IRQ4 level
mov modem.mdintv,MDMINTV ; IRQ4 interrupt vector (0ch)
jmp short comse ; go finish up
comsd: mov modem.mddis,MDINTC2 ; com2, com4. mask to disable IRQ3
mov modem.mden,MDINTO2 ; mask to enable IRQ3
mov modem.mdmeoi,EOICOM2 ; end of interrupt for IRQ3 level
mov modem.mdintv,MDINTV2 ; IRQ3 interrupt vector
comse: call chkport ; get type of UART support (for Clone)
jnc comsu ; nc = has a real 8250 uart
push ax ; else tell user about Bios pathway
push dx
mov ah,prstr
mov dx,offset biosmsg
int dos
pop dx
pop ax
comsu: clc
ret
comsf: mov dx,offset badprt ; say port is not available
mov ah,prstr
int dos
mov flags.comflg,0 ; bad port, reassign to null port
mov dl,bl ; get port number
add dl,'0'
mov ah,conout ; display it
int dos
mov dx,offset badprt2 ; the rest of the message
mov ah,prstr
int dos
stc ; say error
ret
; Network support
comsn: mov ah,cmfile ; get a word (remote node name)
mov dx,offset nambuf ; work buffer
mov word ptr nambuf,0 ; insert terminator
mov bx,offset nethlp ; help message
call comnd ; get the name
nop
nop
nop
xchg ah,al ; put byte count in al
xor ah,ah ; clear junk
mov temp,ax ; save number of chars entered
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
nop
call serrst ; reset serial port
call chknet ; start network usage
cmp pcnet,0 ; is network alive (non-zero)?
jne comsn4 ; ne = yes
mov ah,prstr
mov dx,offset commsg ; say network port will not be used
int dos
stc
ret ; return failure
comsn4: mov portval,offset portn ; set Network port data structure address
mov flags.comflg,'N' ; Set the comm port flag.
call chkport ; get type of port support
clc ; return success
ret
COMS ENDP
; Test presently selected serial port for having a real 8250 UART.
; Return carry clear and clone = 0 if 8250 present,
; else carry set and clone = 'B' for system Bios or
; carry set and clone = 'N' for network.
; Method is to check UART's Interrupt Identification Register for high
; five bits being zero; IBM does it this way. Assumes port structure
; has been initialized with addresses of UART. 21 Feb 1987 [jrd]
; 29 May 1987 Add double check by reading Line Status Register. [jrd]
chkport proc near
cmp portval,offset portn ; network?
je chkporn ; e = yes
push ax
push dx
cmp flags.comflg,0 ; undefined port?
je chkpor1 ; e = yes, assume Bios clone
mov dx,modem.mdcom ; address of UART line control reg (3FBh/2FBh)
sub dx,1 ; Interupt Identification Register address
in al,dx ; read UART's IIR
test al,0f8h ; are any of high 5 bits set?
jnz chkpor1 ; nz = yes, not an 8250
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
mov clone,0 ; clear clone flag
pop dx
pop ax
clc ; clear carry (say 8250)
ret
chkpor1:pop dx
pop ax
mov clone,'B' ; set clone flag
stc ; set carry (say no 8250)
ret
chkporn:mov clone,'N' ; say running on network Bios.
stc ; set carry (say no 8250)
ret
chkport endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
DOBAUD PROC NEAR
push ax ; save some regs
push bx
push dx
call chkport ; check port for real 8250 UART (clone = 0)
cmp clone,'N' ; Network?
je dobd1 ; e = yes, do nothing here
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 clone,'B' ; running on clone?
jne dobd0a ; ne = no
mov bx,offset clbddat ; use Bios speed parameters for clone
dobd0a: add bx,ax
mov ax,[bx] ; The 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 clone,0 ; running on a real uart?
je dobd2 ; e = the real thing
mov dx,0 ; assume port 1 Clone: find current port
mov dl,flags.comflg ; get coms port (1..4)
or dl,dl ; zero (undefined port)?
jz dobd1 ; z = yes, just exit
dec dl ; count ports as 0..3 for Bios
mov ah,0 ; set serial port
int rs232 ; Bios: set the parameters
jmp dobd1 ; and exit
dobd2: mov temp,ax ; 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 bx
pop ax
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
GETBAUD PROC NEAR
call chkport ; check for real 8250 UART
jnc getbud ; nc = have one
ret ; else have semi-clone, no bios feedback
getbud: push ax ; save some regs
push bx
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 hi order byte.
mov ah,al ; Save here.
dec dx
in al,dx ; Get lo 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.
mov cl,0 ; Keep track of index.
getb0: cmp ax,[bx]
je getb1
inc cl
cmp cl,baudlen ; At the end of the list.
jge getb2
add bx,2
jmp getb0
getb1: mov ch,0
mov bx,portval
mov [bx].baud,cx ; Set baud rate.
jmp getb3
getb2: mov ah,prstr
mov dx,offset erms40
int dos
getb3: pop dx ; restore regs
pop cx
pop bx
pop ax
ret
GETBAUD ENDP
; Get Char from serial port buffer.
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
; Revised 22 May 1986, and again slightly 2 August 1986 by [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 25 April 1987 Add Netbios support, remove test for NUL and DEL. [jrd]
PRTCHR PROC NEAR
call chkxon ; see if we need to xon
cmp clone,'B' ; running on a semi-clone?
je prtch6 ; e = yes
cmp count,0 ; any characters available?
jnz prtch1 ; nz = yes, get one
cmp clone,'N' ; running on network?
jne prtch0 ; ne = no
test xofsnt,usron ; user level xoff sent?
jnz prtch0 ; nz = yes, suppress reading here.
call receive ; do a network receive (asynchronous)
prtch0: mov dx,0 ; return count of zero
jmp rskp ; No data - check console.
prtch1: push si ; save si
cli ; interrupts off, to keep srcpnt & count consistent
mov si,srcpnt ; address of next available slot in buffer
sub si,count ; minus number of unread chars in buffer
cmp si,offset source ; located before start of buf?
jae prtch2 ; ae = no
add si,bufsiz ; else do arithmetic modulo bufsiz
prtch2: mov al,byte ptr [si] ; get a character into al
dec count ; one less unread char now
sti ; interrupts back on now.
pop si
mov dx,count ; return # of chars in buffer
ret
prtch6: ; Semi-clone, use Bios calls
mov dx,0 ; assume port 1 Clone: find current port
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz prtch8 ; z = yes, don't access it.
dec dl ; address ports as 0..3 for Bios
prtch7: mov ah,3 ; check port status
int rs232 ; Clone Bios call
test ah,mdminp ; data ready?
jnz prtch9 ; nz = yes, get one
prtch8: mov dx,0 ; return count of zero
mov count,dx
jmp rskp ; No data
prtch9: mov ah,2 ; receive a char into al
int rs232 ; Clone Bios call
test ah,8ch ; timeout, framing error, parity error?
jnz prtch8 ; nz = error, no char
mov count,1 ; set standard variable too
mov dx,count ; return # of chars in buffer
ret
PRTCHR ENDP
; Network Receive packet routine. Request a net packet with no-wait option.
; Return carry clear if success. If failure, reset serial port (Server mode
; reinits serial port) and return carry set. No entry setup needed.
RECEIVE PROC NEAR ; receive network session pkt
cmp pcnet,1 ; net ready yet?
jbe receiv3 ; be = no, declare a broken session
cmp rposted,1 ; is a request outstanding now?
jae receiv4 ; ae = yes, don't do another
mov rposted,1 ; say posting a receive now
mov rcv.scb_length, length rcvbuf ; 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 ; tests below SHOULD take time.
cmp rcv.scb_err,0 ; success?
je receiv4 ; e = yes
cmp rcv.scb_err,npending ; pending receive?
je receiv4 ; e = yes
push ax ; wait one millisec before retesting
push cx
mov ax,1
call pcwait
pop cx
pop ax
cmp rcv.scb_err,06h ; message incomplete?
je receiv4 ; e = is ok (response posted later)
cmp rcv.scb_err,0 ; success now? (here for latency effects)
je receiv4 ; e = yes
cmp rcv.scb_err,18h ; session ended abnormally?
jbe receiv3 ; e = yes, b = other normal errors
push ax ; save regs around error display
push dx
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
pop dx
pop ax
receiv3: ; Error return
mov pcnet,1 ; session broken
call serrst ; reset serial port
test flags.remflg,dserver ; server mode?
jz receiv4 ; z = no, leave system off
call serini ; reinitialize it
receiv4:clc ; carry clear = success
ret
RECEIVE ENDP
; Network Receive post processing interrupt routine.
; Copy chars from rcvbuf to circular buffer source, act on xon/xoff,
; clear rposted interlock flag. At entry, CS is our code segment,
; es:bx points to scb, netbios stack, interrupts are off.
RPOST PROC FAR ; network receive post interrupt routine
push ds ; transfers chars from net buf rcvbuf to
push ax ; main circular buffer source
push bx
push cx
push dx
push si
mov ax,datas ; reestablish datas segment
mov ds,ax
mov cx,rcv.scb_length ; get returned byte count
jcxz rpost6 ; z = nothing there
mov dh,flowon ; flow control characters, for quick ref
mov dl,flowoff
mov si,offset rcvbuf ; source of text
mov bx,srcpnt ; address of buffer storage slot
cld
rpost1: lodsb ; get byte from rcvbuf to al
or dx,dx ; doing flow control?
jz rpost3 ; 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 rpost2 ; ne = Nope, go on.
mov xofrcv,bufon ; Set the flag saying buffer XOFF received
jmp rpost4 ; and skip this character
rpost2: cmp ah,dh ; acting on Xon?
jne rpost3 ; ne = no, go on.
mov xofrcv,off ; Clear the XOFF received flag.
jmp rpost4 ; and skip this character
rpost3: mov byte ptr [bx],al ; store the new char in buffer "source"
inc bx
cmp bx,offset source + bufsiz ; beyond end of buffer?
jb rpost4 ; b = not past end
mov bx,offset source ; wrap buffer around
rpost4: cmp count,bufsiz ; filled already?
jae rpost5 ; ae = yes
inc count ; no, add a char
rpost5: loop rpost1
mov srcpnt,bx ; update pointer to next free slot
rpost6: mov rposted,0 ; clear interlock flag
pop si
pop dx
pop cx
pop bx
pop ax
pop ds
iret ; return from interrupt
RPOST endp
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 25 April 1987 Add Netbios support [jrd]
; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to
; prevent confusion of flow control logic at top of outchr; used by receiver
; buffer high/low water mark flow control code. [jrd]
OUTCHR PROC NEAR
cmp flowoff,0 ; Are we doing flow control.
je outch2 ; No, just continue.
cmp ah,flowoff ; sending xoff?
jne outch1 ; ne = no
mov xofsnt,usron ; indicate user level xoff being sent
jmp outch1b
outch1: cmp ah,flowon ; user sending xon?
jne outch1b ; ne = no
mov xofsnt,off ; say an xon has been sent (cancels xoff)
outch1b:cmp xofrcv,off ; Are we being held (xoff received)?
je outch2 ; e = no - it's OK to go on.
cmp flags.timflg,0 ; is timer off?
je outch2 ; e = yes, no timeout period
push cx ; save reg
mov cl,trans.rtime ; receive timeout interval
mov ch,0
jcxz outch1c ; z = no timeout wanted.
outch1a:cmp xofrcv,off ; Are we being held (xoff received)?
je outch1c ; e = no - it's OK to go on.
mov al,1 ; else sleep for a second
call sleep
loop outch1a ; and try it again
mov xofrcv,off ; timed out, force it off and fall thru
outch1c:pop cx ; end of flow control section
; OUTCH2 is entry point for sending without flow control
OUTCH2: mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status
outch3: cmp clone,0 ; real uart?
je outch3a ; e = yes
cmp clone,'N' ; network?
je outch8 ; e = yes, using netbios
jmp outch6 ; default for others ('B' clones)
outch3a:push cx ; Save registers
push dx
sub cx,cx
outch3b:mov dx,modem.mdstat ; Get port status.
in al,dx
test al,20H ; Transmitter ready?
jnz outch4 ; 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
pop dx ; exit success
pop cx
jmp rskp
outch5: pop dx ; exit failure
pop cx
ret
; finish up for semi-clones, use Bios calls
outch6: push cx ; Clone: find current port
push dx
mov dx,0 ; 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.
dec dl ; address ports as 0..3 for Bios
push ax ; save output character
mov ah,3 ; get status into ax
int rs232
test ah,20h ; xmtr holding reg empty (xmtr is ready)?
pop ax ; restore char
jnz outch7 ; Yes
jmp $+2 ; use time, prevent overdriving UART
jmp $+2
loop outch6
jmp outch5 ; Timeout, exit failure
outch7: mov al,ah ; Now send it out
mov ah,1 ; send char
int rs232 ; Clone: bios send
pop dx ; exit success
pop cx
jmp rskp
outch8: ; Network sending, buffered and single char
cmp netdbfr,0 ; is network board double buffered?
jne outch8a ; ne = yes, ok to reuse current buffer
cmp sposted,0 ; is net buffer still in use?
je outch8a ; e = no, ready for us now
mov temp,ax ; save char, check on last send
call send ; send current packet (really do timed wait)
jc outch11 ; c = failure, last send timed out
mov ax,temp ; recover char
outch8a:push bx
mov bx,xmtcnt ; count of chars in buffer
mov xmtbuf [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: call send ; network send routine
jc outch11 ; c = error
outch10:jmp rskp ; good exit
outch11:ret ; bad exit
OUTCHR ENDP
; Network Send packet routine. Send xmt scb with no-wait option. Waits
; up to 6 seconds for current Send to complete before emitting new Send.
; Failure to Send resets serial port (Server mode allows reiniting of serial
; port). Returns carry clear for success, carry set for failure.
; Enter with xmtcnt holding length of data in xmtbuf to be sent.
SEND PROC NEAR ; Network. Send session packet
cmp pcnet,1 ; network ready yet?
je send0c ; e = net but no session, fail
ja send0b ; a = net is operational
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
je send4 ; don't send null packets
push bx ; save bx
mov bx,xmtcnt ; buffer length
mov xmt.scb_length,bx ; tell buffer length
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
cmp netdbfr,0 ; is network board double buffered?
je send2 ; e = no, let post say empty buffer
mov xmtcnt,0 ; say buffer is empty, ok to reuse
send2: ; 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
send3: ; Error return
mov pcnet,1 ; say no session
call serrst ; reset serial port
test flags.remflg,dserver ; server mode?
jz send3a ; z = no, leave port off
call serini ; reinitialize it for new session
send3a: stc ; set carry for failure
ret
send4: clc ; clear carry as success flag
ret
SEND ENDP
; Network Send packet completion interrupt routine. At entry CS is our
; code segment, es:bx points to scb, netbios stack, interrupts are off.
SPOST PROC NEAR ; post routine for Send packets
push ds
push ax
mov ax,datas
mov ds,ax
mov sposted,0 ; clear send interlock
cmp netdbfr,0 ; is network double buffered?
jne spost1 ; ne = yes, buffer can be in-use again
mov xmtcnt,0 ; say buffer is now empty
spost1: pop ax
pop ds
iret
SPOST ENDP
; dispatch prebuilt network session scb, enter with bx pointing to scb.
; returns status in al (and ah too). Allows STARLAN Int 2ah for netint.
SESSION PROC NEAR
push es ; save es around call
push ds
pop es ; make es:bx point to scb in datas seg
mov ax,exnbios ; funct 4 execute netbios, for Int 2ah
int netint ; use network interrupt
pop es ; saved registers
ret ; exit with status in ax
SESSION ENDP
; Make a virtual circuit Session, given preset scb's from proc chknet.
; For Server mode, does a Listen to '*', otherwise does a Call to indicated
; remote node. Updates vcid number in scb's. Shows success or fail msg.
; Updates network status byte pcnet to 2 if session is established.
; Does nothing if a session is active upon entry; otherwise, does a network
; hangup first to clear old session material from adapter board. This is
; the second procedure to call in initializing the network for usage.
SETNET PROC NEAR ; Network, make a connection
cmp lsn.scb_err,npending ; 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
push bx
mov lsn.scb_cmd,nlisten+nowait ; do LISTEN command, no wait
mov bx,offset lsn
call session
pop bx
ret
setne2: ; Non-server (Client) mode
push bx ; save reg
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
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 es ; restore regs
pop bx
jmp short setne3 ; finish up
setne2a: ; Regular Netbios Call
mov xmt.scb_cmd,ncall ; CALL, wait for answer
mov bx,offset xmt ; setup scb pointer
call session
pop bx ; restore register
setne3: push dx ; 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 setne3a ; nz = bad connection
jmp short setne4 ; 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
mov dx,offset nbaduc ; say try upper case name
int dos
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
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:pop dx
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 16 chars
saynod2:pop si
pop cx
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,datas ; reestablish datas segment
mov ds,cx
mov es,cx
mov si,offset lsn.scb_rname ; copy remote name to rcv and xmt scbs
mov di,offset rcv.scb_rname
mov cx,8 ; 16 byte field
cld
rep movsw
mov cx,8
mov si,offset lsn.scb_rname ; copy remote name to rcv and xmt scbs
mov di,offset xmt.scb_rname
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 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
push bx
mov bx,offset can
mov can.scb_cmd,ncancel ; set cancel op code
mov can.scb_baddr,offset lsn ; cancel listens
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 pcnet,1 ; say network but no session
nethang1:ret
NETHANGUP ENDP
; Called only when Kermit exits. Name passed to mssker by proc chknet
; in word netdone.
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
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
netclo1: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 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
mov dx,offset naskpmt ; prompt for New or Resume
call prompt
mov dx,offset nettab ; table of answers
mov bx,0 ; help for the question
mov ah,cmkey ; get answer keyword
call comnd
jmp r ; failed
nop
mov rdbuf,bl ; save keyword action value here
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
cmp rdbuf,0 ; New session?
je chkneb ; e = yes
clc
ret ; resume old one
chkneb: jmp chknet1 ; skip presence tests
chknec: ; setup addresses and clear junk in scb's
mov rposted,0 ; clear receive interlock flag
mov sposted,0 ; clear send interlock flag
mov xmtcnt,0 ; say buffer is empty
mov netdbfr,0 ; say net board is not double buffered
mov nsbrk,0 ; assume no BREAK across network
push bx
push es ; Test for Netbios presence, IBM way.
mov ah,35h ; DOS get interrupt vector
mov al,5ch ; the netbios vector
int dos ; returns vector in es:bx
mov ax,es
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
or bx,ax ; is vector present?
pop es
pop bx
jz chknet0 ; z = no, stay with basic 5ch netbios
; AT&T STARLAN board check (0ddh=magic #)
mov ah,0 ; vendor installation check on int 2ah
mov al,0 ; 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
;;safety;; mov netdbfr,1 ; say boards are double buffered
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 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
; net ready to operate
chknet1: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 datas 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
push es ; save es around scan
push ds
pop es ; point es at datas segment
cld
repne scasb ; look for the slash
pop es
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,datas ; 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 datas 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 chknet5 ; e = yes, nothing to add
cmp word ptr [di-2],'k.' ; check lower case too
je chknet5 ; e = yes, nothing to add
mov word ptr [di],'K.' ; append our extension of '.K'
; complete field with spaces
jcxz chknet5 ; z = nothing to add
add di,2 ; step over our new extension
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
chknet6:
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
cmp al,0 ; success?
je chknet7 ; e = 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
mov netdone,offset netclose ; address to close network
push ax
push cx
push dx
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 dx
pop cx
pop ax
clc ; carry clear for success
ret
chknet endp
hexout proc near ; display byte in al as hex value
push ax ; all regs preserved
push cx
push dx
mov cx,2 ; two nibbles
hexout1:push cx ; save counter
mov cl,4 ; high nibble
ror al,cl ; put in low order field
mov dl,al
xchg ch,al ; save al byte in ch
and dl,0fh ; four bits
cmp dl,9 ; too big?
jbe hexout2 ; be = no
add dl,'A'-'9'-1 ; bump up to A-F
hexout2:add dl,'0'
mov ah,conout
int dos
xchg ch,al ; recover data byte
pop cx
loop hexout1 ; do second nibble
mov dl,'H' ; add a final hex ident
int dos
pop ax
pop cx
pop dx
ret
hexout endp
; local routine to see if we have to transmit an xon
chkxon proc near
cmp flowon,0 ; doing flow control?
je chkxo1 ; no, skip all this
test xofsnt,usron ; did user send an xoff?
jnz chkxo1 ; nz = yes, don't contradict it here
test xofsnt,bufon ; have we sent a buffer level xoff?
jz chkxo1 ; z = no, forget it
cmp count,mntrgl ; below (low water mark) trigger?
jae chkxo1 ; no, forget it
mov ah,flowon ; ah gets xon
and xofsnt,off ; remember we've sent the xon.
call outch2 ; send via non-flow controlled entry point
nop
nop
nop ; in case it skips
chkxo1: ret
chkxon endp
; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the
; cycle of clear input buffer, wait 1 second, test if buffer empty then exit
; else repeat cycle. Requires that the port be initialized before hand.
; Ihosts is used by the local send-file routine just after initializing
; the serial port.
; 22 March 1986 [jrd]
; 22 June 1986 Don't send null char if not using flow control. [jrd]
IHOSTS PROC NEAR
push ax ; save the registers
push cx
push dx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; check for null char
jz ihosts1 ; z = null, don't send it.
call outchr ; send it (release Host's output queue)
nop ; outchr can do skip return
nop
nop
ihosts1:call clrbuf ; clear out interrupt buffer
;; mov ax,1 ; sleep for 1 second
;; call sleep ; procedure sleep is in msscom.asm
;; call prtchr ; check for char at port
;; jmp ihosts1 ; have a char in al, repeat wait/read cycle
;; nop ; prtchr does skip return on empty buffer
pop dx ; empty buffer. we are done here.
pop cx
pop ax
ret
IHOSTS ENDP
; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port. 22 March 1986 [jrd]
; 22 June 1986 Don't send null char if not using flow control. [jrd]
IHOSTR PROC NEAR
push ax ; save regs
push cx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; check for null char
jz ihostr1 ; z = null, don't send it
call outchr ; send it (release Host's output queue)
nop ; outchr can do skip return
nop
nop
ihostr1:pop cx
pop ax
ret
IHOSTR ENDP
; Send a break out the current serial port. Returns normally.
; Do both regular and long Break. 6 March 1987 [jrd]
SENDBR PROC NEAR
push cx ; Regular Break entry point
mov cx,275 ; 275 milliseconds in regular Break
call sendbw ; call worker routine to do it
pop cx
clc ; don't exit Connect mode
ret
SENDBL: push cx ; Long Break entry point
mov cx,1800 ; 1.8 second long break
call sendbw ; call worker routine to do it
pop cx
clc ; don't exit Connect mode
ret
; worker - send Break for cx millisec
sendbw: test clone,0ffh ; running on a semi-clone?
jnz sendbw2 ; nz = yes, can't do this via Bios
push ax
push dx
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 dx
pop ax
ret
sendbw2:cmp clone,'N' ; is this a network port?
jne sendbw4 ; 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 datas 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 ; And return.
SENDBR ENDP
; Initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
;
; Revised slightly by Joe R. Doupnik 22 Dec 1985 to prevent interrupts
; being enabled until we're done, to stop interrupts from occurring when
; TX holding buffer becomes empty (a useless interrupt for us), and to
; shorten the time between enabling interrupts and our exit. [jrd]
; Returns normally.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 24 April 1987 Add PCnet support calls [jrd]
; 17 May 1987 Redo for COM3/4 support. [jrd]
SERINI PROC NEAR
call pcwtst ; recalibrate pcwait loop timer
cmp portin,0 ; Did we initialize port already?
je serin0 ; e = no, not yet
ret ; Yes, so just leave
serin0: call chkport ; see if have real 8250 UART
jnc serin2 ; nc = the real thing (else clone != 0)
jmp serin3 ; else use Bios. Finish initialization
serin2: cmp clone,'N' ; Network port?
jne serin2a ; ne = no
jmp serin3 ; yes
serin2a:push bx
push es
in al,21H ; Interrupt controller
mov savirq,al ; save state here for restoration
or al,modem.mddis ; Inhibit IRQ3 or IRQ4.
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 in es:bx
mov word ptr savsci,bx ; save offset address of original vector
mov word ptr savsci+2,es ; and its segment.
mov al,byte ptr modem.mdintv ; interrupt number for IRQ4 or IRQ3
mov dx,offset serint ; offset of our interrupt routine
push ds ; save ds around next DOS call.
mov bx,seg serint ; compose full address of our routine.
mov ds,bx ; segment is the code segment.
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
mov al,rs232 ; interrupt number for Bios serial port
mov ah,35H ; get vector into es:bx
int dos
mov word ptr sav232,bx ; save offset
mov word ptr sav232+2,es ; save segment
mov dx,offset serdum ; offset of our interrupt routine
push ds ; save ds around next DOS call.
mov bx,seg serdum ; compose full address of our routine.
mov ds,bx ; segment is the code segment.
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
pop es
pop bx
mov portin,1 ; Remember port has been initialized.
cli ; Disable interrupts
cld ; Do increments in string operations
mov ax,modem.mdstat
mov mst,ax ; Use this address for status.
mov ax,modem.mddat
mov mdat,ax ; Use this address for data.
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 the serial card Line Control Reg.
mov al,3 ; 8 data bits. DLAB = 0
out dx,al
mov dx,modem.mddat ; data and command port, read and flush any
in al,dx ; char in UART's receive buffer
inc dx ; increment to interrupt enable register 3f9h
mov al,1 ; Set up interrupt enable register
out dx,al ; for Data Available only.
add dx,3 ; increment to modem control register 3fch
mov al,0bh ; assert DTR, RTS, not OUT1, and OUT2
out dx,al ; OUT2 high turns on interrupt driver chip.
sti ; Allow interrupts (AFTER next instr)
serin3: cmp clone,'N' ; Network?
jne serin4 ; ne = no
call setnet ; setup network session and pcnet flag
serin4: push bx
mov bx,portval ; get port
mov parmsk,0ffh ; parity mask, assume parity is None.
cmp [bx].parflg,parnon ; is it None?
je serin1 ; e = yes
mov parmsk,07fh ; no, pass lower 7 bits as data
serin1: mov bx,[bx].flowc ; get flow control chars
mov flowoff,bl ; xoff or null
mov flowon,bh ; xon or null
mov xofrcv,off ; clear xoff received flag
pop bx
mov portin,1 ; say initialized
ret ; We're done
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Moved push/pop es code to do quicker exit before interrupts enabled. [jrd]
; Returns normally.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 17 May 1987 Redo for COM3/4 support [jrd]
SERRST PROC NEAR
cmp portin,0 ; Reset already?
je srst1 ; Yes, just leave.
test clone,0ffh ; running on a non-compatible UART clone?
jnz srst3 ; nz = yes, nothing to do on semi-clones.
cli ; Disable interrupts
in al,21H ; Interrupt controller
or al,modem.mddis ; Inhibit IRQ3 or IRQ4.
out 21H,al
mov dx,modem.mddat ; modem base address 3f8h
add dx,1 ; point at int enable reg 3f9h
mov al,0
out dx,al ; disable interrupts from this source
; clear modem's delta status bits and reassert DTR etc
add dx,3 ; increment to modem control register
mov al,03h ; reassert DTR,RTS,but not OUT1 and not OUT2
out dx,al ; OUT2 low to turn off interrupt drivers
add dx,2 ; increment to modem status register
in al,dx ; clear status register by reading it
mov mdstreg,al ; save here for Show Modem
sti ; replace original IRQ interrupt 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 interrupt controller state
xor al,modem.mddis ; remove our IRQ bit
or al,ah ; set previous state
out 21h,al ; reset IRQ3 or 4 to original state
sti
srst3: mov portin,0 ; Reset flag.
srst1: ret ; All done.
SERRST ENDP
; Dummy Interrupt 14H to defeat DOS interference with serial port when CTTY
; and Kermit use the port simultaneously. If ports differ then chain DOS to
; original Int 14H Bios code. Else return dummy status=ok reports and
; Backspace for Read, ignore char for Write.
; Entered with AH = function request, AL = char to be sent, DX = com port num
; CS is our code segment, DS is DOS's, SS is ours or DOS's, interrupts off.
; 25 June 1987 [jrd]
SERDUM PROC FAR
push ds ; preserve all registers.
push ax
mov ax,seg datas ; get our data segment
mov ds,ax
mov al,flags.comflg ; get port id (COM1 = 1, COM2 = 2)
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,0 ; initialization request?
je serdu3 ; e = yes, return dummy status=ok rpt
cmp ah,1 ; send char in al?
jne serdu2 ; ne = no
mov ah,60h ; yes, set line status=ok in ah
iret
serdu2: cmp ah,2 ; receive char (and wait for it)?
jne serdu3 ; ne = no, return dummy report
mov al,bs ; yes, return ascii BS to DOS
mov ah,0 ; ah = errors (none here)
iret
serdu3: mov ax,60b0h ; dummy status report:xmtr empty, CD,
iret ; DSR, and CTS are on.
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. [jrd]
; Srcpnt holds offset, within buffer Source, where next rcv'd char goes.
; Count is number of chars now in buffer, and oldest char is srcpnt-count
; done modulo size of Source. All pointer management is handled here.
; Control-G char substituted for char(s) lost in overrun condition. [jrd]
; Upgraded to read cause of interrupt from interrupt ident reg (accepts only
; data ready), chain to old interrupt if source is not our device. [jrd]
SERINT PROC FAR
push ax ; save registers
push dx ;
push ds
mov ax,seg datas
mov ds,ax ; address data segment
mov dx,mdat ; modem base address
add dx,2 ; increment to Interrupt Identification Reg
in al,dx ; get interrupt cause
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.
in al,dx ; get interrupt cause
cmp al,4 ; data ready?
jne srintc ; ne = not that cause either, keep looking
jmp srint0a ; go process character
srint0: sti ; else turn on interrupts
jmp retint ; and exit now (common jump point)
srint0a:mov dx,mst ; Asynch status port
in al,dx
mov mdstreg,al ; save modem status register
and al,mdmover ; select overrun bit
mov overrun,al ; save it for later
mov dx,mdat
in al,dx ; read the received character into al
cmp flowoff,0 ; flow control active?
je srint2 ; e = no
mov ah,al ; ah = working copy. Check null, flow cntl.
and ah,parmsk ; strip parity temporarily, if any.
jz srint2 ; if null skip flow control
cmp ah,flowoff ; acting on Xoff?
jne srint1 ; ne = Nope, go on.
mov xofrcv,bufon ; Set the flag saying XOFF received.
jmp srint0 ; and exit
srint1: cmp ah,flowon ; acting on Xon?
jne srint2 ; ne = no, go on.
mov xofrcv,off ; Clear the XOFF received flag.
jmp srint0 ; and exit
srint2: push bx ; save register
mov ah,overrun ; get overrun flag
or ah,ah ; overrun?
jz srint2a ; z = no
mov ah,al ; yes, save present char
mov al,bell ; insert control-G for missing char
srint2a:mov bx,srcpnt ; address of buffer storage slot
mov byte ptr [bx],al ; store the new char in buffer "source"
inc srcpnt ; point to next slot
inc bx
cmp bx,offset source + bufsiz ; beyond end of buffer?
jb srint3 ; b = not past end
mov srcpnt,offset source ; wrap buffer around
srint3: cmp count,bufsiz ; filled already?
jae srint4 ; ae = yes
inc count ; no, add a char
srint4: or ah,ah ; anything in overrun storage?
jz srint4a ; z = no
mov al,ah ; recover any recent char from overrun
xor ah,ah ; clear overrun storage
jmp srint2a ; yes, go store real second char
srint4a:pop bx ; restore reg
sti ; ok to allow interrupts now, not before
cmp count,mntrgh ; past the high trigger point?
jbe retint ; be = no, we're within our limit
test xofsnt,bufon ; Has an XOFF been sent by buffer control?
jnz retint ; nz = Yes.
mov al,flowoff ; get the flow off char (Xoff or null)
or al,al ; don't send nul chars
jz retint ; z = null, nothing to send
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status
push cx ; save reg
xor cx,cx ; loop counter
srint5: mov dx,modem.mdstat ; 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,cmtxt ; allow text, to be able to display help
mov bx,offset rdbuf ; dummy buffer
mov dx,offset hnghlp ; help message
call comnd ; get a confirm
jmp r
cmp clone,'C' ; running on a semi-clone?
je dtrlow1 ; e = yes, can't control modem lines
call serhng ; drop DTR and RTS
mov ah,prstr ; give a nice message
mov dx,offset hngmsg
int dos
jmp rskp
dtrlow1:mov ah,prstr ; For Clones, no UART access.
mov dx,offset nohngmsg ; say can't hangup phone on semi-clones
int dos
jmp rskp
DTRLOW ENDP
; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; 5 April 1987 Add 500 millisec wait with lines low before returning. [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; If network then call nethangup procedure to hangup the session without
; losing local name information.
; Returns normally.
serhng proc near ; clear modem's delta status bits and lower DTR & RTS
cmp clone,'N' ; network?
jne shng1 ; ne = no
cmp pcnet,0 ; network operational?
je shng1 ; e = no
call nethangup ; break the session
ret
shng1: 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
add dx,2 ; increment to modem status register
in al,dx ; Clear Status reg by reading it.
shngx: sti ; Enable interrupts
mov ax,500 ; 500 millisec, for pcwait
call pcwait ; keep lines low for at least 500 millisec
pop dx
pop ax
ret
serhng endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end