Google
 

Trailing-Edge - PDP-10 Archives - CFS_TSU04_19910205_1of1 - update/ietsrc/xtencm.p11
There are 5 other files named xtencm.p11 in the archive. Click here to see a list.
.SBTTL	XTENCM - PDP-10/20 interface common code

;	NOTE: this module contains all the common code for supporting the
;	      PDP-10 interface. it works only with the new Xdriver modules
;	      and features smaller, higher performance design plus more legroom
;	      for the rest of the system.

.REPT 0


                          COPYRIGHT (c) 1982,1981,1980, 1979
            DIGITAL EQUIPMENT CORPORATION, maynard, mass.

THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE AND WITH THE
INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR  ANY  OTHER
COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
TRANSFERRED.

THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE  WITHOUT  NOTICE
AND  SHOULD  NOT  BE  CONSTRUED  AS  A COMMITMENT BY DIGITAL EQUIPMENT
CORPORATION.

DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF  ITS
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.

.ENDR
;	REVISION HISTORY

; 4(001) 10-OCT-80 RLS
;	INITIAL CREATION. BASED ON VERSION 4(030) OF HDTE10 CODE BUT 90%
;	 REPLACED.

; 4(002) 17-Nov-80 KR
;	Fix GETCM to decrement TCIMC for 2780/3780 flow
;	control (WACKO).

; 4(003) 11-MAR-81 RLS
;	Make LINABO clear LS.ENB when it sets LF.DIS - the dte error now disables
;	the line.

; 4(004) 20-MAR-81 RLS
;	Check for input/output running in TREAD/TWRITE an reject request if not.

; 4(005) 01-APR-81 RLS
;	Reflect fact that TCCMSG,TCDMSG now in global storage instead of TENTSK tcb.

; 4(006) 07-Apr-81 RLS
;	Changes to reflect use of message header for data storage.
; 4(007) 17-APR-81 RLS
;	Transform static flow control to static/line control
; 4(010) 21-MAR-82 RLS	GC0 4.2.1285
;	Don't clear device active bit in TREAD if abort or eof set.
; 4(011) 15-APR-82 RLS	GCO 4.2.1322
;	Set retry count parameter in line block at enable time.
; 4(012) 26-APR-82 RLS	GCO 4.2.1334
;	set default device characteristics in BLDTCB
; 4(013) 18-JUN-82 RLS GCO 4.2.1392
;	do input abort processing simlilar to input eof.
; 4(014) 11-JUL-82 RLS GCO 4.2.1434
;	go pioff and become TENTSK in QDRAIN long enough to DEQMID a message.
; 4(015) 15-JUL-82 RLS GCO 4.2.1449
;	QDRAIN forgot to do 1 more level of indirect to reference hasp device
;	queues.
; 4(016) 20-AUG-82 RLS GCO 4.2.1496
;	in BLDTCB initialize fcs bits to allow io.

VTENCM=016


VEDIT=VEDIT+VTENCM
	.SBTTL		xmodule interface definitions

;in driver tcb:

;T.HDR:				;beg of arg block from xdriver
;T.FN:	.BLKB	1		;primary function code - tentsk dispatches on it
;T.RES:	.BLKB	1		;result code returned to ten
;T.DEV:	.BLKB	1		;device(0 for 2780/3780,component code for hasp)
;T.LIN:	.BLKB	1		;line number
;T.LNG:	.BLKW	1		;requested number of bytes to transfer

;xdriver functions called

;DLRESP		- called to initiate a response to a ten request
;
; args:		R0/result code to return
;		R1/transfer size to return
;
; returns:	carry clear if all copasetic
;		carry set if ten down

;BLECHI,BLECHO	- read from,send to ten a string
;
; args:		R0/byte count
;		R1/beginning byte ptr
;
; returns:	carry clear, R0/updated byte count
;			     R1/updated byte ptr
;			     condition codes reflect "TST R0"
;		carry set if fatal error has occurred(ten dead,protocol error)

;BYTCHI,BYTCHO	- 1 byte xfer from,to ten
;
; args:		R0/byte (out to ten)
;
; returns:	carry clear,Z clear - byte transferred:  R0/byte (input from ten)
;		carry clear,Z set - byte not transferred
;		carry set if mortally wounded
;
; note:	calls to BYTCHI,BYTCHO should be checked on return:
;	BCS	<ten dead error>
;  followed by
;	BEQ	<no character xferred error>
;  or	BNE	<character xferred>


	.SBTTL		XTENCM conventions

;general register usage

;R5/task tcb - the xdriver task normally
;R4/lcb associated with request(line specified)
;R3/xlate tcb(for dev specified),chunk or msg ptr - context dependent
;R2/requested transfer size for read,write functions
;R0,R1 may be freely used, others are safe over function calls unless
; specificially set as a return value.

;function returns: usually carry clear,response code set in t.res. carry set
;		   will cause TENTSK to abort things.
;		   carry is used for success(clear)/failure(set) for internally
;		   called functions.


	.SBTTL		XTENCM parameters


;device defintions

DV.COU	=	1		;console output device
DV.CIN	=	2		;console input device
DV.CDR	=	3		;card reader
DV.LPT	=	4		;line printer
DV.PUN	=	5		;card punch

;	note:	these definitions are used only in XTENCM - the rest of the
;		fe code still uses absolute numbers!!


;result codes returned to ten

TR.SUC	=	1		;success response - request filled(nearly always)
TR.DLY	=	2		;delay response - some data transfer may have 
				; been done
TR.REJ	=	3		;request rejected - no data transferred


				; the following are not now returned but 
				; ought to be...maybe someday.

TR.EOF	=	4		;input end of file - last data transferred
TR.ABO	=	5		;input abort - available data transferred
TR.LGA	=	6		;line gone away - available data transferred
	.SBTTL		TENTSK - pdp-10 interface task


; this task interfaces to the pdp-10 through the device specific functions

TENSNZ:	DSCHED	#EBTENI		;wake only if something to do

TENTSK:	TST	TENALV		;check if 10 has ever come to life
	BEQ	TENSNZ		;no - nothing to do
	TST	DLGONE		;is 10 already dead?
	BNE	15$		;yes - go process ten death
	CLR	R1
	BISB	T.FN(R5),R1	;get primary function code
	BEQ	TENSNZ		;no - yawn
	CLRB	T.FN(R5)	; no current header

.IF NE,FTRACE
	CLR	R0		;trace args
	BISB	T.LIN(R5),R0
	CLR	R2
	BISB	T.DEV(R5),R2
	TRACE	TRCTEN,<R1,R0,R2,T.LNG(R5)> ;trace op code,line,device,length
.ENDC	;.IF NE,FTRACE

	MOV	#TENDSP,R0	;get the primary function code dispatch table
	CALL	DLDISP		;dispatch to primary function processor
	BCS	15$		;fatal error

10$:	CLR	R0		; get the result code and xfer amt
	BISB	T.RES(R5),R0
	MOV	T.LNG(R5),R1	; and the amount we want to declare
	CALL	DLRESP		;end the operation
	BCS	15$		;10 has crashed
	BR	TENTSK		;go do something else

; here on fatal protocol error or 10 crashed

15$:				;ten really dead - flush all lines

.IF NE,DEBUG
	BIT	#TRCTER,TRCHLT	;stop on pdp-10 error?
	BEQ	16$		;no.
	STOPCD	TER		;yes, pdp-10 error
16$:
.ENDC ;.IF NE,DEBUG


	CALL	DTCERR		;disable the lines
	BR	TENSNZ		;wait for another command
	.SBTTL		TENTSK wake ups for interface driver use

WAKFNC:	SAVE	R5		; R1/ptr to new header block from ten
	MOV	TCDLDR,R5	; get the tentsk tcb
	BNE	10$		; make sure it hasn't disappeared
	STOPCD	TEN		; curious mode

10$:	MOVB	(R0)+,T.FN(R5)	; xfer header data to task block
	MOVB	(R0)+,T.RES(R5)	; which is naturally oraganized the same as
	MOVB	(R0)+,T.DEV(R5)	; the header block
	MOVB	(R0)+,T.LIN(R5)
	MOVB	(R0)+,T.LNG(R5)
	MOVB	(R0)+,T.LNG+1(R5)

	RESTOR	R5

WAKTEN:	TST	TCDLDR		; wake tentsk
	BNE	10$
	STOPCD	TEN		; rather gross

10$:	SIGNAL	TCDLDR,EBTENI	; wake the interface task
	RETURN
	.SBTTL		DLDISP - table dispatcher

; subroutine to call a subroutine based on an index.
;  this is used as a dispatcher.
;
;	R0 = pointer to dispatch table.  the first entry is
;	     the max index, the remainder being pointers
;	     to subroutines.
;	R1 = index, 0 based.
;
; dispatch table format:
;
;	word	0/offset to 1st location beyond legal dispatches
;	words 1-n/legal dispatch addresses
;	word n+1 /illegal function code dispatch address
;
;	zero dispatch entries take the illegal code dispatch
;
;	all returned values and conditions are set by the dispatch function
;
;	note: function code of 0 is illegal by default

