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

📄 llcom3.asm

📁 Microsoft MS-DOS6.0 完整源代码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	TITLE	LLCOM3 - Communications Interface for DOS 3

	PAGE	56,132

;***
; LLCOM3.ASM - GW-BASIC Communications Interface for DOS 3
;
;	Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;	This module supports the initialization/open, read, write, line
;	status check, termination and interrupt/monitor service for
;	communication lines.  In DOS3, BASIC handles the actual low level
;	functions itself, whereas in DOS5, BASIC takes advantage of the dos
;	function calls.
;
;******************************************************************************

INCLUDE switch.inc		;feature switches [new file]
INCLUDE rmacros.inc		

;	Code Segments

	useSeg	DV_TEXT 	
	useSeg	RT_TEXT 	
	useSeg	EV_TEXT 	

;	Data segments

	useSeg	_DATA		
	useSeg	_BSS		

INCLUDE seg.inc 		
INCLUDE ibmunv.inc
INCLUDE	baslibma.inc		; skip macro
INCLUDE comdcb.inc		;comm data control block (DCB) structure
INCLUDE event.inc 		
INCLUDE idmac.inc		

	SUBTTL	local constant/structure definitions

QUE_CTRL_LEN =	QUSIZE		;Length of Queue Control  Block

RS232B	=	400H		; X'400' RS232 Card(s) I/O addr Save area.

COMDEB	STRUC
	DEVID	DB	?	;device id number
	COMBSY	DB	0	; nonzero if Tx Interrupts active
	COMRTS	DB	2	; Request to Send Mask bit if RTS wanted
	COMCTS	DW	?	; CTS timeout count
	COMDSR	DW	?	; DSR timeout count
	COMRLS	DW	?	; CD (RLSD) timeout count
	COMOVF	DB	0	; Nonzero on overflow
	COMERR	DB	0	; Nonzero if I/O error
	MSRERR	DB	0	; Nonzero if lost DSR
	MSREG	DB	?	; Contents of Modem Status Register
	PARTYP	DB	?	; Parity type (internal form see B$INICOM)
	BYTSIZ	DB	?	; Size of byte(internal form - see B$INICOM)
	CTRLZ	DB	0	; ASCII mode EOF flag
	BINMOD	DB	0	; BIN/ASCII (Z/NZ) flag
	COMPE	DB	?	;nonzero if PE option selected
	RCVSEG	DW	?	;segment of receive queue buffer
	XMTSEG	DW	?	;segment of transmit queue buffer
COMDEB	ENDS

PAUSE	MACRO			;macro to insure that an instruction
	JMP	$+2		;fetch occurs between IN and/or OUT
	ENDM			;instructions on the Salmon machine

	SUBTTL	data definitions
	page
sBegin	_DATA			

	COMM1	COMDEB	<>	;COM1 device equipment block
	COMM2	COMDEB	<>	;COM2 device equipment block

sEnd	_DATA			

sBegin	_BSS			

	externB	b$COFlag	; non-zero indicates called from COM_OPEN
	externB	b$EventFlags	; misc. event flags
	externW	b$IPOLKEY	; vector for B$POLKEY routine
	externB b$DOS_INT_MASK ;defined in LLINI.ASM
	externW	b$ComPort	;I/O port address table

	staticB COM1_VECTOR,?,2	; old COM1 vector is saved here
	staticB COM2_VECTOR,?,2	; old COM2 vector is saved here
	externW	b$pTrapEvent	; pointer to B$TrapEvent if events linked in

Q_IN	QUE_CTRL_BLOCK <>	;Input Que Ctrl Data Blk Ptr
Q_IN2	QUE_CTRL_BLOCK <>

Q_OUT	QUE_CTRL_BLOCK <>	;Output Que Ctrl Data Blk Ptr
Q_OUT2	QUE_CTRL_BLOCK <>
sEnd	_BSS			

	SUBTTL	code externals	
	page

sBegin	RT_TEXT 		
	externW b$BASDSG	; in code segment to record basic data seg
sEnd	Rt_TEXT 		

sBegin	EV_TEXT 		
	externNP B$BREAK_CHK	;check ctrl-break
sEnd	EV_TEXT 		

sBegin	DV_TEXT 		
	externNP	B$INIQUE	
	externNP	B$QUE	
	externNP	B$DQUE	
sEnd	DV_TEXT 		

	SUBTTL	Comm initialization
	page
	assumes CS,DV_TEXT	
sBegin	DV_TEXT 		


