Google
 

Trailing-Edge - PDP-10 Archives - BB-X140B-BB_1986 - 10,7/703mon/netdev.mac
There are 9 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	.,STOP,MCRJIZ	;++ JOBNUMBER IS ZERO
	DPB	J,LDPJOB##	;STORE OUR JOB NUMBER (FOR NMCWAK)
	PUSHJ	P,MCRXCN	;ATTEMPT TO SEND A CONNECT.
	  JRST	MCRCN8		;NO CORE.  CLEAN UP AND RETURN
;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE
;HERE TO WAIT FOR A CONNECT CONFIRM/REJECT.

MCRCN2:	MOVE	J,.CPJOB##	;GET OUR JOB NUMBER BACK
	MOVEI	T1,EV.NTC	;GET THE TERMINAL CONNECT EVENT WAIT CODE
	PUSHJ	P,[NTSAVE		;RETURN THE "NT" RESOURCE, AND SLEEP
		S0PSHJ	ESLEEP##	;  TILL REJECT/CONFIRM COMES
		POPJ	P,]		;AND CONTINUE IN THE PROPER SECTION
;RDH	LDB	J,LDPJOB##	;WE WOKE UP. GET LDB'S JOB NUMBER
;RDH	CAME	J,.CPJOB##	;DOES THE LDB STILL BELONG TO US?
;RDH	JRST	TPOPJ##		;NO, THEN MUST HAVE RECYCLED!
	LDB	T1,LDPSLA##	;SEE IF LAT STILL ASSIGNED
	JUMPE	T1,TPOPJ##	;IF LAT HAS BEEN CLEARED, CONNECT WAS REJECTED.
	LDB	T2,LATSTA##	;SEE WHAT STATE WE'RE IN
	CAIN	T2,LAT.OK	;IF WE'RE "OK" THEN CONNECT SUCCEEDED
	JRST	MCRCN4		;  AND THEN WE CAN GIVE GOOD RETURN
	CAIN	T2,LAT.DC	;IT IS POSSIBLE FOR SOMEONE TO DISCONNECT
	JRST	TPOPJ##		;  THE TERMINAL WE JUST CONNECTED BEFORE WE
				;  WAKE UP.  IF SOME ONE DID SNEAK IN,
				;  JUST GIVE UP GRACEFULLY.

IFN PARANOID&P$LAT,<

	CAIE	T2,LAT.CC	;THE ONLY OTHER LEGAL STATE IS CONFIRM WAIT
	STOPCD	.,STOP,MCRILS,	;++ ILLEGAL STATE
>
	JRST	MCRCN2		;LOOP UNTIL CONNECT/DISCONNECT COMES IN

MCRCN4:	MOVEI	T1,M.AIDL##	;GET MAXIMUM IDLE TIME BEFORE AUTO-DISCONNECT
	PUSHJ	P,SCNADT##	;START THE TIMER GOING
	JRST	TPOPJ1##	;GIVE SUCCESS RETURN
;CAN'T CONNECT, NO CORE.
MCRCN8:	PUSHJ	P,MCRFRE	;FREE UP THE LAT SLOT AND THE LDB
	JRST	TPOPJ##		;FAIL RETURN TO CALLER
SUBTTL 4.4        INTERFACE TO ASSIGN COMMAND

;ASGTTY	ROUTINE TO HELP THE ASSIGN FUNCTION OF THE NETWORK ASSIGN COMMNADS
;CALL	MOVE	T1,[XWD NODE#,LINE#]
;	PUSHJ	P,ASGTTY
;RETURN	CPOPJ			;TERMINAL NOT AVAILABLE
;	CPOPJ1			;T1 := SIXBIT /TTYNNN/
;NOTE:	THIS ROUTINE SENDS A CONNECT IF NECESSARY.
;	THIS ROUTINE ALSO PRESERVS M & U

ASGTTY::SE1ENT			;ENTER SECTION 1
	PUSH	P,U		;SAVE THE LDB IN CASE COMCON CALLED
	PUSH	P,T1		;SAVE THE "XWD NODE,LINE"
	PUSH	P,M		;SAVE M OVER CALL TO SCREWY GTXTN
	TLO	M,400000	;SET SIGN BIT TO PROPERLY CONFUSE GTXTN
	PUSHJ	P,GTXTN##	;SEE IF LINE IS ALREADY CONNECTED.
	  JRST	ASGTT1		;IF NOT. THEN GO TRY TO CONNECT IT
	POP	P,M		;IT IS CONNECTED. T1 := 'TTYNNN'
	POP	P,(P)		;CLEAN UP THE STACK
	JRST	UPOPJ1##	;AND GIVE A GOOD RETURN

ASGTT1:	POP	P,M		;WE WON'T CLOBBER M NOW
	POP	P,T1		;GET OUR ARGUMENTS BACK
	PUSHJ	P,MCRCNT	;TRY TO CONNECT THE TERMINAL
	  JRST	UPOPJ##		;FAILURE... GIVE BAD RETURN
	LDB	T1,LDPLNO##	;GET THE LINE NUMBER
	S0PSHJ	CVTSBT##	;CONVERT IT TO SIXBIT
	HLRZ	T1,T1		;PUT IT IN THE RIGHT HALV
	HRLI	T1,'TTY'	;PUT IN THE GENERIC "TTY"
	JRST	UPOPJ1##	;GIVE A GOOD RETURN
SUBTTL 4.5        DISCONNECT/RECONNECT TERMINALS (SET HOST)

HOST.U::SE1ENT			;ENTER SECTION 1
	PUSHJ	P,TTYFNU##	;SET UP U & F
	JUMPE	U,CPOPJ##	;0 IN U IS AN ERROR TO US
	MOVE	T1,LDBDCH##(U)	;GET THE CHARACTERISTICS
	TRNE	T1,LDRPTY##	;PTY'S CAN'T SET HOST
	POPJ	P,		;  WITHOUT CONFUSING THE HELL OUT OF BATCON
	HRR	M,T2		;GET THE LOCATION OF THE ARGUMENT
	PUSHJ	P,GETWDU##	;GET THE NODE NUMBER
	PUSHJ	P,SAVE4##	;SAVE THE P'S
	NETDBJ			;INTERLOCK THE REST OF THIS
	PUSHJ	P,SRCNDB##	;GO FIND THE NODE
	  POPJ	P,		;IF NO NODE, GIVE THE ERROR RETURN
	CAIN	W,NETNDB##	;SEE IF HE'S TRYING TO SET HOST HERE
	RETSKP			;  IF SO, JUST GIVE A GOOD RETURN
	LDB	T1,NETCNF##	;SEE IF THE NODE HAS A MCR
	JUMPE	T1,CPOPJ##	;  IF NO MCR, DON'T LET HIM SET HOST
	SKIPL	LDBTTW##(U)	;IF THIS IS A NON-ANF TERMINAL
	PJRST	VTMHST##	;  CALL NETVTM TO DO THE WORK
	MOVE	T1,LDBREM##(U)	;GET THE REMOTE BITS, AND
	TRNN	T1,LRRSHC##	;  MAKE SURE THIS STATION ISN'T A 72
	POPJ	P,		;GIVE ERROR IF STATION DOESN'T ALLOW SET HOST
	PJRST	HOSTDT		;GO DETACH THE GUY AND DO THE SET HOST
HOST.A::SE1ENT			;DO THIS IN SECTION 1
	MOVE	T2,LDBDCH##(U)	;GET THE CHARACTERISTICS
	TRNE	T2,LDRPTY##	;IF THIS IS A PTY, GIVE HIM AN ERROR
	JRST	[MOVEI	T1,[ASCIZ /PTYs cannot be switched by SET HOST./]
		S0JRST	ERRMES##]	;SINCE JOBSTS WON'T WORK OVER THE NET
	MOVE	S,T1		;SAVE NAME
	JSP	T2,SAVCTX##	;RUN THE REST OF THIS AS A JOB
	MOVE	T1,S		;RESTORE NAME
	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,SRCNDB##	;LOOKUP UP THE NDB
	  JRST	[MOVE	T1,NRTUNN##	;GET THE "NO SUCH NODE" ERROR MSG
		S0JRST	ERRMES##]	;  AND GO PRINT IT
	CAIN	W,NETNDB##	;SEE IF IT'S SET HOST SELF
	JRST	[MOVEI	T1,[ASCIZ /% Already at node /]
		S0PSHJ	CONMES##	;PRINT THE FIRST PART
		S0PSHJ	TYPNOD##	;PRINT THE NODE NAME
		S0JRST	PCRLF##]	;FINISH OFF THE MESSAGE AND EXIT
	LDB	T1,NETCNF##	;SEE IF THE NODE HAS A MCR
	JUMPE	T1,[MOVEI T1,[ASCIZ /Node does not support remote terminals./]
		S0JRST	ERRMES##]	;PRINT THE ERROR
	SKIPL	LDBTTW##(U)	;IF THIS IS A NON-ANF TERMINAL
	PJRST	VTMHST##	;  CALL NETVTM TO DO THE WORK
	MOVE	T1,LDBREM##(U)	;GET THE REMOTE BITS, AND
	TRNN	T1,LRRSHC##	;  SEE IF THIS STATION HAS SET HOST CAPABILITY
	JRST	[MOVEI	T1,[ASCIZ /Your station does not support SET HOST./]
		S0JRST	ERRMES##]	;PRINT THE MESSAGE AND EXIT

HOSTDT:	PUSHJ	P,TSETBI##	;CLEAR OUT THE INPUT BUFFER
	PUSHJ	P,TSETBO##	; AND THE OUTPUT BUFFER
	MOVE	T1,LDBREM##(U)	;NOW, SINCE I CAN'T SEEM TO FATHOM THE
	TLNN	T1,LRLCON	; OBSCURITIES OF SAVCTX, MAKE SURE WE ARE
	POPJ	P,		; STILL "CONNECTED".  (SHOULDN'T HAPPEN BUT)
	MOVEI	P4,RSN.RC	;BUILD THE ARGUMENTS FOR TRMXDC
	HLL	P4,NDBNNM(W)	;ARG IS "XWD NODE,REASON" REASON = RECONNECT
	LDB	T1,LDPRNN##	;GET THE NODE NUMBER OF THIS TERMINALS STATION
	PUSHJ	P,SRCNDB##	;FIND HIS NDB SO WE CAN SEND HIM A DISCONNECT
	 STOPCD	.,STOP,MCRNSN,	;++ NO SOURCE NODE FOR TERMINAL
	MOVE	T1,P4		;GET THE ARGUMENT WE JUST CONSTRUCTED
	PJRST	TRMXDC		;  AND GO SEND THE DISCONNECT/RECONNECT
SUBTTL 4.6        TIMING LOGIC RELATED TO THE AUTO-DISCONNECT FEATURE

;NMCSEC	ROUTINE TO DO DISCONNECT FOR NETWORK DATASETS.
;  THIS ROUTINE DISCONNECTS (AND HANGS UP) ANY LINE THAT HAS LOST
;  ITS CARRIER AND IS A NETWORK DATASET.
;CALLED	FROM NETSER ONCE/SECOND

NMCSEC::SE1ENT			;ENTER SECTION 1
	PUSH	P,P4		;WE USE P4 FOR AN AOBJN POINTER TO THE LDB'S
	MOVE	P4,NETRTY##	;GET AOBJN POINTER TO NETWORK TERMINALS'S
NMCSE1:	MOVE	U,LINTAB##(P4)	;GET ADDRESS OF NEXT LDB TO CHECK.
	SKIPL	LDBTTW##(U)	;IF THIS IS A NON-ANF TERMINAL
	JRST	NMCSE8		;THEN NO ANF ONCE/SECOND STUFF
	SKIPE	T2,LDBREM##(U)	;GET THE REMOTE'S ATTRIBUTES/ET AL
	TLNN	T2,LRLCON##	;STILL CONNECTED?
	JRST	NMCSE8		;DUD TTY, SKIP IT
	TLNE	T2,LRLTMO##	;DID MCRDIS REQUEST A DISCONNECT?
	JRST	NMCSE2		;YES, GIVE IT A TRY
	MOVE	T1,LDBDCH##(U)	;GET BITS WE CARE ABOUT
	TRNE	T1,LDRDSD##	;NO, IS IT A DATASET?
	TLNE	T2,LRLDSR##	;OR IS DATASET STILL RUNNING (DTR/CARRIER)?
	JRST	NMCSE8		;YES, DON'T DISCONNECT IT
	CAMN	U,DIALDB##	;IS THIS LDB TRYING TO DIAL OUT?
	JRST	NMCSE8		;YES, LEAVE IT ALONE
NMCSE2:	PUSHJ	P,NMCXDC	;NO, TRY TO DISCONNECT IT
	  JFCL			;WE'LL TRY AGAIN LATER
NMCSE8:	AOBJN	P4,NMCSE1	;LOOP OVER ALL REMOTE TERMINALS
	POP	P,P4		;RESTORE P4
	POPJ	P,		;ALL DONE.  BACK TO NETSCN

NMCXDC:	LDB	T1,LDPRNN##	;GET NUMBER OF NODE THAT OWNS THIS TERMINAL
	PUSHJ	P,SRCNDB##	;USE IT TO SET UP W AS A POINTER TO THE NDB
	  STOPCD .,STOP,MCRNWA,	;++ MCRNWD SHOULD HAVE DISCONNECTED US
	MOVEI	T1,RSN.OK	;NO PARTICULAR REASON FOR THE DISCONNECT.
	PJRST	TRMXDC		;SEND THE DISCONNECT MESSAGE & RETURN
	SUBTTL	4.7	  ONCE/JIFFY PROCESSING

;MCRJIF	ROUTINE TO START NETWORK TERMINALS
;CALL	PUSHJ	P,MCRJIF
;RET	CPOPJ

MCRJIF::MOVEI	T1,MCRRTQ##	;GET THE QUEUE HEADER
	PUSHJ	P,TOTAKE##	;GET U := TERMINAL NEEDING SERVICE
	  POPJ	P,		;IF NONE, THEN ALL DONE
	PUSHJ	P,SCNMCR	;SEE WHAT MESSAGES NEED BE SENT
	  PJRST	TOPOKE##	;IF NO CORE, RE-QUEUE THIS LDB AND EXIT
	JRST	MCRJIF		;GO SEE IF ANY MORE TERMINALS TO START
SUBTTL 4.8        TABLES

;TABLES FOR FILL.  THE TABLE ENTRIES ARE FOR BS, TAB, LF, VT,
;  FF AND CR FROM LEFT TO RIGHT, AND FILL 0-3 FROM TOP
;  TO BOTTOM.  THE VALUE OF THE ENTRY IS THE NUMBER OF FILL
;  CHARACTERS.  THIS IS CONVERTED TO MILLISECONDS BY DIVIDING
;  BY THE TRANSMIT SPEED OVER 1000.  SOMEDAY MAYBE THE USER
;  WILL BE ABLE TO SET THE TIMES DIRECTLY, BUT THIS METHOD
;  IS USED NOW FOR COMPATABLILTY WITH LOCAL FILLING, WHICH SENDS
;  RUBOUTS INSTEAD OF USING TIMEING.

FILTAB:	POINT	6,[BYTE (6) 0,0,0,0,00,0]	;CLASS 0
	POINT	6,[BYTE (6) 2,2,2,2,14,2]	;CLASS 1
	POINT	6,[BYTE (6) 6,0,6,6,25,4]	;CLASS 2
	POINT	6,[BYTE (6) 6,2,6,6,25,4]	;CLASS 3
SUBTTL 4.8        VARIABLES

	$LOW

NTRPCB:	EXP	0		;CELL THAT CONTAINS A POINTER TO THE CURRENT
				; PCB IN USE WHEN CONSTRUCTING A "MCR" MSG.
				; BECAUSE ALL THIS CODE RUNS UNDER THE NETSER
				; INTERLOCK WE CAN USE A GLOBAL CELL WITH OUT
				; FEAR OF RACES.

	$HIGH

	XLIST			;DON'T LIST THE LITERALS
	$LIT
	LIST
NMCEND::PRGEND
TITLE	NETPLT - NETWORK PLOTTER ROUTINES - V001
SUBTTL	JAC/   21 SEP 81

	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH

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

COMMENT	\

Digital no longer supports ANF remote plotters. The NETPLT module is
included only as a convenience for those customers who might wish to
try it.

\

NETPLT::ENTRY	NETPLT

REPEAT 0,<	CCS Edit History
		----------------

Edit	Date	Who	Comment
----	----	---	-------

The following updates were made to keep NETPLT in line with NETLPT.
They are not actual CCS edits, but have been assigned nominal CCS edit
numbers for convenience.

001)	840808	AGM	Define global symbol NPLTCI, used by COMNET.

002)	840808	AGM	Clean up code and comments. No functional changes.

003)	840808	AGM	Updates to error recovery.

004)	840808	AGM	Decrement data request count at end of first time code.

------------------------>
SUBTTL 1.0      PLT SPECIFIC SYMBOL DEFINITIONS

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)
NDEVPL::JRST	NTDREL##	;RELEASE
	JRST	P.CLOS		;CLOSE OUTPUT
	JRST	P.OUT		;OUTPUT
	JRST	NTDILI##	;ILLEGAL INPUT (RETURN INTERLOCK)


SUBTTL 2.1        OUT UUO.

P.OUT:				;HERE FROM UUOCON TO OUTPUT A BUFFER
	PUSHJ	P,SAVE3##	;WE USE P1, NETSER USER 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

P.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	P.HUNG		;IF PLT IS OFFLINE, GO PLAY DEAD.
	TLNE	S,IOBEG		;IS THIS THE FIRST OUT??
	JRST	P.FRST		; IF SO, GO DO SPECIAL CODE.

	MOVEI	T1,6		;TRY FOR SIXBIT DATA
	TRNN	S,16		; IS IT SIX OR SEVEN BIT ?
	MOVEI	T1,7		;THIS TIME IT IS SEVEN
	PUSHJ	P,NTDSOB##	;SET UP THE OUTPUT BUFFER
	  JRST	P.DONE		;NO MORE DATA. RETURN TO UUOCON.
	SKIPN	DEVAXO+1(F)	;FOR PLT'S MAKE SURE THAT WE DON'T
	JRST	P.LOO1		; SEND ZERO LENGTH BUFFERS
	PUSHJ	P,NTDCDQ##	;SEE IF ANY DATA REQUESTS PENDING
	  JRST	P.WAIT		;NONE AVAILABLE.  WE MUST WAIT.
	MOVEI	T1,PCV.NC	;WE DON'T WANT LINE-PRINTER 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)
		   PUSHJ P,NETSLP## ;PAUSE FOR FREECORE
		   JRST P.LOOP]	; AND TRY AGAIN
	PUSHJ	P,NTDDDQ##	;UPDATE THE DATA REQUEST COUNT
	SKIPN	DEVAXO+1(F)	;ARE THERE ZERO BYTES LEFT??
P.LOO1:	PUSHJ	P,NTDAOB##	;IF SO, THEN GIVE USER BACK THE BUFFER
	JRST	P.LOOP		;LOOP UNTIL ALL DATA IS OUT
SUBTTL 2.2        FIRST TIME ONLY CODE (OUTPUT <PEN UP>)
P.FRST:				;HERE ON FIRST OUT FROM UUOCON
	SETZM	DEVAXO(F)	;CLEAR ANY DATA NOT OUTPUT LAST TIME
	PUSHJ	P,NTDCDQ##	;DO WE HAVE A DATA REQUEST FOR THIS?
	  JRST	P.WAIT		; IF NOT, WE MUST WAIT FOR ONE
	MOVEI	T1,^D16		;WE WANT A 16 WORD DATA MESSAGE
	PUSHJ	P,NTDHDR##	; SET UP P2 := POINTER, P3 := COUNT
	  JRST	[PUSHJ P,NETSLP##	;IF WE CAN'T GET THE MEMORY, SLEEP
		 JRST P.LOOP]	;NOW GO TRY AGAIN
	MOVE	T3,[POINT 8,[BYTE (8)3,DC.DAR,40,40]]
				;LENGTH & MESSAGE TO SEND (REMEMBER
				; COMPRESSION)
	MOVEI	T4,4		;WE WILL SEND 4 BYTES (INCLUDING LENGTH)

P.FRS2:	ILDB	T1,T3		;GET THE NEXT BYTE
	PUSHJ	P,DPBBIN##	; AND PUT IT IN THE MESSAGE
	SOJG	T4,P.FRS2	;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 LPT COMPRESSION
	PUSHJ	P,NTDWRT##	;SEND THE MESSAGE.
	PUSHJ	P,NTDDDQ##	;DECREMENT THE DATA REQUEST COUNT

P.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	P.LOOP		;GO BACK AND TRY TO SEND USER DATA.
SUBTTL 2.3        EXCEPTION HANDLING.

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

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

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

P.GONE:				;HERE WHEN PLT IS DISCONNECTED.
	MOVEI	S,IODERR!IODTER	;TWO BITS FOR UUOCON TO CONTEMPLATE
	IORB	S,DEVIOS(F)	;SET THEM IN DEVIOS
	MOVEI	T1,IONND%	;??????
	DPB	T1,PDVESE##	;??????
	POPJ	P,		;BACK TO UUOCON
SUBTTL 2.4        CLOSE UUO AND LAST TIME ONLY CODE (OUTPUT <PEN UP>)

;	MAY HAVE TO ADD SOME FLAGS ETC HERE IO IN PROCESS OF CLOSE
P.CLOS:	PUSHJ	P,SAVE3##	;GET SOME P'S
	PUSHJ	P,OUT##		;FINNISH OFF BUFFERS
P.LAST:				;HERE FROM CLOSE UUO
P.LAS1:	MOVEI	T1,^D16		;WE WANT A 16 WORD DATA MESSAGE
	PUSHJ	P,NTDHDR##	; SET UP P2 := POINTER, P3 := COUNT
	  JRST	[PUSHJ P,NETSLP##	;IF WE CAN'T GET THE MEMORY, SLEEP
		 PUSHJ P,NTDSET##	;RELOAD W AND S (THEY MAY HAVE CHANGED)
		 TLNN S,IOSCON	;ARE WE STILL CONNECTED ??
		 JRST P.LAS3	;  IF NOT, JUST PRETEND WE SEND THE MSG
		 JRST P.LAS1]	;IF NODE STILL THERE, TRY AGAIN
	MOVE	T3,[POINT 8,[BYTE (8)3,DC.DAR,40,40]]
				;LENGTH & MESSAGE TO SEND (REMEMBER
				; COMPRESSION)
	MOVEI	T4,4		;WE WILL SEND 4 BYTES (INCLUDING LENGTH)

P.LAS2:	ILDB	T1,T3		;GET THE NEXT BYTE
	PUSHJ	P,DPBBIN##	; AND PUT IT IN THE MESSAGE
	SOJG	T4,P.LAS2	;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 LPT COMPRESSION
	PUSHJ	P,NTDWRT##	;SEND THE MESSAGE.

P.LAS3:				;HERE WHEN ALL "LAST TIME" STUFF DONE
	JRST	NTDCLO##	;CLOSE OUTPUT

SUBTTL 3.0      INTERFACE TO NETSER (NETWORK DISPATCH VECTOR)

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


;DUMMY CONNECT INIT PROCESSOR

NPLTCI==:NJNKCI##		;A JUNK CI
SUBTTL 3.1        INPUT STATUS MESSAGE PROCESSING

P.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	NETRDX - REMOTE DATA ENTRY SERVICE ROUTINE TO SUPPORT MCS10 - V001
SUBTTL	D. TODD/WEM   26 JUL 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) 1978,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;XP VRDXSER,052	;PUT VERSION NUMBER IN GLOB AND LOADER MAP

NETRDX::ENTRY	NETRDX


;RDX ONLY DEVICE STATUS BITS

	IOSDRP==IOSFFB		;INDICATES THAT THIS IS A MULTIDROP RDX
SUBTTL 1.0      UUOCON INTERFACE.

	JRST	NTDONL##	;(-5) ONLINE CHECK
	JRST	CPOPJ##		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) LENGTH CAN BE GOTTEN FROM DDB
	JRST	CPOPJ##		;(-2) INITIALIZE
	JRST	CPOPJ##		;(-1) HUNG DEVICE
NDEVRD::JRST	NTDREL##	;(0)  RELEASE
	JRST	NTDCLO##	;(1)  CLOSE OUTPUT
	JRST	R.OUT		;(2)  OUTPUT
	JRST	R.IN		;(3)  INPUT
	JRST	CPOPJ##		;(4)  ENTER
	JRST	CPOPJ##		;(5)  LOOKUP
	JRST	NTDILI##	;(6)  DUMP MODE INPUT
	JRST	NTDILO##	;(7)  DUMP MODE OUTPUT
	JRST	CPOPJ##		;(10) USETO
	JRST	CPOPJ##		;(11) USETI
	JRST	CPOPJ##		;(12) GETF UUO
	JRST	CPOPJ##		;(13) RENAME UUO
	JRST	CPOPJ##		;(14) CLOSE INPUT
	JRST	CPOPJ##		;(15) UTPCLR
	JRST	CPOPJ##		;(16) MTAPE UUO
SUBTTL 1.1        DDB SEARCH LOGIC INTERFACE (TSTRDX)

