	.TITLE	BAUD - Autobaud Terminal Handler
	.IDENT	/1.04/

;++
;  Title:
;	BAUD - Autobaud Terminal Handler
;
;  Facility:
;	System utility to implement automatic baud rate detection
;	for terminal lines.
;
;  Abstract:
;	This program determines the speed of the incoming data on
;	a DZ-11 line.  This is useful when a dial-in line could come
;	in at more than one speed.  The speed cannot be determined until
;	the line is answered.
;
;	A user wishing to login must type one or more carriage returns 
;	until the "Username:" prompt is received.  The speed detection
;	is accomplished by having a one character read pending for every
;	line that is to be autobauded.  When a character is received,
;	it is checked to see if it is a carriage return, or if it is a 
;	known pattern which represents a carriage return read at the wrong
;	speed.  If the character falls into either of these two cases, the
;	DZ-11 speed is adjusted to the incoming speed, and a message is
;	send to the Job Controller mailbox to initiate a login.  If the
;	character cannot be recognized, the DZ-11 speed is adjusted
;	and another read is posted.  This process is repeated until the
;	incoming character is recognizable.  
;
;	The BAUD program is intended to run as a detached process.  It must
;	run with the [1,4] UIC in order to communicate with the Job 
;	Controller.  Configuration information is passed to the detached
;	process via a mailbox.  The DCL command sequence:
;		$COPY TT: BAUD_OPER_MBX
;		baud commands.....
;		^Z
;	can be used to send configuration commands.  The commands can
;	enable and disable autobauding on any line and select the
;	legal baud rates recognized by BAUD.  The configuration
;	commands can also be placed (along with the RUN command to start BAUD)
;	into a detached job submitted by SYSTARTUP.COM.
;
;  	The configuration commands recognized by BAUD are as follows:
;		STOP		Terminate BAUD freeing all terminals.
;		AUTO TTcu:	Enables autobauding on line TTcu:
;		FREE TTcu:	Disables autobauding on line TTcu:
;		ADDR n		Add new allowable baud rate
;		DELR n		Deletes allowable baud rate
;
;	Command names must begin in the first character in the record
;	and contain exactly 4 characters.  If there is a command 
;	parameter, it must be separated from the command by exactly
;	one blank.
;
;	The main program of BAUD is normally in hibernation.  It is 
;	periodically awakened to scan the range of lines known to be
;	available for autobauding.  Any lines which are found to 
;	be available for autobauding, but not owned by any process, are
;	allocated and a read with timeout is made.  This places the line
;	into the "RELEASED" state.  If a character is received on this read,
;	the normal autobaud detection sequence is begun.  If the read instead
;	times out, a HANGUP $QIO function is issued to hangup the line.
;	This hangup causes the DTR modem signal to be dropped.  Dropping this
;	signal usually causes the communications equipment to disconnect
;	the incoming line instead of holding if forever.  When the hangup
;	is initiated, the line is placed into the "HANGUP_PENDING" state.
;	This state is necessary because the hangup takes some period of
;	time to occur, even after the I/O request finishes.  The AST
;	routine for this state is triggered by a timer request, and 
;	eventually issues a read and transitions the the "IDLE" state.
;
;	The normal autobaud sequence takes place when a character is received
;	in response to a read.  The character is analyzed, and if it can
;	be recognized, the DZ-11 speed is set to the incoming line speed, and
;	the line is released for the user.  The Job Controller is sent
;	a message identical to that it normally receives from TTDRIVER, which
;	makes it think there was an unsolicited typein on the newly freed 
;	terminal.  Job Control then starts a login sequence for the user.
;
;	When the character is not recognizable as a carriage return, the
;	DZ-11 speed is adjusted and a read with timeout is issued.  The 
;	line enters the "ADJUST_SPEED" state.  If a character is
;	received on this read, it is analyzed and processed as above.
;	If the read times out, it is assumed that the user has given up,
;	The line is returned to the IDLE state, via the HANGUP_PENDING
;	state as described above.  In the ADJUST_SPEED state, the 
;	timeout read also serves to prevent the line from becoming "lost"
;	if the user radically alters his terminal speed during an
;	autobaud sequence.  This could cause a problem if BAUD is homing
;	in on a low speed signal, and suddenly the user drastically raises
;	the speed.  The start bit is then too short to be detected by the
;	DZ-11 and the line ceases to respond.
;	
;	The default selection of legal baud rates is intended to provide
;	for one or two carriage return selection of the speeds 110, 150, 300, 
;	600, 1200, and 2400 baud.  If different speeds are desired, they
;	can be added via the commands described above.  If it is necessary
;	to autobaud above 4800 baud, it will be necessary to alter the
;	DEFAULT SPEED assembly parameter and reassemble the program.
;	The assembly parameter LOG_ENABLE can be used to enable the printing
;	of log messages tracing the operation of the program. Setting it to
;	causes the logging code to be omitted.  BAUD uses a structured-
;	programming macro package which must be included at assembly.
;	To build BAUD, use the following commands:
;
;		$MACRO/LIST BAUD+SMAC/LIB
;		$MESSAGE/LIST BAUDMSG
;		$LINK BAUD+BAUDMSG
;
;  Environment:
;	Native Mode. Intended to run as detached process with 
;	following privileges and quotas:
;	$RUN/PROCESS_NAME=AUTO_BAUD,-
;	/UIC=[001,004],-
;	/AST_LIMIT=n+2,-
;	/FILE_LIMIT=n+2,-
;	/IO_BUFFERED=n+2,-
;	/PAGE_FILE=1000,-
;	/QUEUE_LIMIT=n
;	/PRIORITY=14,-
;	/PRIVILEGES=PHY_IO
;	Where n is the number of terminals to be autobauded.
;
;  Author: 
;	Gary L. Grebus, Creation date: 17-Feb-1981
;	Battelle Columbus Labs
;
;  Modified by:
;	1.00 - Gary L. Grebus, 27-Feb-1981
;	Initial version up for testing
;
;	1.01 - Gary L. Grebus, 7-Apr-1981
;	Fixed MESSAGE macro to supply correct argument count in vector
;
;	1.02 - Gary L. Grebus, 23-Apr-1981
;	Changed default listening rate to 1200 baud.  Eliminated
;	150 baud as a default rate.  This makes distinguishing
;	1200 and 2400 baud more reliable.
;
;	1.03 - Gary L. Grebus, 27-Apr-1981
;	Corrected bad GARP_TABLE entry for 1200 baud listening.
;	Added 150 baud back as a default rate.  This prevents
;	more serious problems by causing 110 baud to take 2 cr's
;	Problem is 300 baud cr sometimes appearing as a zero and
;	falsing to 110 baud.
;
;	1.04 - Gary L. Grebus, 7-May-1981
;	Fixed access violation in DATA_RECEIVED.  Bit position
;	argument was being supplied as a byte instead of a
;	longword.
;--

	.PAGE
	.SBTTL	Symbol definitions
;  System symbols
	$IODEF				; IO function codes
	$TTDEF				; Terminal related symbols

;  Equated symbols
MAX_TERMS = 48				; Maximum number of terminals allowed
MBX_BUFFER_SZ = 12			; Size of buffer for configuration
					; mailbox
LOG_ENABLE = 1				; Flag - non-zero activates debugging
					; log messages
UNITS_PER_CTRL = 8			; Number of units on a controller


SCAN_SECS = 8				; Interval between wakeups to scan
					; for newly freed terminals and update
					; the TST
RELEASE_SECS = 30			; Timeout after user logs out before
					; we drop DTR and hang up on him.
ADJ_SPEED_SECS = 10			; Timeout after withc we assume we 
					; have lost control of line while
					; adjusting speed.
HANGUP_SECS = 2				; Interval to wait following doing a
					; QIO hangup to make sure it finishes.
					; Should be twice system parameter
					; TTYSCANDELTA

DEFAULT_SPEED = TT$C_BAUD_1200		; Default speed to read terminals at

READ_FUNC = IO$_READPBLK ! IO$M_PURGE !-
	IO$M_NOECHO ! IO$M_CVTLOW !-
	IO$M_NOFILTR			; Function code and modifiers for
					; terminal read

ASCII_CR = ^X0D				; ASCII carriage return

NR_DZ_BAUDS = 15			; # of baud rates available on DZ-11

DEF_HIGHEST_BAUD = TT$C_BAUD_2400	; Default highest baud rate to allow
DEF_LOWEST_BAUD = TT$C_BAUD_110		; Default lowest baud rate to allow
					; These should match selections in
					; OUR_RATES bit table.

	.PAGE
	.SBTTL	Local macros
;  Local macros
	.MACRO	MESSAGE	CODE,F1,F2,F3,F4,F5,F6,F7,F8

;;  Macro to build a message vector for the $PUTMSG system service.
;;  Vector is for only one message and is built on the stack.
;;  Message flags are left null.  R0 is modified in additon to the
;;  $PUTMSG call.
	.IF	BLANK,<CODE>		;; Code must be specified
	  .ERROR			; Message code must be specified
	  .MEXIT
	.ENDC

	.NARG	..MSG_NARGS		;; Get number of arguments
	..LEN = 0			;  Length of vector built on stack

	.IRP	F,<F8,F7,F6,F5,F4,F3,F2,F1>

	  .IF	NB,<F>			;; If parameter was supplied
	    PUSHL	'F		;  Push the parameter
	    ..LEN = ..LEN + 1		;; and count it
	  .ENDC
	.ENDR

	.IF	NE,<..LEN>		;; If there were FAO args
	  PUSHL	#..LEN			; Push FAO count
	  ..LEN = ..LEN + 1		;; and count it
	.ENDC

	PUSHL	CODE			; Store message code
	PUSHL	#..LEN+1		; Store vector length
	MOVL	SP,R0			; Point to vector
	$PUTMSG_S	MSGVEC=(R0)	; Issue the message
	ADDL2	#<4*<..LEN+2>>,SP	; Remove vector from stack

	.ENDM	MESSAGE

	.MACRO	LOG_MESSAGE	CODE,F1,F2,F3,F4,F5,F6,F7,F8
;;  Macro to issue a log message.  Message code is only generated if
;;  logging is enabled.
	.IF	NE,LOG_ENABLE
	  MESSAGE  CODE,<F1>,<F2>,<F3>,<F4>,<F5>,<F6>,<F7>,<F8>
	.ENDC
	.ENDM	LOG_MESSAGE

	.MACRO	IF_ERROR	CODE,F1,F2,F3,F4,F5,F6,F7,F8,?L1
;;  Macro to stop on an error.  Issues the specified local message
;;  then does a LIB$STOP on the system error code in R0.
	BLBS	R0,L1			; Branch if no error
	PUSHR	#^M<R0,R1>		; Save the system code
	MESSAGE  CODE,<F1>,<F2>,<F3>,<F4>,<F5>,<F6>,<F7>,<F8>
	POPR	#^M<R0,R1>		; Restore system code
	CALL	LIB$STOP, R0		; Stop on the system code
L1:
	.ENDM	IF_ERROR

	.MACRO	DELTA	SECONDS=0,HUNDREDTHS=0
;;  Macro to allow easy definition of short delta times.  Time cannot
;;  exceed about 7 minutes when defined in this manner.
	.IIF	GT,<SECONDS-420>,	.WARN ; Delta time may be too big

	.LONG	-1*<<10*1000000*SECONDS>+<100000*HUNDREDTHS>>
	.LONG	-1

	.ENDM	DELTA

	.PAGE
	.SBTTL	Read/write data
	.PSECT	RWDATA	RD,WRT,NOEXE,NOSHR,LONG

;  Read/write data

;
;  Terminal Status Table
;
;  This structure is used to keep track of the status of all terminal (TTcu:)
;  lines on the system.  Table is in order TTA0:, TTA1:,...TTF6:, TTF7:,...
;  Table contains an entry for each terminal found on the system.
;
;  Table entry description
	$DEFINI	TST

	$DEF	TST_Q_IOSB .BLKQ 1	; IOSB for terminal operations

	$DEF	TST_R_CHRBUF .BLKL 1	; Buffer for $GETCHN service. First
	$DEF	TST_Q_DEVCHR .BLKQ 1	; longword needed for $GETCHN. 
					; Remaining quadword used for $QIO
					; SETCHAR

	$DEF	TST_W_CHAN .BLKW 1	; Channel number assigned to terminal

	$DEF	TST_W_STS .BLKW 1	; Status flags
;  Valid status bits
	_VIELD	TST,0,<-
		<AUTO,,M>,-		; Line should be autobauded
		<OWNED,,M>,-		; We own (have allocated) this line
			>

	$DEF	TST_T_BUFFER .BLKB 4	; Buffer for reading from terminal

	$DEF	TST_T_NAME .BLKB 6	; Terminal name

	$DEF	TST_B_STATE .BLKB 1	;  Terminal state code
;  Valid terminal state codes
					; Zero = invalid
	TST_C_ST_IDLE = 1		; Line is idle - read pending
	TST_C_ST_RELEASE = 2		; Line is released - read/tmo pending
	TST_C_ST_ADJ = 3		; Speed being adjusted - read/tmo
					; pending
	TST_C_ST_BUSY = 4		; Line is in use
	TST_C_ST_HNGUP = 5		; Hangup pending 

	$DEF	TST_B_SPEED .BLKB 1	; Code for current terminal speed


	$DEF	TST_C_ENTSZ		; Size of an entry
	$DEFEND	TST

;
;  Reserve storage for the TST and associated variables
;
TERM_STAT:
	.BLKB	MAX_TERMS*TST_C_ENTSZ	; Terminal status table

LOWEST_TERM_IDX:
	COUNT	0			; TST index of lowest terminal
					; to autobaud

HIGHEST_TERM_IDX:
	COUNT	0			; TST index of highest terminal
					; to autobaud

NR_TERMS:
	COUNT	0			;  Number of terminals currently
					;  on system

;
;  Baud rate data
;
;  Longword bit mask of default rates we will recognize.  134 and 150
;  should not be both set.  1800 and 2000 should not be both set.
;  Bit number corresponds to the baud rate code.  Note bit zero unused.
OUR_RATES:				
	.LONG	-			
	<<1@<TT$C_BAUD_110>> ! -
	<1@<TT$C_BAUD_150>> ! -
	<1@<TT$C_BAUD_300>> ! -
	<1@<TT$C_BAUD_600>> ! -
	<1@<TT$C_BAUD_1200>> ! -
	<1@<TT$C_BAUD_2400>>>

;  Table for conversion between speed values and the speed codes
;  returned for device characteristics.
RATE_CODES:
	.WORD	50,TT$C_BAUD_50
	.WORD	75,TT$C_BAUD_75
	.WORD	110,TT$C_BAUD_110
	.WORD	134,TT$C_BAUD_134
	.WORD	150,TT$C_BAUD_150
	.WORD	300,TT$C_BAUD_300
	.WORD	600,TT$C_BAUD_600
	.WORD	1200,TT$C_BAUD_1200
	.WORD	1800,TT$C_BAUD_1800
	.WORD	2000,TT$C_BAUD_2000
	.WORD	2400,TT$C_BAUD_2400
	.WORD	3600,TT$C_BAUD_3600
	.WORD	4800,TT$C_BAUD_4800
	.WORD	7200,TT$C_BAUD_7200
	.WORD	9600,TT$C_BAUD_9600

HIGHEST_BAUD:
	.BLKL	1			; Current highest allowed baud rate
LOWEST_BAUD:
	.BLKL	1			; Current lowest allowed baud rate

;
;   Data structures for configuration mailbox
;
MBX_BUFFER:
	STRING	MBX_BUFFER_SZ

MBX_CHAN:
	.BLKW	1			; Mailbox channel number

MBX_NAME:
	.ASCID	/BAUD_OPER_MBX/		; Logical name for configuration
					; mailbox
MBX_IOSB:
	.BLKQ	1			; IOSB for mailbox
;
;  Delta times for various delays
;
SCAN_DELTA:
	DELTA	SECONDS=SCAN_SECS	; Interval between scans to update TST
HANG_DELTA:
	DELTA	SECONDS=HANGUP_SECS	; Interval to wait following hangups.

	.PAGE
	.SBTTL	BAUD - Main program
	.PSECT	CODE  RD,NOWRT,EXE,SHR,LONG
	.ENTRY	BAUD,0

;
;  Main program for BAUD autobaud terminal handler.  
;  Following initialization, the program waits in a HIBER state until 
;  awoken by a periodic $SCHDWK.  It then updates the Terminal Status
;  Table by searching for lines which have become released and returns
;  to the HIBER state.
;  All other activities take place at AST level.
;

	CALL	INITIALIZE		; Initialize, including requesting
					; the $SCHDWK

	REPEAT

	  $SETAST_S ENBFLG=#0		; Disable AST's to lock TST
	  IF_ERROR -
		CODE=#BAUD_SETAST	; Stop if an error
	  CALL	UPDATE_TST		; Update the TST
	  $SETAST_S ENBFLG=#1		; Enable AST's
	  IF_ERROR -
		CODE=#BAUD_SETAST	; Stop if an error
	
	  $HIBER_S			; Hibernate for next cycle
	  IF_ERROR -
		CODE=#BAUD_HIBER	; Stop if an error

	UNTIL	<FOREVER>		; Loop forever

	.PAGE
	.SBTTL	INITIALIZE - Initialize BAUD program.
