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

📄 llcom3.asm

📁 Microsoft MS-DOS6.0 完整源代码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	MOV	AH,DH		;Copy error code
	CMP	AH,0		;time out?
	JNZ	PUTRET		;br. if so
	MOV	CX,[BX].QUELEN	;Length of queue
;PUTCLP:
	CALL	B$BREAK_CHK	
	CMP	CX,[BX].QUENUM	;Queue full?
;	JZ	PUTCLP		;Wait for space in queue
	JZ	SND2		; always check modem lines
;	PUSH	AX		;save char
;	PUSH	BX		;Save queout
;	CALL	MSRWAT		;Check MSR, (on ret, [BX] = Q_DEB).
;	POP	BX		;[SI] = queout
;	POP	AX		;Restore char to output
;	MOV	AH,DH		;copy error code
;	CMP	AH,0		;time out?
;	JNZ	PUTRET		;br. if so
	CLI			;Critical section
	CMP	[SI].COMBSY,0	;Tx already running?
	JNZ	PUTINQ		;If so, just queue and exit.
	MOV	[SI].COMBSY,255D ;Pre-set Tx busy flag.
	XOR	DX,DX
	MOV	DL,[SI].DEVID	;get device offset
	MOV	DI,DX
	SHL	DI,1		;make word index
	MOV	DX,b$ComPort[DI] ;get the I/O address port
DbAssertRel	DX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 in B$SNDCOM>
	OUT	DX,AL		; restarting Tx interrupts.
	JMP	SHORT POPBAR	
PUTINQ:
	PUSH	ES		; make [ES] equal to [DS]
	MOV	ES,[SI].XMTSEG	;get buffer segment from DEB
	cCALL	B$QUE		; Put char [AL] in output queue
	POP	ES
POPBAR:
	STI			;End Critical
PUTRET:
	POP	BX
	POP	CX
	POP	DX
	POP	SI
	POP	DI
cEnd				; return to caller

;***
; B$STACOM
;[OEM documentation in file LLCOM5]
;
; Purpose:
;	Returns the number of bytes of free space in the input queue
;	and the number of bytes of information queued for input.
;	In order to support the IBM Communications Error Reporting
;	philosophy, this routine will not report communications errors.
;
; Entry:
;	AH = RS232 device ID (0..255)
;
; Exit:
;	AH = 0 for no I/O error
;	CX = number of bytes of free space in the output queue
;	DX = number of bytes queued for input
;
; Modified:
;	None.
;****

cProc	B$STACOM,<PUBLIC,NEAR>,<BX,SI>	;[1]preserve registers

cBegin				
	MOV	BX,OFFSET DGROUP:Q_IN ;Addr of Input Queue
	MOV	SI,OFFSET DGROUP:Q_OUT ;address of COM1 output queue
	OR	AH,AH		;is this COM1?
	JZ	STA2		;br. if so
	MOV	BX,OFFSET DGROUP:Q_IN2 ;else get com2 input queue
	MOV	SI,OFFSET DGROUP:Q_OUT2 ;address of COM2 output queue
STA2:
	MOV	DX,[BX].QUENUM	;get number of bytes in queue
	MOV	CX,[SI].QUELEN	;get length of queue
	SUB	CX,[SI].QUENUM	;determine amount of free space in queue
	XOR	AH,AH		;indicate no errors
cEnd				; pop BX and exit

;***
;B$TRMCOM - Terminate the communications device
;[OEM documentation given in LLCOM5]
;
;Purpose:
;	Terminate an RS232 channel.  This routine is called when a file
;	associated with a COM channel is closed, or when a SYSTEM statement
;	is executed.  It waits for any outbound data to be transmitted, drops
;	the DTR line,  disables interrupts from this device, and disables the
;	queues if needed.  Any interupt handlers or threads should be removed.
;
;	While waiting for any data to be written, make sure to check the
;	keyboard for a ^Break and to check the Modem Status Registers for
;	any timeout conditions so as not to hang. This routine will not
;	report communications errors unless operating under OS/2.
;
;Entry:
;	[AH] = RS232 device ID (0 <= AH < NUM_RS232 <= 2)
;	[CX] = FLAG: 0 = reset DTR
;
;Exit:
;	[AH] = 0 to indicate that there are no errors.
;
;Uses:
;	Per Convention
;
;Preserves:
;	BX, CX, DX
;
;Exceptions:
;	None.
;****

cProc	B$TRMCOM,<PUBLIC,NEAR> 

