Google
 

Trailing-Edge - PDP-10 Archives - bb-d868c-bm_tops20_v4_2020_distr - language-sources/cdrive.mac
There are 37 other files named cdrive.mac in the archive. Click here to see a list.
	TITLE	CDRIVE - Multiple Card Reader Spooler

;
;
;                COPYRIGHT (c) 1978,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.


	SEARCH	GLXMAC,ORNMAC,QSRMAC
	SEARCH	D60UNV			;GET DN60 SYMBOLS
	PROLOG	(CDRIVE)

	.DIRECT	FLBLST

IF1,<
	TOPS10	<PRINTX Assembling Galaxy-10 Card Reader Spooler>
	TOPS20	<PRINTX Assembling Galaxy-20 Card Reader Spooler>
>

	SALL

	;VERSION INFORMATION

	RDRVER==1
	RDRMIN==0
	RDREDT==31
	RDRWHO==0

	%RDR==<BYTE (3)RDRWHO (9)RDRVER (6)RDRMIN (18)RDREDT>

	LOC	137

	EXP	%RDR

	RELOC	0
	SUBTTL	SETUP REMOTE STATION PARAMETERS


	;IF WE HAVE RJE SUPPORT, GET JSYS SIMULATION PACKAGE

	FTRMTE==FTRJE!FTDN60		;SEE IF ANY REMOTES GEN'D

	IFN	FTRJE,<.REQUIRE NURD.REL>	;GET DN200 I/O PACKAGE

	IFN	FTDN60,<.REQUIRE D60JSY.REL	;GET DN60 I/O PACKAGE
			 D60ERR>		;GEN D60 ERROR CODES
	SUBTTL	Revision History

COMMENT \

1	Add Symbols CRDNBR, CRDSIZ. Change the processing routines
	to use them.

2	Add SNDSTS routine to send QUASAR current device status information

3	Change IB to new format and add PIB.

4	Delete routine DISPAT. Add DN200 support.

5	Add Status update messages capability

6	Major revision to support DN200 and DN60 readers

7	Fixup minor bugs caused by revision 6

10	Add routine OACSHT for defered reader shutdown.
	Make a lot of minor cosmetic modifications.

11	Fix major bugs caused by introduction of DN60 support

12	Add the operator command processor for DN60 remote stations

13	For DN60 card readers, after sleeping for 3 seconds following
	an offline condition, when we wake up clear the offline flag
	so that we perform another scheduling pass.

14	Change the IPCF send/recieve quotas from max to 20.

15	Change the DN60 open code to support the new port/line handles.

16	Fix a bug which would enable -20 CDRIVE to miss an IPCF interrupt

17	Fix a bug so that the correct error text is displayed on fork 
	termination

20	Delete the Send/Receive Quotas from the PIB.

21	Make a check for Non-Existant Readers in the Tops20 Open Routine.

22	Delete the call to F%FCHN and use the stream number as the channel
	number (TOPS10 Only)

23	Fix a Bug - Move the code to close the spool file to CREATE.

24	Add DN60 line conditioning support.

25	Don't interrupt the superior when re-initing the reader for device EOF.

26	At last, finish up DN60 changes. Delete DB entry .RDCND and replace
	it with .RDSUP in which we will now store the SETUP message.
	Change the calling parms for D60CND to use the SETUP message
	instead of .RDCND
	Change all references to .RDCND to .RDSUP

27	Add support for Node-Went-Away message.

30	Fix a bug affecting the -10 only. In SETUP, SETZM the FLAG word
	after setting up the card reader data base.

31	Change 'Cancelled' to 'Canceled'

\ ;End of Revision History
	SUBTTL	CARD READER DATA BASE

	FILEMK==17777			;MASK FIELD FOR FILE NAME SPEC
	IBYT60==7			;INPUT DN60 BYTES ARE ASCII
	OBYT60==7			;OUTPT DN60 BYTES ARE ASCII
	IBYTSZ==^D18			;INPUT LOCAL/DN200 BYTES ARE 16 BITS
	OBYTSZ==^D18			;OUTPT LOCAL/DN200 BYTES ARE 18 BITS
	D60RCL==^D82			;DN60 RECORD LENGTH = 80 + <CRLF>
	LOCRCL==^D80			;LOCAL/DN200 RECORD LENGTH = 80


	MAXRDR==^D15			;MAXIMUM NUMBER OF READERS
	PDSIZE==100			;PDL SIZE
	MSBSIZ==30			;MESSAGE BUFFER SIZE

	;AC USAGE

	M==13				;INCOMMING IPCF MESSAGE ADDRESS
	RDR==14				;RDR DATA BASE 
	AP==15				;POINTER TO BYTE TRANSLATION TABLE
	FLAG==16			;AC 16 HOLD FLAGS

	;STREAM STATUS BITS

	JOBCD==1B1			;JOB CARD READ AND JOB SETUP
	INTRPT==1B2			;READER IS CONNECTED TO INTRPT SYSTEM
	ABORT==1B3			;STREAM ABORT BIT.
	GOODBY==1B4			;STREAM IS ON ITS WAY OUT
	CD20==1B6			;READER LINE IS CD20
	EOF==1B8			;AN EOF CONDITION OCCURED

	SYSPRM	FDSIZE,FDMSIZ,10	;SPOOL FILE FD SIZE
	SYSPRM	CRDNBR,5,5		;NBR OF CARDS TO BE PROCESSED AT A TIME
	SYSPRM	BUFSIZ,<<CRDNBR*LOCRCL>/2>,<<<CRDNBR+1>*LOCRCL>/2> ;BUFFER SIZE
	SYSPRM	DBSIZE,2,1		;DYNAMIC DATA BASE SIZE (IN PAGES)

	DEFINE	GETBYT(AC,PTR),<ILDB AC,PTR
	XLIST
	ANDI	AC,7777
	LIST
	>  ;END GETBYT
	SUBTTL	LOCAL, DN200, & DN60 BYTE DEFINITIONS

	LOC	0
JIMGUC:! BLOCK	1			;UPPER CASE CHARACTER 'J'
JIMGLC:! BLOCK	1			;LOWER CASE CHARACTER 'j'
OIMGUC:! BLOCK	1			;UPPER CASE CHARACTER 'O'
OIMGLC:! BLOCK	1			;LOWER CASE CHARACTER 'o'
BIMGUC:! BLOCK	1			;UPPER CASE CHARACTER 'B'
BIMGLC:! BLOCK	1			;LOWER CASE CHARACTER 'b'
DIMGUC:! BLOCK	1			;UPPER CASE CHARACTER 'D'
DIMGLC:! BLOCK	1			;LOWER CASE CHARACTER 'd'
EIMGUC:! BLOCK	1			;UPPER CASE CHARACTER 'E'
EIMGLC:! BLOCK	1			;LOWER CASE CHARACTER 'e'
$IMAGE:! BLOCK	1			;CHARACTER '$'
BLANK:!  BLOCK	1			;CHARACTER ' '
ENDIMG:! BLOCK	1			;END OF JOB CHARACTER
IMGLEN:!				;BLOCK LENGTH
	RELOC

	;DEFINE THE CHARACTER CODES FOR LOCAL AND DN200

LOC200:	$BUILD	IMGLEN
	 $SET(JIMGUC,,2400)		;IMAGE MODE 'J'
	 $SET(JIMGLC,,6400)		;IMAGE MODE 'j'
	 $SET(OIMGUC,,2010)		;IMAGE MODE 'O'
	 $SET(OIMGLC,,6010)		;IMAGE MODE 'o'
	 $SET(BIMGUC,,4200)		;IMAGE MODE 'B'
	 $SET(BIMGLC,,5200)		;IMAGE MODE 'b'
	 $SET(DIMGUC,,4040)		;IMAGE MODE 'D'
	 $SET(DIMGLC,,5040)		;IMAGE MODE 'd'
	 $SET(EIMGUC,,4020)		;IMAGE MODE 'E'
	 $SET(EIMGLC,,5020)		;IMAGE MODE 'e'
	 $SET($IMAGE,,2102)		;IMAGE MODE '$'
	 $SET(BLANK,,00000)		;IMAGE MODE ' '
	 $SET(ENDIMG,,7417)		;IMAGE MODE FOR END OF JOB
	$EOB

	;DEFINE THE CHARACTER CODES FOR THE DN60

CHAR60:	$BUILD	IMGLEN
	 $SET(JIMGUC,,112)		;ASCII MODE 'J'
	 $SET(JIMGLC,,152)		;ASCII MODE 'j'
	 $SET(OIMGUC,,117)		;ASCII MODE 'O'
	 $SET(OIMGLC,,157)		;ASCII MODE 'o'
	 $SET(BIMGUC,,102)		;ASCII MODE 'B'
	 $SET(BIMGLC,,142)		;ASCII MODE 'b'
	 $SET(DIMGUC,,104)		;ASCII MODE 'D'
	 $SET(DIMGLC,,144)		;ASCII MODE 'd'
	 $SET(EIMGUC,,105)		;ASCII MODE 'E'
	 $SET(EIMGLC,,145)		;ASCII MODE 'e'
	 $SET($IMAGE,,44)		;ASCII MODE '$'
	 $SET(BLANK,,40)		;ASCII MODE ' '
	 $SET(ENDIMG,,177)		;ASCII MODE FOR END OF JOB
	$EOB
	SUBTTL	CARD READER DATA BASE

	PHASE	0

.RDIPT:! BLOCK	1			;CARD BUFFER BYTE POINTER
.RDOPT:! BLOCK	1			;OUTPUT BUFFER POINTER
.RDCAD:! BLOCK	1			;CARD ADDRESS WITHIN INPUT BUFFER
.RDNBR:! BLOCK	1			;NUMBER OF CARDS IN THE BUFFER.
.RDSTR:! BLOCK	1			;READER STREAM NUMBER
.RDBFR:! BLOCK	1			;READER BUFFER ADDRESS.
.RDSTA:! BLOCK	1			;DEVICE STATUS WORD
.RDTIM:! BLOCK	1			;JOB START TIME
.RDINI:! BLOCK	1			;END RDR INITIALIZATION FLAG
.RDSUP:! BLOCK	SUP.SZ			;DEVICE SETUP MESSAGE
.RDREM:! BLOCK	1			;0=LOCAL,-1=DN200 REMOTE,+1=DN60 REMOTE
.RDOPB:! BLOCK	OP$SIZ			;DN60 DEVICE OPEN BLOCK
.RDFLG:! BLOCK	1			;FLAG WORD FOR DN60
.RDN60:! BLOCK	1			;HASP CONSOLE INPUT JFN
.RDECT:! BLOCK	1			;DEVICE ERROR COUNT
.RDIBZ:! BLOCK	1			;INPUT BYTE SIZE WE'RE PROCESSING
.RDOBZ:! BLOCK	1			;OUTPT BYTE SIZE WE'RE PROCESSING
.RDRCL:! BLOCK	1			;RECORD SIZE WE ARE PROCESSSING
.RDREG:! BLOCK	20			;STREAM AC SAVE AREA
.RDPDL:! BLOCK	PDSIZE			;STREAM CONTEXT PDL.
.RDIOA:! BLOCK	1			;INTERRUPT RETURN ADDRESS.
.CARDS:! BLOCK	BUFSIZ			;BUFFER AREA
.RDFD:!  BLOCK	FDSIZE			;FILE DESCRIPTOR FOR SPOOL FILE
.RDFOB:! BLOCK	4			;FILE OPEN BLOCK FOR GLXFIL
.RDIFN:! BLOCK	1			;GALAXY IFN FOR SPOOL FILE.
.RDJBT:! BLOCK	1			;COUNT OF CARDS IN DECK
.RDJBC:! BLOCK	1			;COUNT OF TOTAL JOB CARDS FOUND
.RDEOJ:! BLOCK	1			;COUNT OF TOTAL EOJ CARDS
.RDEND:! BLOCK	1			;COUNT OF TOTAL END CARDS
.RDREJ:! BLOCK	1			;COUNT OF REJECTED CARDS
.RDIPC:! BLOCK	1			;IPCF MESSAGES SENT
.RDSHT:! BLOCK	1			;SHUTDOWN FLAG -1=SHUTDOWN THE READER

TOPS10 <
.RDBLK:! BLOCK	3			;TOPS-10 OPEN BLOCK.
.RDIOB:! BLOCK	0			;CDR BUFFER CONTROL BLOCK.
.RDBUF:! BLOCK	1			;CDR BUFFER ADDRESS
.RDBPT:! BLOCK	1			;CDR BYTE POINTER.
.RDBCT:! BLOCK	1			;CDR BUFFER LENGTH
.RDUDX:! BLOCK	1			;CARD READER UDX
.RDCHN:! BLOCK	1			;CDR CHANNEL #
.RDUNT:! BLOCK	1			;READER UNIT NUMBER
.RDDEV:! BLOCK	1			;CARD READER DEVICE NUMBER
>  ;END TOPS10 CONDITIONAL


	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE


TOPS20 <
.RDHND:! BLOCK	1			;INFERIOR PROCESS HANDLE
.RDJFN:! BLOCK	1			;READER JFN
.RDRFD:! BLOCK	5			;READER FILE DESCRIPTOR
.RDOFL:! BLOCK	1			;ONLINE/OFFLINE FLAG (0=ON, -1=OFF)
.RDSTP:! BLOCK	10			;ERROR MESSAGE BUFFER
.RDSAB:! BLOCK	SAB.SZ			;IPCF SAB BLOCK
.RDMSG:! BLOCK	MSBSIZ			;IPCF MESSAGE BUFFER
.RDSTS:! BLOCK	1			;FLAG -1=SEND STATUS UPDT MSG
.RDCAN:! BLOCK	1			;CANCEL FLAG -1=CANCEL CURRENT JOB
>  ;END TOPS20 CONDITIONAL

	DEPHASE
	SUBTTL	Random Impure Storage


PDL:	BLOCK	PDSIZE		;PUSHDOWN LIST
MESSAG:	BLOCK	1		;ADDRESS OF MESSAGE JUST RECEIVED
SAB:	BLOCK	SAB.SZ		;A SEND ARGUMENT BLOCK
MSGBLK:	BLOCK	MSBSIZ		;A BLOCK TO BUILD MESSAGES IN.
BYTPTR:	BLOCK	1		;BYTE POINTER FOR $TEXT ROUTINE
SCHEDL:	BLOCK	1		;STREAM SCHEDULING DATA
CNTSTA: BLOCK	1		;NUMBER OF THE CENTRAL STATION
RUTINE:	BLOCK	1		;MESSAGE PROCESSING ROUTINE ADDRESS.
NOSAVE:	BLOCK	1		;INDICATOR 0=SAVE FLAG BITS, -1=DONT.
FILENM:	BLOCK	1		;READER SPOOL FILE HASH CODE
FILEXT:	0,,1			;READER SPOOL FILE EXTENSION
SPOOL:	BLOCK	1		;SPOOL STRUCTURE PPN
PRGSTA:	BLOCK	1		;SPOOLER START ADDRESS (PAGE NUMBER)
RDRSIZ:	BLOCK	1		;SPOOLER LENGTH IN PAGES
TRMFRK:	BLOCK	1		;FORK TERMINATION FLAG
FRKINI:	BLOCK	1		;END FORK INITIALIZATION FLAG

	SUBTTL	Resident JOB Database

STREAM:	BLOCK	1		;CURRENT STREAM NUMBER

JOBPAG:	BLOCK	MAXRDR		;ADDRESS OF A TWO PAGE BLOCK

JOBOBA:	BLOCK	MAXRDR		;TABLE OF OBJECT BLOCK ADDRESSES

JOBSTW:	BLOCK	MAXRDR		;JOB STATUS WORD

JOBSTS:	BLOCK	MAXRDR		;STATUS UPDATE FLAG 0=NO,-1=YES

JOBOBJ:	BLOCK	3*MAXRDR	;LIST OF SETUP OBJECTS
	SUBTTL	GLXLIB IB AND HELLO MESSAGE STRUCTURES


	TOPS10	<INTVEC==VECTOR>

	TOPS20	<INTVEC==:LEVTAB,,CHNTAB>


IB:	$BUILD	IB.SZ				;
	  $SET	(IB.PRG,,%%.MOD)		;PROGRAM 'CDRIVE'
	  $SET  (IB.FLG,IP.STP,1)		;STOPCODES TO ORION
	  $SET	(IB.PIB,,PIB)			;SET UP PIB ADDRESS
	  $SET	(IB.INT,,INTVEC)		;SETUP INTERRUPT VECTOR ADDRESS
	$EOB					;


PIB:	$BUILD	PB.MNS				;
	  $SET	(PB.HDR,PB.LEN,PB.MNS)		;PIB LENGTH,,0
	  $SET	(PB.FLG,IP.PSI,1)		;PSI ON
	  $SET	(PB.INT,IP.CHN,0)		;INTERRUPT CHANNEL
	  $SET	(PB.SYS,IP.MNP,^D20)		;MAX NUMBER OF PIDS
	$EOB					;