;++
;  Functional Description:
;	Initial setup routine for BAUD.  Initializes TST, creates and reads
;	configuration mailbox, and schedules periodic wakeup.
;
;  Calling Sequence:
;	CALLS	#0,INITIALIZE
;
;  Input Parameters: NONE
;	
;  Output Parameters: NONE
;
;  Implicit Inputs:  NONE
;
;  Implicit Outputs:
;	TERM_STAT - Terminal status table initialized
;	LOWEST_TERM_IDX -  "
;	HIGHEST_TERM_IDX - "
;	NR_TERMS - "
;	MBX_CHAN - Configuration mailbox channel
;	HIGHEST_BAUD - Limits on legal baud rates
;	LOWEST_BAUD -        "
;
;  Completion Status:  NONE
;
;  Side Effects: NONE
;
;--

	.ENTRY	INITIALIZE,^M<>

;  Initialize the Terminal Status Table
	MOVZWL	#MAX_TERMS+1,-
		LOWEST_TERM_IDX		; No lowest terminal yet.
	CLRL	HIGHEST_TERM_IDX	; Ditto highest terminal
	MOVZWL	#DEF_HIGHEST_BAUD,-
		HIGHEST_BAUD		; Init highest current baud rate
					; to default
	MOVZWL	#DEF_LOWEST_BAUD,-
		LOWEST_BAUD		; Ditto lowest rate
	CALL	TST_INI, NR_TERMS	; Zero out TST. Returns number
					; of terminals acutally found.
	
;  Get mailbox for receiving configuration messages.
	$CREMBX_S -
		CHAN=MBX_CHAN,-
		MAXMSG=#MBX_BUFFER_SZ,-
		PROMSK=#^XF000,-
		LOGNAM=MBX_NAME		; Create the mailbox
	IF_ERROR -
		CODE=#BAUD_CREMBX	; Stop if an error

;  Request periodic wakeup.
	$SCHDWK_S -
		DAYTIM=SCAN_DELTA,-
		REPTIM=SCAN_DELTA	; Wake up every SCAN_DELTA.
	IF_ERROR -
		CODE=#BAUD_SCHDWK	; Stop if an error

;  Read with AST on the mailbox.
	$QIO_S	CHAN=MBX_CHAN,-
		FUNC=#IO$_READVBLK,-
		IOSB=MBX_IOSB,-
		ASTADR=MBX_MSG_AST,-
		P1=MBX_BUFFER,-
		P2=#MBX_BUFFER_SZ	; Read from mailbox
	IF_ERROR -
		CODE=#BAUD_QIO		; Stop if an error

;  Log that initialization is complete
	LOG_MESSAGE -
		CODE=#BAUD_INIDONE	; Initialization done
	RET

	.PAGE
	.SBTTL	UPDATE_TST - Update Terminal Status Table

;++
;  Functional Description:
;	This routine is called at each SCAN_DELTA interval to search
;	for terminals which have become available in the last cycle.
;	If a terminal has become available, we allocate it, reset
;	its speed, and to a read with timeout.  If the user attempts
;	to reuse the line before the timeout (RELEASE_SECS) it
;	appears to be a normal autobaud detect.  However, if the 
;	user doesn't try to reuse the line, we will eventually time
;	out and hangup on him.
;
;  Calling Sequence:
;	CALLS	#0,UPDATE_TST
;
;  Input Parameters:  NONE
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	LOWEST_TERM_IDX - Limits of TST entries to scan
;	HIGHEST_TERM_IDX -        "
;	TERM_STAT - Terminal status table
;
;  Implicit Outputs:
;	TERM_STAT - Terminal status table is updated
;
;  Completion Status:  NONE
;
;  Side Effects:
;  	Terminals may be allocated and reads performed.
;
;--

	.PSECT	RWDATA RD,WRT,NOEXE,NOSHR,LONG

;  Local storage
DEV_DESC:
	.LONG	6			; Skeleton descriptor for term name
	.LONG	0

GETCHN_DESC:
	.LONG	<3*4>			; Skeleton descriptor for any $GETCHN
	.LONG	0			; buffer

	.PSECT	CODE NOWRT,EXE,SHR,LONG
	.ENTRY	UPDATE_TST,^M<R2,R3>

;  Register usage
;	R0-R1	Scratch
;	R2 - Pointer to current TST entry
;	R3 - Address of highest TST entry to scan.

;  Setup scan loop start and limit
	MOVAL	TERM_STAT,R0		; Get table base address
	MULL3	#TST_C_ENTSZ,-
		LOWEST_TERM_IDX,R2	; Offset to lowest entry
	ADDL	R0,R2			; Compute address of lowest entry
	MULL3	#TST_C_ENTSZ,-
		HIGHEST_TERM_IDX,R3	; Offset to highest entry
	ADDL	R0,R3			; Compute address of highest entry

;  Loop scanning table 
	ENB_LONG			;; Enable long branches for SMAC
	WHILE <LEQ,R2,R3> DO

	  IF <BS,#TST_V_AUTO,TST_W_STS(R2)> AND -
	    <BC,#TST_V_OWNED,TST_W_STS(R2)> THEN

;  Terminal is available for autobauding and we do not currently own it
	    MOVAL	TST_T_NAME(R2),-
			DEV_DESC+4	; Build desc for device name
	    $ALLOC_S -
		DEVNAM=DEV_DESC	; Try to get the terminal
	    IF <NEQ,R0,#SS$_DEVALLOC> -
		THEN			; If not in use by someone else
	      IF_ERROR	-
		CODE=#BAUD_ALLOC	 ; and not some other error

;  Terminal is not owned.  It must have been released during this cycle
;  by someone logging out.
	      BISW	#TST_M_OWNED,-
			TST_W_STS(R2)	; Mark terminal as owned by us

;  Get a channel
	      $ASSIGN_S -
		DEVNAM=DEV_DESC,-
		CHAN=TST_W_CHAN(R2)	; Get a channel on the terminal
	      IF_ERROR -
		CODE=#BAUD_ASSIGN	; Stop if error
	      LOG_MESSAGE -
		CODE=#BAUD_ASGCHN,-
		F1=#DEV_DESC		; Issue log message. We have channel.

;  Get the device characteristics which are needed for later $QIO SETCHAR's
	      ASSUME -
		TST_R_CHRBUF+4 EQ TST_Q_DEVCHR ; Make sure buffer parts
					; are still declared contiguous
	      MOVAL	TST_R_CHRBUF(R2),-
		GETCHN_DESC+4		; Plug buffer address into desc
	      $GETCHN_S -
		CHAN=TST_W_CHAN(R2),-
		PRIBUF=GETCHN_DESC	; Get the characteristics
	      IF_ERROR -
		CODE=#BAUD_GETCHN	; Stop if error

;  Set the speed
	      CALL	SET_SPEED,-
			R2,-
			#DEFAULT_SPEED	; Set speed to default 
	      MOVB	#DEFAULT_SPEED,-
			TST_B_SPEED(R2)	; Set speed field in TST

;  Read with timeout on terminal.
	      $QIO_S -
		CHAN=TST_W_CHAN(R2),-
		FUNC=#READ_FUNC!IO$M_TIMED,-
		IOSB=TST_Q_IOSB(R2),-
		ASTADR=RELEASE_AST,-
		ASTPRM=R2,-
		P1=TST_T_BUFFER(R2),-
		P2=#1,-
		P3=#RELEASE_SECS
	      IF_ERROR -
		CODE=#BAUD_QIO		; Stop if error

	      LOG_MESSAGE -
		CODE=#BAUD_RELREAD,-
		F1=#DEV_DESC		; Log message. We started a read.

	      MOVB	#TST_C_ST_RELEASE,-
			TST_B_STATE(R2)	; Set state to released
	    ENDIF
	  ENDIF

	  ADDL	#TST_C_ENTSZ,R2		; Point to next TST entry
	ENDWHILE
	DSB_LONG			;; Disable long branches for SMAC

	RET

	.PAGE
	.SBTTL	MBX_MSG_AST Configuration message AST routine

;++
;  Functional Description:
;	This routine is called at AST level to receive a message sent
;	to the configuration mailbox.  The mailbox message is examined
;	for data.  If data is found, a routine is called to process it.
;	A read is then performed on the mailbox.  
;
;  Calling Sequence:
;	Called by VMS with CALLG and AST parameter block.
;
;  Input Parameters:  NONE relevant
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs: 
;	MBX_IOSB - Mailbox I/O status
;	MBX_BUFFER - Data from mailbox read
;	MBX_CHAN - Mailbox channel number
;
;  Implicit Outputs:  NONE
;
;  Completion Status:  NONE
;
;  Side Effects:
;	Issues a read on the mailbox
;
;--

	.ENTRY	MBX_MSG_AST,^M<>

	MOVZWL	MBX_IOSB,R0		; Get IO status
	IF  <EQL,R0,#SS$_ENDOFFILE> THEN ; Map end-of-file status
	  MOVZWL	#SS$_NORMAL,R0	; To normal completion
	ENDIF

	IF_ERROR -
		CODE=#BAUD_MBXIO	; Stop if I/O error

;  Log the message we received
	MOVZWL	MBX_IOSB+2,R1		; Get message length
	LOG_MESSAGE -
		CODE=#BAUD_CONFMSG,-
		F1=R1,-
		F2=#MBX_BUFFER		; Issue log message

	IF  <NEQ,MBX_IOSB+2,TYPE=W> THEN ; If some data received
	  CALL	PROC_MBX_COMMAND	; Process the command
	ENDIF

