	.TITLE	MBDRIVER - STARLET MAILBOX DEVICE DRIVER 
	.IDENT	/X05/		;
;
; COPYRIGHT (C) 1978
; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS 01754
;
; THIS SOFTWARE IS FURNISHED  UNDER A LICENSE FOR USE ONLY ON A SINGLE
; COMPUTER  SYSTEM AND  MAY BE  COPIED ONLY WITH  THE INCLUSION OF THE
; ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE, OR ANY OTHER COPIES THEREOF,
; MAY NOT BE PROVIDED OR  OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON
; EXCEPT FOR USE ON SUCH SYSTEM AND TO ONE WHO AGREES TO THESE LICENSE
; TERMS.  TITLE TO AND  OWNERSHIP OF THE  SOFTWARE  SHALL AT ALL TIMES
; REMAIN IN DEC.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD  NOT BE CONSTRUED  AS A COMMITMENT  BY DIGITAL  EQUIPMENT
; CORPORATION.
;
; DEC ASSUMES  NO  RESPONSIBILITY  FOR  THE USE OR  RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
;
;++
; FACILITY:
;
;	VAX/VMS MAILBOX DEVICE DRIVER
;
; ABSTRACT:
;
;	THIS MODULE CONTAINS THE MAILBOX DRIVER I/O ROUTINES.
;
; AUTHOR: R. HEINEN 16-SEPT-76
;
;--
; EXTERNAL SYMBOLS
;
	$ACBDEF				; DEFINE AST CONTROL BLOCK
	$CADEF				; DEFINE CONDITIONAL ASSEMBLY
	$DDBDEF				; DEFINE DDB
	$DYNDEF				; DEFINE DYNAMIC BLOCK TYPES
	$IODEF				; DEFINE FUNCTION CODES
	$IRPDEF				; DEFINE I/O PACKET OFFSETS
	$IPLDEF				; DEFINE IPL NUMBERS
	$PCBDEF				; DEFINE PCB OFFSETS
	$PRDEF				; DEFINE PROCESSOR REGISTERS
	$PRIDEF				; DEFINE PRIORITY INCREMENTS
	$RSNDEF				; DEFINE RESOURCE NUMBERS
	$SSDEF				; DEFINE SYSTEM STATUS CODES
	$UCBDEF				; DEFINE UCB OFFSETS
 
;
; LOCAL DEFINITIONS
;
UCB$L_MB_MSGQ=UCB$L_FQFL
UCB$L_MB_W_AST = UCB$L_ASTQFL
UCB$L_MB_R_AST = UCB$L_ASTQBL
 
P1		= 0			; OFFSET TO BUFFER ADDRESS IN ARGUMENT BLOCK
P2		= 4			; OFFSET TO REQUEST SIZE IN ARGUMENT BLOCK
P3		= 8			; OFFSET FOR PARAMETER 3
P4		= 12			; OFFSET FOR PARAMETER 4
 
;
; LOCAL DATA STORAGE
;
 
	.PSECT	WIONONPAGED
 
MB$DDT::
	.LONG	STARTIO			; STARTIO OPERATION
	.LONG	0			; NO UNSOLICITED INTERRUTPS
	.LONG	10$			; FUNCTION DECISION TABLE
	.LONG	CANCELIO		; CANCEL I/O
	.LONG	0,0			; DIAGNOSTIC INFO
 
;
; FUNCTION DECISION TABLE
;
 
10$:	FUNCTAB	,<-			; LEGAL FUNCTIONS
		SETMODE,-		; ASK FOR READ OR WRITE AST'S
		WRITEOF,-		; WRITE EOF
		READLBLK,WRITELBLK,-
		READVBLK,WRITEVBLK,-
		READPBLK,WRITEPBLK>
	FUNCTAB,<READLBLK,READVBLK,READPBLK,-
		WRITELBLK,WRITEVBLK,WRITEPBLK>
	FUNCTAB FDTREAD,<READLBLK,READPBLK,READVBLK>; READ FUNCTION
	FUNCTAB FDTWRITE,<WRITELBLK,WRITEPBLK,WRITEVBLK>; WRITE FUNCTION
	FUNCTAB	FDTSET,<SETMODE>	; SET AST CONTROL
	FUNCTAB	FDTEOF,<WRITEOF>	; WRITE EOF

	.SBTTL	EXE$SNDEVMSG - SEND DEVICE DRIVER MAILBOX MESSAGE
;++
; EXE$SNDEVMSG - SEND DEVICE SPECIFIC MESSAGE ON BEHALF OF DRIVER
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE BUILDS AND SENDS A DEVICE SPECIFIC MESSAGE TO A MAILBOX.
; THE MESSAGE IS FORMATTED AS FOLLOWS:
;
;	WORD 0   = TYPE OF MESSAGE
;	WORD 1   = UNIT OF DEVICE
;	REMAINDER = COUNTED STRING OF DEVICE NAME
;
; INPUTS:
;
;	R2 = ADDRESS OF 
;	R3 = MAILBOX UCB ADDRESS
;	R4 = TYPE OF MESSAGE
;	R5 = DEVICE UCB ADDRESS
;
;
; OUTPUTS:
;
;	R0 = STATUS OF THE OPERATION
;	R1,R2,R3,R4,R5 ARE DISTROYED
;
; STATUS RETURNS:
;
;	SEE EXE$WRTMAILBOX.
;--
EXE$SNDEVMSG::				; SEND MESSAGE FOR DEVICE DRIVER
	PUSHL	R5			; SAVE SENDING DEVICE UCB
	PUSHR	#^M<R4,R5,R6,R7,R8>	; PUSH MESSAGE TYPE AND RESERVE SPACE
	MOVW	UCB$W_UNIT(R5),2(SP)	; INSERT UNIT OF DEVICE
	MOVL	UCB$L_DDB(R5),R5	; ADDRESS SENDING DDB
	MOVL	SP,R2			; COPY MESSAGE ADDRESS
	PUSHR	#^M<R2,R3>		; SAVE MESSAGE ADDRESS AND TARGET UCB
	EXTZV	#0,#4,DDB$T_NAME(R5),-(SP); GET SIZE OF NAME TO 15 CHARAS
	INCL	(SP)			; SET UP TO COPY SIZE TOO
	MOVC3	(SP),DDB$T_NAME(R5),4(R2); COPY NAME
	ADDL3	#4,(SP)+,R3		; GET TOTAL MESSAGE SIZE
	POPR	#^M<R4,R5>		; GET ADDRESS AND TARGET UCB
	BSBB	EXE$WRTMAILBOX		; DO THE MAILBOX WRITE
	ADDL	#20,SP			; RESTORE STACK
	POPR	#^M<R5>			; RESTORE SENDING UCB
	RSB				; RETURN

	.SBTTL	SYSTEM INTERNAL WRITE TO MAILBOX SUBROUTINE
;++
; EXE$WRTMAILBOX - WRITE TO MAILBOX SUBROUTINE FOR EXECUTIVE USE
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY SYSTEM ROUTINES TO WRITE A MESSAGE TO A MAILBOX.
;
; INPUTS:
;
;	R3 = SIZE OF MESSAGE
;	R4 = MESSAGE ADDRESS
;	R5 = MAILBOX UCB ADDRESS
;
; OUTPUTS:
;
;	R0 = STATUS OF OPERATION
;
;	R1,R2 USED.
;
; COMPLETION CODES:
;
;	SS$_NORMAL
;	SS$_DEVOFFLIN - MAILBOX IS NOT ONLINE
;	SS$_MBTOOSML - MESSAGE TOO LARGE FOR MAILBOX
;	SS$_MBFULL - MAILBOX FULL OF MESSAGES
;	SS$_INSFMEM - MEMORY ALLOCATION PROBLEM
;
;--
EXE$WRTMAILBOX::			;
;
; SET THE PROPER IPL FOR INTERLOCK
;
	MFPR	#PR$_IPL,-(SP)		; SAVE CURRENT IPL
	CMPB	UCB$B_FIPL(R5),(SP)	; HIGH ENOUGH?
	BLEQU	10$			; IF LEQU THEN YES
	SETIPL	UCB$B_FIPL(R5)		; SET THE PROPER IPL
;
; MAIL THE MESSAGE
;
10$:	MOVZWL	#SS$_DEVOFFLINE,R0	; ASSUME OFF LINE
	BBC	#UCB$V_ONLINE,UCB$W_STS(R5),20$; BR IF NOT ONLINE
	MOVZWL	#SS$_MBFULL,R0		; ASSUME MESSAGE WILL NOT FIT
	CMPW	UCB$W_MSGCNT(R5),UCB$W_MSGMAX(R5); MAIL BOX FULL?
	BEQL	20$			; IF YES THEN NO WRITE
	MOVZWL	#SS$_MBTOOSML,R0	; ASSUME MESSAGE TOO BIG
	MOVAB	22(R3),R1		; SET SIZE TO REQUEST
	CMPW	R3,UCB$W_BUFQUO(R5)	; MESSAGE FIT?
	BGTRU	20$			; IF GTRU THEN NO
	CMPW	R3,UCB$W_DEVBUFSIZ(R5)	; BIGGER THAN ALLOWED?
	BGTRU	20$			; IF YES THEN ALSO ERROR
	PUSHR	#^M<R3,R4,R5>		; SAVE REGISTERS FROM MOVC
	BSBW	EXE$ALONONPAGED		; GET THE MEMORY BLOCK
	BLBC	R0,15$			; RETURN UNSUCESSFULLY ON FAILURE
