MS-DOS Kermit sources (Part 5 of 7)
Jim Knutson
knutson at ut-ngp.UUCP
Sat Oct 6 02:08:34 AEST 1984
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting msxhp150.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxhp150.asm
public serini, serrst, clrbuf, outchr, coms, vts, dodel, ctlu
public cmblnk, locate, prtchr, dobaud, clearl, lclini
public dodisk, getbaud, beep, setkhlp, setktab
public machnam, xofsnt, count, term, poscur
public clrmod, putmod, puthlp, sendbr, showkey
include msdefs.h
false equ 0
true equ 1
wrdev equ 40H
rddev equ 3fH
open equ 3dH
close equ 3eH
rdchan equ 2
e_send_break equ 6
e_ioctl equ 44h ; MSODS io control fct
datas segment public 'datas'
extrn drives:byte, flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'HP-150$'
erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40 db cr,lf,'?Warning: Unrecognized baud rate$'
erms41 db cr,lf,'?Warning: Cannot open com port$'
noimp db cr,lf,'Command not implemented.$'
setktab db 0
setkhlp db 0
shkmsg db 'Not implemented.'
shklen equ $-shkmsg
crlf db cr,lf,'$'
comphlp db cr,lf,'1 (COM1) 2 (COM2)$' ; [19b]
delstr db BS,BS,' ',BS,BS,'$' ; Delete string. [21d]
clrlin db cr,esc,'K$'
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
invseq db esc,'&dB$' ; Reverse video.
nrmseq db esc,'&d@$' ; Normal mode.
ivlseq db 80 dup (' '),cr,'$' ; Make a line inverse video
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
; Entries for choosing communications port. [19b]
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
; variables for serial interrupt handler
source db bufsiz DUP(?) ; Buffer for data from port.
bufout dw 0 ; buffer removal ptr
count dw 0 ; Number of chars in int buffer.
bufin dw 0 ; buffer insertion ptr
telflg db 0 ; Are we acting as a terminal. [16] [17c]
clreol db esc,'K$'
prttab dw com2,com1
com1 db 'COM1',0
com2 db 'COM2',0
blank db esc,'H',esc,'J$'
movcur db esc,'&a'
colno db 20 dup (?)
ten db 10
prthnd dw 0
tempbuf dw 10 dup(?)
ourarg termarg <>
datas ends
code segment public
extrn comnd:near, dopar:near, prserr:near
assume cs:code,ds:datas
; See how many disk drives we have.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; Clear the input buffer before sending a packet. [20e]
CLRBUF PROC NEAR
cli
mov ax,offset source
mov bufin,ax
mov bufout,ax
mov count,0
sti
clrb1: call prtchr ; get a character
jmp clrb1 ; until there aren't any more
nop
ret
CLRBUF ENDP
; Common routine to clear to end-of-line. [19a]
CLEARL PROC NEAR
mov dx,offset clreol
mov ah,prstr
int dos
ret
CLEARL ENDP
dobaud proc near
jmp notimp
dobaud endp
; Send the break signal out data comm.
sendbr: mov al,e_send_break
jmp dc_ioctl
; Set some data comm ioctl option. AL has function code.
dc_ioctl proc near
mov ah,8h
mov tempbuf,ax
mov dx,offset tempbuf
mov ah,e_ioctl
mov al,3
mov bx,prthnd
mov cx,2
int 21h
ret
dc_ioctl endp
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
push cx
push bx
cmp prthnd,0 ; do we have a port handle?
jne outch3 ; yes, go on
push ax
call opnprt ; open the port
pop ax
outch3: mov byte ptr temp,ah ; save character
mov bx,prthnd
mov ah,wrdev
mov cx,1
mov dx,offset temp
int dos
pop bx
pop cx
pop dx
jmp rskp
opnprt: mov al,flags.comflg
mov ah,0
mov si,ax
shl si,1 ; double index
mov dx,prttab[si]
mov ah,open
mov al,2
int dos
jnc opnpr1
mov ah,prstr
mov dx,offset erms41
int dos
ret
opnpr1: mov prthnd,ax
ret
; This routine blanks the screen.
CMBLNK PROC NEAR ; This is stolen from the IBM example.
mov ah,prstr
mov dx,offset blank
int dos
ret
CMBLNK ENDP
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur ; callret...
LOCATE ENDP
GETBAUD PROC NEAR
ret
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
push bx
push cx
push si
push bp
cmp count,0 ; no characters?
jne prtch2 ; no, go fill buffer
cmp prthnd,0 ; have a handle yet?
jne prtch1 ; yes, keep going
call opnprt
prtch1: mov bx,prthnd
mov al,rdchan
mov ah,ioctl
mov dx,offset source ; buffer to read into
mov cx,bufsiz ; length of buffer
int dos
mov count,ax ; reset count
or ax,ax
jz prtch4 ; still no chars
mov bufout,offset source ; this is output ptr
prtch2: dec count
mov dx,count ; return count in dx
mov si,bufout
lodsb ; get character
mov bufout,si ; update ptr
mov bp,portval
cmp ds:[bp].parflg,PARNON ; no parity?
je prtch3 ; then don't strip
and al,7fh ; else turn off parity
prtch3: pop bp
pop si
pop cx
pop bx
ret
prtch4: pop bp
pop si
pop cx
pop bx
jmp rskp ; no chars...
PRTCHR ENDP
; Position the cursor according to contents of DX.
POSCUR PROC NEAR
mov ax,ds
mov es,ax ; address data segment!!!
cld
mov di,offset colno
mov al,dl ; column
call nout
mov al,'c'
stosb
mov al,dh ; row
call nout
mov al,'Y'
stosb
mov al,'$'
stosb
mov dx,offset movcur
mov ah,prstr
int dos ; print the sequence
ret
POSCUR ENDP
NOUT PROC NEAR
cbw ; extend to word
div byte ptr ten ; divide by 10
or al,al ; any quotient?
jz nout1 ; no, forget this
push ax ; save current result
call nout ; output high order
pop ax ; restore
nout1: mov al,ah ; get digit
add al,'0' ; make printable
stosb
ret ; put in buffer and return
NOUT 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 dx ; preserve message
mov dx,24 * 100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
mov ah,prstr
int dos
pop dx
int dos
mov dx,offset nrmseq ; normal videw
int dos
ret ; and return
putmod endp
; Clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,24 * 100H
call poscur
call clearl
ret
clrmod endp
; Put a help message one the screen in reverse video. Pass
; the message in AX, terminated by a null. Returns normally.
; The message is put wherever the cursor currently is located.
puthlp proc near
push ax
mov ah,prstr ; Leave some room before the message.
mov dx,offset crlf
int dos
pop si ; Put message address here.
puth0: mov ah,prstr
mov dx,offset invseq ; Put into reverse video.
int dos
mov ah,prstr
mov dx,offset ivlseq ; Make line inverse video
int dos
puth1: lodsb
cmp al,0 ; Terminated with a null.
je puth2
mov dl,al
mov ah,conout
int dos
cmp al,lf ; Line feed?
je puth0 ; Yes, clear the next line.
jmp puth1 ; Else, just keep on writing.
puth2: mov dx,offset crlf
mov ah,prstr
int dos
mov dx,offset nrmseq ; Normal video.
int dos
ret
puthlp endp
; Perform a delete.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Perform a Control-U.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
ret
CTLU ENDP
COMS PROC NEAR
mov dx,offset comptab
mov bx,offset comphlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
ret
coms0: mov ax,offset port2
mov portval,ax
ret
comx: pop bx
ret
COMS ENDP
VTS PROC NEAR
jmp notimp
VTS ENDP
notimp: mov ah,prstr
mov dx,offset noimp
int dos
jmp prserr
lclini: ret
showkey:
mov ax,offset shkmsg
mov cx,shklen
ret
; Common initialization for using serial port.
SERINI PROC NEAR
call opnprt
call clrbuf ; Clear input buffer. [20e]
ret ; We're done. [21c]
SERINI ENDP
SERRST PROC NEAR
mov bx,prthnd
cmp bx,0 ; none there?
je serrs1 ; no, don't try to close.
mov ah,close
int dos ; close handle
mov prthnd,0
serrs1: ret ; All done. [21c]
SERRST ENDP
; Generate a short beep.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP 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
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
rep movsb ; copy into our arg blk
term1: call prtchr
jmp short term2 ; have a char...
nop
nop
jmp short term3 ; no char, go on
term2: push ax
mov dl,al
and dl,7fh ; mask off parity for terminal
mov ah,dconio
int dos ; write out the character
pop ax
test ourarg.flgs,capt ; capturing output?
jz term3 ; no, forget it
call ourarg.captr ; else call the routine
term3: mov ah,dconio
mov dl,0ffh
int dos
jz term1 ; no character, go on
cmp al,ourarg.escc ; escape char?
je term4 ; yes, exit
push ax ; save char
mov ah,al
or ah,80H ; turn on hi bit so DOS doesn't interfere
call outchr ; output the character
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz term1 ; no, continue loop
mov dl,al
mov ah,dconio
int dos
jmp term1 ; else echo and keep going
term4: ret
term endp
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxhp150.asm
/bin/echo -n ' '; /bin/ls -ld msxhp150.asm
fi
/bin/echo 'Extracting msxibm.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxibm.asm
; Kermit system dependent module for IBM-PC
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, machnam, setktab, setkhlp, lclini, showkey
include msdefs.h
false equ 0
true equ 1
mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full.
; constants used by serial port handler
BRKBIT EQU 040H ; Send-break bit.
TIMER EQU 40H ; Use to issue short beep.
PORT_B EQU 61H ; Port B address.
MCONF EQU 11H ; Machine configuration.
KEYB EQU 16H
BIOS EQU 10H
MDMDAT1 EQU 03F8H ; Address of modem port (data). [19b]
MDMSTS1 EQU 03FDH ; Address of modem port status. [19b]
MDMCOM1 EQU 03FBH ; Address of modem port command. [19b]
MDMDAT2 EQU 02F8H ; Port 2 address. [19b]
MDMSTS2 EQU 02FDH ; Port 2 status. [19b]
MDMCOM2 EQU 02FBH ; Port 2 command. [19b]
MDMINP EQU 1 ; Input ready bit.
MDMINTV EQU 0030H ; Address of modem port interrupt vector.
MDINTV2 EQU 002CH ; Address for port 2. [19b]
MDMINTO EQU 0EFH ; Mask to enable interrupt for modem port.
MDINTO2 EQU 0F7H ; Enable interrupt level 3. [19b]
MDMINTC EQU 010H ; Bit to set to disable interrupts for modem.
MDINTC2 EQU 008H ; Disable IRQ3. [19b]
INTCONT EQU 0021H ; Address of 8259 interrupt controller ICW2-3.
INTCON1 EQU 0020H ; Address of 8259 ICW1.
EOICOM EQU 0064H ; End of interrupt.
EOICOM2 EQU 0063H ; End of interrupt for COM2. [19b]
; 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.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
setktab db 12
mkeyw 'BACKSPACE',0eh
mkeyw 'F1',3bh
mkeyw 'F2',3ch
mkeyw 'F3',3dh
mkeyw 'F4',3eh
mkeyw 'F5',3fh
mkeyw 'F6',40h
mkeyw 'F7',41h
mkeyw 'F8',42h
mkeyw 'F9',43h
mkeyw 'F10',44h
mkeyw 'SCAN',-1
setkhlp db cr,lf,'Keyname: backspace, f1, ... f10, or "SCAN" follwed by '
db 'decimal scan code$'
brkval db 0 ; What to send for a break.
brkadr dw 0 ; Where to send it.
modem mdminfo <MDMDAT1,MDMSTS1,MDMCOM1,MDMINTO,MDMINTC,EOICOM,MDMINTV>
erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40 db cr,lf,'?Warning: Unrecognized baud rate$'
badbd db cr,lf,'Unimplemented baud rate$'
machnam db 'IBM-PC$'
crlf db cr,lf,'$'
delstr db BS,' ',BS,'$' ; Delete string. [21d]
clrlin db cr,'$' ; Clear line (just the cr part).
savsci dw ? ; Save for serial port interrupt vector. [14]
savscs dw ? ; Ditto. [14]
savbr1 dw ? ; "Break" interrupt vector. [25]
savbr2 dw ? ; Ditto. [25]
portin db 0 ; Has comm port been initialized. [21c]
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
ontab db 02H ; Two entries.
db 03H,'OFF$' ; Should be alphabetized. [19a]
dw 00H
db 02H,'ON$'
dw 01H
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
; 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 0FFH ; 19200 baud -- Not supported.
dw 0FFH ; 38400 baud -- Not supported.
; 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.
savesi dw 0 ; Save SI register here.
telflg db 0 ; Are we acting as a terminal.
mst dw 0 ; Modem status address.
mdat dw 0 ; Modem data address.
mdeoi db 0 ; End-of-Interrupt value.
rbtrn db 7fH ; rubout
shkbuf db 300 dup (?) ; room for definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
datas ends
code segment public
extrn comnd:near, dopar:near, defkey:near, gss:near
assume cs:code,ds:datas
; local initialization
lclini proc near
mov ax,0eH ; scan code for arrow key
mov si,offset rbtrn ; translate to rubout
mov cx,1 ; one char translation
call defkey
mov brkval,BRKBIT ; What to send for a break.
mov ax,modem.mdcom ; Where to send it.
mov brkadr,ax
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).
mov drives,al ; Remember how many.
ret
dodsk0: mov ah,prstr ; Print a warning message.
mov dx,offset erms20 ; I'm not sure if things will
int dos ; work with only a cassette.
mov drives,0 ; Say there aren't any drives.
ret
DODISK 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.
showkey proc near
push es
push ax ; save the ptr
mov bx,ds
mov es,bx ; address data segment
cld
showk1: xor ah,ah
int keyb ; read a char
push ax ; save the character
call gss ; get shift state
pop bx
mov ah,al ; shift state to ah
mov al,bh ; scan code to al
push ax ; remember scan code
mov di,offset shkbuf
mov si,offset shkmsg
mov cx,shkmln
rep movsb ; copy in initial message
call nout ; write out scan code
mov si,offset shkms1
mov cx,shkm1ln ; second message
rep movsb
pop ax ; get scan code back
pop bx ; and terminal arg block
mov cx,[bx].klen ; and length
jcxz showk2 ; no table, not defined
push di ; remember output ptr
mov di,[bx].ktab ; get key table
repne scasw ; search for a definition for this
mov si,di ; remember result ptr
pop di ; get output ptr back
jne showk2 ; not defined, forget it
sub si,[bx].ktab ; compute offset from beginning
sub si,2 ; minus 2 for pre-increment
add si,[bx].krpl ; get index into replacement table
mov si,[si] ; pick up replacement
mov cl,[si] ; get length
mov ch,0
inc si
rep movsb ; copy into buffer
showk2: mov ax,offset shkbuf ; this is buffer
mov cx,di
sub cx,ax ; length
pop es
ret ; and return
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 savesi,ax
mov count,0
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov ah,3 ; Clear to end of line.
mov bh,0
int bios ; Get current cursor position
mov cx,dx
mov dl,79
mov ah,7
mov al,0
mov bh,7
int bios
ret
CLEARL 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.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,modem.mdstat ; Get port status.
outch3: in al,dx
test al,20H ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR ; This is stolen from the IBM example.
mov cx,0
mov dx,184FH
mov bh,7
mov ax,600H
int bios
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
; 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 dx ; preserve message
mov cx,1800h
mov dx,184fh
mov ax,600h ; scroll to clear the line
mov bh,70h ; inverse video
int bios
mov dx,1800h ; now address line 24
call poscur
pop dx ; get message back
mov ah,prstr
int dos ; write it out
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov cx,1800h
mov dx,184fh
mov ax,600h
mov bh,7h
int bios
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 ax ; preserve this
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
int bios
call locate ; home cursor
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
mov ah,14
int bios ; else write to screen
jmp puthl3 ; and keep going
puthl4: mov dx,24 * 100H ; go to last line
jmp poscur ; position and return
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
DOBAUD PROC NEAR
mov bp,portval
mov temp1,ax ; Don't overwrite previous rate. [25]
mov ax,ds:[bp].baud ; Check if new rate is valid. [25]
mov tmp,2
mul tmp ; Get index into baud table.
mov bx,offset bddat ; Start of table.
add bx,ax
mov ax,[bx] ; The data to output to port.
cmp ax,0FFH ; Unimplemented baud rate.
jne dobd0
mov ax,temp1 ; Get back orginal value.
mov ds:[bp].baud,ax ; Leave baud rate as is.
mov ah,prstr
mov dx,offset badbd ; Give an error message.
int dos
ret
dobd0: mov temp1,ax ; Remember value to output. [25]
mov dx,modem.mdcom ; LCR -- Initialize baud rate. [19b]
in al,dx
mov bl,al
or ax,80H
out dx,al
mov dx,modem.mddat ; [19b]
mov ax,temp1
out dx,al
inc dx
mov al,ah
out dx,al
mov dx,modem.mdcom ; [19b]
mov al,bl
out dx,al
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
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
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,baudsiz ; At the end of the list.
jge getb2
add bx,2
jmp getb0
getb1: mov ch,0
mov bp,portval
mov ds:[bp].baud,cx ; Set baud rate.
ret
getb2: mov ah,prstr
mov dx,offset erms40
int dos
ret
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we need to xon
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent the xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
push cx
push dx
push ax
xor cx,cx ; Clear loop counter.
mov dx,brkadr ; Port address. [19b]
in al,dx ; Get current setting.
or al,brkval ; Set send-break bit(s).
out dx,al ; Start the break.
pause: loop pause ; Wait a while.
xor al,brkval ; Clear send-break bit(s).
out dx,al ; Stop the break.
pop ax
pop dx
pop cx
ret ; And return.
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
mov ah,2 ; Position cursor.
mov bh,0
int bios
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
; set the current port.
COMS PROC NEAR
mov dx,offset comptab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
mov modem.mddat,MDMDAT1 ; Set COM1 defaults.
mov modem.mdstat,MDMSTS1
mov modem.mdcom,MDMCOM1
mov modem.mddis,MDMINTC
mov modem.mden,MDMINTO
mov modem.mdmeoi,EOICOM
mov modem.mdintv,MDMINTV
mov brkadr,MDMCOM1
ret
coms0: mov ax,offset port2
mov portval,ax
mov modem.mddat,MDMDAT2 ; Set COM2 defaults.
mov modem.mdstat,MDMSTS2
mov modem.mdcom,MDMCOM2
mov modem.mddis,MDINTC2
mov modem.mden,MDINTO2
mov modem.mdmeoi,EOICOM2
mov modem.mdintv,MDINTV2
mov brkadr,MDMCOM2
ret
comx: pop bx
ret
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp vt0 ; Didn't get a confirm.
nop
pop bx
mov flags.vtflg,bl ; Set the VT52 emulation flag.
ret
vt0: pop bx
ret
VTS 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.
SERINI PROC NEAR
push es
cmp portin,0 ; Did we initialize port already? [21c]
jne serin0 ; Yes, so just leave. [21c]
cli ; Disable interrupts
cld ; Do increments in string operations
xor ax,ax ; Address low memory
mov es,ax
mov bx,modem.mdintv ; Save serial card interrupt vector. [19b]
mov ax,es:[bx]
mov savsci,ax
mov ax,offset serint ; And point it to my routine
mov es:[bx],ax
add bx,2 ; Save CS register too. [19b]
mov ax,es:[bx]
mov savscs,ax
mov es:[bx],cs
mov portin,1 ; Remember port has been initialize.
call clrbuf ; Clear input buffer.
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.
out 21H,al
mov dx,modem.mdcom ; Set up the serial card.
mov al,3
out dx,al
mov dl,0F9H
mov al,1 ; Set up interrupt enable register
out dx,al
mov dl,0FCH ; Enable interrupts from serial card
mov al,0BH
out dx,al
sti ; Allow interrupts
mov dl,0F8H
in al,dx
serin0: pop es
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.
; Returns normally.
SERRST PROC NEAR
push es ; preserve this
cmp portin,0 ; Reset already?
je srst1 ; Yes, just leave.
cli ; Disable interrupts
mov dx,03FCH ; Disable modem interrupts
cmp flags.comflg,1 ; Using port 1 ?
je srst0 ; Yes - continue.
mov dh,02 ; Set for port 2.
srst0: mov al,3
out dx,al
in al,21H ; Interrupt controller
or al,modem.mddis ; Inhibit IRQ3 or IRQ4.
out 21H,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
mov portin,0 ; Reset flag.
sti
srst1: pop es
ret ; All done.
SERRST ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
SERINT PROC NEAR
push bx
push dx
push ax
push es
push di
push ds
push bp
push cx
cld
mov ax,seg datas
mov ds,ax ; address data segment
mov es,ax
mov di,srcpnt ; Registers for storing data.
mov dx,mst ; Asynch status port. [19b]
in al,dx
test al,mdminp ; Data available?
jz retint ; Nope.
mov dx,mdat ; [19b]
in al,dx
cmp telflg,0 ; File transfer or terminal mode? [17c]
jz srint0
and al,7FH ; Terminal mode (7 bits only).
srint0: or al,al
jz retint ; Ignore nulls.
mov ah,al
and ah,7fH ; strip parity temporarily
cmp ah,7FH ; Ignore rubouts, too.
jz retint
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je srint2 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp al,bl ; Is it an XOFF?
jne srint1 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp retint
srint1: cmp al,bh ; Get an XON?
jne srint2 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp retint
srint2: stosb
cmp di,offset source + bufsiz
jb srint3 ; not past end...
mov di,offset source ; wrap buffer around
srint3: inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je retint ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je retint ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe retint ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop
nop
nop ; ignore failure.
mov xofsnt,true ; Remember we sent it.
retint: mov srcpnt,di
sti
mov al,mdeoi ; [19b]
out intcon1,al ; Send End-of-Interrupt to 8259.
pop cx
pop bp
pop ds
pop di
pop es
pop ax
pop dx
pop bx
intret: iret
SERINT ENDP
; Produce a short beep. The PC DOS bell is long enough to cause a loss
; of data at the port. Returns normally.
BEEP PROC NEAR
mov al,10110110B ; Gen a short beep (long one losses data.)
out timer+3,al ; Code snarfed from Technical Reference.
mov ax,533H
out timer+2,al
mov al,ah
out timer+2,al
in al,port_b
mov ah,al
or al,03
out port_b,al
sub cx,cx
mov bl,1
beep0: loop beep0
dec bl
jnz beep0
mov al,ah
out port_b,al
ret
BEEP ENDP
; put the number in ax into the buffer pointed to by di. Di is updated
nout proc near
mov dx,0 ; high order is always 0.
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz nout1 ; zero, no more of number
call nout ; else call for rest of number
nout1: pop ax ; get digit back
add al,'0' ; make printable
stosb ; drop it off
ret ; and return
nout 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxibm.asm
/bin/echo -n ' '; /bin/ls -ld msxibm.asm
fi
/bin/echo 'Extracting msxrb.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxrb.asm
; Kermit system dependent module for Rainbow
; Jeff Damens, July 1984
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
; rainbow-dependent screen constants
scrseg equ 0ee00H ; screen segment
latofs equ 0ef4h ; ptrs to line beginnings, used by firmware
l1ptr equ latofs ; ptr to first line
llptr equ latofs+23*2 ; ptr to last line
csrlin equ 0f42h ; current cursor line.
; level 1 console definitions
fnkey equ 100H ; function key flag
shfkey equ 200H ; shift key
ctlkey equ 400H ; control key
cplk equ 800H
prvkey equ 23H
nxtkey equ 25H
brkkey equ 65H
prtkey equ 3
false equ 0
true equ 1
mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full.
mnstata equ 042H ;Status/command port A
mnstatb equ 043H ;Status/command port B.
mndata equ 040H ;Data port.
mndatb equ 041H
mnctrl equ 002H ;Control port.
serchn equ 0A4H ; interrupt to use
serch1 equ 044H ; use this too for older rainbows.
txrdy EQU 04H ;Bit for output ready.
rxrdy EQU 01H ;Bit for input ready.
fastcon equ 29H ; fast console handler
firmwr equ 18H
swidth equ 132 ; screen width
slen equ 24 ; screen length
npgs equ 5 ; # of pages to remember
stbrk equ 15 ; start sending a break
enbrk equ 16 ; stop sending break.
; 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.
; circular buffer ptr
cbuf struc
pp dw ? ; place ptr in buffer
bend dw ? ; end of buffer
orig dw ? ; buffer origin
lcnt dw 0 ; # of lines in buffer.
cbuf ends
; answerback structure
ans struc
anspt dw ? ; current pointer in answerback
ansct db ? ; count of chars in answerback
ansseq dw ? ; pointer to whole answerback
anslen db ? ; original length
ansrtn dw ? ; routine to call.
ans ends
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
setktab db 22
mkeyw 'F4',fnkey+5h
mkeyw 'F5',fnkey+65h
mkeyw 'F6',fnkey+7h
mkeyw 'F7',fnkey+9h
mkeyw 'F8',fnkey+0Bh
mkeyw 'F9',fnkey+0Dh
mkeyw 'F10',fnkey+0Fh
mkeyw 'F11',esc
mkeyw 'F12',bs
mkeyw 'F13',lf
mkeyw 'F14',fnkey+11h
mkeyw 'F17',fnkey+13h
mkeyw 'F18',fnkey+15h
mkeyw 'F19',fnkey+17h
mkeyw 'F20',fnkey+19h
mkeyw 'FIND',fnkey+1bh
mkeyw 'INSERTHERE',fnkey+1dh
mkeyw 'REMOVE',fnkey+1fh
mkeyw 'SCAN',-1
mkeyw 'SELECT',fnkey+21h
ourflgs db 0 ; our flags
fpscr equ 80H ; flag definitions...
crlf db cr,lf
setkhlp db ' F4 ... F20 or SCAN$'
machnam db 'Rainbow$'
nyimsg db cr,lf,'Not yet implemented$'
delstr db BS,' ',BS,'$' ; Delete string.
clrlin db cr,'$' ; Clear line (just the cr part).
oldser dw ? ; old serial handler
oldseg dw ? ; segment of above
old1ser dw ? ; old serial handler, alternate address
old1seg dw ? ; segment of same.
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.
iobuf db 5 dup (?) ; buffer for ioctl
phbuf db swidth dup (?)
gopos db esc,'['
rowp db 20 dup (?)
clrseq db esc,'[H',esc,'[J$'
ceolseq db esc,'[K$'
invseq db esc,'[7m$'
nrmseq db esc,'[0m$'
ivlatt db swidth dup (0fH) ; a line's worth of inverse attribute
; special keys.
spckey dw prvkey,nxtkey,brkkey,prtkey,prtkey+ctlkey,prvkey+ctlkey
dw nxtkey+ctlkey,brkkey+ctlkey
spclen equ ($-spckey)/2
; special key handlers. Must parallel spckey
spchnd dw prvscr,nxtscr,sendbr,prtscr,togprt,prvlin,nxtlin,sendbr
; arrow and PF keys
arrkey db 27H,29H,2bH,2dH,59H,5cH,5fH,62H
arrlen equ $-arrkey
; translations for arrow and PF keys, must parallel arrkey
arrtrn dw uptrn,dntrn,rgttrn,lfttrn
dw pf1trn,pf2trn,pf3trn,pf4trn
; keypad keys
keypad db 2fh,32h,35h,38h,3bh,3eh,41h,44h,47h,4ah,4dh,50h,53h,56h
keypln equ $-keypad
; keytrn and altktrn must parallel keypad
keytrn db '0123456789-,.',cr
altktrn db 'pqrstuvwxymlnM'
keyptr dw keytrn ; pointer to correct translation table
akeyflg db 0 ; non-zero if in alt keypad mode.
; arrow and PF key translations
uptrn db 3,esc,'[A'
dntrn db 3,esc,'[B'
rgttrn db 3,esc,'[C'
lfttrn db 3,esc,'[D'
pf1trn db 3,esc,'OP'
pf2trn db 3,esc,'OQ'
pf3trn db 3,esc,'OR'
pf4trn db 3,esc,'OS'
ourarg termarg <>
; 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.
savesi dw 0 ; Save SI register here.
telflg db 0 ; non-zero if we're a terminal. NRU.
respkt db 10 dup (?) ; ioctl packet
ivec dw tranb ; transmit empty B
dw tranb ; status change B
dw tranb ; receive b
dw tranb ; special receive b
dw stxa ; transmit empty a
dw sstata ; status change a
dw srcva ; receive a
dw srcva ; special receive a
; multi-screen stuff
bsize equ swidth*slen*npgs ; # of bytes needed to store screens
tbuf db bsize dup (?)
bbuf db bsize dup (?) ; top and bottom buffers
topbuf cbuf <tbuf,tbuf+bsize-1,tbuf,0>
botbuf cbuf <bbuf,bbuf+bsize-1,bbuf,0>
tlbuf db swidth dup (?) ; top line temp buffer
blbuf db swidth dup (?) ; bottom line temp buffer
rlbuf db swidth dup (?) ; line temp buffer
prbuf db swidth dup (?) ; print temp buffer
topdwn db esc,'[H',esc,'M$' ; go to top, scroll down
botup db esc,'[24;0H',esc,'D$' ; go to bottom, scroll up
curinq db esc,'[6n$' ; cursor inquiry
posbuf db 20 dup (?) ; place to store cursor position
gtobot db esc,'[24;0H$' ; go to bottom of screen.
ourscr db slen*swidth dup (?)
ourattr db slen*swidth dup (?) ; storage for screen and attributes
inited db 0 ; terminal handler not inited yet.
dosmsg db '?Must be run in version 2.05 or higher$'
anssq1 db esc,'[c'
ansln1 equ $-anssq1
anssq2 db esc,'Z'
ansln2 equ $-anssq2
eakseq db esc,'='
dakseq db esc,'>'
ansbk1 ans <anssq1,ansln1,anssq1,ansln1,sndans> ; two answerbacks
ansbk2 ans <anssq2,ansln2,anssq2,ansln2,sndans>
ansbk3 ans <eakseq,2,eakseq,2,enaaky> ; enable alt keypad
ansbk4 ans <dakseq,2,dakseq,2,deaaky> ; disable alt keypad
ansret db esc,'[?6c'
ansrln equ $-ansret
shkbuf db 300 dup (?) ; room for definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
datas ends
code segment public
extrn comnd:near, dopar:near
assume cs:code,ds:datas
; local initialization routine, called by Kermit initialization.
lclini proc near
; make sure this is DOS version 2.05 or higher...
mov ah,dosver
int dos
xchg al,ah ; put major version in ah, minor in al
cmp ax,205H ; is it 2.05?
jae lclin1 ; yes, go on
mov dx,offset dosmsg
call tmsg
mov ax,4c00H ; exit(0)
int dos
lclin1: mov flags.vtflg,0 ; turn off heath emulation
ret
lclini endp
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. The only problem is that a value of two
; is returned for single drive systems to be consistent
; with the idea of the system having logical drives A and
; B. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK 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.
showkey proc near
push es
push ax ; save the ptr
cld
showk1: mov di,6 ; get level one char
int firmwr
cmp cl,0ffH
jne showk1 ; wait until char available
mov bx,ds
mov es,bx ; address data segment
and ax,not cplk ; no caps lock
push ax ; remember scan code
mov di,offset shkbuf
mov si,offset shkmsg
mov cx,shkmln
rep movsb ; copy in initial message
call nout ; write out scan code
mov si,offset shkms1
mov cx,shkm1ln ; second message
rep movsb
pop ax ; get scan code back
pop bx ; and terminal arg block
mov cx,[bx].klen ; and length
jcxz showk2 ; no table, not defined
push di ; remember output ptr
mov di,[bx].ktab ; get key table
repne scasw ; search for a definition for this
mov si,di ; remember result ptr
pop di ; get output ptr back
jne showk2 ; not defined, forget it
sub si,[bx].ktab ; compute offset from beginning
sub si,2 ; minus 2 for pre-increment
add si,[bx].krpl ; get index into replacement table
mov si,[si] ; pick up replacement
mov cl,[si] ; get length
mov ch,0
inc si
rep movsb ; copy into buffer
showk2: mov ax,offset shkbuf ; this is buffer
mov cx,di
sub cx,ax ; length
pop es
ret ; and return
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 savesi,ax
mov count,0
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov dx,offset ceolseq ; clear sequence
jmp tmsg
CLEARL 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.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,mnstata ; port status register
outch3: in al,dx
test al,txrdy ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,mndata
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov dx,offset clrseq ; clear screen sequence
jmp tmsg
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
; 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 dx ; preserve message
mov dx,24 * 100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
call tmsg
pop dx
call tmsg ; print the message
mov dx,offset nrmseq ; normal videw
call tmsg
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,24 * 100H
call poscur
call clearl
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 ax
mov dx,slen * 100H ; go to bottom line
call poscur
pop ax
push es
mov bx,ds
mov es,bx ; address data segment
mov si,ax ; convenient place for this
mov bx,101H ; current line/position
puthl1: mov di,offset phbuf ; this is destination
xor cx,cx ; # of chars in the line
puthl2: lodsb ; get a byte
cmp al,cr ; carriage return?
je puthl2 ; yes, ignore it
cmp al,lf ; linefeed?
je puthl3 ; yes, break the loop
cmp al,0
je puthl3 ; ditto for null
dec cx ; else count the character
stosb ; deposit into the buffer
jmp puthl2 ; and keep going
puthl3: add cx,80 ; this is desired length of the whole
mov al,' '
rep stosb ; fill the line
push bx
push si
push es ; firmware likes to eat this one
mov ax,0 ; send chars and attributes
mov cx,80 ; this is # of chars to send
mov dx,offset ivlatt ; this are attributes to send
mov si,offset phbuf ; the actual message
mov di,14H ; send direct to screen
mov bp,ds ; need data segment as well
int firmwr ; go send it
pop es
pop si
pop bx ; restore everything
inc bx ; next line
cmp byte ptr [si-1],0 ; were we ended by a 0 last time?
jne puthl1 ; no, keep looping
pop es ; else restore this
ret ; and return
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
; no baud rate.
DOBAUD PROC NEAR
mov dx,offset nyimsg
call tmsg
mov bx,portval
mov [bx].baud,-1 ; keep baud rate unknown.
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
ret ; no baud rate for now.
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we have to xon the host.
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent an xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
push bx
push cx
push dx
push ax
mov ah,ioctl
mov al,3 ; write to control channel.
mov bx,3 ; aux port handle
mov dx,offset iobuf
mov iobuf,stbrk ; start sending a break
int dos
xor cx,cx ; clear loop counter
pause: loop pause ; Wait a while.
mov ah,ioctl
mov al,3
mov bx,3
mov dx,offset iobuf
mov iobuf,enbrk ; stop sending the break
int dos
pop ax
pop dx
pop cx
pop bx
ret ; And return.
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
add dx,101H ; start at 1,1
push es
push dx
cld
mov ax,ds
mov es,ax ; address right segment
mov di,offset rowp
mov al,dh ; row comes first
mov ah,0
call nout
mov al,';'
stosb ; separated by a semi
pop dx
mov al,dl
mov ah,0
call nout
mov al,'H'
stosb ; end w/H
mov byte ptr [di],'$' ; and dollar sign
mov dx,offset gopos
call tmsg
pop es
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 weird character.
jmp tmsg
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov dx,offset clrlin ; this just goes to left margin...
call tmsg
jmp clearl ; now clear line
CTLU ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
VTS 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.
SERINI PROC NEAR
push es
cmp portin,0 ; Did we initialize port already? [21c]
jne serin0 ; Yes, so just leave. [21c]
cli ; Disable interrupts
cld ; Do increments in string operations
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*serchn] ; get old serial handler
mov oldser,ax ; save.
mov ax,es:[4*serchn+2] ; get segment
mov oldseg,ax ; save segment as well
mov ax,es:[4*serch1] ; this is alternate for older rainbows
mov old1ser,ax
mov ax,es:[4*serch1+2]
mov old1seg,ax ; pretty silly, huh?
mov ax,offset serint ; point to our routine
mov word ptr es:[4*serchn],ax ; point at our serial routine
mov word ptr es:[4*serch1],ax ; have to set both of these
mov es:[4*serchn+2],cs ; our segment
mov es:[4*serch1+2],cs
mov al,030h ;[DTR] enable RTS and DTR
out mnctrl,al ;[DTR]
mov portin,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
serin0: pop es
ret ; We're done.
SERINI ENDP
; this is used to by serini
prtset proc near
lodsb ; get a byte
or al,al
jz prtse1 ; end of table, stop here
out dx,al ; else send it out
jmp prtset ; and keep looping
prtse1: ret ; end of routine
prtset endp
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
push es ; preserve this
cmp portin,0 ; Reset already?
je srst1 ; Yes, just leave.
cli ; Disable interrupts
xor ax,ax
mov es,ax ; address segment 0
mov ax,oldser
mov es:[4*serchn],ax
mov ax,oldseg
mov es:[4*serchn+2],ax
mov ax,old1ser
mov es:[4*serch1],ax
mov ax,old1seg
mov es:[4*serch1+2],ax ; restore old handlers
mov portin,0 ; Reset flag.
srst1: pop es
ret ; All done.
SERRST ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
serint PROC NEAR
push bx
push dx
push ax
push es
push di
push ds
push bp
push cx
cld
mov ax,seg datas
mov ds,ax ; address data segment
mov es,ax
mov di,srcpnt ; Registers for storing data.
mov dx,mnstatb ; Asynch status port.
mov al,0 ; innocuous value
out dx,al ; send out to get into a known state...
mov al,2 ; now address register 2
out dx,al
in al,dx ; read interrupt cause
cmp al,7 ; in range?
ja serin7 ; no, just dismiss (what about reset error?)
mov bl,al
shl bl,1 ; double for word index
mov bh,0
call ivec[bx] ; call appropriate handler
serin7: mov dx,mnstata ; reload port address
mov al,38H
out dx,al ; tell the port we finished with the interrupt
pop cx
pop bp
pop ds
pop di
pop es
pop ax
pop dx
pop bx
intret: iret
; handler for serial receive, port A
srcva: mov dx,mnstata
mov al,0
out dx,al ; put into known state...
in al,dx
test al,rxrdy ; Data available?
jnz srcva1 ; yes, go read it
jmp srcva7
srcva1: mov al,30H ; reset any errors
out dx,al
mov dx,mndata
in al,dx ; read the character
cmp telflg,0 ; File transfer or terminal mode?
jz srcva2
and al,7FH ; Terminal mode (7 bits only).
srcva2: or al,al
jz srcva7 ; Ignore nulls.
cmp al,7FH ; Ignore rubouts, too.
jz srcva7
mov ah,al
and ah,7fH ; only consider low-order 7 bits for flow ctl.
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je srcva4 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp ah,bl ; Is it an XOFF?
jne srcva3 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp short srcva7
srcva3: cmp ah,bh ; Get an XON?
jne srcva4 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp srcva7
srcva4: stosb
cmp di,offset source + bufsiz
jb srcva5 ; not past end...
mov di,offset source ; wrap buffer around
srcva5: mov srcpnt,di ; update ptr
inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je srcva7 ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je srcva7 ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe srcva7 ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop
nop
nop ; ignore failure.
mov xofsnt,true ; Remember we sent it.
srcva7: ret
; The interrupt is for the 'B' port - transfer control to
; the original handler and hope for the best.
tranb: pushf ; put flags on stack to simulate interrupt
call dword ptr [old1ser] ; call old handler
ret ; and return
stxa: mov dx,mnstata
mov al,28H ; reset transmit interrupt
out dx,al
ret
sstata: mov dx,mnstata
mov al,10H ; reset status interrupt
out dx,al
ret
SERINT ENDP
; Produce a short beep. The PC DOS bell is long enough to cause a loss
; of data at the port. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; put the number in ax into the buffer pointed to by di. Di is updated
nout proc near
mov dx,0 ; high order is always 0.
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz nout1 ; zero, no more of number
call nout ; else call for rest of number
nout1: pop ax ; get digit back
add al,'0' ; make printable
stosb ; drop it off
ret ; and return
nout endp
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
cld
rep movsb ; copy into our arg blk
cmp inited,0 ; inited yet?
jz term1 ; no, keep going
test ourarg.flgs,scrsam ; do they want us to leave it alone?
jnz term1 ; yes, skip redisplay.
call rstscr ; restore screen
term1: mov inited,1 ; remember inited
term2: call prtchr
jmp short term3 ; have a char...
nop
nop
jmp short term6 ; no char, go on
term3: and al,7fh ; turn off parity for terminal
mov bx,offset ansbk1 ; check 1st answerback
call ansbak ; check for answerback
mov bx,offset ansbk2 ; maybe second answerback
call ansbak
mov bx,offset ansbk3
call ansbak
mov bx,offset ansbk4
call ansbak
cmp al,lf ; linefeed?
jne term4 ; no, keep going
call scrprep ; need to save top line
mov al,lf ; get char back
term4: push ax
int fastcon ; go print it
pop ax
test ourarg.flgs,capt ; capturing output?
jz term5 ; no, forget it
push ax
call ourarg.captr ; else call the routine
pop ax
term5: test ourflgs,fpscr ; print screen toggled on?
jz term6 ; no, keep going
mov dl,al
mov ah,lstout ; printer output
int dos
term6: mov di,6 ; get level 1 character
push es
int firmwr
pop es ; don't let firmware steal registers.
cmp cl,0ffh ; character available?
je term7 ; no, do something else
cmp cl,1 ; maybe level 2 sequence around
jne term2 ; no, forget it
mov di,2 ; get level 2 character
push es
int firmwr
pop es
cmp cl,0ffh ; did we really get one?
jne term2 ; no, something strange happening.
jmp term6 ; else skip and keep trying.
term7: test ax,fnkey ; function-type key?
jnz term8 ; yes, can't be escape character
cmp al,ourarg.escc ; escape char?
je term9 ; yes, exit
term8: call trnout ; perform necessary translations, output char
jmp term2 ; and loop around
term9: call savscr ; save screen
ret ; and return
term endp
; enter with current terminal character in al, answerback ptr in bx.
; calls answerback routine if necessary.
; This can be used to make the emulator recognize any sequence.
ansbak proc near
push ax ; preserve this
mov si,[bx].anspt ; get current pointer
cmp al,[si] ; is it correct?
jne ansba1 ; no, reset pointers and go on
inc [bx].anspt ; increment pointer
dec [bx].ansct ; decrement counter
jnz ansba2 ; not done, go on
push bx
call [bx].ansrtn ; send answerback
pop bx
ansba1: mov ax,[bx].ansseq ; get original sequence
mov [bx].anspt,ax
mov al,[bx].anslen ; and length
mov [bx].ansct,al
ansba2: pop ax
ret
ansbak endp
; send the answerback message.
sndans proc near
mov si,offset ansret ; this is what we say
mov cx,ansrln ; length of same
sndan1: lodsb ; get a byte
mov ah,al
push si
push cx
call outchr
nop
nop
nop
pop cx
pop si
loop sndan1
ret
sndans endp
; enable alternate keypad mode
enaaky proc near
mov akeyflg,1 ; remember alternate mode
mov keyptr,offset altktrn ; set correct translate table
ret
enaaky endp
; disable alternate keypad mode
deaaky proc near
mov akeyflg,0
mov keyptr,offset keytrn
ret
deaaky endp
; enter with char and flags in ax. Does any necessary character translations,
; then outputs character
trnout proc near
and ax,not cplk ; forget about caps lock key
test ourarg.flgs,havtt ; any translate table?
jz trnou2 ; no, just output normally
mov cx,ourarg.klen
mov di,ourarg.ktab ; get redefined keys
repne scasw ; look for this one
jne trnou2 ; not found, try something else
sub di,ourarg.ktab
sub di,2 ; get index
add di,ourarg.krpl ; get translation address
mov si,[di] ; this is translation
mov cl,[si]
inc si ; pick up length, increment past it
mov ch,0
jcxz trnou6 ; no translation, just return
trnou1: lodsb ; get a char
push si
push cx
call sndhst ; send the character
pop cx
pop si
loop trnou1 ; loop thru rest of translation
ret ; and return
trnou2: test ax,fnkey ; function key?
jz trnou5 ; no, keep going
and ax,not fnkey ; turn off function bit.
mov di,offset spckey ; our special keys
mov cx,spclen ; length of special key table
repne scasw ; look for it in our table
jne trnou3 ; not found, maybe arrow key...
sub di,offset spckey+2 ; get index
call spchnd[di] ; call appropriate handler
ret ; and return
trnou3: mov di,offset arrkey ; look for an arrow-type key...
mov cx,arrlen ; length of arrow key table
repne scasb ; is it an arrow key?
jne trnou4 ; no, forget it
sub di,offset arrkey+1 ; get index into table
shl di,1 ; double for word index
mov si,arrtrn[di] ; get translation
mov cl,[si]
inc si
mov ch,0
jmp trnou1 ; go send translation
trnou4: mov di,offset keypad ; look for a keypad key.
mov cx,keypln
repne scasb ; is it in keypad?
jne trnou6 ; no, forget it
sub di,offset keypad+1
add di,keyptr ; index into correct translation table
mov al,[di] ; get translation
cmp akeyflg,0 ; in alternate keypad mode?
je trnou5 ; no, just send the char
push ax ; else save the character
mov al,esc
call sndhst
mov al,'O'
call sndhst ; send prefix
pop ax ; get the character back and fall thru...
trnou5: call sndhst ; send the character
trnou6: ret
trnout endp
; handle the print screen key
prtscr proc near
push ds ; save data segment
mov ax,scrseg
mov ds,ax ; address screen segment
mov cx,slen ; # of lines on screen
mov bx,0 ; current line #
prtsc1: push cx ; save counter
push bx ; and line ptr
mov si,ds:[latofs+bx] ; get ptr to line
mov cx,swidth ; max # of chars/line
mov di,offset prbuf ; print buffer
prtsc2: lodsb ; get a byte
or al,al ; is it a null?
jne prtsc3 ; no, go on
mov al,' ' ; yes, replace by space
prtsc3: stosb ; drop it off
cmp al,' ' ; is it a space?
je prtsc4 ; yes, go on
mov dx,cx ; else remember count at last non-space
prtsc4: cmp al,0ffH ; end of line?
loopne prtsc2 ; continue if not end
mov cx,dx ; count at last non-space, plus 1
neg cx
add cx,swidth+1 ; figure out # of chars to print
mov dx,offset prbuf
push ds ; save this temporarily
mov ax,es
mov ds,ax ; address data segment to print
jcxz prtsc5 ; 0 length, keep going
mov bx,4 ; standard printer device
mov ah,writef2 ; write call
int dos ; write to the printer
prtsc5: mov ah,writef2
mov bx,4
mov dx,offset crlf
mov cx,2
int dos ; follow line with a crlf
pop ds
pop bx
pop cx ; restore counters
add bx,2 ; point to next line
loop prtsc1 ; and keep going
pop ds ; restore registers
ret ; and return
prtscr endp
; toggle print flag...
togprt proc near
xor ourflgs,fpscr ; toggle flag
ret ; and return
togprt endp
; Send a character to the host, handle local echo
sndhst proc near
push ax ; save the character
mov ah,al
call outchr
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz sndhs2 ; no, exit
cmp al,lf ; scrolling? ***
jne sndhs1 ; no, go on
call scrprep
mov al,lf
sndhs1: int fastcon
sndhs2: ret ; and return
sndhst endp
; print a message to the screen. Returns normally.
tmsg proc near
mov ah,prstr
int dos
ret
tmsg endp
; save the screen for later
savscr proc near
push ds
mov ax,scrseg
mov ds,ax
mov cx,slen ; # of lines to do
mov bx,0 ; current line #
mov di,offset ourscr ; place to save screen
mov dx,offset ourattr ; and to save attributes
savsc1: push cx ; save current count
mov si,ds:[latofs+bx] ; get line ptr
mov cx,swidth ; # of chars/line
rep movsb ; copy it out
mov si,ds:[latofs+bx]
add si,1000H ; this is where attributes start
xchg dx,di ; this holds attribute ptr
mov cx,swidth ; # of attrs to move
rep movsb
xchg dx,di
pop cx ; restore counter
add bx,2 ; increment line ptr
loop savsc1 ; save all lines and attributes
pop ds
call savpos ; might as well save cursor pos
ret
savscr endp
; restore the screen saved by savscr
rstscr proc near
call cmblnk ; start by clearing screen
mov si,offset ourscr ; point to saved screen
mov dx,offset ourattr ; and attributes
mov cx,slen ; # of lines/screen
mov bx,101H ; start at top left corner
rstsc1: push bx
push cx
push si ; save ptrs
push dx
mov ax,si ; this is source
call prlina ; print the line
pop dx
pop si
pop cx
pop bx
add si,swidth ; point to next line
add dx,swidth ; and next attributes
inc bx ; address next line
loop rstsc1 ; keep restore lines
call rstpos ; don't forget position
ret
rstscr endp
; circular buffer management for screen.
; for these to work correctly, the buffer size MUST be a multiple
; of the screen width.
; put a line into the circular buffer. Pass the buffer structure
; in bx, the pointer to the line in ax.
putcirc proc near
push si
push di
push cx
push dx
mov di,[bx].pp ; pick up buffer ptr
add di,swidth ; increment to next avail slot
cmp di,[bx].bend ; past end?
jb putci1 ; no, leave alone
mov di,[bx].orig ; else start at beginning
putci1: mov [bx].pp,di ; update ptr
mov si,ax ; this is source
mov cx,swidth
rep movsb ; copy into buffer
cmp [bx].lcnt,npgs*slen ; can we increment it?
jae putci2 ; no, keep going
inc [bx].lcnt ; else count this line
putci2: pop dx
pop cx
pop di
pop si ; restore registers
ret
putcirc endp
; get a line from the circular buffer, removing it from the buffer.
; returns with carry on if the buffer is empty.
; pass the buffer structure in bx, the buffer to copy the line into
; in ax.
getcirc proc near
push si
push di
push cx
push dx
cmp [bx].lcnt,0 ; any lines in buffer?
jne getci1 ; yes, ok to take one out.
stc ; else set carry
jmp short getcir3 ; and return
getci1: mov si,[bx].pp ; this is source
mov di,ax ; this is dest
mov cx,swidth ; # of chars to copy
rep movsb
mov si,[bx].pp ; get ptr again
sub si,swidth ; move back
cmp si,[bx].orig ; compare to origin
jae getcir2 ; still in range, continue
mov si,[bx].bend ; else use end of buffer
sub si,swidth-1 ; minus length of a piece
getcir2:mov [bx].pp,si ; update ptr
dec [bx].lcnt ; decrement # of lines in buffer
clc ; make sure no carry
getcir3:pop dx
pop cx
pop di
pop si
ret
getcirc endp
; prepares for scrolling by saving the top line in topbuf.
scrprep proc near
push ds ; preserve data segment
mov ax,scrseg
mov ds,ax ; address screen segment
cmp byte ptr [ds:csrlin],slen ; are we at the bottom?
pop ds ; restore in case we're returning...
jne scrpr1 ; no, don't save it
; alternate entry that doesn't check if we're on the bottom row.
savtop: push es
push ds
mov ax,ds
mov es,ax
mov ax,scrseg
mov ds,ax ; address screen segment
mov si,ds:word ptr [l1ptr] ; get ptr to top line
mov di,offset tlbuf ; this is where it goes
mov cx,swidth ; # of bytes to copy
rep movsb ; get the top line
pop ds
pop es ; restore segments
mov bx,offset topbuf ; top buffer ptr
mov ax,offset tlbuf ; this is where line is now
call putcirc ; put into circular buffer
scrpr1: ret ; and return
scrprep endp
; get the screen's bottom line into the buffer in ax.
getbot proc near
push es
push ds
push ax
mov ax,ds
mov es,ax
mov ax,scrseg
mov ds,ax
mov si,ds:word ptr [llptr] ; get ptr to bottom line
pop di ; destination is on stack
mov cx,swidth ; # of bytes to copy
rep movsb ; get the top line
pop ds ; restore segments
pop es
ret
getbot endp
; handle the previous screen button...
prvscr proc near
mov ax,offset tlbuf
mov bx,offset topbuf
call getcirc
jc prvsc3 ; no lines, forget it
call savpos ; save cursor position
mov ax,offset botbuf ; place to put screen
mov bx,slen ; else just use last line on screen
mov dx,-1 ; move backwards
call rolscr ; save current screen
call cmblnk ; clear screen
mov cx,slen ; # of lines per screenfull
prvsc1: mov bl,cl ; this is current line
mov bh,1 ; this is column
mov ax,offset tlbuf ; where to get the line from
push cx ; save count
call prlin ; put the line on the screen
mov ax,offset tlbuf
mov bx,offset topbuf
call getcirc ; get another line
pop cx
jc prvsc2 ; no more, exit loop
loop prvsc1 ; loop for all lines
prvsc2: call rstpos ; restore screen position
prvsc3: ret ; and return
prvscr endp
; handle the next screen button...
nxtscr proc near
mov ax,offset tlbuf
mov bx,offset botbuf
call getcirc ; get a line from the bottom
jc nxtsc3 ; no lines, forget it
call savpos ; save cursor pos
mov ax,offset topbuf ; place to put screen
mov bx,1 ; start with first line
mov dx,1 ; move backwards
call rolscr ; save current screen
call cmblnk ; clear screen
mov cx,slen ; # of lines per screenfull
nxtsc1: mov bl,slen+1
sub bl,cl ; this is current line
mov bh,1 ; this is column
mov ax,offset tlbuf ; where to get the line from
push cx ; save count
call prlin ; put the line on the screen
mov ax,offset tlbuf ; where to put the next line
mov bx,offset botbuf
call getcirc ; try to get another
pop cx
jc nxtsc2 ; no more, break loop
loop nxtsc1 ; loop for all lines
nxtsc2: call rstpos ; restore cursor position
nxtsc3: ret ; and return
nxtscr endp
; save a screen by rolling them into a circular buffer.
; enter with ax/ circular buffer ptr, bx/ first line to get
; dx/ increment
rolscr proc near
shl dx,1 ; double increment for word ptr
dec bx ; ptr starts at 0
shl bx,1 ; convert to word ptr
mov cx,slen ; # of lines to save
rolsc1: push cx
push dx
push bx
push ax
push ds
mov ax,scrseg
mov ds,ax ; address screen
mov si,ds:[latofs+bx] ; get current line
mov di,offset rlbuf ; place to put it
mov cx,swidth ; # of bytes to move
rep movsb ; get the lne
pop ds ; restore segment
pop bx ; this is desired circ buffer ptr
mov ax,offset rlbuf ; this is where the line is
call putcirc ; save in circular buffer
mov ax,bx ; put buffer ptr back where it belongs
pop bx ; get line pos back
pop dx ; and increment
pop cx ; don't forget counter
add bx,dx ; move to next line
loop rolsc1 ; loop thru all lines
ret ; and return
rolscr endp
; move screen down a line, get one previous line back
prvlin proc near ; get the previous line back
mov ax,offset tlbuf ; place to put line temporarily
mov bx,offset topbuf ; where to get lines from
call getcirc ; try to get a line
jc prvli1 ; no more, just return
mov ax,offset blbuf ; place for bottom line
call getbot ; fetch bottom line
mov ax,offset blbuf
mov bx,offset botbuf
call putcirc ; save in circular buffer
call savpos ; save cursor position
mov dx,offset topdwn ; home, then reverse index
call tmsg
mov ax,offset tlbuf ; point to data
mov bx,0101H ; print line at top of screen
call prlin ; print the line
call rstpos ; restore cursor position
prvli1: ret ; and return
prvlin endp
; move screen up a line, get one bottom line back
nxtlin proc near
mov ax,offset blbuf ; place to put line temporarily
mov bx,offset botbuf ; where to get lines from
call getcirc ; try to get a line
jc nxtli1 ; no more, just return
call savtop ; save one line off of top
call savpos ; save cursor position
mov dx,offset botup ; go to bottom, then scroll up a line
call tmsg
mov ax,offset blbuf ; point to data
mov bx,0100H + slen ; print at bottom line
call prlin ; print the line
call rstpos ; restore cursor position
nxtli1: ret ; and return
nxtlin endp
; save cursor position
savpos proc near
mov dx,offset curinq ; where is the cursor?
call tmsg
mov posbuf,esc ; put an escape in the buffer first
mov di,offset posbuf+1
savpo1: mov ah,8 ; read, no echo
int dos
cmp al,'R' ; end of report?
je savpo2 ; yes
stosb ; no, save it
jmp savpo1 ; and go on
savpo2: mov al,'H' ; this ends the sequence when we send it
stosb
mov byte ptr [di],'$' ; need this to print it later
ret ; and return
savpos endp
; restore the position saved by savpos
rstpos proc near
mov dx,offset posbuf
call tmsg ; just print this
ret ; and return
rstpos endp
; print a ff-terminated line at most swidth long... Pass the line in ax.
; cursor position should be in bx.
; prlina writes attributes as well, which should be passed in dx.
prlin proc near
mov bp,2 ; print characters only
jmp short prli1
prlina: xor bp,bp ; 0 means print attributes as well.
prli1: push es ; this trashes es!!!
mov si,ax ; better place for ptr
mov di,ax ; need it here for scan
mov cx,swidth ; max # of chars in line
mov al,0ffh ; this marks the end of the line
repne scasb ; look for the end
jne prli2 ; not found
inc cx ; account for pre-decrement
prli2: neg cx
add cx,swidth ; figure out length of line
jcxz prli3 ; 0-length line, skip it.
mov ax,2 ; writing characters
mov bp,ds ; wants segment here
mov di,14H ; fast write to screen
int firmwr ; pos is in bx, char ptr in si
prli3: pop es ; restore register
ret ; and return
prlin 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxrb.asm
/bin/echo -n ' '; /bin/ls -ld msxrb.asm
fi
/bin/echo 'Extracting msxsys.doc'
sed 's/^X//' <<'//go.sysin dd *' >msxsys.doc
SPECIFICATION FOR KERMIT SYSTEM-DEPENDENT MODULES
by Jeff Damens, Columbia University
All the system-independent global data structures used in Kermit-MS are defined
in the file MSDEFS.H.
The routine MSXxxx.ASM contains system-dependent support for system xxx, except
for terminal emulation, which is in MSXxxx.ASM, described below.
The routines in the MSX module may change any registers but the stack pointer
and segment registers, unless otherwise noted. A routine that returns via a
RET instruction is said to return normally; a routine that skip returns is one
that returns to three bytes past the normal return address.
Global variables that must be defined in the system-dependent module:
XXOFSNT byte. This should be set to a non-zero value if we are doing
flow control and have sent an XOFF character to the remote
host, zero otherwise.
MACHNAM byte. A $-terminated string identifying the machine this
version of Kermit is for; it is printed when Kermit starts up.
SETKTAB byte. A keyword table associating terminal key names to 16-bit
scan code values, used in the set key command. If the kermit
version can accept arbitrary decimal values as scan codes, the
word "SCAN" should appear in the table with a scan value of -1.
If key redefinition is not implemented, the first byte of the
table should be a zero.
SETKHLP byte. A $-terminated string to be printed when ? is typed in
the SET KEY command. This is usually simply a list of the key
names in SETKTAB. SETKHLP must be defined even if key
redefinition is not implemented, to satisfy the linker; if key
redefinition is not implemented, SETKHLP will never be
displayed.
COUNT word. The number of characters in the serial input buffer, if
known. This is how Kermit knows to send an XON if the serial
handler has sent an XOFF. If the number of characters in the
buffer isn't known, COUNT should be 0.
These are the required entry points for the system dependent dependent module
MSXxxx.ASM.
SERINI
Parameters None.
Returns Normally, no return value.
Description Perform any initialization that must be done before the serial
port can be used, including setting baud rate, interrupt
vectors, etc. Parity and baud rate should be set according to
the values in the PORTINFO structure. The external variable
PORTVAL points to the PORTINFO structure for the current port.
Calling SERINI more than once without an intervening call to
SERRST should have no effect.
SERRST
Parameters None.
Returns Normally, no return value.
Description Undoes any initialization done by SERINI, including resetting
the serial port, restoring any interrupt vectors changed by
SERINI, etc. Calling this more than once without an
intervening call to SERINI should be harmless.
CLRBUF
Parameters None.
Returns Normally, no return value.
Description Remove and discard from the serial port's input buffer any
characters sent by the remote host that have not yet been read
by Kermit, and set COUNT to 0. This is used before a file
transfer to flush NAK's that accumulate in the buffer when the
remote host is in server mode.
OUTCHR
Parameters A character in AH.
Returns Skip returns if the character has been transmitted; returns
normally if the character can not be transmitted because of a
hardware error.
Description Sends the character in AH out the currently selected serial
port. OUTCHR can assume that SERINI will have been called
previously. OUTCHR should call the external routine DOPAR to
set the parity of the character if the communications hardware
doesn't automatically set parity. Flow control should be
honored; the external variable PORTVAL contains a pointer to a
PORTINFO structure (as defined in MSDEFS.H) containing the
current flow control definitions.
COMS
Parameters None.
Returns Normally if a parse error is encountered, skip returns
otherwise.
Description Called by the SET PORT command. On a machine with multiple
serial ports, COMS should parse for the name or number of a
serial port and make that the port used by succeeding calls to
SERINI, PRTCHR, OUTCHR, and SERRST. It should set the external
variable PORTVAL to point to one of the external port
structures PORT1 or PORT2, and set COMFLG in the FLAGS
structure to 1 for port one, 0 for port 2. For implementations
that use only one serial port, COMS should print a message to
that effect and skip return.
VTS
Parameters None.
Returns Normally if a parse error is encountered, skip returns
otherwise.
Description Parses for an ON or OFF, sets HEATH-19 emulation while in
terminal emulation appropriately. The VTFLG field of the FLAGS
structure should be set non-zero if HEATH-29 emulation is on,
zero otherwise. If HEATH-19 emulation is not done, VTS should
print a message and skip return.
DODEL
Parameters None.
Returns Normally, no return value.
Description Erases the character immediately to the left of the cursor from
the screen, then backs up the cursor.
CTLU
Parameters None.
Returns Normally, no return value.
Description Move the cursor to the left margin, then clear the line.
CMBLNK
Parameters None.
Returns Normally, no return value.
Description Clears the screen and homes the cursor.
LOCATE
Parameters None.
Returns Normally, no return value.
Description Homes the cursor.
LCLINI
Parameters None.
Returns Normally, no return value.
Description Performs any system-dependent initialization required by this
implementation.
PRTCHR
Parameters None.
Returns Normally, with the next character from the currently selected
serial port in AL. Skip returns if no character is available.
Description Reads the next character from the current serial port. PRTCHR
can assume SERINI has been called previously, and should handle
flow control correctly.
DOBAUD
Parameters None.
Returns Normally, no return value.
Description Sets the baud rate for the current port. The baud rate should
be obtained from the BAUD field of the PORTINFO structure,
pointed to by the external variable PORTVAL.
CLEARL
Parameters None.
Returns Normally, no return value.
Description Clears from the cursor to the end of the current line.
DODISK
Parameters None.
Returns Normally, no return value.
Description Sets the external variable DRIVES to the number of disk drives
attached to the machine.
GETBAUD
Parameters None.
Returns Normally, no return value.
Description Store current baud rate of the currently selected port in the
BAUD field of the current PORTINFO structure, which is pointed
to by PORTVAL. If the baud rate is to default to a particular
value, this routine can store that value into the BAUD field
instead.
BEEP
Parameters None.
Returns Normally, no return value.
Description Rings the terminal bell.
PUTHLP
Parameters A pointer to a string in AX.
Returns Normally, no return value.
Description Writes the null-terminated string given in AX to the terminal.
This is used to display help and status messages. The IBM and
Rainbow versions write the string in a reverse video box.
PUTMOD
Parameters A pointer to a string in AX.
Returns Normally, no return value.
Description Writes the null-terminated string given in AX to the last line
of the screen, in inverse video if possible.
CLRMOD
Parameters None.
Returns Normally, no return value.
Description Clears the line written by PUTMOD.
POSCUR
Parameters Row in DH, column in DL.
Returns Normally, no return value.
Description Positions the cursor to the row and column given in DX. Rows
and columns both originate at 0 (not 1!).
SENDBR
Parameters None.
Returns Normally, no return value.
Description Send a break to the current serial port.
SHOWKEY
Parameters Pointer to a terminal argument block in AX (see TERM below).
Returns Normally, with a string pointer in AX and the length of the
string in CX.
Description Called by the SHOW KEY command. Reads a key from the terminal
and returns a string containing implementation-dependent
information about the key. In the usual case, the string
contains the key's (machine-dependent) scan code, and the key's
definition (if any) from the terminal argument block. The
length of the returned string should be returned in CX. The
string may contain any characters; unprintable characters will
be quoted when the string is printed. If the implementation
does not support key redefinition, SHOWKEY may return a static
string saying so.
TERM
Parameters Pointer to terminal argument block in AX.
Returns Normally, no return value.
Description Do terminal emulation, based on argument block described
below...
The terminal emulator is supplied in the file MSYxxx.ASM. The terminal
argument block passed to the terminal emulator has the following fields:
FLGS Byte containing flags. Flags are:
SCRSAM (80H) If on, the terminal emulator shouldn't
re-display the screen when entered.
CAPT (40H) Capture output. If on, the routine passed in
field CAPTR is called with each character sent
to the screen.
EMHEATH (20H) Emulate a Heath-19 terminal if on.
HAVTT (10H) A key redefinition table is present.
TRNCTL (08H) Print control character X as ^X (useful for
debugging).
MODOFF (04H) Do not display emulator mode line if on.
LCLECHO (01H) Echo keyboard characters on the screen in
addition to sending them to the port.
PRT Port to use for terminal emulation, used only in mode line.
This is just a copy of COMFLG in FLAGS.
COLS Number of columns on screen.
ROWS Number of rows on screen.
CAPTR Routine to call to with each character sent to the screen if
CAPT flag is on. Characters are passed in AL.
BELLD Bell divisor (used only on IBM).
KLEN Number of keys in key redefinition table, if HAVTT flag is on.
KTAB Address of key redefinition table. The key redefinition table
is a table of KLEN 16-bit scan codes. Each (machine dependent)
scan code represents a key that is redefined.
KRPL Address of key replacement table. The key replacement table
parallels the key redefinition table given in KTAB. Entries in
the replacement table are 16-bit pointers to redefinitions.
Each redefinition has a one-byte length, followed by the
definition.
ESCC Escape character (single byte). When this character is typed
to the emulator, it should return.
BAUDB byte. Bits describing the baud rate so it can be printed on
the mode line. This is a copy of the BAUD field in the
PORTINFO structure. Currently used only on the IBM. See
MSDEFS.H for possible values.
PARITY byte. Current parity to print on the mode line. This is a
copy of PARFLG in the PORTINFO structure. Currently used only
on the IBM. See MSDEFS.H for possible values.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxsys.doc
/bin/echo -n ' '; /bin/ls -ld msxsys.doc
fi
More information about the Comp.sources.unix
mailing list