DLDISP:	ASL	R1		; get word offset
	BLE	20$		; illegal function code
	CMP	R1,(R0)		; check upper bound
	BLT	25$		; legal range
20$:	MOV	(R0),R1		; get the offset to illegal dispatch
25$:	ADD	R0,R1		; get the dispatch cell adr
	MOV	(R1),R1		; get the dispatch address
	BEQ	20$		; ignore possible loop
	TRACE	TRCTEN,R1	;trace dispatch address
	JMP	(R1)		; dispatch to function
	.SBTTL		TENDSP	- primary function code dispatch table

TENDSP:				; dispatch table for pdp-10 initiated operations

15$:	.WORD	<16$-15$>	; offset to illegal fucntion code dispatch
	.WORD	TREAD		;1=read data into the pdp-10
	.WORD	TWRITE		;2=write data from the pdp-10
	.WORD	DEVSTS		;3=read device status
	.WORD	DEVCMD		;4=write device command
	.WORD	LINSTS		;5=read line status
	.WORD	LINCMD		;6=write line command
	.WORD	PRTSTS		;7=read dn60 status
	.WORD	PRTCMD		;8=write dn60 command
	.WORD	0		;9=examine 11 location - device driver fcn
	.WORD	0		;10=deposit in 11 location  - device driver fcn

16$:	.WORD	RETREJ		;illegal primary function code - reject it
	.SBTTL		DTCERR - port abort, flush everything

; here on pdp-10 protocol error.
;  abort all streams and disable all lines.

DTCERR:				;error return for set dev and line

.IF NE,DEBUG
	BIT	#TRCTER,TRCHLT	;stop on pdp-10 errors?
	BEQ	11$		;no.
	STOPCD	TER		;yes, pdp-10 error
11$:
.ENDC ;.IF NE,DEBUG

	MOV	#NLINES,R1	;number of lines possible
	MOV	#LINTBL,R2	;start with line 0
12$:	MOV	(R2)+,R4	;get the lcb
	BEQ	15$		;no such line
	CALL	LINABO		;abort this line
15$:	SOB	R1,12$
	SEC			;signal failure
	RETURN
	.SBTTL		LINABO	- abort a line


; args:		R4/lcb of line to abort
;
; returns:	nothing in particular


LINABO:	BIT	#LF.DIP,LB.FGS(R4) ;check if line disable in progress
	BNE	16$		;yes - treat as already done
	BIT	#LS.ENB,(R4)	;don't bother unless line is enabled
	BEQ	15$		;but make sure the modem is off

	ATRACE	<(SP),R4>

.IF NE,DEBUG
	BIT	#TRCABO,TRCHLT	;check if we want to die instantly
	BEQ	1$
	STOPCD	DBG
1$:
.ENDC	;.IF NE,DEBUG
	SAVE	<R1,R2,R3,R4>	;save all the safe regs

12$:	CALL	DISLN0		;disable the line
13$:	RESTOR	<R4,R3,R2,R1>

15$:
16$:	RETURN
	.SBTTL		PRTSTS -   read DN60 status

PRTSTS:	MOV	T.LNG(R5),R2	;get the req size
	BEQ	RETREJ		;ten doesn't want to know very much
	CLR	T.LNG(R5)	; init amount xferred
	MOV	#D60ST1,R1	;where the port status info begins
	MOV	#D60ST2,R0	;point to beyond last last word
	SUB	R1,R0		;how big it is
	CALL	XCHKSZ		;check req/arg size
	CALL	BLECHO		;send the cruft
	BCS	RETFAL		;tendeath
	BNE	RDLYX0		;no partials allowed

RETSUC:	MOVB	#TR.SUC,T.RES(R5) ;suc exit

SETSUC:	CLC			;make it suc
	RETURN

RDLYX0:	CLR	T.LNG(R5)	;special delay with no return

RETDLY:	MOVB	#TR.DLY,T.RES(R5) ;delayed return
	BR	SETSUC

RETREJ:	MOVB	#TR.REJ,T.RES(R5) ;reject return
	CLR	T.LNG(R5)	;no data on reject
	BR	SETSUC

RETFAL:	CALL	RETREJ		;return for xdriver errors

SETERR:	SEC			;make a failure
RET:	RETURN

XCHKSZ:	CMP	R0,R2		;common recursor to BLECHI,BLECHO
	BLE	10$		;use smaller of available or requested
	MOV	R2,R0		;use requested
10$:	ADD	R0,T.LNG(R5)	;optimistically update the bytes transferred
	SUB	R0,R2		;reduce requested amt not done
	RETURN

GETLN:	CLR	R0		;get line from ten request and validate it
	BISB	T.LIN(R5),R0
	CMP	NSLINS,R0	;do we have that many lines
	BLE	SETERR		;no - barf
	BR	SETSUC		;yes - be agreeable

GETLB:	CLR	R4
	CALL	GETLN		;get the lcb for line specified in request
	BCS	RET		;nonesuch
	ASL	R0		;word offset
	MOV	LINTBL(R0),R4	;return lcb in r4
	BEQ	SETERR		;no entry for this line - lose
	MOV	R4,TCLCB(R5)	;save the lcb in case we need it later
	BR	SETSUC		; and suc!

GTLBEN:	CALL	GETLB		;get the lcb and make sure line is enabled
	BCS	RET		;no lcb
	BIT	#LF.DIP,LB.FGS(R4) ;check if line disable in progress
	BNE	SETERR		;yes - treat as already done
	BIT	#LS.ENB,(R4)	;lcb exists - check line up
	BNE	SETSUC		;yes - suc
	BR	SETERR		;no - lose

GETXLT:	CALL	GETDEV		;find the xlate tcb for line,,dev
	BCS	RET
	ASL	R1		;r1/generic device number
	ADD	R4,R1		;word offset into block of tcb's in lcb
	MOV	LB.TCD(R1),R3	; get the task block
	BEQ	SETERR		;none - lose
	MOV	R3,TCXLT(R5)	;save it for later
	BR	SETSUC		;and return in r1

GENDEV:	MOVB	T.DEV(R5),R1	;get generic device number specified
	BIC	#177770,R1	;lo 3 bits relevant
	RETURN

WRDARG:	CALL	BYTCHI		; get a word arg from driver
	BCS	15$
	BEQ	15$		; no input available
	MOV	R0,-(SP)	; save the low order byte
	CALL	BYTCHI
	BCS	9$
	BEQ	14$		; no input in the middle
	SWAB	R0		; shift the high byte
	BISB	(SP)+,R0	; put it together
	CLRC	CZ		; carefully set the exit conditions
	RETURN

9$:	MOV	(SP)+,R0	; return the lo byte for what it's worth
10$:	BR	SETERR		; return false

14$:	MOV	(SP)+,R0	; return the half-assed result
	CLC
	SEZ
15$:	RETURN


TWAT:	SAVE	<R0,R1,R2,R3,R4> ; save thee registers cause the WAIT 
	CALL	WAIT		; routine isn't smart enough
	RESTOR	<R4,R3,R2,R1,R0>
	RETURN
	.SBTTL		TREAD - read data (into the ten)

; subroutine to perform the "read data" function.
;  message que is examined for a message from that line
;  and if one is found it becomes current message.

TREAD:	CALL	GTLBEN		;get the lcb/enabled
	BCS	35$		;no, lose.
	CALL	GETXLT		;find the xlate task
	BCS	36$		;curious
	MOV	T.LNG(R5),R2	; get the request size
	CLR	T.LNG(R5)	;init the amt xferred
	TRACE	TRCTEN,<R3,R2,TCFG2(R3)>

11$:	CALL	GENDEV		; get the device number
	CALL	GETCM		;get current or new message
	BCS	22$		;no message for the id.
				;r3/msg ptr
12$:	MOV	MSGLCH(R3),R1	;get pointer to the current chunk
	BEQ	21$		;end of message found

	TST	R2		;have we finished?
	BLE	19$		;yes - depart
	MOV	(R1)+,T.CMSG(R5) ;save pointer to next chunk
	MOV	(R1),R0		;get count, point to data
				;r0/# bytes left in chunk
	BEQ	17$		;check for empty chunk
	MOV	MSGPTR(R3),R1	;get ptr to next byte to send

; the following is the register allocation for tread:

; R0/#bytes in chunk available
; R1/ptr into chunk
; R2/requested bytes not done
; R3/current msg ptr
; R4/lcb
; R5/TENTSK tcb
; MSGLCH(R3)/current chunk to be sent
; MSGPTR(R3)/current byte to be sent