cBegin				
	PUSH	SI
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	SI,OFFSET DGROUP:COMM1 ;Com1 deb
	MOV	BX,OFFSET DGROUP:Q_OUT ; Get Output Queue base
	OR	AH,AH		;is this com1?
	JZ	TRM2		;br.if so
	MOV	SI,OFFSET DGROUP:COMM2 ;get com2 deb
	MOV	BX,OFFSET DGROUP:Q_OUT2 ; Get Output Queue base
TRM2:
	CMP	[BX].QUENUM,0	;Output busy?
	JZ	CLSWAX		;Brif done
CLSWAT:
	CALL	MSRWAT		;Allow "Time out" during CLOSE
	OR	DH,DH		;did a timeout occur?
	JNE	CLSWAX		;if so, just call quits and close it
	CMP	[BX].QUENUM,0	;Output busy?
	JNZ	CLSWAT		;Yes, wait until done
CLSWAX:
	PUSH	CX		; save flag
	XOR	CX,CX		;Lots of time
CLSDLY:
	LOOP	CLSDLY		;for Shift Reg to empty...
	POP	CX		; CX = flag; 0 = reset DTR
	CALL	CLSMSR		;Force the file closed
	POP	DX
	POP	CX
	POP	BX
	POP	SI
	RET			;COM file is closed and deallocated

CLSMSR:
	PUSH	DI
	XOR	DX,DX
	MOV	DL,[SI].DEVID
	MOV	DI,DX		;get device offset
	SHL	DI,1		;make a word index
	MOV	DX,b$ComPort[DI] ;get the device I/O port address
DbAssertRel	DX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 at start of B$TRMCOM>
	MOV	AL,0		; 0 to reset lines
	JCXZ	Reset_RTS	; if CX  = 0, reset DTR
	INC	AX		; else, leave DTR active
Reset_RTS:			; always reset RTS
	ADD	DX,4		;Modem Ctrl reg.
	OUT	DX,AL		;Clear MSR, disable card.
	MOV	[BX].QUENUM,0	;Clear # to output
	SUB	DX,3		;Interrupt Enable Reg.
	PAUSE			;make sure instruction fetch has occurred
	MOV	AX,1000h + 0	; 0 to disable interrupts; AH=10H for below
	OUT	DX,AL		; Disable COMM Interrupts
	DEC	DX		;get back base I/O address
;	MOV	AH,10H		;IRQ-4 Disable Mask
	CMP	DH,3		; RS232 Port addr 3xx?
	JZ	$C_COM_3xx	;Yes, Disable IRQ-4
	MOV	AH,8		;IRQ-3 Disable Mask, assume 2xx.
$C_COM_3xx:
	CLI
	TEST	b$DOS_INT_MASK,AH ;test if bit was initially enabled
	JZ	NO_INT_DISABLE	;if so (bit was 0), then no disable
	IN	AL,INTA1	;Get INT masks from 8259 IMR Reg.
	OR	AL,AH		;Disable IRQ-3 or IRQ-4
	PAUSE			;make sure instruction fetch has occurred
	OUT	INTA1,AL	;For RS232 Cards.
NO_INT_DISABLE:

	MOV	BX,OFFSET DGROUP:COM1_VECTOR ;get start of old COM1 vector
	OR	DI,DI		;test if COM1
	JZ	REST_VECTOR	;if COM1, then jump
	MOV	BX,OFFSET DGROUP:COM2_VECTOR ;get start of old COM2 vector
REST_VECTOR:			

	MOV	AL,IRQ4/4	;vector number for primary card
	CMP	DH,3		;test if primary asynch card
	JE	REST_MASK	;if so, then jump
	MOV	AL,IRQ3/4	;vector number for secondary card
REST_MASK:			

	PUSH	DS		; Save BASIC data segment
	LDS	DX,DWORD PTR [BX] ;load vector into DS:DX
	MOV	AH,25H		;get DOS function code
	INT	21H		;and restore it
	STI
	POP	DS		;and restore DS to it
	XOR	AX,AX		;clear AX
	MOV	[BX],AX 	;clear offset of saved vector
	MOV	[BX+2],AX	;and same for the segment...

;	Set the BIOS data location for the COM I/O port address.

	XOR	BX,BX		; get a zero
	XCHG	BX,b$ComPort[DI] ;get the COM I/O port address [25]& reset
DbAssertRel	BX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 at end of B$TRMCOM>
	PUSH	DS		;save DGROUP on the stack
	XOR	DX,DX		;set to zero to access...
	MOV	DS,DX		;...the BIOS data segment
	MOV	DS:RS232B[DI],BX ;restore the BIOS data location
	POP	DS		;restore DGROUP from the stack

	POP	DI
cEnd				; return to caller

	SUBTTL	Comm interrupt service routine
	page
;***
;COM_INT1 / COM_INT2
;
;PURPOSE:
;	Interrupt handlers for COM1: and COM2:.  This is the communications
;	interrupt service routine for RS232 communications.  When an RS232
;	event occurs the interrupt vectors here.  This routine determines
;	who the caller was and services the appropriate interrupt.  The
;	interrupts are prioritized in the following order:
;		1.  line status interrupt
;		2.  read data available interrupt
;		3.  transmit buffer empty interrupt
;		4.  modem service interrupt
;	This routine continues to service until all interrupts have been
;	satisfied.
;
;ENTRY:
;	none
;EXIT:
;	none
;MODIFIED:
;	none
;******************************************************************************

COM_INT2:
	PUSH	DS
	PUSH	DI
	PUSH	DX
	MOV	DS,CS:b$BASDSG    ;get BASIC's data seg
	MOV	DX,DS:b$ComPort+2 ;DX = COM2 I/O addr.
DbAssertRel	DX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 in COM_INT2>
	MOV	DI,OFFSET DGROUP:COMM2 ;get com2 deb
	JMP	SHORT COMM_INT

COM_INT1:
	PUSH	DS
	PUSH	DI
	PUSH	DX
	MOV	DS,CS:b$BASDSG  ;get BASIC's data seg
	MOV	DX,DS:b$ComPort ;DX = COM1 I/O addr.
DbAssertRel	DX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 in COM_INT1>
	MOV	DI,OFFSET DGROUP:COMM1 ;get com1 deb

COMM_INT:
	PUSH	AX
	PUSH	BX
	PUSH	SI
	INC	DX
	INC	DX		;Interrupt Id Reg.
COMM_ILP:
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;Get Interrupt Id.
	TEST	AL,1		;Interrupt need servicing?
	JNZ	COMSRX		;Brif not, all done..
	XOR	AH,AH		;Using [AX] for Interrupt dispatch.
	MOV	SI,AX
	PUSH	DX		;Save Id reg.
	CALL	CS:SRVTAB[SI]	;Service the Interrupt..
	CLI			; disable interrupts for next iter. of loop
	POP	DX		;Interrupt Id reg.
	JMP	COMM_ILP	; Until all Interrupts Serviced

COMSRX:
	POP	SI
	POP	BX
	MOV	DX,INTA0
	MOV	AL,EOI		;Send End-of-Interrupt
	PAUSE			;make sure instruction fetch has occurred
	OUT	DX,AL		; to 8259
	POP	AX
	POP	DX
	POP	DI
	POP	DS
	IRET

SRVTAB	LABEL	WORD
	DW	MSISRV		;Service Modem Status Interrupt
	DW	THRSRV		;Service Tx Holding Reg. Interrupt
	DW	RDASRV		;Service Rx Data Available Interrupt
	DW	RLSSRV		;Service Line Status Interrupt

; Rx Data Available Interrupt Service (Second)

;		Line Status Interrupt Service (Highest)
;		Not currently enabled.	Line status is read
;		on RDA Interrupt and sets COMERR error flag
;		if any errors exist.

RLSSRV:
	STI			; we're not reading, reenable interrupts
	RET

RDASRV:
	XOR	AH,AH		;Don't set hi bit if no errors
	ADD	DX,3		;Line Status Reg.
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX
	AND	AL,1EH		;Mask for errors
	JZ	RDASR2		;Brif no errors
	CMP	[DI].COMPE,0	;is PE option selected?
	JE	RDASR4		;if not, do not parity error
	CMP	[DI].PARTYP,0	;Checking Parity errors
	JNZ	RDASR1		;Brif so, report all errors
RDASR4:
	CMP	AL,4		;Parity error?
	JZ	RDASR2		;Ignore if so, else report others
RDASR1:
	MOV	[DI].COMERR,AL	;Nonzero for "Device I/O Error"
	MOV	AH,80H		;Will set hi bit of byte in error
RDASR2:
	SUB	DX,5		;Data I/O Reg.
	MOV	BX,OFFSET DGROUP:Q_IN ;Addr of Input Queue
	CMP	[DI].DEVID,0	;is this COM1?
	JZ	RDASR3		;br. if so
	MOV	BX,OFFSET DGROUP:Q_IN2 ;else get com2 input queue
