	.TITLE	COMDRVSUB - COMMUNUCATION DRIVERS SUBROUTINES
	.IDENT	'X-22'
;
;****************************************************************************
;*									    *
;*  COPYRIGHT (c) 1978, 1980, 1982, 1984, 1991, 1993 BY			    *
;*  DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS.		    *
;*  ALL RIGHTS RESERVED.						    *
;* 									    *
;*  THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED   *
;*  ONLY IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND 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.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE IS  HEREBY   *
;*  TRANSFERRED.							    *
;* 									    *
;*  THE INFORMATION IN THIS SOFTWARE IS  SUBJECT TO CHANGE WITHOUT NOTICE   *
;*  AND  SHOULD  NOT  BE  CONSTRUED AS  A COMMITMENT BY DIGITAL EQUIPMENT   *
;*  CORPORATION.							    *
;* 									    *
;*  DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE  OR  RELIABILITY OF ITS   *
;*  SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.		    *
;* 									    *
;*									    *
;****************************************************************************
;
;++
; FACILITY:
;
;	VAX/VMS I/O DRIVERS
;
; ABSTRACT:
;
;	THIS MODULE CONTAINS SUBROUTINES FOR THE TERMINAL,MAILBOX AND DMC11 DRIVERS.
;
; AUTHOR:
;
;	R.HEINEN 8-SEPT-1977
;
; REVISION HISTORY:
;
;	X-22	GCE0328	Glenn C. Everhart		28-Mar-1996
;		Add hook so that fast finish may call IRP$L_PID hook
;		directly if FINIPL8 bit is also set. This can allow
;		drivers to bypass detour via IPL4 and IPL8 interrupts
;		where they need to process a bit, then do a "real"
;		completion. Normal processing will not be altered.
;	X-21	JCH703b	John C. Hallyburton, Jr.	25-Apr-1995
;		No Fast-Finish if IRP$L_PID is negative; it breaks shadowing.
;
;	X-20	LSS0343		Leonard S. Szubowicz	24-Apr-1995
;		Fix for EVMS-ZETA QAR 3735.  In routines COM$DELCTRLAST and
;		COM$DELCTRLASTP save R0.  Prior to the Step 2 work (V6.1) these
;		routines did not alter R0.
;
;	X-19	JCH703a	John C. Hallyburton, Jr.	 3-Mar-1995
;		Don't do fast-finish if IRP$V_COMPLX set; the buffer copy
;		code isn't (yet) that sophisticated.
;
;		Disable error flagging around some MOVQs.
;
;	X-18	JCH703	John C. Hallyburton, Jr.	17-Nov-1994
;		Fast-IO finish code
;		DOCD$:[EVMS.PROJECT_DOCUMENTS]FS-FASTIO.PS
;
;	X-17	PKW235		Paul K. M. Weiss	10-Dec-1993
;		Change JSB EXE$MAXACMODE to $MAXIMIZE_ACCESS_MODE macro
;
;	X-16	LSS0283		Leonard S. Szubowicz	20-Aug-1993
;		HLLDD: Use CALL_x macros instead of soon to be obsolete $x.
;
;	X-12	WDB:HLL064B	Walter D. Blaschuk, Jr.	28-Jul-1993
;		Fix for Show Stopper EVMS-EPSILON QAR 1485.
;		The J2C jacket COM$DELCTRLASTP needs to call  
; 		COM_STD$DELCTRLASTP via the $DELCTRLASTP macro.
;		This problem could be found only when using the J2C
;		jacket, No problem would have been encountered if 
;		STD$ routine was called or the proper macro was used.
;
;	X-11	LSS0274		Leonard S. Szubowicz	16-Jul-1993
;		Merge in OpenVMS AXP V1.5 and OpenVMS VAX V6.0 fix.  
;		In routines COM_STD$DELATTNASTP and COM_STD$DELCTRLASTP add
;		DEVICELOCK synchronization, and, thus, also to the six other
;		non-STD and non-P variants of these routines.
;		Use FORK ENVIRONMENT=CALL in these routines.
;		Also, in COM$DELATTNAST and COM$DELCTRLAST J2C routines remove
;		unnecessary registers from their preserve lists.
;		In routine COM_STD$DELCTRLAST, fix handling of output INCLCHAR
;		parameter.
;
;		*** VAX change picked up for Alpha - INCLUSIVE X-4
;
;		X-4		Brian Porter		15-MAR-1993
;			Add DEVICELOCK synchronization to COM$DELATTNAST,
;			COM$DELATTNASTP, COM$DELCTRLAST, COM$DELCTRLASTP.
;
;       X-10    WDB:HLL64       Walter D. Blaschuk, Jr. 16-Jun-1993
;		R3 is being corrupted by PRIMITIVE_FORK;  reinit R3 
;		after the call to FORK at the CONTINUE label in the
;		routine COM_STD$DELCTLRASTP.  	The UCB is not used 
;		in  COM_STD$DELCTRLAST/P and COM_STD$DELATTNLAST/P.
;		The references to the UCB have been removed from
;		these routines. Changes to the interfaces to these 
;		routines should be done. These changes will be done 
;		in the SYSMAR macors and C function prototypes.
;
;       X-9    	WDB:HLL40       Walter D. Blaschuk, Jr. 15-Jun-1993
;		R5 should contain the UCB address in 
;		COM_STD$DELCTLRASTP.
;
;       X-8    	WDB:HLL40       Walter D. Blaschuk, Jr. 25-Mar-1993
;               HLLDD Project: JtoC Jackets.
;		EVMS$IO_CMS:[IO.CMS]J2C_JACKETS.
;		Create several COM_STD$* routines with standard call
;		interfaces from  COM$* routines with JSB interfaces.
;		Also, replace the "JSB" to several routines with the
;		standard "CALLS" or use the  MACRO to push the input
;		and/or output parameters and do the standard "CALLS".
;
;	X-7	KLN1288		Karen L. Noel	       02-Mar-1993
;		Move COM$DRVDEALMEM to MEMORYALC.MAR to make it more
;		efficient.
;
;       X-6     WDB:HLL030      Walter D. Blaschuk, Jr 05-Feb-1993
;		HLLDD Project: FDT revisions.
;
;       X-5     WDB:HLL010      Walter D. Blaschuk, Jr 13-Jan-1993
;               HLLDD Project: FDT processing changes.
;		EVMS$IO_DOC:[IO.CMS]FDT_DESIGN.
;		Changed SETATTNAST and SETCTRLAST to be callable.
;
;       X-4	WDB:A81		Walter D. Blaschuk, Jr 12-Jun-1992
;		A performance change  was made to more efficiently 
;		save registers returning from FORK routine via RSB
;		in routine COM$DRVDEALMEM.
;
;       X-3	WDB:A80		Walter D. Blaschuk, Jr 28-May-1992
;		Some interface changes were required.
;
;	X-2	MSH1196		Michael S. Harvey	6-Dec-1991
;		Byte/word promotion: $PCBDEF.
;
;	X-6	BJT277		Benjamin J. Thomas III	21-Nov-1991
;		Use IRP for passing of QIO arguments P1 - P6
;
;	X-5	BJT271		Benjamin J. Thomas III	15-Nov-1991
;		Promote FUNC fields
;
;	X-4	LSS0226		Leonard S. Szubowicz	18-Sep-1991
;		Merge in V5.4-1 change:
;		X-13U1	TRM001	Tom Moran		20-Sep-1990
;		Modify COM$FLUSHATTNS to hold the DEVICELOCK until
;		it has completed the entire Attention AST List.
;
;       X-13K5	WDB:A15		Walter D. Blaschuk, Jr    2-Aug-1990
;		Code  review revealed some  necessary changes to the	
;		calling sequence. Also ASSUMEs were added before the
;		ADAWIs to call attention to the alignment needs.
;
;       X-13K4	WDB:A13		Walter D. Blaschuk, Jr  2-Aug-1990
;		Corrected build problems.
;
;       X-13K3	WDB:A12		Walter D. Blaschuk, Jr  2-Aug-1990
;		Corrected typo and piggy-back AST.
;
;       X-13K2	WDB:A01		Walter D. Blaschuk, Jr  15-June-1990
;               Initial EVMS port.   The new  FORK macro is used and
;               several JMPs were changed to JSB/RSB combos.  Rather
;		then use  MOVAB to the stack,  I am allocating stack
;		by using SUBL/ADDL.
;
;	X-13	RNG5013		Rod Gamache		31-Mar-1988
;		Use IOC$GQ_POSTIQ for post processing.
;
;	X-12	RAB0004		Richard A. Bishop	17-Nov-1987
;		Add "PRESERVE=NO" to DEVICE(un)LOCK calls
;
;	X-11	FAK0001		Forrest A.Kenney	27-July-1987
;		Rewrite COM$SETCTRLAST to correct cases where an old 
;		pointer to a TAST block is being used.  This rewrite will 
;		remove routine COM$BLDCTRLAST that used to be used 
;		by COM$SETCTRLAST.
;
;	X-10	WCT0076		Ward C. Travis		29-Apr-1987  
;		Change old  occurrences of  UCB$B_ODIPL and  SMP$C_
;		to UCB$B_DIPL and SPL$C_, respectively.
;
;	X-9	SJF		Stu Farnham		20-Mar-1987
;		Mend broken branches.
;
;	X-8	JDC0321		Jon Callas		 4-FEB-1987
;		Fix access to P3 in control AST code.
;
;	X-7	WMC0001		Wayne Cardoza		07-Jan--1987
;		Change some JSBs to BSBWs.
;
;	X-6	SJF		Stu Farnham		10-Dec-1986
;		Fix broken branch.
;
;	X-5	SJF		Stu Farnham		6-Jul-1986
;		Add $CPUDEF
;
;	X-4	SJF		Stu Farnham		1-Jul-1986
;		Use per-CPU IOPOST queue
;
;	X-1A4	RNG4004		Rod Gamache		21-Nov-1985
;		Change raising to DIPL to using device spinlock.
;
;	X-1A3	RNG4003		Rod Gamache		8-Oct-1985
;		Change FIPL's to FLCK's in fork blocks, in preparation
;		for the second SMP baselevel.
;
;	X-1A2	RNG4002		Rod Gamache		05-Sep-1985
;		Add initial SMP support.
;
;	V03-007	MHB0137		Mark Bramhall		12-Apr-1984
;		Define minimum deallocatable block size as FKB$C_LENGTH.
;		Restore stacked register after BADDALRQSZ bug check.
;
;	V03-006	RKS006		RICK SPITZ		2-MAR-1984
;		Make sure that TAST is removed from UCB queue when
;		TAST replaced and currently busy.
;
;	V03-005	DWT0157		David W. Thiel		30-DEC-1983
;		Modify COM$DRVDEALMEM to avoid unnecessary forks.
;
;	V03-004	JLV0272		Jake VanNoy		14-JUN-1983
;		Add abort I/O flag to out of band logic. Also
;		add new entry points for checking PIDs to qualify
;		AST delivery.
;
;	V03-003	RKS0003		RICK SPITZ		23-SEP-1982
;		INSURE THAT TAST IS NOT BUSY WHEN A REPLACE CURRENT
;		BLOCK OPERATION OCCURS. IF SO, FLAG THE CURRENT BLOCK
;		FOR DELETE AND BUILD A NEW BLOCK.
;
;	V03-002	KDM0002		Kathleen D. Morse	28-Jun-1982
;		Added $IODEF and $SSDEF.
;
;
;--
;
; EXTERNAL SYMBOLS
;
	$ACBDEF				; DEFINE AST CONTROL BLOCK
	$CCBDEF				; DEFINE CCB
	$CPUDEF				; DEFINE PER CPU DATA
	$DYNDEF				; DEFINE DYNAMIC MEMORY BLOCKS
	$FKBDEF				; DEFINE FORK BLOCK
	$IODEF				; DEFINE I/O FUNCTION CODES
	$IPLDEF				; DEFINE IPL LEVELS
	$IRPDEF				; DEFINE I/O PACKET
        .IF     NDF,IRP$M_FINIPL8
