Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!husc6!necntc!ames!sdcsvax!ucbvax!ENGVAX.SCG.HAC.COM!KVC
From: KVC@ENGVAX.SCG.HAC.COM (Kevin Carosso)
Newsgroups: comp.os.vms
Subject: CMU pseudo-terminal drivers (part 2 of 3) [DCL archive format]
Message-ID: <8707200047.AA02741@ucbvax.Berkeley.EDU>
Date: Thu, 16-Jul-87 19:51:00 EDT
Article-I.D.: ucbvax.8707200047.AA02741
Posted: Thu Jul 16 19:51:00 1987
Date-Received: Mon, 20-Jul-87 03:44:44 EDT
Sender: daemon@ucbvax.BERKELEY.EDU
Distribution: world
Organization: The ARPA Internet
Lines: 1014
$ show default
$ check_sum = 1596636955
$ write sys$output "Creating PYDRIVER.MAR"
$ create PYDRIVER.MAR
$ DECK/DOLLARS="$*$*EOD*$*$"
.TITLE PYDRIVER - Pseudo terminal driver interface
.IDENT 'V04-007'
;
;++
; FACILITY:
;
; VAX/VMS Pseudo Terminal Driver interface
;
; ABSTRACT:
;
; The pseudo terminal consists of two devices.
; This is the non terminal part of the two devices.
;
; AUTHOR:
;
; 19-Nov-1982 Dale Moore Redid the TP driver for VMS 3.0
;
; This program has been granted to the public domain by the author.
;
; Revision History:
;
; Version 'V03-001'
; DWM - Added Page seperators
; - On Last cancel, invoke hangup on TP device
; - changed PY_STOP and PY_STOP2 to return instead
; of looping for more.
; - Changed last cancel to call ioc$reqcom instead of
; using macro REQCOM which is a branch ioc$reqcom.
; Version V03-002 - Changed to Clear word rather than clear byte
; in startio routine on word field.
;
; Version V03-003 (Thu Dec 9 12:42:38 1982) D. Kashtan
; Made into a TEMPLATE driver.
; Version V03-004 (Fri Dec 10 11:40:35 1982) D. Kashtan
; Made EXE$... into +EXE$... in FDT dispatch table,
; fixing bug that crashed system in SET/SENSE MODE/CHAR
; Version V03-005 (14-Jun-1983) Dale Moore
; Add R4 to calls to IOC$INITIATE.
; TTY$STARTIO mucks R4
; Version V03-006 (12-Jul-1983) Mark London, MIT Plasma Fusion Center
; - Set terminal to NOBROADCAST when no READ QIO avail-
; able so as to allow Broadcasts without hanging up.
; (When no QIO available, UCB$M_INT is enabled, and
; the Broadcast don't get handled. The sender of a
; Broadcast goes into a wait state until the broadcast
; is completed or timed-out, neither or which can
; happen. Setting NOBROADCASTs at least allow the
; Broadcast to finish. What is needed is a CTRLS state
; that doesn't allow Broadcasts to break through.)
; - Added MOVC3 instruction for burst data in PY$STARTIO,
; which "should" speed up the transfers.
; - Fixed data transfer problem by raising to fork IPL
; while calling PUTNXT in PY$FDTWRITE. NOTE: TPA0 must
; be a mailbox to avoid TT reads from timing out.
;
; Version V04-001 - Doug Davis, Digital Equipment
; - Most of the changes required for migration to
; Version 4.0 relate to the new handling of UCB
; creation and deletion. This includes adding
; a CLONEDUCB entry point to the dispatch table,
; and "cloning" the UNITINIT routine to handle the
; required entry. Also changed the call from
; IOC$CREATE_UCB to IOC$CLONE_UCB, with associated
; maintainence of the UCB$V_DELETEUCB bit in the
; UCB$L_STS field.
; - Changes were also incorporated reflecting new
; methods of XON/XOFF flow control.
; - Although pieces of the original code have been
; superceded by these changes ( example - functions
; that were performed by Unit_Init for new units
; are are now performed by Clone_Init ), most of
; the original code was left in place and/or commented
; out.
;
; NOTE - No subroutines preambles were modified to
; reflect these changes.
;
; Version V04-002 (20-Jan-1985) Mark London, MIT Plasma Fusion Center
; - Changed test for output characters after call to
; UCB$L_TT_PUTNXT and UCB$L_TT_GETNXT. Output is
; indicated in UCB$B_TT_OUTYPE.
;
; Version V04-003 (24-Jun-1985) Kevin Carosso, Hughes Aircraft Co., S&CG
; Cleaned this thing up quite a bit.
; - Got rid of MBX characteristic on the devices. This
; was a holdover to before cloned devices really
; existed.
; - Got rid of the UNIT_INIT routine completely. This
; was replaced by a CLONE_UCB routine.
; - Leave the PY template device OFFLINE. This is what
; other TEMPLATE devices do, to indicate that you
; really cannot do I/O to the template.
; - Rewrote the CANCEL_IO routine to issue a DISCONNECT
; on the TP device at last deassign of the PY device.
; This causes the TP device to hangup on it's process.
; Works quite nicely with VMS V4 connect/disconnect
; mechanism. Also, the devices should never stay
; around after last deassign on the PY, if you want to
; reconnect, count on VMS connect/disconnect instead,
; it's much less of a security hole.
; - Got rid of all modem operations. Improper use tended
; to crash the system and they are not necessary. TP
; device is always NOMODEM. HANGUP works as you want
; it to without the modem stuff.
; - Got rid of the BRDCST on/off stuff. It doesn't seem
; to be necessary any more. It also had a bug in it
; somewhere that caused the terminal to start off
; NOBRDCST when it shouldn't.
; - General house-cleaning. Got rid of commented out
; lines from VMS V3 version. Fixed up typos in
; comments.
;
; Version V04-004 (10-Feb-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
; Changed all references to PTDRIVER to TPDRIVER because
; DEC (bless their little hearts) invented the *#$&
; TU81 and use PTA0: now.
;
; Version V04-005 (3-Sep-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
; Fixed bug whereby the sequence ^S followed by ^Y
; would cause a system hang. The fix is really in
; TPDRIVER.
;
; Version V04-006 (5-Dec-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
; Fixed the infamous character munging bug. Turns
; out that in FDTWRITE we were enabling interrupts
; after doing the PUTNXT and before checking for
; a char. Now check for the character and then
; ENBINT after we've decided what to do. I assume
; UCB$B_TT_OUTYPE field was getting corrupted.
;
; Version V04-007 (10-JUL-1987) Kevin Carosso, Hughes Aircraft Co., S&CG
; Fix in TPDRIVER for timeouts. Don't bother
; clearing the TIM bit all the time in here now.
;
; Also, while we're in here, lets make the device
; acquire "NODE$" prefixes, since mailboxes do.
;--
.PAGE
.SBTTL Declarations
.LIBRARY /SYS$LIBRARY:LIB.MLB/
;
; External Definitions:
;
.NOCROSS
; $ACBDEF ; Define ACB
$CRBDEF ; Define CRB
$CANDEF ; Define cancel codes
$DDBDEF ; DEFINE DDB
$DDTDEF ; DEFINE DDT
$DEVDEF ; DEVICE CHARACTERISTICS
$DYNDEF ; Dynamic structure definitions
$IODEF ; I/O Function Codes
$IRPDEF ; IRP definitions
$JIBDEF ; Define JIB offsets
$SSDEF ; DEFINE System Status
$PCBDEF ; Define PCB
$PRDEF ; Define PR
$TTYDEF ; DEFINE TERMINAL DRIVER SYMBOLS
$TTDEF ; DEFINE TERMINAL TYPES
$TT2DEF ; Define Extended Characteristics
$UCBDEF ; DEFINE UCB
$VECDEF ; DEFINE VECTOR FOR CRB
$TTYMACS ; DEFINE TERMINAL DRIVER MACROS
$TTYDEFS ; DEFINE TERMINAL DRIVER SYMBOLS
.CROSS
;
; Local definitions
;
; QIO Argument list offsets
;
P1 = 0
P2 = 4
P3 = 8
P4 = 12
P5 = 16
P6 = 20
;
; New device class for control end
;
DC$_PY = ^XFF
DT$_PY = 0
;
; Definitions that follow the standard UCB fields for TP driver
; This will all probably have to be the same as the standard term
$DEFINI UCB ; Start of UCB definitions
.=UCB$K_TT_LENGTH ; Position at end of UCB
$DEF UCB$L_TP_XUCB .BLKL 1 ; UCB of corresponding
; control/application unit
$DEF UCB$K_TP_LEN ; Size of UCB
$DEFEND UCB ; End of UCB definitions
;
; Definitions that follow the standard UCB fields in PY devices
;
$DEFINI UCB ; Start of UCB definitions
.=UCB$K_LENGTH ; position at end of UCB
$DEF UCB$L_PY_XUCB .BLKL 1 ; UCB of terminal part of pseudo terminal
$DEF UCB$K_PY_LEN ; Size of UCB
$DEFEND UCB ; end of UCB definitions
.PAGE
;
; LOCAL Storage
;
.PSECT $$$105_PROLOGUE
.SBTTL Standard Tables
;
; Driver prologue table:
;
PY$DPT::
DPTAB - ; Driver Prologue table
END = PY$END,- ; End and offset to INIT's vectors
UCBSIZE = UCB$K_PY_LEN,-; Size of UCB
FLAGS=DPT$M_NOUNLOAD,- ; Don't allow unload
ADAPTER=NULL,- ; ADAPTER TYPE
NAME = PYDRIVER ; Name of driver
DPT_STORE INIT
DPT_STORE UCB,UCB$W_UNIT_SEED,W,0 ; SET UNIT # SEED TO ZERO
DPT_STORE UCB,UCB$B_FIPL,B,8 ; Fork IPL
DPT_STORE UCB,UCB$W_STS,W,- ; TEMPLATE device
DPT_STORE UCB,UCB$L_DEVCHAR,L,<- ; Characteristics
DEV$M_REC!- ; record oriented
DEV$M_AVL!- ; available
DEV$M_IDV!- ; input device
DEV$M_ODV> ; output device
DPT_STORE UCB,UCB$L_DEVCHAR2,L, - ; Device characteristics
; prefix with "NODE$"
DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_PY
DPT_STORE UCB,UCB$B_DIPL,B,8 ; Device IPL = FIPL (no device)
DPT_STORE DDB,DDB$L_DDT,D,PY$DDT
DPT_STORE REINIT
DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,D,PY$INITIAL ; Controller
DPT_STORE END
.PAGE
.SBTTL Driver Dispatch table and function decision table
;
; Driver Dispatch table
;
DDTAB DEVNAM = PY,- ; Device name
START = PY$STARTIO,- ; Start I/O routine
FUNCTB = PY$FUNCTAB,- ; The function table
CANCEL = PY$CANCEL,- ; the cancel i/o routine
CLONEDUCB = PY$CLONE_INIT ; Entry when template cloned.
;
; Function Decision table for PY devices
;
PY$FUNCTAB:
FUNCTAB ,- ; Legal Functions
FUNCTAB ,- ; Buffered I/O functions
FUNCTAB PY$FDTREAD,
FUNCTAB PY$FDTWRITE,
; FUNCTAB +EXE$SETMODE,
; FUNCTAB +EXE$SETCHAR,
FUNCTAB +EXE$SENSEMODE,
.SBTTL Local Storage - Name of companion device
TPSTRING: .ASCII /TPA/
TPLENGTH = . - TPSTRING
.PAGE
.SBTTL PY$FDTREAD - Function decision routine for PY control read
;++
; PY$FDTREAD
;
; Functional Description:
;
; This routine is called from the function decision table dispatcher
; to process a read physical, read logical, read virtual I/O function.
;
; The function first verifies the caller's parameters, terminating
; the request with immediate success or error if necessary.
; A system buffer is allocated and its
; address is saved in the IRP. The caller's quota is updated, and
; the read request is queued to the driver for startup.
;
; Inputs:
;
; R0,R1,R2 = Scratch
; R3 = IRP Address
; R4 = Address of PCB for current process
; R5 = Device UCB address
; R6 = Address of CCB
; R7 = I/O function code
; R8 = FDT Dispatch addr
; R9,R10,R11 = Scratch
; AP = Address of function parameter list
; P1(AP) = Buffer Address
; P2(AP) = Buffer Size
;
; Outputs:
;
; R0,R1,R2,R11 = Destroyed
; R3-R10,AP = Preserved (pickled)
; IRP$L_SVAPTE(R3)= Address of allocated system buffer
; IRP$W_BOFF(R3) = Requested byte count
;
; System Buffer:
; LONGWORD/0 = Address of start of data= buff+12
; LONGWORD/1 = Address of user buffer
;
;--
PY$FDTREAD::
MOVZWL P2(AP),R1 ; Get buffer Size
BNEQ 15$
JMP 10$ ; Is the size zero? If so, go do it easy.
15$: MOVL P1(AP),R0 ; Get buffer Address
JSB G^EXE$READCHK ; Do we have access to the buffer
PUSHR #^M ; Save user buffer address and IRP address
ADDL #12,R1 ; Add 12 bytes for buffer header
JSB G^EXE$BUFFRQUOTA; Is there enough buffer space left in
; the quota?
BLBC R0, 30$ ; Branch if insufficient quota
JSB G^EXE$ALLOCBUF ; Allocate a system buffer
BLBC R0, 30$ ; Branch if none available
POPR #^M ; Restore user buffer and irp address
MOVL R2,IRP$L_SVAPTE(R3) ; Save address of buffer
MOVW R1,IRP$W_BOFF(R3) ; and requested byte count
MOVZWL R1,R1 ; convert to longword count
MOVL PCB$L_JIB(R4),R11 ; Get Jib address
SUBL R1,JIB$L_BYTCNT(R11) ; Adjust quota count
MOVAB 12(R2),(R2) ; Save addr of start of user data
MOVL R0,4(R2) ; Save user buffer address in 2nd
; longword
JMP G^EXE$QIODRVPKT ; Queue I/O packet to start I/O routine
;
; Did he request a read of zero bytes?
;
10$: MOVL #SS$_NORMAL,R0 ; Everything is ok
JMP G^EXE$FINISHIOC ; complete I/O request
;
; Come here when something goes wrong
;
30$: POPR #^M ; Clear buffer addr and restore IRP
JMP G^EXE$ABORTIO ; complete I/O request
.PAGE
.SBTTL PY$FDTWRITE - Function decision routine for PY control write
;++
; PY$FDTWRITE
;
; Functional Description:
;
; This routine is called from the function decision table dispatcher
; to process a write physical, write logical, write virtual I/O
; function.
;
; The function first verifies the caller's parameters, terminating
; the request with immediate success or error if necessary.
; The routine then immediately start cramming the characters into
; the associated units typeahead buffer by calling putnxtchr.
;
; Inputs:
;
; R0,R1,R2 = Scratch
; R3 = IRP Address
; R4 = Address of PCB for current process
; R5 = Device UCB address
; R6 = Address of CCB
; R7 = I/O function code
; R8 = FDT Dispatch addr
; R9,R10,R11 = Scratch
; AP = Address of function parameter list
; P1(AP) = Buffer Address
; P2(AP) = Buffer Size
;
; Outputs:
;
; R0,R1,R2 = Destroyed
; R3-R8,AP = Preserved (pickled)
;
; External Routines:
;
; EXE$ABORTIO - FDT abort io routine
; Input Parameters:
; R0 - First longword of IOSB
; R3 - IRP Address
; R4 - PCB Address
; R5 - UCB Address
;
; EXE$FINISHIOC - FDT finish IO routine
; Input Parameters:
; R0 - First longword of IOSB
; R3 - IRP Address
; R4 - PCB Address
; R5 - UCB Address
;
; EXE$WRITECHK - Check access to buffer
; Input Parameters:
; R0 - Address of buffer
; R1 - Size of buffer
; R3 - IRP Address
; Output Parameters:
; R0,R1,R3 - Preserved
; R2 - clear
;
; @UCB$L_TT_PUTNXT(R5) - Port driver input character routine
; Input Parameters:
; R3 - character
; R5 - UCB Address
; Output Parameters:
; R3 - if EQL then nothing
; if LSS then Burst address to output
; if GTR then char to output
; R5 - UCB Address
; R1,R2,R4 - trashed
; R0 - Is this trashed or preserved? Documentation say preserve.
;
;--
PY$FDTWRITE::
MOVZWL P2(AP),R1 ; Get buffer Size
BEQL 40$ ; Is the size zero? If so, go do it easy.
MOVL P1(AP),R0 ; Get buffer Address
JSB G^EXE$WRITECHK ; Do we have access to the buffer
; No return means no access
;
; Change the UCB's around abit
;
PUSHR #^M
MOVZWL R1,R9 ; Set size in R9
MOVL UCB$L_PY_XUCB(R5),R5 ; Set fake UCB in R5
;
; Loop through the packet R0 is address R9 is size
;
10$:
MOVZBL (R0)+,R3 ; Get the byte and set address to next
DSBINT UCB$B_FIPL(R5)
JSB @UCB$L_TT_PUTNXT(R5) ; Buffer the character
TSTB UCB$B_TT_OUTYPE(R5) ; Test output
BLEQ 20$ ; None or string output
ENBINT
MOVB R3,UCB$W_TT_HOLD(R5) ; save the character in tank
BISW #TTY$M_TANK_HOLD,-
UCB$W_TT_HOLD(R5) ; Signal char in tank
BRB 25$
20$:
BEQL 30$ ; No character
ENBINT
BISW #TTY$M_TANK_BURST,- ; Signal burst
UCB$W_TT_HOLD(R5)
25$: PUSHR #^M ; Save State
MOVL UCB$L_TP_XUCB(R5),R5 ; Switch to PY UCB
DSBINT UCB$B_FIPL(R5)
BBC #UCB$V_BSY,UCB$W_STS(R5),27$
MOVL UCB$L_IRP(R5),R3 ; Get IRP
JSB G^IOC$INITIATE ; Go to the start I/O
27$: ENBINT
POPR #^M ; Restore State
BRB 35$
30$: ENBINT
35$: DECW R9 ; decrease number to do
BGTR 10$ ; if gtr then more to do
POPR #^M ; Restore real UCB and IRP
;
; Finish up the read
;
40$:
MOVZWL P2(AP),R0 ; Move number of bytes output
ASHL #16,R0,R0 ; Put it in the high word
MOVW #SS$_NORMAL,R0 ; Everything is just fine
JMP G^EXE$FINISHIOC ; Complete the I/O request
.PAGE
.SBTTL PY$CANCEL - Cancel the IO on the PY device
;++
;
; Functional Description:
;
; This routine is entered to stop io on a PY unit. If this is the last
; deassign on the PY device, issue a CLASS_DISCONNECT on our associated
; TP device to get it away from any processes using it.
;
; Inputs:
;
; R2 = Negative of the Channel Number,
; also called channel index number
; R3 = Current IO package address
; R4 = PCB of canceling process
; R5 = UCB Address
; R8 = CAN$C_CANCEL on CANCEL IO or CAN$C_DASSGN on DEASSIGN
;
; Outputs:
; Everything should be preserved
;--
PY$CANCEL:: ; Cancel PY usage
JSB G^IOC$CANCELIO ; Call the cancel routine
BBC #UCB$V_CANCEL,UCB$W_STS(R5),10$ ; Branch if not for this guy
MOVQ #SS$_ABORT,R0 ; Status is request canceled
BICW #,- ;
UCB$W_STS(R5) ; Clear unit status flags
JSB G^IOC$REQCOM ; Complete request
10$: TSTW UCB$W_REFC(R5) ; Last Deassign
BNEQ 100$ ; No, just exit
;
; Do a DISCONNECT on the TP device.
;
pushr #^M
movl UCB$L_PY_XUCB(r5), r5 ; Switch to TP UCB
beql 20$ ; if not there, skip
clrl UCB$L_TP_XUCB(r5) ; Clear backlink to PY device
bisl2 #UCB$M_DELETEUCB, UCB$L_STS(r5) ; Set it to go bye-bye
bicw2 #UCB$M_ONLINE,UCB$W_STS(R5) ; Mark offline
bicb2 #UCB$M_INT, UCB$W_STS(r5) ; Don't expect interrupt
movl UCB$L_TT_LOGUCB(r5), r1 ; Look at logical term UCB
tstw UCB$W_REFC(r1) ; See if TP has any references
bneq 15$ ; If so, go and do disconnect
jsb G^IOC$DELETE_UCB ; if not, delete the UCB
brb 20$
15$: clrl r0 ; indicate that we must hangup
movl UCB$L_TT_CLASS(r5), r1
jsb @CLASS_DISCONNECT(r1) ; Force disconnect
20$: popr #^M ; Switch back to PY UCB
clrl UCB$L_PY_XUCB(r5) ; Clear link to deleted TP
bisl2 #UCB$M_DELETEUCB, UCB$L_STS(r5) ; Set our own delete bit
100$: rsb
.PAGE
.SBTTL PY$INITIAL - Initialize Pseudo terminal interface
;++
; PY$INITIAL - Initialize the interface
;
; Functional Description:
;
; This routine is entered at device connect time and power recovery.
; There isn't much to do to the device.
;
; Inputs:
;
; R4 = The devices CSR (but there is no csr!)
; R5 = address of IDB
; R6 = address of DDB
; R7 = address of CRB
;
; Outputs:
;
; All registers preserved
;
;--
PY$INITIAL::
RSB
.PAGE
.SBTTL PY$CLONE_INIT - initialize the unit
;++
; PY$CLONE_INIT - Initialize new PY device
;
; Functional Description:
;
; Main thing we do here is clone up an associated terminal device
; and initialize fields in the two new UCB's.
;
; Inputs:
;
; R5 = Address of UCB
;
; Outputs:
;
; All preserved
;--
PY$CLONE_INIT::
;+ ---
; Ignore inits on UNIT #0 (the template PY UCB)
;- ---
TSTL UCB$W_UNIT(R2) ;UNIT #0??
BNEQ 10$ ;No: Initialize
RSB ;Yes: Return
10$: PUSHR #^M
Bicl2 #UCB$M_DELETEUCB,UCB$L_STS(R2) ; Clear ucbdelete - dec
Movl R2,R5
;
; Find the associated device.
;
; NOTE: We can't call IOC$SEARCHDEV because it expects the string to
; be accessible from the previous access mode. (It executes the
; prober instruction with mode=#0). I don't know how to make the
; string accessible from the previous access mode cleanly, but I
; do know how to move most of IOC$SEARCHDEV into the py driver.
;
MOVAL G^IOC$GL_DEVLIST-DDB$L_LINK,- ; Get address of i/o database
R8 ; listhead
CLRL R6 ; Desired mate = PTY UNIT 0
MOVAB L^TPSTRING,R7 ; String address for TPA
MOVL #TPLENGTH,R4 ; String length
BSBW SEARCHDEV ; Find the DDB
BNEQ 20$ ; Device not found
BSBW SEARCHUNIT ; Search for specific unit
BNEQ 30$ ; unit found
20$: POPR #^M ; NOT FOUND: Return
RSB
;
; Create the PTY, R1 has template UCB of TP device
;
30$: PUSHL R5 ; Save R5
MOVL UCB$L_DDB(R5),R0 ; Find UNIT #0 UCB FOR PY DEV.
MOVL DDB$L_UCB(R0),R0
MOVL R1,R5 ; R5 = UCB to CLONE
JSB G^IOC$CLONE_UCB ; Clone UCB
MOVL R2,R1 ; Put PTY UCB back into R1
POPL R5 ; Restore R5
BLBS R0,40$ ; WIN!!! (big deal.)
;+ ---
; CREATE_UCB failed, mark our PY device offline
;- ---
BICW2 #UCB$M_ONLINE,UCB$W_STS(R5) ; Mark offline
BRW 100$ ; And return
;+ ---
; PTY UCB created successfully, link the UCBs together
;- ---
40$: MOVL R1,UCB$L_PY_XUCB(R5) ; Store associated UCB
MOVL R5,UCB$L_TP_XUCB(R1) ; Store the other one back
CLRL UCB$L_PID(R1) ; Clear the owner PID in PTY
CLRW UCB$W_REFC(R1) ; Reference count is ZERO
Bicl2 #UCB$M_DELETEUCB,UCB$L_STS(R1) ; Inhibit deletion
MOVW UCB$W_UNIT(R1),- ; Set associated TP unit
UCB$L_DEVDEPEND(R5) ; number in PY devdepend
;+ ---
; Call the PTY unit init routine
;- ---
MOVL UCB$L_DDT(R1),R0 ; Get DDT
MOVL DDT$L_UNITINIT(R0),R0 ; Get Unit Init Addr in DDT
CMPL R0,#IOC$RETURN ; Null Address??
BNEQ 50$ ; No: Call it
MOVL UCB$L_CRB(R1),R0 ; Yes: Look in the CRB
MOVL CRB$L_INTD+VEC$L_UNITINIT(R0),R0
BEQL 100$ ; No: Unit init routine
50$: PUSHL R5 ; Save R5
MOVL R1,R5 ; R5 = PTY UCB
JSB (R0) ; CALL THE UNIT INIT ROUTINE
POPL R5 ; Restore R5
100$: POPR #^M
RSB
.PAGE
.SBTTL DDB finding Routines
;++
; SearchDev - Search for device DDB
;
; This routine is called to search the device database for a DDB.
; This is the first step in finding another devices UCB.
;
; This routine copied out of IOC$SEARCHDEV in IOSUBPAGD
;
; Inputs:
;
; R8 = DDB Head
; R7 = Address of String
; String = ddc format: example = /TTA/
; R4 = Length of string
;
; Outputs:
;
; R8 = DDB of desired device if EQL, otherwise not found
; R0 is trashed
; R1 is trashed
;--
SEARCHDEV: ; Search for device name
10$: MOVL DDB$L_LINK(R8),R8 ; Get address of next ddb
BEQL 20$ ; If eql end of list
MOVAL DDB$T_NAME(R8),R0 ; Get address of generic device name
MOVB (R0)+,R1 ; Calculate len of string to compare
CMPB R1,R4 ; Length of names match?
BNEQ 10$ ; If neq no
CMPC R4,(R0),(R7) ; Compare device names
BNEQ 10$ ; If neq names do not match
RSB
20$: INCL R8 ; indicate search failure
RSB
.SBTTL UCB finding routine
;++
; SEARCHUNIT - Subroutine to search for UCB given DDB
;
; Given the DDB of a device, get the UCB and run down the ucb list until
; we get the ucb with the desired unit number. This code is taken out of
; IOC$SEARCHDEV in IOSUBPAGD.
;
; Inputs:
;
; R8 = DDB of device
; R6 = unit number of desired UCB
;
; Outputs:
;
; R1 = UCB of device if NEQ, otherwise not found
; R0 is trashed
;
;--
SEARCHUNIT: ; Search for unit number
MOVAL DDB$L_UCB-UCB$L_LINK(R8),-
R1 ; Get address of next ucb address
10$: MOVL UCB$L_LINK(R1),R1 ; Get Address of next ucb
BEQL 40$ ; If EQL then end of list
CMPW R6,UCB$W_UNIT(R1) ; Unit number match?
BEQL 30$ ; If eql yes
BRB 10$
30$: MOVL #SS$_NORMAL,R0 ; Indicate match
40$: RSB
.PAGE
.SBTTL PY$STARTIO - Device Startio routines
;++
; PY$STARTIO - Start Input on idle device
;
; Functional Description:
;
; If after the read FDT routines are done and nobody is doing
; anything on the device (UCB$V_BSY = 0) then call the start io
; routine.
;
; Called from:
;
; Called from any one of five places:
; - The EXE$QIODRVPKT in the PY FDT READ routine
; which calls EXE$INSIOQ which calls IOC$INITIATE
; - The IOC$REQCOM at the end of this PY startio routine
; which calls IOC$INITIATE
; - The TP startio routine which calls IOC$INITIATE
; - The PY write fdt routine which calls IOC$INITIATE.
; In case we must echo a character.
; - The PY$RESUME routine which calls IOC$INITIATE.
;
; Inputs:
;
; R3 = IRP Address
; R5 = UCB Address
; UCB$W_BCNT and UCB$L_SVAPTE are written by IOC$INITIATE
;
; Outputs:
;
; R5 - UCB Address
;
;--
PY$STARTIO::
.ENABLE LSB
MOVL @UCB$L_SVAPTE(R5),- ; Initialize buffer
UCB$L_SVAPTE(R5) ; pointers
PY_OUT_LOOP:
;
; Here R5 must point at the PY device UCB and not at
; the UCB of the associated TP device.
;
5$: TSTW UCB$W_BCNT(R5) ; Any space left in rd packet
BLEQ 50$ ; No, Completed I/O
;
; Switch to terminal UCB
;
MOVL UCB$L_PY_XUCB(R5),R5 ; Set to TP ucb
;
; Look for next output in state tank
;
; Change Case statement to reflect V4 changes in routines - DEC
;
10$: FFS #0,#6,UCB$W_TT_HOLD+1(R5),R3
CASE R3,TYPE=B,<- ; Dispatch
PY_PREMPT,- ; Send Prempt Characte - DEC
PY_STOP,- ; Stop output
PY_CHAR,- ; Char in tank
PY_BURST,- ; Burst in progress
>
;
; No Pending Data - Look for next character
;
BICB #UCB$M_INT, UCB$W_STS(R5) ; Clear interrupt expected
;
; Call class driver for more output
;
JSB @UCB$L_TT_GETNXT(R5) ; Get the next character
CASEB UCB$B_TT_OUTYPE(R5),#-1,#1
1$: .WORD PY_START_BURST-1$ ; Burst specified
.WORD PY_DONE-1$ ; None
BRW BUFFER_CHAR ; Buffer the character
;
; Output queue exhausted
PY_DONE:
MOVL UCB$L_TP_XUCB(R5),R5 ; Switch UCBs to PY UCB
BBC #UCB$V_BSY,- ; If not BSY then ignore
UCB$W_STS(R5),47$ ; the char
MOVL UCB$L_IRP(R5),R3 ; Restore IRP
CMPW IRP$W_BCNT(R3),- ; Any characters moved
UCB$W_BCNT(R5)
BNEQ 50$ ; Yes complete I/O
47$: RSB
;
; read buffer exhausted
;
50$: MOVL UCB$L_IRP(R5),R3 ; Restore IRP
MOVW #SS$_NORMAL,- ; Set successful completetion
IRP$L_IOST1(R3)
SUBW UCB$W_BCNT(R5),- ; Update byte count
IRP$W_BCNT(R3)
MOVW IRP$W_BCNT(R3),- ; Set in status
IRP$L_IOST1+2(R3)
;
; If we wanted to here we could set the second longword of the device status
;
CLRL IRP$L_IOST2(R3) ; No status
MOVQ IRP$L_IOST1(R3),R0 ; Load IOSB return values
JMP G^IOC$REQCOM
;
; Put the character into the read buffer
;
BUFFER_CHAR:
MOVL UCB$L_TP_XUCB(R5),R5 ; Switch UCBs to PY UCB
BBC #UCB$V_BSY,-
UCB$W_STS(R5), 60$ ; If no PY IRP, ignore
MOVB R3,@UCB$L_SVAPTE(R5) ; Add character to buffer
INCL UCB$L_SVAPTE(R5) ; Bump pointer
DECW UCB$W_BCNT(R5) ; Show character added
60$: BRW PY_OUT_LOOP ; Go for another char
;
; Take care of Burst mode R5 must be TP UCB
;
PY_START_BURST:
BISW #TTY$M_TANK_BURST,- ; Signal burst active
UCB$W_TT_HOLD(R5)
;
; Continue burst
;
PY_BURST:
MOVL UCB$L_TP_XUCB(R5),R1 ; Save PY UCB in R1
CLRL R3 ; Initialize output size
CMPW UCB$W_TT_OUTLEN(R5),UCB$W_BCNT(R1) ; Is buffer too small?
BGTR 61$ ; Yes
MOVW UCB$W_TT_OUTLEN(R5),R3 ; Nope, so output all
BRB 62$
61$: MOVW UCB$W_BCNT(R1),R3 ; Just output what we can
62$: PUSHR #^M ; MOVC3 destroys these registers
MOVC3 R3,@UCB$L_TT_OUTADR(R5),@UCB$L_SVAPTE(R1)
; Transfer burst to the buffer
POPR #^M ; Restore the registers
ADDL2 R3,UCB$L_SVAPTE(R1) ; Update output pointer
SUBW2 R3,UCB$W_BCNT(R1) ; Update output count
ADDL2 R3,UCB$L_TT_OUTADR(R5) ; Update input pointer
SUBW2 R3,UCB$W_TT_OUTLEN(R5) ; Update input count
BNEQ 65$ ; Not the last character
BICW #TTY$M_TANK_BURST,-
UCB$W_TT_HOLD(R5) ; Reset burst not active
65$: MOVL UCB$L_TP_XUCB(R5),R5 ; Swicht UCBs to PY UCB
BRW PY_OUT_LOOP
;
; Get a single char from tt and put in read buffer R5 = TP UCB
;
PY_CHAR:
MOVB UCB$W_TT_HOLD(R5),R3 ; Get the next byte
BICW #TTY$M_TANK_HOLD,- ; Show tank empty
UCB$W_TT_HOLD(R5)
BRW BUFFER_CHAR
;
; Stop the output R5 = TP UCB
;
; Deleted PY_STOP2 routine and changed bit clear to byte operation - DEC
;
PY_STOP:
BICB #UCB$M_INT, -
UCB$W_STS(R5) ; Reset output active
BRW PY_DONE ; DON'T go for anymore
; Or we'll get into an infinite loop
;
; Send Xon or Xoff characters, R5 = TP UCB
;
; Changed PY_XOFF and PY_XON to be PY_PREMPT - DEC
;
PY_PREMPT:
movb UCB$B_TT_PREMPT(r5), r3 ; Pick up the character
BICW #TTY$M_TANK_PREMPT,- ; Reset Xoff state
UCB$W_TT_HOLD(R5)
BRW BUFFER_CHAR
.DISABLE LSB
PY$END:
; End of driver
.END
$*$*EOD*$*$
$ checksum PYDRIVER.MAR
$ if checksum$checksum .ne. check_sum then -
$ write sys$output "Checksum failed, file probably corrupted"
$ exit