;
; FILL IN BLOCK
;
	PUSHAQ	(R2)+			; SAVE BLOCK ADDRESS AND PASS LINK WORDS
	MOVW	R1,(R2)+		; INSERT BLOCK SIZE
	MOVW	#DYN$C_BUFIO,(R2)+	; INSERT BLOCK TYPE
	MOVW	4(SP),(R2)+		; INSERT SIZE OF MESSAGE
	CLRL	(R2)+			; SET NO PACKET
	MOVL	SCH$GL_CURPCB,R0	; GET CURRENT PCB
	MOVL	PCB$L_PID(R0),(R2)+	; INSERT IT ( WHATEVER IT IS! )
;
; COPY DATA
;
	MOVC3	4(SP),(R4),(R2)		; MOVE DATA
;
; INSERT IN MESSAGE QUEUE
;
	POPR	#^M<R2>			; RESTORE BLOCK ADDRESS
	MOVL	8(SP),R5		; RESTORE MAILBOX UCB ADDRESS
	BSBW	INSMBQUEUE		; INSERT ON QUEUE
	MOVZBL	#SS$_NORMAL,R0		; SET SUCCESS
15$:	POPR	#^M<R3,R4,R5>		; RESTORE REGISTERS
20$:	ENBINT				; ENABLE INTERUPTS TO CALLER'S IPL
	RSB				; AND RETURN

	.SBTTL	CANCELIO - CANCEL I/O ON MAILBOX UNIT
;++
; CANCELIO - CANCEL I/O ON MAILBOX UNIT
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS ENTERED TO CANCEL ALL OUTSTANDING I/O FOR A PARTICULAR
; PROCESS AND CHANNEL ON A MAILBOX UNIT.
; IF THE UNIT IS BUSY, THE CURRENT READ PACKET IS CHECKED AND COMPLETED
; IF IT BELONGS TO THE CANCELLING PROCESS. ALL QUEUED REQUESTS HAVE BEEN REMOVED.
; IF NO READER EXISTS THEN THE QUEUE OF OUTSTANDING MESSAGES IS SEARCHED
; FOR MESSAGES AND WAITING WRITES. IF A PID MATCH EXISTS THEN THESE I/O
; ARE ALSO COMPLETED ALONG WITH REMOVING THE MESSAGES.
; THE FINAL ACTION IS TO SEARCH THE QUEUE OF AST REQUESTS TO REMOVE THE ONES
; ASSOCIATED WITH THE CANCELLING PROCESS.
;
; INPUTS:
;
;	R2 = NEGITIVE OF CHANNEL NUMBER
;	R3 = CURRENT PACKET ADDRESS
;	R4 = PCB OF CANCELLING PROCESS
;	R5 = UCB OF UNIT
;
; OUTPUTS:
;
;	R4,R5 ARE PRESERVED
;
; IPL = DEVICE FORK IPL
;--
CANCELIO:				; CANCEL I/O ON MAILBOX UNIT
	MOVQ	R6,-(SP)		; SAVE R6,R7
	MOVL	R2,R6			; COPY CHANNEL NUMBER
	BBC	#UCB$V_BSY,UCB$W_STS(R5),10$; BUSY?
	CMPL	PCB$L_PID(R4),IRP$L_PID(R3); PIDS MATCH?
	BNEQ	40$			; IF NO THEN CANCEL DONE
	CMPW	R6,IRP$W_CHAN(R3)	; CHANNEL MATCH?
	BNEQ	40$			; IF NEQ THEN NO
	MOVQ	#SS$_ABORT,R0		; SET STATUS FOR ABORT
	BSBW	IOC$REQCOM		; COMPLETE THE REQUEST
	BRB	40$			; AND CANCEL IS DONE
;
; NO READER WAITING - CHECK MESSAGE QUEUE
;
10$:	MOVAB	UCB$L_MB_MSGQ(R5),R2	; ADDRESS MESSAGE QUEUE
	MOVL	R2,R0			; COPY LIST HEAD ADDRESS
20$:	MOVL	(R2),R2			; ADDRESS LIST ENTRY
	CMPL	R0,R2			; END OF LIST?
	BEQL	40$			; IF YES THEN DONE
	CMPL	PCB$L_PID(R4),18(R2)	; MESSAGE BELONG TO CANCELLING PROCESS?
	BNEQ	20$			; IF NO THEN SEARCH MORE
	MOVL	14(R2),R3		; ADDRESS PACKET IF ANY
	BEQL	20$			; IF EQL THEN NO ASSOC PACKET
	CMPW	R6,IRP$W_CHAN(R3)	; CHANNEL MATCH?
	BNEQ	20$			; IF NEQ THEN NO
					; BUT GET RID OF MESSAGE
	MOVQ	#SS$_ABORT,IRP$L_MEDIA(R3); SET STATUS
	BSBW	COM$POST		; COMPLETE THE OPERATION
30$:	REMQUE	(R2),R0			; REMOVE MESSAGE FROM QUEUE
	ADDW	12(R2),UCB$W_BUFQUO(R5)	; ADJUST QUOTA
	BSBW	EXE$DEANONPAGED		; DEALLOCATE MESSAGE
	BRB	10$			; SEARCH LIST FROM THE START
