⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 llcom3.asm

📁 Microsoft MS-DOS6.0 完整源代码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	cCALL	B$INIQUE 	; initialize queue
	MOV	[BX].QUETOP,CX	;Store Out buffer Top addr
	MOV	[BX].QUELEN,CX	;Store Out Queue length

	MOV	BX,OFFSET DGROUP:Q_IN ;BX points to COM1 input QCB
	CMP	[SI].DEVID,0	;test if COM1
	JZ	BUFF4		;branch if so
	MOV	BX,OFFSET DGROUP:Q_IN2 ;[BX] points to in_QCB
BUFF4:				
	XOR	AX,AX		;each buffer starts at zero
	MOV	[BX].QUEBOT,AX	;Store In buffer Bottom addr
	cCALL	B$INIQUE 	; initialize queue
	MOV	[BX].QUETOP,DX	;store in_buf1 top addr
	MOV	[BX].QUELEN,DX	;store in_queue length
	POP	AX
	POP	BX
	POP	SI
	RET

;***
; GETDIV
;
; Purpose:
;	gets baud rate divisor from table.
; Entry:
;	[CX] = requested baud rate
; Exit:
;	[CX] = baud rate divisor
;	       0 means invalid baud request
; Modifies:
;	None.
;***************************************************************************

GETDIV:
	PUSH	BX
	PUSH	DX
	MOV	BX,OFFSET CODE:BAUD_TBL-2 ;get address of baud table - 2
	MOV	DX,CX		;copy baud rate for compare
GETRA1:
	INC	BX
	INC	BX
	MOV	CX,CS:[BX]	; Get rate from Table
	INC	BX
	INC	BX		; (Baud value)
	JCXZ	GETEXT		;EOT, Bad Value given
	CMP	DX,CX
	JNZ	GETRA1		; No match, look next
GETEXT:
	MOV	CX,CS:[BX]	; [CX] = Baud Divisor
	POP	DX
	POP	BX
	RET

BAUD	MACRO	RATE,RATDIV
	DW	RATE
	DW	RATDIV
	ENDM

BAUD_TBL:
	BAUD	75,1536 	; 75
	BAUD	110,1047	; 110
	BAUD	150,768 	; 150
	BAUD	300,384 	; 300
	BAUD	600,192 	; 600
	BAUD	1200,96 	; 1200
	BAUD	1800,64 	; 1800
	BAUD	2400,48 	; 2400
	BAUD	4800,24 	; 4800
	BAUD	9600,12 	; 9600
	BAUD	19200,6 	; 19200
	BAUD	0,0		; End

;***
;SETEM
;
; Purpose:
;	Place the RS232 card in a deterministic initial state.	This
;	routine initializes the baud rate, parity, word size, and
;	INS 8250 interrupt enable register for the card.
; Entry:
;	CX = baud rate divisor
;	SI = pointer to deb for this device
;	DI = word index to COM device
; Exit:
;	AH = 0 means no errors occurred
;	     4 means time out occurred while waiting for DSR
;	     5 means time out occurred while waiting for RLSD
; Modifies:
;	AX,CX,DX
;**************************************************************************

SETEM:
	MOV	DX,b$ComPort[DI] ;Get I/O Base Addr.
DbAssertRel	DX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 in SETEM>
	ADD	DX,3		;Line Ctrl Reg.
	MOV	AL,80H		;Set DLAB=1
	OUT	DX,AL		;Enable Baud Latch
	SUB	DX,2		;MSB of Baud Latch
	MOV	AL,CH
	PAUSE			;make sure instruction fetch has occurred
	OUT	DX,AL		;Set MSB of Div
	DEC	DX
	MOV	AL,CL
	PAUSE			;make sure instruction fetch has occurred
	OUT	DX,AL		;Set LSB of Div
	MOV	CH,[SI].PARTYP	;Get Parity
	MOV	CL,3
	SHL	CH,CL		;Shift Parity to D4-D3.
	MOV	AL,[SI].BYTSIZ	;Get Byte size (5,6,7,8)
	OR	AL,CH		;[AL] = Parity+Word size.
	ADD	DX,3		;Line Ctrl Reg.
	PAUSE			;make sure instruction fetch has occurred
	OUT	DX,AL		;Set Line Control Reg.
	SUB	DX,3		;Data reg.
	XOR	CX,CX		;Lots of time