15$:	CALL	XCHKSZ		;get right size
	TRACE	TRCTEN,<R4,R0,R1,R2,R3>
	CALL	BLECHO		;send some bytes to ten
	BCC	16$
	JMP	RETFAL		;oops!

16$:	SUB	R0,T.LNG(R5)	;adjust by amount not xferred - may be 0
	ADD	R0,R2		; also amt requested not done
	MOV	MSGPTR(R3),R0	;get beg output ptr
	MOV	R1,MSGPTR(R3)	;save updated ptr
	SUB	R1,R0		;R0/-<number chars xferred>
	MOV	MSGLCH(R3),R1	;get the current chunk
	ADD	R0,CHLEN(R1)	;update byte count for chunk
	BGT	19$		;if not zero, we can't do more now

17$:	MOV	T.CMSG(R5),R1	;emptiness - get adr of next chunk in message
	MOV	R1,MSGLCH(R3)	;save in message header
	ADD	#CHDAT,R1	;build data pointer
	MOV	R1,MSGPTR(R3)	;save new data pointer
	BR	12$		;send next chunk

19$:	JMP	RETSUC		;report suc since we do have more data


; here on end of message

21$:	MOV	R3,R0		;get the hollow hulk
	CALL	FREMSG		;flush the msg
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BNE	33$		;no.
	CLR	@TCPDM(R5)	;clear device message ptr
	BR	11$		;join the main loop
.ENDC				;.IF NE,FT.HSP

33$:	CALL	GTCBMO		;get 2*line number in r1
	CLR	TCCMSG(R1)	;we have no current message
	BR	11$		;find next message and sent to ten

; here if there is no message for that line

22$:	TST	T.LNG(R5)	;no data - did we xfer any?
	BGT	25$		;yes - delay return
	MOV	TCXLT(R5),R3	;point to xlate task
	BIT	#TCIAC!TCIEC,TCFG2(R3) ;eof or abort?
	BNE	37$		;yes - reject(gets attention)

23$:	BIT	#TCIRN,TCFG2(R3);if input not running should not be doing data
				; transfers
	BEQ	36$		;reject the request

24$:	CALL	CLRDAC		;clear the device active bit

25$:	JMP	RETDLY		;delay

35$:	TST	R4		; here if not enabled line
	BEQ	37$		; check for any lcb and clear dev active if possible

36$:	CALL	CLRDAC		;clear the device active bit

37$:	JMP	RETREJ		;send reject to ten
	.SBTTL		CLRDAC - clear device active bit


CLRDAC:	SAVE	<R0,R1,R3>	;R4/lcb
	CALL	GETDEV		; get the generic device no.
	BCS	30$		; can't do anything
	TST	R1		;check for zero device number
	BNE	35$		;non zero, hasp device
	MOV	TCXLT(R5),R3	;2780/3780 - get xlate task
	BIT	#TCOPR!TCOPG!TCORN!TCOEF!TCOEC!TCOAB!TCOAC,TCFG2(R3)
	BNE	20$		;branch if device is doing output
				;input
	CALL	CACTI		;clear input active
	BR	30$

20$:	CALL	CACTO		;clear output active

30$:	RESTOR	<R3,R1,R0>
	RETURN

35$:	CALL	HCLRAC		;clear hasp device active
	BR	30$
	.SBTTL		GETCM - find next message to be read by the 10

; this subroutine looks for a current message and if )
; none is found, gets oldest message with the id.
;
; R1/device number
;
; R3/msg ptr on success return

GETCM:	MOV	R2,-(SP)
	MOV	R1,R2		; keep dev*2 over here
	ASL	R2
	CALL	GTCBMO		;get device msg que offset in r1

.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BNE	13$		; no
	MOV	TCCMSG(R1),R1	;get ptr to dev msg q = block of dev msg q's
	BNE	12$		;there's one
	SEC			;strange
	BR	16$

12$:	ADD	R2,R1		;get device msg ptr
	MOV	R1,TCPDM(R5)	;save ptr to dev msg
	MOV	(R1),R3		;any device message?
	BNE	17$		;yes.
	MOV	TCXLT(R5),R3	;point to device's tcb
	MOV	TCCTP(R3),R1	;get the rcb 
	MOV	LB.LNU(R4),R3	;get line #
	SWAB	R3		;put in left byte
	ADD	R3,R1		;make i.d. for the message
	CALL	30$		;look for a message
	BCS	16$
	CALL	BSCFLO		;check bsc flow control

	MOV	R3,@TCPDM(R5)	;save device msg ptr
	BR	17$
.ENDC				;.IF NE,FT.HSP

13$:	MOV	TCCMSG(R1),R3	;is there a current message?
	BNE	17$		;yes, continue with it.
	MOV	LB.LNU(R4),R1	;get line # (i.d. for 2780/3780)
	CALL	30$		;look for a message
	BCS	16$		;no message for this i.d.
	MOV	R3,TCCMSG(R1)	;remember current message

17$:	CLC			;successful
16$:	MOV	(SP)+,R2
20$:	RETURN

30$:	CALL	DEQMID		;get oldest msg with that id
	BCS	20$		;there is none.
	MOV	R0,R3		;put it in the right place
	MOV	TCXLT(R5),R2	;point to xlate task
	DEC	TCIMC(R2)	;decrement count of input messages
				;restore line number before returning

GTCBMO:				;get device msg que offset in r1
	MOV	LB.LNU(R4),R1	;get line number
	ASL	R1		;line number * 2
	RETURN
	.SBTTL		TWRITE - write data (from ten to remote)

; subroutine to perform the "write data" function.  data is
;  fetched through the dte20 and placed in chunks.  the chunks
;  are sent to the xlate task for translation and subsequent
;  queueing to the line driver


TWRITE:	CALL	GTLBEN		;get an enabled lcb - r4
	BCS	14$		;too bad
	CALL	GETXLT		; get the xlate task - r3
	BCS	14$		;tsk!
	MOV	T.LNG(R5),R2	; get the req size
	CLR	T.LNG(R5)	;init amount xferred
	CLR	TCXFR(R5)	; init count of chunks q'd to xlate this pass

10$:	TRACE	TRCTEN,<R3,R2,TCFG2(R3)>

11$:	MOV	TCXLT(R5),R3	;get the xlate task
	BIT	#TCOAB!TCOAC,TCFG2(R3)	;check if aborting
	BNE	14$		;yes - no sense in writing anything

	BIT	#LF.SIM,LB.FGS(R4);if emulation
	BNE	12$		;don't require following conditions
				;termination - don't trust him
	BIT	#TCORN!TCOPG,TCFG2(R3);make sure output running
	BEQ	14$		;reject the request

12$:	CALL	OUTFLO		;check if device is suspended or chunks low
	BCC	20$		;no - cramituem
				;yes - can't handle it now
	TRACE	TRCFLO,<R3,TCFG2(R3),LB.FRE(R4),LB.RES(R4),TCXFR(R5)>
				;CHECK FOR BAD REASONS
15$:	BIT	#TCOAB!TCOAC,TCFG2(R3) ;has stream been aborted?
	BNE	14$

13$:	JMP	RETDLY		;no,indicate delayed operation

14$:	JMP	RETREJ		;operation rejected

20$:	CALL	GETCHK		;can do some output
	BCS	13$		;except that we can't after all
	MOV	R0,R1
	MOV	R0,R3		;put chunk ptr in usual place
	ADD	#CHDAT,R1	; make byte ptr
	MOV	#CHDATL,R0	;space available
	CALL	XCHKSZ
	MOV	R0,CHLEN(R3)	;be optimistic
	CALL	BLECHI		;get some bytes
	BCS	55$		;10 death
	BGT	40$		; did it all go?
	CALL	50$		; yes - q the chunk

30$:	TST	R2		;are we done?
	BGT	11$
35$:	JMP	RETSUC		;done

40$:	SUB	R0,T.LNG(R5)	; sub amt not received from total
	ADD	R0,R2		; also amt requested not done
	SUB	R0,CHLEN(R3)	; and from chunk amt
	BGT	45$		; did anything happen?
	MOV	R3,R0		;no transfer happened
	CALL	FRECHK		;flush the chunk
	BR	13$		;delay

45$:	CALL	50$		;chunk did not fill - q it
	BR	35$		;and suc

50$:	MOV	R3,R0		;what to do with a nonempty chunk
	MOV	TCXLT(R5),R1
	INC	TCXFR(R5)	;count the chunks queued to xlate this time
	ADD	#TXLN,LB.RES(R4);reserve enough chunks to translate
	JMP	QUECHK		;queue the chunk to the xlate task

55$:	MOV	R3,R0		; ten died - return the chunk
	CALL	FRECHK
	SEC
	RETURN
	.SBTTL		DEVSTS - read device status

; subroutine to perform the "read device status" function.
;  the status message is assembled in a buffer and sent to-ten
;  as indirect data.  no exceptional conditions are possible.

DEVSTS:	CALL	GTLBEN		; get an enabled lcb
	BCS	30$		; to bad
	CALL	GETXLT		; some hope - get the xlate tcb
	BCS	30$
	MOV	T.LNG(R5),R2	; get the request size
	BEQ	30$		; this is an easy one!
	CLR	T.LNG(R5)	; init amount xferred
	TRACE	TRCTEN,<R3,R2,TCFG2(R3)>
	MOV	#DVSTSB,R0	; get the staging area

	MOVB	TCDVT(R3),(R0)+	;get device type
	MOVB	TCCTP(R3),(R0)+	;get component type
	MOV	TCPGC(R3),(R0)+	;get page count register
	MOV	TCFG1(R3),(R0)+	;get flags word 1
	MOV	TCFG2(R3),(R0)+	;get flags word 2
	MOV	TCRSZ(R3),(R0)+	;get record size for  the device
	MOV	LB.FGS(R4),(R0)+ ;get the line flags 
	MOV	LB.SIG(R4),(R0)+ ;get the line signature 
				;device status now collected
	MOV	#DVSTSB,R1	;ptr to it
	SUB	R1,R0		;how much
	CALL	XCHKSZ		;set xfer size
	CALL	BLECHO		;send it
	BCC	20$
15$:	RETURN			; 10 gasping

20$:	BNE	25$		;don't send partials
	JMP	RETSUC

25$:	JMP	RDLYX0		;send 0 xfer delay

30$:	JMP	RETREJ		;send arrogant reply


DVSTSB:	.BLKW	7		; the amount needed
	.WORD	0		; overrun catcher and detector
	.SBTTL		LINSTS	- read line status

; subroutine to perform the "read line status" function.
;  if the line is not initialized, give a 0-length reply

LINSTS:	CALL	GETLN		; validate line number
	BCS	30$		; if out of range, go reject
	MOV	T.LNG(R5),R2	; get the req size
	CLR	T.LNG(R5)	; init the xferred data count
	ASL	R0		; make word index for line
	MOV	LINTBL(R0),R4	; check for line block
	BEQ	25$		; if it doesn't exist, it is disabled
	MOV	R4,TCLCB(R5)	; remember line block
	TRACE	TRCTEN,<R4,R2,(R4)>

	MOV	#LNSTSB,R0	; the staging area for scattered data
	MOVB	LB.DVT(R4),(R0)+ ; get terminal type
	MOVB	LB.FGS(R4),(R0)+ ; get line flags 
	MOVB	LB.FGS+1(R4),(R0)+ ; and the high byte also

	CLR	R1		;generate info flags
	BIT	#LS.ENB,(R4)
	BEQ	9$
	BIS	#B0,R1		;indicate line is enabled
9$:	BIT	#LF.TSP,LB.FGS(R4) ;output transparent?
	BEQ	10$		;no.
	BIS	#B3,R1		;hope nobody else uses bit 3
10$:	MOV	R0,-(SP)	; save buf ptr
	MOV	R4,R0		; get lcb arg
	CALL	@LB.DTS(R4)	; set dtr and dsr into r1
	MOV	(SP)+,R0
11$:  	MOVB	R1,(R0)+	; stuff the line info
				; send this much separately
	MOV	#LNSTSB,R1	; where it is
	SUB	R1,R0		; how much
	CALL	XCHKSZ		; size check
	CALL	BLECHO		; send it
	BCS	69$		; losing anyhow
	BNE	40$		; can't get very far

				; include line statistics

	MOV	#LB.ST1,R1	; where they are
	MOV	#LB.ST2+2,R0
	SUB	R1,R0		; how much
	ADD	R4,R1		; in the lcb
	CALL	XCHKSZ		; set the xfer size
	CALL	BLECHO		; and send them too
	BCC	20$
69$:	RETURN			; our world is crumbling

20$:	BNE	40$		; no partials
25$:	JMP	RETSUC		; suc'd

30$:	JMP	RETREJ		; thumb node at ten

40$:	JMP	RDLYX0		; no partials allowed


LNSTSB:	.BLKW	2		; the amount needed
	.WORD	0		; overrun catcher and detector
	.SBTTL		PRTCMD	- write port command

; subroutine to perform the "write dn60 command" function.
;  the first byte of the data is the function code, if other
;  data is needed it follows the function code.

PRTCMD:
	JMP	RETREJ		; no defined port commands
	.SBTTL		LINCMD	- write line command

; subroutine to perform the "write line command" function.
;  THE FIRST BYTE OF THE DATA IS THE FUNCTION CODE, IF OTHER
;  data is needed it follows the function code.
;
; line commands which require an enabled line are called with r4/lcb
;  if line up. reject returned otherwise.
;
; line commands set the proper response code

LINCMD:	CALL	BYTCHI		; get the command
	BCS	40$
	BEQ	25$		; no arg ?
	MOV	LNCDSP,R1	; get the offset to illegal command
	ASL	R0		; special check for commands requiring enabled
				;  line to execute
	BLE	10$		; illegal
	CMP	R0,R1
	BLE	20$
10$:	MOV	R1,R0		; dispatch to illegal command processor

20$:	MOV	LNCDSP(R0),R0	; legal offset - check implemented command
	BEQ	10$
	CMP	#ENBLIN,R0	; check for commands not requiring enabled line
	BEQ	30$		; enable is one
	CMP	#DISLIN,R0	; disable is another
	BEQ	30$
	SAVE	R0		; save dispatch over gtlben call
	CALL	GTLBEN		; get an enabled line
	RESTOR	R0		; get dispatch back
	BCC	31$		; ok to go

25$:	JMP	RETREJ		; no - reject the command

30$:	ATRACE	<R0,R4>		; always trace enable,disable
.IIF NE,FTRACE,	BR	32$

31$:	TRACE	TRCTEN,<R0,R4>	; remember where we went if debugging

32$:	CALL	(R0)		; dispatch to command processor - use call for debugging

40$:	RETURN

LNCDSP:				; line command dispatch table


11$:	.WORD	<12$-11$>	;offset to illegal code dispatch
	.WORD	ENBLIN		;1 = enable
	.WORD	SETDTR		;2 = set dtr
	.WORD	CLRDTR		;3 = clear dtr - abort and hang up
	.WORD	DISLIN		;4 = disable
	.WORD	SETCSD		;5 = set cts delay
	.WORD	SETSLO		;6 = set length of silo warning area
	.WORD	SETTRN		;7 = set output in transparent mode
	.WORD	CLRTRN		;8 = set output in non-transparent mode
	.WORD	SETTBL		;9 = set transmission block length
	.WORD	SETRPM		;10= set records per message
	.WORD	SETSIG		;11= set line signature
	.WORD	SETSON		;12= set station signed on(lf.son)
12$:
	.WORD	RETREJ		; illegal code
	.SBTTL		ENBLIN	- line enable processing

; subroutine for line command 1: enable the line

ENBLIN:	CALL	GETLN		; get the line number
	BCC	1$
	JMP	RETREJ		; one we don't know about

1$:	ASL	R0
	MOV	LINTBL(R0),R4	;already a line control block?
	BEQ	24$		;something is screwed up for sure

11$:	BIT	#LF.DIP,LB.FGS(R4) ;check if line disable in progress
	BNE	18$		;yes - treat as already done
	BIT	#LF.EIP,LB.FGS(R4) ;check if enable in progress
	BNE	10$		;yes - skip disabling checks
	BIT	#LS.ENB,(R4)	;is the line enabled?
	BNE	24$		;yes, can't enable it again.
				; check for disable completed

	BIT	#LF.DAC, LB.FGS(R4) ; did bsc disable the line ?
	BEQ	18$		;no, give delayed return

10$:	MOV	LB.TC1(R4),R0	;get pointer to bsc task
	BEQ	26$		;no bsc, exit
	MOV	TCBP2,R3	;r3 must point to start of chain
	CALL	RELTCB		;release tcb and unlink from chain
	MOV	R3,TCBP2	;update start of chain of tcbs

26$:				;clean up lcb

	MOV	#NDHASP+1,R2	;get number of xlate tcbs + bsc tcb
	MOV	R4,R1		;point to lcb 4(024)
	ADD	#LB.TC1,R1	;start with bsc task
27$:	CLR	(R1)+		;clear xlate tcb pointer in lcb
	SOB	R2,27$
	CALL	MAKLB		;now init the line block
25$:
	MOV	R4,TCLCB(R5)	;remember lcb 
	CALL	BYTCHI		;get device type
	BCC	17$		;none specified
5$:	RETURN