;  Issue a new read with AST for next configuration message
	$QIO_S	CHAN=MBX_CHAN,-
		FUNC=#IO$_READVBLK,-
		IOSB=MBX_IOSB,-
		ASTADR=MBX_MSG_AST,-
		P1=MBX_BUFFER,-
		P2=#MBX_BUFFER_SZ	; Read from mailbox
	IF_ERROR -
		CODE=#BAUD_QIO		; Stop if an error
	RET

	.PAGE
	.SBTTL	PROC_MBX_COMMAND - Process configuration command

;++
;  Functional Description:
;	Routine to process commands received in the configuration mailbox.
;	Legal commands are:
;	STOP			Terminate BAUD
;	AUTO TTcu:		Initiate auto baud on TTcu:
;	FREE TTcu:		Terminate auto baud on TTcu:
;	ADDR n			Add new allowable rate
;	DELR n			Delete allowable rate
;
;  Command names must begin in first character in the record and contain
;  exactly 4 characters.  If there is a command parameter, it must be
;  separated from the command by exactly one blank.
;
;  Calling Sequence:
;	CALLS	#0,PROC_MBX_COMMAND
;
;  Input Parameters:  NONE
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	MBX_BUFFER - Mailbox buffer containing the command
;	MBX_IOSB - Mailbox I/O status containing the command length
;
;  Implicit Outputs:  
;	LOWEST_BAUD - Lowest legal baud rate
;	HIGHEST_BAUD - Highest legal baud rate
;	OUR_RATES - Bit mask of legal baud rates
;
;  Completion Status:  NONE
;
;  Side Effects:
;	Command processing may modify TST, cause reads on the terminal,
;	or cause a $EXIT_S to be executed.
;
;--

	.PSECT	RWDATA  RD,WRT,NOEXE,NOSHR,LONG

;  Local data
RATE_NUM:
	COUNT	0			; Temporary storage 

	.PSECT	CODE  NOWRT,EXE,SHR,LONG
	.ENTRY	PROC_MBX_COMMAND,^M<R2>
;
;  Register usage:
;  R0-R2 - Scratch

;  Check for "STOP" command
	IF  <EQL,#^A/STOP/,MBX_BUFFER> THEN
	  $EXIT_S	CODE=#SS$_NORMAL ; Stop if we are told
	ENDIF

	ENB_LONG			;;Enable long branches for SMAC
;  Check for a command with terminal name
	IF <EQL,MBX_BUFFER,#^A/AUTO/> -
	  OR <EQL,MBX_BUFFER,#^A/FREE/> THEN

	  LOCC	#^A/ /,MBX_IOSB+2,-
		MBX_BUFFER		; Look for blank separating name
					; from terminal.  Leaves R1 pointing
					; to the blank. Leave length of 
					; remainder in R0.
	  IF <EQL> THEN			; If no blank found...
	    LOG_MESSAGE -
		CODE=#BAUD_SYNERR	; Log syntax error

	  ELSE
	    INCL	R1		; Skip the blank
	    DECL	R0
	    BSBW	NAME_TO_INDEX	; Convert terminal name to TST index

	    IF <LSS,R2> OR <GEQ,R2,NR_TERMS>  THEN

;  Negative index means bad terminal name format
;  Index greater than number of terminals means non-existent terminal.
	      LOG_MESSAGE -
		CODE=#BAUD_SYNERR	; Issue error message

	    ELSE

	      IF <EQL,MBX_BUFFER,#^A/AUTO/> THEN

;  Process AUTO command by putting autobaud status into TST entry
	        CALL	INS_TST_ENTRY, R2
	      ELSE

;  Process FREE command by removing autobaud status from TST entry
	        CALL	DEL_TST_ENTRY, R2
	      ENDIF
	    ENDIF
	  ENDIF
	  RET
	ENDIF

	IF <EQL,MBX_BUFFER,#^A/ADDR/> OR -
	  <EQL,MBX_BUFFER,#^A/DELR/> THEN

;  Process commands for setting or clearing legal baud rates
	  LOCC	#^A/ /,MBX_IOSB+2,-
		MBX_BUFFER		; Locate separating blank
					; Leaves R1 pointing to blank,-
					; R0 with remaining string length
	  IF <EQL> THEN			; If no blank found...
	    LOG_MESSAGE -
		CODE=#BAUD_SYNERR	; Log a syntax error
	  ELSE

	    INCL	R1		; Skip the blank
	    DECL	R0
	    CALL	LIB$CVT_DTB,-
		R0, R1, RATE_NUM	; Convert string to binary

;  Convert baud rate value to internal code
	    CLRL	R0		; Clear loop count

	    WHILE <LSS,R0,#2*NR_DZ_BAUDS> DO
	      BREAK IF <EQL,RATE_NUM,-
		RATE_CODES[R0],TYPE=W>	; Branch out if first part
					; of table entry matches the specified
					; rate.
	      ADDL	#2,R0		; Index to next entry
	    ENDWHILE

	    IF <GEQ,R0,#2*NR_DZ_BAUDS> THEN

;  Rate not found - syntax error
	      LOG_MESSAGE -
		CODE=#BAUD_SYNERR	; Issue error message
	    ELSE

	      MOVZWL	RATE_CODES+2[R0],-
		RATE_NUM		; Get code for the baud rate

	      IF <EQL,MBX_BUFFER,#^A/ADDR/> THEN

;  Add new legal rate
	        BBCS	RATE_NUM,-
		OUR_RATES,10$		; Set new bit
10$:
	      ELSE

;  Delete old rate
	        BBSC	RATE_NUM,-
		OUR_RATES,20$		; Clear old bit
20$:
	      ENDIF

;  Update baud rate limits
	      FFS	#0,#TT$C_BAUD_9600,-
		OUR_RATES,LOWEST_BAUD	; Update low limit to lowest bit set

	      ASHL	#<32-TT$C_BAUD_9600>,-
		OUR_RATES,R0		; Get bit table with highest possible
					; bit in sign bit
	      MOVL	#TT$C_BAUD_9600,R1 ; Set counter to highest possible 
					; rate
30$:	      ASHL	#1,R0,R0	; Shift off next bit
	      BVS	40$		; Branch out if set bit shifted out
	      DECL	R1		; Decrement highest possible rate
	      BGTR	30$		; Loop until set bit found or all bits
					; checked
40$:	      MOVL	R1,-
		HIGHEST_BAUD		; Update rate scan limit

	    ENDIF
	  ENDIF

	  RET
	ENDIF

	DSB_LONG			;;Disable long branches for SMAC

;  If no one has claimed this command, it must be unknown
	LOG_MESSAGE -
		CODE=#BAUD_UNKCMD	; Log unknown command
	RET

	.PAGE
	.SBTTL	NAME_TO_INDEX  Convert terminal name to TST index

;++
;  Functional Description:
;	Subroutine used to convert the terminal name in the form
;	TTcu: into a TST index.  Validates beginning of argument
;	name to make sure it looks something like a term name.
;
;  Calling Sequence:
;	BSBW	NAME_TO_INDEX
;
;  Input Parameters:
;	R0 - Length of terminal name string
;	R1 - Address of terminal name string
;	
;  Output Parameters:
;	R2 - Set to TST index corresponding to terminal name
;
;  Implicit Inputs:  NONE
;
;  Implicit Outputs:  NONE
;
;  Completion Status: 
;	R2 is set to -1 if the terminal name is invalid.
;
;  Side Effects:  NONE
;
;--

;  Register usage:
;	R0 - Input parameter. Modified.
;	R1 - Input parameter. Modified.
;	R2 - Output parameter.  Modified.

NAME_TO_INDEX::
	IF  <EQL,(R1),#^A/_/,TYPE=B> THEN ; If first char is a "_"
	  INCL	R1			; Skip it
	  DECL	R0
	ENDIF

	IF <LSS,R0,#4> OR -
	  <NEQ,(R1),#^A/TT/,TYPE=W> THEN
	    MNEGL	#1,R2		; Must be bad name

	ELSE
	  ADDL	#2,R1			; Point to controller designator
	  CLRL	R0			; Clear scratch register
	  SUBB3	#^A/A/,(R1),R0		; Get controller index
	  MULL	#UNITS_PER_CTRL,R0	; Times units per controller
	  INCL	R1			; Point to unit designator
	  CLRL	R2			; Clear scratch register
	  SUBB3	#^A/0/,(R1),R2		; Get unit index
	  IF <LSS> OR -
	    <GEQ,R2,#UNITS_PER_CTRL> THEN
	    MNEGL	#1,R2		; Bad digit in unit spot
	  ELSE
	    ADDL	R0,R2		; Add controller index to unit
					; index and return value
	  ENDIF
	ENDIF

	RSB

	.PAGE
	.SBTTL	TST_INI - Initialize Terminal Status Table