HELLO:	$BUILD	HEL.SZ
	  $SET(.MSTYP,MS.TYP,.QOHEL)		;MESSAGE TYPE
	  $SET(.MSTYP,MS.CNT,HEL.SZ)		;MESSAGE LENGTH
	  $SET(HEL.NM,,<'CDRIVE'>)		;PROGRAM NAME
	  $SET(HEL.FL,HEFVER,%%.QSR)		;QUASAR VERSION
	  $SET(HEL.NO,HENNOT,1)			;NUMBER OF OBJ TYPES
	  $SET(HEL.NO,HENMAX,MAXRDR)		;MAX NUMBER OF JOBS
	  $SET(HEL.OB,,.OTRDR)			;RDR OBJECT TYPE
	$EOB


;SCHEDULER FLAGS

	PSF%ID==1B1		;INPUT DONE WAIT
	PSF%DO==1B2		;DEVICE IS OFF-LINE
	PSF%ST==1B3		;STOPPED BY OPERATOR
	PSF%SH==1B4		;SHUT DOWN A CARD READER
	SUBTTL	CDRIVE - Multiple card reader spooler.

CDRIVE:	RESET				;AS USUAL.
	MOVE	P,[IOWD PDSIZE,PDL]	;SET UP THE STACK.
	MOVEI	S1,IB.SZ		;GET THE IB SIZE.
	MOVEI	S2,IB			;ADDRESS OF THE IB.
	PUSHJ	P,I%INIT		;SET UP THE WORLD.
	PUSHJ	P,RDINIT		;GO SETUP READER CONSTANTS
	PUSHJ	P,INTINI		;SET UP THE INTERRUPT SYSTEM.
	PUSHJ	P,I%ION			;TURN ON INTERRUPTS.
	PUSHJ	P,I%NOW			;GET THE DATE/TIME
	MOVEM	S1,FILENM		;SAVE IT AS THE SPOOL FILE HASH CODE
	MOVEI	S1,HELLO		;GET ADDRESS OF HELLO MESSAGE.
	MOVEI	S2,HEL.SZ		;GET LENGTH OF HELLO IN S2
	PUSHJ	P,SNDQSR		;SAY HI TO QUASAR.
	MOVSI	P1,-MAXRDR		;SET UP STREAM COUNTER.
	JRST	MAIN			;GO TO SCHEDULING LOOP
	SUBTTL	Idle Loop

TOPS10 <

MAIN:	SKIPN	JOBPAG(P1)		;IS THE STREAM ACTIVE ???
	JRST	MAIN.2			;NO,,GET THE NEXT STREAM.
	HRRZM	P1,STREAM		;RUNNABLE STREAM!!!
	MOVE	RDR,JOBPAG(P1)		;YES, GET JOB PAGE
	SKIPE	JOBSTS(P1)		;WANT TO SEND STATUS INFO ???
	PUSHJ	P,UPDTST		;GO UPDATE AND SEND STATUS INFORMATION
	SKIPE	JOBSTW(P1)		;IS THE STREAM WAITING ???
	JRST	MAIN.2			;YES,,GET THE NEXT STREAM.
	MOVEM	P1,SCHEDL		;SAVE THE SCHEDULING STREAM.
	MOVSI	17,.RDREG(RDR)		;ELSE SETUP TO RESTORE
	BLT	17,17			;    SOME ACS
	MOVE	S1,.RDNBR(RDR)		;GET # OF CARDS IN TEMP BUFFER
	CAIL	S1,CRDNBR		;HAVE WE READ ENOUGH ???
	PUSHJ	P,READER		;YES,,GO PROCESS THE CARDS
	SKIPE	.RDSHT(RDR)		;IS A SHUTDOWN SCHEDULED ???
	TXNE	FLAG,JOBCD		;YES,,ARE WE PROCESSING A JOB ???
	POPJ	P,			;YES,,JUST RETURN
	PUSHJ	P,SHUTIT		;TIME TO SHUTDOWN,,SO DO IT !!!

MAIN.1:	MOVE	P1,SCHEDL		;GET THE LAST SCHEDULED STREAM.

MAIN.2:	AOBJN	P1,MAIN			;LOOP BACK FOR SOME MORE.
	PUSHJ	P,CHKQUE		;CHECK FOR INCOMMING MESSAGES.
	MOVEI	S1,^D60			;SLEEP FOR 60 SECONDS.
	SKIPN	MESSAGE			;IF WE PROCESSED A MESSAGE,,RESCHEDULE.
	PUSHJ	P,I%SLP			;ELSE,,GO WAIT
	MOVE	P,[IOWD PDSIZE,PDL]	;RESET THE STACK POINTER.
	MOVSI	P1,-MAXRDR		;GET LOOP AC.
	JRST	MAIN			;KEEP ON PROCESSING.


SENDIT:	JRST	SNDQSR			;SLIGHT CROCK FOR -10/-20 COMPATABILITY
SNDOPR:	JRST	OPRMSG			;HERE ALSO
	SUBTTL OACCAN - Operator CANCEL request.

OACCAN:	MOVE	S1,STREAM			;GET THE STREAM NUMBER
	TXZE	FLAG,JOBCD			;TELL READER WE ARE LEAVING.
	$ACK	(Current Job Aborted,,@JOBOBA(S1),.MSCOD(M))
	$RETT

	SUBTTL	OACPAU - Operator PAUSE Request