17$:	BEQ	24$		; arg deficiency is rejectionable
	MOV	R0,LB.DVT(R4)	;store device type
	BEQ	24$		;illegal protocol type
	CMP	R0,#TTHASP	;check range
	BGT	24$		;also illegal
	CALL	BYTCHI		;get characteristics
	BCS	5$		;not specified
	BEQ	24$		; arg deficiency is rejectionable
	MOV	R0,LB.FGS(R4)	;store characteristics
	BIT	#LF.PRI,R0	;primary?
	BNE	12$		;yes.
	MOV	#3*JIFSEC,LB.EQW(R4) ;no, make secondary
	MOV	#SECRTY,LB.ERC(R4) ;set secondary retry count
12$:

.IF EQ,FT.HSP			;check if hasp present

	CMP	#TTHASP,LB.DVT(R4) ;is this a hasp line?
	BEQ	19$		;yes, but hasp not present- error
				;no, continue

20$:
.ENDC			;.IF EQ,FT.HSP

	BIC	#LF.DAC,LB.FGS(R4) ;disable not complete anymore
	BIS	#LF.EIP,LB.FGS(R4) ;enable in progress
	BIS	#LS.ENB,(R4)	;enable the line
	CALL	FLOSHR		;recalculate chunks allocations

	CALL	BLDTCB		;build tcb's for xlate tasks
	BCS	18$		;out of storage

	CALL	GTCBMO		;get 2*line number in r1

.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BEQ	14$		;yes.
.ENDC				;.IF NE,FT.HSP
	CLR	TCCMSG(R1)	;clear it
.IF NE,FT.HSP			;hasp present
	BR	16$		;and exit

; here for hasp line, set device msg ptr

14$:	CLR	R2		;initialize offset in table
	MOV	R1,R0		; calc device msg q adr
	BEQ	32$
	ASR	R0		; get the line number
31$:	ADD	#2*NDHASP,R2	; gen offset to block of q's for line
	SOB	R0,31$
32$:	ADD	#TCDMSG,R2	; tcb offset for this line's block of q's
	MOV	R2,TCCMSG(R1)	;tccmsg entries = ptrs(line) to blocks of dev msg q's
	MOV	#5,R1		;initialize all device msg ptrs
15$:	CLR	(R2)+		;clear msg ptr
	SOB	R1,15$		;cover all device msg ptrs
.ENDC				;.IF NE,FT.HSP

16$:	BIC	#LF.EIP,LB.FGS(R4) ;enable complete and no longer in progress

21$:	JMP	RETSUC		; we did it!

; here if short on storage

18$:	JMP	RETDLY		; delay return


;here if requested a line we do not have

24$:	JMP	RETREJ		; send him refuse

.IF EQ,FT.HSP			;no hasp but hasp line indicated-error

; here if hasp request and no hasp support



19$:	BIS	#LF.DAC,LB.FGS(R4) ;indcate line has been disabled by bsc task
	BR 24$			;no hasp support- return

.ENDC				;.IF EQ,FT.SHP
; subroutine to build the line control block and the
;  task control blocks needed for each  line.
;
; args:	R4/lcb ptr
;
; return:	initialized line block

MAKLB:	CALL	INITLB		;make the line block pure
	MOV	LB.LNU(R4),R0	;get line number
	ASL	R0		;make word offset
	MOV	#1*JIFSEC,LB.EQW(R4) ;time between sending enq's
	MOV	#PRIRTY,LB.ERC(R4) ;default line retry count to primary
	MOV	LB.ERC(R4),LB.EQN(R4) ;number of enq's to send before assuming line is down
	MOV	#MDMXSD,LB.MDS(R4) ;length of silo warning area for kmc11
	MOV	#XBLKDF,LB.MBL(R4) ; set default trnasmission block size
	CALL	DABCLR		;make sure device active bits are off
	RETURN			;return after bulding lcb
;this subroutine builds tcb for the bsc and xlate tasks.
; in 3780/2780 we need only one tcb for xlate task
; while for hasp-multileaving we need 5 tcb's in simulate
; and 4 tcb's in support mode of operation

BLDTCB:	MOV	LB.TC1(R4),R0	;point to bsc tcb
	BNE	10$		;its already set up
	CALL	GETTCB		;get a task control block
	BCC	7$		;got the tcb
	JMP	FLSALL		;out of storage
7$:	MOV	#LINSTR,TCPC(R0) ;store initial address
	CALL	STKINI		;init task stack
	BIS	#BR3,TCPS(R0)	;set priority level to 3
	MOV	R4,TCLCB(R0)	;store lcb pointer
	MOV	R0,LB.TC1(R4)	;store bsc task pointer
	CALL	LDTENV		;load driver entry vectors into task block
	MOV	#104301,TCTFCS(R0);init fcs words
	MOV	#104301,TCRFCS(R0)
	MOV	TCBP2,R1	;medium priority tcb list
	MOV	R0,TCBP2	;put this tcb on the list
	MOV	R1,TCHAIN(R0)	; ...

	BIT	#LF.TSP,LB.FGS(R4) ;check for transparent mode
	BEQ	10$
	BIS	#TCTSP,TCFG1(R0) ;yes - also tell bsc task

10$:	CLR	R2		;clear device # initially
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BEQ	11$		;yes.
.ENDC				;.IF NE,FT.HSP
	CALL	BLDPRO		;set protocol flag for bsc
	MOV	#1,LB.NTC(R4)	; no, set up for 1 tcb for 2780/3780
	CALL	GETTCB		;get a task control block
	BCS	FLSALL		;no room.
	MOV	#XLATE,TCPC(R0)	;store start adr of task
	CLR	TCDEV(R0)	;device is 0 for 2780/3780
	CALL	BLDPRO		;set protocol flag for xlate task

.IF NE,FT.HSP			;hasp present
	BR	13$		;go past hasp settings

11$:	MOV	#4,LB.NTC(R4)	;set up # of tcb's for hasp devices
	BIT	#LF.SIM,LB.FGS(R4) ;sim mode?
	BEQ	12$		;no, 4 tcb for sup mode
	INC	LB.NTC(R4)	;5 tcbs for sim mode
12$:	INC	R2		;make r2 device #
	CALL	GETTCB		;get tcb for xlate task
	BCS	FLSALL		;no room

	MOV	#XLHASP,TCPC(R0) ;set up start adr of task
	MOV	R2,TCDEV(R0)	;and device # in the tcb
.ENDC				;.IF NE,FT.HSP

13$:	BIS	#BR1,TCPS(R0)	;set priority level to 1
	CALL	STKINI		;init task stack
	MOV	R4,TCLCB(R0)	;store lcb pointer
	MOV	R4,R1		;preserve lcb ptr in r4
	ADD	R2,R1		;add device # to get xlate tcb adr
	ADD	R2,R1		; add device # to get xlate tcb adr
	MOV	R0,LB.TCD(R1)	; store comp. pointer
	MOV	TCBP3,R1	; get low-priority tcbs
	MOV	R0,TCBP3	; put this tcb on the list
	MOV	R1,TCHAIN(R0)	; ...

	CALL	DEVINI		;init device characteristics

; here to get storage for line buffer for each device

	BIT	#TCIOM,TCFG1(R0) ;if this is an input mode device
	BNE	14$		;...don't need a line buffer
	CALL	GETPRM		;output device - get storage for it
	BCS	FLSALL		;out of storage
	MOV	TCBP3,R1	;get pointer to xlate tcb
	MOV	R0,TCBFP(R1)	;store pointer to line buffer
	MOV	#CHSIZE,TCBFC(R1) ;store length of line buffer
14$:

.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BNE	15$		;all done for 2780/3780
	CMP	LB.NTC(R4),R2	;done with all devices xlate tcb's
	BNE	12$		;no
.ENDC				;.IF NE,FT.HSP

15$:	MOV	LB.SLV(R4),R1	;get vector address
	MOV	#PR.LIN*40,R0	;get initial ps
	MOV	R4,(R1)		;store pc for interrupt a
	ADD	#LVECRI,(R1)+
	MOV	R0,(R1)+	;store ps for interrupt a
	MOV	R4,(R1)		;store pc for interrupt b
	ADD	#LVECXI,(R1)+
	MOV	R0,(R1)+	;store ps for interrupt b
	CLC			;clear c to flag success
	RETURN

; here if we run out of storage getting a tcb.

FLSALL:	CALL	FLSTCB		;flush everything
	SEC			;set c as a flag
	RETURN

STKINI:	SAVE	R1		;init a task stack
				;R0/task block ptr
				;R4/line block ptr
	MOV	TCSP(R0),R1	;get task stack ptr
	CLR	-(R1)		;KG11/0
	CLR	-(R1)		;R0/0
	CLR	-(R1)		;R1/0
	CLR	-(R1)		;R2/0
	CLR	-(R1)		;R3/0
	MOV	R4,-(R1)	;R4/line block
	MOV	R1,TCSP(R0)	;save updated stack ptr

	CLR	TCCHKQ(R0)	;init the task's chunk queue
	MOV	R0,TCCHK2(R0)
	ADD	#TCCHKQ,TCCHK2(R0) ;make end ptr point to head

	RESTOR	R1
	RETURN

