home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
mskermit
/
msxv90.asm
< prev
next >
Wrap
Assembly Source File
|
2018-01-01
|
42KB
|
1,444 lines
name msxv90
; File MSXV90.ASM
include mssdef.h
; Copyright (C) 1982,1991, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or
; institution to use, copy, or redistribute this software as long as
; it is not sold for profit and this copyright notice is retained.
; Kermit system dependent module for VICTOR 9000/SIRIUS
; Edit History
; 2 March 1991 version 3.10
; Last edit: 17 Dec 1990 MS-DOS Kermit v3.02 editing. [jrd]
; 12 June 1988 Add error recovery if serial port fails to initialize. [jrd]
; 9 March 1988 Add procedure getmodem and global byte mdmhand for use by
; scripts in sensing modem status. Add: ignore received XOFF if we have sent
; an XOFF already (avoids lockouts from echoes). Add user/buffer xon/xoff
; sensing. [jrd]
; 3 March 1988 Add shomodem routine to show status of DSR, CD, CTS lines
; [bgp]
; 7 Sept 1987 Remove keep_delete, pass null, del chars to terminal section.
; [jrd]
; 29 August 1987 Add capability for sending long break [bgp]
; 9 February 1987 Add flag for ignoring delete chars in SERINT - they must
; be retained when emulating a Tektronix (graphics mode) - this is done
; using global symbol keep_delete.
; 6 November 1986 Fix receiver overrun detection and miscellaneous minor
; fixes
; 30 Sept 1986 Reject DEL char at serial port reception level to avoid
; problems when DEL is used as a filler char (be Emacs). [jrd]
; 16 Sept 1986 Revise serial port routines prtchr, outchr, serini, serint
; to use more efficient code from IBM version. [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]
; Original version, BGP, 23 November 1985
; Add global entry point vtstat for use by Status routine in mssset.
; Cleared terminal emulation flag, flags.vtflg, in procedure lclini.
; Add register save/restore in procedure getbaud.
; Joe R. Doupnik 12 March 1986
; Add some register save/restores here and there.
; Add global procedures ihosts and ihostr to handle host initialization
; when packets are to be sent or received by us,resp. 24 March 1986
; Add global procedure dtrlow to force DTR and RTS low in support of Kermit
; command Hangup. B.G.Peterson 10 April 1986
; Add support of serial port settings through use of IOCTL DOS function
; code from Andreas Stumpf (ZRZS@DS0RUS1I), merged by B.G.Peterson 10 April 86
; Moved VTS and VTSTAT routines to MSYxxx.ASM where the terminal emulation
; is done anyway. B.G.Peterson 10 April 1986
; Last update 28 April 1986
; 30 July 1986 Corrected IHOSTS and IHOSTR to prevent sending null byte if
; no flow control.
; Modified SERHNG so it turns DTR and RTS off for 3 seconds and then back
; on again so a new connection can be made easily.
; Modified SERRST to wait until transmitter is empty before turning off
; port.
; Modified port controller access so that if opening it using the standard
; Victor drivers fails, it will just go direct to the hardware. [bgp]
public serini, serrst, clrbuf, outchr, coms, dodel
public ctlu, cmblnk, locate, lclini, prtchr, dobaud
public clearl, getbaud, beep, puthlp, putmod
public clrmod, poscur, sendbr, showkey, sendbl, pcwait
public xofsnt, machnam, setktab, setkhlp, count
public ihosts, ihostr, dtrlow, comptab, serhng, mdmhand
public shomodem, getmodem, baudst, bdtab, portval
public parmsk, flowon, flowoff, peekcom
FALSE equ 0
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 of buffer full.
DEF_BAUD EQU 8 ; Default to 1200 baud
; constants used by serial port handler
SEG_7201 EQU 0E004H ; Segment for 7201 serial controller
DATAA_7201 EQU 0 ; DATA A offset
STATA_7201 EQU 2 ; STATUS A offset
DATAB_7201 EQU 1 ; DATA B offset
STATB_7201 EQU 3 ; STATUS B offset
; no interrupts, no waits
REG1_7201 EQU 0 ; 7201 Register 1 value
ENABLE_INT EQU 18H ; Mask to turn on interrupts (OR)
; non-DMA, non-vectored interrupts, priority type 1 (Ra>Rb>Ta>Tb)
REG2_7201 EQU 14H ; 7201 Register 2 value
; 8 bits/char, no CRC, receiver enabled
REG3_7201 EQU 0C1H ; 7201 Register 3 value
; clock/16, 1.5 stop bit, no parity
REG4_7201 EQU 48H ; 7201 Register 4 value
; DTR low (active), 8 bits/char, transmitter enabled, RTS low, no CRC
REG5_7201 EQU 0EAH ; 7201 Register 5 value
BREAK_ON EQU 10H ; Mask to turn on break bit (OR)
DTR_RTS_OFF EQU 7DH ; Mask to turn off DTR and RTS (AND)
MDMINP EQU 1 ; Input ready bit. [jrd]
MDMOVER EQU 32 ; Receiver overrun bit. [bgp]
SEG_8253 EQU 0E002H ; Segment for 8253 timer
SETA_8253 EQU 0 ; Speed for port A
SETB_8253 EQU 1 ; Speed for port B
CTRL_8253 EQU 3 ; Control for 8253 timer
SEG_8259 EQU 0E000H ; Segment for 8259 int. controller
CW1_8259 EQU 0 ; Offset for 8259 register 1
CW2_8259 EQU 1 ; Offset for 8259 register 2
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
; not implemented)
; setkhlp - help for setktab.
data segment
extrn flags:byte, trans:byte
setktab db 0
setkhlp db CR,LF,'Set Key not supported on VICTOR/SIRIUS Kermit$'
sh_key_str db 'Set Key not supported on VICTOR/SIRIUS Kermit'
sh_key_len dw 45
machnam db 'VICTOR/SIRIUS$'
clrlin db CR ; clears full line with next line...
clreol db ESCAPE,'K$' ; clears from cursor to end of line
home db ESCAPE,'H$' ; homes cursor
clrscr db ESCAPE,'E$' ; clears screen and homes cursor
delstr db BS,BS,' ',BS,BS,'$' ; Delete string
clr_25 db ESCAPE,'j',ESCAPE,'x1',ESCAPE,'Y8 ',ESCAPE,'l',ESCAPE,'k'
db ESCAPE,'y1$'
;clr_25 does the entire operation of clearing the mode line
start_25 db ESCAPE,'j',ESCAPE,'x1',ESCAPE,'Y8 ',ESCAPE,'p$'
; start_25 enables line 25 and moves to the start in reverse video
end_25 db ESCAPE,'q',ESCAPE,'k',ESCAPE,'y1$'
; end_25 turns off reverse video and line 25 and returns the cursor
mov_pfx db ESCAPE,'Y$' ; prefix for moves
mdminfo struc
mddat dw 0 ; data register
mdiir dw 0 ; interrupt identification register
mdstat dw 0 ; line status register
mdcom dw 0
mden db 0
mddis db 0
mdmeoi db 0
mdintv dw 0
mdminfo ends
modem mdminfo <DATAA_7201,0,STATA_7201,SETA_8253,0FDH,2,61H,104H>
port1 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> ; UART ports
port2 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
portval dw port1 ; Default is to use port 1
savsci dw ? ; Save for serial port interrupt vector.
savscs dw ? ; Ditto.
portin db FALSE ; Has comm port been initialized.
xofsnt db FALSE ; Say if we sent an XOFF.
xofrcv db FALSE ; 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
mdmhand db 0 ; Modem status register, current.
erms20 db CR,LF,'?Warning: System has no disk drives$'
badbd db CR,LF,'Unimplemented baud rate$'
hngmsg db CR,LF,' The phone should have hung up.',CR,LF,'$' ; [jrd]
hnghlp db CR,LF,' The modem control lines DTR and RTS for the current'
db ' port are forced low (off)'
db CR,LF,' to hang up the phone. Normally, Kermit leaves them'
db ' high (on) when it exits.'
db CR,LF,' They will return high after about 3 seconds.'
db CR,LF,'$' ; [jrd]
shmdm0 db CR,LF,' Modem is not ready: DSR is off$'
shmdm1 db CR,LF,' Modem is ready: DSR is on$' ; [bgp]
shmdm2 db CR,LF,' no Carrier Detect: CD is off$'
shmdm3 db CR,LF,' Carrier Detect: CD is on$'
shmdm4 db CR,LF,' no Clear to Send: CTS is off$'
shmdm5 db CR,LF,' Clear to Send: CTS is on$' ; [bgp]
tmp db ?,'$'
temp1 dw ? ; Temporary storage.
ontab db 02H ; Two entries.
mkeyw 'OFF',00H
mkeyw 'ON',01H
comptab db 0AH
mkeyw '1',01H
mkeyw '2',00H
mkeyw 'A',01H
mkeyw 'B',00H
mkeyw 'COM1',01H
mkeyw 'COM2',00H
mkeyw 'SERIALA',01H
mkeyw 'SERIALB',00H
mkeyw 'TTY',01H
mkeyw 'UL1',00H
bdtab db 16 ; Baud rate table
mkeyw '45.5',0
mkeyw '50',1
mkeyw '75',2
mkeyw '110',3
mkeyw '134.5',4
mkeyw '150',5
mkeyw '300',6
mkeyw '600',7
mkeyw '1200',8
mkeyw '1800',9
mkeyw '2000',10
mkeyw '2400',11
mkeyw '4800',12
mkeyw '9600',13
mkeyw '19200',14
mkeyw '38400',15
; This table is indexed by the baud rate definitions given above.
; Unsupported baud rates should contain FF.
; This number is determined by 78125/(baud rate) (decimal values)
bddat label word
dw 6B4H ; 45.5 baud
dw 61AH ; 50 baud
dw 411H ; 75 baud
dw 2C6H ; 110 baud
dw 244H ; 134.5 baud
dw 208H ; 150 baud
dw 104H ; 300 baud
dw 82H ; 600 baud
dw 41H ; 1200 baud
dw 2BH ; 1800 baud
dw 26H ; 2000 baud
dw 20H ; 2400 baud
dw 10H ; 4800 baud
dw 8H ; 9600 baud
dw 4H ; 19200 baud
dw 2H ; 38400 baud
; variables for serial interrupt handler
source db BUFSIZ DUP(?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
; variables for accessing portinfo from serial drivers using IOCTL function
;
; Structure is defined according to "Systems Programmers Toolkit II",
; Appendix A. Structure contains baud rate and values of control registers
; 0 through 7.
pval struc
stype dw 11H ; port access
status dw (?)
blocktype dw 0 ; serial
baudr dw (?) ; baud rate to set or get
CR0 db (?)
CR1 db (?)
CR2A db (?)
CR2B db (?)
CR3 db (?)
CR4 db (?)
CR5 db (?)
CR6 db (?)
CR7 db (?)
pval ends
erms41 db CR,LF,'?Warning: Cannot open com port'
db CR,LF,' Going direct to serial controller hardware...$' ; [bgp]
rdbuf db 20 dup (?) ; input buffer
plength equ 17 ; length of pval structure
oldpval pval <,,,41H,,,,,,,,,> ; default to 1200 baud
newpval pval <,,,41H,,,,,,,,,> ; value comes from bdtab above... [bgp]
prttab dw com2,com1 ; 0=com2, 1=com1 in flags.comflg
com1 db 'SERIALA',0 ; name string for device
com2 db 'SERIALB',0
IOread equ 2 ; read status block
IOwrite equ 3 ; write status block
prthnd dw 0 ; handle for accessing port
data ends
code segment
extrn comnd:near, dopar:near, defkey:near
extrn lclyini:near
assume cs:code,ds:data,es:nothing
; local initialization
LCLINI proc near
mov flags.vtflg,TTHEATH ; BIOS does HEATH, use as default
cmp flags.comflg,1 ; using port 1?
jne lclini2 ; no...
mov portval,offset port1
mov modem.mddat,DATAA_7201 ; set COM1 values
mov modem.mdstat,STATA_7201
mov modem.mdcom,SETA_8253
jmp lclini0
lclini2: ; using port2
mov portval,offset port2
mov modem.mddat,DATAB_7201 ; set COM2 values
mov modem.mdstat,STATB_7201
mov modem.mdcom,SETB_8253
lclini0:call opnprt ; get file handle and init port
call lclyini ; init term part too
ret
LCLINI endp
; procedure to get a file handle for the port. if it fails ask the user
; for some predefined handle (3 is the usual value) (Andreas Stumpf)
; 30 July 1986 If it fails, just warn the user and go direct to the
; hardware [bgp]
OPNPRT proc near
cmp prthnd,0 ; is one open?
jle opnprta ; no...
mov bx,prthnd ; better close this
mov ah,CLOSE2 ; to be sure they don't accumulate
int DOS
mov prthnd,0 ; done...
opnprta:
mov al,flags.comflg
mov ah,0
mov si,ax
shl si,1 ; double index
mov dx,prttab[si]
mov ah,OPEN2
mov al,2
int DOS ; open port on handle
jnc opnprt2
mov ah,PRSTR ; it didn't like the string...
mov dx,offset erms41
int DOS
mov prthnd,-1 ; no port is open! [bgp]
push es ; better save this
mov bx,SEG_7201 ; point at controller
mov es,bx
mov bx,modem.mdstat
mov byte ptr es:[bx],1
mov byte ptr es:[bx],18H ; Software reset of current port
push ax ; kill time for four 2.5 MHz cylces
pop ax ; 8 processor cycles
mov bx,STATA_7201 ; First one is always port A
mov byte ptr es:[bx],2 ; must be first one set
mov byte ptr es:[bx],REG2_7201
mov bx,modem.mdstat
mov byte ptr es:[bx],4 ; must be second
mov byte ptr es:[bx],REG4_7201
mov byte ptr es:[bx],1 ; rest any order
mov byte ptr es:[bx],REG1_7201
mov byte ptr es:[bx],3
mov byte ptr es:[bx],REG3_7201
mov byte ptr es:[bx],5
mov byte ptr es:[bx],REG5_7201
pop es
call getbaud ; use this to be sure right value is used
call dobaud ; better set baud rate to the correct value too
jmp opnprt2a ; all init done... [bgp]
opnprt2:
mov prthnd,ax ; call succeeded - save handle
mov bx,ax
mov ah,IOCTL
mov al,IOread ; get old values
mov cx,plength
mov dx,offset oldpval ; place for old values
int DOS
mov ah,IOCTL
mov al,IOread
mov dx,offset newpval ; one to work on
int DOS
; set registers to something neat
cli ; avoid interrupts here
mov bx,offset newpval
mov [bx].CR1,REG1_7201
mov [bx].CR2A,REG2_7201
mov [bx].CR3,REG3_7201
mov [bx].CR4,REG4_7201
mov [bx].CR5,REG5_7201
mov bx,prthnd ; get handle
mov ah,IOCTL
mov al,IOwrite ; set new values
int DOS
opnprt2a:
push es ; save this for a flash
mov bx,SEG_7201
mov es,bx
mov bx,modem.mdstat
mov byte ptr es:[bx],10H ; clear external/status interrupts
mov byte ptr es:[bx],30H ; clear special receive cond. int.
mov byte ptr es:[bx],38H ; set to end of interupt
pop es ; back again
sti ; interrupts are okay again
ret
OPNPRT endp
; Show the definition of a key. Since it isn't really necessary to redefine
; keys for the VICTOR/SIRIUS (assuming that KEYGEN is available), this isn't
; implemented, and the string returned to the calling sequence merely says so.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
SHOWKEY proc near
mov ax,offset sh_key_str
mov cx,sh_key_len
ret
SHOWKEY 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 ax,offset source
mov srcpnt,ax
mov count,0
sti
ret
CLRBUF endp
; Clear to the end of the current line. Returns normally.
CLEARL proc near
mov dx,offset clreol
mov ah,PRSTR
int DOS
ret
CLEARL endp
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Skip returns on success, returns ret if the
; character cannot be written.
; 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 ch,trans.rtime ; receive timeout interval (sec)
mov cl,0 ; convert to 4 millsec increments
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.
push ax
mov ax,4 ; 4 millisec wait loop
call pcwait
pop ax
loop outch1a ; and try it again
mov xofrcv,off ; timed out, force it off 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
push bx
push cx
push es
xor cx,cx
mov bx,SEG_7201 ; point at 7201
mov es,bx
mov bx,modem.mdstat
outch3:
mov al,es:[bx]
test al,4 ; ready?
jnz outch4 ; yes
loop outch3
jmp outch5 ; Timeout
outch4:
mov al,ah ; Now send it out
mov bx,modem.mddat
mov es:[bx],al
pop es
pop cx
pop bx
ret
outch5:
pop es
pop cx
pop bx
ret
OUTCHR endp
; This routine blanks the screen. Returns normally.
CMBLNK proc near
mov dx,offset clrscr
mov ah,PRSTR
int DOS
ret
CMBLNK endp
; Locate: homes the cursor. Returns normally.
LOCATE proc near
mov dx,offset home
mov ah,PRSTR
int DOS
ret
LOCATE endp
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a dollar sign. Returns normally.
PUTMOD proc near
push si ; better save this
push dx ; preserve message
mov dx,offset start_25 ; to set up for write to 25
mov ah,PRSTR
int DOS
mov ah,DCONIO ; output a char at a time
pop si ; get back message
cld ; better increment
putmod1:
lodsb ; get byte
cmp al,'$' ; is it end of string?
je putmod2
mov dl,al
int DOS
jmp putmod1
putmod2:
mov dx,offset end_25 ; back to normal
mov ah,PRSTR
int DOS
pop si ; and restore it
ret
PUTMOD endp
; clear the mode line written by putmod. Returns normally.
CLRMOD proc near
mov dx,offset clr_25 ; to clear line 25
mov ah,PRSTR
int DOS
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 si
mov si,ax
mov ah,DCONIO ; don't check anything...
cld ; better increment on strings
puthlp1:
lodsb ; get byte
cmp al,0 ; is it null (null-terminated string)
je puthlp2
mov dl,al
int DOS
jmp puthlp1
puthlp2:
mov dl,13 ; want a crlf
int DOS
mov dl,10
int DOS
pop si
ret
PUTHLP endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns carry clear.
BAUDST PROC NEAR
mov dx,offset bdtab ; baud rate table, ascii
xor bx,bx ; help is the table itself
mov ah,cmkey ; get keyword
call comnd
jc baudst1 ; c = failure
push bx ; save result
mov ah,cmeol ; get confirmation
call comnd
pop bx
jc baudst1 ; c = failure
mov si,portval
mov ax,[si].baud ; remember original value
mov [si].baud,bx ; set the baud rate
call dobaud ; use common code
clc
baudst1:ret
BAUDST ENDP
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally. Method of setting using
; IOCTL thanks to Andreas Stumpf
DOBAUD proc near
push ax ; these too [jrd]
push bx
push cx
push dx
mov bx,portval
mov bx,[bx].baud
cmp bx,0
jl unk_baud ; out of range
cmp bl,bdtab ; number of table entries
jge unk_baud ; out of range
shl bx,1 ; get index into table
mov ax,offset bddat ; start of table
add bx,ax
mov ax,[bx] ; get divider
cmp ax,0FFH ; unimplemented baud rate?
je unk_baud ; that's right
mov bx,offset newpval
mov [bx].baudr,ax ; set it in structure no matter what [bgp]
cmp prthnd,0 ; anything open?
jge dobaud0 ; yes, do it nice
push es ; better save this...
push ax ; save divider
mov bx,SEG_8253 ; point at timer
mov es,bx
mov bx,CTRL_8253 ; set up function first
mov ax,modem.mdcom ; set up control byte
ror al,1 ; need port number in high bits
ror al,1
and al,0C0H ; keep only top 2 bits
add al,36H ; set both, Mode 3, binary
mov es:[bx],al
mov bx,modem.mdcom ; Where to write the rate
pop ax ; get divider back
mov es:[bx],al
mov es:[bx],ah ; done
pop es
jmp dobaud1
dobaud0: ; [bgp]
mov ah,IOCTL
mov al,IOwrite
mov bx,prthnd ; set the poor thing
mov cx,plength
mov dx,offset newpval
int DOS
dobaud1:
pop dx
pop cx
pop bx
pop ax
ret
unk_baud:
mov ah,PRSTR
mov dx,offset badbd ; Give an error message.
int DOS
pop dx ; restore regs [jrd]
pop cx
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. The method of getting the baud
; rate directly from the port handler is thanks to Andreas Stumpf.
; Note that this assumes that the thing has a defined baud rate to
; start with from the initialization and the opnprt has been called on
; the current port so that the values in newpval are defined.
GETBAUD proc near
push ax
push bx
push cx
push dx
cmp prthnd,0 ; opened?
jne go_gb ; yes, get the rate
call opnprt ; no, open it
go_gb:
mov bx,offset newpval
mov ax,[bx].baudr
xor ch,ch
mov cl,bdtab ; entries in baudtable
mov bx,offset bddat-2
add bx,cx
add bx,cx
loop_gb:
cmp ax,[bx]
je have_gb
dec bx
dec bx
dec cx
jnz loop_gb
have_gb:
dec cx ; value is one greater than desired
mov bx,portval ; cx=-1 means unrecognized (dropped off bottom)
mov [bx].baud,cx
pop dx
pop cx
pop bx
pop ax
ret
GETBAUD endp
; 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]
; Direct copy from msxibm.asm [jrd]
PRTCHR proc near
call chkxon ; see if we need to xon
cmp count,0 ; any characters available?
jnz prtch1 ; nz = yes, get one
xor dx,dx ; return count of zero
stc
ret ; No data
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 buffer (wrapped)?
jae prtch2 ; ae = no
add si,BUFSIZ ; else do arithmetic module bufsiz
prtch2:
mov al,byte ptr [si] ; get a character into si
dec count ; one less unread char now
sti ; interrupts back on now.
pop si
mov dx,count ; return # of chars in bufer
clc
ret
PRTCHR endp
; Examine incoming communications stream for a packet SOP character.
; Return CX= count of bytes starting at the SOP character (includes SOP)
; and carry clear. Return CX = 0 and carry set if SOP is not present.
; Destroys AL.
peekcom proc far
mov cx,count ; qty in circular buffer
cmp cx,6 ; basic NAK
jb peekc4 ; b = two few chars, get more
push bx
cli ; interrupts off, to keep srcpnt & count consistent
mov bx,srcpnt ; address of next available slot in buffer
sub bx,cx ; minus number of unread chars in buffer
cmp bx,offset source ; located before start of buf?
jae peekc1 ; ae = no
add bx,bufsiz ; else do arithmetic modulo bufsiz
peekc1: mov al,[bx]
cmp al,trans.rsoh ; packet receive SOP?
je peekc3 ; e = yes
inc bx
cmp bx,offset source+bufsiz ; beyond end of buffer?
jb peekc2 ; b = no
mov bx,offset source ; wrap around
peekc2: loop peekc1 ; keep looking
sti
pop bx
stc ; set carry for no SOP
ret
peekc3: sti ; interrupts back on now
pop bx
inc cx ; include SOP in count
clc ; say SOP found
ret ; CX has count remaining
peekc4: xor cx,cx ; return count of zero
stc ; say no data
ret
peekcom endp
; local routine to see if we have to transmit an xon
chkxon proc near
cmp flowon,0 ; doing flow control?
je chkxo1 ; no, skip all this
test xofsnt,usron ; did user send an xoff?
jnz chkxo1 ; nz = yes, don't contradict it here
test xofsnt,bufon ; have we sent a buffer level xoff?
jz chkxo1 ; z = no, forget it
cmp count,mntrgl ; below (low water mark) trigger?
jae chkxo1 ; no, forget it
mov ah,flowon ; ah gets xon
and xofsnt,off ; remember we've sent the xon.
call outch2 ; send via non-flow controlled entry point
chkxo1: ret
chkxon endp
; IHOSTS - Initialize the host by sending 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]
; 30 July 1986 Avoid sending nulls if no flow control [bgp]
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)
ihosts1:call clrbuf ; clear out interrupt buffer
pop dx ; empty buffer. we are done here.
pop cx
pop ax
ret
IHOSTS endp
; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port. 22 March 1986 [jrd]
; 30 July 1986 Avoid sending null if no flow control [bgp]
IHOSTR proc near
push ax ; save reg
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)
ihostr1:pop ax
ret
IHOSTR endp
; Global proc to hang up the phone by making DTR and RTS low.
DTRLOW proc near
mov ah,cmline ; allow text to be able to display help
mov bx,offset rdbuf ; dummy buffer
mov dx,offset hnghlp ; help message
call comnd ; get a confirm
jnc dtrlow1 ; nc = success
ret ; carry set = failure
dtrlow1:call serhng ; drop DTR and RTS
mov ah,PRSTR ; give a nice message
mov dx,offset hngmsg
int dos
clc
ret
DTRLOW endp
; SERHNG us used to hang up the phone. This resets the port (by calling
; serrst), and then forces DTR and RTS low to terminate the connection.
; 12 April 1986 [bgp]
; 30 July 1986 Turn them back on again after 3 seconds so new connection can
; be made [bgp]
SERHNG proc near
call serrst ; reset the port to be sure
push dx
push cx
push bx
push ax
cmp prthnd,0 ; nice method open? [bgp]
jge serhng0 ; yes
push es ; better save this
mov bx,SEG_7201 ; point at controller
mov es,bx
mov bx,modem.mdstat
cli ; no interrupts please
mov byte ptr es:[bx],5 ; register 5
mov byte ptr es:[bx],REG5_7201 and DTR_RTS_OFF
sti ; interrupts ok again
mov ax,3000 ; sleep for 3 seconds
call pcwait
mov bx,SEG_7201
mov es,bx
mov bx,modem.mdstat
cli ; no interrupts please
mov byte ptr es:[bx],5
mov byte ptr es:[bx],REG5_7201
sti ; interrupts ok again
pop es
jmp short serhng1 ; [bgp]
serhng0:
mov bx,offset newpval
mov [bx].CR5,REG5_7201 and DTR_RTS_OFF
mov dx,bx ; where the stuff is
mov cx,plength ; how long it is
mov bx,prthnd ; get handle
mov ah,IOCTL
mov al,IOwrite ; set new values
int DOS
mov ax,3000 ; sleep for 3 seconds
call pcwait
mov bx,offset newpval ; turn them back on again...
mov [bx].CR5,REG5_7201
mov dx,bx
mov cx,plength
mov bx,prthnd
mov ah,IOCTL
mov al,IOwrite
int DOS
serhng1:
pop ax
pop bx
pop cx
pop dx
ret
SERHNG endp
; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses global byte mdmhand, the modem line status register. [jrd]
SHOMODEM proc near
mov ah,cmeol
call comnd
jc shomodem4 ; c = failure
mov dx,offset shmdm0 ; assume DSR is not set
test mdmhand,20h ; is bit set?
jnz shomodem1 ; z = no
mov dx,offset shmdm1 ; DSR is asserted (line active)
shomodem1:
mov ah,PRSTR
int DOS
test mdmhand,80h ; test for CD
jz shomodem2 ; z = off
mov dx,offset shmdm3 ; actually have CD
shomodem2:
int DOS
mov dx,offset shmdm4 ; assume no CTS
test mdmhand,10H ; test for CTS
jz shomodem3
mov dx,offset shmdm5 ; actually have CTS
shomodem3:
int DOS
clc
shomodem4:ret
SHOMODEM endp
; Get modem status and set global byte mdmhand. Preserve all registers.
; Check the status of the return control lines from the serial port.
; Since this function doesn't care if the port has been properly
; initialized or anything else we will always go directly to the
; hardware. This is actually quite reasonable since the values
; returned in IOCTL from earlier will have no relation to the current
; state of reality. [bgp]
; Note that the method of getting DSR is a little weird. There are
; no connections on the 7201 for DSR so we have to get it from one
; of the 6522s where there are a few free lines (specifically, the
; one that controls the keyboard interface and the CRT brightness/
; contrast. This one is at E8040-E804F with line PA3 for DSRA and
; PA5 for DSRB. Note that a zero is registered for an active line
; on the DSR sense.
getmodem proc near ; gets modem status upon request
mov mdmhand,0 ; assume nothing is on
push bx
push es ; better save these
mov bx,0E804H ; segment of 6522
mov es,bx
mov bl,8 ; assume looking at port A
cmp flags.comflg,1
je getmod1 ; e = it is A
mov bl,20H ; actually looking at B
getmod1:test es:[1],bl ; is DSR bit set?
jnz getmod2 ; nz = no
or mdmhand,20h ; DSR is asserted (line active)
getmod2:mov bx,SEG_7201 ; point at 7201
mov es,bx
mov bx,modem.mdstat
test byte ptr es:[bx],8 ; test for CD
jz getmod3 ; z = off
or mdmhand,80h ; actually have CD
getmod3:test byte ptr es:[bx],20H ; test for CTS
jz getmodx ; z = off
or mdmhand,10h ; actually have CTS
getmodx:pop es
pop bx
getmodem endp
; Send a break out the current serial port. Returns normally.
; Changed to use IOCTL function 12 April 1986 [bgp]
; 30 July 1986 Direct to hardware if not opened right [bgp]
SENDBR proc near
push es
push dx
push cx
push bx
push ax
mov ax,250 ; break length in msec
push ax ; for later use
jmp sendbrz
sendbl:
push es
push dx
push cx
push bx
push ax
mov ax,3500 ; break length in msec
push ax ; for later use
sendbrz:
cmp prthnd,0 ; open ok? [bgp]
jge sendbr0 ; yes, do it nice
mov bx,SEG_7201 ; point at 7201
mov es,bx
mov bx,modem.mdstat
cli ; no interrupts please
mov byte ptr es:[bx],1 ; register 1
mov byte ptr es:[bx],REG1_7201
mov byte ptr es:[bx],5
mov byte ptr es:[bx],REG5_7201 or BREAK_ON
sti ; interrupts ok again
pop ax
call wait_msec
cli ; no interrupts
mov byte ptr es:[bx],5
mov byte ptr es:[bx],REG5_7201
mov byte ptr es:[bx],1
mov byte ptr es:[bx],REG1_7201 or ENABLE_INT
sti ; interrupts ok again
jmp sendbr1 ; [bgp]
sendbr0:
mov bx,offset newpval
mov [bx].CR1,REG1_7201 ; to disable interrupts
mov [bx].CR5,REG5_7201 or BREAK_ON
mov dx,bx ; where the stuff is
mov cx,plength ; how much there is
mov bx,prthnd ; get handle
mov ah,IOCTL
mov al,IOwrite ; set new values
cli ; avoid interrupts here
int DOS
mov bx,SEG_7201 ; have to explicitly do register 1
mov es,bx ; IOCTL doesn't seem to touch it
mov bx,modem.mdstat
mov byte ptr es:[bx],1 ; Register 1
mov byte ptr es:[bx],REG1_7201
sti ; interrupts back on
pop ax
call wait_msec ; kill time
mov bx,offset newpval
mov [bx].CR5,REG5_7201
mov bx,prthnd
mov ah,IOCTL
mov al,IOwrite
cli ; no interrupts please
int DOS
mov bx,SEG_7201 ; Point at 7201 serial controller
mov es,bx
mov bx,modem.mdstat
mov byte ptr es:[bx],1 ; Register 1 must be done explicitly
mov byte ptr es:[bx],REG1_7201 or ENABLE_INT
sti ; interrupts are okay again
sendbr1:
pop ax
pop bx
pop cx
pop dx
pop es
clc ; need to stay connected
ret ; And return.
SENDBR endp
; Wait for the # of milliseconds in ax. The delay is set for a 5 MHz
; clock rate. Actual delay for ax=1 is 1.007 msec, plus 1.005 msec
; for each increment in ax.
WAIT_MSEC proc near
pcwait: ; entry point for the outside world...
push cx ; 10 cycles
mov cx,ax ; 2 cycles
wait_msec1:
push cx ; 10 cycles
mov cx,294 ; 4 cycles
wait_msec2:
loop wait_msec2 ; 5+17*(CX-1) cycles
pop cx ; 8 cycles
loop wait_msec1 ; 17 cycles if jump, 5 cycles if no jump
pop cx ; 8 cycles
ret
WAIT_MSEC endp
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR proc near
push ax
push dx ; save this
mov dx,offset mov_pfx ; move prefix string
mov ah,PRSTR
int DOS
pop dx
push dx
mov dl,dh
add dl,' ' ; this is the row
mov ah,DCONIO ; no checking please
int DOS
pop dx
push dx
add dl,' ' ; this is the column
int DOS
pop dx
pop ax
ret
POSCUR endp
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL proc near
mov dx,offset delstr ; Erase character.
mov ah,PRSTR
int DOS
ret
DODEL endp
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU proc near
mov dx,offset clrlin
mov ah,PRSTR
int DOS
ret
CTLU endp
; set the current port.
COMS proc near
mov dx,offset comptab
mov bx,0
mov ah,CMKEY
call comnd
jnc coms1 ; nc = success
ret
coms1: push bx
mov ah,cmeol
call comnd ; Get a confirm
pop bx
jnc coms2
ret
coms2: call serrst ; reset current port
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
mov modem.mddat,DATAA_7201 ; Set COM1 defaults.
mov modem.mdstat,STATA_7201
mov modem.mdcom,SETA_8253
call opnprt ; open the handle
ret
coms0:
mov ax,offset port2
mov portval,ax
mov modem.mddat,DATAB_7201 ; Set COM2 defaults.
mov modem.mdstat,STATB_7201
mov modem.mdcom,SETB_8253
call opnprt
ret
COMS 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.
; Returns normally. Modified to IOCTL function 12 April 1986 [bgp]
SERINI proc near
push es
push dx
push cx
push bx
push ax
cmp portin,FALSE ; Did we initialize port already?
je serin0
jmp serin2 ; Yes, just leave
serin0:
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov bx,modem.mdintv
mov ax,es:[bx]
mov savsci,ax
mov ax,offset serint ; Point at our routine
mov es:[bx],ax
add bx,2 ; Now for CS value
mov ax,es:[bx]
mov savscs,ax
mov es:[bx],cs
mov portin,1 ; Note that we are initialized
mov ax,offset source
mov srcpnt,ax
mov count,0
mov ax,SEG_8259 ; Point at 8259 interrupt controller
mov es,ax
mov bx,CW2_8259 ; Control word 2
mov al,es:[bx]
and al,modem.mden ; Enable INT1 (all from 7201)
mov es:[bx],al ; Save it
mov bx,CW1_8259 ; Control word 1
mov al,modem.mdmeoi ; Clear any outstanding requests
mov es:[bx],al
; Note that access to the serial controller here is only to register 1 which
; must be done explicitly anyway, so there is no reason to care about
; whether a port is open [bgp]
mov bx,SEG_7201 ; Point at 7201 serial controller
mov es,bx
mov bx,modem.mdstat
mov byte ptr es:[bx],1 ; Register 1 must be done explicitly
mov byte ptr es:[bx],REG1_7201 or ENABLE_INT
mov byte ptr es:[bx],10H ; Clear external/status interrupts
mov byte ptr es:[bx],30H ; Clear special receive cond. int.
mov byte ptr es:[bx],38H ; Set to end of interrupt
sti ; Allow interrupts
mov bx,portval ; get port [jrd]
mov parmsk,0FFH ; parity mask, assume parity is None. [jrd]
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
serin2: pop ax
pop bx
pop cx
pop dx
pop es
clc ; carry clear for success
ret
SERINI endp
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally. Modified to use IOCTL function 12 April 1986 [bgp]
; 30 July 1986 Make it go direct to hardware if handle open failed [bgp]
; Also, don't reset the port until the transmit buffer is empty
SERRST proc near
push es ; preserve this
push dx
push cx
push bx
push ax
cmp portin,FALSE ; Reset already?
je srst0 ; Yes, just leave.
mov bx,SEG_7201 ; point at 7201 [bgp]
mov es,bx
mov bx,modem.mdstat
sersta:
cli
mov byte ptr es:[bx],1 ; want status register 1
mov al,es:[bx] ; get status
sti
test al,1 ; all sent? (transmitter and shift reg. empty)
jz sersta ; no, wait...
cli ; Disable interrupts
mov bx,SEG_8259 ; Point at 8259 interrupt controller
mov es,bx
mov bx,CW2_8259
mov al,es:[bx]
or al,modem.mddis ; Turn off INT1
mov es:[bx],al
xor bx,bx ; Address low memory
mov es,bx
mov bx,modem.mdintv ; Restore the serial card int vector
mov ax,savsci
mov es:[bx],ax
add bx,2 ; Restore CS too.
mov ax,savscs
mov es:[bx],ax
; As in SERINI, the only access to the serial controller is to register 1
; which must be done explicitly anyway, so we don't care about the handle [bgp]
mov bx,SEG_7201 ; Point at 7201 serial controller
mov es,bx
mov bx,modem.mdstat
mov byte ptr es:[bx],1 ; Register 1 has to be done explicitly
mov byte ptr es:[bx],REG1_7201
mov portin,FALSE ; Reset flag.
sti
srst0:
pop ax
pop bx
pop cx
pop dx
pop es ; All done.
ret ; All done.
SERRST 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]
; Adapted from msxibm.asm code. [jrd]
; Fixed test for receiver overrun. [bgp]
SERINT proc near
push ax ; [jrd]
push ds ; do ds and ax first [jrd]
push es
push bx
push dx
mov ax,seg data
mov ds,ax ; address data segment
mov bx,SEG_7201 ; point at 7201
mov es,bx
mov bx,modem.mdstat
mov al,es:[bx] ; get status (register 0)
mov byte ptr es:[bx],1 ; want status register 1 [bgp]
mov ah,es:[bx] ; get status [bgp]
mov bx,STATA_7201 ; this one is always channel A
mov byte ptr es:[bx],38H ; Notify 7201 of end of interrupt
mov bx,SEG_8259 ; point at 8259
mov es,bx
mov bx,CW1_8259
mov dl,modem.mdmeoi
mov es:[bx],dl ; Clear interrupt
test al,MDMINP ; anything there (status register 0)?
jnz srint0 ; nz = yes
jmp retint ; and exit now (common jump point)
srint0:
mov bx,SEG_7201
mov es,bx
and ah,MDMOVER ; select overrun bit (status register 1)[jrd]
mov overrun,ah ; save it for later [jrd]
jz srint0a ; no overrun
mov bx,modem.mdstat
mov byte ptr es:[bx],30H ; Clear overrun error status
srint0a:
mov bx,modem.mddat
mov al,es:[bx] ; get data byte
cmp flowoff,0 ; flow control active?
je srint4 ; e = no
mov ah,al ; ah = working copy. Check flow cntl.
and ah,parmsk ; strip parity temporarily, if any. [jrd]
cmp ah,flowoff ; acting on Xoff?
jne srint3 ; ne = Nope, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF? [jrd]
jne srint1 ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; Set the flag saying XOFF received
srint1: jmp retint ; and exit
srint3:
cmp ah,flowon ; acting on Xon?
jne srint4 ; ne = Nope, go on
mov xofrcv,off ; Clear the XOFF received flag.
jmp retint ; and exit
srint4:
mov ah,overrun ; get overrun flag [jrd]
or ah,ah ; overrun?
jz srint5 ; z = no
mov ah,al ; yes, save present char
mov al,BELL ; insert control-G for missing character
srint5:
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 srint6 ; b = not past end
mov srcpnt,offset source ; wrap buffer arount
srint6:
cmp count,BUFSIZ ; filled already?
jae srint7 ; ae = yes
inc count ; no, add a char
srint7:
or ah,ah ; anything in overrun storage?
jz srint8 ; z = no
mov al,ah ; recover any recent char from overrun
xor ah,ah ; clear overrun storage
jmp srint5 ; yes, go store real second char
srint8:
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 null 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 [jrd]
xor cx,cx ; loop counter [jrd]
mov bx,SEG_7201 ; point at 7201
mov es,bx
mov bx,modem.mdstat
srint9:
mov al,es:[bx]
test al,4 ; ready?
jnz srint10 ; yes
loop srint9
jmp srint11 ; Timeout
srint10:
mov al,ah ; now send it out
mov bx,modem.mddat
mov es:[bx],al
mov xofsnt,bufon ; Remember we sent an XOFF at buffer level
srint11:
pop cx ; [jrd]
retint:
sti ; be sure that this made it on
pop dx
pop bx
pop es
pop ds
pop ax ; [jrd]
iret
SERINT endp
; Produce a beep. Returns normally.
BEEP proc near
mov dl,BELL
mov ah,DCONIO ; No checks, just do it
int DOS
ret
BEEP endp
CODE ends
end