;***
;B$INICOM - initialize the COM device
;[OEM documentation is in file LLCOM5]
;
;Purpose:
;	Initialize the requested RS232 port, if present, and set
;	up the port with the given attributes, when they are valid.
;	The memory for the input and output queues has already been
;	allocated, but will need to be initialized.  This routine is
;	passed the address of a device control block (DCB) as defined
;	in the file comdcb.inc.
;
;	The signals RLSD, CTS, and DSR should bbe ignored by all
;	COM routines if the curresponding Support of Timeout Flags
;	by BIOS is optional.
;
;IBM Communications Error Reporting
;	The following scheme is used in reporting errors:
;
;	1.) OPEN returns any OPEN specific erros and resets the input buffer.
;	2.) CLOSE, EOF, LOC, LOF, and device polling for trapping returns
;	    no error.
;	3.) INPUT returns only input errors.
;	4.) WRITE and PRINT return only output errors.
;	5.) Errors are reported at the earliest possible BASIC I/O
;	    statement (with respect to the rules above).
;	6.) I/O errors are cleared when they are reported to the runtime
;	    code and the byte being read or written is not removed from
;	    or added to the buffer.
;	7.) If an error occurs when reading a byte and the port is opened
;	    with less than eight data bits, then set the high bit of that
;	    byte.
;
;Entry:
;	BX = points to initialized DCB.
;
;Exit:
;	AH = 0	if no errors occured
;	   = 4	if timeout while waiting for DSR signal
;		(will cause a DEVICE TIMEOUT error)
;	   = 5	if timeout while waiting for RLSD signal
;		(will cause a DEVICE TIMEOUT error)
;	   = FE if device unavailable via BIOS data location
;		(will cause a DEVICE NOT AVAILABLE error)
;	   = FF if requested mode is not supported
;		(will cause a BAD FILE NAME error)
;
;Uses:
;	Per Convention
;
;Exceptions:
;	None.
;*************************************************************************
;
;Algorithm:
;	If DOS 3,
;		check for valid device (0 or 1)
;		if card is present enable it else ERROR
;		initialize buffer control blocks
;		get parity and bytesize
;		if parity=NONE and bytesize=4 then ERROR
;		if parity<>NONE and bytesize=8 then ERROR
;		map parity to easier value
;			(0->0, 1->1, 2->3, 3->5, 4->7)
;		save new parity value
;		get baud rate
;		determine and save divisor for setting baud rate
;		set up card with appropriate characteristics

cProc	B$INICOM,<PUBLIC,NEAR>,<DI,SI> ; save DI, SI

cBegin				
	MOV	AH,0FFH 	;assume requested mode unsupported
	MOV	DL,[BX].CD_DEVID ;get device i.d.
	CMP	DL,1		;is i.d. > 1
	JBE	DeviceOK	;jump if device is 0 or 1
	JMP	INIRET		;near jump to error
DeviceOK:			
	MOV	SI,OFFSET DGROUP:COMM2 ;get com2 deb (dcb in dos5)
	JZ	IdOK		; br. if com2
	MOV	SI,OFFSET DGROUP:COMM1 ;get com1 deb (dcb in dos5)
IdOK:				

	MOV	[SI].DEVID,DL	;save device i.d.
	XOR	DH,DH
	MOV	DI,DX		;copy offset
	SHL	DI,1		;make word index (COM1=0 / COM2=2)
	CALL	InitComPort	;initialize the port, int vector, etc.
	OR	AX,AX		;test if error reported
	JZ	InitComAvail	;if zero, then initialization successful
	JMP	INIRET		;else exit with CH set with 0FEH for DNA
InitComAvail:			

	MOV	DX,[BX].CD_RXSIZ ;get size of the receive buffer
	MOV	CX,[BX].CD_TXSIZ ;get size of the transmit buffer
	CALL	BUFFINI 	;initialize buffer stuff

	MOV	CL,[BX].CD_CMFLG ;get com flags

	MOV	[SI].COMBSY,0	;not initially transmitting
	MOV	[SI].COMRTS,2	;set RTS mask
	AND	[SI].COMRTS,CL	;should RTS be enabled?
	MOV	[SI].COMPE,4D	;set PE mask
	MOV	CL,[BX].CD_CMFLG ;get com flags
	AND	[SI].COMPE,CL	;should PE be enabled?
	MOV	CX,[BX].CD_RXSEG ;get segment of receive comm buffer
	MOV	[SI].RCVSEG,CX	;set segment of receive comm buffer
	MOV	CX,[BX].CD_TXSEG ;get segment of transmit comm buffer
	MOV	[SI].XMTSEG,CX	;set segment of transmit comm buffer

	XOR	CX,CX		;assume no timeout value
	CMP	[BX].CD_RLSTO,CX ;test if RLSD timeout to be tested
	JZ	InicomNoCD	;if not, then leave timeout as zero
	MOV	CX,[BX].CD_OPNTO ;get OPEN timeout value
InicomNoCD:			
	MOV	[SI].COMRLS,CX	;set RLSD timeout count

	XOR	CX,CX		;assume no timeout value
	CMP	[BX].CD_DSRTO,CX ;test if DSR timeout to be tested
	JZ	InicomNoDS	;if not, then leave timeout as zero
	MOV	CX,[BX].CD_OPNTO ;get OPEN timeout value
InicomNoDS:			
	MOV	[SI].COMDSR,CX	;set DSR timeout count

	MOV	[SI].COMCTS,0	;don't check CTS during initialization
	MOV	[SI].COMOVF,0	;clear overflow flag
	MOV	[SI].COMERR,0	;clear I/O error flag
	MOV	[SI].MSRERR,0	;clear modem status flag
	MOV	[SI].MSREG,0	;clear modem error value
	MOV	DH,[BX].CD_BYTSZ ;get number of data bits in byte in [DH]
	MOV	DL,[BX].CD_PARIT ;get requested parity in [DL]
	OR	DL,DL		;is parity "NONE"?
	JZ	ChkParity	; br. if so
	CMP	DH,8		;is byte size 8?
	JNZ	ByteSizeOK	; Brif not
ErrorJmp:			; for jump out of range
	MOV	AH,0FFH 	; require mode not support
	JMP	SHORT TRMRET	; else error (reset interrupt vectors)

ChkParity:			
	CMP	DH,4		;was it no parity and byte size 4?
	JZ	ErrorJmp	; Brif yes, error
ByteSizeOK:			; the following is set line status and baud
				;  rate
	SUB	DH,5		;shift byte size to bits 0&1
	MOV	[SI].BYTSIZ,DH	;save byte size
	MOV	DH,DL		;copy parity
	CMP	DL,2		;does parity need adjustment?
	JB	ParityOK	; br. if not
	MOV	DH,1		;[DH]=new parity value
	DEC	DL		;[DL] = Loop count
AdjParLoop:			; keep adjust
	INC	DH		;parity 0 -> 0, parity 1 -> 1
	INC	DH		;parity 2 -> 3
	DEC	DL		;parity 3 -> 5
	JNZ	AdjParLoop	; parity 4 -> 7
ParityOK:			
	MOV	[SI].PARTYP,DH	;store adjusted parity value
	MOV	AL,[BX].CD_STOPB ;get number of stop bits 0=1,1/2= .GT. 1
	DEC	AL		;Find out if 0 stop bits?
	JS	StopBitOK	; Brif sign, must have been zero stop bits
				;Request > 1 stop bit if by ORing with BIT 2 on
	OR	BYTE PTR [SI].BYTSIZ,00000100B
				;[BYTSIZ] is number of data bits and stop bits
StopBitOK:			
	MOV	CX,[BX].CD_BAUDR ;get requested baud rate
	CALL	GETDIV		;get necessary divisor to support baud rate
	MOV	AH,0FFH		;set error code if baud not supported
	JCXZ	TRMRET		;reset vector if not and give error
	CALL	SETEM		;set up RS232 card
	OR	AH,AH		;test if error occurred
	JNZ	TRMRET		;if so, then reset vector and jump

	MOV	CX,[BX].CD_RLSTO ;get RLSD time out count
	MOV	[SI].COMRLS,CX	;set RLSD timeout count
	MOV	CX,[BX].CD_DSRTO ;get DSR time out count
	MOV	[SI].COMDSR,CX	;set DSR timeout count
	MOV	CX,[BX].CD_CTSTO ;get CTS timeout count
	MOV	[SI].COMCTS,CX	;store real CTS timeout count

	JMP	SHORT INIRET

TRMRET:
	PUSH	AX		;save registers...
	PUSH	BX
	PUSH	CX
	PUSH	DX
	XOR	CX,CX		; reset DTR
	MOV	[b$COFlag],CL	; Clear flag for next call to MSRWAT!
	CALL	CLSMSR		;full termination - bring lines down
	POP	DX		;restore registers...
	POP	CX
	POP	BX
	POP	AX
	CMP	AH,0FCh		; was CTRL-BREAK detected in MSRWAT?
	JNE	INIRET		; brif not
	CALL	B$BREAK_CHK	; process CTRL-BREAK -- should not return
DbHalt	DV_TEXT,<CTRL-BREAK lost during COM OPEN in B$INICOM>	;

INIRET:
cEnd	;B$INICOM		; pop register and exit
	page			