LDTENV:	SAVE	<R0,R1,R2>	;load bsc task block with line  driver entry pts
				;R4/line block ptr
	MOV	LB.TC1(R4),R0	;get bsc task block ptr
	MOV	#T$ENL,R1	;set up line driver entry points
	MOV	LB.TYP(R4),R2	;get line driver type
	ASL	R2
	MOV	DRVTBL(R2),R2	;get entry vector block from line driver
	ADD	#T.ENV,R0	;ptr to block in task block
10$:	MOV	(R2)+,(R0)+	;xfer to task block
	SOB	R1,10$
	RESTOR	<R2,R1,R0>
	RETURN

BLDPRO:	CMP	#TT2780,LB.DVT(R4) ;set protocol flag for task
	BNE	10$
	BIS	#TCOBS,TCFG1(R0) ;2780
10$:	RETURN

DEVINI:				;init some device things
	CALL	DEVIOM		;set device io mode
	CMP	#TTHASP,LB.DVT(R4)
	BNE	10$
	BIS	#TCCMP,TCFG1(R0) ;hasp - set component selection
	MOV	#220,TCCTP(R0)	;set the component type
	ADD	TCDEV(R0),TCCTP(R0)
	CMP	TCDEV(R0),#DV.LPT ;set carriage control
	BEQ	10$		;for lpt
	CMP	TCDEV(R0),#DV.COU
	BNE	20$		;and console output but not anything else

10$:	BIT	#LF.SIM,LB.FGS(R4) ;carraige controls depend on mode
	BEQ	15$
	BIS	#TCPRI,TCFG1(R0) ;emulation - set carriage control on input
	BR	20$

15$:	BIS	#TCPRO,TCFG1(R0) ;termination - set carriage control on output

20$:	CMP	#TT2780,LB.DVT(R4) ;for 3780,hasp
	BEQ	30$
	BIS	#TCCPS,TCFG1(R0) ;set space compression

30$:	MOV	TCDEV(R0),R1	;set default device record size
	MOVB	DVRSZ(R1),TCRSZ(R0)
	RETURN

				;default device record sizes
DVRSZ:	.BYTE	0		;0 - must be set dynamically when line turns around
	.BYTE	80.		;1 - console output
	.BYTE	80.		;2 - console input
	.BYTE	80.		;3 - cdr
	.BYTE	132.		;4 - lpt
	.BYTE	80.		;5 - cdp
	

DEVIOM:	MOV	R4,R1		;set the input/output mode flag for a device
	MOV	TCDEV(R0),R1	;get the device number
	ASL	R1		;make word offset
	BIT	#LF.SIM,LB.FGS(R4) ;modify offset according to emulate/terminate
	BNE	10$		;emulate will be low byte of word
	INC	R1		;terminate will be high byte of word

10$:	CMPB	DEVIOT(R1),#.INDEV ;check for input mode
	BNE	20$		;no - output device
	BIS	#TCIOM,TCFG1(R0) ;mark as input device
20$:	RETURN


.INDEV=1			;flag for input mode device
.OUDEV=0			;flag for output mode device

;io mode table has 1 word entry for each device
;	low order byte for emulation mode
;	high order byte for termination mode

DEVIOT:	.BYTE	.OUDEV,.OUDEV	;0 - set as output mode so it will have a line buffer
	.BYTE	.INDEV,.OUDEV	;1 - console output
	.BYTE	.OUDEV,.INDEV	;2 - console input
	.BYTE	.OUDEV,.INDEV	;3 - cdr
	.BYTE	.INDEV,.OUDEV	;4 - lpt
	.BYTE	.INDEV,.OUDEV	;5 - cdp	
; subroutine to release bsc and xlate tcbs

; args:	R4/lcb


FLSTCB:	MOV	LB.TC1(R4),R0	;get ptr to bsc task
	BEQ	FLXTCB		;no bsc, look for xlate tcb's
	MOV	TCBP2,R3	;r3 must point to start of chain
	CALL	RELTCB		;release tcb and unlink from chain
	MOV	R3,TCBP2	;update start of chain of tcbs
	CLR	LB.TC1(R4)	;clear bsc tcb pointer
FLXTCB:	MOV	LB.NTC(R4),R2	;get # of tcb's for xlate
	BEQ	16$		;just in case its zero
.IF NE,FT.HSP			;hasp present
	CMPB	#TTHASP,LB.DVT(R4) ;2780/3780 mode?
	BNE	11$		;bypass hasp device logic
	INC	R2		;hasp has one more to check
.ENDC				;.IF NE,FT.HSP

11$:	MOV	R2,R1		;start with highest device #
	ASL	R1		;device # mutliplied by 2
12$:	ADD	R4,R1		;get tcb ptr to device's
	MOV	LB.TCD-2(R1),R0	;xlate task
	BEQ	15$		;none for this, check next device
	MOV	R0,-(SP)	;save xlate tcb ptr
	MOV	TCBFP(R0),R0	;release line buffer if any
	BEQ	13$
	CALL	FREPRM
13$:	MOV	(SP),R0		;get tcb ptr back
	MOV	TCSBF(R0),R0	;any compressed buffer to release?
	BEQ	14$		;no.
	MOV	R4,TCLCB(R5)	;make this our line for the moment
	CALL	FRECHK		;now release the chunk

14$:	MOV	(SP)+,R0	;restore xlate ptr
	CLR	LB.TCD-2(R1)	;clear pointer to tcb
	MOV	TCBP3,R3	;point to start of tcb chain
	CALL	RELTCB		;release and unlink tcb for xlate
	MOV	R3,TCBP3	;update pointer to start of tcb chain
15$:	SOB	R2,11$		;do for all device xlate tcb's
	CLR	LB.TCD(R4)	;clear any prev xlate pointer

16$:	CLC			;indicate success
	RETURN
; this subroutine frees the tcb whose address is in r0 and
; unlinks the tcb from the chain whose start is pointed to 
; by r3. r3 is returned with updated pointer to start of chain.
; r1 is destroyed by this routine. r0 and r2 are preserved.

RELTCB:	MOV	R2,-(SP)	;save r2
	CMP	R3,R0		;is it first tcb of chain?
	BNE	13$		;no, hunt thru the chain
	MOV	TCHAIN(R0),R3	;yes, update pointer to start of chain
11$:	CALL	FRETCB		;free the tcb
12$:	MOV	(SP)+,R2	;restore r2
	CLC			;indicate success
	RETURN

13$:	MOV	R3,R1		;make first tcb the previous one
14$:	MOV	TCHAIN(R1),R2	;point to next tcb in chain
	BEQ	16$		;tcb missing from que
	CMP	R0,R2		;match our tcb?
	BEQ	15$		;yes.
	MOV	R2,R1		;make current the prev one
	BR	14$		;hunt till match

15$:	MOV	TCHAIN(R2),TCHAIN(R1) ;unlink tcb from chain
	BR	11$		;free the tcb and exit

; here if tcb is found missing from the que

16$:	STOPCD	DTM		;tcb missing
	.SBTTL		the rest of the line commands


; subroutine to do line command 02: set dtr

SETDTR:	MOV	R4,R0		; copy LCB into correct register
	CALL	@LB.DON(R4)	; set data terminal ready

LCSUC:	JMP	RETSUC		; local suc return

; subroutine to do line command 03: clear dtr

CLRDTR:	MOV	R4,R0		; copy LCB into correct register
	CALL	@LB.DOF(R4)	; clear data terminal ready
	BR	LCSUC

; subroutine to do line command 04: disable

DISLIN:	CALL	GETLB		; get lcb
	BCS	LCSUC		; if no lcb, assume its already done

DISLN0:	BIT	#LF.DAC,LB.FGS(R4) ;check for completely disabled line
	BNE	LCSUC		;yes - nothing to do
	BIT	#LF.DIP,LB.FGS(R4) ;disable in progress?
	BNE	LCSUC		;yes - not done yet
	BIT	#LS.ENB,(R4)	;no - check if line is enabled
	BEQ	LCSUC		;yes - disable in progress
				;no - start disable process
	MOV	LB.TC1(R4),R0	;wake up the BSC task
	BEQ	PKLEEN		;hmmmm - must be enable in progress
	TRACE	TRCLIN,<R4,(R4),LB.FGS(R4),TCFG2(R0),TCST2(R0)>;trace it 1st
	BIC	#LS.ENB,(R4)

	SIGNAL	R0,EBINTR	;wake him no matter what he is waiting on

LCDLY:	JMP	RETDLY		; local delay return

PKLEEN:	TRACE	TRCLIN,<R4,(R4),LB.FGS(R4)> ;disable line in process of enabling
	BIC	#LS.ENB,(R4)	;disable the line
	BIC	#LF.EIP,LB.FGS(R4) ;no longer in progress
	CALL	FLOSHR		;return its resources
	BR	LCSUC		;and suc

