Google
 

Trailing-Edge - PDP-10 Archives - bb-d868c-bm_tops20_v4_2020_distr - language-sources/d60jsy.mac
There are 66 other files named d60jsy.mac in the archive. Click here to see a list.
;<DN65-DEVELOPMENT>D60JSY.MAC.3, 18-Oct-79 15:19:52, Edit by JENNESS
; [203] Decouple D60UNV from D60JSY because of QSRMAC deadly embrace.
;<DN65-DEVELOPMENT>D60JSY.MAC.2,  9-Oct-79 14:26:28, Edit by JENNESS
; [202] Add code in D60CND to support transparent transmission enabling
;       for HASP lines.
;<DN65-DEVELOPMENT>D60JSY.MAC.256,  7-Sep-79 10:19:19, Edit by JENNESS
; [201] Remove edit 175 .. the BOOT JSYS has been fixed.
;<DN65-DEVELOPMENT>D60JSY.MAC.252,  4-Sep-79 15:29:44, Edit by JENNESS
; [200] Remove CONLY conditionals, remove QSRMAC symbol conflicts.
;<DN65-DEVELOPMENT>D60JSY.MAC.250,  4-Sep-79 13:50:44, Edit by JENNESS
; [177] Change arg block to condition call again .. make it QUASAR setup block.
;<DN65-DEVELOPMENT>D60JSY.MAC.249, 15-Aug-79 09:43:42, Edit by JENNESS
; [176] Change D6DNU error so that IBMSPL can turn it off in NBIO.
;<DN65-DEVELOPMENT>D60JSY.MAC.248, 14-Aug-79 09:17:23, Edit by JENNESS
; [175] Change 2020 read routine to do it's own byte pointer updating,
;	the BOOT JSYS doesn't do it.
;<DN65-DEVELOPMENT>D60JSY.MAC.247, 16-Jul-79 14:11:56, Edit by JENNESS
; [174] Add external HOOKing code, gives access to guts of this package.
;<DN65-DEVELOPMENT>D60JSY.MAC.246, 11-Jul-79 16:17:53, Edit by JENNESS
; [173] Give D6DNU (DSR not up) on D60OPN call at appropriate times.
;<DN65-DEVELOPMENT>D60JSY.MAC.244,  5-Jul-79 15:28:28, Edit by JENNESS
; [172] Give reject error code when DN6x gives no bytes read with success code.
;<DN65-DEVELOPMENT>D60JSY.MAC.240,  2-Jul-79 16:25:45, Edit by JENNESS
; [171] Fix another dumb bug in FEI%O for TOPS10.
;<DN65-DEVELOPMENT>D60JSY.MAC.238, 29-Jun-79 13:58:07, Edit by JENNESS
; [170] Another fix for 2780/3780 input/output deadlock race on input EOF.
;<DN65-DEVELOPMENT>D60JSY.MAC.237, 29-Jun-79 13:22:48, Edit by JENNESS
; [167] Typo fix in FEI%O for TOPS10.
;<DN65-DEVELOPMENT>D60JSY.MAC.235, 29-Jun-79 09:04:39, Edit by JENNESS
; [166] Change the ERRS macro to give DDT type out of the error values.
;<DN65-DEVELOPMENT>D60JSY.MAC.235, 29-Jun-79 09:00:27, Edit by JENNESS
; [165] Fix REQOUT to relieve the lost output grant.
;<DN65-DEVELOPMENT>D60JSY.MAC.233, 28-Jun-79 17:59:05, Edit by JENNESS
; [164] Fix to stop deadlock interaction between console and LPT under 3780.
;<DN65-DEVELOPMENT>D60JSY.MAC.231, 26-Jun-79 09:00:59, Edit by JENNESS
; [163] Swap the line signature and line driver type in line status, makes it
;	easier for front end to clear an old LCB.
;<DN65-DEVELOPMENT>D60JSY.MAC.230, 25-Jun-79 16:24:37, Edit by JENNESS
; [162] Change last D6DOL in REQOUT to a D6CGO .. fixes console deadly embrace.
;<DN65-DEVELOPMENT>D60JSY.MAC.229, 25-Jun-79 09:33:46, Edit by JENNESS
; [161] Another fix in edit 153 when DTE is already selected.
;<DN65-DEVELOPMENT>D60JSY.MAC.225, 21-Jun-79 10:41:06, Edit by JENNESS
; [160] Fix the horrible mess made when releasing devices on disabled lines.
;<DN65-DEVELOPMENT>D60JSY.MAC.224, 21-Jun-79 08:53:45, Edit by JENNESS
; [157] Fix REQOUT to check for line gone away in DSRLP.
;<DN65-DEVELOPMENT>D60JSY.MAC.225, 19-Jun-79 09:43:59, Edit by JENNESS
; [156] Fix a problem in OPNFE caused by edit 153 when FEJFN already open.
;<DN65-DEVELOPMENT>D60JSY.MAC.223, 18-Jun-79 13:11:44, Edit by JENNESS
; [155] Change FEI%O for TOPS10 to use reentrant type C11BLKs.
;<DN65-DEVELOPMENT>D60JSY.MAC.222, 15-Jun-79 16:44:48, Edit by JENNESS
; [154] Fix a glaring error in SRCPDD that has been there forever.
;<DN65-DEVELOPMENT>D60JSY.MAC.221, 14-Jun-79 16:54:35, Edit by JENNESS
; [153] Change a little in OPNFE to jump to SELDTE if JFN already assigned.
;<DN65-DEVELOPMENT>D60JSY.MAC.220, 14-Jun-79 15:22:36, Edit by JENNESS
; [152] Add code to release all devices opened on a D60CND line disable.
;<DN65-DEVELOPMENT>D60JSY.MAC.211, 12-Jun-79 13:54:04, Edit by JENNESS
; [151] Add printx to output name, version and other sundries during assembly.
;<DN65-DEVELOPMENT>D60JSY.MAC.209, 12-Jun-79 11:37:27, Edit by JENNESS
; [150] Append line and device command strings to FEI%O arg block. Get rid of
;	the ALC1WD and RLS1WD routines.
;<DN65-DEVELOPMENT>D60JSY.MAC.209, 12-Jun-79 11:36:40, Edit by JENNESS
; [147] Change the status string symbols so SWAPB and SWAP32 aren't needed.
;<DN65-DEVELOPMENT>D60JSY.MAC.208, 12-Jun-79 09:45:35, Edit by JENNESS
; [146] Move some more symbols into the D60JSY.UNV universal file.
;<DN65-DEVELOPMENT>D60JSY.MAC.206, 11-Jun-79 11:19:10, Edit by JENNESS
; [145] Fix a bug in D60SOUT (bad load) and add IOWAIT to SNOOZE in REQOUT.
;<DN65-DEVELOPMENT>D60JSY.MAC.204,  8-Jun-79 09:40:54, Edit by JENNESS
; [144] Add return immediate code in FEI%O to stop blocking on console read.
;<DN65-DEVELOPMENT>D60JSY.MAC.203,  7-Jun-79 17:20:51, Edit by JENNESS
; [143] Change in REQIN to reduce the possibility of a race.
;<DN65-DEVELOPMENT>D60JSY.MAC.202,  7-Jun-79 15:33:57, Edit by JENNESS
; [142] Change status formats to reflect more frontend bullet proofing.
;<DN65-DEVELOPMENT>D60JSY.MAC.199,  7-Jun-79 10:55:08, Edit by JENNESS
; [141] Fix D60SOUT for errors that are appropriate the running flag is cleared
;<DN65-DEVELOPMENT>D60JSY.MAC.197,  7-Jun-79 10:36:37, Edit by JENNESS
; [140] Some fixes for line status failure and a D60RLS on dead lines.
;<DN65-DEVELOPMENT>D60JSY.MAC.196,  7-Jun-79 09:37:23, Edit by JENNESS
; [137] Fix a problem in REQIN that failed it input was already running.
;<DN65-DEVELOPMENT>D60JSY.MAC.194,  6-Jun-79 16:42:57, Edit by JENNESS
; [136] Fix a bug in the DSR wait loop in REQOUT.
;<DN65-DEVELOPMENT>D60JSY.MAC.193,  6-Jun-79 09:32:56, Edit by JENNESS
; [135] Add IOWAIT argument to the SNOOZE macro for task descheduling.
;<DN65-DEVELOPMENT>D60JSY.MAC.191,  4-Jun-79 09:21:51, Edit by JENNESS
; [134] Dump output buffers (in 11) if outputing to a console device.
;<DN65-DEVELOPMENT>D60JSY.MAC.187,  1-Jun-79 10:58:38, Edit by JENNESS
; [133] Add code to handle new line hardware abort checking.
;<DN65-DEVELOPMENT>D60JSY.MAC.184, 30-May-79 16:18:50, Edit by JENNESS
; [132] Don't clear aborts in REQIN/REQOUT, now only set for valid reasons.
;<DN65-DEVELOPMENT>D60JSY.MAC.183, 30-May-79 13:32:02, Edit by JENNESS
; [131] More fixes for device error handling and input/output deadlock.
;<DN65-DEVELOPMENT>D60JSY.MAC.176, 25-May-79 16:23:21, Edit by JENNESS
; [130] Handle aborts caused by line disconnection.
;<DN65-DEVELOPMENT>D60JSY.MAC.175, 24-May-79 15:14:16, Edit by JENNESS
; [127] Fix D60EOF and the line releasing code for 2780/3780.
;<DN65-DEVELOPMENT>D60JSY.MAC.172, 23-May-79 15:21:46, Edit by JENNESS
; [126] Fix D60OPN to properly handle errors on the device commands.
;<DN65-DEVELOPMENT>D60JSY.MAC.172, 23-May-79 15:21:22, Edit by JENNESS
; [125] Have found some more holes in the FE releasing.
;<DN65-DEVELOPMENT>D60JSY.MAC.168, 21-May-79 11:41:31, Edit by JENNESS
; [124] More fixes for properly releasing FE devices.
;<DN65-DEVELOPMENT>D60JSY.MAC.167, 21-May-79 09:38:50, Edit by JENNESS
; [123] Add structure block sizes in universal file.
;<DN65-DEVELOPMENT>D60JSY.MAC.165, 21-May-79 09:36:35, Edit by JENNESS
; [122] Another fix in REQOUT to release the line when input is coming.
;<DN65-DEVELOPMENT>D60JSY.MAC.161, 17-May-79 18:11:01, Edit by JENNESS
; [121] Fix so FE is properly released if DTE select fails.
;<DN65-DEVELOPMENT>D60JSY.MAC.160, 16-May-79 11:21:33, Edit by JENNESS
; [120] Fix write routine to release FE for a second after lot of data output.
;<DN65-DEVELOPMENT>D60JSY.MAC.159, 16-May-79 11:11:28, Edit by JENNESS
; [117] Change ENQD60 to block until lock is gained. Gives higher lock hits.
;<DN65-DEVELOPMENT>D60JSY.MAC.157, 16-May-79 09:22:10, Edit by JENNESS
; [116] Remove copy code for 8 bit DDCMP buffer, now can handle real byte ptrs.
;<DN65-DEVELOPMENT>D60JSY.MAC.152, 14-May-79 14:51:26, Edit by JENNESS
; [115] Add line signature code.
;<DN65-DEVELOPMENT>D60JSY.MAC.146, 10-May-79 12:42:28, Edit by JENNESS
; [114] Fix so delays from the FE on line commands resend command correctly.
;<DN65-DEVELOPMENT>D60JSY.MAC.145, 10-May-79 11:17:39, Edit by JENNESS
; [113] Change location of $FELOG logging calls in FEI%O.
;<DN65-DEVELOPMENT>D60JSY.MAC.144, 10-May-79 10:20:00, Edit by JENNESS
; [112] Add require for FELOG when FTDEBUG switch is turned on.
;<DN65-DEVELOPMENT>D60JSY.MAC.143,  3-May-79 09:57:26, Edit by JENNESS
; [111] And yet another fix for the deadlock problem, release if REQOUT fails.
;<DN65-DEVELOPMENT>D60JSY.MAC.141,  2-May-79 14:29:16, Edit by JENNESS
; [110] Another fix to stop input/output deadlocks on 2780/3780.
;<DN65-DEVELOPMENT>D60JSY.MAC.140,  1-May-79 16:48:50, Edit by JENNESS
; [107] Increase retry counter for BOOT JSYS retry on input.
;<DN65-DEVELOPMENT>D60JSY.MAC.139,  1-May-79 16:33:52, Edit by JENNESS
; [106] Some code clean up, more on the abort problem, and really use D60CGO.
;<DN65-DEVELOPMENT>D60JSY.MAC.137, 30-Apr-79 12:57:04, Edit by JENNESS
; [105] Fix input request code to block less and add better errors to D60CND.
;<DN65-DEVELOPMENT>D60JSY.MAC.133, 25-Apr-79 16:18:22, Edit by JENNESS
; [104] Put in error checks after device and line status calls.
;<DN65-DEVELOPMENT>D60JSY.MAC.129, 25-Apr-79 13:47:32, Edit by JENNESS
; [103] Fix so that the line isn't released if the device goes off line.
;<DN65-DEVELOPMENT>D60JSY.MAC.127, 25-Apr-79 08:25:46, Edit by JENNESS
; [102] Add device command in D60OPN to do space compression.
;<DN65-DEVELOPMENT>D60JSY.MAC.124, 24-Apr-79 14:39:33, Edit by JENNESS
; [101] Add code to ENQ/DEQ line for 2780/3780 so only 1 device can be active
;	at a time.
;   D60JSY - Interface package for DN62/DN65 Galaxy IBM spooling system

;
;
;			  COPYRIGHT (c) 1979
;                    DIGITAL EQUIPMENT CORPORATION
;
;     This software is furnished under a license and may  be  used
;     and copied only in accordance with the terms of such license
;     and with the inclusion of the above copyright notice.   This
;     software  or any other copies thereof may not be provided or
;     otherwise made available to any other person.  No  title  to
;     and ownership of the software is hereby transferred.
;
;     The information  in  this  software  is  subject  to  change
;     without  notice  and should not be construed as a commitment
;     by DIGITAL EQUIPMENT CORPORATION.
;
;     DIGITAL assumes no responsibility for the use or reliability
;     of  its  software  on  equipment  which  is  not supplied by
;     DIGITAL.
;
;	TITLE	D60JSY	DN62/DN65 interface to GALAXY spooling components.

	SALL				; Make nice clean listings

	.DIRECTIVE FLBLST		; List only 1st binary word in multi
					;  word text strings

	SEARCH	GLXMAC			; Use GALAXY group's macros/symbols
	SEARCH	QSRMAC			; Symbols for setup message
	SEARCH	D60UNV			; Search for linkage symbols
	PROLOGUE (D60JSY)		; Initialize Galaxy symbol definitions

; Version

	XP	D60VER,	3		; Major version number
	XP	D60MIN,	0		; Minor version number
	XP	D60EDT,	203		; Edit level
	XP	D60WHO,	0		; Who did last edit (0=DEC)

; Conditional assembly flags.

	ND	FTDEBUG, 0		; If on .. then generate debuging code

	ND	FTNDNU,	0		; Normally give the D6DNU error.

IFN FTDEBUG,<.REQUIRE FELOG>		; Get CAL11. logger if debugging

; Version

	%%.D60=:<VRSN. (D60)>		; Set value of edit level/version

; Print information to log during compilation

Define VOUTX ($S1,$S2,$S3,$S4)
 <TITLE $S1 $S2'$S3'('$S4')
  PRINTX $S1 $S2'$S3'('$S4')>