;
; SEARCH AST QUEUE
;
40$:	MOVAB	UCB$L_MB_W_AST(R5),R7	; ADDRESS LIST OF AST'S
	BSBW	COM$FLUSHATTNS		; FLUSH ATTENTION AST'S
	MOVAB	UCB$L_MB_R_AST(R5),R7	; ADDRESS WRITER AST'S
	BSBW	COM$FLUSHATTNS		; FLUSH THAT LIST
	MOVQ	(SP)+,R6		; RESTORE REGISTERS
	RSB				; RETURN TO CALLER

	.SBTTL	CHECKIO - CHECK READ AND WRITE PARAMETERS
 
	.ENABL	LSB
 
;++
; READCHECKIO - CHECK READ PARAMETERS
; WRITECHECKIO - CHECK WRITE PARAMETERS
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE READ AND WRITE FDT ROUTINES TO VALIDATE THE
; I/O REQUEST. THE CHECKS ARE MADE BASED ON THE SETTING OF THE IRP$V_FUNC
; OPERATION DIRECTION BIT. THE CHECKS ARE, 1) ACCESS TO UNIT BY UIC,
; 2) MESSAGE REQUEST SIZE WITHIN MAX MESSAGE SIZE, 3) BUFFER ACCESSIBLE.
;
; 0 LENGTH TRANSFERS AND ACCESS VIOLATIONS CAUSE COMPLETIONS HERE.
;
; INPUTS:
;
;	R3 = PACKET ADDRESS
;	R4 = PCB ADDRESS
;	R5 = UCB ADDRESS
;	R6 = CCB ADDRESS
;	R7 = FUNCTION CODE
;	AP = ADDRESS OF THE FIRST QIO PARAMETER
;
; OUTPUTS:
;
;	R0 = BUFFER ADDRESS
;	R1 = BUFFER SIZE
;	R3 = PACKET ADDRESS
;	R4 = PCB ADDRESS
;	R5 = UCB ADDRESS
;
; IMPLICIT OUTPUTS:
;
;	THE BUFFER ADDRESS AND COUNT IS SAVED IN IRP$L_MEDIA.
;--
READCHECKIO:				; CHECK READ PARAMETERS
	PUSHAB	W^EXE$READCHK		; READ CHECKS NEEDED
	MOVAB	W^EXE$CHKRDACCES,R0	;
	BRB	10$			; CONTINUE IN COMMON
WRITECHECKIO:				; SET UP FOR WRITE CHECK
	MOVAB	W^EXE$CHKWRTACCES,R0	; SET UP WRITE CHECK
	PUSHAB	W^EXE$WRITECHK		;
10$:	MOVZWL	UCB$W_VPROT(R5),R1	; SET UP FOR UIC CHECK
	MOVL	UCB$L_OWNUIC(R5),R2	;
	CLRW	IRP$W_BOFF(R3)		; RESET QUOTA
	JSB	(R0)			; CHECK UIC ACCESS
	BLBC	R0,ERROR		; BR IF ACCESS FAILURE
	MOVZWL	P2(AP),R1		; GET BUFFER SIZE
	BEQL	70$			; IF EQL THEN COMPLETE HERE
	CMPW	R1,UCB$W_DEVBUFSIZ(R5)	; MESSAGE SIZE IN RANGE?
	BGTRU	50$			; IF GTRU THEN NO
	MOVL	P1(AP),R0		; GET BUFFER ADDRESS
	MOVL	R0,IRP$L_MEDIA(R3)	; SAVE BUFFER ADDRESS
	RSB				; RETURN AND CHECK BUFFER
50$:	MOVZWL	#SS$_MBTOOSML,R0	; SET BOX TOO SMALL
ERROR:	BRW	EXE$ABORTIO		; ABORT THE I/O
70$:	MOVZBL	#SS$_NORMAL,R0		; COMPLETE 0 LENGTH TRANSFERS
	BRW	EXE$FINISHIOC		;
 
	.DSABL	LSB

	.SBTTL	FDTREAD - READ FUNCTION DECISION ROUTINE
;++
; FDTREAD - FUNCTION DECISION ROUTINE FOR READ OPERATIONS
;
; FUNCTIONAL DESCRIPTION:
;
; THE USER REQUEST IS VAILDATED FOR:
;
;	1.ACCESS BY UIC.
;	2.REQUEST WITHIN MAXIMUM MESSAGE SIZE.
;	3.BUFFER ACCESSIBLE FOR WRITE.
;
; THEN THE PACKET IS QUEUED ONTO THE UCB FOR PROCESSING WHEN THE UNIT IS IDLE.
;  FOR READ NOW FUNCTIONS, IF NO MESSAGES ARE PRESENT IN THE MAILBOX
; THE OPERATION IS COMPLETED.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;	R4 = CURRENT PCB ADDRESS
;	R5 = UCB ADDRESS
;	R6 = CCB ADDRESS
;	R7 = FUNCTION CODE
;	AP = PARAMETER BLOCK AT USER ARGUMENT "P1"
;
; OUTPUTS:
;
;	THE PACKET IS QUEUED VIA "EXE$QIODRVPKT" OR
;	THE REQUEST IS COMPLETED WITH AN ERROR VIA "EXE$ABORTIO"
;
; STATUS CODES:
;
;	SS$_NOPRIV - USER DOES NOT HAVE PRIVILEGE TO READ MAILBOX
;	SS$_ACCVIO - BUFFER ACCESS VIOLATION ( "EXE$READCHK" )
;	SS$_MBTOOSML - REQUEST EXCEEDS THE MAXIMUM MESSAGE SIZE
;	SS$_ENDOFFILE - FOR "READNOW" NO DATA RETURN
;	SS$_NORMAL - NORMAL STATUS ( "STARTIO" )
;--
FDTREAD:				;
	BSBB	READCHECKIO		; VALIDATE THE REQUEST
;
; UPDATE MEASUREMENT COUNTER IF ENABLED
;
	.IF NE CA$_MEASURE
	INCL	PMS$GL_MBREADS		; COUNT MAILBOX READS
	.ENDC
;
; CHECK FOR READ NOW FUNCTIONS
;
	BBC	#IO$V_NOW,IRP$W_FUNC(R3),50$; BR IF NOT "NOW"
;
; READ NOW
;
; TEST TO SEE IF THERE ARE ANY MESSAGES WAITING
;
	SETIPL	UCB$B_FIPL(R5)		; SET TO FORK IPL
	TSTW	UCB$W_MSGCNT(R5)	; ANY MESSAGES?
	BNEQ	50$			; IF NEQ THEN YES
;
; COMPLETE "READNOW" FUNCTIONS BECAUSE NO MESSAGES ARE AVAILABLE
;
	MOVZWL	#SS$_ENDOFFILE,R0	; SET NO TRANSFER AND STATUS
	BRW	EXE$FINISHIOC		; COMPLETE THE I/O
;
; QUEUE PACKET TO DRIVER LIST
;
50$:	BRW	EXE$QIODRVPKT		; QUEUE PACKET ON UCB

	.SBTTL	FDTSET - SET UP ATTENTION AST FUNCTION
;++
; FDTSET - SET UP ATTENTION AST
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE PROCESSES SET MODE REQUESTS TO ENABLE OR DISABLE AN ATTENTION
; AST. THE WORK IS DONE BY A COMMUNICATION DRIVER SUBROUTINE AFTER A CHECK
; IS MADE TO SEE IF THE REQUESTOR HAS ACCESS TO THE MAILBOX.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;	R4 = CURRENT PCB
;	R5 = UCB ADDRESS FOR MAILBOX UNIT
;
; OUTPUTS:
;
;	NONE, THE I/O IS COMPLETED
;
; STATUS RETURNS:
;
;	SS$_NORMAL - SUCCESSUFL COMPLETION
;	SS$_INSFMEM - INSUFICIENT MEMORY
;	SS$_EXQUOTA - AST QUOTA EXCEEDED
;--
FDTSET:					; SET RECEIVE AST FUNCTION
;
; SEE IF USER CAN READ THIS MAILBOX
;
	MOVZWL	UCB$W_VPROT(R5),R1	; GET UNIT PROTECTION
	MOVL	UCB$L_OWNUIC(R5),R2	; GET OWNER UIC
	BSBW	EXE$CHKRDACCES		; CHECK THE ACCESS OF THIS USER
	BLBC	R0,ERROR		; IF LOW CLEAR THEN ERROR
	MOVAB	UCB$L_MB_W_AST(R5),R7	; ASSUME WRITER AST
	BBC	#IO$V_READERAST,IRP$W_FUNC(R3),10$; BR IF NOT READER AST
	TSTL	(R7)+			; POINT TO READER AST LIST
10$:	PUSHR	#^M<R4,R7>		; SAVE PCB AND LIST HEAD
	BSBW	COM$SETATTNAST		; CONTINUE IN COMMON
	POPR	#^M<R1,R4>		; POP PCB AND SET LIST HEAD ADDRESS
	SETIPL	UCB$B_DIPL(R5)		; SET UP THE IPL
	BBS	#IO$V_READERAST,IRP$W_FUNC(R3),15$; BR IF READER AST
	TSTW	UCB$W_MSGCNT(R5)	; ANY MESSAGES?
	BEQL	25$			; IF EQL THEN NONE
	BRB	20$			; IF NEQ THEN DELIVER AST
15$:	BBC	#UCB$V_BSY,UCB$W_STS(R5),25$; BR IF NOT BUSY
20$:	BSBW	COM$DELATTNAST		; DELIVER THE ASTS
25$:	MOVL	R1,R4			; RESTORE PCB
	BRW	EXE$FINISHIOC		; COMPLETE THE I/O

	.SBTTL	FDTEOF - WRITE EOF MESSAGE TO MAILBOX
