PAGE 118,121
TITLE RS232 ---- 06/10/85  COMMUNICATIONS BIOS (RS232)
.286C
.XLIST
INCLUDE DSEG.INC
INCLUDE POSTEQU.INC
.LIST
CODE	SEGMENT BYTE PUBLIC
	PUBLIC	RS232_IO_1
	EXTRN	A1:NEAR
	EXTRN	DDS:NEAR

;--- INT 14 H ------------------------------------------------------------------
;RS232_IO								       :
;	THIS ROUTINE PROVIDES BYTE STREAM I/O TO THE COMMUNICATIONS	       :
;	PORT ACCORDING TO THE PARAMETERS:				       :
;									       :
;	(AH)= 00H  INITIALIZE THE COMMUNICATIONS PORT			       :
;		   (AL) HAS PARAMETERS FOR INITIALIZATION		       :
;									       :
;		7	6	5	4	3	2	1	0      :
;		----- BAUD RATE --	-PARITY--     STOPBIT	--WORD LENGTH--:
;									       :
;		000 - 110		XO - NONE	0 - 1	 10 - 7 BITS   :
;		001 - 150		01 - ODD	1 - 2	 11 - 8 BITS   :
;		010 - 300		11 - EVEN			       :
;		011 - 600						       :
;		100 - 1200						       :
;		101 - 2400						       :
;		110 - 4800						       :
;		111 - 9600						       :
;		ON RETURN, CONDITIONS SET AS IN CALL TO COMMO STATUS (AH=03H)  :
;									       :
;      (AH)= 01H   SEND THE CHARACTER IN (AL) OVER THE COMMO LINE	       :
;		   (AL) REGISTER IS PRESERVED				       :
;		   ON EXIT, BIT 7 OF AH IS SET IF THE ROUTINE WAS UNABLE TO    :
;			TO TRANSMIT THE BYTE OF DATA OVER THE LINE.	       :
;			IF BIT 7 OF AH IS NOT SET, THE			       :
;			REMAINDER OF (AH) IS SET AS IN A STATUS REQUEST,       :
;			REFLECTING THE CURRENT STATUS OF THE LINE.	       :
;      (AH)= 02H   RECEIVE A CHARACTER IN (AL), FROM COMMO LINE BEFORE	       :
;			RETURNING TO CALLER				       :
;		   ON EXIT, (AH) HAS THE CURRENT LINE STATUS, AS SET BY THE    :
;			THE STATUS ROUTINE, EXCEPT THAT THE ONLY BITS	       :
;			LEFT ON ARE THE ERROR BITS (7,4,3,2,1)		       :
;			IF (AH) HAS BIT 7 ON (TIME OUT) THE REMAINING	       :
;			BITS ARE NOT PREDICTABLE.			       :
;			THUS, (AH) IS NON ZERO ONLY WHEN AN ERROR OCCURRED.    :
;      (AH)= 03H   RETURN THE COMMO PORT STATUS IN (AX) 		       :
;		    (AH) CONTAINS THE LINE CONTROL STATUS IN (AX)	       :
;			 BIT 7 = TIME OUT				       :
;			 BIT 6 = TRANSMIT SHIFT REGISTER EMPTY		       :
;			 BIT 5 = TRANSMIT HOLDING REGISTER EMPTY	       :
;			 BIT 4 = BREAK DETECT				       :
;			 BIT 3 = FRAMING ERROR				       :
;			 BIT 2 = PARITY ERROR				       :
;			 BIT 1 = OVERRUN ERROR				       :
;			 BIT 0 = DATA READY				       :
;		    (AL) CONTAINS THE MODEM STATUS IN			       :
;			 BIT 7 = RECEIVE LINE SIGNAL DETECT		       :
;			 BIT 6 = RING INDICATOR 			       :
;			 BIT 5 = DATA SET READY 			       :
;			 BIT 4 = CLEAR TO SEND				       :
;			 BIT 3 = DELTA RECEIVE LINE SIGNAL DETECT	       :
;			 BIT 2 = TRAILING EDGE RING DETECTOR		       :
;			 BIT 1 = DELTA DATA SET READY			       :
;			 BIT 0 = DELTA CLEAR TO SEND			       :
;									       :
;	(DX) = PARAMETER INDICATING WHICH RS232 CARD (0,1 ALLOWED)	       :
;									       :
; DATA AREA @RS232_BASE CONTAINS THE BASE ADDRESS OF THE 8250 ON THE CARD      :
;	LOCATION 400H CONTAINS UP TO 4 RS232 ADDRESSES POSSIBLE 	       :
;	DATA AREA LABEL @RS232_TIM_OUT (BYTE) CONTAINS OUTER LOOP COUNT        :
;	VALUE FOR TIMEOUT (DEFAULT=1)					       :
;OUTPUT 								       :
;		AX MODIFIED ACCORDING TO PARAMETERS OF CALL		       :
;		ALL OTHERS UNCHANGED					       :
;-------------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA
RS232_IO_1	PROC	FAR