RDASR3:
	MOV	SI,[BX].QUENUM
	CMP	SI,[BX].QUELEN	;Is queue full?
	JZ	COMOVR		;Yes, comm overrun
	CMP	[DI].CTRLZ,0	;has control z been struck?
	JNZ	COMOVR		;br. if so - treat as overflow
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;Read Char from 8250
	STI			; reenable interrupts now that char is read
	CMP	[DI].BINMOD,0	;is this binary stuff?
	JZ	QUEIT		;br. if so
	CMP	AL,26D		;is this a control z?
	JNZ	QUEIT		;br. if not - que data
	MOV	[DI].CTRLZ,255D ;set control z flag
	JMP	SHORT NOQUE	;skip the queing process
QUEIT:
	OR	AL,AH		;Sets hi bit if error
;#***
	PUSH	ES
	MOV	ES,[DI].RCVSEG	;get buffer segment from DCB
	cCALL	B$QUE		; Put char [AL] in output queue
	POP	ES
	JMP	SHORT NOQUE	
;#***

COMOVR:
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX		;Dismiss and lose char
	STI			; reenable interrupts now that char is read
	MOV	[DI].COMOVF,1	;Set we have overflowed
NOQUE:				
	MOV	AX,DI		; AL = 0 for COM 1, 2 for COM2
	SHR	AL,1		; AL = trap number for B$TrapEvent
;	ADD	AL,COMOFF	; COMOFF = 0
	JMP	[b$pTrapEvent]	; and indicate an event if events linked
				; in, and return

; Tx Holding Reg Empty Interrupt Service (Third)

THRSRV:
	STI			; we're not reading, reenable interrupts
	CMP	[DI].MSRERR,0	;If Modem status fault then turn
	JNZ	TXSTOP		; off Tx interrupts until cleared
THRSR2:
	MOV	SI,BX		;[SI] = Queue base for speed
	MOV	BX,OFFSET DGROUP:Q_OUT ;Get Output Queue
	CMP	[DI].DEVID,0	;is this com1?
	JZ	THRSR3		;br. if so
	MOV	BX,OFFSET DGROUP:Q_OUT2 ;else get com2 output queue
THRSR3:
	CMP	[BX].QUENUM,0	;Zero if queue empty
	JZ	XMITOF		;Brif No chars, Set COMBSY = 0.

	DEC	DX
	DEC	DX		;Data I/O Reg.
	PUSH	ES		;save register
	MOV	ES,[DI].XMTSEG	;get buffer segment from DEB
	cCALL	B$DQUE		; get char from queue in [AL]
	POP	ES		;restore register
	OUT	DX,AL		;Send char
TXSTOP:
	RET
XMITOF:
	MOV	[DI].COMBSY,0	;Set Tx Interrupt status.
	RET

;Modem Status Interrupt Service (Lowest)

MSISRV:
	STI			; we're not reading, reenable interrupts
	ADD	DX,4		;Modem Status Reg.
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX
	MOV	[DI].MSREG,AL	;Save MSR data for others
	CMP	[DI].COMRLS,0	;Did user want to check?
	JZ	MSISRD		;Brif not, Try DSR.
	TEST	AL,RLSD 	;Did we lose RLSD?
	JZ	MSISRE		;"Device Timeout" if so.
MSISRD:
	CMP	[DI].COMDSR,0	;Did user want to check?
	JZ	MSISRC		;Brif not, Try CTS.
	TEST	AL,DSR		;Did we lose DSR?
	JZ	MSISRE		;"Device Timeout" if so.
MSISRC:
	CMP	[DI].COMCTS,0	;Did user want to check?
	JZ	MSISRX		;Brif not.
	TEST	AL,CTS		;id we lose CTS?
	JNZ	MSISRX		;Ignore if not.
MSISRE:
	MOV	[DI].MSRERR,DL	;will give "Device Timeout".
MSIRET:
	RET
MSISRX:
	CMP	[DI].MSRERR,0	;If was running
	JZ	MSIRET		; leave alone
	MOV	[DI].MSRERR,0	;Clear the Modem status fault
	DEC	DX		;Line Status reg.
MSISRH:
	PAUSE			;make sure instruction fetch has occurred
	IN	AL,DX
	AND	AL,20H		;Tx Holding reg empty?
	JZ	MSISRH		;Brif not, wait for it
	SUB	DX,3		;Restore to Int Id reg.
	JMP	THRSRV		; and turn Tx Interrupts on if chars

sEnd	DV_TEXT 		
	END

⌨️ 快捷键说明

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