; subroutine to do line command 05: set cts delay

SETCSD:	CALL	WRDARG		; get the csd word
	BCS	LCRET		; death nell
	BEQ	LCREJ		; no arg - reject
	MOV	R0,LB.CSD(R4)	; store it
	BR	LCSUC

LCRET:	RETURN			; local return for bcs's

LCREJ:	JMP	RETREJ		; local reject return


; subroutine to do line command 06: set length of silo warning area
;  (this is only effective if the line driver includes a kmc11)

SETSLO:	CALL	WRDARG		; silo warning area size word
	BCS	LCRET
	BEQ	LCREJ		; no arg - reject
	TST	R0
	BLE	LCREJ		; kmc can't handle 0
	MOV	R0,LB.MDS(R4)	; STORE IT
	CLR	LB.MDU(R4)	;clear max depth used
	BR	LCSUC

; subroutine to do line command 07: set output in transparency
; this applies only to hasp-multileaving lines

SETTRN:	BIS	#LF.TSP,LB.FGS(R4) ;set flag in line control block
	MOV	LB.TC1(R4),R1	;get pointer to bsc tcb
	BIS	#TCTSP,TCFG1(R1) ;set trasparent flag for bsc
	BR	LCSUC

; subroutine to do line command 08: set output in non-transparency
; this applies only to hasp-multileaving lines

CLRTRN:	BIC	#LF.TSP,LB.FGS(R4) ;set flag in line control block
	MOV	LB.TC1(R4),R1	;point to bsc tcb
	BIC	#TCTSP,TCFG1(R1) ;clear transparency for bsc to look at
	BR	LCSUC

; subroutine to set transmission block size

SETTBL:	CALL	WRDARG		; get the block size
	BCS	LCRET
	BEQ	LCREJ		; reject it in disgust
	MOV	R0,LB.MBL(R4)	; store it
	JMP	RETSUC

; subroutine to set records per message for transmission block

SETRPM:	CALL	WRDARG		; get the arg
	BCS	LCRET
	BEQ	LCREJ		; no arg - reject
	MOV	R0,LB.MLR(R4)	; store it
	JMP	RETSUC

; subroutine to set line signature


SETSIG:	CALL	WRDARG		; get the signature
	BCS	LCRET
	BEQ	LCREJ		; no arg - reject
	MOV	R0,LB.SIG(R4)	; cram it
	JMP	RETSUC

; subroutine to do line command 12: set station signed on

SETSON:	BIS	#LF.SON,LB.FGS(R4) ;claim station signed on
	JMP	RETSUC
	.SBTTL		DEVCMD	- write device command

; subroutine to perform the "write device command" function.
;  the first byte of the data is the function code, if other
;  data is needed it follows the function code.


DEVCMD:	CALL	GTLBEN		; get an enabled lcb
	BCS	10$		; loser
	CALL	GETXLT		; get the xlate tcb
	BCC	20$		; dev was ok too
10$:	JMP	RETREJ		; dump on user

20$:	CALL	BYTCHI		; get the devics command
	BCS	25$		; forget everything
	BEQ	10$		; paucity of args
	MOV	R0,R1
	MOV	#DVCDSP,R0
	TRACE	TRCTEN,<R3,R1,TCFG2(R3)>
	CALL	DLDISP		; dispatch on command
25$:	RETURN			; return whatever
	.SBTTL		DEVCMD dispatch table

DVCDSP:
12$:	.WORD	<13$-12$>	;offset to illegal code dispatch
	.WORD	SETCHR		;1 = set characteristics
	.WORD	0		;2 = reserved
	.WORD	DMPOUT		;3 = dump output [1(627)]
	.WORD	CLRIPR		;4 = clear "input permission was requested"
	.WORD	0		;5 = reserved
	.WORD	DOINCC		;6 = interpret cc on input
	.WORD	NOINCC		;7 = dont
	.WORD	DOOUCC		;8 = interpret cc on output
	.WORD	NOOUCC		;9 = dont
	.WORD	0		; reserved
	.WORD	0		; reserved
	.WORD	DOCSEL		;12 = do component selection
	.WORD	NOCSEL		;13 = dont
	.WORD	ENBPGC		;14 = enable page counter
	.WORD	DISPGC		;15 = disable it
	.WORD	0		;16 = reserved
	.WORD	DOSPCM		;17 = do space compression
	.WORD	NOSPCM		;18 = dont
	.WORD	PR2780		;19 = use old bsc protocol
	.WORD	PR3780		;20 = dont
	.WORD	REQOPR		;21 = request output permission
	.WORD	GRNTIP		;22 = grant input permission
	.WORD	OUTEOF		;23 = signal output eof
	.WORD	CLROEC		;24 = clear output eof complete
	.WORD	OUTABO		;25 = signal output abort
	.WORD	CLROAC		;26 = clear output abort complete
	.WORD	CLRIEC		;27 = clear input eof complete
	.WORD	INPABO		;28 = signal input abort
	.WORD	CLRIAC		;29 = clear input abort complete
	.WORD	SUSPND		;30 = suspend device (hasp)
	.WORD	UNSUSP		;31 = unsuspend device (hasp)
	.WORD	SETDRS		;32 = set device record size
13$:
	.WORD	RETREJ		; illegal command
	.SBTTL		device commands

;device command processors are called with
;
; args:	R4/lcb
;	R3/xlate tcb
;
;they return
;
;	carry clr - with specific response code set in header block
;	carry set - ten interface error


; subroutine to do device command 01: set characteristics

SETCHR:	CALL	WRDARG		; get the characteristics
	BCS	DVRET
	BEQ	DVREJ		; no arg - reject
	MOV	R1,TCDVT(R3)	;store device type
	BR	DVSUC


; subroutine to do device command 03: dump output

DMPOUT:	BIS	#TCDMP,TCFG1(R3) ;set "dump output"
	JMP	XLTWAK		; wake the xlate task and suc

; subroutine to do device command 04: clear "input permission was requested"

CLRIPR:	BIC	#TCIPG!TCIWR,TCFG2(R3) ;clear "input permission was requested"
	BR	DVSUC

; note that command 05 is reserved

; subroutine to do device command 06: set "interpret cc on input"

DOINCC:	BIS	#TCPRI,TCFG1(R3) ;set "cc on input"
	BR	DVSUC

; subroutine to do device command 07: no interpret cc on input

NOINCC:	BIC	#TCPRI,TCFG1(R3) ;clear "cc on input"
	BR	DVSUC

; subroutine to do device command 08: interpret cc on output

DOOUCC:	BIS	#TCPRO,TCFG1(R3) ;set "cc on output"
	BR	DVSUC

; subroutine to do device command 09: no cc on output

NOOUCC:	BIC	#TCPRO,TCFG1(R3) ;clear "cc on output"
	BR	DVSUC

; subroutine to do device command 12: do component selection
; this is used by hasp multileaving only

DOCSEL:	CALL	BYTCHI		;get component code
	BCS	DVRET
	BEQ	DVREJ		; no arg - reject
	TST	R0		;test component code for legal device
.IF NE,FT.HSP			;hasp present
	BNE	10$		;go make sure it is HASP
	CMP	#TTHASP,LB.DVT(R4) ;0 not legal for hasp
	BEQ	DVREJ
.IFF
	BNE	DVREJ		;only 0 legal
.ENDC				;.IF NE,FT.HSP

10$:	MOVB	R0,TCCTP(R3)	;store component code
	BIS	#TCCMP,TCFG1(R3) ;indicate "component selection"
	BR	DVSUC

; subroutine to do device command 13: no component selection

NOCSEL:	BIC	#TCCMP,TCFG1(R3) ;indicate no component selection
	BR	DVSUC

; subroutine to do device command 14: set printer page counter
;  (not yet completely implemented in xlate)

ENBPGC:	CALL	WRDARG		; get the page count
	BCS	DVRET
	BEQ	DVREJ		; no arg - reject
	MOV	R0,TCPGC(R3)	; stuff it
	BIS	#TCPCE,TCFG1(R3) ;turn on page counter
	BIC	#TCPCO,TCFG1(R3) ; and turn off interrupt flag

DVSUC:	JMP	RETSUC		; local suc return

DVRET:	RETURN			; local return for bcs's

DVREJ:	JMP	RETREJ		; local reject return

; subroutine to do device command 15: no printer page counting

DISPGC:	BIC	#TCPCE!TCPCO,TCFG1(R3) ;clear page counter bits
	BR	DVSUC

; subroutine to do device command 17: do space compression

DOSPCM:	BIS	#TCCPS,TCFG1(R3) ;indicate do compression
	BR	DVSUC

; subroutine to do device command 18: don't do space compression

NOSPCM:	BIC	#TCCPS,TCFG1(R3) ;indicate dont do compression
	BR	DVSUC