IRP$M_FINIPL8 = ^X8000000 ;temporary def of new bit
IRP$V_FINIPL8 = 27
        .ENDC
	$PCBDEF				; DEFINE PCB
	$PRDEF				; DEFINE PROCESSOR REGISTERS
	$PRIDEF				; DEFINE NEW PRIORITIES
	$PRVDEF				; DEFINE PRIVELEGE BITS
	$PSLDEF				; DEFINE PSL
	$RSNDEF				; DEFINE RESOURCES
	$SPLCODDEF			; DEFINE SPINLOCK INDICES
	$SSDEF				; DEFINE SYSTEM STATUS CODES
	$TASTDEF			; DEFINE TERMINAL AST BLOCK
	$UCBDEF				; DEFINE UCB

 
	DECLARE_PSECT	EXEC$NONPAGED_CODE

	.PAGE
	.SBTTL	COM$DELATTNAST - DELIVER ATTENTION ASTS
;++
; COM$DELATTNAST  - DELIVER ATTENION ASTS
; COM$DELATTNASTP - DELIVER ATTENION ASTS BY PID
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL AND MAILBOX DRIVERS TO DELIVER 
; ALL OF THE ASTS AWAITING ATTENTION. THE CONTROL BLOCKS ARE USED AS FORK BLOCKS
; TO IPL$_QUEUEAST.
;
; INPUTS:
;
;	R4 = ADDRESS OF LIST HEAD OF AST CONTROL BLOCKS
;	R5 = UCB OF UNIT
;
;	R6 = ACTIVE PID (ONLY AT ENTRY POINT COM$DELATTNASTP)
;
; OUTPUTS:
;
;	R4,R5 ARE PRESERVED.
;--
;COM$DELATTNAST::			; DELIVER ATTENTION ASTS
	UNIVERSAL_JSB	COM$DELATTNAST,-
			INPUT=<R4,R5>, -
			PRESERVE=<R0,R1>

	$COUNT_ENTRY	COM$DELATTNAST	; Debug counting.
	CALL_DELATTNAST	SAVE_R0R1=NO	; Push parms, call the STD routine.
	RSB				; Return to caller.



;COM$DELATTNASTP::			; DELIVER ATTENTION ASTS BY PID
	UNIVERSAL_JSB	COM$DELATTNASTP,-
			INPUT=<R4,R5,R6>,-
			PRESERVE=<R0,R1>

	$COUNT_ENTRY	COM$DELATTNASTP	; Debug counting.
	CALL_DELATTNASTP SAVE_R0R1=NO	; Push parms, call the STD routine.
	RSB				; Return to caller.

	.PAGE
	.SBTTL	COM_STD$DELATTNAST - DELIVER ATTENTION ASTS

;++
; COM_STD$DELATTNAST  - DELIVER ATTENION ASTS
;
; THIS ROUTINE IS USED BY THE TERMINAL AND MAILBOX DRIVERS TO DELIVER ALL OF
; THE ASTS AWAITING ATTENTION. THE CONTROL BLOCKS ARE USED AS FORK BLOCKS TO
; IPL$_QUEUEAST.
;
; CALLING SEQUENCE:
;	COM_STD$DELATTNAST (ASTLIST, UCB)
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_ASTLIST(AP) - AST Control Block list head
;	ARG$_UCB(AP)	 - Unit Control Block (NOT USED!!!)
; OUTPUTS:
;	None
; RETURN STATUS:
;	None
;--

$OFFDEF ARG,< -
	ASTLIST, -
	UCB -
	>

UNIVERSAL_ENTRY COM_STD$DELATTNAST

;COM_STD$DELATTNAST::			; DELIVER ATTENTION ASTS BY PID

	$COUNT_ENTRY COM_STD$DELATTNAST	; Debug counting.

        PUSHL   #0                      ;  PID = 0, by value,
        PUSHL   ARG$_UCB(AP)            ;  Unit Control Block, (NOT USED!!!)
        PUSHL   ARG$_ASTLIST(AP)        ;  AST Control Block list head.
        CALLS   #3,G^COM_STD$DELATTNASTP ; Call the routine.

	RET				; Return to caller.

	.PAGE
	.SBTTL	COM_STD$DELATTNASTP - DELIVER ATTENTION ASTS BY PID
;++
; COM_STD$DELATTNASTP - DELIVER ATTENION ASTS BY PID
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL AND MAILBOX DRIVERS TO DELIVER ALL OF
; THE ASTS AWAITING ATTENTION. THE CONTROL BLOCKS ARE USED AS FORK BLOCKS TO
; IPL$_QUEUEAST.
;
; CALLING SEQUENCE:
;	COM_STD$DELATTNASTP (ASTLIST, UCB, INTPID)
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_ASTLIST(AP) - AST Control Block list head
;	ARG$_UCB(AP)	 - Unit Control Block
;	ARG$_INTPID(AP)  - Process ID (PID) by value 
; OUTPUTS:
;	None
; RETURN VALUE:
;	None
;--

$OFFDEF ARG,< -
	ASTLIST, -
	UCB, -
	INTPID -
	>

UNIVERSAL_ENTRY COM_STD$DELATTNASTP,-
		MASK=<M^<R4,R5,R6,R7>>

;COM_STD$DELATTNASTP::			; DELIVER ATTENTION ASTS BY PID

	$COUNT_ENTRY COM_STD$DELATTNASTP ; Debug counting.
					; Get the inputs from the AP.
	MOVL    ARG$_INTPID(AP),R6	; Get PID from AP.
	MOVL	ARG$_ASTLIST(AP),R7	; Get the AST list head from AP.

	MOVL	ARG$_UCB(AP),R4		; R4 = UCB parameter.
	DEVICELOCK -			; Take device spinlock, raise IPL
		LOCKADDR= UCB$L_DLCK(R4),-
		SAVIPL	= -(SP),-	;   save current IPL
		PRESERVE= NO		;   no need to preserve R0

10$:	MOVL	(R7),R5			; GET NEXT ENTRY
	BEQL	50$			; IF EQL THEN NONE
	TSTL	R6			; CHECKING PIDS?
	BEQL	30$			; NOT IF ZERO
	CMPL	ACB$L_KAST+12(R5),R6	; COMPARE PIDS
	BEQL	30$			; EQUAL, DELIVER AST
	;
	; PIDS NOT EQUAL, SKIP THIS ENTRY AND LEAVE IT IN QUEUE	
	;
	MOVL	R5,R7			; NEXT
	BRB	10$			; LOOP
	;
	; DELIVER AST AND CLOSE UP LIST
	;
30$:	MOVL	(R5),(R7)		; CLOSE LIST

	FORK	-			; CREATE FORK THREAD
		ROUTINE=60$,-		;   fork routine at 60$
		CONTINUE=10$,-
		ENVIRONMENT=CALL	;   EXE_STD$PRIMITIVE_FORK, only R0,R1 scratch

