From:	AITGW::"kenney@star.enet.dec.com" "Forrest A. Kenney 14-Jan-1992 1510" 14-JAN-1992 15:21:47.50
To:	arisia::everhart
CC:	
Subj:	This is the driver build stuff, and souce code

Received: by AITGW.DECnet (utk-mail11 v1.5) ; Tue, 14 Jan 92 15:19:59 EST
Received: from enet-gw.pa.dec.com by aitgw.ge.com (5.65/GE Gateway 1.4)
	id AA23916; Tue, 14 Jan 92 15:19:33 -0500
Received: by enet-gw.pa.dec.com; id AA02443; Tue, 14 Jan 92 12:16:09 -0800
Message-Id: <9201142016.AA02443@enet-gw.pa.dec.com>
Received: from star.enet; by decwrl.enet; Tue, 14 Jan 92 12:16:13 PST
Date: Tue, 14 Jan 92 12:16:13 PST
From: Forrest A. Kenney  14-Jan-1992 1510 <kenney@star.enet.dec.com>
To: arisia::everhart
Apparently-To: everhart@arisia.dnet.ge.com
Subject: This is the driver build stuff, and souce code
 
Glenn,
 
	The driver will not build a couple of itemlist codes have been added
since it was written, updating it should only take a couple of minutes.
 
 
Forrest

$ DEFINE	pt$lib	user$disk:[titan.code]
$ in_lib*rary	== "library/replace/macro/nosqueeze pt$lib:ptlib"

$ ! ===========================================================================
$ !++
$ !
$ !
$ ! ASMPTDRIVER.COM	Compile the PT PSEUDO device driver
$ !
$ !           Copyright (C) 1985, Digital Equipment Corporation and
$ !			U. S. Government
$ !
$ !	Forrest A. Kenney	- Digital Software Services -  28-MAY-1985
$ !
$ !
$ !	Version 1.2			VAX/VMS DCL 4.0
$ !
$ !	Revisions to version:
$ !		1.2-001	F.A.K	03-Jan-1986
$ !		   	Removed building of custom PTDRIVER messages as
$ !			they are no longer used.
$ !
$ !--
$ ! ===========================================================================
$ !
$ !	Compile the driver
$ !
$	ON WARNING THEN goto my_exit
$	ON ERROR THEN goto my_exit
$ !
$ log = f$logical("PT$LIB")
$ if "''log'" .eqs. "" then goto error_1
$ !+
$ ! This block is for our verison only
$ !
$ copy	 [.titan2]ptdriver_tables.mar	ptdriver.mar
$ append [.titan2]pt_unitinit.mar	ptdriver.mar
$ append [.titan3]pt_cloneducb.mar	ptdriver.mar
$ append [.titan2]pt_getio.mar		ptdriver.mar
$ append [.titan2]pt_write.mar		ptdriver.mar
$ append [.titan3]pt_read.mar		ptdriver.mar
$ append [.titan3]pt_finishio.mar	ptdriver.mar
$ append [.titan2]pt_set.mar		ptdriver.mar
$ append [.titan2]pt_sense.mar		ptdriver.mar
$ append [.titan2]pt_queueast.mar	ptdriver.mar
$ append [.titan3]pt_setattn.mar	ptdriver.mar
$ append [.titan3]pt_cancel.mar		ptdriver.mar
$ append [.titan2]pt_post_msg.mar	ptdriver.mar
$ append [.titan3]pt_bldrqs.mar		ptdriver.mar
$ append [.titan2]pt_end.mar		ptdriver.mar
$ !
$ !-
$ !
$ ! Compile the driver
$ !                                     
$ write sys$output "Compiling the driver....."
$ !
$  	MACRO/LIST	PT$LIB:PTDRIVER
$ !
$ ! Compile PT_CREATE
$ !
$ write sys$output "Compiling PT_CREATE....."
$ !
$ 	MACRO/LIST	PT$LIB:PT_CREATE
$ !
$ ! Put code in library
$ !
$	LIBRARY/REPLACE		PT$LIB:PT$LIBRARY.OLB	PT$LIB:PT_CREATE
$ !
$	goto my_exit
$ !
$ my_exit:
$ !
$ !	Clean up
$ !
$  	PURGE	pt$lib:pt*.*
$	DELETE	pt$lib:pt_create.obj.
$ EXIT
$ !
$ error_1:
$ !
$	type sys$input:
 
	The logical name PT$LIB must be defined before running this 
command procedure!!!"
 
$ EXIT

$ ! ===========================================================================
$ !++
$ !
$ !
$ ! LNKPTDRIVER.COM	Link the PT PSEUDO device driver
$ !
$ !           Copyright (C) 1985, Digital Equipment Corporation and
$ !			U. S. Government
$ !
$ !	Forrest A. Kenney 	- Digital Software Services -  28-MAY-1985
$ !
$ !
$ !	Version 1.2			VAX/VMS DCL 4.0
$ !
$ !	Revisions to version:
$ !		X.X     X.X.X.	XX-XXX-XXXX
$ !			WHAT THE CHANGES DID 
$ !
$ !
$ !--
$ ! ===========================================================================
$ !
$ !
$ log = f$logical("PT$LIB")
$ if "''log'" .eqs. "" then goto err1
$ !
$	OPEN/READ/ERROR=ERR2	FILE2	PT$LIB:PT$LIBRARY.OLB
$	CLOSE	FILE2
$	OPEN/READ/ERROR=ERR3	FILE3	SYS$SYSTEM:SYS.STB
$	CLOSE	FILE3
$ !
$ !	Link the driver
$ !
$ LINK/MAP/FULL/NOTRACE 				-
			PT$LIB:PTDRIVER,		-
			PT$LIB:PT$LIBRARY/LIBRARY,	-
			SYS$SYSTEM:SYS.STB/SELECTIVE,	-
			SYS$INPUT:/OPTIONS
BASE=0    
$ !
$ !	Clean up
$ !
$	PURGE PT*.*
$ EXIT
$ !
$ ERR1:
$	TYPE SYS$INPUT:
 
	The logical name PT$LIB must be defined before running this 
command procedure!!!"
 
$ EXIT	
$ !
$ ERR2:
$	TYPE SYS$INPUT:
 
	Unable to open the file PT$LIBRARY.OLB make sure that
this file has been built. 
 
$ EXIT
$ !
$ ERR3:
$	TYPE SYS$INPUT:
 
	Unable to open the file SYS$SYSTEM:SYS.STB make sure that 
this file has been built.
 
$ EXIT

$ ! ===========================================================================
$ !++
$ !
$ !
$ ! INSPTDRIVER.COM		Load and start up the PSEUDO terminal device 
$ !			driver.
$ !
$ !           Copyright (C) 1985, Digital Equipment Corporation and
$ !			Titan Systems
$ !
$ !	Forrest A. Kenney	- Digital Software Services -  28-MAY-1985
$ !
$ !
$ !	Version 1.2-001			VAX/VMS DCL 4.0
$ !
$ !	Revisions to version:
$ !		1.1-001	FAK	16-AUG-85
$ !		Changed device name from PTA0 to PTY0 this should prevent
$ !		conflicts with multiple DSA disk controllers on a machine.
$ !
$ !--
$ ! ===========================================================================
$ !
$ !
$ ON ERROR THEN EXIT
$ !
$ log = f$logical("PT$LIB")
$ if "''log'" .eqs. "" then goto error_1
$ !
$ if .not. f$privileges("CMKRNL") then goto error_2
$ !
$ ASSIGN	SYS$INPUT:	SYS$COMMAND:
$ MCR SYSGEN
LOAD	PT$LIB:PTDRIVER
CONNECT PTY0/NOADAPTER/DRIVER=PTDRIVER
SHOW/DEVICE=PTDRIVER
EXIT
$ SHOW DEVICE PTY0/FULL
$ !
$ EXIT
$ !
$ ERROR_1:
$	TYPE SYS$INPUT:
 
	The logical name PT$LIB must be defined before running this 
command procedure!!!"
 
$ EXIT	
$ !
$ error_2:
$ 	TYPE SYS$INPUT:
 
	You must have change mode to kernel privilege to install the driver.
 
$ EXIT

	.TITLE	PTDRIVER - VAX/VMS PSEUDO TERMINAL DRIVER
 	.IDENT	'V1.2-003'
	.ENABLE SUPPRESSION
	.LIBRARY \SYS$LIBRARY:LIB.MLB\
	.LIBRARY \PT$LIB:PTLIB.MLB\
; =============================================================================
;++
;
;
; PTDRIVER 		Pseudo Terminal driver, this driver allows one
;		program to talk to the driver as though it is the VMS
;		terminal class driver and another process to receive those
;		requests and complete them.
;         
;
;           Copyright (C) 1985, Digital Equipment Corporation and
;			Titan Systems
;
;       Howard  F. Clifford	- Digital Software Services -  27-May-1985
;	Forrest A. Kenney 
;
;
;	Version 1.1-001		VAX-11 MACRO 
;
;	Revisions to version:
;
;		1.1-001	HFC		16-AUG-85
;			Added support for TTYREADALL, TTYREADPALL AND READPBLK.
;
;		1.1-002 FAK & HFC	16-AUG-1985
;			Add support to allow subprocess of the application
;			process to use the same PT.  Some of the changes needed
;			to allow this are listed below:
;
;				1) Add support for IO$M_TT_PROCESS set modifier
;				2) Modify cloned UCB to get SYS$ASSIGN to
;				   call it back upon completion so that
;				   UCB$L_PID can be set to zero
;				3) Make the device no longer shared.
;				4) Change AST deliver code to deliver by
;				   PID and use UCB$L_TL_CTLPID as the PID
;				5) Add code to deliver CTRL/Y ASTs with reason
;				   of SS$_HANGUP if device hung up.
;
;		1.2-001	FAK		03-Jan-1986
;			Changed driver to use VMS status returns with adjusted
;			severity levels instead of PT specific status messages.
;			This will alter the format of the IOSB to be the
;			normal VMS format.
;
;				+------------+-------------+
;				| Byte count | Final Satus |
;				+------------+-------------+
;                               |   Device Specific Data   |
;  				+------------+-------------+
;
;		1.2-002	FAK		03-Jan-1986
;			Modify driver so that if creator uses IO$_READVBLK
;			creator is dispatched to PT_GETIO, and if creator uses 
;			IO$_WRITEVBLK is dispatched to PT_FINISHIO.
;
;		1.2-003 FAK		13-Jan-1986
;			Modify PT_CANCEL to check for UCB$W_REFC being 0
;			if 0 then store UCB$L_PT_SM_PID in UCB$L_PID.  This
;			will insure that the creators JIB$L_BYTLM and
;			JIB$L_BYTCNT get returned when device finally goes
;			away if creator still exists.
;
;--
; ==============================================================================

;+
; The following symbols are used to enable or disable printing of module
; headers and XDELTA debugging support.  If the symbol is commented out
; then the action will not be taken.
;
;
;	SUPPRESS_HEADER = 0			; Print module headers switch
;	PT_UNITINIT_D = 0			; Debug unit init. routine
;	PT_CLONEDUCB_D = 0			; Debug cloned UCB routine
;	PT_GETIO_D = 0				; Debug GET I/O function
;	PT_WRITE_D = 0				; Debug write function
;    	PT_READ_D = 0				; Debug read function
;	PT_ITEM_READ_D = 0			; Debug read itemlist code
;	PT_NORMAL_READ_D = 0			; Debug read normal code
;	PT_FINISHIO_D = 0			; Debug FINISH I/O function
;	PT_SET_D = 0				; Debug set function
;	PT_SENSE_D = 0				; Debug sense function
;	PT_QUEUEAST_D = 0			; Debug QUEUE AST function
;	PT_SETATTN_D = 0			; Debug Set attention function
;	PT_CANCEL_D = 0				; Debug cancel I/O code
;	PT_POST_MSG_D = 0			; Debug post message code
; 	PT_BUILD_REQUEST_D = 0			; Debug build request code
;
;-

	.SBTTL	External and local symbol definitions
 
;+
; External symbols
;-
 
	$ACBDEF				; AST control block
	$AQBDEF				; ACP Queue block
	$CANDEF				; Cancel reason codes
	$CCBDEF				; Channel control block
	$CRBDEF				; Channel request block
	$DCDEF				; Device classes and types
	$DDBDEF				; Device data block
	$DEVDEF				; Device characteristics
	$DYNDEF				; Data structure types
	$IDBDEF				; Interrupt data block
	$IODEF				; I/O function codes
	$IPLDEF				; Hardware IPL definitions
	$IRPDEF				; I/O request packet
	$JIBDEF				; Job information block
	$MSGDEF				; Mailbox message types
	$ORBDEF				; Object right block offsets
	$PCBDEF				; Process control block
	$PRDEF				; Processor register
	$PRVDEF				; Privilege bits
	$PSLDEF				; Processor ststus longword
	$SFDEF				; Call frame symbols
	$SSDEF				; System status codes
	$TRMDEF				; Item list definitions
	$TASTDEF			; Terminal AST definitions
	$TTDEF				; Terminal definitions
	$TT2DEF				; More definitions
	$TTYDEF				; Terminal driver definitions
	$TTYUCBDEF			; Terminal driver UCB offsets & 
					;   constants
	$UCBDEF				; Unit control block
	$VCBDEF				; Volume control block
	$VECDEF				; Interrupt vector block
 
	PT_CUST_MSG			; Modify Standard VMS error codes
					;   to have severity level we desire
	PT_MISC_DEF			; Define miscellaneous constants
	PT_IODEF			; Define our special function codes
	PT_RBFDEF			; Request buffer fixed definition
 
 
;+
; Argument list (AP) offsets for device-dependent QIO parameters
;-
 
P1	= 0				; First QIO parameter
P2	= 4				; Second QIO parameter
P3	= 8				; Third QIO parameter
P4	= 12				; Fourth QIO parameter
P5	= 16				; Fifth QIO parameter
P6	= 20				; Sixth QIO parameter
 
 
;+
; Definitions that follow the standard UCB fields
;-
 
	PT_UCBEXT			; UCB extension
 

	.SBTTL	Standard tables
 
;+
; Driver prologue table
;-
 
 
	DPTAB	-				; DPT-creation macro
		END=PT_END,		-	; End of driver label
		ADAPTER=NULL,		-	; No adapter
		UCBSIZE=UCB$K_PT_LEN,	-	; Length of UCB
		NAME=PTDRIVER			; Driver name
 
	DPT_STORE INIT				; Start of load
						; initialization table
	DPT_STORE UCB,UCB$B_FIPL,B,PT_FIPL	; Device fork IPL
	DPT_STORE UCB,UCB$B_DIPL,B,PT_FIPL	; Device interrupt IPL
	DPT_STORE UCB,UCB$L_DEVCHAR,L,<	-	; Device characteristics
		DEV$M_REC!		-	;  record device
		DEV$M_AVL!		-	;  available
		DEV$M_IDV!		-	;  input device
		DEV$M_ODV!		-	;  output device
		DEV$M_TRM!		-	;  terminal device
		DEV$M_CCL>			;  carriage control device
	DPT_STORE UCB,UCB$L_DEVCHAR2,L,<-	; Device characteristics
		DEV$M_NNM>			;  prefix with "node$"
	DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_TERM	; Terminal device
	DPT_STORE UCB,UCB$B_DEVTYPE,B,TT$_VT100	; VT100 terminal
	DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,-	; Default buffer size
		PT_BUFF_SIZE
	DPT_STORE UCB,UCB$L_DEVDEPEND,L,-	; Default characteristics
		PT_DEVDEPEND
	DPT_STORE UCB,UCB$L_DEVDEPND2,L,-	; Default characteristics
		PT_DEVDEPEND2
	DPT_STORE ORB,ORB$B_FLAGS,B,	-	; Protection block flags
		<ORB$M_PROT_16!ORB$M_NOACL>
	DPT_STORE ORB,ORB$W_PROT,W,0		; Default protection
						;  let everybody at it
	DPT_STORE ORB,ORB$L_OWNER,@L,	-	; Set system to owner UIC
		TTY$GL_OWNUIC
 
	DPT_STORE UCB,UCB$W_STS,W,	-	; Make this a template UCB
		UCB$M_TEMPLATE
 
	DPT_STORE REINIT			; Start of reload 
						;  initialization table
	DPT_STORE DDB,DDB$L_DDT,D,PT$DDT	; Address of DDT
 
	DPT_STORE END				; End of initialization
						;  tables
 
 
;+
; Driver dispatch table
;-
 
	DDTAB	-				; DDT-creation macro
		DEVNAM=PT,		-	; Name of device
		FUNCTB=PT_FUNCTABLE,	-	; FDT address
		CANCEL=PT_CANCEL,	-	; Cancel I/O routine
		UNITINIT=PT_UNITINIT,	-	; Unit initialization routine
       		CLONEDUCB=PT_CLONEDUCB		; Address of cloned UCB routine
;+
; Function decision table
;-                   
 