;++
; FDTEOF - WRITE EOF MESSAGE TO THE MAILBOX
;
; FUNCTIONAL DESCRIPTION:
;
; THIS IS THE FDT ROUTINE FOR IO$WRITEOF. THE ACTION IS TO BUILD A
; ZERO LENGHT MESSAGE AND TO INSERT IT IN THE MAILBOX.
; THIS MESSAGE, WHEN READ RESULTS IN AN SS$_ENDOFILE STATUS RETURN.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;	R4 = CURRENT PCB ADDRESS
;	R5 = MAILBOX UCB ADDRESS
;
; OUTPUTS:
;
;	THE I/O IS COMPLETED IN THE WRITE FDT LOGIC. ( SEE BELOW)
;--
FDTEOF:					;
	CLRL	IRP$W_BOFF(R3)		; SET NO TRANSFER AND NO QUOTA
	MOVZWL	UCB$W_VPROT(R5),R1	; GET VOLUME PROTECTION
	MOVL	UCB$L_OWNUIC(R5),R2	; GET THE OWNER UIC
	BSBW	EXE$CHKWRTACCES		; CHECK THE ACCESS
	BLBC	R0,ERROR		; IF ERROR THEN BR
	CLRL	R1			; SET NO DATA
	MOVAB	(SP),R0			; FAKE GOOD ADDRESS FOR THE FUTURE MOVC
	BRB	WRITE			; WRITE THE MESSAGE

	.SBTTL	FDTWRITE - WRITE OPERATION FDT ROUTINE
;++
; FDTWRITE -- FUNCTION DECISION ACTION ROUTINE FOR WRITE FUNCTIONS
;
; FUNCTIONAL DESCRIPTION:
;
; THE USER REQUEST IS VALIDATED FOR PRIVILEGE, SIZE, ACCESS AND AVAILABLE
; SPACE. IF VALID, A BUFFERED I/O BLOCK IS ALLOCATED (IMPLIED RESOURCE WAIT).
; THE BLOCK IS SET UP AND QUEUED TO THE UNIT MESSAGE LIST. IF THE UNIT
; IS BUSY, THE OUTSTANDING READ OPERATION IS COMPLETED DIRECTLY.
; IN THE CASE OF "WRITENOW" FUNCTIONS THE I/O IS COMPLETED BEFORE THE
; MESSAGE IS QUEUED. OTHERWISE THE READ COMPLETE ROUTINE COMPLETES
; THE MESSAGE ASSOCIATED WRITE.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;	R4 = CURRENT PCB ADDRESS
;	R5 = UCB ADDRESS
;	R6 = CCB ADDRESS
;	R7 = FUNCTION CODE
;	AP = ADDRESS OF USER ARGUMENT BLOCK AT "P1"
;
; OUTPUTS:
;
;	THE I/O IS COMPLETED IN ERROR, THE I/O IS RESTARTED BECAUSE OF
;	RESOURCE WAIT, OR THE I/O IS COMPETED NORMALLY.
;
; STATUS RETURNS:
;
;	SS$_MBTOOSML - MESSAGE IS TOO BIG
;	SS$_ACCVIO - BUFFER ACCESS VIOLATION ( "EXE$WRITECHK" )
;	SS$_MBFULL - MAILBOX IS FULL
;	SS$_NOPRIV - USER DOES NOT HAVE WRITE PRIVILEGE
;	SS$_NORMAL - SUCCESSFUL STATUS
;	SS$_INSFMEM - NO MEMORY FOR BUFFER ALLOCATION
;--
FDTWRITE:				;
	BSBW	WRITECHECKIO		; CHECK OPERATION PARAMETERS
WRITE:
	PUSHR	#^M<R0,R3>		; SAVE REGISTERS
	ADDL	#22,R1			; ADJUST REQUEST SIZE FOR HEADER
;
; GET BUFFER
;
	BSBW	EXE$ALONONPAGED		; ALLOCATE A BUFFER
	BLBC	R0,55$			; CONTINUE
	POPR	#^M<R0,R3>		; RESTORE PACKET ADDRESS AND DATA ADDRESS
;
; SET UP BLOCK
;
	PUSHR	#^M<R2,R3,R4,R5>	; SAVE BLOCK,PACKET,PCB AND UCB
	ADDL	#8,R2			; POINT PAST FIXED PART
	MOVW	R1,(R2)+		; INSERT SIZE
	MOVB	#DYN$C_BUFIO,(R2)+	; INSERT TYPE
	MOVB	#IPL$_MAILBOX,(R2)+	; INSERT IPL
	MOVW	IRP$W_BCNT(R3),(R2)+	; INSERT MESSAGE SIZE
	MOVL	R3,(R2)+		; INSERT SAVED PACKET ADDRESS
	BBC	#IO$V_NOW,IRP$W_FUNC(R3),15$; BR IF NOT "NOW"
	CLRL	-4(R2)			; RESET MESSAGE PACKET POINTER