IF1,<
 IFN <D60MIN>,<VOUTX (D60JSY interface package,\D60VER,\"<"A"+D60MIN>,\D60EDT)>
 IFE <D60MIN>,<VOUTX (D60JSY interface package,\D60VER,,\D60EDT)>

 IFN <FTDEBUG>,<PRINTX Debug code enabled.>
 .IF SNOOZE,MACRO,<PRINTX External SNOOZE macro definition being used.>

 .IF HOOK,MACRO,<PRINTX External HOOK has been defined.
	HOOK			; Invoke the HOOK
     > ;End if HOOK defined
    > ;End IF1
	SUBTTL	Misc. definitions

	XP	SEC,	^d1000		; 1000 milliseconds in a second
	XP	TIMOFF,	^d3		; Time off to wait for 11 to be freed
	XP	TIMDLY,	^d1		; Time waiting for delayed to clear
	XP	TIMSTS,	^d2		; Time waiting on delayed status
	XP	OFLDFL,	^d10		; Default number of delay to offline
	XP	RQREP,	^d10		; Times to check input permission req
	XP	RQTIM,	^d1		; Sleep time between input per req chk
	XP	RQOTIM,	^d30		; Number of seconds to wait for DSR
	XP	SOTDLY,	^d1		; Sleep time between output grant chks
	XP	RQDTRY,	^d10		; Times to chk after output req. drops
	XP	TIMDSR,	^d1500		; Time to wait between DSR check (ms)
	XP	DTEOFF,	10		; Offset from port number to DTE number
	XP	MAXDTE,	13		; Maximum DTE number
	XP	MAXFE,	15		; Maximum number of FE's on system
	XP	MXNHSP,	5		; Maximum device type on 2780/3780
	XP	MXHSP,	6		; Maximum device type on HASP
	XP	MXUHSP,	4		; Maximum unit number on HASP
	XP	HSPOFF,	20		; HASP multiple device offset
	XP	RLSTHR,	^d2000		; FE device transfer release threshold
	SUBTTL	Error symbol definitions

; Use the previously defined macros in D60JSY.UNV to set up the error symbol
; values.

	D60ERR				; Invoke the error symbol macro
	SUBTTL	Macros -- ERT, Snooze

; Macro - ERT
;
; Function - To set an error code in S1 and jump to the specified exit vector.
;
; Parameters -
;
;	$%ERR	Error number (usually a D6xxx mnemonic)
;	$%VEC	Where to jump to after S1 is loaded with the error number

	Define ERT ($%ERR,$%VEC)

<[MOVX	S1,$%ERR		;; Load the error number to return
  IFNB <$%VEC>,<SETZ TF,	;; Set success flag to failure (false)
		JRST $%VEC>	;; If a jump vector given .. then jump there
  IFB  <$%VEC>,<JRST @.RETF>	;;  else give a default of false return
	]
   > ;End of ERT definition


; Macro - Snooze
;
; Function - To put the process to sleep for the specified amount of time.
;
; Parameters -
;
;	$%TIM	# of milli-seconds to sleep
;	$%DUM	Dummy argument (used by externally defined SNOOZE's)
;
; Note -
;
;	This macro is used to dismis the process because of a event wait. If
;	the host program wishes to instead of sleeping reschedule an internal
;	task this macro should be defined in a file that will prefix this one
;	during assembly. This macro generates code that is non-skipable and
;	will always preserve the intergrity of the registers.

.IFN SNOOZE,MACRO,<
	Define SNOOZE ($%TIM,$%DUM)

<	MOVX	S1,$%TIM		;; Get number of milliseconds to sleep
TOPS10 <SLEEP	S1,>			;; Use SLEEP MUUO on TOPS10
TOPS20 <DISMS>				;;  and on TOPS20 dismiss the process
					;;  for the number of mS given.
    > ;End SNOOZE definition
   > ;End if SNOOZE not defined
	SUBTTL	Macros -- $LNCMD, $DVCMD

; Macro - $LNCMD
;
; Function - To set up the arguments to the line command routine (LINCMD)
;
; Parameters -
;
;	$%CMD	Command number
;	$%VEC	Where to vector to on command failure

	Define $LNCMD ($%CMD,$%VEC)

<	MOVX	S1,$%CMD		;; Load the command number
	$CALL	LINCMD			;; Call the line command routine
IFNB <$%VEC>,<JUMPF $%VEC>		;; Command failure .. jump
    > ;End $LNCMD definition

; Macro - $DVCMD
;
; Function - To set up the arguments to the device command routine (DEVCMD)
;
; Parameters -
;
;	$%CMD	Command number
;	$%VEC	Where to vector to on command failure

	Define $DVCMD ($%CMD,$%VEC)

<	MOVX	S1,$%CMD		;; Load the command number
	$CALL	DEVCMD			;; Call the device command routine
IFNB <$%VEC>,<JUMPF $%VEC>		;; Command failure .. jump
    > ;End $DVCMD definition
	SUBTTL	Macros -- $FELOG

; Macro - $FELOG
;
; Function - This macro generates the conditional code, depending on value
;	     of FTDEBUG, for writing entries to the CAL11. log file. Before
;	     TOPS20 style entries can be logged, they must be first converted
;	     to CAL11. style which is done by the external routine FELOG.
;	     Under TOPS10 the CAL11. block is assumed pointer to by P3 and
;	     the C11LOG external routine is called.
;
; Parameters -
;
;	$%PHSE	Phase of logging, "BEFORE" or "AFTER"

	Define $FELOG ($%PHSE)

<IFN FTDEBUG,<				;; If debugging enabled
	%%.PHS==0			;; Init to no phase defined yet
	IFIDN <$%PHSE>,<BEFORE>,<%%.PHS==1b1> ;; Before CAL11.
	IFIDN <$%PHSE>,<AFTER>, <%%.PHS==1b0> ;; After CAL11.
	IFE %%.PHS,<IF1,<PRINTX $FELOG called with illegal phase: "'$%PHSE'">>

	JRST	[MOVX	T4,%%.PHS	;; Load the phase value
		 TDNN	T4,DBGFLG#	;; Check for this phase being logged
		  JRST	.+1		;;  No .. continue on main line
TOPS20 <	 $CALL	FELOG##>	;; Yes .. call external log converter
TOPS10 <	 IOR	T4,P3		;; Point to the CAL11. argument block
		 $CALL	C11LOG##>	;; Call directly to logger
		 JRST	.+1]		;; Return to main line

	PURGE	%%.PHS			;; Kill the extraneous symbol
    >> ;End $FELOG definition
	SUBTTL	Global routine -- D60INI

; Routine - D60INI
;
; Function - To initialize internal data bases to the D60 communication package.
;	This routine assumes that a "RESET" has already been done that will
;	clear all ENQ/DEQ requests/entries and all device/JFN assignments.
;
; Parameters - none

	ENTRY	D60INI

D60INI:	$SAVE	<S1,S2>			; Save registers
TOPS20< MOVEI	S1,LOCALS		; Get location of local data base
	LSH	S1,-^d9			; Convert to page number
	HRLI	S1,.FHSLF		; This process handle
	MOVX	S2,PA%RD+PA%WT+PA%EX+PA%CPY
	SPACS				; Change locals to COPY-ON-WRITE
	 ERJMP	@.RETF			;  on failure .. give error return
	MOVEI	S1,ENDLOC		; Get where the locals end
	LSH	S1,-^d9			; Convert to a page number
	HRLI	S1,.FHSLF		; Point to this process
	MOVX	S2,PA%RD+PA%WT+PA%EX+PA%CPY
	SPACS				; Change up to end of locals to C-O-W

	SETZM	FEJFN			; Clear the JFN for I/O to the FE
	SETZM	LSTDTE			; Clear the last DTE to be selected.
    >; End if TOPS20

	SETOM	HANLST			; Clear the handle list name
ININHN:
TOPS20 <MOVX	S1,.DEQDA		; Dequeue all locks for this process
	DEQ>
TOPS10 <HRLI	S1,.DEQDA		; Dequeue all locks for this job
	DEQ.	S1,>
	 JFCL				;  No relevant errors can occur

TOPS20 <MOVX	S1,.FHSLF		; Point to this process again
	MOVX	S2,LSTRX1		; No last error, error code
	SETER>				; Clear any error up to this point

	$RETT				; It worked (it should).
	SUBTTL	Global routine -- D60OPN

; Routine - D60OPN
;
; Function - To setup a device on a remote station (or link up to 360/370) and
;	define a unique handle that will describe this link.
;
; Parameters -
;
;	S1/	-Count of argument block
;	S2/	Location of open block
;
;		or
;
;	S1/	Dev-type,,Unit
;	S2/	Port,,Line
;
;	The device type codes are:
;	  1=LPT, 2=CDP, 3=CDR, 4=Console in, 5=Console out, 6=Signon
;
;	Format of open block:
;
;	ARGBLK/   Dev-type,,Unit
;	ARGBLK+1/ Port,,Line
;	ARGBLK+2/ Line signature
;
; Returns -
;
;	True	S1/ Handle used for referencing the device
;	False	S1/ Error code
;

	ENTRY	D60OPN

D60OPN:	$SAVE	<S2,T1>			; Save registers
	ACVAR	<SIG>			; Local storage for line signature
	SETZ	SIG,			; Clear line signature
	JUMPG	S1,OPN.1		; If open block type parameters
	 LOAD	SIG,(S2),OP$SIG		;  Get line signature
	 ANDI	SIG,177777		;  Clear to only 16 bits worth
	 LOAD	S1,(S2),OP$DEV		;  Get device and unit number
	 LOAD	S2,(S2),OP$STA		;  Get port and line number
OPN.1:	$CALL	PCKPDD			; Make up the PDD for the device
	MOVE	T1,S1			; Put in another reg for safe keeping
	SKIPGE	S1,HANLST		; Check for handle list already started
	 $CALL	L%CLST			;  and make one up if not
	MOVEM	S1,HANLST		; Save the handle list name
	MOVE	S1,T1			; Get the PDD of this device and
	$CALL	SRCPDD			;  check to see if it already exists
	 JUMPT	ERT (D6AUT,OPNDIE)	;  Error .. the device being used by us
	MOVE	S1,HANLST		; Get the name of the handle list
	$CALL	L%LAST			; Point after the last entry in list
	MOVE	S1,HANLST		; Get name again in case no entries
	MOVX	S2,H$SIZ		; Load in size of a handle list entry
	$CALL	L%CENT			;  and create one.
	STORE	T1,(S2),H$PDD		; Save the PDD in this list entry
	LOAD	T1,(S2),H$DEV		; Get the generic device number
	MOVE	S1,DEFTHR		; Get the default offline threshold
	CAIE	T1,.OPCIN		; If either the console input
	CAIN	T1,.OPCOU		;  or the console output
	 MOVX	S1,1			;   set to very short offline threshold
	STORE	S1,(S2),H$THR		;  and save it for this device
	SETO	S1,			; Initially set the bytes per message
	STORE	S1,(S2),H$BPM		;  to +infinity to force I/O
	LOAD	S1,(S2),H$PRT		; Get the port number
	CAIGE	S1,DTEOFF		; Do we have a DL10 # (0-7)
	 JRST	OPNDL			;  Yes .. so go validate the DL10 #
	CAILE	S1,MAXDTE		; Check to see if the DTE # is ok
	 JRST	ERT (D6NSP,OPNDIE)	;  No .. it's too large
	JRST	PRTOK			; This port is valid.
OPNDL:					; On -10's DL10's are valid
TOPS20 <MOVX	S1,D6NSP		; No such port (no DL10 on -20)
	JRST	OPNDIE>			;  and go release the list entry
PRTOK:	LOAD	S1,(S2),H$PRT		; Get the port from the PDD
	STORE	S1,(S2),H$HPR		;  put into the handle
	LOAD	S1,(S2),H$PDD		; Get the packed device descriptor
	$CALL	ENQDEV			; Enqueue the device (until released)
	 JUMPF	ERT (D6AUA,OPNDEQ)	;  Someone else already has it
	$CALL	OPNFE			; Go open a FE (-10 check for 11 up)
	 JUMPF	ERT (D6COF,OPNDEQ)	;  Can't open a front end
	$CALL	PRTSTS			; Get the port status
	 JUMPF	ERT (D6COF,OPNDEQ)	;  Can't get port status .. dead 11
	LOAD	S1,,S6LIN		; Get the maximum line number
	LOAD	T1,(S2),H$LIN		; Get the line number we want
	CAILE	T1,(S1)			; Check to see if in range
	 JRST	ERT (D6NSL,OPNDEQ)	;  No such line on this port
	LOAD	S1,,S6TRN		; Get the translation options
	TXNN	S1,TR$IBM		; Does the DN60 support IBM stuff?
	 JRST	ERT (D6PIU,OPNDEQ)	;  No ... this port is useless
	$CALL	LINSTS			; Get the line status
	 JUMPF	OPNDEQ			;  Someone died .. go release device
IFE FTNDNU,<
	LOAD	T1,,SLINF		; Get line info
	TXNN	T1,SLDSR		; Check for line dialed up (DSR set)
	 JRST	ERT (D6DNU,OPNDEQ)	;  No .. so give error
    > ;End if not FTNDNU
	LOAD	T1,,SLSIG		; Get line signature
	$CALL	SWAPB			; Move the bytes around
	CAIE	T1,(SIG)		; Check against given line signature
	 JRST	ERT (D6BLS,OPNDEQ)	;  Bad line signature .. refuse open
	STORE	SIG,(S2),H$SIG		; Save the line signature for device
	LOAD	S1,,SLTYP		; Get the remote station type
	STORE	S1,(S2),H$STY		; Save the station type in list entry
	CAIN	S1,SLHSP		; Test to see if it is a HASP station
	 JRST	OPNHSP			;  Yes .. go create HASP device code
	LOAD	S1,(S2),H$UNT		; Get the unit number on 2780/3780
	JUMPN	S1,ERT (D6UNS,OPNDEQ)	;  Can't give a unit number on non-HASP
	LOAD	S1,(S2),H$DEV		; Get the device code
	CAILE	S1,MXNHSP		; Check for max device on non-HASP
	 JRST	ERT (D6UND,OPNDEQ)	;  Unknown device
	STORE	S1,(S2),H$HDV		; Store as the unique device number
	SETZ	S1,			; All devices are really 0 on 2780/3780
	STORE	S1,(S2),H$CDV		; Store the -11 device com. number
	JRST	OPNDFD			; Device found ok .. continue

OPNHSP:	LOAD	S1,(S2),H$DEV		; Get the device code
	CAILE	S1,0			; Check to see if the device type is
	CAILE	S1,MXHSP		;  in range for a HASP station
	 JRST	ERT (D6UND,OPNDEQ)	;   No .. unknown device type
	MOVE	T1,[XWD 0,4		; Translate OPN numbers to DN60 device
		    XWD 0,5		;  numbers used when talking to -11
		    XWD	0,3
		    XWD	0,2
		    XWD 0,1
		    XWD	0,3]-1(S1)
	STORE	T1,(S2),H$CDV		; Store as the -11 com. device number
	MOVE	T1,[SDLP1		; Component code for a LPT
		    SDCP1		;  or a CDP (card punch)
		    SDCR1		;  or a CDR (card reader)
		    SDCIN		;  or a input console
		    SDCOU		;  or a output console
		    SDSON]-1(S1)	;  or a sigon device
	LOAD	S1,(S2),H$UNT		; Get unit of device-type to select
	CAILE	S1,MXUHSP		; Check against maximum number of units
	 JRST	ERT (D6UND,OPNDEQ)	;  Too bad .. unknown unit
	IMULI	S1,HSPOFF		; Multiply by the unit offset
	ADD	S1,T1			; Get the final device selection code
	STORE	S1,(S2),H$HDV		; Store as the unique device number

OPNDFD:	LOAD	S1,(S2),H$LIN		; Get the line number from the PDD
	STORE	S1,(S2),H$HLN		;  put into handle to complete it.
	LOAD	T1,,SLFLG		; Get line status flags
	LOAD	T1,T1,SLETF		; Get termination/emulation flag
	STORE	T1,(S2),H$TEM		; Save it in the handle list entry

	$CALL	SETIOM			; Set the input/output mode of device
	$DVCMD	(DC.COE,OPNDEQ)		; Clear output EOF flag
	$DVCMD	(DC.CIE,OPNDEQ)		; Clear input EOF flag
;	$DVCMD	(DC.COA,OPNDEQ)		; Clear output abort
;	$DVCMD	(DC.CIA,OPNDEQ)		; Clear input abort

	LOAD	S1,(S2),H$TEM		; Get the emulation/termination flag
	JUMPE	S1,OPNSEM		; Jump if we want to do termination
	$DVCMD	(DC.SCI,OPNDEQ)		;  Set interpret CC on input
	$DVCMD	(DC.CCO,OPNDEQ)		;  Clear inpterpret CC on output
	JRST	OPNOV1			; Continue on

OPNSEM:	$DVCMD	(DC.CCI,OPNDEQ)		; Clear interpret CC on input
	$DVCMD	(DC.SCO,OPNDEQ)		; Set interpret CC on output
	LOAD	S1,(S2),H$DEV		; Get device type
	SETZ	T1,			; Clear return immediate
	CAIN	S1,.OPCOU		; Unless a console (output from IBM)
	 SETO	T1,			;  Then set return immediate flag
	STORE	T1,(S2),H$RTI		; Store return immediate for FEI%O

OPNOV1:	LOAD	S1,(S2),H$STY		; Get the station type
	CAIN	S1,SLHSP		; If it is HASP then go give 
	 JRST	OPNHP2			;  component code
	CAIN	S1,SL278		; Check for 2780 type station
	 JRST	OPN278			;  Yes .. go set proper protocol
	$DVCMD	(DC.C27,OPNDEQ)		; Use new protocol for 3780
	JRST	OPNOV3			; Go clear the component code

OPN278:	$DVCMD	(DC.S27,OPNDEQ)		; Use the old protocol for 2780
OPNOV3:	$DVCMD	(DC.DCC,OPNDEQ)		; 2780/3780 so don't use component code
	$DVCMD	(DC.CSC,OPNDEQ)		; Clear space compression flag
	JRST	OPNOV2			; Continue again

OPNHP2:	LOAD	T1,(S2),H$HDV		; Get the device code from handle
	$DVCMD	(DC.SCC,OPNDEQ)		; Specify component code
	$DVCMD	(DC.C27,OPNDEQ)		; Don't use old protocol
	$DVCMD	(DC.SSC,OPNDEQ)		; Set space compression flag

OPNOV2:	MOVX	T1,^d82			; Currently set to 82.
	STORE	T1,(S2),H$BPM		; Save as the bytes per message
	$CALL	SWAPB			; Swap bytes in 16 bit word
	$DVCMD	(DC.BPR,OPNDEQ)		; Set bytes per record of device

	LOAD	S1,(S2),H$HAN		; Get the handle to pass back

	$RETT				; Return saying success

;
; Here when the open has failed and we need to release (Dequeue) the device.
;

OPNDEQ:	PUSH	P,S1			; Save the error code
	LOAD	S1,(S2),H$PDD		; Get the packed device descriptor
	$CALL	DEQDEV			;  and release the device
	SKIPA				; Now go destroy the list entry
;
; Here when the open fails and we need to delete the entry in the handle list
;  that we have created temporarily for this open attempt.
;
OPNDIE:	PUSH	P,S1			; Save the error code
	MOVE	S1,HANLST		; Get the handle list name
	$CALL	L%DENT			; Delete the current entry
	POP	P,S1			; Restore the error code
	$RETF				;  and give the false return
	SUBTTL	Global routine -- D60SIN

; Global routine - D60SIN
;
; Function - To input a string from a remote station device.
;
; Parameters -
;
;	S1/	Handle of remote device (gotten from D60OPN)
;	S2/	Byte pointer to where string is to be read into
;	T1/	Negative byte count to be read


	ENTRY	D60SIN

D60SIN:	ACVAR	<ARGI>			; Allocate register for input arg block
	MOVE	ARGI,S1			; Save the handle temporarily
	$CALL	ALCARG			; Allocate an FEI%O arg block
	EXCH	ARGI,S1			; Swap them back

	STORE	S2,(ARGI),ARG$PT	; Save the byte pointer to input area
	STORE	T1,(ARGI),ARG$BC	; Save the byte count	
	JUMPGE	T1,ERT (D6CNN,SINFAI)	; Test for illegal byte count
	MOVX	T1,FC.RD		; Function to read from device
	STORE	T1,(ARGI),ARG$FC	; Put into I/O argument block
	HRRZS	S1			; Clear the flags in left half
	$CALL	SRCHAN			; Look for handle on handle entry list
	 JUMPF	ERT (D6NSH,SINFAI)	;  Illegal handle
	LOAD	S1,(S2),H$IOM		; Get the input/output mode
	JUMPE	S1,ERT (D6DCI,SINFAI)	;  Device can't do input
	LOAD	S1,(S2),H$RUN		; Get the input running flag
	JUMPN	S1,SINGO		;  If yes then go do some input
	$CALL	LCKLIN			; Lock the line from use (2780/3780)
	 JUMPF	 ERT (D6DOL,SINBAD)	;  Can't .. offline
	$CALL	REQIN			; Go check on input request
	 JUMPF	SINFAI			;  If input grant failed .. return

SINGO:	MOVE	S1,ARGI			; Point to the argblk for FE I/O
	$CALL	FEI%O			; Do the input
	 JUMPF	SINREJ			;  If failed .. check for EOF
	LOAD	S1,(S2),H$HAN		; Get the handle back on success
	JRST	SINSUC			; Set the true flag and return

SINREJ:	$CALL	CKIABT			; Check for input abort
	 JUMPF	SINFAI			;  Yes .. go release and clean up
	TXNE	T1,SDSUS		; Is the device suspended? (HASP)
	 JRST	[MOVX	S1,D6DOL	;  Yes .. so device is offline
		 JRST	SINBAD]		;  Go say that still there, but offline
	TXNE	T1,SDIEC		; Did an EOF occur?
	 JRST	[$DVCMD	(DC.CIE)	;  Yes .. clear EOF complete flag
		 MOVX	S1,D6EOF	;  Set EOF code
		 JRST	SINFAI]		;  Close off line and shutdown device

	LOAD	T1,(ARGI),ARG$RC	; Get the result code from FEI%O
	CAIN	T1,RC.REJ		; Check for a reject
	 JRST	ERT (D6IOE,SINFAI)	;  Yes .. a case of I/O error

	LOAD	T1,(S2),H$DEV		; No .. get generic device number
	CAIE	T1,.OPCIN		; Check for either type of console
	CAIN	T1,.OPCOU		;  device and set the
	 JRST	SINNBR			;   non-blocking return code
	MOVX	S1,D6DOL		; Not console .. so device offline

SINFAI:	ZERO	((S2),H$RUN)		; Clear the I/O running bit
	$CALL	RLSLIN			; Release the line (2780/3780)
	JRST	SINBAD			; Go set the failure and return

SINNBR:	MOVX	S1,D6NBR		; Set non-blocking code
SINSUC:	SKIPA	TF,[TRUE]		; Set true flag
SINBAD:	 MOVX	TF,FALSE		;  Set the failure flag	
SINRET:	LOAD	T1,(ARGI),ARG$BC	; Get the count of bytes not transfered
	LOAD	S2,(ARGI),ARG$PT	; Get pointer where string left off
	EXCH	S1,ARGI			; Exchange return code(handle) and ptr
	$CALL	RLSARG			; Release the argument block
	MOVE	S1,ARGI			; Get the return code(handle) back
	$RET				; Give failure return
	SUBTTL	Global routine -- D60SOUT

; Global routine - D60SOUT
;
; Function - To output a string to a remote device
;
; Parameters -
;
;	S1/	Handle of device received from D60OPN
;	S2/	Byte pointer of string to output
;	T1/	Negative byte count

	ENTRY	D60SOUT
D60SOU:	ACVAR	<ARGO>			; Allocate register for output arg blk
	MOVE	ARGO,S1			; Save the handle temporarily
	$CALL	ALCARG			; Allocate an FEI%O arg block
	EXCH	ARGO,S1			; Swap them back

	STORE	S2,(ARGO),ARG$PT	; Save the byte pointer to input area
	STORE	T1,(ARGO),ARG$BC	; Save the byte count	
	JUMPGE	T1,ERT (D6CNN,SOTF.2)	; Test for illegal byte count
	MOVX	T1,FC.WD		; Function to write data to device
	STORE	T1,(ARGO),ARG$FC	; Put into I/O argument block
	HRRZS	S1			; Clear the flags in left half
	$CALL	SRCHAN			; Look for handle on handle entry list
	 JUMPF	ERT (D6NSH,SOTF.2)	;  Illegal handle
	LOAD	S1,(S2),H$IOM		; Get the input/output mode
	JUMPN	S1,ERT (D6DCO,SOTF.2)	;  Device can't do output
	LOAD	S1,(S2),H$RUN		; Check to see if the output already
	JUMPN	S1,SOTGO		;  running

	$CALL	LCKLIN			; Lock the BSC line (2780/3780)
	 JUMPF	 ERT (D6CGO,SOTRET)	;  Can't .. imply offline
	$CALL	REQOUT			; Request output permission
	 JUMPF	SOTF.1			;  Didn't get it ... release line

SOTGO:	MOVE	S1,ARGO			; Point arg blk for FE I/O
	$CALL	FEI%O			; Do the output
	 JUMPF	SOTTST			;  Go check why the output failed
	LOAD	S1,(S2),H$DEV		; Get device type number
	CAIE	S1,.OPCIN		; Check for console input
	CAIN	S1,.OPCOU		;  or console output device
	 JRST	[$DVCMD	(DC.DOB)	;   Yes .. dump output buffers
		  JUMPF	SOTF.1		;    Failed doing dump
		 JRST	.+1]		;   Continue on with output success
	LOAD	S1,(S2),H$HAN		; Get the handle back on success
	MOVX	TF,TRUE			; Set success code
	JRST	SOTRET			; Go release the arg block and return

SOTTST:	LOAD	T1,(ARGO),ARG$RC	; Get the result code from FEI%O
	CAIN	T1,RC.REJ		; Check for a reject
	 JRST	ERT (D6IOE,SOTF.1)	;  Yes .. a case of I/O error
	$CALL	CKOABT			; Check for output aborts
	 JUMPF	SOTF.1			;  Yes .. go release and clean up
	LOAD	T1,(S2),H$DEV		; Get device type
	CAIE	T1,.OPCIN		; Check for console input device
	CAIN	T1,.OPCOU		;  or console output device
	 SKIPA	S1,[D6NBR]		;   Yes .. set non-blocking error
	MOVX	S1,D6DOL		; No .. so device is off line
	JRST	SOTF.2			; Go give a false return

SOTF.1:	$CALL	RLSLIN			; Release the BSC line (2780/3780)
	ZERO	((S2),H$RUN)		; Clear the running flag
SOTF.2:	MOVX	TF,FALSE		; Set failure flag
	JRST	SOTRET			; Release arg block and return

SOTRET:	LOAD	T1,(ARGO),ARG$BC	; Get the count of bytes not done
	LOAD	S2,(ARGO),ARG$PT	; Get pointer where string left off
	EXCH	S1,ARGO			; Swap error code(handle) and ptr
	$CALL	RLSARG			; Release the argument block
	MOVE	S1,ARGO			; Get the error code(handle) back
	$RET				; Give failure return with code in S1
	SUBTTL	Global routine -- D60OPR

; Global routine - D60OPR
;
; Function - To set parameters and characteristics of a I/O link to a remote
;	device
;
; Parameters -
;
;	S1/	Handle of device
;	S2/	Function code
;	T1/	Optional argument value or block pointer

	ENTRY	D60OPR

D60OPR:	$SAVE	<S2,T1,P1>		; Save registers
	MOVE	P1,S2			; Save the function code
	HRRZS	S1			; Clear out the left half flags
	$CALL	SRCHAN			; Search for the handle on the list
	 JUMPF	ERT (D6NSH)		;  No such handle
	CAIN	P1,.MOABT		; Function to abort I/O transfers
	 JRST	DOPABT			;  Yes .. go set abort flags
	CAIN	P1,.MORQI		; Function to request output permission
	 JRST	DOPRQI			;  Yes .. go get it
	CAIN	P1,.MOTHR		; Function to set off line threshold
	 JRST	 DOPTHR			;  Yes .. go set new threshold
	JRST	ERT (D6FNI)		;  No .. no other function implemented


DOPRQI:	LOAD	S1,(S2),H$IOM		; Get the input/output mode of device
	JUMPN	S1,DOPIN		; Check to see if input .. go grant
	$CALL	REQOUT			;  otherwise get output permission
	CAIA				;  (skip input grant)
DOPIN:	$CALL	REQIN			; Grant input permission
	$RET				; Return T/F from REQOUT or REQIN

DOPABT:	ZERO	((S2),H$RUN)		; Clear the I/O running flag
	LOAD	S1,(S2),H$IOM		; Get the input/output mode
	JUMPN	S1,DOPIAB		; Input flag .. set input abort
	$DVCMD	(DC.SOA)		; Signal output abort on device
	$RET				; Propagate any error back
DOPIAB:	$DVCMD	(DC.SIA)		; Signal input abort on device
	$RET				; Propagate any errors that occured

DOPTHR:	STORE	T1,(S2),H$THR		; Store new value as off line threshold
	$RET
	SUBTTL	Global routine -- D60EOF

; Global routine - D60EOF
;
; Function - To signal the end of I/O on a handle and to turn the line
;	around if it needs to.
;
; Parameters -
;
;	S1/	Handle of device

	ENTRY	D60EOF

D60EOF:	$SAVE	<S2,T1>			; Save some registers
	HRRZS	S1			; Clear out the left half flags
	$CALL	SRCHAN			; Find the handle list entry
	 JUMPF	ERT (D6NSH)		;  Didn't find the handle
	PUSH	P,[RLSLIN]		; Release the line if 2780/3780
INTEOF:	$CALL	LINSTS			; Get the line status
	LOAD	T1,,SLSIG		; Get line signature
	$CALL	SWAPB			; Swap the bytes around
	LOAD	S1,(S2),H$SIG		; Get signature from handle
	CAME	S1,T1			; Check for a match
	 JRST	ERT (D6LGA,EOFL.1)	;  No .. so line has gone away

	LOAD	S1,(S2),H$IOM		; Get the input/output mode
	 JUMPN	S1,ERT (D6DCO)		;  Input device .. can't output EOF
	LOAD	S1,(S2),H$RUN		; Check to see if I/O is running
	 JUMPN	S1,EOFSND		;  Yes .. so go send the EOF
	$CALL	CKOABT			; Check for an output abort
	 JUMPF	EOFL.1			;  Yes .. go clean up and return
	TXNN	T1,SDORN		; Test for output running
	 JRST	EOFL.2			;  No .. so just give successful return

EOFSND:	$DVCMD	DC.SOE			; Signal EOF on device
EOFLOP:	SNOOZE	SEC			; Sleep for a second
	LOAD	T1,(S2),H$DEV		; Get the device number
	CAIN	T1,.OPSGN		; Check for signon device
	 JRST	EOFL.2			;  Yes .. so don't try to read status
	$CALL	CKOABT			; Check for an output abort
	 JUMPF	EOFL.1			;  Yes .. give error and failure return
	TXNN	T1,SDEOC		; Test for output EOF complete
	 JRST	EOFLOP			;  No .. so loop until it is.
	$DVCMD	DC.COE			; Yes .. so clear the EOF complete flg
	JRST	EOFL.2			; Give successful return

EOFL.1:	TDZA	TF,TF			; Set the failue flag if here
EOFL.2:	 SETOM	TF			;  or to success if here
	ZERO	((S2),H$RUN)		; Clear the run flag in handle entry
	$RET				; Successful return
	SUBTTL	Global routine -- D60RLS

; Global routine - D60RLS
;
; Function - To release a device and handle of the device
;
; Parameters -
;
;	S1/	Handle of device received from D60OPN

	ENTRY	D60RLS

D60RLS:	HRRZS	S1			; Clear out and flags that may be set
	$CALL	SRCHAN			; Find the handle list entry
	 JUMPF	ERT (D6NSH)		;  If no entry .. give error return
	$CALL	D60EOF			; Make sure that the I/O is closed off
	 JUMPT	RLS.1			; If no problems releasing .. continue
	CAIE	S1,D6DCO		; If input device .. ignore error
	 $SAVE	<TF,S1>			;  Save error flag and error code
RLS.1:	LOAD	S1,(S2),H$PDD		; Get the packed device descriptor
	$CALL	DEQDEV			;  and release the device to the world
	PJRST	RLSHAN			; Release the handle entry and possibly
					;  the FE device if not needed.
	SUBTTL	Global routine -- D60STS

; Global routine - D60STS
;
; Function - To get the status of a device(s) on a remote station.
;
; Parameters -
;
;	S1/	Function,,arg
;	S2/	Pointer to status return area or line number
;
;	where function is:
;
;		.STDEV	0	for device status
;		.STPRT	1	for port status
;		.STLIN	2	for line status
;
;	where arg is:
;
;		Port number (0-7, 10-13) for .STPRT and .STLIN
;		Device handle (from D60OPN) for .STDEV
;
; Returns -
;
;	Device status and line status - flags in S2
;	Multiple device activity status - in block pointed to by S2

	ENTRY	D60STS

D60STS:	$SAVE	<T1,T2>			; Save registers
	HLRZ	T1,S1			; Get function code
	ANDX	T1,7			; Clear all bits except the function
	CAIN	T1,.STPRT		; Check for port status
	 JRST	MULSTS			;  Yes .. so get the activity status
	CAIN	T1,.STLIN		; Check for line status
	 JRST	STSLIN			;  Yes .. so get line staus flags
	CAIE	T1,.STDEV		; Check for device status
	 JRST	ERT (D6FNI)		;  No .. so the function is not here

	HRRZS	S1			; Clear out the left half flags
	$CALL	SRCHAN			; Go find the handle in the handle list
	JUMPF	ERT (D6NSH)		;  No .. so give error return
	$CALL	DEVSTS			; Get the device status
	 JUMPF	@.RETF			;  Can't get device status .. die
	LOAD	T1,,SDFLG		; Get the status flags for the device
	LOAD	T2,(S2),H$IOM		; Get the Input/Output mode
	STORE	T2,T1,SDIOM		; Put the mode into the status bits
	MOVE	S2,T1			; Put the status value where looked for
	$RETT				; Give a true return

MULSTS:	MOVE	T1,S2			; Save the value return pointer
	$CALL	INIDMY			; Start up a dummy list entry
	 JUMPF	@.RETF			;  Can't get at the port
	$CALL	PRTSTS			; Get the port status
	 JUMPF	RLSHAN			;  If it failed .. give false return
	HRLI	S1,STSBUF+S6ACT		; Point to where active bits start
	HRR	S1,T1			;  and where to transfer them to
	BLT	S1,S6ALN-1(T1)		; Transfer to the user program
	MOVX	TF,TRUE			; Set success flag
	PJRST	RLSHAN			; Return while releasing dummy handle

STSLIN:	MOVE	T1,S2			; Move line number to a safe place
	$CALL	INIDMY			; Start up a dummy list entry
	 JUMPF	@.RETF			;  Failed to start a front end
	STORE	T1,(S2),H$LIN		; Store lower 9 bits as line number
	STORE	T1,(S2),H$HLN		;  in handle and PDD entries
	$CALL	LINSTS			; Get status of line
	$CALL	RLSHAN			; Release the dummy handle
	 JUMPF	@.RETF			;  If line status failed .. bad return
	LOAD	T1,,SLFLG		; Get flags
	ANDI	T1,177400		; Get only significant part
	LOAD	S2,,SLINF		; Get line info
	IOR	S2,T1			; Put them all together
	$RETT				; Return successfully


INIDMY:	$SAVE	<T1>			; Save a register
	$CALL	ALCHAN			; Make up a dummy handle entry
	STORE	S1,(S2),H$PRT		; Put the port number in to dummy entry
	STORE	S1,(S2),H$HPR		;  in both places.
	LOAD	S1,(S2),H$PDD		; Get the packed device descriptor
	$CALL	OPNFE			; Open the front end
	 JUMPF	ERT (D6COF,RLSHAN)	;  Can't open front end, rls dummy
	$RETT				; Front end opened just fine
	SUBTTL	GLobal routine -- D60CND, D60DIS

; Routine - D60CND, D60DIS
;
; Function - To condition a 2780/3780/HASP line with the appropriate parameters
;
; Parameters -
;
;	S1/	Address of QUASAR setup message
;
;		c(S1)+SUP.CN = address of conditioning arg block
;
;	argblk/	Port,,Line		; Only need this word on disable
;		Flags
;		 1b15 Transparent
;		 1b16 Primary protocol
;		 1b17 Emulation
;		 right half - station translation type
;		  1 - 3780
;		  2 - 2780
;		  3 - HASP
;		Clear to send delay
;		Silo warning area size
;		Number of bytes/message
;		Number of records/message
;		Line signature

	ENTRY	D60CND, D60DIS

D60CND:	$SAVE	<S2,T1,T2,P1,P2,P3>	; Save some registers
	MOVX	P1,.CNENB		; Line enable function
	MOVE	P3,S1			; Save address of setup message
	MOVEI	P2,SUP.CN(P3)		; Get address of conditioning block
	JRST	CNDGO			; Go to common code

D60DIS:	$SAVE	<S2,T1,T2,P1,P2,P3>	; Save some registers
	MOVX	P1,.CNDIS		; Line disable function
	MOVE	P2,S1			; Get address of port,,line

CNDGO:	LOAD	T1,(P2),CN$PRT		; Get port number
	LOAD	T2,(P2),CN$LIN		; Get line number being disabled

CND.X:	SKIPGE	S1,HANLST		; Check for any devices opened
	 JRST	CND.2			;  No .. just go disable line
	$CALL	L%FIRST			; Point to first entry in list
	 JUMPF	CND.2			;  No first entry .. go disable line
CND.1:	LOAD	S1,(S2),H$PRT		; Get port number
	CAME	S1,T1			; Check against one being disabled
	 JRST	CND.1A			;  No .. continue to next entry
	LOAD	S1,(S2),H$LIN		; Get line number of entry
	CAME	S1,T2			; Check against one being disabled
	 JRST	CND.1A			;  No .. continue until last entry
	LOAD	S1,(S2),H$HAN		; Get handle of current entry
	$CALL	D60RLS			; Release the device (call global rtn)
	JRST	CND.X			; Go start at top of list again

CND.1A:	MOVE	S1,HANLST		; Get handle list name
	$CALL	L%NEXT			; Find next handle list entry
	 JUMPT	CND.1			;  Another one .. check releasability


CND.2:	$CALL	ALCHAN			; Make up a dummy handle entry

	LOAD	S1,(P2),CN$PRT		; Get the port to start up
	STORE	S1,(S2),H$PRT		;  and save it in pseudo handle block
	LOAD	S1,(P2),CN$LIN		; Get the line to init
	STORE	S1,(S2),H$LIN		;  and save that also
	LOAD	S1,(S2),H$PDD		; Get the packed device descriptor
	$CALL	OPNFE			; Open up the front end for setup
	 JUMPF	ERT (D6COF,RLSHAN)	;  Couldn't open a front end

	$CALL	LINSTS			; Get the line status
;	 JUMPF	RLSHAN			;  Release handle, give error if failed
	LOAD	T1,,SLINF		; Get line info flags
	TXNN	T1,SLLEN		; Check for line enabled
	 JRST	CND.5			;  No .. go issue line enable
	LOAD	T1,,SLTYP		; Get station type enabled for
	CAIN	T1,SLHSP		; Check for HASP
	 JRST	CND.3			;  Yes .. just go disable line
	$CALL	DEVSTS			; Get device (0) sts on 2780/3780 line
	 JUMPF	RLSHAN			;  Failed .. release and clean up
	LOAD	T1,,SDFLG		; Get device flags
	TXNN	T1,SDOAS!SDIAS		; Check for any aborts pending
	 JRST	CND.3			;  No .. just disable the line
	$DVCMD	(DC.CIA,RLSHAN)		; Clear input abort
	$DVCMD	(DC.COA,RLSHAN)		; Clear output abort

CND.3:	$LNCMD	(LC.DIS,RLSHAN)		; Shut down the line (disable)
	SNOOZE	SEC			; Sleep for a second, let -11 catch up

CND.5:	CAIN	P1,.CNDIS		; If the function was to disable the
	 $RETT				;  line only .. we have gone far enough

	$CALL	PRTSTS			; Get status of front end
	 JUMPF	RLSHAN			;  Can't get port status .. so die
	LOAD	T1,(P2),CN$TYP		; Get desired translation type
	MOVE	T1,[EXP TR$X78,TR$X78,TR$HSP]-1(T1)
	LOAD	S1,,S6TRN		; Get translations avaiable in FE
	TDNN	S1,T1			; Check wanted against available
	 JRST	ERT (D6PIU,RLSHAN)	;  Nope .. port is useless
	LOAD	T1,(P2),CN$TYP		; Get the station type (terminal type)
	LSH	T1,^d8			; Shift it up to the second byte
	LOAD	S1,(P2),CN$MAP		; Get the emulation/termination flag
					;  and primary/secondary flag
	IOR	T1,S1			; Put into second byte and
	$LNCMD	(LC.EL,RLSHAN)		;  start it up again (enable)
	LOAD	T1,(P2),CN$CTS		; Get the clear to send delay
	$CALL	SWAPB			;  swap the bytes in 16 bit word
	$LNCMD	(LC.CSD,RLSHAN)		;  and set it
	$LNCMD	(LC.CTR,RLSHAN)		; Clear output transparency
	LOAD	T1,(P2),CN$WRN		; Get the silo warning level
	$CALL	SWAPB			;  swap the bytes in 16 bit word
	$LNCMD	(LC.WAR,RLSHAN)		;  and set it
	LOAD	T1,(P2),CN$BPM		; Get the bytes per message
	$CALL	SWAPB			;  swap the bytes in 16 bit word
	$LNCMD	(LC.BPM,RLSHAN)		;  and set it
	LOAD	T1,(P2),CN$RPM		; Get the records per message
	$CALL	SWAPB			;  swap the bytes in 16 bit word
	$LNCMD	(LC.RPM,RLSHAN)		;  and set it
	LOAD	T1,(P2),CN$SIG		; Get line signature to set
	ANDI	T1,177777		; Clear superfluous bits
	$CALL	SWAPB			;  swap bytes in 16 bit word
	$LNCMD	(LC.SLS,RLSHAN)		; Set the line signature
	LOAD	S1,(P2),CN$TYP		; Get station type again
	CAIE	S1,SLHSP		; Check for HASP station
	 JRST	CND.9			;  No.. ignore transparent transmission
	LOAD	T1,(P2),CN$TRA		; Get transparency flag
	$LNCMD	(LC.STR,RLSHAN)		; Set transparency on/off
CND.9:	$LNCMD	(LC.DTR,RLSHAN)		; Set the data terminal ready

	PJRST	RLSHAN			; Release handle, FE and return
	SUBTTL	Lock/release BSC lines for 2780/3780 half-duplex

; Routine - LCKLIN
;
; Function - This routine locks a BSC line so that no other process or task
;	in this process can attempt to do I/O on the line while the current
;	task has an object (card reader/line printer) already running.
;
; Parameters -
;
;	S2/	Handle list entry

LCKLIN:	$SAVE	<S2>			; Save register

	LOAD	S1,(S2),H$STY		; Get terminal (station) type
	CAIN	S1,SLHSP		; Check for a HASP station
	 $RETT				;  Yes .. so line needn't be locked
	LOAD	S1,(S2),H$PDD		; Get packed device descriptor
	PJRST	ENQLIN			; Enqueue the line and return


; Routine - RLSLIN
;
; Function - To release a line so that it can be turned around or another
;	task can talk to a common device (such as a line-printer being used
;	for both an output console and a printer).
;
; Parameters -
;
;	S2/	Location of handle list entry

RLSLIN:	$SAVE	<TF,S1,S2>		; Save some error code and return value

	LOAD	S1,(S2),H$STY		; Get station type
	CAIN	S1,SLHSP		; Check for a HASP station
	 $RETT				;  Yes .. so just return .. not locked
	LOAD	S1,(S2),H$PDD		; Get packed device descriptor
	PJRST	DEQLIN			; Release the line and return
	SUBTTL	Grant input permission


; Routine - REQIN
;
; Function - To grant an input request if one pending, wait for one and
;	     grant it, or give non-blocking return (if bit set) when no
;	     request has been made.
;
; Parameters -
;
;	S2/	Handle list entry address

REQIN:	$SAVE	<T1,T2>			; Save registers

	$CALL	CKIABT			; Check for any outstanding input abort
	 JUMPF	@.RETF			;  Yes .. so just return with failure
	TXNN	T1,SDIPW!SDIRN		; Check for input perm. was requested
	 JRST	ERT (D6DOL)		;  No .. so say device offline

REQRTY:	MOVX	T2,RQREP		; Get the max number of tries for req
REQRDS:	$CALL	CKIABT			; Check for input aborts again
	 JUMPF	@.RETF			;  Failure caused by abort
	TXNE	T1,SDIRN		; Check for input already running
	 JRST	REQCKI			;  Yes .. go check for aborts
	TXNE	T1,SDIPR		; Check for a new input request
	 JRST	REQGRT			;  Yes .. so go grant it
	SNOOZE	SEC*RQTIM		; No .. sleep for a while
	SOJG	T2,REQRDS		; If more tries left .. go check again
	JRST	ERT (D6DOL)		;  else assume the device is offline

REQGRT:	$DVCMD	DC.GIP			; Do a device input permission grant
	$DVCMD	DC.CIP			; Clear the request flag
REQGLP:	$CALL	CKIABT			; Check for input aborts
	 JUMPF	@.RETF			;  Failure do to abort on device
	TXNN	T1,SDIPG		; Check for the grant cleared
	 JRST	REQCKI			;  Yes .. the device took the grant
	SNOOZE	SEC			;  No .. sleep and loop
	JRST	REQGLP

REQCKI:	TXNN	T1,SDIEC!SDIRN		; Check for EOF or running
	 JRST	REQRTY			;  No .. grant was eaten .. try again
	SETO	T1,			;  Yes .. so turn on
	STORE	T1,(S2),H$RUN		;   the I/O running flag
	$RETT				; Give a successful return
	SUBTTL	Request output permission

; Routine - REQOUT
;
; Funtion - To request output permission on a device
;
; Parameters -
;
;	S2/	Handle list entry address

REQOUT:	$SAVE	<T1,T2>			; Save registers

	MOVX	T2,RQOTIM		; Number of times to retry DSR check
DSRLP:	$CALL	LINSTS			; Get the line status
	 JUMPF	@.RETF			;  Can't get line status .. error
	LOAD	T1,,SLINF		; Get the info status byte
	TXNE	T1,SLDSR		; Test for the DSR set
	 JRST	STOGST			;  Yes .. start output grant request
	SNOOZE	TIMDSR			; No .. so sleep and then
	SOJG	T2,DSRLP		;  go try for DSR again
	LOAD	T1,,SLFLG		; Get line flags.
	MOVX	S1,D6CGO		; Can't get output perm. .. no line
	TXNE	T1,SLCME		; Check for line failure
	 MOVX	S1,D6LGA		;  Yes .. say line has gone away.
	$RETF				; Failure return

STOGST:	$DVCMD	(DC.CIP)		; Clear input requested flag
	LOAD	S1,(S2),H$DEV		; Get the generic device type
	CAIN	S1,.OPSGN		; Check for a signon device
	 JRST	STGRUN			;  Yes .. so imply grant already gotten
	$CALL	CKOABT			; Check for output aborts
	 JUMPF	@.RETF			;  Yes .. just give error return
	TXNE	T1,SDIPW!SDIPR		; Check for input requested
	 JRST	ERT (D6CGO)		;  Input coming .. can't do output
	TXNN	T1,SDORN!SDOPG		; Output running or granted already?
	 JRST	REQGO			;  No so go request output
	$CALL	INTEOF			;  and put out an EOF to stop the
	 JUMPF	@.RETF			;  output (unless failed .. give error)
REQGO:	$DVCMD	DC.ROP			; Request to do output

	MOVX	T2,RQDTRY		; Number of retries after request drops
STGRLP:	SNOOZE	(<SEC*SOTDLY>,IOWAIT)	; Wait for the request to be processed
	$CALL	CKOABT			; Check for output aborts
	 JUMPF	@.RETF			;  Yes .. failure on device
	TXNE	T1,SDOPG!SDORN		; Check to see if grant gotten
	 JRST	STGRUN			;  Yes .. so go set the run flag
	TXNE	T1,SDIPW!SDIPR		; Check for input requested
	 JRST	ERT (D6CGO)		;  Yes .. input is coming, can't output
	TXNE	T1,SDOPR		; Check to see if request still up
	 JRST	STGRLP			;  Yes .. wait for it to go down
	SOJG	T2,STGRLP		; Check for retry exhausted
	JRST	ERT (D6CGO)		;  Device must be off line (maybe)

STGRUN:	SETO	T1,			; Set the flag saying that
	STORE	T1,(S2),H$RUN		;  the output is now running
	$RETT				; Give good return (output running)
	SUBTTL	Check for input abort

; Routine - CKIABT
;
; Function - This routine checks the device status for an occurence of either
;	a hardware line abort or a protocol soft device abort.  If either
;	has occured, an error will be returned.  If device status can't be
;	gotten an error will also be returned.  After a device soft abort
;	is seen it will be acknowledged (cleared) so the front end will
;	clean up.
;
; Parameters -
;
;	S2/	Handle list entry address
;
; Returns -
;
;	False	S1/ error code
;	True	T1/ device flags

CKIABT:	$CALL	DEVSTS			; Get device status
	 JUMPF	@.RETF			;  Failed .. give error return
	LOAD	T1,,SDLFG		; Get line status flags
	TXNE	T1,SDHWA		; Check for a hardware abort
	 JRST	ERT (D6LGA)		;  Yes .. line gone away
	LOAD	T1,,SDFLG		; Get device flags
	TXNN	T1,SDIAS		; Has input abort occured?
	 $RETT				;  No .. we are ok here
	TXNN	T1,SDIAC		; Has the abort completed?
	 JRST	[SNOOZE	SEC		;  No .. sleep for a second
		 JRST	CKIABT]		;  Go check the status again
	$DVCMD	(DC.CIA)		; Clear input abort flag
	 SKIPF				;  Failed to clear flag
	  MOVX	S1,D6IOE		;   Cleared .. I/O error occured
	$RETF				; Give failure return for all
	SUBTTL	Check for output abort

; Routine - CKOABT
;
; Function - This routine checks the device status for an occurence of either
;	a hardware line abort or a protocol soft device abort.  If either
;	has occured, an error will be returned.  If device status can't be
;	gotten an error will also be returned.  After a device soft abort
;	is seen it will be acknowledged (cleared) so the front end will
;	clean up.
;
; Parameters -
;
;	S2/	Handle list entry address
;
; Returns -
;
;	False	S1/ error code
;	True	T1/ device flags

CKOABT:	$CALL	DEVSTS			; Get device status
	 JUMPF	@.RETF			;  Failed .. give error return
	LOAD	T1,,SDLFG		; Get line status flags
	TXNE	T1,SDHWA		; Check for a hardware abort
	 JRST	ERT (D6LGA)		;  Yes .. line gone away
	LOAD	T1,,SDFLG		; Get device flags
	TXNE	T1,SDIEC		; Check for old input EOF still there
	 JRST	[$DVCMD	DC.CIE		;  Clear the input EOF completed
		 JRST	CKOABT]		;  Start abort checking all over.
	TXNN	T1,SDOAS		; Has output abort occured?
	 $RETT				;  No .. we are ok here
	TXNN	T1,SDOAC		; Has the abort completed?
	 JRST	[SNOOZE	SEC		;  No .. sleep for a second
		 JRST	CKOABT]		;  Go check the status again
	$DVCMD	(DC.COA)		; Clear output abort flag
	 SKIPF				;  Failed to clear flag
	  MOVX	S1,D6IOE		;   Cleared .. I/O error occured
	$RETF				; Give failure return for all
	SUBTTL	Pack a unique device descriptor

; Routine - PCKPDD
;
; Function - To pack the PORT, LINE, DEVICE-TYPE and UNIT numbers into a single
;	word to use as a unique descriptor of that device.  This is useful so
;	that when searching tables we will only have to do single word compares.
;
; Parameters -
;
;	S1/	dev-type#,,unit#
;	S2/	port#,,line#
;
; Returns -
;
;	S1/	port,line,dev,unit each in 9 bits


PCKPDD:	$SAVE	<T1,T2>			; Save a couple registers

	HLL	T1,S2			; Get port number into LH
	HLR	T1,S1			; Get device type number into RH
	LSH	T1,^d9			; Shift them up to where they need be
	TLZ	T1,777			; Clear out where line # will be
	HRL	T2,S2			; Get line number into LH
	HRR	T2,S1			; Get unit number into RH
	AND	T2,[777,,777]		; Clear out where port and device go
	IOR	T1,T2			; Put them all together
	MOVE	S1,T1			;  and it's magic. (all packed into A)
	$RETT				; Only a true return
	SUBTTL	Create/destroy a handle list entry

; Routine - ALCHAN
;
; Function - To create a new handle list entry in the handle list. This routine
;	     also initializes the needed values to talk to FEI%O.
;
; Parameters - none
;
; Returns -
;
;	S2/	Location of the new handle list entry

ALCHAN:	$SAVE	<S1>			; Save a register

	SKIPGE	S1,HANLST		; Check for a handle list already
	 $CALL	L%CLST			;  No .. so create one
	MOVEM	S1,HANLST		; Save the name of the handle list
	MOVX	S2,H$SIZ		; Get the size of a handle entry
	$CALL	L%CENT			; Create a handle list entry
	MOVE	S1,DEFTHR		; Get the default threshold
	STORE	S1,(S2),H$THR		;  and save it for this dummy
	SETO	S1,			; Set the bytes per message to
	STORE	S1,(S2),H$BPM		;  +infinity so commands go through
	$RETT				; Only success can be had.

; Routine - RLSHAN
;
; Function - To release a handle list entry and to optionally let the
;	     logical front end device (TOPS20) go back to the monitor pool.
;	     The reason that this routine searches for the handle entry in the
;	     list instead of assuming that the CURRENT entry is the one being
;	     used is that the CURRENT pointer may be changed when the TASK is
;	     descheduled whiling in a wait state.
;
; Parameters -
;
;	S2/	Location of handle list entry
;
;  This routine releases the logical front end when the handle list is
;  empty.

RLSHAN:	$SAVE	<TF,S1,T1>		; Save a couple of registers

	MOVE	T1,S2			; Make a copy of list entry address
	SKIPGE	S1,HANLST		; Get handle list name
	 PJRST	RLSFE			;  If no handle list .. go release FE
	$CALL	L%FIRST			; Point to first entry in list
	JUMPF	RLSFE			; If no first entry .. release FE
RLSH.1:	CAMN	T1,S2			; Check for entry address
	 JRST	RLSH.2			;  Yes .. so go kill the entry
	$CALL	L%NEXT			; Move onto the next entry
	JUMPT	RLSH.1			; If an entry exists .. check it
	PJRST	RLSFE			; No more entries .. release FE

RLSH.2:	MOVE	S1,HANLST		; Get the handle list name
	$CALL	L%DENT			; Destroy the handle list entry
	PJRST	RLSFE			; Go conditionally release the FE
	SUBTTL	Enqueue a line or device for current task

; Routine - ENQLIN, ENQDEV
;
; Function -
;	(ENQLIN) To block a line under 2780/3780 from use by any other process.
;		 This allows only one direction of I/O to proceed at a time.
;
;	(ENQDEV) This routine blocks all others from ever using the device we
;		 are talking to so that two processes can't confuse him.
;
; Parameters -
;
;	S1/	Packed device descriptor (Port/Line/Device/Unit)

ENQDEV:	$SAVE	<S1,S2>			; Save registers
	$CALL	QUEDEV			; Make argblk for device specific ENQ
	JRST	ENQ001			; Go do the ENQ

ENQLIN:	$SAVE	<S1,S2>			; Save registers
	$CALL	QUELIN			; Make up argblk for line specific ENQ

ENQ001:
TOPS20 <MOVX	S1,.ENQAA		; Get the enqueue function number
	ENQ>				;  and try to do it.
TOPS10 <HRLI	S2,.ENQAA		; Put function number in left half
	ENQ.	S2,>			;  try the enqueue.
	 $RETF				;  False return if we can't ENQ
	$RETT				; Do a true return
	SUBTTL Enqueue a port for current task

; Routine - ENQD60
;
; Function -
;	(ENQD60) To ENQ a DN60 front end to block others from using it while
;	 	 we are.
; Parameters -
;
;	S1/	Packed device descriptor (Port/Line/Device/Unit)

ENQD60:	$SAVE	<S2>			; Save registers
	$CALL	QUED60			; Make up the argblk for ENQ

TOPS20 <MOVX	S1,.ENQBL		; Get the enqueue function number
	ENQ>				;  and try to do it.
TOPS10 <HRLI	S2,.ENQBL		; Put function number in left half
	ENQ.	S2,>			;  try the enqueue.
	 $RETF				;  False return if we can't ENQ
	$RETT				; Do a true return
	SUBTTL	Dequeue a port, line or device

; Routine - DEQD60, DEQDEV
;
; Function -
;	(DEQD60) To dequeue a DN60 on a port so that others can use it again.
;
;	(DEQDEV) To release a device off a 2780/3780/HASP station so that
;		 someone else can talk to it.
;
; Parameters-
;
;	S1/	Packed device descriptor (Port/Line/Device/Unit)


DEQDEV:	$SAVE	<S1,S2>			; Save registers
	$CALL	QUEDEV			; Make arg block to DEQ specific device
	JRST	DEQ001			; Go do the DEQ

DEQLIN:	$SAVE	<S1,S2>			; Save registers
	$CALL	QUELIN			; Make arg block to DEQ specific line
	JRST	DEQ001			; Go DEQ the line

DEQD60:	$SAVE	<S1,S2>			; Save registers
	$CALL	QUED60			; Make up the DEQ argblk

DEQ001:
TOPS20 <MOVX	S1,.DEQDR		; Get the DEQ function code
	DEQ>
TOPS10 <HRLI	S2,.DEQDR		; Put function in LH w/ addr in rh
	DEQ.	S2,>
	 $RETF				; False return on error.
	$RETT				;  and give a true return on success
	SUBTTL	Create an ENQ/DEQ argument block for a port

; Routine - QUED60
;
; Function - To make up the argument block needed to ENQ/DEQ a specific port.
;
; Parameters -
;
;	S1/	packed device descriptor (only port number used)

QUED60:	$SAVE	<S1>			; Save registers

	MOVEI	S2,QD60BF		; Location of ENQ D60 port string
	ROT	S1,6			; Move high order port number around
	DPB	S1,QPRT1		;  and store it in string
	ROT	S1,3			; Rotate around the low order number
	DPB	S1,QPRT0		;  and store that also
	HRRM	S2,ENQBLK+3		; Store string loc in the byte pointer
	MOVEI	S2,ENQBLK		; Get the location of the ENQ/DEQ block
	$RETT				;  and do a true return
	SUBTTL	Create ENQ/DEQ argument block for a specific device

; Routine - QUEDEV
;
; Function - To make an argument block for the ENQ/DEQ monitor calls to lock
;	or unlock a specific device.  This is so that only one process can
;	talk to a specific device during the life of that process or until
;	it explicitly releases the device.
;
; Parameters -
;
;	S1/	Packed device descriptor (port/line/device/unit)
;	S2/	returns pointer to arg block here

QUEDEV:	$SAVE	<S1,T1,T2>		; Save registers

	MOVEI	S2,QDEVBF		; Get pointer to device Q' string
	MOVE	T2,S1			; Put packed device descriptor in T2
	LSHC	T1,6			; Shift up to high order port number
	DPB	T1,QPRT1		;  and store it
	LSHC	T1,3			; Shift up the low order port number
	DPB	T1,QPRT0		;  and store that too.
	LSHC	T1,6			; Shift up to high order line number
	DPB	T1,QLIN1		;  and store it
	LSHC	T1,3			; Shift up the low order line number
	DPB	T1,QLIN0		;  and store it.
	LSHC	T1,3			; Shift the first digit of device type
	DPB	T1,QDEV2		;  and store it
	LSHC	T1,3			; Repeat for next two digits of the
	DPB	T1,QDEV1		;  device type number
	LSHC	T1,3
	DPB	T1,QDEV0
	LSHC	T1,6			; Shift up the first unit number
	DPB	T1,QUNT1		;  and store it
	LSHC	T1,3			; Get last number of unit and string
	DPB	T1,QUNT0		;  and store it too.
	HRRM	S2,ENQBLK+3		; Store the pointer to the string
	MOVEI	S2,ENQBLK		;  get the pointer to the ENQ block
	$RETT				; Success and return
	SUBTTL	Create ENQ/DEQ argument block for a port/line

; Routine - QUELIN
;
; Function - To make up the argument block needed to ENQ/DEQ a whole station
;	hung off a DN60 line.
;
; Parameters -
;
;	S1/	PDD of the requested station

QUELIN:	$SAVE	<S1,T1,T2>		; Save registers

	MOVEI	S2,QLINBF		; Get pointer to line Q' string
	MOVE	T2,S1			; Put packed device descriptor in T2
	LSHC	T1,6			; Shift up to high order port number
	DPB	T1,QPRT1		;  and store it
	LSHC	T1,3			; Shift up the low order port number
	DPB	T1,QPRT0		;  and store that too.
	LSHC	T1,6			; Shift up to high order line number
	DPB	T1,QLIN1		;  and store it
	LSHC	T1,3			; Shift up the low order line number
	DPB	T1,QLIN0		;  and store it.
	HRRM	S2,ENQBLK+3		; Store the pointer to the string
	MOVEI	S2,ENQBLK		;  and get the pointer to ENQ/DEQ blk
	$RETT				; Only successful returns available
	SUBTTL	OPNFE -- Open a port and return JFN on TOPS20
TOPS20 <

; Routine - OPNFE
;
; Function - To open up a port and check out the 11
;
; Parameters -
;
;	S1/	Packed device descriptor


OPNFE:	SKIPN	APRNUM			; Is processor serial number known
	 $CALL	PRCTYP			;  No so type the processor
	SKIPE	KSFLG			; Check for a KS10 (2020)
	 JRST	OPN.22			;  Yes .. so go flush DDCMP buffers
	$SAVE	<S2,T1,T2>		; Save registers
	ACVAR	<PDD,FENM>		; Temporary location to save the packed
					;  device descriptor code and FEn
	MOVE	PDD,S1			; Save the PDD

	SETZM	LSTDTE			; Force a new DTE selection
	LOAD	S1,PDD,PD$PRT		; Get port number to work on.
	SKIPE	FEJFN			; If JFN already assigned .. then
	 PJRST	SELDTE			;  just go select the DTE

	MOVX	FENM,1			; Start with FE device FE1:
	MOVE	S1,PDD			; Get the packed device descriptor
	$CALL	ENQD60			; Enqueue the port and get a JFN.

OPFE2:	MOVE	S1,FENM			; Get the next FE number to try to get.
	CAILE	S1,MAXFE		; Check if have run out of FE:'s
	 JRST	OPDIE			;  Yes .. so let go and crap out.
	$CALL	FENAM			; Make up the front end name
	MOVX	S1,GJ%OLD+GJ%SHT	; Old file, short form of GETJFN
	GTJFN				;  and try it.
	 ERJMP	OPERR1			;   Didn't get it.
	MOVEM	S1,FEJFN		; Save the JFN for everyone
	MOVX	S2,FLD(^d8,OF%BSZ)+OF%RD+OF%WR ; Read/write in 8 bit mode
	OPENF				; Try to open the FE
	 ERJMP	OPERR2			;  nope can't do it to this one.
OPNSEL:	LOAD	S1,PDD,PD$PRT		; Get the DTE number from the PDD
	$CALL	SELDTE			; Go select the DTE
	 JUMPF	OPERR3			;  Didn't select properly
	MOVE	S1,PDD			; Get the PDD back again so that
	$CALL	DEQD60			;  we can release the port.
	 JUMPF	@.RETF			; Had a problem dequeueing the port
	$RETT				; Return succesfully (true)

; Here if GTJFN fails on FEn:

OPERR1:	CAIN	S1,GJFX29		; Device available?
	 AOJA	FENM,OPFE2		;  No .. so try next one
	JRST	OPCLR			; Yes it was so just die.

; Here if the DTE select fails

OPERR3:	EXCH	S1,FEJFN		; Save error and get JFN of FE device
	IORX	S1,CZ%ABT		; Set abort and close flag
	CLOSF				; Close the FE device
	 ERJMP	OPCLR			;  Can't release FE device so die
	JRST	OPERRX

; Here if OPENF fails

OPERR2:	EXCH	S1,FEJFN		; Get the JFN of the FE
	RLJFN				; Release the JFN
	 ERJMP	OPCLR			;  Can't release the FE so die.
OPERRX:	HRRZ	S1,FEJFN		; Get the error code back again
	CAIE	S1,OPNX9		; Check for simultaneous access or
	CAIN	S1,OPNX7		;  for device already assigned
	 AOJA	FENM,OPFE2		;  Yes .. so go try another one
	JRST	OPCLR			; No .. we have some other error

; Here on fatal errors that need to dequeue the port

OPCLR:	SETZM	FEJFN			; Clear the JFN before returning
OPDIE:	EXCH	S1,PDD			; Get the device descriptor
	$CALL	DEQD60			; Get rid of the port
	EXCH	S1,PDD			; Get the fatal error back
	$RETF				; And give a failure (false) return.

; Routine - FENAM
;
; Function - To make a name string for a specific front end number. i.e. for
;	front end number 1 we want string "FE1:".
;
; Parameters -
;
;	S1/	FE#
;	S2/	returns pointer to string

FENAM:	MOVE	T2,[POINT 7,FEDEVS,13]	; Point to byte for first digit
	LDB	T1,[POINT 3,S1,32]	; First octal digit
	JUMPE	T1,FEN1			; If zero then suppress it
	ADDX	T1,"0"			;  else make it ASCII
	IDPB	T1,T2			;  and store it in the name
FEN1:	LDB	T1,[POINT 3,S1,35]	; Get 2nd octal digit
	ADDX	T1,"0"			;  make it ASCII
	IDPB	T1,T2			;  and store it in name
	MOVX	T1,":"			; Device name terminator
	IDPB	T1,T2			;  store in the name
	SETZ	T1,			; And the null byte
	IDPB	T1,T2			;  to make it an ASCIZ string
	MOVE	S2,[POINT 7,FEDEVS]	; Pointer to name string
	$RETT				;  and only a true return
	SUBTTL	OPNFE -- Routine to check out the 11 for 2020 TOPS20

; Routine - OPNFE
;
; Function - Under TOPS20 on a 2020 this routine checks to see if the front
;	     end is up and running. It as a side effect also checks to see
;	     if our DDCMP link to the DN200 is running.
;	     If any messages are in the input queue, it is assumed that they
;	     are garbage left from a fatally exited process. They are then
;	     flushed and thrown away.

OPN.22:	$SAVE	<T1,T2,T3,S1,S2>	; Save a register
	LOAD	T2,(S2),H$PRT		; Get the port number
	SUBI	T2,DTEOFF		; Remove the DTE offset
	STORE	T2,(S2),H$HPR		; Store back the DMC line number
	LOAD	T3,(S2),H$PDD		; Get packed device descriptor
	MOVE	S1,T3			; Move to where enq routine expects it
	$CALL	ENQD60			; ENQ the line

OPFE.1:	MOVEI	S2,BTARG		; Point to BOOT argument block
	MOVEM	T2,.BTDTE(S2)		; Set it as the DTE/line in BOOT block
	MOVX	T1,^D500		; Abitrarily large number of bytes
	MOVMM	T1,.BTLEN(S2)		; Set number of bytes to read
	MOVE	T1,[POINT 8,XMSG]	; Point to flush buffer
	MOVEM	T1,.BTMSG(S2)		; Set pointer to 8 bit byte area
	MOVX	S1,.BTRDD		; Read DDCMP message function
	BOOT				; Do the read
	 ERJMP	ERT (D6CTF,OPFE.2)	;  BOOT JSYS failed
	SKIPE	.BTLEN(S2)		; Check for no message returned
	 JRST	OPFE.1			;  Message there .. continue Q flush
	JRST	OPFE.3			; No more .. so return

OPFE.2:	TDZA	TF,TF			; Set error flag
OPFE.3:	 SETOM	TF			;  or set success flag
	$SAVE	<TF,S1>			; Save the failure flag and result code
	MOVE	S1,T3			; Get the PDD again
	$CALL	DEQD60			; Release the line
	$RET
	SUBTTL	PRCTYP -- Routine to type the processor

; Routine - PRCTYP
;
; Function -
;
;	This routine determines whether we are running on a KL or KS system.
;
; Parameters - none
;
; Returns - True always
;
;	APRNUM/	Contains the processor serial number
;	KSFLG/	0 if KL, non-zero if KS

PRCTYP:	$SAVE	<S1,S2>			; Save some registers

	MOVE	S1,[SIXBIT \APRID\]	; Table in TOPS20 to check
	SYSGT				;  for the processor serial number
	MOVEM	S1,APRNUM		; Save the processor serial number
	SETZM	KSFLG			; Default to KL
	CAIL	S1,^d4096		; Test for a KS serial number
	 SETOM	KSFLG			;  Yes .. so set such an indicator
	$RETT

    > ;End if TOPS20
	SUBTTL	OPNFE -- Routine to check out the 11 for TOPS10
TOPS10 <

; Routine - OPNFE
;
; Function - Under TOPS10 to check to see if the 11 is up and running the
;	proper program.  This will also (obviously) catch if there is a FE
;	there at all.
;
; Parameters -
;
;	S1/	PDD	(packed device descriptor)
;
; Returns - CAL11. error codes


OPNFE:	$SAVE	<T1,P2>			; Save registers

	MOVEI	P2,C11BLK		; Get location of CAL11. arg block
	LOAD	T1,S1,PD$PRT		; Get the port number from handle list
	STORE	T1,(P2),C$PRT		; Store it in the CAL11. block
	MOVX	T1,.C11UP		; CAL11. function to check up/down
	STORE	T1,(P2),C$FNC		;  status of the FE
	MOVE	T1,[1,,C11BLK]
	CAL11.	T1,			; Well ... check it.
	 $RETF				;  It didn't go.
	CAIE	T1,1			; Check for 11 up?
	 JRST	ERT (D6DNR)		;  DN60 not running
	MOVX	T1,.C11NM		; Function to get program name from 11
	STORE	T1,(P2),C$FNC		;  to see if it is our kind.
	MOVE	T1,[1,,C11BLK]
	CAL11.	T1,
	 $RETF				; Doesn't like us for some reason
	CAME	T1,[SIXBIT /DN60  /]	; Check for running DN60 type code
	 JRST	ERT (D6DNR)		;  No .. not running DN60 code
	$RETT				; Else we are golden, give good return.
    > ;End if TOPS10
	SUBTTL	Release front end for any device

; Routine - RLSFE
;
; Function - To release the remote device association with the front end.
;	     What this actually does is close the TOPS20 front end JFN
;	     if it is determined that there are no more devices in this
;	     process that are using the FE JFN.

RLSFE:
TOPS20 <
	$SAVE	<TF,S1>			; Save last error flag and return code
	SKIPE	KSFLG			; If a 2020 then just return
	 $RET				;  saying that front end is released
	SKIPGE	S1,HANLST		; Get list name again
	 $RET				;  If no handle list .. just return
	$CALL	L%FIRST			; Position to first entry
	 JUMPT	.POPJ			; If entry found then return
	MOVE	S1,FEJFN		; Last entry in list is destroyed
	IORX	S1,CZ%ABT		; Don't try to clean up any FE buffers
	CLOSF				; Close the front end
	 JFCL				;  Ignore errors
	SETZM	FEJFN			; Clear the front end JFN
	SETZM	LSTDTE			;  and the last port with it.
    >; End if TOPS20

	$RET				; Return saying that it is done.
	SUBTTL	Search handle linked list for PDD

; Routine - SRCPDD
;
; Function - To search the linked list that contains all the info about all the
;	active handles to see if a device specified is already in the list.
;
; Parameters -
;
;	S1/	PDD	(packed device descriptor)
;
; Returns -
;
;	True	Found the PDD in the table, the current pointer points to it.
;	False	Didn't find the PDD in the table, the current pointer points to
;		 where it was before starting the search

SRCPDD:	$SAVE	<S1,T1,T2>		; Save registers

	MOVE	T1,S1			; Put the PDD into another register so
					;   S1 can be used for subr linkage.
	SKIPGE	S1,HANLST		; Check to see if the list is created
	$CALL	L%CLST			;  and make it if not.
	MOVEM	S1,HANLST		; Save the list name for future tests.

	$CALL	L%CURR			; Point to current entry
	 JUMPF	SRCFST			;  if none .. start at first entry
	LOAD	T2,(S2),H$PDD		; Get the handle in the entry
	CAMN	T1,T2			; Check if this is the one
	 $RETT				;  Yes .. then looking for current one

SRCFST:	MOVE	S1,HANLST		; Reset list name in case of error
	$CALL	L%FIRST			; Point to first entry in list
	JUMPF	@.RETF			; No entries ... so not found

SRCLOP:	LOAD	T2,(S2),H$PDD		; Get the PDD field in the entry
	CAMN	T1,T2			; Compare the PDD against list entry
	 $RETT				;  good compare ... this is it.
	$CALL	L%NEXT			; Move onto the next list entry
	JUMPT	SRCLOP			; If no error then assume entries left.
	$RETF				;  else give a false return
	SUBTTL	Search handle linked list for handle

; Routine - SRCHAN
;
; Function - To search the linked list that contains all the info about all the
;	active handles to see if a device specified is already in the list.
;
; Parameters -
;
;	S1/	Handle of device (received from D60OPN)
;
; Returns -
;
;	True	Found handle in the table, the current pointer points to it.
;	False	Didn't find handle in the table, the current pointer points to
;		 where it was before starting the search

SRCHAN:	$SAVE	<S1,T1,T2>		; Save registers

	MOVE	T1,S1			; Put the PDD into another register so
					;  that S1 can be used for subr linkage
	SKIPGE	S1,HANLST		; Check to see if the list is created
	$CALL	L%CLST			;  and make it if not.
	MOVEM	S1,HANLST		; Save the list name for future tests.

	$CALL	L%CURR			; Point to the current entry
	 JUMPF	HSRFST			;  If no current .. start at first
	LOAD	T2,(S2),H$HAN		; Get the handle in the entry
	CAMN	T1,T2			; See if it is the one we want
	 $RETT				;  Yes .. so point at this current one
HSRFST:	MOVE	S1,HANLST		; Reset list name in case of error
	$CALL	L%FIRST			; Point to first entry in list
	JUMPF	@.RETF			; No entries ... so not found

HSRCLP:	LOAD	T2,(S2),H$HAN		; Get the handle field in the entry
	CAMN	T1,T2			; Compare the handle against list entry
	 $RETT				;  good compare ... this is it.
	$CALL	L%NEXT			; Move onto the next list entry
	JUMPT	HSRCLP			; If no error then assume entries left.
	$RETF				;  and give a false return
	SUBTTL	Return port status

; Routine - PRTSTS
;
; Function - To get the status of a port specified in the given PDD.
;
; Parameters -
;
;	S2/	Pointer to handle list entry
;
; Returns -

PRTSTS:	$SAVE	<T1,T2>			; Save registers
	ACVAR	<ARGP>			; Pointer to port argument block
	$CALL	ALCARG			; Allocate a FEI%O argument block	
	MOVE	ARGP,S1			; Save another copy of arg blk ptr
	MOVX	T1,FC.R6S		; Function to read port status
	MOVEM	T1,(ARGP)		; Put into argument block
	DMOVE	T1,[EXP -D6.BYT		;  Reinitialize the byte count
		    POINT 8,STSBUF]	;  and byte pointer, may be destroyed
	DMOVEM	T1,1(ARGP)
	$CALL	FEI%O			; I/O to the front end (Device status)
	SETZ	S1,			; Default to no error occured
	SKIPT				; If an error occured
	 LOAD	S1,(ARGP),ARG$RC	;  get the result code
	EXCH	S1,ARGP			; Exchange error code and blk ptr
	$CALL	RLSARG			; Release the argument block
	MOVE	S1,ARGP			; Get the error code again
	JUMPE	S1,@.RETT		; If no error then give success
	$RETF				;  else give error return
	SUBTTL	Return device status

; Routine - DEVSTS
;
; Function - To get the status of a device specified in the given PDD.
;
; Parameters -
;
;	S2/	Pointer to handle list entry
;
; Returns -

DEVSTS:	$SAVE	<T1,T2>			; Save registers
	ACVAR	<ARGD>			; Pointer to device argument block
	$CALL	ALCARG			; Allocate a FEI%O argument block	
	MOVE	ARGD,S1			; Save another copy of arg blk ptr
	MOVX	T1,FC.RDS		; Function to read device status
	MOVEM	T1,(ARGD)		; Put into argument block
	DMOVE	T1,[EXP -DS.BYT		;  Reinitialize the byte count
		    POINT 8,STSBUF]	;  and byte pointer, may be destroyed
	DMOVEM	T1,1(ARGD)
	$CALL	FEI%O			; I/O to the front end (Device status)
	SETZ	S1,			; Default to no error occured
	SKIPT				; If an error occured
	 LOAD	S1,(ARGD),ARG$RC	;  get the result code
	EXCH	S1,ARGD			; Exchange error code and blk ptr
	$CALL	RLSARG			; Release the argument block
	MOVE	S1,ARGD			; Get the error code again
	JUMPE	S1,@.RETT		; If no error then give success
	$RETF				;  else give error return
	SUBTTL	Return line status

; Routine - LINSTS
;
; Function - To get the status of a line specified in the given PDD.
;
; Parameters -
;
;	S2/	Pointer to handle list entry
;
; Returns -

LINSTS:	$SAVE	<T1,T2>			; Save registers
	ACVAR	<ARGL>			; Pointer to line argument block
	$CALL	ALCARG			; Allocate a FEI%O argument block	
	MOVE	ARGL,S1			; Save another copy of arg blk ptr
	MOVX	T1,FC.RLS		; Function to read line status
	MOVEM	T1,(ARGL)		; Put into argument block
	DMOVE	T1,[EXP -LS.BYT		;  Reinitialize the byte count
		    POINT 8,STSBUF]	;  and byte pointer, may be destroyed
	DMOVEM	T1,1(ARGL)
	$CALL	FEI%O			; I/O to the front end (Device status)
	SETZ	S1,			; Default to no error occured
	JUMPT	LNST.5			; If no error .. continue on

	SETZM	STSBUF			; Clear first word in status buffer
	MOVE	S1,[XWD STSBUF,STSBUF+1] ; Point to the status buffer and
	BLT	S1,STSBUF+<LS.BYT-1>/4	;  clear all words
	LOAD	S1,(ARGL),ARG$RC	; Get the failure result code

LNST.5:	EXCH	S1,ARGL			; Exchange error code and blk ptr
	$CALL	RLSARG			; Release the argument block
	MOVE	S1,ARGL			; Get the error code again
	JUMPE	S1,@.RETT		; If no error then give success
	$RETF				;  else give error return
	SUBTTL	SETIOM -- Set the I/O mode of a device

; Routine - SETIOM
;
; Function - To determine whether a device is setup to do input or output and
;	save a flag in the handle list entry for future reference.
;
; Parameters -
;
;	S2/	Location of handle list entry

SETIOM:	$SAVE	<S1,T1>			; Save a couple of registers

	LOAD	S1,(S2),H$STY		; Get the station type code
	CAIN	S1,SLHSP		; Check for a HASP station
	 JRST	STHSP			;  Yes .. go get IOM from device status
	SETZ	T1,			; On 2780/3780 figure out IOM
	LOAD	S1,(S2),H$DEV		;  from the device type
	CAIN	S1,.OPCDR		;  which if it is a card reader
	 MOVX	T1,1			;  then it's doing input
	LOAD	S1,(S2),H$TEM		;  unless we are in
	SKIPE	S1			;  emulation mode in which case
	 TXC	T1,1			;  the I/O goes in the other direction
	JRST	SETDNE			; Done figuring out for a 2780/3780

STHSP:	LOAD	S1,(S2),H$DEV		; Get D60OPN device number
	CAIN	S1,.OPSGN		; Check for signon device
	 JRST	STHP.1			;  Yes .. so infer default of input
	CAIE	S1,.OPCIN		; Check for console input device
	CAIN	S1,.OPCOU		;  or for console output device
	 CAIA				;   Yes .. set I/O mode
	  JRST	HSPDEV			;  No .. so get I/O mode from DN60
	SETZ	T1,			; Default to output device
	CAIN	S1,.OPCIN		; Check for console input device
STHP.1:	 MOVX	T1,1			;  Yes so set to input mode
	LOAD	S1,(S2),H$TEM		; Get termination/emulation mode flag
	SKIPE	S1			; Check for termination
	 TXC	T1,1			;  No .. so reverse the I/O direction
	JRST	SETDNE			; Go store mode and return

HSPDEV:	$CALL	DEVSTS			; Get the device status
	 JUMPF	@.RETF			;  Can't get status so fail.
	LOAD	T1,,SDFLG		; Get the flags on the device
	LOAD	T1,T1,SDIOM		; Get the I/O mode flag

SETDNE:	STORE	T1,(S2),H$IOM		; Save the I/O mode for this device
	$RETT				; Return succesfully
	SUBTTL	ALCARG, RLSARG -- FEI%O argument block allocation/release

; Routine - ALCARG
;
; Function - This routine allocates a dynamic argument block for use with
;	     FEI%O.
;
; Parameters -
;
;	S1/	Pointer to block returned here

ALCARG:	$SAVE	<S2>			; Save a GLX parameter register
	MOVX	S1,ARGSIZ		; Size of argument block
	$CALL	M%GMEM			; Get from GLX memory mangler
	MOVE	S1,S2			; Move pointer to return register
	$RET				; Return, ignoring errors

; Routing - RLSARG
;
; Function - This routine releases a FEI%O argument block that was allocated
;	     with ALCARG.
;
; Parameters -
;
;	S1/	Location of argument block

RLSARG:	$SAVE	<TF,S1,S2>			; Save GLX parameter register
	MOVE	S2,S1			; Move block pointer
	MOVX	S1,ARGSIZ		; Size of argument block
	$CALL	M%RMEM			; Give it back to GLXLIB
	$RET				; Return, ignoring errors
	SUBTTL	LINCMD, DEVCMD -- Output a line (device) command

; Routine - LINCMD, DEVCMD
;
; Function - To output a DN60 line (device) command to the line (device)
;	specified in the handle entry.
;
; Parameters -
;
;	S1/	Line (device) command function code
;	S2/	Handle list entry
;	T1/	Command value (optional)

LINCMD:	ACVAR	<ARGC,FC,CLEN>		; Arg blk ptr, func code, cmd length
	MOVX	FC,FC.WLC		; Function code to write a line command
	MOVE	CLEN,LNCBYT(S1)		; Get number of bytes in value for cmd
	JRST	CNTCMD			; Continue on common command code

DEVCMD:	ACVAR	<ARGC,FC,CLEN>		; Arg blk ptr, func code, cmd length
	MOVX	FC,FC.WDC		; Function code to write a device cmd
	MOVE	CLEN,DVCBYT(S1)		; Get number of bytes in cmd string

CNTCMD:
	LOAD	TF,(S2),H$THR		; Get offline threshold for device
	PUSH	P,TF			; Save the offline threshold
	SETZ	TF,			; Set threshold so that when a delay
	STORE	TF,(S2),H$THR		;  occurs .. off line returns
	MOVE	ARGC,S1			; Save the command number
	$CALL	ALCARG			; Allocate a FEI%O arg block
	EXCH	S1,ARGC			; Swap arg blk ptr and command number
	STORE	FC,(ARGC),ARG$FC	; Save the function code (write cmd)
	STORE	S1,(ARGC),CMD$FC	; Put command function in cmd string
	CAIN	CLEN,1			; Check for only 1 byte in cmd string
	 JRST	SNDCMD			;  Yes .. so no data follows it.
	CAIN	CLEN,2			; Check for 2 bytes in cmd string
	 JRST	B1CMD			;  Yes .. so 1 byte of data follows
	STORE	T1,(ARGC),CMD$2B	; Otherwise we have 2 bytes of data
	JRST	SNDCMD			;  to send
B1CMD:	STORE	T1,(ARGC),CMD$1B	; Store the single byte of cmd data
SNDCMD:	MOVNS	CLEN			; Make the byte count and
SNDC.1:	MOVE	S1,[POINT 8,]		; Make a pointer to the command string
	HRRI	S1,CMD$WD(ARGC)		;  in dynamic memory
	STORE	S1,(ARGC),ARG$PT	; Put it into the FE I/O arg block
	STORE	CLEN,(ARGC),ARG$BC	; Set the number of bytes to output
	MOVE	S1,ARGC			; Point to the arg block
	$CALL	FEI%O			;  and do the I/O to the front end
	SETZ	S1,			; Default to no error occured
	JUMPF	[LOAD	S1,(ARGC),ARG$RC ; Get the result code on error
		 CAIE	S1,D6DOL	; Check for device off line (delayed)
		  JRST	.+1		;  Nope .. some other obtuse error 
		 SNOOZE	SEC		; Yes .. sleep for a second and
		 JRST	SNDC.1]		;  retry until it works
	EXCH	S1,ARGC			; Exchange error code and blk ptr
	$CALL	RLSARG			; Release the argument block
	MOVE	S1,ARGC			; Get the error code again
	POP	P,TF			; Get real offline threshold back
	STORE	TF,(S2),H$THR		;  and put into handle list entry
	JUMPE	S1,@.RETT		; If no error then give success
	$RETF				;  else give error return
	SUBTTL	Routines -- SWAPB, SWAP32

; Routines - SWAPB, SWAP32
;
; Function - To swap the bytes in 16 bit numeric values before they are
;	shipped to the DN60 front end.  This is needed because the FE
;	always swaps the bytes so that text strings are properly accessable.
;
; Parameters -
;
;	T1/	Value be swapped

; SWAPB returns the 16 bit value in the lower order 15 bits of T1

SWAPB:	$SAVE	<S1,S2>			; Save a couple of registers
	SETZB	S1,S2			; Clear them out
	ROTC	S2,-^d8			; Shift high order byte into S2
	LSHC	S1,^d8			; Shift it into S1
	ROTC	S2,-^d8			; Shift the low order byte into S2
	LSHC	S1,^d8			; Shift it lower into S1
	MOVE	T1,S1			; Move to return value
	$RET				; Give any old return .. no T/F

REPEAT 0,<
; SWAP32 Reverses the order of the 4 8bit bytes in T1

SWAP32:	$SAVE	<S1,S2>			; Save a couple of registers

	SETZB	S1,S2			; Clear them out
	ROTC	S2,-^d8			; Shift the high order byte
	LSHC	S1,^d8			; Put into bottom of S1
	ROTC	S2,-^d8			; Shift next byte down
	LSHC	S1,^d8			; Put below MSB in S1
	ROTC	S2,-^d8			; Same for 3rd byte
	LSHC	S1,^d8			;  and add into S1
	ROTC	S2,-^d8			; Shift the LSB into S2
	LSHC	S1,^d8			; Put as lowest byte in S1
	MOVE	T1,S1			; Return value
	$RET				;  and go back
    > ;End REPEAT 0
	SUBTTL	Select a DTE on the open FEn device
TOPS20 <

; Routine - SELDTE
;
; Function - To select which DTE is currently attached to the FEn: device
;	that was previously opened.  This routine assumes that the caller
;	has already enq'd the port.
;
; Parameters -
;
;	S1/	DTE # to be selected
;
; Returns -
;
;	True	was successful
;	False	MTOPR Jsys failed and the error code is in S1
;
; Note - It has been verified by looking at the monitor listings that this
;	routine does not need the port ENQ'd before selecting the DTE.

SELDTE:	MOVX	S2,.MODTE		; Select the appropriate DTE
	HRROI	T1,-10(S1)		; Get the port number
	CAMN	T1,LSTDTE		; Was it the same as the last one used?
	 $RETT				;  Yes so assume he is still set up.
	HRRZ	T1,T1			; Make it only the DTE number
	MOVE	S1,FEJFN		; Use the FE JFN already opened
	MTOPR				; Do the select
	 ERJMP	DSLERR			;  Didn't work, bad DTE
	HRROM	T1,LSTDTE		; Save the last DTE to be selected
	$RETT				; It is now selected on the DTE

DSLERR:	SETZM	LSTDTE			; Clear the last DTE selected (none)
	MOVX	S1,.FHSLF		; Get the last error that occured
	GETER				;  in this process
	HRRZ	S1,S2			; Set the error value 
	$RETF				;  and return flaging failure.

    >; End if TOPS20
	SUBTTL	FEI%O -- Front end I/O interface

; Routine - FEI%O
;
; Function - To do I/O to a device as specified by an argument block and the
;	data in the specified handle list entry.
;
; Parameters -
;
;	S1/	Location of argument block
;	S2/	Pointer to handle list entry
;
;	argument block format:
;			0/	function code
;			1/	negative number of bytes to transfer
;			2/	byte pointer to buffer to transfer from/to
;			3/	number of bytes actually transfered
;			4/	result code from I/O

FEI%O:
	SUBTTL	FEI%O -- TOPS20 SIN/SOUT front end interface (.C11QU functions)
TOPS20 <

	$SAVE	<P1,P2,T1,T2,T3,T4>	; Save registers

	DMOVE	P1,S1			; Set up arg and handle structure ptrs

	SETZM	NBXFRD(P2)		; Clear the number of bytes transfered
	SETZM	NBSDLY(P2)		; Clear number of bytes since last dly
	LOAD	S1,(P2),H$PRT		; Get the DTE #
	CAIL	S1,DTEOFF		; Check to see if the DTE # is within
	CAILE	S1,MAXDTE		;  valid bounds
	 JRST	ERT (D6NSP,FIOFAI)	;   Port number not defined
	SKIPN	KSFLG			; Check for KL style I/O
	 JRST	[$CALL	SELDTE		;  Make the link to the correct DTE
		  JUMPF	FIOFAI		;   If didn't work give error return
		 JRST .+1]		;  Go back to inline code
	LOAD	T1,(P1),ARG$BC		; Get the number of bytes to transmit
	JUMPGE	T1,ERT (D6CNN,FIOFAI)	; Must be greater than zero bytes
	MOVEM	T1,NBTXFR(P2)		; Save number of bytes yet to transfer
	LOAD	S1,(P2),H$PDD		; Get device descriptor
	$CALL	ENQD60			; Enqueue the port for SIN/SOUT I/O
	LOAD	T1,(P1),ARG$PT		; Get the pointer to the buffer area
	HLRZ	T2,T1			; Get the position/size part
	CAIN	T2,-1			; If it is a HRRO type byte pointer
	 HRLI	T1,440700		;  then convert it to a real byte pntr
	STORE	T1,(P1),ARG$PT		; Put the byte pointer back
	LOAD	T1,(P1),ARG$FC		; Get function code to perform
	STORE	T1,,XMTFC		; Put it into 2nd byte in header
	LOAD	T1,(P2),H$LIN		; Get line number to do I/O to.
	STORE	T1,,XMTLN		; Put it into 3rd byte in header
	LOAD	T1,(P2),H$CDV		; Get communications device number
	STORE	T1,,XMTDV		; Put the device code in the 4th byte
	LOAD	T1,(P1),ARG$FC		; Get the function we are doing
	TRNN	T1,1			; If it is odd then we do a read
	 JRST	WRITE			;  else we are doing a write operation.
	JRST	READ			; Go do read
	SUBTTL	FEI%O -- Read in from device (TOPS20)

READ:	$FELOG	(BEFORE)		; Log before any action on FE device
	$CALL	PUTHDR			; Output the header to say read data
	 JUMPF	FIOFDQ			;  Header failure test
	$CALL	GETHDR			; Get the response header
	 JUMPF	FIOFDQ			;  Input header no good
	LOAD	S1,,RCVRC		; Get the result of the header
	CAIN	S1,RC.REJ		; Check for reject of header
	 JRST	FIOFDQ			;  If so .. terminate this read
	CAIE	S1,RC.DLY		; Check for a delayed return
	 JRST	READOK			;  No .. so continue on reading
	LOAD	S1,(P2),H$DLY		; Get the transfered delayed count
	AOJ	S1,			; Increment the number of delays
	STORE	S1,(P2),H$DLY		;  and save it for next check
	LOAD	S2,(P2),H$THR		; Get the off-line threshold
	CAML	S1,S2			; Check for off-line by inference
	 JRST	ERT (D6DOL,FIOFDQ)	;  Yes .. too long to respond
	$FELOG	(AFTER)			; Log that a delay has occured
	$CALL	FIOSLP			; Dismiss while waiting for -11 to
	JRST	READ			;  catch up .. then try again

READOK:	LOAD	T1,,RCVBC		; Number of bytes to read in
	JUMPE	T1,ERT (RC.REJ,FIOFDQ)	; Can't talk to FE if no bytes Xfer'd
	MOVE	S1,FEJFN		; Get JFN for logical FE
	LOAD	S2,(P1),ARG$PT		; Get byte pointer to data buffer
	MOVN	T1,T1			; Negative the byte count to read
	SKIPE	KSFLG			; Check for 2020 style I/O
	 JRST	RD.220			;  Yes so go do boots
	SIN				; Read in the data string
	 ERJMP	ERT (D6CTF,FIOFDQ)	;  The input JSYS failed
	STORE	S2,(P1),ARG$PT		; Save the pointer to continue on
	$CALL	IOBRK			; Force all the input to be done
	 JUMPF	FIOFDQ			;  The force didn't work
	JRST	RD.WRK			; Input worked .. continue on

RD.220:	$CALL	RD2020			; Do a 2020 style read data string
	 JUMPF	FIOFDQ			;  Input failed
	STORE	S2,(P1),ARG$PT		; Save byte pointer for continuation

RD.WRK:	ZERO	((P2),H$DLY)		; Clear delayed return count
	LOAD	T1,,RCVBC		; Get the byte count to read again.
	ADDM	T1,NBXFRD(P2)		; Up the bytes transfered count
	ADDB	T1,NBTXFR(P2)		; Down the bytes yet to transfer
	JUMPGE	T1,FIOTDQ		; Test for no more bytes yet to move
	LOAD	T1,(P2),H$RTI		; Get return immediately on any data
	JUMPN	T1,FIOTDQ		; If set .. return on partial transfer
	$FELOG	(AFTER)			; Log that partial read has been done
	JRST	READ			; Go continue transfer
	SUBTTL	FEI%O -- Write out to device (TOPS20)

WRITE:	$FELOG	(BEFORE)		; Log before any FE I/O action
	$CALL	PUTHDR			; Output the transmit header
	 JUMPF	FIOFDQ			;  The header transmission failed
	MOVE	S1,FEJFN		; Get the JFN to do I/O on
	LOAD	S2,(P1),ARG$PT		; Point to the string to output
	LOAD	T1,,XMTBC		; Number of bytes to output
	MOVN	T1,T1			; Make negative for JSYS size delimit
	SKIPE	KSFLG			; Check for 2020 style I/O
	 JRST	WR.220			;  Yes .. go do the BOOTS
	SOUT				; Output the string
	 ERJMP	ERT (D6CTF,FIOFDQ)	;  The SOUT failed .. can't talk to FE
	MOVEM	S2,LSTPNT(P2)		; Save the pointer to last byte
	$CALL	IOBRK			; Force the output to the -11
	 JUMPF	FIOFDQ			;  Die if the output didn't go to -11
	JRST	WRT.23			; Data output just fine .. continue

WR.220:	$CALL	WR2020			; Output string 2020 style
	 JUMPF	FIOFDQ			;  Output failed .. release the device
	MOVEM	S2,LSTPNT(P2)		; Save the updated byte pointer

WRT.23:	$CALL	GETHDR			; Get the -11's reply to transmission
	 JUMPF	FIOFDQ			;  Die if we can't get the result
	LOAD	S1,,RCVRC		; Get the result code
	CAIN	S1,RC.REJ		; Check for a reject
	 JRST	FIOFDQ			;  and if so .. give failure return
	LOAD	T1,,RCVBC		; Get the number of bytes sent
	ADDM	T1,NBXFRD(P2)		;  add onto number of bytes transfered
	ADDM	T1,NBSDLY(P2)		;  add onto bytes since last delay
	ADDB	T1,NBTXFR(P2)		; Remove from number of bytes yet to do
	CAIE	S1,RC.DLY		; Check for a delayed I/O return
	 JRST	WRTOK			;  No .. so the -11 is ready
	SETZM	NBSDLY(P2)		; Clear bytes transfered since this dly
	LOAD	S1,(P2),H$DLY		; Get the delayed count
	AOJ	S1,			; Increment it
	STORE	S1,(P2),H$DLY		;  and save it back
	LOAD	S2,(P2),H$THR		; Get the offline threshold
	CAML	S1,S2			; Check for offline inference
	 JRST	ERT (D6DOL,FIOFDQ)	;  Yes .. the device seems offline
	$FELOG	(AFTER)			; Log that a delay has occured
	$CALL	FIOSLP			; Dismiss process for a while
	JRST	WRITE			; Go retry to output

WRTOK:	ZERO	((P2),H$DLY)		; Clear the delayed output counter
	MOVE	S2,LSTPNT(P2)		; Get the pointer to last byte
	STORE	S2,(P1),ARG$PT		; Save byte pointer to next byte
	JUMPGE	T1,FIOTDQ		; If none left .. then successful
	$FELOG	(AFTER)			; Log partial transfer done
	MOVE	S1,NBSDLY(P2)		; Get number of bytes since last delay
	CAIL	S1,RLSTHR		; Check against release threshold
	 $CALL	FIOSLP			;  Yes .. let go for a second
	JRST	WRITE			; Go finish writing
	SUBTTL	FEI%O -- Routine PUTHDR, GETHDR, IOBRK (TOPS20)

; Routine - PUTHDR
;
; Function - To create a transmit header for read/write function that contains
;	the number of bytes to read/write in it. This routine is invoked before
;	each read/write is done if more data is needed to be read/written.
;	This routines also transmits the header and makes sure that it has gone
;	out.

PUTHDR:	MOVM	T1,NBTXFR(P2)		; Get # of bytes left to read/write

	LOAD	T2,(P2),H$BPM		; Get number of bytes per message
	SKIPE	KSFLG			; Check for DDCMP (2020) line
	 MOVX	T2,^O274		;  Max number of bytes for DMC driver

	CAMLE	T1,T2			; Check to see if number of bytes legal
	 MOVE	T1,T2			;  Too many .. truncate 1st message
	STORE	T1,,XMTBC		; Store in the # bytes to transfer cnt
	MOVE	S1,FEJFN		; Get the JFN for the FE
	MOVE	S2,[POINT 8,XMTHDR]	; Point to the transmit header
	MOVX	T1,-6			; Get the string byte count
	SKIPE	KSFLG			; Check for 2020 style I/O
	 JRST	PTH.22			;  Yes .. go do the BOOTS
	SOUT				; Output the header to the device
	 ERJMP	ERT (D6CTF)		;  Can't talk to FE
	PJRST	IOBRK			; Make sure the header gets output.

PTH.22:	$CALL	WR2020			;  and output the header 2020 style
	$RET				; Propagate return success/failure

; Routine - GETHDR
;
; Function - To read a receive header from the port that we are currently
;	talking to.

GETHDR:	MOVE	S1,FEJFN		; Get the JFN of the FE
	MOVE	S2,[POINT 8,RCVHDR]	; Point to the receive header string
	MOVX	T1,-6			; 6 bytes in the header
	SKIPE	KSFLG			; Check for 2020 style I/O
	 JRST	GTH.22			;  Go do the BOOTS
	SIN				; Read the header from the FE
	 ERJMP	ERT (D6CTF)		;  Can't talk to FE
	PJRST	IOBRK			; Force the header to be read

GTH.22:	$CALL	RD2020			; Read header 2020 style
	$RET				; Propagate error return code
; Routine - IOBRK
;
; Function - To create a break in the I/O stream and force the current buffers
;	to be flushed or finished reading in.


IOBRK:	MOVE	S1,FEJFN		; Get the JFN of the FE device
	MOVX	S2,.MOEOF		; Get the EOF function
	MOVX	T1,1			; Clear FE buffers w/o doing real EOF
	MTOPR				; Force I/O completion
	 ERJMP	ERT (D6CTF)		;  Can't talk to FE
	$RETT				; The I/O was completed succesfully.


; Routine - FIOSLP
;
; Function - This routine saves the transmission header before dismissing
;	     the process. This is needed during FEI%O (TOPS20) execution
;	     to insure if the host program is a multi-tasker, that the
;	     header is still intact and the port is DEQ/ENQ for others to use.

FIOSLP:	$SAVE	<XMTHDR,XMTHDR+1>	; Save the transmission header
	LOAD	S1,(P2),H$PDD		; Get the packed device descriptor
	$CALL	DEQD60			; Release the port for some other task
FIOS.1:	SNOOZE	SEC*TIMDLY,IOWAIT	; Delay on time (or IO done if tasking)
	LOAD	S1,(P2),H$PDD		; Get the packec device desriptor again
	$CALL	ENQD60			; Try to get the port back again
	$RET
	SUBTTL	FEI%O -- Routines FIOTDQ, FIOFDQ, FIOFAI (TOPS20)

;
; Common return point for the FEI%O routines after the port has been ENQ'd.
;  This is for good (successful) returns that give a zero result code.
;

FIOTDQ:	LOAD	S1,(P2),H$PDD		; Get the port number
	$CALL	DEQD60			; Dequeue the port
	ZERO	((P1),ARG$RC)		; Clear the result code for good signal
	MOVE	S1,NBXFRD(P2)		; Get the number of bytes transfered
	STORE	S1,(P1),ARG$XF		;  and return that also
	MOVE	S1,NBTXFR(P2)		; Get number of bytes not transfered
	STORE	S1,(P1),ARG$BC		; Save it as the byte count
	DMOVE	S1,P1			; Restore the arg registers
	$FELOG	(AFTER)			; Log the successful result from 11
	$RETT				; Return with success

;
; Common failure return point before the port is enqueued
;

FIOFAI:	STORE	S1,(P1),ARG$RC		; Save the error result code
	JRST	FIOFD0			; Go to common error exit

;
; Common failure return point .. Deq's the port and stores the error code
;

FIOFDQ:	STORE	S1,(P1),ARG$RC		; Save the result code
	LOAD	S1,(P2),H$PDD		; Get the packed device descriptor
	$CALL	DEQD60			; Release the port
	MOVE	S1,NBTXFR(P2)		; Get number of bytes not transfered
	STORE	S1,(P1),ARG$BC		; Save it as the byte count

FIOFD0:	MOVE	S1,NBXFRD(P2)		; Get the number of bytes transfered
	STORE	S1,(P1),ARG$XF		;  and return that also
	DMOVE	S1,P1			; Restore the 2nd arg register
	$FELOG	(AFTER)			; Log the failed result from 11
	$RETF				; Return type of a failure
	SUBTTL	Support for DN200 running DN65B code on a TOPS20 2020


; Routine WR2020
;
; Function - This routine is used to simulate the SOUT to a front end
;	     device. It actually ships the data over a synchronous link
;	     using DDCMP to a DN200
;
; Parameters -
;
;	S1/	Ignored JFN
;	S2/	Byte pointer to string
;	T1/	Negative byte count

WR2020:	SKIPLE	T1			; Check for valid byte count LSS 0
	 JRST	ERT (D6CNN)		;  Byte count not negative
	MOVMM	T1,.BTLEN+BTARG		; Set the byte count to transfer
	MOVEM	S2,.BTMSG+BTARG		; Set pointer to 8 bit byte area
	LOAD	S1,(P2),H$HPR		; Get synchronous line number
	MOVEM	S1,.BTDTE+BTARG		; Set it as the DTE/line in BOOT block
	MOVEI	S2,BTARG		; Get location of BOOT arg block
	MOVX	S1,.BTSDD		; Send DDCMP message to DN200
	BOOT
	 ERJMP	ERT (D6CTF)		;  BOOT JSYS failed
	MOVE	S2,.BTMSG+BTARG		; Get update byte pointer
	SETZ	T1,			; Say that all the bytes where output
	$RETT				; Sucess in sending data
; Routine RD2020
;
; Function - To read a string from a DN200 that is connected by a DDCMP
;	     synchronous link. This routine simulates the SIN JSYS that
;	     is normally used with a front end device.
;
; Parameters -
;
;	S1/	Ignored JFN
;	S2/	Byte pointer to input buffer
;	T1/	Negative byte count to input

RD2020:	DMOVEM	S2,RDSAVE		; Save the read arguments
	MOVX	S1,20			; Set up the retry counter so that
	MOVEM	S1,RETRY		;  we try at least 2 seconds worth
	LOAD	S1,(P2),H$HPR		; Get synchronous line number
	MOVEM	S1,.BTDTE+BTARG		; Set it as the DTE/line in BOOT block

RD20ST:	MOVMM	T1,.BTLEN+BTARG		; Set the byte count to transfer
	MOVEM	S2,.BTMSG+BTARG		; Set pointer to data buffer
	MOVEI	S2,BTARG		; Get location of BOOT arg block
	MOVX	S1,.BTRDD		; Read DDCMP message function
	BOOT				; Do the read
	 ERJMP	ERT (D6CTF)		;  BOOT JSYS failed
	MOVE	S1,.BTLEN+BTARG		; Get transfered length/error code
	JUMPE	S1,R20RTY		; If zero .. must try again
	TXNN	S1,BT%CTL		; Check for control message flag
	 JRST	R20OK			;  No .. so message was read ok
	CAXE	S1,BT%CTL+.BTCMP	; Transmission complete?
	 JRST	ERT (D6DNR)		;  No .. so front end not running
	JRST	R20AGN			; Try to read it again
R20RTY:	SOSGE	S1,RETRY		; Have we already tried enough?
	 JRST	ERT (D6DNR)		;  Yes .. so front end not running
	MOVE	S1,[DEC 1000,1000,1000,1000,1000,100,100,100
		    DEC 100,100,100,100,100,100,100,100](S1)
	DISMS				; Increasing sleep increments
					;  with time
R20AGN:	DMOVE	S2,RDSAVE		; Get the arguments back again
	JRST	RD20ST			; Go try to read it again

R20OK:	MOVE	T1,S1			; Get the count of bytes transfered
	ADD	T1,RDSLEN		; Make it minus the number yet to get
	MOVE	S2,.BTMSG+BTARG		; Get updated byte pointer
	$RETT				; Success

    >;End if TOPS20
	SUBTTL	FEI%O -- TOPS10 CAL11. interface (.C11QU function)

TOPS10 <
	$SAVE	<S1,S2,P1,P2,P3,T4>	; Save registers

	DMOVE	P1,S1			; Setup regs for structure accesses

	MOVX	S1,C$SIZ		; Get size of a CAL11. argument block
	$CALL	M%GMEM			; Get a block from memory mangler
	MOVE	P3,S2			; Point to the new, fresh block
	PUSH	P,[[$SAVE <TF>		; Define return through release routine
		   MOVX	S1,C$SIZ	;  Get size of block
		   MOVE	S2,P3		;  Location of block
		   PJRST M%RMEM]]	;  Give memory to GLX handler; return

	LOAD	S2,(P2),H$PRT		; Get the port number
	STORE	S2,(P3),C$PRT		; Save it in the CAL11. block
	LOAD	S2,(P2),H$LIN		; Get the line number
	STORE	S2,(P3),C$LIN		; Save it also
	LOAD	S2,(P2),H$CDV		; Get device number to talk to
	STORE	S2,(P3),C$DEV		; Save in argument block

	LOAD	S1,(P1),ARG$FC		; Get the desired function to perform
	STORE	S1,(P3),C$FC		; Save in CAL11. argument block
	MOVX	S1,.C11QU		; We assume that all CAL11. functions
	STORE	S1,(P3),C$FNC		;  are subfunctions of the "queue" func

	LOAD	S1,(P1),ARG$PT		; Get the byte pointer to the string
	LOAD	S2,S1,BP.ADR		; Get the address of the string
	STORE	S2,(P3),C$BFA		;  and store as where the string starts
	LOAD	S2,S1,BP.SIZ		; Get the byte size
	CAIN	S2,77			; Check for HRRO type byte pointer
	 MOVX	S2,7			;  and if so assume ASCII (7bit)
	MOVE	S2,[0,,6		; Get the number of bytes per word
		    0,,5		;  depending on the number of bits
		    0,,4]-6(S2)		;  per byte in the string
	STORE	S2,(P3),C$BPW		; Save in CAL11. bytes per word entry
	LOAD	S2,S1,BP.POS		; Get the position of the first byte
	CAIN	S2,77			; Check again for a HRRO pointer
	 MOVX	S2,44			;  and start at MSB if so.
	SUBX	S2,44			; Remove the number of bits per word
	MOVM	S1,S2			; Get the magnitude of the difference
	LOAD	S2,(P3),C$BPW		; Retrieve the number of bytes per word
	IDIV	S1,S2			; Divide to get the position of the
	STORE	S1,(P3),C$PFB		;  first byte in the first word.
	LOAD	S2,(P1),ARG$BC		; Get the number of bytes to transfer
	MOVM	S2,S2			; Get it as a positive number
	STORE	S2,(P3),C$NBT		; Save byte count to transfer
	ADDI	S2,-1(S1)		;  add on the position of first byte -1
	HRRZ	S1,S2			; Move them around so that
	LOAD	S2,(P3),C$BPW		;  we can divide by the number of bytes
	IDIV	S1,S2			;  per word and then increment by
	AOJ	S1,			;  one to round off the odd word
	STORE	S1,(P3),C$BFS		; Store as the buffer size in words.

FERTRY:	ZERO	((P3),C$RC)		; Clear out the result code

	HRLI	S1,C$SIZ		; Length of CAL11. block
	HRR	S1,P3			; Location of CAL11. block
	$FELOG	(BEFORE)		; Log the data before sending it
	CAL11.	S1,			;  for the talk to the 11.
	 JRST	FEERR			;   Error while talking to 11
	$FELOG	(AFTER)			; Log the result from the 11
	LOAD	S1,(P3),C$BXF		; Get the number of byts transfered
	STORE	S1,(P1),ARG$XF		;  and return in to the caller
	LOAD	S1,(P3),C$RC		; Get the result code of the transfer
	STORE	S1,(P1),ARG$RC		;  return that also to the caller
	$RETT				; Return with a good indication

FEERR:	$FELOG	(AFTER)			; Log the failure from the 11
	CAIE	S1,C11IU%		; Was the 11 in use when we tried it?
	 JRST	FEFATL			;  No .. we got some other fatal error
	SNOOZE	SEC*TIMOFF		; Take time off to give the other user
	JRST	FERTRY			;  a chance to release the 11 and retry

FEFATL:	STORE	S1,(P1),ARG$RC		; Store error code for the caller to
	$RETF				;  see and return falsely.
    > ;End if TOPS10
	SUBTTL	Data area - Locals (to this fork)

LOCALS:					; This label must be first in local
					;  data base area.

ENQBLK:	XWD	1,5			; 1 lock,,length of block is 5
	XWD	0,0			; PSI chn 0,, ID
TOPS10 <BYTE	(2)1(16)0(18)-2>	; No PSI or level and exclusive access
TOPS20 <EXP	EN%BLN+EN%LTL+<0,,-3>>	; long term data base,, Operator only
	POINT	7,0			; Pointer to string of resource name
	XWD	0,0			; 1 resource,, number of accesses

QPRT0:	POINT	3,1(S2),20		; Low order digit of port number
QPRT1:	POINT	3,1(S2),13		; High order digit of port number
QLIN0:	POINT	3,2(S2),6		; Low order digit of line number
QLIN1:	POINT	3,1(S2),34		; High order digit of line number
QDEV0:	POINT	3,2(S2),34		; Low order digit of device number
QDEV1:	POINT	3,2(S2),27		; Middle digit of device number
QDEV2:	POINT	3,2(S2),20		; High order digit of device number
QUNT0:	POINT	3,3(S2),20		; Low order digit of unit number
QUNT1:	POINT	3,3(S2),13		; High order digit of unit number

QD60BF:	ASCIZ	\DN60-P00\		; Same name as used by D60SPD and
					;  D60SPL so that if they run at the
					;  same time somehow we won't die.
QLINBF:	ASCIZ	\DN60-P00L00\		; Use to ENQ/DEQ a particular station
QDEVBF:	ASCIZ	\DN60-P00L00D000U00\	; Define unique Q' entry for a
					;  particular device on a specific 2780

FEDEVS:	ASCIZ	/FE/			; Start of front end name

TOPS20 <
FEJFN:	BLOCK	1			; JFN of the front end device FEn:
LSTDTE:	BLOCK	1			; Last DTE that was selected
RCVHDR:: BLOCK	2			; Receive header
XMTHDR:: BLOCK	2			; Transmit header

APRNUM:	BLOCK	1			; Processor serial number
KSFLG:	BLOCK	1			; 0 if KL -1 if KS

XMSG:	BLOCK	^o274/4+1		; DDCMP Q flush buffer
RETRY:	BLOCK	1			; BOOT retry counter
BTARG:	BLOCK	5			; BOOT JSYS argument block
RDSAVE:	BLOCK	1			; Save area for RD2020 arguments
RDSLEN:	BLOCK	1			;  including the length
    >;End if TOPS20

TOPS10 <
C11BLK:	BLOCK	C$SIZ			; Block for OPNFE DN60 checking
    >;End if TOPS10

HANLST:	EXP	-1			; Name of handle linked list.
STSBUF:	BLOCK	<STSMAX+3>/4		; Status buffer for port,line or device
					;  status strings (8 bit bytes).
DEFTHR:	EXP	OFLDFL			; Default number of delayed returns
					;  before offline device implied

 ENDLOC==.-1				; End of process local data base
	SUBTTL	Data area - literals


DVCBYT:	EXP	0,2,3,1,1		; Number of bytes in dev cmd's 0-4
	EXP	0,1,1,1,1		;	5-9
	EXP	0,0,2,1,3		;	10-14
	EXP	1,3,1,1,1		;	15-19
	EXP	1,1,1,1,1		;	20-24
	EXP	1,1,1,1,1		;	25-29
	EXP	1,1,3			;	30-32

LNCBYT:	EXP	0,3,2,1,1		; Number of bytes in line cmds 0-4
	EXP	3,3,1,1,3		;	5-9
	EXP	3,3			;	10,11

D6JVER:: EXP	%%.D60			; Cell containing version number

	XLIST				; Suppress listing of literals
	LIT
	LIST

	END
; Local Modes:
; Mode:Fundamental
; Comment Column:40
; Comment Start:;
; Auto Save Mode:2
; Word Abbrev Mode:1
; End: