home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Beijing Paradise BBS Backup
/
PARADISE.ISO
/
software
/
BBSDOORW
/
UUPC11XS.ZIP
/
UUCICO
/
COMM.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-03-21
|
34KB
|
1,265 lines
TITLE COM_PKG2 -- Last updated 10/6/85
PAGE 75,132
;
; Modified to use COM1 thru COM4 - William W. Plummer, 2/21/91
; Eliminate (incomplete) support for DOS1 - William W. Plummer, 11/13/90
;
; modified to use MSC calling sequence.
; jrr 3/86
;
; Communications Package for the IBM PC, XT, AT and PCjr
; and strict compatibles.
; May be copied and used freely -- This is a public domain program
; Developed by Richard Gillmann, John Romkey, Jerry Saltzer,
; Craig Milo Rogers, Dave Mitton and Larry Afrin.
;
; We'd sure like to see any improvements you might make.
; Please send all comments and queries about this package
; to GILLMANN@USC-ISIB.ARPA
;
; o Supports both serial ports simultaneously
; o All speeds to 19200 baud
; o Compatible with PC, XT, AT and PCjr.
; o Built in XON/XOFF flow control option
; o Assembly language calling conventions
; o Logs all comm errors
; o Direct connect or modem protocol
;
; MAXIMUM BUFFER SIZES
R_SIZE EQU 2048 ; SIZE OF RECEIVE BUFFERS skl/88-05-13
S_SIZE EQU 4096 ; SIZE OF TRANSMIT BUFFERS ahd 01/92
; INTERRUPT NUMBERS
INT_COM1 EQU 0CH ; COM1: FROM 8259
INT_COM2 EQU 0BH ; COM2: FROM 8259
INT_COM3 EQU 0CH ; COM3: FROM 8259
INT_COM4 EQU 0BH ; COM4: FROM 8259
; 8259 PORTS
INTA00 EQU 20H ; 8259A PORT, A0 = 0
INTA01 EQU 21H ; 8259A PORT, A0 = 1
; COM1: & COM3: LEVEL 4
IRQ4 EQU 2*2*2*2 ; 8259A OCW1 MASK, M4=1, A0=0
NIRQ4 EQU NOT IRQ4 AND 0FFH ; COMPLEMENT OF ABOVE
EOI4 EQU 4 OR 01100000B ; 8259A OCW2 SPECIFIC IRQ4 EOI, A0=0
; COM2: & COM4: LEVEL 3
IRQ3 EQU 2*2*2 ; 8259A OCW1 MASK, M3=1, A0=0
NIRQ3 EQU NOT IRQ3 AND 0FFH ; COMPLEMENT OF ABOVE
EOI3 EQU 3 OR 01100000B ; 8259A OCW2 SPECIFIC IRQ3 EOI, A0=0
; FLOW CONTROL CHARACTERS
CONTROL_Q EQU 11H ; XON
CONTROL_S EQU 13H ; XOFF
; MISC.
DOS EQU 21H ; DOS FUNCTION CALLS
PAGE
;
; ROM BIOS Data Area
;
RBDA SEGMENT AT 40H
RS232_BASE DW 4 DUP(?) ; ADDRESSES OF RS232 ADAPTERS
RBDA ENDS
;
; ROM PC-Type IDENT
;
ROM SEGMENT AT 0F000H
ORG 0FFFEH
ROMID DB ? ; 0FFH=PC OR EARLY XT, 0FEH=XT, 0FDH=JR
ROM ENDS
PAGE
;
; TABLE FOR EACH SERIAL PORT
;
SP_TAB STRUC
PORT DB ? ; 1 OR 2 OR 3 OR 4
; PARAMETERS FOR THIS INTERRUPT LEVEL
INT_COM DB ? ; INTERRUPT NUMBER
IRQ DB ? ; 8259A OCW1 MASK
NIRQ DB ? ; COMPLEMENT OF ABOVE
EOI DB ? ; 8259A OCW2 SPECIFIC END OF INTERRUPT
; INTERRUPT HANDLERS FOR THIS LEVEL
INT_HNDLR DW ? ; OFFSET TO INTERRUPT HANDLER
OLD_COM_OFF DW ? ; OLD HANDLER'S OFFSET
OLD_COM_SEG DW ? ; OLD HANDLER'S SEGMENT
; ATTRIBUTES
INSTALLED DB ? ; IS PORT INSTALLED ON THIS PC? (1=YES,0=NO)
BAUD_RATE DW ? ; 19200 MAX
CONNECTION DB ? ; M(ODEM), D(IRECT)
PARITY DB ? ; N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
STOP_BITS DB ? ; 1, 2
XON_XOFF DB ? ; E(NABLED), D(ISABLED)
; FLOW CONTROL STATE
HOST_OFF DB ? ; HOST XOFF'ED (1=YES,0=NO)
PC_OFF DB ? ; PC XOFF'ED (1=YES,0=NO)
; ERROR COUNTS
ERROR_BLOCK DW 8 DUP(?) ; EIGHT ERROR COUNTERS
; 8250 PORTS
DATREG DW ? ; DATA REGISTER
IER DW ? ; INTERRUPT ENABLE REGISTER
IIR DW ? ; INTERRUPT IDENTIFICATION REGISTER
LCR DW ? ; LINE CONTROL REGISTER
MCR DW ? ; MODEM CONTROL REGISTER
LSR DW ? ; LINE STATUS REGISTER
MSR DW ? ; MODEM STATUS REGISTER
; BUFFER POINTERS
START_TDATA DW ? ; INDEX TO FIRST CHARACTER IN X-MIT BUFFER
END_TDATA DW ? ; INDEX TO FIRST FREE SPACE IN X-MIT BUFFER
START_RDATA DW ? ; INDEX TO FIRST CHARACTER IN REC. BUFFER
END_RDATA DW ? ; INDEX TO FIRST FREE SPACE IN REC. BUFFER
; BUFFER COUNTS
SIZE_TDATA DW ? ; NUMBER OF CHARACTERS IN X-MIT BUFFER
SIZE_RDATA DW ? ; NUMBER OF CHARACTERS IN REC. BUFFER
; BUFFERS
TDATA DB S_SIZE DUP(?) ; SEND BUFFER
RDATA DB R_SIZE DUP(?) ; RECEIVE BUFFER
SP_TAB ENDS
; SP_TAB EQUATES
; WE HAVE TO USE THESE BECAUSE OF PROBLEMS WITH STRUC
EOVFLOW EQU ERROR_BLOCK ; BUFFER OVERFLOWS
EOVRUN EQU ERROR_BLOCK+2 ; RECEIVE OVERRUNS
EBREAK EQU ERROR_BLOCK+4 ; BREAK CHARS
EFRAME EQU ERROR_BLOCK+6 ; FRAMING ERRORS
EPARITY EQU ERROR_BLOCK+8 ; PARITY ERRORS
EXMIT EQU ERROR_BLOCK+10 ; TRANSMISSION ERRORS
EDSR EQU ERROR_BLOCK+12 ; DATA SET READY ERRORS
ECTS EQU ERROR_BLOCK+14 ; CLEAR TO SEND ERRORS
DLL EQU DATREG ; LOW DIVISOR LATCH
DLH EQU IER ; HIGH DIVISOR LATCH
PAGE
; put the data in the DGROUP segment
; far calls enter with DS pointing to DGROUP
;
DGROUP GROUP _DATA
_DATA SEGMENT PUBLIC 'DATA'
;
DIV50PC EQU 2304 ; DIVISOR FOR 50 BAUD (PC,XT)
DIV50JR EQU 2237 ; DIVISOR FOR 50 BAUD (JR)
DIV50 DW 2304 ; ACTUAL DIVISOR FOR 50 BAUD IN USE
CURRENT_AREA DW AREA1 ; CURRENTLY SELECTED AREA
; DATA AREAS FOR EACH PORT
AREA1 SP_TAB <1,INT_COM1,IRQ4,NIRQ4,EOI4> ; COM1 DATA AREA
AREA2 SP_TAB <2,INT_COM2,IRQ3,NIRQ3,EOI3> ; COM2 DATA AREA
AREA3 SP_TAB <3,INT_COM3,IRQ4,NIRQ4,EOI4> ; COM3 DATA AREA
AREA4 SP_TAB <4,INT_COM4,IRQ3,NIRQ3,EOI3> ; COM4 DATA AREA
_DATA ENDS
PAGE
COM_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:COM_TEXT,DS:DGROUP,ES:NOTHING
PUBLIC _select_port
PUBLIC _save_com
PUBLIC _install_com
PUBLIC _restore_com
PUBLIC _open_com
PUBLIC _ioctl_com
PUBLIC _close_com
PUBLIC _dtr_on
PUBLIC _dtr_off
PUBLIC _r_count
PUBLIC _s_count
PUBLIC _receive_com
PUBLIC _send_com
PUBLIC _sendi_com
PUBLIC _send_local
PUBLIC _break_com
PUBLIC _com_errors
PUBLIC _modem_status
PAGE
; Here's the order of calls in UUPC. The routines in COMM.ASM are called
; from ulib.c.
; First (when a line in system has been read?), ulib&openline calls
; select_port() ; Sets up CURRENT_AREA
; then, save_com() ; Save INT vector
; then, install_com() ; Init area, hook INT
; then, open_com(&cmd, 'D', 'N', STOP*T, 'D') ; Init UART, clr bufs
; then, dtr_on().
; At that point the line is up and running. UUPC calls ulib&sread()
; which calls, receive_com();
; And UUPC calls ulib&swrite()
; which calls, send_com();
; To cause an error that the receiver will see, UUPC calls ulib&ssendbrk();
; which calls, break_com();
; When all done with the line, UUPC calls ulib&closeline()
; which calls, dtr_off();
; then, close_com();
; then, restore_com(); ; Unhook INT
; and, stat_errors();
; Note that on the PC COM1 and COM3 share IRQ4, while COM2 and COM4 share IRQ3.
; BUT, only one device on a given IRQ line can be active at a time. So it is
; sufficient for UUPC to hook whatever IRQ INT its modem is on as long as it
; unhooks it when it is done with that COM port. COMM cannot be an installed
; device driver since it must go away when UUPC is done so that other devices
; on the same INTs will come back to life. Also, it is OK to have a static
; CURRENT_AREA containing the current area that UUPC is using.
PAGE
;
; SELECT WHICH PORT IS TO BE "ACTIVE"
; [bp+6] = port number
_select_port PROC FAR
push bp
mov bp,sp
mov AX,[bp+6] ; get aguement
CMP AL,1 ; Port 1?
JE SP1 ; Yes
CMP AL,2 ; Port 2?
JE SP2 ; Yes
CMP AL,3 ; Port 3?
JE SP3 ; Yes
CMP AL,4 ; Port 4?
JE SP4 ; Yes
INT 20H ; N.O.T.A. ????? Halt for debugging!
; Assume port 1 if continued
SP1: MOV AX,OFFSET DGROUP:AREA1 ; SELECT COM1 DATA AREA
JMP SHORT SPX ; CONTINUE
SP2: MOV AX,OFFSET DGROUP:AREA2 ; SELECT COM2 DATA AREA
JMP SHORT SPX ; CONTINUE
SP3: MOV AX,OFFSET DGROUP:AREA3 ; SELECT COM3 DATA AREA
JMP SHORT SPX ; CONTINUE
SP4: MOV AX,OFFSET DGROUP:AREA4 ; SELECT COM4 DATA AREA
;Fall into SPX
SPX: MOV CURRENT_AREA,AX ; SET SELECTION IN MEMORY
mov sp,bp
pop bp
RET ; DONE
_select_port ENDP
PAGE
;
; SAVE ORIGINAL COM VECTOR
;
_save_com PROC FAR
push bp
mov bp,sp
push si
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
PUSH ES ; SAVE EXTRA SEGMENT
MOV AREA1.INT_HNDLR,OFFSET INT_HNDLR1
MOV AREA2.INT_HNDLR,OFFSET INT_HNDLR2
MOV AREA3.INT_HNDLR,OFFSET INT_HNDLR3
MOV AREA4.INT_HNDLR,OFFSET INT_HNDLR4
; Save old interrupt vector
MOV AH,35H ; FETCH INTERRUPT VECTOR CONTENTS
MOV AL,INT_COM[SI] ; INTERRUPT NUMBER
INT DOS ; DOS 2 FUNCTION
MOV OLD_COM_OFF[SI],BX ; SAVE
MOV BX,ES ; ES:BX
MOV OLD_COM_SEG[SI],BX ; FOR LATER RESTORATION
POP ES ; RESTORE ES
pop si
mov sp,bp
pop bp
RET ; DONE
_save_com ENDP
PAGE
;
; INSTALL_COM: INSTALL THE ACTIVE PORT
;
; SET 8250 PORTS FROM RS-232 BASE IN ROM BIOS DATA AREA
; INITIALIZE PORT CONSTANTS AND ERROR COUNTS
; INSTALL INTERRUPT VECTOR
;
; return ax=1 on success ax=0 on failure
;
_install_com PROC FAR
push bp
mov bp,sp
push si
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
PUSH ES ; SAVE EXTRA SEGMENT
CMP INSTALLED[SI],1 ; Is port installed on this machine?
JNE INSTOK ; NO, CONTINUE
JMP INSTX ; ELSE JUMP IF ALREADY INSTALLED
; CLEAR ERROR COUNTS
INSTOK: MOV WORD PTR EOVFLOW[SI],0 ; BUFFER OVERFLOWS
MOV WORD PTR EOVRUN[SI],0 ; RECEIVE OVERRUNS
MOV WORD PTR EBREAK[SI],0 ; BREAK CHARS
MOV WORD PTR EFRAME[SI],0 ; FRAMING ERRORS
MOV WORD PTR EPARITY[SI],0 ; PARITY ERRORS
MOV WORD PTR EXMIT[SI],0 ; TRANSMISSION ERRORS
MOV WORD PTR EDSR[SI],0 ; DATA SET READY ERRORS
MOV WORD PTR ECTS[SI],0 ; CLEAR TO SEND ERRORS
; SENSE PC TYPE AND SET DIVISOR ACCORDINGLY
MOV BX,ROM ; HIGH ROM SEGMENT
MOV ES,BX ; TO ES
ASSUME ES:ROM
MOV DIV50,DIV50PC ; ASSUME PC OR XT
CMP ROMID,0FDH ; IS IT A PCjr?
JNE INST0 ; JUMP IF NOT
MOV DIV50,DIV50JR ; ELSE SET JR DIVISOR
; SET 8250 PORT ADDRESSES
INST0: MOV BX,RBDA ; ROM BIOS DATA AREA
MOV ES,BX ; TO ES
ASSUME ES:RBDA
CMP PORT[SI],1 ; PORT 1?
JE INST3F8 ; Yes
CMP PORT[SI],2 ; PORT 2?
JE INST2F8 ; Yes
CMP PORT[SI],3 ; PORT 3?
JE INST3E8 ; Yes
CMP PORT[SI],4 ; PORT 4?
JE INST2E8 ; Yes
INT 20H ; N.O.T.A. (Caller is screwed up badly!)
INST3F8:MOV AX,3F8H ; COM1 BASE PORT ADDRESS
JMP SHORT INST2 ; CONTINUE
INST2F8:MOV AX,2F8H ; COM2 BASE PORT ADDRESS
JMP SHORT INST2 ; CONTINUE
INST3E8:
CMP RS232_BASE+4,0000H ; We have information?
JE INST3E8_A ; No --> Use default
MOV AX,RS232_BASE+4 ; Yes --> Use provided info
JMP SHORT INST2 ; CONTINUE
INST3E8_A:
MOV AX,3E8H ; COM3 BASE PORT ADDRESS
JMP SHORT INST2 ; CONTINUE
INST2E8:
CMP RS232_BASE+6,0000H ; We have information?
JE INST2E8_A ; No --> Use default
MOV AX,RS232_BASE+6 ; Yes --> Use provided info
JMP SHORT INST2 ; CONTINUE
INST2E8_A:
MOV AX,2E8H ; COM4 BASE PORT ADDRESS
; Fall into INST2
INST2: CMP AX,RS232_BASE ; INSTALLED?
JE INST2A ; JUMP IF SO
CMP AX,RS232_BASE+2 ; INSTALLED?
JE INST2A ; JUMP IF SO
CMP AX,RS232_BASE+4 ; INSTALLED?
JE INST2A ; JUMP IF SO
CMP AX,RS232_BASE+6 ; INSTALLED?
JNE INST666 ; JUMP IF NOT
; Fall into INST2A
INST2A: MOV BX,DATREG ; OFFSET OF TABLE OF PORTS
MOV CX,7 ; LOOP SIX TIMES
INST3: MOV WORD PTR [SI][BX],AX ; SET PORT ADDRESS
INC AX ; NEXT PORT
ADD BX,2 ; NEXT WORD ADDRESS
LOOP INST3 ; RS232 BASE LOOP
; RESET VECTOR TO POINT TO OUR HANDLER
MOV AREA1.INT_HNDLR,OFFSET INT_HNDLR1 ;;;Aready done in SaveCom
MOV AREA2.INT_HNDLR,OFFSET INT_HNDLR2
MOV AREA3.INT_HNDLR,OFFSET INT_HNDLR3
MOV AREA4.INT_HNDLR,OFFSET INT_HNDLR4
MOV AH,25H ; SET INTERRUPT VECTOR CONTENTS
MOV AL,INT_COM[SI] ; INTERRUPT NUMBER
MOV DX,OFFSET DGROUP:INT_HNDLR[SI] ; OUR INTERRUPT HANDLER
PUSH DS ; SAVE DATA SEGMENT
PUSH CS ; COPY CS
POP DS ; TO DS
INT DOS ; DOS FUNCTION
POP DS ; RECOVER DATA SEGMENT
; PORT INSTALLED
INSTX: MOV INSTALLED[SI],1 ; PORT INSTALLED
POP ES ; RESTORE ES
mov ax,1
pop si
mov sp,bp
pop bp
RET ; DONE
; PORT NOT INSTALLED
INST666:MOV INSTALLED[SI],0 ; PORT NOT INSTALLED ON THIS PC
POP ES ; RESTORE ES
mov ax,0
pop si
mov sp,bp
pop bp
RET ; DONE
_install_com ENDP
PAGE
;
; RESTORE ORIGINAL INTERRUPT VECTOR
;
_restore_com PROC FAR
push bp
mov bp,sp
push si
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
MOV INSTALLED[SI],0 ; PORT IS NO LONGER INSTALLED
MOV AH,25H ; SET INTERRUPT VECTOR FUNCTION
MOV AL,INT_COM[SI] ; INTERRUPT NUMBER
MOV DX,OLD_COM_OFF[SI] ; OLD OFFSET TO DX
MOV BX,OLD_COM_SEG[SI] ; OLD SEG
PUSH DS ; SAVE DS
MOV DS,BX ; TO DS
INT DOS ; DOS FUNCTION
POP DS ; RECOVER DS
pop si
mov sp,bp
pop bp
RET ; DONE
_restore_com ENDP
PAGE
;
; OPEN_COM ON CURRENT PORT
;
; CLEAR BUFFERS
; RE-INITIALIZE THE INTEL 8250 UART
; ENABLE INTERRUPTS ON THE INTEL 8259 INTERRUPT CONTROL CHIP
;
; [bp+6] = BAUD RATE
; [bp+8] = CONNECTION: M(ODEM), D(IRECT)
; [bp+10] = PARITY: N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
; [bp+12] = STOP BITS: 1, 2
; [bp+14] = XON/XOFF: E(NABLED), D(ISABLED)
;
_open_com PROC FAR
push bp
mov bp,sp
push si
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
CLI ; INTERRUPTS OFF
mov ax,[bp+6]
MOV BAUD_RATE[SI],AX ; SET
mov bh,[bp+8]
MOV CONNECTION[SI],BH ; ARGS
mov bl,[bp+10]
MOV PARITY[SI],BL ; IN
mov ch,[bp+12]
MOV STOP_BITS[SI],CH ; MEMORY
mov cl,[bp+14]
MOV XON_XOFF[SI],CL
; RESET FLOW CONTROL
MOV HOST_OFF[SI],0 ; HOST FLOWING
MOV PC_OFF[SI],0 ; PC FLOWING
; RESET BUFFER COUNTS AND POINTERS
MOV START_TDATA[SI],0
MOV END_TDATA[SI],0
MOV START_RDATA[SI],0
MOV END_RDATA[SI],0
MOV SIZE_TDATA[SI],0
MOV SIZE_RDATA[SI],0
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JNZ OC1 ; SKIP IF SO
JMP OCX ; ELSE ABORT
OC1:
; RESET THE 8250
MOV AL,0
MOV DX,MCR[SI]
OUT DX,AL
JMP $+2 ; I/O DELAY FOR JR
MOV DX,LSR[SI] ; RESET LINE STATUS CONDITION
IN AL,DX
JMP $+2 ; I/O DELAY FOR JR
MOV DX,DATREG[SI] ; RESET RECSIVE DATA CONDITION
IN AL,DX
JMP $+2 ; I/O DELAY FOR JR
MOV DX,MSR[SI] ; RESET MODEM DELTAS AND CONDITIONS
IN AL,DX
; CONVERT PASSED BAUD RATE TO 8250 DIVISOR
MOV AX,50 ; 50 BAUD
MUL DIV50 ; TIMES ITS DIVISOR
DIV BAUD_RATE[SI] ; OTHER SPEEDS ARE PROPORTIONAL
MOV BX,AX ; RESULT TO BX
; SET 8250 DIVISOR
MOV DX,LCR[SI] ; LINE CONTROL REGISTER
MOV AL,80H ; HI BIT ON
OUT DX,AL ; SET DLAB = 1
JMP $+2 ; I/O DELAY FOR JR
MOV DX,WORD PTR DLL[SI] ; LEAST SIGNIFICANT BYTE
MOV AL,BL ; LSB FROM TABLE
OUT DX,AL ; SET LSB ON 8250
JMP $+2 ; I/O DELAY FOR JR
MOV DX,WORD PTR DLH[SI] ; MOST SIGNIFICANT BYTE
MOV AL,BH ; MSB FROM TABLE
OUT DX,AL ; SET MSB ON 8250
JMP $+2 ; I/O DELAY FOR JR
; SET PARITY AND NUMBER OF STOP BITS
MOV AL,03H ; NONE OR SPACE PARITY IS THE DEFAULT
CMP PARITY[SI],'O' ; ODD PARITY REQUESTED?
JNE P1 ; JUMP IF NOT
MOV AL,0AH ; SELECT ODD PARITY
JMP SHORT P3 ; CONTINUE
P1: CMP PARITY[SI],'E' ; EVEN PARITY REQUESTED?
JNE P2 ; JUMP IF NOT
MOV AL,1AH ; SELECT EVEN PARITY
JMP SHORT P3 ; CONTINUE
P2: CMP PARITY[SI],'M' ; MARK PARITY REQUESTED?
JNE P3 ; JUMP IF NOT
MOV AL,2AH ; SELECT MARK PARITY
P3: TEST STOP_BITS[SI],2 ; 2 STOP BITS REQUESTED?
JZ STOP1 ; NO
OR AL,4 ; YES
STOP1: MOV DX,LCR[SI] ; LINE CONTROL REGISTER
OUT DX,AL ; SET 8250 PARITY MODE AND DLAB=0
; ENABLE INTERRUPTS ON 8259 AND 8250
IN AL,INTA01 ; SET ENABLE BIT ON 8259
AND AL,NIRQ[SI]
OUT INTA01,AL
MOV DX,IER[SI] ; ENABLE INTERRUPTS ON 8250
MOV AL,5 ; RECEIVE & LINE ERROR
OUT DX,AL
JMP $+2 ; I/O DELAY FOR JR
MOV DX,MCR[SI] ; SET DTR AND ENABLE INT DRIVER
MOV AL,0BH
OUT DX,AL
OCX: STI ; INTERRUPTS ON
pop si
mov sp,bp
pop bp
RET ; DONE
_open_com ENDP
PAGE;
;
; void far ioctl_com(int Flags, int Arg1, ...)
; Flags have bits saying what to do or change (IGNORED TODAY)
; Arg1, ... are the new values
;
_ioctl_com PROC FAR
PUSH BP
MOV BP,SP
PUSHF ; Save interrupt context
PUSH SI
MOV SI,CURRENT_AREA ; Pointer to COMi private area
CLI ; Prevent surprises
TEST INSTALLED[SI],1
JE IOCTLX ; No good. Just return.
MOV AX,[BP+6] ; Flags
; Check bits here...
MOV AX,[BP+8] ; Line speed
MOV BAUD_RATE[SI],AX ; Save in parameter block
CALL Set_Baud ; Set the baud rate in UART
IOCTLX: POP SI
POPF ; Restore interrupt state
MOV SP,BP
POP BP
RET
_ioctl_com ENDP
PAGE;
; ioctl-called routines (internal) ...
; SI: COMi private block
; CALL Set_Baud
; Returns: (nothing)
; Clobber: AX, BX, DX
Set_Baud PROC NEAR
MOV AX,50
MUL DIV50 ; Could be different on a PCJr!
DIV BAUD_RATE[SI] ; Get right number for the UART
MOV BX,AX ; Save it
MOV DX,LCR[SI] ; Line Control Register
IN AL,DX ; Get current size, stops, parity,...
PUSH AX
OR AL,80H ; DLAB bit
OUT DX,AL ; Talk to the baud rate regs now
MOV DX,WORD PTR DLL[SI] ; Least significant byte
MOV AL,BL ; New value
OUT DX,AL ; To UART
MOV DX,WORD PTR DLH[SI] ; Most signifiant byte
MOV AL,BH ; New value
OUT DX,AL
MOV DX,LCR[SI] ; Line Control Register
POP AX
OUT DX,AL ; Turn off DLAB, keep saved settings
RET
Set_Baud ENDP
PAGE;
;
; CLOSE_COM - TURNS OFF INTERRUPTS FROM THE COMMUNICATIONS PORT
;
_close_com PROC FAR
push bp
mov bp,sp
push si
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ CCX ; ABORT IF NOT
; TURN OFF 8250
MOV DX,IER[SI]
MOV AL,0
OUT DX,AL
; TURN OFF 8259
MOV DX,INTA01
IN AL,DX
OR AL,IRQ[SI]
JMP $+2 ; DELAY FOR AT
OUT DX,AL
CCX: pop si
mov sp,bp
pop bp
RET
_close_com ENDP
PAGE
;
; DTR_OFF - TURNS OFF DTR TO TELL MODEMS THAT THE TERMINAL HAS GONE AWAY
; AND TO HANG UP THE PHONE
;
_dtr_off PROC FAR
push bp
mov bp,sp
push si
PUSHF ; SAVE FLAGS
PUSH AX ; SAVE REGS
PUSH DX
PUSH SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ DFX ; ABORT IF NOT
MOV DX,MCR[SI]
MOV AL,08H ; DTR OFF, RTS OFF, OUT2 ON
OUT DX,AL
DFX: POP SI ; RECOVER REGS
POP DX
POP AX
POPF ; RECOVER FLAGS
pop si
mov sp,bp
pop bp
RET
_dtr_off ENDP
;
; DTR_ON - TURNS DTR ON
;
_dtr_on PROC FAR
push bp
mov bp,sp
push si
PUSHF ; SAVE FLAGS
PUSH AX ; SAVE REGS
PUSH DX
PUSH SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ DNX ; ABORT IF NOT
MOV DX,MCR[SI]
MOV AL,0BH
OUT DX,AL
DNX: POP SI ; RECOVER REGS
POP DX
POP AX
POPF ; RECOVER FLAGS
pop si
mov sp,bp
pop bp
RET ; DONE
_dtr_on ENDP
PAGE
;
; R_COUNT - RETURNS NUMBER OF BYTES IN THE RECEIVE BUFFER IN AX
; total in DX
;
_r_count PROC FAR
push bp
mov bp,sp
push si
PUSHF ; SAVE FLAGS
PUSH SI ; SAVE SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
MOV AX,0 ; NOTHING RECEIVED IF NOT INSTALLED
mov dx,R_SIZE
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ RCX ; ABORT IF NOT
MOV AX,SIZE_RDATA[SI] ; GET NUMBER OF BYTES USED
RCX: POP SI ; RESTORE SI
POPF ; RESTORE FLAGS
pop si
mov sp,bp
pop bp
RET
_r_count ENDP
PAGE
;
; RECEIVE - RETURNS THE NEXT CHARACTER FROM THE RECEIVE BUFFER IN AL
; AND REMOVES IT FROM THE BUFFER
; THE PARITY BIT IS STRIPPED OFF
;
_receive_com PROC FAR
push bp
mov bp,sp
push si
PUSHF ; SAVE FLAGS
PUSH BX ; SAVE REGS
PUSH SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
mov ax,-1 ; -1 if bad call
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ RCVX ; ABORT IF NOT
CMP SIZE_RDATA[SI],0 ; ANY CHARACTERS?
JE RCVX ; ABORT IF NOT
; GOOD CALL
mov ah,0 ; good call
MOV BX,START_RDATA[SI] ; GET POINTER TO OLDEST CHAR
MOV AL,RDATA[SI][BX] ; GET CHAR FROM BUFFER
; MOD BY LBA, 10/6/85 FOR PROPER SUPPORT OF NO PARITY COMMUNICATIONS
CMP PARITY[SI],'N' ; ARE WE RUNNING WITH NO PARITY?
JE L11 ; IF SO, DON'T STRIP HIGH BIT
; END OF MOD
AND AL,7FH ; STRIP PARITY BIT
L11: INC BX ; BUMP START_RDATA
CMP BX,R_SIZE ; SEE IF PAST END
JB L12 ; IF NOT THEN SKIP
MOV BX,0 ; ADJUST TO BEGINNING
L12: MOV START_RDATA[SI],BX ; SAVE THE NEW START_RDATA VALUE
DEC SIZE_RDATA[SI] ; ONE LESS CHARACTER
CMP XON_XOFF[SI],'E' ; FLOW CONTROL ENABLED?
JNE RCVX ; DO NOTHING IF DISABLED
CMP HOST_OFF[SI],1 ; HOST TURNED OFF?
JNE RCVX ; JUMP IF NOT
CMP SIZE_RDATA[SI],R_SIZE/20 ; RECEIVE BUFFER NEARLY EMPTY?
JGE RCVX ; DONE IF NOT
MOV HOST_OFF[SI],0 ; TURN ON HOST IF SO
PUSH AX ; SAVE RECEIVED CHAR
MOV AL,CONTROL_Q ; TELL HIM TO TALK
CLI ; TURN OFF INTERRUPTS
CALL SENDII ; SEND IMMEDIATELY INTERNAL
STI ; INTERRUPTS BACK ON
POP AX ; RESTORE RECEIVED CHAR
RCVX: POP SI ; RECOVER REGS
POP BX
POPF ; RECOVER FLAGS
pop si
mov sp,bp
pop bp
RET ; DONE
_receive_com ENDP
PAGE
;
; S_COUNT - RETURNS IN AX THE AMOUNT OF FREE SPACE
; REMAINING IN THE TRANSMIT BUFFER
; DX total size
;
_s_count PROC FAR
push bp
mov bp,sp
push si
PUSHF ; SAVE FLAGS
PUSH SI ; SAVE SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
MOV AX,0 ; NO SPACE LEFT IF NOT INSTALLED
mov dx,S_SIZE
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ SCX ; ABORT IF NOT
MOV AX,S_SIZE ; GET THE SIZE OF THE X-MIT BUFFER
SUB AX,SIZE_TDATA[SI] ; SUBTRACT THE NUMBER OF BYTES USED
SCX: POP SI ; RECOVER SI
POPF ; RESTORE FLAGS
pop si
mov sp,bp
pop bp
RET
_s_count ENDP
PAGE
;
; SEND - SEND A CHARACTER
; [bp+6] = char
;
_send_com PROC FAR
push bp
mov bp,sp
push si
mov al,[bp+6]
PUSHF ; SAVE FLAGS
PUSH AX ; SAVE REGS
PUSH BX
PUSH DX
PUSH SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ L44 ; ABORT IF NOT
CMP SIZE_TDATA[SI],S_SIZE ; BUFFER FULL?
JL L4A ; JUMP IF NOT
INC WORD PTR EOVFLOW[SI] ; BUMP ERROR COUNT
JMP SHORT L44 ; PUNT
L4A: MOV BX,END_TDATA[SI] ; BX POINTS TO FREE SPACE
MOV TDATA[SI][BX],AL ; MOVE CHAR TO BUFFER
INC BX ; INCREMENT END_TDATA
CMP BX,S_SIZE ; SEE IF PAST END
JL L4 ; IF NOT THEN SKIP
MOV BX,0 ; ADJUST TO BEGINNING
L4: MOV END_TDATA[SI],BX ; SAVE NEW END_TDATA
INC SIZE_TDATA[SI] ; ONE MORE CHARACTER IN X-MIT BUFFER
MOV DX,IER[SI] ; INTERRUPT ENABLE REGISTER
IN AL,DX ; GET IT
TEST AL,2 ; SEE IF TX INTERRUPTS ARE ENABLED
JNZ L44 ; JUMP IF SO
MOV AL,7 ; IF NOT THEN RCV, TX, LINE ERROR
OUT DX,AL ; ARE ENABLED
L44: POP SI ; RESTORE REGS
POP DX
POP BX
POP AX
POPF ; RESTORE FLAGS
pop si
mov sp,bp
pop bp
RET ; DONE
_send_com ENDP
PAGE
;
; SENDI - SEND A CHARACTER IMMEDIATELY
; [bp+6] = char to send
;
_sendi_com PROC FAR
push bp
mov bp,sp
push si
mov al,[bp+6]
PUSHF ; SAVE FLAGS
PUSH AX ; SAVE REGS
PUSH BX
PUSH DX
PUSH SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ LQ44 ; ABORT IF NOT
CLI ; MASK INTERRUPTS
CALL SENDII ; CALL INTERNAL SEND IMMEDIATE
STI ; INTERRRUPTS BACK ON
LQ44: POP SI ; RESTORE REGS
POP DX
POP BX
POP AX
POPF ; RESTORE FLAGS
pop si
mov sp,bp
pop bp
RET ; DONE
_sendi_com ENDP
PAGE
;
; INTERNAL ROUTINE
; DEPENDS ON CALLER TO KEEP INTERRUPTS CLEARED AND SET SI
; SENDI - SEND A CHARACTER IMMEDIATELY (PUT AT BEGINNING OF QUEUE)
; AL = CHAR TO WRITE
;
SENDII PROC NEAR
PUSH DX ; SAVE DX
CMP SIZE_TDATA[SI],S_SIZE ; BUFFER FULL?
JB LI4A ; JUMP IF NOT
INC WORD PTR EOVFLOW[SI] ; BUMP ERROR COUNT
MOV BX,START_TDATA[SI] ; BX POINTS TO FIRST CHAR IN BUFFER
MOV TDATA[SI][BX],AL ; CLOBBER FIRST CHAR IN BUFFER
JMP SHORT LI4B ; CONTINUE
LI4A: MOV BX,START_TDATA[SI] ; BX POINTS TO FIRST CHAR IN BUFFER
DEC BX ; BACKUP THE PTR
CMP BX,-1 ; BEFORE BEGINNING?
JNE LI4 ; JUMP IF NOT
MOV BX,S_SIZE-1 ; POINT TO END IF SO
LI4: MOV TDATA[SI][BX],AL ; MOVE CHAR TO BUFFER
MOV START_TDATA[SI],BX ; SAVE NEW START_TDATA
INC SIZE_TDATA[SI] ; ONE MORE CHARACTER IN X-MIT BUFFER
LI4B: MOV DX,IER[SI] ; INTERRUPT ENABLE REGISTER
IN AL,DX ; GET IT
TEST AL,2 ; SEE IF TX INTERRUPTS ARE ENABLED
JNZ LI44 ; JUMP IF SO
MOV AL,7 ; IF NOT THEN RCV, TX, LINE ERROR
OUT DX,AL ; ARE ENABLED
LI44: POP DX ; RECOVER DX
RET ; DONE
SENDII ENDP
PAGE
;
; S_LOCAL
;
_send_local PROC FAR
push bp
mov bp,sp
push si
mov al,[bp+6]
PUSHF ; SAVE FLAGS
PUSH AX ; SAVE REGS
PUSH BX
PUSH SI
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ SLX ; ABORT IF NOT
CLI ; INTERRUPTS OFF
CMP SIZE_RDATA[SI],R_SIZE ; SEE IF ANY ROOM
JB L13A ; SKIP IF ROOM
INC WORD PTR EOVFLOW[SI] ; BUMP OVERFLOW COUNT
JMP SHORT L14 ; PUNT
L13A: MOV BX,END_RDATA[SI] ; BX POINTS TO FREE SPACE
MOV RDATA[SI][BX],AL ; SEND DATA TO BUFFER
INC BX ; INCREMENT END_RDATA POINTER
CMP BX,R_SIZE ; SEE IF GONE PAST END
JL L13 ; IF NOT THEN SKIP
MOV BX,0 ; ELSE ADJUST TO BEGINNING
L13: MOV END_RDATA[SI],BX ; SAVE VALUE
INC SIZE_RDATA[SI] ; GOT ONE MORE CHARACTER
L14: STI ; INTERRUPTS BACK ON
SLX: POP SI ; RECOVER REGS
POP BX
POP AX
POPF ; RECOVER FLAGS
pop si
mov sp,bp
pop bp
RET ; DONE
_send_local ENDP
PAGE
;
; BREAK - CAUSES A BREAK TO BE SENT OUT ON THE LINE
;
_break_com PROC FAR
push bp
mov bp,sp
push si
PUSHF ; SAVE FLAGS
PUSH AX ; SAVE REGS
PUSH CX
PUSH DX
MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
TEST INSTALLED[SI],1 ; PORT INSTALLED?
JZ BRX ; ABORT IF NOT
MOV DX,LCR[SI] ; LINE CONTROL REGISTER
IN AL,DX ; GET CURRENT SETTING
JMP $+2 ; I/O DELAY FOR JR
OR AL,40H ; TURN ON BREAK BIT
OUT DX,AL ; SET IT ON THE 8250
MOV CX,0C000H ; WAIT APPROX. 1/4 SEC.
BREAK1: LOOP BREAK1 ; BUSY WAIT
AND AL,0BFH ; TURN OFF BREAK BIT
OUT DX,AL ; RESTORE LINE CONTROL REGISTER
BRX: POP DX ; RECOVER REGS
POP CX
POP AX
POPF ; RECOVER FLAGS
pop si
mov sp,bp
pop bp
RET ; DONE
_break_com ENDP
PAGE
;
; COM_ERRORS - RETURN POINTER IN dx:ax TO ERROR COUNTS
;
_com_errors PROC FAR
push bp
mov bp,sp
mov ax,OFFSET DGROUP:CURRENT_AREA
add ax,ERROR_BLOCK
mov dx,ds
mov sp,bp
pop bp
RET ; DONE
_com_errors ENDP
PAGE
;
; INTERNAL ROUTINE
; BUMP ERROR COUNTS FROM LINE STATUS IN AL
;
E_BUMP PROC NEAR
TEST AL,2 ; OVERRUN ERROR?
JZ LSI1 ; JUMP IF NOT
INC WORD PTR EOVRUN[SI] ; ELSE BUMP ERROR COUNT
LSI1: TEST AL,4 ; PARITY ERROR?
JZ LSI2 ; JUMP IF NOT
INC WORD PTR EPARITY[SI] ; ELSE BUMP ERROR COUNT
LSI2: TEST AL,8 ; FRAMING ERROR?
JZ LSI3 ; JUMP IF NOT
INC WORD PTR EFRAME[SI] ; ELSE BUMP ERROR COUNT
LSI3: TEST AL,16 ; BREAK RECEIVED?
JZ LSI4 ; JUMP IF NOT
INC WORD PTR EBREAK[SI] ; ELSE BUMP ERROR COUNT
LSI4: RET ; DONE
E_BUMP ENDP
PAGE
;
; INTERNAL ROUTINE
; MODEM SEND PROTOCOL
;
M_PROTOCOL PROC NEAR
CMP CONNECTION[SI],'M' ; MODEM CONNECTION?
JNE S3 ; IF NOT, SKIP DSR & CTS PROTOCOL
; TELL MODEM WE'RE READY TO SEND
MOV DX,MCR[SI] ; MODEM CONTROL REGISTER
MOV AL,00001011B ; OUT 2, RTS, DTR
OUT DX,AL ; TERMINAL READY, REQUEST TO SEND
JMP $+2 ; I/O DELAY FOR JR
; WAIT UNTIL MODEM SAYS DATA SET READY
MOV CX,1000 ; TIMEOUT COUNT
MOV DX,MSR[SI] ; MODEM STATUS REGISTER
S1: IN AL,DX ; GET MODEM STATUS
TEST AL,20H ; DATA SET READY?
JNZ S1X ; YES, TEST CLEAR TO SEND
LOOP S1 ; NO, BUSY WAIT
INC WORD PTR EDSR[SI] ; BUMP ERROR COUNT
JMP SHORT S3 ; WE TIMED OUT
S1X:
; WAIT UNTIL MODEM SAYS IT'S CLEAR TO SEND
MOV CX,1000 ; TIMEOUT COUNT
S2: IN AL,DX ; GET MODEM STATUS
TEST AL,10H ; CLEAR TO SEND?
JNZ S2X ; YES
LOOP S2 ; NO, KEEP TRYING
INC WORD PTR ECTS[SI] ; BUMP ERROR COUNT - WE TIMED OUT
S2X:
; TEST FOR TRANSMITTER READY
S3: MOV DX,LSR[SI] ; LINE STATUS REGISTER
IN AL,DX ; GET LINE STATUS
TEST AL,20H ; TRANSMITTER READY?
JNZ S4 ; SKIP IF SO
INC WORD PTR EXMIT[SI] ; ELSE BUMP ERROR COUNT
S4: RET ; DONE
M_PROTOCOL ENDP
PAGE
;
; INTERNAL ROUTINES FOR FLOW CONTROL
;
; FLOW_IN - RESPOND TO FLOW CONTROL COMMANDS FROM HOST
; FLOW_OUT - ISSUE FLOW CONTROL COMMANDS TO HOST
;
FLOW_IN PROC NEAR
PUSH AX ; SAVE CHAR
CMP XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
JNE FI_NOCARRY ; DO NOTHING IF DISABLED
AND AL,7FH ; STRIP PARITY
CMP AL,CONTROL_S ; STOP COMMAND RECEIVED?
JNE FI_1 ; JUMP IF NOT
MOV PC_OFF[SI],1 ; WE MUST SHUT UP
STC ; Flag we got special character
JMP SHORT FI_EXIT ; Continue
FI_1: CMP AL,CONTROL_Q ; GO COMMAND RECEIVED?
JNE FI_NOCARRY ; NO, MUST BE NORMAL CHAR
MOV PC_OFF[SI],0 ; WE START TALKING AGAIN
STC ; Flag we got special character
JMP SHORT FI_EXIT ; Continue
FI_NOCARRY:
CLC ; Not special character, no carry
FI_EXIT:
POP AX ; RESTORE CHAR
RET ; DONE
FLOW_IN ENDP
;
FLOW_OUT PROC NEAR
CMP XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
JNE FO_X ; DO NOTHING IF DISABLED
CMP HOST_OFF[SI],1 ; HOST TURNED OFF?
JE FO_X ; JUMP IF SO
CMP SIZE_RDATA[SI],R_SIZE/2 ; RECEIVE BUFFER NEARLY FULL?
JLE FO_X ; DONE IF NOT
MOV AL,CONTROL_S ; TURN OFF HOST IF SO
CALL SENDII ; SEND IMMEDIATELY INTERNAL
MOV HOST_OFF[SI],1 ; HOST IS NOW OFF
FO_X: RET ; DONE
FLOW_OUT ENDP
PAGE ;
;
; _MODEM_STATUS - Returns the modem status register in AL
;
; Bits are: 0x80: -CD (Carrier Detect, inverted)
; 0x40: -RI (Ring Indicator, inverted)
; 0x20: -DSR (Data Set Ready, inverted)
; 0x10: -CTS (Clear to Send, inverted)
; 0x08: Delta Carrier Detect (CD changed)
; 0x04: Trailing edge of RI (RI went OFF)
; 0x02: Delta DSR (DSR changed)
; 0x01: Delta CTS (CTS changed)
;
_modem_status PROC FAR
push bp
mov bp,sp
PUSH DX
PUSH SI
MOV SI,CURRENT_AREA ; Point to block for selected port
MOV DX,MSR[SI] ; IO Addr of Modem Status Register
IN AL,DX ; Get the live value
XOR AH,AH ; Flush unwanted bits
POP SI
POP DX
mov sp,bp
pop bp
RET
_modem_status ENDP
PAGE
;
; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
;
INT_HNDLR1 PROC FAR
PUSH SI ; SAVE SI
MOV SI,OFFSET DGROUP:AREA1 ; DATA AREA FOR COM1:
JMP SHORT INT_COMMON ; CONTINUE
;
; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
;
INT_HNDLR2 PROC FAR
PUSH SI ; SAVE SI
MOV SI,OFFSET DGROUP:AREA2 ; DATA AREA FOR COM2:
JMP SHORT INT_COMMON ; CONTINUE
;
; INT_HNDLR3 - HANDLES INTERRUPTS GENERATED BY COM3:
;
INT_HNDLR3 PROC FAR
PUSH SI ; SAVE SI
MOV SI,OFFSET DGROUP:AREA3 ; DATA AREA FOR COM3:
JMP SHORT INT_COMMON ; CONTINUE
;
; INT_HNDLR4 - HANDLES INTERRUPTS GENERATED BY COM4:
;
INT_HNDLR4 PROC FAR
PUSH SI ; SAVE SI
MOV SI,OFFSET DGROUP:AREA4 ; DATA AREA FOR COM4:
; Fall into INT_COMMON
;
; BODY OF INTERRUPT HANDLER
;
INT_COMMON:
PUSH AX ; SAVE REGS
PUSH BX
PUSH CX
PUSH DX
PUSH BP
PUSH DI
PUSH DS
PUSH ES
MOV AX,DGROUP ; Offsets are relative to DGROUP [WWP]
MOV DS,AX ; TO DS
; CLEAR THE INTERRUPT CONTROLLER FLAG
MOV DX,INTA00 ; 8259 CONTROL PORT
MOV AL,EOI[SI] ; SPECIFIC END OF INTERRUPT
OUT DX,AL ; CLEAR FLAG
; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
REPOLL:
MOV DX,IIR[SI] ; READ INTERRUPT STATUS REGISTER
IN AL,DX
CMP AL,4
JE RX_INT ; IF FROM THE RECEIVER
CMP AL,2
JE TX_INT ; IF FROM THE TRANSMITTER
CMP AL,6
JE LSTAT_INT ; INTERRUPT BECAUSE OF LINE STATUS
CMP AL,0
JE MSTAT_INT ; INTERRUPT BECAUSE OF MODEM STATUS
JMP FAR PTR INT_END ; DONE, EXIT (DON'T FIX FAR PTR STUFF)
LSTAT_INT:
MOV DX,LSR[SI] ; READ AND IGNORE LINE STATUS
IN AL,DX ;
CALL E_BUMP ; JUST BUMP ERROR COUNTS
JMP REPOLL ; SEE IF ANY MORE INTERRUPTS
MSTAT_INT:
MOV DX,MSR[SI] ; READ AND IGNORE MODEM STATUS
IN AL,DX ;
JMP REPOLL ; SEE IF ANY MORE INTERRUPTS
TX_INT:
CMP PC_OFF[SI],1 ; HAVE WE BEEN TOLD TO SHUT UP?
JNE GOODTX1 ; JUMP IF NOT
CMP HOST_OFF[SI],1 ; HAS HOST ALSO SHUT UP?
JNE SEND_NO_MORE ; JUMP IF NOT
; CLEAR XON/XOFF DEADLOCK
MOV PC_OFF[SI],0 ; WE SPEAK
MOV HOST_OFF[SI],0 ; THEY REPLY
MOV AL,CONTROL_Q ; BUT ONLY WHEN
CALL SENDII ; WE LET THEM
GOODTX1:
CMP SIZE_TDATA[SI],0 ; SEE IF ANY MORE DATA TO SEND
JG HAVE_DATA ; IF POSITIVE THEN THERE IS DATA TO SEND
; IF NO DATA TO SEND THEN RESET TX INTERRUPT AND RETURN
SEND_NO_MORE:
MOV DX,IER[SI] ;
MOV AL,5 ; JUST RCV AND LINE ERROR
OUT DX,AL ; ARE SET
JMP REPOLL ;
HAVE_DATA:
CALL M_PROTOCOL ; DO MODEM PROTOCOL IF NECESSARY
MOV BX,START_TDATA[SI] ; BX POINTS TO NEXT CHAR. TO BE SENT
MOV AL,TDATA[SI][BX] ; GET DATA FROM BUFFER
MOV DX,DATREG[SI] ; DX EQUALS PORT TO SEND DATA TO
OUT DX,AL ; SEND DATA
INC BX ; INCREMENT START_TDATA
CMP BX,S_SIZE ; SEE IF GONE PAST END
JB NTADJ ; IF NOT THEN SKIP
MOV BX,0 ; RESET TO BEGINNING
NTADJ: MOV START_TDATA[SI],BX ; SAVE START_TDATA
DEC SIZE_TDATA[SI] ; ONE LESS CHARACTER IN X-MIT BUFFER
JMP REPOLL
RX_INT:
MOV DX,DATREG[SI] ; 8250 DATA REGISTER
IN AL,DX ; GET DATA
CALL FLOW_IN ; RESPOND TO F.C. COMMANDS FROM HOST
JC REPOLL ; If flow control, do not save
; ahd
CMP SIZE_RDATA[SI],R_SIZE ; SEE IF ANY ROOM
JL GOOD_RX1 ; CONTINUE IF SO
INC WORD PTR EOVFLOW[SI] ; BUMP OVERFLOW ERROR COUNT
JMP REPOLL ; PUNT
GOOD_RX1:
MOV BX,END_RDATA[SI] ; BX POINTS TO FREE SPACE
MOV RDATA[SI][BX],AL ; MOVE DATA TO BUFFER
INC SIZE_RDATA[SI] ; GOT ONE MORE CHARACTER
INC BX ; INCREMENT END_RDATA POINTER
CMP BX,R_SIZE ; SEE IF GONE PAST END
JB NRADJ ; IF NOT THEN SKIP
MOV BX,0 ; ELSE ADJUST TO BEGINNING
NRADJ: MOV END_RDATA[SI],BX ; SAVE VALUE
DO_FLOW: ; ahd
CALL FLOW_OUT ; ISSUE FLOW CONTROL COMMANDS TO HOST
JMP REPOLL ;
INT_END:
POP ES ; RESTORE REGS
POP DS
POP DI
POP BP
POP DX
POP CX
POP BX
POP AX
POP SI ; RESTORE SI, TOO
IRET
INT_HNDLR4 ENDP
INT_HNDLR3 ENDP
INT_HNDLR2 ENDP
INT_HNDLR1 ENDP
COM_TEXT ENDS
END