home *** CD-ROM | disk | FTP | other *** search
- TITLE COM_PKG2 -- Last updated 10/6/85
- PAGE 55,131
- ;
- ; 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 500 ; SIZE OF RECEIVE BUFFERS
- S_SIZE EQU 100 ; SIZE OF TRANSMIT BUFFERS
- ; INTERRUPT NUMBERS
- INT_COM1 EQU 0CH ; COM1: FROM 8259
- INT_COM2 EQU 0BH ; COM2: FROM 8259
- ; 8259 PORTS
- INTA00 EQU 20H ; 8259A PORT, A0 = 0
- INTA01 EQU 21H ; 8259A PORT, A0 = 1
- ; COM1: 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: 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
- ; 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
- 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
- DATA ENDS
- PAGE
- CODE SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:CODE,DS:DATA,ES:NOTHING
-
- PUBLIC SELECT_PORT ; SELECT COMMUNICATIONS PORT
- PUBLIC SAVE_COM ; SAVE OLD INTERRUPT VECTOR
- PUBLIC INSTALL_COM ; INSTALL OUR INTERRUPT VECTOR
- PUBLIC RESTORE_COM ; RESTORE OLD INTERRUPT VECTOR
- PUBLIC OPEN_COM ; INITIALIZE PORT
- PUBLIC CLOSE_COM ; TURN OFF INTERRUPTS FROM COM PORT
- PUBLIC DTR_OFF ; TURN OFF DTR
- PUBLIC DTR_ON ; TURN ON DTR
- PUBLIC R_COUNT ; RETURN NUMBER OF CHARACTERS IN INPUT BUFFER
- PUBLIC RECEIVE ; READ NEXT CHARACTER IN INPUT BUFFER
- PUBLIC S_COUNT ; RETURN NO. OF FREE BYTES IN OUTPUT BUFFER
- PUBLIC SEND ; WRITE A CHARACTER TO OUTPUT BUFFER
- PUBLIC SENDI ; WRITE A CHAR TO FRONT OF OUTPUT BUFFER
- PUBLIC S_LOCAL ; WRITE A CHARACTER TO THE INPUT BUFFER
- PUBLIC BREAK ; SEND A BREAK
- PUBLIC COM_ERRORS ; RETURN POINTER TO ERROR COUNTS
- PAGE
- ;
- ; SELECT WHICH PORT IS TO BE "ACTIVE"
- ; AL = PORT NUMBER (1 OR 2)
- ;
- SELECT_PORT PROC NEAR
- PUSHF ; SAVE FLAGS
- PUSH AX ; SAVE AX
- TEST AL,1 ; FIRST PORT?
- JZ SP1 ; IF NOT, IT MUST BE SECOND PORT
- MOV AX,OFFSET AREA1 ; SELECT COM1 DATA AREA
- JMP SHORT SPX ; CONTINUE
- SP1: MOV AX,OFFSET AREA2 ; SELECT COM2 DATA AREA
- SPX: MOV CURRENT_AREA,AX ; SET SELECTION IN MEMORY
- POP AX ; RESTORE AX
- POPF ; RESTORE FLAGS
- RET ; DONE
- SELECT_PORT ENDP
- PAGE
- ;
- ; SAVE ORIGINAL COM VECTOR
- ;
- SAVE_COM PROC NEAR
- 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 AH,30H ; GET DOS VERSION NUMBER
- INT DOS ; DOS FUNCTION
- CMP AL,2 ; AT LEAST DOS 2?
- JB SVC1 ; JUMP IF DOS 1
- ; SAVE OLD VECTOR WITH DOS 2 CALLS
- 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
- JMP SHORT SVCX ; DONE
- ; SAVE OLD VECTOR WITH DOS 1 CALLS
- SVC1: MOV AX,0 ; ZERO SEGMENT
- MOV ES,AX ; ES POINTS TO INTERRUPT VECTORS
- MOV BL,INT_COM[SI] ; OUR INTERRUPT NUMBER
- MOV BH,0 ; BL -> BX
- SHL BX,1 ; TIMES FOUR
- SHL BX,1 ; IS OFFSET OF VECTOR IN MEMORY
- MOV AX,WORD PTR ES:[BX] ; SAVE
- MOV OLD_COM_OFF[SI],AX ; THE
- ADD BX,2 ; OLD
- MOV AX,WORD PTR ES:[BX] ; INTERRUPT
- MOV OLD_COM_SEG[SI],AX ; VECTOR
- SVCX: POP ES ; RESTORE ES
- 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
- ;
- ; RETURNS WITH CARRY CLEARED UPON SUCCESS
- ; RETURNS WITH CARRY SET IF PORT IS UNAVAILABLE ON THIS PC
- ;
- INSTALL_COM PROC NEAR
- MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
- PUSH ES ; SAVE EXTRA SEGMENT
- CMP INSTALLED[SI],1 ; ALREADY INSTALLED?
- 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
- TEST PORT[SI],1 ; PORT 1?
- JZ INST1 ; JUMP IF NOT
- MOV AX,3F8H ; COM1 BASE PORT ADDRESS
- JMP SHORT INST2 ; CONTINUE
- INST1: MOV AX,2F8H ; COM2 BASE PORT ADDRESS
- INST2: CMP AX,RS232_BASE ; INSTALLED?
- JE INST2A ; JUMP IF SO
- CMP AX,RS232_BASE+2 ; INSTALLED?
- JNE INST666 ; JUMP IF NOT
- 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
- MOV AREA2.INT_HNDLR,OFFSET INT_HNDLR2
- MOV AH,25H ; SET INTERRUPT VECTOR CONTENTS
- MOV AL,INT_COM[SI] ; INTERRUPT NUMBER
- MOV DX,OFFSET 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
- CLC ; SUCCESS - CLEAR CARRY BIT
- RET ; DONE
- ; PORT NOT INSTALLED
- INST666:MOV INSTALLED[SI],0 ; PORT NOT INSTALLED ON THIS PC
- POP ES ; RESTORE ES
- STC ; SET CARRY BIT FOR ERROR FLAG
- RET ; DONE
- INSTALL_COM ENDP
- PAGE
- ;
- ; RESTORE ORIGINAL INTERRUPT VECTOR
- ;
- RESTORE_COM PROC NEAR
- 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
- RET ; DONE
- RESTORE_COM ENDP
- PAGE
- ;
- ; OPEN_COM ON CURRENT PORT
- ; AX = BAUD RATE
- ; BH = CONNECTION: M(ODEM), D(IRECT)
- ; BL = PARITY: N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
- ; CH = STOP BITS: 1, 2
- ; CL = XON/XOFF: E(NABLED), D(ISABLED)
- ;
- ; CLEAR BUFFERS
- ; RE-INITIALIZE THE INTEL 8250 UART
- ; ENABLE INTERRUPTS ON THE INTEL 8259 INTERRUPT CONTROL CHIP
- ;
- OPEN_COM PROC NEAR
- MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
-
- CLI ; INTERRUPTS OFF
- MOV BAUD_RATE[SI],AX ; SET
- MOV CONNECTION[SI],BH ; ARGS
- MOV PARITY[SI],BL ; IN
- MOV STOP_BITS[SI],CH ; MEMORY
- 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
- RET ; DONE
- OPEN_COM ENDP
- PAGE
- ;
- ; CLOSE_COM - TURNS OFF INTERRUPTS FROM THE COMMUNICATIONS PORT
- ;
- CLOSE_COM PROC NEAR
- 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: 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 NEAR
- 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
- RET
- DTR_OFF ENDP
- ;
- ; DTR_ON - TURNS DTR ON
- ;
- DTR_ON PROC NEAR
- 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
- RET ; DONE
- DTR_ON ENDP
- PAGE
- ;
- ; R_COUNT - RETURNS NUMBER OF BYTES IN THE RECEIVE BUFFER IN AX
- ; RETURNS TOTAL SIZE IN BX
- ;
- R_COUNT PROC NEAR
- 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 BX,R_SIZE ; GET TOTAL 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
- 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 PROC NEAR
- PUSHF ; SAVE FLAGS
- PUSH BX ; SAVE REGS
- PUSH SI
- MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
- MOV AL,0 ; RETURN NUL 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 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
- RET ; DONE
- RECEIVE ENDP
- PAGE
- ;
- ; S_COUNT - RETURNS IN AX THE AMOUNT OF FREE SPACE
- ; REMAINING IN THE TRANSMIT BUFFER
- ; RETURNS IN BX THE TOTAL SIZE OF THE TRANSMIT BUFFER
- ;
- S_COUNT PROC NEAR
- 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 BX,S_SIZE ; SIZE IN BX
-
- 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
- RET
- S_COUNT ENDP
- PAGE
- ;
- ; SEND - SEND A CHARACTER
- ; AL = CHAR TO WRITE
- ;
- SEND PROC NEAR
- 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
- RET ; DONE
- SEND ENDP
- PAGE
- ;
- ; SENDI - SEND A CHARACTER IMMEDIATELY
- ; AL = CHAR TO WRITE
- ;
- SENDI PROC NEAR
- 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
- RET ; DONE
- SENDI 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
- ; AL = CHAR
- ;
- ; WRITES A CHARACTER TO THE INPUT BUFFER
- ;
- S_LOCAL PROC NEAR
- 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
- RET ; DONE
- S_LOCAL ENDP
- PAGE
- ;
- ; BREAK - CAUSES A BREAK TO BE SENT OUT ON THE LINE
- ;
- BREAK PROC NEAR
- 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
- RET ; DONE
- BREAK ENDP
- PAGE
- ;
- ; COM_ERRORS - RETURN POINTER IN SI TO ERROR COUNTS
- ;
- COM_ERRORS PROC NEAR
- MOV SI,CURRENT_AREA ; SI POINTS TO DATA AREA
- ADD SI,ERROR_BLOCK ; SI POINTS TO ERROR BLOCK
- 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_2 ; 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
- JMP SHORT FI_2 ; CONTINUE
- FI_1: CMP AL,CONTROL_Q ; GO COMMAND RECEIVED?
- JNE FI_2 ; NO, MUST BE NORMAL CHAR
- MOV PC_OFF[SI],0 ; WE START TALKING AGAIN
- FI_2: 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
- ;
- ; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
- ;
- INT_HNDLR1 PROC FAR
- PUSH SI ; SAVE SI
- MOV SI,OFFSET 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 AREA2 ; DATA AREA FOR COM2:
- ;
- ; 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,DATA ; OUR DATA SEG
- 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
- 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
- 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_HNDLR2 ENDP
- INT_HNDLR1 ENDP
- DATA SEGMENT
- DB 'R.A.G. 85'
- DATA ENDS
- CODE ENDS
- END
-