;++
;  Functional Description:
;	Routine to initialize the Terminal Status Table and determine
;	the number of terminals actually on the system.  Zeros each 
;	table entry and moves in the terminal name.
;
;  Calling Sequence:
;	PUSHAL	number-of-terms-found
;	CALLS	#01,TST_INI
;
;  Input Parameters:  NONE
;	
;  Output Parameters:
;	4(AP) - Number of terminals found on system.
;
;  Implicit Inputs:  NONE
;
;  Implicit Outputs:  NONE
;
;  Completion Status:  NONE
;
;  Side Effects:
;	Terminal Status Table is initialized.
;
;--

	.PSECT	RWDATA RD,WRT,NOEXE,NOSHR,LONG

; Local data

TERM_NAME_FORM:
	.ASCII	/_TTcu:/			; Form of a terminal name

TERM_NAME_DESC:
	.LONG	6			; Skeleton desc for terminal name
	.LONG	0

;  Register usage
	.PSECT	CODE EXE,NOWRT,SHR,LONG
	.ENTRY	TST_INI,^M<R2,R3,R4,R5,R6,R7,R8,R9>

;	R0 - R5 - Scratch
;	R6 - Address of TST entry being initialized
;	R7 - Terminal unit counter
;	R8 - Terminal controller counter
;	R9 - Index of TST entry being initialized

	CLRL	R9			; Start with zeroth entry
	CLRL	R7			; and unit 0
	CLRL	R8			; on controller A
	MOVAL	TERM_STAT,R6		; Base address of TST

;  Init the next TST entry
INI_LOOP:
	MOVC5	#0,.,#0,-
		#TST_C_ENTSZ,(R6)	; Clear this TST entry
	MOVC3	#6,TERM_NAME_FORM,-
		TST_T_NAME(R6)		; Stuff in device name skeleton
	ADDB3	#^A/A/,R8,-
		TST_T_NAME+3(R6)	; Add controller name
	ADDB3	#^A/0/,R7,-
		TST_T_NAME+4(R6)	; and unit number

	
;  Find out if this device exists
	MOVAL	TST_T_NAME(R6),-
		TERM_NAME_DESC+4	; Fill in skeleton descriptor
	$GETDEV_S -
		DEVNAM=TERM_NAME_DESC	; Try to get info on the device
	CMPL	R0,#SS$_NOSUCHDEV	; Does device exist?
	BEQL	LAST_FOUND		; Branch if not
	IF_ERROR -
		CODE=#BAUD_GETDEV	; Stop if other error

	ADDL	#TST_C_ENTSZ,R6		; Point to next TST entry
	INCL	R7			; Increment unit counter
	IF  <EQL,R7,#UNITS_PER_CTRL> THEN
	  INCL	R8			; Bump to next controller
	  CLRL	R7			; Recycle to unit zero
	ENDIF
	
	AOBLSS	#MAX_TERMS,R9,INI_LOOP	; Loop through all allowed terminals

;  Last terminal in configuration located
LAST_FOUND:
	MOVL	R9,@4(AP)		; Return nr of terms found
	RET

	.PAGE
	.SBTTL	INS_TST_ENTRY - Enable Autobaud for New Terminal

;++
;  Functional Description:
;	Routine called to make a new terminal available for autobaud.
;	If the terminal is not already owned by us (and therefor already
;	setup), the TST entry is modified to make it appear that the
;	terminal has just been released by a user process.  The next
;	UPDATE_TST cycle will then pick up the terminal (now marked as
;	available for autobauding) and will cycle it from "busy" to
;	to "released" to "idle".
;
;  Calling Sequence:
;	PUSHL	#TST-index
;	CALLS	#1,INS_TST_ENTRY
;
;  Input Parameters:
;	4(AP) - Index of TST entry for terminal to add
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:  NONE
;  
;  Implicit Outputs:
;	TERM_STAT - Terminal Status Table entry modified
;	LOWEST_TERM_IDX - Lowest autobaud terminal. Updated.
;	HIGHEST_TERM_IDX - Highest autobaud terminal. Updated.
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	INS_TST_ENTRY,^M<R2>

;   Register usage:
;	R0-R1 - Scratch
;	R2 - Pointer to TST entry

	MULL3	#TST_C_ENTSZ,4(AP),R2	; Get TST offset to entry to insert
	MOVAL	TERM_STAT,R0		; Get TST base address
	ADDL	R0,R2			; Compute entry address

	IF <BC,#TST_V_AUTO,TST_W_STS(R2)> THEN

;  If not already enabled for autobaud and
	  IF <BC,#TST_V_OWNED,TST_W_STS(R2)> THEN

;  If we don't already own the terminal, grab it and start autobauding
	    MOVB	#TST_C_ST_BUSY,-
		TST_B_STATE(R2)		; Set state to BUSY
	    BISW	#TST_M_AUTO,-
		TST_W_STS(R2)		; Set autobaud enable bit

	    IF <LSS,4(AP),LOWEST_TERM_IDX> THEN
	      MOVL	4(AP),-
			LOWEST_TERM_IDX	; Reduce lower scan limit if needed
	    ENDIF

	    IF <GTR,4(AP),HIGHEST_TERM_IDX> THEN
	      MOVL	4(AP),-
			HIGHEST_TERM_IDX ; Raise higher scan limit if needed
	    ENDIF

	    MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	    LOG_MESSAGE -
		CODE=#BAUD_ADDED,-
		F1=#6,-
		F2=R1			; Issue log message.  New one added.

	  ENDIF

	ELSE

;  Note that autobaud was already enabled
	  MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	  LOG_MESSAGE -
		CODE=#BAUD_AUTONOW,-
		F1=#6,-
		F2=R1			; Issue log message - we already
					; have this one.
	ENDIF
	RET

	.PAGE
	.SBTTL	DEL_TST_ENTRY - Remove Terminal from Autobaud

;++
;  Functional Description:
;	Routine used to remove a terminal for consideration for autobauding.
;	If we don't own the terminal, its easy:  just clear the bit.  If we
;	own it, we must also cancel any outstanding I/O, deassign the channel
;	and deallocate the device.  All AST routines must be prepared to
;	field the $CANCEL on their I/O request.  Note that since removing
;	a terminal is probably in infrequent event, we don't bother to update
;	the lowest and highest terminal index pointers.  Scanning a few extra
;	TST entries is not that slow.
;
;  Calling Sequence:
;	PUSHL	#TST_index
;	CALLS	#1,DEL_TST_ENTRY
;
;  Input Parameters:
;	4(AP) - TST index of terminal to process
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal to be removed.
;
;  Implicit Outputs:
;	TERM_STAT - TST entry is modified to un-autobaud this terminal
;
;  Completion Status:  NON
;
;  Side Effects:
;	$CANCEL can cause AST routines to be called.
;
;--

	.ENTRY	DEL_TST_ENTRY,^M<R2>

;  Register usage:
;	R0-R1 - Scratch
;	R2 - Address of TST entry being manipulated

	MULL3	#TST_C_ENTSZ,4(AP),R2	; Get TST offset to entry to delete
	MOVAL	TERM_STAT,R0		; Get TST base address
	ADDL	R0,R2			; Compute address of entry

	ENB_LONG			;;Enable long branches for SMAC
	IF <BS,#TST_V_OWNED,TST_W_STS(R2)> THEN

;  We own the terminal.  Need to clean up outstanding reads and let it go.
	  BICW	#TST_M_OWNED,-
		TST_W_STS(R2)		; Clear "owned" bit so AST routines
					; know to ignore any I/O completions.

	  $CANCEL_S	CHAN=TST_W_CHAN(R2) ; Cancel pending I/O
					; Don't check for errors

	  $DASSGN_S	CHAN=TST_W_CHAN(R2) ; Deassign the channel
	  IF_ERROR -
		CODE=#BAUD_DASSGN 	; Stop if an error
	  CLRW	TST_W_CHAN(R2)		; Clear channel field in TST entry

	  PUSHAL	TST_T_NAME(R2)	; Build desc for term name. Address
	  PUSHL	#6			; Length of name
	  MOVL	SP,R0			; Get desc address
	  $DALLOC_S	DEVNAM=(R0)	; Deallocate the terminal
	  ADDL	#<2*4>,SP		; Remove desc from stack
	  IF_ERROR -
		CODE=#BAUD_DALLOC	; Stop if error
	ENDIF
	DSB_LONG			;;Disable long branches for SMAC

	BICW	#TST_M_AUTO,-
		TST_W_STS(R2)		; Clear autobaud enable bit

	MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	LOG_MESSAGE -
		CODE=#BAUD_REMOVE,-
		F1=#6,-
		F2=R1			; Issue log message
	RET

	.PAGE
	.SBTTL	HANG_UP - Hang up a terminal line

;++
;  Functional Description:
;	Routine to hang up a terminal line.  Can only be called once a 
;	channel has been assigned on the terminal.
;
;  Calling Sequence:
; 	This routine should be AST re-entrant since it may be called from
;	at AST level.
;
;	PUSHL	TST_entry_address
;	CALLS	#1,HANG_UP
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal to hangup
;	
;  Output Parameters: NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry of terminal to hangup.
;
;  Implicit Outputs:  NONE
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	HANG_UP,^M<R2>

