home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
ccdos.zip
/
ccxibm.asm
< prev
next >
Wrap
Assembly Source File
|
1991-09-08
|
146KB
|
3,066 lines
; File CCXIBM.ASM
; Kermit system dependent module for IBM-PC
;CHINESE
ifdef MSDOS
include msxibm.dat
else
include ccxibm.dat
endif
code segment public 'code'
extrn comnd:near, dopar:near, defkey:near, lclyini:near
extrn sleep:near, atsclr:near, scrseg:near,scrloc:near, scrsync:near
extrn atoi:near, strlen:near, prtscr:near, scroff:near, scron:near
extrn srchkb:near, srchkw:near, prompt:near, statc:near
assume cs:code, ds:datas
; local initialization
lclini proc near
mov flags.comflg,1 ; assume COM1 for communications port
;;; call coms2 ; setup serial port modem.info for COM1
call model ; get model of IBM machine
call lclyini ; let other modules initialize too...
ret
lclini endp
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. Returns normally.
DODISK PROC NEAR
int mconf ; Get equipment configuration
mov ah,al ; Store AL value for a bit
and al,01H ; First, look at bit 0
jz dodsk0 ; No disk drives -- forget it
mov al,ah ; Get back original value
mov cl,6 ; Shift over bits 6 and 7
shr al,cl ; To positions 0 and 1
inc al ; Want 1 thru 4 (not 0 thru 3)
dodsk0: mov drives,al ; Remember how many.
ret
DODISK ENDP
; The IBM PC's. If jr then redo IBM baud rate with jr's values. [jrd]
model proc near
mov isps2,0 ; PS/2 present indicator
push es
push ax ; get IBM model code at F000:FFFEh
mov ax,0f000h ; address ROM
mov es,ax
mov al,byte ptr es:[0fffeh] ; get model id byte
cmp al,0fdh ; PC jr?
jne modelx ; ne = no
push ds
pop es ; set es to datas segment
mov si,offset bddat ; regular IBM baud rate table
mov di,offset jrbddat ; PCjr baud rate table
mov cl,baudlen ; number of words to copy
mov ch,0
cld
rep movsw ; copy PCjr values to IBM table
jmp short modelx
model2: mov ah,0ch ; AT and PS/2 configuration call
mov al,0
int 15h ; IBM Bios
jc modelx ; c = no information
cmp word ptr es:[bx+2],040fch ; PS/2 model 50?
je model3 ; e = yes
cmp word ptr es:[bx+2],050fch ; PS/2 model 60?
je model3 ; e = yes
cmp byte ptr es:[bx+2],0f8h ; PS/2 model 80?
jne modelx ; ne = no
model3: mov isps2,1 ; say real PS/2 for IRQ setting
modelx: pop ax
pop es
ret
model endp
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally. Obsolete, name here for external reference only.
showkey proc near
ret ; return
showkey endp
; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdmhand, the modem line status register. [jrd]
shomodem proc near
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
; mov dx,offset msmsg7 ; no modem status for network
mcmsg msmsg7,cmsmsg7
call getmodem ; get modem status
mov mdmhand,al
mov ah,prstr
; mov dx,offset msmsg1 ; modem ready msg
mcmsg msmsg1,cmsmsg1
test mdmhand,20h ; is DSR asserted?
jz shomd1 ; z = no
; mov dx,offset msmsg2 ; say not asserted
mcmsg msmsg2,cmsmsg2
shomd1: int dos
; mov dx,offset msmsg3 ; CD asserted msg
mcmsg msmsg3,cmsmsg3
test mdmhand,80h ; CD asserted?
jz shomd2 ; z = no
; mov dx,offset msmsg4 ; say not asserted
mcmsg msmsg4,cmsmsg4
shomd2: int dos
; mov dx,offset msmsg5 ; CTS asserted msg
mcmsg msmsg5,cmsmsg5
test mdmhand,10h ; CTS asserted?
jz shomd3 ; z = no
; mov dx,offset msmsg6 ; say not asserted
mcmsg msmsg6,cmsmsg6
shomd3: mov ah,prstr
int dos
jmp rskp
shomodem endp
; Get modem status and set global byte mdmhand. Preserve all registers.
getmodem proc near ; gets modem status upon request
cmp portin,-1 ; done any port yet?
jne getmod1 ; ne = yes
mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT command now
ret ; failed to set port
nop
nop
getmod1:mov al,0 ; assume nothing is on
cmp clone,'N' ; Network?
je getmodx ; e = yes, no status
cmp clone,'B' ; Bios?
je getmod2 ; e = yes
cmp flags.comflg,0 ; null port?
je getmodx ; e = yes, no status
mov dx,mst ; hardware
inc dx ; uart status reg
in al,dx
jmp short getmodx
getmod2:mov ah,3 ; ask Bios for modem status into al
push dx
mov dl,flags.comflg ; get port id
cmp dl,'0' ; ascii?
jb getmod3 ; b = no
sub dl,'0' ; remove ascii bias
getmod3:int rs232
pop dx
getmodx:mov ah,0 ; return status in al
ret
getmodem endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cli
mov srcpnt,offset source ; receive circular buffer
mov count,0 ; receive circular buffer
sti
call prtchr ; empty any intermediate (net) buffers
nop ; got a char, clear again
nop
nop
cli
mov srcpnt,offset source ; receive circular buffer
mov count,0 ; receive circular buffer
mov xmtcnt,0 ; network output buffer count
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
; Upgraded for Topview compatibility. [jrd]
CLEARL PROC NEAR
push ax
push bx
push dx
mov ah,3 ; Clear to end of line
mov bh,0
int video ; Get current cursor position into dx
mov ax,dx ; Topview compatible clear line
mov bh,ah ; same row
mov bl,byte ptr low_rgt ; last column
call atsclr ; clear from ax to bx, screen coord
pop dx
pop bx
pop ax
ret
CLEARL ENDP
; This routine blanks the screen. Returns normally.
; Upgraded to Topview compatiblity. [jrd]
CMBLNK PROC NEAR
push ax
push bx
xor ax,ax ; from screen loc 0,0
mov bx,low_rgt ; to end of text screen (lower right corner)
inc bh ; include status line
call atsclr ; do Topview compatible clear, in msyibm
pop bx
pop ax
ret
CMBLNK ENDP
; Locate: homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen
jmp poscur
LOCATE ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
push ax
push bx
mov ah,2 ; Position cursor
mov bh,0 ; page 0
int video
pop bx
pop ax
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
BEEP PROC NEAR
push ax
push cx
mov al,10110110B ; Gen a short beep (long one losses data.)
out timercmd,al ; set Timer to to mode 3
mov ax,1512 ; divisor, for frequency
out timer2data,al ; send low byte first
mov al,ah
out timer2data,al
in al,ppi_port ; get 8255 Port B setting
or al,3 ; turn on speaker and timer
out ppi_port,al ; start speaker and timer
push ax
mov ax,40 ; 40 millisecond beep, calibrated time
call pcwait
pop ax
in al,ppi_port
and al,0fch ; turn off speaker and timer
out ppi_port,al
pop cx
pop ax
ret
BEEP ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push ax ; save regs
push bx
push cx
push dx ; preserve message
mov bl,scbattr ; screen attributes at Kermit init time
and bl,77h ; get colors, omit bright and blink
rol bl,1 ; interchange fore and background
rol bl,1
rol bl,1
rol bl,1
mov bh,0 ; preset page 0
mov temp,bx ; temp = page 0, reverse video
mov dx,low_rgt ; ending location is lower right corner
inc dh ; of status line
mov cx,dx ; start is status left side
xor cl,cl ; left side
mov ax,600h ; scroll to clear the line
mov bh,byte ptr temp ; set inverse video attributes
int video
mov dx,low_rgt ; last text line
inc dh ; status line
xor dl,dl ; left side
call poscur
pop si ; get message back
mov cx,1 ; only one char at a time
xor bh,bh ; page 0
cld
putmo1: lodsb ; get a byte
cmp al,'$' ; end of string?
je putmo2
push si ; save si
push ax ; and the char
call poscur
inc dl ; increment for next write
pop ax ; recover char
mov ah,9 ; try this
mov bx,temp ; page 0, inverse video
int video
pop si ; recover pointer
jmp putmo1
putmo2: pop cx
pop bx
pop ax
ret
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
push ax ; save regs
push bx
push cx
push dx
mov ax,600h ; do a scroll up
mov dx,low_rgt ; ending location is lower right corner
inc dh ; of status line
mov cx,dx ; start is status left side
xor cl,cl ; left side
;************************ modified in Dec.15,1989
mov ax,cx
mov bx,dx
call atsclr
; mov bh,scbattr ; use screen attributes at Kermit init time
; int video
;************************ modified in Dec.15,1989
pop dx
pop cx
pop bx
pop ax
ret
clrmod endp
; put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push bx ; save regs
push cx
push dx
push si
push ax ; preserve this
cld
mov bl,scbattr ; screen attributes at Kermit init time
and bl,77h ; get colors, omit bright and blink
rol bl,1 ; interchange fore and background
rol bl,1
rol bl,1
rol bl,1
mov bh,0 ; preset page 0
mov temp,bx ; temp = page 0, reverse video
mov si,ax ; point to it
mov dh,1 ; init counter
puthl1: lodsb ; get a byte
cmp al,lf ; linefeed?
jne puthl2 ; no, keep going
inc dh ; count it
jmp puthl1 ; and keep looping
puthl2: cmp al,0 ; end of string?
jne puthl1 ; no, keep going
mov ax,600h ; scroll to clear window
xor cx,cx ; from top left
mov dl,4fh ; to bottom right of needed piece
mov bh,70h ; inverse video
mov bh,bl ; inverse video
int video
call locate ; home cursor
mov bx,0070h ; bh = page 0, bl = inverse video
mov bx,temp
mov cx,1 ; one char at a time
cld ; scan direction is forward
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
push si ; save around bios call
cmp al,' ' ; printable?
jb puth21 ; b = no
mov ah,9 ; write char at current cursor position
int video ; do the Bios int 10h call
inc dl ; point to next column
jmp puth23 ; move cursor there
puth21: cmp al,cr ; carriage return?
jne puth22 ; ne = no
xor dl,dl ; set to column zero
jmp puth23
puth22: cmp al,lf ; line feed?
jne puth23
inc dh ; go to next line
puth23: mov ah,2 ; set cursor position to dx
int video
pop si ; restore pointer
jmp puthl3 ; and keep going
puthl4: mov dh,byte ptr low_rgt+1 ; go to last line
inc dh
xor dl,dl
call poscur ; position cursor
pop si
pop dx
pop cx
pop bx
ret
puthlp endp
; begin Terminal set & status code
; SET Term parameters, especially for use with VT100 emulator. [jrd]
; Taken from work done originally by James Harvey IUPUI.
; VTS is called only by mssset to set terminal type and characteristics.
; Enter via direct jmp. Exit rskp for success, ret for failure.
VTS proc near ; SET TERM whatever
mov ah,cmkey ; Parse another keyword
; mov bx,offset vthlp ; Use this help
mcmsgb vthlp,cvthlp
mov dx,offset vttbl ; Use this table
call comnd
jmp r
nop
cmp bh,1H ; marker for terminal type?
je vsetu0 ; e = yes
cmp bh,2h ; marker for set term color?
jne vset1 ; ne = no
jmp vsetu2 ; e = yes
vset1: cmp bh,3h ; marker for character set?
je vsetu3 ; e = yes
cmp bh,4h ; marker for roll back control?
je vsetu4 ; e = yes
cmp bh,10h ; marker for clear-screen?
jne vset1a ; ne = no
mov ah,cmcfm ; yes
call comnd
jmp r
nop
mov vtclear,1 ; set trigger for emulator startup
jmp rskp ; return successfully
vset1a: cmp bh,8h ; marker for graphics type?
jne short vsetu1 ; ne = no, dispatch on bl
jmp vsetu8 ; yes
vsetu0: mov temp,bx ; set terminal type
mov ah,cmcfm
call comnd ; Get a confirm
jmp r ; Didn't get a confirm
nop
mov bx,temp
mov flags.vtflg,bl ; Set the terminal emulation type
mov tekflg,0 ; clear Tek sub mode
jmp rskp
vsetu1: mov bh,0 ; remove marker bits in bh
shl bx,1 ; Make bx a word index
jmp vtrtns[bx] ; Dispatch
vsetu3: mov ah,cmkey ; Set Term character set
mov bx,0 ; Use character set table for help
mov dx,offset chatab ; Use character set table
call comnd
jmp r ; failure
nop
mov temp,bx
mov ah,cmcfm ; get a confirm
call comnd
jmp vsetu0 ; did not get a confirm
nop
mov ax,temp ; recover value
mov vtemu.vtchset,al ; set default character set
jmp rskp ; return successfully
vsetu4: mov ah,cmkey ; Set Term Roll On/Off, auto roll back
mov bx,0 ; Use on/off table as help
mov dx,offset ontab ; Use on/off table
call comnd
jmp r ; bad keyword
nop
mov temp,bx
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; did not get a confirm
nop
mov bx,temp
mov vtroll,bl ; set roll state (0=no auto rollback)
jmp rskp ; return successfully
; Set Term Color foreground, background
vsetu2: mov ah,cmtxt ; get number(s) after set term color
; mov dx,offset colhlp ; use this help
mcmsg colhlp,ccolhlp
mov bx,offset rdbuf ; temp buffer
mov rdbuf,0 ; clear the buffer
call comnd
jmp r
nop
cmp ah,0 ; text given?
jne vsetu2a ; ne = yes
mov ah,prstr
; mov dx,offset erms41 ; say need more parameters
mcmsg erms41,cerms41
int dos
jmp rskp
vsetu2a:mov bx,vtemu.att_ptr ; get address of attributes byte
mov bl,[bx] ; get attributes
mov byte ptr temp,bl ; save in work temp
mov si,offset rdbuf ; si = place where atoi wants text
jmp vsetu2b ; analyze
colbad: mov ah,prstr ; not in range - complain and exit
; mov dx,offset colerr
mcmsg colerr,ccolerr
int dos
jmp rskp
vsetu2x:mov al,byte ptr temp ; get current attributes
mov bx,vtemu.att_ptr ; get address of attributes byte
mov [bx],al ; store attributes
jmp rskp ; and return normally
vsetu2b:mov dx,si ; analyze values
call strlen ; current length of text to cx
jcxz vsetu2x ; z = nothing left
vsetu2c:cmp byte ptr[si],' ' ; scan off leading spaces
jne vsetu2d ; ne = non-blank text found
inc si ; look at next char
loop vsetu2c ; cx characters to examine
jcxz vsetu2x ; z = nothing left
vsetu2d:mov ah,cl ; put length where atoi wants it
call atoi ; convert text to numeric in ax
jmp colbad ; no value available
nop
cmp ax,0 ; reset all? regular IBM CGA refresh
je vsetu2j ; e = yes
cmp ax,1 ; high intensity?
je vsetu2k ; e = yes
cmp ax,10 ; fast refresh?
je vsetu2l ; e = yes
cmp ax,30 ; check range
jb colbad ; b = too small. complain
cmp ax,37
jna vsetu2f ; 30-37 is foreground color
cmp ax,40
jb colbad
cmp ax,47 ; compare as unsigned
jna vsetu2g ; 40-47 is background
jmp colbad ; else error
vsetu2h:inc si ; skip separator
cmp byte ptr[si-1],0 ; ended on null?
jne vsetu2b ; ne = no, do more
jmp vsetu2x ; e = yes, exit
vsetu2f:sub al,30 ; remove foreground bias
and byte ptr temp,not 07H ; clear foreground bits
mov bx,ax
mov al,colortb[bx] ; get reversed bit pattern
or byte ptr temp,al ; load new bits
jmp vsetu2h
vsetu2g:sub al,40 ; remove background bias
and byte ptr temp,not 70H ; clear background bits
mov bx,ax
mov al,colortb[bx] ; get reversed bit pattern
mov cl,4 ; rotate 4 positions
rol al,cl
or byte ptr temp,al ; load new bits
jmp vsetu2h
vsetu2j:mov refresh,0 ; Regular (slow) screen refresh
mov byte ptr temp,07h ; clear all, set white on black
jmp vsetu2h ; get next value
vsetu2k:or byte ptr temp,08h ; set high intensity
jmp vsetu2h ; get next value
vsetu2l:mov refresh,1 ; Fast screen refresh
jmp vsetu2h
vsetu8: mov ah,cmkey ; Set Term graphics
mov bx,0 ; Use graphics table as help
mov dx,offset graftab ; Use graphics table
call comnd
jmp r ; bad keyword
nop
mov temp,bx
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; did not get a confirm
nop
mov bx,temp
mov tekgraf,bl ; set Tek graphics board type
jmp rskp ; return successfully
; SET Term flags. These are the (near) equivalent of VT100 Setup mode values.
flgset: mov word ptr rdbuf,bx ; save index
mov ah,cmkey ; Another keyword
mov dx,vtable[bx] ; The table to use
mov bx,0 ; Use default help
call comnd
jmp r
nop
mov temp,bx ; Save switch value
mov ah,cmcfm ; Confirm it
call comnd
jmp r
nop
mov dx,temp ; Restore switch value
mov bx,word ptr rdbuf ; And index
shr bx,1 ; Make it a byte index
mov al,vtsflg[bx] ; Get the flag
cmp dx,0 ; Set or clear?
je flgse1 ; Go clear it
or vtemu.vtflgst,al ; Set the flag
or vtemu.vtflgop,al ; in runtime flags too
jmp rskp ; Give good return
flgse1: not al ; Complement
and vtemu.vtflgst,al ; Clear the indicated setup flag
and vtemu.vtflgop,al ; Clear the indicated runtime flag
jmp rskp ; Give good return
; SET Term Tabstops Clear ALL
; SET Term Tabstops Clear AT n1, n2, ..., nx
; SET Term Tabstops At n1, n2, ..., nx
tabset: cld ; Make sure this is clear
mov di,offset decbuf ; clear our temp work area here
mov cx,132 ; 132 columns
mov al,0 ; set "not touched" indicator
rep stosb ; in all decbuf slots
mov ah,cmkey ; Parse keyword
; mov bx,offset clrhlp ; help text
mcmsgb clrhlp,cclrhlp
mov dx,offset tabtab ; table
call comnd
jmp r
nop
mov clrset,2 ; code for set a tab
cmp bl,0 ; Was it set or clear?
jne tabse1 ; SET - go parse column number(s)
mov clrset,1 ; code for clear at/all tab(s)
mov ah,cmkey ; CLEAR - parse ALL or AT
; mov bx,offset clrhlp ; Use this help text
mcmsgb clrhlp,cclrhlp
mov dx,offset alltab ; Parse ALL or AT
call comnd
jmp r
nop
cmp bx,0 ; ALL?
jne tabse1 ; ne = AT, clear at specific places
mov ah,cmcfm ; Confirm the ALL
call comnd
jmp r
nop
mov al,1 ; ALL, means clear all tab stops
mov cx,132 ; use 132 columns
mov di,offset decbuf
cld
rep stosb
jmp tabcpy ; update active & coldstart tabs
tabse1:
; mov dx,offset clrhlp ; Tell them we want a column number
mcmsg clrhlp,cclrhlp
mov ah,cmtxt ; get text w/o white space
mov bx,offset rdbuf ; temp buffer
call comnd
jmp r
nop
cmp ah,0 ; anything given?
jne tabse2 ; ne = yes
mov ah,prstr
; mov dx,offset erms41 ; say need more parameters
mcmsg erms41,cerms41
int dos
jmp rskp
tabse2: mov si,offset rdbuf ; si = place where atoi wants text
tabse3: mov dx,si
call strlen ; cx = current length of text
jcxz tabcpy ; z = nothing left
mov ah,cl ; put length where atoi wants it
call atoi ; convert text to numeric in ax
jmp tabcpy ; no number available
nop
mov bx,ax ; for subscripting in code below
dec bx ; put column in range 0-131
cmp bx,0 ; check range (1-132 --> 0-131)
jl tbsbad ; l = too small. complain
cmp bl,132-1 ; more than the right most column?
jna tabse4 ; na = no, is ok
tbsbad: mov ah,prstr ; not in range - complain and exit
; mov dx,offset tbserr
mcmsg tbserr,ctbserr
int dos
jmp rskp
tabse4: mov al,clrset ; get value for setting or clearing
mov decbuf[bx],al ; store in tabs temp work array
cmp byte ptr [si],':' ; start-column:spacing notation?
jne tabse3 ; ne = no, get next tab stop
inc si ; skip colon, do start:space analysis
mov temp,bx ; save reg around atoi call
mov dx,si ; string address for strlen
call strlen ; get remaining string length into cx
jcxz tabcpy ; z = no space value, all done here
mov ah,cl ; ah = string length for atoi
call atoi ; get space value into ax
jmp tabcpy ; no number available
nop
mov bx,temp
mov cx,ax ; "space" value
cmp cx,0 ; zero spacing?
jne tabse4a ; ne = no
inc cx ; don't get caught with zero spacing
tabse4a:mov al,clrset ; get tab set or clear indicator
tabse5: add bx,cx ; new column value
cmp bx,132-1 ; largest tab stop
ja tabcpy ; a = done largest tab stop
mov decbuf[bx],al ; store set or clear indicator
jmp short tabse5 ; finish spacing loop, then do tabcpy
tabcpy: mov cx,132 ; update all active tab stops
mov si,vtemu.vttbst ; in terminal emulator's active buffer
mov di,vtemu.vttbs ; and in the cold-start buffer
mov bx,0 ; subscript
tabcpy1:mov al,decbuf[bx] ; get a table entry into al
or al,al ; what is the code?
jz tabcpy3 ; z = do not touch
cmp al,2 ; set a tab?
je tabcpy2 ; e = set the tab
mov byte ptr [bx+si],0 ; clear the tab
mov byte ptr [bx+di],0 ; clear the tab
jmp short tabcpy3
tabcpy2:mov byte ptr [bx+si],0ffh ; set the tab
mov byte ptr [bx+di],0ffh ; set the tab
tabcpy3:inc bx ; inc subscript
loop tabcpy1
jmp rskp ; Give good return
VTS endp ; end of Set Term things
; Terminal Status display, called within STAT0: in MSSSET
VTSTAT proc near ; enter with di within sttbuf, save bx
push bx
; mov bx,offset vtstbl ; table of things to show
mcmsgb vtstbl,cvtstbl
call statc ; status common code, in mssset
nop
nop
nop
pop bx
ret ; return to STAT0: in MSSSET
colstat proc near ; foreground/background color status
push si
; mov si,offset colst1
mcmsgsi colst1,ccolst1
cld
colstd1:lodsb
cmp al,'$' ; end of string?
je colstd2 ; e = yes
stosb
jmp short colstd1
colstd2:mov bx,vtemu.att_ptr ; pointer to attributes byte
mov bl,byte ptr[bx]
mov bh,0
push bx
and bx,7 ; get foreground set
mov al,colortb[bx] ; get reversed bit pattern
add al,'0' ; add ascii bias
stosb
pop bx
; mov si,offset colst2
mcmsgsi colst2,ccolst2
colstd3:lodsb
cmp al,'$'
je colstd4
stosb
jmp short colstd3
colstd4:mov cl,4 ; rotate 4 positions
shr bl,cl
and bx,7 ; get background set
mov al,colortb[bx] ; get reversed bit pattern
add al,'0' ; add ascii bias
stosb
pop si
ret
colstat endp
; Tabs Status display
tabstat proc near ; display tabs ruler for Status
push dx
cld
tabstd2:mov al,cr
stosb
tabsta0:mov si,vtemu.vttbst ; active tabs address, not shadow
mov cl,byte ptr low_rgt ; loop screen width-1 times
xor ch,ch ; clear high byte
dec si ; dec for inc below
xor ax,ax ; tens counter
tabsta1:mov dl,'.' ; default position symbol
inc si ; start with position 1
inc al
cmp al,10 ; time to roll over?
jb tabsta2 ; b = not yet
mov al,0 ; modulo 10
inc ah
mov dl,ah ; display a tens-digit
add dl,'0'
cmp dl,'9' ; larger than 90?
jbe tabsta2 ; be = no
sub dl,10 ; roll over to 0, 1, etc
tabsta2:cmp byte ptr [si],0 ; is tab set?
je tabsta3 ; e = no
mov dl,'T' ; yes, display a 'T'
tabsta3:push ax
mov al,dl
stosb
pop ax
loop tabsta1 ; loop til done (cx has count)
pop dx
ret
tabstat endp
filler proc near ; use space
mov cx,20
mov al,' '
rep stosb
ret
filler endp
VTSTAT endp ; end of Terminal set & status code
; Compute number of iterations needed in procedure pcwait inner loop
; to do one millisecond delay increments. Uses Intel 8253/8254 timer chip
; (timer #2) to measure elapsed time assuming 1.193182 MHz clock.
; Called by serini below. For IBM PC compatible machines.
; Regs preserved. 16 April 87 [jrd]
pcwtst proc near
push ax
push cx
push dx
mov pcwcnt,256 ; software loop, initial value
in al,ppi_port ; 8255 chip port B, 61h
and al,0fch ; speaker off (bit 1), stop timer (bit 0)
out ppi_port,al ; do it
; 10 = timer 2, 11 = load low byte then high byte, 010 = mode 2, 0 = binary
mov al,10110100B ; command byte
out timercmd,al ; timer command port, 43h
xor al,al ; clear initial count for count-down
out timer2data,al ; low order byte of count preset, to port 42h
out timer2data,al ; high order byte, to the same place
in al,ppi_port ; get 8255 setting
mov dl,al ; remember it in dl
and al,0fch ; clear our control bits
or al,1 ; start counter now (Gate = 1, speaker is off)
out ppi_port,al ; do it, OUT goes low
; this is the test loop
mov ax,8 ; wait 8 millisec
call pcwait ; call the software timer
; end test loop
mov al,dl ; restore ppi port, stop timer
out ppi_port,al
in al,timer2data ; read count down value
xchg al,ah ; save low order byte
in al,timer2data ; get high order byte
xchg ah,al ; put in correct sequence
neg ax ; subtract from zero to get elapsed tics
xor dx,dx ; clear high order divisor
add ax,1193/2 ; round up
adc dx,0 ; for very very slow machines
mov cx,1193 ; tics per millisec
div cx ; count / 1193 yields millisecs, quo=ax
mov cx,ax ; retain whole number of milliseconds
mov ax,pcwcnt ; get current pcwait inner loop count
xor dx,dx ; clear high order field for division
shl ax,1
rcl dx,1
shl ax,1
rcl dx,1
shl ax,1
rcl dx,1 ; dx:ax = current counter times 8 loops
cmp cx,0 ; no millisec? (super speed machines)
ja pcwtst1 ; a = some
inc cx ; use at least one
pcwtst1:div cx ; divide by observed milliseconds
mov pcwcnt,ax ; store quotient as new inner loop counter
pop dx
pop cx
pop ax
ret
pcwtst endp
;; Wait for the # of milliseconds in ax, for non-IBM compatibles.
;; Thanks to Bernie Eiben for this one. Modified to use adjustable
; inner loop counter (pcwcnt, adjusted by proc pcwtst) by [jrd].
pcwait proc near
push cx
pcwai0: mov cx,pcwcnt ; inner loop counter for 1 ms (240 @ 4.77 MHz)
pcwai1: sub cx,1 ; inner loop takes 20 clock cycles
jnz pcwai1
dec ax ; outer loop counter
jnz pcwai0 ; wait another millisecond
pop cx
ret
pcwait endp
; set the current port.
; Note: serial port addresses are found by looking in memory at 40:00h and
; following three words for COM1..4, resp. All UARTS are assumed to follow
; std IBM addresses relative to 03f8h for COM1, and actual address are offset
; from value found in segment 40h. Global byte flags.comflg is 1,2,3,4 for
; COM1..4, and is 'N' for Network.
; If address 02f8h is found in 40:00h then name COM1 is retained but COM2
; addressing is used to access the UART and a notice is displayed. IRQ 3
; or IRQ 4 is sensed automatically for any COMx port.
COMS PROC NEAR
mov dx,offset comptab ; table of legal comms ports
mov bx,0 ; no extra help text
mov ah,cmkey ; parse key word
call comnd
jmp r ; failed
mov temp,bx
cmp bl,'N' ; NetBios network?
je comstrt ; yes, get another item for networks
cmp bl,'U' ; Ungermann Bass net?
je comstrt ; e = yes
mov ah,cmcfm ; non-network
call comnd ; Get a confirm
jmp r ; Didn't get a confirm
nop
mov bx,temp
COMSTRT:cmp portin,-1 ; first time here?
jne comst1 ; ne = no
mov portin,0 ; say have been here before
comst1: mov temp,bx
cmp bl,'N' ; NetBios network?
jne comst2 ; ne = no
jmp comsn ; yes, get another item for networks
comst2: cmp bl,'U' ; Ungermann Bass net?
jne comst3 ; ne = no
jmp comsub
comst3: cmp flags.comflg,'N' ; have been running on network?
jne coms1b ; ne = no
; turn off sources of net interrupts
mov bx,offset can ; cancel outstanding requests
mov can.scb_cmd,ncancel ; set cancel op code
cmp lposted,1 ; listen outstanding?
jne coms1a ; ne = no
mov can.scb_baddr,offset lsn ; cancel listen
call session
mov lposted,0
coms1a: cmp rposted,1 ; receive outstanding?
jne coms1b ; ne = no
mov can.scb_baddr,offset rcv ; cancel receive
call session
mov rposted,0 ; clear interlock flag
coms1b: call serrst ; close current comms port
mov bx,temp ; get port number/letter
mov flags.comflg,bl ; remember port number
mov bh,0
mov bl,flags.comflg ; get COMx number (1-4)
push bx ; Set UART port addresses
mov ax,bx ; get COMx (1-4)
cmp al,'1' ; ascii numbered Bios port?
jb coms3 ; b = no
sub al,'0' ; remove ascii bias for portinfo
coms3: dec ax ; count ports from zero
mov bx,type prtinfo ; size of each portinfo structure
mul bx ; times port number
add ax,offset port1 ; plus start of COM1
mov portval,ax ; points to our current port struct
pop bx ; restore registers
cmp bl,' ' ; doing forced Bios?
jb coms4 ; b = no, hardware
mov clone,'B' ; set clone flag for Bios usage
jmp rskp ; all done
coms4: push bx ; save register
push es
mov ax,40h ; look at RS232_base [bx] in Bios area 40:00h
mov es,ax
dec bl ; count com1 as bl = 0, etc
mov bh,0 ; clear high byte
shl bx,1 ; make bx a word index
mov ax,es:[bx] ; get modem base address into ax
pop es
pop bx
or ax,ax ; is address zero?
je comsf ; e = yes, no serial port
comsc: ; hardware tests
mov modem.mddat,ax ; set base address (also data address) 03f8h
add ax,3 ; increment to command port 03fbh
mov modem.mdcom,ax ; set line control register address
mov brkadr,ax ; where to send break command
add ax,2 ; increment to status port 03fdh
mov modem.mdstat,ax ; set line-status port address
call chkport ; get type of UART support (for Clone)
jnc comsu ; nc = has a real 8250 uart
add flags.comflg,'0' ; COMn to BIOSn
push ax ; else tell user about Bios pathway
push dx
mov ah,prstr
; mov dx,offset biosmsg
mcmsg biosmsg,cbiosmsg
int dos
pop dx
pop ax
jmp rskp
comsu: call chkint ; find IRQ for the port
jc comsf ; c = not found, an error conditon
jmp rskp
comsf:
; mov dx,offset badprt ; say port is not available
mcmsg badprt,cbadprt
mov ah,prstr
int dos
mov al,flags.comflg ; port ident character
cmp al,' ' ; binary for COM series
jae comsf1 ; ae = no
mov dx,offset compt ; display COM
int dos
mov ah,conout
mov dl,flags.comflg
add dl,'0' ; display port number
int dos
jmp comsf3
comsf1: cmp al,'9' ; ascii numeric for Bios series?
ja comsf2 ; a = no
mov dx,offset biospt ; display BIOS
int dos
mov ah,conout
mov dl,flags.comflg ; ascii port number
int dos
jmp comsf3
comsf2:
; mov dx,offset unkpt ; unknown type
mcmsg unkpt,cunkpt
int dos
comsf3: mov flags.comflg,0 ; bad port, reassign to null port
mov ah,prstr
; mov dx,offset badprt2 ; the rest of the message
mcmsg badprt2,cbadprt2
mov ah,prstr
int dos
stc ; say error
jmp rskp
; NetBios Network support
comsn: mov ah,cmfile ; get a word (remote node name)
mov dx,offset nambuf ; work buffer
mov word ptr nambuf,0 ; insert terminator
; mov bx,offset nethlp ; help message
mcmsgb nethlp,cnethlp
call comnd ; get the name
nop
nop
nop
xchg ah,al ; put byte count in al
xor ah,ah ; clear junk
mov temp,ax ; save number of chars entered
mov ah,cmcfm
call comnd ; Get a confirm
jmp r ; Didn't get a confirm
nop
call serrst ; reset serial port
call chknet ; start network usage
cmp pcnet,0 ; is network alive (non-zero)?
jne comsn4 ; ne = yes
stc
jmp rskp ; return failure
comsn4: mov portval,offset portn ; set Network port data structure address
mov flags.comflg,'N' ; Set the comm port flag
call chkport ; set type of port support
clc ; return success
jmp rskp ; End NetBios
; Ungermann-Bass terminal port [ohl +]
comsub: mov ah,cmcfm
call comnd ; Get a confirm
jmp r ; Didn't get a confirm
nop
call serrst ; reset serial port
call chkub ; check UB network presence
jnc comsub1 ; nc = present
stc
jmp rskp ; return failure
comsub1:call netclose ; better close NetBios parts NOW!
mov portval,offset portn ; set Network port data structure address
mov flags.comflg,'U' ; Set the comm port flag
mov pcnet,2 ; network is present and active
mov lclexit,offset ubclose ; address to close network
call chkport ; get type of port support
clc ; return success
jmp rskp ; End Ungermann Bass [ohl -]
COMS ENDP
; Check which Interrupt ReQuest line the port uses. Technique: allow interrupt
; on transmitter holding register empty, test for that condition first with
; IRQ 4 and then IRQ 3. Returns with IRQ values set and carry clear if success
; or carry set if failure. [jrd]
chkint proc near
cmp flags.comflg,2 ; COM1 or COM2?
jbe chkin2 ; be = yes, use standard IRQ's
mov modem.mddis,MDMINTC ; IRQ 4 test. mask to disable IRQ 4
mov modem.mden,MDMINTO ; mask to enable IRQ 4
mov modem.mdmeoi,20h ; use general in case we guess wrong
mov modem.mdintv,MDMINTV ; IRQ 4 interrupt vector (0ch)
mov intkind,0 ; clear interrupt cause
call serini ; setup port for IRQ 4
jc chkint2 ; c = failure
mov dx,modem.mddat
inc dx ; interrupt enable reg (3f9h)
mov al,2 ; set xmtr holding reg empty interrupt
out dx,al
mov ax,1 ; wait one millisec for interrupt
call pcwait ; to occur
test intkind,2 ; check cause of interrupt, ours?
jz chkint2 ; z = no, try other IRQ
call serrst ; reset port
mov modem.mdmeoi,EOICOM ; use specific EOI for IRQ4 level
clc ; this setup worked
ret
; IRQ 3 test
chkint2:call serrst ; reset port
mov modem.mddis,MDINTC2 ; mask to disable IRQ 3
mov modem.mden,MDINTO2 ; mask to enable IRQ 3
mov modem.mdmeoi,20h ; use general in case we guess wrong
mov modem.mdintv,MDINTV2 ; IRQ 3 interrupt vector
mov intkind,0 ; clear interrupt cause
call serini ; setup port for IRQ 3
jc chkin2 ; c = failure
mov dx,modem.mddat
inc dx ; interrupt enable reg (3f9h)
mov al,2 ; set xmtr holding reg empty interrupt
out dx,al
mov ax,1 ; wait one millisec for interrupt
call pcwait ; to occur
test intkind,2 ; check cause of interrupt, ours?
jz chkin2 ; z = no, so no interrupts for port
call serrst ; reset port
mov modem.mdmeoi,EOICOM2 ; use specific EOI for IRQ 3 level
clc ; this setup worked
ret
chkin2: call serrst ; reset port, auto test did not work
cmp flags.comflg,1 ; COM1?
je chkin4 ; e = yes, use IRQ 4
cmp isps2,0 ; IBM PS/2 Model 50 or above?
jne chkin3 ; ne = yes, other COMs use IRQ 3
cmp flags.comflg,3 ; COM2, COM3, or COM4?
je chkin4 ; e = COM3, use IRQ 4
jmp short chkin3 ; else COM2 or COM4, use IRQ 3
chkin4: cmp modem.mddat,02f8h ; really COM2 material for PCjr?
je chkin3 ; e = yes, use COM2 addresses
mov modem.mdmeoi,EOICOM ; use specific EOI for IRQ4 level
mov modem.mddis,MDMINTC ; IRQ 4 test. mask to disable IRQ 4
mov modem.mden,MDMINTO ; mask to enable IRQ 4
mov modem.mdintv,MDMINTV ; IRQ 4 interrupt vector (0ch)
jmp short chkin5
chkin3: mov modem.mdmeoi,EOICOM2 ; use specific EOI for IRQ 3 level
mov modem.mddis,MDINTC2 ; mask to disable IRQ 3
mov modem.mden,MDINTO2 ; mask to enable IRQ 3
mov modem.mdintv,MDINTV2 ; IRQ 3 interrupt vector
chkin5: clc
ret
chkint endp
; Test presently selected serial port for having a real 8250 UART.
; Return carry clear and clone = 0 if 8250 present,
; else carry set and clone = 'B' for system Bios or
; carry set and clone = 'N' for network.
; Method is to check UART's Interrupt Identification Register for high
; five bits being zero; IBM does it this way. Assumes port structure
; has been initialized with addresses of UART. 21 Feb 1987 [jrd]
; 29 May 1987 Add double check by reading Line Status Register. [jrd]
chkport proc near
cmp portval,offset portn ; network?
je chkporn ; e = yes
push ax
push dx
cmp flags.comflg,0 ; undefined port?
je chkpor1 ; e = yes, assume Bios clone
mov dx,modem.mdcom ; address of UART line control reg (3FBh/2FBh)
sub dx,1 ; Interupt Identification Register address
in al,dx ; read UART's IIR
test al,0f8h ; are any of high 5 bits set?
jnz chkpor1 ; nz = yes, not an 8250
mov dx,modem.mdstat ; line status register
in al,dx ; read to clear UART BI, FE, PE, OE bits
jmp $+2 ; pause, for chip access timing
in al,dx ; these bits should be cleared
test al,8eh ; are they cleared?
jnz chkpor1 ; nz = no, not an 8250
mov clone,0 ; clear clone flag
pop dx
pop ax
clc ; clear carry (say 8250)
ret
chkpor1:pop dx
pop ax
mov clone,'B' ; set clone flag
stc ; set carry (say no 8250)
ret
chkporn:push ax ; Networking
mov al,flags.comflg ; get port letter
mov clone,al
pop ax
stc ; set carry (say no 8250)
ret
chkport endp
;;;;;;;;;;;;;;;;;;;;;; end of part one of msxibm.asm
;;;;;;;;;;;;;;;;;;;;;; start part two of msxibm.asm
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
DOBAUD PROC NEAR
cmp portin,-1 ; port not used yet?
jne dobd3 ; ne = no, go get rate
mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT command now
ret ; failed to set port
nop
nop
dobd3: push ax ; save some regs
push bx
push dx
call chkport ; check port for real 8250 UART (clone = 0)
cmp flags.comflg,'N' ; Netbios?
je dobd1 ; e = yes, do nothing here
cmp flags.comflg,'U' ; UB network?
je dobd1 ; e = yes
mov bx,portval ; pointer to port data structure
mov temp,ax ; Don't overwrite previous rate
mov ax,[bx].baud ; Check if new rate is valid
shl ax,1 ; make a word index
mov bx,offset bddat ; Start of table
cmp clone,'B' ; running on clone?
jne dobd0a ; ne = no
mov bx,offset clbddat ; use Bios speed parameters for clone
dobd0a: add bx,ax
mov ax,[bx] ; The data to output to port
cmp ax,0FFH ; Unimplemented baud rate
jne dobd0
mov ah,prstr
; mov dx,offset badbd ; Give an error message
mcmsg badbd,cbadbd
int dos
jmp dobd1
dobd0: cmp clone,0 ; running on a real uart?
je dobd2 ; e = the real thing
mov dx,0 ; assume port 1 Clone: find current port
mov dl,flags.comflg ; get coms port (1..4)
or dl,dl ; zero (undefined port)?
jz dobd1 ; z = yes, just exit
and dl,7 ; use lower three bits
dec dl ; count ports as 0..3 for Bios
mov ah,0 ; set serial port
int rs232 ; Bios: set the parameters
jmp dobd1 ; and exit
dobd2: mov temp,ax ; Remember value to output
mov dx,modem.mdcom ; LCR -- Initialize baud rate
in al,dx ; get it
mov bl,al ; make a copy
or ax,80H ; turn on DLAB bit to access divisor part
out dx,al
mov dx,modem.mddat
mov ax,temp ; set the baud rate divisor, low byte
out dx,al
inc dx ; next address for high part
mov al,ah ; set high part of divisor
out dx,al
mov dx,modem.mdcom ; LCR again
mov al,bl ; get original setting from bl
out dx,al ; restore it
dobd1: pop dx ; restore regs
pop bx
pop ax
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
GETBAUD PROC NEAR
cmp portin,-1 ; port not used yet?
jne getb4 ; ne = no, go get rate
mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT command now
ret ; failed to set port
nop
nop
getb4: cmp clone,0 ; non-clone
je getbud ; e = yes, real thing
ret ; have semi-clone, no bios feedback
getbud: push ax ; save some regs
push bx
push cx
push dx
mov dx,modem.mdcom ; Get current Line Control Register value
in al,dx
mov bl,al ; Save it
or ax,80H ; Turn on to access baud rate generator
out dx,al
mov dx,modem.mddat ; Divisor latch
inc dx
in al,dx ; Get hi order byte
mov ah,al ; Save here
dec dx
in al,dx ; Get lo order byte
push ax
mov dx,modem.mdcom ; Line Control Register
mov al,bl ; Restore old value
out dx,al
pop ax
cmp ax,0FFFFH ; Who knows what this is
je getb2
mov bx,offset bddat ; Find rate's offset into table
mov cl,0 ; Keep track of index
getb0: cmp ax,[bx]
je getb1
inc cl
cmp cl,baudlen ; At the end of the list
jge getb2
add bx,2
jmp getb0
getb1: mov ch,0
mov bx,portval
mov [bx].baud,cx ; Set baud rate
jmp getb3
getb2: mov ah,prstr
; mov dx,offset erms40
mcmsg erms40,cerms40
int dos
getb3: pop dx ; restore regs
pop cx
pop bx
pop ax
ret
GETBAUD ENDP
; Get Char from serial port buffer.
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
; Revised 22 May 1986, and again slightly 2 August 1986 by [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 25 April 1987 Add Netbios support, remove test for NUL and DEL. [jrd]
PRTCHR PROC NEAR
cmp holdscr,0 ; Holdscreen in effect?
jne prtch0a ; ne = yes, do not read
call chkxon ; see if we need to xon
cmp clone,'B' ; running on a semi-clone?
je prtch6 ; e = yes
cmp clone,'N' ; running on NetBios network?
je prtchn ; e = yes
cmp clone, 'U' ; running Ungermann-Bass port? [ohl]
jne prtch0 ; ne = no
prtchn: test xofsnt,usron ; user level xoff sent?
jnz prtch0a ; nz = yes, suppress reading here
cmp count,mntrgl ; below low water mark?
ja prtch1 ; a = no, read current buffer
cmp clone,'U' ; UB network?
jne prtchn1 ; ne = no
call ubrecv ; do a UB receive
jmp short prtch0
prtchn1:call receive ; do a NetBios receive (asynchronous)
jc prtch0a ; c = failure
prtch0: cmp count,0 ; any characters available?
jnz prtch1 ; nz = yes, get one
prtch0a:mov dx,0 ; return count of zero
jmp rskp ; No data - check console
prtch1: push si ; save si
cli ; interrupts off, to keep srcpnt & count consistent
mov si,srcpnt ; address of next available slot in buffer
sub si,count ; minus number of unread chars in buffer
cmp si,offset source ; located before start of buf?
jae prtch2 ; ae = no
add si,bufsiz ; else do arithmetic modulo bufsiz
prtch2: mov al,byte ptr [si] ; get a character into al
dec count ; one less unread char now
sti ; interrupts back on now
pop si
mov dx,count ; return # of chars in buffer
jmp prtch12 ; screen delivered characters
prtch6: ; Semi-clone, use Bios calls
mov dx,0 ; assume port 1 Clone: find current port
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz prtch8 ; z = yes, don't access it
and dl,7 ; use low three bits
dec dl ; address ports as 0..3 for Bios
prtch7: mov ah,3 ; check port status
int rs232 ; Clone Bios call
test ah,mdminp ; data ready?
jnz prtch9 ; nz = yes, get one
prtch8: mov dx,0 ; return count of zero
mov count,dx
jmp rskp ; No data
prtch9: mov ah,2 ; receive a char into al
int rs232 ; Clone Bios call
test ah,8ch ; timeout, framing error, parity error?
jnz prtch8 ; nz = error, no char
mov dx,1
mov count,dx ; one char received into al
cmp al,flowoff ; acting on Xoff?
jne prtch10 ; ne = no, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF?
jne prtch8 ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; Set the flag saying XOFF received
jmp prtch8 ; and exit
prtch10:cmp al,flowon ; acting on Xon?
jne prtch12 ; ne = no, go on
mov xofrcv,off ; Clear the XOFF received flag
jmp short prtch8 ; no data to return
prtch12:test flags.debug,logses ; debug mode?
jnz prtch14 ; nz = yes, pass all chars
cmp rxtable+256,0 ; translation turned off?
jne prtch14 ; ne = table is on, pass all chars
cmp al,0 ; NUL?
je prtch13 ; e = yes, ignore it
cmp tekflg,0 ; Tek emulation active?
jne prtch14 ; ne = yes, pass DEL
cmp al,DEL ; DEL char
jne prtch14 ; ne = no, pass char
prtch13:mov dx,0
jmp rskp ; no chars
prtch14:ret ; return char in al
PRTCHR ENDP
; Network Receive packet routine. Request a net packet with no-wait option.
; Return carry clear if success. If failure, reset serial port (Server mode
; reinits serial port) and return carry set. No entry setup needed.
RECEIVE PROC NEAR ; receive network session pkt
cmp pcnet,1 ; net ready yet?
jbe receiv3 ; be = no, declare a broken session
cmp rposted,1 ; is a request outstanding now?
jae receiv4 ; ae = yes, don't do another
mov rposted,1 ; say posting a receive now
mov rcv.scb_length, length rcvbuf ; length of input buffer
mov rcv.scb_cmd,nreceive+nowait ; receive, no wait
push bx
mov bx,offset rcv ; setup pointer to scb
call session
pop bx ; tests below SHOULD take time
cmp rcv.scb_err,0 ; success?
je receiv4 ; e = yes
cmp rcv.scb_err,npending ; pending receive?
je receiv4 ; e = yes
push ax ; wait one millisec before retesting
push cx
mov ax,1
call pcwait
pop cx
pop ax
cmp rcv.scb_err,06h ; message incomplete?
je receiv4 ; e = is ok (response posted later)
cmp rcv.scb_err,0 ; success now? (here for latency effects)
je receiv4 ; e = yes
cmp rcv.scb_err,18h ; session ended abnormally?
jbe receiv3 ; e = yes, b = other normal errors
push ax ; save regs around error display
push dx
mov ah,prstr
; mov dx,offset recmsg ; give error message
mcmsg recmsg,crecmsg
int dos
mov al,rcv.scb_err ; get error code
call hexout ; show error code
pop dx
pop ax
; Error return
receiv3:mov pcnet,1 ; say session is broken
call serrst ; reset serial port
test flags.remflg,dserver ; server mode?
jz receiv3a ; z = no
call serini ; reinitialize it for new session
receiv3a:stc ; say failure to receive
ret
receiv4:clc ; carry clear = success
ret
RECEIVE ENDP
; Network Receive post processing interrupt routine.
; Copy chars from rcvbuf to circular buffer source, act on xon/xoff,
; clear rposted interlock flag. At entry, CS is our code segment,
; es:bx points to scb, netbios stack, interrupts are off.
RPOST PROC NEAR ; network receive post interrupt routine
push ds ; transfers chars from net buf rcvbuf to
push ax ; main circular buffer source
push bx
push cx
push dx
push si
mov ax,datas ; reestablish datas segment
mov ds,ax
mov cx,rcv.scb_length ; get returned byte count
jcxz rpost6 ; z = nothing there
mov dh,flowon ; flow control characters, for quick ref
mov dl,flowoff
mov si,offset rcvbuf ; source of text
mov bx,srcpnt ; address of buffer storage slot
cld
rpost1: lodsb ; get byte from rcvbuf to al
or dx,dx ; doing flow control?
jz rpost3 ; z = no
mov ah,al ; get copy of character
and ah,parmsk ; strip parity, if any, before testing
cmp ah,dl ; acting on Xoff?
jne rpost2 ; ne = Nope, go on
cmp xofsnt,0 ; have we sent an XOFF?
jne rpost5 ; ne = yes, ignore this XOFF char
mov xofrcv,bufon ; Set the flag saying buffer XOFF received
jmp rpost5 ; and skip this character
rpost2: cmp ah,dh ; acting on Xon?
jne rpost3 ; ne = no, go on
mov xofrcv,off ; Clear the XOFF received flag
jmp rpost5 ; and skip this character
rpost3: mov byte ptr [bx],al ; store the new char in buffer "source"
inc bx
cmp bx,offset source + bufsiz ; beyond end of buffer?
jb rpost4 ; b = not past end
mov bx,offset source ; wrap buffer around
rpost4: cmp count,bufsiz ; filled already?
jae rpost5 ; ae = yes
inc count ; no, add a char
rpost5: loop rpost1
mov srcpnt,bx ; update pointer to next free slot
rpost6: mov rposted,0 ; clear interlock flag
pop si
pop dx
pop cx
pop bx
pop ax
pop ds
iret ; return from interrupt
RPOST endp
; Ungermann-Bass NETCI port receive characters routine. Receive one or more
; characters. Calls the Rpost routine to transfer character to main source
; circular buffer. Return carry clear if success.
UBRECV PROC near
push ax
push bx
push cx
push es
mov ax, datas
mov es, ax ; es:bx will point to rcvbuf
mov ax, nciread ; function 1 (receive) port 0 [ohl]
mov bx, offset rcvbuf
mov cx, length rcvbuf
int netci ; get characters [ohl]
stc
jcxz ubrec1 ; cx = z = nothing to do
mov rcv.scb_length, cx ; prepare for rpost call [ohl]
mov bx, offset rcv
pushf ; simulate interrupt [ohl]
push cs ; rpost is an interrupt routine (iret)
call rpost ; do Near call with preset stack
clc
ubrec1: pop es
pop cx
pop bx
pop ax
ret
UBRECV ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 25 April 1987 Add Netbios support [jrd]
; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to
; prevent confusion of flow control logic at top of outchr; used by receiver
; buffer high/low water mark flow control code. [jrd]
OUTCHR PROC NEAR
cmp flowoff,0 ; Are we doing flow control
je outch2 ; No, just continue
cmp ah,flowoff ; sending xoff?
jne outch1 ; ne = no
mov xofsnt,usron ; indicate user level xoff being sent
jmp outch1b
outch1: cmp ah,flowon ; user sending xon?
jne outch1b ; ne = no
mov xofsnt,off ; say an xon has been sent (cancels xoff)
outch1b:cmp xofrcv,off ; Are we being held (xoff received)?
je outch2 ; e = no - it's OK to go on
cmp flags.timflg,0 ; is timer off?
je outch2 ; e = yes, no timeout period
push cx ; save reg
mov 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
outch3: cmp clone,0 ; real uart?
je outch3a ; e = yes
cmp clone,'N' ; network?
je outch8 ; e = yes, using netbios
cmp clone,'U' ; Ungermann Bass network?
je outch8 ; e = yes
jmp outch6 ; default for others ('B' clones)
outch3a:push cx ; Save registers
push dx
sub cx,cx
outch3b:mov dx,modem.mdstat ; Get port status
in al,dx
test al,20H ; Transmitter ready?
jnz outch4 ; Yes
jmp $+2 ; use time, prevent overdriving UART
jmp $+2
loop outch3b
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat ; use a little time
jmp $+2
out dx,al
pop dx ; exit success
pop cx
jmp rskp
outch5: pop dx ; exit failure
pop cx
ret
; finish up for semi-clones, use Bios calls
outch6: push cx ; Clone: find current port
push dx
mov dx,0 ; assume port 1
mov dl,flags.comflg ; get port number (1..4)
or dl,dl ; zero (no such port)?
jz outch5 ; z = yes, don't access it
and dl,7 ; use lower three bits
dec dl ; address ports as 0..3 for Bios
mov al,ah ; Now send it out
mov ah,1 ; send char
int rs232 ; Clone: bios send
pop dx ; exit success
pop cx
jmp rskp
outch8: ; Network sending, buffered and single char
push bx
mov bx,xmtcnt ; count of chars in buffer
mov xmtbufx[bx],ah ; put char in buffer
pop bx
inc xmtcnt ; count of items in this buffer
cmp xmtcnt,length xmtbuf ; is buffer full now?
jae outch9 ; ae = buffer is full, send it now
cmp ah,trans.seol ; end of packet?
je outch9 ; e = yes, send buffer
cmp ah,flowon ; flow control?
je outch9 ; e = yes, always expedite
cmp ah,flowoff ; ditto for flow off
je outch9
cmp ttyact,0 ; are we in Connect mode?
je outch10 ; e = no, wait for more before sending
outch9: cmp clone, 'U' ; check for UB port [ohl]
je outch12 ; e = yes [ohl]
call send ; NetBios network send routine
jc outch11 ; c = error
outch10:jmp rskp ; good exit
outch11:ret ; bad exit
outch12:call ubsend ; UB network send [ohl]
jmp rskp ; good exit [ohl]
OUTCHR ENDP
; Network Send packet routine. Send xmt scb with no-wait option. Waits
; up to 6 seconds for current Send to complete before emitting new Send.
; Failure to Send resets serial port (Server mode allows reiniting of serial
; port). Returns carry clear for success, carry set for failure.
; Enter with xmtcnt holding length of data in xmtbuf to be sent.
SEND PROC NEAR ; Network. Send session packet
cmp pcnet,1 ; network ready yet?
ja send0b ; a = net is operational
je send0c ; e = net but no session, fail
jmp send3a ; no net, fail
send0c: jmp send3 ; net but no session
send0b: cmp sposted,0 ; is a send outstanding now?
je send1 ; e = no, go ahead
push cx ; Timed test for old send being done
mov ch,trans.rtime ; receive timeout other side wants
mov cl,80h ; plus half a second
shl cx,1 ; sending timeout * 512
send0: cmp sposted,0 ; is a send outstanding now?
je send0a ; e = no, clean up and do send
push cx ; save cx
push ax ; and ax
mov ax,2 ; wait 2 milliseconds
call pcwait ; between retests
pop ax
pop cx ; loop counter
loop send0 ; repeat test
pop cx ; recover cx
jmp send3a ; get here on timeout, can't send
send0a: pop cx ; recover cx and proceed to send
send1: cmp xmtcnt,0 ; number of items to send
jne send1a ; ne = some
clc ; else don't send null packets
ret
send1a: push bx ; save bx
mov bx,xmtcnt ; buffer length
mov xmt.scb_length,bx ; tell buffer length
push cx
push si
push di
push es
push ds
pop es ; set es to datas segment
mov si,offset xmtbufx ; external buffer
mov di,offset xmtbuf ; copy for network packets
mov cx,bx ; buffer length
shr cx,1 ; divide by two (words), set carry
jnc send2 ; nc = even number of bytes
movsb ; do single move
send2: cmp cx,0
jle send2a ; le = none to do
rep movsw ; copy the data
send2a: pop es
pop di
pop si
pop cx
mov xmtcnt,0 ; say xmtbufx is available again
mov xmt.scb_cmd,nsend+nowait ; send, don't wait for completion
mov sposted,1 ; say send posted
mov bx,offset xmt ; set pointer to scb
call session
pop bx ; recover pointer to scb
; success or failure?
cmp xmt.scb_err,0 ; good return?
je send4 ; e = yes
cmp xmt.scb_err,npending ; pending?
je send4 ; e = yes
cmp xmt.scb_err,18h ; session ended abnormally?
jbe send3 ; e = yes, b = other normal errors
push ax
push dx ; another kind of error, show message
mov ah,prstr
; mov dx,offset sndmsg ; say send failed
mcmsg sndmsg,csndmsg
int dos
mov al,xmt.scb_err ; show error code (hex)
call hexout
pop dx
pop ax
; Error return
send3: mov pcnet,1 ; say session is broken
call serrst ; reset serial port
test flags.remflg,dserver ; server mode?
jz send3a ; z = no
call nethangup ; Server: purge old NAKs etc
send3a: call serini ; reinitialize it for new session
stc ; set carry for failure to send
ret
send4: clc
ret
SEND ENDP
; Network Send packet completion interrupt routine. At entry CS is our
; code segment, es:bx points to scb, netbios stack, interrupts are off.
SPOST PROC NEAR ; post routine for Send packets
push ds
push ax
mov ax,datas
mov ds,ax
mov sposted,0 ; clear send interlock
pop ax
pop ds
iret
SPOST ENDP
; Ungermann-Bass NETCI port send packet routine. [ohl] +++
; Enter with xmtcnt holding length of data in xmtbuf to be sent.
ubsend proc near
push ax
push bx
push cx
push es
mov cx, xmtcnt ; number of chars [ohl]
jcxz ubsend1 ; dont send zero chars [ohl]
mov bx, offset xmtbufx ; buffer address in es:bx [ohl]
mov ax, datas
mov es, ax
ubsend2:
mov ax, nciwrit ; write function, port 0 [ohl]
int netci
cmp cx,xmtcnt ; check that all characters sent [ohl]
je ubsend1 ; e = yes [ohl]
add bx, cx ; point to remaining chars [ohl]
sub xmtcnt,cx ; count of remaining characters [ohl]
mov cx,xmtcnt ; need count in cx too
jmp short ubsend2 ; try again to send [ohl]
ubsend1:mov xmtcnt,0
pop es
pop cx
pop bx
pop ax
ret
ubsend endp ; [ohl] ---
; dispatch prebuilt network session scb, enter with bx pointing to scb.
; returns status in al (and ah too). Allows STARLAN Int 2ah for netint.
SESSION PROC NEAR
push es ; save es around call
push ds
pop es ; make es:bx point to scb in datas seg
mov ax,exnbios ; funct 4 execute netbios, for Int 2ah
int netint ; use network interrupt
pop es ; saved registers
ret ; exit with status in ax
SESSION ENDP
; Make a virtual circuit Session, given preset scb's from proc chknet.
; For Server mode, does a Listen to '*', otherwise does a Call to indicated
; remote node. Updates vcid number in scb's. Shows success or fail msg.
; Updates network status byte pcnet to 2 if session is established.
; Does nothing if a session is active upon entry; otherwise, does a network
; hangup first to clear old session material from adapter board. This is
; the second procedure to call in initializing the network for usage.
SETNET PROC NEAR ; Network, make a connection
cmp lposted,1 ; Listen pending?
je setne0 ; e = yes, exit now
cmp pcnet,1 ; session active?
jbe setne1 ; be = no
setne0: ret
; No Session
setne1: call nethangup ; clear old session material
test flags.remflg,dserver ; Server mode?
jz setne2 ; z = no, file xfer or Connect
; Server mode, post a Listen (async)
mov lsn.scb_rname,'*' ; accept anyone
mov ax,500
call pcwait ; 0.5 sec wait
push bx
mov lposted,1 ; set listen interlock flag
mov lsn.scb_cmd,nlisten+nowait ; do LISTEN command, no wait
mov bx,offset lsn
call session
pop bx
ret
setne2: ; Non-server (Client) mode
push bx ; save reg
test nettype,starlan ; STARLAN?
jz setne2a ; z = no
cmp xmt.scb_vrlen,0 ; yes, using long name support?
je setne2a ; e = no
push es ; save reg
push ds
pop es ; make es:bx point to xmt scb
mov bx,offset xmt ; use xmt scb for the call
mov xmt.scb_cmd,ncall ; CALL_ISN, vrname + vrlen are ready
int 5bh ; STARLAN CALL Int 5bh, wait
pop es ; restore regs
pop bx
jmp short setne3 ; finish up
setne2a: ; Regular Netbios Call
mov xmt.scb_cmd,ncall ; CALL, wait for answer
mov bx,offset xmt ; setup scb pointer
call session
pop bx ; restore register
setne3: push dx ; common Call completion, show status
test xmt.scb_err,0ffh ; is there a non-zero return code?
jnz setne3a ; nz = yes, do bad return
or al,al ; check error return
jnz setne3a ; nz = bad connection
jmp short setne4 ; good connection so far
setne3a:
; mov dx,offset nbadset ; say can't reach remote node
mcmsg nbadset,cnbadset
mov ah,prstr
int dos
call saynode ; show remote host node name
jmp setne4c
; keep results of Call (vcid)
setne4: mov al,xmt.scb_vcid ; local session number
mov rcv.scb_vcid,al ; for receiver too
mov can.scb_vcid,al ; for sending Breaks
mov pcnet,2 ; say session has started
test flags.remflg,dregular+dquiet ; regular or quiet display?
jnz setne4c ; nz = yes, show only no-connect msg
; mov dx,offset ngodset ; say good connection
mcmsg ngodset,cngodset
mov ah,prstr
int dos
call saynode ; show remote host name
setne4c:pop dx
cmp pcnet,1 ; check connection again
ja setne5 ; a = good so far
stc ; set carry for failure
ret
setne5: clc ; carry clear for success
ret
SETNET ENDP
saynode proc near ; display node name on screen, si=name ptr
push ax
push cx
push dx
push si
mov ah,conout
mov si,offset nambuf ; remote node string
mov cx,64 ; up to 64 bytes long
saynod1:cld
lodsb ; get remote node name char into al
mov dl,al
int dos ; display it
cmp al,' ' ; was it a space?
jbe saynod2 ; be = yes, quit here
loop saynod1 ; do all 16 chars
saynod2:mov ah,prstr
mov dx,offset crlf
int dos
pop si
pop cx
pop cx
pop ax
ret
saynode endp
LPOST PROC FAR ; Interrupt Post routine for Listen call
push ds ; update vcid and calling node name in scb's
push cx
push es
push si
push di
mov cx,datas ; reestablish datas segment
mov ds,cx
mov es,cx
mov si,offset lsn.scb_rname ; copy remote name to rcv and xmt scbs
push si
mov di,offset rcv.scb_rname
mov cx,8 ; 16 byte field
cld
rep movsw
mov cx,8
pop si
push si
mov di,offset xmt.scb_rname
rep movsw
mov cx,8
pop si
mov di,offset nambuf ; and to nambuf for display
rep movsw
mov cl,lsn.scb_vcid ; local session number
mov rcv.scb_vcid,cl
mov xmt.scb_vcid,cl
mov can.scb_vcid,cl
mov lposted,0 ; clear interlock flag
mov pcnet,2 ; say net ready due to a Listen
pop di
pop si
pop es
pop cx
pop ds
iret ; return from interrupt
LPOST ENDP
NETHANGUP PROC NEAR ; disconnect network session, keep names
cmp pcnet,0 ; network started?
je nethang1 ; e = no
cmp clone, 'U' ; Ungermann-Bass port? [ohl]
je nethang2 ; e = yes [ohl]
push bx ; NetBios network
mov bx,offset can
mov can.scb_cmd,ncancel ; set cancel op code
mov can.scb_baddr,offset lsn ; cancel listens
mov lposted,0 ; say no listen
call session
mov can.scb_baddr,offset rcv ; cancel receives
call session
mov rposted,0 ; say no receives posted
mov can.scb_baddr,offset xmt ; cancel sends
call session
mov sposted,0 ; say no sends posted
mov xmtcnt,0 ; reset output buffer counter
mov xmt.scb_cmd,nhangup ; hangup, and wait for completion
mov bx,offset xmt
call session
pop bx
mov pcnet,1 ; say network but no session
call serrst ; reset the serial port for reiniting
nethang1:ret
; UB network [ohl] +++
nethang2:call ubclose ; close connection if any [ohl]
mov xmtcnt,0
mov pcnet,1
ret ; [ohl] ---
NETHANGUP ENDP
; Ungermann Bass. Do a disconnect from the current connection.
ubclose proc near
push ax
push cx
cmp nettype,netone ; UB network has been activated?
jz ubclos1 ; z = no
mov ax, ncistat ; get status [ohl]
int netci
cmp ch, 1 ; check if we have a connection [ohl]
jne ubclos1 ; ne = no [ohl]
mov ax, ncicont ; control function [ohl]
mov cx, ncidis ; say disconnect [ohl]
int netci
ubclos2:call ubrecv ; read response from net cmdintpr[ohl]
jnc ubclos2 ; continue till no chars [ohl]
ubclos1:and nettype,not netone ; remove network type
mov pcnet,0 ; say no network
pop cx
pop dx
ret
ubclose endp
; Called when Kermit exits. Name passed to mssker by proc chknet
; in word lclexit.
NETCLOSE PROC NEAR ; close entire network connection
cmp pcnet,0 ; network ever used?
je netclo1 ; e = no, so don't touch it
call nethangup ; close connections
test nettype,netbios ; NetBios activated?
jz netclo1 ; z = no
push bx
mov bx,offset xmt
mov xmt.scb_cmd,ndelete ; delete our local Kermit name
call session ; from net adapter board
pop bx
mov pcnet,0 ; say no network
and nettype,not netbios ; remove network kind
netclo1:ret
NETCLOSE ENDP
; Start connection process to network. Obtains Network board local name
; and appends '.K' to form Kermit's local name (removed when Kermit exits).
; If no local name is present then use name 'mskermit.K'.
; Sets local name in scb's for xmt, rcv, lsn. (Does not need DOS 3.x)
; Sets NETDONE pointer to procedure netclose for Kermit exit.
; Verifies existance of interrupt 5ch support, verifies vendor specific
; support for BREAK and other features, sets network type bit in nettype,
; sets BREAK support in nsbrk, hangsup old session if new node name given,
; fills in local and remote node names and name number in scbs (including ISN
; names for STARLAN), and sets network status byte pcnet to 0 (no net) or
; to 1 (net ready). This is the first procedure called to init network usage.
; Byte count of new host name is in temp from COMS.
chknet proc near
cmp clone,'U' ; Ungermann Bass network?
jne chknea ; ne = no
mov pcnet,0 ; force reactivation of UB net
chknea: cmp pcnet,2 ; session active now?
jb chknec ; b = no
cmp temp,0 ; byte count of new name, if any
je chkneb ; e = none, resume old session
; mov dx,offset naskpmt ; prompt for New or Resume
mcmsg naskpmt,cnaskpmt
call prompt
mov dx,offset nettab ; table of answers
mov bx,0 ; help for the question
mov ah,cmkey ; get answer keyword
call comnd
jmp r ; failed
nop
mov rdbuf,bl ; save keyword action value here
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
cmp rdbuf,0 ; New session?
je chkneb ; e = yes
clc
ret ; resume old one
chkneb: jmp chknet1 ; skip presence tests
chknec: ; setup addresses and clear junk in scb's
cmp pcnet,0 ; have we been here already?
je chkned ; e = no
jmp chknet1 ; yes, skip init part
chkned: mov xmtcnt,0 ; say buffer is empty
mov nsbrk,0 ; assume no BREAK across network
and nettype,not netbios ; say no NetBios network yet
push bx
push es ; Test for Netbios presence, IBM way
mov ah,35h ; DOS get interrupt vector
mov al,netint ; the netbios vector
int dos ; returns vector in es:bx
mov ax,es
cmp ax,0f000h ; rom bios segment??
jb chknee ; b = not likely, else Bios has
mov ax,0 ; trapped this vector to dummy iret
mov bx,0 ; fake null vector
chknee: or bx,ax ; is vector present?
pop es
pop bx
jz chknet0 ; z = no
mov xmt.scb_cmd,7fh ; presence test, 7fh is illegal command code
mov xmt.scb_err,0 ; clear response field
push bx
mov bx,offset xmt ; address of the session control block
call session ; execute operation
pop bx
mov al,xmt.scb_err ; get response
cmp xmt.scb_err,3 ; 'illegal function', so adapter is ready
jne chknet0 ; ne = failure
push bx
push es ; Test for Netbios presence, IBM way
mov ah,35h ; DOS get interrupt vector
mov al,2ah ; the netbios vector 2ah
int dos ; returns vector in es:bx
mov ax,es
cmp ax,0f000h ; rom bios segment??
jb chknef ; b = not likely
mov ax,0
mov bx,0 ; fake null vector
chknef: or bx,ax ; is vector present?
pop es
pop bx
jz chknet0 ; z = no, no NetBios network
or nettype,netbios ; say have NetBios network
; AT&T STARLAN board check (0ddh=magic #)
mov ah,0 ; vendor installation check on int 2ah
mov al,0 ; do error retry
int 2ah ; session level interrupt
cmp ah,0ddh ; 0ddh = magic number, success?
jne chknet1 ; ne = no
or nettype,starlan ; say using STARLAN, have int 2ah
push bx
push es ; Test for vector
mov ah,35h ; DOS get interrupt vector
mov al,5bh ; 5bh = STARLAN netbios ext'd vector
int dos ; returns vector in es:bx
mov ax,es
or bx,ax ; is vector present?
pop es
pop bx
jz chknet1 ; z = no
mov nsbrk,1 ; network BREAK supported
jmp chknet1
chknet0:mov pcnet,0 ; no network yet
push ax
push dx
mov ah,prstr
; mov dx,offset nonetmsg ; say network is not available
mcmsg nonetmsg,cnonetmsg
int dos
pop dx
pop ax
stc ; set carry for failure
ret ; and exit now
; net ready to operate
chknet1:cmp temp,0 ; byte count of new name, from COMS
jne chkne1e ; ne = new name given
jmp chknet2 ; nothing, so leave names intact
chkne1e:cmp pcnet,2 ; is session active now?
jb chkne1d ; b = no
call nethangup ; hangup net to clear old connection
chkne1d: ; start fresh connection
push si
push di
push es
push ds
pop es ; make es:di point to datas segment
cld
mov cx,8 ; 16 bytes for a node name
mov ax,' ' ; first, fill with spaces
mov di,offset xmt.scb_rname ; remote name field, clear it
rep stosw
test nettype,starlan ; STARLAN?
jz chkne1b ; z = no
; begin STARLAN section
mov xmt.scb_vrname,0 ; STARLAN var length name ptr
mov xmt.scb_vrname+2,0 ; segement of name
mov xmt.scb_vrlen,0 ; and its length
mov cx,temp ; count of characters in new name
cmp cx,16 ; > 16 chars in remote node name?
ja chkne1a ; a = yes, too long for Netbios
mov al,'/' ; scan for slashes in name
mov di,offset nambuf ; source of text
push es ; save es around scan
push ds
pop es ; point es at datas segment
cld
repne scasb ; look for the slash
pop es
jne chkne1b ; ne = none, do regular Netbios name storage
chkne1a: ; STARLAN ISN long remote name support
mov xmt.scb_vrname,offset nambuf ; STARLAN var length name ptr
mov xmt.scb_vrname+2,datas ; segment of remote name
mov cx,temp ; get name length again (in cl)
mov xmt.scb_vrlen,cl ; indicate its length
jmp chkne1c ; copy blanks in remote name field
; end STARLAN section
chkne1b:mov cx,temp ; Regular Netbios form, name length
mov si,offset nambuf ; source of text
mov di,offset xmt.scb_rname ; destination is remote name
rep movsb ; copy text to transmitter's scb
mov cx,16
chkne1c:mov cx,8 ; 8 words
mov si,offset xmt.scb_rname ; from here
mov di,offset rcv.scb_rname ; to receiver's scb also
rep movsw
pop es
pop di
pop si
chknet2:cmp pcnet,0 ; started net?
je chknet2c ; e = no
ret ; else quit here
chknet2c:
mov ah,prstr
; mov dx,offset netmsg1 ; say checking node name
mcmsg netmsg1,cnetmsg1
int dos
push word ptr xmt.scb_rname ; save first two bytes (user spec)
mov byte ptr xmt.scb_rname,'*' ; call to local name
push bx
mov xmt.scb_cmd,naustat ; get Network Adapter Unit status
mov bx,offset xmt
call session
pop bx
pop word ptr xmt.scb_rname ; restore remote name first two bytes
chknet2a:
push es ; save registers
push di
push si
push cx
push ds
pop es ; set es:di to datas segment
mov si,offset xmtbuf+60 ; where local name is returned (1st entry)
cmp word ptr xmtbuf+58,0 ; is local name empty?
jne chknet2b ; ne = no, use name from table
mov si,offset deflname ; else use default local name
chknet2b:
mov di,offset xmt.scb_lname ; where to put it in scb
mov cx,14 ; 16 bytes minus extension of '.K'
cld ; append extension of '.K' to loc name
chknet3:cmp byte ptr[si],' ' ; find first space (end of regular node name)
jbe chknet4 ; be = found one (or control code)
movsb ; copy local name to scb
loop chknet3 ; continue though local name
chknet4:cmp word ptr [di-2],'K.' ; is extension '.K' present already?
je chknet4a;;;5 ; e = yes, nothing to add
cmp word ptr [di-2],'k.' ; check lower case too
je chknet4a;;;5 ; e = yes, nothing to add
mov word ptr [di],'K.' ; append our extension of '.K'
add di,2 ; step over our new extension
sub cx,2
; complete field with spaces
add cx,2 ; 15th and 16th chars
chknet4a:jcxz chknet5 ; z = nothing to add
mov al,' ' ; space as padding
rep stosb
chknet5:mov si,offset xmt.scb_lname
mov di,offset rcv.scb_lname ; put in receiver scb too
mov cx,8
rep movsw
mov cx,8
mov si,offset xmt.scb_lname
mov di,offset lsn.scb_lname ; in Listen scb also
rep movsw
pop cx
pop si
pop di
pop es
chknet6:
push bx ; Put our new local name in NAU
mov xmt.scb_cmd,nadd ; ADD NAME, wait
mov bx,offset xmt
call session
pop bx
mov al,xmt.scb_err ; get error code
cmp al,0 ; success?
jne chknet60 ; [zqf]
jmp chknet7 ; e = yes
chknet60:
cmp al,0dh ; duplicate name in local table?
je chknet6a ; e = yes
cmp al,16h ; name used elsewhere?
je chknet6a ; e = yes
cmp al,19h ; name conflict?
je chknet6a ; e = yes
push ax
mov ah,prstr ; another kind of error
; mov dx,offset chkmsg1 ; say can't construct local name
mcmsg chkmsg1,cchkmsg1
int dos
pop ax
call hexout ; display it (in al)
mov ah,prstr
mov dx,offset crlf
int dos
mov pcnet,0 ; say no connection today
stc ; set carry for failure
ret
chknet6a:
mov ah,prstr ; ask for another name
; mov dx,offset chkmsg2 ; prompt message
mcmsg chkmsg2,cchkmsg2
int dos
mov ah,conout ; show name itself
push cx
mov cx,16 ; 16 bytes in name field
mov si,offset xmt.scb_lname
chknet6c:
lodsb ; get name char into al
mov dl,al
int dos
mov byte ptr[si-1],' ' ; clear old name as we go
loop chknet6c
pop cx
mov ah,prstr
; mov dx,offset chkmsg3 ; rest of prompt
mcmsg chkmsg3,cchkmsg3
int dos
mov ah,0ah ; read buffered line from stdin
mov dx,offset xmtbuf+58 ; where to put text (xmtbuf+60=text)
mov xmtbuf+58,15 ; buf capacity, including cr at end
mov xmtbuf+59,0 ; say text in buffer = none
int dos
jc chknet6b ; c = error
cmp xmtbuf+59,0 ; any bytes read?
je chknet6b ; e = no, exit failure
mov ah,prstr ; say rechecking name
; mov dx,offset netmsg1
mcmsg netmsg1,cnetmsg1
int dos
jmp chknet2a ; go reinterpret name
chknet6b:
stc ; set carry for failure
ret
chknet7:mov pcnet,1 ; network is present (but not active)
mov al,xmt.scb_num ; name number
mov rcv.scb_num,al
mov lsn.scb_num,al
mov lclexit,offset netclose ; address to close network
push ax
push cx
push dx
; mov dx,offset netmsg2 ; say net going
mcmsg netmsg2,cnetmsg2
mov ah,prstr
int dos
mov si,offset rcv.scb_lname ; display our local name
mov ah,conout
mov cx,16
cld
chknet9:lodsb ; byte from si to al
mov dl,al
int dos ; display it
loop chknet9
mov ah,prstr
mov dx,offset crlf ; add cr/lf
int dos
pop dx
pop cx
pop ax
clc ; carry clear for success
ret
chknet endp
; ; [ohl] ++++
; Verifies existance of interrupt 6Bh support, verifies vendor specific
; support for BREAK and other features, sets network type bit in nettype,
; sets BREAK support in nsbrk and sets network status byte pcnet to 0
; (no net) or to 1 (net ready). This is the first procedure called to
; init Ungermann-Bass NETCI terminal port network usage.
chkub proc near
push bx
push es ; Test for vector
mov ah,35h ; DOS get interrupt vector
mov al,6bh ; 6bh = Net/One command interpreter
; interface, with break support
int dos ; returns vector in es:bx
mov ax,es ; is vector in rom bios??? [jrd]
cmp ax,0f000h ; rom bios starts here
jb chkub2 ; b = not likely
mov ax,0 ; yes, say no network
mov es,ax ; fake a null vector
mov bx,ax
chkub2: mov ax,es
or bx,ax ; is vector present?
jz chkub0 ; z = no
mov al,0ffh ; test value (anything non-zero)
mov ah,2 ; function code for testing net board
int netci
or al,al ; al = 0 means board is ok
jnz chkub0 ; nz = not ok
pop es
pop bx
mov nsbrk,1 ; network BREAK supported
or nettype,netone ; say have Net/One
clc ; return success
ret
chkub0: pop es ; clean stack from above
pop bx
push ax
push dx
mov ah,prstr
; mov dx,offset nonetmsg ; say network is not available
mcmsg nonetmsg,cnonetmsg
int dos
pop dx
pop ax
stc ; set carry for failure
ret ; and exit now
chkub endp ; [ohl] ----
hexout proc near ; display byte in al as hex value
push ax ; all regs preserved
push cx
push dx
mov cx,2 ; two nibbles
hexout1:push cx ; save counter
mov cl,4 ; high nibble
ror al,cl ; put in low order field
mov dl,al
xchg ch,al ; save al byte in ch
and dl,0fh ; four bits
cmp dl,9 ; too big?
jbe hexout2 ; be = no
add dl,'A'-'9'-1 ; bump up to A-F
hexout2:add dl,'0'
mov ah,conout
int dos
xchg ch,al ; recover data byte
pop cx
loop hexout1 ; do second nibble
mov dl,'H' ; add a final hex ident
int dos
pop ax
pop cx
pop dx
ret
hexout endp
; local routine to see if we have to transmit an xon
chkxon proc near
cmp flowon,0 ; doing flow control?
je chkxo1 ; no, skip all this
test xofsnt,usron ; did user send an xoff?
jnz chkxo1 ; nz = yes, don't contradict it here
test xofsnt,bufon ; have we sent a buffer level xoff?
jz chkxo1 ; z = no, forget it
cmp count,mntrgl ; below (low water mark) trigger?
jae chkxo1 ; no, forget it
mov ah,flowon ; ah gets xon
and xofsnt,off ; remember we've sent the xon
call outch2 ; send via non-flow controlled entry point
nop
nop
nop ; in case it skips
chkxo1: ret
chkxon endp
; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the
; cycle of clear input buffer, wait 1 second, test if buffer empty then exit
; else repeat cycle. Requires that the port be initialized before hand.
; Ihosts is used by the local send-file routine just after initializing
; the serial port.
; 22 March 1986 [jrd]
; 22 June 1986 Don't send null char if not using flow control. [jrd]
IHOSTS PROC NEAR
push ax ; save the registers
push cx
push dx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; check for null char
jz ihosts1 ; z = null, don't send it
call outchr ; send it (release Host's output queue)
nop ; outchr can do skip return
nop
nop
ihosts1:call clrbuf ; clear out interrupt buffer
pop dx ; empty buffer. we are done here
pop cx
pop ax
ret
IHOSTS ENDP
; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port. 22 March 1986 [jrd]
; 22 June 1986 Don't send null char if not using flow control. [jrd]
IHOSTR PROC NEAR
push ax ; save regs
push cx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; check for null char
jz ihostr1 ; z = null, don't send it
call outchr ; send it (release Host's output queue)
nop ; outchr can do skip return
nop
nop
ihostr1:pop cx
pop ax
ret
IHOSTR ENDP
; Send a break out the current serial port. Returns normally.
; Do both regular and long Break. 6 March 1987 [jrd]
SENDBR PROC NEAR
push cx ; Regular Break entry point
mov cx,275 ; 275 milliseconds in regular Break
call sendbw ; call worker routine to do it
pop cx
clc ; don't exit Connect mode
ret
SENDBL: push cx ; Long Break entry point
mov cx,1800 ; 1.8 second long break
call sendbw ; call worker routine to do it
pop cx
clc ; don't exit Connect mode
ret
; worker - send Break for cx millisec
sendbw: test clone,0ffh ; running on a semi-clone?
jnz sendbw2 ; nz = yes, can't do this via Bios
push ax
push dx
mov dx,brkadr ; Port address
in al,dx ; Get current setting
push ax ; save setting on the stack
or al,brkval ; Set send-break bit(s)
out dx,al ; Start the break
mov ax,cx ; # of ms to wait
call pcwait ; hold break for desired interval
pop ax ; restore Line Control Register
out dx,al ; Stop the break
pop dx
pop ax
ret
sendbw2:
cmp clone, 'U' ; is it an UB NETCI port? [ohl]
je sendbw6 ; e = yes [ohl]
cmp clone,'N' ; is this a NetBios network port?
jne sendbw4 ; ne = no
cmp nsbrk,0 ; is network able to send a break?
je sendbw4 ; e = no
test nettype,starlan ; STARLAN: network break supported?
jz sendbw4 ; z = no
push bx
push es ; save es around call
push ds
pop es ; make es:bx point to scb in datas segment
mov bx,offset can ; use Cancel control block
mov can.scb_cmd,netbrk ; send net Break command
int 5bh ; use network Break interrupt
pop es ; saved registers
pop bx
sendbw4:ret
sendbw6: ; UB port send break [ohl] +++
push ax
push cx
mov ax, ncicont + 0 ; call control, use 0 for network port num [ohl]
mov cl, ncibrk ; request break [ohl]
int netci ; Net/One command interface int. (6Bh) [ohl]
pop cx
pop ax
ret ; [ohl] ---
SENDBR ENDP
; Initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
;
; Revised slightly by Joe R. Doupnik 22 Dec 1985 to prevent interrupts
; being enabled until we're done, to stop interrupts from occurring when
; TX holding buffer becomes empty (a useless interrupt for us), and to
; shorten the time between enabling interrupts and our exit.
; Returns carry clear if success, else carry set.
SERINI PROC NEAR
call pcwtst ; recalibrate pcwait loop timer
cmp portin,0 ; Did we initialize port already?
jle serin0 ; le = no, not yet
jmp serin4 ; Yes, update flow and leave
serin0: cmp portin,-1 ; have we run SET PORT or equiv?
jne serin5 ; ne = yes, continue
mov bl,flags.comflg ; pass current port ident
call comstrt ; do SET PORT now
ret ; failed, exit now
nop
nop
serin5: cmp clone,0 ; non-clone
je serin2 ; e = yes, real thing
jmp serin3 ; else use Bios. Finish initialization
serin2: cmp clone,'N' ; Network port?
jne serin2a ; ne = no
jmp serin3 ; yes
serin2a:push bx
push es
in al,21H ; Interrupt controller
mov savirq,al ; save state here for restoration
or al,modem.mddis ; Inhibit IRQ 3 or IRQ 4
out 21H,al
mov al,byte ptr modem.mdintv ; desired interrupt vector
mov ah,35H ; Int 21H, function 35H = Get Vector
int dos ; get vector into es:bx
mov word ptr savsci,bx ; save address offset of original vector
mov word ptr savsci+2,es ; and its segment
mov al,byte ptr modem.mdintv ; interrupt number for IRQ 4 or IRQ 3
mov dx,offset serint ; offset of our interrupt routine
push ds ; save ds around next DOS call
mov bx,cs ; compose full address of our routine
mov ds,bx ; segment is the code segment
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
mov al,rs232 ; interrupt number for Bios serial port
mov ah,35H ; get vector into es:bx
int dos
mov word ptr sav232,bx ; save offset
mov word ptr sav232+2,es ; save segment
mov dx,offset serdum ; offset of our interrupt routine
push ds ; save ds around next DOS call
mov bx,cs ; compose full address of our routine
mov ds,bx ; segment is the code segment
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
pop es
pop bx
mov portin,1 ; Remember port has been initialized
cli ; Disable interrupts
cld ; Do increments in string operations
mov ax,modem.mdstat
mov mst,ax ; Use this address for status
mov ax,modem.mddat
mov mdat,ax ; Use this address for data.
mov al,modem.mdmeoi
mov mdeoi,al ; Use to signify end-of-interrupt.
in al,21H ; Set up 8259 interrupt controller
and al,modem.mden ; Enable INT3 or INT4. (bit=0 means enable)
out 21H,al ; rewrite interrupt mask byte
mov dx,modem.mdcom ; Set up the serial card Line Control Reg.
in al,dx ; get present settings
mov savlcr,al ; save them for restoration
mov al,3 ; 8 data bits. DLAB = 0
out dx,al
mov dx,modem.mddat ; data and command port, read and flush any
in al,dx ; char in UART's receive buffer
inc dx ; increment to interrupt enable register 3f9h
mov al,1 ; Set up interrupt enable register
out dx,al ; for Data Available only
add dx,3 ; increment to modem control register 3fch
mov al,0bh ; assert DTR, RTS, not OUT1, and OUT2
out dx,al ; OUT2 high turns on interrupt driver chip
sti ; Allow interrupts (AFTER next instr)
jmp short serin4 ; finish up
serin3: cmp flags.comflg,'N' ; Network?
jne serin4 ; ne = no
call setnet ; setup network session and pcnet flag
jnc serin4 ; nc = success
ret ; fail, carry set, leave portin at 0
serin4: push bx
mov bx,portval ; get port data structure
mov parmsk,0ffh ; parity mask, assume parity is None
cmp [bx].parflg,parnon ; is it None?
je serin1 ; e = yes
mov parmsk,07fh ; no, pass lower 7 bits as data
serin1: mov bx,[bx].flowc ; get flow control chars
mov flowoff,bl ; xoff or null
mov flowon,bh ; xon or null
mov xofrcv,off ; clear xoff received flag
pop bx
mov portin,1 ; say initialized
clc ; carry clear for success
ret ; We're done
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Moved push/pop es code to do quicker exit before interrupts enabled. [jrd]
; Returns normally.
; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd]
; 21 Feb 1987 Add support for Bios calls (Clone) [jrd]
; 17 May 1987 Redo for COM3/4 support [jrd]
SERRST PROC NEAR
cmp portin,0 ; Reset already?
jg srst3 ; g = no
ret ; e = yes, l=not used yet, just leave
srst3: test clone,0ffh ; running on a non-compatible UART?
jz srst4 ; z = no, real UART
jmp srst1 ; nz = yes (Bios or Net)
srst4: push word ptr savsci ; save original interrupt owner
push word ptr savsci+2 ; offset and segment
mov word ptr savsci,offset nulint ; redirect to our null routine
mov ax,cs ; segment of null routine is code
mov word ptr savsci+2,ax
mov cx,0 ; loop counter
srst2: mov dx,modem.mdstat ; status register
in al,dx
jmp $+2 ; chip access delay
test al,40h ; both xmtr output registers empty?
loopz srst2 ; z = no, wait for them a while
mov dx,modem.mddat ; modem base address 3f8h
add dx,1 ; point at int enable reg 3f9h
mov al,0
out dx,al ; disable interrupts from this source
jmp $+2 ; let stray interrupts occur now
jmp $+2
add dx,2 ; point at Line Control Register 3fbh
mov al,savlcr ; saved bit pattern
and al,not 80h ; force DLAB bit to 0
out dx,al ; restore line control state
; clear modem's delta status bits and reassert DTR etc
inc dx ; increment to modem control register 3fch
mov al,03h ; reassert DTR,RTS,but not OUT1 and not OUT2
out dx,al ; OUT2 low to turn off interrupt drivers
jmp $+2 ; pause, in case stray interrupt is generated
jmp $+2 ; which is more than likely, hence nulint.
add dx,2 ; modem status register 3feh
in al,dx ; clear status register by reading it
jmp $+2
mov mdmhand,al ; save here for Show Modem
cli ; Disable interrupts
in al,21H ; Interrupt controller
or al,modem.mddis ; Inhibit IRQ 3 or IRQ 4
pop word ptr savsci+2 ; recover original int owner's addr
pop word ptr savsci
sti ; replace original IRQ intrpt vector
push bx
mov al,byte ptr modem.mdintv ; vector number to do
mov dx,word ptr savsci ; offset part
push ds
mov bx,word ptr savsci+2 ; segment part
mov ds,bx ; ds:dx has interrupt vector
mov ah,25H ; set interrupt vector
int dos ; replaced
pop ds
mov al,rs232 ; Bios serial port interrupt vector to restore
mov dx,word ptr sav232 ; offset part
push ds
mov bx,word ptr sav232+2 ; segment part
mov ds,bx
mov ah,25h ; set interrupt vector
int dos
pop ds
pop bx
cli
mov ah,savirq ; saved Interrupt state
and ah,modem.mddis ; pick out our IRQ bit
in al,21h ; get current intrpt controller state
jmp $+2
xor al,modem.mddis ; remove our IRQ bit
or al,ah ; set previous state
out 21h,al ; reset IRQ 3 or 4 to original state
sti
; non-UART processes
srst1: cmp pcnet,0 ; a network active?
je srst9 ; e = no
cmp flags.comflg,'N' ; NetBios network?
jne srst9 ; ne = no
cmp rposted,0 ; receive outstanding?
je srst9 ; e = no
mov can.scb_baddr,offset rcv ; cancel receives
push bx
mov bx,offset can
call session
pop bx
mov ax,1
call pcwait ; wait one millisec
cmp rcv.scb_err,0 ; success?
jne srst9 ; ne = no, leave interlock set
mov rposted,0 ; say no receives posted
srst9: mov portin,0 ; Reset flag
ret ; All done
SERRST ENDP
; Null interrupt routine, to handle strays
nulint proc near
push ax
push dx
mov al,20h ; general EOI
mov dx,intcon1 ; to 8259 interrupt controller
out dx,al ; clear controller chip
pop dx
pop ax
iret
nulint endp
; Dummy Interrupt 14H to defeat DOS interference with serial port when CTTY
; and Kermit use the port simultaneously. If ports differ then chain DOS to
; original Int 14H Bios code. Else return dummy status=ok reports and
; Backspace for Read, ignore char for Write.
; Entered with AH = function request, AL = char to be sent, DX = com port num
; CS is our code segment, DS is DOS's, SS is ours or DOS's, interrupts off.
; 25 June 1987 [jrd]
SERDUM PROC FAR
push ds ; preserve all registers
push ax
mov ax,seg datas ; get our data segment
mov ds,ax
mov al,flags.comflg ; get port id (COM1 = 1, COM2 = 2)
and al,7 ; use lower three bits
dec al ; DOS counts COM1 as 0, etc
cmp dl,al ; referencing same port as Kermit is using?
pop ax ; recover request parameters
jne serdu1 ; ne = no, chain to Bios routine
pop ds
cmp ah,0 ; initialization request?
je serdu3 ; e = yes, return dummy status=ok rpt
cmp ah,1 ; send char in al?
jne serdu2 ; ne = no
mov ah,60h ; yes, set line status=ok in ah
iret
serdu2: cmp ah,2 ; receive char (and wait for it)?
jne serdu3 ; ne = no, return dummy report
mov al,bs ; yes, return ascii BS to DOS
mov ah,0 ; ah = errors (none here)
iret
serdu3: mov ax,60b0h ; dummy status report:xmtr empty, CD,
iret ; DSR, and CTS are on
serdu1: pop tempdum ; save old ds
push word ptr sav232+2 ; push Bios int 14H handler segment
push word ptr sav232 ; push Bios int 14H handler offset
push tempdum ; recover old ds
pop ds
ret ; do a ret far (chain to Bios)
SERDUM ENDP
; Serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
; Revised on 22 May 1986, again 2 August 1986 to run at 38.4kb on PC's.
; Srcpnt holds offset, within buffer Source, where next rcv'd char goes.
; Count is number of chars now in buffer, and oldest char is srcpnt-count
; done modulo size of Source. All pointer management is handled here.
; Control-G char substituted for char(s) lost in overrun condition.
; Upgraded to read cause of interrupt from interrupt ident reg (accepts only
; data ready), chain to old interrupt if source is not our device.
; 9 Feb 1988 Add storage of interrupt cause in intkind. [jrd]
SERINT PROC FAR
push ax ; save registers
push dx ;
push ds
mov ax,seg datas
mov ds,ax ; address data segment
mov dx,mdat ; modem base address
add dx,2 ; increment to Interrupt Identification Reg
in al,dx ; get interrupt cause
mov intkind,al ; save cause here
test al,1 ; interrupt available if this bit is zero
jz srintc ; z = interrupt is from our source
pop tempsci ; save old ds
pop dx ; clean the stack and prepare for ret far
pop ax ; to old int handler (same as a jump there)
push word ptr savsci+2 ; old handler segment
push word ptr savsci ; old handler offset
push tempsci ; recover old ds
pop ds
ret ; do far return (chain to old handler)
srintc: mov al,mdeoi ; allow interrupt controller to run
out intcon1,al ; Send End-of-Interrupt to 8259
test intkind,4 ; data ready?
jnz srint0a ; nz = yes, else ignore
srint0: sti ; else turn on interrupts
jmp retint ; and exit now (common jump point)
srint0a:mov dx,mst ; Asynch status port
in al,dx
and al,mdmover ; select overrun bit
mov ah,al ; save it for later
mov dx,mdat
in al,dx ; read the received character into al
mov dh,al ; dh = working copy. Check null, flow cntl
and dh,parmsk ; strip parity temporarily, if any
;;;;; jz srint0 ; if null ignore char
srint0b:cmp flowoff,0 ; flow control active?
je srint2 ; e = no
cmp dh,flowoff ; acting on Xoff?
jne srint1 ; ne = Nope, go on
cmp xofsnt,0 ; have we sent an outstanding XOFF?
jne srint0 ; ne = yes, ignore (possible echo)
mov xofrcv,bufon ; Set the flag saying XOFF received
jmp srint0 ; and exit
srint1: cmp dh,flowon ; acting on Xon?
jne srint2 ; ne = no, go on
mov xofrcv,off ; Clear the XOFF received flag
jmp srint0 ; and exit
srint2: push bx ; save register
or ah,ah ; overrun?
jz srint2a ; z = no
mov ah,al ; yes, save present char
mov al,bell ; insert control-G for missing char
srint2a:mov bx,srcpnt ; address of buffer storage slot
mov byte ptr [bx],al ; store the new char in buffer "source"
inc srcpnt ; point to next slot
inc bx
cmp bx,offset source + bufsiz ; beyond end of buffer?
jb srint3 ; b = not past end
mov srcpnt,offset source ; wrap buffer around
srint3: cmp count,bufsiz ; filled already?
jae srint4 ; ae = yes
inc count ; no, add a char
srint4: or ah,ah ; anything in overrun storage?
jz srint4a ; z = no
mov al,ah ; recover any recent char from overrun
xor ah,ah ; clear overrun storage
jmp srint2a ; yes, go store real second char
srint4a:pop bx ; restore reg
sti ; ok to allow interrupts now, not before
cmp count,mntrgh ; past the high trigger point?
jbe retint ; be = no, we're within our limit
test xofsnt,bufon ; Has an XOFF been sent by buffer control?
jnz retint ; nz = Yes
mov al,flowoff ; get the flow off char (Xoff or null)
or al,al ; don't send nul chars
jz retint ; z = null, nothing to send
call dopar ; Set parity appropriately
mov ah,al ; Don't overwrite character with status
push cx ; save reg
xor cx,cx ; loop counter
srint5: mov dx,modem.mdstat ; Get port status
in al,dx
test al,20H ; Transmitter ready?
jnz srint6 ; nz = yes
jmp $+2 ; use time, prevent overdriving UART
loop srint5 ; else wait loop, cx times
jmp srint7 ; Timeout
srint6: mov al,ah ; Now send out the flow control char
mov dx,modem.mddat
jmp $+2
out dx,al
mov xofsnt,bufon ; Remember we sent an XOFF at buffer level
srint7: pop cx ; restore reg
retint: pop ds
pop dx
pop ax
iret
SERINT ENDP
DTRLOW PROC NEAR ; Global proc to Hangup the Phone or Network
; by making DTR and RTS low (phone). [jrd]
mov ah,cmtxt ; allow text, to be able to display help
mov bx,offset rdbuf ; dummy buffer
; mov dx,offset hnghlp ; help message
mcmsg hnghlp,chnghlp
call comnd ; get a confirm
jmp r
nop
cmp clone,'0' ; running on a semi-clone?
jb dtrlow2 ; b = no
cmp clone,'4'
jb dtrlow1 ; b = yes, can't access modem lines
dtrlow2:call serhng ; drop DTR and RTS
cmp taklev,0 ; in a Take file or macro?
jne dtrlow1 ; ne = yes, no message
mov ah,prstr ; give a nice message
; mov dx,offset hngmsg
mcmsg hngmsg,chngmsg
int dos
dtrlow1:jmp rskp
DTRLOW ENDP
; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; 5 April 1987 Add 500 millisec wait with lines low before returning. [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; If network then call nethangup procedure to hangup the session without
; losing local name information.
; Returns normally.
serhng proc near ; clear modem's delta status bits and lower DTR & RTS
cmp clone,'U' ; Ungermann Bass network?
je shng2 ; e = yes
cmp clone,'N' ; network?
jne shng1 ; ne = no
shng2: cmp pcnet,0 ; network operational?
je shng1 ; e = no
call nethangup ; break the session
call serrst ; reset port so can be opened again
ret
shng1: call serrst ; reset port so serini can set DTR
cli ; Disable interrupts
push ax
push dx
mov dx,modem.mddat ; serial port base address
add dx,4 ; increment to control register
mov al,08h ; reassert OUT2, un-assert DTR,RTS,OUT1
out dx,al
jmp $+2
add dx,2 ; increment to modem status register
in al,dx ; Clear Status reg by reading it
shngx: sti ; Enable interrupts
mov ax,500 ; 500 millisec, for pcwait
call pcwait ; keep lines low for at least 500 millisec
pop dx
pop ax
clc
ret
serhng endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret
R PROC NEAR
ret
R ENDP
code ends
end