PT_FUNCTABLE:					; FDT for driver
	FUNCTAB	,-				; Valid I/O functions
		<GETIO,	-			; Get terminal request
		WRITEVBLK,	-		; Write virtual block
		WRITELBLK,	-		; Write logical block
		WRITEPBLK,	-		; Write physical block
		READVBLK,	-		; Read virtual block
		READLBLK,	-		; Read logical block
		READPBLK,	-		; Read physical block
		READPROMPT,	-		; Read with prompt
		TTYREADALL,	-		; Read without interpretation
   		TTYREADPALL,	-		; No interpretation with prompt
		FINISHIO,	-		; Finish terminal request
		SETMODE,	-		; Set device mode
		SETCHAR,	-		; Set device characteristics
		SENSEMODE,	-		; Sense device mode
		SENSECHAR,	-		; Sense device characteristics
		QUEUEAST,	-		; Queue AST character
		SETATTN>			; Setup up attention AST 
 
	FUNCTAB	,-				; Buffered functions
		<GETIO,	-			; Get terminal request
		WRITEVBLK,	-		; Write virtual block
		WRITELBLK,	-		; Write logical block
		WRITEPBLK,	-		; Write physical block
		READVBLK,	-		; Read virtual block
		READLBLK,	-		; Read logical block
		READPBLK,	-		; Read physical block
		READPROMPT,	-		; Read with prompt
		TTYREADALL,	-		; Read without interpretation
   		TTYREADPALL,	-		; No interpretation with prompt
		FINISHIO,	-		; Finish terminal request
		SETMODE,	-		; Set device mode
		SETCHAR,	-		; Set device characteristics
		SENSEMODE,	-		; Sense device mode
		SENSECHAR,	-		; Sense device characteristics
   		QUEUEAST,	-		; Queue AST character
		SETATTN>			; Setup up attention AST 
 
	FUNCTAB	PT_GETIO,	-		; FDT routine for get I/O
		<GETIO> 
	FUNCTAB	PT_WRITE,	-		; FDT routine for
		<WRITEVBLK,	-		;  write virtual block
		WRITELBLK,	-		;  write logical block
		WRITEPBLK>			;  write physical block
	FUNCTAB	PT_READ,	-		; FDT routine for
		<READVBLK,	-		;  read virtual block
		READLBLK,	-		;  read locigal block
		READPBLK,	-		;  read physical block
		TTYREADALL,	-		;  read without interpretation
		TTYREADPALL,	-		;  no interpretation with prompt
		READPROMPT>			;  read with prompt
   	FUNCTAB	PT_FINISHIO,	-		; FDT routine for finish I/O
		<FINISHIO> 
	FUNCTAB	PT_SET,		-		; FDT routine for
		<SETCHAR,	-		;  set characterisitcs
		SETMODE>			;  set mode
	FUNCTAB	PT_SENSE,	-		; FDT routine for
		<SENSECHAR,	-		;  sense characteristics
		SENSEMODE>			;  sense mode 
   	FUNCTAB	PT_QUEUEAST,	-		; FDT routine for queue AST
		<QUEUEAST> 
	FUNCTAB	PT_SETATTN,	-		; FDT routine for set attention
		<SETATTN>

	.SBTTL	PT_UNITINIT, Initialize the template UCB
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_UNITINIT	Initialize the template UCB
;
;	Description:
;		Set UCB status and characteristics bits intialize the PT
;	defined UCB extension queue headers.  This routine also initializes
;	the terminal driver UCB fields that the PT uses.
;
;	Execution requirements:
;
;		This routine is entered via a JSB from the sysgen utility.
;
;	Inputs:
;
;		R3	- address of the the primary CSR
;		R4	- address of the secondary CSR, if it exists if
;			    not the address of CSR
;		R5	- address of the UCB (unit control block)
;
;	Outputs:
;
;		UCB	- The driver specific UCB fields are initialized.
;
;	The routine must preserve all registers except R0-R2.
;
;	Data structures:
;
;		None
;
;	External references:
;
;		None
;
;
;	Special notes:
;
;		None
;
;--
;+
;	Module Algorithm:
;	   BEGIN
;
;		fill in the TTDRIVER UCB extensions we use
;		initialize the PT drivers queue headers
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_UNITINIT:
	PT_DEBUG PT_UNITINIT_D			; Macro to enable/disable
						;   XDELTA debugging support
	PUSHR	#^M<R1,R2,R3,R4,R5>		; save for dirty MOVC5
 
	MOVC5	#0,#0,#0,		      -	; zero out the UCB extensions
		#<UCB$K_PT_LEN-UCB$K_LENGTH>, -
		UCB$K_LENGTH(R5)
 
	POPR	#^M<R1,R2,R3,R4,R5>		; restore pointers
 
	ASSUME	UCB$L_TT_LOGUCB GT 	-	; make sure our
		UCB$L_TL_PHYUCB			; UCB extension includes both
						;  UCB$L_TL_PHYUCB and
						;  UCB$L_TL_LOGUCB
 
	MOVL	R5,UCB$L_TL_PHYUCB(R5)		; not a redirected terminal
	MOVL	R5,UCB$L_TT_LOGUCB(R5)
 
;+
; initialize queue headers, and UCB extensions
;-
	MOVB	#TT$C_BAUD_9600,UCB$B_PT_XMIT_SPEED(R5)
 
	MOVAL	UCB$L_PT_APP_IOQFL(R5),UCB$L_PT_APP_IOQFL(R5)
	MOVAL	UCB$L_PT_APP_IOQFL(R5),UCB$L_PT_APP_IOQBL(R5)
 
	MOVAL	UCB$L_PT_APP_BRK_IOQFL(R5),UCB$L_PT_APP_BRK_IOQFL(R5)
	MOVAL	UCB$L_PT_APP_BRK_IOQFL(R5),UCB$L_PT_APP_BRK_IOQBL(R5)
 
	MOVAL	UCB$L_PT_SM_IOQFL(R5),UCB$L_PT_SM_IOQFL(R5)
	MOVAL	UCB$L_PT_SM_IOQFL(R5),UCB$L_PT_SM_IOQBL(R5)
 
	RSB					; All done go home

	.SBTTL	PT_CLONEDUCB, Initialize newly created UCB
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_CLONEDUCB	Initialize newly created UCB.
;
;	Description:
;		Set UCB status and characteristics bits, set UCB PID and
;	initialize the PT defined UCB extension fields.
;
;	Execution requirements:
;
;	Inputs:
;
;		R2	- address of cloned UCB
;		R3	- address of the DDT
;		R4	- address of the PCB (process control block)
;		R5	- address of the template UCB (unit control block)
;
;	Outputs:
;
;		UCB	- fields UCB$L_DEVCHAR, UCB$L_STS, UCB$L_PID
;			   and PT defined UCB extensions
;		R0	- SS$_NORMAL cloning succeeded
;             		- ^SS$_NORMAL cloning is vetoed by this routine
;
;	The routine must preserve all registers except R0.
;
;	Data structures:
;		None
;
;	External references:
;		None
;
;	Special notes:
;		This routine is JSBed to from $ASSIGN only and only on
;		an assign to the template UCB. This assign causes a UCB
;		to be cloned and a channel to be assigned to the cloned
;		UCB.
;
;		A trick is played on $ASSIGN. $ASSIGN sets the owner PID
;		of the cloned UCB after the call to this routine. We want to
;		have the owner PID clear. So, we change the saved PC in 
;		$ASSIGNs call frame to be an address in this routine. When
;		$ASSIGN does a RET it returns to the address in this routine.
;		This routine clears the owner PID and returns to the place
;		$ASSIGN normally returns to.
;--
;+
;	Module Algorithm:
;	   BEGIN
;		set all UCB extension fields to zero
;		set the VMS terminal driver UCB extension fields PHYUCB and
;		 LOGUCB to point to the cloned UCB
;		set the cloned device's SM PID to the PID of the caller to
;		 $ASSIGN
;		set the UCB xmit speed to 9600 baud
;		initialize UCB queue data elements to an empty queue
;		save call frame PC and AP
;		set call frame AP to the address of the cloned UCB
;		set call frame PC to the address of the routine CALL_BACK
;		RETURN to $ASSIGN
;	   END
;	   BEGIN routine CALL_BACK when $ASSIGN tries to return to its caller
;		restore saved call frame PC and AP
;		clear the UCB owner PID
;		RETURN to caller of $ASSIGN
;	   END
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_CLONEDUCB:					; init cloned UCB
	PT_DEBUG PT_CLONEDUCB_D			; Macro to enable/disable
						;   XDELTA debugging support
	PUSHR	#^M<R1,R2,R3,R4,R5>		; save for dirty MOVC5
 
	MOVC5	#0,#0,#0,		      -	; zero out the UCB extensions
		#<UCB$K_PT_LEN-UCB$K_LENGTH>, -
		UCB$K_LENGTH(R2)
 
	POPR	#^M<R1,R2,R3,R4,R5>		; restore pointers
 
	ASSUME UCB$L_TT_LOGUCB GT UCB$Q_TL_BRKTHRU
	ASSUME UCB$L_TT_LOGUCB GT UCB$L_TL_PHYUCB ; make sure our
						; UCB extension includes
						;  UCB$L_TL_PHYUCB and
						;  UCB$L_TL_LOGUCB and
						;  UCB$Q_TL_BRKTHRU
 
	MOVL	R2,UCB$L_TL_PHYUCB(R2)		; not a redirected terminal
	MOVL	R2,UCB$L_TT_LOGUCB(R2)
;+
; initialize queue headers, and UCB extensions
;-
	MOVL	PCB$L_PID(R4),UCB$L_PT_SM_PID(R2)	; set the creator PID
 
	MOVB	#TT$C_BAUD_9600,UCB$B_PT_XMIT_SPEED(R2)
 
	MOVAL	UCB$L_PT_APP_IOQFL(R2),UCB$L_PT_APP_IOQFL(R2)
	MOVAL	UCB$L_PT_APP_IOQFL(R2),UCB$L_PT_APP_IOQBL(R2)
 
	MOVAL	UCB$L_PT_APP_BRK_IOQFL(R2),UCB$L_PT_APP_BRK_IOQFL(R2)
	MOVAL	UCB$L_PT_APP_BRK_IOQFL(R2),UCB$L_PT_APP_BRK_IOQBL(R2)
 
	MOVAL	UCB$L_PT_SM_IOQFL(R2),UCB$L_PT_SM_IOQFL(R2)
	MOVAL	UCB$L_PT_SM_IOQFL(R2),UCB$L_PT_SM_IOQBL(R2)
 
	MOVL	#SS$_NORMAL,R0				; don't veto the clone
;+
; Here's where we play a trick with $ASSIGN.
;   When $ASSIGN does a RET, have it return to the routine CALL_BACK.
;-
	MOVL	SF$L_SAVE_PC(FP)	-	; save the return address
		,UCB$L_TL_CTRLY(R2)
 
	MOVL	SF$L_SAVE_AP(FP)	-	; save the return AP
		,UCB$L_TL_CTRLC(R2)
 
	MOVAL	CALL_BACK,SF$L_SAVE_PC(FP)	; move in our return address
	MOVL	R2,SF$L_SAVE_AP(FP)		; have AP point to the UCB
 
	RSB					; go back to $ASSIGN
;+
; Routine which is returned to when $ASSIGN executes a RET instruction.
; INPUTS:
;	AP - address of the UCB
;-
 
CALL_BACK:
	PUSHL	AP
	CALLS	#1,10$				; create a dummy call frame
 
;	We don't return here from CALLS, we return to caller of $ASSIGN
 
10$:	.WORD	^M<R2>
 
	MOVL	4(AP),R2			; R2 -> cloned UCB
;+
; Make things so that we can return to the caller of $ASSIGN.
;-
	MOVL	UCB$L_TL_CTRLY(R2)	-	; return to where $ASSIGN
		,SF$L_SAVE_PC(FP)		; should have returned to
 
	MOVL	UCB$L_TL_CTRLC(R2)	-	; restore saved AP
		,SF$L_SAVE_AP(FP)
 
	CLRL	UCB$L_TL_CTRLY(R2)		; keep these guys clear
	CLRL	UCB$L_TL_CTRLC(R2)
;+
; Now we can do the work all this nonsense bought us.
;-
	CLRL	UCB$L_PID(R2)			; clear the owner PID
 
	RET					; return to caller of $ASSIGN

	.SBTTL	PT_GETIO, Processes a get I/O request
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC                                                                          
; =============================================================================
;++
;
;	PT_GETIO	Process a get I/O request
;
;	Description:
;		Processes a Screen Managers IO$_GETIO request.  This request
;	is used to read an applications I/O request for the Screen Manager
;	to process.  The actual delivery of a applications request is performed
;	by the PT_POST_MSG routine.
;
;	Execution requirements:
;		$QIOW 	func = IO$_GETIO
;			chan = SCREEN_MANGERS_CHANNEL
;			iosb = GETIO_IOSB
;			p1   = GETIO_BUFFER_ADDRESS
;			p2   = GETIO_BUFFER_SIZE
;
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;		P1(AP)	- Addess of users buffer
;		P2(AP)	- Size of users buffer in bytes
;
;	Outputs:
;
;		UCB	The following fields in the UCB will be changed:
;
;			UCB$L_PT_SM_IOQFL
;			UCB$L_PT_SM_IOQBL
;
;	The routine must preserve R3 - R8.
;
;	Data structures:
;               Non
;
;	External references:
;
;      List all extrnal references:
;
;		EXE$ABORTIO	- Aborts an I/O operation
;		EXE$INSERTIRP	- Insert IRP into specified I/O queue
;		EXE$QIORETURN	- Returns from FDT routine with success
;		EXE$READCHK	- Checks users buffer for write access
;		PT_BUILD_REQUEST- Allocate a request buffer and fill in fixed
;				    information
;		PT_POST_MSG	- Check and post pending requests to 
;				    Screen Manager
;
;	Special notes:
;
;		Use PT_BUILD_REQUEST to build system buffer.  The reqest
;	buffer segments will be filled in this will not cause a problem
;	as the post operation will overwrite this information.
;
;--
;+
;	Module Algorithm:
;	   BEGIN
;
;          IF requestor's PID and device owner PID match THEN
;
;             check the user's buffer for write access via EXE$READCHK
;             build and link buffer via PT_BUILD_REQUEST 
;
;             IF buffer build ok THEN 
;                queue IRP to UCB via EXE$INSERTIRP
;                see if pending operation via PT_POST_MSG
;             ELSE
;               abort function via EXE$ABORTIO
;             ENDIF
;
;          ELSE
;             save return status SS$_ILLIOFUNC and abort function 
;               via EXE$ABORTIO
;          ENDIF
;
;          return to user via EXE$QIORETURN   
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_GETIO:
	PT_DEBUG PT_GETIO_D			; Macro to enable/disable
						;   XDELTA debugging support
 	CMPL	IRP$L_PID(R3),		-	; Are we the device owner?
		UCB$L_PT_SM_PID(R5)		;
	BEQL	10$				;
	MOVL	#SS$_ILLIOFUNC,R0		; Store error reason
	BRW	30$				; Not owner branch to abort code
10$:	MOVL	P1(AP),R0			; Get buffer address
	MOVL	P2(AP),R1			; Get buffer size
	JSB	G^EXE$READCHK			; Verify write access to buffer
   						;   (automatic transfer to 
						;    EXE$ABORTIO in no write)
						; NOTE: also fills in 
						;       IRP$W_BCNT & IRP$V_FUNC
	CMPL	#RBF_K_LEN_FIXED,R1		; Users buffer large enough?
	BLSS	20$				;
	MOVL	#RBF_K_LEN_FIXED,R1		; User buffer to small increase
						;   size
20$:	JSB	PT_BUILD_REQUEST		; Call build request to
						;   allocate buffer.
	BLBC	R0,30$				; LBC error branch to abort
						;   routine
	MOVAB	UCB$L_PT_SM_IOQFL(R5),R2	; Get queue list head address
						;   for EXE$INSETRIRP
	DSBINT	UCB$B_DIPL(R5)			; Disable interrupts
	JSB	G^EXE$INSERTIRP			; Insert request in queue
	ENBINT					; Allow interrupts
	JSB	PT_POST_MSG			; See it applications request
						;   to post
	JMP	G^EXE$QIORETURN			; All done exit QIO call
 
