.TITLE PTYDRIVER - Port Driver for PTY's .IDENT /4.00/ ;++ ; Facility: ; VAX/VMS Pseudo-terminal driver ; ; Abstract: ; This is a port driver to provide a pseudo-terminal capability for VAX ; VMS. The pseudo-terminal is a pair of pseudo devices with consecutive ; unit numbers. These devices behave like mailboxes in that ; they are created dynamically when a channel is assigned. Assigning ; a channel on the device PTY0: will automatically create two new ; devices, PTYn and PTY(n+1). A PTY differs from a mailbox in that it ; is a terminal class device, and responds correctly to all terminal ; driver QIO functions. ; ; The PTY(n+1) device is called the terminal device. It is ; usually assigned as the primary input/output device (the "terminal") ; for a process created to perform some task. The PTYn device is ; called the control device. It is usually assigned to a program which ; transmits and receives messages from the terminal device process. ; ; The two devices communicate at STARTIO level through ; the code of this driver. Both devices are terminal class devices and ; are serviced by the terminal class driver. The characteristics of ; the control device are fixed and cannot be changed. Any changes made ; to the control device characteristics will be propagated to the ; terminal device. The temporary and permanent characteristics of ; the device are always kept identical. ; ; The process which creates a PTY device must have sufficient BYTLM ; quota for the UCB. ; ; Author: ; Gary L. Grebus, 27-Nov-1983 00:28:15 ; ; Revision History: ; ; 4.00 -- Kevin Carosso, 6-Jan-1985 ; Converted to VMS V4. Did the following: ; - Changed references to owner and prot to use new ORB structure. ; - Changed PORT/CLASS interface table to use $VEC macros. ; - Changed SET_UNIT port interface to SET_LINE for the table. ; - Changed PORT/CLASS interface to use unit/controller init macros. ; - Moved PTY specific UCB fields to end of the TTY UCB, since it ; used to use (unused) TT_MAP which is no longer in the UCB. ; - Completely rewrote the mechanism whereby master and slave UCBs ; are cloned. I now use the CLONE_UCB entry point in the DDT to ; initialize the master UCB. The CLONE initialization code then ; calls the proper IOC$ routines to clone yet another UCB for the ; slave. This gets rid of the odd restrictions on UCB size brougt ; about by the old method of cloning a huge UCB and cutting it in ; half for the two PTY's. This meant I had to rewrite the code ; that handles DISCONNECTs so that it either marks a UCB for ; deletion by $DASSGN or deletes it explicitly. ; ; I have a better way of handling DISCONNECT so that the PTY ; works more like a terminal with the HANGUP characteristic. I ; will work on that once I figure out how the class driver really ; handles terminal hangup. ; ;-- .PAGE .SBTTL Declarations .LIBRARY /SYS$LIBRARY:LIB/ ; External Constants $CRBDEF ; Define CRB $DCDEF ; Define adapter types $DDBDEF ; Define DDB $DDTDEF ; Need to store into the DDT $DEVDEF ; Define device types $DYNDEF ; Define DYN symbols $IDBDEF ; Define IDB $TTYDEF ; Define terminal driver symbols $TTDEF ; Define terminal types $TT2DEF ; Define extended characteristics $UCBDEF ; Define UCB $VECDEF ; Define CRB vector fields $TTYMACS ; Define terminal driver macros $TTYDEFS ; Define terminal driver symbols $ORBDEF ; Object rights block ; ; Add some fields to the end of the UCB. ; $DEFINI LOCAL,GLOBAL .=UCB$C_TT_LENGTH ; Add to end of normal TT UCB $DEF UCB$L_PTY_CPID .BLKL 1 ; Place to save creator PID $DEF UCB$L_PARTNER_UCB .BLKL 1 ; Address of partner's UCB. $DEF UCB$C_PTY_LENGTH .BLKW 1 ; New length of UCB $DEFEND UCB ; Local symbols ; Control PTY characteristics PTY_DEFCHAR = TT$M_HOSTSYNC ! TT$M_LOWER ! TT$M_MECHFORM ! TT$M_MECHTAB - ! TT$M_NOECHO ! TT$M_SCOPE ! TT$M_TTSYNC ! TT$M_NOBRDCST - ! TT$M_EIGHTBIT PTY_DEFCHAR2 = TT2$M_HANGUP ! TT2$M_ALTYPEAHD ! TT2$M_PASTHRU PTY_DEFWIDTH = 80 PTY_DEFPAGE=0 PTY_DEFTYPE = TT$_UNKNOWN ; Local macros ; .MACRO IF_TERMINAL LABEL BLBC UCB$W_UNIT(R5),LABEL ;; Branch if even (terminal) unit .ENDM IF_TERMINAL .MACRO IF_CONTROL LABEL BLBS UCB$W_UNIT(R5),LABEL ;; Branch if odd (control) unit .ENDM IF_CONTROL ; ; Local storage ; .PSECT $$$105_PROLOGUE ; ; Driver prologue table ; PTY$DPT:: ; Driver start DPTAB - END=PTY$END,- ; End of driver UCBSIZE=UCB$C_PTY_LENGTH,- ; Size of UCB (double size) FLAGS=DPT$M_NOUNLOAD,- ; No unload allowed ADAPTER=NULL,- ; No adapter NAME=PTYDRIVER,- ; Name of driver VECTOR=PORT_VECTOR ; Port driver vector table DPT_STORE INIT ; DPT initialization DPT_STORE UCB,UCB$B_FIPL,B,8 ; Fork IPL DPT_STORE UCB,UCB$L_DEVCHAR,L,<- DEV$M_REC!- ; Leave AVL clear, will be DEV$M_IDV!- ; set in the UNIT_INIT if DEV$M_ODV!- ; no errors creating new DDT. DEV$M_TRM!- DEV$M_CCL> ; The site-defined default characteristics are specified for PTY devices so ; that the terminal device will resemble a default terminal. The values which ; could affect PTYDRIVER operation are reset in the unit init routine. DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_TERM ; Class DPT_STORE UCB,UCB$B_TT_DETYPE,B,TT$_UNKNOWN ; Type DPT_STORE UCB,UCB$W_TT_DESIZE,@W,TTY$GW_DEFBUF ; Buffer size DPT_STORE UCB,UCB$L_TT_DECHAR,@L,TTY$GL_DEFCHAR ; Default character DPT_STORE UCB,UCB$L_TT_DECHA1,@L,TTY$GL_DEFCHAR2 ; Ditto DPT_STORE UCB,UCB$W_TT_DESPEE,@B,TTY$GB_DEFSPEED ; Default speed DPT_STORE UCB,UCB$W_TT_DESPEE+1,@B,TTY$GB_RSPEED ; Default rspeed DPT_STORE UCB,UCB$B_TT_DEPARI,@B,TTY$GB_PARITY ; Default parity DPT_STORE UCB,UCB$B_TT_PARITY,@B,TTY$GB_PARITY ; Ditto DPT_STORE UCB,UCB$B_DEVTYPE,B,TT$_UNKNOWN ; Type DPT_STORE UCB,UCB$W_DEVBUFSIZ,@W,TTY$GW_DEFBUF ; Buffer size DPT_STORE UCB,UCB$L_DEVDEPEND,@L,TTY$GL_DEFCHAR ; Default character DPT_STORE UCB,UCB$L_TT_DEVDP1,@L,TTY$GL_DEFCHAR2 ; Ditto DPT_STORE UCB,UCB$W_TT_SPEED,@B,TTY$GB_DEFSPEED ; Default speed DPT_STORE UCB,UCB$W_TT_SPEED+1,@B,TTY$GB_RSPEED ; Default rspeed DPT_STORE UCB,UCB$B_DIPL,B,8 ; Device IPL (no device involved) DPT_STORE UCB,UCB$L_TT_WFLINK,L,0 ; Zero write queue DPT_STORE UCB,UCB$L_TT_WBLINK,L,0 ; Ditto DPT_STORE UCB,UCB$L_TT_RTIMOU,L,0 ; Zero read timed out disp. DPT_STORE ORB,ORB$B_FLAGS,B, ; Allow world access DPT_STORE ORB,ORB$W_PROT,@W,TTY$GW_PROT ; Default TTY prot DPT_STORE ORB,ORB$L_OWNER,@L,TTY$GL_OWNUIC ; Default TTY owner DPT_STORE DDB,DDB$L_DDT,D,PTY$DDT ; Dispatch table DPT_STORE REINIT ; Reinitialization DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,D,PTY$INITIAL ; Ctrller init DPT_STORE END DDTAB DEVNAM = PTY,- ; Dummy dispatch table START = 0,- FUNCTB = 0, - UNITINIT = PTY$INIT_UNIT, - .PSECT $$$115_DRIVER,LONG ; The associated class driver uses this table to command the port driver. ; The address of this table is contained in the terminal UCB extension area. ; The offset definitions are defined by $TTYDEFS. PORT_VECTOR: ; PTY port specific dispatch table $VECINI PTY, PTY$NULL $VEC STARTIO, PTY$STARTIO ; Start new output $VEC DISCONNECT, PTY$DISCONNECT ; Disconnect port $VEC SET_LINE, PTY$SET_LINE ; Set unit characteristics $VEC XON, PTY$XON ; Send XON sequence $VEC XOFF, PTY$XOFF ; Send XOFF sequence $VEC STOP, PTY$STOP ; Stop output $VEC ABORT, PTY$ABORT ; Abort output in progress $VEC RESUME, PTY$RESUME ; Resume stopped output $VEC MAINT, PTY$MAINT ; Do maint. function (dummy) $VECEND ; Dummy entry points for unsupported functions PTY$null:: RSB ; Null routine PTY$MAINT:: MOVZWL #1,R0 ; Null routine which returns success RSB .PAGE .SBTTL Controller Initialization ;++ ; Functional Description: ; This routine is entered at controller configuration and power ; recovery. ; ; Inputs: ; R4 - address of the CSR (controller status register) ; R5 - address of the IDB (interrupt data block) ; R6 - address of the DDB (device data block) ; R8 - address of the CRB (channel request block) ; ; Outputs: ; None ; ; Implicit inputs: ; IPL = IPL$_POWER ; ;-- PTY$INITIAL:: ; Hook to class driver class_ctrl_init PTY$DPT, port_vector CLRB CRB$B_TT_TYPE(R8) ; Set unknown controller type 10$: RSB .PAGE .SBTTL Unit Initialization ;++ ; PTY$INIT_UNIT - Unit Initialization ; ; Functional Description: ; This routine performs unit initialization for the PTY device. ; It hooks us to the class driver and allocates and builds a special ; separate DDT that includes a clone UCB entry point. It also ; initializes some fields in the UCB that need it. ; ; This will never be called at powerfail since the vector to it will ; be missing from the DDT (both the old and the new one) and it is not ; in the CRB. This is fine since there is no action we need to take ; on powerfail anyway. ; ; Inputs: ; R5 - Address of our UCB ; ; Outputs: ; R3, R4, R5 must be preserved ; Device available (AVL) bit set in UCB$L_DEVCHAR if no errors. ; ; Implicit inputs: ; IPL = IPL$_POWER ;-- PTY$INIT_UNIT:: moval PTY$VEC, r0 ; Set PTY port vector table class_unit_init ; Init class/port interface ; ; Because we have cloned devices, we have to supply a CLONEDUCB entry ; in the DDT. This means we cannot use the class driver's DDT, which is ; common to all terminal class devices. Thus, we allocate our own, set ; up the UCB and DDB to point at it, copy in the terminal class DDT, then ; add the CLONEDUCB entry. ; pushr #^M ; Preserve R2, R3 movl #DDT$K_LENGTH, r1 ; Length of a DDT jsb G^EXE$ALONONPAGED ; Allocate one movl r2, r1 ; Save address of it popr #^M ; Retrieve regs blbc r0, 99$ pushr #^M movc3 #DDT$K_LENGTH, @UCB$L_DDT(r5), (r1) ; Copy the DDT popr #^M movl r1, UCB$L_DDT(r5) ; Save its address movl r1, DDB$L_DDT(r2) ; where its needed moval Clone_UCB, DDT$L_CLONEDUCB(r1) ; Add clone routine ; Perform special processing for unit zero. Most fields have already been ; set by DPT_STORE MOVL UCB$L_TT_CLASS(R5),R1 ; Address class vector table JSB @CLASS_SETUP_UCB(R1) ; Init UCB fields MOVW #UCB$M_TEMPLATE,- UCB$W_STS(R5) ; Make this a template device BISL2 #TT2$M_ALTYPEAHD,- UCB$L_TT_DECHA1(R5) ; Force PTY's to be ALTYPEAHD BISL2 #TT2$M_ALTYPEAHD,- UCB$L_TT_DEVDP1(R5) ; ; Leaving the unit off-line does not seem to prevent access to a template ; device, therefore we are going to make use of the available bit. The ; available bit is left clear in the DPT and we set it here. If we do not ; make it all the way through the code that created the new DDT, the device ; will not become available. ; bisl2 #DEV$M_AVL, UCB$L_DEVCHAR(r5) ; Make it available 99$: rsb .PAGE .SBTTL Clone a new UCB and create a new pair of PTY's ;++ ; Clone_UCB - Clone UCB from PTY0 ; ; Functional Description: ; ; We are called with the cloned UCB. This clone will become the controlling ; device. We then clone a newer device by calling the appropriate VMS UCB ; cloning routines. Note that the method for this madness is taken from ; the code for EXE$ASSIGN. ; ; Inputs: ; R0 - SS$_NORMAL ; R2 - UCB address of cloned UCB ; R3 - DDT address ; R4 - PCB address ; R5 - Address of template UCB ; ; Outputs: ; R0 - SS$_NORMAL ; R1 - trashed ; R5 - UCB address of cloned UCB ; All other registers and IPL are preserved ; ; Implicit inputs: ; IPL = IPL$_ASTDEL ;-- CLONE_UCB:: ; Clone yet another device. After the clone, the control device will be ; in r2 and the terminal device will be in r5. jsb G^IOC$CHKUCBQUOTA ; See if process has enough for another blbc r0, 90$ ; branch on not enough BYTLM pushl r2 ; Save the controller clone jsb G^IOC$CLONE_UCB ; Make terminal unit clone movl r2, r5 ; in r5 popl r2 ; and restore controller unit to r2 blbc r0, 90$ bicl2 #UCB$M_DELETEUCB, - ; Don't automatically delete yet UCB$L_STS(r5) clrw UCB$W_REFC(r5) ; Clear reference count jsb G^IOC$DEBIT_UCB ; Debit the process's BYTLM CLRL UCB$L_PARTNER_UCB(R5) ; Don't admit to partner yet CLRL UCB$L_PARTNER_UCB(R2) MOVL UCB$L_CPID(R2),- ; Save creator PID so we can return UCB$L_PTY_CPID(R5) ; quota to the right place MOVL UCB$L_CPID(R2),- UCB$L_PTY_CPID(R2) clrl UCB$L_TT_WFLINK(r2) ; Clear queue so it is inited clrl UCB$L_TT_WFLINK(r5) ; by the class driver. movl r5,r0 ; Save terminal UCB address movl r2,r5 ; Point to control UCB movl UCB$L_TT_CLASS(r5), r1 ; Do class driver setup jsb @CLASS_SETUP_UCB(r1) bsbb PTY$SET_LINE ; Set our characteristics movl r0,r5 ; Restore terminal UCB pointer movl UCB$L_ORB(r2), r1 ; Get ORB address movw #^xFF00,- ; Only allow owner or system ORB$W_PROT(r1) ; to access the control device movl UCB$L_TT_CLASS(r5), r1 jsb @CLASS_SETUP_UCB(r1) bsbb PTY$SET_LINE ; Set our characteristics movl r5,UCB$L_PARTNER_UCB(r2) ; Link terminal to control movl r2,UCB$L_PARTNER_UCB(r5) ; and vice versa movl #SS$_NORMAL, r0 90$: rsb .PAGE .SBTTL Set Unit Characteristics ;++ ; Functional Description: ; This routine is called by the class driver whenever device ; characteristics have been changed. On a real device, it would ; set the device registers that control characteristics such as ; speed and parity. We use this routine to control the ; terminal specific characteristics on the PTY. ; ; Inputs: ; R5 - UCB address ; ;-- PTY$SET_LINE:: ; Restore default device characteristics when called during shutdown or ; reinit of idle unit. PUSHR #^M ; Save registers IF_CONTROL 10$ ; Branch if this is a control PTY ; Fixup characteristics for the terminal device MOVL R5,R0 ; UCB address parameter in R0 BSBb TERMINAL_UNIT ; Fix characteristics BRB 5$ ; For control device, propagate any changes to the terminal device and restore ; the special set of control characteristics 10$: MOVL UCB$L_PARTNER_UCB(R5),R0 ; Get our partner (terminal) UCB BEQL 20$ ; Branch if terminal is gone MOVL UCB$L_DEVDEPEND(R5),- UCB$L_DEVDEPEND(R0) ; Copy terminal characteristics MOVL UCB$L_TT_DEVDP1(R5),- UCB$L_TT_DEVDP1(R0) MOVB UCB$B_DEVTYPE(R5),- UCB$B_DEVTYPE(R0) ; Copy terminal type MOVW UCB$W_DEVBUFSIZ(R5),- UCB$W_DEVBUFSIZ(R0) ; and width MOVB UCB$B_VERTSZ(R5),- UCB$B_VERTSZ(R0) ; and page length BSBB TERMINAL_UNIT ; Enforce terminal device requirements ; Restore fixed characteristics for control device 20$: MOVL #PTY_DEFCHAR,- UCB$L_DEVDEPEND(R5) ; Reset characteristics MOVL #PTY_DEFCHAR2,- UCB$L_TT_DEVDP1(R5) MOVB #PTY_DEFTYPE,- UCB$B_DEVTYPE(R5) ; Restore terminal type MOVW #PTY_DEFWIDTH,- UCB$W_DEVBUFSIZ(R5) ; and width MOVB #PTY_DEFPAGE,- UCB$B_VERTSZ(R5) ; and page length MOVL R5,R0 ; UCB address parameter in R0 BSBB COPY_PERM ; Copy temp characteristics to perm 5$: POPR #^M ; Restore registers RSB ; For a terminal device, just insure that the user has not changed any bits ; which will break the driver. TERMINAL_UNIT: BICL2 #,- UCB$L_DEVDEPEND(R0) ; Temporary char - longword 1 BISL2 #,- UCB$L_DEVDEPEND(R0) ; Temporary char - longword 1 BICL2 #,- UCB$L_TT_DEVDP1(R0) ; Temporary char - longword 2 BISL2 #TT2$M_HANGUP!TT2$M_ALTYPEAHD,- UCB$L_TT_DEVDP1(R0) ; Temporary char - longword 2 BSBB COPY_PERM ; Copy temp characteristics to perm RSB ; Copy the terminal temporary characteristics as permanent characteristics COPY_PERM: MOVB UCB$B_DEVTYPE(R0),- UCB$B_TT_DETYPE(R0) ; Terminal type MOVW UCB$W_DEVBUFSIZ(R0),- UCB$W_TT_DESIZE(R0) ; Terminal width MOVL UCB$L_DEVDEPEND(R0),- UCB$L_TT_DECHAR(R0) ; Characteristic bits (part 1) MOVL UCB$L_TT_DEVDP1(R0),- UCB$L_TT_DECHA1(R0) ; Characteristic bits (part 2) rsb .PAGE .SBTTL Start I/O Routine ;++ ; PTY$STARTIO - Start I/O operation ; ; Functional Description: ; This routine is called from the class driver to start output ; on the device. It accomplishes its transfer by calling the ; equivalent of the interrupt service routine for its partner ; device. ; ; Inputs: ; R3 = Character AND CC=Plus ; Address AND CC=Negative ; R5 = UCB address ; ; Outputs: ; R5 = UCB address ; -- PTY$STARTIO:: BGEQ 20$ ; Branch if single character I/O ; Here for multiple character case TSTW UCB$W_TT_OUTLEN(R5) ; Really characters to output? BLEQ 30$ ; Branch if not 10$: BBS #TTY$V_ST_CTRLS,- UCB$Q_TT_STATE(R5),40$ ; If we get XOFF'ed, abort the output MOVZBL @UCB$L_TT_OUTADR(R5),- R3 ; Get next character to output BSBB PTY$INPUT_CHAR ; Ship the character to our partner INCL UCB$L_TT_OUTADR(R5) ; Adjust pointer DECW UCB$W_TT_OUTLEN(R5) ; Decrement character count BGTR 10$ ; Loop while characters remain BRB 30$ ; Here for single character case 20$: beql 30$ ; If no character then skip. BSBB PTY$INPUT_CHAR ; Ship character to our partner 30$: PUSHR #^M ; Save registers JSB @UCB$L_TT_GETNXT(R5) ; Get new characters to output POPR #^M ; Restore registers bneq PTY$STARTIO ; do another if there is one 40$: rsb ; Else, all done .PAGE .SBTTL Receiver service routine ;++ ; PTY$INPUT_CHAR - Receive a character ; ; Functional Description: ; This routine is entered when a character is to be passed to ; the current device's partner. It is analogous to an interrupt ; service routine for the receive side. It is important that ; the interrupt expected (INT) bit be kept clear since parts ; of the class driver will not initiate actions when they think ; the next device interrupt (which we lack) will trigger them. ; ; Inputs: ; R3 - Character to be received ; R5 - Address of sender's UCB ; ; Outputs: ; R5 - Address of sender's UCB ;-- PTY$INPUT_CHAR:: BICW #,- UCB$W_STS(R5) ; Make things happen synchronously. ; Don't let write time out. PUSHL R5 ; Save UCB context MOVL UCB$L_PARTNER_UCB(R5),- R5 ; Switch to receiver's context BEQL 10$ ; Branch if partner has vanished TSTW UCB$W_REFC(R5) ; Does partner have a channel? BEQL 10$ ; If not, discard this character BICW #,- UCB$W_STS(R5) ; Make driver think things must be ; handled synchronously PUSHR #^M ; Save registers JSB @UCB$L_TT_PUTNXT(R5) ; Store the character in receiver's ; buffer POPR #^M ; Restore registers ; At this point, the PUTNXT routine may have returned characters to be ; output on the receiver's output side. This may be something like a ; multi-character echo sequence or an XOFF. Heaven help us if we ; ever get here with conventional echo turned on for the control device!! BEQL 10$ ; Branch if no character BSBB PTY$STARTIO ; Output the character 10$: POPL R5 ; Restore UCB context RSB .PAGE .SBTTL Port control routines - STOP,RESUME,XON,XOFF ;++ ; PTY$XOFF - Send XOFF ; PTY$XON - Send XON ; PTY$STOP - Stop output ; PTY$RESUME - Resume output ; PTY$ABORT - Abort current port activity ; PTY$DISCONNECT - "Hangup" a deassigned unit ; ; Functional description: ; These routines are used by the class driver to control output ; on the port. ; ; Inputs: ; R5 = UCB address ; ; Outputs: ; Preserve all registers. ;-- ; Send XON or XOFF PTY$XOFF:: PUSHL R5 ; Save UCB context MOVL UCB$L_PARTNER_UCB(R5),R5 ; Get partner's UCB BEQL 10$ ; Branch if he is gone BSBB PTY$STOP ; Call his port stop routine 10$: POPL R5 ; Restore our context RSB PTY$XON:: PUSHL R5 ; Save UCB context MOVL UCB$L_PARTNER_UCB(R5),R5 ; Get partner's UCB BEQL 10$ ; Branch if he is gone BSBB PTY$RESUME ; Call his port resume routine 10$: POPL R5 ; Restore our context RSB ; Stop output on port PTY$STOP:: BICW #UCB$M_INT!UCB$M_TIM,- UCB$W_STS(R5) ; Clear timer and device active status BBCS #TTY$V_ST_CTRLS,- UCB$Q_TT_STATE(R5),5$ ; Interrupt current output and block new BISW2 #TTY$M_TANK_STOP,- UCB$W_TT_HOLD(R5) ; CTRLS already set - require two XON's 5$: RSB ; Resume interrupted output PTY$RESUME:: BBSC #TTY$V_TANK_STOP,- UCB$W_TT_HOLD(R5),10$ ; We were XOFF'ed twice - require two ; XON's PUSHL R3 ; Save register BBCC #TTY$V_ST_CTRLS,- UCB$Q_TT_STATE(R5),5$ ; Clear output blocked flag 5$: MOVL UCB$L_TT_OUTADR(R5),- R3 ; Get address of output burst (also sets ; CC=negative BSBW PTY$STARTIO ; Go do the output POPL R3 ; Restore register 10$: RSB ; Abort current output on port PTY$ABORT:: BISW2 #TTY$M_TANK_STOP,- UCB$W_TT_HOLD(R5) ; Unblock port output BBCC #TTY$V_ST_CTRLS,- UCB$Q_TT_STATE(R5),10$ 10$: RSB ; This entry point is called by TTDRIVER's cancel I/O processing when the last ; channel has been removed from the device. This happens because PTY's are ; forced to be HANGUP devices. PTY$DISCONNECT:: pushr #^M ; Save r0 movl UCB$L_PARTNER_UCB(r5), r0 ; If no partner, skip... beql 10$ if_terminal 10$ ; Following for control only: bisl2 #UCB$M_DELETEUCB, - ; Mark partner for deletion UCB$L_STS(r0) tstw UCB$W_REFC(r0) ; If he has references bneq 5$ ; only clear his partner. ; ; Note: the call to IOC$CREDIT_UCB will SETIPL to IPL$_SYNCH temporarily. ; This shouldn't be a problem since we are at FIPL (which is 8) ; and SYNCH is now (as of V4) 8 as well. Thus, we aren't in danger ; of lowering IPL while still in the driver. ; pushl r5 ; Save current UCB movl r0, r5 ; Point to terminal unit movl UCB$L_PTY_CPID(r5), - ; Process to restore quota to UCB$L_CPID(r5) jsb G^IOC$CREDIT_UCB ; Give back BYTLM jsb G^IOC$DELETE_UCB ; Delete the unit popl r5 ; and restore the control UCB brb 10$ 5$: clrl UCB$L_PARTNER_UCB(r0) ; Clear ref to control in ; term if term not deleted. 10$: movl UCB$L_PTY_CPID(r5), - ; Process to restore quota to UCB$L_CPID(r5) popr #^M rsb .PAGE .SBTTL End of PTYDRIVER PTY$END:: .END