;-----	VECTOR TO APPROPRIATE ROUTINE

	STI				; INTERRUPTS BACK ON
	PUSH	DS			; SAVE SEGMENT
	PUSH	DX
	PUSH	SI
	PUSH	DI
	PUSH	CX
	PUSH	BX
	MOV	SI,DX			; RS232 VALUE TO (SI)
	MOV	DI,DX			; AND TO (DI) (FOR TIMEOUTS)
	SHR	DX,2			; TEST PARAMETER
	JNZ	A3			; RETURN IF NOT IN RANGE
	SHL	SI,1			; WORD OFFSET
	CALL	DDS
	MOV	DX,@RS232_BASE[SI]	; GET BASE ADDRESS
	OR	DX,DX			; TEST FOR 0 BASE ADDRESS
	JZ	A3			; RETURN
	OR	AH,AH			; TEST FOR (AH)= 00H
	JZ	A4			; COMMO INITIALIZATION
	DEC	AH			; TEST FOR (AH)= 01H
	JZ	A5			; SEND (AL)
	DEC	AH			; TEST FOR (AH)= 02H
	JZ	A12			; RECEIVE INTO (AL)
A2:
	DEC	AH			; TEST FOR (AH)= 03H
	JNZ	A3
	JMP	A18			; COMMUNICATION STATUS
A3:					; RETURN FROM RS232
	POP	BX
	POP	CX
	POP	DI
	POP	SI
	POP	DX
	POP	DS
	IRET				; RETURN TO CALLER, NO ACTION
PAGE
;-----	INITIALIZE THE COMMUNICATIONS PORT

A4:
	MOV	AH,AL			; SAVE INITIALIZATION PARAMETERS IN (AH)
	ADD	DX,3			; POINT TO 8250 CONTROL REGISTER
	MOV	AL,80H
	OUT	DX,AL			; SET DLAB=1

;-----	DETERMINE BAUD RATE DIVISOR

	MOV	DL,AH			; GET PARAMETERS TO (DL)
	MOV	CL,4
	ROL	DL,CL
	AND	DX,0EH			; ISOLATE THEM
	MOV	DI,OFFSET A1		; BASE OF TABLE
	ADD	DI,DX			; PUT INTO INDEX REGISTER
	MOV	DX,@RS232_BASE[SI]	; POINT TO HIGH ORDER OF DIVISOR
	INC	DX
	MOV	AL,CS:[DI]+1		; GET HIGH ORDER OF DIVISOR
	OUT	DX,AL			; SET ms OF DIVISOR TO 0
	DEC	DX
	JMP	$+2			; I/O DELAY
	MOV	AL,CS:[DI]		; GET LOW ORDER OF DIVISOR
	OUT	DX,AL			; SET LOW OF DIVISOR
	ADD	DX,3
	MOV	AL,AH			; GET PARAMETERS BACK
	AND	AL,01FH 		; STRIP OFF THE BAUD BITS
	OUT	DX,AL			; LINE CONTROL TO 8 BITS
	DEC	DX
	DEC	DX
	JMP	$+2			; I/O DELAY
	MOV	AL,0
	OUT	DX,AL			; INTERRUPT ENABLES ALL OFF
	JMP	SHORT A18		; COM_STATUS

;-----	SEND CHARACTER IN (AL) OVER COMMO LINE

A5:
	PUSH	AX			; SAVE CHAR TO SEND
	ADD	DX,4			; MODEM CONTROL REGISTER
	MOV	AL,3			; DTR AND RTS
	OUT	DX,AL			; DATA TERMINAL READY, REQUEST TO SEND
	INC	DX			; MODEM STATUS REGISTER
	INC	DX
	MOV	BH,30H			; DATA SET READY & CLEAR TO SEND
	CALL	WAIT_FOR_STATUS 	; ARE BOTH TRUE
	JE	A9			; YES, READY TO TRANSMIT CHAR
A7:
	POP	CX
	MOV	AL,CL			; RELOAD DATA BYTE
A8:
	OR	AH,80H			; INDICATE TIME OUT
	JMP	A3			; RETURN

A9:					; CLEAR TO SEND
	DEC	DX			; LINE STATUS REGISTER
A10:					; WAIT SEND
	MOV	BH,20H			; IS TRANSMITTER READY
	CALL	WAIT_FOR_STATUS 	; TEST FOR TRANSMITTER READY
	JNZ	A7			; RETURN WITH TIME OUT SET
A11:					; OUT CHAR
	SUB	DX,5			; DATA PORT
	POP	CX			; RECOVER IN CX TEMPORARILY
	MOV	AL,CL			; MOVE CHAR TO AL FOR OUT, STATUS IN AH
	OUT	DX,AL			; OUTPUT CHARACTER
	JMP	A3			; RETURN

;-----	RECEIVE CHARACTER FROM COMMO LINE

A12:
	ADD	DX,4			; MODEM CONTROL REGISTER
	MOV	AL,1			; DATA TERMINAL READY
	OUT	DX,AL
	INC	DX			; MODEM STATUS REGISTER
	INC	DX
A13:					; WAIT_DSR
	MOV	BH,20H			; DATA SET READY
	CALL	WAIT_FOR_STATUS 	; TEST FOR DSR
	JNZ	A8			; RETURN WITH ERROR
A15:					; WAIT_DSR_END
	DEC	DX			; LINE STATUS REGISTER
A16:					; WAIT_RECV
	MOV	BH,1			; RECEIVE BUFFER FULL
	CALL	WAIT_FOR_STATUS 	; TEST FOR RECEIVE BUFFER FULL
	JNZ	A8			; SET TIME OUT ERROR
A17:					; GET_CHAR
	AND	AH,00011110B		; TEST FOR ERROR CONDITIONS ON RECEIVE

	MOV	DX,@RS232_BASE[SI]	; DATA PORT
	IN	AL,DX			; GET CHARACTER FROM LINE
	JMP	A3			; RETURN

;-----	COMMO PORT STATUS ROUTINE

A18:
	MOV	DX,@RS232_BASE[SI]
	ADD	DX,5			; CONTROL PORT
	IN	AL,DX			; GET LINE CONTROL STATUS
	MOV	AH,AL			; PUT IN (AH) FOR RETURN
	INC	DX			; POINT TO MODEM STATUS REGISTER
	IN	AL,DX			; GET MODEM CONTROL STATUS
	JMP	A3			; RETURN
PAGE
;----------------------------------------
;	WAIT FOR STATUS ROUTINE 	:
;ENTRY: (BH)= STATUS BIT(S) TO LOOK FOR :
;	(DX)= ADDRESS OF STATUS REG	:
;EXIT:	ZERO FLAG ON = STATUS FOUND	:
;	ZERO FLAG OFF = TIMEOUT.	:
;	(AH)= LAST STATUS READ		:
;----------------------------------------

WAIT_FOR_STATUS PROC  NEAR
	MOV	BL,@RS232_TIM_OUT[DI]	; LOAD OUTER LOOP COUNT

;-----	ADJUST OUTER LOOP COUNT

	PUSH	BP			; SAVE (BP)
	PUSH	BX			; SAVE (BX)
	POP	BP			; USE BP FOR OUTER LOOP COUNT
	AND	BP,00FFH		; STRIP HIGH BITS
	RCL	BP,1			; MULTIPLY OUTER COUNT BY 4
	RCL	BP,1
WFS0:
	SUB	CX,CX
WFS1:
	IN	AL,DX			; GET STATUS
	MOV	AH,AL			; MOVE TO (AH)
	AND	AL,BH			; ISOLATE BITS TO TEST
	CMP	AL,BH			; EXACTLY = TO MASK
	JE	WFS_END 		; RETURN WITH ZERO FLAG ON

	LOOP	WFS1			; TRY AGAIN

	DEC	BP
	JNZ	WFS0

	OR	BH,BH			; SET ZERO FLAG OFF
WFS_END:
	POP	BP			; RESTORE (BP)
	RET

WAIT_FOR_STATUS ENDP

RS232_IO_1	ENDP

CODE	ENDS
	END