DATDLY:
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;Trash data
	LOOP	DATDLY		;  waiting for 8250 to settle

	ADD	DX,5		;line status register (port xFDH)
	PAUSE			;wait for bus settle
	IN	AL,DX		;read to clear DR,OE,PE,FE,BI,THRE,TEMT

	INC	DX		;modem status register (port xFEH)
;	ADD	DX,6		;Modem Status reg
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;Throw away 1st status read
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;Save 2nd
	MOV	[SI].MSREG,AL	; so MSRWAT works right
	DEC	DX		;Subtract 2 to get
	DEC	DX		;Modem Contrl Register
	MOV	AL,[SI].COMRTS	;Get RTS mask
	XOR	AL,2		;toggle rts bit
	OR	AL,9		;  or in DTR/INT enable
	PAUSE			;make sure instruction fetch has occurred
	OUT	DX,AL		;Enable the Card..
	SUB	DX,3		;Interrupt Enable Reg.
	MOV	AL,MSRIE+RDAIE+TBEIE ;MSR/RDA/THRE Enable
	PAUSE			;make sure instruction fetch has occurred
	OUT	DX,AL		;Enable Tx/Rx Interrupts.
	INC	DX		;Interrupt I.D. reg.
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;  so interrupt line goes low
;	----------------
	CALL	MSRWAT		;Check MSR (On ret, [DH] = ERROR CODE).
;	----------------
	MOV	AH,DH		;copy error code
	RET

;***
;MSRWAT:
;
;PURPOSE:
;	Checks the modem status register for CTS,DSR, and/or RLSD
;	signals.  If a timeout occurred while checking then this
;	routine will return the appropriate error code in DH.
;	This routine will not check for any signal with a corresponding
;	time out value of 0.
;ENTRY:
;	[SI] = Pointer to deb for this device
;	time out values in COMCTS,COMDSR, and COMRLS
;EXIT:
;	[DH] = 0 indicates no time out errors occurred.
;	       3 CTS timeout occurred
;	       4 DSR timeout occurred
;	       5 RLSD timeout occurred
;	      FC CTRL-BREAK found but not handled (COM OPEN ONLY)
;MODIFIED:
;	AX,CX
;****

	PUBLIC	MSRWAT
MSRWAT:
	PUSH	BX		;save registers
	PUSH	CX		
	PUSH	DI

	XOR	BX,BX		;initialize CX:BX to zero...
	MOV	CX,BX		;...for first time in
MSRWA0:				
	XOR	DI,DI		;initialize millisecond timeout value
MSRWA1:
	CMP	[b$COFlag],0	; Is this a COM OPEN?
	JNZ	MSRComOpen	; brif so -- special case
	CALL	B$BREAK_CHK	
MSRWA2:				
	XOR	AH,AH		;[AH] will be 0 if status is Ok.
	MOV	AL,[SI].MSREG	;Read Modem Status
	TEST	AL,CTS
	JNZ	MSRWA3		;Brif got CTS
	CMP	[SI].COMCTS,0	;Checking CTS?
	JZ	MSRWA3		;Brif not
	MOV	DH,3		;assume CTS timeout
	CMP	DI,[SI].COMCTS	;CTS timeout yet?
	JAE	MSRWAX		;jump if so
	INC	AH		;Status retry
MSRWA3:
	TEST	AL,DSR
	JNZ	MSRWA4		;Brif got DSR
	CMP	[SI].COMDSR,0	;Checking DSR?
	JZ	MSRWA4		;Brif not
	MOV	DH,4		;assume DSR timeout
	CMP	DI,[SI].COMDSR	;DSR timeout yet?
	JAE	MSRWAX		;jump if so
	INC	AH		;Status retry
MSRWA4:
	TEST	AL,RLSD
	JNZ	MSRWA5		;Brif got RLSD
	CMP	[SI].COMRLS,0	;Checking RLSD?
	JZ	MSRWA5		;Brif not
	MOV	DH,5		;assume MSR timeout
	CMP	DI,[SI].COMRLS	;RLDS timeout yet?
	JAE	MSRWAX		;jump if so
	INC	AH		;Status retry
MSRWA5:
	OR	AH,AH		;Check final status
	JZ	MSRWA8		;Brif Status is Ok!

