KVC@BUSTER.NRC.COM (Kevin Carosso) (06/22/88)
+-+-+-+ Beginning of part 4 +-+-+-+ X;`009the request with immediate success or error if necessary. X;`009The routine then immediately start cramming the characters into X;`009the associated units typeahead buffer by calling putnxtchr. X; X; Inputs: X; X;`009R0,R1,R2`009= Scratch X;`009R3`009`009= IRP Address X;`009R4`009`009= Address of PCB for current process X;`009R5`009`009= Device UCB address X;`009R6`009`009= Address of CCB X;`009R7`009`009= I/O function code X;`009R8`009`009= FDT Dispatch addr X;`009R9,R10,R11`009= Scratch X;`009AP`009`009= Address of function parameter list X;`009`009P1(AP)`009= Buffer Address X;`009`009P2(AP)`009= Buffer Size X; X; Outputs: X; X;`009R0,R1,R2`009= Destroyed X;`009R3-R7,AP`009= Preserved (pickled) X; X; X;`009N O T E: X;`009`009This routine now assumes that TW and PY's fork and DEVICE X;`009locks are the same lock. This allows use to keep from having to X;`009do an extra unecessary lock acquisition. X;`009 X; X; X; External Routines: X; X;`009EXE$ABORTIO - FDT abort io routine X;`009Input Parameters: X;`009`009R0 - First longword of IOSB X;`009`009R3 - IRP Address X;`009`009R4 - PCB Address X;`009`009R5 - UCB Address X; X;`009EXE$FINISHIOC - FDT finish IO routine X;`009Input Parameters: X;`009`009R0 - First longword of IOSB X;`009`009R3 - IRP Address X;`009`009R4 - PCB Address X;`009`009R5 - UCB Address X; X;`009EXE$WRITECHK - Check access to buffer X;`009Input Parameters: X;`009`009R0 - Address of buffer X;`009`009R1 - Size of buffer X;`009`009R3 - IRP Address X;`009Output Parameters: X;`009`009R0,R1,R3 - Preserved X;`009`009R2 - clear X; X;`009@UCB$L_TT_PUTNXT(R5) - Port driver input character routine X;`009Input Parameters: X;`009`009R3 - character X;`009`009R5 - UCB Address X;`009Output Parameters: X;`009`009R3 - if EQL then nothing X;`009`009 if LSS then Burst address to output X;`009`009 if GTR then char to output X;`009`009R5 - UCB Address X;`009`009R1,R2,R4 - trashed X;`009`009R0 - Is this trashed or preserved? Documentation say preserve. X; X;-- XPY$FDTWRITE:: X`009MOVZWL`009P2(AP),R1`009`009; Get buffer Size X`009BNEQ`00910$`009`009`009; Is the non zero? If so, do it easy. X`009BRW`009160$`009`009`009; Zero size buffer just finish it now X X10$: X`009MOVL`009P1(AP),R0`009`009; Get buffer Address X`009JSB`009G^EXE$WRITECHK`009`009; Do we have access to the buffer X`009`009`009`009`009; No return means no access X`009MOVL`009R1,R9`009`009`009; Number of characters to send X`009CLRL`009R10`009`009`009; Clear count of characters sent X`009MOVL`009R5,R11`009`009`009; Save away PY UCB ptr X`009PUSHR`009#^M<R3,R4,R5>`009`009; Save PCB, IRP,and UCB address X; X;`009User request ok. X; X;`009R0`009-> `009Address of characters to input X;`009R5`009->`009Address of TW's UCB X;`009R8`009->`009Number of characters to send this time X;`009R9`009->`009Total number of characters to send X;`009R10`009->`009Numbers of characters already sent X;`009R11`009->`009Address of Py's UCB X; X20$: X`009SUBL3`009R10,R9,R8`009`009; Get number of characters send X`009CMPB`009R8,#BUFFER_SIZE`009`009; More data than buffer can hold X`009BGEQ`00930$`009`009`009; GEQ then use BUFFER_SIZE segment X`009CMPB`009R8,#1`009`009`009; Test for one byte only X`009BGTR`00940$`009`009`009; GTR more than one fill up buffer X`009MOVZBL`009(R0),R3`009`009`009; Move single character into R3 X`009BRB`00960$`009`009`009; Now go ahead and send it X30$: X`009MOVC3`009#BUFFER_SIZE,(R0)[R10],-; Store data in UCB buffer X`009`009UCB$T_PY_BUFFER(R11)`009; X`009MOVZBL`009#BUFFER_SIZE,R8`009`009; Number of characters in burst X`009BRB`00950$`009`009`009; Now finish setup for transfer X40$: X`009MOVC3`009R8,(R0)[R10],`009-`009; Store data in UCB buffer X`009`009UCB$T_PY_BUFFER(R11)`009; X50$: X`009MOVAB`009UCB$T_PY_BUFFER(R11),R0`009; Get buffer address X`009MOVZBL`009(R0)+,R3`009`009; Get first character X60$: X`009MOVL`009UCB$L_PY_XUCB(R11),R5`009; Get TW's UCB address X X.IF`009DEFINED`009VMS_V4 X`009DSBINT`009UCB$B_DIPL(R5) X.IF_FALSE X`009DEVICELOCK`009`009-`009; Take device lock for TW device X`009`009LOCKADDR=UCB$L_DLCK(R5),- ; X`009`009LOCKIPL=UCB$B_DIPL(R5), - ; X`009`009SAVIPL=-(SP),`009-`009; X`009`009PRESERVE=YES`009`009; X.ENDC X X70$: X`009INCL`009R10`009`009`009; Increment sent character count X`009JSB`009@UCB$L_TT_PUTNXT(R5)`009; Buffer character X`009BLSS`00990$`009`009`009; LSS burst X`009BGTR`009100$`009`009`009; GTR single character X80$:`009BBS`009#TTY$V_TP_XOFF,`009-`009; See if XOFFED is so then X`009`009UCB$B_TP_STAT(R5),120$`009; stop input and check for echoed data X`009DECW`009R8`009`009`009; Decrease number to send in burst X`009BLEQ`009110$`009`009`009; LEQ block done see if request done X`009MOVZBL`009(R0)+,R3`009`009; Get next character X`009BRB`00970$`009`009`009; Send next character X90$: X`009BISW`009TTY$M_TANK_BURST, -`009; Signal burst X`009`009UCB$W_TT_HOLD(R5)`009; X`009BRB`00980$`009`009`009; Continue processing X100$: X`009MOVB`009R3,UCB$W_TT_HOLD(R5)`009; Store character in tank X`009BISW`009#TTY$M_TANK_HOLD, -`009; Signal character in tank X`009`009UCB$W_TT_HOLD(R5)`009; X`009BRB`00980$`009`009`009; Continue processing X X; X; See if this request is done or if more to do X; X110$: X`009CMPL`009R10,R9`009`009`009; All done X`009BGEQ`009120$`009`009`009; GEQ done so check for echo X X.IF`009DEFINED`009VMS_V4 X`009ENBINT X.IF_FALSE X`009DEVICEUNLOCK`009`009-`009; More in request release lock X`009`009LOCKADDR=UCB$L_DLCK(R5), - ; and go back and get it X`009`009NEWIPL=(SP)+,`009-`009; X`009`009PRESERVE=YES`009`009; X.ENDC X X`009MOVL`009P1(AP),R0`009`009; Restore users buffer address X`009BRW`00920$`009`009`009; X X; X; See if need to start up pending read X; X120$: X`009BBS`009#TTY$V_TANK_HOLD, -`009; If storing character in hold X`009`009UCB$W_TT_HOLD(R5),130$`009; start output X`009BBC`009#TTY$V_TANK_BURST, -`009; If no output burst then all done X`009`009UCB$W_TT_HOLD(R5),140$`009; finish up X130$: X`009BBC`009#UCB$V_BSY,`009-`009; PY ready to take data X`009`009UCB$W_STS(R11),140$`009; X`009MOVL`009UCB$L_IRP(R11),R3`009; Get IRP address X`009MOVL`009R11,R5`009`009`009; Get PY UCB address X`009JSB`009G^IOC$INITIATE`009`009; Now start PY read X140$: X X.IF`009DEFINED`009VMS_V4 X`009ENBINT X.IF_FALSE X`009DEVICEUNLOCK`009`009-`009; Done release lock X`009`009LOCKADDR=UCB$L_DLCK(R11), - ; NOTE PY & TW lock are the same X`009`009NEWIPL=(SP)+`009`009; X.ENDC X X`009BBS`009#TTY$V_TP_XOFF,`009-`009; See if XOFFED report this special X`009`009UCB$B_TP_STAT(R5),170$`009; case X; X; Finish up the read X; X150$: X`009POPR`009#^M<R3,R4,R5>`009`009; Restore IRP, PCB, and UCB X160$: X`009INSV`009R10,#16,#16,R0`009`009; Move number of bytes INPUT X`009MOVW`009#SS$_NORMAL,R0`009`009; Everything is just fine X`009JMP`009G^EXE$FINISHIOC`009`009; Complete the I/O request X X;+ X; Special code to deal with input while xoffed. X;- X`009TTY$M_TP_XOFF = 8 X`009TTY$V_TP_XOFF = 3 X`009ASSUME`009TTY$M_TP_XOFF EQ TTY$M_TP_DLLOC+4 X`009ASSUME TTY$V_TP_XOFF EQ TTY$V_TP_DLLOC+1 X X170$: X`009POPR`009#^M<R3,R4,R5>`009`009; Restore IRP, PCB, and UCB X`009INSV`009R10,#16,#16,R0`009`009; Move number of bytes INPUT X`009MOVW`009#SS$_DATAOVERUN,R0`009; Cannot input more data X`009JMP`009G^EXE$FINISHIOC`009`009; Complete the I/O request X`012 X`009.PAGE X`009.SBTTL`009PY$CANCEL - Cancel the IO on the PY device X;++ X; X; Functional Description: X; X;`009This routine is entered to stop io on a PY unit. If this is the last X;`009deassign on the PY device, issue a CLASS_DISCONNECT on our associated X;`009TW device to get it away from any processes using it. X; X; Inputs: X; X;`009R2 = Negative of the Channel Number, X;`009`009also called channel index number X;`009R3 = Current IO package address X;`009R4 = PCB of canceling process X;`009R5 = UCB Address X;`009R8 = CAN$C_CANCEL on CANCEL IO or CAN$C_DASSGN on DEASSIGN X; X; Outputs: X;`009Everything should be preserved X;-- XPY$CANCEL::`009`009`009`009`009; Cancel PY usage X`009JSB`009G^IOC$CANCELIO`009`009`009; Call the cancel routine X`009BBC`009#UCB$V_CANCEL,UCB$W_STS(R5),10$`009; Branch if not for this guy X`009MOVQ`009#SS$_ABORT,R0`009`009`009; Status is request canceled X`009BICW`009#<UCB$M_BSY!UCB$M_CANCEL>,-`009; X`009`009UCB$W_STS(R5)`009`009`009; Clear unit status flags X`009JSB`009G^IOC$REQCOM`009`009`009; Complete request X10$:`009TSTW`009UCB$W_REFC(R5)`009`009`009; Last Deassign X`009BNEQ`009100$`009`009`009`009; No, just exit X; X; Last DEASSIGN we need to get rid of AST's X; X`009pushr`009#^M<r2, r3, r4, r5, r7> X`009movl`009UCB$L_PY_XUCB(r5), r5`009`009; Switch to TW UCB X`009beql`00920$`009`009`009`009; if not there, skip X`009MOVAB`009UCB$L_TW_XON_AST(R5),R7`009`009; Get XON list head address X`009TSTL`009(R7)`009`009`009`009; Any ast to deliver X`009BEQL`00911$`009`009`009`009; EQL 0 do not flush it X`009JSB`009G^COM$FLUSHATTNS`009`009; Flush it X11$:`009MOVAB`009UCB$L_TW_XOFF_AST(R5),R7`009; Get XOFF list head address X`009TSTL`009(R7)`009`009`009`009; Any ast to deliver X`009BEQL`00912$`009`009`009`009; EQL 0 do not flush it X`009JSB`009G^COM$FLUSHATTNS`009`009; Flush it V12$:`009MOVAB`009UCB$L_TW_SET_AST(R5),R7`009`009; Get SET_LINE list head addres Xs X`009TSTL`009(R7)`009`009`009`009; Any ast to deliver X`009BEQL`00913$`009`009`009`009; EQL 0 do not flush it X`009JSB`009G^COM$FLUSHATTNS`009`009; Flush it X; X; Do a DISCONNECT on the TW device. X; X13$: X`009clrl`009UCB$L_TW_XUCB(r5)`009`009; Clear backlink to PY device X`009bisl2`009#UCB$M_DELETEUCB, UCB$L_STS(r5) ; Set it to go bye-bye X`009bicw2`009#UCB$M_ONLINE,UCB$W_STS(R5)`009; Mark offline X`009bicb2`009#UCB$M_INT, UCB$W_STS(r5)`009; Don't expect interrupt X`009movl`009UCB$L_TT_LOGUCB(r5), r1`009`009; Look at logical term UCB X`009tstw`009UCB$W_REFC(r1)`009`009`009; See if TW has any references X`009bneq`00915$`009`009`009`009; If so, go and do disconnect X`009jsb`009G^IOC$DELETE_UCB`009`009; if not, delete the UCB X`009brb`00920$ X15$:`009clrl`009r0`009`009`009`009; indicate that we must hangup X`009movl`009UCB$L_TT_CLASS(r5), r1 X`009jsb`009@CLASS_DISCONNECT(r1)`009`009; Force disconnect X20$:`009popr`009#^M<r2, r3, r4, r5, r7>`009`009; Switch back to PY UCB X`009clrl`009UCB$L_PY_XUCB(r5)`009`009; Clear link to deleted TW X`009bisl2`009#UCB$M_DELETEUCB, UCB$L_STS(r5)`009; Set our own delete bit X100$:`009rsb X`012 X`009.PAGE X`009.SBTTL PY$INITIAL - Initialize Pseudo terminal interface X X;++ X; PY$INITIAL - Initialize the interface X; X; Functional Description: X; X;`009This routine is entered at device connect time and power recovery. X;`009There isn't much to do to the device. X; X; Inputs: X; X;`009R4 = The devices CSR (but there is no csr!) X;`009R5 = address of IDB X;`009R6 = address of DDB X;`009R7 = address of CRB X; X; Outputs: X; X;`009All registers preserved X; X;-- XPY$INITIAL:: X`009RSB X`012 X`009.PAGE X`009.SBTTL`009PY$CLONE_INIT - initialize the unit X;++ X; PY$CLONE_INIT - Initialize new PY device X; X; Functional Description: X; X;`009Main thing we do here is clone up an associated terminal device X;`009and initialize fields in the two new UCB's. X; X; Inputs: X; X;`009R5`009= Address of UCB X; X; Outputs: X; X;`009All preserved X;-- X XPY$CLONE_INIT:: X X;+ --- X;`009Ignore inits on UNIT #0 (the template PY UCB) X;- --- X`009TSTL`009UCB$W_UNIT(R2)`009`009`009;UNIT #0?? X`009BNEQ`00910$`009`009`009`009;No: Initialize X`009RSB`009`009`009`009`009;Yes: Return X X10$:`009PUSHR`009#^M<R0,R1,R2,R4,R6,R7,R8> X`009Bicl2`009#UCB$M_DELETEUCB,UCB$L_STS(R2)`009; Clear ucbdelete - dec X`009Movl`009R2,R5 X; X; Find the associated device. X; X; NOTE: We can't call IOC$SEARCHDEV because it expects the string to X;`009be accessible from the previous access mode. (It executes the X;`009prober instruction with mode=#0). I don't know how to make the X;`009string accessible from the previous access mode cleanly, but I X;`009do know how to move most of IOC$SEARCHDEV into the py driver. X; X`009MOVAL`009G^IOC$GL_DEVLIST-DDB$L_LINK,-`009; Get address of i/o database X`009`009R8`009`009`009`009; listhead X`009CLRL`009R6`009`009`009`009; Desired mate = PTY UNIT 0 X`009MOVAB`009L^TWSTRING,R7`009`009`009; String address for TWA X`009MOVL`009#TWLENGTH,R4`009`009`009; String length X`009BSBW`009SEARCHDEV`009`009`009; Find the DDB X`009BNEQ`00920$`009`009`009`009; Device not found X`009BSBW`009SEARCHUNIT`009`009`009; Search for specific unit X`009BNEQ`00930$`009`009`009`009; unit found X20$:`009POPR`009#^M<R0,R1,R2,R4,R6,R7,R8>`009; NOT FOUND: Return X`009RSB X`009 X; X; Create the PTY, R1 has template UCB of TW device X; X30$:`009PUSHL`009R5`009`009`009`009; Save R5 X`009MOVL`009UCB$L_DDB(R5),R0`009`009; Find UNIT #0 UCB FOR PY DEV. X`009MOVL`009DDB$L_UCB(R0),R0 X`009MOVL`009R1,R5`009`009`009`009; R5 = UCB to CLONE X`009JSB`009G^IOC$CLONE_UCB`009`009`009; Clone UCB X X`009MOVL`009R2,R1`009`009`009`009; Put PTY UCB back into R1 X`009POPL`009R5`009`009`009`009; Restore R5 X`009BLBS`009R0,40$`009`009`009`009; WIN!!! (big deal.) X;+ --- X;`009CREATE_UCB failed, mark our PY device offline X;- --- X`009BICW2`009#UCB$M_ONLINE,UCB$W_STS(R5)`009; Mark offline X`009BRW`009100$`009`009`009`009; And return X;+ --- X;`009PTY UCB created successfully, link the UCBs together X;- --- X40$:`009MOVL`009R1,UCB$L_PY_XUCB(R5)`009`009; Store associated UCB X`009MOVL`009R5,UCB$L_TW_XUCB(R1)`009`009; Store the other one back X`009CLRL`009UCB$L_PID(R1)`009`009`009; Clear the owner PID in PTY X`009CLRW`009UCB$W_REFC(R1)`009`009`009; Reference count is ZERO X`009Bicl2`009#UCB$M_DELETEUCB,UCB$L_STS(R1)`009; Inhibit deletion X`009MOVW`009UCB$W_UNIT(R1),-`009`009; Set associated TW unit X`009`009UCB$L_DEVDEPEND(R5)`009`009; number in PY devdepend X;+ --- X;`009Call the PTY unit init routine X;- --- X`009MOVL`009UCB$L_DDT(R1),R0`009`009; Get DDT X`009MOVL`009DDT$L_UNITINIT(R0),R0`009`009; Get Unit Init Addr in DDT X`009CMPL`009R0,#IOC$RETURN`009`009`009; Null Address?? X`009BNEQ`00950$`009`009`009`009; No: Call it X`009MOVL`009UCB$L_CRB(R1),R0`009`009; Yes: Look in the CRB X`009MOVL`009CRB$L_INTD+VEC$L_UNITINIT(R0),R0 X`009BEQL`009100$`009`009`009`009; No: Unit init routine X X50$:`009PUSHL`009R5`009`009`009`009; Save R5 X`009MOVL`009R1,R5`009`009`009`009; R5 = PTY UCB X`009JSB`009(R0)`009`009`009`009; CALL THE UNIT INIT ROUTINE X`009MOVL`009G^CTL$GL_PCB,R4`009`009`009; Use current PCB X`009MOVL`009UCB$L_ORB(R5),R0`009`009; Fetch ORB address X`009MOVL`009PCB$L_UIC(R4),ORB$L_OWNER(R0)`009; Set device owner V`009BISB`009#ORB$M_PROT_16,ORB$B_FLAGS(R0)`009; Indicate using SOGW device prot Xection X`009BICW`009#^XFF,ORB$W_PROT(R0)`009`009; Make device S:O:RWLP X `009POPL`009R5`009`009`009`009; Restore R5 X X100$:`009POPR`009#^M<R0,R1,R2,R4,R6,R7,R8> X`009RSB X`012 X`009.PAGE X`009.SBTTL`009DDB finding Routines X;++ X; SearchDev - Search for device DDB X; X; This routine is called to search the device database for a DDB. X; This is the first step in finding another devices UCB. X; X; This routine copied out of IOC$SEARCHDEV in IOSUBPAGD X; X; Inputs: X; X;`009R8 = DDB Head X;`009R7 = Address of String X;`009`009String = ddc format: example = /TTA/ X;`009R4 = Length of string X; X; Outputs: X; X;`009R8 = DDB of desired device if EQL, otherwise not found X;`009R0 is trashed X;`009R1 is trashed X;-- XSEARCHDEV:`009`009`009`009; Search for device name X10$:`009MOVL`009DDB$L_LINK(R8),R8`009; Get address of next ddb X`009BEQL`00920$`009`009`009; If eql end of list X`009MOVAL`009DDB$T_NAME(R8),R0`009; Get address of generic device name X`009MOVB`009(R0)+,R1`009`009; Calculate len of string to compare X`009CMPB`009R1,R4`009`009`009; Length of names match? X`009BNEQ`00910$`009`009`009; If neq no X`009CMPC`009R4,(R0),(R7)`009`009; Compare device names X`009BNEQ`00910$`009`009`009; If neq names do not match X`009RSB X20$:`009INCL`009R8`009`009`009; indicate search failure X`009RSB X X`009.SBTTL`009UCB finding routine X;++ X; SEARCHUNIT - Subroutine to search for UCB given DDB X; X; Given the DDB of a device, get the UCB and run down the ucb list until X; we get the ucb with the desired unit number. This code is taken out of X; IOC$SEARCHDEV in IOSUBPAGD. X; X; Inputs: X; X;`009R8 = DDB of device X;`009R6 = unit number of desired UCB X; X; Outputs: X; X;`009R1 = UCB of device if NEQ, otherwise not found X;`009R0 is trashed X; X;-- XSEARCHUNIT:`009`009`009`009; Search for unit number X`009MOVAL`009DDB$L_UCB-UCB$L_LINK(R8),- X`009`009R1`009`009`009; Get address of next ucb address X10$:`009MOVL`009UCB$L_LINK(R1),R1`009; Get Address of next ucb X`009BEQL`00940$`009`009`009; If EQL then end of list X`009CMPW`009R6,UCB$W_UNIT(R1)`009; Unit number match? X`009BEQL`00930$`009`009`009; If eql yes X`009BRB`00910$ X30$:`009MOVL`009#SS$_NORMAL,R0`009`009; Indicate match X40$:`009RSB X`012 X`009.PAGE X`009.SBTTL`009PY$STARTIO - Device Startio routines X;++ X; PY$STARTIO`009- Start Input on idle device X; X; Functional Description: X; X;`009If after the read FDT routines are done and nobody is doing X;`009anything on the device (UCB$V_BSY = 0) then call the start io X;`009routine. X; X; Called from: X; X;`009Called from any one of five places: X;`009- The EXE$QIODRVPKT in the PY FDT READ routine X;`009`009which calls EXE$INSIOQ which calls IOC$INITIATE X;`009- The IOC$REQCOM at the end of this PY startio routine X;`009`009which calls IOC$INITIATE X;`009- The TW startio routine which calls IOC$INITIATE X;`009- The PY write fdt routine which calls IOC$INITIATE. X;`009`009In case we must echo a character. X;`009- The PY$RESUME routine which calls IOC$INITIATE. X; X; Inputs: X; X;`009R3 = IRP Address X;`009R5 = UCB Address X;`009`009UCB$W_BCNT and UCB$L_SVAPTE are written by IOC$INITIATE X; X; Outputs: X; X;`009R5 - UCB Address X; X;-- XPY$STARTIO:: X`009.ENABLE LSB X X`009MOVL`009@UCB$L_SVAPTE(R5),-`009`009; Initialize buffer X`009`009UCB$L_SVAPTE(R5)`009`009; pointers XPY_OUT_LOOP: X; X; Here R5 must point at the PY device UCB and not at X; the UCB of the associated TW device. X; X5$:`009TSTW`009UCB$W_BCNT(R5)`009`009`009; Any space left in rd packet X`009BLEQ`00950$`009`009`009`009; No, Completed I/O X; X; Switch to terminal UCB X; X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009`009; Set to TW ucb X; X; Look for next output in state tank X; X; Change Case statement to reflect V4 changes in routines - DEC X; X10$:`009FFS`009#0,#6,UCB$W_TT_HOLD+1(R5),R3 X`009CASE`009R3,TYPE=B,<-`009`009`009; Dispatch X`009`009PY_PREMPT,-`009`009`009; Send Prempt Characte - DEC X`009`009PY_STOP,-`009`009`009; Stop output X`009`009PY_CHAR,-`009`009`009; Char in tank X`009`009PY_BURST,-`009`009`009; Burst in progress X`009`009> X; X; No Pending Data - Look for next character X; X`009BICB`009#UCB$M_INT, UCB$W_STS(R5)`009; Clear interrupt expected X; X; Call class driver for more output X; X`009JSB`009@UCB$L_TT_GETNXT(R5)`009; Get the next character X`009CASEB`009UCB$B_TT_OUTYPE(R5),#-1,#1 X1$:`009.WORD`009PY_START_BURST-1$`009; Burst specified X`009.WORD`009PY_DONE-1$`009`009; None X`009BRW`009BUFFER_CHAR`009`009; Buffer the character X; X; Output queue exhausted XPY_DONE: X`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Switch UCBs to PY UCB X`009BBC`009#UCB$V_BSY,-`009`009; If not BSY then ignore X`009`009UCB$W_STS(R5),47$`009; the char X`009MOVL`009UCB$L_IRP(R5),R3`009; Restore IRP X`009CMPW`009IRP$W_BCNT(R3),-`009; Any characters moved X`009`009UCB$W_BCNT(R5) X`009BNEQ`00950$`009`009`009; Yes complete I/O X47$:`009RSB X; X; read buffer exhausted X; X50$:`009MOVL`009UCB$L_IRP(R5),R3`009; Restore IRP X`009MOVW`009#SS$_NORMAL,-`009`009; Set successful completetion X`009`009IRP$L_IOST1(R3) X`009SUBW`009UCB$W_BCNT(R5),-`009; Update byte count X`009`009IRP$W_BCNT(R3) X`009MOVW`009IRP$W_BCNT(R3),-`009; Set in status X`009`009IRP$L_IOST1+2(R3) X; X; If we wanted to here we could set the second longword of the device status X; X`009CLRL`009IRP$L_IOST2(R3)`009`009; No status X`009MOVQ`009IRP$L_IOST1(R3),R0`009; Load IOSB return values X X`009JMP`009G^IOC$REQCOM X; X; Put the character into the read buffer X; XBUFFER_CHAR: X`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Switch UCBs to PY UCB X`009BBC`009#UCB$V_BSY,- X`009`009UCB$W_STS(R5), 60$`009; If no PY IRP, ignore X`009MOVB`009R3,@UCB$L_SVAPTE(R5)`009; Add character to buffer X`009INCL`009UCB$L_SVAPTE(R5)`009; Bump pointer X`009DECW`009UCB$W_BCNT(R5)`009`009; Show character added X60$:`009BRW`009PY_OUT_LOOP`009`009; Go for another char X; X; Take care of Burst mode R5 must be TW UCB X; XPY_START_BURST: X`009BISW`009#TTY$M_TANK_BURST,-`009; Signal burst active X`009`009UCB$W_TT_HOLD(R5) X; X; Continue burst X; XPY_BURST: X`009MOVL`009UCB$L_TW_XUCB(R5),R1`009; Save PY UCB in R1 X`009CLRL`009R3`009`009`009; Initialize output size X`009CMPW`009UCB$W_TT_OUTLEN(R5),UCB$W_BCNT(R1) ; Is buffer too small? X`009BGTR`00961$`009`009`009; Yes X`009MOVW`009UCB$W_TT_OUTLEN(R5),R3`009; Nope, so output all X`009BRB`00962$ X61$:`009MOVW`009UCB$W_BCNT(R1),R3`009; Just output what we can X X62$:`009PUSHR`009#^M<R0,R1,R2,R3,R4,R5>`009; MOVC3 destroys these registers X`009MOVC3`009R3,@UCB$L_TT_OUTADR(R5),@UCB$L_SVAPTE(R1) X`009`009`009`009`009; Transfer burst to the buffer X`009POPR`009#^M<R0,R1,R2,R3,R4,R5>`009; Restore the registers X X`009ADDL2`009R3,UCB$L_SVAPTE(R1)`009; Update output pointer X`009SUBW2`009R3,UCB$W_BCNT(R1)`009; Update output count X`009ADDL2`009R3,UCB$L_TT_OUTADR(R5)`009; Update input pointer X`009SUBW2`009R3,UCB$W_TT_OUTLEN(R5)`009; Update input count X`009BNEQ`00965$`009`009`009; Not the last character X`009BICW`009#TTY$M_TANK_BURST,- X`009`009UCB$W_TT_HOLD(R5)`009; Reset burst not active X65$:`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Swicht UCBs to PY UCB X`009BRW`009PY_OUT_LOOP X; X; Get a single char from tt and put in read buffer R5 = TW UCB X; XPY_CHAR: X`009MOVB`009UCB$W_TT_HOLD(R5),R3`009; Get the next byte X`009BICW`009#TTY$M_TANK_HOLD,-`009; Show tank empty X`009`009UCB$W_TT_HOLD(R5) X`009BRW`009BUFFER_CHAR X; X; Stop the output R5 = TW UCB X; X; Deleted PY_STOP2 routine and changed bit clear to byte operation - DEC X; XPY_STOP: X`009BICB`009#UCB$M_INT, - X`009`009UCB$W_STS(R5)`009`009; Reset output active X`009BRW`009PY_DONE`009`009`009; DON'T go for anymore X`009`009`009`009`009; Or we'll get into an infinite loop X; X; Send Xon or Xoff characters, R5 = TW UCB X; X; Changed PY_XOFF and PY_XON to be PY_PREMPT - DEC X; XPY_PREMPT: X`009movb`009UCB$B_TT_PREMPT(r5), r3`009; Pick up the character X`009BICW`009#TTY$M_TANK_PREMPT,-`009; Reset Xoff state X`009`009UCB$W_TT_HOLD(R5) X`009BRW`009BUFFER_CHAR X`009.DISABLE LSB X`012 X`009.SBTTL`009PY$SET - Set up ATTENTION AST's X;++ X; PY$FDTSET - FUNCTION DECISION ROUTINE FOR SET MODE/CHAR FUNCTIONS X; X; FUNCTIONAL DESCRIPTION: X; X; This routine is the function decision routine for SET MODE/CHAR X; functions. X; X; P4(AP)`009Determines what AST get's setup. X;`009`009`0091 -> XON AST X;`009`009`0092 -> XOFF AST X;`009`009`0093 -> SET_LINE AST X; X; INPUTS: X; X;`009R3 = I/O PACKET ADDRESS X;`009R4 = PCB ADDRESS OF CURRENT PROCESS X;`009R5 = UCB ADDRESS X;`009R6 = CCB ADDRESS FOR ASSIGNED UNIT X;`009AP = ADDRESS OF ARGUMENT LIST AT USER PARAMETERS X; X; OUTPUTS: X; X;`009The function is completed here by "EXE$FINISHIO". X; X; IMPLICIT OUTPUTS: X; X; `009R3,R5 ARE PRESERVED. X;-- XPY$FDTSET: X`009PUSHL`009R5 X`009MOVZWL`009#SS$_NOSUCHDEV,R0`009; Assume no TW device X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009; Switch to TW UCB X`009BEQL`009SET_ABORT`009`009; No TW UCB exit X`009CASE`009P4(AP),LIMIT=#1,TYPE=B,<- ; Figure out what to set X`009`009SET_XON_AST,-`009`009; X`009`009SET_XOFF_AST,-`009`009; X`009`009SET_LINE_AST>`009`009; XBAD_SET: X`009MOVZWL`009#SS$_BADPARAM,R0`009; Failure reason XSET_ABORT: X`009POPL`009R5 X`009JMP`009G^EXE$ABORTIO X XSET_XON_AST: X`009MOVAB`009UCB$L_TW_XON_AST(R5),R7`009; XON AST list head address X`009BRB`009SET_CMN`009`009`009; Go to common code X XSET_XOFF_AST: X`009MOVAB`009UCB$L_TW_XOFF_AST(R5),R7 ; XOFF AST list head address X`009BRB`009SET_CMN`009`009`009; Go to common code X XSET_LINE_AST: X`009MOVAB`009UCB$L_TW_SET_AST(R5),R7`009; SET_LINE AST list head address X XSET_CMN: X`009POPL`009R5 X`009JSB`009G^COM$SETATTNAST`009; Insert into AST list X`009JMP`009G^EXE$FINISHIOC`009`009; Complete request X`012 X`009.SBTTL`009PY$FDTSENSEM - Sense mode routine X;++ X; TTY$FDTSENSEM - SENSE MODE X; X; FUNCTIONAL DESCRIPTION: X; X; This routine passes the the current characteristics for SENSEMODE. X; The buffer returned is a 8 or 12 bytes depending upon users request. X; X; INPUTS: X; X;`009R3 = I/O PACKET ADDRESS X;`009R4 = CURRENT PCB ADDRESS X;`009R5 = UCB ADDRESS X;`009R6 = CCB ADDRESS X;`009R7 = FUNCTION CODE X;`009AP = ARG LIST FROM QIO X; X; OUTPUTS: X; X;`009CONTROL IS PASSED TO EXE$ABORTIO ON FAILURE X;`009OR COMPLETED VIA EXE$FINISHIO X; X; STATUS RETURNS: X; X;`009SS$_NORMAL - SUCCESSFULL X;`009SS$_ACCVIO - BUFFER NOT ACCESSIBLE X; X; NOTE: X;`009The following code assumes that the DEVICE and FORK lock X;`009for the TW device are the same. If this changes then this X;`009code is broken. X; X;-- XPY$FDTSENSEM:: X`009BSBW`009VERIFY_SENSE`009`009; VERIFY USER STORAGE X`009PUSHR`009#^M<R5,R6,R7,R8,R10,R11> X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009; Switch to TW UCB X`009BEQL`009PY$SENSE_ERR`009`009; Have UCB X`009MOVL`009UCB$L_TT_LOGUCB(R5),R5`009; Switch to logical device is one exists X`009BSBW`009GET_DCL`009`009`009; BUILD SPECIAL CHARACTERISTICS X X.IF`009DEFINED`009VMS_V4 X`009DSBINT`009UCB$B_DIPL(R5) X.IF_FALSE X`009DEVICELOCK LOCKADDR=UCB$L_DLCK(R5),- ; Lock out TW activity X`009`009LOCKIPL=UCB$B_DIPL(R5),-; RAISE IPL X`009`009SAVIPL=-(SP),`009-`009; SAVE CURRENT IPL X`009`009PRESERVE=YES`009`009; X.ENDC X X`009MOVL`009UCB$B_DEVCLASS(R5),R6`009; BUILD TYPE, AND BUFFER SIZE X`009MOVL`009UCB$L_DEVDEPEND(R5),R7`009;RETURN 1ST CHARACTERISTICS LONGWORD X`009BISL3`009R2,UCB$L_DEVDEPND2(R5),R8;AND 2ND LONGWORD (IF REQUESTED) X`009MOVL`009UCB$W_TT_SPEED-2(R5),R10; RETURN SPEED X`009MOVL`009UCB$B_TT_PARITY-2(R5),R11; RETURN PARITY INFO X`009BICL`009#^XFF000000,R11`009`009; ZERO HIGH BYTE X`009MOVW`009UCB$B_TT_CRFILL(R5),R11`009; AND CR/LF FILL X X.IF`009DEFINED`009VMS_V4 X`009ENBINT X.IF_FALSE X`009DEVICEUNLOCK LOCKADDR=UCB$L_DLCK(R5),- ; RELEASE INTERLOCK X`009`009NEWIPL=(SP)+,`009-`009; RESTORE IPL X`009`009CONDITION=RESTORE, -`009; X`009`009PRESERVE=YES`009`009; X.ENDC X X`009MOVL`009R6,(R1)`009`009`009; RETURN USER DATA X`009MOVL`009R7,4(R1)`009`009; X`009CMPB`009R0,#12`009`009`009; DID HE ASK FOR 2ND ? X`009BLSS`00910$`009`009`009; NO X`009MOVL`009R8,8(R1)`009`009; X10$:`009MOVL`009R10,R0`009`009`009; RETURN IOSB DATA X`009MOVL`009R11,R1`009`009`009; X`009BRW`009CMN_EXIT`009`009; EXIT RETURNING R0,R1`009 X`012 X;`009If no TW device abort with SS$_NOSUCHDEV XPY$SENSE_ERR: X`009POPR`009#^M<R5,R6,R7,R8,R10,R11> X`009MOVZWL`009#SS$_NOSUCHDEV,R0`009; Save error reason X`009JMP`009G^EXE$ABORTIO`009`009; Abort request X`012 X`009.SBTTL`009PY$FDTSENSEC - Sense char routine X;++ X; TTY$FDTSENSEC - SENSE CHARACTERISTICS X; X; FUNCTIONAL DESCRIPTION: X; X; This routine passes the the permanent characteristics for SENSECHAR. X; The buffer returned is a 8 or 12 bytes depending upon users request. X; X; INPUTS: X; X;`009R3 = I/O PACKET ADDRESS X;`009R4 = CURRENT PCB ADDRESS X;`009R5 = UCB ADDRESS X;`009R6 = CCB ADDRESS X;`009R7 = FUNCTION CODE X;`009AP = ARG LIST FROM QIO X; X; OUTPUTS: X; X;`009CONTROL IS PASSED TO EXE$ABORTIO ON FAILURE X;`009OR COMPLETED VIA EXE$FINISHIO X; X; STATUS RETURNS: X; X;`009SS$_NORMAL - SUCCESSFULL X;`009SS$_ACCVIO - BUFFER NOT ACCESSIBLE X; X; NOTE: X;`009The following code assumes that the DEVICE and FORK lock X;`009for the TW device are the same. If this changes then this X;`009code is broken. X;-- XPY$FDTSENSEC::`009`009`009`009; SENSE CHAR X`009BSBW`009VERIFY_SENSE`009`009; VERIFY USER STORAGE X`009PUSHR`009#^M<R5,R6,R7,R8,R10,R11> X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009; Switch to TW UCB X`009BEQL`009PY$SENSE_ERR`009`009; Have UCB X`009BSBW`009GET_DCL`009`009`009; BUILD SPECIAL CHARACTERISTICS X X.IF`009DEFINED`009VMS_V4 X`009DSBINT`009UCB$B_DIPL(R5) X.IF_FALSE X`009DEVICELOCK LOCKADDR=UCB$L_DLCK(R5),- ; Lock out TW activity X`009`009LOCKIPL=UCB$B_DIPL(R5),-; RAISE IPL X`009`009SAVIPL=-(SP)`009`009; SAVE CURRENT IPL X.ENDC X X`009MOVL`009UCB$B_TT_DETYPE-1(R5),R6; BUILD TYPE, AND BUFFER SIZE X`009MOVB`009#DC$_TERM,R6`009`009; BUILD DEVICE CLASS X`009MOVL`009UCB$L_TT_DECHAR(R5),R7`009;RETURN 1ST CHARACTERISTICS LONGWORD X`009BISL3`009R2,UCB$L_TT_DECHA1(R5),R8;AND 2ND LONGWORD (IF REQUESTED) X`009MOVL`009UCB$W_TT_DESPEE-2(R5),R10; RETURN SPEED X`009MOVL`009UCB$B_TT_DEPARI-2(R5),R11; RETURN PARITY INFO X`009BICL`009#^XFF000000,R11`009`009; ZERO HIGH BYTE X`009MOVW`009UCB$B_TT_DECRF(R5),R11`009; AND CR/LF FILL X X.IF`009DEFINED`009VMS_V4 X`009ENBINT X.IF_FALSE X`009DEVICEUNLOCK LOCKADDR=UCB$L_DLCK(R5),- ; RELEASE INTERLOCK X`009`009NEWIPL=(SP)+,`009-`009; RESTORE IPL X`009`009CONDITION=RESTORE`009; X.ENDC X X`009MOVL`009R6,(R1)`009`009`009; RETURN USER DATA X`009MOVL`009R7,4(R1)`009`009; X`009CMPB`009R0,#12`009`009`009; DID HE ASK FOR 2ND ? X`009BLSS`00910$`009`009`009; NO X`009MOVL`009R8,8(R1)`009`009; X10$:`009MOVL`009R10,R0`009`009`009; RETURN IOSB DATA X`009MOVL`009R11,R1`009`009`009; X`009BRW`009CMN_EXIT`009`009; EXIT RETURNING R0,R1`009 X`012 X;`009THIS ROUTINE BUILDS DCL PRIVATE CHARACTERISTICS X XGET_DCL: X`009CLRL`009R2`009`009`009; INIT RETRUN ARGUMENT X`009TSTL`009UCB$L_AMB(R5)`009`009; ANY ASSOCIATED MAILBOX? X`009BEQL`00910$`009`009`009; NO X`009BISL`009#TT2$M_DCL_MAILBX,R2`009; YES, SO BUILD CHARACTERISTIC X10$:`009RSB X`012 X;`009Common exit path for PY$FDTSENSEM and PY$FDTSENSEC X XCMN_EXIT: X`009POPR`009#^M<R5,R6,R7,R8,R10,R11> ; RESTORE SCRATCH REGISTERS X`009MOVW`009#SS$_NORMAL,R0 X`009JMP`009G^EXE$FINISHIO`009`009; COMPLETE REQUEST IOSB WORD 0,1 X`012 X;`009This routine verifies that the user buffer is accessable X XVERIFY_SENSE:`009`009`009`009; X`009MOVL`009P1(AP),R1`009`009; ADDRESS USER BUFFER X`009IFNOWRT`009#8,(R1),20$`009`009; BR IF NO ACCESS TO QUADWORD BUFFER X`009MOVL`009#8,R0`009`009`009; INIT DEFAULT ARGUMENT SIZE X`009CLRQ`009(R1)`009`009`009; INIT RETURN DATA X`009MOVZWL`009P2(AP),R2`009`009; GET SIZE ARGUMENT X`009CMPL`009R2,#12`009`009`009; ROOM FOR SECOND DEVDEPEND SPECIFIED? X`009BLSSU`00910$`009`009`009; NO X`009IFNOWRT`009#12,(R1),20$`009`009; CHECK IF WRITE ACCESS -+-+-+-+-+ End of part 4 +-+-+-+-+-