50$:	DEVICEUNLOCK -			; Release device spinlock
		LOCKADDR= UCB$L_DLCK(R4),- ;UCB parameter still in R4
		NEWIPL	= (SP)+,-	;   restore IPL
		CONDITION=RESTORE,-
		PRESERVE= NO		;   no need to preserve R0
	RET     			; Return from COM_STD$DELATTNASTP 

;
; AST QUEUE FORK ROUTINE
;
60$:	FORK_ROUTINE	-
		ENVIRONMENT=CALL,-
		FETCH=NO		; Don't load R3,R4,R5

	MOVL	FORKARG$_FKB(AP),R5	; R5 = FKB parameter (it's an ACB)
	.DSABL	FLAGGING
	MOVQ	ACB$L_KAST(R5),ACB$L_AST(R5); REARRANGE ENTRIES
	.ENABL	FLAGGING
	MOVB	ACB$L_KAST+8(R5),ACB$B_RMOD(R5);
	MOVL	ACB$L_KAST+12(R5),ACB$L_PID(R5);
	CLRL	ACB$L_KAST(R5)		;
	MOVZBL	#PRI$_IOCOM,R2		; SET UP PRIORITY INCREMENT
	.SET_REGISTERS	READ=<R2,R5>,WRITTEN=<R0,R1,R4>
	JSB	G^SCH$QAST		; QUEUE THE AST
	RET				; Return from fork routine

	.PAGE
	.SBTTL	COM$FLUSHATTNS - FLUSH ATTENTION AST LIST
;++
; COM$FLUSHATTNS - FLUSH ATTENTION AST LIST
;
; THIS ROUTINE IS USED BY THE TERMINAL AND MAILBOX DRIVERS TO FLUSH
; AN ATTENTION AST LIST. THIS IS DONE AT CANCEL I/O TIME AND WHEN A
; QIO SPECIFIES A 0 AST ADDRESS ON A SET ATTENTION AST FUNCTION.
; IF THE AST CONTROL BLOCK OWNER IS NO LONGER IN THE SYSTEM THE AST IS ALSO
; FLUSHED.
;
; INPUTS:
;
;	R4 = PCB ADDRESS 
;	R5 = UCB ADDRESS OF RELATED UNIT
;	R6 = CHANNEL NUMBER
;	R7 = LIST HEAD
;
; OUTPUTS:
;
;	R0 = SS$_NORMAL
;	R1 and R7 ARE DESTROYED.
;
;--
;COM$FLUSHATTNS::			; FLUSH ATTENTION AST LIST
	UNIVERSAL_JSB	COM$FLUSHATTNS,-
			INPUT=<R4,R5,R6,R7>,-
			OUTPUT=<R0>

	$COUNT_ENTRY	COM$FLUSHATTNS	; Debug counting.
	CALL_FLUSHATTNS			; Push parms, call the STD routine.
	RSB				; Return to caller.


	.PAGE
	.SBTTL	COM_STD$FLUSHATTNS - FLUSH ATTENTION AST LIST
;++
; COM_STD$FLUSHATTNS - FLUSH ATTENTION AST LIST
;
; THIS ROUTINE IS USED BY THE TERMINAL AND MAILBOX DRIVERS TO FLUSH
; AN ATTENTION AST LIST. THIS IS DONE AT CANCEL I/O TIME AND WHEN A
; QIO SPECIFIES A 0 AST ADDRESS ON A SET ATTENTION AST FUNCTION.
; IF THE AST CONTROL BLOCK OWNER IS NO LONGER IN THE SYSTEM THE AST IS ALSO
; FLUSHED.
;
; CALLING SEQUENCE:
;	Status = COM_STD$FLUSHATTNS (PCB, UCB, CHANNELNUM, ASTLIST) 
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_PCB(AP)     	- Process Control Block
;	ARG$_UCB(AP)		- Unit Control Block
;	ARG$_CHANNELNUM(AP)  	- Channel Number, by value 
;	ARG$_ASTLIST(AP) 	- AST Control Block list head
; OUTPUTS:
;	None
; RETURN VALUE:
;	Status - Standard VMS condition code.
;
$OFFDEF ARG,< -
	PCB, -
	UCB, -
	CHANNELNUM, -
	ASTLIST -
	>
UNIVERSAL_ENTRY COM_STD$FLUSHATTNS, -
		MASK=<M^<R4,R5,R6,R7>>

;COM_STD$FLUSHATTNS::			; FLUSH ATTENTION AST LIST

	$COUNT_ENTRY COM_STD$FLUSHATTNS	; Debug counting.
					; Get the inputs from the AP.
	MOVL    ARG$_PCB(AP),R4		; Get PCB from AP.
	MOVL	ARG$_UCB(AP),R5		; Get UCB from AP.
	MOVL	ARG$_CHANNELNUM(AP),R6	; Get Channel Number from AP.
	MOVL	ARG$_ASTLIST(AP),R7	; Get the AST list head from AP.

	DEVICELOCK -
		LOCKADDR=UCB$L_DLCK(R5),- ; LOCK DEVICE INTERRUPTS
		SAVIPL=-(SP),-		; SAVE CURRENT IPL
		PRESERVE=NO		; We don't need to keep R0!
10$:	MOVL	(R7),R0			; GET LIST ENTRY
	BEQL	50$			; IF EQL THEN DONE
	CMPL	PCB$L_PID(R4),ACB$L_KAST+12(R0); PID MATCH?
	BNEQ	40$			; IF NEQ THEN NO
	CMPW	R6,ACB$L_KAST+10(R0)	; CHANNEL MATCH?
	BNEQ	40$			; IF NEQ THEN NO
	MOVL	(R0),(R7)		; CLOSE UP LIST TO REMOVE ENTRY

	.PRESERVE ATOMICITY
	INCL	PCB$L_ASTCNT(R4)	; RESTORE AST QUOTA
	.NOPRESERVE ATOMICITY
	; COM_STD$DRVDEALMEM (BLOCK(R0))
	CALL_DRVDEALMEM SAVE_R0R1=NO	; CALL TO DEALLOCATE THE BLOCK. 
	BRB	10$			; CONTINUE

40$:	MOVL	R0,R7			; LOOK TO NEXT ENTRY
	BRB	10$			; CONTINUE

50$:	DEVICEUNLOCK -
		LOCKADDR=UCB$L_DLCK(R5),- ; UNLOCK DEVICE INTERRUPTS
		NEWIPL=(SP)+,-		; RESTORE IPL
		CONDITION=RESTORE,-
		PRESERVE=NO

	MOVZBL	#SS$_NORMAL,R0		; SET NORMAL RETURN
	RET				; Return to caller.

	.PAGE
	.SBTTL	COM$POST - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS
;++
; COM$POST - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL, MAILBOX AND DMC DRIVER TO COMPLETE
; I/O OPERATIONS INDEPENDENT OF THE STATUS OF THE UNIT. NO ATTEMPT IS MADE
; TO DE-QUEUE ANOTHER PACKET OR CHANGE THE BUSY STATUS OF THE UNIT.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;	R5 = UCB ADDRESS (COM$POST ONLY)
;
; IMPLICIT INPUTS:
;
;	CALLER AT DRIVER FORK IPL OR GREATER (COM$POST ONLY)
;	IRP$L_MEDIA AND IRP$L_MEDIA+4 ARE THE IOSB QUAD WORD.
;
; OUTPUTS:
;
;	R0 IS DESTROYED.
;--
;COM$POST::				; COMPLETE I/O

	UNIVERSAL_JSB	COM$POST,-
			INPUT=<R3,R5>,-
			PRESERVE=<R1>,-
			SCRATCH=<R0>

	$COUNT_ENTRY	COM$POST	; Debug counting.
	CALL_POST	SAVE_R1=NO	; Push parms, call the STD routine.
	RSB				; Return to caller.
               
	.PAGE
	.SBTTL	COM_STD$POST - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS
;++
; COM_STD$POST - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL, MAILBOX AND DMC DRIVER TO COMPLETE
; I/O OPERATIONS INDEPENDENT OF THE STATUS OF THE UNIT. NO ATTEMPT IS MADE
; TO DE-QUEUE ANOTHER PACKET OR CHANGE THE BUSY STATUS OF THE UNIT.
;
; CALLING SEQUENCE:
;	COM_STD$POST (IRP, UCB) 
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_IRP(AP)     	- I/O Request Packet
;	ARG$_UCB(AP)		- Unit Control Block
; OUTPUTS:
;	None
; RETURN VALUE:
;	None
$OFFDEF ARG,< -
	IRP, -
	UCB -
	>
UNIVERSAL_ENTRY COM_STD$POST, -
		MASK=<M^<R5>>

;COM_STD$POST::				; COMPLETE I/O

	$COUNT_ENTRY	COM_STD$POST	; Debug counting.
					; Get the inputs from the AP.
	MOVL	ARG$_UCB(AP),R5		; Get UCB from AP.
	INCL	UCB$L_OPCNT(R5)		; INCREMENT OPERATION COUNT
					; Push input parameter...
        PUSHL   ARG$_IRP(AP)            ;  I/O Request Packet.
        CALLS   #1,G^COM_STD$POST_NOCNT ; Call the routine.
	RET				; Return to caller.

	.PAGE
	.SBTTL	COM$POST_NOCNT - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS
;++
; COM$POST_NOCNT - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL, MAILBOX AND DMC DRIVER TO COMPLETE
; I/O OPERATIONS INDEPENDENT OF THE STATUS OF THE UNIT. NO ATTEMPT IS MADE
; TO DE-QUEUE ANOTHER PACKET OR CHANGE THE BUSY STATUS OF THE UNIT.
;
; INPUTS:
;
;	R3 = I/O PACKET ADDRESS
;
; IMPLICIT INPUTS:
;
;	CALLER AT DRIVER FORK IPL OR GREATER (COM$POST ONLY)
;	IRP$L_MEDIA AND IRP$L_MEDIA+4 ARE THE IOSB QUAD WORD.
;
; OUTPUTS:
;
;	R0 IS DESTROYED.
;--
;COM$POST_NOCNT::				; COMPLETE I/O

	UNIVERSAL_JSB	COM$POST_NOCNT,-
			INPUT=<R3>,-
			PRESERVE=<R1>,-
			SCRATCH=<R0>

	$COUNT_ENTRY	COM$POST_NOCNT	; Debug counting.
	CALL_POST_NOCNT	SAVE_R1=NO	; Push parm, call the STD routine.
	RSB				; Return to caller.

	.PAGE
	.SBTTL	COM_STD$POST_NOCNT - POST I/O COMPL INDEP OF STAT, DON'T INC OPCNT
;++
; COM_STD$POST_NOCNT - POST I/O COMPLETION INDEPENDENT OF UNIT STATUS, 
;		       DO NOT INCREMENT OPERATIONS COUNT.
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL, MAILBOX AND DMC DRIVER TO COMPLETE
; I/O OPERATIONS INDEPENDENT OF THE STATUS OF THE UNIT. NO ATTEMPT IS MADE
; TO DE-QUEUE ANOTHER PACKET OR CHANGE THE BUSY STATUS OF THE UNIT.  DON'T
; INCREMENT OPERATIONS COUNT IN UCB.
;
; CALLING SEQUENCE:
;	COM_STD$POST_NOCNT (IRP)
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_IRP(AP)     	- I/O Request Packet
; OUTPUTS:
;	None
; RETURN VALUE:
;	None
$OFFDEF ARG,< -
	IRP -
	>
UNIVERSAL_ENTRY COM_STD$POST_NOCNT, -
		MASK=<M^<R3>>		

;COM_STD$POST_NOCNT::			; COMPLETE I/O - DON'T BUMP OPCNT.

	$COUNT_ENTRY COM_STD$POST_NOCNT	; Debug counting.

        MOVL    ARG$_IRP(AP),R3		; Get I/O Request Packet from AP.
	BBS	#IRP$V_FAST_FINISH,-	; If Fast-IO express completion
		IRP$L_STS(R3),86$	;  avoid IPL4 path
	ASSUME	SMP$V_ENABLED  EQ  0
10$:	BLBS	G^SMP$GL_FLAGS,20$	; Br if a multi-processor
	$INSQTI	(R3),G^IOC$GQ_POSTIQ	; INSERT PACKET ON QUEUE
	SOFTINT	S^#IPL$_IOPOST		; REQUEST FORK
	RET				; RETURN

20$:	; This is a multiprocessor, don't allow rescheduling so that
	; we guarantee the SOFTINT will happen on the correct CPU.

	SAVIPL	-(SP)			; Save the current IPL
	CMPB	(SP),S^#IPL$_IOPOST	; Is current IPL high enough?
	BGEQ	40$			; Br if yes, continue
	SETIPL	S^#IPL$_IOPOST,ENVIRON=UNIPROCESSOR ; Else, raise IPL
40$:	$INSQTI	(R3),G^IOC$GQ_POSTIQ	; INSERT PACKET ON QUEUE
	BNEQ	60$			; BRANCH IF QUEUE IS NOT EMPTY
	FIND_CPU_DATA	R0		; GET ADDRESS OF PER-CPU DATA
	CMPL	G^SMP$GL_PRIMID,CPU$L_PHY_CPUID(R0) ; Are we the primary?
	BNEQ	80$			; Br if not primary
	SOFTINT	S^#IPL$_IOPOST		; REQUEST FORK
60$:	ENBINT				; RESTORE IPL
	RET				; RETURN TO CALLER.

80$:	; This is not the primary CPU on an MP

	IPINT_CPU   IOPOST,G^SMP$GL_PRIMID ; Tell the primary to do a softint
	BRB	60$			; Non-optimal case, don't bother

86$:	BBS	#IRP$V_COMPLX,-		; Branch back if complex buffered I/O
		IRP$L_STS(R3),10$

	TSTL	IRP$L_PID(R3)		; Check negative PID
	BGEQ	87$			; If positive, normal treatment
; Third party hook. If FINIPL8 bit is set, call the completion
; routine here. If not, special action, follow normal path.
	BBC	#IRP$V_FINIPL8, - 	; If "FINIPL8" bit is clear treat
		IRP$L_STS(R3),10$	; via IPL 4 route
; The called routine expects the IRP address in R5, so provide it here.
	PUSHL	R5
	PUSHL	R3
	MOVL	R3,R5			; NORMAL ENTRY IS R5=IRP
	CALLS	#1,@IRP$L_PID(R3)	; Call user routine with IRP as arg
	POPL	R5
	RET
87$:
	; Fast finish. Insert the IRP on the IPL8 fork queue with an FPC of
	; the fast-finish routine.

FQH_SIZE=8           			; Assumption required for offsetting
OFFSET8=<8-6>*FQH_SIZE			; Offset of IPL8 fork queue from start
					; of fork queue in Cpu Data Area
	EVAX_MFPR_PRBR			; R0/CPU data area
	CLRB	IRP$B_FLCK(R3)		; No fork IPL
	MOVAB	EXE$FASTIO_FINISH,-	; Routine to execute
		IRP$L_FPC(R3)
	EVAX_STQ R3,IRP$Q_FR3(R3)	; R3 (IRP) for routine
	INSQUE	IRP$L_FQFL(R3),-	; Put the IRP on the queue
		CPU$Q_SWIQFL+OFFSET8(R0)
	.BRANCH_LIKELY

; Unresolved issue: can we really get here at IPL < FIPL ?

	BBC	#IRP$V_HIFORK,-		; Branch if we're at IPL8 right now
		IRP$L_STS(R3),88$	;  (no need to fire up IPL8 forker)
	SOFTINT	S^#IPL$_IOLOCK8		; Else request fork at 8 (rare)
88$:	RET

	.PAGE
	.SBTTL	COM_STD$SETATTNAST - SET UP ATTENTION AST
;++
; COM_STD$SETATTNAST - SET UP ATTENTION AST
;
; FUNCTIONAL DESCRIPTION:
;
; THIS FDT SUPPORT ROUTINE IS USED BY THE TERMINAL AND MAILBOX 
; DRIVERS TO PROCESS REQUESTS FOR ENABLE OR DISABLE OF ATTENTION ASTS.
; THE ADDRESS OF THE AST SERVICE FOR ENABLES IS THE PARAMETER AT AP OFFSET
; ASTLIST. ITS VALUE IS 0 FOR DISABLES.
; FOR DISABLES, THE SPECIFIED LIST IS SEARCHED AND THE ENTRY EXTRACTED AND
; DEALLOCATED.
; FOR ENABLES, A CONTROL BLOCK IS SET UP THAT WILL DOUBLE AS THE AST CONTROL
; BLOCK WHEN THE AST IS DELIVERED. THE BLOCK IS FORMATTED AS FOLLOWS:
;
;	ACB$B_RMOD 	= IPL$_QUEUEAST
;	ACB$L_KAST 	= AST PC
;	ACB$L_KAST+4 	= AST PARAMETER (P2)
;	ACB$L_KAST+8 	= ACCESS MODE OF REQUEST
;	ACB$L_KAST+10 	= CHANNEL NUMBER
;	ACB$L_KAST+12 	= PID OF REQUEST
;
; THE NEW BLOCK IS PLACED AT THE HEAD OF THE CURRENT LIST.
;
; IN BOTH CASES THE I/O IS COMPLETED.
;
; CALLING SEQUENCE:
;	Status = COM_STD$SETATTNAST (IRP, PCB, UCB, CCB, ASTLIST)
; OUTPUTS:
;	None
; RETURN VALUES:
;	SS$_NORMAL
;	SS$_EXQUOTA  -- BUFFERED I/O OR AST QUOTA FAILURE
;	SS$_INSUFMEM -- DYNAMIC MEMORY FAILURE
;	SS$_FDT_COMPL-- FDT PROCCESSING COMPLETE: ERROR.  CALLED $ABORTIO.
;--
; INPUTS:
;
$OFFDEF ARG,<-           ; Define the AP offset of the input parameters.
        IRP,-            ; Offset of IRP parameter.
        PCB,-            ; Offset of PCB parameter.
        UCB,-            ; Offset of UCB parameter.
        CCB,-            ; Offset of CCB parameter.
        ASTLIST-         ; Offset of ASTLIST parameter.
        >

UNIVERSAL_ENTRY COM_STD$SETATTNAST, -
                MASK= <M^<R2,R3,R4,R5,R6,R7,R8>>
;COM_STD$SETATTNAST::                   ; SET UP ATTENTION AST

        MOVL    ARG$_ASTLIST(AP),R7     ; Get the ASTLISTaddress input.
        MOVL    ARG$_UCB(AP),R5         ; Get the UCB address input.
        MOVL    ARG$_PCB(AP),R4         ; Get the PCB address input.
        MOVL    ARG$_IRP(AP),R3         ; Get the IRP address input.

	MOVZWL	IRP$L_CHAN(R3),R6	; GET PACKET CHANNEL NUMBER
	MOVL	IRP$L_QIO_P1(R3),R8	; GET USER AST ADDRESS
	BEQL	10$			; IF EQL THEN DISABLE FUNCTION
;
; REQUEST TO ENABLE AST
;
; SET UP AST BLOCK
;
	MOVZWL	#SS$_EXQUOTA,R0		; ASSUME AST QUOTA EXCEEDED

	.PRESERVE ATOMICITY
	DECL	PCB$L_ASTCNT(R4)	; ADJUST QUOTA
	.NOPRESERVE ATOMICITY

	BLSS	20$			; BR IF NOT ENOUGH
	MOVZBL	#ACB$L_KAST+16,R1	; SET SIZE OF NEEDED BLOCK
	; status = EXE_STD$ALLOCBUF (REQSIZE(R1),-
	;			     ALLOCSIZE(R1), BLOCK(R2))
	CALL_ALLOCBUF			; Call to allocate the buffered block.
	BLBC	R0,20$			; IF LOW SET THEN ALLOCATED
	MOVB	#SPL$C_QUEUEAST,ACB$B_RMOD(R2); INSERT FORK IPL
	MOVL	R8,ACB$L_KAST(R2)	; INSERT AST ROUTINE ADDRESS
	MOVL	IRP$L_QIO_P2(R3),ACB$L_KAST+4(R2)	; INSERT PARAMETER FOR AST
	EXTZV	#0,#2,IRP$L_QIO_P3(R3),R0 ; GET REQUEST ACCESS MODE
	$MAXIMIZE_ACCESS_MODE
	MOVZBL	R0,ACB$L_KAST+8(R2)	; INSERT IN CONTROL BLOCK
	BISB	#ACB$M_QUOTA,ACB$L_KAST+8(R2); INSERT TARGET ACCESS MODE
	MOVW	R6,ACB$L_KAST+10(R2)	; SAVE CHANNEL
	MOVL	PCB$L_PID(R4),ACB$L_KAST+12(R2); INSERT PID ADDRESS OF REQUESTOR
;
; LOCK OUT INTERRUPTS TO ENTER BLOCK ON UCB
;
	DEVICELOCK -
		LOCKADDR=UCB$L_DLCK(R5),- ; LOCK DEVICE INTERRUPTS
		SAVIPL=-(SP),-		; SAVE CURRENT IPL
		PRESERVE=NO		; We don't need to keep R0!
	MOVL	(R7),(R2)		;  MERGE WITH CURRENT ENTRY
	MOVL	R2,(R7)			; INSERT NEW ENTRY VALUE
	DEVICEUNLOCK -
		LOCKADDR=UCB$L_DLCK(R5),- ; UNLOCK DEVICE INTERRUPTS
		NEWIPL=(SP)+,-		; RESTORE IPL
		CONDITION=RESTORE,-
		PRESERVE=NO
	MOVZBL	#SS$_NORMAL,R0		; SET NORMAL RETURN
	RET				; RETURN TO CALLER

10$:	; Status =COM_STD$FLUSHATTNS(PCB(R4),UCB(R5),CHANNELNUM(R6),ASTLIST(R7))
	CALL_FLUSHATTNS			; Call to DISABLE FUNCTION.
	RET				; RETURN TO CALLER WITH STATUS.

20$:	.PRESERVE ATOMICITY
	INCL	PCB$L_ASTCNT(R4)	; RESTORE TAKEN QUOTA
	.NOPRESERVE ATOMICITY
                                        ; R0 contains the final $QIO status...
                                        ;   for input into EXE_STD$ABORTIO.
        CALL_ABORTIO DO_RET=YES		; Abort the I/O and...
                                        ; Ret from FDT Completion Routine with:
                                        ;  1)$QIO status in FDT Context area,
                                        ;  2)IRP$PS_FDT_CONTEXT cleared,
                                        ;  3)SS$_FDT_COMPL in R0.

	.PAGE
	.SBTTL	COM$DELCTRLAST - DELIVER CONTROL ASTS