;***
; InitComPort - Initialize a communications port
;
; Purpose:
;	First tests if device is available through the BIOS data location
;	(0:400H for COM1 - 0:402H for COM2) which contains the I/O data port.
;	If the device is available, then set up the ISR vector and initialize
;	the hardware.
; Entry:
;	DI = device index (COM1=0 / COM2=2)
; Exit:
;	AH = 0FEH if device is not available.
;	AX = 0 if device is available.
; Modifies:
;	AX, DX.
; Exceptions:
;	None.
;*************************************************************************

;	First, determine if the device is available by examining the
;	BIOS location of the I/O port number.  If zero, it is unavailable.
;	If nonzero, clear the value for exclusive use and store the port
;	address in the DCB.

InitComPort:
	PUSH	DS		;save DGROUP on stack
	XOR	DX,DX		;clear DX for use as BIOS segment
	MOV	DS,DX		;set segment to access BIOS data area
	XCHG	DX,DS:RS232B[DI] ;get I/O address in DX, clear BIOS data
	POP	DS		;restore DGROUP from stack

	MOV	b$ComPort[DI],DX ;store I/O port address in DCB
	OR	DX,DX		;test if device is available
	JNZ	ComPortAvail	;if so, then jump
	MOV	AH,0FEH		;set CH for "device not ready" error
	RET			;do a near return to caller with CH=0FEH

;	With the device index in DI and the I/O port address in DX,
;	initialize the hardware and interrupt vectors.

ComPortAvail:
	PUSH	BX		;save registers...
	PUSH	SI

	MOV	SI,OFFSET CODE:COM_INT1 ;COM1: Service addr
	MOV	BX,OFFSET DGROUP:COM1_VECTOR ;get offset for saved vector

	OR	DI,DI		;test if COM1 is being initialized
	JZ	ComPortStart	;if so, then start the initialization

	MOV	SI,OFFSET CODE:COM_INT2 ;COM2: Service addr
	MOV	BX,OFFSET DGROUP:COM2_VECTOR ;get offset for saved vector
ComPortStart:

	MOV	CX,0EF00H+IRQ4/4 ;8259 enable mask/int number (primary)

	CMP	b$ComPort[DI],03F8H ;test if primary asynch card
	JE	ComPortPrimary	;if so, then jump

	MOV	CX,0F700H+IRQ3/4 ;8259 enable mask/int number (secondary)
ComPortPrimary:			

	CLI			;disable interrupts during initialization
	ADD	DX,4		;Modem Control Register
	MOV	AL,1		; AL = 1 = DTR active; RTS off
	OUT	DX,AL		; Turn of RTS; leave DTR active
	PAUSE			;Delay
	SUB	DX,3		;Interrupt Enable Register
	DEC	AX		; AL = 0 = disable interrupts
	OUT	DX,AL		;Turn off interrupts
	MOV	DX,SI		;Set IRQ-4 Vector
	MOV	SI,BX		;get pointer to save vector addr
	MOV	AL,CL		;get interrupt number
	MOV	AH,35H		;get vector function call
	INT	21H		;get vector in ES:BX
	MOV	[SI],BX 	;store away current vector offset
	MOV	[SI+2],ES	;and likewise the current segment
	PUSH	DS		;get BASIC data segment
	POP	ES		;and restore ES with it
	PUSH	CS		;DS = CS
	POP	DS
	MOV	AH,25H		;DOS Set Vector Function
	INT	21H
	PUSH	ES		;save BASIC data segment
	POP	DS		;Original DS
	MOV	AH,CH		;get mask to AND with current one
	IN	AL,INTA1	;get interrupt mask for 8259
	AND	AL,AH		;include IRQ-3 or IRQ-4
	PAUSE			;to give settle time for I/O bus signals
	OUT	INTA1,AL	;output the new interrupt mask
	XOR	AX,AX		;clear AX for no error
	STI			;re-enable interrupts

	POP	SI		;restore registers...
	POP	BX
	RET			;near return to caller

;***
; BUFFINI - initialize COM buffers
;
; Purpose:
;	This routine is responsible for initializing the queue control
;	block field elements for the input and output buffers.
; Entry:
;	DX = size of receive buffer.	
;	SI = pointer to deb.
; Exit:
;	None.
; Modifies:
;	None.
; Exceptions:
;	None.
;***************************************************************************

BUFFINI:
	PUSH	SI
	PUSH	BX
	PUSH	AX
	MOV	BX,OFFSET DGROUP:Q_OUT ;get output QCB for COM1
	CMP	[SI].DEVID,0	;is this com1?
	JZ	BUFF2		;jump if so
	MOV	BX,OFFSET DGROUP:Q_OUT2 ;[BX]= Out QCB
BUFF2:
	XOR	AX,AX		;each buffer starts at zero
	MOV	[BX].QUEBOT,AX	;Store Out buffer Bottom addr

⌨️ 快捷键说明

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