;+
; Error path out for all errors
;-
30$:	JMP	G^EXE$ABORTIO			; Abort QIO call

	.SBTTL	PT_WRITE, Support VMS terminal driver write function
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_WRITE	Support VMS terminal driver write function
;
;	Description:
;		Process an applications terminal write request.  This routine
;	prepares and queues a write request to be delivered by PT_POST_MSG.
;	This routine will prepare a dummy IOSB to be returned to the user.
;	The IOSB that is returned assumes that the Screen Manager actually 
;	completed the request successfully.
;
;	Execution requirements:
;		$QIOW 	func = IO$_WRITEXXXX
;			chan = WRITE_CHAN
;			iosb = WRITE_IOSB
;			p1   = WRITE_BUFFER_ADDRESS
;			p2   = WRITE_BUFFER_SIZE
;			p3   = WRITE_CARRIAGE_CONTROL
;
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;		P1(AP)	- Address of users buffer
;		P2(AP)	- Size of users buffer in bytes
;		P4(AP)	- Carriage control to be applied to this request
;
;	Outputs:
;
;		IRP	The following fields in the IRP will be changed:
;
;			IRP$W_BOFF
;			IRP$L_SVAPTE
;			IRP$L_BCNT
;			IRP$L_IOST1
;
;		UCB	The following fields in the UCB may/will be changed:
;
;			UCB$L_PT_APP_IOQFL
;			UCB$L_PT_APP_IOQBL
;			UCB$L_PT_APP_BRK_IOQFL
;			UCB$L_PT_APP_BRK_IOQBL
;
;	The routine must preserve R3 - R8. 
;
;	Data structures:
;               RBF 	- All request buffer fields needed to describe a 
;			  write request are filled in.
;
;	External references:
;
;		EXE$ABORTIO	- Aborts an I/O operation
;		EXE$INSERTIRP	- Insert IRP into specified I/O queue
;		EXE$QIORETURN	- Returns from an FDT routine with success
;		EXE$WRITECHK	- Check users buffer for read access
;		PT_BUILD_REQUEST- Allocate a request buffer and fill in fixed
;				    information
;		PT_POST_MSG	- Check and post pending request to 
;				    Screen Manager
;	Special notes:
;
;		None
;
;--
;+
;	Module Algorithm:
;	   BEGIN
;                                                                 
;          IF requestors PID does not equal the creators PID THEN
;
;             IF buffer length is non-zero THEN
;                check buffer read access via EXE$WRITECHK
;             ENDIF
;
;             allocate and fill in a request buffer via PT_BUILD_REQUEST
;
;             IF got buffer THEN
;                clear mailbox enable modifier
;                fill request buffer
;                queue request buffer to application I/O queue 
;                  via EXE$INSERTIRP
;                attempt to deliver request to Screen Manager 
;                  via PT_POST_MSG
;             ELSE
;                save error return status and exit via EXE$ABORTIO
;             ENDIF
;
;          ELSE
;             branch to PT_FINISHIO
;          ENDIF
;
;          exit via EXE$QIORETURN
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC            
PT_WRITE:
	PT_DEBUG PT_WRITE_D			; Macro to enable/disable
						;   XDELTA debugging support
	CMPL	IRP$L_PID(R3),		-	; Is requestor the device 
	   	UCB$L_PT_SM_PID(R5)		;   creator?
	BNEQ	10$				; OK to allow this request
 	BRW    	PT_FINISHIO			; Creators write is the same as 
						;   IO$_FINISHIO function
                   
10$:	MOVL	P1(AP),R0			; Get users buffer address
	MOVZWL	P2(AP),R1			; Get users buffer size
	BEQL	20$				; Zero length don't check 
     	JSB	G^EXE$WRITECHK			; Verify readability of buffer
   						;   (automatic transfer to 
						;    EXE$ABORTIO if no read)
						; NOTE: also fills in
						;       IRP$W_BCNT 
20$:	ADDL2	#RBF_K_WRITE_FIXED,R1		; Compute size of 
						;   required system buffer
	JSB	PT_BUILD_REQUEST		; Allocate & fill in fixed
						;   part of request buffer
  	BLBC	R0,40$				; 
 
;+
; All checks ok so lets really set up request and post it
;-
	BISW2	#IRP$M_TERMIO,IRP$W_STS(R3)	; Set terminal I/O bit for
						;   computing priority
						;   increment on I/O completion
	BICL2	#IO$M_ENABLMBX,		-	; Turn off mailbox enable
		RBF_L_FUNC_CODE(R2)		;
	MOVZWL	P2(AP),R1			; Get users buffer size
	ADDL3	#<RBF_K_WRITE_FIXED-RBF$K_SYS_SIZE>,-	; Fill in actual size of
		R1,RBF_L_SIZE(R2)			;   request buffer 
	MOVL	P2(AP),RBF_L_WRITELEN(R2)	; Fill in number of bytes to 
				     		;   write
    	MOVL	P4(AP),RBF_L_CARCON(R2)		; Fill in carriage control data
	PUSHR	#^M<R3,R4,R5>			; MOVC3 uses R0 - R5
	MOVC3	R1,@P1(AP),		-	; Fill in request buffer
		RBF_K_WRITE_FIXED(R2)		;
	POPR	#^M<R3,R4,R5>			; 
	MOVW	#SS$_NORMAL,IRP$L_IOST1(R3)	; Fill in IOSB status field
	CVTLW	P2(AP),IRP$L_IOST1+2(R3)	; Fill in IOSB length field
	CLRL	IRP$L_IOST2(R3)			; Clear rest of IOSB
	MOVAB	UCB$L_PT_APP_IOQFL(R5),R2	; Assume normal write queue
	BBC	#IO$V_BREAKTHRU,	-	; Use break through write
		IRP$W_FUNC(R3),30$		;   queue?
	MOVAB	UCB$L_PT_APP_BRK_IOQFL(R5),R2	; Break through write queue
30$:	DSBINT	UCB$B_DIPL(R5)			; Disable interrupts
	JSB	G^EXE$INSERTIRP			; Insert request in queue
	ENBINT					; Allow interrupts
	JSB	PT_POST_MSG			; See if Screen Managers
						;   request to post
	JMP	G^EXE$QIORETURN			; All done exit QIO call
 
;+
; Common error path 
;-
40$:	JMP	G^EXE$ABORTIO			; Abort QIO call

	.SBTTL	PT_READ,  Emulate terminal read
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;	PT_READ		Emulate terminal read
;
;	Description:
;		When an application issues a read request, PTDRIVER verifies
;	that the request is valid and formats a buffer describing the request.
;	The formatted buffer is passed to the Screen Manager when the Screen
;	Manager issues a Get I/O request. Appendix A lists the format of the
;	buffers. All documented VMS terminal read functions are accepted. See
;	the VAX/VMS I/O User's Reference Manual for the format of the terminal
;	I/O requests.
;
;	Execution requirements:
;		$QIO(W)	efn    = event flag number      (optional)
;			func   = IO$_ READxBLK or READPROMPT, READALL, READPALL
;			chan   = I/O channel number
;			iosb   = I/O status block       (optional)
;			ast    = address of AST routine (optional)
;			astprm = AST parameter          (optional)
;
;	Non-Item List Reads
;		P1(AP)	- Address of buffer to receive read data.
;		P2(AP)	- Size of buffer to receive read data.
;		P3(AP)	- Timeout count (seconds) for read with timeout.
;		P4(AP)	- Address of read terminator descriptor block.
;		P5(AP)	- Address of prompt buffer (READPROMPT, READPALL only).
;		P6(AP)	- Size of prompt buffer (READPROMPT, READPALL only).
;
;	Item List Reads
;		P1(AP)	- Address of buffer to receive read data.
;		P2(AP)	- Size of buffer to receive read data.
;		P3(AP)	- Access mode at which the Item List is probed.
;		P4(AP)	- Ignored.
;		P5(AP)	- Address of the Item List buffer.
;		P6(AP)	- Size of the Item List in bytes.
;
;	Inputs:
;		R0-R2	- Scratch registers.
;		R3	- Address of the IRP (I/O request packet).
;		R4	- Address of the PCB (process control block).
;		R5	- Address of the UCB (unit control block).
;		R6	- Address of the CCB (channel control block).
;		R7	- Bit number of the I/O function code.
;		R8	- Address of the FDT table entry for this routine.
;		R9-R11	- Scratch registers.
;		AP	- Pointer to QIO device independent parameters.
;
;	Outputs:
;		Request Buffer is built and queued for Screen Manager.
;
;	The routine preserves registers R3-R8
;
;	Data structures:
;		RBF		- read function specific general Request Buffer
;
;	External references:
;
;		EXE$ABORTIO	-	abort the I/O request
;		EXE$BUFFRQUOTA	-	verify requestor has
;		EXE$INSERTIRP	-	queue IRP to UCB in priority order
;		EXE$MAXACMODE	-	maximize the P3 access mode with
;		EXE$PROBER	-	verify read access to the Item List
;		EXE$QIORETURN	-	return from FDT routine with success
;		EXE$READCHK	-	verify requestor has write access to
;					 a buffer
;		EXE$WRITECHK	-	verify requestor has read access to
;					 a buffer
;		PT_BUILD_REQUEST -	allocate a request buffer and fill in
;					 the function independent fields.
;		PT_ITEM_READ	-	build Item List request buffer
;		PT_NORMAL_READ	-	build non-Item List request buffer
;		PT_POST_MSG	-	check and post pending requests to 
;					 Screen Manager
;	Special notes:
;--
;+
; Module Algorithm for : PT_READ
;
;	BEGIN PT_READ
;
;	IF requestor's PID != UCB's creator's PID match THEN
;	   IF size of read request is greater than 0 THEN
;		CALL EXE$READCHK to verify requestor has write access
;		 to the read buffer, if no access EXE$READCHK aborts
;		 the request with reason SS$_ACCVIO.
;	   END IF
;	   IF this request is an Item List read THEN
;		CALL PT_ITEM_READ to build Item List request buffer
;	   ELSE
;		CALL PT_NORMAL_READ to build a non-Item List request
;		 buffer
;	   END IF
;	   CALL EXE$INSERTIRP to queue the IRP to the UCB application's
;	    I/O queue
;	   CALL PT_POST_MSG to attempt to deliver request to Screen Manager
;	ELSE
;	   BRANCH TO PT_GETIO
;	END IF
;	CALL EXE$QIORETURN to return to QIO
;
;	END PT_READ
;
; Module Algorithm for : PT_NORMAL_READ
;
;	BEGIN PT_NORMAL_READ
;
;	IF a prompt string is specified THEN
;	   CALL EXE$WRITECHK to verify requestor has read access
;	    to the prompt string, if no access EXE$WRITECHK aborts
;	    the request with reason SS$_ACCVIO.
;	END IF
;	IF a terminator descriptor is specified THEN
;	   CALL EXE$WRITECHK to verify requestor has read access
;	    to the descriptor, if no access EXE$WRITECHK aborts
;	    the request with reason SS$_ACCVIO.
;	   IF the terminator mask is the long form THEN
;		CALL EXE$WRITECHK to verify requestor has read access
;		 to the mask, if no access EXE$WRITECHK aborts
;		 the request with reason SS$_ACCVIO.
;	   END IF
;	END IF
;	calculate the size of the request buffer as follows:
;
;	  size  =   size of prompt string
;		  + size of terminator mask
;		  + 4 longwords for the read function buffer overhead
;		  + 4 longwords for the function independent buffer
;		       overhead
;		  + 3 longwords for the system buffered I/O overhead
;
;	CALL PT_BUILD_REQUEST to allocate a buffer which is the larger of
;	 the size of the request buffer and the amount to be read, and
;	 fill in the function independent fields.
;	IF error returned THEN
;	   CALL EXE$ABORTIO to abort the read request returning to caller
;	END IF
;	Fill in the following read function fields in the request buffer.
;
;	   FIELD 			VALUE OBTAINED FROM
;	 size of read request	  P2 argument
;	 timeout value		  P3 argument
;	 terminator mask size	  0 if not specified, 4 if short form
;				   or from descriptor
;	 terminator mask	  none if not specified, or from descriptor
;	 size of prompt string	  P6 argument
;	 prompt string		  P5 argument
;
;	RETURN
;
;	END PT_NORMAL_READ
;
; Module Algorithm for : PT_ITEM_READ
;
;	BEGIN PT_ITEM_READ
;
;	CALL EXE$MAXACMODE to maximize the P3 access mode with
;	 the mode of the requestor
;	CALL EXE$PROBER to verify read access to the Item List
;	IF requestor does not have read access THEN
;	   CALL EXE$ABORTIO to abort this request with reason
;	    SS$_ACCVIO
;	END IF
;	IF the Item List size is not a multiple of 12 THEN
;	   CALL EXE$ABORTIO to abort this request with reason
;	    SS$_BADPARAM
;	END IF
;	set temporary variable SAVE_LEN to 0
;	DO FOR each of the Item List descriptors in the Item List
;	   IF the code is one of:   TRM$_TERM  (long form only)
;				    TRM$_PROMPT
;				    TRM$_INISTRNG
;				    TRM$_PICSTRNG
;				    TRM$_ALTECHSTR
;	   THEN
;		CALL EXE$PROBER to verify read access to the buffer
;		 pointed to by the Item List descriptor
;		IF no read access THEN
;		   CALL EXE$ABORTIO to abort the request with reason
;		    SS$_ACCVIO
;		END IF
;		add the buffer length value to the temporary variable SAVE_LEN
;	   END IF
;	END DO
;	calculate the size of the request buffer as follows:
;
;	  size  =   SAVE_LEN
;		  + length of the Item List
;		  + 2 longwords for the read function buffer overhead
;		  + 4 longwords for the function independent buffer
;		       overhead
;		  + 3 longwords for the system buffered I/O overhead
;
;	CALL PT_BUILD_REQUEST to allocate a buffer which is the larger of
;	 the size of the request buffer and the amount to be
;	 read, and fill in the function independent fields.
;	IF error returned THEN
;	   CALL EXE$ABORTIO to abort the read request returning to caller
;	END IF
;	Fill in the following read function fields in the request buffer.
;
;	   FIELD 			VALUE OBTAINED FROM
;	 size of read request	  P2 argument
;	 access mode		  P3 argument
;	 length of Item List	  P6 argument
;	 Item List descriptors	  P5 argument
;
;	DO FOR each of the Item List descriptors in the Item List
;	   IF the code is one of:   TRM$_TERM  (long form only)
;				    TRM$_PROMPT
;				    TRM$_INISTRNG
;				    TRM$_PICSTRNG
;				    TRM$_ALTECHSTR
;	   THEN
;		copy buffer pointed to by Item List descriptor
;		 to the end of the used portion of the request
;		 buffer
;		set the 2nd longword in Item List descriptor to
;		 be an offset value to the start of the buffer
;		 just copied
;	   END IF
;	END DO
;	RETURN
;
;	END PT_ITEM_READ
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
 
PT_READ:
	PT_DEBUG PT_READ_D			; Macro to enable/disable
						;   XDELTA debugging support
;+
;  Verify requestor is not the device's creator
;-
	CMPL	IRP$L_PID(R3),UCB$L_PT_SM_PID(R5) ; are we the device creator
	BNEQ	30$				; No, goto 30$
 
 	BRW	PT_GETIO			; Creators read is that same as
						;   IO$_FINISHO request
 
;+
; Verify that requestor can write into the buffer.
; If no access EXE$READCHK branches to EXE$ABORTIO with reason SS$_ACCVIO.
;-
30$:
	MOVL	P1(AP),R0			; get address of return data
	MOVZWL	P2(AP),R1			; and its size
	BEQL	40$				; if size = 0 skip access check
	JSB	G^EXE$READCHK			; can requestor write the buffer
;+
;  Allocate and fill a read Request Buffer
;-
40$:
	BBC	#IO$V_EXTEND,IRP$W_FUNC(R3),50$	; is this an Item List read ?
 
	BSBW	PT_ITEM_READ			; Yes, process as Item List
	BRB	60$
50$:
	BSBW	PT_NORMAL_READ			; No, process a normal request
;+
;  Request Buffer is filled, queue IRP to UCB and call PT_POST_MSG to attempt
;   to deliver an outstanding GET_IO request.
;-
60$:
	MOVZWL	P2(AP),IRP$L_BCNT(R3)		; # bytes to read
	MOVAL	UCB$L_PT_APP_IOQFL(R5),R2	; R2 => IRP list head
	BISW2	#IRP$M_TERMIO,IRP$W_STS(R3)	; get TERM IO priority boost
	DSBINT	UCB$B_DIPL(R5)			; disable interrupts
	JSB	G^EXE$INSERTIRP			; put IRP in APP queue
	ENBINT					; enable interrupts
 
	JSB	PT_POST_MSG			; attempt to deliver request
 
	MOVL	#SS$_NORMAL,R0			; sweet success
	JMP	G^EXE$QIORETURN			; done with request
 
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC

	.SBTTL  PT_NORMAL_READ, Normal Read Processing
;+
; PT_NORMAL_READ - Build Request Buffer for application's non-Item List read.
;
;  This routine is branched to from PT_READ, to build and fill a normal
;   read Request Buffer. The Request Buffer is queued to the requestor's IRP.
;
;  Inputs:
;	same as for PT_READ
;
;  Outputs:
;	Request Buffer is built and filled.
;       Request Buffer is queued to IRP$L_SVAPTE
;-
.IF DEFINED SUPPRESS_HEADER
.LIST
.ENDC
 
PT_NORMAL_READ:
 
	PT_DEBUG PT_NORMAL_READ_D		; Macro to enable/disable
						;   XDELTA debugging support
;+
;  make sure user has access to the terminator mask (if specified)
;-
	CLRQ	R9				; start with term mask size = 0
						;  and prompt size = 0
	MOVL	P4(AP),R0			; R0 => terminator descriptor
	BEQL	10$				; If none goto 10$
 
	MOVL	#8,R1				; size of descriptor
	JSB	G^EXE$WRITECHK			; can caller read descriptor
						; No abort, Yes continue
	MOVL	#4,R9				; assume mask is 4 bytes long
	MOVW	(R0),R1				; long form or short form
	BEQL	10$				; short form, continue on
 
	MOVL	R1,R9				; R9 <- mask length
	MOVL	4(R0),R0			; long form, check accessability
	JSB	G^EXE$WRITECHK			; of terminator mask
;+
;  make sure user has access to the prompt string (if specified)
;-
10$:
	CMPB	R7,#IO$_READPROMPT		; is there a prompt
	BEQL	15$				; Yes, goto 15$
	CMPB	R7,#IO$_TTYREADPALL		; is there a prompt
	BNEQ	20$				; No, then goto 20$
15$:	MOVZWL	P6(AP),R1			; get prompt size
	BEQL	20$				; size = 0 then forget prompt
 
	MOVL	R1,R10				; save size of prompt string
 
	MOVL	P5(AP),R0			; R0 => prompt string
	JSB	G^EXE$WRITECHK			; can caller read it