;++
; COM$DELCTRLAST  - DELIVER CONTROL ASTS
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL  SERVICES TO DELIVER 
; ALL OF THE ASTS AWAITING ATTENTION WHICH MATCH THE CONDITION.
; THE AST BLOCK IS NOT DELETED AND IS REUSED.
;
; INPUTS:
;
;	R3 = MATCH CHARACTER
;	R4 = ADDRESS OF LIST HEAD OF AST CONTROL BLOCKS
;	R5 = UCB OF UNIT
;
; OUTPUTS:
;
;	R3 = (low byte) CHARACTER TO INCLUDE IN DATA STREAM OR NULL
;		TAST$V_ABO - set to signal driver to abort I/O in progress
;	   	TAST$V_INC - set to include this character in datastream
;
;	R0 PRESERVED
;	R1,R4 DESTROYED
;--

	UNIVERSAL_JSB 	COM$DELCTRLAST,-
			INPUT=<R3,R4,R5>,-
			OUTPUT=<R3>,-
			PRESERVE=<R0>,-
			SCRATCH=<R1,R4>
;COM$DELCTRLAST::			; DELIVER CONTROL ASTS

	$COUNT_ENTRY	COM$DELCTRLAST	; Debug counting.
	CALL_DELCTRLAST	-		; Push parm, call the STD routine.
			SAVE_R0=NO	;   (R0 saved via routine preserve list)
	RSB				; Return to caller.

	.PAGE
	.SBTTL	COM_STD$DELCTRLAST - DELIVER CONTROL ASTS