15$:	MOVL	PCB$L_PID(R4),(R2)+	; INSERT PID OF SENDER
;
; COPY DATA FROM USER TO SYSTEM
;
	MOVC3	IRP$W_BCNT(R3),(R0),(R2); MOVE CHARACTERS TO SYSTEM SPACE
	POPR	#^M<R2,R3,R4,R5>	; RESTORE REGISTERS
;
; MAKE FINAL QUOTA CHECKS INTERLOCKED WITH DRIVER WRITERS
;
; THESE CHECKS MUST BE MADE AT DRIVER FORK LEVEL TO PRESERVE THE
; INTEGRITY OF THE QUOTAS. IF THE QUOTA IS EXCEEDED THEN THE PROCESS 
; IS PLACED IN A "RSN$_MAILBOX" WAIT STATE. THE PROCEEDURE FOR
; PLACING THE PROCESS IN THE WAIT STATE IS COMPLICATED BY THE
; HIGHER THAN "IPL$_SYNCH" EXECUTION LEVEL. IN THIS CASE IT
; IS OK TO CALL RESOURCE WAIT BECAUSE THE IPL WAS RAISED TO FORK
; LEVEL AND NOT REACHED BECAUSE OF AN INTERRUPT LEVEL FORK.
;
;
; MAIL BOX OVER QUOTA?
;
20$:	DSBINT	UCB$B_FIPL(R5)		; RAISE TO DRIVER FORK LEVEL
;
; TEST FIRST TO SEE IF ROOM IS AVAILABLE FOR THE MESSAGE
;
	CMPW	IRP$W_BCNT(R3),UCB$W_BUFQUO(R5); MESSAGE FIT?
	BGTRU	60$			; IF GTR THEN NO
;
; SEE IF MAILBOX IS FULL
;
	CMPW	UCB$W_MSGCNT(R5),UCB$W_MSGMAX(R5); FULL?
	BEQL	60$			; IF EQL THEN YES
;
; QUEUE THE MESSAGE
;
	PUSHR	#^M<R3,R5>		; SAVE UCB ADDRESS AND PACKET
	BSBB	INSMBQUEUE		; INSERT THE MESSAGE
	POPR	#^M<R3,R5>		; RESTORE UCB ADDRESS AND PACKET
	ENBINT				; LOWER IPL
;
; SEE IF WRITE I/O GETS COMPLETED NOW
;
	BBS	#IO$V_NOW,IRP$W_FUNC(R3),50$; BR IF WRITE NOW
	BRW	EXE$QIORETURN		; RETURN TO CALLER
;
; FINISH WRITE I/O OPERATION
;
50$:	MOVL	IRP$W_BCNT-2(R3),R0	; GET TRANSFER COUNT
	MOVW	#SS$_NORMAL,R0		; SET STATUS IN LOW
	BRW	EXE$FINISHIOC		; COMPLETE THE I/O
55$:	POPR	#^M<R1,R3>
	MOVZBL	#RSN$_NPDYNMEM,R1	; SET RESOURCE TO AWAIT
	BRB	65$			;
60$:	MOVL	R2,R0			; DEALLOCATE MESSAGE BLOCK
	PUSHL	R3			; SAVE PACKET
	BSBW	EXE$DEANONPAGED		;
	POPL	R3			; RESTORE PACKET
	MOVZBL	#RSN$_MAILBOX,R1	; SET RESOURCE TO AWAIT
65$:	SETIPL	#IPL$_SYNCH		; UP IPL FOR WAIT
	BRW	EXE$IORSNWAIT		; ENTER WAIT STATE


	.SBTTL INSERT MESSAGE IN MAILBOX QUEUE
;++
; INSMBQUEUE - INSERT MESSAGE ON MAILBOX QUEUE
;
; INPUTS:
;
;	R2 = ADDRESS OF MESSAGE BLOCK
;	R5 = UCB OF MAILBOX
;
; OUTPUTS:
;
;	THE MESSAGE IS QUEUED AND IF THE UNIT IS BUSY THEN
;	CONTROL IS TRANSFERED TO "FINISHREAD" TO COMPLETE THE
;	WAITING READ REQUEST.
;--
INSMBQUEUE:				;
	INCW	UCB$W_MSGCNT(R5)	; ADJUST MESSAGE COUNT
	SUBW	14(R2),UCB$W_BUFQUO(R5)	; ADJUST BYTE QUOTA BY MESSAGE SIZE
	.IF NE CA$_MEASURE		; CHECK FOR MEASUREMENT ENABLED
	INCL	PMS$GL_MBWRITES		; COUNT MAILBOX WRITES
	.ENDC
;
; TEST UNIT BUSY -- IF BUSY FINISH OUTSTANDING READ
;
	BBS	#UCB$V_BSY,UCB$W_STS(R5),FINISHREAD; BRANCH IF BUSY