; subroutine to do device command 19: use old bsc protocol

PR2780:	BIS	#TCOBS,TCFG1(R3) ; use 2780 protocol
	MOV	LB.TC1(R4),R0	;point to bsc task
	BIS	#TCOBS,TCFG1(R0) ;tell bsc task to use old bsc
	BR	DVSUC

; subroutine to do device command 20: dont use old bsc

PR3780:	BIC	#TCOBS,TCFG1(R3) ; use 3780 protocol
	MOV	LB.TC1(R4),R0	;point to bsc task
	BIC	#TCOBS,TCFG1(R0) ;tell bsc task not to use old bsc protocol
	BR	DVSUC

; subroutine to do device command 21: request output permission

REQOPR:	BIT	#TCIPR,TCFG2(R3) ;input permission requested?
	BNE	10$		;yes, this is a no-op.
	BIS	#TCOPR,TCFG2(R3) ;no, flag output permission requested
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BNE	10$		;no
	MOV	LB.TC1(R4),R0	;point to bsc task
	BIS	#TCOPR,TCFG2(R0) ;tell bsc task there is output to do
.ENDC				;.IF NE,FT.HSP

10$:	JMP	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 22: grant input permission

GRNTIP:	BIT	#TCIPR!TCIWR,TCFG2(R3) ;has input permission been requested?
	BEQ	10$		;no, this is a no-op.
	BIS	#TCIPG,TCFG2(R3) ;yes, flag input permission granted
10$:	JMP	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 23: signal output eof

OUTEOF:	BIS	#TCOEF,TCFG2(R3) ;flag end-of-file on output
	JMP	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 24: clear output eof complete

CLROEC:	BIC	#TCOEF!TCOEC,TCFG2(R3) ;clear output eof flags

CLACWK:	CALL	CLRDAC		; clear device active set by eof condition
	JMP	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 25: signal output abort

OUTABO:
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DV(R4! ;hasp line?
	BEQ	10$		;yes, indicate abort to device
.ENDC				;.IF NE,FT.HSP
	MOV	LB.TC1(R4),R0	;point to bsc task
	BIS	#TCOAB,TCFG2(R0) ;signal abort to bsc task
10$:	BIS	#TCOAB,TCFG2(R3) ;signal abort to xlate task
	JMP	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 26: clear output abort complete

CLROAC:	BIC	#TCOAB!TCOAC,TCFG2(R3) ;clear abort bits
	CALL	CACTO		;clear active bit 
	JMP	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 27: clear input eof complete

CLRIEC:	BIC	#TCIEC,TCFG2(R3) ;clear input eof complete
	BR	CLACWK		; clear active bit and wake xlate task

; subroutine to do device command 28: signal input abort

INPABO:
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BEQ	10$		;yes, indicate abort to device
.ENDC				;.IF NE,FT.HSP
	MOV	LB.TC1(R4),R0	;point to bsc task
	BIS	#TCIAB,TCFG2(R0) ;signal abort to bsc task
10$:	BIS	#TCIAB,TCFG2(R3) ;signal abort to xlate task
	BR	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 29: clear input abort complete

CLRIAC:	BIC	#TCIAB!TCIAC,TCFG2(R3) ;clear abort bits
	CALL	CACTI		;clear the active bit 
	BR	XLTWAK		; wake the xlate task and return suc

; subroutine to do device command 30: suspend device

SUSPND:	BIS	#TCDSP,TCFG2(R3) ;mark device suspended
.IF NE,FT.HSP			;hasp present
	BIT	#TCIOM,TCFG1(R3) ;input device ?
	BEQ	10$		;no, exit
	MOV	TCDEV(R3),R1	;get dev #
	MOV	LB.TC1(R4),R0	;point to bsc tcb
	ASL	R1		;dev # * 2
	MOV	SUSTBL(R1),R1	;get suspend bit for device
	BIC	R1,TCTFCS(R0)	;r0 still points to bsc
				;this indication goes to remote
.ENDC				;.IF NE,FT.HSP

10$:	BR	XLTWAK		; wake the xlate task and return suc

; this subroutine to do device command 31: unsuspend device

UNSUSP:	BIC	#TCDSP,TCFG2(R3) ;mark device unsuspended
.IF NE,FT.HSP			;hasp present
	BIT	#TCIOM,TCFG1(R3) ;input device ?
	BEQ	10$		;no, exit
	MOV	TCDEV(R3),R1	;get dev #
	MOV	LB.TC1(R4),R0	;point to bsc tcb
	ASL	R1		;dev # * 2
	MOV	SUSTBL(R1),R1	;get suspend bit for device
	BIS	R1,TCTFCS(R0)	;r0 still points to bsc
				;this indication goes to remote
.ENDC				;.IF NE,FT.HSP

10$:	BR	XLTWAK		; wake the xlate task and return suc

; subrotine to do device command 32: set device record size

SETDRS:	CALL	WRDARG		; get the device record size
	BCS	DVRET1
	BEQ	DVREJ1		; no arg - reject
	MOV	R0,TCRSZ(R3)	; crammit
	BR	XLTWAK		; wake the xlate task and return suc

DVRET1:	RETURN			; local return for bcs's

DVREJ1:	JMP	RETREJ		; local reject return
	.SBTTL		misc. support functions

; subroutine to drain a device input queue on an abort.
;
; Parameters:	R3/device tcb
;		R4/line block ptr

	.ENABL	LSB
QDRAIN:	SAVE	<R0,R1>

11$:	MOV	LB.LNU(R4),R1	;get line number
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BNE	12$		;no, use line no as i.d.
	SWAB	R1		;put line # in left byte
	ADD	TCCTP(R3),R1	;make i.d. for hasp device
.ENDC				;.IF NE,FT.HSP

12$:	PIOFF			; protect this process
	SAVE	R5
	MOV	TCDLDR,R5	;have to be TENTSK for this
	
	CALL	DEQMID		;get message from this line
	RESTOR	R5
	BCS	13$
	PION
	CALL	30$		;flush it
	BR	11$

13$:	PION
	CALL	GTCBMO		;now flush any messages being processed
	ADD	#TCCMSG,R1	;make ptr to device message cell
.IF NE,FT.HSP			;hasp present
	CMP	#TTHASP,LB.DVT(R4) ;hasp line?
	BNE	15$		;no, @R1/message
	MOV	(R1),R1		;yes,@R1/ptr to block of device queues
	BEQ	20$		;this can't happen of course
	MOV	TCDEV(R3),R0	;get device number
	ASL	R0
	ADD	R0,R1		;R1 was ptr to block of device messages
.ENDC				;.IF NE,FT.HSP

15$:	MOV	(R1),R0		;get the message
	BEQ	20$		;none
	CALL	30$		;toss it
	CLR	(R1)		;not there anymore

20$:	RESTOR	<R1,R0>
	RETURN			; done

30$:	ATRACE	<6(SP),R3,R0>
LOSDAT:
	CALL	FREMSG		;flush the garbage
	RETURN
	.DSABL	LSB

; here to wake the xlate task and give ok return.

XLTWAK:	SIGNAL	R3,EBINTR 	;maybe, wake it.
10$:	JMP	RETSUC


; this subroutine checks if a device number is legitimate
; for the mode of the line. the device number must be zero
; for 3780/2780. the device number must be between one and
; five, inclusive, for hasp. this routine also saves the
; address of the last call that had the a device number.
;
; args:	R4/lcb
;
; return:	c-bit clear, R1/device number
;		c-bit set implies device number illegitimate for mode

GETDEV:	CALL	GENDEV		; get the generic device number - in r1

.IF NE,FT.HSP			;hasp present
	BEQ	1$		;if zero, better be 3780/2780

	BIT	#LF.SIM,LB.FGS(R4) ;are we doing simulation ?
	BNE	4$		;yes, up to device # 5 allowed

	CMP	R1,#DV.LPT	;no, support, only lpt device allowed
	BGT	2$		;error, > than 4 for hasp simulation
	BR	5$		;now make sure line is in hasp mode

4$:	CMP	R1,#DV.PUN	;greater than 5 ?
	BGT	2$		;yes, error, number to big for hasp
5$:	CMP	#TTHASP,LB.DVT(R4) ;no, hasp mode ?
	BNE	2$		;no, error, its 3780/2780
	BR	3$		;yes, device number is good

1$:	CMP	#TTHASP,LB.DVT(R4) ;hasp mode ?
	BNE	3$		;no, 3780/2780, zero is good
.IFF
	BEQ	3$		;2780/3780, zero is good
.ENDC				;.IF NE,FT.HSP

2$:	MOV	(SP),DLIMPC	;save the address of the caller
	SEC			;tell caller he had a bad device number
	RETURN

3$:	CLC			;tell caller his device number is good
	RETURN


DLIMPC:	.WORD	0		;pc of last call with bad device number