;++
; COM_STD$DELCTRLAST  - DELIVER CONTROL ASTS
;
; THIS ROUTINE IS USED BY THE TERMINAL  SERVICES TO DELIVER 
; ALL OF THE ASTS AWAITING ATTENTION WHICH MATCH THE CONDITION.
; THE AST BLOCK IS NOT DELETED AND IS REUSED.
;
; CALLING SEQUENCE:
;	COM_STD$DELCTRLAST (ASTLIST, UCB, MATCHCHAR, INCLCHAR)
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_ASTLIST(AP) 	- AST Control Block list head
;	ARG$_UCB(AP)		- Unit Control Block
;	ARG$_MATCHCHAR(AP)	- Match character 
; OUTPUTS:
;	ARG$_INCLCHAR(AP)	- Include character
; RETURN VALUE:
;	None
;--

$OFFDEF ARG,< -
	ASTLIST, -
	UCB, -
	MATCHCHAR, - 
	INCLCHAR -
	>

UNIVERSAL_ENTRY COM_STD$DELCTRLAST

;COM_STD$DELCTRLAST::			; DELIVER CONTROL ASTS

	$COUNT_ENTRY COM_STD$DELCTRLAST	; Debug counting.
					; Push input parameters...
	PUSHL   ARG$_INCLCHAR(AP)	;  Addr of include char, output, by ref
	PUSHL   ARG$_MATCHCHAR(AP)	;  Match Character, by value,
        PUSHL   #0                      ;  PID = 0, by value,
        PUSHL   ARG$_UCB(AP)            ;  Unit Control Block
        PUSHL   ARG$_ASTLIST(AP)        ;  AST Control Block list head.
        CALLS   #5,G^COM_STD$DELCTRLASTP ; Call the STD routine.
 	RET				; Return to caller.

	.PAGE
	.SBTTL	COM$DELCTRLASTP - DELIVER CONTROL ASTS AND CHECK PIDS
;++
; COM$DELCTRLASTP - DELIVER CONTROL ASTS AND CHECK PIDS
;
; FUNCTIONAL DESCRIPTION:
;
; THIS ROUTINE IS USED BY THE TERMINAL  SERVICES TO DELIVER 
; ALL OF THE ASTS AWAITING ATTENTION WHICH MATCH THE CONDITION.
; THE AST BLOCK IS NOT DELETED AND IS REUSED.
;
; INPUTS:
;
;	R3 = MATCH CHARACTER
;	R4 = ADDRESS OF LIST HEAD OF AST CONTROL BLOCKS
;	R5 = UCB OF UNIT
;	R6 = ACTIVE PID
;
; OUTPUTS:
;
;	R3 = (low byte) CHARACTER TO INCLUDE IN DATA STREAM OR NULL
;		TAST$V_ABO - set to signal driver to abort I/O in progress
;	   	TAST$V_INC - set to include this character in datastream
;
;	R0 PRESERVED
;	R1,R4 DESTROYED
;--

;COM$DELCTRLASTP::			; DELIVER CONTROL ASTS BY PID
	UNIVERSAL_JSB 	COM$DELCTRLASTP,-
			INPUT=<R3,R4,R5,R6>,-
			OUTPUT=<R3>,-
			PRESERVE=<R0>,-
			SCRATCH=<R1,R4>

	$COUNT_ENTRY	COM$DELCTRLASTP	; Debug counting.
	CALL_DELCTRLASTP -		; Push parms, call the STD routine.
			SAVE_R0=NO	;   (R0 saved via routine preserve list)
	RSB				; Return to caller

	.PAGE
	.SBTTL	COM_STD$DELCTRLASTP - DELIVER CONTROL ASTS AND CHECK PIDS
;++
; COM_STD$DELCTRLASTP - DELIVER CONTROL ASTS AND CHECK PIDS
;
; THIS ROUTINE IS USED BY THE TERMINAL  SERVICES TO DELIVER 
; ALL OF THE ASTS AWAITING ATTENTION WHICH MATCH THE CONDITION.
; THE AST BLOCK IS NOT DELETED AND IS REUSED.
;
; CALLING SEQUENCE:
;	COM_STD$DELCTRLASTP (ASTLIST, UCB, INTPID, MATCHCHAR, INCLCHAR)
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_ASTLIST(AP) 	- AST Control Block list head
;	ARG$_UCB(AP)		- Unit Control Block
;	ARG$_INTPID(AP)		- Process ID (PID) by value
;	ARG$_MATCHCHAR(AP)	- Match character 
; OUTPUTS:
;	ARG$_INCLCHAR(AP)	- Include character
; RETURN VALUE:
;	None
;--

$OFFDEF ARG,< -
	ASTLIST, -
	UCB, -
	INTPID, -
	MATCHCHAR, - 
	INCLCHAR -
	>

UNIVERSAL_ENTRY COM_STD$DELCTRLASTP,-
		MASK=<M^<R2,R3,R4,R5,R6>>

;COM_STD$DELCTRLASTP::			; Deliver control AST by PID

	$COUNT_ENTRY COM_STD$DELCTRLASTP ; Debug counting.

	CLRL	R2			; INIT RETURN CHARACTER
	MOVL	ARG$_MATCHCHAR(AP),R3	; Get Match character.
	MOVL	ARG$_ASTLIST(AP),R4 	; Get AST Control Block list head.
	MOVL	ARG$_INTPID(AP),R6	; Get Process ID (PID) by value.

	MOVL	ARG$_UCB(AP),R5		; R5 = UCB parameter
	DEVICELOCK -			; Take device spinlock, raise IPL
		LOCKADDR= UCB$L_DLCK(R5),-
		SAVIPL	= -(SP),-	;   save current IPL
		PRESERVE= NO		;   no need to save R0

10$:	MOVL	(R4),R4			; ADDRESS FIRST BLOCK
	BEQL	50$			; NO MORE
	SUBL3	#TAST$L_FLINK,R4,R5	; ADDRESS START OF BLOCK
	BBC	R3,TAST$L_MASK(R5),10$	; SKIP IF CHARACTER NOT IN MASK
	;
	; Check PID
	;
	TSTL	R6			; checking pids?
	BEQL	11$			; Branch if not
	CMPL	TAST$L_PID(R5),R6	; compare
	BNEQ	10$			; skip if not equal
11$:
	;
	; This one matches, check include and abort
	;
	BBC	#TAST$V_ABORT,-
		TAST$B_CTRL(R5),12$ 		; BRANCH IF NOT ABORT
	MOVZBL	R3,R2				; FETCH CHARACTER
	BISW	#TAST$M_ABO,R2			; SET ABORT
	BRB	15$				; 
12$:
	BBC	#TAST$V_INCLUDE,-
		TAST$B_CTRL(R5),15$		; SKIP IF STRIP CHARACTER
	MOVZBL	R3,R2				; CHARACTER NOT STRIPPED
	BBSS	#TAST$V_INC,R2,15$		; MARK CHARACTER PRESENT
15$:
	BBSS	#TAST$V_BUSY,-
		TAST$B_CTRL(R5),10$		; SKIP IF IN USE/ MARK IN USE
	MOVZBL	R3,TAST$L_ASTPRM(R5)		; RETURN CHARACTER TO USER
20$:
	MOVB	#SPL$C_QUEUEAST,ACB$B_RMOD(R5)	; INSERT FORK IPL,TO ALLOW USE AS
						; FORK BLOCK
	FORK	-			; CREATE FORK THREAD
		ROUTINE=60$,-		;   fork routine at 60$
		CONTINUE=10$,-
		ENVIRONMENT=CALL	;   EXE_STD$PRIMITIVE_FORK, only R0,R1 scratch
;
50$:	MOVL	ARG$_UCB(AP),R5		; R5 = UCB parameter
	DEVICEUNLOCK -			; Release device spinlock
		LOCKADDR= UCB$L_DLCK(R5),-
		NEWIPL	= (SP)+,-	;   restore IPL
		CONDITION=RESTORE,-
		PRESERVE= NO		;   no need to preserve R0

	MOVL	R2,@ARG$_INCLCHAR(AP)	; Return Include character
	RET				; return from COM_STD$DELCTRLASTP
;
;
; AST QUEUE FORK ROUTINE
;
60$:	FORK_ROUTINE	-
		ENVIRONMENT=CALL,-
		FETCH=NO		; Don't load R3,R4,R5

	MOVL	FORKARG$_FKB(AP),R5	; R5 = FKB parameter (it's a TAST)

	ASSUME	TAST$L_ASTPRM EQ <TAST$L_AST + 4>
	ASSUME	ACB$L_ASTPRM EQ <ACB$L_AST + 4>
	.DSABL	FLAGGING
	MOVQ	TAST$L_AST(R5),ACB$L_AST(R5)	; REARRANGE ENTRIES
	.ENABL	FLAGGING
	BISB	#<ACB$M_NODELETE!ACB$M_PKAST>,-
		TAST$B_RMOD(R5)			; PK AST, NODELETE
	MOVB	TAST$B_RMOD(R5),ACB$B_RMOD(R5)	; MODE
	MOVL	TAST$L_PID(R5),ACB$L_PID(R5)	; PID
	MOVAL	B^ASTACNTNG,ACB$L_KAST(R5) 	; ADDRESS OF PIGGY-BACK KERNEL ROUTINE
	MOVZBL	#PRI$_IOCOM,R2			; SET UP PRIORITY INCREMENT
	.SET_REGISTERS	READ=<R2,R5>,WRITTEN=<R0,R1,R4>
	JSB	G^SCH$QAST			; QUEUE THE AST
	RET				; Return from fork routine
;
;
; PIGGY-BACK KERNEL MODE ROUTINE TO:
;	1. MARK TAST AVAILABLE FOR USE
;	2. DEALLOCATE "LOST" BLOCK(S) AND RETURN THEIR QUOTA
;
ASTACNTNG:
	.JSB_ENTRY	INPUT=<R5>,-
			SCRATCH=<R0>

	BICB	#TAST$M_BUSY, TAST$B_CTRL(R5) ; Mark block available.
	BBC	#TAST$V_LOST, -		; Branch if still using this block.
		TAST$B_CTRL(R5), 150$	; Otherwise,
	MOVZWL	TAST$L_PID(R5), R0	;  use PID index to locate PCB for
	MOVL	@L^SCH$GL_PCBVEC[R0], R0 ; this process.

	.PRESERVE ATOMICITY
	INCL	PCB$L_ASTCNT(R0)	;  Then return AST quota for and
	.NOPRESERVE ATOMICITY

	MOVL	R5,R0			;  deallocate this block.
	JSB	G^EXE$DEANONPAGED
150$:	RSB				; That completes piggy-back accounting.

	.PAGE
	.SBTTL	COM$FLUSHCTRLS - FLUSH CONTROL AST LIST
;++
; COM$FLUSHCTRLS - FLUSH CONTROL AST LIST
;
; THIS ROUTINE IS USED BY THE TERMINAL SERVICES TO FLUSH
; THE CONTROL AST LIST. THIS IS DONE AT CANCEL I/O TIME AND WHEN A
; QIO SPECIFIES A 0 AST ADDRESS ON A SET AST FUNCTION.
; THE SUMMARY MASK POINTED TO BY R2 IS UPDATED.
;
; INPUTS:
;
;	R2 = ADDRESS OF SUMMARY MASK 
;	R4 = PCB ADDRESS 
;	R5 = UCB ADDRESS OF RELATED UNIT
;	R6 = CHANNEL NUMBER
;	R7 = LIST HEAD
;
; OUTPUTS:
;
;	R0 = SS$_NORMAL
;	R1 AND R7 ARE DESTROYED.
;
;--
;COM$FLUSHCTRLS::			; FLUSH CONTROL AST LIST
	UNIVERSAL_JSB 	COM$FLUSHCTRLS,-
			INPUT=<R2,R4,R5,R6,R7>,-
			OUTPUT=<R0>,-
			SCRATCH=<R1,R7>

	$COUNT_ENTRY	COM$FLUSHCTRLS	; Debug counting.
	CALL_FLUSHCTRLS			; Push parm, call the STD routine.
	RSB				; Return to caller.

	.PAGE
	.SBTTL	COM_STD$FLUSHCTRLS - FLUSH CONTROL AST LIST
;++
; COM_STD$FLUSHCTRLS - FLUSH CONTROL AST LIST
;
; THIS ROUTINE IS USED BY THE TERMINAL SERVICES TO FLUSH
; THE CONTROL AST LIST. THIS IS DONE AT CANCEL I/O TIME AND WHEN A
; QIO SPECIFIES A 0 AST ADDRESS ON A SET AST FUNCTION.
; THE SUMMARY MASK POINTED TO BY R2 IS UPDATED.
;
; CALLING SEQUENCE:
;	Status = COM_STD$FLUSHCTRLS (PCB, UCB, CHANNELNUM, ASTLIST, MASK) 
;	NOTE: If calling sequence changes, the MACRO in SYSMAR must be changed.
; INPUTS:
;	ARG$_PCB(AP)     	- Process Control Block
;	ARG$_UCB(AP)		- Unit Control Block
;	ARG$_CHANNELNUM(AP)  	- Channel Number, by value 
;	ARG$_ASTLIST(AP) 	- AST Control Block list head
;	ARG$_MASK(AP)		- Summary mask
; OUTPUTS:
;	None
; REURN VALUE:
;	Status - SS$_NORMAL.
;
$OFFDEF ARG,< -
	PCB, -
	UCB, -
	CHANNELNUM, -
	ASTLIST,-
	MASK -
	>
UNIVERSAL_ENTRY COM_STD$FLUSHCTRLS, -
	MASK=<M^<R2,R4,R5,R6,R7>>

;COM_STD$FLUSHCTRLS::			; FLUSH CONTROL AST LIST

	$COUNT_ENTRY COM_STD$FLUSHCTRLS	; Debug counting.
					; Get the inputs from the AP.
	MOVL    ARG$_PCB(AP),R4		; Get PCB from AP.
	MOVL	ARG$_UCB(AP),R5		; Get UCB from AP.
	MOVL	ARG$_CHANNELNUM(AP),R6	; Get Channel Number from AP.
	MOVL	ARG$_ASTLIST(AP),R7	; Get AST list head from AP.
	MOVL	ARG$_MASK(AP),R2	; Get Summary Mask from AP.

	DEVICELOCK -
		LOCKADDR=UCB$L_DLCK(R5),- ; LOCK DEVICE INTERRUPTS
		SAVIPL=-(SP),-		; SAVE CURRENT IPL
		PRESERVE=NO		; We don't need to keep R0!
	CLRL	R1			; INIT RETURN MASK
5$:	MOVL	(R7),R0			; GET LIST ENTRY
	BEQL	50$			; IF EQL THEN DONE
	SUBL	#TAST$L_FLINK,R0	; COMPUTE START OF BLOCK
	CMPL	PCB$L_PID(R4),TAST$L_PID(R0); PID MATCH?
	BNEQ	40$			; IF NEQ THEN NO
	CMPW	R6,TAST$W_CHAN(R0)	; CHANNEL MATCH?
	BNEQ	40$			; IF NEQ THEN NO
	MOVL	TAST$L_FLINK(R0),(R7)	; CLOSE UP LIST TO REMOVE ENTRY

	BBC	#TAST$V_BUSY,TAST$B_CTRL(R0),20$; BLOCK CAN BE DELETED NOW?
	BISB	#TAST$M_LOST,TAST$B_CTRL(R0) ; NO, FLAG IT FOR LATER DELETION
	BRB	5$			; THAT'S ALL WE CAN DO RIGHT NOW
	
20$:	; COM_STD$DRVDEALMEM (TAST(R0))
	CALL_DRVDEALMEM SAVE_R0R1=YES	; DEALLOCATE THE BLOCK - Save R0 and R1.

	.PRESERVE ATOMICITY
	INCL	PCB$L_ASTCNT(R4)	; RESTORE AST QUOTA
	.NOPRESERVE ATOMICITY

	BRB	5$			; CONTINUE

40$:	BISL	TAST$L_MASK(R0),R1	; OR IN ACTIVE CONTROL CHARACTERS
	MOVAL	TAST$L_FLINK(R0),R7	; LOOK TO NEXT ENTRY
	BRB	5$			; CONTINUE

50$:	MOVL	R1,(R2)			; UPDATE SUMMARY MASK
	DEVICEUNLOCK -
		LOCKADDR=UCB$L_DLCK(R5),- ; UNLOCK DEVICE INTERRUPTS
		NEWIPL=(SP)+,-		; RESTORE IPL
		CONDITION=RESTORE,-
		PRESERVE=NO
	MOVZBL	#SS$_NORMAL,R0		; SET NORMAL RETURN
	RET				; Return to caller.

	.PAGE
	.SBTTL	COM_STD$SETCTRLAST - SET UP CONTROL AST
;++
; COM_STD$SETCTRLAST - SET UP CONTROL AST
;
; FUNCTIONAL DESCRIPTION:
;
; This routine is used by the terminal services FDT routines during the 
; processing of requests to enable out-of-band ASTs.  The current list is 
; scanned for a block with a requestor matching that of the request being 
; processed.  If a match is found, the specified mask and AST routine address 
; in the matching block are replaced.  If no match is found, COM$BLDCTRLAST is 
; called to create a new block.  The summary mask pointed is updated to be the 
; "inclusive or" of all masks in the control AST list.
;
; If either the AST routine address or the out-of-band enable mask is zero, 
; all out-of-band AST requests entered by this requestor are flushed from 
; AST queue.
;
; CALLING SEQUENCE:
;	Status = COM_STD$SETCTRLAST (IRP, PCB, UCB, ASTLIST, MASK, TAST)
; OUTPUTS:
;
;	R0 = STATUS OF THE I/O
;	     SS$_NORMAL    if successful,
;	     SS$_FDT_COMPL if error (via EXE$ABORTIO)
;	R2 = ADDRESS OF TAST BLOCK
;
;	IPL at exit is the same as IPL at entry.
;
;	The summary mask pointed is updated to be the "inclusive or" of 
;	all masks in the control AST list.
;
;	The control AST list is flushed, extended, or an 
;	entry in the list is updated.
;
; COMPLETION CODES:
;
;	SS$_NORMAL	if successful
;	SS$_FDT_COMPL	if not successful (Called $ABORTIO)
;
;     The following final $QIO system service codes are returned by EXE$ABORTIO:
;	SS$_ACCVIO   -- specified mask not accessable
;	SS$_EXQUOTA  -- buffered I/O or AST quota failure
;	SS$_INSUFMEM -- dynamic memory failure
;--
;
; COM_STD$SETCTRLAST, COM$BLDCTRLAST, and COM$FILLCTRLAST build and use the 
; following information block. COM_STD$SETCTRLAST builds the block on the stack 
; and points R11 to it.  COM$BLDCTRLAST and COM$FILLCTRLAST use infomation 
; stored to build or update a TAST control block.

	$OFFSET	0,POSITIVE,<-
		ASTROUT,-		; User's AST routine address
	   	ASTPARM,-		; AST routine parameter
		USRMSK,-		; User's OOB mask
		CURMSKADR,-		; Pointer to current summary mask
		SAVED_P3,-		; Saved P3 parameter
		<TINFOSIZE,0>-		; Size of the block
		>
;
; INPUTS:
;
$OFFDEF ARG,<-           ; Define the AP offset of the input parameters.
        IRP,-            ; Offset of IRP parameter.
        PCB,-            ; Offset of PCB parameter.
        UCB,-            ; Offset of UCB parameter.
        ASTLIST,-        ; Offset of ASTLIST parameter.
	MASK,- 		 ; Offset of summary mask parameter.
	TAST-		 ; Offset of TAST block - OUTPUT.
        >
;
;	IRP$L_QIO_P1 	= ADDRESS OF AST ROUTINE TO CALL WHEN OUT-OF-BAND 
;			  CHARATER IS TYPED (0 ==> FLUSH QUEUE)
;	IRP$L_QIO_P2 	= ADDRESS OF SHORT FORM TERMINATOR MASK GIVING WHICH 
;			  OUT-OF-BAND CHARACTERS WILL PRECIPATATE DELIVERY OF 
;			  AN AST.
;		 	  (0 MASK VALUE==>FLUSH QUEUE: This addr will be passed
;			   as the AST parameter when the AST is delivered)
;	IRP$L_QIO_P3 	= ACCESS MODE IN WHICH THE AST IS TO BE DELIVERED
;		 	  (This is maximized against the caller's access mode)
;
;	IPL at entry is assumed to be IPL$_ASTDEL.

UNIVERSAL_ENTRY COM_STD$SETCTRLAST, -
                MASK= <M^<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>>

;COM_STD$SETCTRLAST::                   ; SET UP CONTROL AST

        MOVL    ARG$_ASTLIST(AP),R7     ; Get the ASTLIST address input.
        MOVL    ARG$_UCB(AP),R5         ; Get the UCB address input.
        MOVL    ARG$_PCB(AP),R4         ; Get the PCB address input.
        MOVL    ARG$_IRP(AP),R3         ; Get the IRP address input.

	MOVZWL	IRP$L_CHAN(R3),R6	; Get packet channel number
	MOVL	IRP$L_QIO_P1(R3),R8	; Get user AST address
	BEQL	10$			; No AST then flush TAST for this channel
	MOVL	IRP$L_QIO_P2(R3),R9	; Get address of Out-of-Band Mask 
	MOVZWL	#SS$_ACCVIO,R0		; Assume no access
	IFNORD	#8,(R9),20$		; Probe for read access
	MOVZWL	#SS$_BADPARAM,R0	; Assume invalid mask format
	TSTL	(R9)			; Verify short form terminator
	BNEQ	30$			; Not short form abort request
	TSTL	4(R9)			; Any characters specified
	BNEQ	30$			; If characters specified continue
					;  otherwise 
10$: ;R0=COM_STD$FLUSHCTRLS(PCB(R4),UCB(R5),CHANNELNUM(R6),ASTLIST(R7),MASK(R2))
	CALL_FLUSHCTRLS			; Flush Out-of-Band request
	RET				; Return to caller with R0 = SS$_NORMAL.

20$:	                                ; R0 contains the final status input...
                                        ;   for input into EXE_STD$ABORTIO.
        CALL_ABORTIO DO_RET=YES		; Abort the I/O and...
                                        ; Ret from FDT Completion Routine with:
                                        ;  1)$QIO status in FDT Context area,
                                        ;  2)IRP$PS_FDT_CONTEXT cleared,
                                        ;  3)SS$_FDT_COMPL in R0.
