Google
 

Trailing-Edge - PDP-10 Archives - BB-F493Z-DD_1986 - 10,7/703mon/netdev.mac
Click 10,7/703mon/netdev.mac to see without markup as text/plain
There are 8 other files named netdev.mac in the archive. Click here to see a list.
TITLE	NETDEV - NETWORK DEVICE SERVICE ROUTINES - V176	
SUBTTL	NETDEV -- WEM/	14 JAN 86
	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1978,1986>
;COPYRIGHT (C) 1978,1979,1980,1982,1984,1986
; BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.


XP VNETDV,176		;PUT VERSION NUMBER IN GLOB AND LOADER MAP
	XLIST
	$LIT
	LIST

	PRGEND
TITLE	NETCDR - NETWORK CARD READER ROUTINES - V001
SUBTTL	NETCDR -- WEM/	4-JUN-78
	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VNETCD,001		;PUT VERSION NUMBER IN GLOB AND LOADER MAP
	ENTRY	NETCDR
NETCDR::
SUBTTL 1.0      CDR SPECIFIC SYMBOL DEFINITIONS

;SPECIAL CHARACTERS

	C%EOF==7417		;END OF FILE CHARACTER
	C%026==4242		;CHANGE MODE TO 026 CHARACTER
	C%029==5252		;CHANGE MODE TO 029 CHARACTER


;BITS IN LH OF DEVIOS(F)

	IOS029==IOSFFB		;IF SET THEN DO TRANSLATION IN 029 MODE


;BIT INDICATING SUPER-IMAGE-MODE INPUT

	IO.SIM==1B29		;BIT THAT SAYS SUPER-IMAGE-INPUT
SUBTTL 2.0      INTERFACE TO UUOCON (DEVSER DISPATCH VECTOR)

	JRST	NTDONL##	;(-5) CHECK IF DEVICE IS ON LINE
	JRST	CPOPJ##		;(-4) SPECIAL ERROR STATUS
	JRST	C.BFSZ		;(-3) BUFFER SIZE
	JRST	CPOPJ##		;(-2) INITIALIZATION
	JRST	CPOPJ1##	;(-1) HUNG DEVICE
NDEVCD::JRST	NTDREL##	;RELEASE
	JRST	CPOPJ##		;CLOSE OUTPUT
 	JRST	NTDILO##	;ILLEGAL OUTPUT (RETURN INTERLOCK)
	JRST	C.IN		;INPUT
SUBTTL 2.1        INPUT UUO PROCESSING

C.IN:				;HERE FROM UUOCON ON IN UUO
	PUSHJ	P,SAVE4##	;WE CLOBBER ALL THE P'S
	MOVSI	S,IOSUSI	;CLEAR THE "UUOCON STOPED INPUT" BIT SINCE
	ANDCAB	S,DEVIOS(F)	;  IT HAS JUST TRIED TO START IT AGAIN.

C.LOOP:	PUSHJ	P,NTDSET##	;SET UP W, S ETC.
	MOVE	S,DEVIOS(F)	;FAMOUS STYLE OF LOOP DRIVEN CODE.
	TLNN	S,IOSCON	;STILL THERE?
	PJRST	NTDGON##	;NODE WENT AWAY
	TLNE	S,IOBEG		;IS THIS THE FIRST TIME THROUGH?
	JRST	C.FRST		; IF IT IS, DO SOME SPECIAL CHECKING
	MOVSI	S,IO		;WE ARE AN INPUT DEVICE
	ANDCAB	S,DEVIOS(F)	;MAKE SURE THAT UUOCON NOTICES
	PUSHJ	P,NTDIBA##	;CHECK TO MAKE SURE THAT NTDSIB WON'T FAIL
	  POPJ	P,		;IF NO INPUT BUFFER, RETURN TO UUOCON
	HRRZ	T1,DEVPCB(F)	;IS THERE ANY INPUT TO PROCESS??
	JUMPE	T1,C.WAIT	;IF NO DATA, GO WAIT FOR SOME
	PUSHJ	P,NTDDID##	;PROCESS THE NEXT NCL SUB-MESSAGE
	JRST	C.LOOP		;MAKE SURE EVERYTHING'S STILL OK.



C.WAIT:	PUSHJ	P,NTDONL##	;SEE IF THERE'S ANY BAD REASON FOR NO DATA
	  JRST	C.HUNG		; IF ERROR BIT IS SET. GO FIND OUT WHY.
	PUSHJ	P,NTDXDQ##	;SEE IF WE ARE BEHIND ON OUR DRQ'S
	PUSHJ	P,C.CLRS	;MAKE SURE THE CDR IS RUNNING
	PUSHJ	P,NTDWTI##	;WAIT FOR INPUT (EW STATE)
	  POPJ	P,		;IF NONBLOCKING, RETURN TO UUOCON NOW.
	JRST	C.LOOP		;SOMETHING WOKE US UP.  GO SEE WHAT
SUBTTL 2.2        INPUT UUO EXCEPTION PROCESSING

C.FRST:				;HERE ON THE FIRST IN
	MOVSI	S,IO!IOBEG!IOSREL ;CLEAR THESE BITS
	ANDCAB	S,DEVIOS(F)	;SINCE WE ARE APPARENTLY RUNNING NOW
	MOVSI	S,IOS029	;INITIALIZE THE TRANSLATION MODE
	IORB	S,DEVIOS(F)	;MODEL 029.
	SETZM	DEVAXI(F)	;CLEAR ANY PARTIAL BUFFER THAT MAY BE LEFT
	PUSHJ	P,C.CLRS	;CLEAR THE "STOP" BITS
	JRST	C.LOOP


C.HUNG:				;HERE FROM C.LOOP WHEN IOSERR IS SET.
	TLNN	S,IOSCON	;ARE WE STILL CONNECTED
	PJRST	NTDGON##	; NO. TELL USER THE DEVICE IS GONE
	PUSHJ	P,C.CLRS	;CLEAR THE STOP BITS
	TLNE	S,IOSERR	;IS THE CDR ONLINE YET??
	PUSHJ	P,NTDHNG##	;SET OFF-LINE AND TELL THE OPERATOR
	JRST	C.LOOP		;BACK TO LOOP TO TRY AGAIN.



C.CLRS:				;HERE TO CLEAR THE "EOF" AND "STOP" BITS
	MOVEI	T1,SCD.SR!SCD.HZ!SCD.CZ ;"STOP READ", "HARD EOF", "EOF CARD"
	PUSHJ	P,NTDCST##	;SEND THE "CLEAR BITS" MESSAGE
	  JRST	C.CLR1		;COULDN'T SEND MSG. SLEEP AND TRY AGAIN LATER.
	POPJ	P,		;ALL DONE.  RETURN

C.CLR1:	PUSHJ	P,NETSLP##	;SLEEP FOR 2 SECONDS
	PUSHJ	P,NTDSET##	;SET UP "W" AND "S" AGAIN
	TLNE	S,IOSCON	;MAKE SURE NODE DIDN'T GO AWAY
	JRST	C.CLRS		;IF STILL THERE, TRY SENDING STATUS AGAIN
	POPJ	P,		;IF NODE GONE, JUST PRETEND MSG WENT OUT.


;ROUTINE TO RETURN BUFFER SIZE
C.BFSZ:	MOVEI	T1,^D81		;ASSUME THAT WE ARE IN SUPER IMAGE MODE
	TRNE	M,IO.SIM	;IF WE ARE IN SUPER IMAGE MODE
	POPJ	P,		; THEN THE BUFFER SIZE IS 80. WORDS
	JRST	REGSIZ##	;IF NOT IN SUPERIMAGE MODE, LOOK IN THE DDB
SUBTTL 3.0      INTERFACE TO NETSER (NETWORK DISPATCH VECTOR)

	IFIW	NTDNWD##	;USE DEFAULT "NODE WENT DOWN" HANDLER
	IFIW	NTDDSC##	;USE DEFAULT DISCONNECT HANDLER
	IFIW	NTDCNC##	;USE STANDARD CONNECT CONFIRM CODE
	IFIW	NTDSTP##	;++ SHOULD NEVER GET HERE
	IFIW	CPOPJ##		;WE SHOULDN'T GET DATA REQUESTS
CDRNDP::IFIW	NTDQIP##	;QUEUE INCOMING MESSAGE TO UUO LEVEL
	IFIW	C.DATA		;DATA
	IFIW	C.DATA		;DATA WITH E-O-R
	IFIW	C.STAT		;STATUS
	IFIW	CPOPJ##		;WE DONT GET CONTROL
	IFIW	CPOPJ##		;OR UID
	IFIW	CPOPJ##		;OR FILE-SPEC'S



;DUMMY CONNECT INIT PROCESSOR

NCDRCI==:NJNKCI##		;A JUNK CI
SUBTTL 3.1        INPUT DATA MESSAGE PROCESSING

;REGISTER USAGE IS AS FOLLOWS.
;  P1	SET UP AT ENTRY BY NTDISP.  POINTS TO FIRST DATA BYTE IN MESSAGE
;  P4	SET UP AT ENTRY BY NTDISP.  CONTAINS NUMBER OF DATA BYTES LEFT.
;  P2	USED AS A COLUMN COUNTER. (STARTS AT 80. COUNTS DOWN)
;  P3	USED BY C.NEXT WHEN DE-COMPRESSING CDR DATA.

C.DATA:				;HERE TO PROCESS CDR DATA
	SETZ	P3,		;CLEAR REPEAT COUNT FOR C.NEXT
	MOVEI	P2,^D80		;INITIALIZE THE COLUMN COUNTER.
	TRNE	S,IO.SIM	;IS IT SUPER IMAGE MODE?
	JRST	C.SIMG		; YES. GO TO SUPER IMAGE MODE PROCESSOR.
	LDB	T1,PIOMOD##	;GET THE MODE.
	CAIG	T1,AL		;IS IT ONE OF THE ASCII MODES
	JRST	C.ASCI		; YES. GO TO SPECIAL PROCESSOR
	CAIN	T1,I		;IMAGE?
	JRST	C.IMAG		; YES.
	CAIL	T1,IB		;IS IT ONE OF THE SCREWY
	CAILE	T1,B		; BINARY MODES?
	JRST	C.IMPM		;NO. BAD MODE. GIVE ERROR
	JRST	C.BIN		;BINARY MODE. GO READ SCREWY CARDS.
SUBTTL 3.1.1        IMAGE MODE INPUT PROCESSING

C.SIMG:				;CDR SUPER-IMAGE MODE.
	SKIPA	T4,[EXP ^D36]	;SUPER-IMAGE MODE USES 36 BIT BYTES
C.IMAG:				;IMAGE MODE
	MOVEI	T4,^D12		;IMAGE MODE USES 12 BIT BYTES.
	PUSHJ	P,NTDSIB##	;SET UP THE INPUT BUFFER
	 STOPCD	.,STOP,CDRIMG,	;++ NTDSIB FAILED IN C.IMAG

C.IMG1:	PUSHJ	P,C.NEXT	;GET THE NEXT 12 BIT CHARACTER
	  JRST	C.DERR		;IF NONE, THEN REMOTE SENT BAD MESSAGE.
	SOSGE	DEVAXI+1(F)	;COUNT DOWN THE BYTE COUNT
	JRST	C.BKTL		; IF EMPTY, THEN USER'S BUFFER IS TOO SMALL
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE BYTE
	SOJG	P2,C.IMG1	;LOOP OVER ALL COLUMNS
	PJRST	NTDA1B##	;ADVANCE THE INPUT BUFFER AND SKIP RETURN
SUBTTL 3.1.2        ASCII MODE INPUT PROCESSING

C.ASCI:				;ASCII MODE CARDS (UGH)
	MOVEI	T4,^D7		;SEVEN BIT BYTES FOR ASCII MODES
	PUSHJ	P,NTDSIB##	;SET UP THE INPUT BUFFER
	 STOPCD	.,STOP,CDRASC,	;++ NTDSIB FAILED IN C.ASCI
				; CAN'T HAPPEN. WE CHECKED AT C.LOOP
	PUSHJ	P,C.NEXT	;GET COLUMN 1
	  JRST	C.DERR		;?? NO FIRST COLUMN ??
	CAIN	T1,C%EOF	;IS IT AN E-O-F CARD
	JRST	C.DEND		; IF SO, GO TELL THE USER
	CAIN	T1,C%029	;IS IT A CHANGE TO 029 STYLE TRANSLATION
	JRST	[MOVSI S,IOS029	;IF SO, FIRST SET THE "029 MODE"
		 IORB S,DEVIOS(F) ; BIT FOR C.CONV TO SEE, AND
		 PJRST CPOPJ1##]  ; GIVE GOOD RETURN (BUT DON'T ADVANCE BUFFER)
	CAIN	T1,C%026	;IS IT A CHANGE TO 026 STYLE TRANSLATION
	JRST	[MOVSI S,IOS029	;IF SO, FIRST CLEAR THE "029 MODE"
		 ANDCAB S,DEVIOS(F) ; FOR C.COMV
		 PJRST CPOPJ1##]    ;GIVE GOOD RETURN.

	JRST	C.ASC2		;NORMAL CARD. SKIP INTO COPY LOOP.
C.ASC1:	PUSHJ	P,C.NEXT	;GET THE NEXT BYTE
	  JRST	C.DERR		;REMOTE SENT BAD DATA
C.ASC2:	PUSHJ	P,C.CONV	;DO THE DATA CONVERSION
	SOSGE	DEVAXI+1(F)	;COUNT DOWN THE BYTE COUNT
	JRST	C.BKTL		;USER DIDN'T GIVE BIG ENOUGH BUFFER.
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE BYTE IN THE USERS BUFFER.
	SOJG	P2,C.ASC1	;LOOP FOR ALL 80 CHARACTERS.

	SOSGE	DEVAXI+1(F)	;COUNT OFF THE <CR>
	JRST	C.BKTL		;BUFFER TOO SMALL
	MOVEI	T1,15		;<CR>
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE <CR>

	SOSGE	DEVAXI+1(F)	;COUNT OFF THE <LF>
	JRST	C.BKTL		;BUFFER TOO SMALL
	MOVEI	T1,12		;<LF>
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE <LF>

	PJRST	NTDA1B##	;ADVANCE BUFFER AND NCL MESSAGE
SUBTTL 3.1.3        BINARY MODE INPUT PROCESSING

C.BIN:				;BINARY MODE
	MOVEI	T4,^D12		;12 BIT BYTES IN BINARY MODE
	PUSHJ	P,NTDSIB##	;SET UP THE INPUT BUFFER
	 STOPCD	.,STOP,CDRBIN,	;++ NTDSIB FAILED IN C.BIN
	PUSHJ	P,C.NEXT	;GET THE FIRST COLUMN
	  JRST	C.DERR		;?? NO FIRST BYTE ??
	CAIN	T1,C%EOF	;WAS THIS AN EOF CARD
	JRST	C.DEND		;IF SO, GO SET E-O-F AND RETURN
	MOVEI	T2,-5(T1)	;TAKE OUT THE 7-9 BITS
	TRNE	T2,17		;MAKE SURE THAT'S ALL THAT WAS THERE
	JRST	C.IMPB		;IMPROPER BINARY CARD. ABORT.
	LSH	T1,-6		;SHIFT TO GET JUST WORD COUNT.
	JUMPE	T1,CPOPJ1##	;IF NO WORDS. JUST RETURN
	HRLM	T1,DEVAXO(F)	;STORE WORD COUNT IN OUTPUT WORD FOR A BIT
	IMUL	T1,3		;CONVERT WORD COUNT INTO A COLUMN COUNT
	MOVEI	T2,(T1)		;INITIALIZE "GLOBAL" COLUMN COUNT.

	PUSHJ	P,C.NEXT	;GET THE CHECKSUM BYTE
	  JRST	C.DERR		;?? STRANGE MESSAGE ??
	HRRM	T1,DEVAXO(F)	;SAVE THE CHECKSUM TILL LATER TOO!

C.BIN1:				;COPY LOOP.
	PUSHJ	P,C.NEXT	;GET THE NEXT BYTE
	  JRST	C.DERR		;CARD ENDED TOO SOON!
	SOSGE	DEVAXI+1(F)	;COUNT DOWN THE BYTE
	JRST	C.BKTL		;USER DIDN'T MAKE BUFFER BIG ENOUGH.
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE BYTE IN THE USERS BUFFER.
	SOJG	P2,C.BIN1	;COMPLETE THE REST OF THE CARD.

;NOW WE MUST COMPUTE THE "FOLDED 12 BIT" CHECKSUM

	HRRZ	T2,DEVIAD(F)	;GET A POINTER TO THE BUFFER HEADER
	HLRZ	T3,DEVAXO(F)	;RECOVER THE WORD COUNT
	MOVNS	T3		;NEGATIVE WORD COUNT
	HRL	T2,T3		;MAKE INTO -COUNT,,ADDRESS-2
	SETZ	T1,		;INITIALIZE THE CHECKSUM

	EXCTUX	<ADD T1,2(T2)>	;ADD THE NEXT WORD
	AOBJN	T2,.-1		;LOOP UNTIL ALL WORDS ARE COLLECTED

	LSHC	T1,-^D24	;SHIFT SO AS TO GET TOP AND
	LSH	T2,-^D12	; BOTTOM THIRD ADDED
	ADD	T1,T2		; TOGETHER IN T1
	LSHC	T1,-^D12	;SHIFT SO AS TO GET MIDDLE
	LSH	T2,-^D24	; THIRD ADDED IN
	ADD	T1,T2		; THERE TOO
	TRZE	T1,770000	;CLEAR EXTRA BITS, BUT CHECK
	ADDI	T1,1		; AND CORRECT FOR CARRY (CIRCULAR CHECKSUM)
	HRRZ	T2,DEVAXO(F)	;GET THE ORIGIONAL CHECKSUM
	CAIE	T1,(T2)		;SEE IF THEY AGREE.
	JRST	C.DTER		;IF NOT, GIVE IODTER
	PJRST	NTDA1B##	;IF THEY DO, THEN ADVANCE BUFFERS
SUBTTL 3.2        INPUT STATUS MESSAGE PROCESSING

C.STAT:				;HERE UPON RECEIPT OF A STATUS MESSAGE
;STC
	PUSHJ	P,EBI2BI##	;READ THE CODE (STATUS, SET, OR CLEAR)
	JUMPN	T1,CPOPJ##	;WE ONLY ACCEPT THE ZERO KIND.
;STD
	PUSHJ	P,EBI2BI##	;READ THE STATUS BITS
	XOR	T1,DEVSTS(F)	;GET A MASK OF THE BITS THAT CHANGED
	TRNN	T1,-1		;DID ANY CHANGE?
	JRST	CPOPJ1##	;IF NOT, DON'T GO ANY FARTHER
	XORB	T1,DEVSTS(F)	;REMEMBER THE NEW STATUS
	MOVSI	S,IOSERR	;GET ERROR BIT TO SET/CLEAR
	MOVE	T2,[0 S,DEVIOS(F)] ;GET SKELETON INSTRUCTION TO SET/CLEAR BITS
	TRNE	T1,SCD.ME	;IS THE ERROR BIT LIT?
	TLOA	T2,(IORB)	;YES. SET ERROR BITS
	TLO	T2,(ANDCAB)	;NO. CLEAR ERROR BITS
	XCT	T2		;SET/CLEAR THE BITS
	PUSHJ	P,NTDIAV##	;TELL LOWLEVEL THAT SOMETHING HAPPENED
	JRST	CPOPJ1##	;NO NEED TO DO MORE.  C.LOOP & C.HUNG WILL
				; NOTICE THESE BITS SOON ENOUGH.
SUBTTL 4.0      UTILITY ROUTINES

SUBTTL 4.1        ERROR HANDLING ROUTINES

COMMENT \

Possible CDR error codes and their causes are as follows.

    IOEND
	Ascii and binary modes.  Indicates an "EOF" card
    IOBKTL
	All modes.  A user specified buffer was too small to hold an
	entire card.
    IODTER
	Binary mode only.  Indicates that the checksum was wrong.
    IODERR
	Device error (usually a bad message from the remote)
    IOIMPM
	Improper mode. Cdr was not opened in a legal mode, or while in
	binary mode a non-binary card was read.

\


C.SER0==.+1			;KONSTANT TO NORMALIZE "T1"
C.DEND:	JSP	T1,C.SERR	;END-OF-FILE
C.BKTL:	JSP	T1,C.SERR	;BLOCK TO LARGE
C.DTER:	JSP	T1,C.SERR	;CHECKSUM ERROR
C.DERR:	JSP	T1,C.SERR	;DEVICE ERROR (OR REMOTE ERROR)
C.IMPM:	JSP	T1,C.SERR	;IMPROPER MODE (OPEN)
C.IMPB:	JSP	T1,C.SERR	;IMPROPER MODE (BINARY MODE AND NOT BINARY CARD)

;THE FORMAT OF ENTRIES IN THIS NEXT TABLE ARE "XWD FLAGS,BIT"
; WHERE BIT IS THE "DEVIOS" ERROR BIT TO SET, AND
; WHERE FLAGS ARE BITS THAT SAY:
;  1 - ADVANCE THE USERS BUFFER
;  2 - SKIP RETURN (ADVANCE THE NCL MESSAGE)

C.SERR:	MOVE	T1,[XWD 7,IOEND		;E-O-F
		    XWD 3,IOBKTL	;BLOCK-TOO-LARGE
		    XWD 3,IODTER	;DATA-ERROR
		    XWD 3,IODERR	;DEVICE ERROR
		    XWD 1,IOIMPM	;IMPROPER MODE (OPEN)
		    XWD 3,IOIMPM	;IMPROPER MODE (BINARY CARD)
		   ]-C.SER0(T1)	;GET XWD FLAGS,BIT
	MOVEI	S,(T1)		;GET OUR BIT TO SET
	TLNE	T1,4		;IF THIS BIT IS SET,
	HRLZ	S,S		;THEN PUT THE BIT IN THE LH
	IORB	S,DEVIOS(F)	;AND SET IT
	TLNE	T1,2		;SKIP RETURN?
	AOS	(P)		;YES. MAKE SURE IT HAPPENS
	TLNE	T1,1		;ADVANCE INPUT BUFFER?
	PUSHJ	P,NTDAIB##	;YES. GO DO IT.
	POPJ	P,		;ALL DONE
SUBTTL 4.2        DATA DECOMPRESSION ROUTINE

COMMENT \
DATA SENT TO DECSYSTEM-10 IS ESSENTIALY IMAGE MODE
	REPRESENTATION	MEANING
	1CCCCCCC	CCCCCCC = SEVEN BIT ENCODED CHARACTER
			PUNCH 12=B6; PUNCH 11=B5; PUNCH 0=B4
			CODE	PUNCHES IN ROWS 1-9
			0	NONE
			1	1
			2	2
			3	3
			4	4
			5	5
			6	6
			7	7
			10	8
			11	9
			12	8-2
			13	8-3
			14	8-4
			15	8-5
			16	8-6
			17	8-7
	01XXXXXX	XXXXXX =COUNT OF BLANKS
	001XXXXX	XXXXX = COUNT OF REPETITIONS, 0-31
	0000CCCC
	CCCCCCCC	CCCCCCCCCCCC = TWELVE BIT ENCODED CHARACTER

DB.DCS - DEVICE CONTROL STATUS BITS

	CS.ERR=0001	;CARD READER ERROR(MASTER ERROR)
	CS.HEM=0002	;HOPPER EMPTY
	CS.RER=0004	;REGISTRATION ERROR
	       0010	;INVALID PUNCH
	CS.FUL=0020	;STACKER FULL
	CS.JAM=0040	;JAM WHILE FEEDING
	CS.PCK=0100	;PICK FAILURE
	CS.EOF=0200	;END OF FILE CARD
	       0400	;HDW EOF
	       1000	;CDR OVERRAN THE PROCESSOR
	CS.OFL=2000	;CDR HAS GONE OFF LINE
	CS.STP=4000	;CDR STOPPED (CLEARED BY 10 WITH CLEAR STATUS MSG)

\
;SUBROUTINE C.NEXT RETURN THE NEXT CHAR FROM THE DAP MESSAGE POINTED
; TO BY P1 (WITH SUB-MESSAGE LENGTH IN P4)
;
;CALL	MOVE P1,BYTE POINTER TO FIRST CHAR OF DATA IN MESSAGE (AFTER TYP)
;	MOVE P4,COUNT OF DAP DATA BYTES
;	SETZ P3,		;CLEAR THE REPEAT COUNT
;	PUSHJ P,C.NEXT
;RETURN	CPOPJ			;NO CHAR AVAILABLE (MESSAGE COUNTED OUT, OR
;				; SOMETHING WAS WRONG WITH THE MESSAGE)
;	CPOPJ1			;T1 := THE NEXT 12 BIT CHAR FROM THE STREAM
;
;NOTE.	WHEN THIS ROUTINE IS DECOMPRESSING CHARACTERS IT USES P3 AS
;	A REPEAT COUNT.  IF YOU CLOBBER P3 BETWEEN CALLS TO C.NEXT, YOU
;	WILL GET GARBAGE.

C.NEXT:				;MAIN ENTRY TO GET NEXT 12 BYTE CHAR.
	JUMPN	P3,C.RPT	;IF WE ARE IN A REPEAT, GO USE LH OF P3
C.NXT0:				;RECURSIVE ENTRY POINT WHEN PICKING
				; A REPEATED CHARACTER
	SOJL	P4,C.IERR	;COUNT OFF NEXT BYTE (ERROR IF MESSAGE IS DONE)
	ILDB	T1,P1		;FETCH THE NEXT CHARACTER

	TRZE	T1,1_7		;IS THIS A "COMPRESSED" CHAR
	JRST	C.NXT1		; IF SO, EXPAND IT AND RETURN

	TRZE	T1,1_6		;IS THIS A REPEATED BLANK?
	JRST	C.NXT2		; IF SO, SET COUNT AND LET C.RPT LOOSE ON IT.

	TRZE	T1,1_5		;IS THIS A REPEAT COUNT?
	JRST	C.NXT3		; IF SO, THEN GET NEXT CHAR AND REPEAT IT.

	TRZE	T1,1_4		;IS IT AN "UNUSED" FORM...
	JRST	C.IERR		; IF SO, THEN SOMETHING IS WRONG.

	MOVEI	T2,(T1)		;IT MUST BE THE FIRST 4 BITS OF A TWO BYTE CHAR
	LSH	T2,^D8		;SHIFT UP THE MOST SIGNIFICANT 4 BITS
	SOJL	P4,C.IERR	;COUNT DOWN THE NEXT BYTE
	ILDB	T1,P1		;GET THE NEXT CHAR
	IORI	T1,(T2)		;OR IN THE HIGH FOUR BITS
	JRST	CPOPJ1##	;GIVE A GOOD RETURN
C.NXT1:				;HERE IF THIS IS A "COMPRESSED" CHAR
	IDIVI	T1,20		;SEPARATE THE ZONES (CLEVER DON'T YOU THINK...)
	LSHC	T2,-2		;NOW T2 := WORD INDEX, T3(B0, B1) HAS BYTE INDEX
	MOVE	T2,[BYTE (9)000,400,200,100 ;NOW LOAD T2 WITH A WORD THAT
		    BYTE (9)040,020,010,004 ; HAS FOUR DIFFERENT LOW ORDER
		    BYTE (9)002,001,202,102 ; BYTES.  WE WILL THEN CLEVERLY
		    BYTE (9)042,022,012,006](T2) ; POSITION IT AT THE TOP OF T2
	TLZE	T3,(1B0)	;SKIP IF TOP HALF-WORD IS RIGHT.
	HRLZI	T2,(T2)		;MAKE UPPER HALF CONTAIN THE DESIRED BYTE
	TLZE	T3,(1B1)	;SKIP IF THE TOP BYTE IS RIGHT.
	LSH	T2,^D9		;MOVE THE SECOND BYTE UP TO WHERE IT BELONGS
	LSHC	T1,^D9		;(REMEMBER THAT T1 HAS TOP 4 BITS ALREADY)
	JRST	CPOPJ1##	;ALL DONE. THE CHAR IS THE LOW 12 BITS IN T1!

C.NXT2:				;HERE IF WE HAVE REPEATED BLANKS
	JUMPN	P3,C.IERR	;NESTED REPEATS ARE ILLEGAL!
	MOVEI	P3,(T1)		;COPY THE REPEAT COUNT
	JUMPE	P3,C.NEXT	;IGNORE ZERO LENGTH REPEATS
	PJRST	C.RPT		;PASS THE BUCK TO C.RPT.

C.NXT3:				;HERE TO REPEAT AN ARBITRARY CHAR.
	JUMPN	P3,C.IERR	;NEXTED REPEATS ARE NOT ALLOWED.
	MOVEI	P3,(T1)		;COPY THE REPEAT COUNT
	PUSHJ	P,C.NXT0	;CALL OURSELF RECURSIVLY FOR THE REPEATED CHAR.
	  PJRST	C.IERR		;?? THIS IS WRONG. WE SHOULD HAVE ANOTHER CHAR.
	JUMPE	P3,C.NEXT	;LET ZERO LENTGH REPEATS WORK. (WONT HAPPEN)
	HRLI	P3,(T1)		;COPY THE CHAR TO REPEAT SO C.RPT WILL SEE IT.
;	PJRST	C.RPT		;LET C.RPT DO THE REST.

C.RPT:	HLRZ	T1,P3		;GET THE CHAR THAT'S BEING REPEATED
	SUBI	P3,1		;DECREMENT THE COUNT
	TRNN	P3,77		;SEE IF WE HAVE COUNTED DOWN ALL CHARS.
	SETZ	P3,		; IF WE HAVE, CLEAR THE REPEAT CHAR
	JRST	CPOPJ1##	;GIVE A GOOD RETURN

C.IERR:	POPJ	P,		;GIVE ERROR RETURN (WHAT ELSE CAN I DO??)
SUBTTL 4.3        CARD CODE TO ASCII CONVERSION ROUTINE

;C.CONV	THIS ROUTINE TRANSLATES A 12 BIT CARD CODE INTO A 7 BIT
;	ASCII CHAR (GOD KNOWS HOW...)
;CALL	MOVEI	T1,"THE 12 BIT CHAR"
;	PUSHJ	P,C.CONV
	;RETURN	CPOPJ		;CONVERTED CHAR IN T1
C.CONV:
	MOVEI	T3,(T1)		;PUT THE CHAR IN T3 FOR EXAMINATION
	SETZB	T1,T2		;CLEAR T1 AND T2
	JUMPE	T3,C.CNV1	;BLANKS ARE VERY SIMPLE
	CAIN	T3,5000		;12-0?
	MOVEI	T3,4242		;YES, TREAT AS 12-8-2 ([)
	CAIN	T3,3000		;NO, 11-0?
	MOVEI	T3,2202		;YES, TREAT AS 11-8-2 (!)
	LDB	T2,[POINT 3,T3,26]
	TRNE	T3,3		;DIDDLE T1 AND T2 TO FORM
	TRC	T2,7		;INDEXES INTO CHAR TABLE
	TRNE	T3,74
	TRO	T2,10
	TRNE	T3,314
	TRO	T1,2
	TRNE	T3,525
	TRO	T1,1
	TLNE	S,IOS029	;IN 026 CHAR SET MODE?
	TRO	T2,20		;NO, USE SECOND TABLE
C.CNV1:	LDB	T1,CRCVPT##(T1)	;GET 7-BIT TRANSLATION
	POPJ	P,
	XLIST			;DON'T LIST THE LITERALS
	$LIT
	LIST

NTCDRX::PRGEND
TITLE	NETDDP - NETWORK "DDCMP" DEVICE SERVICE ROUTINES - V001
SUBTTL	NETDDP -- RDH/	21-APR-82

	SEARCH	F,S,NETPRM,D36PAR,MACSYM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE SUED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1982,1984  BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.

XP VNETDP,001		;PUT VERSION NUMBER IN GLOB AND LOADER MAP

NETDDP::ENTRY	NETDDP
SUBTTL	GENERAL DEFINTIONS PECULIAR TO THE DDP DEVICE/KONTROLLER

;DEVIOUS BITS

XP	IOSDDK,IOSFFB_0		;DDP IS IN USE AS A KONTROLLER
				;  IF 0 THEN USER I/O (IN, OUT UUOS) OK
				;  IF 1 THEN USER GETS IO.IMP
XP	IOSDDH,IOSFFB_1		;DDP KONTROLLER IS "HALTED" (BY DRIVER REQUEST)
				;  IF 0 THEN DDP RUNNING, PASS DATA
				;  IF 1 THEN DDP DOWN, DISCARD DATA
XP	IOSDDD,IOSFFB_2		;DDP'S DDCMP PROTOCOL IS DOWN
				;  IF 0 THEN DDCMP IS RUNNING
				;  IF 1 THEN DDCMP IS DOWN



;DDP DDB WORDS ABOVE AND BEYOND STANDARD NETWORK DEVICE

DEFINE	X(NAM,SIZ<1>),<NAM==:<%%%OFF==%%%OFF+SIZ>-SIZ>

	%%%OFF==NETLEN

X	DDPUSR			;LINE USER OF DDP KONTROLLER (E.G., DECNET)
X	DDPLBK			;DRIVER'S LINE BLOCK ADDRESS
X	DDPQOB			;POINTER TO QUEUE OF OUTPUT MESSAGES
X	DDPMBP			;POINTER TO RECEIVE MESSAGE BUFFER

X	DDPDLN,0		;LENGTH OF DDP DDB
SUBTTL	UUO INTERFACE - DEVSER UUO DISPATCH VECTOR


	JRST	NTDONL##	;(-5) CHECK IF DEVICE IS ONLINE
	JRST	CPOPJ##		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) BUFFER SIZE
	JRST	CPOPJ##		;(-2) INITIALIZATION
	JRST	CPOPJ1##	;(-1) HUNG DEVICE CHECK (REMOTE DOES IT)
NDEVDP::JRST	NTDREL##	;(00) RELEASE
	JRST	NTDCLO##	;(01) CLOSE
	JRST	DDPUOU		;(02) BUFFERED OUT
	JRST	DDPUIN		;(03) BUFFERED IN
SUBTTL	UUO INTERFACE - DDB CREATION

;TSTDDP - TEST FOR DDP DEVICE, CREATE DDB IF NEEDED
;CALL	MOVEI	P1,FLAGS	;(ONLY MATCH IF LOOKING FOR PHYSICAL DEVICE)
;	MOVE	T1,[SIXBIT /DD?NNX/] ;DEVICE NAME
;	PUSHJ	P,TSTDDP
;RETURN	CPOPJ			;NOT A DDP DEVICE
;	CPOPJ1			;IS A DDP DEVICE; F := DDP DDB.

TSTDDP::TRNE	P1,DD%LOG##	;LOOKING AT LOGICAL NAMES?
	POPJ	P,		;GIVE UP NOW IF NOT PHYSICAL SEARCH
	HLRZ	T2,T1		;GET JUST THE NAME
	CAIL	T2,'DDA'	;SEE IF WITHIN RANGE OF ALLOWABLE
	CAILE	T2,'DDH'	; "CONTROLLER"S
	POPJ	P,		;NOT A DDP-CLASS DEVICE
	PUSHJ	P,NTDPRV##	;DDP'S ARE PRIVILEGED GADGETS
	 POPJ	P,		;AND THE USER ISN'T
	PUSHJ	P,SAVJW##	;WE CLOBBER W RIGHT AWAY, AND J IF WE CONNECT.
	PUSHJ	P,SAVE4##	;NETSER CLOBBERS MOST OF THESE
	NETDBJ			;BETTER INTERLOCK FROM HERE ON OUT.
	PUSH	P,T1		;SAVE THE DEVICE NAME
	PUSHJ	P,DVSCVT##	;GET THE NODE NUMBER FROM THE NAME
	  PJRST	TPOPJ##		;NOT A NETWORK NAME.
	MOVEI	T1,(T2)		;COPY THE NODE NUMBER
	PUSHJ	P,SRCNDB##	;GET A NDB POINTER
	  PJRST	TPOPJ##		;NO NODE MEANS NO DDP
	MOVEI	P1,(W)		;COPY THE NDB POINTER FOR MAKDDB
	MOVEI	T1,'DDP'	;GET GENERIC DEVICE NAME IN RH(T1)
	PUSHJ	P,SRCNDT##	;SEE IF THE NODE SUPPORTS DDP'S
	  PJRST	TPOPJ##		;IF NOT, THEN DEVICE DOESN'T EXIST
	LDB	T1,[POINT 6,(P),17] ;POINT TO "CONTROLLER" CHARACTER
	SUBI	T1,'A'		;CONVERT TO A CONTROLLER NUMBER
	LDB	T2,[POINT 3,(P),35] ;GET THE UNIT DIGIT (NUMERIC)
	CAIL	T2,0		;MAKE SURE THAT IT'S IN THE
	CAILE	T2,7		; RANGE 0-7
	PJRST	TPOPJ##		;NOT A VALID DIGIT.
	LSH	T1,3		;CONTROLLER BECOMES TOP HALF OF "PUNIT"
	IORI	T1,(T2)		;T1 := FULL UNIT SPECIFICATION
	PUSH	P,T1		;SAVE "PUNIT" VALUE UNTIL WE SEND THE CONNECT.

	MOVE	P2,-1(P)	;GET THE FULL NAME BACK
	PUSHJ	P,MAKDDP	;MAKE A DDP DDB
	  JRST	TTPOPJ##	;NO CORE. GIVE ERROR RETURN
	POP	P,T1		;GET THE UNIT NUMBER BACK
	DPB	T1,PUNIT##	;STORE THE UNIT NUMBER IN THE DDB
	MOVEI	W,(P1)		;SET UP THE NDB POINTER AGAIN
	PUSHJ	P,NTDCNT##	;ATTEMPT TO CONNECT THE DEVICE
	  JRST	[PUSHJ P,UNLDDB## ;CONNECT FAILED. FREE THE DDB
		 JRST TPOPJ##]	;AND GIVE UUOCON THE ERROR RETURN
	PJRST	TPOPJ1##	;ALL DONE. GOOD RETURN, F := DDB POINTER.
SUBTTL	UUO INTERFACE - CONVERT LINE-ID TO DDB
;DDPSRC - CONVERT LINE-ID TO DDB
;CALL	MOVE	T2,<LINE-ID>
;	PUSHJ	P,DDPSRC
;	 <ERROR>
;	<GOOD>
;RETURN CPOPJ IF NOT A DDP LINE ID
;RETURN CPOPJ1 WITH DDB ADDRESS IN T2
DDPSRC:	PUSH	P,T1		;SAVE WORK AC'S
	LOAD	T1,LIDEV,+T2	;GET LINE ID
	CAIE	T1,LD.DDP	;IS IT ONE OF OURS?
	PJRST	TPOPJ##		;NO, DON'T TOUCH IT
	PUSH	P,T2		;SAVE THE OTHER TEMPS
	PUSH	P,T3
	LOAD	T1,LIKON,+T2	;GET KONTROLLER NUMBER(REALLY NODE)
	LOAD	T3,LIUNI,+T2	;GET THE UNIT NUMBER
	IDIVI	T1,10		;GET THE HIGH ORDER DIGIT OF NODE NUMBER
	ADDI	T1,'0'		;MAKE IT SIXBIT
	LSH	T1,6		;SHIFT FOR NEXT DIGIT
	ADDI	T1,'0'(T2)	;SIXBIT ALSO
	LSH	T1,6		;SHIFT ONE LAST TIME
	ADDI	T1,'0'(T3)	;INCLUDE THE UNIT NUMBER
	HRLI	T1,'DDA'	;FORCE KONTROLLER NUMBER
	DDBSRL			;LOCK THE DDB DATA BASE
	HLRZ	T2,NETDDB##+DEVSER ;GET ADDRESS OF FIRST DDB IN CHAIN
DDPSR1:	CAMN	T1,DEVNAM(T2)	;IS THIS THE ONE
	JRST	DDPSR2		;YES, WE FOUND IT
	HLRZ	T2,DEVSER(T2)	;NO, STEP TO NEXT DDB
	JUMPN	T2,DDPSR1	;LOOP IF ONE THERE
DDPSR2:	DDBSRU			;DONE FOOLING WITH DDBS
	SKIPN	T2		;NO SKIP IF NO DDB
	JRST	DDPSR3		;WE DIDN'T FIND ON
	AOS	-3(P)		;WE FOUND ONE, SKIP RETURN
	MOVEM	T2,-1(P)	;STORE DDB ADDRESS
DDPSR3:	POP	P,T3		;RESTORE AC'S
	POP	P,T2
	POP	P,T1
	POPJ	P,		;RETURN TO CALLER
SUBTTL	UUO INTERFACE - DDB DESTRUCTION

;ZAPDDP - SEE IF OK TO DESTROY DDP DDB
;CALL	MOVE	F,<DDB>
;	PUSHJ	P,ZAPNET
;RETURN	CPOPJ			;ALWAYS
;
;IF DDP IS IN USE AS KONTROLLER (AND THUS CANNOT BE ZAPPED) THEN THIS
;ROUTINE (CALLED BY ZAPNET) RETURNS, AND ZAPNET DOES NOTHING. IF THE
;DDP IS IDLE (I.E., IS NOT A KONTROLLER), THEN ZAPNET IS ALLOWED TO
;GO AHEAD AND DESTROY THE DDB, RELEASING THE DDP DEVICE BACK TO THE
;REMOTE NODE.

ZAPDDP::MOVE	S,DEVIOS(F)	;GET THE I/O STATUS BITS
	TLNN	S,IOSDDK	;IN USE AS A KONTROLLER?
	PJRST	ZAPNE1##	;NO, OFF TO ZAPNET TO ZAP THE DEVICE
	POPJ	P,		;YES, RETURN HAVING DONE NOTHING
SUBTTL	UUO INTERFACE - IN UUO

;HERE FROM UUOCON ON USER IN UUO

DDPUIN:	TLNE	S,IOSDDK	;IS DDP IN USE AS A KONTROLLER
	PJRST	DDPIMP		;YES, NAUGHTY BOY, HE GETS AN ERROR RETURN

;DDP IS AVAILABLE AS AN I/O DEVICE TO THE USER

	PUSHJ	P,SAVE4##	;WE NEED LOTS OF P'S
	MOVSI	S,IOSUSI	;CLEAR THE UUOCON-STOPPED-INPUT BIT
	ANDCAB	S,DEVIOS(F)	; SINCE WE ARE DOING AN IN NOW

DDPUI1:	PUSHJ	P,NTDSET##	;SETUP NETWORK CONTEXT (W, S, ETC)
	TLNE	S,IOSERR	;ANYTHING SERIOUSLY WRONG?
	JRST	DDPIER		;YES, NODE DOWN, ETC.
	TLNE	S,IOBEG		;HAVE WE BEEN HERE BEFORE?
	PUSHJ	P,DDPFIR	;NO, FIRST IN, SPECIAL
	MOVSI	S,IO		;THE IN VERSUS OUT BIT
	ANDCAB	S,DEVIOS(F)	;WE ARE DOING "IN" TYPE STUFF

;NOW TRY TO FILL A USER BUFFER FROM INCOMING DATA MESSAGE(S)

DDPUI3:	PUSHJ	P,NTDIBA##	;VERIFY BUFFERS ETC
	 POPJ	P,		;NO BUFFER, RETURN TO UUOCON
	HRRZ	T1,DEVPCB(F)	;ADDRESS OF PENDING PCB CHOCK FULL OF DATA
	JUMPE	T1,DDPUI8	;NO DATA, GO WAIT FOR INPUT
	PUSHJ	P,NTDDID##	;PROCESS THIS NCL SUBMESSAGE
	JRST	DDPUI1		;LOOP ON INPUT


;HERE WHEN NO INPUT

DDPUI8:	PUSHJ	P,NTDONL##	;CHECK THE DEVICE
	 JRST	DDPIER		;ERROR?
	PUSHJ	P,NTDXDQ##	;SEND ANY DATA REQUESTS NEEDED
	PUSHJ	P,NTDWTI##	;WAIT FOR INPUT
	 POPJ	P,		;NON-BLOCKING, BACK TO UUOCON
	JRST	DDPUI1		;LOOP BACK FOR INPUT PROCESSING


;HERE ON INPUT ERROR FROM NTDONL

DDPIER:	MOVE	S,DEVIOS(F)	;ENSURE FRESH COPY
	TLNN	S,IOSCON	;IS DEVICE STILL CONNECTED?
	PJRST	NTDGON##	;NO - NETWORK CONNECTION GONE
	TLNE	S,IOSERR	;IS THE DDP "OFFLINE"
	PUSHJ	P,NTDHNG##	;YES, COMPLAIN
	JRST	DDPUI1		;BACK TO TRY INPUT PROCESSING
SUBTTL	UUO INTERFACE - OUT UUO

;HERE FROM UUOCON ON OUT UUO

DDPUOU:	TLNE	S,IOSDDK	;IS DDP IN USE AS A KONTROLLER?
	PJRST	DDPIMP		;YES, DISALLOW UUO-LEVEL DIDDLING

;DDP IS AVAILABLE AS AN I/O DEVICE

	PUSHJ	P,SAVE4##	;USE LOTS OF P'S
	MOVSI	S,IOSUSO	;CLEAR THE UUOCON-STOPPED-OUTPUT BIT
	ANDCAB	S,DEVIOS(F)	; SINCE ITS DOING ANOTHER OUT

;LOOP OUTPUTTING DATA FROM USER'S I/O BUFFER(S)

DDPUO1:	PUSHJ	P,NTDSET##	;SETUP NETWORK ACS (W, S, ETC)
	TLNE	S,IOSERR	;ANYTHING SERIOUSLY WRONG?
	JRST	DDPOER		;YES, SEE IF STILL THERE
	TLNE	S,IOBEG		;FIRST TIME HERE?
	PUSHJ	P,DDPFIR	;YEAH, DO SOME CLEANUP FIRST
	MOVSI	S,IO		;THE IN VERSUS OUT BIT
	IORB	S,DEVIOS(F)	;WE ARE DOING "OUT" TYPE STUFF

;TRY TO SEND ONE BUFFER'S WORTH OF DATA

DDPUO3:	PUSHJ	P,NTDCDQ##	;CHECK TO SEE IF ANY DATA REQUESTS AVAILABLE
	 JRST	DDPUO8		;NONE AVAILABLE, WAIT
	MOVEI	T1,^D08		;DDP DATA IS BY DEFINITION 8 BITS
	PUSHJ	P,NTDSOB##	;SET UP AN OUTPUT BUFFER
	 POPJ	P,		;TIME TO RETURN TO UUOCON (NO MORE DATA, ETC)
	MOVEI	T1,PCV.NC	;NO FUNNY BIT DIDDLING, JUST STRAIGHT IMAGE DATA
	MOVEI	T2,DC.DAR	;NCL DATA WITH EOR
	PUSHJ	P,NTDXMT##	;SEND A BUFFER
	 JRST	DDPUO7		;NO FREE CORE FOR PCB
	PUSHJ	P,NTDDDQ##	;WE JUST USED UP ONE DATA REQUEST
	SKIPE	DEVAXO+1(F)	;DID NTDXMT EMPTY THE BUFFER?
	JRST	DDPBTL		;NO - BLOCK TOO LARGE ERROR
	PUSHJ	P,NTDAOB##	;ADVANCE USER'S BUFFER
	JRST	DDPUO1		;TRY FOR ANOTHER BUFFER
;HERE WHEN NO FREE CORE FOR OUTPUT PCBS

DDPUO7:	CAIE	T1,0		;0 MEANS NO FREE CORE
	STOPCD	.,STOP,DDPXMT,	;++ NTDXMT FAILED, NOT RUNNING OUT OF FREECORE
	PUSHJ	P,NETSLP##	;WAIT FOR FREE CORE
	JRST	DDPUO1		;LOOP BACK AND TRY AGAIN


;HERE TO WAIT FOR OUTPUTABILITY

DDPUO8:	PUSHJ	P,NTDONL##	;ENSURE NICE JUICY DEVICE
	 JRST	DDPOER		;CHECK OUT BADNESS
	PUSHJ	P,NTDWTO##	;WAIT FOR OUTPUT (DATA REQUESTS)
	 POPJ	P,		;NON-BLOCKING, BACK TO UUOCON NOW
	JRST	DDPUO1		;TRY OUTPUT AGAIN


;HERE ON OUTPUT ERROR FROM NTDONL

DDPOER:	MOVE	S,DEVIOS(F)	;ENSURE FRESH COPY
	TLNN	S,IOSCON	;IS DDP DEVICE STILL CONNECTED?
	PJRST	NTDGON##	;NO, NETWORK CONNECTION GONE
	TLNE	S,IOSERR	;IS THE DDP "OFFLINE"
	PUSHJ	P,NTDHNG##	;YEAH, COMPLAIN
	JRST	DDPUO1		;LOOP BACK AND TRY OUTPUT AGAIN
SUBTTL	UUO INTERFACE - DDP SERVICE INITIALIZATION

DDPFIR:	MOVSI	S,IOBEG!IOSREL	;KRUFTY BITS
	ANDCAB	S,DEVIOS(F)	;CLEAR OLD BITS IN DDB
	SETZM	DEVAXI(F)	;CLEAR DANGLING INPUT
	SETZM	DEVAXO(F)	;AND ANY DANGLING OUTPUT
	POPJ	P,		;NOW SET FOR CLEAN I/O



SUBTTL	UUO INTERFACE - DDP DEVICE ERRORS

;HERE WHEN USER TRIED TO PLAY WITH A DDP IN KONTROLLER MODE

DDPIMP:	MOVEI	S,IOIMPM	;IMPROPER MODE
	JRST	DDPERS		;SET ERROR AND RETURN


;HERE WHEN OUTPUT BUFFER OVERFLOWED NETWORK PCB

DDPBTL:	MOVEI	S,IOBKTL	;BLOCK-TOO-LARGE FOR NETWORK BUFFER
DDPERS:	IORB	S,DEVIOS(F)	;SET ERROR BITS IN DDB
	POPJ	P,		;ERROR RETURN TO UUOCON
SUBTTL	UUO INTERFACE - DDP. UUO -  CONTROL OF DDP KONTROLLER

;THE DDP. UUO ALLOWS UUO-LEVEL CONTROL OF DDP DEVICES/KONTROLLERS.
;CALL IS:
;
;	MOVE	AC,[LEN,,ADR]
;	DDP.	AC,
;	 ERROR RETURN
;	NORMAL RETURN
;
;ADR:	FUNCTION
;	DDP DEVICE ID
;	ARGUMENT (AS NEEDED)
;
;FUNCTION IS ONE OF
;
; (00)	.DPFAS	ASSIGN (CREATING IF NEEDED) DDP DEVICE
; (01)	.DPFZP	ZAP ("RELEASE") DDP DEVICE/KONTROLLER
; (02)	.DPFDV	SET DDP TO "DEVICE" MODE (IN/OUT/ETC. UUOS)
; (03)	.DPFKN	SET DDP TO "KONTROLLER" MODE
; (04)	.DPFUS	SET DDP "KONTROLLER" USER TYPE
; (10)	.DPFHL	HALT THE DDP KONTROLLER
; (11)	.DPFIN	INITIALIZE DDP KONTROLLER
; (12)	.DPFMA	SET TO MAINTENANCE MODE (FOR BOOTSTRAPING)
;
;ON ERROR, AC CONTAINS ERROR CODE:
;
; (01)	DPEIF%	ILLEGAL DDP. FUNCTION CODE
; (02)	DPESH%	ARGUMENT LIST TOO SHORT
; (03)	DPEID%	ILLEGAL DDP. DEVICE (NOT DDP, ETC.)
; (04)	DPEPR%	USER NOT PRIVILEGED
; (05)	DPEIM%	ILLEGAL OPERATION MODE (DDP NOT IN KONTROLLER MODE)
; (06)	DPEIU%	ILLEGAL USER NAME
; (07)	DPEOU%	DDP IS IN USE BY OTHER USER/JOB


;DEFINE ERROR RETURNS

	DDE%IF==ECOD1##		;ILLEGAL FUNCTION
	DDE%SH==ECOD2##		;ARG LIST TOO SHORT
	DDE%ID==ECOD3##		;ILLEGAL DEVICE
	DDE%PR==ECOD4##		;USER NOT PRIVILEGED
	DDE%IM==ECOD5##		;ILLEGAL OPERATION MODE
	DDE%IU==ECOD6##		;ILLEGAL USER NAME
	DDE%OU==ECOD7##		;OTHER USER HAS THE DDP
DDPUUO::HLRZ	P2,T1		;SAVE LENGTH OF ARG LIST
	HRR	M,T1		;POSITION ADDRESS OF ARG LIST
	SOJL	P2,DDE%SH	;ERROR IF TOO SHORT
	PUSHJ	P,GETWDU##	;GET THE FUNCTION CODE
	HRRZ	P1,T1		;POSITION JUST FUNCTION CODE (ALLOW FOR FUTURE)
	CAILE	P1,DDPCMX	;RANGE-CHECK THE FUNCTION CODE
	JRST	DDE%IF		;ILLEGAL FUNCTION CODE
	SOJL	P2,DDE%SH	;ERROR IF ARG LIST TOO SHORT
	PUSHJ	P,NTDPRV##	;IS THIS USER PRIVILEGED?
	 JRST	DDE%PR		;NO, HE LOSES
	PUSHJ	P,GETWD1##	;GET THE DEVICE NAME/ID
	PUSHJ	P,DVCNSG##	;TRY TO DECIPHER THE DEVICE NAME
	 JRST	DDE%ID		;ILLEGAL DEVICE
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,.TYDDP/.TYEST;IS IT A REAL DDP DEVICE?
	JRST	DDE%ID		;NO, ILLEGAL DEVICE
	MOVE	S,DEVIOS(F)	;PRE-LOAD S
	PJRST	@DDPCMT(P1)	;DISPATCH ON FUNCTION

DDPCMT:	IFIW	DDPCAS		;(00) ASSIGN (CREATE) DDP DEVICE
	IFIW	DDPCZP		;(01) ZAP (DESTROY/RELEASE) DDP DEVICE
	IFIW	DDPCDV		;(02) SET TO DEVICE MODE
	IFIW	DDPCKN		;(03) SET TO KONTROLLER MODE
	IFIW	DDPCUS		;(04) SET KONTROLLER USER
	IFIW	DDE%IF		;(05) RESERVED/ILLEGAL
	IFIW	DDE%IF		;(06) RESERVED/ILLEGAL
	IFIW	DDE%IF		;(07) RESERVED/ILLEGAL
	IFIW	DDPCHA		;(10) HALT KONTROLLER PROTOCOL
	IFIW	DDPCIN		;(11) INITIALIZE KONTROLLER PROTOCOL
	IFIW	DDPCMA		;(12) SET TO MAINTENANCE MODE PROTOCOL

	DDPCMX==.-DDPCMT	;MAX DDP COMMAND FUNCTION
;DDPCAS - ASSIGN (CREATE IF NEEDED) DDP DEVICE

;NOTE THAT THE DDP WILL HAVE BEEN CREATED IF NECESSARY BY THE DVCNSG
;PRIOR TO MAIN FUNCTION DISPATCH . . .

DDPCAS:	PUSHJ	P,DDPCAZ	;SEE IF WE CAN MUNCH ON THE DDP
	 JRST	DDE%OU		;OTHER USER HAS THE DDP
	MOVEI	T1,ASSCON	;THE "IN USE BY ASSIGN COMMAND" FLAG
	IORM	T1,DEVMOD(F)	;WE NOW OWN THE DDP
	DPB	J,PJOBN##	;MAKE SURE "WE" IS US
	JRST	CPOPJ1##	;SUCCESSFUL RETURN



;DDPCZP - ZAP (DESTROY) THE DDP DEVICE

DDPCZP:	PUSHJ	P,DDPCAZ	;SEE IF WE CAN MUNCH ON THE DDP
	 JRST	DDE%OU		;OTHER USER HAS THE DDP
	TLNE	S,IOSDDK	;IS THE DDP IN USE AS A KONTROLLER?
	PUSHJ	P,DDPKZP	;YES, ZAP THE KONTROLLER USER FIRST
	MOVEI	T1,ASSCON	;THE "IN USE" BY ASSIGNMENT FLAG
	ANDCAM	T1,DEVMOD(F)	;ALLOW UUOCON TO KRUMP ON THE DDB NOW
	PUSHJ	P,URELEA##	;NOW DO UUO-LEVEL DDB ZAPPING
				; (EVENTUALLY WINDING UP IN ZAPNET/ZAPDDP)
	JRST	CPOPJ1##	;SUCCESSFUL RETURN



;HELPER FOR DDPCAS/DDPCZP
;
;RETURNS CPOPJ IF THE DDP DDB IS NOT AVAILABLE TO THIS JOB (I.E., SOME OTHER
;JOB HAS THE DDB "IN USE"); RETURNS CPOPJ1 IF THE DDB CAN BE ASSIGNED TO
;THIS JOB.

DDPCAZ:	MOVEI	T1,ASSCON!ASSPRG;THE "IN USE" FLAGS
	LDB	T2,PJOBN##	;THE JOB NUMBER (IF ANY) USING THE DDP
	TDNE	T1,DEVMOD(F)	;IS THE DDB IN USE BY A JOB?
	CAMN	T2,J		;YES, IS THAT JOB THIS JOB?
	AOS	(P)		;EITHER AVAILABLE, OR ALREADY IN USE BY US
	POPJ	P,		;RETURN AS APPROPRIATE
;DDPCDV - SET DDP TO "DEVICE" MODE

DDPCDV:	TLNN	S,IOSDDK	;IN KONTROLLER MODE?
	JRST	CPOPJ1##	;NO, ALL DONE HERE
	PUSHJ	P,DDPKZP	;YES, ZAP THE KONTROLLER'S USER FIRST
				; (ALSO FLUSHES ANY QUEUED DATA)
	MOVSI	S,IOSDDK	;THE KONTROLLER-MODE FLAG
	ANDCAB	S,DEVIOS(F)	;SWITCH THE DDP INTO DEVICE MODE
	JRST	CPOPJ1##	;SUCCESSFUL RETURN



;DDPCKN - SET DDP TO "KONTROLLER" MODE

DDPCKN:	MOVSI	S,IOSDDK	;THE KONTROLLER MODE FLAG
	IORB	S,DEVIOS(F)	;SWITCH TO KONTROLLER MODE
	JRST	CPOPJ1##	;ALL DONE HERE
;DDPCUS - SET THE KONTROLLER'S USER

DDPCUS:	SOJL	P2,DDE%SH	;ERROR IF TOO SHORT
	PUSHJ	P,GETWD1##	;GET THE USER NAME (INTO T1)
DDPCU1:	PUSHJ	P,KONUSN##	;TRANSLATE USER NAME INTO TYPE (IN T2)
	 JRST	DDE%IU		;ILLEGAL USER NAME
DDPCU2:	CAMN	T2,DDPUSR(F)	;IS USER TYPE CHANGING?
	JRST	CPOPJ1##	;NO, THIS IS A NO-OP THEN

;*** KROCK FOR NOW

	CAIE	T2,DD.NOB	;ALLOW NOBODY
	CAIN	T2,DD.DEC	;AND DECNET, THAT'S IT
	CAIA			;HAPPY
	JRST	DDE%IU		;UNHAPPY

;CHANGING DRIVER ("USER") TYPE, QUIESCE THE KONTROLLER FIRST

	TLNN	S,IOSDDK	;BUT IS THE DDP A KONTROLLER?
	JRST	DDPCU9		;NO, NOT TO WORRY, JUST SET NEW USER
	PUSH	P,T2		;SAVE TENTATIVE NEW USER
	PUSHJ	P,DDPKZP	;"ZAP" THE KONTROLLER
	MOVSI	S,IOSDDK	;RESET THE "KONTROLLER" STATUS
	IORB	S,DEVIOS(F)	; 'CUZ DDPKZP CLEARS THE KONTROLLER STATUS
	POP	P,T2		;RETRIEVE NEW USER
DDPCU9:	HRRZM	T2,DDPUSR(F)	;SET NEW USER TYPE
	PUSHJ	P,@DDPCUT(T2)	;DO ANY HACKERY REQUIRED BY NEW USER
	 JRST	DDE%IU		;SOMETHING IS ILLEGAL
	JRST	CPOPJ1##	;SUCCESSFUL RETURN

DEFINE	X(USR,CON,DSP),<
	IFN	.-DDPCUT-DD.'USR,<
		PRINTX	? DDPCUT "USR" initialization dispatch out of order>
	IFE	CON,<IFIW CPOPJ##>
	IFN	CON,<IFIW DSP>
> ;END X MACRO

DDPCUT:	X	(NOBODY,1,CPOPJ1##)
	X	(ANF,FTNET,NTDSTP##)
	X	(DECNET,FTDECN,DDPC2T)
	X	(PROGRA,1,CPOPJ##)
	X	(IBMCOM,FTDN60,CPOPJ##)

	IFN	.-DDPCUT-<DD.MAX+1>,<
		PRINTX	? DDPCUT initialization dispatch missing>
;DDPC2T - INITIALIZE FOR DECNET USER

IFN	FTDECN,<
DDPC2T:	SKIPE	DDPLBK(F)	;ALREADY HAVE LINE BLOCK?
	PJRST	CPOPJ1##	;YES, SKIP THIS
	SETZ	T3,		;START OFF WITH A CLEAN LINE ID
	MOVEI	T1,LD.DDP	;GET THE DEVICE TYPE
	STOR	T1,LIDEV,+T3	;SAVE IN LINE ID
	HRRZ	T1,DEVNET(F)	;NODE NUMBER OWNING THE DDP DEVICE
	STOR	T1,LIKON,+T3	;SAVE AS KONTROLLER NUMBER
	LDB	T1,PUNIT##	;GET THE DDP UNIT NUMBER AT SAID NODE
	STOR	T1,LIUNI,+T3	;SAVE AS THE UNIT NUMBER
	MOVEI	T1,DI.ICB	;OPEN THIS CIRCUIT
	PUSHJ	P,DDPDVR	;TELL DLL OF NEW KONTROLLER
	POPJ	P,		;GIVE ERROR RETURN
	MOVEM	T1,DDPLBK(F)	;REMEMBER THE DLL'S DATA BLOCK ADDRESS
	JRST	CPOPJ1##	;GIVE A GOOD RETURN
> ;END IFN FTDECN
;DDPCHA - HALT THE DDP KONTROLLER

DDPCHA:	TLNN	S,IOSDDK	;IS DDP IN KONTROLLER MODE?
	JRST	DDE%IM		;ILLEGAL OPERATING MODE
	JRST	DDE%IF		;*** ILLEGAL FUNCTION . . .



;DDPCIN - INITIALIZE DDP KONTROLLER

DDPCIN:	TLNN	S,IOSDDK	;IS DDP IN KONTROLLER MODE?
	JRST	DDE%IM		;NO, ERROR
	JRST	DDE%IF		;*** ILLEGAL FUNCTION . . .



;DDPCMA - SET DDP KONTROLLER TO MAINTENANCE MODE

DDPCMA:	TLNN	S,IOSDDK	;IS DDP IN KONTROLLER MODE?
	JRST	DDE%IM		;NO, ERROR
	JRST	DDE%IF		;*** ILLEGAL FUNCTION . . .
SUBTTL	NETSER INTERFACE

	IFIW	DDPNND		;(-5) NODE WENT DOWN
	IFIW	DDPNRL		;(-4) DISCONNECT ("RELEASE") INIT RECEIVED
	IFIW	NTDCNC##	;(-3) STANDARD CONNECT CONFIRM PROCESSOR
	IFIW	NTDSTP##	;(-2) ERROR - WE DON'T POST DDBS
	IFIW	DDPNIQ		;(-1) DATA REQUEST PROCESSOR
DDPNDP::IFIW	DDPNIL		;(00) INCOMING NCL TO PROCESS
	IFIW	CPOPJ##		;(01) SHOULD NEVER RECEIVE DATA SANS EOR
	IFIW	DDPNIN		;(02) RECEIVE DATA WITH EOR
	IFIW	DDPNST		;(03) DEVICE STATUS
	IFIW	DDPNCT		;(04) DEVICE CONTROL
	IFIW	CPOPJ##		;(05) UID (?)
	IFIW	CPOPJ##		;(06) FILE SPECIFICATION (?)
SUBTTL	NETSER INTERFACE - INCOMING NCL PROCESSORS

;HERE FOR CONNECT INITIATE

NDDPCI::PUSH	P,U		;PROTECT THE INPUT PCB
	PUSHJ	P,DPCIDD	;ALLOCATE US A NETWORK DDP DEVICE DDB
	 JRST	DPCIE3		;NO FREE CORE FOR EVEN A DDB??? JEEEZZ
	HRRZ	T1,F		;ADDRESS OF NEWLY-ACQUIRED DDB
	MOVEI	T2,LAT.OK	;INITIAL LAT STATE
	PUSHJ	P,GETSLA##	;GET A LAT SLOT FOR THE DDB
	 JRST	DPCIE2		;NO FREE LAT SLOTS, BOMB THE CONNECT INIT
	DPB	T1,NETSLA##	;REMEMBER THE LAT SLOT
	HLRZ	T1,P3		;GET THE REMOTE'S "LAT" SLOT
	DPB	T1,NETDLA##	;AND REMEMBER THAT TOO

;DPN(,PID)

	PUSHJ	P,XSKIP##	;SKIP THE REMOTE'S REQUEST

;SPN(OBJ,)

	PUSHJ	P,EBI2BI##	;GET REMOTE'S OBJECT TYPE
	CAIE	T1,OBJ.DP	;MAKE SURE IT IS CONSISTENT
	JRST	DPCIE4		;WHOA! WHAT NONSENSE IS THIS?

;SPN(,PID)

	PUSHJ	P,EBI2BI##	;GET REMOTE "UNIT" NUMBER
	CAIL	T1,0		;CAN'T BE NEGATIVE (TEXT???)
	CAILE	T1,77		;AND CAN'T EXCEED DDH7
	JRST	DPCIE4		;MORE NONSENSE
	DPB	T1,PUNIT##	;STORE DEVICE UNIT NUMBER
	LSHC	T1,-3		;SEPARATE "CONTROLLER" AND "UNIT"
	LSH	T1,^D18-3	;PARTIALLY POSITION
	LSHC	T1,3		;MAKE XWD CONTROLLER,UNIT
	IOR	T1,['DDA  0']	;SIXBITDEVICEIFY THE VALUE
	IORM	T1,DEVNAM(F)	;MAKE FULL-FLEDGED DEVICE NAME
				;(MAKDDC LEFT THE NODE NUMBER FIELD SETUP)

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;PROCESS THE MML AND FEA FIELDS

	PUSHJ	P,NTDCNF##	;SLURP UP MML AND RLN
	 JFCL			;NOT USED

;WE LIKE THE DEVICE, ACCEPT THE CONNECT (SEND A CONNECT CONFIRM)

	MOVE	T1,[NTDXMN##,,NTDXPN##]  ;SPN AND DPN ROUTINES
	PUSHJ	P,NCSCNC##	;SEND CONNECT CONFIRM
	 JRST	DPCIE1		;AFTER ALL THAT WORK, CAN'T BUILD A MESSAGE!

;THE DEVICE IS NOW READY AND RARING TO GO. FOR LACK OF ANYTHING BETTER
;TO DO (AND BECAUSE IT WAS THE REASON FOR CREATING DDP'S IN THE FIRST
;PLACE) MAKE THE DDP INTO A DECNET KONTROLLER

	PUSHJ	P,DDPCKN	;MAKE A KONTROLLER OUT OF IT
	 STOPCD	.,STOP,DDPKON,	;++ CAN'T MAKE A KONTROLLER OUT OF DDP
	MOVEI	T2,DD.DEC	;USER: DECNET
	PUSHJ	P,DDPCU2	;ANNOUNCE NEW KONTROLLER TO DECNET
	 JRST	[PUSHJ	P,DDPCDV	;WELL! UNMAKE IT A KONTROLLER
		STOPCD .,STOP,DDPBAU,	;++ BEING AWFULLY UNCOOPERATIVE!
		JRST	UPOPJ1##]	;AND LEAVE DEVICE LYING AROUND

;ALL DONE

	JRST	UPOPJ1##	;SUCCESSFUL RETURN
;HELPER TO CREATE DDB (NETSER INTERRUPT LEVEL)

DPCIDD:	PUSHJ	P,SAVE4##	;PROTECT INPUT POINTER/ET AL
	PUSHJ	P,SAVJW##	;ALSO J AND W
	MOVE	P1,W		;POSITION NDB POINTER FOR MAKDDC
	SETZB	P2,J		;FRESH SLATE FOR THE NAME

;ENTRY FROM TSTDDP (UUO LEVEL)

MAKDDP:	SKIPN	W,NDTTAB##+OBJ.DP  ;POSITION NDT POINTER FOR MAKDDC
	STOPCD	.,STOP,DDPNDT,	;++ NO NDT ENTRY
	SETZ	P3,		;NO LOGICAL NAME (YET, ANYWAY)
	MOVEI	T2,DDPDLN	;LENGTH OF A DDP DDB
	PUSHJ	P,MAKDDC##	;MAKE GENERAL NETWORK DEVICE DDB
	 POPJ	P,		;NO CORE, ERROR RETURN
	MOVSI	T1,DEPRAS	;THE RESTRICTED-DEVICE FLAG
	IORM	T1,DEVSTA(F)	;REQUIRE PRIVILEGES TO PLAY WITH DDPS
	PUSHJ	P,LNKDDB##	;MAKE THE DDB "REAL"
	JRST	CPOPJ1##	;SUCCESS RETURN WITH NICE SHINY NEW DDB



;ERRORS FOR DDP CONNECT INIT

DPCIE1:	LDB	T1,NETSLA##	;GET LAT SLOT INDEX
	PUSHJ	P,GIVSLA##	;FREE UP THE LAT
DPCIE2:	PUSHJ	P,UNLDDB##	;FREE UP THE DDB
DPCIE3:	MOVEI	T1,RSN.XN	;REASON: NO RESOURCES
	JRST	UPOPJ##		;RESTORE U AND ERROR EXIT

DPCIE4:	LDB	T1,NETSLA##	;GET LAT SLOT INDEX
	PUSHJ	P,GIVSLA##	;FREE UP THE LAT
	PUSHJ	P,UNLDDB##	;FREE UP THE DDB
	MOVEI	T1,RSN.OT	;REASON: JUNK
	JRST	UPOPJ##		;RESTORE U AND ERROR EXIT
;HERE FOR DISCONNECT INITIATE

DDPNRL:	MOVE	S,DEVIOS(F)	;GET THE DDP I/O STATUS FLAGS
	TLNE	S,IOSDDK	;IN USE AS A KONTROLLER?
	PUSHJ	P,DDPKZP	;YES, ZAP THE KONTROLLER FIRST
	PJRST	NTDDSC##	;NOW ALLOW NETSER TO ZAP THE DEVICE/DDB



;HERE FOR NODE DOWN

DDPNND:	HRRZ	T1,DEVNET(F)	;GET OWNING NODE
	MOVE	S,DEVIOS(F)	;GET THE DDP I/O STATUS FLAGS
	TLNE	S,IOSDDK	;IN USE AS A KONTROLLER?
	PUSHJ	P,DDPKZP	;YES, ZAP THE KONTROLLER FIRST
	PJRST	NTDNWD##	;NOW ALLOW NETSER TO CLEAN UP THE DDB
;HERE FOR AN NCL DATA REQUEST RECEIVED (AT NETWORK INTERRUPT LEVEL)

DDPNIQ:	MOVE	S,DEVIOS(F)	;DEVICE STATUS FLAGS
	TLNE	S,IOSDDK	;IS DDP A DEVICE OR A KONTROLLER?
	PJRST	DDPKIQ		;A KONTROLLER, NUDGE OUTPUT, ETC.
	PJRST	NTDRDQ##	;A DEVICE, USE STANDARD NETSER ROUTINE



;HERE FOR AN NCL MESSAGE RECEIVED (AT NETWORK INTERRUPT LEVEL)

DDPNIL:	MOVE	S,DEVIOS(F)	;DEVICE STATUS FLAGS
	TLNE	S,IOSDDK	;IS DDP A DEVICE OR A KONTROLLER?
	PJRST	DDPKIL		;A KONTROLLER, IT RUNS AT INTERRUPT LEVEL
	PJRST	NTDQIP##	;A DEVICE, IT RUNS AT UUO LEVEL, SO TELL
				; NETSER TO "QUEUE" THE NCL TO BE PROCESSED
				; LATER AT USER/UUO LEVEL.
;HERE FOR INCOMING DATA (WITH EOR)

DDPNIN:	MOVE	S,DEVIOS(F)	;GET DEVIOUS BITS
	TLNE	S,IOSDDK	;IS DDP IN USE AS A KONTROLLER?
	PJRST	DDPKIN		;YES, INTERRUPT LEVEL BEHAVES DIFFERENTLY

;DDP IS NOT A KONTROLLER, THEREFORE DATA IS DESTINED FOR USER I/O BUFFER

	MOVEI	T4,^D08		;DDCMP DATA IS *ALWAYS* 8 BITS
	PUSHJ	P,NTDSIB##	;SETUP USER'S INPUT BUFFER POINTER/COUNTER
	 STOPCD	.,STOP,DDPSIB,	;++ NTDSIB FAILED AFTER NTDIBA SUCCEEDED
	DMOVE	T3,DEVAXI(F)	;GET BYTE POINTER AND COUNTER FOR SPEED
	JRST	DDPNI5		;ENTER DATA COPY LOOP

;LOOP COPYING DATA FROM NCL INTO USER BUFFER

DDPNI3:	ILDB	T1,P1		;NEXT NCL DATA BYTE
	SOJL	T4,DDPNI9	;COUNT DOWN ROOM LEFT, IOBKTL IF OVERFLOW
	EXCTUU	<IDPB T1,T3>	;STORE BYTE INTO USER'S BUFFER
DDPNI5:	SOJGE	P4,DDPNI3	;COPY ENTIRE NCL DATA MESSAGE
	DMOVEM	T3,DEVAXI(F)	;RESTORE BYTE COUNTER/POINTER FOR USER
	PJRST	NTDA1B##	;ADVANCE USER'S BUFFER, RETURN TO DDPUIN

;HERE IF NCL DATA OVERFLOWED USER'S BUFFER

DDPNI9:	PUSHJ	P,DDPBTL	;SET IOBKTL ERROR
	PJRST	NTDAIB##	;AND RETURN USER HIS STUFFED BUFFER
;HERE FOR STATUS MESSAGE

DDPNST:				;HERE ON RECEIPT OF DEVICE STATUS MESSAGE

;STC

	PUSHJ	P,EBI2BI##	;READ THE CODE (STATUS, SET, OR CLEAR)
	JUMPN	T1,CPOPJ##	;MUST BE BASIC STATUS

;STS

	PUSHJ	P,EBI2BI##	;READ IN STATUS BITS
	XOR	T1,DEVSTS(F)	;GET CHANGE FROM PREVIOUS STATUS
	XORM	T1,DEVSTS(F)	;AND UPDATE TO NEW STATUS
	HRL	T1,DEVSTS(F)	;CARRY CURRENT STATUS IN LH, DELTA IN RH
	TRNN	T1,-1		;ANYTHING OF CONSEQUENCE CHANGE?
	JRST	CPOPJ1##	;SUCCESSFUL RETURN

;SOMETHING HAPPENED TO THE DDP, TELL SOMEONE ABOUT IT, IF ANYONE CARES

	MOVE	S,DEVIOS(F)	;S PROBABLY TRASHED BY NOW
	TLNE	S,IOSDDK	;IS DDP IN USE AS A KONTROLLER?
	PJRST	DDPKST		;YES, PROCESS KONTROLLER STATUS CHANGE
				; (WE ARE AT INTERRUPT LEVEL)

;DDP IN USE AS AN I/O DEVICE, GIVE USER PSI/ETC.

	PUSHJ	P,NTDIAV##	;NUDGE LOW LEVEL ROUTINES
	JRST	CPOPJ1##	;SUCCESSFUL RETURN
;HERE FOR DEVICE CONTROL

DDPNCT:	POPJ	P,		;HO HUM.
SUBTTL	KONTROLLER SERVICE - VECTORED DRIVER INTERFACE

;REMEMBER, KONTROLLERS RUN AT INTERRUPT LEVEL, GOTTA BE CAREFUL NOT TO
;OFFEND ANYONE!

;DDPDSP  --  ENTRY INTO KONTROLLER LAYER FROM DRIVER LAYER
;CALL IS:
;
;	MOVX	T1,<FNC>
;	MOVX	T2,<DDP>
;	MOVX	T3,<ARG>
;	MOVX	T4,<USR>
;	PUSHJ	P,DDPDSP
;	 ERROR RETURN
;	NORMAL RETURN
;
;WHERE <FNC> IS THE KONTROLLER FUNCTION (DD.???) TO BE PERFORMED, SUCH
;AS START OR STOP THE DEVICE, ETC.; <DDP> IS THE DDP DATA BLOCK ADDRESS
;(I.E., THE DDB, THE SAME AS IN UUO-LEVEL PROCESSING). <ARG> IS ANY
;ARGUMENT APPROPRIATE TO THE PARTICULAR FUNCTION REQUESTED (E.G., BUFFER
;ADDRESS FOR OUTPUT DATA) AND <USR> IS THE "LINE USER" - ANF, DECNET,
;ETC.
;
;ON ERROR RETURN SOMETHING AWFUL HAPPENED, SUCH AS ILLEGAL USER.
;
;ON NORMAL RETURN THE REQUESTED FUNCTION HAS BEEN SUCCESSFULLY PERFORMED
;(WHICH IS NOT TO SAY IT CAN'T FAIL LATER - SUCH AS THE DDP GOING DOWN
;WHILE OUTPUT DATA IS STILL QUEUED).

DDPDSP::CAIL	T1,0		;RANGE-CHECK THE FUNCTION CODE
	CAILE	T1,DD.MAX	; TO MAKE SURE WE UNDERSTAND IT
	STOPCD	CPOPJ##,DEBUG,DDPFNC,	;++ ILLEGAL KONTROLLER FUNCTION CALL
	CAIE	T4,DD.DEC	;IS IT A LINE-ID FROM DECNET
	JRST	DDPDS1		;NO, DON'T CONVERT IT
	TLNN	T2,-1		;IS IT A LINE-ID
	JRST	DDPDS1		;NO, ITS A DDB USE IT
	PUSHJ	P,DDPSRC	;GET THE DDB
	POPJ	P,		;COULDN'T DO IT
DDPDS1:	CAME	T4,DDPUSR(T2)	;CALLED BY LEGIT USER?
	POPJ	P,		;NO, ERROR RETURN
	PUSH	P,F		;SAVE F
	PUSH	P,S		; AND S
	PUSH	P,U		;ALSO SAVE U
	PUSH	P,W		;AND DOUBLE-U
	MOVE	F,T2		;PUT DDB ADDRESS IN F
	MOVE	S,DEVIOS(F)	;LOAD S ON G.P.S
	TLNE	S,IOSDDK	;HAD BETTER BE IN KONTROLLER MODE!
	PUSHJ	P,@DDPDST(T1)	;DISPATCH BASED ON FUNCTION
	 TRNA			;HO HUM
	AOS	-4(P)		;PROPIGATE SKIP
	POP	P,W		;RANDOM ACS
	POP	P,U		;TRASHED BY NETSER
	POP	P,S		;RESTORE S
	POP	P,F		;AND F
	POPJ	P,		;RETURN TO DRIVER
DDPDST:	IFIW	DDPOPN		;0 = OPEN CIRCUIT (INITIALIZE PROTOCOL)
	IFIW	DDPCLS		;1 = CLOSE CIRCUIT (HALT PROTOCOL)
	IFIW	DDPQUE		;2 = QUEUE OUTPUT BUFFER
	IFIW	DDPPRB		;3 = POST RECEIVE BUFFER
	IFIW	CPOPJ##		;4 = CHECK FOR EXISTANCE
IFN <.-DDPDST-DD.MAX-1>,<PRINTX ? Table DDPDST is incorrect>
;KONTROLLER FUNCTION: OPEN CIRCUIT (INITIALIZE PROTOCOL)

DDPOPN:	SKIPE	DDPMBP(F)	;JUST CAUTIOUS
	STOPCD	.+1,DEBUG,DDPRBA, ;++ RECIEVE BUFFER ALLREADY ALLOCATED
	SETZM	DDPMBP(F)	;CLEAR IT (OR STOPCD LATER)
	TLNN	S,IOSDDH	;WERE WE HALTED BEFORE?
	JRST	DDPOP2		;NO, SEE IF DDCMP IS RUNNING
	MOVSI	S,IOSDDH	;THE "HALTED BY REQUEST" BIT
	ANDCAB	S,DEVIOS(F)	;TURN THE DDP BACK ON
DDPOP2:	TLNE	S,IOSDDD	;WAS THE DDCMP PROTOCOL RUNNING?
	PUSHJ	P,DDPKUP	;DDCMP IS NOW RUNNING
	HRRZ	T1,F		;RETURN DDB ADDRESS TO USER
	JRST	CPOPJ1##	;SUCCESSFUL (I HOPE)



;KONTROLLER FUNCTION: CLOSE CIRCUIT (HALT PROTOCOL)

DDPCLS:	TLNE	S,IOSDDH	;ALREADY HALTED?
	JRST	DDPCL1		;YES
	MOVSI	S,IOSDDH	;THE "HALTED BY REQUEST" BIT
	IORB	S,DEVIOS(F)	;STOP FURTHER USAGE
	TLNN	S,IOSDDD	;WAS THE PROTOCOL UP BEFORE?
	PUSHJ	P,DDPKDN	;YES, TAKE IT DOWN FORCIBLY
				; IOSDDH WILL HOLD IT DOWN EVEN THOUGH
				; DDCMP IS REALLY STILL RUNNING
DDPCL1:	MOVE	T1,DDPMBP(F)	;GET ANY MESSAGE POINTER
	SETZM	DDPMBP(F)	;CLEAR KNOWLEDGE
	JRST	CPOPJ1##	;SUCCESSFUL (MORE OR LESS)


;KONTROLLER FUNCTION: QUEUE OUTPUT DATA

DDPQUE:	TLNN	S,IOSDDD	;MAKE SURE THE PROTOCOL IS "UP"
	SKIPN	DDPUSR(F)	; AND IS IN USE BY SOMEBODY
	POPJ	P,		;IT ISN'T, DON'T QUEUE IT
	SETZM	MB.NXT(T3)	;CLEAR GARBAGE IN MESSAGE BLOCK
				; (I PERSONALLY THINK THIS, AH, IS JUNK!
				;  HOWEVER, THAT'S THE WAY IT IS)
	XMOVEI	T1,DDPQOB-MB.NXT(F)  ;PRIME THE PUMP, SO TO SPEAK
	SETZ	T4,		;*** FOR KICKS
	NETOFF			;TIME TO PLAY WITH THE OUTPUT QUEUE

DDPDM3:	MOVE	T2,T1		;SAVE CURRENT MESSAGE
	SKIPE	T1,MB.NXT(T2)	;STEP TO NEXT MESSAGE
	AOJA	T4,DDPDM3	;*** FOR KICKS
	MOVEM	T3,MB.NXT(T2)	;STASH THIS MESSAGE AT THE TAIL OF THE QUEUE
	NETON			;ALLOW INTS AGAIN
	AOS	(P)		;WHATEVER ELSE HAPPENS, THIS FUNCTION WORKED
	PJRST	DDPKOU		;NOW TRY TO OUTPUT WHAT WE CAN
;KONTROLLER FUNCTION: POST RECEIVE BUFFER

DDPPRB:	TLNN	S,IOSDDD	;MAKE SURE THE PROTOCOL IS "UP"
	SKIPN	DDPUSR(F)	; AND IS IN USE BY SOMEBODY
	POPJ	P,		;NO, REFUSE RECEIVE BUFFER
	SKIPE	DDPMBP(F)	;ALREADY HAVE RECEIVE BUFFER POINTER?
	STOPCD	CPOPJ##,DEBUG,DDPAHB ;++ALREADY HAVE RECEIVE BUFFER
	MOVEM	T3,DDPMBP(F)	;SAVE RECEIVE BUFFER ADDRESS
	PJRST	CPOPJ1##	;AND RETURN
;CONTINUED FROM PREVIOUS PAGE

;TRY TO PROCESS ANY QUEUED DATA AWAITING TRANSMISSION

DDPKOU:	SKIPN	DDPQOB(F)	;ANY DATA QUEUED FOR OUTPUT?
	POPJ	P,		;NO, NOTHING TO DO

;TIS NOW TIME TO ARRANGE NETSER'S INTERLOCK. WISH ME LUCK.

	SKIPL	NTLOCK##	;IS NETSER INTERLOCK TAKEN?
	JRST	[PUSHJ	P,NTCHCK##	;YES, CHECK NETSER INTERLOCK
		  POPJ	P,		;IT'S OWNED BY SOMEONE ELSE, PUNT
		PJRST	DDPKO1]		;WE ALREADY OWN IT, ALL SET

	PUSHJ	P,INTLVL##	;ARE WE AT INTERRUPT LEVEL?
	 JRST	[NETDBL			;GET NETSER INTERLOCK AT UUO LEVEL
		PUSHJ	P,DDPKO1	;DO IT
		NETDBU			;FREE NETSER INTERLOCK
		POPJ	P,]		;ALL DONE
	NTDBLI			;GET NETSER INTERLOCK AT INTERRUPT LEVEL
	 POPJ	P,		;CAN'T DO IT NOW
	PUSHJ	P,DDPKO1	;DO IT
	NTDBUI			;FREE NETSER INTERLOCK
	POPJ	P,		;ALL DONE
;NOW SETUP NDB POINTER FOR NETSER.

DDPKO0:	SE1ENT			;HERE FROM NETSER, GET TO SECTION 1
DDPKO1:	PUSHJ	P,SAVE4##	;NETSER TRASHES THE P'S
	HRRZ	T1,DEVNET(F)	;GET THE NODE NUMBER
	PUSHJ	P,SRCNDB##	;FIND THE DDP'S NDB
	 STOPCD	.,STOP,DDPFIX,	;++ THIS NEEDS TO BE FIXED

;LOOP BUILDING NCL OUTPUT MESSAGES FOR NETSER

DDPKO2:	NETOFF			;TIME TO DIDDLE THE QUEUE
	SKIPE	P1,DDPQOB(F)	;GET ADDRESS OF NEXT OUTPUT MESSAGE
	PUSHJ	P,NTDCDQ##	;GOT OUTPUT PENDING, ANY DATA REQUESTS FOR IT?
	 JRST	DDPKP2		;OOPS - NO MORE LEFT, PUNT
	MOVE	T1,MB.NXT(P1)	;NEXT QUEUED DATA MESSAGE
	MOVEM	T1,DDPQOB(F)	;BECOMES NEW FIRST QUEUED MESSAGE
	NETON			;SAFE AGAIN

;START UP A NETSER DATA MESSAGE

	SKIPN	T2,MB.FMS(P1)	;ADDRESS OF FIRST MESSAGE SEGMENT DESCRIPTOR
	STOPCD	.,STOP,DDPBBM,	;++ BUTTS BAD MESSAGE
	SKIPA	T1,MD.BYT(T2)	;START WITH FIRST BYTE COUNT
	ADD	T1,MD.BYT(T2)	;ACCUMULATE TOTAL MESSAGE BYTE COUNT
	SKIPE	T2,MD.NXT(T2)	;ADVANCE TO NEXT SEGMENT
	JRST	.-2		;WALK THE ENTIRE CHAIN
	PUSH	P,T1		;SAVE DATA BYTE COUNT
	ADDI	T1,17		;ALLOW FOR NCL HEADER (AND ROUND UP)
	LSH	T1,-2		;CONVERT TO WORD ALLOCATION

;THIS WOULD BE A CLEVER PLACE TO TRY TO PIGGYBACK OUTGOING DATA REQUESTS
;WITH RELATIVELY NON-HUGE OUTGOING DATA MESSAGES

	S0PSHJ	NTDHDR##	;FIRE UP NCL DATA MESSAGE
	 JRST	DDPKPU		;NO NETSER FREE CORE, PUNT FOR NOW
	MOVE	T1,0(P)		;RETRIEVE THE DATA BYTE COUNT
	ADDI	T1,1		;ALLOW FOR "TYP" NCL FIELD
	PUSHJ	P,BI2EBI##	;OUTPUT "CNT" (COUNT OF DATA) FIELD
	MOVEI	T1,DC.DAR	;DATA WITH END OF RECORD
	PUSHJ	P,DPBBIN##	;OUTPUT "TYP" FIELD
	ADDM	P3,PCBCTR(U)	;ACCOUNT FOR ADDITIONAL NCL BYTES

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;LOOP COPYING DATA FROM MESSAGE BLOCK INTO PCB

	MOVEM	P1,0(P)		;SAVE ORIGINAL MESSAGE BLOCK ADDRESS
	MOVE	P1,MB.FMS(P1)	;ADDRESS OF FIRST MESSAGE SEGMENT DESCRIPTOR
	PUSH	P,T5		;SAVE PROTECTED TEMPORARY
	PUSH	P,T6		;AND THE OTHER ONE TOO

;AT THIS POINT, P1 IS THE FIRST LINK OF A CHAIN OF "MESSAGE SEGMENT DESCRIPTOR"
;BLOCKS (ANY ONE OF WHICH CAN BE "NULL") CONTAINING THE DATA TO BE SENT. THE
;MD.AUX WORD IDENTIFIES THE FIRST BYTE WITHIN THE FIRST WORD CONTAINING VALID
;DATA, AND THE MD.ALA WORD IDENTIFIES THE FIRST WORD. WE CONSTRUCT OUR OWN
;BYTE POINTER SINCE THE DRIVER MAY HAVE INDEXED MD.AUX WITH SOME BIZARRE
;REGISTER.

DDPKO4:	SKIPG	T1,MD.BYT(P1)	;COUNT OF BYTES IN THIS SEGMENT
	JRST	DDPKO6		;NULL SEGMENT, PITCH AND ADVANCE TO NEXT ONE
	HLLZ	T2,MD.AUX(P1)	;GET FIRST-WORD BYTE POSITION
	TLZ	T2,77		;ENSURE ONE-WORD LOCAL SANS @(XX)
	TLO	T2,T3		;GLOBALLY INDEX TO DATA
	SKIPN	T3,MD.ALA(P1)	;ADDRESS OF DATA
	STOPCD	.,STOP,DDPNDA,	;++ NO ALLOCATED DATA ADDRESS
	MOVE	T4,T1		;SET "DESTINATION" BYTE COUNT = "SOURCE"
	ADDM	T4,PCBCTR(U)	;UPDATE PCB'S BYTE COUNT
	MOVE	T5,P2		;SETUP "DESTINATION" BYTE POINTER
	TLO	T5,T6		;GLOBALLY INDEX TO DATA
	MOVSI	T6,(MCSEC1)	;WHICH IS IN SECTION 0/1
				;*** USING A GLOBAL INDEX IS REQUIRED DUE TO
				;*** A UCODE BUG WHEREIN THE EXTEND/MOVSLJ
				;*** GETS CONFUSED OVER WHICH SECTION TO USE
				;*** AS THE DEFAULT SECTION, LEADING TO AN
				;*** IME (IF YOU'RE LUCKY)
	EXTEND	T1,[MOVSLJ]	;COPY DRIVER DATA INTO PCB
	STOPCD	.,STOP,DDPSLJ,	;++ COULDN'T MOVE THE SLUDGE
	TLZ	T5,77
	MOVEM	T5,P2		;UPDATE NETSER'S COPY OF THE BYTE POINTER

DDPKO6:	SKIPE	P1,MD.NXT(P1)	;GET ADDRESS OF NEXT MESSAGE SEGMENT
	JRST	DDPKO4		;COPY NEXT SEGMENT OF DATA INTO ANF PCB
	POP	P,T6		;RESTORE FUNNY T-REG
	POP	P,T5		;AND THE OTHER ONE TOO
	MOVEI	T1,PCV.NC	;"NO COMPRESSION"
	S0PSHJ	NTDWRT##	;GIVE THIS BUFFER TO NETSER TO TRANSMIT
	PUSHJ	P,NTDDDQ##	;COUNT DOWN AVAILABLE DATA REQUESTS
	POP	P,T3		;ADDRESS OF USED-UP MESSAGE BLOCK
	MOVEI	T1,DI.ODN	;"OUTPUT DONE" INTERRUPT
	PUSHJ	P,DDPDV1	;CALL OUR DRIVER
	JFCL			;HO HUM
	JRST	DDPKO2		;CHECK FOR MORE OUTPUT
;HERE WHEN NETSER IS OUT OF MEMORY - TRY TO REQUEUE THE MESSAGE BLOCK

DDPKPU:	POP	P,T1		;PITCH THE UNUSEABLE BYTE COUNT
	NETOFF			;BACK TO DIDDLING THE QUEUE
	MOVE	T1,MB.NXT(P1)	;MB THAT WE LEFT AS THE NEXT IN THE QUEUE
	CAME	T1,DDPQOB(F)	;STILL THERE?
	JUMPN	T1,DDPKP5	;QUEUE HAS CHANGED (UNLESS NEW ENTRY APPEARED)
	MOVE	T1,DDPQOB(F)	;GET PENDING HEAD OF QUEUE
	MOVEM	T1,MB.NXT(P1)	;PRE-PEND THE DE-QUEUED MESSAGE BLOCK
				; (THIS IS NEEDED FOR THE CASE WHERE
				;  THE DE-QUEUED MB WAS THE ONLY ENTRY IN
				;  THE QUEUE, THEN A NEW ENTRY WAS ADDED
				;  AFTER THIS ONE GOT DE-QUEUED)
	MOVEM	P1,DDPQOB(F)	;RE-QUEUE THE DE-QUEUED MESSAGE BLOCK
DDPKP2:	NETON			;SAFE AGAIN
	PJRST	DDPKK7		;TRY TO OUTPUT DATA REQUESTS (IF NEEDED)

;HERE WHEN WE CAN'T RE-QUEUE THE MESSAGE 'CUZ THE QUEUE CHANGED. PROBABLY
;KONTROLLER GOT HALTED OR SOMETHING LIKE THAT. PITCH THE MESSAGE AND LET
;THE DRIVER WORRY ABOUT IT. THIS SHOULD NOT HAPPEN OFTEN.

DDPKP5:	NETON			;HO HUM
	MOVE	T3,P1		;ADDRESS OF MESSAGE BLOCK
DDPKP7:	MOVEI	T1,DI.ODN	;FUNCTION: LIE AND SAY "OUTPUT DONE"
	PUSHJ	P,DDPDV1	;TELL DRIVER OUR WOES
	JFCL			;IGNORE ERROR
	POPJ	P,
;HERE WHEN RECEIVE DATA REQUESTS FROM REMOTE
;
;ENTERED WITH NETSER INTERLOCK . . .

DDPKIQ:	PUSHJ	P,NTDRDQ##	;ACCUMULATE DATA REQUESTS FOR OUTPUT
	 STOPCD	.,STOP,DDPRDQ,	;++ NTDRDQ FAILED
	PUSHJ	P,DDPKKO	;KICK THE OUTPUT STUFF
	JRST	CPOPJ1##	;SKIP RETURN (FOR NCTDSP)



;HERE WHEN WE'VE RECEIVED AN NCL MESSAGE FOR THIS DDP, MAY BE DATA, STATUS,
;ETC. LET NETSER DO THE BRUNT OF THE PARSING AND DISPATCHING (BACK TO DDPSER
;VIA NDEVDP DISPATCH - AND NO, THIS IS NOT RECURSIVE, EVEN THOUGH WE GOT
;HERE VIA SAID NDEVDP DISPATCH).
;
;ENTERED WITH NETSER INTERLOCK . . .

;***	AT THIS POINT, WE REALLY SHOULD CHECK FOR ANY DATA LEFT OVER FROM
;***	"UUO" DAYS (READ, "DEVPCB") SINCE IT IS POSSIBLE THAT BETWEEN THE
;***	CREATION OF THE DDP AS A DEVICE (DDB) AND THE SWITCHING OF THE
;***	DDP INTO KONTROLLER MODE ONE OR MORE DATA MESSAGES IN THE PIPE
;***	ARRIVED AND GOT QUEUED FOR "IN" UUOS . . .

DDPKIL:	PUSHJ	P,NTDILD##	;GO PROCESS NCL INPUT
;	PJRST	DDPKKO		;GO KICK THE OUTPUT ROUTINES
;CHECK FOR OUTPUTTABILITY

DDPKKO:	PUSHJ	P,SAVJW		;SAVE REGISTERS J AND W
	PUSHJ	P,SAVE4##	;SAVE REGISTERS P1 - P4
	PUSH	P,U		;FINALLY SAVE THE INPUT'S PCB ADDRESS
	SETZ	U,		;TAKE NO CHANCES
	PUSHJ	P,DDPKK0	;DO IT!
	POP	P,U		;RESTORE INPUT'S PCB ADDRESS
	POPJ	P,		;AND LOTS OF REGISTERS TOO!


;SEE IF THERE IS ANY QUEUED OUTPUT WE CAN SHIP TO THE REMOTE

DDPKK0:	NTDBUG	YES, EITHER	;MUST HAVE NETSER INTERLOCK HERE!
	PUSHJ	P,DDPKO0	;TRY TO FORCE OUT ANY PENDING OUTPUT

;TRY TO OUTPUT ANY DATA REQUESTS

DDPKK7:	HRLOI	T1,6		;AIM AT 6 OUTSTANDING DATA REQUESTS
	SUB	T1,DEVDRQ(F)	;LH(T1) IS SHORT-COUNT
	HLRZ	T1,T1		;T1 IS COUNT OF DATAREQUESTS NEEDED
	CAIGE	T1,2		;WAIT FOR AT LEAST 2
	POPJ	P,		;DON'T BOTHER WITH JUST 1
	PUSH	P,T1		;SAVE DATA REQUEST INCREMENT
	S0PSHJ	NCSDRQ##	;SEND DATA REQUEST(S)
	  JRST	TPOPJ##		;NO CORE, TRY LATER
	POP	P,T1		;DATA REQUESTS SENT
	HRLZ	T1,T1		;POSITION IN LH
	ADDM	T1,DEVDRQ(F)	;AND ACCOUNT FOR OUTSTANDING DATA REQUESTS
	POPJ	P,		;ALL DONE
;HERE FOR DATA INPUT (VIA DDPKIL), PASS TO THE DRIVER (OR "TRANSPORT") LAYER

DDPKIN:	SE1ENT			;NEED TO RUN IN EXTENDED ADDRESS SPACE
	TLNN	S,IOSDDH	;IS THE PROTOCOL "RUNNING"
	SKIPN	DDPUSR(F)	;YES, AND DO WE HAVE SOMEBODY TO RECEIVE DATA?
	JRST	DDPKI9		;NO, JUST EAT INCOMING DATA

;GET A BUFFER FROM OUR DRIVER INTO WHICH TO COPY DATA

	SKIPN	T3,DDPMBP(F)	;DO WE HAVE A RECEIVE MESSAGE BUFFER
	JRST	DDPKI9		;NO, PITCH DATA, MUST BE SHUTTING DOWN
	SETZM	DDPMBP(F)	;CLEAR PREVIOUS MESSAGE BUFFER POINTER
	PUSH	P,T5		;SAVE EXTEND TEMPS
	PUSH	P,T6		;THE OTHER ONE

;COPY DATA INTO MESSAGE BLOCK

	MOVE	P2,T3		;ADDRESS OF MESSAGE BLOCK
	MOVE	P3,MB.FMS(P2)	;POINTER TO FIRST (AND ONLY) MESSAGE SEGMENT
	MOVEM	P4,T1		;SET "SOURCE" BYTE COUNT
	MOVEM	P4,MD.BYT(P3)	;ALSO TELL THE DRIVER
	MOVE	T2,P1		;"SOURCE" BYTE POINTER
	TLO	T2,T3		;GLOBALLY INDEX TO DATA
	MOVSI	T3,(MCSEC1)	;WHICH IS IN SECTION 0/1
				;*** UCODE BUG, SEE DDPKO4
	HRRZ	T4,MD.ALL(P3)	;GET MAXIMUM MESSAGE SIZE
	CAMLE	P4,T4		;WILL IT FIT?
	STOPCD	.,STOP,DDPMTB	;++ DDP MESSAGE IS TOO BIG
	MOVEM	P4,T4		;SET "DESTINATION" BYTE COUNT
	MOVSI	T5,(POINT 8,(T6))  ;"DESTINATION" BYTE POINTER (PROTOTYPE)
	SKIPN	T6,MD.ALA(P3)	;ADDRESS OF "DESTINATION" DATA SEGMENT
	STOPCD	.,STOP,DDPALA,	;++ DESTINATION ALLOCATED ADDRESS IS ZERO
	EXTEND	T1,[MOVSLJ]	;BLT THE BYTES INTO THE DRIVER BUFFER
	STOPCD	.,STOP,DDPBCD,	;++ BYTE COPY DIDN'T
	TLZ	T2,77
	MOVEM	T2,P1		;UPDATE NETSER'S BYTE POINTER
	SETZ	P4,		;AND SUBMESSAGE BYTE COUNTER
	POP	P,T6		;DONE WITH EXTEND INSTRUCTION
	POP	P,T5		;THE OTHER ONE

;GIVE THE DATA TO OUR DRIVER

	MOVE	T3,P2		;POSITION MESSAGE BLOCK ADDRESS
	MOVEI	T1,DI.INC	;FUNCTION "INPUT COMPLETE"
	PUSHJ	P,DDPDV1	;GIVE DATA TO OUR DRIVER
	JFCL			;IGNORE ERROR
	JRST	CPOPJ1##	;SUCCESSFUL RETURN TO NETSER


;HERE TO EAT THE NCL INPUT DATA

DDPKI9:	ADJBP	P4,P1		;SKIP PAST THIS NCL SUB-MESSAGE
	MOVEM	P4,P1		;PUT INCREMENTED POINTER BACK IN P1
	SETZ	P4,		;PUT DECREMENTED COUNTER BACK IN P4
	JRST	CPOPJ1##	;AND TAKE THE SUCCESSFUL RETURN
;HERE FOR STATUS CHANGE, PASS PROTOCOL UP/DOWN/ETC TO THE DRIVER

DDPKST:	SE1ENT			;THIS NEEDS TO BE IN SECTION 1
	PUSH	P,T1		;SAVE A COPY OF THE STATUS

;BASICALLY, THE SDP.AV STATUS IS IGNORED (IF SDP.AV CLEARS, IT WILL DRAG
;SDP.RN WITH IT), ONLY SDP.RN IS CHECKED TO SEE IF THE DDP IS "VIABLE"

	TRNN	T1,SDP.RN	;DID PROTOCOL GO UP/DOWN?
	JRST	TPOPJ##		;NO, (Should check for errors)
	XMOVEI	T3,DDPKUP	;YES, ASSUME IT WENT UP
	TLNN	T1,SDP.RN	;IS DDCMP PROTOCOL NOW RUNNING?
	XMOVEI	T3,DDPKDN	;NO, THEN THE PROTOCOL WENT DOWN
	TLNN	S,IOSDDH	;IGNORE IF HALTED BY DRIVER
	PUSHJ	P,0(T3)		;HANDLE PROTOCOL STATUS CHANGE
	JRST	TPOPJ##		;RESTORE STATUS THEN RETURN
;PROCESS DDP PROTOCOL UP CONDITION

DDPKUP:	MOVSI	S,IOSDDD	;THE "PROTOCOL DOWN" FLAG
	ANDCAB	S,DEVIOS(F)	;PROTOCOL IS NOT DOWN

	MOVEI	T1,DI.LSC	;LINE STATE CHANGE
	MOVEI	T3,LS.ON	;PROTOCOL IS UP
	PUSHJ	P,DDPDV1	;TELL OUR DRIVER THE GOOD NEWS
	 TRN			;HO HUM
	POPJ	P,
;PROCESS DDP PROTOCOL DOWN CONDITION

DDPKDN:	MOVSI	S,IOSDDD	;THE "PROTOCOL DOWN" FLAG
	IORB	S,DEVIOS(F)	;FLAG THE EVENT

;CLEAN UP STALE OUTPUT AND DECLARE THE KONTROLLER "PROTOCOL DOWN"

DDPKD3:	NETOFF			;NO INTERRUPTS WHILST DIDDLING QUEUES
	SKIPN	T3,DDPQOB(F)	;GET START OF OUTPUT QUEUE
	JRST	DDPKD7		;NONE, ALL CLEAR
	MOVE	T1,MD.NXT(T3)	;GET ADDRESS OF NEXT MESSAGE IN THE QUEUE
	MOVEM	T1,DDPQOB(F)	;DELINK THE FIRST MESSAGE
	NETON			;SAFE AGAIN
	MOVEI	T1,DI.ODN	;LIE AND SAY OUTPUT DONE
	PUSHJ	P,DDPDV1	;TELL DRIVER THE BAD NEWS
	JFCL			;IGNORE ERRORS
	JRST	DDPKD3		;FREE THE REST OF THE OUTPUT QUEUE

DDPKD7:	NETON			;SAFE AGAIN
	MOVEI	T1,DI.LSC	;LINE STATE CHANGE
	MOVEI	T3,LS.OFF	;PROTOCOL IS DOWN
	PUSHJ	P,DDPDV1	;TELL THE DRIVER WE ARE NOW "HALTED"
	JFCL
	POPJ	P,
;ZAP (DESTROY) A DDP KONTROLLER

DDPKZP:	SE1ENT			;NEED SECTION 1 . . .
	PUSHJ	P,DDPKDN	;FIRST SHUT DOWN THE DDP PROTOCOL/DRIVER
	MOVSI	S,IOSDDK!IOSDDD	;VARIOUS KONTROLLER FLAGS
	ANDCAB	S,DEVIOS(F)	;DDP IS NO LONGER A KONTROLLER!
	SETZM	DDPUSR(F)	; . . .
	SETZM	DDPLBK(F)	; . . .
	POPJ	P,		;AND THAT IS THE END OF THAT
SUBTTL	SUBSIDIARY ROUTINES

;DDPDVR	ROUTINE TO CALL THIS LINE'S DRIVER
;CALL:
;
;	MOVX	T1,<FNC>
;	MOVX	T3,<ARG>
;	PUSHJ	P,DDPDVR
;	RETURN
;
;WHERE <FNC> IS THE DRIVER FUNCTION (DI.???) TO PERFORM; AND <ARG> IS
;ANY ARGUMENT AS NEEDED BY THE DRIVER.
;
;F MUST BE POINTING TO THE DDP DDB
;
;DDPDVR WILL DISPATCH INTO THE APPROPRIATE DRIVER BASED ON THE LINE
;USER IN DDPUSR, WITH T2 CONTAINING THE APPROPRIATE DATA BLOCK ADDRESS

DEFINE	X(TYP,CON,DAT,ADR),<
	IFN	.-DDPDX0-<2*DD.'TYP>,<
		PRINTX	? DDPDVR vector dispatch phase error for TYP user>
	IFE	CON,<
		PUSHJ	P,NTDSTP##	;;DIE IF NO DRIVER SUPPORTED
		HALT	.>		;;FILLER FOR TWO-WORD VECTOR
	IFN	CON,<
		MOVE	T2,DAT(F)	;;GET "DRIVER" DATA BLOCK ADDRESS
		PJRST	ADR>		;;AND GO TO APPROPRIATE DRIVER
> ;END DEFINE X

DDPDVR:	SE1ENT			;RUN IN EXTENDED ADDRESS SPACE
DDPDV1:
	XMOVEI	T2,.		;*** JUST CHECKING
	TLNN	T2,1		;*** TO MAKE SURE
	STOPCD	.,STOP,DDPSE0,	;++ NOT IN SECTION 1
	PUSHJ	P,SAVR##	;DECnet USES R AS A TRASH AC.
	HRRZ	T2,DDPUSR(F)	;GET THE USER CODE
	CAILE	T2,DD.MAX	; AND RANGE CHECK IT
	STOPCD	.,STOP,DDPIDV,	;++ ILLEGAL DRIVER NUMBER
	LSH	T2,1		;TRANSLATE INTO TWO-WORD BLOCK OFFSET
	PJRST	.+1(T2)		;DISPATCH BASED ON "USER" TYPE

DDPDX0:	X	(NOBODY,1,0,CPOPJ1##)	;ALWAYS SAY GOODNESS FOR "NOBODY"
DDPDX1:	X	(ANF10,FTNET,0,DDPDXE)
DDPDX2:	X	(DECNET,FTDECN,DDPLBK,DDIPPI##)
DDPDX3:	X	(PROGRAM,1,0,DDPDXE)
DDPDX4:	X	(IBMCOMM,FTDN60,0,DDPDXE)
	IFN	.-DDPDX0-<2*<DD.MAX+1>>,<
		PRINTX	? DDPDVR vector dispatch entry missing>
DDPDXE:	STOPCD	CPOPJ##,DEBUG,DDPIOT ;++ UNUSED DISPATCH (Illegal Owner Type)
	XLIST			;THE LITERALS
	LIT
	LIST

	PRGEND
TITLE	NETLPT - NETWORK LINE PRINTER ROUTINES - V001
SUBTTL	NETLPT -- WEM/	18 OCT 83
	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1977, 1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;XP VNETLP,001		;PUT VERSION NUMBER IN GLOB AND LOADER MAP
NETLPT::ENTRY	NETLPT
SUBTTL 1.0      LPT SPECIFIC SYMBOL DEFINITIONS

;BITS IN LPT IOS STATUS REGISTER

LPTNFF==100			;SUPPRESSS FORM FEED AT START/END
LPTSVF==2000			;SUPPRESS VFU CONTROL ("GRAPHICS DATA")


SUBTTL 2.0      INTERFACE TO UUOCON.  (DEVSER DISPATCH VECTOR)

	JRST	NTDONL##	;(-5) CHECK IF DEVICE IS ON LINE
	JRST	CPOPJ##		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) BUFFER SIZE
	JRST	CPOPJ##		;(-2) INITIALIZATION
	JRST	CPOPJ1##	;(-1) HUNG DEVICE (IGNORE. REMOTE WORRYS)
NDEVLP::JRST	NTDREL##	;RELEASE
	JRST	L.CLO		;CLOSE OUTPUT
	JRST	L.OUT		;OUTPUT
	JRST	NTDILI##	;ILLEGAL INPUT (RETURN INTERLOCK)
SUBTTL 2.1        OUT UUO.

L.OUT:				;HERE FROM UUOCON TO OUTPUT A BUFFER
	PUSHJ	P,SAVE3##	;WE USE P1, NETSER USES P2, P3 FOR PCB'S
	MOVSI	S,IOSUSO	;CLEAR THE "UUOCON STOPED OUTPUT"
	ANDCAB	S,DEVIOS(F)	;  SINCE IT JUST TRIED TO START IT AGAIN

L.LOOP:	PUSHJ	P,NTDSET##	;SET UP W, S AND CHECK IOSCON
	MOVSI	S,IO		;GET AND SET 'OUTPUT"
	IORB	S,DEVIOS(F)	; JUST TO KEEP WSYNC HAPPY.
	PUSHJ	P,NTDONL##	;CHECK IOSERR TO SEE IF STILL ONLINE
	  JRST	L.HUNG		;IF LPT IS OFFLINE, GO PLAY DEAD.
	TLNE	S,IOBEG		;IS THIS THE FIRST OUT??
	JRST	L.FRST		; IF SO, GO DO SPECIAL CODE.

;ENSURE THAT THE REMOTE LPT IS SETUP ACCORDING TO DESIRED OPERATION
;(E.G., NORMAL 7-BIT COMPRESSED, LN01 EIGHT-BIT GRAPHICS, ETC.)
;
;*** REALLY SHOULD TRY TO PIGGYBACK THE POTENTIAL STATUS MESSAGES BELOW

L.LOO0:	MOVEI	T1,SLP.SV	;THE "GRAPHICS" OUTPUT (SUPPRESS VFU) FLAG
	TRNN	S,LPTSVF	;USER WANT VFU SUPPRESSION (E.G., GRAPHICS)?
	JRST	L.LOO1		;NO, MAKE SURE IT IS CLEAR
	TDNE	T1,DEVSTS(F)	;YES, IS IT ALREADY SET?
	JRST	L.LOO2		;OK
	IORM	T1,DEVSTS(F)	;WE WILL/HAVE SET IT
	PUSHJ	P,NTDSST##	;SEND STATUS TO REMOTE TO SET IT
	JRST	L.LOO2		;GRAPHICS/VFU ALL SET

L.LOO1:	TDNN	T1,DEVSTS(F)	;IS SUPPRESSION SET?
	JRST	L.LOO2		;NO, OK
	ANDCAM	T1,DEVSTS(F)	;WE WILL/HAVE CLEARED IT
	PUSHJ	P,NTDCST##	;SEND STATUS TO REMOTE TO CLEAR IT

L.LOO2:	MOVEI	T1,SLP.8B	;THE EIGHT-BIT-DATA-NO-COMPRESSION FLAG
	LDB	T2,PIOMOD##	;GET LPT DATA MODE
	CAIE	T2,A8		;IS LPT IN EIGHT-BIT-ASCII MODE?
	JRST	L.LOO3		;NO
	TDNE	T1,DEVSTS(F)	;MORE TO THE POINT, IS IT IN 8-BIT MODE NOW?
	JRST	L.LOO5		;YES, ALL SET
	LDB	T2,NETDVT##	;GET REMOTE'S LPT ATTRIBUTES
	TRNN	T2,DLP.8B	;DOES THE REMOTE LPT SUPPORT 8-BIT?
	JRST	L.8IMP		;NO, RETURN I/O ERROR
	IORM	T1,DEVSTS(F)	;WE WILL/HAVE SET IT
	PUSHJ	P,NTDSST##	;SEND STATUS TO REMOTE
	JRST	L.LOO5		;KEEP ON PLUGGIN'

L.LOO3:	TDNN	T1,DEVSTS(F)	;IS THE LPT IN 8-BIT MODE NOW?
	JRST	L.LOO5		;NO, ALL SET
	ANDCAM	T1,DEVSTS(F)	;YES, WE MUST CLEAR IT
	PUSHJ	P,NTDCST##	;CLEAR IT IN THE REMOTE TOO

L.LOO5:	MOVEI	T1,^D07		;LPT'S ARE USUALLY IN 7-BIT DATA MODE
	MOVEI	T2,SLP.8B	;THE EIGHT-BIT FLAG
	TDNE	T2,DEVSTS(F)	;IS THE LPT IN 8-BIT MODE?
	MOVEI	T1,^D08		;YES, SELECT 8-BIT DATA BYTES
	PUSHJ	P,NTDSOB##	;SET UP THE OUTPUT BUFFER
	  JRST	L.DONE		;NO MORE DATA. RETURN TO UUOCON.
	SKIPN	DEVAXO+1(F)	;FOR LPT'S MAKE SURE THAT WE DON'T
	JRST	L.LOO9		; SEND ZERO LENGTH BUFFERS
	PUSHJ	P,NTDCDQ##	;SEE IF ANY DATA REQUESTS PENDING
	  JRST	L.WAIT		;NONE AVAILABLE.  WE MUST WAIT.
	MOVEI	T1,PCV.LC	;WE WANT LINE-PRINTER COMPRESSION
	MOVEI	T2,SLP.8B	;THE EIGHT-BIT FLAG
	TDNE	T2,DEVSTS(F)	;IS THE LPT IN 8-BIT MODE?
	MOVEI	T1,PCV.NC	;YES, THEN NO DATA COMPRESSION
	MOVEI	T2,DC.DAR	; NOT-INTERRUPT, DATA WITH E-O-R
	PUSHJ	P,NTDXMT##	;SEND ANOTHER PCB'S WORTH OF DATA
	  PUSHJ	P,[JUMPN T1,NTDSTP##	;WE SHOULD NEVER GET AN IO-ERROR
		POP	P,(P)		;CLEAN OFF THE RETURN ADDRESS (UGLY)
		JRST	L.SLP]		;A QUICK NAP AND TRY AGAIN
	PUSHJ	P,NTDDDQ##	;UPDATE THE DATA REQUEST COUNT
	SKIPN	DEVAXO+1(F)	;ARE THERE ZERO BYTES LEFT??
L.LOO9:	PUSHJ	P,NTDAOB##	;IF SO, THEN GIVE USER BACK THE BUFFER
	JRST	L.LOOP		;LOOP UNTIL ALL DATA IS OUT
SUBTTL 2.2        FIRST TIME ONLY CODE (OUTPUT <CR><FF>)

L.FRST:				;HERE ON FIRST OUT FROM UUOCON
	SETZM	DEVAXO(F)	;CLEAR ANY DATA NOT OUTPUT LAST TIME
	TRNE	S,LPTNFF	;SHOULD WE OUTPUT THE FIRST <CR><FF>
	JRST	L.FRS3		; IF NOT, THEN SKIP MOST OF THIS
	PUSHJ	P,L.XFF		;SEND THE INITIAL <CR><FF> SEQUENCE
	 POPJ	P,		;FORGET IT

L.FRS3:				;HERE WHEN ALL "FIRST TIME" STUFF DONE.
	MOVSI	S,IOBEG!IOSREL	;GET AND CLEAR "RELEASED"
	ANDCAB	S,DEVIOS(F)	; AND "FIRST TIME" BIT
	JRST	L.LOOP		;GO BACK AND TRY TO SEND USER DATA.



;HERE ON "CLOSE" UUO - 'LAST' TIME ONLY PROCESSING

L.CLO:	PUSHJ	P,NTDCLO##	;FLUSH OUT ANY DANGLING LPT DATA
	MOVE	S,DEVIOS(F)	;DEVICE STATUS FLAGS
	TRNE	S,LPTNFF	;SHOULD WE OUTPUT A TRAILING <CR><FF>?
	JRST	L.CLO4		; IF NOT, THEN SKIP MOST OF THIS
	PUSHJ	P,L.XFF		;SEND THE TRAILING <CR><FF> SEQUENCE
	 POPJ	P,		;FORGET IT
L.CLO4:	POPJ	P,		;RETURN FROM NETWORK CLOSE PROCESSING



;SEND A <CR><FF> SEQUENCE TO REMOTE LINE PRINTER

L.XFF:	PUSHJ	P,NTDSET##	;SET UP REGS, IOSCON, ETC.
	PUSHJ	P,NTDONL##	;MAKE SURE LPT IS STILL VIABLE
	 JRST	[TLNN	S,IOSCON	;ARE WE STILL CONNECTED?
		PJRST	NTDGON##	; NO. TELL USER DEVICE IS GONE
		TLNE	S,IOSERR	;IS THE LPT ON LINE YET??
		PUSHJ	P,NTDHNG##	;SET OFF-LINE AND TELL THE OPERATOR
		JRST	L.XFF]		;TRY AGAIN
	PUSHJ	P,NTDCDQ##	;DO WE HAVE A DATA REQUEST FOR THIS?
	  JRST	[PUSHJ	P,NTDWTO##	;WAIT FOR DRQ.
		  POPJ	P,		;RETURN TO UUOCON IF NON-BLOCKING.
		JRST	L.XFF]		;TRY AGAIN
	MOVEI	T1,^D16		;WE WANT A 16 WORD DATA MESSAGE
	PUSHJ	P,NTDHDR##	; SET UP P2 := POINTER, P3 := COUNT
	  JRST	[PUSHJ	P,NETSLP##	;WAIT A BIT
		JRST	L.XFF]		;AND TRY AGAIN
	MOVEI	T3,SLP.8B	;THE 8-BIT MODE FLAG
	TDNN	T3,DEVSTS(F)	;IS THE NET LPT IN 7-BIT OR 8-BIT MODE?
	SKIPA	T3,[POINT 8,[BYTE (8)3,DC.DAR,215,214]]  ;7-BIT, COMPRESSED
	MOVE	T3,[POINT 8,[BYTE (8)3,DC.DAR,15,14]]  ;8-BIT, UNCOMPRESSED
				;LENGTH & MESSAGE TO SEND
	MOVEI	T4,4		;WE WILL SEND 4 BYTES (INCLUDING LENGTH)

L.XFF2:	ILDB	T1,T3		;GET THE NEXT BYTE
	PUSHJ	P,DPBBIN##	; AND PUT IT IN THE MESSAGE
	SOJG	T4,L.XFF2	;LOOP TILL ALL BYTES IN MESSAGE.
	ADDB	P3,PCBCTR(U)	;UPDATE THE COUNT IN FIRST SEGMENT.
	SETZB	P3,PCBCT2(U)	;INDICATE THAT THERE IS NO SECOND SEG.
	MOVEI	T1,PCV.NC	;NO DATA COMPRESSION (ALREADY HANDLED ABOVE)
	PUSHJ	P,NTDWRT##	;SEND THE MESSAGE.
	PUSHJ	P,NTDDDQ##	;DECREMENT THE DATA REQUEST COUNT
	JRST	CPOPJ1##	;SUCCESSFUL RETURN
SUBTTL 2.3        EXCEPTION HANDLING.

L.DONE:				;HERE IF ALL USERS BUFFERS SENT
	POPJ	P,		;I THINK UUOCON WILL DO THE REST

L.SLP:	PUSHJ	P,NETSLP##	;WAIT A BIT
	JRST	L.LOOP		;AND TRY AGAIN

L.WAIT:				;HERE WHEN NO DATA REQUESTS.
	PUSHJ	P,NTDWTO##	;WAIT FOR DRQ.
	  POPJ	P,		;RETURN TO UUOCON IF NON-BLOCKING.
	JRST	L.LOOP		;TRY FOR MORE DATA-OUT.
				;L.LOOP WILL RELOAD "S" AND "W"

L.HUNG:				;HERE WHEN IOSERR IS SET.
	TLNN	S,IOSCON	;ARE WE STILL CONNECTED
	PJRST	NTDGON##	; NO. TELL USER DEVICE IS GONE
	TLNE	S,IOSERR	;IS THE LPT ON LINE YET??
	PUSHJ	P,NTDHNG##	;SET OFF-LINE AND TELL THE OPERATOR
	JRST	L.LOOP		;TRY TO SEND SOME MORE DATA.


L.8IMP:	MOVEI	S,IOIMPM	;SET "IMPROPER MODE"
	IORB	S,DEVIOS(F)	;IN THE DDB
	POPJ	P,		;AND LET UUOCON GIVE USER THE ERROR
SUBTTL 3.0      INTERFACE TO NETSER (NETWORK DISPATCH VECTOR)

	IFIW	NTDNWD##	;USE DEFAULT "NODE WENT DOWN" HANDLER
	IFIW	NTDDSC##	;USE DEFAULT DISCONNECT HANDLER
	IFIW	L.CNC		;CONNECT CONFIRM HANDLER
	IFIW	NTDSTP##	;++ SHOULD NEVER GET CONNECT INITIATE ENTRY
	IFIW	NTDRDQ##	;USE STANDARD DATA-REQUEST HANDLER
LPTNDP::IFIW	NTDILD##	;USE CANNED INTERRUPT LEVEL DISPATCH
	IFIW	CPOPJ##		;WE DON'T GET ANY DATA
	IFIW	CPOPJ##		; ESPECIALY DATA WITH E-O-R...
	IFIW	L.STAT		;WE DO GET STATUS MESSAGES
	IFIW	CPOPJ##		;WE DONT GET CONTROL
	IFIW	CPOPJ##		;OR UID
	IFIW	CPOPJ##		;OR FILE-SPEC'S



;DUMMY CONNECT INIT PROCESSOR

NLPTCI==:NJNKCI##		;A JUNK CI
SUBTTL	CONNECT CONFIRM HANDLER

L.CNC:	PUSHJ	P,NTDCNC##	;STANDARD CONNECT CONFIRM PROCESSING
	  POPJ	P,		;ERROR, PROPAGATE BACK TO NETSER
	LDB	T1,NETDVT##	;RETRIEVE "DVT" ATTRIBUTES FIELD
	SETZ	T2,		;INITIAL "HCW" HARDWARE CHARACTERISTICS
	TRNE	T1,DLP.LL	;LOWERCASE?
	TLO	T2,(HC.LCP)	;YES
	LDB	T1,NETDVU##	;RETRIEVE "UNIT" TYPE
	DPB	T1,[POINT 3,T2,14]  ;AND STUFF INTO HCW WORD
	LDB	T1,NETDVV##	;RETRIEVE "CONTROLLER" TYPE
	DPB	T1,[POINT 3,T2,11]  ;AND STUFF INTO HCW WORD
	MOVEM	T2,DEVHCW(F)	;SET LINEPRINTER HARDWARE CHARACTERISTICS
	JRST	CPOPJ1##	;SUCCESSFUL RETURN BACK TO NETSER
SUBTTL 3.1        INPUT STATUS MESSAGE PROCESSING

L.STAT:				;HERE FROM NETSER WITH A STATUS MESSAGE.
				;STC
	PUSHJ	P,EBI2BI##	;GET TYPE OF STATUS MESSAGE
	JUMPN	T1,CPOPJ##	; (WE ONLY RESPECT TYPE 0)
				;STD
	PUSHJ	P,EBI2BI##	;GET THE DEVICE BITS.
	HRRM	T1,DEVSTS(F)	;STORE THE STATUS FOR UUOLEVEL TO WATCH
	AOS	(P)		;WE ARE NOW SATISFIED THAT MSG IS GOOD.
	MOVE	T2,[IORB S,DEVIOS(F)]	;ASSUME THAT WE ARE OFFLINE.
	TRNN	T1,SLP.OL	; BUT CHANGE OUR MINDS IF WE
	MOVE	T2,[ANDCAB S,DEVIOS(F)]	; WE ARE ONLINE
	MOVE	T3,DEVIOS(F)	;COPY OLD STATUS
	MOVSI	S,IOSERR	;AND SET/CLEAR
	XCT	T2		; THE ERROR BIT "IOSERR" IN DEVIOS

	CAME	S,T3		;DID THE STATUS CHANGE??
	PUSHJ	P,NTDOAV##	; IF IT DID, THEN WAKE UP UUOLEVEL
	POPJ	P,		;GIVE GOOD RETURN TO NETSER



	XLIST			;DON'T LIST LITERALS
	$LIT
	LIST
	PRGEND
TITLE	NETMCR - NETWORK MONITOR CONTROL ROUTINES  VERSION 001
SUBTTL	NETMCR -- WEM/	4-JUN-78

	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1984  BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VNEMCR,001		;PUT VERSION NUMBER IN GLOB AND LOADER MAP

NETMCR::ENTRY NETMCR


NDEVMC==:777740			;DUMMY DEVSER DISPATCH FOR NDT MACRO
SUBTTL 1.0      INTERFACE TO SCNSER

SUBTTL 1.1        SCNSER DISPATCH TABLE

MCRDSP::JRST	D85TYP		;ILLEGAL NOW.  DON'T USE!!
	JRST	CPOPJ##		;MODEM CONTROL
	JRST	CPOPJ##		;ONCE A SECOND STUFF
	JRST	CPOPJ##		;INITIALIZE
	JRST	D85CHP		;CHANGE HARDWARE PARMS
	JRST	D85LPC		;LINE PARM CONTROL
	JRST	D85ELE		;SET TERMINAL ELEMENT
	JRST	D85REM		;STUFF FOR REMOTE TERMINALS
	JRST	D85OFL		;IS THE LINE DEFINED ON THE STATION

;FUNCTION CODE 0 IS ILLEGAL
D85TYP:	STOPCD	.,STOP,CU0,	;++ CAN'T USE ZERO DISPATCH
	POPJ	P,
;HERE TO REQUEST A CHANGE OF PARAMETERS
D85CHP:	PJRST	SETCHP##	;LET SCNSER DO THE WORK
;HERE TO REQUEST A LINE PARM CHANGE.
D85LPC:	CAIE	T3,<LPCUKB>B27	;UNLOCK KEYBOARD OR TERMINAL INPUT WAIT?
	POPJ	P,		;??
	PJRST	D85CHP		;REQUEST THE CHANGE OF PARMS
;HERE TO CHANGE THE ELEMENT ON A 2741
D85ELE:	PUSHJ	P,ELEINX##	;CONVERT TO AN INDEX
	  POPJ	P,		;ILLEGAL
	DPB	T2,LDPELE##	;STORE THE NEW ELEMENT NUMBER,
	AOS	(P)		;GIVE A GOOD SKIP RETURN
	PJRST	D85CHP		; AND SIGNAL THE CHANGE IN PARAMETERS

;SEE IF THE TERMINAL IS ON-LINE
D85OFL:	MOVE	T1,LDBREM##(U)	;GET THE STATUS BITS
	TLNE	T1,LRLCON##	;IF THIS IS SET WE ARE PROBABLY
	AOS	(P)		; STILL CONNECTED, IF IT IS ZERO, WE
	POPJ	P,		; ARE MOST CERTAINLY NOT.
;COME HERE ON SPECIAL CALLS FROM SCNSER

;CODE IN T3:
;1 = BUFFER LOW
;2 = CHARACTER NOT STORED
;3 = CONTROL O PROCESSING.

D85REM:	CAILE	T3,IRRINV	;VALIDATE RANGE
	CAILE	T3,IRRTMO	; ...
	POPJ	P,		;IGNORE IF NOT IN RANGE
	JRST	@.(T3)		;OTHERWISE DISPATCH
	IFIW	MCRBFL		;BUFFER LOW
	IFIW	MCRCNS		;CHARACTER NOT STORED
	IFIW	MCRCTO		;CONTROL O
	IFIW	MCRCSA		;CHUNK SPACE AVAILABLE
	IFIW	MCRDIS		;DISCONNECT
	IFIW	MCRCIB		;CLEAR INPUT BUFFER
	IFIW	MCRTMO		;AUTO-DISCONNECT TIMEOUT

;THESE ARE NO-OPS FOR NOW.

MCRCNS==CPOPJ##
MCRCSA==CPOPJ##
MCRCIB==CPOPJ##

;COME HERE ON CONTROL O ACTION.  THE CONTROL O MAY HAVE BEEN
;  SET EITHER ON OR OFF.  CHECK THE LDB TO DETERMINE WHICH AND
;  SEND A CHARACTER GOBBLER IF IT HAS BEEN SET ON.

MCRCTO:	MOVSI	T2,LRLSCG##	;GET AND SET THE BIT
	IORM	T2,LDBREM##(U)	; SAYING WE WANT A CHAR GOBBLER SENT
	PJRST	D85CHP		;NOW QUEUE THE LDB FOR SERVICE

;COME HERE IF INPUT BUFFER IS FULL
;THIS TELLS THE FRONT END THAT AN XOFF IS NEEDED
;	SKIP	RETURNS IF MESSAGE GETS SENT
MCRBFL:	MOVSI	T2,LRLXOF##	;GET THE XOFF FLAG
	IORM	T2,LDBREM##(U)	;SET IT SO SCNMC7 WILL SEE IT
	AOS	(P)		;GIVE A GOOD SKIP RETURN
	PJRST	D85CHP		;AND QUEUE THE LDB

;COME HERE ON AUTO-DISCONNECT TIMEOUT FROM SCNSEC.
;  THIS WILL TRY TO DISCONNECT THE TERMINAL IF AT ALL REASONABLE.
MCRTMO:	MOVEI	T2,LDRDSD##	;DATASET BIT
	TDNN	T2,LDBDCH##(U)	;IS IT ONE?
	PJRST	MCRDIS		;NO, TRY IT THIS WAY
	PUSHJ	P,MCRCHK	;SEE IF A LEGAL TERMINAL
	  POPJ	P,		;RETURN FAILURE IF NOT
	PJRST	D85OFF		;JUST DO THE DISCONNECT IF SO

;COME HERE ON USER DISCONNECT REQUEST (E.G., FROM TRMOP. .TODNT).
;  THIS WILL SEND THE DISCONNECT IF REASONABLE.

MCRDIS:	PUSHJ	P,MCRCHK	;SEE IF A LEGAL TERMINAL
	  POPJ	P,		;RETURN IF NOT
	MOVE	T2,LDBREM##(U)	;NO, GET ITS REMOTE STATUS BITS
	TRNN	T2,LRRSHC##	;CAN THIS LINE HANDLE A DISCONNECT?
	POPJ	P,		;NO, DON'T DISCONNECT IT
	MOVSI	T2,LRLTMO##	;YES, GET TIME-OUT BIT
	IORM	T2,LDBREM##(U)	;LIGHT IT
	JRST	CPOPJ1##	;NMCSEC WILL DISCONNECT THE LINE
SUBTTL 1.2        SCNSER MODEM CONTROL.

;HERE FOR MODEM CONTROL FROM SCNSER
D85DSC::PUSHJ	P,MCRCHK	;SEE IF A LEGAL TERMINAL
	  JRST	ECOD4##		;NOT A TERMINAL
	MOVE	T2,LDBDCH##(U)	;GET THE STATUS BITS
	TRNN	T2,LDRDSD##	;IS THIS A DATA SET LINE
	JRST	ECOD4##		;NO
	CAIN	T3,DSTSTS##	;STATUS?
	JRST	D85STS		;YES
	CAIN	T3,DSTOFF##	;MODEM OFF
	JRST	D85OFF		;YES,
	CAIN	T3,DSTON##	;MODEM ON
	JRST	D85ON		;YES
	CAIN	T3,DSTCRQ##	;REQUEST DIAL OUT
	JRST	D85CRQ		;YES
	JRST	ECOD3##		;NONE OF ABOVE


D85STS:	MOVSI	T2,LRLDSR##	;CARRIER ON BIT
	TDNN	T2,LDBREM##(U)	;IS IT?
	TDZA	T1,T1		;NO
	MOVSI	T1,DSCHWC##	;YES
	JRST	STOTC1##	;STORE ANSWER FOR USER


D85OFF:	MOVSI	T2,LRLHUR##	;HANG-UP BIT
	IORM	T2,LDBREM##(U)	;REQUEST REMOTE TO HANG UP THE PHONE
	PUSHJ	P,D85CHP	;GO KICK THE REMOTE
	JRST	CPOPJ1##	;WE'VE DONE OUR PART


D85ON:	JRST	CPOPJ1##	;JUST PRETEND ALL IS WELL
;HERE FOR CALL REQUEST (DIALOUT)
D85CRQ:	MOVSI	T2,LRLADL##	;GET AUTO DIAL LINE BIT
	TDNN	T2,LDBREM##(U)	;IS THIS A AUTO DIAL LINE
	PJRST	ECOD4##		;NOPE FAIL
D85CR1:	SKIPN	DIALDB##	;IS THE DIALER AVAILABLE
	JRST	D85CR2		;YES, CONTINUE
	MOVEI	T1,5		;NO
	PUSHJ	P,[NTSAVE	;RETURN THE 'NT RESOURCE
		   S0PSHJ SLEEP## ;AND NOW SLEEP.
		   POPJ P,]	;RETURN IN CORRECT SECTION
	JRST	D85CR1		;TRY AGAIN
D85CR2:	MOVEM	U,DIALDB##	;STORE THE LDB OF THE REQUESTER
	MOVEM	J,DIALJB##	;STORE THE JOB NUMBER FOR NETCTC
	SETZM	DIALFL##	;INITIALIZE DIALOUT "STATE"
	PUSHJ	P,GETWRD##	;GET PART ONE OF THE NUMBER
	  PJRST	ECOD3##		;BAD ADDRESS
	MOVEM	T1,DIALNM##	;STORE PART ONE
	PUSHJ	P,GETWR1##	;GET SECOND PART
	  PJRST	ECOD3##		;ADDRESS CHECK
	TRO	T1,17		;FORCE AN END CHARACTER
	MOVEM	T1,DIALNM+1	;STORE PART TWO
	MOVSI	T2,LRLADR##	;GET AUTO DIAL REQUEST BIT
	IORM	T2,LDBREM##(U)	;SET IT
	PUSHJ	P,D85CHP	;REQUEST SERVICE
D85CR3:	MOVEI	T1,^D3		;WAIT FOR THREE SECONDS
	PUSHJ	P,[NTSAVE	;SAVE THE 'NT'
		   S0PSHJ SLEEP## ;AND GO SLEEP
		   POPJ P,]	;AND RETURN IN THE CORRECT SECTION
	SKIPL	T1,DIALFL##	;CHECK FOR A COMPLETED CALL
	JRST	D85CR3		;NO, WAIT AGAIN
	SETZM	DIALDB##	;YES, MAKE THE DIALER AVAILABLE
	SETZM	DIALJB##	;DON'T CONFUSE NETCTC
	TLNN	T1,LRLDSR	;DID THE DIALOUT SUCCEED?
	JRST	ECOD5##		;NO, GIVE AN ERROR RETURN
	JRST	CPOPJ1##	;YES, GOOD RETURN

SUBTTL 2.0      INTERFACE TO NETSER FOR INCOMING DATA

SUBTTL 2.1        NETWORK DISPATCH TABLE FOR TERMINALS (NDP)

	IFIW	MCRNWD		;(-5)NODE WENT DOWN
	IFIW	MCRDSC		;(-4)DISCONNECT MESSAGE
	IFIW	MCRCNC		;(-3)CONNECT CONFIRM
	IFIW	NTDSTP##	;(-2)CONNECT INITIATE (WE DON'T POST DDB'S)
	IFIW	MCRDRQ		;(-1)DATA REQUESTS
MCRNDP::IFIW	MCRDAP		;(0) DISPATCH ON INCOMING DAP MESSAGE
	IFIW	MCRDAT		;(1) DATA WITHOUT END OF RECORD
	IFIW	MCRDAR		;(2) DATA WITH END OF RECORD (MTA'S)
	IFIW	MCRSTS		;(3) STATUS
	IFIW	MCRCTL		;(4) CONTROL MESSAGE
	IFIW	CPOPJ##		;(5) USER ID
	IFIW	CPOPJ##		;(6) FILE SPEC
SUBTTL 2.2        NETWORK CONTROL MESSAGE PROCESSING

SUBTTL 2.2.1        NODE WENT DOWN

;MCRNWD	ROUTINE TO HANDLE THE "NODE WENT DOWN" NETWORK DISPATCH ENTRY
;CALL	MOVEI	F,LAT-ENTRY	;RH CONTAINS LDB POINTER
;	MOVEI	P1,NODE NUMBER OF THE DEAD NODE
;	PUSHJ	P,MCRNWD
;RETURN	CPOPJ			;ALWAYS

MCRNWD:	PUSH	P,U		;SAVE U
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"
	LDB	T1,LDPRNN##	;GET THE REMOTE NODE NUMBER
	CAIE	T1,(P1)		;IS IT THE SAME AS THE ONE WE ARE LOOKING AT?
	STOPCD	.,STOP,MCRBRN,	;++ BAD REMOTE NODE NUMBER
	PUSHJ	P,NMCWAK	;WAKE ANYONE WHO MIGHT BE WAITING
	PUSHJ	P,MCRDET	;THEN DETACH THE TERMINAL
	PUSHJ	P,MCRFRE	; AND FREE THE LDB
	PJRST	UPOPJ##		;RESTORE U AND WE ARE DONE
SUBTTL 2.2.2        DISCONNECT MESSAGES (BOTH INIT AND CONFIRM)

;MCRDSC	ROUTINE TO HANDLE INCOMING DISCONNECTS FOR MCR'S
;CALL	MOVEI	F,LDB		;(CAUSE THAT'S HOW ICMDSC DOES IT)
;	P1, P4 := POINT TO "SLA" OF THE DISCONNECT MESSAGE. (BUT WE DON'T CARE)
;	MOVEI	W,NDB
;	PUSHJ	P,MCRDSC
;RETURN	CPOPJ			;WE SHOULDN'T HAVE GOTTEN A DISCONNECT. BAD MSG.
;	CPOPJ1			;MESSAGE ACCEPTED.

MCRDSC:	PUSH	P,U		;SAVE THE INCOMING PCB
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"
	LDB	T1,LDPSLA##	;GET OUR LAT ADDRESS
	LDB	T2,LATSTA##	;GET THE STATE OF THE CONNECTION
	CAIL	T2,LAT.CC	;THE ONLY TIMES DISCONNECT IS LEGAL IS
	CAILE	T2,LAT.DC	; ARE LAT.CC, LAT.OK, AND LAT.DC
	JRST	UPOPJ##		;IF IT'S NOT ONE OF THEM, WE CAN'T PROCESS IT.
	CAIE	T2,LAT.OK	;DO WE NEED TO SEND A DISCONNECT CONFIRM?
	JRST	MCRDS1		; IF NOT. SKIP THE CODE THAT DOES
	MOVEI	T1,RSN.OK	;GET THE REASON FOR THE DISCONNECT CONFIRM
	EMRGCY			;USE "EMERGENCY" MEMORY IF NECESSARY
	PUSHJ	P,TRMXDC	;SEND THE DISCONNECT.
	 STOPCD	.,STOP,MCRDSF,	;++ DISCONNECT FAILED. EMRGCY HACK F.U.
MCRDS1:	PUSHJ	P,NMCWAK	;WAKE ANY JOB THAT MAY BE WAITING ON A CONNECT.
	PUSHJ	P,MCRDET	;ATTEMPT TO "DETACH" THE USER (IF THERE IS ONE)
	PUSHJ	P,MCRFRE	;FREE THE LAT AND THE LDB
	PJRST	UPOPJ1##	;RETURN PCB AND GIVE A GOOD RETURN
SUBTTL 2.2.3        CONNECT CONFIRM

;MCRCNC	ROUTINE TO PROCESS A MCR CONNECT CONFIRM MESSAGE.
;CALL	MOVEI	W,NDB
;	MOVEI	F,LDB
;	P1, P4 := POINTER TO THE "SLA" SECTION OF THE CONNECT CONFIRM
;RETURN	CPOPJ1			;ALWAYS

MCRCNC:	PUSH	P,U		;SAVE THE PCB POINTER
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"

;SLA

	PUSHJ	P,EBI2BI##	;GET THE LINK ADDRESS AT THE OTHER END
	DPB	T1,LDPDLA##	;REMEMBER IT SO WE CAN SEND HIM STUFF

;DPN(OBJ)

	PUSHJ	P,XSKIP##	;IGNORE "OUR" OBJECT TYPE

;DPN(,PID)

	PUSHJ	P,XSKIP##	;IGNORE "OUT" PROCESS NAME (OR UNIT #)

;SPN(OBJ,PID)

	PUSHJ	P,TTYRPN	;READ HIS LINE NUMBER AND CHECK FOR OPR.

;MML,FEA(DCM,RLN,DVT,DVU,DVV)

	PUSHJ	P,TTYRAT	;READ THE "ATTRIBUTES"
	PUSHJ	P,TRM.UP	;MARK TERMINAL ONLINE (MCRCHK WILL NOW SKIP)
	MOVSI	T1,LRLGRT##	;AS THIS IS A TERMINAL ASSIGNMENT REQUEST,
	IORM	T1,LDBREM##(U)	;LET THE OWNER "GREET" IT IF NECESSARY
	PUSHJ	P,NMCWAK	;WAKE ANY JOB THAT MAY BE WAITING FOR CONNECT
	JRST	UPOPJ1##	;RESTORE THE PCB AND SKIP RETURN
SUBTTL 2.2.4        CONNECT INITIATE

;NMCRCI	ROUTINE TO HANDLE THE CONNECT INITIATE MESSAGE FOR A MCR.
;CALLED	BY THE NDTCNI DISPATCH IN ICMCNT.
;	P1, P4 POINT TO THE "DPN" OF THE CONNECT MESSAGE
;	P3 := XWD DLA,OBJ	;AS READ FROM THE CONNECT
;	W := POINTER TO THE NDB
;RETURN	CPOPJ			;CONNECT REJECT. REASON IN "T1"
;	CPOPJ1			;CONNECT ACCEPTED. CONNECT CONFIRM SENT.

NMCRCI::MOVE	T1,STATES##	;GET THE SCHEDULE BITS
	TRNE	T1,ST.NRT	;ANY REASON NOT TO CONNECT?
	JRST	[MOVEI	T1,RSN.OT	;IF SO, GIVE A "NOT AVAILABLE" CODE
		POPJ	P,]		; AND GIVE AN ERROR RETURN
	PUSH	P,U		;SAVE THE INPUT PCB
	PUSHJ	P,MCRGET	;GET AN ANF/MCR LDB
	  JRST	NMCRC9		;CAPACITY EXCEEDED ERROR
	MOVEI	T1,M.AIDL##	;GET MAXIMUM IDLE TIME BEFORE AUTO-DISCONNECT
	PUSHJ	P,SCNADT##	;START THE TIMER GOING
	MOVE	T1,U		;ADDRESS OF LDB FOR GETSLA
	TLO	T1,LAT.TY	;THIS WILL BE A LDB-TYPE OF ADDRESS
	MOVEI	T2,LAT.OK	;AND ITS INITIAL STATE IS "OK"
	PUSHJ	P,GETSLA##	;ALLOCATE A LAT ENTRY
	  JRST	NMCRC8		;IF NONE LEFT, THEN CAPACITY EXCEEDED.
	DPB	T1,LDPSLA##	;STORE THE LAT ADDRESS IN THE SLA FIELD
	HLRZ	T1,P3		;GET AND
	DPB	T1,LDPDLA##	; SAVE THE DLA
	PUSHJ	P,TRM.UP	;ANTICIPATE SUCCESS, AND DECLARE THE LDB ONLINE
				; (IF WE FAIL LATER, ALL WILL BE CLEARED UP)

;DPN(,PID)

	PUSHJ	P,XSKIP##	;THE REMOTE CAN'T SELECT PARTICULAR MCR'S

;SPN(OBJ,PID)

	PUSHJ	P,TTYRPN	;READ THE REMOTE LINE NUMBER.

;MML,FEA(DCM,RLN,DVT,DVU,DVV)

	PUSHJ	P,TTYRAT	;READ THE REMOTE MCR'S ATTRIBUTES.
	PUSHJ	P,MCRXCN	;TRY TO SEND A CONNECT-CONFIRM.
	 JRST	NMCRC8		;FAILED, CLEAR LAT AND FREE LDB
	MOVSI	T1,LRLGRT##	;SINCE THIS IS AN UNSOLICITED TTY CONNECT
	ANDCAM	T1,LDBREM(U)	;FLAG THE TERMINAL TO BE "GREETED" ASAP
	JRST	UPOPJ1##	;CONNECT COMPLETED SUCCESSFULLY


;CAN'T ACCEPT INCOMING CONNECT, RETURN "CAPACITY EXCEEDED" ERROR

NMCRC8:	PUSHJ	P,MCRFRE	;GIVE UP LAT SLOT, FREE LDB
NMCRC9:	MOVEI	T1,RSN.XN	;GET CAPACITY EXCEEDED ERROR CODE
	PJRST	UPOPJ##		;RESTORE "U" AND GIVE ERROR RETURN
SUBTTL 2.2.5        DATA REQUEST

;MCRDRQ	ROUTINE TO PROCESS A DATA REQUEST FOR A MCR.
;CALL	MOVEI	T4,"DRQ" FIELD OF THE MESSAGE (READ IN ICMDRQ)
;	MOVEI	F,LDB
;	PUSHJ	P,MCRDRQ	;(ACTUALLY MCRNDP+NDPDRQ)
;RETURN	CPOPJ			;MESSAGE BAD.
;	CPOPJ1			;DATA REQUEST ACCEPTED

MCRDRQ:	NTDBUG			;VERIFY THE INTERLOCK
	PUSH	P,U		;SAVE THE PCB
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"
	LDB	T2,LDPDRQ##	;GET THE CURRRENT DATA REQUEST COUNT
	ADD	T2,T4		;FORM NEW SUM
	CAILE	T2,^D256	;UNREASONABLE?
	PJRST	UPOPJ##		;YES, IGNORE THE REQUEST
	DPB	T2,LDPDRQ##	;STORE THE NEW COUNT
	MOVSI	T1,LRLTTW##	;GET AND CLEAR THE
	ANDCAM	T1,LDBREM##(U)	; WAITING BIT
	PUSHJ	P,TOREQ##	;REQUEST SERVICE ON THE LINE
	PJRST	UPOPJ1		;GIVE GOOD RETURN
SUBTTL 2.3        DAP MESSAGE PROCESSING

SUBTTL 2.3.1        DAP DISPATCH ROUTINE

;MCRDAP	ROUTINE TO SEPARATE THE NCL SUB-MESSAGES
;CALL	MOVEI	F,LDB
;	MOVE	P1,BYTE POINTER TO THE FIRST "CNT" FIELD IN THE MESSAGE
;	PUSHJ	P,MCRDAP	;DO DAP DISPATCHING
;RETURN	CPOPJ

MCRDAP:	PUSH	P,U		;SAVE THE PCB
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"

;LOOP DISPATCHING FOR EACH SUB-MESSAGE

MCRDP1:	JUMPLE	P4,UPOPJ##	;EXIT IF ALL SUB-MESSAGES HAVE BEEN DONE

;CNT

	PUSHJ	P,EBI2BI##	;GET THE LENGTH OF NEXT SUB-MESSAGE
	SUB	P4,T1		;UPDATE TOTAL MESSAGE LEFT LENGTH
	SKIPGE	P4		;MAKE SURE SUB-MSG IS A REASONABLE LENGTH
	JSP	T1,MCRDP3	;++ SUB-MSG EXTENDS PAST TOTAL MESSAGE'S END
	PUSH	P,P4		;SAVE LENGTH OF REST OF TOTAL MESSAGE
	MOVEI	P4,(T1)		;COPY THE LENGTH OF THE SUB-MESSAGE

;TYP

	PUSHJ	P,EBI2BI##	;GET THE IDC TYPE FIELD
	CAIL	T1,DC.DAT	;RANGE CHECK
	CAILE	T1,DC.MAX	; THE TYPE FEILD
	PJSP	T1,MCRDP2	;BAD MESSAGE. ILLEGAL TYPE.
	PUSHJ	P,@MCRNDP(T1)	;DO THE DISPATCH
	  PJSP	T1,MCRDP2	;THE DRIVER DIDN'T LIKE THE MESSAGE?
	SOJG	P4,[IBP P1	;MAKE SURE P1 POINTS AT THE NEXT "CNT" BYTE
		    JRST .]
	POP	P,P4		;GET LENGTH OF "REST" OF MESSAGE BACK
	JRST	MCRDP1		;LOOP OVER ALL SUB-MESSAGES

MCRDP2:	POP	P,T2		;POP TOTAL MESSAGE LENGTH OFF STACK
MCRDP3:	POP	P,U		;HERE IF BAD MSG, RESTORE PCB POINTER
	PJRST	INCTBD##	;  CALL INCTBD WITH T1 = ADDR OF ERROR
SUBTTL 2.3.2        DAP DATA MESSAGE (WITH AND WITH E-O-R)

;MCRDAR/MCRDAT ROUTINES TO PROCESS TERMINAL INPUT DATA.
;CALL	MOVEI	U,LDB
;	P1, P4 := POINTER TO THE FIRST BYTE OF DATA.
;RETURN	CPOPJ1			;ALWAYS (IT DOESN'T DETECT ANY ERRORS)

MCRDAR:				;DATA WITH END OF RECORD
MCRDAT:	PUSH	P,F		;RECINT CLOBBERS F
MCRDA1:	SOJL	P4,FPOPJ1##	;ALL DONE
	ILDB	T3,P1		;GET NEXT CHARACTER
	MOVEI	T1,STY.DE	;DEFERRED ECHO BIT
	TDNN	T1,LDBREM##(U)	;IS FRONT-END DOING THE ECHO?
	TRO	T3,CK.FDE	;YES, NOTE THAT
	PUSHJ	P,RECPTY##	;PROCESS CHARACTER
	JRST	MCRDA1		;AND PROCESS NEXT CHAR, IF ANY.
SUBTTL 2.3.3        DAP STATUS MESSAGE

;MCRSTS	ROUTINE TO PROCESS DAP TERMINAL STATUS MESSAGES
;CALL	MOVEI	U,LDB
;	P1, P4 := POINTER TO THE "STC" BYTE OF A DAP STATUS MESSAGE
;RETURN	CPOPJ			;MESSAGE'S "STC" WAS BAD
;	CPOPJ1			;MESSAGE PROCESSED OK

MCRSTS:

;STC

	PUSHJ	P,EBI2BI	;GET THE STATUS CODE
	JUMPN	T1,CPOPJ##	;WE ONLY ACCEPT THE "STC=0" TYPE STATUS MESSAGES

;STY

	PUSHJ	P,EBI2BI	;GET THE STATUS BITS
	DPB	T1,LDPSTS##	;STORE THE NEW STATUS BITS
	MOVSI	T2,LDLLCT##	;LOWER-CASE CONVERSION FLAG
	TRNN	T1,STY.CV	;DOES REMOTE HAVE TTY LC SET?
	ANDCAM	T2,LDBDCH##(U)	;YES, SET TTY LC (CLEAR CASE CONVERSION)
	TRNE	T1,STY.CV	;DOES REMOTE HAVE TTY LC SET?
	IORM	T2,LDBDCH##(U)	;NO, SET TTY UC (SET CASE CONVERSION)
	MOVSI	T2,LDLTAB##	;HARDWARE-TABS FLAG
	TRNE	T1,STY.HT	;DOES REMOTE HAVE TTY TAB SET?
	IORM	T2,LDBDCH##(U)	;YES, SET TTY TAB
	TRNN	T1,STY.HT	;DOES REMOTE HAVE TTY TAB SET?
	ANDCAM	T2,LDBDCH##(U)	;NO, SET TTY NO TAB
	MOVSI	T2,LDLFRM##	;HARDWARE-FORMS FLAG
	TRNE	T1,STY.FF	;DOES REMOTE HAVE TTY FORM SET?
	IORM	T2,LDBDCH##(U)	;YES, SET TTY FORM
	TRNN	T1,STY.FF	;DOES REMOTE HAVE TTY FORM SET?
	ANDCAM	T2,LDBDCH##(U)	;NO, SET TTY NO FORM
	MOVSI	T2,LDLNFC##	;NO-FREE-CRLF FLAG
	TRNN	T1,STY.CR	;DOES REMOTE HAVE TTY CRLF SET?
	ANDCAM	T2,LDBDCH##(U)	;YES, SET TTY CRLF
	TRNE	T1,STY.CR	;DOES REMOTE HAVE TTY CRLF SET?
	IORM	T2,LDBDCH##(U)	;NO, SET TTY NO CRLF
	MOVSI	T2,LPLXNF##	;XON-XOFF FLAG
	TRNE	T1,STY.TP	;DOES REMOTE HAVE TTY XONXOF SET?
	IORM	T2,LDBPAG##(U)	;YES, SET TTY XONXOF
	TRNN	T1,STY.TP	;DOES REMOTE HAVE TTY XONXOF SET?
	ANDCAM	T2,LDBPAG##(U)	;NO, CLEAR TTY XONXOF
	TRNN	T1,STY.DE	;IF THE REMOTE IS LOCAL ECHOING
	JRST	[PUSHJ	P,MCROKE	;SEE IF WE THINK THAT'S OK
		  PUSHJ	P,D85CHP	;IF NOT, QUEUE A STATUS CHECK
		LDB	T1,LDPSTS##	;GET STATUS BITS BACK
		JRST	.+1]		;BACK TO MAIN FLOW.

;FALL THROUGH TO PLAY WITH THE MODEM-CONTROL BITS
SUBTTL 2.3.3.1        INCOMING MODEM CONTROL

MCRTIW:	MOVE	T2,LDBDCH##(U)	;THE UBIQUITOUS DCH BITS
	TRNN	T2,LDRDSD##	;SEE IF THIS IS A DATA SET
	JRST	CPOPJ1##	;NOT A DATA SET LINE
	MOVE	T2,LDBREM##(U)	;GET THE DATA SET BITS
	SETZ	T3,		;START OUR STATE VARIABLE WITH A ZERO
	TRNE	T1,STY.RG	;MAP REMOTE CARRIER/RING INTO
	IORI	T3,1		; BIT 35
	TRNE	T1,STY.DT	;MAP REMOTE DATA TERMINAL READY INTO
	IORI	T3,2		; BIT 34
	CAMN	U,DIALDB##	;IS THIS THE DIALOUT LINE?
	IORI	T3,4		;YES, DTR/CARRIER HAS DIFFERENT MEANING THEN
	PUSHJ	P,@MCRSTD(T3)	;DISPATCH ON STATE VAR
	PJRST	CPOPJ1		;AND WE ARE DONE!


;MODEM STATUS DISPATCH TABLE

MCRSTD:	IFIW	D85LST		;(I00) MAYBE NOTHING, MAYBE LOST CARRIER
	IFIW	D85RNG		;(I01) THE PHONE IS RINGING.
	IFIW	D85MLC		;(I10) MOMENTARY LOSS OF CARRIER?
	IFIW	D85RUN		;(I11) DTR AND CARRIER - DATASET UP AND RUNNING
	IFIW	D85DL0		;(O00) POSSIBLE SYNCHRONIZATION
	IFIW	D85DLR		;(O01) RING - ACKNOWLEDGEMENT OF DIALOUT REQ
	IFIW	D85DLX		;(O10) DTR - DIALOUT SUCCEEDED (BUT NO CARRIER)
	IFIW	D85DLW		;(O11) DTR - DIALOUT SUCCEEDED, LINE IS UP
;HERE TO SEE IF LOST THE PHONE

D85LST:	TLNN	T2,LRLDSR	;DID WE USED TO HAVE CARRIER?
	POPJ	P,		;NO, IGNORE
	MOVEI	T3,DSTOFF##	;GET PSISER'S MODEM OFFLINE FLAG
	PUSHJ	P,DSCSG		;SIGNAL LOST CARRIER
	PUSHJ	P,MCRDET	;DETACH THE JOB (OR WHATEVER)
	MOVSI	T1,LRLDSR##	;NOW CLEAR DSR SO WE KNOW THAT HE HAS
	ANDCAM	T1,LDBREM##(U)	;  GONE.  (KEEPS D85LST FROM RUNNING)
	POPJ	P,		;THAT'S THE END OF THAT PHONE CONVERSATION


;HERE IF THE PHONE IS RINGING

D85RNG:	HRRZ	T1,LDBDDB(U)	;HERE SEE IF THE TERMINAL HAS BEEN OPENED.
	JUMPE	T1,CPOPJ##	; NOT, WAIT FOR THE REMOTE
	MOVEI	T3,DSTRNG##	;OTHERWISE JUST SIGNAL THE FACT
	PJRST	DSCSG		;THAT A DATASET LINE IS RINGING


;HERE IF MOMENTARY LOSS OF CARRIER

D85MLC:	TLNN	T2,LRLDSR##	;DID WE HAVE CARRIER BEFORE?
	POPJ	P,		;NO, NOT TO WORRY THEN
	HRRZ	T1,LDBDDB##(U)	;ADDRESS OF ASSOCIATED DDB
	JUMPE	T1,CPOPJ##	;IGNORE IF NO TTY DDB
	MOVE	T2,DEVMOD(T1)	;GET DEVICE CHARACTERISTICS
	TRNN	T2,ASSPRG	;IN USE AS I/O DEVICE?
	POPJ	P,		;NO, NOBODY CARES
	MOVEI	T2,IODERR	;YES, SET THE DEVICE-ERROR FLAG
	IORM	T2,DEVIOS(T1)	;TO TELL USER THAT HIS I/O DEVICE HICCUPPED
	POPJ	P,		;OTHERWISE IGNORE MOMENTARY LOSS OF CARRIER


;DTR AND CARRIER - DATASET IS UP AND RUNNING

D85RUN:	TLNE	T2,LRLDSR##	;WAS CARRIER UP BEFORE??
	POPJ	P,		; IF IT WAS, THEN EVERYTHING'S OK
	PUSH	P,W		;THIS LINE JUST CAME UP. SAVE W,
	PUSHJ	P,TSETBI##	; AND CLEAR THE INPUT BUFFER.
	POP	P,W		; ...
	MOVSI	T1,LRLGRT##	;THE NEED-TO-BE-GREETED FLAG
	TDNE	T1,LDBREM(U)	;IS THIS GUY LONELY?
	JRST	D85RU4		;NO, HE'S HAPPY
	IORM	T1,LDBREM(U)	;YES, SO TAKE NOTICE OF HIM
	PUSHJ	P,TTFGRT##	;"WELL HELLO THERE"
D85RU4:	MOVSI	T1,LRLDSR##	;NOW SET A BIT TO REMEMBER THAT THIS
	IORM	T1,LDBREM##(U)	;LINE THINK'S THAT IT'S UP.
	PUSHJ	P,D85CHP	;KICK THE REMOTE TO LET IT KNOW WE CARE
	MOVEI	T3,DSTON##	;AND FINALLY TELL PSISER
	PJRST	DSCSG		; THAT IT'S UP.
;HERE FOR NO DTR/CARRIER ON DIALOUT, MAY BE DIALOUT FAILURE

D85DL0:	MOVSI	T2,LRLCHR##	;A TIMESHARED FLAG NAME HERE
	TDNN	T2,DIALFL##	;HAS REMOTE ACKNOWLEDGED THE DIALOUT REQ?
	POPJ	P,		;NO, JUST IGNORE
	MOVSI	T2,400000	;YES, THE LACK OF DTR IS DIALOUT FAILED
	IORM	T2,DIALFL##	;SET DIALOUT COMPLETION SANS SUCCESS
	POPJ	P,		;THAT'S THE END OF THAT


;DIALOUT "RING" IS ACKNOWLEDGEMENT

D85DLR:	MOVSI	T2,LRLCHR##	;A TIMESHARED FLAG NAME
	IORM	T2,DIALFL##	;WHICH IN THIS CASE MEANS REMOTE ACK OF DIALOUT
	POPJ	P,		;WHICH IS ALWAYS NICE TO KNOW


;DIALOUT DTR AND CARRIER = HAPPINESS

D85DLW:	MOVSI	T2,LRLDSR##	;OUR COPY OF CARRIER
	IORM	T2,LDBREM##(U)	;WE HAVE AN UP AND RUNNING DATASET LINE

;DIALOUT DTR SANS CARRIER = PUZZLEMENT

D85DLX:	MOVSI	T2,LRLDSR##!400000  ;THE DIALOUT HAS SUCCEEDED
	IORM	T2,DIALFL##	;SET COMPLETION AVEC SUCCESS
	POPJ	P,		;LET D85CRQ WAKE UP AND FIND THE GOOD NEWS


IFN FTPI,<
DSCSG:	PUSH	P,T1
	PUSH	P,F
	LDB	T2,LDPLNO##	;PSISER WANT'S ITS ARG AS A LINE NUMBER
	PUSHJ	P,SIGDSC##	;SIGNAL DATA SET STATUS CHANGE
	POP	P,F
	JRST	TPOPJ##
> ;END IFN FTPI

IFE FTPI,<
DSCSG:	POPJ	P,		;NO PSISER
> ;END IFE FTPI
SUBTTL 2.3.4        DAP CONTROL

;MCRCTL	ROUTINE TO PROCESS DAP TERMINAL CONTROL MESSAGES
;CALL	MOVEI	U,PCB
;	MOVEI	F,LDB
;	P1, P4 := POINTER TO THE "DCT" FIELD OF A DAP CONTROL MESSAGE
;RETURN	CPOPJ			;CONTROL TYPE NOT RECOGNIZED
;	CPOPJ1			;MESSAGE ACCEPTED

MCRCTL:				;SET LDB FIELDS AS FROM "SET TERMINAL" COMMAND.

;DCT

	PUSHJ	P,EBI2BI	;READ THE TYPE OF CONTROL
	CAIN	T1,DCT.EP	;ECHO PIPLINE
	JRST	MCREPM		;YES
	CAIN	T1,DCT.TC	;TERMINAL CHARACTERISTICS
	JRST	MCRCHR		;YES,
	POPJ	P,		;NONE OF THE ABOVE, ERROR RETURN

MCREPM:				;HERE TO PROCESS AN ECHO PIPELINE MARKER

;CDT

	ILDB	T1,P1		;GET THE SERIAL NUMBER
	SUBI	P4,1		;REDUCE THE COUNT
	DPB	T1,LDPEPM##	;STORE THE PIPELINE MARKER
	MOVSI	T1,LRLEPW##	;RETURN MARKER AT ONCE
	IORM	T1,LDBREM##(U)
	PUSHJ	P,MCROKE	;OK TO ECHO (TEST THE LDB)?
	  PJRST	CPOPJ1##	;EXIT. CAN'T SEND IT NOW
	PUSHJ	P,D85CHP	;QUEUE THE REQUEST SO IT GOES QUICK
	PJRST	CPOPJ1##	;EXIT
MCRCHR:	MOVSI	T1,LRLCHR##	;THE CHARACTERISTICS-SEEN FLAG
	TDNE	T1,LDBREM(U)	;BEEN HERE BEFORE?
	JRST	MCRCH4		;YEAH, JUST PROCESS THE NEW CHARACTERISTICS

;HERE WHEN A NEWLY-CONNECTED TERMINAL HAS SENT THE INITIAL CHARACTERISTICS

	IORB	T1,LDBREM##(U)	;MARK WE HAVE NOW RECEIVED CHARACTERISTICS
	MOVE	T2,LDBDCH##(U)	;GET GENERAL DEVICE CHARACTERISTICS
	TLNN	T1,LRLGRT##	;IF TERMINAL NEEDS TO BE GREETED
	TRNE	T2,LDRDSD##	;AND ISN'T A DATASET (D85RUN HANDLES THIS CASE)
	JRST	MCRCH4		;ALREADY GREETED, OR A DATASET
	MOVSI	T1,LRLGRT##	;THE GREETED FLAG
	IORM	T1,LDBREM##(U)	;WE ARE NOW GREETING IT
	PUSHJ	P,TTFGRT##	;"WELL HELLO THERE"

MCRCH4:	PUSHJ	P,XSKIP##	;READ
	PUSHJ	P,XSKIP##	; AND
	PUSHJ	P,XSKIP##	;  IGNORE
	PUSHJ	P,XSKIP##	;   THE
	PUSHJ	P,XSKIP##	;    FILL
	PUSHJ	P,XSKIP##	;     TIME(S)

	PUSHJ	P,EBI2BI	;GET THE RECEIVE SPEED
	MOVEI	T2,(T1)		;COPY TO T2
	PUSHJ	P,TTCSP1##	;GET THE SPEED INDEX
	CAIA			;DON'T SAVE INVALID SPEED
	DPB	P2,LDPRSP##	;STORE

	PUSHJ	P,EBI2BI	;GET THE TRANSMIT SPEED
	MOVEI	T2,(T1)		;COPY THE SPEED
	PUSHJ	P,TTCSP1##	;GET THE SPEED INDEX
	CAIA			;DON'T SAVE INVALID SPEED
	DPB	P2,LDPTSP##	;STORE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

	LDB	T2,LDPRSP##	;GET THE RECEIVE SPEED BACK
	MOVEI	T1,LDR274##	;GET 2741 BIT
	CAIN	T2,(P2)		;RECEIVE AND TRANSMIT THE SAME
	CAIE	T2,LS0134##	;IS IT AN IBM 2741
	SKIPA	T2,[ANDCAM T1,LDBDCH##(U)]	;CLEAR THE BIT
	MOVE	T2,[IORM T1,LDBDCH##(U)]	;SET THE BIT
	XCT	T2		;DO IT

	PUSHJ	P,EBI2BI	;WIDTH OF TERMINAL'S CHARRIAGE
	SKIPE	T1
	DPB	T1,LDPWID##	;STORE

	PUSHJ	P,EBI2BI	;GET THE AUTO CRLF
	SKIPE	T1
	DPB	T1,LDPACR##	;STORE

	PUSHJ	P,EBI2BI	;READ THE ELEMENT #
	MOVE	T3,T1		;COPY TO T3
	PUSHJ	P,ELEINX##	;GET THE INDEX
	  SETZ	T2,		;ILLEGAL
	DPB	T2,LDPELE##	;STORE THE ELEMENT NUMBER

	PUSHJ	P,EBI2BI	;GET THE 2741 BITS
	MOVE	T2,LDBISB##(U)	;GET THE FLAGS
	TRNE	T1,CDT.PL	;APL
	TLOA	T2,LILAPL##	;YES, SET
	TLZ	T2,LILAPL##	;NO, CLEAR
	TRNE	T1,CDT.CB	;DEBREAK
	TLOA	T2,LILDBK##	;YES, SET
	TLZ	T2,LILDBK##	;NO, CLEAR
	TRNE	T1,CDT.TD	;TIDY MODE?
	TLOA	T2,LILTDY##	;YES, SET
	TLZ	T2,LILTDY##	;NO, CLEAR
	HLLM	T2,LDBISB##(U)	;STORE THE RESULT
	PJRST	CPOPJ1		;RESTORE PCB AND GIVE GOOD RETURN
SUBTTL 3.0      INTERFACE TO NETSER FOR OUTPUT OF DATA

SUBTTL 3.1        NETWORK CONTROL MESSAGE OUTPUT (NCL)

SUBTTL 3.1.1        OUTPUT A CONNECT MESSAGE


;MCRXCN	ROUTINE TO SEND A MCR CONNECT MESSAGE.
;CALL	MOVEI	W,NDB		;NODE THAT OWNS THE TERMINAL
;	MOVEI	U,LDB		;LDB OF MCR TO CONNECT.
;				; SLA MUST BE SET UP.  DLA = 0 IMPLIES INITIATE.
;RETURN	CPOPJ			;COULDN'T SEND. NO CORE
;	CPOPJ1			;MESSAGES GIVEN TO NCL

MCRXCN:	PUSH	P,U		;SAVE THE LDB FOR A BIT
	PUSHJ	P,NCMHDR##	;U := PCB, (P)+ := "CNT" BYTE POINTER
	  JRST	UPOPJ##		;NO CORE?  GIVE ERROR RETURN
	EXCH	U,-1(P)		;GET THE LDB BACK FOR A WHILE.

;TYP

	XMTI	NC.CNT		;THIS IS A CONNECT MESSAGE

;DLA

	XMTB	LDPDLA##	;SEND DLA (OR 0 IF CONNECT INITIATE)

;SLA

	LDB	T1,LDPSLA##	;WE MUST HAVE A LAT ASSIGNED. SO
	SKIPN	T1		; MAKE SURE THAT THE SLA IS NON-ZERO
	STOPCD	.,STOP,MCRSLZ,	;++ SLA IS ZERO
	XMT	T1		;WRITE THE SLA

;DPN(OBJ)

	XMTI	OBJ.TY		;WE ARE CONNECTING TO A TERMINAL

;DPN(,PID)

	XMTB	LDPRLN##	; AND THIS IS HIS LINE NUMBER

;SPN(OBJ)

	XMTI	OBJ.TT		;WE ARE THE MONITOR CONTROL ROUTINE (MCR)

;SPN(,PID)

	XMTS	STANAM##	; AND THIS IS OUR NAME

;MML

	XMTI	^D512		;SEND THE MAX-MESSAGE-LENGTH (BUT NO-ONE CARES)

;FEA(DCM)

	XMTI	DCM.AS		;ASCII MODE

;FEA(,RLN)

	XMTI	0		;VARIABLE RECORD LENGTH

;FEA(,,DTY)

	XMTI	DTY.MC!DTY.AB!DTY.SB!DTY.27 ;OUR ATTRIBUTES

	EXCH	U,-1(P)		;GET THE PCB BACK
	JSP	T1,NETWRC##	;GIVE THE MESSAGE TO NCL
	PJRST	UPOPJ1##	;GIVE A GOOD RETURN
SUBTTL 3.1.2        OUTPUT A DISCONNECT MESSAGE

;TRMXDC	ROUTINE TO SEND A DISCONNECT TO A REMOTE TERMINAL.
;CALL	MOVE	T1,XWD NODE,RSN	;NODE IS NODE TO RE-CONNECT TO IF REASON
;				; IS RSN.RC (IE A SET-HOST STYLE DISCONNECT)
;	MOVEI	U,LDB
;	MOVEI	W,NDB
;	PUSHJ	P,TRMXDC
;RETURN	CPOPJ			;NO CORE.
;	CPOPJ1			;MESSAGE SENT
;
TRMXDC::			;HERE TO SEND A REMOTE TERMINAL A DISCONNECT.
	PUSH	P,T1		;SAVE THE "XWD NODE,RSN" FOR A BIT
	PUSH	P,U		;SAVE THE LDB
	PUSHJ	P,NCMHDR##	;GET A PCB, PUSH "CNT" POINTER ON STACK
	  JRST	[POP P,U	;IF NO CORE, REPLACE THE LDB,
		 JRST TPOPJ##]	; AND GIVE A BAD RETURN
	EXCH	U,-1(P)		;GET THE LDB ADDRESS BACK
;TYP
	XMTI	NC.DSC		;THIS IS A DISCONNECT MESSAGE
;DLA
	XMTB	LDPDLA##	;INSERT THE REMOTE'S LINK ADDRESS
;SLA
	XMTB	LDPSLA##	;INSERT OUR LINK ADDRESS
;RSN
	HRRZ	T1,-2(P)	;GET THE REASON
	XMT	T1		;SEND IT
;NNM
	HRRZ	T1,-2(P)	;GET THE REASON AGAIN
	CAIE	T1,RSN.RC	;IS THIS A "SET HOST" STYLE DISCONNECT?
	JRST	MCRXD1		;NO. DON'T SEND THE "NNM" BYTE
	HLRZ	T1,-2(P)	;GET THE "NNM"
	XMT	T1		; AND SEND THAT TOO

MCRXD1:	EXCH	U,-1(P)		;GET THE PCB BACK
	JSP	T1,NETWRC##	;GIVE THE MESSAGE TO NCL TO SEND
	POP	P,U		;RESTORE THE LDB
	LDB	T1,LDPSLA##	;NOW GET THE LAT ADDRESS, AND
	MOVEI	T2,LAT.DC	; CHANGE THE STATE TO BE
	DPB	T2,LATSTA##	; DISCONNECT CONFIRM WAIT.
	MOVSI	T1,LRLCON##	;GET THE "CONNECTED BIT"
	ANDCAB	T1,LDBREM##(U)	;AND CLEAR IT SO SCNMCR WON'T RUN
	JRST	TPOPJ1##	;GIVE GOOD RETURN
SUBTTL 3.2        TERMINAL OUTPUT SERVICE (SCNMCR)

				COMMENT @

There are three basic phases to the SCNMCR routine. They are:

   1)	Save and set up registers, and ensure that the terminal is connected.

   2)	Do a priority based scan looking for messages to send.  In decreasing
	priority these messages are:
	   a)	XOFF (DAP control)
	   b)	Character Gobbler (DAP control)
	   c)	Terminal Status (DAP status)  (From SCNCHP routine)
	   d)	Terminal Characteristics (DAP control)  (From SCNCHP routine)
	   e)	Terminal Data (DAP data)
	   f)	Auto Dial (DAP control)
	   g)	Terminal Echo Pipeline Marker (DAP control)

   3)	Send the message.  (Give it to NCL to send)

				    @
;SCNMCR	ROUTINE TO CONSTRUCT MCR MESSAGES.  (CALLED FROM NETSCN)
;CALL	MOVEI	U,LDB		;LDB WANTING SERVICE
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;LDB PROCESSED OK
;CLOBBERS W

SCNMCR::NTDBUG			;VERIFY THE INTERLOCK
	PUSHJ	P,SAVE4##	;SAVE THE P'S CAUSE SCNSER CALLS US.
	LDB	T2,LDPLNO##	;MAKE SURE A NETWORK LINE
	SUBI	T2,NETOFS##	;(THIS IS ONLY PART OF MCRCHK)
	JUMPL	T2,CPOPJ1##	;IF NOT, OK RETURN SO WON'T REQUEUE
	CAILE	T2,M.RMCR##	;OFF END?
	 JRST	CPOPJ1##	;GLAD WE CHECKED
	MOVE	T1,LDBREM##(U)	;STILL CONNECTED?
	TLNE	T1,LRLCON##	;??
	 JRST	SCNMC0		;YES, CONTINUE
	SKIPLE	LDBTOC##(U)	;NO - OUTPUT LEFT?
	 PUSHJ	P,TSETBO##	;YES, FLUSH IT
	PUSH	P,F		;SAVE F A BIT
	HRRZ	F,LDBDDB##(U)	;GET DDB
	JUMPE	F,FPOPJ1##	;IF NONE, GIVE OK RETURN
	MOVE	S,DEVIOS(F)	;GET STATUS BITS
	TLNE	S,IOW		;I/O WAIT?
	 PUSHJ	P,TTWAKE##	;YES, WAKE IT
	JRST	FPOPJ1##	;GIVE GOOD RETURN

SCNMC0:	LDB	T1,LDPRNN##	;GET THE NODE NUMBER, AND USE IT
	PUSHJ	P,SRCNDB##	; TO SET UP W (POINTER TO THE NDB)
	  JRST	CPOPJ1##	; IF NO NDB GIVE GOOD RETURN.
;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE
;COME HERE WITH U := LDB ADDRESS
;HERE IS WHERE WE SEE WHAT SORT OF SERVICE A MCR NEED'S

SCNMC1:	MOVE	T1,LDBREM##(U)	;GET THE REMOTE STATION BITS
	TLNN	T1,LRLXOF!LRLSCG ;NEED AN XOFF OR A GOBBLER?
	JRST	SCNMC2		; IF NOT, THEN CHECK THE PARMS
	TLNE	T1,LRLXOF##	;WAS IT AN XOFF WE NEEDED?
	JRST	[PUSHJ P,MCXXOF	; IF SO, THEN SEND THE XOFF, AND
		  JRST SCNMC6	; IF NO CORE, RE-QUEUE THE LINE
		 JRST SCNMC1]	; SEE IF THE MCR NEEDS OTHER SERVICE
	PUSHJ	P,MCXGBL	;IF IT WAS A GOBBLER, THEN SEND THAT,
	  JRST	SCNMC6		;IF NO CORE, RE-QUEUE THE LINE
	JRST	SCNMC1		; AND PERFORM OTHER SERVICES.

SCNMC2:	MOVE	T2,LDBBYT##(U)	;GET SCNSER'S FLAGS.
	TRNE	T2,L1RCHP##	;DOES SCNSER WANT A PARM CHANGE?
	JRST	[PUSHJ P,SCNCHP	; IF SO, THEN SEND THE CHANGE,
		  JRST SCNMC6	; IF NO CORE, REQUEUE THE LINE
		 JRST SCNMC1]	; AND PERFORM OTHER SERVICES.
	TLNE	T1,LRLTTW##	;ARE WE WAITING FOR A DATA-REQUEST?
	JRST	SCNMC4		; IF SO, THEN SKIP OUTPUT CHECK
	TLNE	T1,LRLTTO##	;DO WE ALREADY HAVE A CHAR IN LDPCHR?
	JRST	SCNMC3		;IF WE HAVE THE CHAR, DON'T CALL XMTCHR
	PUSHJ	P,XMTCHR##	;SEE IF SCNSER WILL GIVE US A CHAR
	  JRST	SCNMC4		;NO OUTPUT.  GO LOOK FOR OTHER WORK
	DPB	T3,LDPCHR##	;SAVE THE CHAR WHERE MCXDAT WILL LOOK
	MOVSI	T1,LRLTTO##	;GET THE "CHAR IN LDPCHR" BIT
	IORB	T1,LDBREM##(U)	; AND SET IT SO WE DON'T LOSE THE CHAR
SCNMC3:	PUSHJ	P,MCXDAT	; SEND THE DATA, AND
	  JRST	SCNMC6		; IF NO CORE, GET OUT NOW, OTHERWISE
	JRST	SCNMC1		; FINISH THE SERVICE

SCNMC4:	MOVE	T1,LDBREM(U)	;RELOAD T1
	TLNE	T1,LRLADR	;IS THERE AN AUTO DIAL REQUEST?
	JRST	[PUSHJ P,MCX801	; IF SO, THEN SEND THE NUMBER, AND
		  JRST SCNMC6	; IF NO CORE, RE-QUEUE THE LINE
		 JRST SCNMC1]	; CONTINUE PROCESSING
	TLNE	T1,LRLEPW	;IS ECHO PIPELINE MARKER WAITING?
	PUSHJ	P,MCROKE	;LOCAL ECHO OK NOW?
	  JRST	SCNMC5		; IF NOT, DON'T SEND EPM
	PUSHJ	P,TRXEPM	;OTHERWISE SEND THE EPM
	  JRST	SCNMC6		;NO CORE. REQUEUE THE LINE
SCNMC5:	AOS	(P)		;GIVE SKIP RETURN (WON'T REQUE THE LINE)
SCNMC6:	PUSHJ	P,TSDPCB	;FINALLY SEND THE MULTIPART MESSAGE
	POPJ	P,		; AND RETURN
;SCNCHP	ROUTINE TO DETERMINE IF TERMINAL STATUS, OR TERMINAL CHARACTERISTICS
;	MESSAGE NEEDS TO BE SENT.  ROUTINE IS CALLED FROM "SCNMCR" WHENEVER
;	SCNSER LITES THE "L1RCHP" BIT.  (THIS IS DONE BY THE "SETCHP" ROUTINE.)
;	THIS ROUTINE PERFORMS THE NECESSARY TRANSLATION FROM SCNSER'S BIT'S
;	TO NETMCR'S.
;CALL	MOVEI	U,LDB
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;WITH "L1RCHP" OFF.

SCNCHP:	PUSHJ	P,SAVE1##	;SAVE THE P'S
	SETZ	P1,		;LH = BITS TO SET, RH = CLEAR
	PUSHJ	P,MCROKE	;CHECK ON ECHOING MODE
	  TLO	P1,STY.DE	; AND CLEAR DE IF WE CAN'T ECHO NOW
	MOVE	T4,LDBDCH##(U)	;CARRY THE UBIQITOUS DCH IN T4
	TLNN	T4,LDLLCT##	;"TTY LC" SET?
	TROA	P1,STY.CV	;DONT TRANSLATE
	TLO	P1,STY.CV	;TRANSLATE
	MOVEI	T2,LRRXFF##	;GET SEND-XOFF STATUS BIT
	TDNN	T2,LDBREM##(U)	;SET FOR REMOTE?
	JRST	SCNCH0		;NO, SKIP IT
	ANDCAM	T2,LDBREM##(U)	;CLEAR THE BIT
	MOVSI	T2,LOLSTP##	;GET OUTPUT STOPPED BIT
	TDNN	T2,LDBOST##(U)	;IS IT SET IN THE STATES WORD?
	TROA	P1,STY.XS	;NO.
	TLO	P1,STY.XS	;YES.
SCNCH0:	TLNE	T4,LDLIMI##	;IF IMAGE MODE IS SET IN LDBDCH,
	TLOA	P1,STY.II	; TELL REMOTE TO SEND EVERYTHING
	TRO	P1,STY.II	;IF NOT, USE ASCII MODE
	MOVSI	T1,LRLIMO##	;IMAGE OUTPUT BIT
	TDNN	T1,LDBREM##(U)	;IMAGE OUTPUT?
	TROA	P1,STY.IO	;NO
	TLO	P1,STY.IO	;YES
	MOVE	T2,LDBOST##(U)	;GET SPECIAL STATES BITS
	TLNE	T2,LOLPIM##	;IF WE ARE IN PIM MODE, THEN OVER-RIDE
	JRST	[TRZ P1,STY.II!STY.IO	; ANY OTHER IMAGE MODE DECISIONS, AND
		 TLO P1,STY.II!STY.IO	; SINCE PIM DOESN'T ALWAYS GET THE
		 JRST .+1]		; BITS RIGHT CONTINUE.

	;FALL INTO NEXT PAGE
	;FROM ABOVE

	MOVE	T1,LDBPAG##(U)	;GET PAGING CONTROL
	MOVE	T2,LDBBY2##(U)	;AND CLOSELY RELATED BITS
	TLNE	T1,LPLXNF##	;IS XON/XOFF PROCESSING ENABLED?
	TLNE	T2,L2LTAP##	;YES, BUT "TTY TAPE" OVERRIDES IT
	TROA	P1,STY.TP	;NO - CLEAR XONXOFF PROCESSING IN REMOTE.
	TLO	P1,STY.TP	;YES - SET XONXOFF PROCESSING IN REMOTE.
	TRNN	T2,L2RXON##	;CHECK "TAPE IS XON'ED" BIT
	TROA	P1,STY.TT	;NOT IN TAPE MODE
	TLO	P1,STY.TT	;IN TAPE MODE
	TLNN	T4,LDLTAB##	;IS "TTY TAB" SET IN LDBDCH?
	TROA	P1,STY.HT	;NO.
	TLO	P1,STY.HT	;YES.
	TLNN	T4,LDLFRM##	;IS "TTY FORM" SET IN LDBDCH?
	TROA	P1,STY.FF	;NO.
	TLO	P1,STY.FF	;YES.
	TLNN	T4,LDLNFC##	;IS "TTY CRLF" SET IN LDBDCH?
	TROA	P1,STY.CR	;NO.
	TLO	P1,STY.CR	;YES.
	MOVSI	T2,LRLHUR##	;THE HANG-UP PHONE BIT
	TRNE	T4,LDRDSD##	;IS THIS A DATA-SET-LINE,
	TDNN	T2,LDBREM##(U)	; WITH A HANG-UP REQUEST PENDING?
	JRST	SCNCH1		;NO CONTINUE
	TRO	P1,STY.DT+STY.RG;TELL REMOTE TO CLEAR DTR AND CARRIER
SCNCH1:	ANDCAB	T2,LDBREM##(U)	;AND NOTE REQUEST HONORED

	HLRZ	T1,P1		;GET THE BITS TO "SET"
	TRNE	T1,STY.XS	;ARE WE SETTING XOFF?
	 JRST	SCNC1A		;YES, ALWAYS SEND XOFF STATUS
	LDB	T2,LDPSTS##	;GET THE CURRENT STATUS
	ANDCM	T1,T2		;WILL ANY REALLY GET SET?
	JUMPE	T1,SCNCH2	;IF NOT, DON'T SEND A "SET BITS" MESSAGE
SCNC1A:	PUSHJ	P,MCXSST	;SET THE BITS (IN REMOTE AND LDPSTS)
	  POPJ	P,		;GIVE ERROR RETURN IF NO CORE
SCNCH2:	HRRZ	T1,P1		;GET THE BITS TO "CLEAR"
	TRNE	T1,STY.XS	;ARE WE CLEARING XOFF?
	 JRST	SCNC2A		;YES, ALWAYS SEND XOFF STATUS
	LDB	T2,LDPSTS##	;GET THE CURRENT STATUS
	IORI	T2,STY.DT!STY.RG;ALWAYS SEND REQUEST TO CLEAR DTR/CARRIER
	AND	T1,T2		;WILL ANY BITS REALLY BE CLEARED
	JUMPE	T1,SCNCH3	;IF NOT, DON'T TRY TO CLEAR THEM
SCNC2A:	PUSHJ	P,MCXCST	;CLEAR THE BITS IN REMOTE AND LDPSTS
	  POPJ	P,		;GIVE ERROR RETURN IF NO CORE

	;DROP THROUGH
	;FROM ABOVE

;NOW CHECK TO SEE IF WE MUST SEND TERMINAL CHARACTERISTICS.

SCNCH3:	MOVE	T1,LDBREM##(U)	;GET REMOTE TERMINAL BITS
	TRC	T1,LRRSHC##	;CHANGE "CAN SET HOST" INTO "DC72" BIT
	TDNN	T1,[XWD LRLCHR##,LRRSHC##] ;IF DC72 OR WE HAVE RECEIVED CHARACTERSISTICS, OK TO SEND
	JRST	SCNCH4		;OTHERWISE, DON'T SEND ONE (***SEE FOOTNOTE)
	PUSHJ	P,GETCR		;TRANSLATE SPEED ETC TO CHARACTERISTICS WORD

	CAMN	T1,LDBCCH##(U)	;ANY CHANGE?
	JRST	SCNCH4		;NO CHANGE. GIVE GOOD RETURN
	PUSHJ	P,TRXTCR	;SEND THE CHARACTERISTICS. (WILL PUT T1 IN LDBCCH)
	  POPJ	P,		;NO CORE. GIVE ERROR RETURN

SCNCH4:	MOVEI	T1,L1RCHP##	;WE'VE SUCCESSFULY SCANED THE PARAMETERS
	ANDCAB	T1,LDBBYT##(U)	;SO CLEAR REQUEST SO WE DON'T DO IT AGAIN
	JRST	CPOPJ1##	;GOOD RETURN

;GETCR	ROUTINE TO TRANSLATE THE VARIOUS "CHARACTERISTICS"  IN TO A SINGLE WORD
GETCR::	MOVSI	T1,400000	;BUILD ENCODED CHARASTICS
	LDB	T2,LDPFLC##	;GET FILL CLASS
	DPB	T2,[POINT 4,T1,35]	;BITS 35-32
	LDB	T2,LDPRSP##	;GET RECEIVE SPEED
	DPB	T2,[POINT 4,T1,31]	;BITS 31-28
	LDB	T2,LDPTSP##	;GET TRANSMIT SPEED
	DPB	T2,[POINT 4,T1,27]	;BITS 27-24
	LDB	T2,LDPWID##	;GET WIDTH
	DPB	T2,[POINT 8,T1,23]	;BITS 23-16
	LDB	T2,LDPACR##	;GET AUTO CRLF POINT
	DPB	T2,[POINT 8,T1,15]	;BITS 15-8
	LDB	T2,LDPELE##	;GET THE ELEMNET NUMBER
	DPB	T2,[POINT 4,T1,7]	;BITS 4-7
	MOVE	T2,LDBISB##(U)	;GET THE CONTROL BITS
	TLNE	T2,LILAPL##	;APL MODE
	TLO	T1,(1B3)	;YES
	TLNE	T2,LILDBK##	;DEBREAK
	TLO	T1,(1B2)	;YES
	TLNE	T2,LILTDY##	;TIDY?
	TLO	T1,(1B1)	;YES
	POPJ	P,

;*** FOOTNOTE ***

				COMMENT @

     The terminal characteristics "protocol" is laden with races.  If both
the remote and the host decide to change the characteristics at the same time,
there is no telling what may happen.  This "hack" of the LRLCHR bit is a lame
effort to minimize the effects of this race.  It avoids the case of the host
sending a characteristics message with a speed of zero baud before the remote
has had a chance to tell the host what it's speed really is.

				    @
;MCXDAT	ROUTINE TO PACKAGE CHARACTERS INTO A DATA MESSAGE.
;CALL	PUSHJ	P,MCXDAT
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;SENT DATA

MCXDAT:	NTDBUG			;VERIFY THE INTERLOCK
	LDB	T1,LDPDRQ##	;GET THE NUMBER OF OUTSTANDING DATA-REQUESTS
	JUMPE	T1,[MOVSI T1,LRLTTW## ;IF WE DON'T HAVE ANY,
		    IORB T1,LDBREM##(U) ; THEN LITE LRLTTW SO WE WON'T
		    JRST CPOPJ1##] ; CALLED UNTIL SOME COME IN.
	LDB	T3,LDPCHR##	;GET THE STORED CHAR (FOR IT'S IMAGE BIT)
	PUSHJ	P,MCXDAM	;SEE IF IT'S BIT AGREES WITH LAST STATUS MSG
	  JRST	CPOPJ1##	;NEED TO SEND STATUS MSG. RETURN TO SCNMCR
	MOVEI	T1,2		;REQUEST A 2 BYTE MESSAGE (MINIMUM...)
	PUSHJ	P,TRQPCB	;TRY TO GET THE PCB
	  PJRST	TOPOKE##	;NO CORE.  REQUEUE THE LINE AND LEAVE.
	PUSH	P,W		;RUMOR HAS IT THAT SCNSER WILL CLOBBER THIS.
;TYP
	XMTI	DC.DAT		;WE ARE SENDING A DATA MESSAGE
	MOVSI	T1,LRLTTO##	;GET THE "OUTPUT CHAR IN LDPCHR" BIT
IFN PARANOID&P$MCR,<		;IF WE'RE PARANOID,
	TDNN	T1,LDBREM##(U)	;MAKE SURE IT'S ON
	STOPCD	.+1,DEBUG,MCRNCO,	;++NO CHARACTER FOR OUTPUT
> ;END PARANOIA
	ANDCAB	T1,LDBREM##(U)	;CLEAR THE "CHARACTER WAITING" BIT
	LDB	T3,LDPCHR##	;GET THE WAITING CHARACTER
	JRST	MCXD.2		;JUMP INTO THE MIDDLE OF THE COPY LOOP.

MCXD.1:	MOVEI	T1,L1RCHP##	;GET SCNSER'S "PARM CHANGE NEEDED" BIT
	TDNN	T1,LDBBYT##(U)	;AND SEE IF WE SHOULD SEND A STATUS MSG FIRST
	CAIL	P3,(P4)		;SEE IF WE HAVE FILLED UP THE ENTIRE MSG
	JRST	MCXD.4		;FILLED ENTIRE MESSAGE, OR PARM CHANGE NEEDED
	PUSHJ	P,XMTCHR##	;GET THE NEXT CHAR TO GO
	  JRST	MCXD.4		;NO OUTPUT READY.  CLOSE OFF MSG AND EXIT
MCXD.2:	PUSHJ	P,MCXDAM	;MAKE SURE THE IMAGE MODE BITS AGREE
	  JRST	MCXD.3		; IF NOT, STASH THE CHAR AWAY & SEND STATUS
	IDPB	T3,P2		;SEND THE CHAR
	AOJA	P3,MCXD.1	;COUNT THE CHAR AND TRY TO GET ANOTHER.
MCXD.3:	MOVSI	T1,LRLTTO##	;HERE TO GET OUT WHILE HOLDING A CHAR.
	IORB	T1,LDBREM##(U)	;SIGNIFY WE HAVE A CHAR IN LDPCLR
	DPB	T3,LDPCHR##	;STORE THE CHAR FOR NEXT TIME

MCXD.4:	POP	P,W		;GET OUR NDB POINTER BACK
	PUSHJ	P,TWRPCB	;SEND THE SUB MESSAGE
	HRRZ	T1,NTRPCB	;GET A POINTER TO OUR PCB
	MOVSI	T2,(<NCT.IT>B7)	;GET THE "INTERRUPT MESSAGE" BIT
	TDNN	T2,@PCBPTR(T1)	;SEE IF WE'VE ALREADY COUNTED THIS DRQ
	JRST	CPOPJ1##	;IF WE'VE COUNTED THE DRQ, THEN JUST LEAVE
	ANDCAB	T2,@PCBPTR(T1)	;CLEAR THE INT BIT (SO MESSAGE WILL COUNT)
	LDB	T2,LDPDRQ##	;GET THE DATA-REQUEST COUNT
	SOSGE	T2		;AND DECREMENT IT
	STOPCD	.+1,STOP,DRQNEG,;++ DATA REQUEST WENT NEGATIVE
	DPB	T2,LDPDRQ##	;SAVE THE UPDATED DRQ COUNT
	JRST	CPOPJ1##	;GIVE A GOOD RETURN
;MCXDAM	ROUTINE TO CHECK THE STATE OF THE IMAGE-OUTPUT BITS
;	USED ONLY BY MCXDAT
;CALL	T3 := CHAR (WITH CK.IMG BIT ON/OFF)
;	J  := LDB
;RETURN	NONSKIP			;MODES ARE DIFFERENT
;	SKIP			;MODES ARE THE SAME
;PRESERVES T3
MCXDAM:	SETZ	T1,		;START WITH A ZERO
	TRNE	T3,CK.IMG##	;IS THE "IMAGE MODE CHAR" BIT SET?
	TRC	T1,1		;IF AN IMAGE MODE CHAR, THEN T1 := 1
	MOVSI	T2,LRLIMO##	;GET THE IMAGE MODE OUTPUT BIT
	TDNE	T2,LDBREM##(U)	;SEE IF WE ARE IN IMAGE OUTPUT MODE
	TRC	T1,1		;IF WE ARE IN IMAGE MODE OUTPUT, COMPLEMENT T1
	JUMPE	T1,CPOPJ1##	;GIVE GOOD RETURN IF MODES ARE OK
	XORM	T2,LDBREM##(U)	;FLIP THE STATE OF THE LRLIMO
	PUSH	P,T3		;PRESERVE THE CHAR FOR A BIT
	PUSHJ	P,SETCHP##	;TELL SCNMCR TO SEND A STATUS MSG
	POP	P,T3		;GET THE CHAR BACK
	POPJ	P,		; AND GIVE AN ERROR RETURN
SUBTTL 3.2.2        OUTPUT DAP STATUS MESSAGE

;MCXSST/MCXCST ROUTINES TO SET AND CLEAR STATUS BITS
;CALL	MOVEI	T1,BITS		;TO BE CLEARED OR SET
;	PUSHJ	P,MCXSST/MCXCST
;	CPOPJ			;NO CORE
;	CPOPJ1			;MESSAGE SENT,  BITS SET/CLEARED IN LDPSTS

MCXSTA::MOVEI	T2,0		;SEND STATUS
	JRST	MCXST1		;GO TO COMMON CODE
MCXSST:	SKIPA	T2,[1]		;SET STATUS
MCXCST:	MOVEI	T2,2		;CLEAR STATUS
MCXST1:	PUSH	P,T1		;SAVE STD
	PUSH	P,T2		;SAVE STC
	MOVEI	T1,4		;WE WANT A 4 BYTE SUBMESSAGE
	PUSHJ	P,TRQPCB	; SET UP P3 & MUNG THE STACK
	  JRST	[POP P,(P)	;NO CORE. GIVE ERROR RETURN
		 JRST TPOPJ##]	; AND HOPE WE GET IT OUT LATER
	MOVEI	T1,DC.STS	;GET STATUS MESSAGE CODE
	PUSHJ	P,BI2EBI	;WRITE
;STC
	MOVE	T1,-1(P)	;GET THE STC
	PUSHJ	P,BI2EBI	;WRITE
;STD
	MOVE	T1,-2(P)	;GET THE STD
	PUSHJ	P,BI2EBI	;WRITE
;CNT
	PUSHJ	P,TWRPCB	;STORE BACK P3 & FIXUP THE STACK
	POP	P,T3		;GET THE STC BACK (1 = SET, 2 = CLEAR)
	POP	P,T2		;GET THE STD BACK (BITS TO SET/CLEAR)
	JUMPE	T3,CPOPJ1##	;IF SEND STATUS, DONT UPDATE STATUS
	LDB	T1,LDPSTS	;GET THE UN-UPDATED STATUS
	CAIN	T3,1		;WAS CODE SET OR CLEAR?
	TROA	T1,(T2)		;IS WAS SET. SET THE BITS
	TRZ	T1,(T2)		;IT WAS CLEAR.  CLEAR THE BITS
	DPB	T1,LDPSTS	;STORE THE UPDATED STATUS
	JRST	CPOPJ1##	;GOOD RETURN
SUBTTL 3.2.3        OUTPUT DAP CONTROL MESSAGE

SUBTTL 3.2.3.1        ECHO PIPELINE MARKER MESSAGE

;TRXEPM ROUTINE TO SEND AN ECHO PIPE LINE MARKER
;CALL	MOVEI	U,LDB
;	PUSHJ	P,TRXEPM
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;MESSAGE SENT

TRXEPM::MOVEI	T1,4		;REQUEST A 4 BYTE SUBMESSAGE
	PUSHJ	P,TRQPCB	; AND SET UP P3 AND STACK
	  POPJ	P,		;NO CORE, ERROR RETURN
;TYP
	MOVEI	T1,DC.CTL	;CONTROL MESSAGE
	PUSHJ	P,BI2EBI##	;SEND

;DCT
	MOVEI	T1,DCT.EP	;PIPE LINE MARKER FLAG
	PUSHJ	P,BI2EBI	;SEND

;CDT
	LDB	T1,LDPEPM##	;GET THE PIPE LINE MARKER
	PUSHJ	P,DPBBIN##	;SEND
;CNT

	MOVSI	T1,LRLEPW##	;EPM NO LONGER WAITING
	ANDCAM	T1,LDBREM##(U)	;CLEAR
	PUSHJ	P,TWRPCB	;STORE BACK P3 AND FIXUP STACK
	JRST	CPOPJ1##	;GOOD RETURN
SUBTTL 3.2.3.2        CHARACTER GOBBLER MESSAGE

;MCXGBL ROUTINE TO SEND A CHARACTER GOBBLER
;CALL	MOVEI	U,LDB
;	PUSHJ P,MCXGBL
;RETURN	CPOPJ		;MESSAGE SENT

MCXGBL:	MOVEI	T1,2		;REQUEST A 2 BYTE SUBMESSAGE
	PUSHJ	P,TRQPCB	; SET UP P3 AND STACK
	  POPJ	P,		;NO CORE, GIVE ERROR RETURN
;TYP
	MOVEI	T1,DC.CTL	;TELETYPE CONTROL MESSAGE
	PUSHJ	P,BI2EBI	;SEND
;DCT
	MOVEI	T1,DCT.CG	;CHARACTER GOBLER CODE
	PUSHJ	P,BI2EBI	;SEND
	MOVSI	T1,LRLSCG##!LRLTTO##	;CHARACTER GOBBLER AND LDPCHR BITS
	ANDCAM	T1,LDBREM##(U)	;CLEAR THEM
;CNT
	PUSHJ	P,TWRPCB	;WRITE BACK P3 AND FIXUP STACK
	JRST	CPOPJ1##	;GIVE GOOD RETURN
SUBTTL 3.2.3.3        TERMINAL CHARACTERISTICS MESSAGE

;TRXTCR ROUTINE TO SEND TERMINAL CHARACTERISTICS MESSAGE.
;CALL	MOVEI	U,LDB
;	MOVE	T1,NEW-CHARACTERISTICS (WILL BE PUT IN LDBCCH IF SUCCESSFUL)
;	PUSHJ	P,TRXTCR
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;CHARACTERISTICS SENT

TRXTCR::PUSHJ	P,SAVE1##	;WE WANT TO USE P1 FOR A TEMP
	MOVE	P1,T1		;SAVE CHARACTERISTICS TO SEND

	MOVEI	T1,27		;REQUEST A LARGE SUBMESSAGE
	PUSHJ	P,TRQPCB	; AND SET UP P3 AND STACK
	  POPJ	P,		;NO CORE. GIVE AN ERROR RETURN
;TYP
	MOVEI	T1,DC.CTL	;SET UP CONTROL MESSAGE
	PUSHJ	P,BI2EBI	;WRITE
;DCT
	MOVEI	T1,DCT.TC	;TELETYPE CHARASTICS
	PUSHJ	P,BI2EBI	;WRITE
;CDT
	PUSH	P,P1			;SAVE "P1" OVER THIS LOOP
	LDB	T1,[POINT 2,P1,35]	;FILL CLASS
	MOVE	P1,FILTAB(T1)	;GET POINTER TO CONSTANTS
	MOVEI	T4,6		;COUNTER
MCRTC1:	ILDB	T1,P1		;GET FILL VALUE
	LDB	T2,[POINT 4,(P),27]	;XMIT SPEED
	MOVE	T2,LSPTAB##(T2)	;GET SPEED VALUE
	SKIPN	T2		;PRESENT?
	MOVEI	T2,^D110	;NO, ASSUME 110 BAUD.
	MOVEI	T3,^D10000	;COMPUTE BAUD RATE FACTOR
	CAIN	T2,^D110	;110 BAUD?
	MOVEI	T3,^D11000	;YES, ASSUME 11-UNIT CODE
	IMUL	T1,T3		;MULTIPLY BY FACTOR
	IDIV	T1,T2		;COMPUTE WAIT TIME IN MS.
	PUSHJ	P,BI2EBI	;WRITE
	SOJG	T4,MCRTC1	;DO FOR ALL SIX TIMES
	POP	P,P1		;GET OUR CHARACTERISTICS BACK
	LDB	T1,[POINT 4,P1,31]
	MOVE	T1,LSPTAB##(T1)	;GET RECEIVE SPEED
	PUSHJ	P,BI2EBI	;WRITE
	LDB	T1,[POINT 4,P1,27]
	MOVE	T1,LSPTAB##(T1)	;GET TRANSMIT SPEED
	PUSHJ	P,BI2EBI	;WRITE
	LDB	T1,[POINT 8,P1,23]
	PUSHJ	P,BI2EBI	;WRITE
	LDB	T1,[POINT 8,P1,15]
	PUSHJ	P,BI2EBI	;WRITE
;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE
	LDB	T1,LDPELE##	;ELEMENT NUMBER NOT IMPLEMENTED
	MOVE	T1,ELETAB##(T1)	;GET THE VALUE FROM THE TABLE
	PUSHJ	P,BI2EBI	;WRITE
	MOVEI	T1,0		;IBM 2741 BITS
	MOVE	T2,P1		;GET THE 2741 BITS
	TLNE	T2,(1B3)	;APL MODE
	TRO	T1,CDT.PL	;YES, SET THE BIT
	TLNE	T2,(1B2)	;DEBREAK FEATURE
	TRO	T1,CDT.CB	;YES, SET THE BIT
	TLNE	T2,(1B1)	;TIDY?
	TRO	T1,CDT.TD	;YES
	PUSHJ	P,BI2EBI	;WRITE
	PUSHJ	P,TWRPCB	;WRITE BACK P3
	MOVEM	P1,LDBCCH(U)	;STORE THE NEW CHARACTERISTICS
	JRST	CPOPJ1##	;GIVE A GOOD RETURN
SUBTTL 3.2.3.4        AUTO DIAL MESSAGE

;MCX801 ROUTINE TO SEND A AUTO DIAL MESSAGE TO THE REMOTE DN80
;CALL	MOVEI	U,LDB
;	PUSHJ	P,MCX801
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;ALWAYS (WE CHECKED FOR CORE)

MCX801:	MOVEI	T1,30		;REQUEST A 24 BYTE SUBMESSAGE
	PUSHJ	P,TRQPCB	; AND SET UP P3 AND STACK
	  POPJ	P,		;GIVE ERROR RETURN IF NO CORE
;TYP
	MOVEI	T1,DC.CTL	;CONTROL MESSAGE
	PUSHJ	P,BI2EBI	;SEND
;DCT
	MOVEI	T1,DCT.AD	;AUTO DIAL CODE
	PUSHJ	P,BI2EBI	;SEND
;CDT
	MOVE	T4,[POINT 4,DIALNM##]	;GET THE POINTER TO THE PHONE NUMBER
MCX802:	ILDB	T1,T4		;GET A DIGIT
	ADDI	T1,"0"+200	;MAKE EXTENSIBLE ASCII
	IDPB	T1,P2		;STORE IN THE MESSAGE
	CAIE	T1,17+"0"+200	;IS IT THE END
	AOJA	P3,MCX802	;COUNT THE CHARACTER
	ADDI	P3,1		;COUNT THE LAST BYTE
	TRZ	T1,200		;CLEAR THE CONTINUE BIT
	DPB	T1,P2		;RESTORE IT
	MOVE	U,DIALDB##	;GET THE LDB FOR THE DIAL
	MOVSI	T1,LRLADR##	;GET THE AUTO DIAL BIT
	ANDCAM	T1,LDBREM##(U)	;CLEAR THE REQUEST
	MOVEM	T1,DIALFL##	;NOTE DIALOUT REQUEST PROCESSED
				; WAITING FOR REMOTE TO ACKNOWLEDGE
				;   RING = ACKNOWLEDGEMENT OF DIALOUT REQ, THEN
				;      DTR ASSERTED = SUCCESS, OR
				;      DTR CLEARED  = FAILURE
;CNT
	PUSHJ	P,TWRPCB	;WRITE BACK P3 AND FIXUP STACK
	JRST	CPOPJ1##	;GIVE SUCCESSFUL RETURN
SUBTTL 3.2.3.5        XOFF MESSAGE

;MCXXOF ROUTINE TO ASK THE REMOTE TO XOFF A USER
;CALL	MOVEI	U,LDB
;	PUSHJ	P,MCXXOF
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;XOFF MESSAGE SENT SUCCESSFULY


MCXXOF:	MOVEI	T1,2		;GET A 2 BYTE SUBMESSAGE
	PUSHJ	P,TRQPCB	; AND SET UP P3 AND STACK
	  POPJ	P,		;GIVE ERROR RETURN IF NO CORE
;TYP
	MOVEI	T1,DC.CTL	;TERMINAL CONTROL MSG
	PUSHJ	P,BI2EBI	;SEND THAT TOO
;DCT
	MOVEI	T1,DCT.XF	;XOFF REQUEST
	PUSHJ	P,BI2EBI	;SEND THAT
	MOVSI	T1,LRLXOF##	;GET AND CLEAR THE BIT
	ANDCAM	T1,LDBREM##(U)	; SO WE DON'T DO IT AGAIN
;CNT
	PUSHJ	P,TWRPCB	;WRITE BACK P3 AND FIXUP STACK
	JRST	CPOPJ1##	; AND GIVE A GOOD RETURN
SUBTTL 3.3        OUTPUT PCB MANIPULATION

;THE FOLLOWING FOUR ROUTINES ARE USED FOR HANDLING TERMINAL PCB'S.  THE
; REASON THAT THEY ARE SO COMPLEX IS TO MAKE IT EASY TO SEND
; MULTI-PART MESSAGES.
;
;TRQPCB	REQUEST A TERMINAL PCB.
;CALL	PUSHJ	P,TRQPCB
;ARGS	T1 := MINIMUM NUMBER OF BYTES REQUIRED (LESS COUNT FIELD)
;RET	CPOPJ	;COULD NOT GET THE PCB.  "U" NOT SET UP.
;	CPOPJ1	;DID GET THE PCB. THE FOLLOWING HAS BEEN DONE:
;		;  A)	P2 := BYTE POINTER (TO IDPB WITH)
;		;  B)	P3 := ZERO (USE TO COUNT BYTES)
;		;  C)	P4 := MAX NUMBER OF BYTES LEFT IN THIS
;		;	      SUB MESSAGE. (IE. TO END OF PCB)
;		;  D)	A "PUSH P,P2" HAS BEEN DONE. (IE THIS
;		;	ROUTINE HAS LEFT A COPY OF P2 ON THE STACK)
;		;	THIS IS TO MAKE IT EASY TO FILL IN THE
;		;	COUNT FIELD LATER.  TWRPCB MUST BE CALLED
;		;	TO PERFORM THIS ACTION. (CANNOT BE CALLED WITH
;		;	A ZERO COUNT)
;
;TWRPCB	WRITE BACK THE PCBPTR AND PCBCTR FIELDS AND POP OLD BYTE
;	POINTER OFF OF THE STACK
;CALL	PUSHJ	P,TSRPCB
;RET	CPOPJ
;
;TSDPCB	SEND THE CURRENT PCB. (QUEUE IT FOR OUTPUT)
;CALL	PUSHJ	P,TSDPCB
;RET	CPOPJ	;NTRPCB WILL BE CLEARED TO INDICATE PCB WAS SENT.
SUBTTL 3.3.1        REQUEST AN OUTPUT PCB

;TRQPCB	GET A TERINAL PCB
;	T1 := MINIMUM NUMBER OF BYTES
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;PCB ACQUIRED SUCCESSFULY

TRQPCB::SKIPLE	T1		;WE DON'T ALLOW NEGATIVE REQUESTS
	CAIL	T1,NTTPLN##*4-7	;HERE MAKE SURE HE ASKED FOR A REASONABLE AMT.
	STOPCD	.,STOP,RTM,	;++REQUESTED TOO MUCH.
	PUSH	P,T1		;REMEMBER THIS FOR LATER
	PUSH	P,U		;SAVE THE LDB (WILL SWAP FOR PCB LATER)
	HRRZ	U,NTRPCB	;NOW GET CURRENT PCB (IF ANY)
	SKIPE	U		; IF THERE WAS ONE, THEN
	JRST	[MOVE P3,PCBCTR(U) ; SET UP THE COUNT AND SKIP THE CODE THAT
		 JRST TRQP.2]	   ; TRIES TO ALLOCATE A NEW PCB
TRQP.1:	MOVEI	T1,NTTPLN##	;GET LENGTH OF A TERMINAL PCB
	SETZ	F,		;MAKE SURE MAKPCB DOESN'T HACK ANY DDB
	PUSHJ	P,MKNPCB##	; AND GO GET A NEW PCB.
	  JRST	[POP P,U	;NO CORE. RESTORE THE LDB
		 JRST TPOPJ##]	; AND GIVE AN ERROR RETURN
	HRRM	U,NTRPCB	;NOW STORE THE FACT WE HAVE A PCB.
	MOVE	P2,PCBPTR(U)	; AND SET UP THE INITIAL BYTE POINTER
	MOVEI	T1,NCT.IT	;GET THE NCT BITS
	PUSHJ	P,NCSWHD##	;WRITE THE NCL HEADER.
	SETZ	P3,		;NOW WRITE OUR DLA.  TO DO THIS WE MUST
	EXCH	U,(P)		; GET BACK OUR LDB,
	LDB	T1,LDPDLA##	; USE IT TO EXTRACT OUR DESTINATION LINK,
	PUSHJ	P,BI2EBI	; AND THIS WILL WRITE IT OUT.
	EXCH	U,(P)		;NOW GET BACK THE PCB POINTER,
	ADDB	P3,PCBCTR(U)	; UPDATE THE POINTERS, AND DROP INTO MAIN FLOW

TRQP.2:	MOVEI	P4,NTTPLN##*4	;HERE WE MUST CALCULATE TO SEE IF THE CURRENT
	SUBI	P4,1(P3)	; PCB WILL HOLD AS MUCH AS OUR CALLER
	CAMGE	P4,-1(P)	; REQUESTED IT SHOULD.  IF IT CAN'T, THEN
	JRST	[PUSHJ P,TSDPCB	; SEND THIS PCB OUT, AND
		 JRST TRQP.1]	; START ON A NEW ONE.
	POP	P,U		;RESTORE THE LDB
	POP	P,T1		; THE REQUEST (WHICH WE CAN NOW IGNORE)
	POP	P,T1		; AND POP OFF OUR RETURN ADDRESS.
	PUSH	P,P2		;NOW SAVE A BYTE POINTER TO COUNT FIELD
	IBP	P2		; AND MAKE POINTER POINT TO THE TYP FIELD
	SETZ	P3,		;SET THE INITIAL COUNT TO ZERO.
	JRST	1(T1)		;ALL DONE.  RETURN TO CALLER.
				; (WITH UNESTHETIC GARBAGE ON THE STACK ...)
SUBTTL 3.3.2        CLOSE OFF A DAP SUB-MESSAGE

;TWRCPB	THIS ROUTINE WRITES BACK THE COUNT FIELD AND UPDATES THE POINTER
;	IN THE PCB.  IT ALSO REMOVES UNESTHETIC GARBAGE FROM THE STACK
;CALL	PUSHJ	P,TWRPCB
;RETURN	CPOPJ		;WITH ONE LESS WORD ON THE STACK

TWRPCB::SKIPG	P3		;IF NO-ONE WROTE ANYTHING, THEN COMPLAIN
	STOPCD	.,STOP,NWA,	;++NO-ONE WROTE ANYTHING?
	PUSH	P,U		;SAVE THE LDB, AND
	HRRZ	U,NTRPCB	; GET BACK A POINTER TO THE PCB
	SKIPE	U		;HERE JUST MAKE A LITTLE CHECK ON U'S VALIDITY
	CAILE	P3,(P4)		; AND MAKE SURE NO ONE WROTE TOO FAR
	STOPCD	.,STOP,SNS,	;++NTRPCB NOT SETUP??
	ADDM	P3,PCBCTR(U)	;NOW UPDATE THE COUNT AND
	AOS	PCBCTR(U)	; DON'T FORGET ABOUT THE 'COUNT' BYTE
	POP	P,U		;RESTORE THE LDB,
	POP	P,T1		; GET OUR RETURN ADDRESS,
	POP	P,T2		; AND GET BACK THE POINTER TO THE COUNT FIELD.
	IDPB	P3,T2		;STORE THE COUNT,
	JRST	(T1)		; AND RETURN
SUBTTL 3.3.3        SEND A COMPLETED NCL MESSAGE

;TSDPCB	SEND A PCB OUT.  THIS NUMBERS AND SENDS THE CURRENT PCB.
;CALL	PUSHJ	P,TSDPCB
;RETURN	CPOPJ			;ALWAYS

TSDPCB::PUSH	P,U		;SAVE THE LDB (OR WHATEVER)
	HRRZ	U,NTRPCB	;GET THE PCB POINTER
	JUMPE	U,UPOPJ		; BUT RETURN QUICK IF THERE ISN'T ONE
	PUSHJ	P,NETWRT##	;ASSIGN MESSAGE NUMBERS AND SEND THE MESSAGE
	HLLZS	NTRPCB		;CLEAR POINTER TO PCB
	JRST	UPOPJ		; AND RETURN
SUBTTL 4.0      UTILITY ROUTINES AND INTERFACE TO UUOCON
SUBTTL 4.1        PARSE THE NCL CONNECT MESSAGE FOR A TERMINAL


;TTYRPN	ROUTINE TO READ THE "SPN" FIELD OF A CONNECT AND LOOK FOR OPR TERMINALS.
;CALL	MOVEI	U,LDB		;OF TTY BEING CONNECTED
;	P1, P4 POINT TO THE "SPN" FIELD OF THE CONNECT (OBJ AND PID)
;RETURN	CPOPJ			;WITH NDBOPR SET IF THIS WAS TERMINAL #0
TTYRPN:				;HERE TO READ THE "SPN" ON A MCR CONNECT
;SPN(OBJ)
	PUSHJ	P,EBI2BI##	;GET THE OBJECT TYPE
	CAIE	T1,OBJ.TY	;SEE IF IT'S A TERMINAL.
	PJRST	XSKIP##		;DON'T LET TASKS BECOME "OPR'S"
;SPN(PID)
	PUSHJ	P,EBI2BI##	;READ THE LINE NUMBER
	DPB	T1,LDPRLN##	;SAVE IT FOR POSTERITY
	CAIN	T1,0		;IS IT THE OPR'S LINE
	HRRM	U,NDBOPR(W)	;IF SO, REMEMBER THIS LDB
	POPJ	P,
;TTYRAT	ROUTINE TO READ THE "ATTRIBUTES" FROM A TERMINAL'S CONNECT MESSAGE
;CALL	MOVEI	U,LDB		;TERMINAL TO READ ATTRIBUTES FOR
;	P1, P4 POINT TO THE "MML" BYTE OF THE CONNECT MESSAGE (AFTER DPN)
;RETURN	CPOPJ			;AFTER SETTING/CLEARING THE PROPER BITS IN LDB
;				; AND FORCING A "GREETING"
;
TTYRAT:				;HERE TO READ ATTRIBUTES OF A CONNECT

;MML
	PUSHJ	P,XSKIP##	;SO FAR WE IGNORE MAX-MESSAGE-LENGTH...

;FEA(DCM)

	PUSHJ	P,XSKIP##	;WE KNOW MORE ABOUT THE MODES THAN THE REMOTE...

;FEA(RLN)

	PUSHJ	P,XSKIP##	;WE ASSUME A VARIABLE RECORD LENGTH

;FEA(DVT)=DTY

	PUSHJ	P,EBI2BI##	;READ THE ATTRIBUTES
	MOVE	T2,[XWD LRLADL##!LRLATO##!LRLDSR##,LRRSHC##]
	ANDCAM	T2,LDBREM##(U)	;CLEAR ALL "ATTRIBUTE" TYPE BITS
	MOVEI	T2,LDRDSD##!LDR274##	;DATASET, 2741 LINE FLAGS
	ANDCAM	T2,LDBDCH##(U)	;CLEAR OTHER "ATTRIBUTE" TYPE BITS
	MOVEI	T3,APCHWD##	;ASSUME A HARDWIRED LINE

;FIRST, THE DCH ATTRIBUTES

	TRNE	T1,DTY.MC	;MODEM CONTROL ON THIS LINE
	SKIPA	T3,[APCDSD##]	;YES--GET DATASET APC CODE
	TDZA	T2,T2		;NOT A DATASET
	MOVEI	T2,LDRDSD##	;MARK TTY AS A DATASET TTY
	TRNE	T1,DTY.27	;IBM 2741?
	TRO	T2,LDR274##	;YES, SET THE BIT
	IORM	T2,LDBDCH##(U)	;SET APPROPRIATE DCH ATTRIBUTES/CHARACTERISTICS

;SECOND, THE REM ATTIBUTES

	TRNE	T1,DTY.AD	;AUTO DIAL LINE (BELL 801)
	SKIPA	T3,[APCADL##]	;YES--GET DIALOUT APC CODE
	TDZA	T2,T2		;NOT AUTO DIAL
	MOVSI	T2,LRLADL##	;FLAG AS DIALOUT CAPABLE
	TRNE	T1,DTY.AB	;AUTO BAUD LINE
	TLO	T2,LRLATO##	;YES, SET THE BIT
	TRNE	T1,DTY.SH	;CAN THIS LINE DO "SET HOST"
	TRO	T2,LRRSHC##	;IF SO, THEN ENABLE THE COMMAND
	IORB	T2,LDBREM##(U)	;SET APPROPRIATE REM ATTRIBUTES
	DPB	T3,LDPAPC##	;SET ASYNC PORT CHARACTERISTIC

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;FEA(DVU)

	PUSHJ	P,EBI2BI	;GET THE "UNIT" TYPE
	CAILE   T1,APCMAX##	;APC CODE OUT OF RANGE
	MOVEI	T1,APCHWD##	;YES--ASSUME A HARD WIRED LINE
	CAIE	T1,APCUNK##	;UNKNOWN?
	DPB	T1,LDPAPC##	;NO--STORE APC FOR CURIOUS PROGRAMS

;FEA(DVV)

	PUSHJ	P,EBI2BI	;GET THE "CONTROLLER" TYPE
				; AND PITCH IT TOO

;ALL DONE WITH TTY "ATTRIBUTES"

	PJRST	SETCHP##	;MAKE SURE WE SEND STATUS SOON
SUBTTL 4.2        MANIPULATE LDB'S

;MCRCHK	ROUTINE TO ENSURE THAT A LDB IS USABLE
;CALL	MOVEI	U,LDB
;	PUSHJ	P,MCRCHK
;RETURN	CPOPJ			;LDB NOT CONNECTED, (OR WORSE...)
;	CPOPJ1			;LOOKS OK AS FAR AS I CAN TELL ...
MCRCHK::MOVE	T1,LDBREM##(U)	;GET THE REMOTE BITS
	TLNN	T1,LRLCON##	;IS THIS LDB "CONNECTED"
	POPJ	P,		;IF NOT, DON'T USE IT (ERROR RETURN)
	LDB	T2,LDPLNO##	;YES, GET PHYSICAL LINE NO.
	SUBI	T2,NETOFS##	;RELOCATE TO A REMOTE LINE
	JUMPL	T2,CPOPJ##	;NOR IN RANGE
	CAIG	T2,M.RMCR##	;CHECK LENGTH
	AOS	(P)		;OK
	POPJ	P,		;NO ERROR

;MCROKE	ROUTINE TO TEST THE LDB AND SKIP RETURN IF LOCAL
;  ECHOING SHOULD BE ALLOWED.
;LDB ADDRESS IN U.
MCROKE:	MOVE	T1,LDBREM##(U)	;GET REMOTE STATION BITS
	TLNE	T1,LRLTTW##!LRLTTO##	;THIS TERMINAL WAITING?
	POPJ	P,		; THEN DONT SEND EPM.
	MOVE	T1,LDBBY2##(U)	;NO, GET MISC. TERMINAL BITS
	SKIPL	LDBBKB##(U)	;IN USER DEFINED BREAK SET MODE
	TLNE	T1,L2LDEL##	;NO, ARE WE IN RUBOUT SEQUENCE?
	POPJ	P,		;YES, DONT RETURN EPM.
	SKIPGE	T1,LDBDCH##(U)	;GET STATUS BITS, SKIP IF OUTPUT ACTIVE
	TLNE	T1,LDLNEC##!LDLLCP##!LDLCNE##!LDLBKA##!LDLIMI##	;PROGRAM CONTROL?
	POPJ	P,		;YES
	SKIPL	LDBATR##(U)	;IF 8-BIT
	SKIPGE	LDBCHM##(U)	;OR FANCY MAPPING
	POPJ	P,		;CAN'T DO IT
		EXTERN	LAL8BT,LMLNDS	;FLAG BITS REFERENCED
	SKIPE	LDBIST##(U)	;IF DOING FANCY TWO-CHARACTER INPUT,
	POPJ	P,		;CAN'T DO IT
	MOVE	T1,LDBBYT##(U)	;GET THE DEFERRED ECHO BITS
	TRNE	T1,L1RDEM##	;IF NOT DEFERRED ECHO,
	TRNE	T1,L1RDEL##	; OR IF WAITING FOR A LINE
	TLNE	T1,L1LUNR##	;AND NOT DOING UNREAD
	POPJ	P,		;NO--FAIL IF NOT WAITING FOR A LINE
	JRST	CPOPJ1##	;YES--WE CAN DO IT
;TRM.UP	ROUTINE TO DECLARE AN LDB AS "ON LINE".
;CALL	MOVEI	U,LDB		;WITH DLA, SLA SET UP
;	PUSHJ	P,TRM.UP
;RETURN	CPOPJ			;WITH LDB READY TO MASH BITS
TRM.UP::LDB	T1,LDPSLA##	;GET OUR LAT ADDRESS
	MOVEI	T2,LAT.OK	; AND SET OUR STATE
	DPB	T2,LATSTA##	; TO BE "OK"
	MOVSI	T1,LRLCON##	;GET THE "CONNECTED" BIT
	IORB	T1,LDBREM##(U)	; AND SET IT.  LDB IS OFFICIALLY "ON LINE"
	MOVSI	T1,L1LOFL##	;SCNSER OFF-LINE BIT
	ANDCAM	T1,LDBOFL##(U)	;CLEAR NOW, IRMA WON"T BE AROUND FOR AWHILE
	POPJ	P,



;NMCWAK	ROUTINE TO TRY TO WAKE A JOB WAITING FOR A TERMINAL CONNECT.
;CALL	MOVEI	U,LDB
;	PUSHJ	P,NMCWAK
;RETURN	CPOPJ			;ALWAYS.
NMCWAK:	LDB	T1,LDPJOB##	;GET THE NUMBER OF JOB WAITING
	JUMPE	T1,CPOPJ##	;IF NONE, DON'T WAKE JOB ZERO
	PUSHJ	P,EWAKE##	;WAKE THE JOB
	SETZ	T1,		;GET A ZERO,
	DPB	T1,LDPJOB##	;  AND CLEAR THE JOB NUMBER FIELD
	POPJ	P,		;ALL DONE
;MCRGET ROUTINE TO GET AN ANF TERMINAL LDB
;CALL	PUSHJ	P,MCRGET
;RETURN CPOPJ IF FAILURE
;	CPOPJ1 WITH U/LDB ADDRESS

MCRGET:	MOVSI	T1,LTLANF##	;FLAG NEW ANF-10 TERMINAL
	MOVEI	T3,MCRDSP	;ANF MCR ISR DISPATCH VECTOR
	PUSHJ	P,GETLDB##	;GET A FREE LDB
	 POPJ	P,		;CAN'T, FAILURE RETURN
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER
	DPB	T1,LDPRNN##	;ASSIGN THE LDB TO THE REMOTE NODE
	MOVEI	T1,MCRRTQ	;ANF MCR QUEUE HEADER
	HRLZM	T1,LDBQUH##(U)	;STORE FOR SCNSER'S TOPOKE/TOTAKE
	JRST	CPOPJ1##	;SUCCESS RETURN



;MCRDET ROUTINE TO DETACH A TERMINAL FROM THE JOB
;CALL	MOVEI	U,LDB
;	PUSHJ	P,MCRDET
;RETURN	CPOPJ

MCRDET:	PUSHJ	P,SAVJW		;SAVE J,W
	MOVEI	T1,IONND%	;"NODE DOWN" I/O ERROR STATUS
	PJRST	DETLDB##	;DETACH THE LDB/DDB



;MCRFRE	ROUTINE TO FREE AN ANF TERMINAL'S ASSOCIATED LAT & LDB
;CALL	MOVEI	U,LDB
;	PUSHJ	P,MCRFRE
;RETURN	CPOPJ

MCRFRE::NTDBUG
	LDB	T1,LDPSLA##	;DOES THIS LDB HAVE A LAT SLOT ASSIGNED?
	JUMPE	T1,MCRFR1	;NO, DON'T TOUCH NDBOPR OR NETLAT
	SETZB	T1,NETLAT##(T1)	;FREE THE LAT SLOT
	DPB	T1,LDPSLA##	;FREE THE LAT POINTER
	LDB	T2,LDPRLN##	;GET THE REMOTE LINE NUMBER
	JUMPN	T2,MCRFR1	;JUMP IF THIS IS NOT AN OPR LINE
	LDB	T1,LDPRNN##	;GET THE NUMBER OF THE NODE
	PUSHJ	P,SRCNDB##	;GET "W" POINTING TO THE NDB
	  CAIA			;IF NODE GONE, THEN DON'T BLAST MEMORY
	HLLZS	NDBOPR(W)	;CLEAR THE OPR POINTER
MCRFR1:	SETZM	LDBREM##(U)	;CLEAR LRLCON (ET AL)
	PJRST	FRELDB##	;RETURN LDB TO SCNSER'S FREE POOL
;NETOP. UUO

;NETDIA - NETOP. function to return node and port ID for a TTY
;
;Call: (in section 1 already)
;
;	U/ LDB of terminal
;	M/ Address of user's NETOP. arg list
;Return:
;	ECDX?	depending on error
;	RETSKP	node name stored in string block pointed to by user's arg list
;
;Uses P1,P2 (already saved by higher routine), T1-T4, M

NETDIA::MOVE	P1,M		;SAVE ARG LIST POINTER
	PUSHJ	P,GTNTS1##	;GET NODE#,,LINE# IN T1
	  JRST	NOPDNC##	;NOT CONNECTED
	MOVE	P2,T1		;SAVE IT
	EXCTUX	<SKIPN	M,5(P1)>	;DOES HE WANT NODE NAME?
	  JRST	NTDIA2		;NO
	HLRZ	T1,P2		;GET NODE NUMBER
	NETDBL			;NEXT STUFF IS INTERLOCKED
	PUSHJ	P,SRCNDB##	;FIND NDB
	  TDZA	T1,T1		;CLEAR THE NAME IF CAN'T FIND IT
	MOVE	T1,NDBSN2(W)	;GET THE REMOTE'S NODE NAME
	NETDBU			;GIVE BACK THE INTERLOCK
	JUMPN	T1,NTDIA1	;IF THERE IS A NAME WE'RE OK
	HLRZ	T1,P2		;ELSE, GET NUMBER AGAIN
	PUSHJ	P,CVTSBT##	;AND USE SIXBIT VERSION OF THAT
NTDIA1:	PUSHJ	P,PU6STB##	;PUT SIXBIT INTO STRING BLOCK
	  JRST	NOPADC##	;CAN'T
NTDIA2:	EXCTUX	<SKIPN	M,6(P1)>;DOES THE GUY WANT PORT NAME?
	  JRST	CPOPJ1##	;NO, DONE
	HRRZ	T1,P2		;ISOLATE LINE NUMBER
	PUSHJ	P,CVTSBT##	;CONVERT TO SIXBIT
	HRRI	T1,'TTY'	;STUFF DEVICE NAME
	MOVSS	T1		;MAKE 'TTYNNN'
	PUSHJ	P,PU6STB##	;STORE SIXBIT NAME INTO STRING BLOCK
	  JRST	NOPADC##	;NO LUCK
	JRST	CPOPJ1##	;DONE
SUBTTL 4.3        CONNECT TO REMOTE TERMINALS

;MCRCNT	ROUTINE TO SEND A CONNECT TO A REMOTE TERMINAL.
;CALL	MOVE	T1,[XWD NODE#,LINE#]
;	PUSHJ	P,MCRCNT
;RETURN	CPOPJ			;CONNECT REJECTED,  NO CORE, NO LDB'S, ...
;	CPOPJ1			;CONNECTED.  U := LDB THAT WAS USED.
;NOTE!	THIS ROUTINE WILL SEND A CONNECT EVEN IF THE TERMINAL IS ALREADY
;	CONNECTED.  USE ASGTTY IF YOU JUST WANT THE LINE.

MCRCNT::PUSHJ	P,SAVE3##	;WE CLOBBER THESE WHEN SENDING THE MESSAGE
	PUSHJ	P,SAVJW##	;THESE WHEN WE LOOK AT THE NDB
	PUSH	P,T1		;SAVE THE ARGUMENT FOR LATER.
	HLRZ	T1,T1		;GET THE NODE NUMBER
	PUSHJ	P,SRCNDB##	; AND TRY TO FIND THE NDB.
	  JRST	TPOPJ##		; GIVE ERROR RETURN IF NO NDB
	PUSHJ	P,MCRGET	;GET A NEW ANF/MCR LDB
	  JRST	TPOPJ##		; GIVE ERROR RETURN IF NONE AVAILABLE
	MOVE	T1,U		;LDB ADDRESS FOR GETSLA
	TLO	T1,LAT.TY	;FLAG THAT THIS IS AN LDB-STYLE ADDRESS
	MOVEI	T2,LAT.CC	;WHOSE INITIAL STATE IS CONNECT-CONFIRM
	PUSHJ	P,GETSLA##	;TRY TO ASSIGN AN SLA
	  JRST	MCRCN8		; NO LUCK.  CLEAN UP AND FAIL
	DPB	T1,LDPSLA##	;REMEMBER THE LAT ADDRESS
	HRRZ	T1,(P)		;GET THE NUMBER OF THE LINE TO CONNECT TO
	DPB	T1,LDPRLN##	; AND SAVE IT SO THAT MCRXCN CAN SEND IT

	SKIPN	J,.CPJOB##	;LOAD OUR JOB NUMBER
	STOPCD	.,STO