;	CX:BX has entry tick value if nonzero.
;	If zero, the entry tick value is set.

	MOV	DI,CX		;DI:BX has entry tick value
	XOR	AH,AH		;clear AH to get time-of-day...
	INT	1AH		;...tick value in CX:DX
	XCHG	DI,CX		;CX:BX has entry - DI:DX has t-o-d value
	MOV	AX,CX		;get low-order t-o-d value...
	OR	AX,BX		;...and OR with high-order to test if zero
	JNZ	MSRNotFirst	;if nonzero, then not first time in
	MOV	CX,DI		;CX:BX zero, set to value...
	MOV	BX,DX		;...in DI:DX
	JMP	SHORT MSRWA0	;jump to init DI to 0

MSRNotFirst:			
	SUB	DX,BX		;subtract CX:BX from DI:DX...
	SBB	DI,CX		;...to get elapsed tick value
	JNC	MSRNoWrap	;if no wraparound, then jump
	ADD	DX,00B0H	;add 0018:00B0H to DI:DX...
	ADC	DI,0018H	;...to wrap for the next day
MSRNoWrap:			
	OR	DI,DI		;test if over 64K ticks
	MOV	DI,0FFFFH	;assume maximum millisecond value
	JNZ	MSRWA1		;if over 64K ticks, use maximum value
	MOV	AX,55D		;convert ticks to milliseconds...
	MUL	DX		;...where 1 tick is 55 milliseconds
	JC	MSRWA1		;if over 64K milliseconds, use maximum value
	MOV	DI,AX		;move computed millisecond value
	JMP	SHORT MSRWA1	;jump to retry the test

MSRComOpen:			; special handling for COM OPEN
	CALL	[b$IPOLKEY]	; check keyboard buffer (if /D or QB)
	TEST	[b$EventFlags],CNTLC ; test for CTRL-BREAK
	JZ	MSRWA2		; brif no CTRL-BREAK
	MOV	DH,0FCh		; set error flag to indicate CTRL_BREAK
	SKIP	2		; and exit via MSRWAX
MSRWA8:
	XOR	DH,DH		;indicate no errors occurred
MSRWAX:
	POP	DI
	POP	CX		
	POP	BX		
	RET

	SUBTTL	Comm read/write/status
	page
;***
;B$RECCOM
;[OEM documentation in LLCOM5]
;
;PURPOSE:
;	Read Byte From RS232 Input Queue If Data Is Ready
;
;ALGORITHM:
;	If COM interrupt handler detected error for this device,
;	  set PSW.C and return error code in [AH]
;	Else if interrupt handler has queued data for this device,
;	  move 1 byte from queue into [AL] and
;	  return with [AH]=0 and PSW.Z reset
;	Else if cntrl z (eof) then
;	  return with [AH]=26 and PSW.Z reset
;	Else
;	  return with [AH]=0 and PSW.Z set.
;ENTRY:
;	[AH] = RS232 device ID (0..255)
;
;EXIT:
;	[AH] = 0 if no I/O errors have occured
;	     = 1 if receive data queue overflow
;	     = 2 if receive parity error
;	     = 3 if CTS timeout
;	     = 4 if DSR timeout
;	     = 5 if RLSD timeout
;	     = 6 if receive Overrun error
;	     = 7 if receive Framing error
;	     = FF for all other I/O errors
;	If data is available, PSW.Z is reset & [AL] = input byte
;	else PSW.Z is set.
;
;MODIFIED:
;	none
;****

cProc	B$RECCOM,<PUBLIC,NEAR> 

cBegin				
	PUSH	SI
	PUSH	BX
	MOV	SI,OFFSET DGROUP:COMM1 ;get comm1 deb
	OR	AH,AH		;is it com1?
	JZ	RECC2		;br. if so
	MOV	SI,OFFSET DGROUP:COMM2 ;get com2 deb
RECC2:
	CALL	CHKERR		;get any errors in [AH]
	CMP	AH,0		;have any errors occurred?
	JNZ	RECERR		;br. if so
	MOV	BX,OFFSET DGROUP:Q_IN ;get address of queue control block
	CMP	[SI].DEVID,0	; is this COM1?
	JZ	RECC3		;br. if so
	MOV	BX,OFFSET DGROUP:Q_IN2 ; must be COM2 - get its queue
RECC3:
	CMP	[BX].QUENUM,0	;are there elements in the queue
	JNZ	NOZYET		;br. if so
	CMP	[SI].CTRLZ,0	;has control z been struck?
	JZ	RECERR		;br. if not
	MOV	AL,26D		;else return control z
	JMP	SHORT RETOK	;avoid deque