;TSTRDX	ROUTINE TO SEE IF A RDX DDB SHOULD BE CREATED.  CALLED FROM
; UUOCON'S DDB SEARCH LOGIC ROUTINE.
;CALL	MOVEI	P1,FLAGS	;(ONLY MATCH IF LOOKING FOR PHYSICAL DEVICE)
;	MOVE	T1,[SIXBIT /RD?NNX/] ;DEVICE NAME
;	PUSHJ	P,TSTRDX
;RETURN	CPOPJ			;NOT AN RDX DEVICE
;	CPOPJ1			;IS AN RDX DEVICE. F := RDX DDB.
TSTRDX::HLRZ	T2,T1		;GET JUST THE NAME
	XORI	T2,'RDA'	;"COMPARE" IT WITH SIXBIT /RDA/
	TRNN	T2,777700	;MAKE SURE IT'S OF THE FORM RD?
	TRNE	P1,DD%LOG##	;MAKE SURE IT'S A PHYSICAL DEVICE SEARCH
	POPJ	P,		;EITHER NOT RD?, OR LOGICAL DEVICE
	NETDBJ			;BETTER INTERLOCK FROM HERE ON OUT.
	PUSHJ	P,SAVJW##	;WE CLOBBER W RIGHT AWAY, AND J IF WE CONNECT.
	PUSHJ	P,SAVE4##	;NETSER CLOBBERS MOST OF THESE
	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 RDX
	MOVEI	P1,(W)		;COPY THE NDB POINTER FOR MAKDDB
	MOVEI	T1,'RDA'	;GET GENERIC DEVICE NAME IN RH(T1)
	PUSHJ	P,SRCNDT##	;SEE IF THE NODE SUPPORTS RDA'S
	  PJRST	TPOPJ##		;IF NOT, THEN DEVICE DOESN'T EXIST
	LDB	T1,[POINT 6,(P),17] ;POINT TO "CONTROLLER" CHARACTER
	CAIL	T1,'A'		;MAKE SURE THAT IT'S IN THE
	CAILE	T1,'H'		; RANGE A-H (= 0-7)
	PJRST	TPOPJ##		;NOT AN RDX DEVICE IF NOT IN RANGE
	SUBI	T1,'A'		;CONVERT TO A CONTROLLER NUMBER
	LDB	T2,[POINT 6,(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.
	SUBI	T2,'0'		;CONVERT NUMERIC TO NUMBER
	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.

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

	MOVE	P2,-1(P)	;GET THE FULL NAME BACK
	SETZ	P3,		;THERE IS NO LOGICAL NAME
	PUSHJ	P,MAKDDB##	;MAKE A DDB (NDB POINTER IN P1)
	  JRST	[POP P,T1	;NO CORE. FLUSH THE UNIT NUMBER
		 JRST TPOPJ##]	;AND GIVE THE 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
	PUSHJ	P,LNKDDB##	;IT CONNECTED. PUT THE DDB IN THE CHAIN
	LDB	T1,NETDVT##	;GET THE ATTRIBUTES
	TRNN	T1,DRX.MD	;IS THIS A MULTIDROP LINE?
	TDZA	T2,T2		;NO, LEAVE DEVSTS 0
	MOVEI	T2,1		;YES, LEAVE A 1 IN DEVSTS
	MOVEM	T2,DEVSTS(F)	;SET DEVSTS FOR USERS TO LOOK AT
	LSH	T2,<^D35-^L<IOSDRP>>+^D18  ;POSITION IOSDRP
	IORB	T2,DEVIOS(F)	;AND SET INTERNAL MULTI-DROP LINE FLAG
	PJRST	TPOPJ1##	;ALL DONE. GOOD RETURN, F := DDB POINTER.
SUBTTL 1.2        OUTPUT UUO.

R.OUT:	PUSHJ	P,SAVE4##	;NETSER LIKES ITS P'S.
	MOVSI	S,IOSUSO	;CLEAR "UUOCON STOPPED OUTPUT" SINCE
	ANDCAB	S,DEVIOS(F)	;  IT'S TRYING TO START IT NOW

ROLOOP:	PUSHJ	P,NTDSET##	;SET UP "W" ETC.
	TLNE	S,IOBEG		;FIRST TIME THROUGH?
	PUSHJ	P,RDXFIR	;YES, DO SOME CLEANUP BEFORE REAL I/O
	MOVSI	S,IO		;MARK DIRECTION AS OUTPUT
	IORB	S,DEVIOS(F)	;SO THAT "WAIT" WORKS RIGHT
	PUSHJ	P,NTDONL##	;MAKE SURE WE ARE STILL CONNECTED
	  PJRST	R.HUNG		;NOT THERE?? RETURN IODERR
ROLOO0:	LDB	T2,PIOMOD##	;GET THE DEVICE MODE
	MOVEI	T1,7		;ASSUME THAT IT'S ASCII (7 BIT BYTES)
	CAIE	T2,A8		;BUT IF IT'S EIGHT-BIT ASCII
	CAIN	T2,BYTMOD	;OR IF IT'S BYTE MODE
	MOVEI	T1,^D8		;THEN SELECT 8-BIT-BYTE DATA
	PUSHJ	P,NTDSOB##	;SET UP THE OUTPUT BUFFER
	  POPJ	P,		;NO MORE OUTPUT DATA.  RETURN TO UUOCON.
	SKIPN	DEVAXO+1(F)	;MAKE SURE WE DON'T TRY TO SEND
	JRST	ROLOO6		; A ZERO LENGTH BUFFER
	PUSHJ	P,NTDCDQ##	;CHECK FOR AVAILABLE DATA REQUESTS
	  JRST	ROWAIT		;IF NONE, THEN WE MUST WAIT
	TLNE	S,IOSDRP	;IS THIS A MULTIDROP LINE?
	JRST	R.MXMT		;IF MULTIDROP, THEN USE SPECIAL ROUTINE
	MOVEI	T1,PCV.NC	;NO CONVERSION AT FEK TIME
	MOVEI	T2,DC.DAR	;DATA WITH END OF RECORD
	PUSHJ	P,NTDXMT##	;SEND A 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)
		PUSHJ	P,NETSLP##	;PAUSE FOR FREECORE
		JRST	ROLOOP]		; AND TRY AGAIN
	PUSHJ	P,NTDDDQ##	;UPDATE THE DATA REQUEST COUNT
ROLOO5:	SKIPE	DEVAXO+1(F)	;DID THAT FINISH OFF THE BUFFER?
	JRST	ROLOOP		;IF NOT, THEN  GO TRY TO SEND SOME MORE
ROLOO6:	SETZM	DEVAXO+1(F)	;INDICATE THAT THE BUFFER IS ALL GONE
	PUSHJ	P,NTDAOB##	;ADVANCE THE OUTPUT BUFFER
	JRST	ROLOOP		;GO TRY TO SEND MORE


ROWAIT:	PUSHJ	P,NTDWTO##	;WAIT FOR A DATA REQUEST
	  POPJ	P,		;  IF NON-BLOCKING, RETURN TO UUOCON.
	JRST	ROLOOP		;GO TRY TO SEND MORE NOW.
;MULTIDROP RDX OUTPUT CODE.

R.MXMT:	SETZ	T1,		;WE WILL ACCUMULATE THE DROP NUMBER HERE
	MOVEI	T2,5		;THERE ARE 5 CHARACTERS IN THE DROP NUMBER

R.MXM1:	SOSGE	DEVAXO+1(F)	;COUNT OFF ONE MORE BYTE
	JRST	R.IMPM		;BUFFER DIDN'T CONTAIN A DROP NUMBER??
	EXCTUX	<ILDB T3,DEVAXO(F)> ;GET THE NEXT CHARACTER FROM THE BUFFER
	CAIN	T3," "		;IF IT'S A SPACE,
	MOVEI	T3,"0"		; THEN TREAT IT AS A ZERO
	CAIL	T3,"0"		;MAKE SURE THAT IT'S IN THE RANGE
	CAILE	T3,"9"		; 0-9 (DECIMAL)
	JRST	R.IMPM		;BAD DROP NUMBER. SET IOIMPM
	SUBI	T3,"0"		;CONVERT NUMERIC TO A NUMBER
	IMULI	T1,^D10		;MULTIPLY THE PARTIAL NUMBER BY THE RADIX
	ADDI	T1,(T3)		;ADD IN THE NEXT DIGIT
	SOJG	T2,R.MXM1	;LOOP OVER ALL FIVE DIGITS.
	TRNE	T1,740000	;ABSURD DROP NUMBER?
	JRST	R.IMPM		;YEAH, FLAG IO.IMP ERROR
	PUSH	P,T1		;SAVE THE DROP NUMBER

;START UP AN NCL MESSAGE (CAN'T USE NTDXMT DUE TO MULTIPOINT'S UNIQUE
;"DROP" NUMBER SANDWICHED BETWEEN "TYP" AND "DATA" FIELDS . . .)

	MOVE	T1,DEVAXO+1(F)	;COUNT OF ACTUAL DATA BYTES TO BE SENT
	LDB	T2,NETMML##	;GET RDM'S MAX MESSAGE LENGTH
	CAMLE	T1,T2		;WILL USER'S BUFFER FIT IN ONE MESSAGE?
	JRST	R.MXME		;NO, BLOCK-TOO-LARGE ERROR
	ADDI	T1,20+3		;ALLOW FOR NCL OVERHEAD, ROUND UP
	LSH	T1,-2		;AND CONVERT TO WORD SIZE
	CAILE	T1,MSGMAW##	;CAN WE GET A PCB THAT LARGE?
	JRST	R.MXME		;NO, BLOCK-TOO-LARGE ERROR
	PUSHJ	P,NTDHDR##	;FILL IN THE HEADER UP TO THE "DLA"
	  JRST	[POP	P,T1		;NO PCB MEMORY, BACK OUT OF TRANSMIT
		MOVNI	T1,5		;NUMBER OF BYTES IN "DROP"
		ADJBP	T1,DEVAXO(F)	;ADJUST BUFFER POINTER BACKWARDS
		MOVEM	T1,DEVAXO(F)	;TO START OF DROP FOR NEXT ROLOOP CYCLE
		MOVEI	T1,5		;NUMBER OF BYTES IN "DROP"
		ADDM	T1,DEVAXO+1(F)	;ADJUST BUFFER COUNTER TOO
		MOVEI	T1,DEPAIO	;THE "NON-BLOCKING-I/O" BIT
		TDNE	T1,DEVAIO(F)	;IS JOB DOING ASYNC I/O?
		POPJ	P,		;YES, "NON-BLOCKING" RETURN TO UUOCON
		PUSHJ	P,NETSLP##	;NO, WAIT A BIT FOR SOME FREE CORE
		JRST	ROLOOP]		;AND TRY AGAIN

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

	POP	P,T4		;RETRIEVE THE DROP NUMBER
	MOVEI	T1,2		;COUNT "TYP" BYTE, ASSUME ONE BYTE FOR DROP
	TRNE	T4,777600	;SMALL OR LARGE DROP NUMBER?
	ADDI	T1,1		;TWO BYTE'S WORTH OF DROP NUMBER
	ADD	T1,DEVAXO+1(F)	;ADD COUNT OF DATA BYTES LEFT
;CNT
	XMT	T1		;SEND THE "COUNT" FIELD
;TYP
	XMTI	DC.DAR		;SEND THE "TYP" = DATA WITH EOR
;DROP
	XMT	T4		;AND SEND THE DROP NUMBER
;DATA
	SETZ	T4,		;COUNT OF BYTES THAT WILL BE LEFT OVER
	EXCH	T4,DEVAXO+1(F)	;GET COUNT OF USER DATA BYTES IN BUFFER
	JRST	R.MXM3		;ENTER OUTPUT LOOP

R.MXM2:	EXCTUX	<ILDB T1,DEVAXO(F)> ;GET ANOTHER BYTE FROM THE USER'S BUFFER
	XMT1	T1		;SEND THE BYTE
R.MXM3:	SOJGE	T4,R.MXM2	;LOOP UNTIL WE'VE SENT IT ALL

	ADDB	P3,PCBCTR(U)	;UPDATE THE PCB'S LENGTH
	MOVEI	T1,PCV.NC	;THIS IS TO BE SENT UN-ADULTERATED
	PUSHJ	P,NTDWRT##	;SEND THE MESSAGE ON IT'S CONTORTED WAY
	PUSHJ	P,NTDDDQ##	;ACCOUNT FOR DATA REQUEST THAT JUST GOT USED
	JRST	ROLOO5		;GO SEE IF THE USER'S BUFFER WANTS ADVANCING


;HERE ON OUTPUT BLOCK TOO LARGE (RETURN IO.BKT ERROR)

R.MXME:	POP	P,T1		;PITCH DROP NUMBER
	JRST	R.OBTL		;GO SET IO.BKT ERROR FOR USER
SUBTTL 1.3        INPUT UUO.

R.IN:	PUSHJ	P,SAVE4##	;WE CLOBBER MOST EVERYTHING
	MOVSI	S,IOSUSI	;CLEAR "UUOCON STOPED INPUT" SINCE IT'S
	ANDCAB	S,DEVIOS(F)	;  TRYING TO START IT NOW.

RILOOP:	PUSHJ	P,NTDSET##	;SET UP "W" ETC.
	TLNE	S,IOBEG		;FIRST TIME THROUGH SERVICE ROUTINE?
	PUSHJ	P,RDXFIR	;YES, CLEAN UP SOME OLDE KRUFTE
	MOVSI	S,IO		;THE I/O DIRECTION BIT
	ANDCAB	S,DEVIOS(F)	;TELL "WAITX" THAT WE'RE DOING INPUT
	PUSHJ	P,NTDIBA##	;IS THERE AN INPUT BUFFER AVAILABLE TO FILL?
	  POPJ	P,		; IF NOT, THEN GO BACK TO UUOCON
	HRRZ	T1,DEVPCB(F)	;IS THERE A PCB AVAILABLE?
	JUMPE	T1,RIWAIT	;IF NOT, WE MUST WAIT FOR ONE
	PUSHJ	P,NTDDID##	;IF THERE IS A PCB, THEN DECODE IT.
	JRST	RILOOP		;KEEP IT UP TILL SOME ONE GETS BORED.

RIWAIT:	PUSHJ	P,NTDONL##	;ARE WE STILL ONLINE?
	  JRST	R.HUNG		;IF NOT, THEN SET IODERR AND RETURN
	PUSHJ	P,NTDXDQ##	;MAKE SURE WE'VE SENT ENOUGH DATA REQUESTS
	PUSHJ	P,NTDWTI##	;WAIT FOR DATA.
	  POPJ	P,		;NO DATA, BUT NON-BLOCKING. RETURN TO UUOCON
	JRST	RILOOP		;GO SEE IF IT WAS DATA THAT WOKE US UP.



;FIRST-TIME SERVICE ROUTINE INITIALIZATION

RDXFIR:	MOVSI	S,IOBEG!IOSREL	;OBNOXIOUS FLAGS
	ANDCAB	S,DEVIOS(F)	;CLEAR DEVICE I/O FLAGS
	SETZM	DEVAXI(F)	;CLEAR ANY DANGLING INPUT
	SETZM	DEVAXO(F)	;AND/OR DANGLING OUTPUT
	POPJ	P,		;DDB CLEANED UP, READY FOR I/O
SUBTTL 2.0      NETSER INTERFACE.

;RDXSER'S NDP DISPATCH VECTOR (HERE ON MESSAGES FROM NETSER)

	IFIW	NTDNWD##	;NODE WENT DOWN
	IFIW	NTDDSC##	;DISCONNECT MESSAGE (INIT/CONFIRM)
	IFIW	NTDCNC##	;CONNECT CONFIRM MESSAGE
	IFIW	NTDSTP##	;CONNECT INITIATE MESSAGE (CAN'T HAPPEN)
	IFIW	NTDRDQ##	;RECIEVED DATA REQUEST
RDANDP::IFIW	NTDQIP##	;QUEUE INCOMING PCB'S TO UUO LEVEL
	IFIW	R.DATA		;DATA WITH OUT E-O-R
	IFIW	R.DATA		;DATA WITH E-O-R
	IFIW	CPOPJ##		;STATUS ??
	IFIW	CPOPJ##		;CONTROL ??
	IFIW	CPOPJ##		;UNIT ID ??
	IFIW	CPOPJ##		;FILE SPEC ??



;DUMMY CONNECT INIT PROCESSOR

	NRDACI==:NJNKCI##	;JUNK CI PROCESSOR
SUBTTL 2.1        DAP INPUT DATA MESSAGE.

R.DATA:	LDB	T2,PIOMOD##	;GET THE DATA MODE
	MOVEI	T4,7		;ASSUME THAT IT'S ASCII (7 BIT BYTES)
	CAIN	T2,BYTMOD	;BUT IF IT'S BYTE MODE, CHANGE OUT MIND
	MOVEI	T4,^D8		; (8 BIT BYTES)
	PUSHJ	P,NTDSIB##	;SET UP THE INPUT BUFFER
	 STOPCD	.,STOP,RDXDAT,	;++ NTDSIB FAILED IN R.DATA
	TLNN	S,IOSDRP	;IS THIS IS MULTI DRIP LINE?
	JRST	R.DAT1		;IF NOT, SKIP READING THE DROP NUMBER

	PUSHJ	P,EBI2BI##	;GET THE DROP NUMBER
	SETZB	T2,T3		;CLEAR THESE (WE ACCUMULATE THE NUMBER HERE)
	MOVEI	T4,5		;WE WANT A 5 DIGIT NUMBER

R.RDR1:	IDIVI	T1,^D10		;GET THE REMAINDER (NEXT DIGIT)
	ADDI	T2,"0"		;ASCIIZ IT
	LSHC	T2,-7		;SAVE IT IN T3 (DON'T USE THE STACK)
	SOJG	T4,R.RDR1	;LOOP OVER ALL 5 CHARS

	MOVEI	T4,5		;NOW STORE ALL 5 CHARS
R.RDR2:	SOSGE	DEVAXI+1(F)	;COUNT DOWN ANOTHER BYTE
	JRST	R.BKTL		;?? USER GAVE US AN AWFULLY TINY BUFFER
	LSHC	T2,7		;GET THE NEXT BYTE BACK
	EXCTUU	<IDPB T2,DEVAXI(F)> ;STORE THE DIGIT
	SOJG	T4,R.RDR2	;LOOP OVER ALL 5 DIGITS

R.DAT1:	SOJL	P4,NTDA1B##	;COUNT OFF THE NEXT DATA CHARACTER
	ILDB	T2,P1		;GET THE NEXT DATA CHARACTER
	SOSGE	DEVAXI+1(F)	;COUNT DOWN THE USERS FREE BUF CNT
	JRST	R.BKTL		;IOBKTL IF HE DIDN'T GIVE A BIG BUFFER
	EXCTUU	<IDPB T2,DEVAXI(F)> ;STORE THE BYTE
	JRST	R.DAT1		;LOOP OVER ALL THE DATA
SUBTTL 3.0      UTILITY SUBROUTINES.

;R.BKTL	ROUTINE TO SET IOBKTL IF THE USER GAVE US AN INPUT BUFFER THAT
; WAS TOO SMALL.  IT ALSO ADVANCES THE INPUT BUFFER WHEN DONE.
;
R.BKTL:	MOVEI	S,IOBKTL	;GET THE ERROR BIT
	IORB	S,DEVIOS(F)	;SET IT WHERE UUOCON WILL NOTICE
	PJRST	NTDA1B##	;ADVANCE THE USERS BUFFER AND SKIP RETURN


;R.OBTL	ROUTINE TO SET IOBKTL IF THE USER GAVE US AN OUTPUT BUFFER THAT
; WAS TOO LARGE.  IT ALSO SETS THE OUTPUT BUFFER AS "DONE" SO THAT THE
; NEXT "OUT" CALL WILL AUTOMATICALLY ADVANCE PAST THE OFFENDING BUFFER.

R.OBTL:	SETZM	DEVAXO+1	;MARK THE OUTPUT BUFFER AS "DONE" (EMPTY)
	MOVEI	S,IOBKTL	;GET THE ERROR BIT
	JRST	R.ERRS		;SET ERROR BIT, TAKE NON-SKIP RETURN


;R.HUNG	RDA IS "OFFLINE" (NTDONL), CHECK IT OUT

R.HUNG:	TLNN	S,IOSCON	;STILL CONNECTED?
	PJRST	NTDGON##	;NO, DEVICE WENT AWAY
				;YES, FALL INTO R.DERR

;R.DERR, R.IMPM ROUTINES TO SET IODERR AND IOIMPM

R.DERR:	MOVE	S,[XWD IOSERR,IODERR] ;TWO ERROR BITS TO SET
	CAIA
R.IMPM:	MOVEI	S,IOIMPM	;ERROR BIT TO SET
R.ERRS:	IORB	S,DEVIOS(F)	;SET THE BIT(S)
	POPJ	P,		;AND RETURN





	XLIST			;DON'T LIST LITERALS
	$LIT
	LIST
RDXEND::PRGEND
TITLE	NETTSK - TASK TO TASK COMMUNICATION SERVICE ROUTINE - V001
SUBTTL	W. E. MATSON/WEM  20 SEP 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) 1978,1979,1980,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;XP VTSKSER,001	;PUT VERSION NUMBER IN GLOB AND LOADER MAP

NETTSK::ENTRY	NETTSK	;LOADING IF IN LIBRARY SEARCH MODE
;TSK. ERROR CODES
	TK%TNL==ECOD1##		; 1 = TSKSER NOT LOADED.
	TK%ATS==ECOD2##		; 2 = ARG LIST TOO SHORT
	TK%UNP==ECOD3##		; 3 = USER NOT PRIVLEDGED
	TK%ILF==ECOD4##		; 4 = ILLEGAL FUNCTION
	TK%ILC==ECOD5##		; 5 = ILLEGAL CHANNEL (OR NOT TASK)
	TK%ILN==ECOD6##		; 6 = ILLEGAL NPD
	TK%NTS==ECOD7##		; 7 = NPD TOO SHORT
	TK%ILS==ECOD10##	; 10 = ILLEGAL FUNCTION WHILE IN THIS STATE
	TK%NFC==ECOD11##	; 11 = NO MONITOR FREE CORE
	TK%NFL==ECOD12##	; 12 = NO FREE LINKS
	TK%NXN==ECOD13##	; 13 = ATTEMPT TO CONNECT TO A NONEXISTANT NODE
	TK%UDW==ECOD14##	; 14 = UUO (IN OR OUT) DIDN'T SKIP

;TSK. FUNCTION CODES
	.TKFRS==1		; 1 = RETURN STATUS, NPD'S
	.TKFEP==2		; 2 = ENTER PASSIVE STATE
	.TKFEA==3		; 3 = ENTER ACTIVE STATE
	.TKFEI==4		; 4 = ENTER IDLE STATE
	.TKFWT==5		; 5 = WAIT
	.TKFOT==6		; 6 = OUTPUT WITH CONTROL OF TYPE/E-O-R
	.TKFIN==7		; 7 = INPUT WITH NOTIFICATION OF TYPE/E-O-R
	.TKFRX==10		;10 = RETURN STATUS, MESSAGE SIZE

;TSK. STATE VALUES
	.TKSID==0		; 0 = LINE IS IDLE
	.TKSCI==1		; 1 = WAITING FOR CONNECT INITIATE
	.TKSCC==2		; 2 = WAITING FOR CONNECT CONFIRM
	.TKSOK==3		; 3 = LINK IS OPERATIONAL
	.TKSDC==4		; 4 = WAITING FOR A DISCONNECT CONFIRM
				COMMENT @

The first NPD in the UUO argument list is the Right-hand one (RH(DEVNPD))
The second NPD is the Left-hand one (LH(DEVNPD))

For the passive task.

    1)	The enter passive state uuo
	-   NPD1 := Name we wish to be identified as (our process name)
	-   NPD2 := The "pattern" we wish to match
    2)	After a successful connection,
	-   NPD1 := The "actual" that the pattern successfully matched
	-   NPD2 := The name of the remote process that sent the connect.

For the active task.

    1)	The enter active state uuo
	-   NPD1 := The name we want to return as "ours" on the confirm
	-   NPD2 := The the "actual" we try to connect to.
    2)	After a successful connection,
	-   NPD1 := The name the remote thinks we are.
	-   NPD2 := The name he gave us as "his"

				    @
TSK.::	PUSHJ	P,SAVE4##	;WE USE A LOT OF P'S
	HLRZ	P4,T1		;P4 := LENGTH OF ARG LIST
	HRRZ	P3,T1		;P3 := ADDRESS OF ARG LIST
	CAIGE	P4,2		;MAKE SURE AT LEAST FCN & CHAN ARE THERE
	PJRST	TK%ATS		;ERROR: ARG LIST TOO SHORT
	HRRI	M,(P3)		;SET "M" UP TO READ FUNCTION CODE
	PUSHJ	P,GETWDU##	;READ FUNCTION
	SKIPG	P2,T1		;P2 := FUNCTION CODE
	PJRST	TK%ILF		;ILLEGAL FUNCTION CODE
	PUSHJ	P,GETWD1##	;GET THE CHANNEL NUMBER
	MOVE	P1,T1		;P1 := CHANNEL NUMBER
	PUSHJ	P,SETUF##	;SET UP F WITH ADDRESS OF DDB
	  PJRST	TK%ILC		;ERROR: ILLEGAL CHANNEL
	HRLM	P1,.USCTA	;SET UP THE EXTENDED CHANNEL NUMBER
	LDB	T1,PDVTYP##	;GET THE DEVICE TYPE
	CAIE	T1,<.TYTSK/.TYEST> ;MAKE SURE THAT THIS IS A TASK DEVICE
	PJRST	TK%ILC		;ERROR: ILLEGAL CHANNEL
	CAILE	P2,TSKMX	;IS THIS A LEGAL FUNCTION CODE
	PJRST	TK%ILF		;ILLEGAL FUNCTION
	JRST	@.(P2)		;DISPATCH TO SUBFUNCTION
	JRST	TSKRS		; 1 = RETURN TASK STATUS
	JRST	TSKEP		; 2 = ENTER PASSIVE TASK STATE
	JRST	TSKEA		; 3 = ENTER ACTIVE TASK STATE
	JRST	TSKEI		; 4 = ENTER IDLE TASK STATE
	JRST	TSKWT		; 5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT
	JRST	TSKOU		; 6 = OUT WITH CONTROL OF E-O-R.
	JRST	TSKIN		; 7 = IN WITH NOTIFICATION OF E-O-R.
	JRST	TSKRX		;10 = RETURN STATUS, MESSAGE SIZE MAXIMA
	TSKMX=10		;10 = MAXIMUM LEGAL FUNCTION.
;SUB-FUNCTION #1 = RETURN STATUS, NPD'S

TSKRS:	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIGE	P4,3		;IF WE CAN'T STORE THE STATUS
	JRST	TK%ATS		;ERROR: ARG LIST TOO SHORT
	HRRI	M,2(P3)		;GET THE ADDRESS OF THE RETURN VALUE AREA
	PUSHJ	P,PUTWDU##	;RETURN THE STATE
	CAIN	T1,LAT.ID	;SKIP IF WE HAVE TO RETURN NPD'S
	JRST	[LDB	T1,NETRSN##	;GET REASON FOR LAST DISCONNECT
		CAIL	P4,4		;ONLY RETURN IT IF HE ASKED FOR IT
		PUSHJ	P,PUTWD1##	;RETURN THAT AS SECOND ARG
		RETSKP]			;GIVE GOOD RETURN
	CAIGE	P4,4		;IF THE LIST IS ONLY 3 WDS LONG
	JRST	CPOPJ1		; THEN WE'RE DONE
	HRRI	M,3(P3)		;GET ADDRESS OF THE FIRST NPD POINTER
	HRRZ	J,DEVNPD(F)	;GET THE POINTER TO THE LOCAL NPD
	PUSHJ	P,WRTNPD	;STORE THE NPD IN THE USER'S AREA
	  POPJ	P,		;PROPAGATE THE ERROR RETURN
	CAIGE	P4,5		;IF THE LIST ISN'T LONG ENOUGH
	JRST	CPOPJ1		; THEN RETURN
	HRRI	M,4(P3)		;GET THE ADDRESS OF THE SECOND NPD POINTER
	HLRZ	J,DEVNPD(F)	;GET THE POINTER TO THE REMOTE NPD
	PUSHJ	P,WRTNPD	;STORE THE NPD
	  POPJ	P,		;PROPAGATE THE ERROR RETURN
	RETSKP			;ALL DONE, GOOD RETURN


;SUB-FUNCTION #10 = RETURN STATUS, MESSAGE ("SEGMENT") SIZE

TSKRX:	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIGE	P4,3		;IF WE CAN'T STORE THE STATUS
	JRST	TK%ATS		;ERROR: ARG LIST TOO SHORT
	HRRI	M,2(P3)		;GET THE ADDRESS OF THE RETURN VALUE AREA
	PUSHJ	P,PUTWDU##	;RETURN THE STATE
	CAIGE	P4,4		;WANT MESSAGE SIZE TOO?
	JRST	CPOPJ1##	;NO, THEN ALL DONE
	LDB	T1,NETMML##	;YES, GET "MAX MESSAGE LENGTH" (OF USER DATA)
	LDB	T2,NETRLN##	;AND RECORD LENGTH TOO (FOR WHAT IT'S WORTH)
	HRL	T1,T2		;RETURN AS RECORD,,MESSAGE LENGTH
	PUSHJ	P,PUTWD1##	;RETURN SECOND VALUE
	JRST	CPOPJ1##	;SUCCESSFUL RETURN
;SUB-FUNCTION #2 = ENTER PASSIVE STATE.  (WAITING FOR CONNECT INITIATE)

TSKEP:	PUSHJ	P,GETSTA	;GET AND RANGE CHECK THE STATE
	CAIE	T1,LAT.ID	;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE
	PJRST	TK%ILS		;ERROR: ILLEGAL STATE
	PUSHJ	P,RD2NPD	;READ THE TWO NPD'S (ARG'S 1 & 2)
	  POPJ	P,		;NPD WAS BAD, PROPAGATE THE ERROR RETURN
	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,T.PSIV	;ENTER PASSIVE STATE.
	  JRST	[PUSHJ	P,GV2NPD##	;NO FREE LAT'S, FIRST RETURN THE NPD'S
		PJRST	TK%NFL]		;GIVE "NO FREE LINK ADDRESSES" ERROR
	RETSKP			;GIVE GOOD RETURN. STATE = LAT.CI



;SUB;SUB-FUNCTION #3 = ENTER ACTIVE STATE. (SEND CONNECT INITIATE)

TSKEA:	PUSHJ	P,GETSTA	;GET AND RANGE CHECK THE STATE
	CAIE	T1,LAT.ID	;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE
	PJRST	TK%ILS		;ERROR: ILLEGAL STATE
	PUSHJ	P,RD2NPD	;READ THE TWO NPD'S (ARG'S 1 & 2)
	  POPJ	P,		;NPD WAS BAD, PROPAGATE THE ERROR RETURN
	HLRZ	J,DEVNPD(F)	;GET THE ADDRESS OF THE REMOTE NPD
	SKIPG	T1,NPDNOD(J)	;T1 := THE NODE NUMBER TO SEND CONNECT TO
	JRST	[PUSHJ	P,GV2NPD##	;IF IT'S NEGATIVE, RETURN NPD'S
		JRST	TK%NXN]		;GIVE ILLEGAL NODE ERROR.
	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,SRCNDB##	;W := NDB ADDRESS (IF NODE IS UP)
	  JRST	[PUSHJ	P,GV2NPD##	;RETURN THE NPD'S
		PJRST	TK%NXN]		;  AND GIVE AN ILLEGAL NODE ERROR
	HRRM	T1,DEVNET(F)	;MAKE THIS TASK'S NODE BE .T1 (FOR NCSCNT)
	PUSHJ	P,T.ACTV	;ENTER ACTIVE STATE. SEND CONNECT INITIATE
	  JRST	[PUSHJ	P,GV2NPD##	;NO FREE CORE. FIRST RETURN THE NPD'S
		PJRST	TK%NFC]		;  THEN GIVE "NO FREE CORE" ERROR
	RETSKP			;GIVE GOOD RETURN. STATE = LAT.CC
;SUB-FUNCTION #4 = ENTER IDLE STATE.  SEND DISCONNECT IF NECESSARY.

TSKEI:	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,GETSTA	;GET AND RANGE CHECK THE CONNECTION STATE
	JRST	@.+1(T1)	;DISPATCH
	IFIW	CPOPJ1##
	IFIW	TSKEI1
	IFIW	TK%ILS
	IFIW	TSKEI3
	IFIW	TK%ILS


;LAT.CI - WAITING FOR A CONNECT INITIATE

TSKEI1:	PUSHJ	P,GV2NPD##	;RETURN THE TWO NPD'S
	PUSHJ	P,GIVSLA##	;RETURN THE SLA, ENTER STATE LAT.ID
	RETSKP			;GIVE GOOD RETURN


;LAT.OK - LINK IS UP AND RUNNING

TSKEI3:	CAIL	P4,3		;USER SPECIFY DISCONNECT REASON?
	JRST	[PUSHJ	P,GETWD1	;YES, GET "ARG1"
		JRST	.+2]		;AND USE IT
	MOVEI	T1,RSN.OK	;GET THE "NORMAL" REASON FOR DISCONNECT
	PUSHJ	P,NTDXDS	;SEND THE DISCONNECT, ENTER LAT.DC STATE
	  PJRST	TK%NFC		;ERROR: NO MONITOR FREE CORE
	RETSKP			;GIVE GOOD RETURN



;SUB-FUNCTION #5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT

TSKWT:	PUSHJ	P,T.WAIT	;WAIT FOR TASK TO ENTER "ID" OR "OK" STATE
	RETSKP			;GIVE GOOD RETURN
;SUB-FUNCTION #6 = OUTPUT WITH CONTROL OF INTERRUPT/DAP MESSAGE TYPE

TSKOU:	PUSHJ	P,GETSTA	;GET THE STATE OF THE CONNECTION,
	CAIE	T1,LAT.OK	;  AND IF WE AREN'T CONNECTED, THEN
	PJRST	TK%ILS		;  GIVE "ILLEGAL STATE" ERROR CODE
	HRRI	M,2(P3)		;GET THE ADDRESS OF TSKOP.'S ARG #1
	PUSHJ	P,GETWDU##	;READ THE DAP TYPE
	PUSH	P,T1		;SAVE THE TYPE FOR A BIT
	HLR	M,DEVBUF(F)	;GET THE ADDRESS OF THE BUFFER CONTROL BLOCK
	PUSHJ	P,GETWDU##	;GET THE ADDRESS OF THE BUFFER HEADER
	JUMPL	T1,TSKOU1	;RING NOT SET UP.  CALL "TOUT" TO SET UP RING
	HRRI	M,(T1)		;GET THE USE BIT
	PUSHJ	P,GETWDU##	;  TO SEE IF THIS BUFFER HAS HAD AN "OUT"
	JUMPL	T1,TSKOU1	;  DONE.  IF SO, DON'T CHANGE THE DAP TYPE
	PUSHJ	P,GETWD1##	;GET "XWD 0,WORD-COUNT"
	HRL	T1,(P)		;T1 := "XWD DAP-TYPE,WORD-COUNT"
	PUSHJ	P,PUTWDU##	;STORE TYPE AND COUNT IN THE BUFFER HEADER
TSKOU1:	POP	P,T2		;CLEAN UP THE STACK
	HLLZS	M,M		;CLEAR "BUFFER POINTER" BEFORE DOING AN OUT
	PUSHJ	P,TOUT##	;DO THE OUT. (NTDXMT WILL NOTICE THE DAP TYPE)
	  RETSKP		;IF UUO SUCCEEDS, RETURN NOW.
	JRST	TSKIOE		;IF THE UUO DIDN'T WORK, TELL THE USER
;SUB-FUNCTION #7 = INPUT WITH NOTIFICATION OR INTERRUPT/MESSAGE TYPE

TSKIN:	HRRZ	T1,DEVPCB(F)	;FIRST SEE IF ANY INPUT IS QUEUED
	JUMPN	T1,TSKIN1	;IF SO, READ IT. (EVEN IF DISCONNECTED)
	PUSHJ	P,GETSTA	;GET OUR STATE AND MAKE SURE
	CAIE	T1,LAT.OK	;  THAT WE ARE CONNECTED.
	PJRST	TK%ILS		;IF NOT CONNECTED, "ILLEGAL STATE"
TSKIN1:	HLLZS	M,M		;CLEAR THE "BUFFER POINTER"
	PUSHJ	P,TIN##		;DO THE "IN" UUO
	  SKIPA			;SKIP IF THE UUO WAS SUCCESSFUL
	JRST	TSKIOE		;IF UUO DIDN'T GIVE A BUFFER, GO SEE WHY
	HRR	M,DEVBUF(F)	;TO RETURN E-O-R NOTIFICATION, GET BUFFER
	PUSHJ	P,GETWDU##	;  HEADER, AND FROM THAT TRACK DOWN THE
	HRRI	M,1(T1)		;  ".BTCNT" WORD OF THE BUFFER JUST
	PUSHJ	P,GETWDU##	;  RETURNED.
	HLRZ	T1,T1		;TSKSER PUTS THE DAP TYPE IN LH(.BFCNT)
	HRRI	M,2(P3)		;GET THE ADDRESS OF ARG#1 OF THE TSKOP.
	PUSHJ	P,PUTWDU##	;  BLOCK AND RETURN THE DAP TYPE CODE
	RETSKP			;GIVE A GOOD RETURN TO THE ENTIRE UUO.

TSKIOE:	HRRZ	T1,DEVIOS(F)	;IF UUO FAILS, GET THE DEVICE STATUS
	HRRI	M,2(P3)		;  AND RETURN IT IN ARG #1 OF THE
	PUSHJ	P,PUTWDU##	;  TSK. ARGUMENT BLOCK.
	PJRST	TK%UDW		;TELL THE USER IT FAILED WITH "UUO DIDN'T WORK"
;T.WAIT	ROUTINE TO WAIT FOR A TASK TO ENTER EITHER "LAT.ID" OR "LAT.OK" STATE
;CALL	F := DDB POINTER
;RETURN	CPOPJ			;ALWAYS

T.WAIT:	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIE	T1,LAT.ID	;IF IT'S IDLE, OR
	CAIN	T1,LAT.OK	;  IF IT'S "RUNNING"
	POPJ	P,		;  THEN RETURN
	PUSHJ	P,NETHIB##	;OTHERWISE SLEEP TILL SOMEONE WAKES US.
	JRST	T.WAIT		;UPON AWAKING, SEE IF THE STATE CHANGED.


;T.PSIV	ROUTINE TO PUT A TASK IN THE PASSIVE (LAT.CI) STATE.
;CALL	F := DDB POINTER
;RETURN	CPOPJ			;IF NO FREE LINK ADDRESSES (LAT FULL)
;	CPOPJ1			;LINK ADDRESS ASSIGNED. WAITING FOR CI

T.PSIV:
IFN PARANOID&P$TSK,<		;IF WE'RE BEING CAUTIOUS,

	PUSHJ	P,T.CHKC	;MAKE SURE WE'RE NOT CONNECTED
>
	HRRZ	T1,F		;DDB ADDRESS FOR GETSLA
	MOVEI	T2,LAT.CI	;INITIAL LAT STATE IS CONNECT-INIT
	PUSHJ	P,GETSLA##	;ASSIGN A SLA, SET NEW STATE
	  POPJ	P,		;NO FREE LINK ADDRESSES
	DPB	T1,NETSLA##	;REMEMBER THE LINK ADDRESS
	RETSKP			;GIVE GOOD RETURN

;T.ACTV	ROUTINE TO PUT A TASK IN THE ACTIVE (LAT.CC) STATE. SENDS CONNECT
;CALL	F := DDB POINTER (WITH RH(DEVNET) := NODE NUMBER)
;RETURN	CPOPJ			;NO CORE, OR NO FREE LINKS, OR NO NODE
;	CPOPJ1			;CONNECT INITIATE SENT. STATE := LAT.CC

T.ACTV:
IFN PARANOID&P$TSK,<		;IF WE'RE BEING CAUTIOUS,

	PUSHJ	P,T.CHKC	;MAKE SURE WE'RE NOT CONNECTED
>
	HRRZ	T1,F		;DDB ADDRESS FOR GETSLA
	MOVEI	T2,LAT.CC	;INITIAL LAT STATE IS CONNECT-SENT (CFM WAIT)
	PUSHJ	P,GETSLA##	;ASSIGN A LINK ADDRESS
	  POPJ	P,		;ERROR: NO FREE LINK ADDRESSES
	DPB	T1,NETSLA##	;REMEMBER OUR LINK ADDRESS
	MOVEI	T1,MSGMAD##	;GET OUR DATA MAXIMUM
	DPB	T1,NETMML##	;SET FOR REMOTE TO SEE
	MOVE	T1,[XWD T.XSPN,T.XDPN] ;GET ADDRESS OF ROUTINE TO SEND "DPN"
	PUSHJ	P,NCSCNT##	;CALL ROUTINE TO ACTUALLY SEND THE CONNECT
	  PJRST	GIVSLA		;ERROR: NO CORE. FREE THE SLA AND RETURN
	RETSKP			;GIVE GOOD RETURN
IFN PARANOID&P$TSK,<		;IF CHECKING, STOP IF DDB IS CONNECTED
T.CHKC:	PUSHJ	P,GETSTA	;GET THE STATE (BETTER BE ZERO)
	MOVE	S,DEVIOS(F)	;GET THE "CONNECTED" BIT (AND OTHERS...)
	CAIN	T1,LAT.ID	;DIE IF STATE /= "IDLE"
	TLNE	S,IOSCON	;DIE IF DEVIOS THINKS WERE CONNECTED
	STOPCD	.,STOP,TSKIOS,	;++ IOSCON IS ON
	POPJ	P,		;RETURN IF EVERYTHING'S OK
>
SUBTTL 1.0      UUOCON INTERFACE.

;DISPATCH TABLE (FROM UUOCON)

	JRST	CPOPJ##		;(-5) DEVICE OFF LINE
	JRST	CPOPJ##		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) LENGTH CAN BE GOTTEN FROM DDB
	JRST	CPOPJ##		;(-2) INITIALIZE
	JRST	CPOPJ##		;(-1) HUNG DEVICE
NDEVTK::JRST	NTDREL##	;(0)  RELEASE
	JRST	T.CLSO		;(1)  CLOSE OUTPUT
	JRST	T.OUT		;(2)  OUTPUT
	JRST	T.IN		;(3)  INPUT
	JRST	T.ENTR		;(4)  ENTER
	JRST	T.LOOK		;(5)  LOOKUP
	JRST	NTDILI##	;(6)  DUMP MODE INPUT
	JRST	NTDILO##	;(7)  DUMP MODE OUTPUT
	JRST	CPOPJ##		;(10) USETO
	JRST	CPOPJ##		;(11) USETI
	JRST	CPOPJ##		;(12) GETF UUO
	JRST	CPOPJ##		;(13) RENAME UUO
	JRST	T.CLSI		;(14) CLOSE INPUT
	JRST	CPOPJ##		;(15) UTPCLR
	JRST	CPOPJ##		;(16) MTAPE UUO
SUBTTL 1.1        DDB SEARCH LOGIC INTERFACE.

;TSTTSK	ROUTINE TO SEE IF A TASK DDB SHOULD BE CREATED.
;CALL	MOVEI	P1,FLAGS	;DD%LOG ETC
;	MOVE	T1,[SIXBIT /DEVICE/]
;	PUSHJ	P,TSTTSK
;RETURN	CPOPJ			;NOT A TSK
;	CPOPJ1			;WAS A TSK, F := DDB POINTER

TSTTSK::TRNE	P1,DD%LOG##	;IS THIS A LOGICAL SEARCH?
	POPJ	P,		;IF SO, THEN DON'T MATCH PHYSICAL TASKS
	TLC	T1,(SIXBIT /TSK/) ;IF T1 := "TSKNNM" THEN THE LH(T1)
	TLNE	T1,-1		; IS NOW ZERO.
	JRST	[TLC T1,(SIXBIT /TSK/) ;IF IT'S NOT, FIXUP T1 AGAIN
		 POPJ P,]	; AND FAIL RETURN
	TLC	T1,(SIXBIT /TSK/) ;FIX UP T1 AGAIN...
	TRNE	P1,DD%DEA##
	  JRST	[TRZ P1,DD%DEA##
		 JRST CPOPJ##]
	NETDBJ			;INTERLOCK THIS CODE
	PUSHJ	P,SAVE4##	;SAVE THE P'S
	PUSHJ	P,SAVT##	;UUOCON LIKES ITS TEAS
	MOVE	P2,T1		;COPY DEVICE NAME TO A REASONABLE REGISTER
	PUSHJ	P,DVSCVT##	;CONVERT THE NETWORK DEVICE NAME, GET NODE #
	  POPJ	P,		;ILLEGAL DEVICE NAME
	MOVEI	T1,(T2)		;COPY THE NODE NUMBER FOR SRCNDB
	PUSHJ	P,SRCNDB##	;DOES THE NODE EXIST
	  POPJ	P,		;IF NOT, WE CAN'T CONNECT TO IT'S DEVICES
	MOVEI	P1,(W)		;COPY THE NDB FOR SRCNDT
	SETZ	P3,		;CLEAR THE LOGICAL NAME WORK
	HLRZ	T1,P2		;GET THE GENERIC DEVICE NAME
	PUSHJ	P,SRCNDT##	;DOES THIS NODE SUPPORT THIS DEVICE?
	  POPJ	P,		;IF NOT. THEN SEARCH FAILS
	PUSHJ	P,MAKDDB##	;IF NODE DOES SUPPORT THEM, THEN MAKE A DDB
	  POPJ	P,		;IF NO CORE. JUST MAKE SEARCH FAIL
	PUSHJ	P,LNKDDB##	;LINK IN THIS DDB (EVEN THOUGH NOT CONNECTED)
	RETSKP			;RETURN WITH NEWLY CONSTRUCTED DDB.
SUBTTL 1.2        OUTPUT UUO.

;T.OUT	ROUTINE TO HANDLE THE OUT UUO FOR THE TSK DEVICE.

T.OUT:	PUSHJ	P,SAVE4##	;THEY GET CLOBBERED NTDXMT AND FRIENDS
	MOVSI	S,IOSUSO	;CLEAR "UUOCON STOPED OUTPUT" SINCE IT
	ANDCAB	S,DEVIOS(F)	;  APPEARS TO BE TRYING TO START IT AGAIN

TOLOOP:	PUSHJ	P,NTDSET##	;SET UP S, W ETC
	MOVSI	S,IO		;SET DIRECTION TO "OUTPUT"
	IORB	S,DEVIOS(F)	; SO THAT UUOCON WILL BE HAPPY (WAIT1 ETC)
	PUSHJ	P,NTDONL##	;SEE IF THIS DEVICE IS STILL CONNECTED.
	  PJRST	T.HUNG		;NOT CONNECTED. SET IOSERR

; AS AN ECONOMY OF CODE, SET P1 := XWD CONVERSION-CODE, BYTE-SIZE.  P1
; SHOULD CONTAIN THESE VALUES UNTIL NTDISP IS CALLED.

	LDB	T1,PIOMOD##	;GET THE CURRENT MODE
	MOVE	P1,[XWD PCV.NC,^D07] ;ASSMUE ASCII MODE. (NO CONVERSION, 7 BIT)
	CAILE	T1,AL		;IF IT'S NOT [7-BIT] ASCII, IT'S IMAGE/BINARY
	MOVE	P1,[XWD PCV.BN,^D12] ; (BINARY CONVERSION, 12 BITS)
	CAIE	T1,A8		;UNLESS IT'S 8-BIT ASCII,
	CAIN	T1,BYTMOD	; OR 8-BIT BYTE MODE.
	MOVE	P1,[XWD PCV.NC,^D08] ; (NO CONVERSION, 8 BIT BYTES)

	MOVEI	T1,(P1)		;GET THE BYTE SIZE
	PUSHJ	P,NTDSOB##	;SET UP THE OUTPUT BUFFER
	  JRST	TODONE		;IF NO BUFFER, OUTPUT UUO IS DONE.

; NOTE: THIS CODE ALLOWS ZERO LENGTH DATA BUFFERS

	HRRZ	T1,DEVOAD(F)	;GET A POINTER TO THE BUFFER HEADER
	EXCTUX	<HLRZ P2,1(T1)>	; AND USE IT TO GET THE TYPE/INTERRUPT BIT
	PUSHJ	P,NTDCDQ##	;SEE IF WE HAVE ANY DRQ'S
	  JRST	TOWAIT		;IF NO DRQ'S, THEN GO WAIT FOR SOME
	HLRZ	T1,P1		;GET THE CONVERSION CODE
	SKIPN	T2,P2		;GET THE IDC TYPE FIELD
	MOVEI	T2,DC.DAR	;IF THE USER DIDN'T SPECIFY ONE. USE THE DEFAULT
	PUSHJ	P,NTDXMT##	;SEND A PCB'S WORTH OF DATA
	  JRST	[JUMPN T1,T.SET	;IF WE GOT AN ERROR, GO TELL THE USER
		 PUSHJ P,NETSLP	;IF NO CORE, SLEEP FOR A WHILE
		 JRST TOLOOP]	; AND TRY AGAIN
	PUSHJ	P,NTDDDQ##	;DECREMENT THE DATA REQUEST COUNT
	SKIPN	DEVAXO+1(F)	;IS THE BUFFER FINALLY EMPTY
	PUSHJ	P,NTDAOB##	;IF SO, ADVANCE THE OUTPUT BUFFER
	JRST	TOLOOP		;CONTINUE TILL SOMEONE GETS BORED.
;TOWAIT	ROUTINE TO WAIT FOR TASK OUTPUT DATA REQUESTS
TOWAIT:	PUSHJ	P,NTDWTO##	;LET NETSER DO THE WORK.
	  POPJ	P,		;NON-BLOCKING. RETURN TO UUOCON
	JRST	TOLOOP		;WHEN WE WAKE UP. TRY TO DO MORE OUTPUT




;TODONE	HERE WHEN WE HAVE OUTPUT ALL THE USERS BUFFERS
TODONE:	POPJ	P,
SUBTTL 1.3        INPUT UUO.

;T.IN	ROUTINE TO HANDLE THE "IN" UUO ENTRY TO THE TSK DEVICE
T.IN:	PUSHJ	P,SAVE4##	;WE CLOBBER MOST OF THEM
	MOVSI	S,IOSUSI	;CLEAR "UUOCON STOPED INPUT" SINCE IT'S
	ANDCAB	S,DEVIOS(F)	; OBVIOUSLY TRYING TO START IT AGAIN

TILOOP:	PUSHJ	P,NTDSET##	;USE COMMON SETUP ROUTINE (S, W, ETC)
	MOVE	S,DEVIOS(F)	;GET STATUS BITS BACK AFTER A POSSIBLE SLEEP
	TLNE	S,IOBEG		;IS THIS THE FIRST TIME THROUGH
	JRST	TIFRST		;IF SO, LOOK FOR PSUEDO NON-BLOCKING CONNECT

	MOVSI	S,IO		;CLEAR THE DIRECTION BIT SO THAT
	ANDCAB	S,DEVIOS(F)	; UUOCON WON'T GET CONFUSED.

	PUSHJ	P,NTDIBA##	;IS THERE AN INPUT BUFFER AVAILABLE?
	  POPJ	P,		;IF NOT, WE ARE DONE.
	HRRZ	T1,DEVPCB(F)	;GET A POINTER TO THE LIST OF INPUT PCB'S
	JUMPE	T1,TIWAIT	;IF NO DATA, WE MUST WAIT
	PUSHJ	P,NTDDID##	;DO THE DELAYED INPUT DISPATCH
	JRST	TILOOP		;KEEP IT UP TILL WE RUN OUT OF DATA.
;TIFRST	HERE WE CHECK TO SEE IF WE ARE CONNECTED.  IF NOT, AND THIS IS NON-
; BLOCKING STYLE I/O. THEN WE DO A DEVERR RETURN TO UUOCON.  OTHERWISE WE JUST
; WAIT.  WHEN WE FINNALY GET CONNECTED. WE MUST REMEMBER TO TURN OFF "IOSERR"
; WHICH GOT SET BY NTDSET.
TIFRST:	TLNE	S,IOSCON	;ARE WE CONNECTED YET
	JRST	[MOVSI S,IOBEG!IOSERR!IOSREL ;IF WE ARE CONNECTED, CLEAR
		 ANDCAB S,DEVIOS(F)	;  THESE BITS,
		 JRST TILOOP]	;  AND TRY ONCE AGAIN TO PROCESS DATA.
	PUSHJ	P,NTDWTI##	;IF NON CONNECTED, THEN WAIT FOR CONNECT/DATA
	  POPJ	P,		;IF NONBLOCKING, RETURN TO UUOCON
	JRST	TILOOP		;TRY ONCE MORE TO DO INPUT

;TIWAIT	HERE IF WE HAVE NO INPUT PCB'S TO PROCESS.  FIRST MAKE SURE WE HAVEN'T
; BEEN DISCONNECTED. IF SO, SET EOF.  OTHERWISE SEND DATA REQUESTS, AND
; WAIT IT OUT.
TIWAIT:	PUSHJ	P,NTDONL##	;IS THERE ANY PARTICULAR PROBLEM??
	  JRST	T.EOF		; IF SO, GO SEE WHAT IT IS
	PUSHJ	P,NTDXDQ##	;SEE IF WE ARE BEHIND ON OUR DATA-REQUESTS
	PUSHJ	P,NTDWTI##	;WAIT FOR DATA
	  POPJ	P,		;RETURN TO UUOCON IF NON-BLOCKING
	JRST	TILOOP		;AND GO MUNCH IT


;T.EOF	ROUTINE TO RETURN END-OF-FILE ON FIRST "IN" AFTER DISCONNECT.
T.EOF:	TLNE	S,IOEND		;SEE IF END-OF-FILE ALREADY SET
	JRST	T.HUNG		;YUP, GET SERIOUS ABOUT ERROR STATUS
	MOVSI	S,IOEND		;NO, SET EOF NOW
	JRST	T.SET		;AND LET UUOCON WORRY ABOUT IT


;T.HUNG	DEVICE IS OFFLINE (NTDONL), SEE IF STILL CONNECTED

T.HUNG:	TLNN	S,IOSCON	;STILL CONNECTED?
	PJRST	NTDGON##	;NO, GIVE ERROR
				;YES, FALL INTO T.SERR

;T.IMPM, T.SERR ROUTINES TO SET ERROR BITS AND RETURN
T.SERR:	MOVE	S,[XWD IOSERR,IODERR]	;THE TWO DEVICE ERROR BITS
	JRST	T.SET		; AND SET THEM IN DEVIOUS
T.IMPM:	MOVEI	S,IOIMPM	;IMPROPER MODE (NOT LOOKED UP/ENTERED)
T.SET:	IORB	S,DEVIOS(F)	;SET THE BITS
	POPJ	P,		;RETURN TO UUOCON.
SUBTTL 1.4        ENTER UUO.

;T.ENTR	ROUTINE TO HANDLE THE ENTER VECTORED ENTRY FROM UUOCON
;CALL	F := XWD FLAGS,DDB
;	M := UUO		;POINTE TO LOOKUP/ENTER BLOCK (LEB)
;RETURN	CPOPJ			;NOT ENTERED. ERROR STORED IN LEB
;	CPOPJ1			;ENTERED.  TASK IS CONNECTED.

T.ENTR:	PUSHJ	P,GETSTA	;GET OUR STATE.
	MOVEI	T2,1		;GET A "1"
	LSH	T2,(T1)		;MAKE IT A 1 BIT MASK
	TRNN	T2,1_LAT.ID!1_LAT.CI!1_LAT.OK ;LEGAL STATES FOR ENTER'ING
	PJRST	RTNISU		;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S"
	PUSHJ	P,SAVJW##	;WE CLOBBER THEM WITH NPD'S AND NDB'S
	PUSHJ	P,SAVE4##	;SAVE THE P'S
	PUSHJ	P,GETLEA	;GET THE LOOKUP ENTER ARG'S IN THE P'S
	  PJRST	RTNLEE		;  IF LEB ARGS BAD, STORE ERROR IN LEB & RETURN
	PUSHJ	P,GETSTA	;GET THE STATE AGAIN
	CAIN	T1,LAT.ID	;IF WE ARE IDLE, THEN
	JRST	T.ENT1		;  GO STORE ARGS & CONTINUE

;HERE IF TASK HAS BEEN LOOKED-UP (PUT IN PASSIVE STATE, POSSIBLY CONNECTED)

	PUSHJ	P,CHKLEA	;MAKE SURE THAT THE LEB'S ARE IN AGREEMENT
	  PJRST	RTNAEF		;  IF LEB BAD, GIVE AN "AEF" ERROR
	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIN	T1,LAT.OK	;IF WE'RE ALREADY CONNECTED, THEN
	RETSKP			;  GIVE A GOOD RETURN TO THE ENTER.

IFN PARANOID&P$TSK,<		;IF WE'RE BEING PARANOID, MAKE SURE
	CAIE	T1,LAT.CI	;  WE'RE IN THE "PASSIVE" STATE
	STOPCD	.,STOP,TSKNIP,	;++ NOT IN PASSIVE STATE
>
	PUSHJ	P,GV2NPD	;RETURN THE LOOKUP'S NPDS
	PUSHJ	P,GIVSLA##	;RETURN THE LAT (T.ACTV ASSIGNS A NEW ONE)
	JRST	T.ENT2		;GO SEND THE CONNECT INITIATE AND RETURN
;HERE IF WE HAVEN'T BEEN LOOKED UP YET. (STATE IS "IDLE")
T.ENT1:	PUSHJ	P,STOLEA	;STORE THE LOOKUP/ENTER ARGS
;HERE WE SET UP "W", BUILD TWO NPD'S, SEND THE CONNECT & WAIT FOR A REPLY
T.ENT2:	HRRZ	T1,DEVNET(F)	;GET THIS DEVICE'S NODE NUMBER
	PUSHJ	P,SRCNDB##	;SET W := NDB POINTER.
	  PJRST	RTNUNN		;  ERROR. RETURN "UNKNOWN NETWORK NODE"
	PUSHJ	P,LE2NPD	;MAKE 2 NPD'S, REMOTE & LOCAL FOR T.ACTV
	  PJRST	RTNENC		;  IF NO CORE "EXCEEDED NETWORK CAPACITY"
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER WE'RE TRYING TO CONNECT TO
	HLRZ	J,DEVNPD(F)	;GET THE "REMOTE" NPD
	MOVEM	T1,NPDNOD(J)	;SET THE NPD'S NODE NUMBER
	PUSHJ	P,T.ACTV	;SEND THE CONNECT INITIATE
	  JRST	[PUSHJ P,GV2NPD	;IF NO CORE, OR NO LATS, FREE NPD'S
		 PJRST RTNENC]	;RETURN EXCEEDED NETWORK CAPACITY

;IF NONBLOCKING, WE MIGHT WANT TO RETURN HERE

	PUSHJ	P,T.WAIT	;WAIT FOR CONNECT CONFIRM/REJECT
	PUSHJ	P,GETSTA	;GET OUR STATE (TO SEE IF CONFIRM/REJECT)
	CAIE	T1,LAT.OK	;IF WE'RE NOT CONNECTED, THEN
	JRST	[PUSHJ P,GV2NPD	;  RETURN BOTH THE NPD'S, AND
		 PJRST RTNTNA]	;  GIVE A "TASK NOT AVAILABLE" ERROR
	RETSKP			;  OTHERWISE, GIVE A GOOD RETURN
SUBTTL 1.5        LOOKUP UUO.

;T.LOOK	ROUTINE TO HANDLE THE LOOKUP VECTORED ENTRY FROM UUOCON
;CALL	F := XWD FLAGS,DDB
;	M := UUO		;POINTS TO THE USERS LOOKUP/ENTER BLOCK (LEB)
;RETURN	CPOPJ			;IF ERROR, CODE RETURNED IN LEB
;	CPOPJ1			;TASK LOOKED-UP. NOW IN "PASSIVE" STATE

T.LOOK:	PUSHJ	P,GETSTA	;GET OUR CONNECTION STATE
	MOVEI	T2,1		;GET A "1"
	LSH	T2,(T1)		;MAKE IT A 1 BIT MASK
	TRNN	T2,1_LAT.ID!1_LAT.OK ;LEGAL STATES FOR LOOKING UP
	PJRST	RTNISU		;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S"
	PUSHJ	P,SAVJW##	;J := NPD'S, W := NDB'S
	PUSHJ	P,SAVE4##	;WE PUT THE LOOKUP/ENTER ARGS HERE
	PUSHJ	P,GETLEA	;GET THE LEB'S DATA
	  PJRST	RTNLEE		;LEB BAD, RETURN ERROR CODE IN "T1"
	PUSHJ	P,GETSTA	;GET THE STATE AGAIN
	CAIN	T1,LAT.ID	;IF NOT IDLE, JUST CHECK THE ARGUMENTS
	JRST	T.LOO1		;IF IDLE, GO TO "PASSIVE" STATE

;HERE IF WE'VE BEEN ENTERED, CHECK THE LEB'S ARGS AND RETURN

	PUSHJ	P,CHKLEA	;MAKE SURE THE LOOKUP AGREES WITH THE ENTER
	  PJRST	RTNAEF		;  IF LEB IS BAD, RETURN "AEF"
	RETSKP			;GIVE GOOD RETURN TO THE LOOKUP

;HERE IF WE'VE NOT BEEN ENTERED, MAKE 2 NPD'S AND ENTER PASSIVE STATE
T.LOO1:	PUSHJ	P,STOLEA	;STORE DEVFIL AND FRIENDS FOR LE2NPD.

IFN PARANOID&P$TSK,<		;IF WERE CAUTIOUS, MAKE SURE NOT CONNECTED
	SKIPE	DEVNPD(F)	;DIE IF WE'VE ALREADY GOT 1 OR MORE NPD'S
	STOPCD	.,STOP,TSKAND,	;++ ALREADY GOT AN NPD
>
	HRRZ	T1,DEVNET(F)	;GET THE NUMBER OF THIS TASK'S NODE
	PUSHJ	P,SRCNDB##	;SET W := NDB POINTER.
	  PJRST	RTNUNN		;  ERROR. RETURN "UNKNOWN NETWORK NODE"
	PUSHJ	P,LE2NPD	;MAKE NPD'S BASED ON DEVFIL & FRIENDS
	  PJRST	RTNENC		;  NO CORE. RETURN "EXCEEDED NET CAP"

	CAIE	W,NETNDB##	;IF HE SPECIFIED "ANY" NODE, DON'T SET NPDNOD
	JRST	[HLRZ J,DEVNPD(F) ;GET ADDRESS OF "REMOTE" NPD.
		 HLRZ T1,NDBNNM(W) ;GET OUR NODE NUMBER
		 MOVEM T1,NPDNOD(J) ;SET THE NODE NUMBER
		 JRST .+1]	;CONTINUE WITH MAIN CODE

	PUSHJ	P,T.PSIV	;ENTER "PASSIVE" STATE
	  JRST	[PUSHJ P,GV2NPD	;IF NO CORE, OR NO LATS, FREE NPD'S
		 PJRST RTNENC]	;RETURN EXCEEDED NETWORK CAPACITY
	RETSKP			;GIVE GOOD RETURN TO THE LOOKUP
SUBTTL 1.6        CLOSE UUO.

;T.CLS	ROUTINE TO HANDLE THE CLOSE ENTRY FROM UUOCON
;CALL	MOVEI	F,DDB
;	PUSHJ	P,T.CLS		;FROM CLOSE1 CODE IN UUOCON
;RETURN	CPOPJ
;
;THE CLOSE UUO CODE DOES NOTHING IF THE TSK HAS NOT BEEN CLOSED ON BOTH INPUT
; AND OUTPUT.  IF IT HAS, IT DOES THE FINAL "OUT" TO FLUSH THE BUFFERS, AND
; SENDS A DISCONNECT INITIATE WAITING FOR THE DISCONNECT CONFIRM.
T.CLSO:	TLNE	F,ENTRB		;DON'T FORCE OUTPUT IF NOT ENTERED
	PUSHJ	P,NTDCLO##	;FORCE OUT THE LAST BUFFER (AND WAIT)
	TLZA	F,ENTRB		;SIGNIFY THAT WE ARE NO LONGER "ENTERED"
T.CLSI:	TLZ	F,LOOKB		;SIGNIFY THAT WE ARE NO LONGER "LOOKED UP"
T.CLS:	TLNE	F,ICLOSB	;IF WE HAVEN'T CLOSED BOTH INPUT AND
	TLNN	F,OCLOSB	; OUTPUT, THEN
	POPJ	P,		; DON'T ATTEMPT TO DISCONNECT THIS TASK

	PUSHJ	P,T.WAIT	;WAIT FOR CONNECTS/DISCONNECTS TO FINISH
	MOVE	S,DEVIOS(F)	;NOW SEE IF WE ARE CONNECTED
	TLNN	S,IOSCON
	JRST	T.CLS4		;DON'T SEND DISCONNECT IF NOT CONNECTED

T.CLS2:	MOVEI	T1,RSN.OK	;STANDARD REASON
	PUSHJ	P,NTDXDS##	;SEND THE DISCONNECT
	  JRST	[PUSHJ P,NETSLP## ;IF WE CAN'T SEND THE DISCONNECT, THEN
		 JRST T.CLS2]	; THEN WAIT FOR A BIT AND TRY AGAIN
T.CLS3:	PUSHJ	P,NETHIB##	;WAIT FOR THE CONFIRM
	LDB	T1,NETSLA##	;GET OUR LAT ADDRESS
	JUMPE	T1,T.CLS5	;THE DISCONNECT CONFIRM CODE WILL ZERO IT

IFN PARANOID&P$LAT,<		;MAKE SURE LAT ENTRY IS RIGHT
	LDB	T1,LATSTA##	;GET THE STATE
	CAIE	T1,LAT.DC	;SHOULD STILL BE DISCONNECT CONFIRM
	STOPCD	.,STOP,TSKNID,	;++ NOT IN DISCONNECT CONFIRM
>
	JRST	T.CLS3		;MUST HAVE BEEN A SPURIOUS WAKE
T.CLS4:	LDB	T1,NETSLA##	;FIRST CHECK TO SEE IF WE HAVE
	JUMPE	T1,T.CLS5	;LAT ASSIGNED. IF NOT, DON'T FREE IT.

IFN PARANOID&P$LAT,<
	LDB	T2,LATSTA##	;GET THE STATE
	CAIE	T2,LAT.CI	;THE ONLY LEGAL STATE AT THIS POINT IS "CI"
	STOPCD	.,STOP,TSKNIC,	;++ NOT IN "CI" STATE
>
	PUSHJ	P,GIVSLA##	;FREE THE SLA

T.CLS5:	PUSH	P,J		;NOW FREE THE NPD'S.  FIRST SAVE J
	PUSHJ	P,GV2NPD##	;FREE THE NPD'S
	POP	P,J
	SETZM	DEVFIL(F)	;CLEAR THE FILE NAME
	HRRZS	DEVEXT(F)	; THE EXTENSION
	SETZM	DEVPPN(F)	; THE PPN
	POPJ	P,		;ALL DONE.
SUBTTL 2.0      NETSER INTERFACE.

;TSKSER'S NDP DISPATCH VECTOR (HERE ON MESSAGES FROM NETSER)

	IFIW	NTDNWD##	;COMMON CODE FOR CRASHED NODE
	IFIW	NTDDSC##	;COMMON CODE FOR DISCONNECT
	IFIW	T.CONC		;SPECIAL CODE FOR CONNECT CONFIRM
	IFIW	T.CONI		;SPECIAL CODE FOR CONNECT INITIATE
	IFIW	NTDRDQ##	;COMMON CODE FOR DATA-REQUESTS
TSKNDP::IFIW	NTDQIP##	;QUEUE INCOMING PCB'S TO UUO LEVEL
	IFIW	T.DAPI		;DATA WITH OUT EOR
	IFIW	T.DAPI		;DATA WITH EOR
	IFIW	T.DAPI		;STATUS
	IFIW	T.DAPI		;CONTROL
	IFIW	T.DAPI		;UNIT ID
	IFIW	T.DAPI		;FILE SPEC



;DUMMY CONNECT INIT PROCESSOR (SHOULD HAVE MATCHED IN ICMCN1)

	NTSKCI==:NJNKCI##	;JUNK CI PROCESSOR IN NETSER
SUBTTL 2.1        CONNECT CONFIRM NCL MESSAGE.

;T.CONC	ROUTINE TO PROCESS THE CONNECT CONFIRM FOR A TASK
;CALL	MOVEI	F,DDB
;	P1, P4 := POINT TO THE "SLA" FIELD OF THE CONNECT
;RETURN	CPOPJ1			;ALWAYS

T.CONC:	PUSHJ	P,SAVJW##	;WE USE J FOR THE NPD

;SLA

	PUSHJ	P,EBI2BI##	;READ OUR REMOTE LAT ADDRESS
	DPB	T1,NETDLA##	;SAVE IT SO WE CAN TALK TO HIM
	PUSHJ	P,GV2NPD	;RETURN THE TWO STALE NPD'S.

;DPN(OBJ)

	PUSHJ	P,XSKIP##	;WE'RE NOT INTERESTED

;DPN(,PID)

	PUSHJ	P,GETSPN	;GET WHAT HE THINKS WE ARE
	  SETZ	J,		;  IF NO CORE, DON'T WORRY...
	HRRM	J,DEVNPD(F)	;STORE NEW LOCAL NPD

;SPN(OBJ)

	PUSHJ	P,XSKIP##	;WE'RE NOT INTERESTED

;SPN(PID)

	PUSHJ	P,GETSPN	;GET HIS ID
	  SETZ	J,		;  IF NO CORE, JUST RETURN ZERO
	HRLM	J,DEVNPD(F)	;STORE THE NEW REMOTE NPD

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

	PUSHJ	P,GETFEA	;READ THE "FEATURES"
	PUSHJ	P,T.OK		;SET BITS SAYING WE ARE CONNECTED
	RETSKP			;GIVE GOOD RETURN
SUBTTL 2.2        CONNECT INITIATE NCL MESSAGE.

;T.CONI	ROUTINE TO HANDLE THE CONNECT INITIATE ENTRY FOR THE TSK DEVICE.
;CALL	MOVEI	F,DDB
;	MOVE	P3,[XWD SLA,OBJ]
;	P1, P4 := POINT TO THE "DPN(PID)" FIELD OF THE CONNECT MESSAGE
;RETURN	CPOPJ			;DIDN'T LIKE THE CONNECT
;	CPOPJ1			;OK. CONNECT CONFIRM SENT. LINK IN "OK" STATE

T.CONI:	HRRZ	T1,P3		;GET THE OBJECT TYPE
	CAIE	T1,OBJ.TK	;  AND MAKE SURE IT'S FOR TYPE "TSK"
	POPJ	P,		;  IF NOT FOR US, EXIT NOW
	PUSHJ	P,SAVJW##	;WE CLOBBER J
	PUSHJ	P,SAVE4##	;  AND MASSACRE THE P'S
	MOVS	J,DEVNPD(F)	;GET THE "PATTERN" NPD POINTER
	TLNE	J,-1		;MAKE SURE THAT BOTH NPD'S
	TRNN	J,-1		;  EXIST
	POPJ	P,		;IF EITHER NPD MISSING, DON'T MATCH

	HLRZ	T1,NDBNNM(W)	;GET THIS NODE'S NUMBER
	SKIPL	T2,NPDNOD(J)	;GET THE PATTERN'S NODE NUMBER
	CAIN	T1,(T2)		;SKIP IF THEY DON'T MATCH
	SKIPA			;EITHER WILD CARD, OR MATCH, SUCCEED.
	POPJ	P,		;NO MATCH. EXIT NOW.

	PUSHJ	P,T.CON1	;CALL ROUTINE TO DO PATTERN MATCH
	  POPJ	P,		;  IF NO MATCH, GIVE "REJECT" RETURN

	HLRZ	T1,P3		;GET THE SLA
	DPB	T1,NETDLA##	;  AND REMEMBER IT.
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER
	HRRM	T1,DEVNET(F)	;  AND REMEMBER THAT TO.
;READ NCD'S

;DPN(,PID)

	PUSHJ	P,GETSPN	;SET J := NPD DESCRIBING WHAT WE MATCHED
	  POPJ	P,		;  NO CORE, GIVE ERROR RETURN FROM T.CONI
	HLRZ	T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER
	MOVEM	T1,NPDNOD(J)	;AND USE THAT INSTEAD OF HIS.
	PUSH	P,J		;SAVE NPD FOR A BIT

;SPN(OBJ)

	PUSHJ	P,XSKIP##	;WE'RE NOT INTERESTED

;SPN(,PID)

	PUSHJ	P,GETSPN	;READ THE SOURCE PID
	  JRST	[POP P,J	;IF NO CORE, GET LAST NPD READ
		 PJRST GIVNPD]	;  RETURN IT, AND ERROR RETURN FROM T.CONI
	HRLM	J,0(P)		;SAVE THE NEW "REMOTE" NPD

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

	PUSHJ	P,GETFEA	;READ THE "FEATURES"

;SEND CONFIRM

	HLRZ	J,DEVNPD(F)	;GET OLD "REMOTE" NPD AND FREE IT.
	PUSHJ	P,GIVNPD##	;  (THERE MUST BE ONE TO GET THIS FAR...)
	HLRZ	J,0(P)		;GET THE NEW "REMOTE" NPD
	HRLM	J,DEVNPD(F)	;  AND PUT IT WHERE T.XDPN CAN FIND IT.

	MOVE	T1,[XWD T.XSPN,T.XDPN] ;ROUTINES TO SEND SPN AND DPN
	EMRGCY			;USE EMERGENCY MEMORY IF NECESSARY
	PUSHJ	P,NCSCNT##	;SEND THE CONNECT CONFIRM
	 STOPCD	.,STOP,TSKSCC,	;++ SEND CONNECT CONFIRM FAILED

	HRRZ	J,DEVNPD(F)	;GET OLD "LOCAL" NPD AND FREE IT
	PUSHJ	P,GIVNPD##	;  (THERE MUST BE ONE IF WE GOT THIS FAR)
	POP	P,J		;GET NEW "LOCAL" NPD
	HRRM	J,DEVNPD(F)	;AND PUT IT WHERE A ".TKFRS" CAN FIND IT

	PUSHJ	P,T.OK		;DECLARE THE TSK UP, WAKE ANY WAITING JOBS
	RETSKP			;GIVE GOOD RETURN
;T.CON1	SUB-ROUTINE TO SET THINGS UP FOR THE "MATCH" ROUTINE.
;	THE ONLY REASON THAT THIS IS A SUBROUTINE IS TO MAKE IT EASY
;	TO SKIP/NON-SKIP RETURN.
;CALL	J := POINTER TO THE "PATTERN" NPD
;	P1, P4 := MESSAGE POINTER,COUNT TO PID (AS USUAL)
;RETURN	CPOPJ			;PATTERN DIDN'T MATCH PID
;	CPOPJ1			;PATTERN DID MATCH, P1, P4 UPDATED TO AFTER
;				;  PID

T.CON1:	PUSH	P,P3		;SAVE THE "XWD SLA,OBJ" INFORMATION
	PUSH	P,P1		;SAVE THE BYTE POINTER TO THE MESSAGE
	PUSH	P,P4		;SAVE THE LENGTH OF THE MESSAGE
	MOVE	P3,P4		;COPY THE LENGTH FOR MATCH
	PUSHJ	P,XSKIP##	;ADVANCE PAST PID SO WE CAN CALCULATE LENGTH
	SUB	P3,P4		;SET P3 := LENGTH(PID)
	MOVE	P4,-1(P)	;SET P4 := BYTE-POINTER TO PID

	MOVE	P1,NPDNLN(J)	;SET P1 := LENGTH OF THE "PATTERN"
	MOVEI	P2,NPDNAM(J)	;GET THE ADDRESS OF THE "PATTERN"
	HRLI	P2,(POINT 7)	;SET P2 := BYTE-POINTER TO "PATTERN"

	SETZ	T4,		;GET A ZERO
	EXCH	T4,TKMTCH	;SEE IF THERE IS ALREADY A PSUEDO-STACK
	JUMPE	T4,[MOVEI T2,100	;GET LENGTH OF PSUEDO-STACK
		    PUSHJ P,GETZWD##	;TRY TO ALLOCATE A NEW PSUEDO-STACK
		      JRST T.CON3	;IF NO CORE, CLEAN UP AND ERROR RETURN
		    MOVEI T4,(T1)	;COPY ADDRESS OF NEW STACK
		    HRLI T4,-100	;MAKE IT AN AOBJN POINTER
		    JRST .+1]	;RETURN TO MAIN CODE WITH T4 := STACK POINTER
	PUSHJ	P,MATCH		;SEE IF THE PID MATCHES THE PATTERN
	  JRST	T.CON2		;  IF NO MATCH, CLEAN UP AND ERROR RETURN
	AOS	-3(P)		;IF IT MATCHES. GIVE SKIP RETURN (UGH...)
T.CON2:	EXCH	T4,TKMTCH	;PUT STACK IN THE PSUEDO-STACK CACHE
	JUMPN	T4,[MOVEI T1,(T4)	;IF THERE IS ALREADY A P-STACK,
		    HRLI T2,(T4)	;  THEN WE MUST FREE THE EXTRA
		    MOVN T2,T2		;  ONE.
		    PUSHJ P,GIVZWD##	;CALL NETSER TO FREE THE CORE.
		    JRST .+1]	;RETURN TO MAIN LINE CODE.

T.CON3:	POP	P,P4		;SET P4 := LENGTH(MESSAGE-PID)
	POP	P,P1		;SET P1 := BYTE-POINTER TO PID
	POP	P,P3		;SET P3 := "XWD SLA,OBJ"
	POPJ	P,		;GIVE (POSSIBLY SKIP) RETURN
SUBTTL 2.3        DAP MESSAGES.

;T.DAPI	HERE TO PROCESS ALL OF THE INCOMING DAP MESSAGES
;CALL	MOVEI	T1,IDC MESSAGE TYPE
;	MOVEI	F,DDB OF DEVICE GETTING MESSAGES
;RETURN	CPOPJ			;MESSAGE BAD
;	CPOPJ1			;MESSAGE OK

T.DAPI:	HRRZ	T2,DEVPCB(F)	;GET A POINTER TO THE PCB WE'RE READING
	MOVE	T2,PCBPTR(T2)	;GET A BYTE POINTER TO THE NCT FIELD OF THE MSG
	ILDB	T2,T2		;GET THE NCT BYTE
	TLNE	T2,NCT.IT	;IF THIS IS AN INTERRUPT MESSAGE,
	IORI	T1,(1B0)	;  REMEMBER, SET "INTERRUPT" BIT IN BUFFER HEAD
	MOVE	P2,T1		;COPY THE HALFWORD INTO A SAFER REGISTER.

	LDB	T1,PIOMOD##	;GET THE MODE IN WHICH WE ARE READING.
	CAIG	T1,AL		;7-BIT ASCII OR ASCII LINE?
	JRST	T.ASCI		;IF SO, GO TO ASCII CODE
	CAIE	T1,A8		;8-BIT ASCII MODE?
	CAIN	T1,BYTMOD	; OR BYTE MODE?
	JRST	T.BYTE		;IF SO, SPECIAL CODE
	JRST	T.IMAG		;ALL THE REST IS IMAGE.



T.ASCI:	SKIPA	T4,[7]		;SEVEN BIT BYTES IN ASCII
T.BYTE:	MOVEI	T4,8		;EIGHT BIT BYTES IN BYTE MODE
	PUSHJ	P,T.SIB		;USE COMMON SET-UP ROUTINE
T.BYT1:	SOJL	P4,T.ADVB	;IF DONE. ADVANCE PCB & USER'S BUFFERS
	ILDB	T1,P1		;GET THE NEXT DATA BYTE
	SOSGE	DEVAXI+1(F)	;COUNT OFF NEXT BYTE IN THE BUFFER
	JRST	T.BKTL		;IF NO ROOM, SET IOBKTL
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE BYTE
	JRST	T.BYT1		;LOOP UNTIL INPUT MESSAGE IS USED UP.
T.IMAG:	MOVEI	T4,^D12		;12 BIT BYTES
	PUSHJ	P,T.SIB		;USE COMMON SETUP ROUTINE
T.IMG1:	SOJL	P4,T.ADVB	;IF NO MORE, ADVANCE PCB'S AND USER'S BUFFERS
	ILDB	T1,P1		;GET THE TOP 8 BITS OF THE FIRST BYTE
	LSH	T1,4		;POSITION THEM IN THE 12 BIT FIELD
	SOJL	P4,T.IMG2	;IF NO MORE, STORE THIS WITH ZERO FILL
	ILDB	T2,P1		;GET LOW 4 BITS THIS BYTE, HIGH 4 OF THE NEXT
	ROT	T2,-4		;POSITION THE LOW 4 BITS
	IORI	T1,(T2)		;COMBINE BOTH HALVES FOR A 12 BIT BYTE
	SOSGE	DEVAXI+1(F)	;COUNT OFF THIS BYTE
	JRST	T.BKTL		;GIVE AN ERROR IF IT WON'T FIT
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THIS FIRST 12 BIT BYTE
	SOJL	P4,T.ADVB	;IF NO MORE, LAST 4 BITS ARE GARBAGE.
	ILDB	T1,P1		;GET THE LAST 8 BITS OF THE SECOND 12 BIT BYTE
	ROT	T2,^D12		;ISOLATE THE LOW 4 BITS AS THE HIGH 4
	IORI	T1,(T2)		;BUILD THE SECOND 12 BIT BYTE
T.IMG2:	SOSGE	DEVAXI+1(F)	;COUNT OFF THIS BYTE
	JRST	T.BKTL		;GIVE AN ERROR IF IT WON'T FIT
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE SECOND 12 BIT BYTE
	JRST	T.IMG1		;LOOP UNTIL ALL INPUT IS PROCESSED.


;T.SIB	ROUTINE TO SET UP AN INPUT BUFFER FOR TSK INPUT
; CALLS NTDSIB, AND STORES THE MESSAGE TYPE AND INTERRUPT BIT IN THE
; USER'S BUFFER HEADER.
T.SIB:	PUSHJ	P,NTDSIB##	;SET UP THE INPUT BUFFER
	 STOPCD	.,STOP,TSKSIB,	;++ NO INPUT BUFFER (BUT WE CHECKED IN T.IN)
	HRRZ	T1,DEVIAD(F)	;GET THE ADDRESS OF THE BUFFER HEADER
	EXCTUU	<HRLM P2,1(T1)>	;STORE THE MESSAGE TYPE AND INTERRUPT BIT
	POPJ	P,		;RETURN TO MAIN-LINE CODE.

;T.ADVB	TASK ADVANCE BUFFER AND PCB ROUTINE.  THIS ROUTINE ADVANCES
;  THE BUFFER IFF THE MESSAGE RECEIVED WAS NOT DATA-WITHOUT-EOR, OR
;  IF THE "DISABLE MESSAGE RE-ASSEMBLY" (IOSDMR) BIT WAS SET.
;CALL	P2 := IDC TYPE		;LEFT OVER FROM EARLIER
;RETURN	CPOPJ1			;ALWAYS.

T.ADVB:	TRZ	P2,(1B0)	;MAKE SURE THE "INTERRUPT" BIT IS OFF
	CAIN	P2,DC.DAT	;IF IT'S NOT DATA-WITHOUT-EOR,
	TLNE	S,IOSDMR	;  OR WE'RE NOT RE-ASSEMBLING BUFFERS
	PJRST	NTDA1B##	;  THEN ADVANCE THE BUFFER
	RETSKP			;IF DATA WITHOUT-EOR, THEN DON'T ADVANCE
				;  THE BUFFER


;T.BKTL	ROUTINE TO SET THE "IOBKTL" ERROR BIT IF A USERS BUFFER IS TOO SMALL
; IT ADVANCES THE USERS BUFFER, AND SKIP RETURNS (ADVANCING THE DAP MESSAGE)
;
T.BKTL:	MOVEI	S,IOBKTL	;GET THE BLOCK TOO LARGE BIT
	IORB	S,DEVIOS(F)	;SET IT
	PJRST	NTDA1B##	;ADVANCE THE USERS BUFFER AND THE DAP MESSAGE
SUBTTL X.X	ONCE/SECOND TASK CODE

;FREE THE TEMPORARY "PSUEDO-STACK" USED BY TSKSER
TSKSEC::SETZ	T2,		;GET A ZERO TO INDICATE NO BLOCK
	EXCH	T2,TKMTCH	;GET "XWD LENG,ADDR" OF BLOCK
	JUMPE	T2,CPOPJ##	;IF NONE, RETURN NOW
	HLRE	T1,T2		;COPY (MINUS) THE LENGTH
	MOVN	T1,T1		;MAKE THE LENGTH POSITIVE
	PJRST	GIVZWD##	;RETURN THE STORAGE
SUBTTL 3.0      SUBROUTINES.

SUBTTL 3.1        LOOKUP/ENTER BLOCK MANIPULATION

;GETLEA	ROUTINE TO GET THE LOOKUP/ENTER ARGUMENTS FOR THE TSK DEVICE.
;CALL	MOVE	M,THE UUO
;	PUSHJ	P,GETLEA
;RETURN	CPOPJ			;ERROR CODE IN T1
;	CPOPJ1			;P1 := DEVNAM
;				;P2 := DEVEXT
;				;P3 := DEVPPN (THE USERS IF NOT PRVJ)
GETLEA:	PUSH	P,U		;USE U AS A TEMP TO
	MOVE	U,M		; THE ADDRESS OF THE ARGUMENT LIST
	PUSHJ	P,GETWDU##	;GET THE FIRST (DEVNAM OR COUNT)
	MOVE	P1,T1		;RETURN FIRST WORD AS DEVNAM
	TLNN	T1,-1		;IS IT AN EXTENDED BLOCK
	JRST	GETLEE		; IF SO. GO TO SPECIAL CODE TO READ IT
	HRRI	M,UUNEXT(U)	;GET THE EXTENSION
	PUSHJ	P,GETWDU##	; FROM THE USERS MEMORY, AND
	MOVE	P2,T1		; RETURN THAT AS DEVEXT
	HRRI	M,UUNPPN(U)	;GET THE PPN FROM THE USERS MEMORY
	JRST	GETLE1		; AND GO TO COMMON CODE.

GETLEE:	MOVEI	T1,FNFERR	;IN CASE TOO SHORT
	CAIGE	P1,UUXEXT	;IS THIS BLOCK LONG ENOUGH
	JRST	UPOPJ##		; IF TOO SHORT, GIVE AN ERROR RETURN
	HRRI	M,UUXNAM(U)	;GET THE FILE NAME
	PUSHJ	P,GETWDU##	; FROM THE USERS MEMORY,
	MOVE	P1,T1		; AND RETURN AS DEVNAM
	HRRI	M,UUXEXT(U)	;GET THE EXTENSION
	PUSHJ	P,GETWDU##	; FROM THE USER
	MOVE	P2,T1		; AND RETURN AS DEVEXT
	HRRI	M,UUXPPN(U)	;GET THE PPN

GETLE1:	PUSHJ	P,GETWDU##	;GET THE PPN
	JUMPE	T1,GETL1A	;DEFAULT PPN?
	TLNE	T1,-1		;IS IT A PATH BLOCK?
	JRST	GETL1A		;NO,CONTINUE ONWARD
	HRRI	M,2(T1)		;YES, POINT TO PPN IN PATH BLOCK
	PUSHJ	P,GETWDU##	;GET THE REAL PPN
GETL1A:	MOVE	T2,.CPJOB##	;GET THIS GUY'S JOB NUMBER
	SKIPN	P3,T1		;GET USER-SPECIFIED PPN
	MOVE	P3,JBTPPN##(T2)	;HE DIDN'T SPECIFY ONE, USE JOB'S PPN.
	CAME	P3,JBTPPN##(T2)	;SPECIFYING A PPN OTHER THAN HIS?
	CAMN	P3,[-1]		;(OR [777777,777777]?)
	  JRST	GETLE2		;NO, IT IS OK
	MOVEI	T1,PRTERR	;IN CASE NOT PRIVILEGED
	PUSHJ	P,NTDPRV##	; HE MUST BE PRIVILEGED
	  JRST	GETLE9		; AND HE IS NOT, PROTECTION ERROR
GETLE2:	MOVE	T1,P3		;GET THE PPN THAT WE WILL USE
	PUSHJ	P,PUTWDU##	;TELL THE USER WHAT PPN WE REALLY ARE USING
	AOS	-1(P)		;GIVE A GOOD RETURN
GETLE9:	MOVE	M,U		;RESTORE THE UUO
	PJRST	UPOPJ##
;CHKLEA	ROUTINE TO CHECK TO MAKE SURE THAT THE DDB'S DEVNAM, DEVEXT, AND
;	DEVPPN AGREE WITH THE LOOKUP/ENTER BLOCK'S
;CALL	MOVEI	F,DDB		;WITH DEVNAM ... SET UP
;	P1, P2, P3 := THE LOOKUP/ENTER ARGS
;RETURN	CPOPJ			;THEY DON'T AGREE (AEF ERROR RETURNED)
;	CPOPJ1			;THEY AGREE
CHKLEA:	CAMN	P1,DEVFIL(F)	;COMPARE THE FILE NAMES
	CAME	P3,DEVPPN(F)	;COMPARE THE PPN'S
	JRST	RTNAEF		;GIVE THE "AEF" ERROR (ALREADY EXISTING FILE)
	XOR	P2,DEVEXT(F)	;COMPARE THE EXTENSIONS
	TLNE	P2,-1		; AND ONLY THE EXTENSIONS
	JRST	RTNAEF		;DIFFERENT. GIVE ERROR
	RETSKP			;ALL THE SAME. GIVE GOOD RETURN


;STOLEA	ROUTINE TO STORE THE LOOKUP/ENTER ARGS IN P1, P2, P3 INTO A DDB
;CALL	MOVEI	F,DDB
;	P1, P2, P3 := FILE NAME, EXTENSION, PPN
;	PUSHJ	P,STOLEA
;RETURN	CPOPJ			;ALWAYS
STOLEA:	MOVEM	P1,DEVFIL(F)	;STORE THE FILE NAME
	HLLM	P2,DEVEXT(F)	;STORE JUST THE EXTENSION
	MOVEM	P3,DEVPPN(F)	;STORE THE PPN
	POPJ	P,		;ALL DONE
;ERRORS	ROUTINES TO RETURN VARIOUS LOOKUP/ENTER ERRORS
;
;    RTNFNF	;(00) FILE NOT FOUND
;    RTNPRT	;(02) PROTECTION ERROR
;    RTNAEF	;(04) ALREADY EXISTING FILE
;    RTNENC	;(37) EXCEEDED NETWORK CAPACITY
;    RTNTNA	;(40) TASK NOT AVAILABLE
;    RTNUNN	;(41) UNKNOWN NETWORK NODE


DEFINE X(CODE),<		;;SIMPLE MACRO TO MAKE DEFINING THESE EASY
RTN'CODE:
	MOVEI	T1,CODE'ERR	;;S.MAC HAS ALL THESE SYMBOLS DEFINED
	PJRST	RTNLEE		;;COMMON CODE TO RETURN THE ERROR
>

	X	FNF		;FILE NOT FOUND
	X	PRT		;PROTECTION FAILURE (USER NOT PRIVILEGED)
	X	AEF		;ALREADY EXISTING FILE
	X	ISU		;ILLEGAL SEQUENCE OF UUO'S
	X	ENC		;EXCEEDED NTEWORK CAPACITY
	X	TNA		;TASK NOT AVAILABLE
	X	UNN		;UNKNOWN NETWORK NODE



;RTNLEE	ROUTINE TO RETURN A LOOKUP/ENTER ERROR CODE.
;CALL	MOVE	U,UUO
;	MOVEI	T1,ERROR NUMBER
;	PUSHJ	P,RTNLEE
;RETURN	CPOPJ			;ALWAYS
RTNLEE:	PUSH	P,M		;SAVE THE UUO
	PUSH	P,T1		;STORE THE ERROR CODE FOR LATER
	PUSHJ	P,GETWDU##	;GET THE FIRST WORD (TO SEE IF EXTENDED L/E)
	MOVEI	M,UUNEXT	;ASSUME THAT THIS IS THE OLD NON-EXTENDED FORM
	TLNN	T1,-1		; BUT IF IT IS EXTNEDED,
	MOVEI	M,UUXEXT	; THEN CHANGE OUR MIND
	ADD	M,-1(P)		;ADD IN OFFSET OF THE BASE OF THE BLOCK
	PUSHJ	P,GETWDU##	;GET THE "EXTENSION" FIELD
	HRR	T1,(P)		;PUT THE ERROR CODE IN THE RH
	PUSHJ	P,PUTWDU##	;STORE THE ERROR CODE IN THE USERS MEMORY
	POP	P,T1		;RESTORE THE ERROR CODE
	POP	P,M		;RESTORE THE UUO
	POPJ	P,		;ALL DONE
SUBTTL 3.2        NPD MANIPULATION
SUBTTL 3.2.1	    USER NPD MANIPULATION

;ADCNPD	ROUTINE TO ADDRESS CHECK AN NPD
;CALL	M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR)
;RETURN	NOT AT ALL -- PAGE FAULT, OR ADDRESS ERROR
;	CPOPJ		NPD TOO SHORT
;	CPOPJ1		ALL'S OK

ADCNPD:	PUSHJ	P,GETWDU##	;GET XWD LENGTH,ADDRESS
	HLRZ	T2,T1		;COPY THE LENGTH
	CAIGE	T2,3		;IS IT LONG ENOUGH TO HOLD A VALID NPD
	JRST	TK%ILN		;IF NOT, SAY "ILLEGAL NPD"
	HRLI	T1,(IFIW)	;MAKE SECTION LOCAL REFERENCE
	PUSHJ	P,ARNGE##	;MAKE SURE THAT THE NPD IS INCORE
	  JRST	ADRERR##	;ADDRESS CHECK
	  JRST	UADERR##	;ILLEGAL FOR I/O
	RETSKP			;IF IT IS, GIVE GOOD RETURN
;REDNPD	ROUTINE TO READ AN NPD.  NPD MUST BE ADDRESSABLE (FAULT = "IME")
;CALL	M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR)
;RETURN	CPOPJ		SOME SORT OF ERROR, ERROR CODE STORED
;	CPOPJ1		J := NPD

REDNPD:	PUSHJ	P,SAVE1##	;USE P1 FOR A TEMP
	PUSHJ	P,GETWDU##	;GET "XWD LENGTH,ADDRESS" OF NPD
	MOVE	P1,T1		;SAVE XWD LENGTH,ADDR
	HRRZS	T1		;PREVENT ILLEGAL-SECTION IMES
	EXCTUX	<SKIPL T1,1(T1)>;GET THE LENGTH OF THE NAME-STRING
	CAILE	T1,^D100	;ALLOW THIS MANY CHARS FOR THE NPD
	PJRST	TK%ILN		;GIVE ILLEGAL NPD ERROR IF BAD LENGTH
	ADDI	T1,<2*5>+4	;ADD 3 WORDS, ROUND UP
	IDIVI	T1,5		;CALCULATE NUMBER OF WORDS TO HOLD NPD
	HLRZ	T2,P1		;GET "DECLARED" LENGTH
	CAILE	T1,(T2)		;MAKE SURE NPD FITS IN RANGE-CHECKED REGION
	PJRST	TK%ILN		;GIVE ILLEGAL NPD ERROR IF IT DOESN'T FIT
	ADDI	T1,1		;ACCOUNT FOR MONITOR'S "NPDBLK" WORD
	PUSHJ	P,GETNPD##	;ALLOCATE AN NPD, J := ADDRESS
	  PJRST	TK%NFC		;ERROR: NO MONITOR FREE CORE
IFE FTXMON,<
	HRLZ	T1,P1		;MAKE BLT POINTER: FROM = USER ADDRESS
	HRRI	T1,NPDNOD(J)	;  TO = MONITOR NPD ADDRESS
	HLRZ	T2,NPDBLK(J)	;T2 := LENGTH OF THE NPD
	ADDI	T2,-1(J)	;T2 := ADDRESS OF LAST WORD IN THE NPD
	EXCTUX	<BLT T1,(T2)>	;COPY THE NPD
>
IFN FTXMON,<
	XSFM	T2		;GET PCS
	HRLZS	T2		;IN LH WHERE IT BELONGS
	HRR	T2,P1		;FORM USER SOURCE ADDRESS
	HRRZI	T3,NPDNOD(J)	;FORM MONITOR DESTINATION ADDRESS
	HLRZ	T1,NPDBLK(J)	;GET LENGTH IN WORDS OF TRANSFER
	SUBI	T1,NPDNOD	;OFFSET SINCE WE DON'T START AT BEGINNING
	XBLTUX	T1		;COPY THE NPD
>
	RETSKP			;GIVE GOOD RETURN
;RD2NPD	ROUTINE TO READ BOTH NPD'S FOR .TKFEA OR .TKFEP SUB FUNCTIONS
;	FREE'S OLD NPD'S FIRST, THEN READS NEW ONES.
;CALL	P1, P2, P3, P4 := CHANNEL, SUB=FUNCTION, ADDRESS, LENGTH
;RETURN	CPOPJ		SOMETHING'S WRONG, ERROR CODE STORED
;	CPOPJ1		NPD'S READ.  DEVNPD(F) HAS POINTERS TO BOTH

RD2NPD:	SKIPE	DEVNPD(F)	;MAKE SURE THAT THERE AREN'T ANY NPD'S ASSIGNED
	STOPCD	.,STOP,TSKNPD,	;++ NPD ALREADY ASSIGNED

	HRRI	M,2(P3)		;GET THE ADDRESS OF THE FIRST NPD POINTER
	PUSHJ	P,ADCNPD	;ADDRESS CHECK IT
	  POPJ	P,		;ERROR?  PASS IT BACK
	HRRI	M,3(P3)		;GET THE ADDRESS OF THE SECOND NPD POINTER
	PUSHJ	P,ADCNPD	;ADDRESS CHECK THIS ONE TOO
	  POPJ	P,		;ERROR. PASS IT BACK

	HRRI	M,2(P3)		;GET THE ADDRESS OF THE FIRST NPD POINTER AGAIN
	PUSHJ	P,REDNPD	;GET J := ADDRESS OF NPD IN MONITOR FREE CORE
	  POPJ	P,		;SOME RANDOM ERROR. CODE ALREADY STORED
	HRRM	J,DEVNPD(F)	;STORE "LOCAL" NPD
	HRRI	M,3(P3)		;GET ADDRESS OF SECOND NPD POINTER
	PUSHJ	P,REDNPD	;GET J := ADDRESS OF COPY
	  JRST	[SETZ J,	;ERROR. FIRST FREE "LOCAL" NPD
		 EXCH J,DEVNPD(F) ;AND CLEAR DEVNPD
		 PJRST GIVNPD##];THEN RETURN. (ERROR CODE ALREADY STORED)
	HRLM	J,DEVNPD(F)	;STORE THE "REMOTE" NPD
	RETSKP
;WRTNPD	ROUTINE TO COPY A MONITOR NPD BACK INTO USER SPACE.
;CALL	M := ADDRESS OF USER'S NPD POINTER (XWD LENGTH,ADDR)
;	J := ADDRESS OF MONITOR NPD.
;RETURN	CPOPJ			;USER'S NPD DESCRIPTOR IS BAD
;	CPOPJ1			;ALL'S OK. NPD RETURNED.

WRTNPD:	JUMPE	J,[SETZ T1,	;IF NO NPD, (PROBABLY SHORT OF CORE)
		   PJRST PUTWDU##] ;WRITE ZERO'S OVER THE USERS NPD POINTER
	PUSHJ	P,SAVE1##	;WE USE P1 AS A TEMP
	PUSH	P,J		;SAVE NPD POINTER (???WDU## CLOBBERS J)
	PUSHJ	P,GETWDU##	;GET THE NPD POINTER (XWD LENGTH,ADDRESS)
	POP	P,J		;GET NPD POINTER BACK
	HLRZ	T2,NPDBLK(J)	;GET THE LENGTH OF THE MONITOR NPD
	SUBI	T2,1		;  LESS ONE (MONITOR'S LENGTH INCLUDES NPDBLK)
	HLRZ	T3,T1		;GET THE LENGTH OF THE USER'S AREA
	CAIGE	T3,(T2)		;SEE IF THE NPD WILL FIT.
	PJRST	TK%NTS		;ERROR: USER'S NPD IS TOO SHORT
	MOVNI	T2,1(T2)	;GET NEGATIVE COUNT (+1 FOR AOBJP)
	HRLZ	P1,T2		;SET UP THE LH OF THE AOBJN POINTER
	HRRI	P1,(J)		;SET UP THE RH.
	HRRI	M,(T1)		;GET THE ADDRESS OF THE USER'S NPD AREA
	PUSH	P,J		;SAVE NPD POINTER AGAIN. (PUTWRD...)
WRTNP1:	AOBJP	P1,JPOPJ1##	;COUNT OFF THE NEXT ITEM, EXIT IF DONE
	MOVE	T1,(P1)		;FETCH THE NEXT WORD OF THE NPD
	PUSHJ	P,PUTWDU##	;STORE THE WORD
	AOJA	M,WRTNP1	;INCREMENT USER'S ADDRESS AND DO NEXT WORD.
SUBTTL 3.2.2	    MONITOR NPD MANIPULATION

;GETSPN	ROUTINE TO BUILD A REMOTE NPD BASED ON CONNECT MSG DATA
;CALL	P1, P4 := POINTER TO THE "PID"
;	W := POINTER TO NDB OF REMOTE NODE
;	PUSHJ	P,GETPID
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;J := POINTER TO A NEWLY CONS-ED NPD
;				;  P1, P4 POINT AFTER THE PID

GETSPN:	MOVE	T2,P1		;COPY THE BYTE POINTER
	HRREI	T1,-1(P4)	;GET THE COUNT -1
GETSP1:	ILDB	T4,T2		;GET THE NEXT CHAR FROM THE MESSAGE
	TRNE	T4,200		;SKIP OUT OF THE LOOP IF NOT EXTENSIBLE
	SOJGE	T1,GETSP1	;LOOP COUNTING ALL CHARS IN THE PID

	SUBM	P4,T1		;CALCULATE THE NUMBER OF CHARS IN THE PID
	PUSH	P,T1		;SAVE THE PID'S LENGTH (IN CHARACTERS)
	ADDI	T1,3*5+4	;ACCOUNT FOR NPDNOD AND NPDNLN, ROUND UP
	IDIVI	T1,5		;DIVIDE TO GET WORDS NEEDED TO HOLD PID
	PUSHJ	P,GETNPD##	;ALLOCATE A NEW NPD
	  JRST	[PUSHJ P,XSKIP##;SKIP OVER THE PID
		 JRST TPOPJ##]	;  FIXUP STACK, RETURN WITH PID NOT COPIED
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER OF THE REMOTE
	MOVEM	T1,NPDNOD(J)	;  AND SAVE IT IN THE NPD
	POP	P,T4		;GET THE CHARACTER COUNT BACK
	MOVEM	T4,NPDNLN(J)	;  AND SAVE THAT TOO
	MOVE	T3,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE "NAME" PART
	SUBI	P4,(T4)		;MAKE T4 REFLECT THE CHARS WE ARE ABOUT TO READ
GETSP2:	ILDB	T1,P1		;READ A CHAR FROM THE MESSAGE
	IDPB	T1,T3		;STORE IT IN THE NEW PID STRING
	SOJG	T4,GETSP2	;LOOP OVER ALL CHARACTERS
	RETSKP			;ALL DONE.  GIVE GOOD RETURN
;GETFEA	ROUTINE TO COPY THE "FEA" FIELDS FROM A MESSAGE TO A DDB
;CALL	P1, P4 := MESSAGE POINTERS
;	F := DDB POINTER
;	PUSHJ	P,GETFEA
;RETURN	CPOPJ			;ALWAYS

GETFEA:	PUSHJ	P,NTDCNF##	;READ IN MML AND FEA FIELDS
	 JFCL			;NOT SUPPOSED TO HAPPEN
	LDB	T1,NETMML##	;GET MAX MESSAGE LENGTH
	CAILE	T1,MSGMAD##	;IS HE RESTRICTING US?
	MOVEI	T1,MSGMAD##	;NO, WE MUST RESTRICT HIM
	DPB	T1,NETMML##	;SET FOR CONNECT CONFIRM
	POPJ	P,		;ALL DONE
;GETSTA	ROUTINE TO RETURN THE CONNECTION STATE OF A TASK
;CALL	F := DDB ADDRESS
;RETURN	T1 := CONNECTION STATE

GETSTA:	LDB	T1,NETSLA##	;GET THE SOURCE LINK ADDRESS
	SKIPE	T1		;IF NONE, THEN ZERO IS THE STATE
	LDB	T1,LATSTA##	;GET THE STATE
	CAIG	T1,LAT.MX	;MAKE SURE THAT IT'S A LEGAL STATE
	SKIPGE	T1		;  AND NOT NEGATIVE
	STOPCD	.,STOP,TSKSOR,	;STATE IS OUT OF RANGE
	POPJ	P,		;RETURN
;LE2NPD	ROUTINE TO DUMMY UP THE NPD'S FOR TASKS OPENED VIA THE
;	LOOKUP/ENTER MECHANISM.  THIS ROUTINE CREATES 2 NPD'S
;	(ONE REMOTE AND ONE LOCAL) BASED ON THE TASK'S FILE-NAME
;	AND THE JOB'S NAME
;CALL	F := DDB POINTER
;RETURN	CPOPJ			;IF NO CORE
;	CPOPJ1			;DEVNPD(F) := XWD RMT,LOCAL NPD'S

LE2NPD:	SKIPE	DEVNPD(F)	;MAKE SURE THAT THERE AREN'T ANY NPD'S
	STOPCD	.,STOP,TSKLE2,	;++ NPD ALREADY ASSIGNED IN LOOKUP/ENTER

;FIRST BUILD THE "LOCAL" NPD

	MOVEI	T1,3+5		;5 WORDS HOLDS ANY "NAME[P,PN]"
	PUSHJ	P,GETNPD##	;GET STORAGE FOR A "LOCAL" NPD
	  POPJ	P,		;IF NO CORE, JUST GIVE ERROR RETURN
	HLRZ	T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER
	MOVEM	T1,NPDNOD(J)	;STORE IT IN THE NPD

	MOVE	P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA
	SETZ	P3,		;COUNT STARTS AT ZERO

	MOVE	T1,.CPJOB##	;GET OUR JOB NUMBER
	MOVE	T1,JBTNAM##(T1)	;GET OUR JOB NAME
	PUSHJ	P,SX2EAS##	;WRITE THE NAME

	MOVE	T1,.CPJOB##	;GET OUR JOB NUMBER AGAIN...
	MOVE	T1,JBTPPN##(T1)	;GET OUR P,PN
	PUSHJ	P,PP2EAS##	;WRITE THE "[P,PN]"
	MOVEM	P3,NPDNLN(J)	;STORE THE STRING'S LENGTH
	HRRM	J,DEVNPD(F)	;STORE THE NPD POINTER IN THE DDB

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE
;NOW BUILD THE "REMOTE" NPD

	MOVEI	T1,3+5		;GET THE LENGTH OF THE NPD
	PUSHJ	P,GETNPD##	;TRY TO ALLOCATE ONE
	  PJRST	GV2NPD		;IF NO CORE, RETURN THE "LOCAL" NPD AND ERR

	SETOM	NPDNOD(J)	;DEFAULT TO A WILD-CARD NODE.
	MOVE	P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA
	SETZ	P3,		;COUNT STARTS AT ZERO

	MOVE	T1,DEVFIL(F)	;GET THE FILE NAME
	PUSHJ	P,SX2EAS##	;  AND "OUTPUT" THAT

	XMTI	"["		;OUTPUT THE OPEN BRACKET
	SKIPGE	T1,DEVPPN(F)	;GET THE PPN, AND
	AOJE	T1,[XMTI "*"	;IF IT'S -1 THEN OUTPUT A WILDCARD (*)
		 JRST LE2NP1]	;  AND WE'RE DONE WITH THE PPN
	HLRZ	T1,DEVPPN(F)	;GET THE PROJECT NUMBER
	PUSHJ	P,OC2EAS##	;OUTPUT THE NUMBER
	XMTI	","		;OUTPUT THE COMMA
	HRRZ	T1,DEVPPN(F)	;GET THE PROGRAMMER NUMBER
	PUSHJ	P,OC2EAS##	;OUTPUT THAT TOO
LE2NP1:	XMTI	"]"		;CLOSE OFF THE PPN
	MOVEM	P3,NPDNLN(J)	;REMEMBER THE LENGTH
	HRLM	J,DEVNPD(F)	;SAVE THE "REMOTE" NPD
	RETSKP			;GIVE A GOOD RETURN
;T.X?PN	ROUTINE CALLED BY NCSCNT TO SEND THE "?PN" PART OF A CONNECT MESSAGE
;CALL	P2, P3 := POINTERS TO CONNECT MESSAGE SO FAR
;	F := POINTER TO TASK DDB
;RETURN	CPOPJ			;ALWAYS

T.XSPN:	HRRZ	J,DEVNPD(F)	;GET NPD FOR LOCAL TASK NAME
	PJRST	T.XPN		;GO TO COMMON ROUTINE TO SEND "SPN"

T.XDPN:	HLRZ	J,DEVNPD(F)	;GET NPD FOR REMOTE TASK NAME
;	PJRST	T.XPN		;GO TO COMMON ROUTINE TO SEND "DPN"

T.XPN:				;ROUTINE TO SEND A "DPN/SPN"  J := NPD.
;?PN(OBJ)
	XMTI	OBJ.TK		;SEND THE TASK OBJECT TYPE
;?PC(PID)
	SKIPE	J		;IF NO NPD,
	SKIPN	T3,NPDNLN(J)	;  OR IF NAME IS OF LENGTH "ZERO"
	JRST	[XMTI 0	;  SEND A "ZERO" NAME
		   POPJ P,]	;  AND RETURN
	MOVE	T4,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE NAME
T.XPN1:	ILDB	T1,T4		;GET THE NEXT CHARACTER
	IORI	T1,200		;SET THE EXTENSIBLE BIT.
	XMT1	T1		;SEND THE CHAR
	SOJG	T3,T.XPN1	;LOOP OVER ALL CHARACTERS
	PJRST	CLRBT8##	;CLEAR THE BIT ON LAST CHAR & RETURN


;T.OK	ROUTINE CALLED WHEN A TASK CONNECTION COMPLETED.  SETS THE TASK
; AS ONLINE (CONNECTED, LAT-STATE OK)
T.OK:	LDB	T1,NETSLA##	;GET THE LAT ADDRESS
	MOVEI	T2,LAT.OK	;THE "OK" STATE
	DPB	T2,LATSTA##	;SET THE STATE OF THE LAT
	MOVSI	S,IOSCON
	IORB	S,DEVIOS(F)	;SET THE "WE ARE CONNECTED" BIT
	MOVE	S,[XWD IOSERR+IOEND,IODERR]
	ANDCAB	S,DEVIOS(F)	;CLEAR THESE ERROR BITS.
	PUSHJ	P,PSIONL##	;GIVE THE USER AN ON-LINE INTERRUPT
	PUSHJ	P,NTDIAV##	;SAY INPUT IS NOW AVAILABLE
	PJRST	NETWAK##	;  AND WAKE HIM IF SLEEPING OR HIBERING
;MATCH	Routine to perform a pattern match.
;Call	P1, P2 := Length, Byte pointer to the "Pattern"
;	P3, P4 := Length, Byte pointer to the "Source"
;	T4 :=	  Aobjn pointer to block of "free" storage.  This
;		  is used as a Psuedo-stack.  This routine uses no
;		  "real" stack.
;Return	CPOPJ			;Source did not match Pattern
;	CPOPJ1			;Source did match Pattern
;
;Note	Only T1, T2 and T3 are modified.   T4, and P1 - P4 are returned
;	unchanged.
;
;	The algorithm works in the obvious way.  Special "pattern"
;	characters are:
;
;	   ?	Match any next source character.
;	   *	Match zero or more next source characters.
;	   ^V	(Control "V") Treat the next "pattern" char as a normal
;		char even if it is a "?" or a "*".

MATCH:	MOVE	T3,T4		;COPY THE PSUEDO-STACK POINTER
	HLRE	T1,T3		;GET MINUS(LENGTH) OF STACK LEFT
	CAMLE	T1,[EXP -4]	;MAKE SURE WE HAVE AT LEAST 4 WORDS LEFT
	POPJ	P,		;GIVE ERROR RETURN IF NOT ENOUGH STORAGE

;BIG LOOP. ONCE PER STRING
MATCH1:	DMOVEM	P1,0(T3)	;SAVE THE PATTERN DESCRIPTORS
	DMOVEM	P3,2(T3)	;SAVE THE SOURCE DESCRIPTORS

;LOOP. ONCE PER CHARACTER
MATCH2:	SOJL	P1,[SOJL P3,MATCHS ;IF BOTH ARE NULL, RETURN SUCCESS
		    JRST MATCH3];IF SOURCE STRING TOO LONG, BACK-UP
	ILDB	T1,P2		;GET THE NEXT PATTERN CHARACTER
	CAIN	T1,"*"		;SEE IF IT'S A STAR
	JRST	MATCH4		;  IF IT'S A STAR, GO RECURSE ON REST.
	CAIN	T1,"?"		;SEE IF IT'S A WILD CHARACTER
	JRST	[SOJL P3,MATCHF	;  IF SO, COUNT ONE SOURCE CHAR (FAIL IF NONE)
		 IBP P4		;  SKIP OVER NEXT SOURCE CHAR
		 JRST MATCH2]	;  AND CONTINUE THE MATCH WITH NEXT CHAR
	CAIN	T1,"V"-100	;IS IT A ^V?
	JRST	[SOJL P1,MATCHF	;  IF IT'S A ^V, COUNT OFF ON PATTERN CHAR
		 ILDB T1,P2	;  GET THE NEXT "QUOTED" CHAR
		 JRST .+1]	;  AND CONTINUE WITH THE MATCH
	SOJL	P3,MATCHF	;COUNT OFF SOURCE CHAR. COMPLETE FAIL IF NONE.
	ILDB	T2,P4		;GET THE NEXT SOURCE CHARACTER
	XORI	T1,(T2)		;COMPARE THE CHARACTERS
	TRNN	T1,177		;  BUT ONLY LOOK AT LOW 7 BITS
	JRST	MATCH2		;IF THEY MATCH, GO COMPARE NEXT CHARS.

;BACKUP.  HERE IF CHARS DON'T MATCH

MATCH3:	CAMN	T3,T4		;ARE WE AT "LEVEL 0"
	JRST	MATCHF		;IF AT LEVEL 0 THEN THE MATCH FAILED
	DMOVE	P1,0(T3)	;GET BACK ORIGIONAL PATTERH
	DMOVE	P3,2(T3)	;GET BACK SOURCE
	SOJL	P3,MATCHF	;WE ARE PROCESSING A "*".  EAT ONE MORE SOURCE
	IBP	P4		;  CHARACTER.
	DMOVEM	P3,2(T3)	;REMEMBER THE UPDATED SOURCE
	JRST	MATCH2		;NOW TRY THE COMPARE AGAIN ON SHORTER SOURCE

;STAR. RECURSE
MATCH4:	ADD	T3,[XWD 4,4]	;BUMP OUR "PSUEDO-STACK" POINTER
	HLRE	T1,T3		;GET THE NUMBER OF WORDS LEFT
	CAMLE	T1,[EXP -4]	;MAKE SURE THERE ARE AT LEAST 4 LEFT.
	JRST	MATCHF		;IF NO "STACK", RETURN FAILURE
	JRST	MATCH1		;GO "RECURSE"


MATCHS:	AOS	(P)		;IF WE SUCCEED, GIVE SKIP RETURN
MATCHF:	DMOVE	P1,0(T4)	;LOAD ORIGIONAL P1 & P2
	DMOVE	P3,2(T4)	;  OLD P3 & P4
	POPJ	P,		;RETURN
SUBTTL 4.0      TSKSER IMPURE STORAGE.

	$LOW

TKMTCH:	EXP	0		;THIS TEMP CONTAINS THE "PATTERN" MATCH
				;  TEMPORARY PSUEDO-STACK.



	XLIST			;DON'T LIST LITERALS
	$LIT
	LIST
TSKEND::PRGEND
TITLE	NETVTM - VIRTUAL TERMINAL ROUTINES VERSION 001
SUBTTL	NETVTM -- MAT/	21-FEB-79
	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) 1979,1984 By Digital Equipment Corp., Maynard, Ma.

xp	vnetvtm,002	;version number in Glob and Loader Map

NETVTM::ENTRY NETVTM


NDEVTY==:777740			;DUMMY DEVSER DISPATCH FOR NDT MACRO


	EXTERN	LTLANF		;SINCE ".CREF LTLANF##" DOESN'T WORK...
				;AND I WANT SOME FLAG FOR THE "SKIPL LDBTTW"
;VTMREC	ROUTINE TO PROCESS LOCALLY INPUT CHARS THAT ARE DESTINED FOR
;	A REMOTE MCR.
;CALL	U  := POINTER TO THE LDB OF THE "VTM" LINE
;	T3 := THE CHAR
;RETURN	CPOPJ			;ALWAYS

VTMREC::MOVE	T2,LDBREM##(U)	;GET THE REMOTE STATUS BITS
	TLNN	T2,LRLCON##	;MAKE SURE WE'RE CONNECTED
	JRST	[PUSHJ P,PCRLF##;GIVE THE USER A HINT AS TO HOW HE'S SCREWED
		 MOVEI T1,[ASCIZ /Waiting for connect confirm./]
		 PJRST CONMES##];  IF THE CONNECT IS NOT COMPLETE
	TLNE	T2,LRLDIP##	;IF A DISCONNECT IS IN PROGRESS,
	JRST	[PUSHJ P,PCRLF##;TELL THE TYPIST THAT HIS CHARACTER IS LOST
		 MOVEI T1,[ASCIZ /Waiting for disconnect confirm./]
		 PJRST CONMES##];  AND WAIT TILL THE CONFIRM FINALLY COMES IN

;MAKE SURE WE HAVE THE RESOURCES (CHUNKS) TO HANDLE THIS CHARACTER.

	MOVE	T2,LDBTIC##(U)	;GET THE NUMBER OF CHARS IN THE INPUT BUFFER.
				;  (DON'T BOTHER WITH COUNT IN LDBECC)
	CAIG	T2,^D150	;IF MORE THAN THIS ARBITRARY NUMBER,
	SKIPG	TTFREN##	;  OR THERE ARE NO MORE CHUNKS,
	JRST	[MOVE T2,FLPBEL## ;THEN DING THE USER'S BELL TO TELL
		 PJRST SETXNP##];  THE USER HIS CHARACTER WAS DESTROYED
	CAIL	T2,^D100	;IF MORE THAN THIS ARBITRARY NUMBER,
	PUSHJ	P,SNDXOF##	;  THEN TELL THE USER'S MACHINE TO STOP

;CHECK FOR ^S

	MOVE	T2,LDBREM##(U)	;GET THE DAP STATUS BITS
	MOVEI	T1,(T3)		;GET A COPY OF THE CHARACTER
	ANDI	T1,177		; AND IGNORE THE PARITY BIT
	TRNN	T2,STY.TP	;IF WE'RE NOT IN "TERMINAL PAGE" MODE
	JRST	VTMRE1		;  DON'T STOP OUTPUT.
	CAIE	T1,"S"-100	;IF IT'S NOT A ^S,
	JRST	VTMRE0		;  THEN CHECK FOR ^Q
	MOVSI	T1,LOLSTP##	;GET SCNSER'S BIT MEANING THE SAME THING,
	IORM	T1,LDBOST##(U)	;  AND SET IT SO OUTPUT WILL STOP.
	JRST	VTMRE3		;GO SHIP THE ^S TO THE REMOTE MCR.
;CHECK FOR ^Q

VTMRE0:	CAIE	T1,"Q"-100	;IF IT'S NOT A ^Q,
	JRST	VTMRE1		;  THEN KEEP GOING
	MOVSI	T1,LOLSTP##	;GET SCNSER'S BIT MEANING THE SAME THING
	ANDCAM	T1,LDBOST##(U)	;  AND CLEAR IT SO OUTPUT WILL START.
	PUSHJ	P,SETCHP##	;  AND START OUTPUT
	JRST	VTMRE3		;GO SHIP THE ^Q TO THE REMOTE MCR

;SEE IF IMAGE INPUT MODE.  IF NOT, DO AUTO-CRLF, ^S AND CASE CONVERSION

VTMRE1:	TRNE	T2,STY.II	;  AND SEE IF WE'RE IN IMAGE INPUT.
	JRST	VTMRE3		;  IF IMAGE INPUT, SKIP THE NEXT FEW CHECKS.

	ANDI	T3,177		;NOT IMAGE MODE, SO GET RID OF PARITY BIT
	JUMPE	T3,CPOPJ##	;THROW AWAY ANY NULL CHARACTERS.

;CHECK FOR CASE CONVERSION

	TRNN	T2,STY.CV	;SEE IF CASE CONVERSION IS ENABLED
	JRST	VTMRE2		;IF NOT ENABLED, DON'T DO IT.
	CAIL	T3,140		;RANGE CHECK THE CHARACTER
	CAIL	T3,175		;  TO SEE IF IT SHOULD BE CONVERTED
	JRST	VTMRE2		;IF NOT A LOWER CASE CHAR, DON'T CONVERT IT
	TRZ	T3,40		;MAKE UPPER CASE LOWER CASE
	JRST	VTMRE3		;SKIP NEXT CHECK SINCE CHAR ISN'T A SPACE

;NOW DO AUTO-CRLF CHECK.

VTMRE2:	CAIE	T3,40		;IS THE CHAR A SPACE?
	JRST	VTMRE3		;  IF NOT, DON'T CONVERT IT TO A CR.
	LDB	T4,LDPACR##	;GET THE "AUTO-CRLF" POSITION
	JUMPE	T4,VTMRE3	;  IF AUTO-CRLF NOT ENABLED, CHECK NO FARTHER
	PUSHJ	P,HPOS##	;GET OUR CURRENT HORIZONTAL POSITION.
	CAIL	T2,(T4)		;  AND IF WE'RE PAST THE "AUTO-CRLF" LOCATION
	MOVEI	T3,15		;  THEN PRETEND THE USER TYPE "CR" NOT SPACE.

;ALL LOCAL CHARACTER PROCESSING IS DONE (EXCEPT POSSIBLY ECHO).  NOW
;  IT'S TIME TO SHIP THE CHARACTER TO THE REMOTE MCR.

VTMRE3:	SCNOFF			;IN PREPARATION FOR TICKLING CHUNK CHAINS
	MOVE	T2,LDBREM##(U)	;GET THE DAP STATUS ONCE AGAIN
	TRNE	T2,STY.DE	;  AND SEE IF WE'RE IN DEFERED (MCR) ECHO
	JRST	[PUSHJ P,VTMSTI	;  IF DEFERED ECHO, FIRST STORE THE CHARACTER
		 LDB T1,LDPEPM##;GET THE OLD ECHO PIPELINE SERIAL
		 AOS T1		;  AND MAKE A NEW ONE
		 DPB T1,LDPEPM##;STORE NEW ONE SO MARKER FROM HOST WON'T MATCH
		 SCNON		;INTERRUPTS OK NOW.
		 PJRST VTMENQ]	;QUEUE THE LINE SO THE DATA GETS SENT TO MCR.

;HERE IF WE'RE IN LOCAL ECHO.  NOW CHECK TO SEE IF THERE IS ANY REASON
;  FOR GOING INTO DEFERED ECHO.

	CAIG	T3,176		;SEE IF THIS CHARACTER IS
	CAIGE	T3,40		;  IN THE RANGE OF BREAK CHARACTERS
	JRST	[CAIE T3,11	;  OR IF IT IS THE "NON BREAK" TAB
		 JRST VTMRE4	;IF IT'S A BREAK GO ENTER DEFERED ECHO
		 JRST .+1]	;NON-BREAK TAB. STAY IN LOCAL ECHO
	PUSHJ	P,VTMSTE	;GO STORE THE CHARACTER AS "ECHOED"
	PUSHJ	P,VTMSTO	;ECHO THE CHARACTER BY PUTTING IN OUTPUT STREAM
	SCNON			;INTERRUPTS OK NOW.
	PUSHJ	P,TOPOKE##	;START THE OUTPUT GOING.
	MOVE	T1,LDBECC##(U)	;GET THE COUNT OF ECHOED CHARACTERS
	CAIL	T1,^D72		;  AND IF MORE THAN 30 WAITING TO GO,
	PUSHJ	P,VTMENQ	;  THEN QUEUE THE LINE FOR SERVICE.
	POPJ	P,		;RETURN.  CHAR HAS BEEN STORED AND ECHOED.


;HERE WHEN WE RECEIVE A BREAK CHARACTER WHILE WE ARE IN LOCAL ECHO MODE.
;  WE MUST STORE THE CHARACTER, ENTER DEFERED ECHO MODE, AND QUEUE
;  THE LINE SO THE DATA GETS SHIPPED TO THE MCR.  NOTE THAT "CR" IS
;  SPECIAL IN THAT IT IS THE ONLY BREAK CHARACTER THAT IS ECHOED LOCALLY.
;  THIS IMPROVES THE "FEEL" OF THE NETWORK AND GIVES AN ILLUSION OF
;  GREAT SPEED.

VTMRE4:	CAIE	T3,15		;WAS THIS A "CR"
	JRST	VTMRE5		;  IF NOT, DON'T DO THE FANCY LOCAL ECHO
	PUSHJ	P,VTMSTE	;STORE THE CHAR AS AN "ECHOED" CHAR
	PUSHJ	P,VTMSTO	;  AND ECHO A "CR" TO THE OUTPUT STRING
	MOVEI	T3,12		;GET A "LF"
	PUSHJ	P,VTMSTO	;  AND PUT THAT IN THE OUTPUT STRING TOO.
	SCNON			;ALL CHARS STORED.  INTERRUPTS OK NOW.
	PUSHJ	P,TOPOKE##	;START UP OUTPUT TO GET THE ECHO OUT.
	PJRST	VTMEDM		;ENTER DEFERED ECHO MODE (QUEUE LINE) & EXIT

VTMRE5:	PUSHJ	P,VTMSTI	;STORE THE CHAR AS A NORMAL NON-ECHOED CHAR
	SCNON			;INTERRUPTS OK NOW...
	PJRST	VTMEDM		;QUEUE THE LINE SO MCR GETS DATA & EXIT.
;VTMDSO	ROUTINE CALLED BY SCNSER WHEN A DATA-SET LINE COMES UP
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;ALWAYS

VTMDSO::MOVEI	T1,STY.RG	;GET THE RING/CARRIER BIT
	IORM	T1,LDBREM##(U)	;  AND SET IT IN THE STATUS
	PJRST	VTMSSS		;GO "SET SEND STATUS" AND QUEUE THE LINE



;VTMDSF	ROUTINE CALLED BY SCNSER WHEN A DATA-SET LINE HANGS UP
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;ALWAYS

VTMDSF::MOVEI	T1,STY.RG	;GET THE RING/CARRIER BIT
	ANDCAM	T1,LDBREM##(U)	;  AND CLEAR IT IN THE STATUS WORD
	MOVSI	T1,LRLDIP##	;GET THE "WE WANT TO DISCONNECT" BIT
	IORM	T1,LDBREM##(U)	;  AND SET IT
	PJRST	VTMENQ		;QUEUE THE LINE SO THAT IT GETS SENT



;VTMSSS	ROUTINE TO "SET SEND STATUS" AND QUEUE A LINE
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;ALWAYS

VTMSSS:	MOVSI	T1,LRLSTS##	;GET THE "PLEASE SEND STATUS BIT"
	IORM	T1,LDBREM##(U)	;  AND SET IT SO STATUS GOES SOON
	PJRST	VTMENQ		;QUEUE THE LINE SO IT GETS SCANNED
;NETWORK DISPATCH VECTOR.

	IFIW	VTMNWD		;(-5) NODE DOWN
	IFIW	VTMDCC		;(-4) DISCONNECT MESSAGE
	IFIW	VTMCNC		;(-3) CONNECT CONFIRM
	IFIW	NTDSTP##	;(-2) CONNECT INITIATE
	IFIW	CPOPJ##		;(-1) DATA REQUESTS (DON'T GET ANY ON THIS SIDE)
TTYNDP::IFIW	VTMDAP		;( 0) INCOMING DAP MESSAGES.
	IFIW	VTMDAT		;( 1) DATA WITH-OUT END OF RECORD
	IFIW	VTMDAT		;( 2) DATA WITH END OF RECORD
	IFIW	VTMSTS		;( 3) DAP STATUS MESSAGE
	IFIW	VTMCTL		;( 4) DAP CONTROL MESSAGE
	IFIW	CPOPJ##		;( 5) USER ID
	IFIW	CPOPJ##		;( 6) FILE SPEC
;FIELD A CONNECT-INIT ON A LOCAL TERMINAL
;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.

NTTYCI::PUSH	P,U		;PROTECT THE INPUT PCB
	MOVE	T1,STATES##	;GET THE SCHEDULE FLAGS
	TRNE	T1,ST.NRT	;IF SYSTEM IS S/A
	JRST	VTMCE3		;THEN DISALLOW REMOTE CONNECTS

;DPN(,PID)

	PUSHJ	P,EBI2BI##	;READ IN REMOTE'S REQUESTED "UNIT" NUMBER
	MOVE	U,LINTAB##(T1)	;GET ADDRESSED LDB
	HRRZ	F,LDBDDB##(U)	;GET LDB'S DDB (IF ANY)
	JUMPN	F,VTMCE4	;IF DDB THEN IN USE, ERROR
	SKIPL	T1,LDBCOM##(U)	;GET LDB 'COMMAND' WORD
	TLNE	T1,LDBCMF##	;CHECK FOR FORCED COMMAND PENDING
	JRST	VTMCE4		;COMMAND PENDING, CAN'T HAVE THE TERMINAL
	MOVE	T1,LDBTTW##(U)	;GET LDB 'TYPE' WORD
	TLNE	T1,LTLUSE##	;IF THE LDB IS 'NOT-IN-USE'
	TLNE	T1,LTLANF##	;OR IF THE LDB IS AN ANF TERMINAL
	JRST	VTMCE4		;THEN ALSO CAN'T ASSIGN IT
	MOVE	T1,LDBDCH##(U)	;GET LDB DEVICE CHARACTERISTICS
	TRNN	T1,LDRPTY##!LDRCTY##  ;REMOTE CAN'T HAVE PTYS OR OUR CTY
	SKIPE	LDBREM##(U)	;IF ALREADY 'HOSTED' AWAY
	JRST	VTMCE4		;THEN ALSO CAN'T ASSIGN IT

;THE REQUESTED TERMINAL IS AVAILABLE

	PUSHJ	P,VTMLOC	;MAKE SURE LDB IS PRESENTABLE
	  PUSHJ	P,FRELDB##	;LDB DEFUNCT??? SHOULDN'T EVER HAPPEN!
	 JRST	VTMCE3		;LDB ZAPPED? TELL REMOTE HE CAN'T HAVE THIS ONE
	MOVE	T1,U		;ADDRESS OF LDB FOR GETSLA
	TLO	T1,LAT.TY!LAT.VT;FLAG THIS IS A VTM/LDB ADDRESS
	MOVEI	T2,LAT.CC	;WHOSE INITIAL STATE WILL BE "CC"
	PUSHJ	P,GETSLA##	;GET A LINK ADDRESS
	 JRST	VTMCE3		;NO LAT SLOTS, NO RESOURCES
	DPB	T1,LDPSLA##	;MARK OUR LINK ADDRESS
	HLRZ	T1,P3		;GET REMOTE'S LINK ADDRESS
	DPB	T1,LDPDLA##	;AND SAVE THE DLA TOO
	HLRZ	T1,NDBNNM(W)	;REMOTE'S NODE NUMBER
	DPB	T1,LDPRNN##	;SET LDB'S REMOTE OWNER
	MOVSI	T1,LRLVTM##!LRLSCH##!LRLSTS##  ;IMPORTANT VTM FLAGS
	IORM	T1,LDBREM##(U)	;TO MAKE ALL SORTS OF 'RIGHT' THINGS HAPPEN

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;SPN(OBJ)

	PUSHJ	P,EBI2BI##	;READ IN REMOTE'S OBJECT TYPE
	CAIE	T1,OBJ.TT	;MUST BE A TERMINAL HANDLER (MCR)
	JRST	VTMCE2		;NOT - SOMEONE IS CONFUSED

;SPN(,PID)

	PUSHJ	P,XSKIP##	;IGNORE REMOTE'S 'PID'

;MML

	PUSHJ	P,XSKIP##	;IGNORE REMOTE'S MAX MESSAGE SIZE

;FEA

	PUSHJ	P,XSKIP##	;IGNORE DATA CODES (WE *KNOW* WHAT IS LEGAL)
	PUSHJ	P,XSKIP##	;IGNORE RECORD LENGTH
	PUSHJ	P,XSKIP##	;IGNORE DEVICE ATTRIBUTES
	PUSHJ	P,XSKIP##	;IGNORE DEVICE 'UNIT TYPE'
	PUSHJ	P,XSKIP##	;IGNORE DEVICE 'CONTROLLER TYPE'

;ALL IS HAPPY, SEND CONNECT CONFIRM TO REMOTE

	PUSHJ	P,VTMXCN	;SEND A CONNECT CONFIRM
	 JRST	VTMCE2		;OOPS, CAN'T, ABORT AND RETURN LAT SLOT
	PUSHJ	P,VTMENQ	;GET THE BALL ROLLING
	PUSHJ	P,TRM.UP##	;FLAG THE TERMINAL "UP"
	JRST	UPOPJ1##	;THE VTM IS NOW CONNECTED


;VTM CONNECT INIT ERRORS

VTMCE2:	PUSHJ	P,VTMLOC	;RESTORE THE TERMINAL TO [LOCAL] GOODNESS
	  PUSHJ	P,FRELDB##	;LDB DEFUNCT??? SHOULDN'T EVER HAPPEN!
	 JFCL			;LDB ZAPPED?
VTMCE3:	MOVEI	T1,RSN.OT	;CAN'T DO THE CONNECT
	JRST	UPOPJ##		;ABORT AND RETURN BAD NEWS

VTMCE4:	MOVEI	T1,RSN.XP	;THIS TERMINAL IS UNAVAILABLE
	JRST	UPOPJ##		;ABORT AND RETURN BAD NEWS
;VTMNWD	THE "NODE WENT DOWN" NDP ENTRY
;CALL	F := LAT ENTRY
;	P1 := NODE NUMBER OF NODE THAT HAS JUST GONE OFFLINE
;RETURN	CPOPJ			;WITH TTY "LOCAL" IF LINE WAS "SET HOSTED"
;				;  TO THE JUST CRASHED NODE.

VTMNWD:	PUSH	P,U		;SAVE U
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"
	LDB	T1,LDPRNN##	;GET THE NODE NUMBER
	CAIE	T1,(P1)		;COMPARE OUR NUMBER WITH THAT OF CRASHED NODE
	STOPCD	.,STOP,VTMNDA,	;++ NODE NUMBER DOESN'T AGREE
	MOVEI	T1,[ASCIZ \Path to host system was lost.\]
	PUSHJ	P,VTMLOP	;MAKE LINE LOCAL AND TELL USER WHAT HAPPENED.
	  PUSHJ	P,FRELDB##	;DEFUNCT LDB, RETURN IT TO THE FREE POOL
	 PJRST	UPOPJ##		;IDLE PTY (OR THE LIKE), DON'T "GREET" IT
	PUSHJ	P,TTFGRT##	;USEABLE LOCAL TERMINAL, "GREET" IT
	PJRST	UPOPJ##		;RESTORE "U" AND WE'RE DONE.  LINE IS NOW
				;  USABLE LOCALLY.
;VTMDCC	ROUTINE TO HANDLE DISCONNECT MESSAGES FOR A VTM.
;CALL	F := LDB ADDRESS (REALLY THE LAT ENTRY)
;	W := NODE WHO SENT THE DISCONNECT
;	P1 & P4 := POINTERS TO THE DISCONNECT MESSAGE
;RETURN	CPOPJ			;BAD MESSAGE (CAN'T HAPPEN)
;	CPOPJ1			;DISCONNECT PROCESSED.
;THIS ROUTINE CHECKS THE REASON FOR THE DISCONNECT.  IF IT IS
;  "RSN.RC" (REASON -- RECONNECT) AN IMPLICIT "SET HOST" IS DONE

VTMDCC:	PUSHJ	P,SAVJW##	;WE MAY CLOBBER THESE IF IT'S A "SET HOST"
	PUSH	P,U		;SAVE INCOMING PCB POINTER
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"
	LDB	T1,LDPSLA##	;GET OUR LOCAL LAT ADDRESS
	LDB	T2,LATSTA##	;  AND GET OUR CONNECTION STATE.
	CAIN	T2,LAT.CC	;SEE IF THIS IS A CONNECT REJECT.
	JRST	[MOVEI T1,[ASCIZ \Host rejected connection.\]
		PJRST	VTMDC7]		;RESTORE "U" AND RETURN
	CAIN	T2,LAT.DC	;IS THIS A DISCONNECT CONFIRM
	JRST	VTMDC6		;  IF D-CONFIRM, PRINT GREETING AND MAKE LOCAL

IFN PARANOID&P$VTM,<		;IF WE'RE BEING CAUTIOUS,
	CAIE	T2,LAT.OK	;  MAKE SURE WE'RE IN A REASONABLE STATE
	STOPCD	.,STOP,VTMILS,	;++ ILLEGAL STATE
>

;FALL THROUGH TO PROCESS DISCONNECT INITIATE
;CONTINUED FROM PREVIOUS PAGE

;HERE WHEN WE RECEIVE A DISCONNECT INITIATE.  SEND THE DISCONNECT
;  CONFIRM, AND SEE IF WE MUST PERFORM AN IMPLICIT "SET HOST"

	MOVEI	T1,RSN.OK	;GIVE AN "OK" REASON FOR THE CONFIRM
	EMRGCY			;USE THE EMERGENCY FREE-POOL IF NECESSARY
	PUSHJ	P,TRMXDC##	;SEND THE DISCONNECT CONFIRM
	 STOPCD	.,STOP,VTMSDF,	;++ SEND DISCONNECT FAILED

;SLA

	PUSHJ	P,XSKIP##	;SKIP OVER THE SLA (USELESS)

;RSN

	PUSHJ	P,EBI2BI##	;GET THE REASON FOR THE DISCONNECT.
	CAIE	T1,RSN.RC	;IF ITS NOT RECONNECT (SET HOST)
	JRST	[MOVEI	T1,[ASCIZ \Host sent disconnect.\]
		JRST	VTMDC7]		;LOCAL'IZE LINE AND PRINT MESSAGE

;HERE TO DO THE IMPLICIT SET HOST.

;NNM

	PUSHJ	P,EBI2BI##	;GET THE NUMBER OF THE NODE TO RECONNECT TO.
	HLRZ	T2,NETNDB##+NDBNNM ;GET OUR LOCAL NODE NUMBER
	CAIN	T1,(T2)		;IF THEY ARE THE SAME, THEN
	JRST	VTMDC6		;  PRINT A GREETING AND LET HIM RUN HERE AGAIN
	PUSHJ	P,SRCNDB##	;GET NDB OF HOST TO RECONNECT TO
	  JRST	[MOVEI	T1,[ASCIZ \? Unable to complete SET HOST command.\]
		JRST	VTMDC7]		;LOCAL'IZE LINE AND PRINT MESSAGE
	PUSHJ	P,VTMCNT	;[RE]CONNECT TO REMOTE MCR SERVICE
	PJRST	UPOPJ1##	;RESTORE PCB POINTER AND EXIT


;HERE TO MAKE A LINE LOCAL AND FORCE A GREETING

VTMDC6:	PUSHJ	P,VTMLOC	;MAKE LINE LOCAL
	  PUSHJ	P,FRELDB##	;DEFUNCT LDB, RETURN IT TO SCNSER'S FREE POOL
	 PJRST	UPOPJ1##	;IDLE PTY (OR THE LIKE), DON'T GREET IT
	JRST	VTMDC8		;USEABLE LOCAL TERMINAL, GREET IT

VTMDC7:	PUSHJ	P,VTMLOP	;MAKE LINE LOCAL AND PRINT MESSAGE
	  PUSHJ	P,FRELDB##	;DEFUNCT LDB, RETURN IT TO SCNSER'S FREE POOL
	 PJRST	UPOPJ1##	;IDLE PTY (OR THE LIKE), DON'T GREET IT
VTMDC8: PUSHJ	P,TTFGRT##	;GREET THE NEWFOUND TERMINAL
	PJRST	UPOPJ1##	;RESTORE PCB AND RETURN
;VTMCNC	ROUTINE TO PROCESS AN INCOMING CONNECT CONFIRM MESSAGE
;CALL	W := NDB OF NODE WE'VE SENT A CONNECT TO
;	F := LDB OF TERMINAL
;	P1 & P4 := POINTER TO THE CONNECT CONFIRM MESSAGE
;RETURN	CPOPJ			;ILLEGAL CONNECT CONFIRM MESSAGE
;	CPOPJ1			;LINK SET UP.  TERMINAL NOW "SET HOSTED" TO
;				;  OTHER SYSTEM.

VTMCNC:	PUSH	P,U		;SAVE THE INCOMING PCB ADDRESS
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"
	LDB	T1,LDPSLA##	;GET OUR LOCAL LAT ADDRESS
	LDB	T2,LATSTA##	;  AND FROM THAT OUR LOCAL CONNECT STATE
	CAIE	T2,LAT.CC	;IF WE'RE NOT IN CONNECT CONFIRM WAIT,
	JRST	UPOPJ##		;  THEN THIS IS AN ILLEGAL MESSAGE.

;DLA

	PUSHJ	P,EBI2BI##	;GET THE LAT ADDR ASSIGNED TO US BY THE MCR
	JUMPE	T1,UPOPJ##	;DON'T EVER USE A ZERO DLA...
	DPB	T1,LDPDLA##	;STORE THE REMOTE LINE ADDRESS
	PUSHJ	P,TRM.UP##	;INITIALIZE THE LINE, SET LRLCON.
	MOVE	T1,LDBDCH##(U)	;GET THE CHARACTERISTICS FOR THIS LINE
	TRNN	T1,LDRDSD##	; ARE WE A DATA-SET LINE?
	  JRST	VTMCN1		;NOT A DATA SET, NEVER MIND
	LDB	T1,LDPDSC##	;GET DATASET TABLE INDEX
	MOVE	T1,DSCTAB##(T1)	;GET DATASET DATA
	TLNE	T1,DSCSWC##	;IS THE CARRIER THERE?
	SKIPA	T1,[XWD LRLSTS##+LRLSCH##,STY.DE+STY.DT+STY.RG]
VTMCN1:	MOVE	T1,[XWD LRLSTS##+LRLSCH##,STY.DE]
	IORM	T1,LDBREM##(U)	;SAY WE NEED TO SEND STATUS, GO TO DEFERED ECHO
	PUSHJ	P,VTMENQ	;QUEUE THE VTM SO WE SEND THESE MESSAGES
	JRST	UPOPJ1##	;DONE PROCESSING THE CONNECT-CONFIRM
;VTMDAP	ROUTINE TO DIS-ASSEMBLE AN INCOMING DAP MESSAGE AND DISPATCH
;  ON THE VARIOUS DAP SUB-MESSAGES.
;CALL	F := LAT ENTRY (RH(F) = LDB POINTER)
;	W := NDB THAT THE LINE IS CONNECTED TO
;	P1 & P4 := BYTE POINTER & COUNT TO THE INCOMING MESSAGE
;RETURN	CPOPJ			;MESSAGE WAS "BAD" IN ONE WAY OR ANOTHER
;	CPOPJ1			;MESSAGE HAS BEEN PROCESSED.

VTMDAP:	MOVE	T1,PCBPTR(U)	;GET MESSAGE POINTER (SO WE CAN GET NCT LATER)
	PUSH	P,U		;PRESERVE THE PCB ADDRESS
	MOVE	U,F		;THE LDB ADDRESS IS CARRIED IN "U"

;NOW LOOK AT THE NCT BYTE TO SEE IF THIS MESSAGE IS INTERRUPT OR NORMAL

	ILDB	T1,T1		;GET THE NCT BYTE
	TRNE	T1,NCT.IT	;  AND SEE IF IT HAS THE INTERRUPT BIT SET
	JRST	VTMDP1		;IT'S AN INTERRUPT MSG.  LEAVE DRQ ALONE.
	LDB	T1,LDPDRQ##	;IT'S NORMAL DATA. GET THE DRQ COUNT
	SOSGE	T1		;  AND COUNT OFF ONE LESS OUTSTANDING DRQ
	PJSP	T1,VTMDP3	;IF DRQ WENT NEGATIVE, REMEMBER OUR PC
				;  FIXUP THE STACK AND MARK THE MSG AS BAD.
	DPB	T1,LDPDRQ##	;STORE THE UPDATED DRQ

;DROP THROUGH TO DISSECT THE INCOMING MESSAGE.
VTMDP1:	JUMPLE	P4,UPOPJ##	;IF AT END OF MESSAGE, GIVE GOOD RETURN

;CNT

	PUSHJ	P,EBI2BI##	;GET THE LENGTH OF THIS SUB-MESSAGE
	SUB	P4,T1		;  CALCULATE LENGTH OF REMAINDER OF MSG.
	SKIPGE	P4		;MAKE SURE MSG LENGTH DOESN'T GO NEGATIVE
	PJSP	T1,VTMDP3	;IF SUB MSG LONGER THAN MSG, TOSS MSG AS BAD
	PUSH	P,P4		;REMEMBER HOW MUCH IS LEFT IN THE MESSAGE
	MOVEI	P4,(T1)		;  AND SET UP THE LENGTH FOR THIS SUB-MSG

;TYPE

	PUSHJ	P,EBI2BI##	;GET THE IDC TYPE FIELD
	CAIL	T1,DC.DAT	;RANGE CHECK IT
	CAILE	T1,DC.CTL	;  SO WE DON'T JUMP OFF INTO THE WEEDS
	PJSP	T1,VTMDP2	;IF OUT OF RANGE TYPE, REPORT BAD MESSAGE
	PUSHJ	P,@TTYNDP(T1)	;CALL THE APPROPRIATE SUB-MSG PROCESSOR
	  PJSP	T1,VTMDP2	;  AND IF HE THINKS THE MSG IS BAD, TOSS IT.
	SOJG	P4,[IBP P1	;SKIP TO THE END OF THE SUB-MSG
		    JRST .]	;  SO WE'RE READY TO READ THE NEXT "CNT" FIELD
	POP	P,P4		;RECOVER THE LENGTH OF THE UNPROCESSED PART
	JRST	VTMDP1		;  AND GO DO THE NEXT SUB-MESSAGE


;HERE IF FOR SOME REASON WE THINK THE MESSAGE IS BAD.
;CALL	T1 := ADDRESS OF CODE THAT DECIDED IT DIDN'T LIKE THE MSG

VTMDP2:	POP	P,P4		;FIXUP THE STACK IF WE HAVE THE LENGTH ON IT
VTMDP3:	POP	P,U		;GET THE PCB POINTER BACK FOR INCTBD
	JRST	INCTBD##	;MARK THE MESSAGE AS BAD & RETURN
;VTMDAT	ROUTINE TO PROCESS INCOMING DAP-DATA MESSAGES
;CALL	U := POINTER TO LDB
;	P1 & P4 := POINTER AND LENGTH OF DATA TO STORE.
;RETURN	CPOPJ			;ONLY IF WE GOT A ZERO LENGTH MSG
;	CPOPJ1			;DATA COPIED INTO OUTPUT BUFFER AND
;				;  OUTPUT HAS BEEN STARTED.

VTMDAT:	JUMPLE	P4,CPOPJ##	;WE DON'T LIKE ZERO LENGTH MSGS

;FIRST MAKE SURE WE HAVE ENOUGH CHUNKS TO ACCOMODATE THIS DATA

	MOVE	T1,TTFREN##	;GET NUMBER OF FREE CHUNKS
	IMULI	T1,CK.CPC##	;CONVERT THAT NUMBER INTO CHARACTERS
	CAIG	T1,10(P4)	;  AND SEE IF MSG (PLUS A FUDGE) WILL FIT
	POPJ	P,		;SAY THAT MESSAGE IS BAD IF IT WON'T FIT
	MOVE	T1,LDBTOC##(U)	;GET THE NUMBER OF CHARS TO OUTPUT
	CAIL	T1,<MAXODR*NTTPLN##*4>+100 ;SEE IF IT'S MORE THAN "MAXODR"
	POPJ	P,		;  DRQ'S WORTH OF DATA. IF SO, TOSS IT.
				;  SOME-ONE IS SENDING US DATA WE DIDN'T ASK
				;  FOR.  (CALCULATION IS BASED ON "NTTPLN" WORD
				;  MESSAGES OF 4 CHARS PER WORD)
	MOVE	T4,LDBREM##(U)	;GET THE DAP-STATUS WORD
	TRNN	T4,STY.IO	;  AND IF WE'RE NOT DOING IMAGE OUTPUT
	TDZA	T4,T4		;  MAKE OUR "IOR" MASK ZERO.
	MOVEI	T4,CK.IMG##	;  IF IMAGE-OUT, GET MASK TO SET "IMAGE" BIT
	SCNOFF			;GET A LITTLE PROTECTION WHILE WE HACK CHUNKS
	ADDM	P4,LDBTOC##(U)	;COUNT THE CHARS WE'RE ABOUT TO STUFF
VTMDA1:	ILDB	T3,P1		;GET THE NEXT CHAR
	IOR	T3,T4		;SET THE IMAGE BIT IF WE'RE IN IMAGE MODE
	TRNN	T3,CK.IMG##	;ARE WE?
	SKIPGE	LDBATR##(U)	;OR ARE WE IN 8-BIT MODE?
		EXTERN	LAL8BT	;FLAG BIT REFERENCED
	TRNA			;YES, SKIP ON
	TRZ	T3,CK.PAR##	;NO, CLEAR THAT OBNOXIOUS PARITY BIT
	STCHK	T3,LDBTOP##(U),VTMDA5  ;STORE THE CHAR IN THE OUTPUT CHAIN
	SOJG	P4,VTMDA1	;LOOP OVER ALL CHARS.
	SCNON			;ALL'S CONSISTANT AGAIN.  TURN ON INTS.
	PUSHJ	P,TOPOKE##	;START THE LINE TYPING
	RETSKP			;  AND GIVE A GOOD RETURN


;EAT REST OF DATA SUB-MESSAGE (NO ROOM IN CHUNKS)

	ILDB	T3,P1		;ADVANCE P1
VTMDA5:	SOJG	P4,.-1		;LOOP
	SCNON			;RELEASE INTERLOCK
	POPJ	P,		;ERROR
;VTMSTS	ROUTINE TO PROCESS INCOMING DAP-STATUS MESSAGES
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO, AND LENGTH OF THE MESSAGE
;RETURN	CPOPJ			;IF IT'S A GARBAGE MESSAGE
;	CPOPJ1			;STATUS MESSAGE PROCESSED.

VTMSTS:				;PROCESS VTM STATUS

;STC

	PUSHJ	P,EBI2BI##	;READ THE STATUS CODE
	CAIL	T1,STC.SB	;RANGE CHECK THE CODE (1 = SET BITS)
	CAILE	T1,STC.CB	;  (2 = CLEAR BITS)
	POPJ	P,		;STATUS CODE NOT SET/CLEAR.
	SOS	T4,T1		;COPY THE STATUS CODE (MINUS ONE)

;STY

	PUSHJ	P,EBI2BI##	;READ THE STATUS BITS TO SET/CLEAR

IFN FTKL10,<
	TRNN	T1,STY.XS	;DO WE WANT OUTPUT STOPPED OR STARTED?
	 JRST	VTMST3		;NO
	HRRZ	T2,LDBISR##(U)	;GET ISR DISPATCH
	CAIE	T2,TTDDSP##	;IS THIS A -20F LINE
	 JRST	VTMST3		;NO
	MOVSI	T2,LTLXFF##	;YES, SET BIT TO INFORM -20F
	IORM	T2,LDBTTD##(U)	;
> ;END IFN FTKL10
VTMST3:	MOVE	T2,LDBREM##(U)	;SAVE THE PREVIOUS STATUS FOR A BIT
	XCT	[IORB	T1,LDBREM##(U)	;SET OR
		ANDCAB	T1,LDBREM##(U)](T4) ;CLEAR THE BITS AS DIRECTED
	TRNN	T2,STY.DE	;IF WE WERE IN LOCAL ECHO
	TRNN	T1,STY.DE	; AND WE ARE NOW IN REMOTE
	CAIA			; (IE DEFERRED ECHO)
	PUSHJ	P,VTMEDM	; THEN SEND THE HOST A STATUS MSG

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;MAKE LDBDCH AGREE WITH LDPSTS (LH(T2) = BITS TO SET, RH(T2) = CLEAR)

	MOVE	T1,LDBREM##(U)	;RESTORE BITS
	SETZ	T2,		;START WITH NO BITS TO CHANGE
	TRNE	T1,STY.XS	;IF WE WANT OUTPUT STOPPED,
	TLOA	T2,LOLSTP##	;  THEN SET THIS BIT
	TRO	T2,LOLSTP##!LOLSSO## ;OTHERWISE CLEAR THESE BITS
	HLLZ	T3,T2		;COPY BIT TO SET
	IORM	T3,LDBOST##(U)	;SET IN APPROPRIATE WORD
	HRLZ	T3,T2		;GET BITS TO CLEAR
	ANDCAM	T3,LDBOST##(U)	;DO SO
	SETZ	T2,		;CLEAR FOR LDBDCH BITS
	TRNE	T1,STY.HT	;IF WE HAVE HARDWARE TABS
	TLOA	T2,LDLTAB##	;  THEN TELL SCNSER
	TRO	T2,LDLTAB##	;  CLEAR BIT IF NO TABS
	TRNE	T1,STY.FF	;IF WE HAVE TTY FORM
	TLOA	T2,LDLFRM##	;  SET THE BIT
	TRO	T2,LDLFRM##	;  OTHERWISE CLEAR IT
	TRNN	T1,STY.CR	;IF WE'RE DOING FREE CRLF
	TROA	T2,LDLNFC##	;  THEN CLEAR THE "NO FREE CRLF" BIT
	TLO	T2,LDLNFC##	;  OTHERWISE SET IT.
	HRLZ	T3,T2		;GET THE BITS TO CLEAR
	ANDCAM	T3,LDBDCH##(U)	;  AND CLEAR THEM
	HLLZ	T3,T2		;GET THE BITS TO SET,
	IORM	T3,LDBDCH##(U)	;  AND SET THEM.

;NOW MAKE LDBBY2 AGREE WITH LDPSTS

	MOVEI	T2,L2RXON##	;THE "SET TTY TAPE" BIT
	TRNE	T1,STY.TT	;IF WE'RE IN TERMINAL TAPE MODE
	SKIPA	T3,[IORM T2,LDBBY2##(U)] ;THEN SET THE BIT
	MOVE	T3,[ANDCAM T2,LDBBY2##(U)] ;OTHERWISE CLEAR IT
	XCT	T3		;SET/CLEAR THE BIT

;NOW MAKE THE MODEM CONTROL BITS AGREE WITH THE MODEM STATUS

	PUSHJ	P,SETCHP##	;KICK THE LINE INCASE WE JUST STARTED OUTPUT
	RETSKP			;ALL DONE WITH STATUS MESSAGE
;VTMCTL	ROUTINE TO DISPATCH ON INCOMING DAP-CONTROL MESSAGES
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO, AND LENGTH OF THE CONTROL MESSAGE
;RETURN	CPOPJ			;IF MESSAGE IS BAD
;	CPOPJ1			;IF MESSAGE IS PROCESSED.

VTMCTL:	PUSHJ	P,EBI2BI##	;GET THE CONTROL-MESSAGE TYPE
	SKIPL	T1		;RANGE CHECK THE TYPE
	CAILE	T1,DCT.XF	;  SO WE DON'T JUMP OFF INTO THE WEEDS
	POPJ	P,		;BAD CONTROL TYPE.  GIVE "BAD-MSG" RETURN
	JRST	@.+1(T1)	;DISPATCH ON THE CONTROL CODE
	IFIW	VTMEPM		; (0) = ECHO PIPELINE MARKER
	IFIW	VTMCGB		; (1) = CHARACTER GOBBLER (^O)
	IFIW	VTMCHR		; (2) = "CHARACTERISTICS" (SPEED ETC.)
	IFIW	VTMADL		; (3) = AUTO DIAL-OUT
	IFIW	VTMXOF		; (4) = SEND "XOFF" IMMEDIATLY
;VTMEPM	ROUTINE TO PROCESS AN INCOMING ECHO-PIPELINE-MARKER.
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO AND LENGTH OF SUB MESSAGE
;RETURN	CPOPJ			;NEVER
;	CPOPJ1			;EPM PROCESSED.
;FCN	IF THE EPM SERIAL NUMBER MATCHES THE LAST ONE SENT, THEN
;	THERE ARE NO MORE CHARS IN THE "PIPELINE".  IN THIS CASE
;	WE CAN GO INTO LOCAL ECHO ONLY IF WE HAVE NO INPUT CHARS
;	QUEUED FOR THE REMOTE HOST.

VTMEPM:	PUSHJ	P,BYT2BI##	;GET THE 8 BIT EPM SERIAL NUMBER
	LDB	T2,LDPEPM##	;GET THE SERIAL NUMBER OF THE LAST EPM SENT
	CAIE	T1,(T2)		;IF WE HAVEN'T GOTTEN OUR LAST EPM BACK
	RETSKP			;  THEN THERE ARE STILL CHARS IN THE PIPE
	MOVEI	T1,STY.DE	;GET THE "REMOTE IS ECHOING" BIT
	TDNN	T1,LDBREM##(U)	;SEE IF WE ARE ALREADY IN LOCAL ECHO
	RETSKP			;  IF IN LOCAL ECHO, IGNORE EXTRA EPM
	SCNOFF			;MAKE SURE WE DON'T ECHO A CHAR FOR A WHILE
	SKIPN	LDBTIC##(U)	;MAKE SURE THAT NO CHARS HAVE
	SKIPE	LDBECC##(U)	;  SNUCK IN WHILE WE WEREN'T LOOKING
	JRST	SONPJ1##	;IF CHARS QUEUED, DON'T ENTER LOCAL ECHO MODE
	ANDCAB	T1,LDBREM##(U)	;CLEAR REMOTE ECHO (ENABLE LOCAL ECHO)
	DPB	T1,LDPDST##	;SAVE THE STATUS MESSAGE
	MOVSI	T1,LRLDST##	;GET THE BIT SAYING A STATUS MSG IS "SAVED"
	IORM	T1,LDBREM##(U)	;  SO THAT NEXT TIME WE START A MESSAGE
				;  FOR THE REMOTE WE WILL SEND A STATUS
				;  MESSAGE TELLING HIM WE'RE LOCAL ECHOING
	SCNON			;INTERRUPTS OK NOW.
	AOS	(P)		;GIVE GOOD RETURN
	PJRST	VTMENQ		;NOW QUEUE THE LINE TO SEND THE STATUS
				;  *** NOTE ***  WHILE IT WOULD BE NICE
				;  TO BE ABLE TO DELAY SENDING THIS STATUS
				;  MESSAGE, UNTIL NETMCR GETS SMARTER ABOUT
				;  TELLING US IF WE SHOULD ECHO OR NOT, WE
				;  MUST INFORM IT IMMEDIATLY UPON ENTERING
				;  LOCAL ECHO MODE.  IF WE DON'T, PASSWORDS
				;  WILL ECHO...



;VTMCGB	ROUTINE TO PROCESS A "CHARACTER GOBBLER" (^O) REQUEST
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO, AND LENGTH OF SUB MSG (WE IGNORE IT)
;RETURN	CPOPJ			;NEVER
;	CPOPJ1			;OUTPUT STREAM "GOBBLED"

VTMCGB:	PUSHJ	P,TSETBO##	;SCNSER DOES ALL THE WORK
	RETSKP			;GIVE GOOD RETURN
;VTMCHR	ROUTINE TO PROCESS AN INCOMING CHARACTERISTICS MESSAGE
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO, AND LENGTH OF THIS SUB-MESSAGE
;RETURN	CPOPJ			;SOMETHING WAS WRONG WITH THE MESSAGE
;	CPOPJ1			;MESSAGE PROCESSED

VTMCHR:	PUSHJ	P,EBI2BI##	;GET BACK-SPACE FILL TIME
	PUSH	P,T1		;  AND SAVE FOR JUST A BIT
	PUSHJ	P,EBI2BI##	;GET H-TAB FILL TIME
	HRLM	T1,(P)		;  AND SAVE THAT TOO.
	PUSHJ	P,EBI2BI##	;GET LF FILL TIME (IGNORE)
	PUSHJ	P,EBI2BI##	;GET V-TAB FILL TIME (IGNORE)
	PUSHJ	P,EBI2BI##	;GET FORM FEED FILL TIME (IGNORE)
	PUSHJ	P,EBI2BI##	;GET CR FILL TIME (IGNORE)

;NOW WE MUST GUESS WHAT FILL CLASS WE WANT GIVEN THE TIMES.
;  RATHER THAN TRY TO INVERT THE ALGORITHM IN NETMCR(TTXTCR),
;  THIS CODE RELYS ON THE FACT THAT ONE CAN DETERMINT THE
;  CLASS FROM THE FIRST TWO ENTRIES IN FILTAB.
;EG.	BSP	H-TAB	CLASS
;	 0	  0	  0
;	 2	  2	  1
;	 6	  0	  2
;	 6	  2	  3

	POP	P,T2		;GET XWD H-TAB,BSP FILL TIMES BACK
	MOVEI	T1,3		;INITIALIZE "T1" FOR THE SOS'ES COMING UP
	JUMPE	T2,VTMCH1+0	;IF BOTH ARE "0" THEN FILL CLASS MUST BE TOO.
	TLNN	T2,-1		;IF "H-TAB" IS ZERO, THEN
	JRST	VTMCH1+2	;  WE HAVE FILL CLASS "2"
	TSC	T2,T2		;COMPARE THE TWO TIMES
	JUMPE	T2,VTMCH1+1	;IF EQUAL, THEN FILL CLASS = 1
	JRST	VTMCH1+3	;IF NOT EQUAL, THEN CLASS = 3

VTMCH1:	SOS	T1		;HERE FOR FILL CLASS 0
	SOS	T1		;HERE FOR FILL CLASS 1
	SOS	T1		;HERE FOR FILL CLASS 2
;	JFCL			;HERE FOR FILL CLASS 3
	DPB	T1,LDPFLC##	;REMEMBER THE FILL CLASS

;DROP THROUGH TO PROCESS THE REST OF THE MSG (SPEEDS ETC...)
;NOW PROCESS THE SPEEDS ETC.

	PUSH	P,P2		;PROTECT P2 FROM RAVAGES OF COMCON
	PUSHJ	P,EBI2BI##	;GET THE RECEIVE SPEED
	MOVEI	T2,(T1)		;COPY IT FOR COMCON
	PUSHJ	P,TTCSP1##	;TRANSLATE SPEED INTO AN INDEX
	  LDB	P2,LDPRSP##	;IF ILLEGAL SPEED, THEN DON'T CHANGE IT
	DPB	P2,LDPRSP##	;STORE THE NEW SPEED
	PUSHJ	P,EBI2BI##	;GET THE TRANSMIT SPEED
	MOVEI	T2,(T1)		;COPY IT FOR COMCON
	PUSHJ	P,TTCSP1##	;TRANSLATE SPEED INTO INDEX
	  LDB	P2,LDPTSP##	;DON'T CHANGE SPEED IF IT'S ILLEGAL
	DPB	P2,LDPTSP##	;STORE THE NEW TRANSMIT SPEED
	POP	P,P2		;RESTORE P2
	PUSHJ	P,EBI2BI##	;READ THE WIDTH
	SKIPE	T1		;DON'T SET WIDTH TO ZERO
	DPB	T1,LDPWID##	;STORE THE NEW WIDTH
	PUSHJ	P,EBI2BI##	;READ THE AUTO-CRLF POSITION
	DPB	T1,LDPACR##	;  AND STORE THAT (ZERO IS OK)
	PUSHJ	P,XSKIP##	;SKIP 2741 ELEMENT NUMBER (NOT IMPLEMENTED)
	PUSHJ	P,XSKIP##	;SKIP 2741 "BITS" (NOT IMPLEMENTED)
	PUSHJ	P,SETCHP##	;QUEUE A KICK TO THE LINE DRIVER'S HARDWARE
	RETSKP			;GIVE GOOD RETURN
;VTMADL	ROUTINE TO PROCESS AN AUTO-DIAL MESSAGE
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO, AND LENGTH OF THE SUB MSG
;RETURN	CPOPJ			;IF MESSAGE IS BAD
;	CPOPJ1			;WITH AUTO-DIAL MESSAGE PROCESSED

VTMADL:	POPJ	P,		;WE DON'T HANDLE THIS MESSAGE



;VTMXOF	ROUTINE TO PROCESS THE "SEND XOFF IMMEDIATELY" REQUEST
;CALL	U := POINTER TO THE LDB
;	P1 & P4 := POINTER TO, AND LENGTH OF THE SUB MSG (NULL)
;RETURN	CPOPJ			;NEVER
;	CPOPJ1			;XOFF FILLER POINTER SET.

VTMXOF:	MOVE	T2,FLPPXF##	;GET THE XOFF FILLER POINTER
	PUSHJ	P,SETXNP##	;CALL SCNSER TO SET THE "XON CLASS" FILL PTR
	PUSHJ	P,TOPOKE##	;KICK THE LINE (PROBABLY NOT NECESSARY...)
	RETSKP			;GIVE GOOD RETURN, XOFF FILLER QUEUED TO GO.
;VTMSCN	ROUTINE TO SCAN THE STAUS OF A VTM AND SEND MESSAGES NEEDED.
;CALL	U := LDB OF VTM
;RETURN	CPOPJ			;NO CORE.  REQUEUE THE LINE
;	CPOPJ1			;PROCESSING COMPLETED.
;FUNCTION
;	VTMSCN CHECKS FOR MESSAGES TO SEND IN THE FOLLOWING PRIORITY:
;	    .	CHARACTERISTICS (NEEDED IMMEDIATLY AFTER A CONNECT)
;	    .	DELAYED STATUS (STATUS SAVED JUST AS LINE GOES INTO LOCAL ECHO)
;	    .	CHARACTERS IN THE "LOCAL ECHOED" CHAIN.
;	    .	NORMAL STATUS
;	    .	CHARACTERS IN THE "REMOTE ECHO" CHAIN
;	    .	ECHO PIPELINE MARKERS.

VTMSCN:	MOVE	T1,LDBREM##(U)	;GET THE REMOTE STATUS BITS
	TLNE	T1,LRLSCH##	;SEE IF WE NEED TO SEND CHARACTERISTICS
	JRST	[PUSHJ P,VTMXCH	;SEND THE CHARACTERISTICS
		   JRST VTMSC1	;REQUEUE THE LINE IF NO CORE
		 JRST VTMSCN]	;SEE WHAT ELSE THERE IS TO DO.

	TLNE	T1,LRLDST##	;DO WE HAVE A "DELAYED STATUS" MESSAGE TO SEND
	JRST	[PUSHJ P,VTMXDS	;SEND THE DELAYED STATUS
		   JRST VTMSC1	;REQUEUE THE LINE IF NO CORE
		 JRST VTMSCN]	;SEE WHAT ELSE THERE IS TO DO

	SKIPE	LDBECC##(U)	;ANY "LOCALLY ECHOED" CHARS TO GO
	JRST	[PUSHJ P,VTMXEC	;SEND THE "ECHOED" CHARS
		   JRST VTMSC1	;NO CORE. REQUEUE LINE
		 JRST VTMSCN]	;GO LOOK AT THE LINE AGAIN

	TLNE	T1,LRLSTS##	;DO WE NEED TO SEND "NORMAL" STATUS
	JRST	[PUSHJ P,VTMXST	;SEND THE STATUS
		   JRST VTMSC1	;NO CORE
		 JRST VTMSCN]

	SKIPE	LDBTIC##(U)	;ANY "REMOTE ECHO" CHARS TO GO
	JRST	[PUSHJ P,VTMXUC	;SEND THE "UN-ECHOED CHARS"
		   JRST VTMSC1	;NO CORE
		 JRST VTMSCN]	;RELOAD T1 AND HAVE ANOTHER GO AT IT...

	PUSHJ	P,CHKXON##	;SEND AN XON (IF WE OWE ONE) NOW THAT
				;  WE'VE EMPTIED THE CHUNKS.
	PUSHJ	P,VTMXEP	;TRY TO SEND AN ECHO-PIPELINE MARKER
	  JRST	VTMSC1		;NO CORE.  REQUEUE

	AOS	(P)		;SCAN IS COMPLETE.  GIVE GOOD RETURN
VTMSC1:	PUSHJ	P,TSDPCB##	;FORCE ANY PARTIAL MESSAGES OUT.
	POPJ	P,		;ALL DONE. RETURN
;VTMXCH	ROUTINE TO SEND THE "CHARACTERISTICS" MESSAGE FOR A VTM
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;MESSAGE SENT

VTMXCH:	PUSHJ	P,GETCR##	;GET THE "CONDENSED CHARACTERISTICS" IN T1
	PUSHJ	P,TRXTCR##	;CALL ROUTINE IN NETMCR TO SEND THEM
	  POPJ	P,		;NO CORE. GIVE ERROR ROUTINE
	MOVSI	T1,LRLSCH##	;GET THE "CHARACTERISTICS REQUEST" BIT
	ANDCAB	T1,LDBREM##(U)	;  AND CLEAR THE REQUEST.
	RETSKP			;GIVE GOOD RETURN



;VTMXDS	ROUTINE TO SEND THE "DELAYED" STATUS MESSAGE FOR A VTM.
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;DELAYED STATUS SENT, LRLDST CLEARED

VTMXDS:	LDB	T1,LDPDST##	;GET THE DELAYED STATUS
	MOVEI	T2,0		;GET THE DAP STATUS CODE (FULL STATUS)
	PUSHJ	P,MCXSTA##	;CALL NETMCR TO SEND THE MSG
	  POPJ	P,		;GIVE ERROR RETURN IF NO CORE
	MOVSI	T1,LRLDST##	;GET THE "DELAYED STATUS" QUEUED BIT
	ANDCAB	T1,LDBREM##(U)	;  AND CLEAR IT SO WE DON'T SEND IT AGAIN
	RETSKP			;GIVE GOOD RETURN WITH MSG SENT



;VTMXST	ROUTINE TO SEND THE "NORMAL" STATUS MESSAGE FOR A VTM.
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;IF NO CORE
;	CPOPJ1			;STATUS SENT

VTMXST:	LDB	T1,LDPSTS##	;GET THE DAP STATUS BITS
	PUSHJ	P,MCXSTA##	;CALL NETMCR TO SEND THE STATSU
	  POPJ	P,		;GIVE AN ERROR RETURN IF NO CORE
	MOVSI	T1,LRLSTS##	;GET THE "PLEASE SEND STATUS" REQUEST
	ANDCAB	T1,LDBREM##(U)	;  BIT, AND CLEAR IT SO WE DON'T SEND IT AGAIN
	RETSKP			;GIVE GOOD RETURN NOW THAT MSG HAS GONE.
;VTMXEC	ROUTINE TO SEND THE "LOCALLY ECHOED" CHARACTERS
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;NO CORE.
;	CPOPJ1			;ALL CHARACTERS SENT.

VTMXEC:	MOVEI	T1,2		;MINIMUM ACCEPTABLE LENGTH
	PUSHJ	P,TRQPCB##	;REQUEST A PCB
	  POPJ	P,		;GIVE ERROR RETURN IF NO CORE
;TYP
	XMTI	DC.DAT		;SEND "DATA WITH EOR"

	SCNOFF			;NO INTERRUPTS WHILE WE LOOK AT CHUNKS.
	PUSH	P,P4		;SAVE NETMCR'S "P4"
	SOS	P4		;ACCOUNT FOR THE DAP MSG TYPE JUST WRITTEN
	CAMLE	P4,LDBECC##(U)	;IF ALL THE CHARS WILL FIT IN THE MESSAGE
	MOVE	P4,LDBECC##(U)	;  THEN USE THE SMALLER VALUE.
	MOVN	P4,P4		;GET "MINUS" THE NUMBER
	ADDM	P4,LDBECC##(U)	;ACCOUNT FOR THE NUMBER WE'RE ABOUT TO SEND

IFN PARANOID&P$VTM,<
	SKIPGE	P4		;MAKE SURE THIS COUNT IS NEGATIVE,
	SKIPGE	LDBECC##(U)	;  AND THIS ONE ISN'T
	STOPCD	.,STOP,VTMECC,	;++ ECHO COUNTS MESSED UP
>
VTMXE1:	LDCHKR	T1,LDBTIT##(U),VTMXE3  ;GET THE NEXT CHARACTER
	XMT1	T1		;WRITE THE CHAR
	AOJL	P4,VTMXE1	;LOOP OVER ALL THE CHARS
VTMXE3:	POP	P,P4		;GET THE MESSAGE LENGTH BACK FOR NETMCR
	SCNON			;CHUNKS ARE CONSISTANT AGAIN
	PUSHJ	P,TWRPCB##	;SEND THE DATA
	SKIPE	LDBECC##(U)	;IF THERE ARE MORE CHARS,
	JRST	VTMXEC		;  THEN GO SEND THEM
	RETSKP			;ALL DONE.  GIVE GOOD RETURN
;VTMXUC	ROUTINE TO SEND THE "NOT LOCALLY ECHOED" CHARACTERS
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;NO CORE.
;	CPOPJ1			;ALL CHARACTERS SENT.

VTMXUC:	MOVEI	T1,2		;MINIMUM ACCEPTABLE LENGTH
	PUSHJ	P,TRQPCB##	;TRY TO GET A PCB (AND SCREW UP THE STACK)
	  POPJ	P,		;NO CORE.  GIVE ERROR RETURN
;TYP
	XMTI	DC.DAT		;SEND "DATA WITH EOR"

	PUSH	P,P1		;SAVE "P1" AND KEEP THE CONTENTS OF
	MOVE	P1,LDBREM##(U)	;  LDBREM IN IT FOR THE ENTIRE LOOP
	SCNOFF			;NO INTERRUPTS WHILE WE LOOK AT CHUNKS.
	PUSH	P,P4		;SAVE NETMCR'S "P4"
	SOS	P4		;ACCOUNT FOR THE DAP MSG TYPE JUST WRITTEN
VTMXU1:	SOSGE	LDBTIC##(U)	;COUNT OUT ONE MORE CHAR FROM CHUNKS
	JRST	[AOS LDBTIC##(U);  IF NO MORE, FIX UP THE COUNT
		 JRST VTMXU2]	;  AND SEND THE MESSAGE.
	LDCHKR	T1,LDBTIT##(U),VTMXU2  ;GET THE NEXT CHARACTER
	XMT1	T1		;WRITE THE CHAR
	ANDI	T1,177		;MASK OFF PARITY
	CAIN	T1,"S"-100	;IF THE CHAR IS A CONTROL "S"
	 JRST	VTMXU2		;EXIT THE LOOP TO LET XOFF BE SENT
	SOJG	P4,VTMXU1	;LOOP OVER ALL THE CHARS
VTMXU2:	POP	P,P4		;GET THE MESSAGE LENGTH BACK FOR NETMCR
	SCNON			;CHUNKS ARE CONSISTANT AGAIN
	POP	P,P1		;RECOVER "P1"
	PUSHJ	P,TWRPCB##	;SEND THE DATA
	SKIPE	LDBTIC##(U)	;IF THERE ARE MORE CHARS,
	JRST	VTMXUC		;  THEN GO SEND THEM
	RETSKP			;ALL DONE.  GIVE GOOD RETURN
;VTMXEP	ROUTINE TO SEND AN ECHO-PIPELINE-MARKER (IF NECESSARY)
;CALL	U := LDB POINTER
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;EITHER NO REASON SEND AN EPM, OR EPM SENT.

VTMXEP:	MOVE	T1,LDBREM##(U)	;GET THE REMOTE STATUS BITS
	TRNE	T1,STY.DE	;IF WE'RE ALREADY IN LOCAL ECHO,
	TRNE	T1,STY.II	;  OR WE'RE DOING IMAGE MODE INPUT,
	RETSKP			;THEN THERE'S NO REASON TO SEND AN EPM.
	PJRST	TRXEPM##	;LET NETMCR DO ALL THE WORK...
;VTMXDQ	ROUTINE TO SEND ANY DATA-REQUESTS THAT ARE NECESSARY.
;CALL	U := POINTER TO THE LDB
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;ALL CAUGHT UP W.R.T. DRQ'S

VTMXDQ:	MOVE	T1,LDBTOC##(U)	;GET THE COUNT OF CHARS TO OUTPUT
	CAILE	T1,^D100	;IF THERE ARE MORE THAN THIS MANY,
	RETSKP			;  THEN DON'T SEND ANY MORE DRQ'S
	MOVE	T1,TTFREN##	;GET THE COUNT OF FREE CHUNKS
	CAIG	T1,^D25		;  AND REQUIRE THAT THERE BE AT LEAST
	RETSKP			;  THIS MANY FREE.
	LDB	T1,LDPDRQ##	;GET THE NUMBER OF OUTSTANDING DRQ'S
	MOVN	T1,T1		;GET MINUS THE NUMBER OF DRQ
	ADDI	T1,MAXODR##	;T1 = (MAXODR - NUMBER OF DRQ'S)
	SKIPG	T1		;SKIP IF WE NEED TO SEND SOME.
	RETSKP			;RETURN IF WE'VE ALREADY SENT THE DRQ'S
	PUSH	P,T1		;SAVE THE NUMBER OF MESSAGES WE WILL REQUEST
	PUSH	P,U		;SAVE OUR LDB POINTER
	PUSHJ	P,NCMHDR##	;CALL NETSER TO GET A CONTROL MESSAGE HEADER.
	  JRST	[POP P,U	;IF NO CORE, FIXUP THE STACK
		 JRST TPOPJ##]	;  AND GIVE THE "NO CORE" RETURN.
	EXCH	U,-1(P)		;GET OUR LDB ADDRESS BACK
;TYP
	XMTI	NC.DQR		;THE "TYPE" IS DATA-REQUEST
;DLA
	XMTB	LDPDLA##	;SEND OUR FRIENDS REMOTE LINK ADDRESS
;DRQ
	XMT	-2(P)		;WRITE THE DATA-REQUEST COUNT
	EXCH	U,-1(P)		;GET THE PCB BACK, SAVE LDB ADDRESS
	JSP	T1,NETWRC##	;FINISH OFF AND SEND THE CONTROL MSG
	POP	P,U		;CLEAN UP THE STACK
	LDB	T1,LDPDRQ##	;GET THE OLD DATA-REQUEST COUNT
	POP	P,T2		;GET THE VALUE OF THIS DRQ
	ADD	T1,T2		;GET THE TOTAL OUTSTANDING DRQ
	DPB	T1,LDPDRQ##	;  AND SAVE THAT
	RETSKP			;ALL DONE.  RETURN SUCCESSFULLY
;VTMSTE & VTMSTI  --  ROUTINES TO STORE CHARACTERS IN THE LDB'S INPUT STRING.
;CALL	T3 := CHAR TO STORE
;	U  := POINTER TO THE LDB
;	<SCANNER INTERRUPTS OFF>
;RETURN	CPOPJ			;WITH T3 STORED AND EITHER
;				;  LDBECC (VTMSTE) OR LDBTIC (VTMSTI)
;				;  INCREMENTED

VTMSTE:	AOSA	LDBECC##(U)	;COUNT UP ONE MORE "ECHOED" CHAR
VTMSTI:	AOS	LDBTIC##(U)	;COUNT UP ONE MORE "UN-ECHOED" CHAR
VTMST1:	STCHK	T3,LDBTIP##(U),VTMST2  ;STORE THE CHARACTER
VTMST2:	POPJ	P,		;  AND RETURN



;VTMSTO	ROUTINE TO STORE A CHARACTER IN THE LDB'S OUTPUT BUFFER
;CALL	T3 := CHAR TO STORE
;	U  := POINTER TO THE LDB
;	<SCANNER INTERRUPTS OFF>
;RETURN	CPOPJ			;WITH T3 STORED AND LDBTOC INCREMENTED

VTMSTO:	AOS	LDBTOC##(U)	;COUNT THE CHAR,
	STCHK	T3,LDBTOP##(U),VTMST2  ;  STORE IT IN THE OUTPUT BUFFER,
	POPJ	P,		;  AND RETURN.



;VTMEDM	ROUTINE TO "ENTER DEFERED ECHO MODE" FROM LOCAL ECHO MODE.
;CALL	U := LDB.
;RETURN	CPOPJ			;WITH EPM SERIAL# INCREMENTED AND
;				;  ALL (HOPEFULLY) RELEVANT BITS SET/CLEARED.

VTMEDM:	LDB	T1,LDPEPM##	;GET THE SERIAL OF THE LAST EPM SEND
	AOS	T1		;  INCREMENT THE NUMBER AND STORE SO WE DON'T
	DPB	T1,LDPEPM##	;  HAVE TO WORRY ABOUT AN EPM RACE.
	MOVE	T1,[XWD LRLSTS##,STY.DE] ;SAY SEND STATUS, NOW DEFERED ECHO
	IORM	T1,LDBREM##(U)	;  AND SET THESE IN THE DAP STATUS WORD
	PJRST	VTMENQ		;QUEUE THE LINE AND EXIT
;VTMLOP	ROUTINE TO MAKE LINE LOCAL (ALA VTMLOC) AND THEN PRINT A MESSAGE.
;CALL	T1 := ADDRESS OF ASCIZ STRING TO PRINT
;	U  := ADDRESS OF LDB
;RETURN	CPOPJ			;DEFUNCT LDB, NEED TO CALL FRELDB
;RETURN CPOPJ1			;INERT LDB (IDLE PTY, ETC), DON'T TYPE ON IT
;RETURN	CPOPJ2			;SUCCESSFUL WITH USEABLE LOCAL TERMINAL

VTMLOP:	PUSH	P,T1		;SAVE THE MESSAGE ADDRESS
	PUSHJ	P,VTMLOC	;MAKE THE LINE LOCAL
	  JRST	TPOPJ##		;DEFUNCT LDB, NEED TO CALL FRELDB
	 JRST	TPOPJ1##	;INERT LDB, JUST DON'T TYPE ON IT
	PUSHJ	P,PCRLF##	;PRINT INITIAL "CRLF" TO GET MSG ON NEW LINE
	POP	P,T1		;GET THE MESSAGE POINTER BACK
	PUSHJ	P,CONMES##	;PRINT THAT.
	PUSHJ	P,PCRLF##	;  AND PRINT A LAST "CRLF" TO END THE MSG.
	JRST	CPOPJ2##	;SUCCESSFUL RETURN



;VTMLOC	ROUTINE TO CLEAN UP A LINE THAT HAS BEEN "SET HOSTED" AWAY.
;CALL	U := LDB TO "MAKE LOCAL"
;RETURN	CPOPJ			;DEFUNCT LDB, NEED TO CALL FRELDB
;RETURN CPOPJ1			;INERT LDB (IDLE PTY, ETC), DON'T TYPE ON IT
;RETURN	CPOPJ2			;SUCCESSFUL WITH USEABLE LOCAL TERMINAL

VTMLOC:	PUSH	P,W		;PROTECT "W"
	PUSH	P,LDBREM##(U)	;NEED A COPY OF LRLVTZ!LRLVTF
	PUSHJ	P,VTMDEQ	;MAKE SURE THE LINE IS NOT QUEUED.
	PUSHJ	P,VTMCLR	;CLEAR LDBREM WORDS (IN PARTICULAR LRLVTM)
	PUSHJ	P,LDBINI##	;CLEAN UP PARAMETERS ETC.  (DOES A TSETBI
				;  WHICH FIXES UP THE INPUT CHUNK CHAIN)
	PUSHJ	P,CLRPCT##	;CLEAR THE PAGE COUNTERS.
	POP	P,T1		;COPY OF LRLVTZ!LRLVTF
	TLNE	T1,LRLVTF##	;IS THIS LDB TOTALLY DEFUNCT?
	PJRST	WPOPJ##		;YES, LINE IS NOW A USELESS LOCAL LINE.
	AOS	-1(P)		;LDB IS VALID, SKIP CALL TO FRELDB
	TLNE	T1,LRLVTZ##	;IS THE LDB ZAPPED OR GOOD?
	PJRST	WPOPJ##		;ZAPPED, SHOULDN'T GREET IT OR TYPE ON IT
	PJRST	WPOPJ1##	;GOOD, LINE IS NOW A USEABLE LOCAL LINE
;VTMHST	ROUTINE TO PERFORM THE "SET HOST" FUNCTION FOR A LOCAL TERMINAL
;CALL	W := ADDRESS OF THE NODE TO "SET HOST" THIS TERMINAL TO
;	U := ADDRESS OF THE LDB TO THAT IS DOING THE "SET HOST"
;RETURN	CPOPJ			;WITH EITHER THE CONNECT DONE, OR AN
;				;  ERROR MESSAGE PRINTED

VTMHST::HRRZ	F,LDBDDB##(U)	;GET THE ADDRESS OF THIS GUY'S TTY DDB
	SKIPE	F		;DON'T DO THE DETACH IF NO DDB
	PUSHJ	P,TTYDET##	;DETACH THIS GUY
;	PJRST	VTMCNT		;LET VTMCNT DO THE REST OF THE WORK



;VTMCNT	ROUTINE TO PERFORM THE CONNECT FUNCTION FOR A TERMINAL.
;CALL	W := ADDRESS OF NDB OF NODE TO CONNECT TO
;	U := ADDRESS OF LDB TO CONNECT
;RETURN	CPOPJ			;WITH EITHER THE CONNECT SENT, OR
;				;  AN ERROR MESSAGE PRINTED.

VTMCNT:	PUSHJ	P,VTMLOC	;CLEAN UP THE LDBREM WORDS.
	  PJRST	FRELDB##	;AWKWARD TIME FOR LAT/NRT/ETC TO DIE. FREE LDB
	 POPJ	P,		;RETURN WITH NO MORE ADO
	MOVE	T1,U		;LDB ADDRESS FOR GETSLA
	TLO	T1,LAT.TY!LAT.VT;REMEMBER THAT THIS IS VTM/LDB-STYLE
	MOVEI	T2,LAT.CC	;INITIAL STATE IS CONNECT-CONFIRM
	PUSHJ	P,GETSLA##	;ATTEMPT TO ASSIGN AN SLA
	  JRST	[MOVEI	T1,[ASCIZ \No free LAT entries.\]
		JRST	VTMCN8]		;MAKE LINE LOCAL AND PRINT ERROR
	DPB	T1,LDPSLA##	;SAVE THE SOURCE LINK ADDRESS
	HLRZ	T1,NDBNNM(W)	;GET THE NUMBER OF THE NODE TO CONNECT TO
	DPB	T1,LDPRNN##	;  AND SAVE THAT AS THE VTMS REMOTE NODE #
	PUSHJ	P,VTMXCN	;SEND THE CONNECT.
	  JRST	[MOVE	T1,NRTNCE##	;"NETWORK CAPACITY EXCEEDED ERROR
		JRST	VTMCN8]		;MAKE LINE LOCAL AND PRINT ERROR

;AT THIS POINT WE HAVE SENT THE CONNECT.  NOW MAKE THE LINE "REMOTE"

	MOVSI	T1,LRLVTM##	;GET THE "THIS IS A VTM" BIT
	IORM	T1,LDBREM##(U)	;  AND SET IT SO TYPEIN COMES TO US AND
				;  DOESN'T GO TO SCNSER
	POPJ	P,		;EXIT WITH LINE WAITING FOR CONNECT CONFIRM.


;HERE ON ERROR TRYING TO DO THE CONNECT, ERROR MESSAGE IN T1

VTMCN8:	PUSHJ	P,VTMLOP	;MAKE LINE LOCAL AND PRINT ERROR MESSAGE
	  PJRST	FRELDB##	;AWKWARD TIME FOR LAT/NRT/ETC TO DIE. FREE LDB
	 POPJ	P,		;RETURN WITH NO MORE ADO
	POPJ	P,		;RETURN WITH LINE LOCAL AND USEABLE
;VTMXCN	ROUTINE TO SEND A CONNECT MESSAGE FOR A VTM. (EITHER CONFIRM --
;  DLA SET UP, OR INITIATE -- DLA = 0)
;CALL	W := NDB OF THE NODE TO SEND THE CONNECT TO.
;	U := POINTER TO THE LDB TO SEND CONNECT FOR
;RETURN	CPOPJ			;NOT ENOUGH CORE TO BUILD A MSG
;	CPOPJ1			;CONNECT SENT

VTMXCN:	PUSH	P,U		;SAVE THE LDB WHILE WE GO GET A PCB
	PUSHJ	P,NCMHDR##	;GO GET A NUMBERED PCB WITH THE NCL HEADER
	  JRST	UPOPJ##		;GIVE ERROR RETURN IF NO CORE.
	EXCH	U,-1(P)		;REMEMBER PCB ADDRESS, RECOVER LDB ADDRESS

;TYP

	XMTI	NC.CNT		;CONNECT MESSAGE TYPE

;DLA

	XMTB	LDPDLA##	;SEND DLA (IF = 0, THEN CONNECT INIT)

;SLA

	LDB	T1,LDPSLA##	;GET OUR LOCAL LAT ADDRESS
	SKIPN	T1		;MAKE SURE THERE IS ONE
	STOPCD	.,STOP,VTMLAT	;++ LAT ADDRESS NOT SET UP (CALL GETSLA FIRST)
	XMT	T1		;WRITE THE SOURCE LINK ADDRESS FIELD

;DPN(OBJ)

	XMTI	OBJ.TT		;WE WANT A TERMINAL HANDLER (MCR)

;DPN(,PID)

	XMTI	0		;(DUMMY PROCESS NAME)

;SPN(OBJ)

	XMTI	OBJ.TY		;WE ARE A TERMINAL (TTY)

;SPN(,PID)

	XMTB	LDPLNO##	;THIS IS OUR LOCAL LINE NUMBER

;MML

	XMTI	^D512		;RECORD LENGTH (IGNORED EVERYWHERE)

;FEA(DCM)

	XMTI	DCM.AS		;ASCII DEVICE MODE

;FEA(,RLN)

	XMTI	0		;VARIABLE RECORD LENGTH

;FEA(,,DTY)

	MOVEI	T1,DTY.SB!DTY.SH;WE CAN SET HOST AND CHANGE SPEEDS,
	MOVE	T2,LDBDCH##(U)	;  AND, IF WE
	TRNE	T2,LDRDSD##	;  ARE A DATA-SET LINE
	IORI	T1,DTY.MC	;  WE CAN PERFORM MODEM CONTROL.
	XMT	T1		;WRITE THE "ATTRIBUTES"

	EXCH	U,-1(P)		;GET PCB BACK, PRESERVE LDB ADDRESS
	JSP	T1,NETWRC##	;GO SEND THE MESSAGE
	PJRST	UPOPJ1##	;GIVE GOOD RETURN NOW THAT MESSAGE HAS GONE
;VTMENQ	ROUTINE TO QUEUE A VTM FOR PROCESSING.
;CALL	U := ADDR OF THE LDB TO QUEUE
;RETURN	CPOPJ			;WITH THE LINE QUEUED

VTMENQ::
IFN PARANOID&P$VTM,<		;IF WE'RE BEING CAREFUL,
	TRNN	U,-1		;MAKE SURE THAT WE'VE GOT A LDB POINTER
	STOPCD	.,STOP,VTMLDB,	;++ NO LDB IN VTMENQ
>
	SCNOFF			;NO JOSTLING IN THE WAITING ROOM PLEASE.
	MOVSI	T1,LRLQED##	;GET THE "LDB ALREADY QUEUED BIT"
	TDNE	T1,LDBREM##(U)	;  AND SEE IF WEVE ALREADY BEEN QUEUED
	JRST	SONPPJ##	;IF ALREADY QUEUED, WE'RE DONE.
	IORM	T1,LDBREM##(U)	;MARK THIS LDB AS QUEUED.
	MOVE	T1,VTMQUE##	;GET THE FIRST QUEUE ENTRY
	HRRM	T1,LDBVTQ##(U)	;MAKE OUR LDB POINT TO IT.
	HRRZM	U,VTMQUE##	;MAKE OUR LDB THE HEAD OF THE LIST.
	JRST	SONPPJ##	;RE-ENABLE INTERRUPTS AND RETURN

;VTMDEQ	ROUTINE TO REMOVE A LINE FROM THE VTMQUE.
;CALL	U := POINTER TO THE LDB TO DE-QUEUE (CALLED BY VTMLOC ONLY)
;RETURN	CPOPJ			;WITH THE LINE DEQUEUED, BUT THE "QUEUED BIT"
;				;  STILL ON (SO LINE WON'T GET RE-QUEUED BY
;				;  AN INTERRUPT)

VTMDEQ:	SCNOFF			;NO INTERRUPTS WHILE THIS IS GOING ON.
	MOVSI	T1,LRLQED##	;GET THE "THIS VTM IS QUEUED BIT"
	TDNN	T1,LDBREM##(U)	;  AND SEE IF WE THINK IT IS QUEUED
	JRST	[IORM T1,LDBREM##(U) ;IF NOT, SET BIT TO PREVENT RE-QUEUE
		 JRST SONPPJ##]	;  AND WE'RE DONE
	HRRZ	T1,VTMQUE##	;GET ADDR OF FIRST LDB IN THE QUEUE
	HRLI	T1,(MS.SCN)	; USING SCNSER SECTION
	CAMN	T1,U		;  AND SEE IF WE'RE FIRST
	JRST	[HRRZ T1,LDBVTQ##(U) ;GET POINTER TO THE "NEXT" LDB
		 HRRZM T1,VTMQUE##   ;  AND MAKE THAT THE "FIRST"
		 JRST SONPPJ##]	;EXIT WITH LINE DE-QUEUED.
	JRST	VTMDE2		;FIRST DIDN'T MATCH, CHECK FOR EMPTY QUEUE
VTMDE1:	MOVE	T2,T1		;REMEMBER THE ADDRESS OF THE "LAST" LDB
 	HRRZ	T1,LDBVTQ##(T1)	;STEP TO THE "NEXT" LDB
	HRLI	T1,(MS.SCN)	;SCNSER SECTION
	CAMN	T1,U		;IF THIS LDB IS THE ONE WE WANT,
	JRST	[HRRZ T1,LDBVTQ##(T1) ;GET THE ADDR OF THE ONE AFTER THAT
		 HRRM T1,LDBVTQ##(T2) ;  AND PUT IT IN OUR PLACE
		 JRST SONPPJ##]	;EXIT WITH THE LINE DE-QUEUED.
VTMDE2:	TRNE	T1,-1		;IF WE'RE NOT AT THE END YET,
	JRST	VTMDE1		;KEEP LOOKING
	STOPCD	.,STOP,VTMQED,	;++ LINE NOT QUEUED THOUGH LRLQED IS SET
;VTMFRE - "FREE" A VTM'ED LDB (E.G., IF A LAT/ETC TERMINAL VTM'S OUT)
;CALL WITH U/LDB ADDRESS
;
;ON RETURN, THE VTM IS IN THE PROCESS OF BEING DISCONNECTED, NETVTM WILL
;EVENTUALLY RETURN THE LDB TO FRELDB WHEN THE DISCONNECT IS COMPLETE.
;RETURN	CPOPJ		;ALWAYS


;VTMPRL	ROUTINE CALLED WHEN A PTY IS RELEASED.  IF SET-HOSTED,
;	A DISCONNECT IS QUEUED
;CALL	U := LDB
;	PUSHJ	P,VTMPRL
;RETURN	POPJ	P,		;ALWAYS.

VTMFRE::SKIPA	T1,[LRLDIP##!LRLVTF##,,0]  ;FLAG NEED TO FRELDB LATER
VTMPRL::MOVSI	T1,LRLDIP##!LRLVTZ##  ;FLAG THIS LDB IS ZAPPED
	SKIPL	LDBREM##(U)	;IF NOT A "SET HOSTED" LINE,
	POPJ	P,		;  THEN RETURN NOW
	IORM	T1,LDBREM(U)	;SET THE DISCONNECT PROCESSING FLAGS
	PJRST	VTMENQ		;QUEUE THE LINE AND RETURN



;VTMCLR	ROUTINE TO CLEAN UP FOR A VTM CONNECT
;CALL	PUSHJ	P,VTMCLR
;RETURN	CPOPJ

VTMCLR:	LDB	T1,LDPSLA##	;GET OUR ("SOURCE") LAT ADDRESS
	JUMPE	T1,VTMCL1	;NONE (?), NOT MUCH TO DO HERE THEN
	LDB	T2,LATPTR##	;GET NETLAT'S LDB ADDRESS
	CAME	T2,U		;IS THE CIRCLE COMPLETE?
	STOPCD	.,STOP,VTMLAL	;++LAT AND LDB DON'T AGREE
	SETZM	NETLAT##(T1)	;FREE UP THIS NETLAT ENTRY
VTMCL1:	SETZM	LDBREM##(U)	;CLEAR THE VTM/ANF WORDS
	SETZM	LDBREM##+1(U)	;..
	SETZM	LDBREM##+2(U)	;..
	SETZM	LDBREM##+3(U)	;..
	SETZM	LDBREM##+4(U)	;..
	POPJ	P,
;VTMJIF	ONCE/JIFFY PROCESSING FOR VTMS.
;CALL	PUSHJ	P,VTMJIF	;FROM JIFFY CODE IN NETSER
;RETURN	CPOPJ			;ALWAYS (WITH VTMQUE PROCESSED)

VTMJIF::SKIPN	VTMQUE##	;JUST A QUICKY CHECK (SINCE WE GET HERE A LOT)
	POPJ	P,		;VTMQUE IS EMPTY.
	SCNOFF			;GET THE SCNSER INTERLOCK.
	HRRZ	U,VTMQUE##	;GET THE NEXT ENTRY
	JUMPE	U,SONPPJ##	;?? SOME ONE SNUCK IN.
	HRLI	U,(MS.SCN)	;SCNSER SECTION
	HRRZ	T1,LDBVTQ##(U)	;GET THE ADDRESS OF THE NEXT ENTRY
	HRRZM	T1,VTMQUE##	;  AND MAKE THAT LDB BE THE NEW "FIRST"
	MOVSI	T1,LRLQED##	;GET THE "THIS LDB IS QUEUED" BIT
	ANDCAB	T1,LDBREM##(U)	;  AND CLEAR IT SO WE CAN RE-QUEUE LATER.
	SCNON			;RE-ENABLE INTERRUPTS
	TLNN	T1,LRLCON##	;MAKE SURE WE'RE CONNECTED
	JRST	VTMJIF		;IF NOT CONNECTED YET, DON'T PROCESS
				;  (THIS HAPPENS WHEN WE RUN OUT OF CHARS
				;  AND "ZAPBUF" IN SCNSER RE-QUEUES THE
				;  LINE BEFORE THE CONNECT FINISHES)
	TLNE	T1,LRLDIP##	;IF WE WANT TO SEND A DISCONNECT-INIT
	JRST	VTMJI1		;  THEN SEE IF WE ALREADY HAVE
	LDB	T1,LDPRNN##	;GET THE NUMBER OF THE NODE WE'RE TALKING TO
	PUSHJ	P,SRCNDB##	;SET W := A POINER TO THE NODES NDB
	 STOPCD	.,STOP,VTMNDB,	;++ NO NDB FOR LDB'S NODE.
	PUSHJ	P,VTMSCN	;GO DO WHATEVER IS NECESSARY FOR THE VTM
	  PJRST	VTMENQ		;  IF NO CORE. REQUEUE LINE, AND WAIT TILL
				;  NEXT JIFFY.
	PUSHJ	P,VTMXDQ	;TRY TO SEND DATA-REQUESTS
	  PJRST	VTMENQ		;REQUEUE IF NO CORE
	JRST	VTMJIF		;LOOP OVER ALL LINES IN VTMQUE.


;HERE SEE IF WE NEED TO SEND A DISCONNECT FOR THIS TERMINAL

VTMJI1:	LDB	T1,LDPSLA##	;GET THE SOURCE LAT ADDRESS
	SKIPN	T1		;MAKE SURE WE HAVE ONE
	STOPCD	.,STOP,VTMNLA,	;++ NO LAT ADDRESS FOR VIRTUAL TERMINAL?
	LDB	T2,LATSTA##	;GET OUR CONNECTION STATE
	CAIE	T2,LAT.OK	;IF WE'RE NOT IN "OK" STATE
	JRST	VTMJIF		;  THEN WE'VE SENT THE DISCONNECT. NEXT TERMINAL
	LDB	T1,LDPRNN##	;GET THE REMOTE NODE NUMBER
	PUSHJ	P,SRCNDB##	;SET UP "W" WITH THE NDB ADDRESS
	 STOPCD	.,STOP,VTMNNN,	;++ BUT VTMNWD SHOULD HAVE CAUGHT THIS
	MOVEI	T1,RSN.OK	;REASON = GOODNIGHT
	PUSHJ	P,TRMXDC##	;SEND THE DISCONNECT
	  PJRST	VTMENQ		;REQUEUE THE LINE IF NO CORE
	JRST	VTMJIF		;OTHERWISE GO DO THE NEXT LINE
	XLIST
	$LIT
	LIST
VTMEND::END			;END OF NETWORK VIRTUAL TERMINAL SERVICE