;
; INSERT MESSAGE IN QUEUE
;
	INSQUE	(R2),@UCB$L_MB_MSGQ+4(R5); INSERT MESSAGE IN QUEUE
;
; DELIVER ALL AST'S WAITING FOR MESSAGES ON THIS MAILBOX
;
	MOVAB	UCB$L_MB_W_AST(R5),R4	; ADDRESS ATTENTION LIST HEAD
	BRW	COM$DELATTNAST		; DELIVER THE AST'S

	.SBTTL	STARTIO - STARTIO OPERATION
;++
; STARTIO - START READ OPERATION ON IDLE MAILBOX UNIT
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS ENTERED WHEN THE UNIT IS NOT BUSY AND THERE IS A 
; PACKET TO PROCESS. IF THERE IS ANY MESSAGE WAITING THE READ IS COMPLETED
; OTHERWISE, AN RSB IS DONE LEAVING THE UNIT BUSY AND THE PACKET IN
; LIMBO.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;	R5 = UCB ADDRESS
;
; OUTPUTS:
;
;	R2 = MESSAGE ADDRESS ON TRANSFER TO "FINISHREAD".
;
;	OTHERWISE AN RSB IS DONE.
;--
STARTIO:				;
	REMQUE	@UCB$L_MB_MSGQ(R5),R2	; GET MESSAGE IF ANY FROM QUEUE
	BVC	FINISHREAD		; IF V-CLEAR THEN COMPLETE THE READ
	MOVAB	UCB$L_MB_R_AST(R5),R4	; ADDRESS LIST OF READER AST'S
	BRW	COM$DELATTNAST		; DELIVER AST'S

	.SBTTL	FINISHREAD - FINISH READ I/O OPERATION
;++
; FINISHREAD - FINISH READ OPERATION
;
; FUNCTIONAL DECRIPTION:
;
; THIS ROUTINE IS ENTERED WHEN THE UNIT IS BUSY AND A MESSAGE
; IS AVAILABLE.
; THE WAITING READ IS COMPLETED ALONG WITH THE MATCHING WRITE
; REQUEST IF THE WRITE WAS A WAIT TYPE.
;
; INPUTS:
;
;	R2 = MESSAGE ADDRESS
;	R5 = UCB ADDRESS
;
; OUTPUTS:
;
;--
FINISHREAD:				;
	MOVL	UCB$L_IRP(R5),R3	; GET CURRENT I/O PACKET
	MOVL	R2,IRP$L_SVAPTE(R3)	; INSERT BLOCK ADDRESS IN PACKET
	MOVAB	22(R2),(R2)+		; INSERT ADDRESS OF DATA
	MOVL	IRP$L_MEDIA(R3),(R2)+	; INSERT USER VIRTUAL ADDRESS
	TSTL	(R2)+			; PASS TYPE WORD
	ADDW	(R2),UCB$W_BUFQUO(R5)	; ADJUST QUOTA BY MESSAGE BLOCK SIZE
	CMPW	IRP$W_BCNT(R3),(R2)	; REQUEST GTRU ACTUAL?
	BGTRU	10$			; IF GTRU THEN MESSAGE SIZE CORRECT
	MOVW	IRP$W_BCNT(R3),(R2)	; OTHERWISE REQUEST SIZE IS CORRECT
10$:	ASHL	#16,(R2),R0		; GET SIZE TO UPPER WORD
	MOVW	#SS$_NORMAL,R0		; ASSUME NORMAL STATUS
	MOVW	(R2)+,IRP$W_BCNT(R3)	; REPLACE ORIGIONAL SIZE WITH CORRECT
	BNEQ	15$			; IF NEQ THEN OK
	MOVW	#SS$_ENDOFFILE,R0	; SET EOF STATUS
15$:	DECW	UCB$W_MSGCNT(R5)	; ADJUST MESSAGE COUNT
	PUSHL	R3			; SAVE PACKET OF READER
	MOVL	IRP$L_PID(R3),R1	; GET READER PID
	MOVL	(R2)+,R3		; GET WRITER PACKET
	BEQL	20$			; IF EQL THEN NONE
	MOVQ	R0,IRP$L_MEDIA(R3)	; SET READ STATUS AND PID OF RECEIVER
	MOVZBW	#SS$_NORMAL,IRP$L_MEDIA(R3); INSURE SUCCESS
	BSBW	COM$POST		; COMPLETE THE I/O
20$:	MOVL	(R2),-(SP)		; GET WRITER PID
	MOVL	R0,-(SP)		; SAVE STATUS VALUE
	MOVZBL	#RSN$_MAILBOX,R0	; SET NUMBER OF RESOURCE AVAILABLE
	BSBW	SCH$RAVAIL		; DECLARE IT
	POPR	#^M<R0,R1,R3>		; RESTORE REGISTERS
	REQCOM				; COMPLETE REQUEST!!!
 	.END