OACPAU:	MOVX	S2,PSF%ST		;GET THE STOPPED BITS
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	IORM	S2,JOBSTW(S1)		;LITE THE STOPPED BITS.
	SETOM	JOBSTS(S1)		;SEND STATUS TO QUASAR NEXT SCHD PASS
	$ACK	(Stopped,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR WHAT HE DID
	$RETT				;AND RETURN.


	SUBTTL	OACCON - Operator CONTINUE Request

OACCON:	MOVX	S2,PSF%ST		;GET THE STOPPED BITS.
	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	ANDCAM	S2,JOBSTW(S1)		;DE-LITE THE STOPPED BITS.
	SETOM	JOBSTS(S1)		;SEND STATUS TO QUASAR NEXT SCHD PASS
	$ACK	(Continued,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPR WHAT HE DID.
	$RETT				;AND RETURN.


	SUBTTL	OACSHT - ROUTINE TO VALIDATE THE READER SHUTDOWN STATUS

OACSHT:	TXNN	FLAG,JOBCD		;ARE WE PROCESSING A JOB ???
	$RETT				;NO,,THEN SHUTDOWN IS OK.
	SETOM	.RDSHT(RDR)		;YES,,LITE DEFERED SHUTDOWN FLAG
	$RETF				;AND RETURN (NO SHUTDOWN)
	SUBTTL	RDINIT - ROUTINE TO INITIALIZE SOME READER CONSTANTS

RDINIT:	PUSHJ	P,I%HOST		;GET OUR SITE ID
	MOVEM	S2,CNTSTA		;SAVE AS OUR CENTRAL SITE NUMBER
	MOVX	S1,%LDQUE		;GET THE GETTAB PPN CODE
	GETTAB	S1,			;GET THE SPOOL PPN
	 $STOP	(CGS,Cannot Get Spool File PPN)
	MOVEM	S1,SPOOL		;SAVE IT
	$RETT				;RETURN
	SUBTTL 	DOJOB - ROUTINE TO PROCESS THE CARD READERS.

DOJOB:	HRLZ	S1,.RDOBZ(RDR)		;GET THE OUTPUT BYTE SIZE
	LSH	S1,6			;POSITION IT
	ADD	S1,[POINT 0,.CARDS(RDR)] ;MAKE THE BYTE POINTER
	MOVEM	S1,.RDOPT(RDR)		;AND SAVE IT.
	MOVE	S1,SPOOL		;GET THE SPOOL PPN
	MOVEM	S1,.RDFD+.FDPPN(RDR)	;SAVE IT
	MOVX	S1,FSSSTR		;GET THE SPOOL STRUCTURE NAME
	MOVEM	S1,.RDFD+.FDSTR(RDR)	;SAVE IT
	MOVEI	S1,FDSIZE		;GET THE FD SIZE
	STORE	S1,.RDFD+.FDLEN(RDR),FD.LEN ;SAVE IT
	MOVEI	S1,.RDFD(RDR)		;GET THE FD ADDRESS
	MOVEM	S1,.RDFOB+FOB.FD(RDR)	;SAVE IT
	MOVE	S1,.RDOBZ(RDR)		;GET THE BYTE SIZE
	STORE	S1,.RDFOB+FOB.CW(RDR),FB.BSZ ;SAVE IT
	MOVEI	S1,1			;GET A BIT
	STORE	S1,.RDFOB+FOB.CW(RDR),FB.NFO ;WANT 'NEW FILE ONLY'

CARDS:	PUSHJ	P,INCARD		;GET SOME CARDS
	JUMPF	CRDEOF			;NO MORE,,FINISH UP.
	PUSHJ	P,PRORDR		;GO PROCESS THE DATA CARDS.
	JRST	CARDS			;AND GET SOME MORE.

CRDEOF:	MOVE	S1,ENDIMG(AP)		;GET THE EOF CARD BITS
	IDPB	S1,.RDOPT(RDR)		;PUT IT IN THE BUFFER
	TXO	FLAG,EOF		;TURN ON EOF INDICATOR
	PUSHJ	P,READER		;GO FINISH UP THIS FILE
	JRST	CARDS			;GO LOOK FOR MORE CARDS.
SUBTTL	Deschedule Process


DEFINE $DSCHD(FLAGS),<
	PUSHJ	P,DSCHD
	XLIST
	JUMP	[EXP FLAGS]
	LIST
	SALL
>  ;END DEFINE $DSCHD


;DSCHD is called by the $DSCHD macro to cause the "current" stream to
;	be un-scheduled.  The call is:
;
;	$DSCHD(flags)
;
;which generates:
;
;	PUSHJ   P,DSCHD
;	JUMP    [EXP flags]

DSCHD:	MOVEM	0,.RDREG(RDR)		;SAVE AC 0
	MOVEI	0,.RDREG+1(RDR)		;PLACE TO PUT AC 1
	HRLI	0,1			;SETUP THE BLT POINTER
	BLT	0,.RDREG+17(RDR)		;SAVE AWAY THE ACS
	HRRZ	S1,0(P)			;GET ADDRESS OF "JUMP [FLAGS]"
	MOVE	S1,@0(S1)		;GET THE FLAGS
	MOVE	S2,STREAM		;GET THE STREAM NUMBER
	IORM	S1,JOBSTW(S2)		;SET THE FLAGS
	MOVE	P,[IOWD PDSIZE,PDL]	;RESET THE STACK POINTER.
	JRST	MAIN.1			;AND CONTINUE SCHEDULING.
	SUBTTL	PRORDR--READER INPUT PROCESSING

PRORDR:	TXNE	FLAG,CD20		;IS THIS A CD20 LINE ???
	JRST	PROR.4			;YES,,DO IT DIFFERENTLY
	HLLZ	P1,.RDBPT(RDR)		;SAVE READERS BYTE SIZE.
	MOVEI	S1,1400			;GEN A 12 BIT BYTE SIZE.
	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	ADDI	S1,440000		;IF SO, ADD BYTE POSITION.
	HRLM	S1,.RDBPT(RDR)		;CREATE A NEW BYTE POINTER.
	AOS	.RDBPT(RDR)		;POINT TO ACTUAL DATA.
PROR.1:	SKIPE	.RDREM(RDR)		;IF A LOCAL READER,,SKIP THIS
	ILDB	T1,.RDBPT(RDR)		;PICK UP A REMOTE CHARACTER.
	SKIPN	.RDREM(RDR)		;IF A REMOTE READER,,SKIP THIS
	LDB	T1,.RDBPT(RDR)		;PICK UP A LOCAL BYTE.
	JUMPE	T1,PROR.2		;IF A BLANK,,SKIP THIS.
	LDB	S1,[POINT 7,T1,33]	;GET CDR COLS 1-7.
	LSH	S1,35			;LEFT JUSTIFY THOSE BITS.
	JFFO	S1,.+2			;GET # OF LEADING 0 BITS.
	JRST	PROR.2			;NOTHING THERE,,SO SKIP THIS
	ADDI	S2,1			;ADD 1 TO 0 BIT COUNT.
	LSH	S1,1(S2)		;SHIFT THEM OUT + 1.
	SKIPE	S1			;IF S1=0, THEN NO READER ERROR.
	ADDI	S2,10			;ELSE TURN ON ERROR BIT.
	LSH	S2,^D12			;SHIFT TO CORRECT BIT POSITION.
	ADD	T1,S2			;MERGE INTO CORRECTED WORD.
PROR.2:	IDPB	T1,.RDOPT(RDR)		;AND SAVE THE RESULTING 18 BIT BYTE.
	SKIPN	.RDREM(RDR)		;IF THIS IS A LOCAL READER, THEN
	AOS	.RDBPT(RDR)		;    ADD 1 TO INPUT ADDRESS.
	SOSLE	.RDBCT(RDR)		;SUBTRACT 1 FROM BYTE COUNT
	JRST	PROR.1			;AND GO PROCESS THE NEXT BYTE.
	HLLM	P1,.RDBPT(RDR)		;RESTORE ORIGIONAL BYTE SIZE.
PROR.3:	AOS	S1,.RDNBR(RDR)		;BUMP THE NUMBER OF CARDS BY 1
	CAIL	S1,CRDNBR		;HAVE WE TRANSLATED ENOUGH YET ???
	PUSHJ	P,READER		;YES,,GO PROCESS THEM
	POPJ	P,			;RETURN TO MAIN PROGRAM

PROR.4:	MOVE	T1,.RDRCL(RDR)		;GET THE BYTE COUNT
	HRRZ	T2,.RDBPT(RDR)		;GET THE INPUT BUFFER ADDRESS
	ADD	T2,[POINT 16,1]		;CREATE THE BYTE POINTER
PROR.5:	ILDB	S1,T2			;GET AN INPUT BYTE
	IDPB	S1,.RDOPT(RDR)		;PUT IT OUT
	SOJG	T1,PROR.5		;MORE??,,KEEP PROCESSING
	JRST	PROR.3			;GO FINISH UP
	SUBTTL	INCARD - ROUTINE TO READ CARDS FROM THE CARD READER.

INCARD:	MOVE	S1,.RDCHN(RDR)		;GET THE READERS CHANNEL.
	TLO	S1,(IN 0,0)		;CREATE AN INPUT UUO.
	XCT	S1			;READ SOME DATA CARDS.
	$RETT				;NORMAL RETURN,,RETURN OK.

INERR:	MOVE	S1,.RDCHN(RDR)		;GET THE CHANNEL NUMBER.
	IOR	S1,[GETSTS .RDSTA(RDR)]	;CREATE A GETSTS UUO.
	XCT	S1			;GET THE DEVICE STSTUS.
	MOVE	S1,.RDSTA(RDR)		;LOAD IT HERE ALSO.
	TXNE	S1,IO.ERR		;WAS THERE AN ERROR ???
	JRST	INER.1			;YES,,GO PROCESS IT.
	$DSCHD(PSF%ID)			;BLOCK STREAM FOR INPUT DONE
	JRST	INCARD			;AND GO TRY AGAIN

INER.1:	TXNE	S1,IO.EOF		;WAS THE ERROR EOF ???
	$RETF				;YES,,RETURN NO MORE DATA.
	TRZ	S1,IO.ERR		;CLEAR ERROR BITS.
	HRLI	S1,(SETSTS 0,0)		;CREATE SETSTS UUO.
	ADD	S1,.RDCHN(RDR)		;ADD THE CHANNEL NUMBER.
	XCT	S1			;CLEAR THE ERROR BITS IN STATUS WORD.
	JRST	INCARD			;OK,,RETRY THE READ.
	SUBTTL	INPGET  --  OPEN the input device

INPGET:	SETOM	.RDCHN(RDR)		;INDICATE NO OUTPUT CHANNEL YET.
	PUSHJ	P,GENDEV		;CREATE THE PHYSICAL DEVICE NAME.
	MOVEM	S1,.RDDEV(RDR)		;AND SAVE IT
	MOVX	T1,UU.AIO+IO.SIM+.IOIMG	;GET OPEN FLAG BITS.
	MOVE	T2,.RDDEV(RDR)		;OUTPUT DEVICE NAME
	MOVEI	T3,.RDIOB(RDR)		;BUFFER HEADER
	MOVE	S1,STREAM		;USE OUR STREAM NUMBER AS THE CHANNEL #
	LSH	S1,^D23			;SHIFT IT TO ITS PROPER POSITION.
	MOVEM	S1,.RDCHN(RDR)		;SAVE IT FOR LATER
	IOR	S1,[OPEN T1]		;MAKE IT AN INSTRUCTION
	XCT	S1			;AND EXECUTE IT
	   JRST	OUTDNA			;LOSE GIVE ERROR

	MOVE	S2,STREAM		;AND STREAM NUMBER
	MOVE	S1,OBJ.UN(S2)		;GET THE UNIT NUMBER
	MOVEM	S1,.RDUNT(RDR)		;AND SAVE IT FOR CDRIVE
	SETZM	JOBSTW(S2)		;CLEAR THE STREAM STATUS BITS.
	MOVE	T1,.RDCHN(RDR)		;NO, GET THE CHANNEL
	LSH	T1,-^D23		;PUT IT IN THE RIGHT POSITION.
	WHERE	T1,			;GET THE LOCATION
	  SETZ	T1,			;ASSUME STATION 0
	TLZ	T1,-1			;CLEAR STATION FLAGS
	CAME	T1,CNTSTA		;IS IT THE CENTRAL STATION?
	SETOM	.RDREM(RDR)		;NO,,MAKE IT REMOTE
	MOVEI	T1,.DFHCW		;GET READER HARDWARD CHARACTERISTICS
	MOVE	T2,.RDDEV(RDR)		;FOR THIS READER
	MOVE	S1,[2,,T1]		;SET UP DEVOP. PARAMETER LIST
	DEVOP.	S1,			;GET CHARACTERISTICS...
	 $STOP	(CGC,Cannot Get Reader Hardware Characteristics)
	LOAD	S2,S1,DF.CLS		;GET THE LINE TYPE 
	CAXN	S2,.DFS20		;IS IT A CD20 LINE ???
	TXO	FLAG,CD20		;YES,,SET IT.
	MOVE	S1,.RDBFR(RDR)		;GET THE READERS BUFFER ADDRESS.
	EXCH	S1,.JBFF		;MAKE IT OUT END ADDRESS.
	MOVE	S2,.RDCHN(RDR)		;GET THE CHANNEL NUMBER
	IOR	S2,[INBUF CRDNBR]	;MAKE AN INSTRUCTION
	XCT	S2			;AND CREATE 'CRDNBR' BUFFERS
	MOVEM	S1,.JBFF		;RESTORE JOBFF
	JRST	OUTSOK			;AND CONTINUE ON

GENDEV:	MOVE	T1,STREAM		;PICK UP STREAM NUMBER.
	MOVE	T1,JOBOBA(T1)		;PICK UP OBJECT BLOCK ADDRESS.
	MOVE	S1,OBJ.ND(T1)		;PICK UP THE NODE NUMBER.
	IDIVI	S1,10			;SPLIT IT IN HALF.
	IMULI	S1,100			;SHIFT LEFT 2 DIGITS.
	ADD	S1,S2			;ADD SECOND NODE DIGIT.
	IMULI	S1,100			;SHIFT LEFT ANOTHER 2 DIGITS.
	ADD	S1,OBJ.UN(T1)		;ADD THE UNIT NUMBER.
	ADD	S1,[SIXBIT/CDR000/]	;CREATE THE PHYSICAL DEVICE NAME.
	POPJ	P,			;RETURN. . . . .
	SUBTTL	GENFIL - ROUTINE TO GENERATE THE SPOOL FILENAME

GENFIL:	PUSH	P,T1			;SAVE T1
	MOVE	S1,[POINT 6,.RDFD+.FDNAM(RDR)] ;BYTE PTR FOR FILENAME
	MOVEM	S1,BYTPTR		;SAVE IT.
	$TEXT	(CV26BT,<RD^D4L0/FILENM,FILEMK/>) ;CREATE THE SPOOL FILE NAME
	AOS	FILENM			;CREATE ANOTHER
	SETZM	.RDFD+.FDEXT(RDR)	;ZERO THE FILENAME EXT.
	MOVE	S1,FILEXT		;GET THE EXTENSION NUMBER
	IDIVI	S1,100			;GET THE THIRD DIGIT
	ADDI	S1,20			;MAKE IT SIXBIT.
	LSH	S1,6			;SHIFT IT OVER
	IDIVI	S2,10			;GET SECOND AND FIRST DIGITS
	ADDI	S2,20			;MAKE IT SIXBIT
	ADDI	T1,20			;HERE ALSO
	ADD	S1,S2			;PUT INTO S1
	LSH	S1,6			;SHIFT IT OVER
	ADD	S1,T1			;ADD FIRST DIGIT
	HRLZM	S1,.RDFD+.FDEXT(RDR)	;SAVE IT AS FILE EXT
	POP	P,T1			;RETSORE T1
	$RETT				;AND RETURN


CV26BT:	SUBI	S1,40			;CONVERT TO SIXBIT
	ANDI	S1,77			;JUST USE LAST 2 DIGITS
	IDPB	S1,BYTPTR		;SAVE THE BYTE
	$RETT				;AND RETURN


OUTSOK:	PUSHJ	P,INTCNL		;CONNECT UP THE READER
	TXO	FLAG,INTRPT		;TURN ON CONNECTED FLAG
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$WTO	(Started,,@JOBOBA(S1))	;TELL OPERATOR WE'RE STARTED
	MOVX	S1,%RSUOK		;LOAD THE CODE
	$RETT				;AND RETURN

OUTDNA:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$WTO	(Not available right now,,@JOBOBA(S1)) ;TELL THE OPERATOR
	MOVX	S1,%RSUNA		;NOT AVAILABLE RIGHT NOW
	$RETF				;AND RETURN

OUTDDE:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$WTO	(Does not exist,,@JOBOBA(S1)) ;TELL THE OPERATOR
	MOVX	S1,%RSUDE		;NEVER AVAILABLE
	$RETF				;RETURN
	SUBTTL	INPREL - ROUTINE TO RELEASE A CARD READER

INPREL:	TXZE	FLAG,INTRPT		;ARE WE CONNECT TO THE INTRPT SYSTEM ??
	PUSHJ	P,INTDCL		;REMOVE THE READER FROM THE INTRPT SYS
	SKIPGE	S1,.RDCHN(RDR)		;DID WE INIT A CHANNEL ???
	$RETT				;NO,,JUST RETURN
	LSH    S1,-^D23			;GET THE CHANNEL NUMBER
	RESDV. S1,			;RESET THE CHANNEL
	POPJ   P,			;IGNORE ERRORS
	POPJ   P,			;RETURN IF NORMAL
SUBTTL	Interrupt Module

;		INTINI		INITIALIZE INTERRUPT SYSTEM
;		INTCNL		CONNECT THE CARD READER
;		INTDCL		DISCONNECT THE CARD READER
;		INTIPC		INTERRUPT ROUTINE  --  IPCF


;INTERRUPT SYSTEM DATABASE


VECTOR:	BLOCK	0			;BEGINNING OF INTERRUPT VECTOR
VECIPC:	BLOCK	4			;IPCF INTERRUPT BLOCK
VECDEV:	BLOCK	4*MAXRDR		;DEVICE INTERRUPT BLK
	ENDVEC==.-1			;END OF INTERRUPT VECTOR

DEFINE CDINHD(Z),<
	XLIST
	$BGINT	1,
	MOVEI	S1,Z
	MOVEI	S2,VECDEV+<4*Z>
	JRST	CDINTR
	CDHDSZ==4
	LIST
>  ;END DEFINE CDINHD

INTINI:	MOVEI	S1,INTIPC		;GET ADDRESS OF IPCF INT RTN
	MOVEM	S1,VECIPC+.PSVNP	;SAVE IN VECTOR
	Z==0
REPEAT	MAXRDR,<XLIST
	MOVEI	S1,INTDEV+<CDHDSZ*Z>	;GET ADDRESS OF RDR HEADER
	MOVEM	S1,VECDEV+<4*Z>+.PSVNP	;STORE IN THE VECTOR
	Z==Z+1
	LIST
>  ;END REPEAT MAXRDR
	POPJ	P,			;AND RETURN


INTDCL:	SKIPA	S1,[PS.FRC+T1]		;REMOVE CONDITION USINGS ARGS IN T1
INTCNL:	MOVX	S1,PS.FAC+T1		;ADD CONDITION USING ARGS IN T1
	MOVE	T1,.RDCHN(RDR)		;USE CHANNEL AS CONDTION
	LSH	T1,-^D23		;MAKE IT RIGHT !!!
	MOVE	T2,STREAM		;GET STREAM NUMBER
	IMULI	T2,4			;GET BLOCK OFFSET
	ADDI	T2,VECDEV-VECTOR	;GET OFFSET FROM BEGINNING
	HRLZS	T2			;GET OFFSET,,0
	HRRI	T2,PS.RID+PS.RDO+PS.ROL	;AND CONDITIONS
	SETZ	T3,			;ZERO T3
	PISYS.	S1,			;TO THE INTERRUPT SYSTEM
	 $STOP	(CAD,CANNOT ADD/DELETE READER TO/FROM INTERRUPT SYSTEM)
	POPJ	P,			;AND RETURN
;Here on device interrupts on the -10.  This routine consists of multiple
;	interrupt headers (one for each stream) which load S1 and S2 and
;	call the main interrupt body, CDINTR.  Note that on the -10, while
;	it is assumed that 'input done' and 'on-line' interrupts can happen
;	anytime and anywhere, it is also assumed that 'device off-line'
;	interrupts ONLY HAPPEN IN THE STREAM CONTEXT.

INTDEV:	Z==0
	REPEAT MAXRDR,<
	CDINHD(Z)
	Z==Z+1 	      >

CDINTR:	MOVE	RDR,JOBPAG(S1)		;GET THE JOB PARAMETER PAGE
	SETOM	JOBSTS(S1)		;SEND STATUS INFO BACK ON NEXT SCHD PASS
	HRRZ	T1,.PSVFL(S2)		;GET I/O REASON FLAGS
	ANDCAM	T1,.PSVFL(S2)		;AND CLEAR THEM
	SETZ	T2,			;CLEAR AN AC
	TXNE	T1,PS.ROL		;IS IT ON-LINE?
	MOVX	T2,PSF%DO		;YES, GET THE CORRECT FLAG
	TXNE	T1,PS.RID		;IS IT INPUT DONE?
	TXO	T2,PSF%ID		;YES, GET SCHEDULER BIT
	ANDCAM	T2,JOBSTW(S1)		;CLEAR THE SCHEDULER FLAGS
	TXNN	T1,PS.RDO		;IS IT DEVICE OFF-LINE?
	$DEBRK				;NO,,DISMISS THE INTERRUPT.
	TXNE	T1,PS.ROL		;IF BOTH OFFLINE AND ONLINE,
	$DEBRK				;DISMISS THE INTERRUPT.
	MOVX	T2,PSF%DO		;GET OFF-LINE BIT.
	IORM	T2,JOBSTW(S1)		;   AND SET IT.
	MOVEI	T1,INPOFF		;LOAD RESTART ADDRESS
	EXCH	T1,.PSVOP(S2)		;STORE FOR DEBRK AND GET OLD ADRESS
	MOVEM	T1,.RDIOA(RDR)		;STORE OLD-ADDRESS FOR DEVICE ON AGAIN
INTDON:	$DEBRK				;DISMISS THE INTERRUPT.

INPOFF:	PUSH	P,S1			;SAVE S1
	PUSH	P,S2			;SAVE S2
	SKIPE	.RDNBR(RDR)		;ANYTHING IN THE BUFFERS ???
	PUSHJ	P,READER		;GO PROCESS THE BUFFERS
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	TXNE	FLAG,JOBCD		;ARE WE PROCESSING A JOB ???
	$WTO	(Offline,,@JOBOBA(S1))	;TELL THE OPERATOR RDR IS OFFLINE.
	SKIPE	S2,.RDREJ(RDR)		;ARE WE REJECTING CARDS ???
	$WTO	(< ^D/S2/ Cards Flushed >,,@JOBOBA(S1))
	SETZM	.RDREJ(RDR)		;ZERO THE REJECT COUNT
	$DSCHD(0)			;WAIT FOR ONLINE INTERRUPT.
	POP	P,S2			;RESTORE S2
	POP	P,S1			;RESTORE S1
	JRST	@.RDIOA(RDR)		;CONTINUE PROCESSING.
	SUBTTL	INTIPC - IPCF INTERRUPT PROCESSING ROUTINE


INTIPC:	$BGINT	1,			;SETUP FOR INTERRUPT
	PUSHJ	P,C%INTR		;FLAG THE INTERRUPT
	$DEBRK				;RETURN

>  ;END OF TOPS-10 CONDITIONAL CODE
	SUBTTL	CHKQUE - ROUTINE TO CHECK FOR IMCOMMING MESSAGES.

CHKQUE:	SETZM	MESSAG			;NO MESSAGE YET
	PUSHJ	P,C%RECV		;RECEIVE A MESSAGE
	JUMPF	.POPJ			;RETURN,,NOTHING THERE.
	LOAD	S2,MDB.SI(S1)		;GET SPECIAL INDEX WORD
	TXNN	S2,SI.FLG		;IS THERE AN INDEX THERE?
	JRST	CHKQ.1			;NO, IGNORE IT
	ANDX	S2,SI.IDX		;AND OUT THE INDEX
	CAIE	S2,SP.OPR		;IS IT FROM OPR?
	CAIN	S2,SP.QSR		;IS IT FROM QUASAR?
	JRST	CHKQ.2			;YES, CONTINUE ON
CHKQ.1:	PUSHJ	P,C%REL			;RELEASE THE MESSAGE
	POPJ	P,			;RETURN TO THE SCHEDULER.
CHKQ.2:	LOAD	S1,MDB.MS(S1),MD.ADR	;GET THE MESSAGE ADDRESS
	MOVEM	S1,MESSAG		;SAVE IT AWAY
	MOVE	M,S1			;SAVE THE MESSAGE ADDRESS HERE TOO
	LOAD	S2,.MSTYP(M),MS.TYP	;GET THE MESSAGE TYPE
	MOVSI	S1,-NMSGT		;MAKE AOBJN POINTER FOR MSG TYPES

CHKQ.3:	HRRZ	T1,MSGTAB(S1)		;GET A MESSAGE TYPE
	CAMN	S2,T1			;MATCH?
	JRST	CHKQ.4			;YES, WIN
	AOBJN	S1,CHKQ.3		;NO, LOOP
	PJRST	C%REL			;NO,,RELEASE THE MESSAGE

CHKQ.4:	HLRZ	T2,MSGTAB(S1)		;PICK UP THE PROCESSING ROUTINE ADDRESS.
	MOVEM	T2,RUTINE		;SAVE THE ROUTINE ADDRESS.
	SETZM	NOSAVE			;RESET THE FLAG SAVE FLAG WORD.
	PUSHJ	P,CHKOBJ		;GO FIND THE OBJECT BLOCK.
	PUSHJ	P,@RUTINE		;DISPATCH THE MESSAGE PROCESSOR.
	SKIPN	NOSAVE			;DO WE WANT TO SAVE THE FLAGS ???
	MOVEM	FLAG,.RDREG+FLAG(RDR)	;YES,,SAVE THE STATUS BITS.
	PUSHJ	P,C%REL			;RELEASE THE MESSAGE
	POPJ	P,			;RETURN TO THE SCHEDULER.

MSGTAB:	XWD	.RETT,.QORCK		;REQUEST-FOR-CHECKPOINT
	XWD	SETUP,.QOSUP		;SETUP/SHUTDOWN
	XWD	OACCON,.OMCON		;OPERATOR CONTINUE REQUEST.
	XWD	OACCAN,.OMCAN		;OPERATOR CANCEL REQUEST.
	XWD	OACPAU,.OMPAU		;OPERATOR PAUSE/STOP REQUEST.
	XWD	QSRNWA,.QONWA		;NODE-WENT-AWAY PROCESSOR

	NMSGT==.-MSGTAB
	SUBTTL - CHKOBJ - ROUTINE TO VALIDATE QUASAR/ORION/OPR MSG OBJ BLKS.


CHKOBJ:	CAIE	T1,.QORCK		;IS THIS A REQUEST FOR CHECKPOINT ???
	CAIN	T1,.QOSUP		; OR IS THIS A SETUP/SHUTDOWN MESSAGE ??
	$RETT				;YES,,RETURN.

	LOAD	S2,.OHDRS+ARG.HD(M),AR.TYP  ;PICK UP THE MSG BLK TYPE.
	CAIE	S2,.OROBJ		;IS IT THE OBJ BLK ???
	$STOP	(NFB,FIRST BLOCK IN MESSAGE NOT THE OBJECT BLOCK)
	MOVEI	S1,.OHDRS+ARG.DA(M)	;POINT TO THE OBJECT BLOCK.

	PUSHJ	P,FNDOBJ		;GO FIND THE OBJECT BLOCK.
	$RETT				;  AND RETURN.
	SUBTTL	SETUP/SHUTDOWN Message

SETUP:	LOAD	S1,SUP.FL(M)		;GET THE FLAGS
	TXNE	S1,SUFSHT		;IS IT A SHUTDOWN?
	JRST	SHUTDN			;IF SO,,SHUT IT DOWN !!!
	SETZ	T2,			;CLEAR A LOOP REG

SETU.1:	SKIPN	JOBPAG(T2)		;A FREE STREAM?
	JRST	SETU.2			;YES!!
	CAIGE	T2,MAXRDR-1		;NO, LOOP THRU THEM ALL?
	AOJA	T2,SETU.1		;NO, KEEP GOING
	$STOP(TMS,Too many setups)

SETU.2:	MOVEM	T2,STREAM		;SAVE THE STREAM NUMBER
	MOVEI	S1,DBSIZE		;NUMBER OF PAGES NEEDED
	PUSHJ	P,M%AQNP		;GET THEM
	PG2ADR	S1			;CONVERT TO AN ADDRESS
	MOVEM	S1,JOBPAG(T2)		;AND SAVE IT
	MOVE	RDR,S1			;PUT IT IN RDR
	SETZM	FLAG			;CLEAR THE READER FLAG WORD
	MOVEM	T2,.RDSTR(RDR)		;SAVE THE STREAM NUMBER
	MOVEI	S1,.RDPDL-1(RDR)	;SET UP THE STREAM CONTEXT
	HRLI	S1,-PDSIZE		;STACK POINTER.
	PUSH	S1,[EXP DOJOB]		;LETS START AT THE RIGHT SPOT.
	MOVEM	S1,.RDREG+P(RDR)	;SAVE THE STREAM STACK POINTER.
	MOVEM	RDR,.RDREG+RDR(RDR)	;SAVE RDR AWAY
	MOVEI	S1,1000(RDR)		;RDR BUFFER ADDRESS or END ADDRESS
	MOVEM	S1,.RDBFR(RDR)		;STORE IT
	MOVE	S2,T2			;COPY OVER THE STREAM NUMBER
	IMULI	T2,OBJ.SZ		;GET OFFSET OF OBJECT BLOCK
	ADDI	T2,JOBOBJ		;ADD IN THE BASE
	MOVEM	T2,JOBOBA(S2)		;STORE OBJECT ADDRESS
	MOVE	S2,T2			;GET DESTINATION OF BLT INTO S2
	HRLI	S2,SUP.TY(M)		;MAKE A BLT POINTER
	BLT	S2,OBJ.SZ-1(T2)		;BLT THE OBJECT BLOCK
	HRL	S2,M			;GET THE SETUP MESSAGE ADDRESS
	HRRI	S2,.RDSUP(RDR)		;WHERE WE WANT IT PUT
	BLT	S2,.RDSUP+SUP.SZ-1(RDR)	;SAVE THE SETUP MESSAGE IN THE DATA BASE

	SETZM	.RDREM(RDR)		;ASSUME THAT IT IS LOCAL OR DN200
	MOVEI	AP,LOC200		;SINCE LOCAL,,GET LOCAL/DN200 BYTE TABLE
	MOVX	S1,IBYTSZ		;SINCE LOCAL,,GET INPUT BYTE SIZE
	MOVEM	S1,.RDIBZ(RDR)		;   AND SAVE IT FOR LATER
	MOVX	S1,OBYTSZ		;SINCE LOCAL,,GET OUTPT BYTE SIZE
	MOVEM	S1,.RDOBZ(RDR)		;   AND SAVE IT FOR LATER
	MOVX	S1,LOCRCL		;GET LOCAL/DN200 RECORD LENGTH
	MOVEM	S1,.RDRCL(RDR)		;   AND SAVE IT FOR LATER
	MOVE	S1,SUP.NO(M)		;GET THIS GUYS NODE NAME
	CAMN	S1,CNTSTA		;IS IT REALLY LOCAL ???
	JRST	SETU.3			;YES,,SKIP THIS REMOTE STUFF

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	SKIPN	SUP.CN(M)		;IS THIS A DN60 REMOTE ???
	JRST	[SETOM  .RDREM(RDR)	;NO,,MUST BE DN200 - SET DN200 FLAG
		 JRST	SETU.3    ]	;AND CONTINUE PROCESSING

	MOVEI	S1,1			;GET A 1 (DN60 FLAG)
	MOVEM	S1,.RDREM(RDR)		;MAKE THIS A DN60 REMOTE
	MOVE	S1,SUP.ST(M)		;GET THE DN60 FLAG WORD
	MOVEM	S1,.RDFLG(RDR)		;SAVE IT FOR LATER
	MOVEI	AP,CHAR60		;GET DN60 BYTE TRANSLATION TABLE
	MOVX	S1,IBYT60		;GET DN60 INPUT BYTE SIZE
	MOVEM	S1,.RDIBZ(RDR)		;AND SAVE IT
	MOVX	S1,OBYT60		;GET DN60 OUTPUT BYTE SIZE
	MOVEM	S1,.RDOBZ(RDR)		;AND SAVE IT
	MOVX	S1,D60RCL		;GET DN60 RECORD LENGTH
	MOVEM	S1,.RDRCL(RDR)		;AND SAVE IT

SETU.3:	MOVEM	AP,.RDREG+AP(RDR)	;SAVE AP FOR PROCESSING
	PUSHJ	P,INPGET		;GET THE INPUT DEVICE.
	CAIE	S1,%RSUOK		;ALL IS OK?
	PJRST	SHUTIT			;NO, SHUT IT DOWN AND RETURN
TOPS10<	PUSHJ	P,RSETUP >		;SEND THE RESPONSE TO SETUP MSG.
	$RETT				;RETURN 
	SUBTTL	QSRNWA - ROUTINE TO PROCESS NODE-WENT-AWAY MESSAGES


QSRNWA:	MOVX	S1,%RSUNA		;GET NOT AVAILABLE RIGHT NOW STATUS
	PUSHJ	P,RSETUP		;TELL QUASAR HE CAN HAVE OBJECT BACK NOW
	SETOM	NOSAVE			;DON'T SAVE READER FLAG WORD
	PUSHJ	P,INPREL		;RELEASE THE READER
	MOVE	S2,RDR			;GET THE DATA BASE ADDRESS
	ADR2PG	S2			;CONVERT TO A PAGE NUMBER
	MOVX	S1,DBSIZE		;GET THE DATA BASE LENGTH
	PUSHJ	P,M%RLNP		;RETURN THE PAGES BACK TO MEMORY MANAGER
	PUSHJ	P,M%CLNC		;REALLY WIPE THEM OUT !!!
	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	SETZM	JOBPAG(S1)		;CLEAR THE DATA BASE POINTER
	$RETT				;RETURN
	SUBTTL	SHUTDN - ROUTINE TO SHUT DOWN A LINE-PRINTER


SHUTDN:	MOVEI	S1,SUP.TY(M)		;GET THE OBJECT BLOCK ADDRESS
	PUSHJ	P,FNDOBJ		;GO FIND IT
	PUSHJ	P,OACSHT		;GO SEE IF ITS OK TO SHUT IT DOWN
	JUMPF	.RETT			;NO,,RETURN NOW
SHUTIT:	PUSHJ	P,INPREL		;GO RELEASE THE READER
	MOVE	S2,RDR			;GET THE JOBPAG ADDRESS
	ADR2PG	S2			;CONVERT TO A PAGE NUMBER
	MOVEI	S1,DBSIZE		;LOAD THE NUMBER OF PAGES
	PUSHJ	P,M%RLNP		;RETURN THEM
	PUSHJ	P,M%CLNC		;GET RID OF UNWANTED PAGES.
	MOVE	S1,STREAM		;GET HIS STREAM NUMBER
	SETZM	JOBPAG(S1)		;CLEAR THE PAGE WORD
	SETOM	NOSAVE			;WE DONT WANT STREAM FLAG BITS SAVED.
	MOVX	S1,%RSUDE		;GET 'DOES NOT EXIST'
	PUSHJ	P,RSETUP		;TELL QUASAR TO GET RID OF IT
	$RETT				;RETURN


	SUBTTL	RSETUP - ROUTINE TO SEND A RESPONSE-TO-SETUP MSG TO QUASAR

RSETUP:	MOVE	T2,S1			;SAVE THE SETUP CONDITION CODE.
	MOVEI	S1,RSU.SZ		;GET MESSAGE LENGTH
	MOVEI	S2,MSGBLK		;AND THE ADDRESS OF THE BLOCK
	PUSHJ	P,.ZCHNK		;ZERO IT OUT
	MOVEI	T1,MSGBLK		;GET THE BLOCK ADDRESS
	MOVX	S1,RSU.SZ		;GET MESSAGE SIZE
	STORE	S1,.MSTYP(T1),MS.CNT	;STORE IT
	MOVX	S1,.QORSU		;GET FUNCTION CODE
	STORE	S1,.MSTYP(T1),MS.TYP	;STORE IT
	MOVE	S1,STREAM		;GET STREAM NUMBER
	MOVS	S1,JOBOBA(S1)		;GET OBJADR,,0
	HRRI	S1,RSU.TY(T1)		;AND PLACE TO MOVE IT TO
	BLT	S1,RSU.TY+OBJ.SZ-1(T1)	;AND MOVE THE OBJECT BLOCK
	STORE	T2,RSU.CO(T1)		;STORE TH CODE
	MOVE	S1,T1			;GET THE MESSAGE ADDRESS.
	MOVEI	S2,RSU.SZ		;GET THE MESSAGE LENGTH.
	PUSHJ	P,SNDQSR		;AND SEND THE MESSAGE
	$RETT				;RETURN.
	SUBTTL FNDOBJ - ROUTINE TO FIND THE OBJ BLK IN THE DATA BASE.

FNDOBJ:	MOVE	T1,.ROBTY(S1)		;GET OBJECT TYPE
	MOVE	T2,.ROBAT(S1)		;GET UNIT NUMBER
	MOVE	T3,.ROBND(S1)		;AND NODE NUMBER
	SETZ	T4,			;CLEAR AN INDEX REGISTER

FNDO.1:	MOVE	S2,T4			;GET THE INDEX
	IMULI	S2,3			;MULTIPLY BY OBJECT BLCK SIZE
	CAMN	T1,JOBOBJ+OBJ.TY(S2)	;COMPARE
	CAME	T2,JOBOBJ+OBJ.UN(S2)	;COMPARE
	JRST	FNDO.2			;NOPE
	CAMN	T3,JOBOBJ+OBJ.ND(S2)	;COMPARE
	JRST	FNDO.3			;WIN, SETUP THE CONTEXT
FNDO.2:	ADDI	T4,1			;INCREMENT
	CAIL	T4,MAXRDR		;THE END OF THE LINE?
	$STOP(ONF,Object not found)
	JRST	FNDO.1			;OK, LOOP

FNDO.3:	MOVEM	T4,STREAM		;SAVE STREAM NUMBER
	MOVE	RDR,JOBPAG(T4)		;GET ADDRESS OF DATA
	MOVE	FLAG,.RDREG+FLAG(RDR)	;GET HIS 'FLAGS'
	$RETT				;AND RETURN
	SUBTTL	UPDTST - ROUTINE TO SEND READER STATUS INFORMATION TO QUASAR

	;CALL:	PUSHJ P,UPDTST
	;
	;RETURN: ALWAYS TRUE +1

UPDTST:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVEI	S1,MSGBLK		;GET THE SOON TO BE MSG BLOCK ADDRESS
	MOVE	P1,STREAM		;GET THE STREAM NUMBER
	SETZM	JOBSTS(P1)		;ZAP THE STATUS UPDATE FLAG
	HRLZ	S2,JOBOBA(P1)		;GET THE STREAM'S OBJ BLOCK ADDRESS
	HRRI	S2,STU.RB(S1)		;GET THE DESTINATION ADDRESS
	BLT	S2,STU.RB+OBJ.SZ-1(S1)	;COPY THE OBJ BLK OVER
	SETZM	.MSCOD(S1)		;NO ACK CODE
	SETZM	.MSFLG(S1)		;NO FLAG BITS
	MOVE	S2,JOBSTW(P1)		;GET THE JOB STATUS BITS
	MOVX	P1,%READN		;DEFAULT TO 'READING'
	TXNE	S2,PSF%DO		;ARE WE OFFLINE ???
	MOVX	P1,%OFLNE		;YES,,THEN WE ARE REALLY OFFLINE
	TXNE	S2,PSF%ST		;ARE WE STOPPED BY THE OPERATOR
	MOVX	P1,%STOPD		;YES,,THEN SAY SO
	STORE	P1,STU.CD(S1)		;SAVE THE STATUS CODE
	MOVX	S2,.QOSTU		;GET THE MESSAGE TYPE
	STORE	S2,.MSTYP(S1),MS.TYP	;SAVE IT IN THE MSG
	MOVX	S2,STU.SZ		;GET THE MSG LENGTH
	STORE	S2,.MSTYP(S1),MS.CNT	;SAVE IT IN THE MSG
	PJRST	SNDQSR			;SEND IT OFF TO QUASAR
	SUBTTL SNDQSR - ROUTINE TO SEND A MESSAGE TO QUASAR.

	;CALL:	S1/ The message address
	;	S2/ The message length
	;
	;RET:	TRUE  if sent successfully
	;	Stopcode 'QSF' if the send fails
	;


OPRMSG:	TDZA	TF,TF			;FLAG SEND ORION ENTRY POINT
SNDQSR:	SETOM	TF			;FLAG SEND QUASAR ENTRY POINT
	MOVEM	S1,SAB+SAB.MS		;SAVE THE MESSAGE ADDRESS
	MOVEM	S2,SAB+SAB.LN		;SAVE THE MESSAGE LENGTH
	MOVX	S1,SP.QSR		;GET QUASAR FLAG
	SKIPN	TF			;UNLESS WE WANT TO THEN TO THE OPERATOR
	MOVX	S1,SP.OPR		;   THEN GET OPERATOR INDEX
	TXO	S1,SI.FLG		;SET SPECIAL INDEX FLAG
	STORE	S1,SAB+SAB.SI		;AND STORE IT
	SETZM	SAB+SAB.PD		;CLEAR THE PID WORD
	MOVEI	S1,SAB.SZ		;LOAD THE SIZE
	MOVEI	S2,SAB			;AND THE ADDRESS
	PUSHJ	P,C%SEND		;SEND THE MESSAGE
	JUMPT	.RETT			;AND RETURN

	$STOP(QSF,Send to QUASAR FAILED)
TOPS20 <
	SUBTTL	IDLE LOOP

MAIN:	SETZM	SCHEDL			;SLEEP AFTER THIS PASS
	PUSHJ	P,CHKQUE		;GO CHECK THE MESSAGE QUEUE
	PUSHJ	P,CHKFRK		;GO CHECK FOR FORK TERMINATION
	SKIPN	MESSAGE			;DID WE PROCESS A MESSAGE ???
	SKIPE	SCHEDL			;DO WE WANT ANOTHER SCHEDULING PASS ???
	JRST	MAIN			;YES,,GO CHECK AGAIN
	SETZM	S1			;SLEEP TILL WE'RE NEEDED
	PUSHJ	P,I%SLP			;NO,,GO TO SLEEEEEEEEEEEPPPPP
	JRST	MAIN			;GO CHECK TO MESSAGE QUEUE
	SUBTTL	CHKFRK - ROUTINE TO PROCESS INFERIOR FORK TERMINATION

CHKFRK:	SKIPN	TRMFRK			;DID ANY FORK GO AWAY ???
	JRST	CHKF.4			;NO,,GO CHECK FOR FORK INITIALIZATION
	SETOM	SCHEDL			;SCHEDULE ANOTHER PASS
	SETZM	TRMFRK			;ZERO FORK TERMINATION FLAG
	MOVSI	P1,-MAXRDR		;MAKE AN AOBJN AC

CHKF.1:	SKIPN	RDR,JOBPAG(P1)		;IS THIS STREAM ACTIVE ???
	JRST	CHKF.3			;NO,,TRY THE NEXT ONE
	SKIPE	.RDSHT(RDR)		;DID THIS READER SHUTDOWN ???
	JRST	CHKF.2			;YES,,SHUT IT DOWN
	MOVE	S1,.RDHND(RDR)		;GET THE PROCESS HANDLE
	RFSTS				;GET THE FORK STATUS
	 ERJMP	CHKF.2			;IGNORE ANY ERRORS
	TXZ	S1,RF%FRZ		;CLEAR THE FROZEN FORK BIT
	HLRZ	S1,S1			;MOVE LEFT TO RIGHT AND ZERO LEFT
	CAIE	S1,.RFHLT		;IS THIS FORK HALTED ???
	CAIN	S1,.RFFPT		;HERE TOO !
	SKIPA				;YES TO EITHER,,CONTINUE ON
	JRST	CHKF.3			;ELSE TRY NEXT FORK
	HRROI	S1,.RDSTP(RDR)		;POINT TO ERROR BUFFER
	HRLOI	S2,@.RDHND(RDR)		;ELSE GET FORK HANDLE,,-1
	SKIPE	.RDSTP(RDR)		;IS THERE ANY ERROR CODE ???
	HRR	S2,.RDSTP(RDR)		;YES,,GET FORK HANDLE,,ERROR CODE
	MOVE	T1,[-^D49,,0]		;GET -LENGTH,,0
	ERSTR				;CONVERT ERROR TO A STRING
	 ERJMP	.+2			;IGNORE THIS ERROR
	 ERJMP	.+1			;AND THIS ONE
	$WTO	(< ^B/@JOBOBA(P1)/ Terminated >,<Reason: ^T/.RDSTP(RDR)/>,,<$WTFLG(WT.SJI)>)
CHKF.2:	HRRZM	P1,STREAM		;SAVE THE STREAM NUMBER
	SKIPN	135			;UNLESS WE ARE DEBUGGING
	PUSHJ	P,SHUTIT		;SHUT DOWN THE FORK

CHKF.3:	AOBJN	P1,CHKF.1		;GO CHECK THE NEXT FORK

	;Here to Check to see if any fork is finished initialization.

CHKF.4:	SKIPN	FRKINI			;ANY FORK END ITS INITIALIZATION ???
	$RETT				;NO,,JUST RETURN
	SETOM	SCHEDL			;YES,,SCHEDULE ANOTHER PASS
	SETZM	FRKINI			;ZERO FORK TERMINATION FLAG
	MOVSI	P1,-MAXRDR		;MAKE AN AOBJN AC
CHKF.5:	SKIPE	RDR,JOBPAG(P1)		;IS THIS READER SETUP ???
	SKIPN	.RDINI(RDR)		;YES,,INITIALIZATION FLAG LIT ???
	JRST	CHKF.6			;NO,,TRY NEXT
	HRRZM	P1,STREAM		;SAVE OUR STREAM NUMBER
	SETZM	.RDINI(RDR)		;CLEAR THE INITIALIZATION FLAG
	MOVX	S1,%RSUOK		;GET RESPONSE TO SETUP CODE (OK)
	PUSHJ	P,RSETUP		;SEND THE RESPONSE TO SETUP MESSAGE
CHKF.6:	AOBJN	P1,CHKF.5		;GO CHECK THE NEXT RDR
	$RETT				;RETURN WHEN DONE
	SUBTTL	RDINIT - ROUTINE TO INITIALIZE READER CONSTANTS

RDINIT:	PUSHJ	P,I%HOST		;GET OUR HOST NAME
	MOVEM	S1,CNTSTA		;SAVE THE SIXBIT NODE NAME
	SKIPE	135			;ARE WE DEBUGGING
	SKIPN	116			;AND ARE SYMBOLS DEFINED ???
	JRST	RDIN.1			;NO TO EITHER,,SKIP THIS
	HLRO	S1,116			;GET AOBJN LENGTH
	MOVMS	S1			;GET ABSOLUTE VALUE
	HRRZ	S2,116			;GET SYMBOL TABLE START ADDRESS
	ADDI	S1,-1(S2)		;CALC SYMBOL TABLE LENGTH
	SKIPA				;SKIP OVER NORMAL CALC
RDIN.1:	HLRZ	S1,.JBSA##		;GET THE PROGRAM END ADDRESS
	ADDI	S1,777			;ROUND IT OFF
	ADR2PG	S1			;MAKE IT A PAGE NUMBER
	MOVEM	S1,RDRSIZ		;SAVE IT
	$RETT				;RETURN
	SUBTTL	INPGET - ROUTINE TO SETUP THE READER FORK

INPGET:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	MOVE	S1,JOBOBA(S1)		;GET THE OBJECT BLOCK ADDRESS
	SKIPN	.RDREM(RDR)		;IS THIS A LOCAL READER ???
	$TEXT	(<-1,,.RDRFD(RDR)>,<PCDR^O/OBJ.UN(S1)/:^0>) ;YES,,GEN DEV NAME
	SKIPGE	.RDREM(RDR)		;OR IS IT A REMOTE READER ???
	$TEXT	(<-1,,.RDRFD(RDR)>,<^W/OBJ.ND(S1)/::PCDR^O/OBJ.UN(S1)/:^0>)

	MOVX	S1,<CR%CAP+CR%ACS>	;SUPERIOR CAPS AND AC'S
	MOVEI	S2,.RDREG(RDR)		;AC LOAD BUFFER
	CFORK				;CREATE A SPOOLER
	 ERJMP	FRKERR			;ON ERROR,,GO PROCESS IT

	MOVEM	S1,.RDHND(RDR)		;SAVE THE INFERIOR HANDLE
	MOVSI	S1,.FHSLF		;GET MY HANDLE
	HRLZ	S2,.RDHND(RDR)		;GET THE SPOOLER HANDLE
	HRR	T1,RDRSIZ		;GET THE LENGTH IN PAGES
	HRLI	T1,(PM%RWX!PM%CNT)	;COUNT+READ+EXECUTE
	PMAP				;MAP THE PAGES
	 ERJMP	PMPERR			;ON ERROR,,GO PROCESS IT

	MOVE	S1,RDR			;GET THE DATA BASE ADDRESS
	ADR2PG	S1			;CONVERT IT TO A PAGE NUMBER
	MOVE	S2,S1			;SAVE IT IN S2
	HRLI	S1,.FHSLF		;GET MY HANDLE
	HRL	S2,.RDHND(RDR)		;GET THE SPOOLER HANDLE
	HRRI	T1,DBSIZE		;GET THE PAGE COUNT
	HRLI	T1,(PM%RWX!PM%CNT)	;R,W,E + COUNT
	PMAP				;MAP THE DATA BASE
	 ERJMP	PMPERR			;ON ERROR,,GO PROCESS IT

	MOVE	S1,.RDHND(RDR)		;GET THE SPOOLER HANDLE
	MOVEI	S2,DOJOB		;GET THE START ADDRESS
	SFORK				;START THE SPOOLER
	ERJMP	FRKERR			;ON ERROR,,PROCESS IT
	MOVX	S1,%RSUOK
	$RETT				;AND RETURN

FRKERR:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$WTO	(Cant create a Fork,,@JOBOBA(S1)) ;TELL THE OPERATOR
	MOVX	S1,%RSUDE		;GET THE ERROR CODE
	$RETT				;AND RETURN

PMPERR:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$WTO	(Cant PMAP Spooler Pages,,@JOBOBA(S1)) ;TELL THE OPERATOR
	MOVX	S1,%RSUDE		;GET THE ERROR CODE
	$RETT				;AND RETURN
	SUBTTL	OACPAU - ROUTINE TO STOP A READER

OACPAU:	MOVE	S1,.RDHND(RDR)		;GET THE SPOOLER HANDLE
	FFORK				;FREEZE THE FORK
	ERJMP	OACC.1			;IF AN ERROR,,PROCESS IT
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$ACK	(Stopped,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR
	MOVX	S2,PSF%ST		;GET 'STOPPED' BIT
	IORM	S2,JOBSTW(S1)		;SET IT
	PUSHJ	P,UPDTST		;SEND A STATUS MESSAGE
	$RETT				;AND RETURN

OACC.1:	MOVE	S1,STREAM		;GET THE STREAM	NUMBER
	$ACK	(Cannot Be Stopped,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR
	$RETT				;AND RETURN

	SUBTTL	OACCON - ROUTINE TO CONTINUE A READER

OACCON:	MOVE	S1,.RDHND(RDR)		;GET THE SPOOLER HANDLE
	RFORK				;RESTART THE SPOOLER
	ERJMP	OACC.2			;IF AN ERROR,,GO PROCESS
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$ACK	(Continued,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR
	MOVX	S2,PSF%ST		;GET THE 'STOPPED' BIT
	ANDCAM	S2,JOBSTW(S1)		;CLEAR IT
	MOVE	S1,.RDHND(RDR)		;GET THE FORKS HANDLE
	MOVX	S2,<1B1>		;WANT CHANNEL 1
	IIC				;TELL FORK TO SEND STATUS
	$RETT				;AND RETURN

OACC.2:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$ACK	(Cannot Be Continued,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR
	$RETT				;AND RETURN

	SUBTTL	OACCAN - ROUTINE TO CANCEL THE CURRENT JOB ON THE READER

OACCAN:	MOVE	S1,.RDHND(RDR)		;GET THE FORKS HANDLE
	MOVX	S2,<1B2>		;GET CHANNEL 2
	IIC				;TELL THE FORK TO CANCEL THE JOB
	$RETT				;AND RETURN

	SUBTTL	OACSHT - ROUTINE TO SHUTDOWN THE CARD READER

OACSHT:	MOVE	S1,.RDHND(RDR)		;GET THE FORKS HANDLE
	MOVX	S2,<1B3>		;GET CHANNEL 3
	IIC				;TELL THE FORK TO SHUTDOWN
	ERJMP	.RETT			;ON AN ERROR,,RETURN OK
	$RETF				;AND RETURN
	SUBTTL	INTERRUPT ROUTINES


LEVTAB:	EXP	LEV1PC			;INTRPT LEVEL 1 PC ADDRESS
	EXP	LEV2PC			;INTRPT LEVEL 2 PC ADDRESS
	EXP	LEV3PC			;INTRPT LEVEL 3 PC ADDRESS

CHNTAB:	XWD	1,INTIPC		;IPCF INTERRUPT ON CHANNEL 0
	XWD	1,INTFKI		;FORK INITIALIZATION END INTERRUPT
	BLOCK	^D34			;INFERIOR PROCESS TERM ON CHNL 19
					;ALL OTHER CHANNELS 0

LEV1PC:	BLOCK	1			;LEVEL 1 INTERRUPT PC
LEV2PC:	BLOCK	1			;LEVEL 2 INTERRUPT PC
LEV3PC:	BLOCK	1			;LEVEL 3 INTERRUPT PC


INTINI:	MOVE	S1,[1,,ENDFRK]		;SET UP INFERIOR FORK TERM PARMS
	MOVEM	S1,CHNTAB+.ICIFT	; IN THE CHANNEL TABLE
	MOVX	S1,.FHSLF		;GET MY HANDLE
	MOVX	S2,1B0+1B1+1B19		;GET CHNL 0 (IPCF)+CHNL 19 (FORK TERM)
	AIC				;ACTIVATE CHANNEL 0 AND 1 AND 19
	$RETT				;RETURN

INTIPC:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	PUSHJ	P,C%INTR		;FLAG THE IPCF INTERRUPT
	$DEBRK				;AND LEAVE INTERRUPT LEVEL

ENDFRK:	$BGINT	1,			;INTIALIZE INTERRUPT LEVEL
	SETOM	TRMFRK			;INDICATE WE DID THIS
	$DEBRK				;AND LEAVE INTERRUPT LEVEL

INTFKI:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	SETOM	FRKINI			;FLAG THE INTERRUPT
	$DEBRK				;AND LEAVE INTERRUPT LEVEL
	SUBTTL	INPREL - ROUTINE TO RELEASE A CARD  READER

INPREL:	MOVE	S1,.RDHND(RDR)		;GET THE SPOOLER HANDLE
	KFORK				;KILL THE FORK
	ERJMP	.+1			;IGNORE ANY ERRORS
	$RETT				;AND RETURN
	SUBTTL	SPOOLER - CARD READER SPOOLER FORK ROUTINE START ADDRESS


RDRIB:	$BUILD	IB.SZ				;
	  $SET	(IB.PRG,,%%.MOD)		;PROGRAM 'CDRIVE'
	  $SET  (IB.FLG,IP.STP,1)		;STOPCODES TO ORION
	  $SET	(IB.PIB,,RDRPIB)		;SET UP PIB ADDRESS
	  $SET(IB.INT,,<LEVTBL,,CHNTBL>)	;SETUP INTERRUPT VECTOR
	$EOB					;

RDRPIB:	$BUILD	PB.MNS				;
	  $SET	(PB.HDR,PB.LEN,PB.MNS)		;
	$EOB					;


DOJOB:	MOVEI	S1,IB.SZ		;GET THE IB SIZE
	MOVEI	S2,RDRIB		;GET THE IB ADDRESS
	PUSHJ	P,I%INIT		;GO MAP THE LIBRARY
	SKIPE	135			;ARE WE DEBUGGING ???
	PUSHJ	P,GETDDT		;YES,,GO LOAD DDT AND WAIT
	MOVEI	S1,.RDFD(RDR)		;GET THE FD ADDRESS
	MOVEM	S1,.RDFOB+FOB.FD(RDR)	;SAVE IT IN THE FOB
	MOVE	S1,.RDOBZ(RDR)		;GET THE OUTPUT BYTE SIZE
	STORE	S1,.RDFOB+FOB.CW(RDR),FB.BSZ ;SAVE IT IN THE FOB
	MOVEI	S1,1			;GET A BIT
	STORE	S1,.RDFOB+FOB.CW(RDR),FB.NFO ;WANT 'NEW FILE ONLY' !!
	MOVX	S1,.FHSLF		;GET MY HANDLE
	RPCAP				;GET MY CAPABILITIES
	 ERJMP	INTERR			;STOP ON AN ERROR
	MOVE	T1,S2			;WANT ALL AVAILABLE CAPABILITIES
	MOVX	S1,.FHSLF		;GET MY HANDLE
	EPCAP				;ENABLE ALL CAPABILITIES
	 ERJMP	INTERR			;STOP ON AN ERROR

	PUSHJ	P,OPENIT		;GO OPEN THE READER

	MOVE	S1,.RDSTR(RDR)		;GET THE STREAM NUMBER
	$WTO	(Started,,@JOBOBA(S1)) ;TELL THE OPERATOR

	;SETUP THE UPDATE STATUS MESSAGE (ONCE ONLY)

	MOVE	S1,[STU.SZ,,.QOSTU]	;GET STATUS MSG LENGTH,,TYPE
	MOVEM	S1,.RDMSG+.MSTYP(RDR)	;SAVE IT
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	HRLZ	S1,JOBOBA(S1)		;GET OUR OBJECT BLOCK ADDRESS
	HRRI	S1,.RDMSG+STU.RB(RDR)	;GET THE DESTINATION ADDRESS
	BLT	S1,.RDMSG+STU.RB+OBJ.SZ-1(RDR) ;COPY THE OBJ BLK OVER
	SETOM	.RDSTS(RDR)		;LETS TRY IT FIRST CHANCE WE GET
	MOVEI	S1,2			;GET A MAX ERROR COUNT OF 2
	MOVEM	S1,.RDECT(RDR)		;SAVE IT JUST IN CASE WE NEED IT

	JRST	MAINRT			;GO PROCESS
	SUBTTL	MAINRT - ROUTINE TO INPUT AND PROCESS CARDS

MAINRT:	MOVE	S1,.RDJFN(RDR)		;GET THE JFN
	HRLZ	S2,.RDIBZ(RDR)		;GET THE INPUT BYTE SIZE
	LSH	S2,6			;POSITION IT
	ADD	S2,[POINT 0,.CARDS(RDR)] ;CREATE THE BYTE POINTER
	MOVE	T1,[EXP -CRDNBR]	;GET THE NUMBER OF CARDS TO READ
	IMUL	T1,.RDRCL(RDR)		;MULTIPLY BY RECORD LENGTH
	PUSHJ	P,$SIN			;GET A BATCH OF CARDS
	JUMPT	MAIN.1			;WE WIN,,SO CONTINUE

	MOVE	P1,S2			;SAVE THE OUTPUT BYTE POINTER
	MOVE	P2,T1			;SAVE THE BYTE COUNT
	PUSHJ	P,$GTSTS		;GO SET THE READER STATUS
	PUSHJ	P,$GETER		;READ THE ERROR STATUS BITS
	MOVE	T1,P2			;RESTORE THE NUMBER OF BYTES READ
	CAXE	S1,OPNX8		;IS IT DEVICE OFFLINE ???
	CAXN	S1,IOX5			;   OR WAS IT AN I/O ERROR ???
	JRST	MAIN.1			;YES,,GO PROCESS IT
	CAXE	S1,IOX4			;WAS IT EOF ???
	PJRST	INTERR			;NO,,THEN A FATAL ERROR
	TXO	FLAG,EOF		;INDICATE AN EOF CONDITION OCCURED
	PUSHJ	P,RESDEV		;ON EOF,,GO CLOSE AND RE-OPEN THE RDR
	MOVE	S1,ENDIMG(AP)		;GET AN EOF BYTE
	IDPB	S1,P1			;MAKE AN EOF CARD
	MOVE	T1,P2			;GET THE NUMBER OF BYTES READ
	ADD	T1,.RDRCL(RDR)		;ADD 1 MORE CARD LENGTH

MAIN.1:	MOVE	S1,.RDRCL(RDR)		;GET THE RECORD LENGTH
	IMULI	S1,CRDNBR		;CALC # OF BYTES TO BE READ
	ADD	T1,S1			;CALC # OF BYTES READ
	IDIV	T1,.RDRCL(RDR)		;CALC # OF CARDS READ
	MOVEM	T1,.RDNBR(RDR)		;SAVE IT
	SKIPE	T1			;NO CARDS,,DONT PROCESS 
	PUSHJ	P,READER		;GO PROCESS THE CARDS
	SKIPG	.RDREM(RDR)		;IS THIS A DN60 READER ???
	PUSHJ	P,CHKOFL		;NO,,GO CHECK FOR OFFLINE'NESS

MAIN.2:	PUSHJ	P,CHKSTS		;GO CHECK OUR STATUS
	SETZM	S1			;SLEEP TILL WE'RE  NEEDED
	SKIPLE	.RDREM(RDR)		;IS THIS A DN60 CDR ???
	MOVEI	S1,5			;YES,,JUST SLEEP 5 SECONDS
	SKIPE	.RDOFL(RDR)		;IS THE READER OFFLINE ???
	PUSHJ	P,I%SLP			;YES,,JUST SLEEEEEEP
	JRST	MAINRT			;ELSE,,GO PROCESS SOME MORE CARDS
	SUBTTL	GENFIL - ROUTINE TO GENERATE A SPOOL FILENAME

GENFIL:	MOVEI	S1,.RDFD(RDR)		;GET THE FD ADDRESS
	MOVEI	S2,10			;GET THE FD LENGTH
	STORE	S2,.FDLEN(S1),FD.LEN	;SAVE IT IN THE FD
	AOS	S2,FILENM		;BUMP HASH COUNT BY 1,,PUT IN S2
	$TEXT	(<-1,,.FDSTG(S1)>,<^T/SPL/RD^D4L0/S2,FILEMK/-^D3R0/FILEXT/>)
	$RETT				;AND RETURN


RESDEV:	SKIPLE	.RDREM(RDR)		;IS THIS A DN60 CARD READER ???
	$RETT				;YES,,JUST RETURN
	MOVE	S1,.RDJFN(RDR)		;GET THE JFN
	TXO	S1,CZ%ABT		;ABORT ANY INPUT PROCESSING
	PUSHJ	P,$CLOSF		;CLOSE THE READER DOWN
	JUMPF	OPNERR			;NO,,STOP ON AN ERROR

	;FALL INTO READER OPEN CODE

OPENIT:	MOVX	S1,GJ%SHT+GJ%PHY	;SHORT JFN+PHYSICAL UNIT
	HRROI	S2,.RDRFD(RDR)		;GET THE DEVICE ADDRESS
	PUSHJ	P,$GTJFN		;GET A JFN
	JUMPF	OPNERR			;STOP ON AN ERROR
	MOVEM	S1,.RDJFN(RDR)		;SAVE THE JFN
	MOVX	S2,^D16B5+10B9+OF%RD+OF%HER+OF%OFL ;16 BIT BYTES+IMAGE MODE+
	PUSHJ	P,$OPENF		;OPEN THE READER
	JUMPF	OPNERR			;STOP ON AN ERROR
	PUSHJ	P,SETINT		;GO SETUP THE INTERRUPTS
	PUSHJ	P,$GTSTS		;GO GET THE READER STATUS
	MOVE	S1,.RDSTA(RDR)		;GET THE DEVICE STATUS BITS
	TXNE	S1,MO%FNX		;DOES THE DEVICE REALLY EXIST ???
	JRST	[MOVX	S1,DIAGX8	;NO,,GET 'DEVICE DOESN'T EXIST' CODE
		 MOVEM	S1,.RDSTP(RDR)	;SAVE IT IN OUR DATA BASE
		 HALTF  ]		;WE'RE DONE FOR !!!
	TXNE	FLAG,EOF		;HERE BECAUSE OF DEVICE EOF ???
	$RETT				;YES,,JUST RETURN
	SETOM	.RDINI(RDR)		;FLAG END OF INITIALIZATION
	MOVX	S1,.FHSUP		;WANT SUPERIOR PROCESS
	MOVX	S2,<1B1>		;GET CHANNEL
	IIC				;TELL SUPERIOR TO SEND RSP MSG TO QUASAR
	ERJMP	OPNERR			;CAN'T,,OH WELL !!!
	$RETT				;OK,,RETURN

SPL:	ASCIZ/PS:<SPOOL>/




	SUBTTL	CHKOFL - ROUTINE TO CHECK LOCAL/REMOTE OFFLINE STATUS

CHKOFL:	SKIPN	.RDOFL(RDR)		;ARE WE OFFLINE ???
	$RETT				;NO,,JUST RETURN
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	TXNE	FLAG,JOBCD		;DO WE HAVE A JOB CARD ???
	$WTO	(Offline,,@JOBOBA(S1))	;TELL THE OPERATOR ITS OFFLINE
	SKIPE	.RDREJ(RDR)		;ARE WE REJECTING CARDS ???
	$WTOJ	(< ^D/.RDREJ(RDR)/ Cards Flushed >,,@JOBOBA(S1)) ;YES,,TELL OPR
	SETZM	.RDREJ(RDR)		;ZERO THE REJECT COUNT
	$RETT				;AND RETURN
	SUBTTL	CHKSTS - ROUTINE TO PROCESS THE DIFFERENT STATUS INTERRUPTS

CHKSTS:	PUSHJ	P,GETHSP		;GO READ THE HASP CONSOLE (IF NEEDED)
	SKIPE	.RDSTS(RDR)		;DO WE WANT TO SEND A STATUS UPDATE ??
	PUSHJ	P,SNDSTS		;YES,,DO IT
	SKIPN	.RDCAN(RDR)		;DO WE WANT TO CANCEL THIS GUY ???
	JRST	CHKS.1			;NO,,CONTINUE ON
	SETZM	.RDCAN(RDR)		;CLEAR THE CANCEL FLAG
	TXZ	FLAG,JOBCD		;CLEAR THE JOBCARD FLAG
	MOVE	S1,.RDSTR(RDR)		;GET THE STREAM NUMBER
	$WTOJ	(Current Job Canceled,,@JOBOBA(S1)) ;TELL THE OPERATOR

CHKS.1:	SKIPE	.RDSHT(RDR)		;DO WE WANT TO SHUT DOWN
	SKIPN	.RDOFL(RDR)		;IF SO ARE WE OFFLINE ???
	$RETT				;NO TO EITHER,,RETURN
	TXNE	FLAG,JOBCD		;ARE WE PROCESSING A JOB ???
	$RETT				;YES,,RETURN
	HALTF				;NO,,KILL THE FORK



	SUBTTL	GETDDT - ROUTINE TO LOAD DDT IF WE ARE DEBUGGING

GETDDT:	MOVX	S1,GJ%OLD+GJ%SHT	;OLD FILE+SHORT JFN
	HRROI	S2,[ASCIZ/SYS:SDDT.EXE/] ;WANT DDT IN HERE TOO
	GTJFN				;GET DDT'S JFN
	 ERJMP	INTERR			;CANT,,TOO BAD !!
	HRLI	S1,.FHSLF		;GET MY HANDLE
	GET				;LOAD DDT
	 ERJMP	INTERR			;CANT LOAD IT,,TOO BAD !!
	MOVE	S1,116			;GET CONTENTS OF .JBSYM
	HRRZ	S2,770001		;GET ADDRESS OF WHERE TO PUT IT
	MOVEM	S1,0(S2)		;POINT DDT AT MY SYMBOL TABLE
	JRST	770000			;AND ENTER DDT
GO:	$RETT				;RETURN
	SUBTTL	SENDIT - ROUTINE TO SEND IPCF MESSAGES TO QUASAR

	;CALL:	S1/ THE MESSAGE ADDRESS
	;	S2/ THE MESSAGE LENGTH
	;
	;RET:	TRUE ALWAYS

SNDOPR:	TDZA	TF			;ZAP ENTRY FLAG WORD AND SKIP
SENDIT:	SETOM	TF			;SET ENTRY FLAG WORD AND CONTINUE
	MOVEM	S1,.RDSAB+SAB.MS(RDR)	;SAVE THE MESSAGE ADDRESS
	MOVEM	S2,.RDSAB+SAB.LN(RDR)	;SAVE THE MESSAGE LENGTH
	MOVX	S1,SP.QSR		;GET QUASAR'S SPECIAL INDEX
	SKIPN	TF			;CHECK ENTRY FLAG; IS IT OPR ENTRY POINT
	MOVX	S1,SP.OPR		;YES,,GET ORIONS SPECIAL INDEX
	TXO	S1,SI.FLG		;SET SPECIAL INDEX FLAG
	MOVEM	S1,.RDSAB+SAB.SI(RDR)	;SAVE THE RECIEVERS ID
	SETZM	.RDSAB+SAB.PD(RDR)	;CLEAR THE PID WORD
	MOVEI	S1,PIB			;GET SUPERIORS PIB ADDRESS
	MOVEM	S1,.RDSAB+SAB.PB(RDR)	;SAVE IT FOR 'IN BEHALF OF' SEND
	MOVEI	S1,SAB.SZ		;GET THE SAB LENGTH
	MOVEI	S2,.RDSAB(RDR)		;GET THE SAB ADDRESS
	PUSHJ	P,C%SEND		;SEND IT TO QUASAR
	JUMPT	.RETT			;RETURN IF OK
	PJRST	INTERR			;ELSE END IT ALL
	SUBTTL	SNDSTS - ROUTINE TO SEND READER STATUS UPDATES TO QUASAR

SNDSTS:	SETZM	.RDSTS(RDR)		;CLEAR SEND STATUS FLAG
	MOVX	S1,%OFLNE		;DEFAULT TO OFFLINE
	TXNN	FLAG,JOBCD		;IF NO JOB,,THEN
	MOVX	S1,%IDLE		;   DEFAULT TO IDLE
	SKIPN	.RDOFL(RDR)		;IF WE ARE READING
	MOVX	S1,%READN		;    SET IT
	STORE	S1,.RDMSG+STU.CD(RDR)	;SAVE THE READER STATUS
	MOVEI	S1,.RDMSG(RDR)		;GET THE MESSAGE ADDRESS
	MOVEI	S2,STU.SZ		;GET THE MESSAGE LENGTH
	PUSHJ	P,SENDIT		;SEND IT TO QUASAR
	$RETT				;AND RETURN
	SUBTTL	SETINT - ROUTINE TO SETUP PROCESS INTERRUPTS

	;INTERRUPT DATA BASE

LEVTBL:	EXP	LVL1PC			;INTRPT LEVEL 1 PC ADDRESS
	EXP	LVL2PC			;INTRPT LEVEL 2 PC ADDRESS
	EXP	LVL3PC			;INTRPT LEVEL 3 PC ADDRESS

CHNTBL:	XWD	1,CDRINT		;ONLINE/OFFLINE ON CHANNEL 0
	XWD	1,STSINT		;UPDATE STATUS INTRPTS ON CHANL 1
	XWD	1,CANINT		;CANCEL JOB INTRPTS ON CHANL 2
	XWD	1,SHTINT		;SHUTDOWN READER INTRPTS ON CHANL 3
	BLOCK	^D35			;ALL OTHER CHANNELS 0

LVL1PC:	BLOCK	1			;LEVEL 1 INTRPT PC
LVL2PC:	BLOCK	1			;LEVEL 2 INTRPT PC
LVL3PC:	BLOCK	1			;LEVEL 3 INTRPT PC


SETINT:	MOVX	S1,.FHSLF		;GET THE PROCESS HANDLE
	SETOM	S2			;DISABLE ALL 36 CHANNELS
	DIC				;LETERRIP
	 ERJMP	INTERR			;ON ERROR,,HALT
	CIS				;CLEAR THE INTERRUPT SYSTEM
	MOVX	S1,.FHSLF		;GET MY PROCESS HANDLE
	MOVE	S2,[LEVTBL,,CHNTBL]	;GET PRTY LEVEL,,CHANNEL
	SIR				;SETUP THE MONITOR INTRPT TABLE ADDRS
	 ERJMP	INTERR			;ON ERROR,,HALT
	MOVX	S1,.FHSLF		;GET MY PROCESS HANDLE
	EIR				;ENABLE THE INTERRUPT SYSTEM
	 ERJMP	INTERR			;ON ERROR,,HALT
	MOVE	S1,.RDJFN(RDR)		;GET THE JFN
	MOVX	S2,.MOPSI		;FUNCTION: ADD TO INTRPT SYSTEM
	MOVEI	T1,T2			;ARGUMENT BLOCK ADDRESS
	MOVEI	T2,3			;    ""     ""  LENGTH
	MOVEI	T3,0			;INTERRUPTS ON CHANNEL 0
	MOVX	T4,MO%MSG		;NO MESSAGE
	PUSHJ	P,$MTOPR		;ADD TO THE INTERRUPT SYSTEM
	JUMPF	INTERR			;ON AN ERROR,,STOP
	MOVX	S1,.FHSLF		;GET MY PROCESS HANDLE
	MOVX	S2,1B0+1B1+1B2+1B3	;INTERRUPT ON CHANNEL 0+1+2+3
	AIC				;ACTIVATE THE INTERRUPT SYSTEM
	 ERJMP	INTERR			;ON ERROR,,HALT
	$RETT				;RETURN

INTERR:
OPNERR:	MOVX	S1,.FHSLF		;GET MY HANDLE
	SETZM	S2			;CLEAR S2 (RESULT)
	GETER				;GET THE LAST ERROR CODE
	MOVEM	S2,.RDSTP(RDR)		;SAVE THE ERROR CODE
	HALTF				;END IT ALL
	SUBTTL	INTERRUPT ROUTINES

	;READER ONLINE/OFFLINE INTERRUPT ROUTINE

CDRINT:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	SETOM	.RDSTS(RDR)		;WANT A STATUS UPDATE MSG SENT
	MOVE	S1,.RDJFN(RDR)		;GET THE JFN
	MOVX	S2,.MORST		;READ DEVICE STATUS FUNCTION
	MOVEI	T1,T2			;ARGUMENT BLOCK ADDRESS
	MOVEI	T2,2			;ARGUMENT BLOCK LENGTH
	SETZ	T3,			;DEVICE STATUS
	PUSHJ	P,$MTOPR		;GET THE READER STATUS
	MOVEM	T3,.RDSTA(RDR)		;SAVE THE DEVICE STATUS BITS
	SETZM	.RDOFL(RDR)		;ASSUME WE ARE ON-LINE !!!
	TXNE	T3,MO%OL		;IS THE READER OFFLINE ???
	SETOM	.RDOFL(RDR)		;IF OFFLINE,,SAY SO.
	SKIPE	.RDREM(RDR)		;IF REMOTE,,
	JRST	CDRI.1			;   THEN SKIP THIS LOCAL STUFF
	MOVEI	S1,.RETT		;GET OFFLINE EXIT ADDRESS
	SKIPE	.RDIOA(RDR)		;WERE WE I/O ACTIVE ???
	MOVEM	S1,LVL1PC		;YES,,SAVE IT FOR DEBRK
CDRI.1:	SETZM	.RDIOA(RDR)		;CLEAR I/O ACTIVE
	$DEBRK				;DISMISS THE INTERRUPT.

	;UPDATE READER STATUS INTERRUPT ROUTINE

STSINT:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	SETOM	.RDSTS(RDR)		;SAY WE WANT A STATUS UPDATE MSG SENT
	$DEBRK				;LEAVE INTERRUPT LEVEL

	;JOB CANCEL INTERRUPT ROUTINE

CANINT:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	SETOM	.RDCAN(RDR)		;SAY WE WANT TO CANCEL THE CURRENT JOB
	$DEBRK				;LEAVE INTERRUPT LEVEL

	;CARD READER SHUTDOWN INTERRUPT ROUTINE

SHTINT:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	SETOM	.RDSHT(RDR)		;SAY WE WANT TO SHUT DOWN
	$DEBRK				;LEAVE INTERRUPT LEVEL
	SUBTTL	LOCAL/REMOTE I/O SUBROUTINES

$GTSTS:	SKIPLE	.RDREM(RDR)		;IS THIS A LOCAL OR DN200 CDR ???
	$RETT				;NO, SO DN60, SO RETURN
	MOVX	S1,.FHSLF		;YES,,GET MY HANDLE
	MOVX	S2,<1B0>		;WANT CHANNEL 0
	IIC				;FORCE INTERRUPT ON ONLINE/OFFLINE CHNL
	ERJMP	.+1			;IGNORE ANY ERROR
	$RETT				;AND RETURN

$GETER:	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	JRST	[SKIPG	.RDREM(RDR)	;YES,,IS THIS A DN200 READER ???
		 JRST	GETE.2		;YES,,MUST BE DN200
		 JRST	GETE.6 ]	;NO,,MUST BE DN60
	MOVX	S1,.FHSLF		;GET MY HANDLE
	GETER				;GET THE LAST ERROR CODE
	HRRZ	S1,S2			;PUT IT INTO S1
	$RETT				;AND RETURN

$SIN:	SETOM	.RDIOA(RDR)		;MARK I/O ACTIVE
	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	JRST	[SKIPG	.RDREM(RDR)	;YES,,IS IT THE DN200 READER ???
		 JRST	SIN.2		;YES,,GO PROCESS IT
		 JRST	SIN.6 ]		;NO,,MUST BE DN60 READER
	SKIPE	.RDOFL(RDR)		;IS THE READER OFFLINE ???
	JRST	SIN.T			;YES,,JUST RETURN
	SIN				;FINALLY READ THE DATA
	ERJMP	SIN.F			;RETURN FALSE ON AN ERROR
SIN.T:	SETZM	.RDIOA(RDR)		;CLEAR I/O ACTIVE
	$RETT				;AND RETURN
SIN.F:	SETZM	.RDIOA(RDR)		;CLEAR I/O ACTIVE
	$RETF				;AND RETURN

$OPENF:	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	JRST	[SKIPG	.RDREM(RDR)	;YES,,IS IT THE DN200 READER ???
		 JRST	OPEN.2		;YES,,GO PROCESS IT
		 JRST	OPEN.6 ]		;NO,,MUST BE DN60 READER
	OPENF				;OPEN THE CARD READER
	ERJMP	.RETF			;ON AN ERROR,,RETURN WITH ERROR
	$RETT				;ELSE JUST RETURN

$MTOPR:	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	JRST	[SKIPG	.RDREM(RDR)	;YES,,IS IT THE DN200 READER ???
		 JRST	MTOP.2		;YES,,GO PROCESS IT
		 JRST	.RETT ]		;NO,,MUST BE DN60 READER (NO MTOPR)
	MTOPR				;LOCAL,,ISSUE MTOPR NORMALLY
	ERJMP	.RETF			;ON AN ERROR,,RETURN NO GOOD
	$RETT				;RETURN OK

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

$GTJFN:	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	JRST	[SKIPG	.RDREM(RDR)	;YES,,IS IT THE DN200 READER ???
		 JRST	GTJF.2		;YES,,GO PROCESS IT
		 JRST	GTJF.6 ]	;NO,,MUST BE DN60 READER (NO MTOPR)
	GTJFN				;LOCAL,,ISSUE GTJFN NORMALLY
	ERJMP	.RETF			;NO GOOD,,SAY SO
	$RETT				;ELSE RETURN OK

$CLOSF:	SKIPE	.RDREM(RDR)		;IS THIS A REMOTE READER ???
	JRST	[SKIPG	.RDREM(RDR)	;YES,,IS IT THE DN200 READER ???
		 JRST	CLOS.2		;YES,,GO PROCESS IT
		 JRST	CLOS.6 ]	;NO,,MUST BE DN60 READER (NO MTOPR)
	CLOSF				;LOCAL,,ISSUE CLOSF NORMALLY
	ERJMP	.RETF			;NO GOOD,,SAY SO
	$RETT				;ELSE RETURN OK
	SUBTTL	DN200 I/O SUPPORT ROUTINES

IFN FTRJE,<
GETE.2:	MOVE	S1,.RDJFN(RDR)		;GET THE JFN
	MOVX	S2,.MORST		;GET READ DEVICE STATUS FUNCTION
	MOVEI	T1,T2			;GET ARG BLOCK ADDRESS
	MOVEI	T2,2			;GET BLOCK LENGTH
	SETZM	T3			;CLEAR ANSWER WORD
	PUSHJ	P,UMTOPR##		;ISSUE THE MTOPR
	ERJMP	INTERR			;NO GOOD,,FORGET IT
	TXNE	T3,MO%OL+MO%HEM+MO%SCK+MO%PCK+MO%RCK+MO%SER
	MOVX	S1,IOX5			;ANY OF THE ABOVE,,SET I/O ERROR
	TXNE	T3,MO%EOF		;HARDWARE EOF ???
	MOVX	S1,IOX4			;YES,,MAKE IT EOF
	$RETT

SIN.2:	SKIPE	.RDOFL(RDR)		;IS THE READER OFFLINE ???
	JRST	SIN.T			;YES,,JUST RETURN
	PUSHJ	P,USIN##		;READ CARDS THROUGH NURD
	ERJMP	SIN.F			;RETURN FALSE ON AN ERROR
	JRST	SIN.T			;ELSE RETURN TRUE

OPEN.2:	PUSHJ	P,UOPENF##		;OPEN THE CARD READER THROUGH NURD
	ERJMP	.RETF			;CANT,,THATS AN ERROR
	$RETT				;OK,,JUST RETURN

MTOP.2:	PUSHJ	P,UMTOPR##		;MAKE CALL VIA NURD
	ERJMP	.RETF			;NO GOOD,,SAY SO
	$RETT				;ELSE RETURN OK

GTJF.2:	PUSHJ	P,UGTJFN##		;GET A JFN VIA NURD
	ERJMP	.RETF			;NO GOOD,,SAY SO
	$RETT				;ELSE RETURN OK

CLOS.2:	PUSHJ	P,UCLOSF##		;CLOSE DOWN VIA NURD
	ERJMP	.RETF			;NO GOOD,,SAY SO
	$RETT				;ELSE RETURN OK
>
IFE FTRJE,<
GETE.2:
SIN.2:
OPEN.2:
MTOP.2:
GTJF.2:
CLOS.2:
	MOVX	S1,DIAGX8		;GET 'DEVICE DOES NOT EXIST'
	MOVEM	S1,.RDSTP(RDR)		;SAVE IT
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	$WTO	(DN200 Remote not Supported,,@JOBOBA(S1)) ;TELL OPERATOR
	HALTF				;END IT ALL
>
	SUBTTL	DN60 I/O SUPPORT ROUTINES

IFN FTDN60,<
SIN.6:	PUSHJ	P,D60SIN##		;TRY TO READ SOME CARDS
	JUMPT	SIN.6C			;OK,,RETURN
	CAIN	S1,D6NBR		;WAS THE ERROR 'NON-BLOCKING RETURN' ?
	JRST	SIN.6C			;YES,,RETURN
	CAIN	S1,D6DOL		;IS THE ERROR 'DEVICE OFFLINE' ???
	JRST	SIN.6A			;YES,,GO PROCESS IT
	CAIN	S1,D6EOF		;IS THE ERROR 'END OF FILE' ???
	JRST	SIN.6B			;YES,,GO PROCESS IT
	MOVE	S2,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	$WTO	( DN60 I/O Error ,,@JOBOBA(S2)) ;TELL THE OPR
	SOSG	.RDECT(RDR)		;COUNT DOWN THE HARD ERRORS
	JRST	[SETOM .RDSHT(RDR)	;TOO MANY ERRORS,,LITE SHUTDOWN FLAG
		 $WTO( Too Many Device Errors ,,@JOBOBA(S2)) ;TELL OPR
		 HALTF ]		;AND SHUT US DOWN
	SKIPA	S1,[EXP IOX5]		;SKIP AND LOAD I/O ERROR CODE
SIN.6A:	MOVX	S1,OPNX8		;LOAD 'DEVICE OFFLINE' ERROR CODE
	SKIPA				;SKIP OVER EOF
SIN.6B:	MOVX	S1,IOX4			;LOAD 'END OF FILE' ERROR CODE
	MOVEM	S1,.RDSTP(RDR)		;SAVE THE ERROR CODE FOR LATER
	SKIPE	.RDOFL(RDR)		;WERE WE OFFLINE BEFORE THIS CALL ???
	$RETF				;YES,,JUST TAKE THE ERROR RETURN
	SETOM	.RDSTS(RDR)		;NO,,THEN SEND A STATUS MESSAGE
	SETOM	.RDOFL(RDR)		;WE CERTAINLY ARE OFFLINE NOW !!
	PUSHJ	P,CHKOFL		;PROCESS THE OFFLINE MESSAGE
	$RETF				;TAKE THE ERROR RETURN

SIN.6C:	SKIPE	.RDOFL(RDR)		;WERE WE OFFLINE BEFORE THIS CALL ???
	SETOM	.RDSTS(RDR)		;YES,,THEN SEND A STATUS MESSAGE
	SETZM	.RDOFL(RDR)		;WE CERTAINLY ARE ONLINE NOW !!!
	$RETT				;TAKE THE TRUE RETURN

GETE.6:	MOVE	S1,.RDSTP(RDR)		;GET THE LAST ERROR CODE
	$RETT				;AND RETURN

GTJF.6:	PUSHJ	P,D60INI##		;INITIALIZE THE DN60 I/O PACKAGE
	SETZM	S1			;NO JFN FOR DN60
	$RETT				;RETURN OK

CLOS.6:	MOVE	S1,.RDJFN(RDR)		;GET JUST THE JFN
	PUSHJ	P,D60RLS##		;CLOSE DOWN VIA D60JSY
	$RETT				;AND RETURN
	;DN60 LINE CONDITIONING AND DEVICE OPENING ROUTINE

OPEN.6:	MOVEI	S1,.RDSUP(RDR)		;POINT TO OUR SETUP MESSAGE
	PUSHJ	P,D60CND##		;CONDITION THE FRONT END 
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	MOVE	S1,JOBOBA(S1)		;AND GET OUT OBJECT BLOCK ADDRESS
	JUMPT	OPN.6A			;THE LINE CONDITIONING WON,,SKIP THIS
	SETOM	.RDSHT(RDR)		;INDICATE WE WERE SHUT DOWN
	$WTO( Can't Condition Front End ,,0(S1)) ;TELL OPR
	HALTF				;AND END IT HERE !!!
OPN.6A:	MOVE	S1,OBJ.UN(S1)		;GET OUR UNIT NUMBER
	STORE	S1,.RDOPB(RDR),OP$UNT	;SAVE THE UNIT NUMBER IN OPEN BLOCK
	MOVX	S1,.OPCDR		;WANT 'CDR' DEVICE
	STORE	S1,.RDOPB(RDR),OP$TYP	;SAVE THE DEVICE TYPE IN THE OPEN BLOCK
	LOAD	S1,.RDSUP+SUP.CN(RDR),CN$PRT	;GET THE PORT NUMBER
	STORE	S1,.RDOPB(RDR),OP$PRT	;SAVE IT IN THE OPEN BLOCK
	LOAD	S1,.RDSUP+SUP.CN(RDR),CN$LIN	;GET THE LINE NUMBER
	STORE	S1,.RDOPB(RDR),OP$LIN	;SAVE IT IN THE OPEN BLOCK
	LOAD	S1,.RDSUP+SUP.CN(RDR),CN$SIG	;GET THE LINE SIGNATURE
	STORE	S1,.RDOPB(RDR),OP$SIG	;SAVE IT IN THE OPEN BLOCK

	MOVEI	T1,^D60			;GET A COUNT OF 60
OPN.6B:	HRROI	S1,-OP$SIZ		;GET THE NEGATIVE BLOCK LENGTH
	MOVEI	S2,.RDOPB(RDR)		;GET THE PARM BLOCK ADDRESS
	PUSHJ	P,D60OPN##		;OPEN THE READER
	JUMPT	OPN.6C			;THAT WINS,,CONTINUE ON

	CAXE	S1,D6DNU		;WAS THE ERROR 'DSR NOT UP' ???
	$RETF				;NO,,TRASH THE REQUEST !!!
	MOVEI	S1,5			;GET 5 SECONDS
	PUSHJ	P,I%SLP			;WAIT FOR DSR TO COME UP
	SKIPE	.RDSHT(RDR)		;HAVE WE BEEN SHUTDOWN ???
	HALTF				;YES,,STOP
	SOJGE	T1,OPN.6B		;KEEP TRYING FOR 5 MINUTES
	SETOM	.RDSHT(RDR)		;INDICATE WE WERE SHUT DOWN
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	$WTO	( Does Not Exist ,,@JOBOBA(S1)) ;TELL OPR
	HALTF				;END IT ALL
OPN.6C:	MOVEM	S1,.RDJFN(RDR)		;SAVE THE CDR HANDLE
	LOAD	S1,.RDFLG(RDR),NT.TYP	;GET THE REMOTE TYPE
	CAXE	S1,DF.HSP		;IS IT HASP ???
	$RETT				;NO,,JUST RETURN
	HRLZI	S1,.OPCIN		;YES,,GET OPR CONSOLE ID
	STORE	S1,.RDOPB(RDR),OP$DEV	;SAVE IT IN THE OPEN BLOCK
	HRROI	S1,-OP$SIZ		;GET THE NEGATIVE BLOCK LENGTH
	MOVEI	S2,.RDOPB(RDR)		;GET THE BLOCK ADDRESS
	PUSHJ	P,D60OPN##		;OPEN THE OPERATORS CONSOLE
	JUMPF	.RETF			;CANT,,THATS AN ERROR
	MOVEM	S1,.RDN60(RDR)		;SAVE THE OPR CONSOLE JFN
	$RETT				;AND RETURN
	;ROUTINE TO READ THE HASP OPERATORS CONSOLE

GETHSP:	LOAD	S1,.RDFLG(RDR),NT.TYP	;GET THE STATION TYPE
	SKIPLE	.RDREM(RDR)		;IS IT A DN60 TYPE REMOTE ???
	CAXE	S1,DF.HSP		;YES,,IS IT A HASP REMOTE ???
	$RETT				;NOT DN60/NOT HASP,,RETURN NOW
	MOVE	S1,.RDN60(RDR)		;GET THE HASP CONSOLE JFN
	MOVE	S2,[POINT 7,.CARDS(RDR)] ;GET THE INPUT BUFFER BYTE POINTER
	HRROI	T1,-^D140		 ;GET A LARGE BYTE COUNT
	PUSHJ	P,D60SIN##		 ;READ THE HASP OPERATORS CONSOLE
	SKIPF				 ;IF THE READ FAILED
	CAMN	S2,[POINT 7,.CARDS(RDR)] ;   OR NO DATA WAS READ
	$RETT				 ;       THEN JUST RETURN
	MOVE	S1,[POINT 7,.CARDS(RDR)] ;GET OUR INPUT BYTE POINTER BACK
	PUSHJ	P,OPRCMD		 ;GO PROCESS THE OPERATOR COMMAND
	$RETT				;AND RETURN
>

IFE FTDN60,<
GETE.6:
SIN.6:
OPEN.6:
GTJF.6:
CLOS.6:
GETHSP:
	MOVX	S1,DIAGX8		;GET 'DEVICE DOES NOT EXIST'
	MOVEM	S1,.RDSTP(RDR)		;SAVE IT
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	$WTO	(DN60 Type Remote not Supported,,@JOBOBA(S1)) ;TELL OPERATOR
	HALTF				;END IT ALL
>
>  ;END OF TOPS-20 CONDITIONAL CODE
	SUBTTL	READER - ROUTINE TO PROCESS THE INPUT CARDS.

READER:	SKIPN	.RDNBR(RDR)		;ARE THERE ANY CARDS THERE ???
	JRST	READ.4			;NO,,JUST RETURN
	PUSHJ	P,.SAVE1		;YES,,SAVE P1
	HRLZ	P1,.RDOBZ(RDR)		;GET THE CORRECT BYTE SIZE
	LSH	P1,6			;POSITION SIZE FOR BYTE POINTER
	ADD	P1,[POINT 0,.CARDS(RDR)] ;COMBINE THE BYTE PTR & BYTE SIZE
	MOVEM	P1,.RDIPT(RDR)		;SAVE IT THE FIRST TIME THROUTH
READ.2:	GETBYT	S1,P1			;GET A BYTE
	HRRI	S2,@P1			;GET THE CARD STARTING ADDRESS
	MOVEM	S2,.RDCAD(RDR)		;SAVE IT FOR LATER
	CAMN	S1,$IMAGE(AP)		;IS IT A $ SIGN ???
	JRST	$CARD			;YES,,GO PROCESS IT
	CAMN	S1,ENDIMG(AP)		;IS IT AN EOF CARD ???
	JRST	ENDCRD			;YES,,GO PROCESS IT.
	TXNN	FLAG,JOBCD		;IS THERE A JOB SETUP ???
	JRST	REJECT			;NO,,REJECT THE CARD.
	PUSHJ	P,OUTCRD		;ELSE PUT OUT THE CARD.
READ.3:	MOVE	P1,.RDRCL(RDR)		;GET THE RECORD LENGTH IN BYTES
	ADJBP	P1,.RDIPT(RDR)		;POINT TO THE NEXT CARD
	MOVEM	P1,.RDIPT(RDR)		;SAVE THE POINTER FOR LATER
	SOSLE	.RDNBR(RDR)		;SUB 1 FROM CARD COUNT
	JRST	READ.2			;MORE,,CONTINUE
READ.4:	SETZM	.RDNBR(RDR)		;ZERO THE NUMBER OF CARDS COUNTER
	HRLZ	S1,.RDOBZ(RDR)		;GET THE OUTPUT BYTE SIZE
	LSH	S1,6			;POSITION IT
	ADD	S1,[POINT 0,.CARDS(RDR)] ;MAKE IT A BYTE POINTER
	MOVEM	S1,.RDOPT(RDR)		;AND SAVE IT
	$RETT				;RETURN.
	SUBTTL	$CARD - ROUTINE TO PROCESS $ CARDS

$CARD:	GETBYT	S1,P1			;GET A BYTE
	CAME	S1,JIMGUC(AP)		;IS IT A 'J' ??
	CAMN	S1,JIMGLC(AP)		;IS IT 'j' ???
	JRST	JOBCRD			;YES TO EITHER,,PROCESS JOB CARD.
	CAME	S1,EIMGUC(AP)		;IS IT A 'E' ???
	CAMN	S1,EIMGLC(AP)		;IS IT A 'e' ???
	JRST	EOJCRD			;YES TO EITHER,,PROCESS EOJ CARD.
	CAMN	S1,$IMAGE(AP)		;IS IT A COMMAND ??? ($$??)
	JRST	COMMAND			;YES,,GO PROCESS IT.
	TXNN	FLAG,JOBCD		;IS THERE A JOB SETUP ???
	JRST	REJECT			;NO,,REJECT IT.
	PUSHJ	P,OUTCRD		;ELSE WRITE IT OUT
	JRST	READ.3			;AND CONTINUE

REJECT:	TXZN	FLAG,EOF		;REJECTING AN EOF GENERATED CARD ???
	AOS	.RDREJ(RDR)		;NO,,BUMP REJECT COUNT.
	JRST	READ.3			;AND GO PROCESS IT.
	SUBTTL	JOBCRD - ROUTINE TO PROCESS A JOB CARD.

JOBCRD:	GETBYT	S1,P1			;GET A BYTE.
	CAME	S1,OIMGUC(AP)		;IS IT A 'O' ???
	CAMN	S1,OIMGLC(AP)		;IS IT A 'o' ???
	SKIPA				;YES,,KEEP ON GOING
	JRST	REJECT			;ELSE REJECT IT.
	GETBYT	S1,P1			;GET THE NEXT BYTE.
	CAME	S1,BIMGUC(AP)		;IS IT A 'B' ???
	CAMN	S1,BIMGLC(AP)		;IS IT A 'b' ???
	SKIPA				;YES,,KEEP ON GOING
	JRST	REJECT			;ELSE REJECT IT.
	GETBYT	S1,P1			;GET THE NEXT BYTE.
	CAME	S1,BLANK(AP)		;IS IT A BLANK ???
	JRST	REJECT			;NO,,REJECT IT
	AOS	.RDJBC(RDR)		;BUMP JOB COUNT BY 1.
	TXNE	FLAG,JOBCD		;IS THE JOBCARD BIT ON ???
	PUSHJ	P,CREATE		;GO SEND CREATE MSG FOR THE LAST JOB.
	TXO	FLAG,JOBCD		;TURN ON THE JOB CARD BIT.
	MOVEI	S1,2			;GET AN ERROR COUNT OF 2
	MOVEM	S1,.RDECT(RDR)		;SAVE IT FOR LATER
	PUSHJ	P,I%NOW			;GET THE TIME.
	MOVEM	S1,.RDTIM(RDR)		;SAVE AS JOB START TIME
	MOVE	S1,.RDSTR(RDR)		;GET THE STREAM NUMBER
	SKIPE	S2,.RDREJ(RDR)		;ANY REJECTED CARDS ???
	$WTO	(< ^D/S2/ Cards Flushed >,,@JOBOBA(S1)) ;YES,,TELL OPERATOR
	SETZM	.RDREJ(RDR)		;ZERO THE REJECT COUNT
	PUSHJ	P,GETFIL		;GO SETUP THE OUTPUT SPOOL FILE
	PUSHJ	P,OUTCRD		;PUT IT OUT
	JRST	READ.3			;AND GO PROCESS THE NEXT CARD.
	SUBTTL	EOJCRD - ROUTINE TO PROCESS $EOJ CARDS.

EOJCRD:	TXNN	FLAG,JOBCD		;IS THERE A JOB SETUP ???
	JRST	REJECT			;NO,,REJECT THIS CARD.
	GETBYT	S1,P1			;GET THE NEXT BYTE
	CAME	S1,OIMGUC(AP)		;IS IT A 'O' ???
	CAMN	S1,OIMGLC(AP)		;IS IT A 'o' ???
	SKIPA				;YES,,KEEP ON GOING
	JRST	REJECT			;ELSE REJECT IT.
	GETBYT	S1,P1			;GET THE NEXT BYTE.
	CAME	S1,JIMGUC(AP)		;IS IT A 'J' ???
	CAMN	S1,JIMGLC(AP)		;IS IT A 'j' ???
	SKIPA				;YES,,KEEP ON GOING
	JRST	EODCRD			;ELSE CHECK FOR 'EOD'.
	GETBYT	S1,P1			;GET THE NEXT BYTE
	CAME	S1,BLANK(AP)		;IS IT A BLANK ???
	JRST	REJECT			;NO,,REJECT IT
	AOS	.RDEOJ(RDR)		;BUMP END OF JOB COUNT BY 1
	PUSHJ	P,OUTCRD		;PUT IT OUT
	PUSHJ	P,CREATE		;SEND THE CREATE MSG OFF
	JRST	READ.3			;AND CONTINUE PROCESSING

EODCRD:	PUSHJ	P,OUTCRD		;PUT IT OUT...
	JRST	READ.3			;GO PROCESS THE NEXT CARD
	SUBTTL	ENDCRD - ROUTINE TO PROCESS END-OF-FILE CARDS

ENDCRD:	AOS	.RDEND(RDR)		;BUMP END CARD COUNT BY 1
	TXNN	FLAG,JOBCD		;IS THERE A JOB SETUP ???
	JRST	REJECT			;NO,,REJECT THIS CARD
	PUSHJ	P,CREATE		;GO SEND A CREATE MSG
	JRST	READ.3			;AND GO GET THE NEXT CARD






	SUBTTL	COMMAND - ROUTINE TO PROCESS THE $$ COMMAND FOR OPR

COMMAND: TXNE	FLAG,JOBCD		;ARE WE IN A JOB ???
	JRST	COMM.1			;YES,,THEN JUST OUTPUT THE CARD
	SKIPG	.RDREM(RDR)		;IS THIS A DN60 REMOTE STATION ???
	JRST	REJECT			;NO,,REJECT THE CARD
	MOVE	S1,P1			;GET THE CARD BYTE POINTER
	PUSHJ	P,OPRCMD		;GO PROCESS THE CARD
	JRST	READ.3			;AND CONTINUE ON

COMM.1:	PUSHJ	P,OUTCRD		;OUTPUT THE CARD
	JRST	READ.3			;AND CONTINUE ON
	SUBTTL	OPRCMD - ROUTINE TO GENERATE AN OPR COMMAND MESSAGE

	;CALL:	S1/ Byte Pointer to the Operator message terminated by a CRLF
	;
	;RET:	True Always

OPRCMD:	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE INPUT BYTE POINTER ALSO
	PUSHJ	P,M%GPAG		;GET A PAGE FOR THE MESSAGE
	PUSH	P,S1			;SAVE THE PAGE ADDRESS
	MOVE	P2,S1			;HERE ALSO
	MOVX	S1,.OMD60		;GET THE MESSAGE TYPE
	STORE	S1,.MSTYP(P2),MS.TYP	;SAVE IT IN THE MESSAGE
	MOVEI	S1,3			;GET THE BLOCK COUNT
	MOVEM	S1,.OARGC(P2)		;SAVE IT IN THE MESSAGE
	MOVEI	P2,.OHDRS(P2)		;GET THE FIRST BLOCK ADDRESS
	MOVE	S1,[2,,.ORNOD]		;GET THE FIRST BLOCK HEADER
	MOVEM	S1,ARG.HD(P2)		;SAVE IT IN THE MESSAGE
	MOVE	S1,.RDSTR(RDR)		;GET OUR STREAM NUMBER
	MOVE	S1,JOBOBA(S1)		;GET OUR OBJECT BLOCK ADDRESS
	MOVE	S1,OBJ.ND(S1)		;GET OUR NODE NAME IN SIXBIT
	MOVEM	S1,ARG.DA(P2)		;SAVE IT IN THE MESSAGE
	ADDI	P2,2			;POINT TO THE NEXT BLOCK
	MOVE	S1,[3,,.ORD60]		;GET THE NEXT BLOCK HEADER
	MOVEM	S1,ARG.HD(P2)		;SAVE IT IN THE MESSAGE
	LOAD	S1,.RDSUP+SUP.CN(RDR),CN$PRT	;GET THE PORT NUMBER
	HRLM	S1,ARG.DA(P2)		;SAVE IT IN THE MSG DATA BLOCK
	LOAD	S1,.RDSUP+SUP.CN(RDR),CN$LIN	;GET THE LINE NUMBER
	HRRM	S1,ARG.DA(P2)		;SAVE IT IN THE MSG DATA BLOCK
	LOAD	S1,.RDFLG(RDR)		;GET THE FLAG BITS
	MOVEM	S1,ARG.DA+1(RDR)	;SAVE IT IN THE MSG DATA BLOCK
	ADDI	P2,3			;POINT TO THE NEXT BLOCK
	MOVX	S1,.CMTXT		;GET THE BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE IT IN THE MESSAGE
	MOVE	S1,[POINT 7,ARG.DA(P2)]	;GET THE OUTPUT BYTE POINTER
OPRC.1:	ILDB	S2,P1			;GET A TEXT BYTE
	IDPB	S2,S1			;SAVE IT IN THE MESSAGE
	CAIE	S2,12			;IS IT THE LINE FEED ???
	JRST	OPRC.1			;NO,,KEEP GOING TILL WE FIND ONE
	MOVEI	S1,@S1			;GET THE ENDING ADDRESS
	POP	P,S2			;RESTORE OUR STARTING ADDRESS
	SUBI	S1,-1(S2)		;CALC THE TOTAL MESSAGE LENGTH
	STORE	S1,.MSTYP(S2),MS.CNT	;SAVE THE MESSAGE LENGTH
	SUBI	S1,^D10			;CALC THE LENGTH OF THE TEXT BLOCK
	STORE	S1,ARG.HD+^D10(S2),AR.LEN ;SAVE IT IN THE MESSAGE
	LOAD	S1,.MSTYP(S2),MS.CNT	;GET THE MESSAGE LENGTH IN S1
	EXCH	S1,S2			;GET ADDRESS IN S1 AND LENGTH IN S2
	PUSHJ	P,SNDOPR		;SEND THE MESSAGE OFF
	$RETT				;AND RETURN
	SUBTTL	GETFIL - ROUTINE TO CREATE AN OUTPUT SPOOL FILE

GETFIL:	PUSHJ	P,GENFIL		;GO GENERATE THE SPOOL FILENAME
	MOVEI	S1,2			;GET FOB SIZE
	MOVEI	S2,.RDFOB(RDR)		;GET FOB ADDRESS
	PUSHJ	P,F%OOPN		;OPEN THE SPOOL FILE
	JUMPT	GETF.1			;IF OK,,CONTINUE ON
	CAIE	S1,ERFAE$		;IS THE ERROR 'FILE-ALREADY-EXISTS' ?
	$STOP(COS,CANNOT OPEN SPOOL FILE) ;NO,,THEN ITS A FATAL ERROR
	MOVE	S1,FILENM		;GET THE FILE NAME HASH CODE
	ANDI	S1,FILEMK		;GET THE GOOD PART
	CAIG	S1,17500		;IS IT LESS THEN 8000 (DECIMAL) ??
	JRST	GETFIL			;YES,,TRY THE NEXT FILE NAME
	SETZM	FILENM			;CREATE A NEW HASH CODE
	AOS	FILEXT			;AND A NEW EXTENSION
	JRST	GETF.1			;AND TRY AGAIN
GETF.1:	MOVEM	S1,.RDIFN(RDR)		;SAVE THE IFN
	$RETT				;AND RETURN
	SUBTTL	OUTCRD - ROUTINE TO OUTPUT A CARD.

OUTCRD:	AOS	.RDJBT(RDR)		;BUMP JOB CARD COUNT BY 1
	SKIPLE	.RDREM(RDR)		;IS IT LOCAL OR DN200 ???
	JRST	OUTD60			;NO,,MUST BE DN60 !!!
	MOVE	S1,.RDIFN(RDR)		;GET THE SPOOL FILE IFN
	HRL	S2,.RDRCL(RDR)		;GET THE RECORD LENGTH
	HRR	S2,.RDCAD(RDR)		;GET THE CARD ADDRESS.
	PUSHJ	P,F%OBUF		;WRITE OUT THE CARD
	JUMPT	.RETT			;IF OK,,RETURN
	$STOP(EWS,ERROR WRITING SPOOL FILE)

OUTD60:	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A MINUTE
	MOVE	P1,.RDIPT(RDR)		;GET THE RECORD POINTER
	MOVE	P2,.RDRCL(RDR)		;GET THE RECORD LENGTH IN BYTES
OUTD.1:	MOVE	S1,.RDIFN(RDR)		;GET THE SPOOL FILE IFN
	ILDB	S2,P1			;GET A BYTE
	PUSHJ	P,F%OBYT		;PUT IT OUT
	JUMPF	S..EWS			;CANT,,FORGET IT !!!
	SOJG	P2,OUTD.1		;CONTINUE TILL DONE
	$RETT				;AND RETURN
	SUBTTL	CREATE - ROUTINE TO GENERATE A CREATE MESSAGE FOR QUASAR

CREATE:	MOVE	S1,.RDIFN(RDR)		;GET THE FILE IFN
	PUSHJ	P,F%REL			;RELEASE THE IFN AND CLOSE THE FILE.
	SKIPT				;IF OK,,CONTINUE
	$STOP(CCS,CANNOT CLOSE SPOOL FILE) ;ELSE COMMIT SUICIDE

	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	PUSHJ	P,M%ACQP		;ACQUIRE PAGE FOR MESSAGE TO QUASAR
	PG2ADR	S1			;CONVERT PAGE NUMBER TO ADDRESS
	MOVEM	S1,P1			;SAVE IN MES (AC FOR EQ ENTRY)

	MOVEI	S1,<EQHSIZ+FPMSIZ+FDSIZE> ;SIZE OF FULL MESSAGE
	STORE	S1,.MSTYP(P1),MS.CNT	;SAVE IN HEADER FOR SIZE
	MOVEI	S1,.QOCRE		;CREATE INDICATOR TYPE
	STORE	S1,.MSTYP(P1),MS.TYP	;PLACE TYPE IN HEADER
	MOVEI	S1,%%.QSR		;QUASAR VERSION NUMBER
	STORE	S1,.EQLEN(P1),EQ.VRS	;SAVE VERSION NUMBER IN EQ
	MOVEI	S1,EQHSIZ		;EQ HEADER SIZE
	STORE	S1,.EQLEN(P1),EQ.LOH	;LENGTH OF HEADER FIELD
	MOVX	S1,<.OTBIN>		;BATCH INPUT QUEUE (SPRINT)
	STORE	S1,.EQROB+.ROBTY(P1)	;SAVE IN OBJECT TYPE
	MOVE	S1,CNTSTA		;GET THIS NODES ID
	MOVEM	S1,.EQROB+.ROBND(P1)	;SAVE NODE IN MESSAGE
CREA.1:	MOVEI	S1,1			;NUMBER OF FILES IN REQUEST
	STORE	S1,.EQSPC(P1),EQ.NUM	;STORE IN EQ
	
	MOVEI	S1,FPMSIZ		;SIZE OF THE FP
	STORE	S1,<EQHSIZ+.FPLEN>(P1),FP.LEN ;FP HEADER SIZE

	MOVSI	S1,.RDFD(RDR)		;BEGIN OF FD (OLD FD)
	HRRI	S1,<EQHSIZ+FPMSIZ>(P1)	;DESTINATION ADDRESS
	BLT	S1,<EQHSIZ+FPMSIZ+FDSIZE-1>(P1) ;MOVE THE FD
	MOVEI	S2,EQHSIZ(P1)		;GET THE FP ADDRESS IN S2
	MOVEI	S1,.RDRCL(RDR)		;GET CARD SIZE OF DATA
	STORE	S1,.FPINF(S2),FP.RCL	;SAVE THE RECORD LENGTH
	MOVEI	S1,.FPFAI		;GET THE AUGMENTED IMAGE MODE BITS
	SKIPLE	.RDREM(RDR)		;UNLESS THIS IS A DN60 READER
	MOVEI	S1,.FPFSA		;   THEN MAKE IT ASCII MODE
	STORE	S1,.FPINF(S2),FP.RCF	;SAVE THE RECORD FORMAT
	MOVE	S1,.RDJBT(RDR)		;CARD COUNT FOR JOB
	STORE	S1,.FPRCD(S2)		;SAVE THE NUMBER OF RECORDS
	MOVEI	S1,1			;GET A ONE..... 
	STORE	S1,.FPINF(S2),FP.SPL	;LITE THE SPOOLED FILE BIT
	STORE	S1,.FPINF(S2),FP.PCR	;SET PHYSICAL CARD READER BIT
	STOLIM	S1,.EQLIM(P1),CJOB	;ALSO 1 JOB PER FILE (FOR NOW)
	MOVE	S1,.RDTIM(RDR)		;GET START TIME OF JOB
	STOLIM	S1,.EQLIM(P1),CTIM	;SAVE START TIME OF JOB
	MOVE	S1,.RDSTR(RDR)		;GET THE STREAM NUMBER
	MOVE	S2,JOBOBA(S1)		;GET OUR OBJECT BLOCK ADDRESS
	MOVE	S2,OBJ.ND(S2)		;GET OUR NODE NAME
	STOLIM	S2,.EQLIM(P1),CNOD	;SAVE AS THE DESTINATION NODE

	$WTO	(< 1 Job: ^D/.RDJBT(RDR)/ Cards Spooled >,,@JOBOBA(S1))
	AOS	.RDIPC(RDR)		;COUNT OF MESSAGES SENT
	TXZ	FLAG,JOBCD		;TURN OFF THE JOB CARD BIT
	SETZM	.RDJBT(RDR)		;ZERO THE JOB CARD COUNT
	MOVE	S1,P1			;PUT THE MSG ADDRESS INTO S1.
	MOVEI	S2,1000			;PUT THE LENGTH IN S2.
	PJRST	SENDIT			;GO SEND IT OFF AND RETURN
	END	CDRIVE