;
; Now have a valid request for an enable Out-of-Band character AST.
; 
; Now for the big change from older versions of this code.  Always 
; allocate a TAST block.  This allows to keep the device lock, instead of 
; releasing it and potentially allowing the TAST list to change.  In the 
; hopefully rare cases where a block is reused the allocated block will be 
; returned to pool.
;
30$:	MOVZWL	#TAST$C_LENGTH,R1	; Set size for TAST block
	; Status = EXE_STD$ALLOCBUF (REQSIZE(R1),-
	;			     ALLOCSIZE(R1), BLOCK(R2))
	CALL_ALLOCBUF			; Call Allocate buffer
	MOVL	R2,R10			; Save block address
        MOVL    ARG$_MASK(AP),R2        ; Get the summary mask address input.
	BLBC	R0,20$			; If unable to allocate abort I/O request
	SUBL	#TINFOSIZE,SP   	; Allocate information block on the stack
	MOVL	SP,R11			; Save the information block address
	MOVL	R8,ASTROUT(R11)		; Save AST routine address.
	MOVL	R9,ASTPARM(R11)
	MOVL	4(R9),USRMSK(R11)	; Save user's Out-of-Band mask
	MOVL	R2,CURMSKADR(R11)	; Save current summary mask address
	CLRQ	R8			; Clear summary mask and status register
	MOVL	IRP$L_QIO_P3(R3),SAVED_P3(R11)	; Save access mode on stack

;
; At this point these registers are redefined
;
;	R8	-	Current summary Out-of-Band mask
;	R9	-	Status of search, 1 means reused block
;	R10	-	Address of pre-allocated block
;

	DEVICELOCK	-		; Take device lock to prevent TAST list
		LOCKADDR=UCB$L_DLCK(R5),- ;from changing
		SAVIPL=-(SP),-		; Save current IPL
		PRESERVE=NO		; Wipe out R0
40$:	MOVL	(R7),R2		    	; Get list entry
	BEQL	70$			; If no more entries exit search
	MOVAB	-TAST$L_FLINK(R2),R2	; Compute starting address of block
	CMPL	PCB$L_PID(R4),TAST$L_PID(R2) ; Do PIDs match?
	BNEQ	60$			; No match then update mask and get another block
	CMPW	R6,TAST$W_CHAN(R2)	; Do channels match
	BNEQ	60$			; No match then update mask and get another block
;
; If block is not busy then delete allocated TAST block and update this one.  If
; it is busy mark it as lost and use allocated block and end scan of TAST list.
;
	BBC	#TAST$V_BUSY,TAST$B_CTRL(R2),50$ ; Is block busy
	BISB	#TAST$M_LOST,TAST$B_CTRL(R2) 	; Mark block for later deletion
	MOVL	TAST$L_FLINK(R2),(R7)	; Remove entry from list
	BRB	70$			; End search want to insert here not
					;  end of list
50$:	MOVB	#1,R9			; Indicate reusing block
	MOVL	R10,R0			; Get address of block to deallocate
	; COM_STD$DRVDEALMEM (BLOCK(R0))
	CALL_DRVDEALMEM SAVE_R0R1=NO	; Call to free allocated block.
	.SET_REGISTERS READ=<R2,R3,R4,R6,R11>,WRITTEN=<R0,R1>
	BSBB	COM$FILLCTRLAST		; Update block
	MOVL	R2,R10			; Save address of updated block

60$:	BISL	TAST$L_MASK(R2),R8	; Accumulate running Out-of-Band mask
	MOVAL	TAST$L_FLINK(R2),R7	; Point to next queue entry
	BRB	40$			; Start search again

70$:	MOVL	R8,@CURMSKADR(R11)	; Update saved summary mask
	BLBS	R9,90$			; If reused block then exit

	.PRESERVE ATOMICITY
	DECL	PCB$L_ASTCNT(R4)	; Charge for this AST block
	.NOPRESERVE ATOMICITY

	BLSS	80$			; Used up all quota?
	MOVL	R10,R2			; Enough quota so use allocated block
	.SET_REGISTERS READ=<R2,R3,R4,R6,R11>,WRITTEN=<R0,R1>
	BSBB	COM$FILLCTRLAST		; Fill AST block
	MOVL	(R7),TAST$L_FLINK(R2)	; Fill pointer to next block
	MOVAL	TAST$L_FLINK(R2),(R7)	; Point previous entry at new entry
	BISL	TAST$L_MASK(R2),@CURMSKADR(R11) ; Updated saved summary mask
	MOVZWL	#SS$_NORMAL,R0		; Setup success status
	BRB	100$			; Take success exit path

80$:	.PRESERVE ATOMICITY
	INCL	PCB$L_ASTCNT(R4)	; Restore AST quota
	.NOPRESERVE ATOMICITY

	MOVL	R10,R0			; Get address of block to deallocate
	; COM_STD$DRVDEALMEM (BLOCK(R0))
	CALL_DRVDEALMEM SAVE_R0R1=NO	; Call to dealocate block.
	MOVZWL	#SS$_EXQUOTA,R0		; Set error reason
	BRB	100$			; Release lock almost done

90$:	MOVL	R10,@ARG$_TAST(AP)	; Return address of TAST.
	MOVZWL	#SS$_NORMAL,R0		; Setup success status
100$:	DEVICEUNLOCK -			; Release the lock conditionally
	LOCKADDR=UCB$L_DLCK(R5),-	;
	NEWIPL=(SP)+,-			; Restore IPL
	CONDITION=RESTORE		;
	ADDL	#TINFOSIZE,SP		; Restore stack
	BLBC	R0,110$			; Error? YES- Abort the I/O request,
	RET				; NO - Return to caller with success.

110$:	                                ; R0 contains the final $QIO status...
                                        ;   for input into EXE_STD$ABORTIO.
        CALL_ABORTIO DO_RET=YES		; Abort the I/O and...
                                        ; Ret from FDT Completion Routine with:
                                        ;  1)$QIO status in FDT Context area,
                                        ;  2)IRP$PS_FDT_CONTEXT cleared,
                                        ;  3)SS$_FDT_COMPL in R0.

	.PAGE
	.SBTTL	COM$FILLCTRLAST - FILLIN A CONTROL AST CONTROL BLOCK
;++
; COM$FILLCTRLAST - FILLIN A CONTROL AST CONTROL BLOCK
;
; FUNCTIONAL DESCRIPTION:
;
; This routine fills in the terminal AST control block pointed to by R2.  The 
; block may be either a previously allocated block which is already linked to 
; a control AST queue, or a newly allocated block which is being filled in for 
; the first time.
;
; INPUTS:
;
;	R2 = ADDRESS OF TAST CONTROL BLOCK TO BE FILLED IN
;	R3 = I/O PACKET ADDRESS
;	R4 = CURRENT PCB
;	R6 = CHANNEL ON WHICH OOB AST REQUEST IS BEING MADE
;	R11= THE ADDRESS OF A TAST INFORMATION LIST (SEE COM$SETCTRLAST)
;
;	P3 = ACCESS MODE IN WHICH THE AST IS TO BE DELIVERED
;		 (This is maximized against the caller's access mode)
;
;	ASTROUT(R11)  = ADDRESS OF AST ROUTINE TO CALL WHEN OUT-OF-BAND
;			CHARACTER IS TYPED
;	ASTPARM(R11)  = AST PARAMETER VALUE TO BE PASSED TO AST ROUTINE WHEN
;			OUT-OF-BAND AST IS DELIVERED
;	USRMSK(R11)   = OUT-OF-BAND MASK SPECIFIED BY USER FOR
;			THIS AST ENABLE
;
;	If this routine is called to operate on a TAST block which is already 
;	linked to a control queue, it should be called at device IPL.  
;	Otherwise, it can be called at IPL$_ASTDEL.
;
; OUTPUTS:
;
;	R0 & R1 ARE DESTROYED.
;	ALL OTHER REGISTERS ARE PRESERVED.
;
;	IPL at exit is the same as IPL at entry.
;
;	The TAST control block pointed to by R2 is filled in.
;
; COMPLETION CODES:
;
;	There is no completion status.  This routine is always successful.
;--

COM$FILLCTRLAST:
	.JSB_ENTRY  	INPUT=<R2,R3,R4,R6,R11>,-
			SCRATCH=<R0,R1>

	ASSUME	TAST$L_ASTPRM EQ <TAST$L_AST + 4>
	ASSUME	ASTPARM EQ <ASTROUT + 4>
	.DSABL	FLAGGING
	MOVQ	ASTROUT(R11), -		; Plant AST routine and
		TAST$L_AST(R2) 		; parameter addresses.
	.ENABL	FLAGGING
	MOVL	USRMSK(R11), -
		TAST$L_MASK(R2) 	; Plant OOB mask.
	CLRL	R0			; Assume no flags
	;
	; Check for ABORT
	;
	BBC	#IO$V_TT_ABORT, -
		IRP$L_FUNC(R3),5$	; Branch if not abort
	BISB	#TAST$M_ABORT,R0	; Else set abort flag.
	BRB	10$			; Ignore INCLUDE
	;
	; Check for INCLUDE
	;
5$:	BBC	#IO$V_INCLUDE, -
		IRP$L_FUNC(R3), 10$ 	; BR if striping OOB chars. 
	BISB	#TAST$M_INCLUDE,R0	; Else set no-strip flag.

10$:	MOVB	R0,TAST$B_CTRL(R2)	; Set TAST control field.
	EXTZV	#0, #2,SAVED_P3(R11),R0	; Get requested delivery access mode.
	MOVPSL	R1			; Get access mode of requestor.
	EXTZV	#PSL$V_PRVMOD, #PSL$S_PRVMOD, R1, R1 ; If requestor's access
	CMPB	R0, R1			; mode is bigger than delivery access
	BGEQ	20$			; mode, then delivery AST in
	MOVB	R1, R0			; requestor's access mode.
20$:	MOVB	R0, TAST$B_RMOD(R2)	; Plant delivery access mode.
	MOVW	R6, TAST$W_CHAN(R2)	; Plant requestor's channel.
	MOVL	PCB$L_PID(R4), TAST$L_PID(R2) ; Plant requestor's PID.
	RSB				; Return to caller.

	.END