;+
;  calculate size of Request Buffer:
;    size  =      size of prompt string
;		+ size of terminator mask
;		+ 4 longwords for Non-Item List read function buffer overhead
;		+ 4 longwords for the function independent buffer overhead
;		+ 3 longwords for the system buffered I/O overhead
;
;  Maximize size of RBF with size of read.
;
;  at this point R9  contains the size of the terminator mask
;  		 R10 contains the size of the prompt string
;-
20$:
	ADDL3	#<11*4>,R9,R11			; calculate size of RBF
	ADDL	R10,R11				; R11 <- size of RBF
	MOVL	R11,R1				; R1 <- size of buffer to alloc
	MOVZWL	P2(AP),R0			; get read size
	CMPL	R1,R0				; RBF .GE. size of read ??
	BGEQ	25$				; Yes, then use that size
	MOVZWL	P2(AP),R1			; No, then use size of read
25$:
	MOVL	P1(AP),R0			; R0 => user's buffer
 
	JSB	PT_BUILD_REQUEST		; get a Request Buffer
	BLBS	R0,30$				; successful continue on
 
	JMP	G^EXE$ABORTIO			; abort the read request
;+
;  fill in the Read specific part of the Request Buffer
;-
30$:
	BICL2	#IO$M_DSABLMBX,		-	; No disable mailbox allowed
		RBF_L_FUNC_CODE(R2)
 
	MOVL	R3,R8				; save IRP
 
	SUBL3	#RBF$K_SYS_SIZE,R11,	-	; store size of RBF
		RBF_L_SIZE(R2)
	MOVZWL	P2(AP),RBF_L_RDSIZE(R2)		; read request size
	MOVL	P3(AP),RBF_L_TIMEOUT(R2)	; timeout value
	MOVAL	RBF_B_TERM(R2),R3		; R3 => end of used RBF
	MOVL	R9,RBF_L_TRMSIZE(R2)		; terminator mask size
	BEQL	50$				; No mask, move on
;+
;  Fill in terminator mask. R9 is actual size calculated above. Size in
;   descrip. may be 0, which means 4 byte mask is in descriptor; or non 0
;   which means descriptor points to terminator mask.
;-
	MOVL	P4(AP),R0			; R0 => term descriptor
	BEQL	50$				; No terminator, try for prompt
	MOVL	(R0),R1				; R1 <- size of mask in descr.
	BNEQ	40$				; 
						; SHORT FORM
	MOVL	4(R0),RBF_B_TERM(R2)		; fill in term mask
	MOVAL	RBF_B_TERM+4(R2),R3		; R3 => position in buffer
	BRB	50$				; move on
40$:						; LONG FORM
	MOVQ	R4,-(SP)			; save PCB, UCB
	MOVC	R1,@4(R0),RBF_B_TERM(R2)	; move the long form
	MOVQ	(SP)+,R4			; restore PCB, UCB
;+
;  Fill in prompt string. R10 is the size of the string.
;-
50$:
	MOVL	R10,(R3)+			; fill in prompt size (may be 0)
	BEQL	60$				; if none then skip
	MOVQ	R4,-(SP)			; save PCB, UCB
	MOVC	R10,@P5(AP),(R3)		; move in the string
	MOVQ	(SP)+,R4			; restore PCB, UCB
60$:
	MOVL	R8,R3				; restore IRP
	RSB					; back to PT_READ
 
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC

	.SBTTL  PT_ITEM_READ, Item List Read Processing
;+
; PT_ITEM_READ - Build Request Buffer for application's Item List read.
;
;  This routine is JSB'd to from PT_READ, to build and fill an Item
;   List read Request Buffer. The Request Buffer is queued to the
;   requestor's IRP.
;
;  Inputs:
;	same as for PT_READ
;
;  Outputs:
;	Request Buffer is built.
;       Request Buffer is queued to IRP$L_SVAPTE
;
;  Registers are used as follows:
;
;	R0-R2 -	scratch registers
;	R3    - access mode maximized with current mode for probeing
;	R4    - PCB pointer (never touched)
;	R5    - UCB pointer (never touched)
;	R6    - scratch register
;	R7    - accumulated length of data areas pointed to by Item List
;	R8    - number of Item List descriptors
;	R9    - points to Item List
;	R10   - Item List length
;	R11   - saved copy of IRP pointer
;-
.IF DEFINED SUPPRESS_HEADER
.LIST
.ENDC
 
PT_ITEM_READ:
 
	PT_DEBUG PT_ITEM_READ_D			; Macro to enable/disable
						;   XDELTA debugging support
;+
;  Get access mode to use when probing the item list.
;  (maximized with the access mode of the caller)
;-
	MOVL	R3,R11				; save IRP pointer
	MOVL	P3(AP),R0			; get requested access mode
	JSB	G^EXE$MAXACMODE			; maximize with mode of caller
	MOVL	R0,R3				; R3 <- maximized access mode
;+
;  Check for access to Item List
;-
	MOVQ	P5(AP),R9			; saved copy
						; R9  => item list
						; R10 <- size of item list
	MOVL	R9,R0				; working copy
	MOVL	R10,R1				;
	BNEQ	30$				; size != 0 then move on
10$:						; otherwise error
	MOVZWL	#SS$_BADPARAM,R0		; parameter not acceptable
20$:
	MOVL	R11,R3				; restore IRP
	JMP	G^EXE$ABORTIO			; abort request
30$:
	JSB	G^EXE$PROBER			; can item list be read
	BLBC	R0,20$				; No, error
						; Yes, move on
;+
;  Verify size is a multiple of 12.
;-
	MOVL	R10,R0				; get item list size
	CLRL	R1				; EDIV needs quadword
	EDIV	#12,R0,R8,R0			; get mod(12)[item list]
	TSTL	R0				; remainder 0
	BNEQ	10$				; No, then error goto 10$
;+
;  Loop through Item List and check read access to data buffers (prompt string,
;   term mask, etc).
;  R8 has the number of Item List descriptors (from EDIV above).
;-
	CLRL	R7				; accumulate data buffer lengths
	MOVL	R9,R6				; working copy of item list ->
40$:
	MOVZWL	(R6)+,R1			; R1 <- buffer length
	MOVZWL	(R6)+,R2			; R2 <- item code
	MOVL	(R6)+,R0			; R0 either <- immediate data or
						;	    => data buffer
	TSTL	(R6)+				; must be zero
	BNEQ	10$				; if not, bad param error
 
	CASE	R2,-				; item type
		<100$,-				; TRM$_MODIFIERS (0) ignore
		100$,-				; TRM$_EDITMODE  (1) ignore
		100$,-				; TRM$_TIMEOUT   (2) ignore
		200$,-				; TRM$_TERM      (3) process
		300$,-				; TRM$_PROMPT    (4) process
		300$,-				; TRM$_INISTRNG  (5) process
		300$,-				; TRM$_PICSTRNG  (6) process
		100$,-				; TRM$_FILLCHR   (7) ignore
		100$,-				; TRM$_INIOFFSET (8) ignore
		300$,-				; TRM$_ALTECHSTR (9) process
		>,-				; TRM$_LASTITM   (10)
		TYPE = B
 
	ASSUME TRM$_LASTITM EQ 10		; won't work if not true
	BRB	10$				; fall through then bad param
 
100$:						; MOST CODES (ignore)
	SOBGTR	R8,40$				; ignore most codes for now
	BRB	50$
200$:						; TRM$_TERM
	TSTW	R1				; short form or long form
	BEQL	100$				; short form, ignore for now
 
300$:						; CODES WE PROCESS
	TSTL	R1				; zero length item ??
	BEQL	310$				; Yes, then no access check
 
	PUSHL	R1				; save length
	JSB	G^EXE$PROBER			; can item list be read
	BLBC	R0,20$				; report access violations
	ADDL	(SP)+,R7			; accumulate the length
310$:
	SOBGTR	R8,40$				; keep looping
;+
;  Calculate the size of the buffer we need to allocate.
;    size  =    size of data pointed to by Item List (prompt string, etc.)
;    		+ size of Item List
;		+ 3 longwords for Item List read function buffer overhead
;		+ 4 longwords for the function independent buffer overhead
;		+ 3 longwords for the system buffered I/O overhead
;
;  Maximize size of RBF with size of read.
;-
50$:
	ADDL	R10,R7				; len(item list) + len(data buf)
	ADDL	#<10*4>,R7			; overhead
	MOVL	R7,R1				; R1 <- size of buffer to alloc
	MOVZWL	P2(AP),R0			; get read size
	CMPL	R1,R0				; RBF .GE. size of read ??
	BGEQ	55$				; Yes, then use that size
	MOVZWL	P2(AP),R1			; No, then use size of read
55$:
	MOVL	P1(AP),R0			; R0 => user's buffer
	MOVL	R11,R3				; restore IRP
	JSB	PT_BUILD_REQUEST		; allocate the buffer
	BLBS	R0,57$				; successful continue on
	BRW	20$				; else abort
;+
;  fill in the Read specific part of the Request Buffer
;-
57$:
	SUBL3	#RBF$K_SYS_SIZE,R7,	-	; size of RBF
		RBF_L_SIZE(R2)
 
	MOVZWL	P2(AP),RBF_L_RSIZE(R2)		; read request size
	MOVL	P3(AP),RBF_L_ACCMODE(R2)	; access mode
	MOVL	R10,RBF_L_ITMSIZE(R2)		; item list size
 
	PUSHR	#^M<R2,R4,R5>
	MOVC	R10,(R9),RBF_W_BUFLEN(R2)	; move in the item list
	POPR	#^M<R2,R4,R5>
;+
;  Loop through Item List and fix up those descriptors which point
;   to a data buffer.
;  R3 points to end of Item List in Request Buffer due to MOVC above.
;-
	MOVAL	RBF_W_BUFLEN(R2),R6		; R6 => item list in RBF
	MOVL	R10,R0				; R10 size of item list
	CLRL	R1				; EDIV needs quadword
	EDIV	#12,R0,R8,R0			; get mod(12)[item list]
60$:
	MOVZWL	(R6)+,R1			; R1 <- buffer length
	MOVZWL	(R6)+,R2			; R2 <- item code
	MOVL	(R6)+,R0			; R0 either <- immediate data or
						;	    => data buffer
	TSTL	(R6)+				; move past MBZ field
 
	CASE	R2,-				; item type
		<1000$,-			; TRM$_MODIFIERS (0) ignore
		2000$,-				; TRM$_EDITMODE  (1) ignore
		2000$,-				; TRM$_TIMEOUT   (2) ignore
		3000$,-				; TRM$_TERM      (3) process
		4000$,-				; TRM$_PROMPT    (4) process
		4000$,-				; TRM$_INISTRNG  (5) process
		4000$,-				; TRM$_PICSTRNG  (6) process
		2000$,-				; TRM$_FILLCHR   (7) ignore
		2000$,-				; TRM$_INIOFFSET (8) ignore
		4000$,-				; TRM$_ALTECHSTR (9) process
		>,-				; TRM$_LASTITM   (10)
		TYPE = B
 
	BRW	10$				; fall through then bad param
 
1000$:						; TRM$_MODIFIERS 
	BICL2	#TRM$M_TM_DSABLMBX,-8(R6)	; No disable mailbox allowed
	SOBGTR	R8,60$				; 
	BRB	70$				; all done
2000$:						; MOST CODES (ignore)
	SOBGTR	R8,60$				; ignore most codes for now
	BRB	70$				; all done
3000$:						; TRM$_TERM
	TSTW	R1				; short form or long form
	BEQL	2000$				; short form, ignore for now
;+
;  Copy data buffer to end of used portion of Request Buffer.
;  Set the Item List descriptor 2nd longword in the Request Buffer
;   to an offset to the data buffer just copied.
;-
4000$:						; CODES WE PROCESS
 
	MOVAL	-8(R6),R7			; R7 => offset field
	SUBL3	R7,R3,(R7)			; get offset to data
 
	MOVQ	R4,-(SP)			; save PCB, UCB
	MOVC	R1,(R0),(R3)			; copy into RBF
	MOVQ	(SP)+,R4
 
	SOBGTR	R8,60$				; keep looping
70$:
	MOVL	R11,R3				; restore IRP pointer
	RSB

	.SBTTL	PT_FINISHIO, Satisfy applications I/O request
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;	PT_FINISHIO	Satisfy applications I/O request
;
;	Description:
;		This routine services a Screen Manager IO$_FINISHIO
;	request. The request is to complete an application's I/O request
;	that the Screen Manager processed.
;		The P1 data is moved to the application's buffer, the
;	application's I/O request is completed, the current I/O request is
;	completed, and a call to PT_POST_MSG is made to attempt to get the
;	next request started.
;
;	Execution requirements:
;		$QIOW 	func = IO$_FINISHIO
;			chan = SCREEN_MANAGERS_CHANNEL
;			iosb = FINISHIO_IOSB
;			p1   = FINISHIO_BUFFER_ADDRESS
;			p2   = FINISHIO_BUFFER_SIZE
;			p3   = FINISHIO_APPLICATIONS_IOSB
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;
;	Outputs:
;
;		UCB$L_IOQFL	- active IRP is removed
;		UCB$L_IOQBL
;		@IRP$L_SVAPTE	- data is copied to applications request buffer
;		IRP$L_IOST1	- application's IOSB
;		IRP$L_IOST2
;		UCB$V_PT_BUSY	- device is set to not busy
;
;	The routine preserves registers R3-R8
;
;	Data structures:
;
;	None
;
;	External references:
;
;		COM$POST	-	complete an I/O request
;		EXE$FINISHIO	-	complete an I/O request (don't return)
;		EXE$QIORETURN	-	return from FDT routine with success
;		EXE$WRITECHK	-	check memory for read accessibility
;		PT_POST_MSG	-	check and post pending requests to
;					 Screen Manager
;	Special notes:
;
;	None
;--
;+
;	Module Algorithm:
;	   BEGIN
;
;	IF requestor's PID and device owner PID match THEN
;	   disable interruption
;	   CALL EXE$WRITECHK to verify requestor can read
;	    the data buffer being returned to the application
;	   CALL EXE$WRITECHK to verify requestor can read the
;	    IOSB buffer being returned to the application
;	   Disable interrupts so that the rest can occur without
;	    interruption
;	   IF this device is busy THEN
;	      IF buffer size .LE. application's I/O buffer THEN
;		   Reenable interrupts so that page faulting can 
;		    occur
;		   copy the data being returned to the
;		    application into the buffer 
;		   mark device as not busy
;		   store SS$_NORMAL in IRP return status
;		   Disable interrupts so COM$POST can walk the I/O
;		    post processing queue
;		   CALL COM$POST to post the requestor's IRP
;		   CALL COM$POST to post the application's IRP
;		   CALL PT_POST_MSG to attempt to complete the next
;		    GET_IO request
;	      ELSE
;		   store SS$_RESULTOVF in IRP return status
;		   CALL EXE$FINISHIO to abort this request
;	      END IF
;	   ELSE
;	      IF device cancel bit is set THEN
;		store SS$_CANCEL in IRP return status
;	      ELSE
;		store SS$_NOSOLICIT in IRP return status
;	      END IF
;	      CALL EXE$FINISHIO to abort this request
;	   END IF
;	ELSE
;	   store SS$_ILLIOFUNC in IRP return status
;	   CALL EXE$FINISHIO to abort this request
;	END IF
;	return via EXE$QIORETURN
;
;	   END
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_FINISHIO:
	PT_DEBUG PT_FINISHIO_D			; Macro to enable/disable
						;   XDELTA debugging support
	CMPL	IRP$L_PID(R3),UCB$L_PT_SM_PID(R5) ; are we the device owner
	BEQL	10$				; Yes, then move on
 
	MOVL	#SS$_ILLIOFUNC,R0		; Not owner
	CLRL	R1				; 0 bytes transferred
	JMP	G^EXE$FINISHIO			; puts R0, R1 in caller's IOSB
						; and returns through QIO
;+
; verify that requestor can read the returning data and the IOSB
; if no access EXE$WRITECHK branches to EXE$ABORTIO with reason SS$_ACCVIO
;-
10$:
	MOVL	IRP$L_BCNT(R3),R9		; EXE$WRITECHK kills this
						;  so let's save it
	MOVL	P1(AP),R0			; R0 -> address of return data
	MOVZWL	P2(AP),R1			; R1 -> its size (P2 arg.)
	BEQL	20$
 
	JSB	G^EXE$WRITECHK			; can requestor read the buffer
20$:
	MOVL	P3(AP),R0			; get addr. of return IOSB
	MOVZBL	#8,R1				; size of IOSBs
	JSB	G^EXE$WRITECHK			; can requestor read the IOSB
 
	MOVL	R9,IRP$L_BCNT(R3)		; restore after EXE$WRITECHK
	MOVZWL	P2(AP),R9			; save number of bytes moved
 
	DSBINT	UCB$B_DIPL(R5)			; don't allow interruption
 
	BBS	#UCB$V_PT_BUSY,		-	; is the device busy
		 UCB$W_PT_DEVSTATUS(R5),40$	; Yes, then move on
 
	BBC	#UCB$V_PT_CANCEL,	-	; Has a cancel been done
		 UCB$W_PT_DEVSTATUS(R5),30$	; Yes, then tell him
 
	MOVZWL	#SS$_CANCEL,R0			; cancel has been done
	CLRL	R1				; 0 bytes transferred
	JMP	G^EXE$FINISHIO			; puts R0, R1 in caller's IOSB
30$:
	MOVL	#SS$_NOSOLICIT,R0		; Otherwise no I/O to finish
	CLRL	R1				; 0 bytes transferred
	JMP	G^EXE$FINISHIO			; puts R0, R1 in caller's IOSB
						; and returns through QIO
40$:
	MOVL	UCB$L_IRP(R5),R2		; R2 => IRP we're finishing
	CMPL	R9,IRP$L_BCNT(R2)		; return data .LE. app. request
	BLEQ	50$				; Yes, Finish the app. request
 
	CVTLW	IRP$L_BCNT(R2),R1		; Tell him the max allowed
    	ASHL	#16,R1,R0			; Store size in highorder word
	MOVL	#SS$_RESULTOVF,R0		; No, tell him there's too much
 
	JMP	G^EXE$FINISHIOC			; puts R0, R1 in caller's IOSB
						; and returns through QIO
 
50$:
	CLRL	UCB$L_IRP(R5)			; no active IRP anymore
 
	ENBINT					; reenable interrupts
						; allowing page faults !!!!
 
	PUSHR	#^M<R2,R3,R4,R5>
 
	MOVZBL	#RBF$K_SYS_SIZE,R3		; index past system header
	MOVC	R9,@P1(AP),		-	; put return data => app. buffer
		@IRP$L_SVAPTE(R2)[R3]
 
	POPR	#^M<R2,R3,R4,R5>
 
	MOVL	R9,IRP$L_BCNT(R2)		; IO post processing will return
						;  BCNT bytes to user buffer
	MOVQ	@P3(AP),IRP$L_IOST1(R2)		; return the IOSB
;+
; Post the Finish request, and post the application request just
;  finished.
;-
	DSBINT	UCB$B_DIPL(R5)			; don't allow interruption
 
	PUSHL	R3
	MOVL	R2,R3				; R3 => app. IRP
	JSB	G^COM$POST			; finish the guy
	POPL	R3				; R3 => finish IRP
 
	BBSC	#UCB$V_PT_BUSY,		-	; mark device not busy
		 UCB$W_PT_DEVSTATUS(R5),60$
60$:
	MOVZWL	#SS$_NORMAL,IRP$L_IOST1(R3)	; request was successful
	CVTLW	R9,IRP$L_IOST1+2(R3)		; return number of bytes moved
	CLRL	IRP$L_IOST2(R3)			; clear device specific part 
						;   of IOSB
	JSB	G^COM$POST			; post this finish request
 
	JSB	PT_POST_MSG			; check for next Get_IO request
 
	JMP	G^EXE$QIORETURN			; back to caller (QIO)

	.SBTTL	PT_SET, Support VMS terminal driver set function
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_SET		Support VMS terminal driver Set function
;
;	Description:
;		Process a set characteristics or set modem function.  This
;	function sets the specified characteristics immediately for all
;	cases except CTRL/C, CTRL/Y, or out-of-band AST requests.    In
;	these cases it stores the necessary information locally and sends
;	a notification message to the Screen Manager.  Once the Screen Manager
;	has received the data these operations are completed.	
;
;	Execution requirements:
;		$QIOW 	func = IO$_SETXXXX
;			chan = SET_CHANNEL
;			iosb = SET_IOSB
;			p1   = SET_FUNCTION_ARGUMENT_1
;			p2   = SET_FUNCTION_ARGUMENT_2
;			p3   = SET_FUNCTION_ARGUMENT_3
;			p4   = SET_FUNCTION_ARGUMENT_4
;			p5   = SET_FUNCTION_ARGUMENT_5
;
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;
;	Normal set:
;		P1(AP)	- Address of users buffer
;		P2(AP)	- Size of users buffer in bytes
;		P3(AP)	- Speed information
;		P4(AP)	- Fill specification
;		P5(AP)	- Parity flags
;
;	Set CTRL/C or CTRL/Y:
;		P1(AP)	- Address of AST service routine
;		P2(AP)	- AST parameter
;		P3(AP)	- Access mode to deliver AST
;
;	Set Modem:
;		P1(AP)	- Address of block of modem control information
;
;	Set Broadcast:
;		P1(AP)	- Address of buffer containing bits of message(s)
;			    to be broadcast
;		P2(AP)	- Size of buffer pointed to by P1(AP)
;
;	Outputs:
;
;		IRP	The following fields in the IRP may be changed:
;
;			IRP$W_BOFF
;			IRP$L_SVAPTE
;			IRP$L_BCNT
;			IRP$L_IOST1
;			IRP$L_IOST2
;
;		UCB	The following fields in the UCB may be changed:
;
;			UCB$B_DEVCLASS
;			UCB$B_DEVTYPE
;			UCB$B_DEVBUFSIZE
;			UCB$L_DEVDEPEND
;			UCB$L_DEVDEPND2
;			UCB$W_DEVSTS
;			UCB$L_TL_CTLPID
;			UCB$L_PT_APP_IOQFL
;			UCB$L_PT_APP_IOQBL
;			UCB$L_PT_CTRLC
;			UCB$L_PT_CTRLY
;			UCB$L_PT_OUTBAND_QUEUE
;			UCB$L_PT_OUTBAND_MASK
;			UCB$B_PT_XMIT_SPEED
;			UCB$B_PT_RCV_SPEED
;			UCB$B_PT_CRFILL
;			UCB$B_PT_LFILL
;			UCB$B_PT_PARITY
;			UCB$Q_PT_MODEM
;			UCB$Q_TL_BRKTHRU
;			UCB$B_PT_ALTERED_CHARS
;
;	The routine must preserve R3 - R8.
;
;	Data structures:
;
;		RBF	- All fileds in the RBF needed to describe a set
;			  AST operation will be filled in.
;
;	External references:
;
;	COM$DELATTNAST	- Deliver attention ASTs
;	COM$SETATTNAST	- Set up attention AST
;	COM$SETCTRLAST	- Set up out-of-band AST
;	EXE$ABORTIO	- Abports an I/O operation
;	EXE$FINISHIO	- Complete an I/O operation
;	EXE$FINISHIOC	- Complete an I/O operation with R0 status only
;	EXE$INSERTIRP	- Insert IRP into specified I/O queue
;	EXE$QIORETURN	- Return from an FDT routine with success
;	PT_BUILD_REQUEST- Allocate a request buffer and fill in
;			    fixed information
;	PT_POST_MSG	- Check and post pending request to Screen Manager
;
;
;	Special notes:
;
;		This routine only check for legal modifiers any illegal
;	modifiers are ignored and the normal case for set is assumed.
;
;		When setting up an AST of any type failure to setup AST
;	will return its status as the QIO status return value.  Failure
;	to queue notification to the Screen Manager will be returned in
;	the IOSB.
;
;		The device creator can clear the fields UCB$L_PID, and 
;	UCB$L_TL_CTLPID if the reference count is 1.  If the reference count
;	is not one the he will receive an SS$_DEVCMDERR status.
;
;--
;+
;	Module Algorithm:
;	   BEGIN
;
;
;          CASE
;               NORMAL SET
;                 Check the validity of P1 & P2 arguments
;                 IF parameters ok THEN
;                    fill in correct fileds in the UCB
;                    fill in the necessary fields in the UCB for the
;                      P3 - P5 parameters
;                    note characteristics changed for use by PT_POST_MSG
;                    save data for IOSB and exit via EXE$FINISHIO
;                 ELSE
;                    save return status and exit via EXE$ABORTIO
;                 ENDIF
;
;               MAINTENANCE
;                 IF set modem THEN
;                    validate buffer
;                    IF buffer ok THEN
;                       save modem information
;                       note characteristics changed for use by PT_POST_MSG
;                       save data for IOSB and exit via EXE$FINISHIO
;                    ELSE
;                       save return status and exit EXE$ABORTIO
;                    ENDIF
;                 ELSE
;                    save data for IOSB and exit via EXE$FINISHIO
;                 ENDIF
;
;               CTRL/C and CTRL/Y
;                 IF the requestors PID is not the device creators THEN
;                    set the AST via COM$SETATTNAST
;                    IF set ok THEN
;                       IF the device is hungup and the request is for 
;                          CTRL/Y AST THEN
;                          deliver the CTRL/Y AST with the reason of SS$_HANGUP
;                            via COM$DELATTNAST
;                          save data for IOSB and exit via EXE$FINISHIO
;                       ELSE
;                          allocate, fill in, and queue a request buffer
;                          return to the QIO dispatcher via EXE$QIORETURN
;                       ENDIF
;                    ELSE
;                       save error return status and abort via EXE$ABORTIO
;                    ENDIF
;                 ELSE
;                   save error return status SS$_ILLIOFUNC and abort via
;                     EXE$ABORTIO
;                 ENDIF
;
;               HANGUP
;                 IF no CTRL/Y ASTSs to deliver THEN
;                    set hangup in UCB
;                 ELSE
;                    set reason code for all CTRL/Y ASTs to be SS$_HANGUP 
;                      and deliver them via COM$DELATTNAST
;                 ENDIF
;                 save data for IOSB and exit via EXE$FINISHIO
;
;               OUT-OF-BAND
;                 IF the requestors PID is not the device creators THEN
;                    set out-of-band AST via COM$SETCTRLAST
;                    allocate, fill in, and queue a request buffer
;                    return to the QIO dispatcher via EXE$QIORETURN
;                 ELSE
;                    save error return status SS$_ILLIOFUNC and abort via
;                      EXE$ABORTIO
;                 ENDIF
;
;               CONNECT and DISCONNECT
;                 save error return status SS$_IVDEVNAM via EXE$ABORTIO
;
;               PID
;                 IF the requestors PID is the creators PID THEN
;                    IF the reference count equals 1 THEN
;                       clear UCB$L_PID, and UCB$L_TL_CTLPID
;                       save data for IOSB and exit via EXE$FINISHIO
;                    ELSE
;                       save error return status SS$_ABORT and abort via
;                         EXE$ABORTIO
;                    ENDIF
;                 ELSE
;                    store PCB$L_PID in UCB$L_TL_CTLPID
;                    save data for IOSB and exit via EXE$FINISHIO
;                 ENDIF
;
;               BROADCAST
;                 check and validate P1 & P2 parameters
;                 IF parameters ok THEN
;                    store broadcast information in the UCB
;                    note characteristics changed for use by PT_POST_MSG
;                    save data for IOSB and exit via EXE$FINISHIO
;                 ELSE
;                   save error return status and exit via EXE$ABORTIO
;                 ENDIF
;
;          END CASE
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_SET:
	PT_DEBUG PT_SET_D			; Macro to enable/disable
						;   XDELTA debugging support
	FFS	#IO$V_MAINT,#9,		-	; Get first modifier
		IRP$W_FUNC(R3),R1		;
	CASE	R1,TYPE=B,LIMIT=#6,<	-	; Vector to correct special
		PT_SET_MAINT,		-	;   set routine
		PT_SET_CTRLY,		-	;
		PT_SET_CTRLC,		-	;
		PT_SET_HANGUP,		-	;
		PT_SET_OUTBAND,		-	;
		PT_SET_CONNECT,		-	;
		PT_SET_DISCONNECT,	-	;
		PT_SET_PID,		-	;
		PT_SET_BRDCST>			;

;+
; If here normal set case
;-
PT_SET_NORMAL:
 	BSBW	PT_SET_ARG_VALID		; Validate P1 & P2 arguments
						;   R0 - Status
						;   R1 - address of buffer
						;   R2 - buffer size
	BLBS	R0,10$				; OK?
	BRW	PT_SET_ABORT			; Branch to common abort code
 
10$:	BISW2	#UCB$M_PT_NEWCHAR,	-	; Note device characteristics
		UCB$W_PT_DEVSTATUS(R5)		;   have changed
	BISB2	#<RBF_M_NEW_CHAR!	-	; Store mask of what changed
		  RBF_M_BASIC_CHAR>,	-	;
		UCB$B_PT_ALTERED_CHARS(R5)	;
	MOVQ   	(R1)+,UCB$B_DEVCLASS(R5)	; Fill first 8 bytes of 
						;   characteristics
   	CMPL	#12,R2				; See if more characteristics
						;   data to store
  	BNEQ	20$				; No more go handle P3 - P5
	BISB2	#RBF_M_EXTENDED_CHAR,	-	; Note that extended 
		UCB$B_PT_ALTERED_CHARS(R5)	;   characteristics changed
	MOVL	(R1),UCB$L_DEVDEPND2(R5)	; Store secondary 
						;   characteristics
 
20$:	BBC	#TT2$V_SETSPEED,	-	; See if need priv to alter
		UCB$L_DEVDEPND2(R5),30$		;   speed
	BITL	#<<1@PRV$V_LOG_IO>!	-	; Check privilege
		  <1@PRV$V_PHY_IO>>,	-	;
		@IRP$L_ARB(R3)
	BNEQ	30$
	MOVZWL	#SS$_NOPRIV,R0	     		; No privilege so abort
    	BRW	PT_SET_ABORT			; Branch to common abort code
	
30$:	TSTB	P3(AP)		     		; See if altering XMIT speed
	BEQL	40$				; No speed to change 
	MOVW	P3(AP),UCB$B_PT_XMIT_SPEED(R5)	; Store new speeds
 
40$:	BBCC	#TT$V_CRFILL,		-	; Is CRFILL alterable?
		UCB$L_DEVDEPEND(R5),50$		;
	MOVB	P4(AP),UCB$B_PT_CRFILL(R5)	; Store new CRFILL
 
50$:	BBCC	#TT$V_LFFILL,		-	; Is LFFILL alterable?
		UCB$L_DEVDEPEND(R5),60$		;
	MOVB	P4+1(AP),UCB$B_PT_LFILL(R5)	; Store new LFFILL
 
60$:	BBC	#TT$V_ALTRPAR,P5(AP),70$	; Is parity alterable?
	BICB3	#^C<TT$M_PARITY!TT$M_ODD>, -	; Reset bits
		P5(AP),R0			;
	BICB	#<TT$M_PARITY!TT$M_ODD>, -	; Clear stored parity
		UCB$B_PT_PARITY(R5)		; 
	BISB	R0,UCB$B_PT_PARITY(R5)		; Set new parity
 
70$:	BRW	PT_SET_FINISH			; Branch to finish path

;+
; Handle maintenance commands
;-
PT_SET_MAINT:
	BBS	#IO$V_SET_MODEM,	-	; Set modem?
		IRP$W_FUNC(R3),10$		;
	BRW	PT_SET_FINISH			; Branch to finish path
 
10$: 	BSBW	PT_SET_ARG_VALID		; Validate P1 & P2 arguments
						;   R0 - Status
						;   R1 - address of buffer
						;   R2 - buffer size
	BLBS	R0,20$				; OK?
	BRW	PT_SET_ABORT			; Branch to common abort code
 
20$:	MOVQ	(R1),UCB$Q_PT_MODEM(R5)		; Store modem information
	BISW2	#UCB$M_PT_NEWCHAR,	-	; Note device characteristics
		UCB$W_PT_DEVSTATUS(R5)		;   have changed       
	BISB2	#<RBF_M_NEW_CHAR!	-	; Store mask of what changed
		  RBF_M_MODEM>,		-	;
		UCB$B_PT_ALTERED_CHARS(R5)	;
	BRW	PT_SET_FINISH			; Branch to finish path

;+
; Handle CTRL/C and CTLR/Y AST setup
;-
PT_SET_CTRLC:
	MOVAB	UCB$L_PT_CTRLC(R5),R7		; CTRL/C AST queue head
	BRB	PT_SET_CTRL			; Branch to common set
 
PT_SET_CTRLY:
	MOVAB	UCB$L_PT_CTRLY(R5),R7		; CTRL/Y AST queue head
 
PT_SET_CTRL:					; Now set up AST 
	CMPL	IRP$L_PID(R3),		-	; Check that requestor is
		UCB$L_PT_SM_PID(R5)		;   not device owner
	BNEQ	10$				;
	MOVZWL	#SS$_ILLIOFUNC,R0		; Device owner not allowed
						;   to do this request type
	BRW	PT_SET_ABORT			; Branch to common code
 
10$:	DSBINT	UCB$B_DIPL(R5)			; Insure creator cannot deliver
						;   this AST
	CLRL	R2				; Null mask
	JSB	G^COM$SETATTNAST		; Setup AST
	BBC	#IO$V_CTRLYAST,		- 	; Enabling CTRL/Y?
		IRP$W_FUNC(R3),30$		;
	BBCC	#UCB$V_TT_HANGUP,	-	; Check for lost hangup 
		UCB$W_DEVSTS(R5),30$		;   notification
	MOVL	R7,R4				; Get queue Address
	MOVL	(R4),R0				; Get AST block address
       	BEQL	20$				; Queue empty exit creator beat
						;   us via context switch
      	MOVZWL	#SS$_HANGUP,ACB$L_KAST+4(R0)	; Signal special hangup status
	JSB	G^COM$DELATTNAST		; Deliver the AST
20$:	ENBINT					; Allow interrupts 
	MOVZWL	#SS$_NORMAL,R0			; Store successful exit
	JMP	G^EXE$FINISHIOC			; Finish the request
 
30$:	ENBINT					; Allow interrupts 
	
	BLBC	R0,40$				; IF LBC SET failed
	BRW	PT_SET_NOTIFY_SM		; Set ok if LBS so notify SM
40$:	BRW	PT_SET_ABORT			; Setup of AST failed so
						;   branch to common abort

;+
; Mark the device as having been hung up
;-
PT_SET_HANGUP:
	DSBINT	UCB$B_DIPL(R5)			; Insure creator cannot deliver
						;   CTRL/Y ASTs on us
	BISW2	#UCB$M_PT_NEWCHAR,	-	; Note device characteristics
		UCB$W_PT_DEVSTATUS(R5)		;   have changed       
	BISB2	#<RBF_M_NEW_CHAR!	-	; Store mask of what changed
		  RBF_M_HANGUP>,	-	;
		UCB$B_PT_ALTERED_CHARS(R5)	;
	MOVAB	UCB$L_PT_CTRLY(R5),R4		; Address of CTRL/Y list
	MOVL	R4,R0 				; Copy list address
	TSTL	(R0)				; Any ASTs to process?
    	BNEQ	20$				; ASTs to process so do it
 
10$:	BISW2	#UCB$M_TT_HANGUP,	-	; Mark the device as having
		UCB$W_DEVSTS(R5)		;   been hung up
    	BRB	40$				; No ASTs to process so exit
 
20$:	MOVL	(R0),R0				; Check for end of list
	BEQL	30$				; If equal then done
      	MOVZWL	#SS$_HANGUP,ACB$L_KAST+4(R0)	; Signal special hangup status
    	BRB	20$				; Look for another to deliver
 
30$:	JSB	G^COM$DELATTNAST		; Deliver all the attention ASTs
 
40$:	ENBINT					; Allow interrupts again
	BRW	PT_SET_FINISH			; Branch to finish path

;+
; Enable out-of-band AST
;-
PT_SET_OUTBAND:
	CMPL	IRP$L_PID(R3),		-	; Check that requestor is
		UCB$L_PT_SM_PID(R5)		;   not device owner
	BNEQ	10$				;
	MOVZWL	#SS$_ILLIOFUNC,R0		; Device owner not allowed
						;   to do this request tyep
	BRW	PT_SET_ABORT			;
 
10$:   	MOVAB	UCB$L_PT_OUTBAND_QUEUE(R5),R7	; Get out-of-band queue address
    	MOVAB	UCB$L_PT_OUTBAND_MASK(R5),R2	; Get out-of-band mask address
	JSB	G^COM$SETCTRLAST		; Enable/disable AST(s)
                                                        
;+
; Common routine for completing CTRL/C, CTRL/Y, and out-of-band ASTs
;-
PT_SET_NOTIFY_SM:
	CLRL	R0				; Make sure no user buffer
    	MOVL	#RBF_K_SET_LEN,R1		; Store buffer size
	BSBW	PT_BUILD_REQUEST		; Allocate & fill in fixed
						;   part of request buffer
	BLBS	R0,10$				;
	JMP	G^EXE$FINISHIOC			; Don't abort finish with
						;   error to distinguish
						;   that AST was queued
 
10$:	BISW2	#IRP$M_TERMIO,		-	; Set terminal I/O bit so
		IRP$W_STS(R3)			;   priority will be recomputed
      	MOVL	#<RBF_K_SET_LEN-RBF$K_SYS_SIZE>,-	; Store request buffer
      		RBF_L_SIZE(R2)				;   size in request 
							;   buffer
	MOVL	P1(AP),RBF_L_AST_ADDR(R2)	; Store AST routine address
	MNEGW	IRP$W_CHAN(R3),R0		; Store channel number in
	CVTWL	R0,RBF_L_CHANNEL(R2)		;   request buffer
    	BBC	#IO$V_OUTBAND,IRP$W_FUNC(R3), -	; If out-of-band store mask
		30$				;   and summary mask
	MOVL	P2(AP),R0			; Get address of mask block
	BEQL	20$				; No mask so skip next step
	MOVL	4(R0),RBF_L_MASK(R2)		; Store mask bits
20$:	MOVL	UCB$L_PT_OUTBAND_MASK(R5), -	;
    		RBF_L_SUM_MASK(R2)		;
 
30$:	MOVZWL	#SS$_NORMAL,IRP$L_IOST1(R3)	; Store success in IRP IOSB
	CLRL	IRP$L_IOST2(R3)			; Clear 2nd longword of IRP IOSB
	MOVAB	UCB$L_PT_APP_IOQFL(R5),R2	; Get queue head address
	DSBINT	UCB$B_DIPL(R5)			; Disable interrupts
	JSB	G^EXE$INSERTIRP			; Insert request in queue
	ENBINT					; Allow interrupts
	BSBW	PT_POST_MSG			; See if Screen Manager
						;   request to post
	JMP	G^EXE$QIORETURN			; All done exit QIO call

;+
; Do not support these undocumented modifiers!!!
;-
PT_SET_CONNECT:
PT_SET_DISCONNECT:
  	MOVZWL	#SS$_IVDEVNAM,R0		; Error off for these modifiers
    	BRB	PT_SET_ABORT			; Branch to common error code
;+
; Handle setting of PIDs
;-
PT_SET_PID:
	CMPL	IRP$L_PID(R3),		-	; Is requestor device creator?
		UCB$L_PT_SM_PID(R5)		;
      	BNEQ	20$				; Not owner branch to set CTLPID
     	CMPW	UCB$W_REFC(R5),#1		; Is creator only device user?
	BEQL	10$				;
    	MOVZWL	#SS$_DEVCMDERR,R0		; Illegal at present time
    	BRB	PT_SET_ABORT			; Branch to common error code
 
10$:	CLRL	UCB$L_PID(R5)			; Clear device owner PID 
   	CLRL	UCB$L_TL_CTLPID(R5)		; Clear device controlling PID
 	BRB	PT_SET_FINISH			; Branch to finish path
 
20$:	MOVL	PCB$L_PID(R4),		-	; Store new controlling PID
		UCB$L_TL_CTLPID(R5)
	BRB	PT_SET_FINISH			; Branch to finish path

;+
; Store broadcast information
;-
PT_SET_BRDCST:
	BSBB	PT_SET_ARG_VALID		; Validate P1 & P2 argumants
						;   R0 - status
						;   R1 - buffer address
						;   R2 - buffer size
	BLBC	R0,PT_SET_ABORT			; If error branch to abort
	MOVQ	(R1),UCB$Q_TL_BRKTHRU(R5)	; Move quadword of messge
						;   type data
	BISW2	#UCB$M_PT_NEWCHAR,	-	; Note device characteristics
		UCB$W_PT_DEVSTATUS(R5)		;   have changed       
	BISB2	#<RBF_M_NEW_CHAR!	-	; Store mask of what changed
		  RBF_M_BROADCAST>,	-	;
		UCB$B_PT_ALTERED_CHARS(R5)	;
						; Fall through to exit routine

;+
; Common exit code paths for finish I/O with success, and abort
;-
PT_SET_FINISH:
   	MOVL	UCB$B_PT_XMIT_SPEED-2(R5),R0	; Store speed data in IOSB
	MOVL	UCB$B_PT_CRFILL(R5),R1		; Store fill and parity in IOSB
	MOVW	#SS$_NORMAL,R0			; Store success
	JMP	G^EXE$FINISHIO			; Finish I/O
 
PT_SET_ABORT:
						; Assume R0 has status at
						;   this point
	JMP	G^EXE$ABORTIO			; Abort QIO call

;+
; This routine validates the set function arguments
;-
PT_SET_ARG_VALID:
	MOVL	P1(AP),R1			; Address of users buffer
  	IFNORD	#8,(R1),20$			; Branch if no read access to
						;   quadword buffer
    	MOVL	#8,(R2)				; Assume default buffer size
	CMPL	P2(AP),#12			; Buffer size ok?
	BLSSU	10$				;
	BGTRU	30$				;
     	MOVL	#12,R2				; If here size must be 12 bytes
  	IFNORD	#12,(R1),20$			; Branch if no read access to
						;   whole buffer
 
10$:	MOVZWL	#SS$_NORMAL,R0			; Store success code
	RSB
 
20$:	MOVZWL	#SS$_ACCVIO,R0			; Store Access violation
	RSB
 
30$:	MOVZWL	#SS$_BADPARAM,R0		; Store bad parameter
	RSB

	.SBTTL	PT_SENSE, Support VMS terminal driver Sense Function
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_SENSE	Support VMS terminal driver Sense Function
;
;	Description:
;		Process a sense characteristics or sense mode function.
;	This function returns the requested information immediately for
;	all cases except TYPE-AHEAD.  In the case of type-ahead a requested
;	is queued to the Screen Manager for completion.
;
;	Execution requirements:
;		$QIOW 	func = IO$_SENSEXXXX
;			chan = SENSE_CHAN
;			iosb = SENSE_IOSB
;			p1   = SENSE_BUFFER_ADDRESS
;			p2   = SENSE_BUFFER_SIZE
;
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;		P1(AP)	- Address of users buffer
;		P2(AP)	- Size of users buffer in bytes
;
;	Outputs:
;
;	   	IRP	The following fields in the IRP may be changed:
;
;			IRP$W_BOFF
;			IRP$L_SVAPTE
;			IRP$L_BCNT
;			IRP$L_IOST1
;			IRP$L_IOST2
;
;		UCB	The following fields in the UCB may be changed:
;
;			UCB$L_PT_APP_IOQFL
;			UCB$L_PT_APP_IOQBL
;
;	The routine must preserve R3 - R8.
;
;	Data structures:
;
;		RBF	- All fields in the RBF needed to describe a sense
;			  type-ahead operation will be filled.
;
;	External references:
;
;		EXE$ABORTIO	- Aborts an I/O operation
;		EXE$FINISHIO	- Complets an I/O operation
;		EXE$INSERTIRP	- Insert IRP into specified I/O queue
;		EXE$QIORETURN	- return from and FDT routine with success
;		PT_BUILD_REQUEST- Allocate a request buffer and fill in
;				    fixed information
;		PT_POST_MSG	- Check and post pending request to screen
;				    Manager
;
;	Special notes:
;
;		Routine only checks for legal modifiers any illegal modifiers
;	are ignored and the normal case for sense is assumed.
;
;--
;+
;	Module Algorithm:
;
;	   BEGIN
;
;          determine buffer size
;          IF buffers size ok THEN
;             IF access to buffer THEN
;               CASE 
;                   NORMAL SENSE
;                    fill in the buffer from data in the UCB
;                    save IOSB data and exit via EXE$FINISHIO
;
;                   BROADCAST
;                     read broadcast information in the UCB
;                     save IOSB information and exit via EXE$FINISHIO
;
;                   TYPE-AHEAD 
;                     IF requestor's PID is not device owner PID THEN
;                        allocate a request buffer via PT_BUILD_REQUEST
;                        fill in the request buffer
;                        queue request to the application I/O queue 
;                          via EXE$INSERTIRP
;                        see if can deliver request to Screen Manager 
;                          via PT_POST_MSG
;                        return to the QIO dispatcher via EXE$QIORETURN
;                     ELSE
;                        save error return status SS$_ILLIOFUNC and abort
;                          via EXE$ABORTIO
;                     ENDIF
;
;                   READ-MODEM
;                     read modem information in the UCB
;                     save IOSB information and exit via EXE$FINISHIO
;
;               ENDCASE
;
;             ELSE
;               save error return SS$_ACCVIO and abort via EXE$ABORTIO
;             ENDIF
;
;             ELSE
;               save error return SS$_BADPARAM and abort via EXE$ABORTIO
;             ENDIF
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_SENSE:
	PT_DEBUG PT_SENSE_D			; Macro to enable/disable
						;   XDELTA debugging support
	JSB	PT_SEN_ARG_VALID		; Validate sense aruments 
						;   R0 - Status
						;   R1 - buffer address
						;   R2 - buffer size
	BLBS	R0,10$				; Continue is success
	BRW	PT_SENSE_ABORT		 	; Branch to common abort code
 
;+
; Determine if special action needed if not do normal case
;-
10$:	BITW	#<IO$M_TYPEAHDCNT!	-	; Check if any special cases
		  IO$M_RD_MODEM!	-	;
		  IO$M_BRDCST>,		-	;
		IRP$W_FUNC(R3)			;
	BNEQ	PT_SENSE_DISPATCH		; Skip if special case
 
	MOVL	UCB$B_DEVCLASS(R5),(R1)		; Store class, type and buffer 
						;   size	
	MOVL	UCB$L_DEVDEPEND(R5),4(R1)	; Store primary charcteristics
	CMPL	R2,#12				; Requested secondary char?
	BLSSU	20$				;
	MOVL	UCB$L_DEVDEPND2(R5),8(R1)	; Store secondary char
	TSTL	UCB$L_AMB(R5)			; Associated mailbox?
	BEQL	20$		     		;
   	BISL	#TT2$M_DCL_MAILBX,8(R1)		; Acssociated mailbox set bit
20$: 	BRW	PT_SENSE_FINISH 		; Branch to finish path  

;+
; Dispatch to correct action routine
;-
PT_SENSE_DISPATCH:				; Dispatch for other options
	BBS	#IO$V_BRDCST,IRP$W_FUNC(R3), -	; Broadcast?
		PT_SENSE_BRDCST			;
	BBS	#IO$V_TYPEAHDCNT,	-	; Type-ahead?
		IRP$W_FUNC(R3),PT_SENSE_TYPAHD	;
	BRW	PT_SENSE_MODEM			; Must be sense modem

;+
; Get broadcast information
;-
PT_SENSE_BRDCST:
     	MOVQ	UCB$Q_TL_BRKTHRU(R5),(R1)	; Store broadcast message types
    	BRW	PT_SENSE_FINISH			; Branch to finish path  

;+
; Get type-ahead count
;-
PT_SENSE_TYPAHD:
	CMPL	IRP$L_PID(R3),		-	; Check that requestor is
		UCB$L_PT_SM_PID(R5)		;   not device owner
	BNEQ	10$				; 
	MOVZWL	#SS$_ILLIOFUNC,R0		; Device owner not allowed
						;   to do this request type
	BRB	PT_SENSE_ABORT			;
 
    	ASSUME	<RBF_K_LEN_FIXED-RBF$K_SYS_SIZE> GE 8	; Make sure request
      							;   buffer large enough
							;   to hold type-ahead
							;   response
10$:	MOVL	R1,R0				; Store users buffer Address
						;   for build request
	MOVL	#RBF_K_LEN_FIXED,R1		; Store buffer size
	JSB	PT_BUILD_REQUEST		; Allocate & fill in fixed
						;   part of request buffer
	BLBC	R0,PT_SENSE_ABORT		;
	BISW2	#<IRP$M_FUNC!IRP$M_TERMIO>,-	; Force I/O post processing
		IRP$W_STS(R3)			;   to copy system buffer
   						;   back to users buffer, and
						;   compute priority boost
	MOVL	#8,IRP$L_BCNT(R3)		; Set returned buffer size
    	MOVL	#<RBF_K_LEN_FIXED-RBF$K_SYS_SIZE>,-	; Fill in the request 
		RBF_L_SIZE(R2)				;   buffer size
	MOVAB	UCB$L_PT_APP_IOQFL(R5),R2	; Get queue head address
	DSBINT	UCB$B_DIPL(R5)			; Disable interrupts
	JSB	G^EXE$INSERTIRP			; Insert request in queue
	ENBINT					; Allow interrupts again
	JSB	PT_POST_MSG			; See if Screen Manager
						;   request to post
	JMP	G^EXE$QIORETURN			; All done exit QIO call

;+
; Get modem data
;-
PT_SENSE_MODEM:
       	MOVQ	UCB$Q_PT_MODEM(R5),(R1)		; Store modem data and fall 
						;   through to finish code

;+
; Common exit code paths for finish I/O with success, and abort
;-
PT_SENSE_FINISH:
	MOVL	UCB$B_PT_XMIT_SPEED-2(R5),R0 	; Store speed data in IOSB
       	MOVL	UCB$B_PT_CRFILL(R5),R1		; Store fill and parity in IOSB
	MOVW	#SS$_NORMAL,R0			; Store success
	JMP	G^EXE$FINISHIO			; Finish I/O 
 
PT_SENSE_ABORT:
	JMP	G^EXE$ABORTIO			; Abort QIO call  

;+
; This routine reads and validate the sense function arguments
; -
PT_SEN_ARG_VALID:
	MOVL	P1(AP),R1			; Address of users buffer
      	IFNOWRT	#8,(R1),20$			; Branch if no access to 
						;   quadword buffer
	MOVL	#8,R2				; Assume default buffer size
	CLRQ	(R1)				; Clear out buffer
	MOVL	P2(AP),R2			; Get buffer size
	CMPL	R2,#12				; Buffer size ok?
	BLSSU	10$				; 
	BGTRU	30$				; 
	IFNOWRT	#12,(R1),20$			; Branch if no access to buffer
	CLRL	8(R1)				; Clear last longword of buffer
 
10$:	MOVW	#SS$_NORMAL,R0			; Store success code
	RSB	 				;
 
20$:	MOVZWL	#SS$_ACCVIO,R0			; Store access violation error
	RSB					; 
 
30$:	MOVZWL	#SS$_BADPARAM,R0		; Store bad parameter error
	RSB 

	.SBTTL	PT_QUEUEAST, Deliver ASTs for specified control character
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_QUEUEAST	Deliver ASTs for specified control character
;
;	Description:
;		This routine will deliver all outstanding ASTs for a supplied
;	control character.  The routine first checks for an out-of-band
;	AST for the character.  It then looks for CTRL/C or CTRL/Y ASTs
;	for the supplied character.
;
;	Execution requirements:
;		$QIOW 	func = IO$_QUEUEAST
;			chan = SCREEN_MANAGER_CHANNEL
;			iosb = QUEUEAST_IOSB
;			p1   = QUEUEAST_CHARACTER
;
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;		P1(AP)	- Control character to be checked
;
;	Outputs:
;
;		UCB	The following fields in the UCB may be changed:
;
;			UCB$L_TL_CTLPID
;			UCB$L_PT_CTRLC
;			UCB$L_PT_CTRLY
;
;	The routine must preserve R3 - R8.
;
;	Data structures:
;
;		None
;
;	External references:
;
;	COM$DELATTNASTP	- Deliver attention ASTs
;	COM$DELCTRLASTP	- Deliver out-of-band ASTs
;	EXE$ABORTIO	- Abort an I/O operation
;	EXE$FINISHIOC	- Complets an I/O operation with only R0 status
;
;
;	Special notes:
;
;		Routine raises IPL to device IPL to prevent disruption of
;	queues by applicaton process.  This routine will destroy R6 permanetly
;	if in the future need R6 then must perserve it.
;
;--
;+
;	Module Algorithm:
;	   BEGIN
;
;          IF requestors PID and device owners PID match THEN
;             check that control character is valid
;             IF character valid THEN
;                IF control character has enabled ASTs THEN
;                   count number of matches also note if character is to
;                     be included in data stream
;                   post all out-of-band asts via COM$DELCTRLASTP
;                 ENDIF
;
;                 IF control character is CTRL/C or THEN
;                    assume using CTRL/C queue
;                    IF CTRL/C queue empty THEN
;                       use CTRL/Y queue
;                    ENDIF
;                 ELSEIF character is CTRL/Y THEN
;                       use CTRL/Y queue
;                 ENDIF
;
;                 IF queue specified and
;                    character is included or
;                    no ASTs delivered already THEN
;                    count number of ASTs
;                    deliver ASTs via COM$DELATTNASTP
;                 ENDIF
;                 IF no ASTs delivered THEN
;                    save return status SS$_NOTQUEUED and exit EXE$FINISHIOC
;                 ELSE
;                    save return status SS$_NORMAL and AST count and exit
;                      via EXE$FINISHIOC
;                 ENDIF
;             ELSE
;               store error return SS$_BADPARAM and abort via EXE$ABORTIO
;             ENDIF
;          ELSE
;            save error return status SS$_ILLIOFUNC and abort via EXE$ABORTIO
;          ENDIF
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_QUEUEAST:
	PT_DEBUG PT_QUEUEAST_D			; Macro to enable/disable
						;   XDELTA debugging support
	CMPL	IRP$L_PID(R3),		-	; Are we the device owner?
		UCB$L_PT_SM_PID(R5)		;
	BEQL	10$				;
	MOVZWL	#SS$_ILLIOFUNC,R0		; Store error reason
    	BRW	120$				; Not owner branch to abort code
 
10$:	CMPB	P1(AP),#31			; Check if valid control code
	BLEQU	20$				; 
	MOVZWL	#SS$_BADPARAM,R0		; Store error reason
    	BRW	120$				; Bad param branch to abort code
 
20$: 	CLRL	R1				; Clear out mask storeage
	MOVZBL	P1(AP),R8			; Get AST character
	BISL2	R8,R1				; Set mask character
	DSBINT	UCB$B_DIPL(R5)			; From here on need to block
						;   interrupts to prevent
						;   AST queues from changing
		  				;   while we are using them
	CLRQ	R9				; Clear out temporary for
						;   counting ASTs and noting
						;   if include flag set
      	BBC	R1,			-	; Out-of-band AST for this char?
		UCB$L_PT_OUTBAND_MASK(R5),50$	;
	
;+
; If here must have valid AST character so loop through queue of ASTs and 
;   count the matches.  Also note if this character included in data stream
;-
	MOVAB	UCB$L_PT_OUTBAND_QUEUE(R5),R0	; Store address of queue
 
30$:	MOVL	(R0),R0				; Address of block
	BEQL	40$				; All done
	SUBL3	#TAST$L_FLINK,R0,R2		; Address of start of block
   	BBC	R1,TAST$L_MASK(R2),30$		; If no match look for next AST
	INCL	R9				; Increment count of characters
	BBC	#TAST$V_INCLUDE,	-	; Is character included?
		TAST$B_CTRL(R2),30$		;
	BISB2	#1,R10				; Note that we have an included
						;   character
	BRB	30$				;
 
40$:	PUSHL	R3				; Save IRP address
	MOVL	R8,R3				; Save character
	MOVAB	UCB$L_PT_OUTBAND_QUEUE(R5),R4	; Get queue head address
	MOVL	UCB$L_TL_CTLPID(R5),R6		; Store device controller PID 
      						;   used to deliver ASTs by PID
	JSB	G^COM$DELCTRLAST		; Deliver out-of-band ASTs
	POPL	R3				; Restore IRP address
 
;+
; If here now look to see if we are doing CTRL/C or CTRL/Y
;-
50$:	CMPB	#3,R8				; Is this a CTRL/C?
	BNEQ	60$				;
	MOVAB	UCB$L_PT_CTRLC(R5),R4		; Assume CTRL/C
	TSTL	(R4)				; Is queue empty?
	BNEQ	70$				;
	MOVAB	UCB$L_PT_CTRLY(R5),R4		; Use CTRL/Y for CTRL/C	
						;   as no CTRL/C specified
	BRB	70$				; No try and queue it
 
60$:	CMPB	#25,R8				; Is character CTRL/Y?
	BNEQ	100$ 				;
	MOVAB	UCB$L_PT_CTRLY(R5),R4		; Use CTRL/Y queue
 
70$:	TSTL   	(R4)				; Is queue specified?
	BEQLU	100$				;
    	MOVL	R4,R0				; Save queue address
	TSTL	R9				; Any ASTs already delivered?
	BEQL	80$				;
	BBC	#0,R10,100$			; Was the CTRL/C,Y included?
 
80$:	MOVL	(R0),R0				; Get queue entry
	BEQL	90$				; No more
	INCL	R9				; incremet count
	BRB	80$				; Look for more
 
90$:	MOVL	UCB$L_TL_CTLPID(R5),R6		; Store device controller PID 
      						;   used to deliver ASTs by PID
	JSB	G^COM$DELATTNAST		; Deliver Attention ASTs
 
;+
; Determine what status messages to return
;-
100$:	TSTL	R9				; Any ASTs delivered?
	BNEQ	110$				;
   	MOVZWL	#SS$_NOTQUEUED,R0		; Store no AST delivered msg
 	ENBINT					; Allow interrupts
	JMP	G^EXE$FINISHIOC			; Finish I/O
 
110$:	CVTLW	R9,R0				; Store number of ASTs delivered
      	ASHL	#16,R0,R0			; Move to high word 
	MOVW	#SS$_NORMAL,IRP$L_IOST1(R3)	; Store success
	ENBINT					; Allow interrupts
	JMP	G^EXE$FINISHIOC			; Finish I/O
 
;+
; Common path for aborting requests
;-
 
120$:	JMP	G^EXE$ABORTIO

	.SBTTL	PT_SETATTN, Enable attention AST
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_SETATTN	Enable attention AST
;
;	Description:
;		This routine services a Screen Manager request to enable
;	an attention AST. The attention AST is delivered when the application
;	process cancels its I/O requests.
;
;	Execution requirements:
;		$QIOW 	func = IO$_SETATTN
;			chan = SCREEN_MANAGERS_CHANNEL
;			iosb = SETATTN_IOSB
;			p1   = AST_ROUTINE_ADDRESS
;			p2   = AST_PARAMETER
;			p3   = AST_MODE
;
;	Inputs:
;
;		R0-R2	- scratch registers
;		R3	- address of the IRP (I/O request packet)
;		R4	- address of the PCB (process control block)
;		R5	- address of the UCB (unit control block)
;		R6	- address of the CCB (channel control block)
;		R7	- bit number of the I/O function code
;		R8	- address of the FDT table entry for this routine
;		R9-R11	- scratch registers
;		AP	- address of the 1st function dependent QIO parameter
;
;	Outputs:
;
;		
;	The routine preserves registers R3-R8
;
;	Data structures:
;
;	None
;
;	External references:
;
;		COM$POST	-	complete an I/O request
;		EXE$QIORETURN	-	return from FDT routine with success
;		PT_POST_MSG	-	check and post pending requests to
;					 Screen Manager
;	Special notes:
;
;	None
;--
;+
;	Module Algorithm:
;	BEGIN
;
;	IF requestor's PID and device owner PID match THEN
;	   IF device's attention AST field is zero THEN
;		store SS$__NORMAL in IRP return status
;	   ELSE
;		store SS$__WASSET in IRP return status
;	   	CALL COM$FLUSHATTNS to remove and deallocate
;		  the present AST
;	   END IF
;	   CALL COM$SETATTNAST to set the attention AST
;	   Post requester's IRP
;	ELSE
;	   store SS$_ILLIOFUNC
;	   CALL EXE$ABORTIO to abort this request
;	END IF
;	CALL EXE$QIORETURN to return to the FDT routine with success
;
;	END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_SETATTN:
	PT_DEBUG PT_SETATTN_D			; Macro to enable/disable
						;   XDELTA debugging support
	CMPL	IRP$L_PID(R3),UCB$L_PT_SM_PID(R5) ; are we the device owner
	BEQL	10$				; Yes, then move on
 
	MOVL	#SS$_ILLIOFUNC,R0		; Not owner
	CLRL	R1				; 0 bytes transferred
	JMP	G^EXE$FINISHIO			; puts R0, R1 in caller's IOSB
						; and returns through QIO
10$:
	MOVAL	UCB$L_PT_ATTN(R5),R7		; R7 => list head
	MOVL	(R7),R0				; already an attn AST set ?
	BNEQ	20$
	MOVL	#SS$_NORMAL,R0			; indicate no AST already
	BRB	30$
20$:
	MOVZWL	IRP$W_CHAN(R3),R6		; channel to flush
	JSB	G^COM$FLUSHATTNS		; get rid of it
	MOVL	#SS$_WASSET,R0			; indicate AST already enabled
30$:
	PUSHL	R0
	JSB	G^COM$SETATTNAST		; enable new AST
	BLBC	R0,40$				; did it work
 
	POPL	R0				; IOSB return
	CLRL	R1				;
40$:
	JMP	G^EXE$FINISHIO			; puts R0, R1 in caller's IOSB

	.SBTTL	PT_CANCEL, Cancel I/O Requests on a Channel
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_CANCEL	Cancel I/O Requests on a Channel
;
;	Description:
;		This routine receives control when either the Screen Manager
;	or an application process issues a $DASSGN, $DALLOC, or $CANCEL VMS
;	system service.
;		If called on behalf of an application process; cancel all
;	outstanding I/O requests on the specified channel, flush ASTs, and
;	if enabled, deliver an attention AST to the Screen Manager.
;		If called on behalf of the Screen Manager; cancel all
;	outstanding I/O requests on the specified channel.
;	
;	Execution requirements:
;
;	Inputs:
;
;		R0-R1	- Scratch
;		R2	- negated channel number
;		R3	- address of UCB's active IRP
;		R4	- address of PCB
;		R5	- address of UCB
;		R8	- cancel reason code, one of:
;			  CAN$C_CANCEL if invoked by $CANCEL or $DALLOC
;			  CAN$C_DASSGN if invoked by $DASSGN
;	Outputs:
;
;		UCB$L_PT_CTRLY	- header of list
;		UCB$L_PT_CTRLC	- header of list
;		UCB$L_PT_OUTBAND_QUEUE - header of list
;		UCB$L_PT_OUTBAND_MASK  - bit mask indicating ASTs enabled
;		UCB$L_IRP	- pointer to current active IRP
;		UCB$L_PT_APP_BRK_IOQXX - IRP queue header 
;		UCB$L_PT_APP_IOQXX     - IRP queue header 
;		UCB$L_PT_SM_IOQXX      - IRP queue header 
;		UCB$L_PT_ATTN	- pointer to SM attention AST
;		UCB$W_PT_DEVSTATUS     - bit UCB$M_PT_CANCEL set
;		IRP$L_IOST1	- current active IRP <- SS$_ABORT
;				   all other IRPs <- SS$_CANCEL
;
;	This routine preserves all registers except R0-R3
;
;	Data structures:
;		None
;
;	External references:
;
;		COM$DELATTNAST	- 	deliver AST
;		COM$FLUSHATTNS	-	flush all ASTs on a channel
;		COM$FLUSHCTRLS	-	flush out-of-band ASTs on a channel
;		COM$POST	-	complete an IO request
;		PT_POST_MSG	-	check and post pending requests to
;					 Screen Manager
;;	Special notes:
;		None
;--
;+
;	Module Algorithm:
;
;	IF (UCB$W_REFC equal 0) THEN
;	   UCB$L_PID = UCB$L_PT_SM_PID
;	END IF
;	IF requestor's PID and UCB's owner PID match THEN
;	   CALL COM$FLUSHATTNS to flush the ATTN AST
;	   DO FOR each IRP in the UCB's owner IO queue
;		CALL COM$POST to abort the IO request with
;		 reason SS$_CANCEL
;	   END DO
;	   CALL PT_POST_MSG to check and post a pending Get IO
;	      request if one exists
;	ELSE
;	   IF this routine is invoked from $DASSGN THEN
;		CALL COM$FLUSHATTNS to flush all CTRLY ASTs
;	   END IF
;	   CALL COM$FLUSHATTNS to flush all CTRLC ASTs
;	   CALL COM$FLUSHCTRLS to flush all out-of-band ASTs
;	END IF
;	DO FOR each IRP in the UCB's application break-through IO queue
;	   IF IRP channel matches Cancel channel AND
;	      IRP PID matches requestor PID            THEN
;		CALL COM$POST to abort the IO request with reason SS$_CANCEL
;	   END IF
;	END DO
;	DO FOR each IRP in the UCB's application IO queue
;	   IF IRP channel matches Cancel channel AND
;	      IRP PID matches requestor PID            THEN
;		CALL COM$POST to abort the IO request with reason SS$_CANCEL
;	   END IF
;	END DO
;	IF UCB's active IRP PID matches requestor PID  THEN
;	   IF IRP channel matches Cancel channel THEN
;		CALL COM$POST to abort the IO request with reason SS$_CANCEL
;		clear the busy bit in the UCB
;		set the cancel bit in the UCB
;		CALL PT_POST_MSG to check and post a pending Get_IO request
;		 if one exists
;	      IF the device owner has enabled ATTN AST THEN
;		CALL COM$DELATTNAST to deliver the ATTN AST to the device's
;		   owner
;	      END IF
;	   END IF
;	END IF
;	RETURN
;	END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_CANCEL:					; flush I/O on a channel
	PT_DEBUG PT_CANCEL_D			; Macro to enable/disable
						;   XDELTA debugging support
 
	PUSHR	#^M<R6,R7,R9,R10,R11>
	MOVL	R2,R6				; copy of channel number
	MOVL	PCB$L_PID(R4),R11		; requestor's PID
 
	DSBINT	UCB$B_DIPL(R5)			; don't let us be interrupted
;+
;  If device reference count is 0 then restore creators PID to owners PID
;  this insures that creator gets his quota returned when UCB is deleted
;-
	TSTW	UCB$W_REFC(R5)	      		; is reference count 0
	BNEQ	1$				; NO, goto 1$
 
  	MOVL	UCB$L_PT_SM_PID(R5),UCB$L_PID(R5)  ; YES, restore creators PID
 
1$:
	CMPL	R11,UCB$L_PT_SM_PID(R5) 	; are we the Screen Manager
	BNEQ	10$				; NO, goto to 10$
;+
;  Flush the attn AST and abort all waiting SM IO requests
;-
	MOVAL	UCB$L_PT_ATTN(R5),R7		; R7 => attn listhead
	JSB	G^COM$FLUSHATTNS		; flush attn AST
 
	MOVAL	UCB$L_PT_APP_BRK_IOQFL(R5),R10	; R10 => IRP listhead
	JSB	FLUSH_IRPS			; Kill the IRPs
 
	MOVAL	UCB$L_PT_SM_IOQFL(R5),R10	; R10 => IRP listhead
	JSB	FLUSH_IRPS			; Kill the IRPs
 
	BRW	DONE				; get out of here
;+
;  If we are the UCB's Application then flush ^Y, ^C and out-of-band ASTs.
;-
10$:
	CMPB	#CAN$C_DASSGN,R8		; CANCEL or DASSGN
	BNEQ	20$				; IF CANCEL goto 20$
 
	MOVAL	UCB$L_PT_CTRLY(R5),R7		; R7 => ^Y listhead
	JSB	G^COM$FLUSHATTNS		; flush ^Y ASTs
20$:
	MOVAL	UCB$L_PT_CTRLC(R5),R7		; R7 => ^C listhead
	JSB	G^COM$FLUSHATTNS		; flush ^C ASTs
 
	MOVAL	UCB$L_PT_OUTBAND_QUEUE(R5),R7	; R7 => out-of-band listhead
	MOVAL	UCB$L_PT_OUTBAND_MASK(R5),R2	; R2 <- Unit out-of-band mask
	JSB	G^COM$FLUSHCTRLS		; flush out-of-band ASTs
;+
;  Abort all I/O requests made by the requestor on specified channel.
;-
30$:
	MOVAL	UCB$L_PT_APP_BRK_IOQFL(R5),R10	; R10 => breakthrough listhead
	JSB	FLUSH_IRPS			; Kill the IRPs
 
	MOVAL	UCB$L_PT_APP_IOQFL(R5),R10	; R10 => normal IRP listhead
	JSB	FLUSH_IRPS			; Kill the IRPs
;+
;  Abort UCB currently active IRP.
;-
35$:	MOVL	UCB$L_IRP(R5),R3		; abort active IRP
	BEQL	DONE				; No current IRP
 
	CMPL	R11,IRP$L_PID(R3)		; requestor own the IRP ?
	BNEQ	DONE				; No, then ignore it
	CMPW	R6,IRP$W_CHAN(R3)		; requestor's channel ?
	BNEQ	DONE				; No, then ignore it
 
	CLRL	UCB$L_IRP(R5)			; no more active IRP
 
	BISW	#UCB$M_PT_CANCEL,UCB$W_PT_DEVSTATUS(R5)	; cancel has been done !
	BICW	#UCB$M_PT_BUSY,UCB$W_PT_DEVSTATUS(R5)	; not busy any more
 
	MOVZWL	#SS$_ABORT,IRP$L_IOST1(R3)
	CLRL	IRP$L_IOST2(R3)
	JSB	G^COM$POST			; kill the IRP
;+
;  If the SM has an ATTN AST enabled then deliver it, informing him that the
;   application has cancelled.
;-
	TSTL	UCB$L_PT_ATTN(R5)		; attention AST enabled ?
	BEQL	40$				; No, goto 40$
 
	PUSHL	R4				; Yes, save PCB pointer
	MOVAL	UCB$L_PT_ATTN(R5),R4		; R4 => attn listhead
	JSB	G^COM$DELATTNAST		; deliver the attn AST
	POPL	R4				; restore PCB pointer
40$:
	JSB	PT_POST_MSG			; keep the ball rolling
;+
;  Exit back to CANCEL or DASSGN
;-
DONE:
	ENBINT					; clean up and leave
	POPR	#^M<R6,R7,R9,R10,R11>
	RSB
;+
;  FLUSH_IRPS - post IRPs by channel and PID
;
;	Post all IRPs which match the input PID and channel number.
;
;  INPUTS:
;	R6  - channel number
;       R10 - IRP queue head
;	R11 - PID
;
;  OUTPUTS:
;	R0 - R3, R9 are trashed.
;-
FLUSH_IRPS:
	MOVL	R10,R9				; save listhead
10$:
	MOVL	(R9),R9				; get next IRP
	CMPL	R9,R10				; are we at the end??
	BEQL	20$				; Yes, then return
	CMPW	IRP$W_CHAN(R9),R6		; IRP channel right ?
	BNEQ	10$				; No, try next IRP
	CMPL	IRP$L_PID(R9),R11		; IRP PID right ?
	BNEQ	10$				; No, try next IRP
 
	REMQUE	(R9),R3				; remove IRP from UCB
	MOVL	4(R3),R9			; R9 => IRP's predecessor
	MOVZWL	#SS$_CANCEL,IRP$L_IOST1(R3)	; set value for IOSB
	CLRL	IRP$L_IOST2(R3)
	JSB	G^COM$POST			; kill the IRP
 
	BRB	10$				; get next IRP
20$:
	RSB					; RETURN to caller

	.SBTTL	PT_POST_MSG, Post applications request to Screen Manager
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_POST_MSG		Routine to post applications request to 
;			the Screen Manager
;
;	Description:
;		This routine is called by every terminal driver function
;	as well as PT_GETIO, PT_FINISHIO, and PT_CANCEL to deliver 
;	outstanding applications request to the Screen Manager.
;
;	Execution requirements:
;		JSB	PT_POST_MSG
;
;	Inputs:
;
;		R5	- address of the UCB (unit control block)
;
;	Outputs:
;
;
;		UCB	The following fields in the UCB may be changed:
;
;			UCB$L_IRP
;			UCB$L_PT_APP_IOQFL
;			UCB$L_PT_APP_IOQBL
;			UCB$L_PT_APP_BRK_IOQFL
;			UCB$L_PT_APP_BRK_IOQBL
;			UCB$L_PT_SM_IOQFL
;			UCB$L_PT_SM_IOQBL
;			UCB$W_PT_DEVSTATUS
;			UCB$B_PT_ALTERED_CHARS
;
;		IRP	The following fields in the IRPs may be changed:
;
;			IRP$L_IOST1
;			IRP$L_IOST2
;			IRP$L_BCNT
;
;	The routine preserves all registers except R0-R2.
;
;	Data structures:
;               None
;
;	External references:
;
;		COM$POST	Post an IRP to the I/O post processing queue
;
;	Special notes:
;
;		This routine will not return any status information indicating
;	the success or failure of this operation.
;
;--
;+
;	Module Algorithm:
;	   BEGIN
;
;          IF device not busy and 
;             entry in application's I/O queue or
;             entry in application's break through I/O queue and
;             entry in Screen Manager's I/O queue THEN
;
;            IF the Screen Manager's buffer is large 
;               enough for the application request buffer THEN
;
;              mark the device as busy
;              remove entries from both queues
;              copy the application's request buffer to the 
;              Screen Manager's buffer
;              fill in the Screen Manager's IOSB
;              post the Screen Manager's request via COM$POST
;
;              IF request is a SET or WRITE THEN
;                fill in the appication's IOSB
;                post the application's request via COM$POST
;                set the device not busy
;              ENDIF
;
;            ELSE
;              store error status SS$_BUFFEROVF and needed buffer size
;              in IOSB and post Screen Manager's request via COM$POST
;            ENDIF
;
;          ENDIF
;
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
PT_POST_MSG:
	PT_DEBUG PT_POST_MSG_D			; Macro to enable/disable
						;   XDELTA debugging support
	BBC 	#UCB$V_PT_BUSY,	      	-	; Is device free ?
		UCB$W_PT_DEVSTATUS(R5),10$	;
	BRW	90$				; Device busy
10$:	DSBINT	UCB$B_DIPL(R5)			; Prevent interruption while
						;   handling queues
	MOVAB	UCB$L_PT_APP_BRK_IOQFL(R5),R0	; Get address of break through
					  	;   queue head
	CMPL	R0,UCB$L_PT_APP_BRK_IOQBL(R5)	; Is queue empty?
	BNEQ	20$				;
	MOVAB	UCB$L_PT_APP_IOQFL(R5),R0	; Get address of regular
						;   I/O queue head
	CMPL	R0,UCB$L_PT_APP_IOQBL(R5)	; Is queue empty?
	BNEQ	20$				;
	BRW	80$				; Queue empty exit
20$: 	REMQUE	@UCB$L_PT_SM_IOQFL(R5),R1	; Remove Screen Manager
						;   I/O request
	BVC	30$				; Got IRP continue
	BRW	80$				; Queue empty exit
30$:	MOVL	(R0),R2				; Get IRP address
	MOVL	IRP$L_SVAPTE(R2),R2		; Get request buffer address
	CMPW	IRP$W_BOFF(R1),RBF_L_SIZE(R2)	; Get I/O request large enough?
	BGEQU	40$				; Large enough continue
	BRW	70$				; Not large enough
 
;+
; Request ok so set up and send back screen managers request.
;
;	R0 - address of applications IRP (after REMQUE instruction)
;	R1 - address of Screen Managers IRP
;	R2 - address of application request buffer
; 
;-
40$:	BISW	#UCB$M_PT_BUSY,		-	; Mark device busy
		UCB$W_PT_DEVSTATUS(R5)		;
	BICW	#UCB$M_PT_CANCEL,	-	; Clear cancel bit
		UCB$W_PT_DEVSTATUS(R5)		;
	REMQUE	@(R0),R0			; Remove I/O request
	MOVL	R0,UCB$L_IRP(R5)		; Store applications IRP
						;   address in UCB
	BBCC	#UCB$V_PT_NEWCHAR,	-	; Clear changed characteristics
		UCB$W_PT_DEVSTATUS(R5),50$	;   bit
	MOVB	UCB$B_PT_ALTERED_CHARS(R5), -	; Store mask of altered
		RBF_B_CHAR_FLAG(R2)		;   characteristics
   	CLRB	UCB$B_PT_ALTERED_CHARS(R5)	; Clear mask for future use
50$: 	PUSHR	#^M<R0,R1,R2,R3,R4,R5>		; MOVC3 uses R0 - R5
    	MOVL	#RBF$K_SYS_SIZE,R3		; Store sys buffer header size
	MOVC3	RBF_L_SIZE(R2),	 	-	; Store request buffer into
		RBF_L_SIZE(R2),		-	;   Screen Managers buffer
		@IRP$L_SVAPTE(R1)[R3]		;
	POPR	#^M<R0,R1,R2,R3,R4,R5>		; Restore registers
	MOVL	RBF_L_SIZE(R2),IRP$L_BCNT(R1)	; Store number of bytes
						;   to return to Screen Manager
	MOVW	#SS$_NORMAL,IRP$L_IOST1(R1)	; Set up successful return
	CVTLW	RBF_L_SIZE(R2),	 	-	; Size of transfer
		IRP$L_IOST1+2(R1)		;  
	CLRL	IRP$L_IOST2(R1)			; Clear device specific part 
						;   of IOSB
	PUSHR	#^M<R0,R3>			; Save registers destroyed
						;   by posting IRP
    	MOVL	R1,R3				; Store Screen Managers IRP 
						;   address for posting
	JSB	G^COM$POST			; Post Screen Managers IRP
   	POPR	#^M<R0,R3>			; Restore registers
 
;+
; Complete applications request immediately? 
;
;	R0 - address of applications IRP
;	R2 - will be used to hold application function code only
;
; -
	BICW3	#^C<IO$M_FCODE>,	-	; Get function code only
		IRP$W_FUNC(R0),R2 		;
	CMPW	#IO$_WRITEVBLK,R2		; Write virtual block ?
	BEQL    60$				;
	CMPW	#IO$_WRITELBLK,R2		; Write logical block ?
	BEQL	60$				;
	CMPW	#IO$_WRITEPBLK,R2		; Write Physical block ?
	BEQL	60$				;
	CMPW	#IO$_SETMODE,R2			; Set mode ?
	BEQL	60$				;
	CMPW	#IO$_SETCHAR,R2			; Set char ?
	BNEQ	80$				;
60$:    CLRL	UCB$L_IRP(R5)			; Clear application IRP
						;   address from UCB
	BICW	#UCB$M_PT_BUSY,		-	; Clear busy bit 
		UCB$W_PT_DEVSTATUS(R5)		;
	CLRL	IRP$L_BCNT(R0)			; Clear byte count field
						;   so I/O post processing
						;   does not attempt to
						;   return request buffer
						;   to users buffer
	MOVL 	R3,R2				; Save callers R3
	MOVL	R0,R3				; Store applications IRP
						;   address for posting
	JSB	G^COM$POST			; Post application IRP
	MOVL	R2,R3				; 
	BRB	80$				;
	
;+ 
; Get I/O buffer to small set up error status and return request.
;
;	R1 - address of Screen Managers IRP
;	R2 - address of applications request buffer
;
;-	
70$:	MOVW	#SS$_BUFFEROVF,IRP$L_IOST1(R1)	; Store error reason
	CVTLW	RBF_L_SIZE(R2),		-	; Store needed buffer size
		IRP$L_IOST1+2(R1)		;
	CLRL	IRP$L_IOST2(R1)			; Clear device specific part 
						;   of IOSB
	CLRL	IRP$L_BCNT(R1)			; Zero byte count 
	MOVL	R3,R2				; 
	MOVL	R1,R3				; Store IRP address 
	JSB	G^COM$POST			; Post Screen Managers request
	MOVL	R2,R3				; Restore caller IRP address
 
80$:
	ENBINT					; Allow interrupts again
90$:
	RSB					; All done exit

	.SBTTL	PT_BUILD_REQUEST, Allocate and partially fill a Request Buffer
.IF DEFINED SUPPRESS_HEADER
.NLIST
.ENDC
; =============================================================================
;++
;
;	PT_BUILD_REQUEST	Allocate and partially fill a Request Buffer
;
;	Description:
;		Allocate a buffer from non-paged pool and fill in the
;	general Request Buffer fields.
;
;	Execution requirements:
;
;	Inputs:
;
;		R0		- address of user's buffer
;		R1		- size of buffer to allocate
;		R3		- address of IRP
;		AP		- pointer to QIO device dependent args
;
;	Outputs:
;
;		R0		- SS$_NORMAL if successful
;             			- LBC unsuccessful return from EXE$BUFFRQUOTA
;             			- LBC unsuccessful return from EXE$ALLOCBUF
;		R1		- size of buffer allocated (requested size
;				   rounded up to 16 byte multiple)
;		R2		- address of allocated buffer
;		IRP$W_BOFF	- size of buffer allocated
;		IRP$L_SVAPTE	- pointer to buffer allocated
;
;	The routine preserves registers R3-R11.
;
;	Data structures:
;		RBF		- system header and general Request Buffer
;				   fields are filled
;
;	External references:
;		EXE$ALLOCBUF	- allocate block of non-paged pool
;		EXE$BUFFRQUOTA	- verify process has quota for buffer allocation
;
;	Special notes:
;		The I/O function code is obtained from the QIO argument list,
;		 because the copy in the IRP has been changed slightly by QIO.
;		It is the responsibility of the caller to ensure the
;		 request size is greater than the size of a general
;		 Request Buffer + size of system buffered I/O header.
;		Must be called at FDT default IPL (IPL$_ASTDEL).
;		EXE$BUFFRQUOTA may place the process in a resource wait
;		 if resource wait mode is enabled and buffer usage is
;		 too large.
;		There are 3 size fields (all are in bytes)
;			1)  IRP$L_BOFF	- size of request buffer allocated
;			2)  IRP$L_BCNT	- size of requested I/O transfer
;			3)  RBF_L_SIZE	- size of request buffer used
;		 This routine sets IRP$L_BOFF, it is the responsibility
;		 of the caller to set the other two.
;--
;+
;	Module Algorithm:
;	   BEGIN
;		IF requestor has enough buffer I/O quota THEN
;		   allocate system buffer
;		   IF allocation is successful THEN
;			charge the requestor's buffer 
;			zero the buffer
;			fill in general Request Buffer fields
;			fill in IRP fields
;		   END IF
;		END IF
;		RETURN
;	   END
;
;-
; =============================================================================
.IF DEFINED SUPPRESS_HEADER
.LIST