;  Register usage:
;  R0 - R1 - Scratch
;  R2 - Address of TST entry of terminal to hangup

;  Hangup specified terminal
	MOVL	4(AP),R2		; Get pointer to TST entry
	$QIOW_S -
		CHAN=TST_W_CHAN(R2),-
		FUNC=#IO$_SETCHAR!IO$M_HANGUP,-
		IOSB=TST_Q_IOSB(R2),-
		P1=TST_Q_DEVCHR(R2)	; Hang it up!
	IF_ERROR -
		CODE=#BAUD_QIO		; Stop if error
	MOVZWL	TST_Q_IOSB(R2),R0	; Get I/O status
	IF_ERROR -
		CODE=#BAUD_HANGERR	; Stop if I/O error

;  Issue a log message
	MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	LOG_MESSAGE -
		CODE=#BAUD_HANG,-
		F1=#6,-
		F2=R1			; We hung it up
	RET

	.PAGE
	.SBTTL	SET_SPEED - Set Terminal Speed

;++
;  Functional Description:
;	Routine used to set the DZ-11 speed on a terminal line.
;	Cannot be used until a channel has been assigned on the device.
;
;  Calling Sequence:
;	This routine should be AST reentrant since it may be called from
;	AST level routines.
;
;	PUSHL	#speed_code
;	PUSHL	TST_entry_address
;	CALLS	#2,SET_SPEED
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal to set speed on.
;	8(AP) - Code for baud rate to be set
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal to be modified
;
;  Implicit Outputs:  NONE
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	SET_SPEED,^M<R2>

;  Register usage
;	R0-R1 - Scratch
;	R2 - Address of TST entry

	MOVL	4(AP),R2		; Get pointer to TST entry

;  Set the characteristics including speed.
	$QIOW_S -
		CHAN=TST_W_CHAN(R2),-
		FUNC=#IO$_SETCHAR,-
		IOSB=TST_Q_IOSB(R2),-
		P1=TST_Q_DEVCHR(R2),-
		P3=8(AP)		; Set speed characteristic

	IF_ERROR -
		CODE=#BAUD_QIO		; Stop if error on QIO
	MOVZWL	TST_Q_IOSB(R2),R0	; Get I/O status
	IF_ERROR -
		CODE=#BAUD_SPEEDERR	; Stop if I/O error

;  Issue log message
	MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	LOG_MESSAGE -
		CODE=#BAUD_SPEED,-
		F1=#6,-
		F2=R1,-
		F3=8(AP)		; Say what terminal and speed

	RET

	.PAGE
	.SBTTL	READ_AST - Terminal Read AST Routine

;++
;  Functional Description:
;	This AST routine is the one called when a read completes on an
;	autobaud terminal in the IDLE state.  When we are called, a
;	terminal received a character to initiate the autobaud sequence.
;	This routine could also be called when the actual device times out,
;	or when a $CANCEL is done on the line, such as when a FREE command
;	is done.
;
;  Calling Sequence:
;	Called at AST level by VMS.
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal completing. (AST parameter)
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal whose read completed.
;
;  Implicit Outputs:  NONE
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	READ_AST,^M<R2>

;  Register usage
;  	R0-R1 - Scratch
;	R2 - Address of TST entry

	MOVL	4(AP),R2		; Get pointer to TST entry

;  Log the read completion
	MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	LOG_MESSAGE -
		CODE=#BAUD_NRMCOM,-
		F1=#6,-
		F2=R1,-
		F3=TST_Q_IOSB(R2),-
		F4=TST_Q_IOSB+4(R2),-
		F5=TST_T_BUFFER(R2),-
		F6=TST_B_SPEED(R2)	; Log all the details

	ENB_LONG			;; Enable long branches for SMAC
	IF  <EQL,#SS$_CANCEL,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR <EQL,#SS$_ABORT,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR <EQL,#SS$_HANGUP,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR  <EQL,#SS$_TIMEOUT,-
		TST_Q_IOSB(R2),TYPE=W> THEN

	  IF <BS,#TST_V_OWNED,TST_W_STS(R2)> THEN

;  If we get one of these statuses and the "owned" bit is clear, we are
;  in the process of freeing the terminal from autobaud so we do nothing.
;  If the bit is set, there must have been a real device timeout or carrier
;  drop.  In this case, everything is still setup correctly, so we just issue
;  a new read.

	    $QIO_S -
		CHAN=TST_W_CHAN(R2),-
		FUNC=#READ_FUNC,-
		IOSB=TST_Q_IOSB(R2),-
		ASTADR=READ_AST,-
		ASTPRM=R2,-
		P1=TST_T_BUFFER(R2),-
		P2=#1			; Read again
	    IF_ERROR -
		CODE=#BAUD_QIO		; Stop if an error
	    MOVAL	TST_T_NAME(R2),R1 ; Get address of terminal name
	    LOG_MESSAGE -
		CODE=#BAUD_NRMREAD,-
		F1=#6,-
		F2=R1			; Log the read

	  ENDIF

	ELSE

;  Must be a  read completion with real data.  Process it.
	    CALL	DATA_RECEIVED, R2 ; Process read completion
	ENDIF
	DSB_LONG			;;Disble long branches for SMAC

	RET

	.PAGE
	.SBTTL	RELEASE_AST - Terminal AST Read Routine

;++
;  Functional Description:
;	Routine called when the RELEASED state read (with timeout) completes.
;	The RELEASED state is entered when a terminal is first enabled for
;	autobaud, or when a user logs off the terminal, and it becomes free.
;	There are three possible reasons for this AST routine to be entered:
;	One, the user could have typed another carriage return before the
;	line was hung up.  This is treated as a normal read completion.
;	We also could get here as a result of the timeout of the RELEASE
;	state read.  This occurs when the logged off user does not type
;	anything following his logout.  At this point, we hangup the line
;	(to drop DTR), and enter the HANGUP_PENDING state.  From HANGUP_
;	PENDING we will eventually return the line state to IDLE.   The 
;	third possibility is that the terminal is being removed from
;	autobauding and a $CANCEL was issued.  In that case, we do nothing.
;
;  Calling Sequence:
;	Called at AST level by VMS.
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal whose read completed.(AST 
;		parameter)
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal being processed
;
;  Implicit Outputs:
;	TERM_STAT - TST entry may be updated
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	RELEASE_AST,^M<R2>

;  Register usage:
;	R0-R1 - Scratch.
;	R2 - Address of TST entry for terminal whose read completed.

	MOVL	4(AP),R2		; Get pointer to TST entry

	ENB_LONG			;;Enable long branches for SMAC

;  Log the read completion
	MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	LOG_MESSAGE -
		CODE=#BAUD_RELCOM,-
		F1=#6,-
		F2=R1,-
		F3=TST_Q_IOSB(R2),-
		F4=TST_Q_IOSB+4(R2),-
		F5=TST_T_BUFFER(R2),-
		F6=TST_B_SPEED(R2)	; Log the read with all details

	IF  <EQL,#SS$_CANCEL,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR <EQL,#SS$_ABORT,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR <EQL,#SS$_HANGUP,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR <EQL,#SS$_TIMEOUT,-
		TST_Q_IOSB(R2),TYPE=W> THEN 

	  IF <BS,#TST_V_OWNED,TST_W_STS(R2)> THEN

;  If the "owned" bit is clear, we do nothing, since this can only happen
;  during the removal of a terminal from autobauding.
;  If the bit is set, we must process the termination.  Either the user hung
;  up, or the RELEASE state read timed out, or the physical device timed
;  out.  In any case, we hangup and wait for the hangup to complete.
	    CALL  HANG_UP, R2		; Hangup the line
	    MOVB  #TST_C_ST_HNGUP,-
		TST_B_STATE(R2)		; Set state to HANGUP_PENDING
	    $SETIMR_S -
		DAYTIM=HANG_DELTA,-
		ASTADR=HANG_AST,-
		REQIDT=R2		; Issue timer request for enough
					; time for hangup to complete.
	    IF_ERROR -
		CODE=#BAUD_SETIMR	; Stop if error
	  ENDIF

	ELSE

;  The read completed with some data, so process it.
	  CALL	DATA_RECEIVED, R2

	ENDIF
	DSB_LONG			;;Disable long branches for SMAC

	RET

	.PAGE
	.SBTTL	ADJ_SPEED_AST - Terminal Read AST Routine