NOZYET:
	PUSH	ES
	MOV	ES,[SI].RCVSEG	;get buffer segment from DCB
	cCALL	B$DQUE		; get char from queue in [AL]
	POP	ES
RETOK:
	OR	SP,SP		;reset PSW.Z
	JMP	SHORT RECEXIT	

RECERR:
	XOR	AL,AL		;set PSW.Z
RECEXIT:			; get back registers and exit
	POP	BX
	POP	SI
cEnd				; return to caller

;***
;CHKERR
;
;PURPOSE:
;	checks to see if framing, overrun, parity, or data queue overflow
;	errors have taken place.
;
;ENTRY:
;	[SI] = Pointer to deb for this device
;
;EXIT:
;	[AH] = 0 if no errors have occurred
;	       1 if receive data queue overflow
;	       2 if receive parity error
;	       6 if ovrrun error
;	       7 if framing error
;	       FF if other errors occurred
;
;MODIFIED:
;	AH
;****

CHKERR:
	CMP	[SI].COMERR,0	;did line status register return errors?
	JZ	NOCMER		;br. if not
	MOV	AL,[SI].COMERR	;get error
	MOV	AH,6		;assume overrun error
	TEST	AL,2		;was this overrun error?
	JNZ	CHKRET		;br. if so
	MOV	AH,2		;assume parity error
	TEST	AL,4		;was it parity error?
	JNZ	CHKRET		;br. if so
	MOV	AH,7		;assume framing error
	TEST	AL,8		;was it a framing error?
	JNZ	CHKRET		;br. if so
	MOV	AH,0FFH 	;assume break error
	TEST	AL,10H		;was it a break error
	JNZ	CHKRET		;br. if so
NOCMER:
	MOV	AH,1		;assume overflow
	CMP	[SI].COMOVF,0	;was there overflow
	JNZ	CHKRET		;br. if so
	XOR	AH,AH		;must have been no errors
CHKRET:
	MOV	[SI].COMOVF,0	;reset for next time
	MOV	[SI].COMERR,0	;reset for next time
	RET

;***
; B$SNDCOM
;[OEM documentation in LLCOM5]
;
; Purpose:
;	Transmit one character over the specified serial port.
; Algorithm:
;	if COM interrupt handler detected error for this device,
;	  reset error-flag and return error code in [AH]
;	else if [DCB].CD_CTSTO > 0 then begin
;	  wait [DCB].CD_CTSTO milliseconds for CTS signal to become true.
;	  If TIMEOUT, return CTS timeout indication.
;	if [DCB].CD_DSRTO > 0 then begin
;	  wait [DCB].CD_DSRTO milliseconds for DSR signal to become true.
;	  If TIMEOUT, return DSR timeout indication.
;	if [DCB].CD_RSLTO > 0 then begin
;	  wait [DCB].CD_RSLTO milliseconds for RSLD signal to become true.
;	  If TIMEOUT, return RSLD timeout indication.
;	if queue is full wait until there is room in queue
;	queue Data and return with [AH] = 0.
; Entry:
;	 [AH] = RS232 device ID (0..255)
;	 [AL] = byte to be output
;
; Exit:
;	 [AH] = 0 if no I/O errors have occured
;	      = 1 if receive data queue overflow
;	      = 2 if receive parity error
;	      = 3 if CTS timeout
;	      = 4 if DSR timeout
;	      = 5 if RLSD timeout
;	      = 6 if receive Overrun error
;	      = 7 if receive Framing error
;	      = FF for all other I/O errors
; Modifies:
;	None.
;******************************************************************************

cProc	B$SNDCOM,<PUBLIC,NEAR> 

cBegin				
	PUSH	DI
	PUSH	SI
	PUSH	DX
	PUSH	CX
	PUSH	BX
	MOV	SI,OFFSET DGROUP:COMM1 ;get com1 deb
	MOV	BX,OFFSET DGROUP:Q_OUT ; get com1 queue
	OR	AH,AH		;is it comm1?
	JZ	SND2		;br. if so
	MOV	SI,OFFSET DGROUP:COMM2 ;get com2 deb
	MOV	BX,OFFSET DGROUP:Q_OUT2 ; get com2 queue
SND2:
	PUSH	AX		
	CALL	MSRWAT		;Check MSR, return or "timeout"
	POP	AX		;restore char

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -