Google
 

Trailing-Edge - PDP-10 Archives - BB-F492Z-DD_1986 - 10,7/703anf/dndev.p11
There are 3 other files named dndev.p11 in the archive. Click here to see a list.
.SBTTL	DNDEV - DEVICE IO ROUTINES  11 DEC 84

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979,1980,1981,1982,1983,1984
; BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

VRDEV=074			;FILE EDIT NUMBER

.SBTTL		DEVICE DATA BLOCK DEFINITIONS

.IF NE DEVN

	BLOCK	DB	;DEF DB.??? OFFSETS

X	STS,1	;STATUS WORD
	DS.CAC=000001	;SEND CONNECT ACCEPT
	DS.DSC=000002	;SEND DISCONNECT CONFIRM
	DS.QUE=000004	;DEVICE HAS REQUEST TO RUN IN QUEUE
	DS.OUT=000010	;DEVICE DOES OUTPUT(E.G. LPT)
	DS.ACT=000020	;DEVICE ACTIVE
	DS.DIE=000040	;ABORT - OTHER NODE DISAPPEARED
	DS.IST=000100	;WE STOPPED INPUT WITH AN XOFF
	.IF NE FT.TSK
	DS.PAU=000200	;TASK USING TTY FOR INPUT
	DS.Q10=000400	;TASK HAS QUEUED CHARS TO 10
	.ENDC;	.IF NE FT.TSK
	DS.COR=001000	;DEVICE WANTS TO RUN WHEN CORE IS FREE
	DS.XCH=002000	;NEED TO SEND CHARACTERISTICS
	DS.EPL=004000	;NEED TO SEND AN ECHO PIPELINE MARKER
	DS.IQU=010000	;INPUT QUEUED TO NCL - USED SO TTY'S DON'T HAVE
			; TWO MESSAGES IN PIPE AT ONCE
	DS.TTY=020000	;DEVICE IS A TTY
	DS.XDS=040000	;NEED TO SEND DB.DCS TO OTHER GUY
	DS.CON=100000	;DEVICE IS CONNECTED
	DS.CLR=^C<DS.TTY!DS.OUT!DS.QUE!DS.ACT>	;BITS CLRDDB WILL CLEAR

X	LNK,1	;LINK TO NEXT DEVICE DATA BLOCK

X	HDW,1	;HARDWARE ADR FOR DEVICE

X	RPC,1	;DEFAULT STARTING ADDRESS - CLRDDB MOVES THIS TO DB.OPC

X	TPC,1	;PC IF TIMER GOES OFF

X	DVT,1	;DEVICE ATTRIBUTES

XX	DVU,1	;DEVICE "UNIT" TYPE

XX	DVV,1	;DEVICE "CONTROLLER" TYPE

XX	WID,0	;WIDTH

X	RLN,1	;RECORD LENGTH

XX	ACR,1	;AUTO CRLF POINT

XX	UNI,1	;UNIT NUMBER

XX	OBJ,1	;NCL OBJECT TYPE

XX	ROT,1	;NCL REMOTE OBJECT TYPE

XX	MDR,1	;FOR OUTPUT DEVICES MAX # OF DATA REQUESTS FOR DEVICE

XX	CHK,1	;MAX CHUNKS DEVICE CAN HAVE BEFORE SENDING DATA REQUEST

XX	TYP,1	; TYPE OF DEVICE (INDEX FOR JSR)

.IIF NE FT.RNN,XX	RNN,1	;ONLY NODE NUMBER WHICH MAY CONNECT TO DEVICE

.IIF NE FT.PFH,XX	PFH,1	;PREFERED HOST TO CONNECT TO

.IIF NE FTHOST,XX	RCN,1	;NODE TO RECONNECT TO

X	OLA,1	;OUR LINK ADDRESS FOR THIS DEVICE

.IIF NE FT.RDM!FT.RDP!FT.RDA,X	RDT,1	; REMOTE DATA TYPE
	RDEMPT=1	; FOR MULTIPOINT RDE TYPE
	RDEPTP=2	; FOR P-P RDE
	RDEASC=4	; FOR ASCII RDE
	RDEBRK=100000	; ASCII TYPE BREAK HAS BEEN SEEN

.IIF NE FT.TSK,X	TSK,4	;ADDRESS OF TASK FOR DEVICE
				; 1ST WORD IS PRINTER GET TASK
				; 2ND WORD IS KEYBOARD GET TASK
				; 3RD WORD IS PRINTER PUT TASK
				; 4TH WORD IS KEYBOARD PUT TASK

X	ZER,0	;START CLEARING HERE ON A RESTART

X	DCS,1	;DEVICE CONTROL STATUS

X	MML,1	;MAXIMUM MESSAGE LENGTH FOR DEVICE

XX	DCM,1	;DATA CODE AND MODE
	DCM.AS=	B0	; ASCII
	DCM.EB=	B1	; EBCDIC
	DCM.IM=	B2	; IMAGE
	DCM.HO=	B3	; HOLLERITH (CDR ONLY)
	DCM.DI=	B4	; DEC IMAGE (CDR ONLY)
	DCM.XX=	B5	; RESERVED
	DCM.CF=	B6	; COMPRESSED FORMAT

X	RLA,1	;REMOTE LINK ADDRESS FOR THIS DEVICE

X	SCB,1	;SCB ADDRESS FOR THIS DEVICE

X	OBF,1	;OUTPUT(FROM-TEN) BUFFER POINTER

X	OLN,1	;LENGTH OF CURRENT MSG

X	OCN,1	;COUNT FOR CURRENT SUBMESSAGE

X	OAD,1	;CURRENT BYTE POINTER

X	OPC,1	;ADDRESS TO RUN WHEN HAS REQUEST TO RUN IN QUEUE

XX	ODR,1	;COUNT OF OUTPUT(E.G. LPT) DATA REQUESTS

XX	COL,1	;COLUMN DEVICE IS ON

XX	IDR,1	;COUNT OF INPUT(E.G. CDR) DATA REQUESTS

XX	CCN,1	;COMPRESSED CHAR COUNT

	.EVEN

X	TSZ,0	;FORCE US EVEN, REDEFINE LATER

XX	TIM,2	;EIGHT BIT TIMER (COUNTED DOWN ONCE A CLOCK TICK
		; IF POS, AND UP ONCE A SECOND IF NEG
		; 2ND BYTE IS CODE FOR TYPE OF TIMER

X	HLD,1	;CHAR WE ARE HOLDING

X	VFU,1	;POINTER TO LPTVFU FOR LPT

X	CHR,1	;CHAR WE ARE UNCOMPRESSING

X	IBF,1	;POINTER TO INPUT(TO-TEN) BUFFERS

X	ICC,1	;INPUT CHARACTER COUNT

X	ICN,3	;INPUT MSG COUNT(1ST IS TOTAL, 2ND IS INCREMENTAL)
		; 3RD IS ADDRESS OF COUNT

X	IAD,1	;INPUT CHAR ADDRESS

X	SIZ,0	;SIZE OF DEVICE BLOCK

X	BIT,1	;BIT FOR LINE

	DB.DHB=DB.HDW	;ADDRESS OF DH11 DEVICE BLOCK

XX	.LN,1	;4 BIT LINE NUMBER

XX	FIL,6	;FILLER FOR 10,11,12,13,14,15

XX	EPL,1	;SERIAL NUMBER FOR ECHO PIPELINE MARKER

X	LCB,1	;LINE CONTROL BLOCK ADDRESS


.IF NE FTDN11

XX	DNS,1	;DN11 TABLE (DNTAB) DISPLACEMENT
		; SIGN BIT IS DIAL IN PROGRESS

XX	DNT,1	;DN11 TIMER (SECONDS)
		; TWO HIGH ORDER BITS ARE TIMER CODE
.ENDC;.IF NE FTDN11
X	TTS,1	;TTY STATUS
	TT.APL=000001	;TERMINAL IS IN APL MODE
	CHRAPL=000002


X	TZR,0	;CLEAR FROM HERE ON RESTART


.IF NE FTDN11

X	DNR,1	;DN11 REQUEST WORD

.ENDC ; FTDN11



.IF NE FT2741

X	BCD,1		;IF WORD IS NONZERO LINE IS A 2741
	BCD274=100000	;I AM A 2741
	BCDXRB=040000	;SENDING REVERSE BREAK
	BCDKBL=020000	;IF KEYBOARD IS LOCKED
	BCDPRL=010000	;IF PRINTER IS LOCKED
	BCDCDB=004000	;LAST TIME WE REVERSED LINE IT WAS BECAUSE
			; WE NEEDED INPUT
	BCDCOD=003400	;MASK FOR CODE
	BCDBRK=000200	;PROCESSING A RECEIVED BREAK
	BCDUPS=000100	;IF IN UPPERSHIFT MODE
	BCDOCR=000040	;LAST CHARACTER OUT WAS A CR
	BCDRCR=000020	;LAST CHARACTER RECEIVED WAS A CR
	BCDCON=000010	;LAST CHARACTER IN WAS "CONTROL" FAN
	BCDTDY=000004	;TTY TIDY MODE
	BCDAPL=000002	;SPECIAL "APL-MODE"
			; NO SPCIAL HANDLING FOR UPARROW
			; BREAK IS TO BE TREATED AS ^C^C
	BCDHDB=000001	;TERMINAL HAS DEBREAK FEATURE
	BCDB27=^C<BCDAPL> ;ALL 2741 BITS
			; AS SHIFT HAS BEEN SENT
.IIF EQ <PASS-1>,BCDVRG=BCDPRL	;VIRGIN BITS FOR A BCD LINE
.ENDC;.IF NE FT2741


X	STR,1	;POINTER TO STRING TO TYPE

X	TOC,1	;COUNT OF OUTPUT CHARS IN CHUNK

X	TOB,2	;TTY OUTPUT POINTER - 1ST IS POINTER TO 1ST CHAR
		; 2ND POINTER IS TO LAST CHAR

XX	ASP,1	;ASAP CHAR

XX	BUF,1	;PUT CHARS HERE FOR DH11 TO TYPE THEM
		; EACH IS NUMBER OF TICKS TO WAIT AFTER TYPING

X	FTM,1	;FILL TIME ON CHAR


.IF NE FT.TSK

TQS=20	;SIZE OF TTY QUEUES

X	PCN,1	;PRINTER COUNT (COUNT OF CHARS FROM NCL)

X	PPT,1	;PRINTER PUTTER

X	PTK,1	;PRINTER TAKER

X	KPT,1	;KEYBOARD PUTTER

X	KTK,1	;KEYBOARD TAKER

X	KQU,TQS	;QUEUE FOR KEYBOARD

.ENDC;.IF NE FT.TSK


X	TSZ,0	;SIZE OF TTY BLOCKS
;MACRO TO FINISH MESSAGE OFF AND SEND IT
.MACRO	DVXMSG
	MOVB	R2,@(P)+		;PUT CNT FIELD INTO CONNECT
	ADD	(P)+,R2			;MAKE REAL COUNT
	MOV	(P)+,R0			;GET MESSAGE POINTER
	MOV	R2,CN.LEN(R0)		;PUT COUNT INTO MSG
	MOV	J,-(P)			;BE SURE NCLIN1 IS HONEST
	TRACE	DV			;FOR THOSE WHO WATCH
	JSR	PC,NCLIN1		;GIVE TO NCL TO GET RID OF
	MOV	(P)+,J
.ENDM	DVXMSG
.SBTTL	DEVICE ROUTINES

;HERE TO BEGIN A NCL MESSAGE(CONNECT, DISCONNECT, OR DATA REQUEST, ETC)
; CALL WITH J SETUP
;	MOV	DB.RLA,-(P)	;PUT DLA ON STACK
;	MOV	MSG TYPE,-(P)	;PUT MSG TYPE ON STACK
;	JSR	PC,DVXNCL
;	  ERROR RETURN
;	ON RETURN @P WILL BE ADR OF COUNT
;	AND 2(P) WILL BE COUNT
;	AND 4(P) WILL BE ADR OF CHUNK

DVXNCL:	CLR	R1			;WE ARE SENDING NUMBERED NCL MSG
	MOV	DB.SCB(J),SB		;DESTINATION NODE FOR MSG
	MOV	SB,DNA			;SAVE FOR NCLBMS
	MOV	#OURSCB,SNA		;SOURCE FOR THIS MESSAGE
	JSR	PC,NCLBMS		;TRY TO BEGIN NCL MSG
	BNE	10$			;BRANCH IF WE WON
	BIS	#DS.COR,@J		;FLAG WE RAN OUT OF CORE
	MOV	@P,R1			;GET RETURN ADDRESS
	ADD	#6,P			;CLEAN OFF STACK
	SEC				;SET CARRY CONDITION
	JMP	@R1			;RETURN

10$:	MOV	6(P),R0			;GET DLA
	MOV	@P,6(P)			;AND REPOSITION CHUNK POINTER
	MOV	2(P),@P			;AND REPOSITION RETURN ADDRESS
	ADD	#2,@P			;SKIP RETURN
	JSR	PC,PUTEXN		;PUT DLA INTO THE MESSAGE
	MOV	R3,2(P)			;PUT ADR OF COUNT FIELD INTO MESSAGE
	JSR	PC,PUTBYT		;PUT DUMMY COUNT INTO THE MESSAGE
	MOV	4(P),R0			;GET MESSAGE TYPE
	MOV	R2,4(P)			;PUT COUNT ONTO STACK
	CLR	R2			;RESTART COUNT
	JSR	PC,PUTBYT		;AND PUT IT INTO MESSAGE
	CLC				;CLEAR CARRY AND EXIT
	RTS	PC
;DVDNCL - SAME AS DVXNCL ONLY FOR LARGE MESSAGES

.IF NE FT.DDP!FTECHO			;ONLY USED BY DDP AND ECHO DEVICE SO FAR
DVDNCL:	CLR	R1			;WE ARE SENDING NUMBERED NCL MSG
	MOV	DB.SCB(J),SB		;DESTINATION NODE FOR MSG
	MOV	SB,DNA			;SAVE FOR NCLBMS
	MOV	#OURSCB,SNA		;SOURCE FOR THIS MESSAGE
	JSR	PC,NCLBMS		;TRY TO BEGIN NCL MSG
	BNE	10$			;BRANCH IF WE WON
	BIS	#DS.COR,@J		;FLAG WE RAN OUT OF CORE
	MOV	@P,R1			;GET RETURN ADDRESS
	ADD	#6,P			;CLEAN OFF STACK
	SEC				;SET CARRY CONDITION
	JMP	@R1			;RETURN

10$:	MOV	6(P),R0			;GET DLA
	MOV	@P,6(P)			;AND REPOSITION CHUNK POINTER
	MOV	2(P),@P			;AND REPOSITION RETURN ADDRESS
	ADD	#2,@P			;SKIP RETURN
	JSR	PC,PUTEXN		;PUT DLA INTO THE MESSAGE
	MOV	R3,DB.ICN+0(J)		;SAVE ADDRESS OF LOW-ORDER COUNT BYTE
	JSR	PC,PUTBYT		;ALLOCATE DUMMY COUNT LOW-ORDER BYTE
	MOV	R3,DB.ICN+2(J)		;SAVE ADDRESS OF HIGH-ORDER COUNT BYTE
	JSR	PC,PUTBYT		;ALLOCATE DUMMY COUNT HIGH-ORDER BYTE
	MOV	4(P),R0			;GET MESSAGE TYPE
	MOV	R2,4(P)			;PUT COUNT ONTO STACK
	CLR	R2			;RESTART COUNT
	JSR	PC,PUTBYT		;AND PUT IT INTO MESSAGE
	CLC				;CLEAR CARRY AND EXIT
	RTS	PC
.ENDC ;.IF NE FT.DDP!FTECHO
;QUEDEV  --  QUEUE UP A DEVICE SERVICE ROUTINE TO BE RUN
;QUEXDS  --  SET THE NEED-TO-SEND-STATUS STATUS AND QUEUE UP THE DEVICE

QUEXDS:	BIS	#DS.XDS,@J		;SET NEED-TO-SEND-STATUS
QUEDEV:	TRACE	DV
	QUEPUT	DV 10$			;PUT DEVICE BLOCK ADDRESS INTO THE QUEUE
	RTS	PC

;HERE TO CLEAN OUT A DEVICE BLOCK AFTER A DISCONNECT OR OTHER END DIED
CLNDDB:	TRACE	DV
.IF NE FT.RDM
	BIT	#RDEPTP!RDEMPT,DB.RDT(J); DDCMP RDE ?
	BEQ	10$			; NO, SPLIT
	MOV	J,-(P)			;MUST SET ALL STATIONS OFFLINE
	MOV	DB.HDW(J),J		;GET FIRST LINE BLOCK ADR
	MOV	J,-(P)			;SAVE IT
5$:	BITB	#MP.OFF,LB.MPS(J)	;IF NOT OFFLINE
	BNE	7$
	JSR	PC,L.DOWN		;SET IT OFFLINE
7$:	MOV	LB.MPL(J),J		;GET NEXT BLOCK
	CMP	J,(P)			;IF ITS A NEW ONE LOOP
	BNE	5$
	TST	(P)+			;POP STACK
	MOV	(P)+,J			;RESTORE J
.ENDC ;.IF NE FT.RDM
10$:	MOV	DB.IBF(J),R0		;GET INPUT(E.G. CDR)
	BEQ	20$
	CLR	DB.IBF(J)		;NO LONGER HAVE A MESSAGE LIST
	JSR	PC,FRECNL		;FREE UP THE LINKED LIST
20$:
	JSR	PC,CLRDDB		;CLEAN OUT REST OF BLOCK
.IF NE FT.TSK
	JSR	PC,HSTWAK		;WAKE TASK ON DISCONNECT
.ENDC
	RTS	PC
;HERE TO CLEAR A DEVICE BLOCK
CLRDDB:	BIC	#DS.CLR,@J		;CLEAR MOST OF STATUS BITS
	MOV	J,R0			;COPY DEVICE BLOCK ADR
	ADD	#DB.ZER,R0		;POINT TO FIRST WORD TO ZERO
	MOV	#<DB.SIZ-DB.ZER>/2,R1	;NUMBER OF WORDS TO CLEAR
.IF NE FT.RDM
	BIT	#RDEPTP!RDEMPT,DB.RDT(J) ; IF ASCII, TREAT LIKE TTY
	BEQ	5$
	SAVE	<R0,R2>
	MOV	DB.HDW(J),R0		;LOCATE LINE BLOCKS
	MOVB	LB..LN(R0),R2		;FETCH DH11 LINE #
	MOV	LB.LCB(R0),R1		;GET THE LINE SPEED
	MOV	LC.SPD(R1),R1
	BIC	#17,R1			;AND SET THE RECEIVER TO ZERO BAUD
	MOV	@LB.DHB(R0),R0		;LOCATE DH11 HDW
	JSR	PC,DHSPD		;AND SET IT
	RESTORE	<R2,R0>
	MOV	#<DB.PLE-DB.ZER>/2,R1	;HAVE TO CLEAN MORE IN THIS CASE
5$:
.ENDC	;.IF NE FT.RDM

.IF NE FTHOST
	MOV	DB.DCS(J),R2
.ENDC;.IF NE FTHOST
10$:	CLR	(R0)+			;CLEAR BLOCK
	SOB	R1,10$			;LOOP TILL ALL CLEAR
	MOV	DB.RPC(J),DB.OPC(J)	;WHERE TO START SERVICE ROUTINE
.IF NE FTHOST
.IF NE <TTYN!FT.CTY>
	BIT	#DS.TTY,@J		;WAS THIS A TTY
	BEQ	16$			;IF NOT FORGET OLD STATUS
	BIC	#^CTS.RCN,R2		;FORGET SOME STATUS
	MOV	R2,DB.DCS(J)		;RESTORE DATASET STATUS
.ENDC;.IF NE <TTYN!FT.CTY>
16$:	MOVB	DB.RCN(J),R0		;GET NODE TO CONNECT TO
	BEQ	CLRD90
	CLRB	DB.RCN(J)
	JSR	PC,FNDSCB		;GET SCB FOR IT
	BEQ	CLRD90			;BRANCH IF IMPOSSIBLE
SNDCON:	MOV	SB,DB.SCB(J)		;SAV SCB ADDRESS
	BIS	#DS.CAC!DS.CON!DS.XDS!DS.XCH,@J	;SO WE SEND CONNECT
	CLR	DB.RLA(J)		;CLEAR RLA SO WE DON'T SEND MSGS
					;  TILL A CONFIRM COMES IN.
	JSR	PC,QUEDEV		;WAKE DEVICE
.ENDC;.IF NE FTHOST
CLRD90:	RTS	PC
;HERE TO SEND A CONNECT CONFIRM MSG, OR A DISCONNECT CONFIRM MSG,
; OR BECAUSE OTHER GUY DIED

DVCCFM:	BIT	#DS.DIE,@J		;DID OTHER END DIE ?
	BEQ	15$
	JSR	PC,CLNDDB		;IF SO JUST CLEAN HIM OUT
.IF NE <FT.CTY!TTYN>
	BIT	#DS.TTY,(J)		;IF ITS A TTY SEND A MSG
	BEQ	10$
	JSR	PC,TYPHWA		;TELL USER THAT HOST WENT AWAY
.ENDC	;.IF NE <FT.CTY!TTYN>
10$:	RTS	PC
15$:	BIT	#DS.CAC!DS.DSC,@J	;DO WE NEED TO SEND CONFIRM ?
	BEQ	10$
	CLR	-(P)			;DLA = 0 = NCL
	MOV	#NCLCON,-(P)		;TYPE IS CONNECT
	BIT	#DS.CAC,@J		;CHECK AGAIN
	BNE	20$
	INC	@P			;MAKE THAT DISCONNECT
20$:	JSR	PC,DVXNCL		;BEGIN MESSAGE
	BR	95$			;MUST BE OUT OF CORE SO TRY LATER
	MOV	DB.RLA(J),R0		;GET DESTINATION LINK NUMBER
	JSR	PC,PUTEXN		;PUT IT INTO MSG
	MOV	DB.OLA(J),R0		;GET OUR LINK ADR
	JSR	PC,PUTEXN		;PUT IT INTO THE MSG
	CLR	R0			;IN CASE DOING A DISCONNECT
	BIT	#DS.CAC,@J		;ARE WE DOING A CONNECT ?
	BEQ	60$			;IF NOT PUT IN DISCONNECT CODE
	MOVB	DB.ROT(J),R0		;GET HIS OBJECT TYPE
	JSR	PC,PUTBYT		;PUT IT INTO THE MSG
.IF NE,FT.TDV
	CMPB	DB.OBJ(J),#OBJTSK
	BNE	30$
	JSR	PC,DVCTNM
	BR	31$
30$:
.ENDC;.IF NE,FT.TDV
	CLR	R0			;HIS PROCESS NAME
	JSR	PC,PUTBYT
31$:	MOVB	DB.OBJ(J),R0		;OUR OBJECT TYPE
	JSR	PC,PUTBYT		;INTO THE MSG
.IF NE,FT.TDV
	CMPB	DB.OBJ(J),#OBJTSK
	BNE	40$
	JSR	PC,DVCTNM
	BR	41$
40$:
.ENDC;.IF NE,FT.TDV
	MOVB	DB.UNI(J),R0		;UNIT NUMBER = PROCESS NAME
	JSR	PC,PUTEXN		;INTO THE MSG
41$:	MOV	DB.MML(J),R0		;MAXIMUM MESSAGE LENGTH
	JSR	PC,PUTEXN		;PUT INTO CONNECT
	MOVB	DB.DCM(J),R0		;GET CODE AND MODE
	JSR	PC,PUTBYT		;PUT INTO MESSAGE
	MOV	DB.RLN(J),R0		;GET RECORD SIZE
	JSR	PC,PUTEXN		;PUT INTO MESSAGE
	MOV	DB.DVT(J),R0		;GET DEVICE ATTRIBUTES
	JSR	PC,PUTEXN		;PUT INTO MESSAGE
	MOVB	DB.DVU(J),R0		;GET DEVICE "UNIT" TYPE
	JSR	PC,PUTEXN		;PUT INTO MESSAGE
	MOVB	DB.DVV(J),R0		;GET DEVICE "CONTROLLER" TYPE
60$:	JSR	PC,PUTEXN		;PUT INTO MESSAGE
	DVXMSG				;SEND MESSAGE
	BIT	#DS.CAC,@J		;WAS THIS A CONNECT ?
	BNE	70$
	JSR	PC,CLNDDB		;IF DISCONNECT CLEAN OUT DEVICE BLOCK
.IF NE <FT.CTY!TTYN>
	BIT	#DS.TTY,(J)		;IF IT'S A TTY, TYPE A MSG
	BEQ	65$			;  IF NOT, DONT.
	BIT	#DS.CAC,(J)		;IS THIS A "SET HOST" DISCONNECT
	BNE	65$			;  IF SO, DON'T TYPE MSG
	JSR	PC,TYPHSD		;SAY "HOST SENT DISCONNECT"
.ENDC
65$:	RTS	PC			;ALL DONE.
70$:	BIC	#DS.CAC,@J		;HAVE SENT CONNECT CONFIRM NOW
	MOV	@P,DB.OPC(J)		;DON'T RETURN AGAIN
.IF NE FT.RDM!FT.RDP
	CMPB	DB.OBJ(J),#OBJRDE	;IF RDE DEVICE,
	BNE	90$
	SAVE	<R2>
	MOV	DB.HDW(J),R0		;LOCATE LINE BLOCKS
	MOVB	LB..LN(R0),R2		;FETCH DH11 LINE #
	MOV	LB.LCB(R0),R1		;FETCH LINE SPEED
	MOV	LC.SPD(R1),R1
	MOV	@LB.DHB(R0),R0		;LOCATE DH11 HDW
	JSR	PC,DHSPD		;AND SET SPEED
	RESTORE	<R2>
80$:	CMPB	DB.ODR(J),DB.MDR(J)	;IF WE NEED SOME MORE DATA REQUESTS,
	BHIS	90$
	JSR	PC,DVXDRQ		;SEND A DATA REQUEST
	BR	80$			;CHECK REQUESTS AGAIN
.ENDC ;.IF NE FT.RDM!FT.RDP
90$:	RTS	PC

;HERE BECAUSE CAN'T CONNECT BECAUSE OUT OF CORE
95$:	TWIDDLE
	RTS	PC
.IF NE,FT.TDV
;ROUTINE TO COPY A TSK NAME INTO THE CURRENT MESSAGE

DVCTNM:	SAVE	R5			;SAVE R5 FOR LATER
	MOV	DB.RPC(R5),R5		;POINT TO THE TSK NAME
	SUB	#2,R5			;BACKUP TO THE BEGINING
	MOV	@R5,R5			;POINT TO THE ASCIZ STRING
10$:	MOVB	(R5)+,R0		;GET A CHARACTER OF THE NAME
	BEQ	20$			;IF A NUL WE ARE DONE
	TSTB	@R5			;SEE IF NEXT CHARACTER IS A NUL
	BEQ	11$			;IF YES, DON'T SET EXTENSIBLE BIT
	BIS	#200,R0			;IF NO, DO SET THE EXTENSIBLE BIT
11$:	JSR	PC,PUTBYT		;PUT THE CHARACTER IN MESSAGE
	BR	10$			;AND LOOP FOR MORE
20$:	RESTORE	R5			;RESTORE R5 AND RETURN
	RTS	PC
.ENDC;.IF NE,FT.TDV
;HERE TO SEND A DATA REQUEST
DVXDRQ:	BIT	#DS.DSC!DS.DIE,@J	;ARE WE STOPPING DEVICE ?
	BNE	90$			;IF SO DON'T SEND DATA REQUEST
	TST	DB.RLA(J)		;WAITING FOR CONNECT CONFIRM ?
	BEQ	90$			;IF SO DON'T SEND DRQ UNTIL CONFIRMED
	CMP	#ERSCNT*2,FRECNT	;GOTS LOTS OF ROOM STILL LEFT?
	BLE	2$			;YES
	TWIDDLE				;NO - THAT'S INTERESTING
	BIS	#DS.COR,@J		;FLAG DEVICE WANTS CORE
	BR	90$			;AND WAIT UNTIL LESS CONGESTED

2$:	MOVB	DB.ODR(J),R0		;GET COUNT OF DATA REQUESTS SENT
.IF EQ DGUTS
	ASSERT	PL
.IFF
	BPL	03$
	CLRB	DB.ODR(J)
03$:
.ENDC ; .IF EQ DGUTS
	CMPB	DB.ODR(J),DB.MDR(J)	;HAVE WE SENT ENOUGH DATA-REQ'S
	BPL	90$			;IF SO, GOOD NIGHT
	PIOFF				;DON'T LET ANY GET AWAY...
	SAVE	<R1,R2>			;SAVE REGS, PREPARE TO COUNT THE
					;NUMBER OF CHUNKS THIS DEVICE HAS
	CLR	R0			;R0 := TOTAL NUMBER OF CHUNKS
.IF NE FT.RDA
	BIT	#RDEASC,DB.RDT(J)	;IF THIS IS RDA THEN
	BNE	5$			; MUST COUNT UP DB.TOB CHUNKS ALSO
.ENDC ; FT.RDA
.IF NE TTYN+FT.CTY
	BIT	#DS.TTY,@J		;IF IT IS A TTY, THEN FALL
	BEQ	20$			; INTO STUFF TO COUNT OUTPUT BUFFER
5$:	MOV	DB.TOB(J),R1		;GET A POINTER TO THE OUTPUT BUFFER
	BEQ	20$			;IF NONE, THEN COUNT QUEUED CHUNKS
	DEC	R1			;NOW MAKE POINTER POINT TO
	BIC	#CNKSIZ-1,R1		;THE START OF THE CHUNK
10$:	INC	R0			;COUNT THAT CHUNK AND
	MOV	@R1,R1			;FOLLOW THE CHAIN
	BNE	10$			;A ZERO WORD MARKS THE END
					;WHEN DONE FALL THRU TO CODE TO
					;COUNT QUEUED CHUNKS
.ENDC
20$:	MOV	DB.OBF(J),R2		;GET POINTER TO LIST OF MESSAGES
	BR	35$			;JUMP INTO DOUBLE LOOP
30$:	MOV	CN.MLK(R2),R2		;FOLLOW LINK TO NEXT MESSAGE
35$:	BEQ	50$			;IF NONE, THEN COUNTING IS DONE
	INC	R0			;OTHERWISE COUNT THE CHUNK, AND
	MOV	@R2,R1			;FOLLOW THE REST OF THE MESSAGE
40$:	BEQ	30$			;IF END OF MESSAGE, GO TO NEXT ONE
	INC	R0			;ELSE COUNT THIS CHUNK AND
	MOV	@R1,R1			;FOLLOW THE CHAIN FOR THE
	BR	40$			;MESSAGE
50$:	RESTORE	<R2,R1>			;DONE COUNTING THE MESSAGES
	PION				;LET THE WORLD RUN AGAIN
	CMPB	R0,DB.CHK(J)		;TOO MANY CHUNKS IN USE?
	BPL	90$			;YES, DON'T ASK FOR MORE
	MOVB	DB.MDR(J),R1
	MOVB	DB.ODR(J),R0
	SUB	R0,R1			; ASK FOR THE RIGHT AMOUNT OF DATA
	MOV	R1,-(P)			;SAVE COUNT WE ARE NOW SENDING
	CLR	-(P)			;DLA IS 0 = NCL
	MOV	#NCLDRQ,-(P)		;MESSAGE TYPE IS DATA REQUEST
	JSR	PC,DVXNCL		;BEGIN NCL MESSAGE
	  RTS	PC			;CAN'T SEND IT NOW
	MOV	DB.RLA(J),R0		;GET DLA
	JSR	PC,PUTEXN		;PUT INTO MESSAGE
	MOV	6(P),R0			;DATA REQUEST COUNT
	JSR	PC,PUTBYT		;PUT IT INTO THE MSG
	DVXMSG				;SEND MESSAGE
	ADD	(P)+,DB.ODR(J)		;COUNT REQUESTS SENT
90$:
	RTS	PC
;HERE TO SEND DEVICE CONTROL STATUS

DVXDCS:	BIT	#DS.XDS,@J		;DO WE NEED TO SEND STATUS ?
	BEQ	90$
	TST	DB.RLA(J)		;DO WE HAVE A REMOTE ADDRESS YET
	BEQ	90$			;DON'T SEND STATUS TILL CONNECT CONFIRM
	BIT	#DS.DIE,@J		;HAVE WE LOST CONTACT WITH HOST
	BNE	90$			;YES, DON'T SEND STATUS
.IF NE TTYN+FT.CTY
	BIT	#DS.TTY,@J		;TTY?
	BEQ	10$			; NO, SKIP IT
	TST	DB.LCB(J)		;CONNECTED??
	BEQ	10$			; NO, THIS LOSES TOO
	BIT	#LCB.TM,@DB.LCB(J)	;TIMER RUNNING
	BNE	90$			; YES, DONT SEND STATUS
.ENDC
10$:	MOV	DB.RLA(J),-(P)		;PUT DLA ON STACK
	MOV	#3,-(P)			;CODE FOR STATUS MESSAGE
	JSR	PC,DVXNCL		;BEGIN A MESSAGE
	  RTS	PC			;NOT ENOUGH CORE NOW
	BIC	#DS.XDS,@J		;HAVE SENT STATUS NOW
	CLR	R0
	JSR	PC,PUTBYT		;PUT STC INTO MESSAGE
	MOV	DB.DCS(J),R0		;GET DEVICE CONTROL STATUS
	JSR	PC,PUTEXN		;PUT IT INTO THE MESSAGE
	MOV	4(P),R0			;GET ADR OF CHUNK
	BISB	#NCFINT,CN.NCT(R0)	;SO DATA REQUESTS WORK
	DVXMSG				;SEND MESSAGE TO 10
90$:	RTS	PC
;HERE TO GET NEXT OUTPUT BYTE FROM AN NCL MESSAGE
; CALL	JSR	PC,DVGBYT	;WITH J SETUP
;				; USES R1 AS SCRATCH
;	NORMAL RETURN WITH DATA IN R0
;	RETURN WITH MSG TYPE IN R0
;	RETURN IF NO MORE DATA
;	DB.OBF	POINTS TO MESSAGES STRAIGHT FROM NCL
;	DB.OLN	IS LENGTH LEFT IN MESSAGE AFTER CURRENT SUBMESSAGE SEGMENT
;	DB.OCN	IS LENGTH OF CURRENT SUBMESSAGE
;	DB.OAD	POINTS TO CURRENT CHARACTER

DVGBUF:	MOV	DB.OBF(J),R0		;GET ADR OF NEXT BUFFER FROM NCL
	BNE	30$
	ADD	#4,@P
	RTS	PC
30$:	MOV	CN.MLK(R0),DB.OBF(J)	;DELINK THIS MESSAGE
;
;********* here is a convenient place for a sink macro call ******
;
	MOV	CN.CNT(R0),DB.OLN(J)	;SAVE LENGTH OF MESSAGE
	MOV	CN.ADR(R0),DB.OAD(J)	;SAVE ADR OF NEXT DATA BYTE
.IF EQ DGUTS
	ASSERT	NE
.IFF
	BNE	DVGBYT
DVGBFE:	JSR	PC,FRECKS		;CHUCK MSG AND REPORT ERROR
	CTYMSG	NCL
	BR	DVGBUF
.ENDC ; .IF EQ DGUTS
DVGBYT:	MOV	DB.OAD(J),R0		;GET POINTER TO CURRENT MESSAGE IF ANY
	BEQ	DVGBUF			;GET NEXT BUFFER IF ANY
30$:	DEC	DB.OCN(J)		;COUNT BYTE OUT OF SUBMESSAGE
	BPL	50$
	DEC	DB.OLN(J)		;COUNT PART OF COUNT OUT MESSAGE
	BPL	40$			;BRANCH IF THERE IS MORE
	BIC	#CNKSIZ-1,R0		;MAKE CHUNK ADR FROM BYTE ADR
	JSR	PC,FRECKS		;AND RELEASE ALL CHUNKS
	CLR	DB.OAD(J)		;CLEAR BYTE POINTER
	JSR	PC,QUEDEV		;SO WE SEND MORE DATA REQUESTS
	BR	DVGBYT			;AND BACK TO CHECK FURTHER
40$:	MOVB	(R0)+,R1		;GET PART OF COUNT
	ADVCNK	R0 FREE
42$:	TSTB	R1			;WAS COUNT EXTENDED ?
	BPL	48$
	DEC	DB.OLN(J)		;ADJUST TOTAL COUNT
	BIC	#^C177,R1		;STRIP EXTENSIBLE BIT
	MOV	R1,-(P)			;AND SAVE LOW ORDER BITS
	MOVB	(R0)+,R1		;GET HIGH ORDER BITS
	ADVCNK	R0 FREE
46$:	SWAB	R1			;PUT HIGH ORDER BITS IN LH
.IF EQ DGUTS
	ASSERT	PL			;BETTER NOT BE EXTENSIBLE
.IFF
	BPL	47$
	TST	(P)+			;GET STACK BACK IN SYNC
	BIC	#CNKSIZ-1,R0		;RETURN TO START OF CHUNK
	BR	DVGBFE			;AND CHUCK THE WHOLE THING
47$:
.ENDC ; .IF EQ DGUTS
	ASR	R1			;POSITION HIGH ORDER BITS
	ADD	(P)+,R1			;MAKE TOTAL COUNT
48$:	SUB	R1,DB.OLN(J)		;ADJUST HOW MUCH LEFT IN MESSAGE
	ASSERT	PL			;BETTER NOT BE NEGATIVE
	DEC	R1			;COUNT NEXT BYTE WE TAKE OUT
	MOV	R1,DB.OCN(J)		;SAVE SUBMESSAGE LENGTH
	ADD	#2,@P			;SKIP RETURN
50$:	MOVB	(R0)+,R1		;GET DATA
	ADVCNK	R0 FREE
56$:	MOV	R0,DB.OAD(J)		;SAVE BYTE ADDRESS
	MOV	R1,R0
	RTS	PC

;HERE TO GET A DATA BYTE FROM A MESSAGE
DVGDBY:
.IF NE DGUTS
	TST	DB.OAD(J)		;CHECK FOR DATA TO READ
	BEQ	05$
	TST	DB.OCN(J)
	BEQ	05$
.IFTF
	JSR	PC,DVGBYT		;GET NEXT BYTE
	RTS	PC
.IFF
	TRAP
	TRAP
.IFT
	NOP
05$:	CLR	R0			;HALUCINATE A NULL
	CTYMSG	NCL
	RTS	PC
.ENDC ;.IF NE DGUTS

;HERE TO GET AN EXTENSIBLE NUMBER FROM NCL HEADER
DVGEXF:	JSR	PC,DVGDBY		;GET 1ST BYTE
	TSTB	R0			;SEE IF EXTENDED FLAG IS SET IN BYTE
	BPL	92$			;IF NOT WE ARE DONE
	SAVE	<R0>
	JSR	PC,DVGDBY		;GET 2ND BYTE
	SWAB	R0			;NOW PATCH THESE 14 BITS TOGETHER
	COM	R0
	ASR	R0
	BIC	#177,R0
	BIC	R0,(P)
	BPL	91$			;IF BITS 14,15 ARE ZERO, WE'RE DONE
	JSR	PC,DVGDBY		;GET THE LAST TWO BITS
	SAVE	<R0>
	BPL	90$			;IF FLAG BIT IS OFF, WE'RE DONE
	TWIDDLE				;COUNT TOOOO LOOOONG FIELD ERRORS
89$:	JSR	PC,DVGDBY		;ELSE EAT UP THE REST OF THIS GARBAGE
	TSTB	R0
	BMI	89$
90$:	RESTORE	<R0>			;GET BITS 14,15
	ASR	R0
	ROR	R0
	ROR	R0
	BIS	#37777,R0
	COM	R0
	BIC	R0,(P)
91$:	RESTORE	<R0>
92$:	RTS	PC
;HERE TO PUT A BYTE INTO A SUBMESSAGE AS AN EXTENSIBLE FIELD
DVPEXA:	BIC	#^C377,R0		;STRIP EXTRA BITS
;HERE TO PUT AN EXTENSIBLE FIELD INTO A SUBMESSAGE
DVPEXD:	BIT	#^C177,R0		;IF MORE THAN 7 BITS
	BEQ	DVPDAT
	MOV	R0,-(P)			;SAVE VALUE
	JSR	PC,DVPEDT		;INSERT FIRST BYTE
	MOV	(P)+,R0			;GET VALUE BACK
	SWAB	R0			;MOVE BITS 7-15 TO 0-8
	ASL	R0
	ADC	R0
	BIC	#<^C777>,R0		;STRIP EXTRA BITS
	BR	DVPEXD			;LOOP ON THE NEXT BYTE
;HERE TO BEGIN A SUBMESSAGE
; CALL	MOV	#TYPE,R0
;	JSR	PC,DVPBSM
;
;RETURN WITH CARRY CLEAR IF SUCCESS, CARRY SET IF FAILURE (E.G., NO FREE
;CHUNKS TO START A NEW MESSAGE).
;
;ONLY SUBMESSAGES UP TO 177 BYTES MAY BE SENT, FOR LARGER MESSAGES USE
;DVDBSM INSTEAD.

DVPBSM:	MOV	R0,-(P)			;SAVE TYPE CODE
	TST	DB.ICN(J)		;DANGLING PREVIOUS SUBMSG ?
	BEQ	10$
	JSR	PC,DVPSBM		;FINISH PREVIOUS SUBMESSAGE
10$:	MOV	DB.IBF(J),R0		;GET POINTER TO MSG
	BNE	30$
	MOV	(P)+,R0			;GET CODE
	MOV	DB.RLA(J),-(P)		;DESTINATION LINK ADDRESS
	BEQ	40$			;IF CONNECT NOT CONFIRMED, DON'T SEND
	MOV	R0,-(P)			;SAVE SUBMESSAGE TYPE
	JSR	PC,DVXNCL		;BEGIN MSG
	 BR	44$			; ERROR TIME
	MOV	R3,DB.IAD(J)		;SAVE BYTE POINTER
	MOV	(P)+,DB.ICN(J)		;SAVE ADDRESS OF COUNT FIELD
	MOV	(P)+,R1			;GET COUNT BACK
	MOV	(P)+,R0			;GET BUFFER ADDRESS
	MOV	R1,CN.LEN(R0)		;PUT COUNT INTO THE MSG
	MOV	R0,DB.IBF(J)		;SAVE MSG POINTER
	MOVB	#001,@DB.ICN(J)		;INITIAL COUNT IS 1
	CLC				;FLAG GOOD RETURN
	RTS	PC

;HERE WHEN ALREADY HAVE AN NCL MESSAGE, JUST START NEW SUBMESSAGE

30$:	INC	CN.LEN(R0)		;COUNT COUNT FIELD
	MOV	DB.IAD(J),DB.ICN(J)	;SAVE POINTER TO COUNT BYTE
	CLR	R0			;VIRGIN COUNT
	JSR	PC,DVPBYT		;PUT COUNT INTO THE MSG
	MOV	(P)+,R0			;GET TYPE CODE BACK
	BR	DVPDAT			;PUT CODE INTO THE MESSAGE

;HERE WHEN CAN'T START NEW [SUB]MESSAGE - NO CORE, NO RLA, ETC.

40$:	TST	(P)+			;POP DUD RLA
44$:	SEC				;ERROR RETURN
	RTS	PC
DVPEDT:	BIS	#200,R0			;ADD EXTENSIBLE FLAG

;HERE TO PUT NEXT DATA BYTE IN AN NCL MESSAGE
; CALL	JSR	PC,DVPDAT	;WITH J SETUP AND CHAR IN R0
;				; USES R1 AS SCRATCH
;	DB.IBF	IS POINTER TO 1ST CHUNK IN MESSAGE
;	DB.IAD	IS INPUT CHAR POINTER
;	DB.ICN	IS POINTER TO CURRENT COUNT IN MESSAGE

DVPDAT:	MOV	DB.IAD(J),R3		;GET POINTER TO CHUNK
	BEQ	20$
10$:	TST	DB.ICN(J)	;IF NO PARTIAL MESSAGE, MAKE A NEW MSG.
	BEQ	20$
15$:	INCB	@DB.ICN(J)	;INCREMENT THE BYTE COUNT.
	BPL	DVPBYT		;IF ITS NOT TOO LARGE, INSERT THE BYTE.
	DECB	@DB.ICN(J)	;DECREMENT THE COUNT, CAUSE THE CHARACTER
				; DOESN'T FIT IN THE MESSAGE.
	MOV	R0,-(P)
	JSR	PC,DVPSBM	;FINISH OFF THE SUB MESSAGE.
	MOV	DB.IBF(J),R0	;GET THE MESSAGE POINTER.
	MOV	J,CN.DDB(R0)	;PUT THE DDB ADDRESS IN THE HEADER.
	CLR	DB.ICC(J)	;CLEAR THE CHARACTER COUNT
	JSR	PC,NCLIN1	;SEND THE MESSAGE.
	CLR	DB.IBF(J)	;MESSAGE IS GONE.
	CLR	DB.IAD(J)	;
	BR	25$

20$:	MOV	R0,-(P)		;START A NEW DATA SUBMESSAGE.
25$:	MOV	#2,R0		;SAVE DATA
	JSR	PC,DVPBSM	;BEGIN SUBMESSAGE
	MOV	(P)+,R0		;GET CHAR BACK
	  BCC	15$		;INSERT THE CHARACTER, IF THIS SUCCEEDED.
.IF EQ DGUTS
	TRAP
.IFF
	CTYMSG	BME		;NCL MESSAGE GENERATION FAILURE.
	SEC
	RTS	PC
.ENDC ; .IF EQ DGUTS

DVPBYT:	MOV	DB.IAD(J),R3		;GET BYTE POINTER
.IF EQ DGUTS
	ASSERT	NE			;BETTER BE ONE
.IFF
	BEQ	DVPDAT			;IF NONE, TRY STARTING A NEW MSG
.ENDC ; .IF EQ DGUTS
	MOVB	R0,(R3)+		;PUT CHARACTER INTO THE MESSAGE
	ADVCNK	R3 EXTEND		;ALLOCATE ANOTHER CHUNK IF REQUIRED
76$:	MOV	R3,DB.IAD(J)		;SAVE UPDATED BYTE POINTER
	CLC				;SET SUCCESS
DVPEXT:	RTS	PC
;HERE TO PUT DEVICE CONTROL STATUS INTO AN NCL MESSAGE
; CALL	JSR	PC,DVPDCS	;WITH J SETUP (USES R0 AND R1)

DVPDCS:	MOV	DB.IAD(J),R3		;GET POINTER TO CHUNK
	BNE	30$
	ASSERT EQ DB.IBF(J)
	TST	DB.RLA(J)		;SEE IF WE ARE CONNECTED (CONFIRMED)
	BEQ	DVPEXT			;DON'T SEND MSG TO A ZERO LAT
	MOV	DB.RLA(J),-(P)		;DESTINATION LINK ADDRESS
	MOV	#3,-(P)			;CODE FOR STATUS
	JSR	PC,DVXNCL		;BEGIN A MESSAGE
.IF EQ DGUTS
	TRAP
.IFF
	RTS	PC
.ENDC ; .IF EQ DGUTS
;.IF NE TTYN
;	BIT	#DS.TTY,@J
;	BEQ	20$
;	MOV	DB.DCS(J),R0		;GET DEVICE STATUS
;	BIC	#TS.CAR,R0		;CLEAR CARRIER FLAG
;	MOV	DB.LCB(J),R1		;POINT TO DATA SET STATUS
;	BIT	#LCB.DS,LC.CAR(R1)	;IS IT DATA SET LINE?
;	BEQ	38$			; NO, GIVE UP
;	MOVB	LC.STA(R1),R1		;GET STATE
;	MOV	CRBTAB(R1),R1		;GET CARRIER BIT
;	BIS	R1,R0			;SET IT IF WE HAVE IT
;38$:	MOV	R0,DB.DCS(J)		;SAVE UPDATED STATUS
;.ENDC;.IF NE TTYN
20$:	MOV	(P)+,DB.ICN(J)		;SAVE ADDRESS OF COUNT FIELD
	MOVB	#001,@DB.ICN(J)		;INITIAL COUNT IS ONE FOR TYPE
	MOV	(P)+,R1			;GET COUNT BACK
	MOV	(P)+,R0			;GET BUFFER ADDRESS
	MOV	R1,CN.LEN(R0)		;PUT COUNT INTO MESSAGE
	MOV	R0,DB.IBF(J)		;SAVE BUFFER ADDRESS
	MOV	R3,DB.IAD(J)		;SAVE POINTER TO CHAR
	BR	40$
30$:	MOV	#3,R0			;CODE FOR STATUS MESSAGE
	JSR	PC,DVPBSM		;BEGIN STATUS SUBMESSAGE
	BCC	40$
	  RTS	PC			;ERROR RETURN
40$:	CLR	R0			;CODE FOR PLAIN STATUS
	JSR	PC,DVPDAT		;PUT CODE INTO MESSAGE
	  BCS	DVPSBM			;IF ERROR, SEND GARBAGE, AND CORRECT IT LATER
	MOV	DB.DCS(J),R0		;GET DEVICE CONTROL STATUS
	JSR	PC,DVPEXD		;PUT STATUS INTO THE MESSAGE
	BIC	#DS.XDS,@J		;HAVE SENT STATUS NOW
	;CLOSE OUT STATUS SUBMESSAGE (FALL INTO CODE)

;HERE TO CLOSE OUT CURRENT SUBMESSAGE
DVPSBM:	MOV	DB.IBF(J),R0		;GET ADDRESS OF MESSAGE
	TST	DB.ICN(J)		;SEE IF COUNT EXISTS
	BEQ	90$			; NO, EXIT
	MOVB	@DB.ICN(J),R1		;GET COUNT FOR STATUS PORTION
	ADD	R1,CN.LEN(R0)		;PUT COUNT INTO MESSAGE
	CLR	DB.ICN(J)		;NO MORE POINTER TO COUNT
90$:	RTS	PC

;.IF NE TTYN
;;TABLE OF IF CARRIER IS ON OR OFF
;CRBTAB:	.WORD	0			;(00) VIRGIN
;	.WORD	TS.CAR			;(02) RING
;	.WORD	0			;(04) CARRIER DETECT (WAITING FOR)
;	.WORD	0			;(06) CARRIER DETECT SATISFIED
;	.WORD	0			;(08) AUTO BAUD DETECT
;	.WORD	TS.CAR			;(10) RUNNING UNCONNECTED
;	.WORD	TS.CAR			;(12) RUNNING CONNECTED, WAITING FOR -10
;	.WORD	TS.CAR			;(14) RUNNING, CONNECTED, CONFIRMED
;	.WORD	TS.CAR			;(16) LOST CARRIER (TEMP, 5. SECONDS)
;	.WORD	0			;(18) WANT TO HANG UP
;	.WORD	0			;(20) HANG UP
;.IF NE FTDN11
;	.WORD	TS.CAR			;(22) DIALING
;	.WORD	TS.CAR			;(24) DIALOUT SUCCEEDED
;	.WORD	0			;(26) DIALOUT FAILED
;.ENDC;.IF NE FTDN11
;.IIF NE .-CRBTAB-2-LCS.MX,.ERROR <.-CRBTAB>;CRBTAB STATE PHASE ERROR IN DNDEV
;.ENDC ;.IF NE TTYN
;HERE TO BEGIN A SUBMESSAGE
; CALL	MOV	#TYPE,R0
;	JSR	PC,DVDBSM
;
;RETURN WITH CARRY CLEAR IF SUCCESS, CARRY SET IF FAILURE (E.G., NO FREE
;CHUNKS TO START A NEW MESSAGE).
;
;DVDBSM SETS UP FOR LARGE (.GT. 177 BYTES) SUBMESSAGES, FOR KNOWN SHORT
;MESSAGES USE DVPBSM INSTEAD.

.IF NE FT.DDP!FTECHO		;ONLY USED BY DDP AND ECHO-TASK DEVICE(S) SO FAR
DVDBSM:	MOV	R0,-(P)		;SAVE TYPE CODE
	TST	DB.ICN(J)	;DANGLING PREVIOUS SUBMSG ?
	BEQ	10$		;NO, JUST START NEW ONE
	JSR	PC,DVDSBM	;FINISH PREVIOUS SUBMESSAGE
10$:	MOV	DB.IBF(J),R0	;GET POINTER TO MSG
	BNE	30$		;AND JUST APPEND NEW SUBMESSAGE
	MOV	(P)+,R0		;GET CODE
	TST	DB.RLA(J)	;SEE IF WE HAVE A REMOTE LINK #
	BEQ	40$		;IF CONNECT NOT CONFIRMED, DON'T SEND
	MOV	DB.RLA(J),-(P)	;DESTINATION LINK ADDRESS
	MOV	R0,-(P)		;SAVE SUBMESSAGE TYPE
	JSR	PC,DVDNCL	;BEGIN MSG
	 BR	40$		; ERROR TIME
	TST	(P)+		;TOSS DUMMY (A LA DVXNCL) WORD
	MOV	R3,DB.IAD(J)	;SAVE BYTE POINTER
	MOV	(P)+,R1		;GET COUNT BACK
	MOV	(P)+,R0		;GET BUFFER ADDRESS
	MOV	R1,CN.LEN(R0)	;PUT COUNT INTO THE MSG
	MOV	R0,DB.IBF(J)	;SAVE MSG POINTER
	MOV	#001,DB.ICN+4(J);INITIAL COUNT IS 1
	CLC			;FLAG GOOD RETURN
	RTS	PC

;HERE TO APPEND TO ALREADY-EXTANT NCL MESSAGE

30$:	ADD	#2,CN.LEN(R0)	;ACCOUNT FOR 2-BYTE COUNT FIELD COMING UP
	MOV	DB.IAD(J),DB.ICN+0(J)  ;SAVE LOW-ORDER COUNT BYTE ADDRESS
	JSR	PC,DVDBYT	;ALLOCATE COUNT (LOW ORDER) BYTE
	MOV	DB.IAD(J),DB.ICN+2(J)  ;SAVE HIGH-ORDER COUNT BYTE ADDRESS
	JSR	PC,DVDBYT	;ALLOCATE COUNT (HIGH ORDER) BYTE
	CLR	DB.ICN+4(J)	;INITIALIZE NCL SUBMESSAGE COUNT
	MOV	(P)+,R0		;GET TYPE CODE BACK
	BR	DVDDAT		;PUT CODE INTO THE MESSAGE

40$:	SEC			;ERROR RETURN
	RTS	PC
;STILL IN IF NE FT.DDP!FTECHO

;HERE TO PUT NEXT DATA BYTE IN AN NCL MESSAGE
; CALL	JSR	PC,DVDDAT	;WITH J SETUP AND CHAR IN R0
;				; USES R3 AS SCRATCH
;	DB.IBF	 IS POINTER TO 1ST CHUNK IN MESSAGE
;	DB.IAD	 IS INPUT CHAR POINTER
;	DB.ICN	 IS POINTER TO CURRENT COUNT (LOW ORDER) IN SUBMESSAGE
;	DB.ICN+2 IS POINTER TO CURRENT COUNT (HIGH ORDER) IN SUBMESSAGE
;	DB.ICN+4 IS CURRENT SUBMESSAGE BYTE COUNT

DVDDAT:	TST	DB.ICN(J)	;IF NO PARTIAL MESSAGE, MAKE A NEW MSG.
	BEQ	DVDDAX		;NO MESSAGE, START UP A NEW ONE
	INC	DB.ICN+4(J)	;INCREMENT THE BYTE COUNT.

DVDBYT:	MOV	DB.IAD(J),R3	;GET BYTE POINTER

.IF EQ DGUTS
	ASSERT	NE		;BETTER BE ONE
.IFF
	BEQ	DVDDAT		;IF NONE, TRY STARTING A NEW MSG
.ENDC ; .IF EQ DGUTS

	MOVB	R0,(R3)+	;PUT CHARACTER INTO THE MESSAGE
	ADVCNK	R3 EXTEND	;ALLOCATE ANOTHER CHUNK IF REQUIRED
76$:	MOV	R3,DB.IAD(J)	;SAVE UPDATED BYTE POINTER
	CLC			;SET SUCCESS
	RTS	PC

DVDDAX:	MOV	R0,-(P)		;START A NEW DATA SUBMESSAGE.
	MOV	#2,R0		;SAVE DATA
	JSR	PC,DVDBSM	;BEGIN SUBMESSAGE
	MOV	(P)+,R0		;GET CHAR BACK
	  BCC	DVDDAT		;INSERT THE CHARACTER, IF THIS SUCCEEDED.
.IF EQ DGUTS
	TRAP
.IFF
	CTYMSG	BME		;NCL MESSAGE GENERATION FAILURE.
	SEC
	RTS	PC
.ENDC ; .IF EQ DGUTS
;STILL IN IF NE FT.DDP!FTECHO

;HERE TO CLOSE OUT CURRENT SUBMESSAGE

DVDSBM:	MOV	DB.IBF(J),R0	;GET ADDRESS OF MESSAGE
	TST	DB.ICN(J)	;ADDRESS OF SAVED SUBMESSAGE COUNT FIELD
	BEQ	90$		;EXIT IF NO SUBMESSAGE
	MOV	DB.ICN+4(J),R1	;LENGTH OF THIS SUBMESSAGE
	ADD	R1,CN.LEN(R0)	;ADD INTO TOTAL NCL MESSAGE LENGTH
	MOVB	R1,@DB.ICN(J)	;SET LOW ORDER BYTE LENGTH
	BISB	#200,@DB.ICN(J)	;SET IT AS EXTENSIBLE
	ASL	R1		;SHIFT TO HIGH-ORDER 7-BIT'S WORTH
	SWAB	R1		;POSITION FOR BYTE OPERATION
	MOVB	R1,@DB.ICN+2(J)	;SET HIGH-ORDER BYTE LENGTH
	CLR	DB.ICN(J)	;NO MORE POINTER TO COUNT
90$:	RTS	PC

.ENDC ;.IF NE FT.DDP!FTECHO
;HERE TO RECEIVE A STATUS MESSAGE
; CALL	JSR	PC,DVRSTS	;WITH J SETUP AFTER GETTING TYPE = 3 = STATUS

DVRSTS:	JSR	PC,DVGDBY		;GET CODE IN STATUS MSG
	MOV	R0,-(P)			;SAVE CODE
	JSR	PC,DVGEXF		;GET BITS TO SET/CLEAR
	ASSERT	EQ DB.OCN(J)
	MOV	(P)+,R1			;GET CODE AGAIN
	MOV	DB.DCS(J),-(P)		;SAVE CURRENT STATUS

;DO "STATUS" IF REQUESTED

	TST	R1			;DOES HE WANT A "MOVEM" STATUS?
	BNE	60$			;NO
	MOV	R0,DB.DCS(J)		;YES, SET NEW STATUS
	BR	90$			;CHECK FOR CHANGES

;DO "SET" BITS IF REQUESTED

60$:	CMP	#1,R1			;DOES HE WANT A SET BITS ?
	BNE	70$
	BIS	R0,DB.DCS(J)		;SET BITS
	BR	90$			;AND NOW DONE

;DO "CLEAR" BITS IF REQUESTED

70$:	CMP	#2,R1			;WANT TO CLEAR BITS ?
	BNE	80$
	BIC	R0,DB.DCS(J)		;CLEAR THE BITS LIKE BEFORE
	BR	90$			;NOW DONE


;ILLEGAL STATUS FUNCTION

80$:
.IF EQ DGUTS
	TRAP
.IFF
	TST	(P)+			;GET STACK BACK INTO SYNC
	CTYMSG	NCL			;LOG BAD NCL MSG ERROR
	RTS	PC			;AND EXIT
.ENDC ;.IF EQ DGUTS

;CHECK FOR STATUS CHANGES

90$:	TRACE	DV
	MOV	DB.DCS(J),R0		;COPY OF NEW STATUS
	CMP	(P)+,R0			;DID DEVICE CONTROL STATUS CHANGE?
	BEQ	95$			;NO, ALL SET
	BIS	#DS.XDS,@J		;YES, SEND -10 OUR NEW STATUS
95$:	RTS	PC
.IF NE FTHOST
;HERE TO FIND A HOST (E.G., FOR A TTY)
;CALL	JSR PC,FNDHST WITH J SETUP
;	JSR PC,FNDPFH TO FIND THE GUY'S PREFERED HOST
;	RETURN WITH ZBIT SET IF LOSE

FNDPFH:
.IF NE FT.RNN
	MOVB	DB.RNN(J),R0		;GET THE RESTRICTED NODE NUMBER
	BEQ	10$			;IF NONE, TRY THE PREFERRED HOST
	JSR	PC,FNDSCB		;TRY TO FIND THE RESTRICTED HOST
	BEQ	9$			;IF IT'S NOT THERE, TOUGH LUCK
	BIT	#SBF.IC,@SB		;ARE WE IN CONTACT?
	BEQ	9$			;NO, GIVE UP
	BIT	#SF.MCR,@SB		;DOES HE HAVE AN MCR?
9$:	RTS	PC
10$:
.ENDC ;FT.RNN
.IF NE FT.PFH				;IF WE'RE TRYING FOR A PREFERED HOST
	MOVB	DB.PFH(J),R0		;  GET THE NUMBER OF THE HOST
	BEQ	FNDHST			;IF NONE, JUST TRY NORMAL FNDHST
	JSR	PC,FNDSCB		;SEE IF THE HOST EXISTS
	BEQ	FNDHST			;  IF NOT, HUNT FOR SOME OTHER
	BIT	#SBF.IC,@SB		;IF WE ARE NOT IN CONTACT
	BEQ	FNDHST			;  DON'T USE THIS GUY
	BIT	#SF.MCR,@SB		;IF HE DOESN'T SUPPORT TERMINALS,
	BEQ	FNDHST			;  DON'T USE HIM EITHER
	RTS	PC			;RETURN WITH ZBIT CLEAR
.ENDC ;FT.PFH

FNDHST:
.IF NE FTDL10!FT.DTE
	MOV	TENSCB,SB		;GET OUR -10'S SCB
	BEQ	10$			;DON'T HAVE NEIGHBORING -10
	BIT	#SBF.IC,@SB		;PROTOCOL UP YET?
	RTS	PC			;RETURN WITH/OUT AN SCB
.ENDC ;.IF NE FTDL10!FT.DTE
10$:	MOV	HOSTES,SB		;GET SCB WE LAST CONNECTED TO
	BNE	16$			;AND USE NEXT SCB
12$:	MOV	#FIRSCB,SB		;IF HAVEN'T DONE BEFORE USE FIRST
14$:	BIT	#SBF.IC,@SB		;ARE WE IN CONTACT ?
	BEQ	16$			;DON'T USE UNKNOWN NODES
	BIT	#SF.MCR,@SB		;DOES IT HAVE MCR ?
	BNE	17$			;IF HAS MCR USE IT
16$:	SB.ADV	14$			;GET ADR OF NEXT SCB
	TST	HOSTES			;DID WE TRY EVERYONE ?
	BEQ	90$			;IF SO USERS LOSES
	CLR	HOSTES			;FLAG COMPLETE SCAN
	BR	12$			;TRY AGAIN FROM TOP
17$:	MOV	SB,HOSTESS		;REMEMBER WHO WE WENT TO LAST
90$:	RTS	PC
.ENDC ;.IF NE FTHOST

.ENDC ;.IF NE DEVN