;++
;  Functional Description:
;	Routine called when a read issued from the ADJUST_SPEED state 
; 	completes.  The ADJUST_SPEED state is entered after a character
;	has been read, but before it is possible to determine the speed
;	of the terminal.  There are three reasons why this AST routine
;	could be called.  We could get called as a result of a normal
;	read completing with the users next carriage return.  We could
;	also get called as a result of the ADJUST_SPEED read timing out.
;	Either the user gave up (after we had modified the line speed 
;	at least once for him), or the user modified his terminal speed while
;	we were trying to figure it out.  If he raises his speed while
;	we are adjusting the DZ-11 speed downward, we could start missing
;	his input (the start bits are too short for the DZ-11 at a slow 
;	speed setting).  In either case, we hangup the line and go into
;	the HANGUP_PENDING state to wait for the hangup to complete.
;	Eventually, that state returns to the IDLE state.
;	The third possibility is that a $CANCEL  was done while removing the
;	terminal from autobauding.
;
;  Calling Sequence:
;	Called at AST level by VMS.
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal whose read completed (AST
;		parameter)
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal
;
;  Implicit Outputs:
;	TERM_STAT - TST entry may be updated
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	ADJ_SPEED_AST,^M<R2>

;  Register usage:
;	R0-R1 - Scratch
;	R2 - Address of TST entry for terminal being processed

	MOVL	4(AP),R2		; Get pointer to TST entry


;  Log the read completion
	MOVAL	TST_T_NAME(R2),R1	; Get pointer to terminal name
	LOG_MESSAGE -
		CODE=#BAUD_ADJCOM,-
		F1=#6,-
		F2=R1,-
		F3=TST_Q_IOSB(R2),-
		F4=TST_Q_IOSB+4(R2),-
		F5=TST_T_BUFFER(R2),-
		F6=TST_B_SPEED(R2)	; Log all the details

	ENB_LONG			;;Enable long branches for SMAC
	IF  <EQL,#SS$_CANCEL,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR  <EQL,#SS$_ABORT,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR <EQL,#SS$_HANGUP,-
		TST_Q_IOSB(R2),TYPE=W> -
	  OR  <EQL,#SS$_TIMEOUT,-
		TST_Q_IOSB(R2),TYPE=W> THEN

	  IF <BS,#TST_V_OWNED,TST_W_STS(R2)> THEN

;  If the owned bit is clear, we were called during the release of a
;  terminal from autobauding.  In that case, we do nothing.  If the bit
;  is set, either the read timed out while we were adjusting, or the
;  physical device timed out or lost carrier.  In either case, reset 
;  speed, hangup, and await hangup completion.
	    CALL	SET_SPEED,-
		R2,#DEFAULT_SPEED	; Set terminal speed to defaule
	    MOVB	#DEFAULT_SPEED,-
		TST_B_SPEED(R2)		; and update speed field of TST
	    CALL	HANG_UP, R2	; Hangup the line

	    MOVB	#TST_C_ST_HNGUP,-
		TST_B_STATE(R2)		; Set state to HANGUP_PENDING

	    $SETIMR_S -
		DAYTIM=HANG_DELTA,-
		ASTADR=HANG_AST,-
		REQIDT=R2		; Issue timer request to wait for 
					; hangup to complete.
	    IF_ERROR -
		CODE=#BAUD_SETIMR	; Stop if error
	  ENDIF
 	ELSE

;  Another read completed with real data.  Process it
	  CALL	DATA_RECEIVED, R2

	ENDIF
	DSB_LONG			;;Disable long branches for SMAC

	RET

	.PAGE
	.SBTTL	HANG_AST - Hangup Timer AST Routine

;++
;  Functional Description:
;	This routine is called in response to a timer request used to
;	wait for a line hangup to complete.  The hangup function takes
;	some interval to complete after the HANGUP I/O function completes.
;	Since the line is safely hung up, we can now issue a normal, non-
;	timed read and set the state to IDLE
;
;  Calling Sequence:
;	Called at AST level by VMS.
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal whose read completed (AST
;		parameter)
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal
;
;  Implicit Outputs:
;	TERM_STAT - TST entry is updated
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.ENTRY	HANG_AST,^M<R2>

;  Register usage:
;	R0-R1 - Scratch
;	R2 - 	Address of TST entry for line being hung up

	MOVL	4(AP),R2		; Get pointe to TST entry
	$QIO_S -
		CHAN=TST_W_CHAN(R2),-
		FUNC=#READ_FUNC,-
		IOSB=TST_Q_IOSB(R2),-
		ASTADR=READ_AST,-
		ASTPRM=R2,-
		P1=TST_T_BUFFER(R2),-
		P2=#1			; Issue a normal read
	IF_ERROR -
		CODE=#BAUD_QIO		; Stop if error
	MOVAL	TST_T_NAME(R2),R1 ; Get address of terminal name
	LOG_MESSAGE -
		CODE=#BAUD_NRMREAD,-
		F1=#6,-
		F2=R1			; Log the read

	MOVB	#TST_C_ST_IDLE,-
		TST_B_STATE(R2)		; Set state to IDLE
	RET

	.PAGE
	.SBTTL	DATA_RECEIVED - Terminal Read Completed with DATA

;++
;  Functional Description:
;	This routine is called by all of the terminal AST routines when
;	a read completes with data.  This routine attempts to determine
;	the baud rate of the incoming signal based on the rate at which
;	the read took place, and the garbage which was received.  If the
;	rate can be determined, the line is set to the correct speed, the
;	line is freed, and a message is sent to the job controller to 
;	initiate a login.  If the incoming rate cannot be determined,
;	the DZ-11 speed is adjusted and another read is posted.  This
;	is the ADJUST_SPEED state, and the read is with timeout.  That
;	is so if the user goes away, or we manage to totally misadjust
;	the DZ-11 speed, we will be able to recover.
;
;  Calling Sequence:
;	Called at AST level.
;	PUSHL	TST_entry_address
;	CALLS	#1,DATA_RECEIVED
;
;  Input Parameters:
;	4(AP) - Address of TST entry for terminal that completed
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for terminal.
;
;  Implicit Outputs:
;	TERM_STAT - TST entry may be updated
;
;  Completion Status:  NONE
;
;  Side Effects:
;	Terminal may be freed from our control and a login started.
;
;--

	.PSECT	RODATA RD,NOWRT,NOEXE,SHR,LONG

;  This table is used for mapping the received garbage character to a 
;  possible baud rate.  Each row corresponds to a rate at which a 
;  read took place.  Each column corresponds to the garbage that would
;  be received if the line were at one of the 15 possible baud rates.
GARP_TABLE:
	.BYTE	13,98,124,126,127,127,0,0,0,0,0,0,0,0,0 	; 50 baud
	.BYTE	114,13,98,114,114,127,127,0,0,0,0,0,0,0,0 	; 75 baud
	.BYTE	70,59,13,71,71,126,127,0,0,0,0,0,0,0,0		; 110 baud
	.BYTE	12,118,25,13,13,126,127,127,0,0,0,0,0,0,0	; 134 baud
	.BYTE	28,102,59,29,13,114,127,127,0,0,0,0,0,0,0	; 150 baud
	.BYTE	96,120,28,78,102,13,114,127,0,0,0,0,0,0,0	; 300 baud
	.BYTE	0,0,112,120,120,102,13,126,127,127,127,127
	.BYTE	127,0,0			 			; 600 baud
	.BYTE	0,0,0,0,0,120,102,13,98,114,126,127,127,0,127 	; 1200 baud
	.BYTE	0,0,0,0,0,96,28,114,13,5,70,114,127,0,127 	; 1800 baud
	.BYTE	0,0,0,0,0,64,60,114,29,13,5,114,126,0,127 	; 2000 baud
	.BYTE	0,0,0,0,0,0,120,102,59,25,13,98,114,0,127 	; 2400 baud
	.BYTE	0,0,0,0,0,0,96,28,102,118,59,13,71,0,127 	; 3600 baud
	.BYTE	0,0,0,0,0,0,0,120,12,78,102,59,13,0,114 	; 4800 baud
	.BYTE	0,0,0,0,0,0,0,96,120,56,28,102,123,13,71  	; 7200 baud
	.BYTE	0,0,0,0,0,0,0,0,112,112,120,12,102,0,13  	; 9600 baud

	.PSECT	CODE EXE,NOWRT,SHR,LONG
	.ENTRY	DATA_RECEIVED,^M<R2,R3,R4,R5>

;  Register usage:
;	R0 - R1 - Scratch
;	R2 - Pointer to TST entry
;	R3 - The character read from the terminal
;	R4 - If non-zero, the baud rate of the incoming signal
;	R5 - Base address of the row of GARP_TABLE for the baud
;		rate we read at.

	MOVL	4(AP),R2		; Get pointer to TST entry
	LOG_MESSAGE -
		CODE=#BAUD_DATARX	; Log that we are processing 
					; received data

;  Analyze the character we received
	CLRL	R3			; Clear out garbage
	BICB3	#^X80,TST_T_BUFFER(R2),-
		R3			; Get significant part of char

	CLRL	R4			; Clear "character found" baud rate
	MOVZBL	TST_B_SPEED(R2),R0	; Get code for current speed
	ENB_LONG			;;Enable long branches for SMAC
	IF <EQL,R3,#ASCII_CR,TYPE=B> -
	  AND <BS,R0,-
	  OUR_RATES> THEN		; If we got a CR and it was at a legal
					; baud rate
	  MOVZBL -
		TST_B_SPEED(R2),R4	; Set the baud rate to use

	ELSE