.ENDC
	BR_EFN	=	0  - 24		; QIO arguments
	BR_CHAN	=	4  - 24
	BR_FUNC	=	8  - 24		; <== this is the guy we really
	BR_IOSB	=	12 - 24		;     want, since AP points to P1,
	BR_AST	=	16 - 24		;     FUNC has a negative offset
	BR_APRM =	20 - 24
	BR_P1	=	24 - 24		; <== AP
 
PT_BUILD_REQUEST:
	PT_DEBUG PT_BUILD_REQUEST_D		; Macro to enable/disable
						;   XDELTA debugging support
	PUSHL	R11				; save R11
	CMPL	R1,#RBF_K_LEN_FIXED		; requesting buffer big enough
	BGEQ	5$				; Yes, continue
	MOVZWL	#^C<SS$_NORMAL>,R0		; No, return failure code
	BRB	10$
5$:
	MOVL	R0,R11				; save pointer to user buffer
	MOVQ	R2,-(SP)
	JSB	G^EXE$BUFFRQUOTA		; check for enough buff quota
	MOVQ	(SP)+,R2
	BLBC	R0,10$				; exceed quota report to caller
 
	PUSHL	R3				; EXE$ALLOCBUF destroys this
	JSB	G^EXE$ALLOCBUF			; get size rounded up to 16 mult
	POPL	R3				; get IRP address back
	BLBC	R0,10$				; didn't work? get out of here
 
	MOVL	PCB$L_JIB(R4),R0		; get JIB
	SUBL	R1,JIB$L_BYTCNT(R0)		; charge buffer quota
 
	PUSHR	#^M<R1,R2,R3,R4,R5>		; save for dirty MOVC5
 
	SUBL	#RBF$K_SYS_SIZE,R1		; clean size allocated, after
	MOVC5	#0,#0,#0,	-		;  EXE$ALLOCBUF header
		R1,RBF$K_SYS_SIZE(R2)
 
	POPR	#^M<R1,R2,R3,R4,R5>		; restore pointers
;+
; fill in the system header and general Request Buffer fields
;-
	MOVAB	RBF_L_SIZE(R2),RBF$L_DATA_AREA(R2) ; top of buff => data area
	MOVL	R11,RBF$L_USR_BUF(R2)		; 2nd long word => user buffer
						; next word <- size of buffer
						; (filled in by EXE$ALLOCBUF)
	MOVZWL	BR_FUNC(AP),RBF_L_FUNC_CODE(R2)	; I/O function code
	MOVL	IRP$L_PID(R3),RBF_L_PID(R2)	; set the requestors PID
;+
; fill in IRP description of buffer
;-
	MOVW	R1,IRP$W_BOFF(R3)		; size in IRP for quota
	MOVL	R2,IRP$L_SVAPTE(R3)		; set pointer to buffer
 
	MOVL	#SS$_NORMAL,R0			;
10$:
	POPL	R11				; restore before leaving
	RSB

	.SBTTL	PT_END
 
;+
; Label that marks the end of the driver
;-
 
PT_END:						; Last location in driver
	.END