;  Look for what we got in the translation table, and maybe we can tell
;  what the incoming rate is.
	  MOVZBL	TST_B_SPEED(R2),R5 ; Get the speed we read at
	  DECL	R5			; Less one
	  MULL	#NR_DZ_BAUDS,R5		; Times nr of baud rates per row
					; gives index to first value for
					; our speed.
	  MOVAL	GARP_TABLE-1,R0		; Translation table base addr less 1
	  ADDL	R0,R5			; Gives base address for our row -1 
	  MOVL	#1,R1			; Init loop count (corresponds to
					; speed code)

	  WHILE <LEQ,R1,#NR_DZ_BAUDS> THEN

	    BREAK IF <EQL,R3,(R5)[R1],TYPE=B> AND -
	      <BS,R1,OUR_RATES> 	; Break if match found and it's at a
					; legal speed.

	    INCL	R1		; Increment loop counter
	  ENDWHILE

	  IF <LEQ,R1,#NR_DZ_BAUDS> THEN

;  We found a match in the table.  Now look to see if it is unique.
	    MOVL	R1,R0		; Save the location of the match
	    INCL	R1		; and start one beyond there

	    WHILE <LEQ,R1,#NR_DZ_BAUDS> THEN ; Loop through remainder of table
	      BREAK IF <EQL,R3,(R5)[R1],TYPE=B> AND -
		<BS,R1,OUR_RATES>	; Break if another match found at a
					; legal speed
	      INCL	R1		; Increment loop counter
	    ENDWHILE

	    IF <GTR,R1,#NR_DZ_BAUDS> THEN ; If we reached limit, no match
	      MOVL	R0,R4		; The unique match was as found
					; above. Use that as the line speed.
	    ENDIF

	  ENDIF

	ENDIF

	IF <NEQ,R4> THEN

;  If R4 contains a baud rate, we know what rate to use for the  line

	  IF <NEQ,R4,TST_B_SPEED(R2),TYPE=B> THEN
;  If not already at this baud rate, set it
	    CALL	SET_SPEED,R2,R4	; Set to right speed
	    MOVB	R4,TST_B_SPEED(R2) ; and update TST
	  ENDIF

;  Give the terminal to the user
	  $DASSGN_S -
		CHAN=TST_W_CHAN(R2)	; Deassign and deallocate terminal
	  IF_ERROR -
		CODE=#BAUD_DASSGN	; Stop if an error
	  PUSHAL	TST_T_NAME(R2)	; Build desc for term name. Address
	  PUSHL	#6			; and length
	  MOVL	SP,R1			; Get descriptor address
	  $DALLOC_S -
		DEVNAM=(R1)		; Deallocate the term
	  IF_ERROR -
		CODE=#BAUD_DALLOC	; Stop if error
	  BICW	#TST_M_OWNED,-
		TST_W_STS(R2)		; Clear the "owned" bit
	  CALL	SND_JBC_MSG, R2		; Yell at JOB_CONTROL
	  MOVAL	TST_T_NAME(R2),-
		R1			; Get address of terminal name
	  MOVZBL	TST_B_SPEED(R2),-
		R3			; Get speed as longword
	  LOG_MESSAGE -
		CODE=#BAUD_TOUSER,-
		F1=#6,-
		F2=R1,-
		F3=R3			; Log that we let the user have the 
					; line
	ELSE

;  Can't make speed determination yet.  Adjust DZ-11 speed and try another
;  read.  This moves into the ADJUST_SPEED state
	  CLRL	R1			; R1 will hold new baud rate

	  IF <EQL,R3,#^X7F> THEN	; If DZ too slow

	    IF <GEQ,TST_B_SPEED(R2),-
	      HIGHEST_BAUD,TYPE=B> THEN

	      ADDB3	LOWEST_BAUD,-
		#2,R1			; If already at top limit, start down
	    ELSE
	      ADDB3	TST_B_SPEED(R2),#2,-
		R1			; Else raise rate some more
	    ENDIF

	  ENDIF

	  IF <EQL,R3,#^X0> THEN		; If DZ too fast

	    IF <LEQ,TST_B_SPEED(R2),-
	      LOWEST_BAUD,TYPE=B> THEN
	      SUBB3	#2,-
		HIGHEST_BAUD,R1		; If at lower limit, try higher speed.
	    ELSE
	      SUBB3	#3,TST_B_SPEED(R2),-
		R1			; Else lower baud rate some
	    ENDIF

	  ENDIF

	  IF <EQL,R1> THEN		; If neither of these cases
	    ADDB3	#1,-
		TST_B_SPEED(R2),R1	; Try raising a little
	  ENDIF

;  Insure our selection is in range
	  IF <GTR,R1,HIGHEST_BAUD> THEN
	    MOVL	HIGHEST_BAUD,R1	; Limit upper to HIGHEST_BAUD
	  ENDIF

	  IF <LSS,R1,LOWEST_BAUD> THEN
	    MOVL	LOWEST_BAUD,R1	; Limit lower to LOWEST_BAUD
	  ENDIF

	  MOVB	R1,TST_B_SPEED(R2)	; And update TST
	  CALL	SET_SPEED, R2, R1	; Set the speed to our choice
	  $QIO_S -
		CHAN=TST_W_CHAN(R2),-
		FUNC=#READ_FUNC!IO$M_TIMED,-
		IOSB=TST_Q_IOSB(R2),-
		ASTADR=ADJ_SPEED_AST,-
		ASTPRM=R2,-
		P1=TST_T_BUFFER(R2),-
		P2=#1,-
		P3=#ADJ_SPEED_SECS	; Issue timed read
	  IF_ERROR -
		CODE=#BAUD_QIO		; Stop if error
	  MOVAL	TST_T_NAME(R2),R1	; Get address of terminal name
	  LOG_MESSAGE -
		CODE=#BAUD_ADJREAD,-
		F1=#6,-
		F2=R1			; Log the read
	  MOVB	#TST_C_ST_ADJ,-
		TST_B_STATE(R2)		; Set state to adjust speed

	ENDIF
	DSB_LONG			;;Disable long branches for SMAC

	RET


	.PAGE
	.SBTTL	SND_JBC_MSG - Send message to JOB_CONTROL

;++
;  Functional Description:
;	Routine to send a message to the Job Controller process to simulate
;	a terminal unsolicited interrupt.  This is done following
;	a baud rate determination so that the user's login will be initiated
;	on the terminal.
;
;  Calling Sequence:
;	PUSHL	TST_entry_address
;	CALLS	#1,SND_JBC_MSG
;
;  Input Parameters:
;	4(AP) - Address of TST entry for the terminal
;	
;  Output Parameters:  NONE
;
;  Implicit Inputs:
;	TERM_STAT - TST entry for the specified terminal
;
;  Implicit Outputs:  NONE
;
;  Completion Status:  NONE
;
;  Side Effects:  NONE
;
;--

	.PSECT	RWDATA RD,WRT,NOEXE,NOSHR,LONG

;  Local storage
JBC_MSG:
	.WORD	1			; Job controller message type
JBC_MSG_UNIT:
	.BLKW	1			; Unit number field
	.BYTE	3			; Length of device/controller name
	.WORD	^A/TT/			; Device name/controller field
JBC_MSG_CTRL:
	.BLKB	1

JBC_MSG_CHAN:
	.BLKW	1			; Buffer to hold mailbox channel

JBC_MBX_NAME:
	.ASCID	/_MB1:/			; Job control mailbox name

	.PSECT	CODE NOWRT,EXE,SHR,LONG
	.ENTRY	SND_JBC_MSG,^M<R2>

;  Register usage
;	R0-R1 - Scratch
;	R2 - Address of TST entry for terminal

;  Build message
	MOVL	4(AP),R2		; Get pointer to TST entry
	MOVB	TST_T_NAME+3(R2),-
		JBC_MSG_CTRL		; Put controller name into message
	SUBB3	#^A/0/,-
		TST_T_NAME+4(R2),-
		JBC_MSG_UNIT		; Convert unit name to binary and plug
					; into message

;   Get channel on mailbox and send message
	$ASSIGN_S -
		DEVNAM=JBC_MBX_NAME,-
		CHAN=JBC_MSG_CHAN	; Get channel
	IF_ERROR -
		CODE=#BAUD_ASSIGN	; Stop if error

	$QIO_S -
		CHAN=JBC_MSG_CHAN,-
		FUNC=#IO$_WRITEVBLK,-
		P1=JBC_MSG,-
		P2=#8			; Send the message
	IF_ERROR -
		CODE=#BAUD_QIO		; Stop if error

	$DASSGN_S -
		CHAN=JBC_MSG_CHAN	; Deassign channel
	IF_ERROR -
		CODE=#BAUD_DASSGN	; Stop if error

	RET

	.END	BAUD
