.MCALL .MODULE .MODULE XL,VERSION=40,COMMENT= ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL Abstract and Edit History ;+ ; ; FACILITY: RT-11 Device driver ; ; FUNCTIONAL DESCRIPTION: ; ; This driver aids in the writing of virtual terminal software. It ; supports the XON/XOFF protocol in that if recieves too many chars ; it will transmit a CTRL/S and send a CTRL/Q when it again has room. ; It will also stop transmitting if it recieves a CTRL/S and resume ; on a CTRL/Q. Normal RT-11 READ/WRITE commands can be done to the ; plus various special functions. On any data transfer, chars are ; striped to seven bits and chars of value zero are ignored. On output ; the character following a carriage return is not output. ; ; ENVIRONMENT: Any type RT-11 system ; ; AUTHOR: Janice Ann Kelso, CREATION DATE: 12-Feb-81 ; .SBTTL EDIT HISTORY ; ; MODIFIED BY: ; ; 23-Mar-81 JLB Added DTR support for ZK switch and modems. ; ; X05 (013) 09-Aug-83 Added PRO-3xx support as a conditional ; MBG assembly. Major code clean-up. ; ; X05 (014) 12-Sep-83 Added SBC-11 (Falcon board) support as a ; MHB conditional assembly. ; ; Y01 (000) 06-Oct-83 Correct version number passing and change ; JRW the name of module to XL. ; ; Y01 (001) 11-Oct-83 Added conditional checking and changed device ; MBG ID to 57 to bring in line with documentation. ; ; Y01 (004) 16-Nov-83 Clean up for SBC ; MBG ; ; Y01 (005) 17-Nov-83 Remove forcing of CSR/VECTORs for Falcon ; MBG ; ; V05 (006) 23-Jan-84 Ready for release ; ; V05 (007) 24-Jan-84 Fixed internal queueing problems on PRO ; MBG ; ; V05 (012) 20-Oct-84 Adding DTR control for mini-exchange code plus ; MBG possible HANGUP et al commands. ; ; 4-Aug-85 Added .DRPTR, .DREST, .DRSPF ; JFW ; ; V05 (016) 23-Sep-85 Added .DRINS, changed references to 176 to INSCSR. ; MBG ; ; V05 (019) 03-Dec-85 Added code to handle abort by channel (.ABTIO) ; MBG due to change in RMON ; ; V05 (020) 08-Jul-86 Return more modem information through status ; MBG spfun. Included 'Carrier detect' and 'Ring ; indicate' ; ; V05 (021) 17-Jul-86 Changed CMP to CMPB for character comparisons. ; MBG ; ; (029) 15-Aug-90 Adding multi-terminal handler hooks support ; MBG ; ; (030) 28-Sep-90 MBG Fixing SET code overflow ; ; (031) 16-Nov-90 MBG Modification to allow installation of MTYHK ; handler when install-time CSR is not present ; ; (032) 08-Jan-91 MBG Fix to release code regarding register usage ; ; (033) 08-Jan-91 MBG SETSTT was inadvertently clearing bits it ; shouldn't have been affecting due to use of ; a MOV rather than a BIS ; ; (034) 12-Feb-91 MBG SET CSR should know when MTTY is in affect and ; put the new CSR in the right place. ; ; (035) 21-Feb-91 MBG Have XL tell multiterminal that it will process ; modem control signals. ; ; (036) 01-Apr-91 MBG Change back to previous method of detecting ; handler hooks support ; ; (037) 20-Jun-91 WFG Conditionalize .END to work with XC.MAC ; ; (038) 16-Jul-91 MBG Changed previous 'fix' of SETSTT back to use ; of MOV. Any code which requires SETSTT should ; first call GETSTT and assert or deassert the ; bits to be changed. Removed unused routine ; RESSTT. ; ; (039) 24-Aug-91 MBG Ensure aborted Qelements have hard error set ; in CSW and that no completion routines will ; run for aborted Qelements. Change to algorithm ; for aborting internally queued handlers - Qelements ; are returned one at a time via the fake device ; queue. ; ; (040) 31-Aug-91 MBG Change back to previous method of aborting ; Qelements. Removed setting of hard error bit ; for aborted Qelements, retained code to clear ; completion word. ; ;- .SBTTL Conditional assembly summary ;+ ;COND ; ; XL$DVE (0) support for DLV11E ; 0 no support ; 1 support ; ; XL$PC (0) support for PRO300 series ; 0 no support ; 1 support ; ; XL$SBC (0) support for SBC-11/21[+] and MXV SLUs ; 0 no support ; 1 support ; ; Exactly one of XL$PC, XL$DVE and XL$SBC ; may be specified. ; ; XL$PDT (0) support PDT lights ; 0 no support ; 1 support ; ; XL$PDT is ignored if XL$PC is 1 ; ; XL$PRI (4) interrupt priority ; (5) if XL$SBC is 1 ; 4-7 range ; ; XL$CSR (176500) CSR address ; (173300) if XL$PC is 1 ; ; XL$VEC (300) Vector address ; (210) if XL$PC is 1 ; ; XL$MTY (0) No support multiterminal handler hooks ; 1 Support for multiterminal handler hooks ; ; XL$MTY may be 1 only when XL$PC is 0. ; ; XL$LUN (1) Line number to use in multiterminal ; ; MMG$T std conditional ; TIM$IT std conditional (no code effect) ; ERL$G std conditional (no code effect) ; ;- .ENABL LC .SBTTL MACROS AND DEFINITIONS .LIBRARY "SRC:SYSTEM.MLB" ; Declare the RT system macros we'll be using .MCALL .DRDEF .MTPS .INTEN .MCALL .ASSUM .ADDR .BR .MCALL .MTSTA ; Define and verify some conditionals .IIF NDF XL$DVE XL$DVE = 0 ;Default to non DLV11-E interface .IIF NDF XL$PC XL$PC = 0 ;Default to non PRO-3xx support .IIF NDF XL$PDT XL$PDT = 0 ;Default to no PDT lights display .IIF NDF XL$SBC XL$SBC = 0 ;Default to non SBC-11 interface .IIF NDF XL$MTY XL$MTY = 0 ;Default to no support for MTY hooks .IIF NDF XL$LUN XL$LUN = 1 ;Default to LUN 1 .Assume > EQ 0 MESSAGE= .Assume LE 1 MESSAGE= .Assume EQ 0 MESSAGE= ; Set the audit trail .XLGEN = XL$PC ! ! ! .XLGEN = .XLGEN ! .AUDIT .XL ;The handler .AUDIT .XLGEN ; and the conditionals ; Define the device ; o Entered on all aborts ; o handles .SPFUN system call .IF NE XL$PC XL$CSR = 173300 ;Force these for a PRO XL$VEC = 210 .ENDC ;NE XL$PC .IIF NDF XL$PRI XL$PRI = 4 ;Interrupt processing level .IF NE XL$SBC XL$PRI = 5 ;Force this for SBC-11/12[+] and MXV .ENDC ;NE XL$SBC .DRDEF XL,57,,0,176500,300,DMA=NO .IF EQ XL$PC .DRPTR FETCH=FETCH,LOAD=LOAD,UNLOAD=UNLOAD,RELEAS=RELEAS .IFF ;EQ XL$PC .DRPTR UNLOAD=UNLOAD,RELEAS=RELEAS .ENDC ;EQ XL$PC .DREST CLASS=DVC.VT .DRSPF <201> ;Reset 'received XOFF from host' flag ; and send XON to host .DRSPF <202> ;Set/clear BREAK ; word count <> 0, BREAK ; word count = 0, end BREAK .DRSPF <203> ;Special read. Word count is maximum ; number of bytes to read. Terminates ; when number of bytes specified have ; been read or when the input buffer ; is empty. Always reads at least one ; byte even if buffer is empty when ; the read is issued. .DRSPF <204> ;Returns driver status in first word ; of buffer. High byte = driver edit ; level. Low byte = XOFF status and ; some modem signals. .DRSPF <205> ;Sets a flag which will cause ; interrupts to be turned off on ; program exit .DRSPF <206> ;Sets/Resets DTR ; word count <> 0, set DTR ; word count = 0, reset DTR ; Handler version number given to VTCOM in INIT message $$$VER == 18. ;VTCOM and XL must be a matched set ; RT-11 System communications area .MCALL .SYCDF .SYCDF ;Define system communications area ; RMON Fixed offset area .MCALL .FIXDF .CF1DF .CF2DF .MCALL .SGNDF .FIXDF ;Define RMON fixed offsets .CF1DF ;Define config word 1 bits .CF2DF ;Define config word 2 bits .SGNDF ;Define SYSGEN features word bits ; Multiterminal status block .MCALL .MSTDF .MSTDF ;Define .MTSTA status block ; Handler header definitions .MCALL .HBGDF .HBGDF ;Define handler header ; Handler hooks related definitions .MCALL .THKDF .TCBDF .TSTDF .TCBDF ;Define TCB offsets .THKDF ;Define handler hooks data structure .TSTDF ;Define T.STAT word bits ; Input buffer definitions BUFSIZ = 64. ;Size of input buffer (in bytes) STPSIZ = BUFSIZ/4 ;Low-water mark (when to send XOFF) RSTSIZ = BUFSIZ*3/4 ;High-water mark (when to send XON) ; Control Characters C.LF = 12 ;Line feed C.CR = 15 ;Carriage return C.CTLQ = 21 ;XON (^Q) C.CTLS = 23 ;XOFF (^S) C.CTLZ = 32 ;End-of-file (^Z) ; .SPFUN codes supported by driver CLRDRV = 201 ;Reset 'received XOFF from host' flag ; and send XON to host BRKDRV = 202 ;Set/clear BREAK ; word count <> 0, BREAK ; word count = 0, end BREAK SRDDRV = 203 ;Special read. Word count is maximum ; number of bytes to read. Terminates ; when number of bytes specified have ; been read or when the input buffer ; is empty. Always reads at least one ; byte even if buffer is empty when ; the read is issued. STSDRV = 204 ;Returns driver status in first word ; of buffer. High byte = driver edit ; level. Low byte = ST.XFH = 000001 ;XOFF sent to host ST.XOF = 000002 ;XOFF received from host ST.CTS = 000004 ;Dataset: Clear To Send asserted ST.CD = 000010 ;Dataset: Carrier Detect asserted ST.RI = 000020 ;Dataset: Ring Indicate asserted OFFDRV = 205 ;Sets a flag which will cause ; interrupts to be turned off on ; program exit DTRDRV = 206 ;Sets/Resets DTR ; word count <> 0, set DTR ; word count = 0, reset DTR ;NOTE: if you add special function code, add them to .DRSPF too! ; Interface bit definitions RC.RI = 040000 ;Ring indicator RC.CTS = 020000 ;Clear to send RC.CD = 010000 ;Carrier detect RC.IE = 000100 ;Interrupt enable RC.RTS = 000004 ;Request to send RC.DTR = 000002 ;Data terminal ready XC.IE = 000100 ;Transmitter: interrupt enable .IF NE XL$DVE XC.SMK = 170000 ;Speed mask XC.SCE = 004000 ;Speed change enable .ENDC ;NE XL$DVE .IF NE XL$SBC XC.SMK = 000070 ;Speed mask XC.SCE = 000002 ;Speed change enable .ENDC ;NE XL$SBC XC.BRK = 000001 ; BREAK .IF NE XL$PC ; PRO-3xx Interrupt controller registers IC0DR = 173200 ;Interrupt controller 0 data register IC0CR = IC0DR+2 ;Interrupt controller 0 csr register ; PRO-3xx Communications port registers XL$BUF = XL$CSR ;Recv/Xmit buffer register XL$CSA = XL$CSR+2 ;CSR register A XL$CSB = XL$CSR+6 ;CSR register B XL$MC0 = XL$CSR+10 ;Modem control register 0 XL$MC1 = XL$CSR+12 ;Modem control register 1 XL$BAU = XL$CSR+14 ;Baud rate control register ; CSRA Write/Read register bit definitions RPT.R0 = 000 ;Write/Read register 0 CRC.TR = 300 ; Reset transmit underrun/end of message latch CMD.RE = 020 ; Reset external/status interrupts CMD.CR = 030 ; Channel reset CMD.RT = 050 ; Reset transmitter interrupt pending CMD.ER = 060 ; Reset error latches CMD.EI = 070 ; End of interrupt RPT.R1 = 001 ;Write/Read register 1 W1.RIE = 030 ; Receiver interrupt enable ; (Int. on rec. char or special (no parity)) W1.TIE = 002 ; Transmitter interrupt enable RPT.R2 = 002 ;Write/Read register 2 RPT.R3 = 003 ;Write register 3 RCL.8 = 300 ; Receiver character length (8 bits) W3.RXE = 001 ; Receiver enable RPT.R4 = 004 ;Write register 4 CLK.16 = 100 ; 16x rate multiplier STP.1 = 004 ; 1 stop bit W4.EVN = 002 ; Even parity W4.PEN = 001 ; Parity enable RPT.R5 = 005 ;Write register 5 TCL.8 = 140 ; Transmit character length (8 bits) W5.SB = 020 ; Send break W5.TXE = 010 ; Transmitter enable ; CSRB Write/Read register bit definitions RPT.R1 = 001 ;Write/Read register 1 W1.REQ = 004 ; MUST be loaded with 004 RPT.R2 = 002 ;Write/Read register 2 W2.REQ = 000 ; MUST be loaded with 000 R2.IMK = 034 ; Interrupt vector mask IMK.BE = 020 ; Transmit buffer empty IMK.ES = 024 ; External/Status change IMK.CA = 030 ; Received character available IMK.SR = 034 ; Special receiver condition ; Modem control Register bit definitions CLK.BG = 000 ; Rx = RBRG, Tx = TBRG ->MD = none M0.DTR = 020 ; Data terminal ready M0.RTS = 010 ; Request to send M1.RI = 100 ; Ring indicator M1.CTS = 040 ; Clear to send M1.CD = 020 ; Carrier detect .ENDC ;NE XL$PC ; Baud rate mask definitions (PRO-3xx, DLV11-E,F and MXV11-B) .IF NE B.50 = 000 ; 50 baud B.75 = 001 ; 75 baud B.110 = 002 ; 110 baud B.134 = 003 ; 134.5 baud B.150 = 004 ; 150 baud B.300 = 005 ; 300 baud B.600 = 006 ; 600 baud B.1200 = 007 ; 1200 baud B.1800 = 010 ; 1800 baud B.2000 = 011 ; 2000 baud B.2400 = 012 ; 2400 baud B.3600 = 013 ; 3600 baud B.4800 = 014 ; 4800 baud B.7200 = 015 ; 7200 baud B.9600 = 016 ; 9600 baud B.192K = 017 ; 19.2k baud .ENDC ;NE ; Baud rate mask definitions [SBC-11 only] .IF NE XL$SBC B.300 = 000 ; 300 baud B.600 = 001 ; 600 baud B.1200 = 002 ; 1200 baud B.2400 = 003 ; 2400 baud B.4800 = 004 ; 4800 baud B.9600 = 005 ; 9600 baud B.192K = 006 ; 19.2K baud B.384K = 007 ; 38.4k baud .ENDC ;NE XL$SBC ; Miscellaneous definitions PS =: 177776 ; Processor status word UNITMK =: 007 ;Q$UNIT unit number mask JOBMK =: 370 ;Q$JNUM job number mask ; Macro to define LSB of bit field .MACRO LSBDF SYMBOL,VALUE SYMBOL = VALUE & <-VALUE> .ENDM ;LSBDF .SBTTL Block 0 of handler file .ASECT . = 120 .IF NE ; SPEED table. Mask for given speed is same as word offset into table. ; To select 134.5 bps, specify 134 in the SET command. SPEEDT: .IF NE .WORD 50., 75., 110., 134., 150., 300. .WORD 600., 1200., 1800., 2000., 2400., 3600. .WORD 4800., 7200., 9600., 19200. .ENDC ;NE .IF NE XL$SBC .WORD 300., 600., 1200., 2400., 4800., 9600. .WORD 19200., 38400. .ENDC ;NE XL$SBC .WORD 0 ;Table fence .ENDC ;NE .Assume . LE DISCSR-2 MESSAGE= .SBTTL INSTALLATION CODE .ENABL LSB .IF EQ XL$MTY .DRINS XL .IFF ;EQ XL$MTY .DRINS -XL .ENDC ;EQ XL$MTY BR 10$ ;Install as a data device BR 40$ ; never as a system device 10$: MOV @#$SYPTR,R0 ;R0->$RMON BIT #PROS$,$CNFG2(R0) ;Installing on a PRO-3xx? .IF EQ XL$PC BNE 40$ ;Yes, then reject the installation .IF NE XL$MTY TSTB I$MTTY ;Are handler hooks needed? BEQ 20$ ;Nope... TST $THKPT(R0) ;Yes, is the support available? BEQ 40$ ;Nope, reject the installation BR 30$ ;Yes, nothing to do until fetch/load 20$: .ENDC ;NE XL$MTY .IFF ;EQ XL$PC BEQ 40$ ;Nope, then reject the installation .ENDC ;EQ XL$PC .IF EQ XL$PC .IF NE MOV INSCSR,R0 ;R0->Receiver CSR MOV ISPEED,4(R0) ;Set the speed (in transmitter CSR) .ENDC ;NE .IFF ;EQ XL$PC MOVB ISPEED,@#XL$BAU ;Set the XMIT/RECV baud rate ; Things to do through csr A MOV #XL$CSA,R0 ;R0->csr A MOVB #CMD.CR,@R0 ;Reset channel A MOVB #CRC.TR,@R0 ;Reset transmitter underrun latch MOVB #RPT.R4,@R0 ;Select csr A, write register 4 MOVB #,@R0 ; set clock rate x16, 1 stop bit MOVB #RPT.R3,@R0 ;Select csr A, write register 3 MOVB #,@R0 ; set receiver enable, 8-bit chars MOVB #RPT.R5,@R0 ;Select csr A, write register 5 MOVB #,@R0 ; set transmitter enable, 8-bit chars MOVB #RPT.R2,@R0 ;Select csr A, write register 2 MOVB #0,@R0 ; *** must be loaded with 0 *** MOVB #CMD.RE,@R0 ;Reset external/status interrupts ; Things to do through csr B MOV #XL$CSB,R0 ;R0->csr B MOVB #CMD.CR,@R0 ;Reset channel B MOVB #RPT.R2,@R0 ;Select csr B, write register 2 MOVB #W2.REQ,@R0 ; *** ensure base vector of 0 *** MOVB #RPT.R1,@R0 ;Select csr B, write register 1 MOVB #W1.REQ,@R0 ; *** ensure correct vector info *** ; Now we play with the interrupt controller MOVB #<30!3>,@#IC0CR ;Enable comm port interrupts ; And finally, the modem MOVB #CLK.BG,@#XL$MC0 ;Set modem clock .ENDC ;EQ XL$PC 30$: TST (PC)+ ;Accept the installation (carry=0) 40$: SEC ;Reject the installation (carry=1) RETURN .DSABL LSB .IF NE .IF NE LSBDF ...,XC.SMK ;Determine lowest bit of speed mask .ENDC ;NE ISPEED: .IF NE XL$PC .WORD + B.1200 ;Default to 1200 baud RECV and XMIT .ENDC ;NE XL$PC .IF NE .WORD ! XC.SCE ;Default to 1200 baud RECV and XMIT .ENDC ;NE .ENDC ;NE .IF NE XL$MTY I$MTTY: .BYTE -1 ; : Install-time 'hooks required' flag .BYTE ;reserved VECSAV: .WORD 100000+</2-1> ; : Vector info for SET NOMTTY CSRSAV: .WORD XL$CSR ; : CSR info for SET NOMTTY .ENDC ;NE XL$MTY .Assume . LE 400 MESSAGE= .SBTTL SET OPTION PARAMETER TABLE ; Option Data Routine Syntax ; ------ ---- ------- ------ .IF EQ 1 .DRSET BIT8 <^c177> O.BIT8 NO ;[NO]BIT8 .ENDC ;EQ 1 .IF EQ XL$PC .DRSET CSR 160012 O.CSR OCT ;CSR=n .DRSET VECTOR 477 O.VEC OCT ;VECTOR=n .ENDC ;EQ XL$PC .IF EQ XL$PC .IF NE XL$PDT .DRSET LIGHTS -1 O.LGHT NO ;[NO]LIGHTS .ENDC ;NE XL$PDT .ENDC ;EQ XL$PC .IF NE XL$MTY .DRSET LINE 16. O.LINE NUM ;LINE=n .DRSET MTTY -1 O.MTTY NO ;[NO]MTTY .ENDC ;NE XL$MTY .IF NE .DRSET SPEED NOP O.SPEE NUM ;SPEED=n .ENDC ;NE .SBTTL SET OPTION PROCESSING ROUTINES .IF EQ 1 ; SET XL [NO]BIT8 O.BIT8: CLRB R3 ;Ensure high bit is left alone NOP ;placekeeper MOV R3,CHMASK ;Save character alteration mask RETURN .ENDC ;EQ 1 .IF EQ XL$PC ; SET XL CSR=octal_address O.CSR: .IF NE XL$MTY MOV R0,CSRSAV ;Yes, update saved CSR for SET NOMTTY TSTB I$MTTY ;Are we set MTTY? BNE 20$ ;Yep, don't set install-time word .ENDC ;NE XL$MTY 10$: MOV R0,INSCSR ;Let installation code know 20$: MOV R0,DISCSR ;Fill in display CSR .ADDR #XIS,R1 ;R1 -> Where to put CSR info MOV #4,R2 ;R2 = Count of words to set 30$: MOV R0,(R1)+ ;Set a table entry ADD #2,R0 ;Prepare for next entry DEC R2 ;More to do? BGT 30$ ;Yep... CMP R0,R3 ;Was address specified in range? RETURN ; c-bit=0 if so, =1 if not ; SET XL VECTOR=octal_address O.VEC: MOV R0,XL$VTB ;Save the new input interrupt vector ADD #4,R0 MOV R0,XL$VTB+6 ; and output interrupt vector CMP R3,R0 ;Was address specified in range? RETURN ; c-bit=0 if so, =1 if not .IF NE XL$PDT ; SET XL [NO]LIGHTS O.LGHT: CLR R3 ;LIGHTS entry point NOP ; (padding) COM R3 ;NOLIGHTS entry point MOV R3,LitFlg ;Set/Reset lights flag BR O.NOR .ENDC ;NE XL$PDT .IF NE XL$MTY ; SET XL LINE=line_number O.LINE: CMPB R0,R3 ;Is line number valid? BHI O.ERR ;Nope... MOVB R0,O$LINE ;Yes, set line number to use BR O.NOR ; SET XL [NO]MTTY O.MTTY: BR 10$ ;Entry point for MTTY NOP ;placekeeper CLR R0 ;Entry point for NOMTTY MOV CSRSAV,INSCSR ;Nope, restore install-time CSR MOV VECSAV,H1.VEC ; and vector information BR 20$ 10$: CLR INSCSR ;Reset install-time CSR and CLR H1.VEC ; vector so handler installs 20$: MOVB R0,O$MTTY ;Set/Reset MTTY hooks use flag MOVB R0,I$MTTY ; and inform install code of setting BR O.NOR .ENDC ;NE XL$MTY .ENDC ;EQ XL$PC .IF NE ; SET XL SPEED=decimal_speed O.SPEE: .IF NE XL$MTY TSTB I$MTTY ;Handler hooks in use? BNE O.ERR ;Yes, can't touch the CSR .ENDC ;NE XL$MTY .ADDR #SPEEDT,R1 ;R1 -> Baud rate table 10$: TST @R1 ;End of table? BEQ O.ERR ;Yes, speed requested is invalid CMP R0,(R1)+ ;Nope, request match this entry? BNE 10$ ;Nope, try another speed entry SUB PC,R1 ;Yes, determine speed mask SUB #,R1 ; ... .IF NE XL$PC ASR R1 ;Convert from byte to word offset MOVB R1,-(SP) ;Save the receive speed mask ASL R1 ;And make transmit speed match ASL R1 ; by shifting ASL R1 ; it to the ASL R1 ; high nibble BISB (SP)+,R1 ;OR in the receive speed mask MOVB R1,@#XL$BAU ; and change the speed now .ENDC ;NE XL$PC .IF NE XL$DVE SWAB R1 ;Move to high byte ASL R1 ; then shift mask to where ASL R1 ; it should be for ASL R1 ; a DLV11-E .ENDC ;NE XL$PC .IF NE XL$SBC ASL R1 ;Shift mask to where it ASL R1 ; should be for SBC or MXV SLU .ENDC ;NE XL$SBC .IF NE BIS #XC.SCE,R1 ;Set the 'speed change enable' bit MOV INSCSR,R0 ;R0->Receiver CSR .ENDC ;NE MOV R1,ISPEED ;Save new speed for installation .IF NE MOV ISPEED,4(R0) ;Set the speed (in transmitter CSR) .ENDC ;NE .BR O.NOR .ENDC ;NE O.NOR: TST (PC)+ ;Success (carry=0) O.ERR: SEC ;Failure (carry=1) RETURN .Assume . LE 1000 MESSAGE= .SBTTL DRIVER ENTRY ; The handler gets entered here each time the monitor places a new ; request on the device queue. The handler either processes the ; request immediately and returns it to the monitor or the request ; is removed from the device queue and placed on one of the internal ; queues. There is one internal queue for input and one for output. ; ; Because of the separate queues, simultaneous input and output may ; be performed. .ENABL LSB .IF EQ XL$MTY .DRBEG XL .IFF ;EQ XL$MTY .DRBEG XL,0 ;Default to use handler hooks .ENDC ;EQ XL$MTY MOV XLCQE,R4 ;R4->Current queue element STATFG = <. + 2> ASR #1 ;First call since .FETCH/LOAD or ; last shutdown? BCC 40$ ;Nope... .IF EQ XL$PC CALL ENAINI ;Turn on receiver interrupts CALL GETSTT ;Get current modem status BIS #,R0 ;Assert DTR and RTS CALL SETSTT ; ... MOV #-2,SNDS ;Indicate we must send an XON CALL ENAOUI ;Enable output interrupts .IF NE XL$PDT CALL SETLIT ;Set the lights to indicate state .ENDC ;NE XL$PDT .IFF ;EQ XL$PC MOV #RPT.R1,@CSRA ;Select csr A, write register 1 BIS #,SSRAW1 ;Turn on RECV and XMIT interrupts MOV SSRAW1,@CSRA ; (update from software register) BIS #,@MCR0 ;Force DTR and RTS MOVB #C.CTLQ,@DBUF ;First thing we send is an XON .ENDC ;EQ XL$PC 40$: MOVB Q$FUNC(R4),R5 ;Get the function code BNE SPFUN ;If non-zero, we have a .SPFUN ASL Q$WCNT(R4) ;Convert word count to byte count BCS WRITE ;If negative, write request ; otherwise, read READ: JSR R5,XLENQ ;Queue the read request XICQE: .WORD 0 ; : address of first element on queue XILQE: .WORD 0 ; : address of last element on queue CALLR XIIN ;Process any input already received, ; read will be completed via ; interrupts WRITE: INC QCHG ;Set 'queue being modified' flag JSR R5,XLENQ ;Queue the write request XOCQE: .WORD 0 ; : address of first element on queue XOLQE: .WORD 0 ; : address of last element on queue CLR QCHG ;Reset 'queue being modified' flag .IF EQ XL$PC CALL ENAOUI ;Enable output interrupts .IFF ;EQ XL$PC CALL GNXTCH ;Get a character for output BEQ 50$ ;None available... MOVB R5,@DBUF ;Now prime the interrupt pump .ENDC ;EQ XL$PC 50$: RETURN .DSABL LSB .SBTTL REGISTERS AND VECTOR TABLES .IF EQ XL$PC ; *** Begin Critical Ordering *** XIS: .WORD XL$CSR ; : Receiver status register XIB: .WORD XL$CSR+2 ; : Receiver buffer register XOS: .WORD XL$CSR+4 ; : Transmitter status register XOB: .WORD XL$CSR+6 ; : Transmitter buffer register ; *** End Critical Ordering *** .IFF ;EQ XL$PC DBUF: .WORD XL$BUF ; : Input/Output buffer register CSRA: .WORD XL$CSA ; : Control/Status register A CSRB: .WORD XL$CSB ; : Control/Status register B MCR0: .WORD XL$MC0 ; : Modem control/status register 0 MCR1: .WORD XL$MC1 ; : Modem control/status register 1 BAUD: .WORD XL$BAU ; : Baud rate control register .ENDC ;EQ XL$PC ; Now for some software registers .IF NE XL$PC SSRAW1: .WORD 0 ;Software status A, write register 1 SSRAW5: .WORD ;Software status A, write register 5 .ENDC ;NE XL$PC ; Define the interrupt vectors .IF EQ XL$PC .DRVTB XL,XL$VEC,XIINT ;Input interrupt servicer .DRVTB ,XL$VEC+4,XLINT ;Output interrupt servicer .IFF ;EQ XL$PC .DRVTB XL,XL$VEC,XLINT ;Input/Output interrupt servicer .DRVTB ,XL$VEC+4,XLINT .ENDC ;EQ XL$PC CHMASK: .WORD ^C177 ;Character mask .IF EQ XL$PC .IF NE XL$PDT .SBTTL LIGHTS ROUTINE FOR PDT-11'S ;+ ; ; Sets PDT lights to indicate XON/XOFF state. ; ; LED 1 on if PDT has sent XOFF ; LED 2 on if PDT has received XOFF ; ;- SETLIT: TST (PC)+ ;SET XL LIGHTS in effect? LITFLG: .WORD 0 ; : lights flag (0 = no, <>0 = yes) BEQ 30$ ;Nope... MOV #040000,R5 ;Default to lights off TST SNDS ;XOFF sent to host? BLE 10$ ;Nope... BIS #000100,R5 ;Yes, turn on LED 1 10$: TST RECS ;XOFF received from host? BEQ 20$ ;Nope... BIS #000200,R5 ;Yes, turn on LED 2 20$: MOV R5,@#177420 ;Force the new lights setting 30$: RETURN .ENDC ;NE XL$PDT .ENDC ;EQ XL$PC .SBTTL SPFUN PROCESSING ; This section of code gets jumped to. It expects that the address of the ; queue element is is R4 and the address of the special function code to ; be executed is in R5. SPFUN: CMPB R5,#SRDDRV ;Special read request? BEQ READ ; Yes, go queue it CMPB R5,#BRKDRV ;[end]BREAK request? BEQ 20$ ; Yes... CMPB R5,#CLRDRV ;Clear driver flags request? BEQ 40$ ; Yes... CMPB R5,#STSDRV ;Status request? BEQ 50$ ; Yes... CMPB R5,#OFFDRV ;Shutting us down? BEQ 100$ ;Yes... CMPB R5,#DTRDRV ;DTR set/reset? BEQ 110$ ;Yes... ;Unknown .SPFUN, ignore 10$: .DRFIN XL ;Inform monitor of completion ; [end]BREAK processing ; Word count indicates operation ; (0 = end break, non-zero = break) 20$: TST Q$WCNT(R4) ;Break or end-break? BEQ 30$ ;If zero, end-break... MOV #1,BRKFLG ;Break, set 'break in progress' flag .IF EQ XL$PC CALL SETBRK ;Turn on break .IFF ;EQ XL$PC MOV #RPT.R5,@CSRA ;Select csr A, write register 5 BIS #W5.SB,SSRAW5 ;Turn on break MOV SSRAW5,@CSRA ; (update from software register) .ENDC ;EQ XL$PC BR 10$ 30$: .IF EQ XL$PC CALL RESBRK ;Turn off break .IFF ;EQ XL$PC MOV #RPT.R5,@CSRA ;Select csr A, write register 5 BIC #W5.SB,SSRAW5 ;Turn off break MOV SSRAW5,@CSRA ; (update from software register) .ENDC ;EQ XL$PC CLR BRKFLG ;Reset the 'break in progress' flag .IF EQ XL$PC CALL ENAOUI ;Make sure output is running .ENDC ;EQ XL$PC BR 10$ ; Clear driver flags request ; resets received XOFF flag ; sends XON to host 40$: CLR RECS ;Reset the 'received XOFF' flag .IF EQ XL$PC MOV #-2,SNDS ;Indicate we want an XON sent CALL ENAOUI ;Make sure output is running .IF NE XL$PDT CALL SETLIT ;Update lights display .ENDC ;NE XL$PDT .IFF ;EQ XL$PC CLR SNDS ;Indicate that an XON has been MOVB #C.CTLQ,@DBUF ; sent .ENDC ;EQ XL$PC BR 10$ ; Get Status request ; returns handler version in high byte ; returns XON/XOFF state in low byte ; bit 0 on if host has been XOFF'd ; bit 1 on if host has XOFF'd us ; bit 2 on if CTS is asserted ; bit 3 on if CD is asserted ; bit 4 on if RI is asserted 50$: MOV #$$$VER*400,R5 ;High byte = handler version TST SNDS ;Have we XOFF'd host? BLE 60$ ;Nope... .ASSUME ST.XFH EQ 1 INC R5 ;Yes, set the indicator 60$: TST RECS ;Have we been XOFF'd? BEQ 70$ ;Nope... BIS #ST.XOF,R5 ;Yes, set the indicator 70$: .IF EQ XL$PC CALL GETSTT ;Get current status BIT #RC.CTS,R0 ;Is 'Clear To Send' asserted? .IFF ;EQ XL$PC BIT #M1.CTS,@MCR1 ;Is 'Clear To Send' asserted? .ENDC ;EQ XL$PC BEQ 80$ ;Nope... BIS #ST.CTS,R5 ;Yes, set an indicator 80$: .IF EQ XL$PC BIT #RC.CD,R0 ;Is 'Carrier Detect' asserted? .IFF ;EQ XL$PC BIT #M1.CD,@MCR1 ;Is 'Carrier Detect' asserted? .ENDC ;EQ XL$PC BEQ 82$ ;Nope... BIS #ST.CD,R5 ;Yes, set an indicator 82$: .IF EQ XL$PC BIT #RC.RI,R0 ;Is 'Ring Indicator' asserted? .IFF ;EQ XL$PC BIT #M1.RI,@MCR1 ;Is 'Ring Indicator' asserted? .ENDC ;EQ XL$PC BEQ 84$ ;Nope... BIS #ST.RI,R5 ;Yes, set an indicator 84$: .IF EQ MMG$T MOV R5,@Q$BUFF(R4) ;Return the status word .IFF ;EQ MMG$T MOV R5,-(SP) ;Return the status word CALL @$PTWRD ; ... .ENDC ;EQ MMG$T BR 10$ ; Shut down driver request (OFFDRV) ; Sets a flag such that when VTCOM exits, interrupts will ; not be re-enabled. STATFG is used as the once-only, ; interrupt startup flag. 100$: MOVB Q$JNUM(R4),-(SP) ;Save Q$JNUM BIC #^C,@SP ;Isolate job number issuing request ASR @SP ;Shift for abort code check ASR @SP ASR @SP MOVB (SP)+,JNUM ;Save it for later check MOV #1,STATFG ;Reset us to pre-start state BR 10$ ; Set/Reset DTR (DTRDRV) ; Sets or resets DTR based on word count ; (0 = DTR off, <>0 = DTR on) 110$: .IF EQ XL$PC CALL GETSTT ;Get current state BIC #,R0 ;Assume DTR is desired off .IFF ;EQ XL$PC MOVB @MCR0,R0 ;Get current state BIC #,R0 ;Assume DTR is desired off .ENDC ;EQ XL$PC TST Q$WCNT(R4) ;Correct assumption? BEQ 115$ ;Yep... .IF EQ XL$PC BIS #,R0 ;Nope, turn it on .IFF ;EQ XL$PC BIS #,R0 ;Nope, turn it on .ENDC ;EQ XL$PC 115$: .IF EQ XL$PC CALL SETSTT ;Assert desired bits .IFF ;EQ XL$PC MOVB R0,@MCR0 ;Set desired state .ENDC ;EQ XL$PC BR 10$ JNUM: .BLKW ; :Job number which issued OFFDRV .IF NE XL$PC .SBTTL INTERRUPT SERVICE/DISPATCHER ;+ ; ; Interrupt entry point for input and output interrupts. The interrupt ; type is determined by bits <04:02> in RR2 of CSR B. The four defined ; types of interrupts are: ; ; 1) Transmitter buffer empty (^B100xx) ; 2) External/status change (^B101xx) ; 3) Received character available (^B110xx) ; 4) Special receiver condition (^B111xx) ; ;- .DRAST XL,4,XLDONE MOV #RPT.R2,@CSRB ;Select csr B, read register 2 MOV @CSRB,-(SP) ;Get the interrupt type BIC #^C,@SP ;Strip the uninteresting stuff ASR @SP ;Shift for word table offset .ADDR #INTTAB,@SP,ADD ;Add address of start of table MOV @(SP),@SP ;Get the table entry ADD PC,@SP ;Convert to address INTDSP: JMP @(SP)+ ;Dispatch the interrupt ESINT: MOV #CMD.RE,@CSRA ;Reset external/status interrupts IECOM: MOV #CMD.EI,@CSRA ;Declare end of interrupt RETURN SRINT: MOV #CMD.ER,@CSRA ;Reset error latches JMP XIINT ; then handle as received character INTTAB: .WORD IECOM-INTDSP ;unknown interrupt .WORD IECOM-INTDSP ;unknown interrupt .WORD IECOM-INTDSP ;unknown interrupt .WORD IECOM-INTDSP ;unknown interrupt .WORD XOINT-INTDSP ;Transmitter buffer empty .WORD ESINT-INTDSP ;External/Status change .WORD XIINT-INTDSP ;Received character available .WORD SRINT-INTDSP ;Special receiver interrupt .ENDC ;NE XL$PC .IF NE XL$MTY .SBTTL Multiterminal Handler Hooks Support Data ; The following byte indicates whether the handler should make use ; of the multiterminal hooks during FETCH/LOAD and during operation. ; *** SET *** O$MTTY: .BYTE -1 ;Default to hooks used .Assume LE 1000 MESSAGE= ; *** SET *** O$LINE: .BYTE XL$LUN ;Default line to use .Assume LE 1000 MESSAGE= ISPND: .BYTE -1 ; : Input suspend flag OSPND: .BYTE -1 ; : Output suspend flag .EVEN .SBTTL XLHOOK - Multiterminal Handler Hooks Hook Routine ;+ ; ; XLHOOK ; Entered from multiterminal input or output interrupt service. ; ; Call (TH.GOC): ; R0 = Function code ; ; Return (TH.GOC): ; PSW = 0, R5 = character ; PSW = 1, no character available ; ; Call (TH.PIC): ; R0 = Function code ; R5 = character ; ;- .ENABL LSB XLPNAM: .Rad50 /XL/ ; : Rad50 physical name ; loaded by FETCH/LOAD code XLHOOK: .Assume EQ 2 MESSAGE= MOV R4,-(SP) ;Save register for awhile ; Function code = 1 = TH.GOC ; (Get Output Character) CMP R0,#TH.GOC ;'Get Output Character' request? BNE 10$ ;Nope... TSTB OSPND ;Is output suspended? BNE 20$ ;Yep... CALL HOINT ;Yes, hook handler output service BR 30$ ; Function code = 2 = TH.PIC ; (Put Input Character) 10$: CMP R0,#TH.PIC ;'Put Input Character' request? BNE 20$ ;Nope... TSTB ISPND ;Is input suspended? BNE 20$ ;Yep... CALL HIINT ;Yes, hook handler input service BR 30$ 20$: SEC ;Return failure 30$: MOV (SP)+,R4 ;*C* Restore previously saved register RETURN .DSABL LSB .SBTTL PREMTY - Prepare for multiterminal hook ;+ ; ; PREMTY ; Prepares for use of a multiterminal hook. ; ; Return: ; R3 -> TCB ; ; Note: ; *** Co-routine *** ; Saves R3 ; ;- PREMTY: TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... MOV R3,-(SP) ;Save some registers for awhile MOV TCBADX,R3 ;R3 -> TCB hooked to us MOV 2(SP),-(SP) ;Restack the return address CALL @(SP)+ ;Co-routine back to caller MOV (SP)+,R3 ;Restore previously saved register TST (SP)+ ;Discard old return address ; to return to callers caller 10$: RETURN .ENDC ;NE XL$MTY .SBTTL DRIVER RESET ENTRY ;+ ; ; This routine is entered on the abort of a job or an HRESET. It ; deques and tells RT that all I/O requests by a job are done. It ; expects to be entered with the number of the aborting job in R4. ; ; Entered with: ; R4 = Job number {aborting | issuing .ABTIO} ; R5 = 0 if abort by job ; -> Channel Control Block (CCB) if abort by channel (.ABTIO) ; ;- .ENABL LSB XLDONE: MOV R0,-(SP) ;Save R0 for awhile .IF EQ XL$PC CALL DISINI ;Turn off input interrupts .IFF ;EQ XL$PC MOV #RPT.R1,@CSRA ;Select csr A, write register 1 BIC #W1.RIE,SSRAW1 ;Turn off input interrupts MOV SSRAW1,@CSRA ; (update from software register) .ENDC ;EQ XL$PC JSR R4,50$ ; while we remove entries from the .WORD XICQE-60$-Q$LINK ; input queue CMPB R4,JNUM ;Is aborting job same as one which ; issued OFFDRV call? BNE 5$ ;No, so interrupts should still be on TST STATFG ;Should we turn interrupts back on? BNE 10$ ;Nope... 5$: .IF EQ XL$PC CALL ENAINI ;Turn input interrupts back on .IFF ;EQ XL$PC MOV #RPT.R1,@CSRA ;Select csr A, write register 1 BIS #W1.RIE,SSRAW1 ;Turn input interrupts back on MOV SSRAW1,@CSRA ; (update from software register) .ENDC ;EQ XL$PC 10$: INC QCHG ;Set the 'queue being modified' flag JSR R4,50$ ; while we remove entries from the .WORD XOCQE-60$-Q$LINK ; output queue CLR QCHG ;Reset the 'queue being modified' flag CMPB R4,JNUM ;Is aborting job same as one which ;issued OFFDRV call? BNE 15$ ;No, so interrupts should still be on TST STATFG ;Again, interrupts back on? BNE 30$ ;Nope... 15$: .IF EQ XL$PC CALL ENAOUI ;Turn output interrupts back on .IFF ;EQ XL$PC MOV R5,-(SP) ;Save R5 for awhile CALL GNXTCH ;Get a character for output BEQ 20$ ;None available... MOVB R5,@DBUF ;Now prime the interrupt pump 20$: MOV (SP)+,R5 ;Restore R5 .ENDC ;EQ XL$PC 30$: MOV (SP)+,R0 ;Restore R0 TST XLCQE ;Anything to return to RT? BNE 40$ ;Yes... RETURN ;Nope, just return 40$: .DRFIN XL ; The following code scans the internal queue for queue elements which ; match the abort criteria (job number for job abort, channel if abort ; by channel). It then dequeues them from the internal queue, returning ; them to the device queue. SP.CCB = 4 ;Stacked CCB pointer SP.JOB = 6 ;Stacked job number 50$: MOV R5,-(SP) ;Save CCB pointer MOV (R4)+,R5 ;Pick up the displacement and MOV R4,-(SP) ; store the return address ADD PC,R5 ;Calculate actual address ; (60$ must follow this) .BR 60$ 60$: MOV R5,-(SP) ;Save the Q header address 70$: MOV Q$LINK(R5),R4 ;Link to the next entry BEQ 120$ ;If zero, no more TST SP.CCB(SP) ;Abort by channel (.ABTIO) ? BEQ 80$ ;Nope, aborting job... CMP Q$CSW(R4),SP.CCB(SP) ;Yes, this qelement for that channel? BNE 110$ ;Nope... BR 90$ ;Yes, go remove it 80$: MOVB Q$JNUM(R4),R0 ;Get number of job being aborted ASR R0 ; and ASR R0 ; shift ASR R0 ; to BIC #^C<37>,R0 ; isolate job bits CMP R0,SP.JOB(SP) ;Job own this queue element? BNE 110$ ;Nope... 90$: MOV Q$LINK(R4),Q$LINK(R5) ;Yes, unlink it from the list CLR Q$LINK(R4) ;Make sure it doesn't link anywhere CLR Q$COMP(R4) ; and disable any completion for it TST XLCQE ;Anything on the queue? BNE 100$ ;Yes, then link it in at the end MOV R4,XLCQE ;Otherwise, make it the first MOV R4,XLLQE ; and only BR 70$ ;Check for more elements to abort 100$: MOV XLLQE,R0 ;R0->element at end of queue MOV R4,Q$LINK(R0) ;Link it to this new one MOV R4,XLLQE ; and make the new one last BR 70$ ;Check for more elements to abort ; Here if element is not part of the aborting job 110$: MOV R4,R5 ;Skip this element BR 70$ ;Check for more elements to abort ; DeQueue is done, record the new end of the queue 120$: MOV (SP)+,R4 ;R4->Queue header MOV R5,Q$LINK+2(R4) ;Set the new end of queue MOV (SP)+,R4 ;Recover the return address MOV (SP)+,R5 ;Restore CCB pointer RTS R4 .DSABL LSB .SBTTL OUTPUT INTERRUPT SERVICER .IF EQ XL$PC .DRAST XL,XL$PRI,XLDONE .IFF ;EQ XL$PC XOINT: .ENDC ;EQ XL$PC .ENABL LSB HOINT: ;Output interrupt hook point TST (PC)+ ;Is break in progress? BRKFLG: .WORD 0 ; : 'break in progress' flag (0=no) BNE 30$ ;Yes, then don't do any output TST (PC)+ ;Need to send an XON or XOFF? SNDS: .WORD 0 ; : send XON/XOFF flag ; -2 = XON should be sent ; -1 = XOFF should be sent ; 0 = XON has been sent ; 1 = XOFF has been sent BPL 10$ ;Neither... MOVB #C.CTLQ,R5 ;Assume we are to send an XON ADD #2,SNDS ;Are we correct? (SNDS = 0 if yes) BEQ 20$ ;Yes, go send it MOVB #C.CTLS,R5 ;No, we must send an XOFF BR 20$ ;Now go send it 10$: TST (PC)+ ;Have we been XOFF'd? RECS: .WORD 0 ; : received XOFF flag BNE 30$ ;Yes, then don't do any output TST (PC)+ ;No, are output queues being modified? QCHG: .WORD 0 ; : 'queues being modified' flag BNE 30$ ;Yes, then don't do any output CALL GNXTCH ;Go get a character to output BEQ 30$ ;None available... 20$: CALL PUTC ;Output the character .IF EQ XL$PC .IF NE XL$PDT CALL SETLIT ;Update the PDT lights display .ENDC ;NE XL$PDT BR 40$ .ENDC ;EQ XL$PC 30$: .IF EQ XL$PC CALL DISOUI ;Turn off output interrupts .IFF ;EQ XL$PC MOV #CMD.RT,@CSRA ;Reset transmitter interrupt pending MOV #CMD.EI,@CSRA ;Declare end of interrupt .ENDC ;EQ XL$PC BR 50$ 40$: TST (PC)+ 50$: SEC 60$: RETURN .DSABL LSB .SBTTL GNXTCH - Get next output character ;+ ; ; GNXTCH ; Obtains the next character from the output queue and returns ; it in R5. ; ; CALL: ; CALL GNXTCH ; ; RETURNS: ; z-bit = 0, R5 contains character to be output ; z-bit = 1, no characters available to output ; ; NOTES: ; As requests are completed, the associated queue elements are ; returned to RT-11. ; ;- .ENABL LSB GNXTCH: MOV XOCQE,R4 ;R4->current output queue element BEQ 10$ ;None available... .IF EQ MMG$T ADD #Q$WCNT,R4 ;R4->word count TST @R4 ;Any characters left to output? BEQ 20$ ;Nope, this request is complete INC @R4 ;Yes, now there is one less to do MOVB @-(R4),R5 ;Get the byte to output INC @R4 ;bump pointer to next byte .IFF ;EQ MMG$T TST Q$WCNT(R4) ;Any characters left to output? BEQ 20$ ;Nope, this request is complete INC Q$WCNT(R4) ;Yes, now there is one less to do CALL @$GTBYT ;Get the byte to output MOVB (SP)+,R5 .ENDC ;EQ MMG$T BIC CHMASK,R5 ;Strip the undesired bits BEQ GNXTCH ; and nulls are not to be suffered ASR (PC)+ ;Was last character a ? CRFLG: .WORD 0 ; : flag BCC 5$ ;Nope... CMPB R5,#C.LF ;Yes, is this character a ? BEQ GNXTCH ;Yes, then suppress it... 5$: CMPB R5,#C.CR ;Is this character a ? BNE 10$ ;Nope... INC CRFLG ;Yes, set the flag 10$: RETURN 20$: INC QCHG ;Set the 'queue being modified' flag .IF EQ XL$PC CALL DISOUI ;Shut off the output .ENDC ;EQ XL$PC MOV XOCQE,R4 ;R4->Current output queue element MOV Q$LINK(R4),XOCQE ;Replace top of output queue with ; next element CALL XLFIN ;Return the element to RT CLR QCHG ;Reset the 'queue being modified' flag .IF EQ XL$PC CALL ENAOUI ;Restart the output .ENDC ;EQ XL$PC BR GNXTCH .DSABL LSB .SBTTL INPUT INTERRUPT SERVICER ; This is the input interrupt servicer. Input interrupts are always enabled ; once this driver is called for the first time. Only a "RstDrv" SPFUN ; request will shut off its interrupt enable. .IF EQ XL$PC .DRAST XI,XL$PRI .IFF ;EQ XL$PC XIINT: .ENDC ;EQ XL$PC .ENABL LSB HIINT: ;Input interrupt hook point CALL GETC ;Get an input character BIC CHMASK,R5 ;Strip the undesired bits BEQ 10$ ; and nulls are not to be suffered CMPB R5,#C.CTLS ;Are we being XOFF'd? BNE 20$ ;Nope... MOV #1,RECS ;Yes, set the 'received XOFF' flag 10$: .IF EQ XL$PC .IF NE XL$PDT CALL SETLIT ;Update the PDT lights display .ENDC ;NE XL$PDT .IFF ;EQ XL$PC MOV #CMD.EI,@CSRA ;Declare end of interrupt .ENDC ;EQ XL$PC RETURN 20$: CMPB R5,#C.CTLQ ;Are we being XON'd? BNE 30$ ;Nope... CLR RECS ;Yes, reset the 'received XOFF' flag .IF EQ XL$PC CALL ENAOUI ;Get the output going again .IFF ;EQ XL$PC CLR SNDS ;Indicate that an XON has been MOVB #C.CTLQ,@DBUF ; sent .ENDC ;EQ XL$PC BR 10$ ; Here for characters other than XON (^Q) and XOFF (^S) 30$: TST XIBFRE ;Any room in the input buffer? BEQ 50$ ;Nope, go force an XOFF to the host ; We have room, so store the character in the ring buffer. It will ; be processed at FORK level. MOV XIBIN,R4 ;Yes, R4=offset into buffer .ADDR #XIBUF,R4,ADD ;Add address of start of buffer MOVB R5,@R4 ;Store the character DEC XIBFRE ;Buffer has one less free byte now INC XIBIN ;Bump the offset for next time CMP XIBIN,#BUFSIZ ;Time to wrap? BLO 40$ ;Nope... CLR XIBIN ;Reset the buffer offset ; Here to check for 'low-water' mark (running out of buffer space) 40$: CMP XIBFRE,#STPSIZ ;Crossed the 'low-water' mark yet? BHI 60$ ;Nope, then go process some input TST SNDS ;Yes, have we already sent an XOFF? BGT 60$ ;Yes, so go process some input ; Here to send an XOFF to the host 50$: .IF EQ XL$PC MOV #-1,SNDS ;Request an XOFF to be sent CALL ENAOUI ;Turn on output to make sure .IFF ;EQ XL$PC MOV #1,SNDS ;Indicate that an XOFF has been MOVB #C.CTLS,@DBUF ; sent .ENDC ;EQ XL$PC ; Here to process some input 60$: TST XICQE ;Any requests to satisfy? BEQ 10$ ;No, so just return .IF NE XL$PC MOV #CMD.EI,@CSRA ;Declare end of interrupt .ENDC ;NE XL$PC .BR XIIN .DSABL LSB .SBTTL PROCESS INPUT RECIEVED FROM INTERRUPT SERVICER .ENABL LSB ; This routine runs at fork level. It's purpose is to remove characters ; from the ring buffer and use them to satisfy input requests. XIIN: INC INPRC ;Did someone beat us to this routine? BNE 110$ ;Yes.. CALL SAV30 ; We have the routine. Now we loop to process as much of the input as we can. ; Clear flag to say we own routine and no others can come in. This can be ; done because we are going to check to see if anything is in the input buffer ; after clearing the flag. 5$:;;; CLR INPRC ;We're now the owner of this routine ; *** ACTION *** No high-water mark checking done for BIT8, nothing ; can be done if it is passed anyway, what do you send? CMP XIBFRE,#RSTSIZ ;Crossed the 'high-water' mark yet? BLO 10$ ;Nope... TST SNDS ;Yes, have we already sent an XON? BEQ 10$ ;Yes... .IF EQ XL$PC MOV #-2,SNDS ;No, then request an XON to be sent CALL ENAOUI ;Turn on output to make sure .IFF ;EQ XL$PC CLR SNDS ;Now indicate that an XON has been MOVB #C.CTLQ,@DBUF ; sent .ENDC ;EQ XL$PC 10$: MOV XICQE,R4 ;Any input requests to satisfy? BEQ 100$ ;Nope... ASR (PC)+ ;Time to return an EOF? CTZFLG: .WORD 0 ; : EOF flag (^Z) BCS 90$ ;Yes... CMP XIBFRE,#BUFSIZ ;Anything in the buffer? BEQ 100$ ;Nope... ; Here to remove a character from the input ring buffer MOV XIBOUT,R5 ;R5=Offset into buffer for next char. .ADDR #XIBUF,R5,ADD ;Add address of start of buffer MOVB @R5,R5 ;Get a character from the ring buffer INC XIBFRE ;Buffer has one more free byte INC XIBOUT ;Bump offset for next time CMP XIBOUT,#BUFSIZ ;Time to wrap? BLO 20$ ;Nope... CLR XIBOUT ;Yes, reset the buffer offset 20$: TSTB Q$FUNC(R4) ;Special function read? BNE 30$ ;Yes.. CMPB R5,#C.CTLZ ;No, is character a ^Z? BEQ 40$ ;Yes, handle it specially 30$: .IF EQ MMG$T ADD #Q$WCNT,R4 ;R4->Word count MOVB R5,@-(R4) ;Return the character INC (R4)+ ;Bump the buffer pointer DEC @R4 ;Is transfer complete? (z-bit=1 if so) .IFF ;EQ MMG$T MOVB R5,-(SP) ;Return the character CALL @$PTBYT ; ... DEC Q$WCNT(R4) ;Is transfer complete? (z-bit=1 if so) .ENDC ;EQ MMG$T BEQ 70$ ;Yes... CMP XIBFRE,#BUFSIZ ;Anything left in buffer? BNE 5$ ;Yes, go process it MOV XICQE,R4 ;R4->Input request queue element TSTB Q$FUNC(R4) ;Special request? BEQ 5$ ;Nope, process some more input BR 50$ ;Yes, then request is done 40$: INC CTZFLG ;Set the EOF flag 50$: .IF EQ MMG$T ADD #Q$WCNT,R4 ;R4->word count 60$: CLRB @-(R4) ;Return a zero byte INC (R4)+ ;Bump the buffer pointer DEC @R4 ;Is the transfer complete? BNE 60$ ;Nope... .IFF ;EQ MMG$T CLRB -(SP) ;Return a zero byte CALL @$PTBYT ; ... DEC Q$WCNT(R4) ;Is the transfer complete? BNE 50$ ;Nope... .ENDC ;EQ MMG$T 70$: MOV XICQE,R4 ;R4->Current input queue element MOV Q$LINK(R4),XICQE ;Replace top of input queue with ; next queue element 80$: CALL XLFIN ;Return the element to RT BR 5$ ;And check for more input 90$: BIS #EOF$,@-(R4) ;Indicate EOF BR 70$ ;And declare queue element done 100$: DEC INPRC ;Did anything else come in while ; we were otherwise occupied? BPL 5$ ;Yes, then go process it MOV #-1,INPRC ;Release the input processing routine 110$: RETURN ;Nope, then we'll retire for awhile ; This flag is -1 when no one is executing the XIIN routine. ; It is zero when someone is executing in the XIIN routine. ; It becomes greater than zero to indicate that more input has come ; in while someone was executing the XIIN routine. INPRC: .WORD -1 .DSABL LSB ; The following routine is used by XIIN to simulate the effects of a ; FORK (saving of registers 0-3 and lowering of priority) SAV30: MOV R0,-(SP) ;Save some registers MOV R1,-(SP) ; ... MOV R2,-(SP) ; ... MOV R3,-(SP) ; ... MOV 10(SP),-(SP) ;Restack the return address .MTPS #0 ;Lower our priority CALL @(SP)+ ;Co-routine back to caller MOV (SP)+,R3 ;Restore the registers MOV (SP)+,R2 ; ... MOV (SP)+,R1 ; ... MOV (SP)+,R0 ; ... TST (SP)+ ;Discard old return address RETURN ; and return to caller's caller .SBTTL XLENQ - Place Qelement on internal queue ;+ ; ; XLENQ ; Removes the current Qelement from the device queue and places ; it on an internal queue. It is presumed (by virtue of the way ; RT works) that there will be only one Qelement in the device ; queue. ; ; Call: ; R4 -> Qelement to be queued ; ; JSR R5,Q ; .BLKW ;CQE pointer of internal queue ; .BLKW ;LQE pointer of internal queue ; ; Return: ; Qelement has been removed from the device queue and placed on ; the specified internnal queue. ; ;- XLENQ: CLR XLCQE ;Ensure there are no Qelements CLR XLLQE ; on the device queue TST @R5 ;Is our internal queue empty? BNE 10$ ;Nope... MOV R4,(R5)+ ;Yes, so make it the first MOV R4,(R5)+ ; and last element RTS R5 10$: TST (R5)+ ;Bump to last element pointer MOV R4,-(SP) ;Save address of new element MOV @R5,R4 ;R4->Last queue element MOV @SP,Q$LINK(R4) ;Link it to the new element MOV (SP)+,(R5)+ ; and make the new element the last RTS R5 .SBTTL XLFIN - Internal Queue Element Completion ;+ ; ; XLFIN ; Used to inform RT-11 of a Qelement which has completed. ; ; Call: ; R4 -> Completed Qelement ; ; Return: ; Qelement has been returned to RT-11 ; ; Note: ; o All registers except R4 are preserved ; o Fake device queue is used to return the Qelement to ; RT-11 to avoid race conditions with the real device ; queue. ; o A CALL to monitor completion is used because there may ; be more to do at this time, we don't want to lose control ; to the monitor yet. ; ;- XLFIN: MOV R4,XLFCQE ;Queue element we are returning will MOV R4,XLFLQE ; become first and last element CLR Q$LINK(R4) ;Unlink it from everything else .ADDR #XLFCQE,R4 ;R4 -> Fake device queue for passing ; to DRFIN MOV @#$SYPTR,R5 ;R5->$RMON CALL @$QCOMP(R5) ;Inform monitor of I/O completion RETURN .IF EQ XL$PC .SBTTL DISINI - Disable input interrupts .SBTTL ENAINI - Enable input interrupts DISINI: .IF NE XL$MTY TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... MOVB #-1,ISPND ;Disable input interrupt processing BR 20$ .ENDC ;NE XL$MTY 10$: BIC #RC.IE,@XIS ;Turn off input interrupts 20$: RETURN ENAINI: .IF NE XL$MTY TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... CLRB ISPND ;Enable input interrupt processing BR 20$ .ENDC ;NE XL$MTY 10$: BIS #RC.IE,@XIS ;Turn input interrupts back on 20$: RETURN .SBTTL DISOUI - Disable output interrupts .SBTTL ENAOUI - Enable output interrupts DISOUI: .IF NE XL$MTY TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... MOVB #-1,OSPND ;Disable output interrupt processing BR 20$ .ENDC ;NE XL$MTY 10$: BIC #XC.IE,@XOS ;Disable output interrupts 20$: RETURN ENAOUI: .IF NE XL$MTY CALL PREMTY ;Prepare for hook BEQ 10$ ;Terminal hooks not active... CLRB OSPND ;Enable output interrupt processing CALL @MTOENX ; and then enable output interrupts BR 20$ .ENDC ;NE XL$MTY 10$: BIS #XC.IE,@XOS ;Enable output interrupts 20$: RETURN .SBTTL RESBRK - Turn off BREAK .SBTTL SETBRK - Turn on BREAK RESBRK: .IF NE XL$MTY CALL PREMTY ;Prepare for hook BEQ 10$ ;Terminal hooks not active... CLR R0 ;Deassert BREAK CALL @MTYBRX ; ... BR 20$ .ENDC ;NE XL$MTY 10$: BIC #XC.BRK,@XOS ;Deassert BREAK 20$: RETURN SETBRK: .IF NE XL$MTY CALL PREMTY ;Prepare for hook BEQ 10$ ;Terminal hooks not active... MOV #XC.BRK,R0 ;Assert BREAK CALL @MTYBRX ; ... BR 20$ .ENDC ;NE XL$MTY 10$: BIS #XC.BRK,@XOS ;Assert BREAK 20$: RETURN .SBTTL GETSTT - Get line status .SBTTL SETSTT - Set line state bits ;+ ; ; GETSTT ; Returns the current line status ; ; Call: ; none ; ; Return: ; R0 = Line status ; ; Note: ; R3 is altered ; ;- GETSTT: .IF NE XL$MTY CALL PREMTY ;Prepare for hook BEQ 10$ ;Terminal hooks not active... CALL @MTYSTX ;Get current line status BR 20$ .ENDC ;NE XL$MTY 10$: MOV @XIS,R0 ;R0 = Current line status 20$: RETURN ;+ ; ; SETSTT ; Asserts line state bits ; ; Call: ; R0 = Bits to assert ; ; Return: ; R0 = Updated line status ; ; Note: ; o R3 is altered ; ;- SETSTT: .IF NE XL$MTY CALL PREMTY ;Prepare for hook BEQ 10$ ;Terminal hooks not active... CALL @MTYCTX ;Yes, set desired bits BR 20$ .ENDC ;NE XL$MTY 10$: MOV R0,@XIS ;Set new line status 20$: RETURN .ENDC ;EQ XL$PC .SBTTL GETC - Input a character .SBTTL PUTC - Output a character ;+ ; ; GETC ; Gets a character from the interface. ; ; Return: ; R5 = Character ; ; Note: ; In the case of call during multiterminal hook operation, ; the character is already in R5 due to the multiterminal ; input interrupt service code. ; ;- GETC: .IF NE XL$MTY TSTB O$MTTY ;Terminal hooks in use? BNE 10$ ;Yep, bypass normal DL input .ENDC ;NE XL$MTY .IF EQ XL$PC MOVB @XIB,R5 ;R5 = Character .IFF ;EQ XL$PC MOVB @DBUF,R5 ;Get a character from input .ENDC ;EQ XL$PC 10$: RETURN ;+ ; ; PUTC ; Puts a character to the interface. ; ; Call: ; R5 = Character ; ; Note: ; In the case of call during multiterminal hook operation, ; the character is already in R5 due to the multiterminal ; input interrupt service code. ; ;- PUTC: .IF NE XL$MTY TSTB O$MTTY ;Terminal hooks in use? BNE 10$ ;Yep, bypass normal DL output .ENDC ;NE XL$MTY .IF EQ XL$PC MOVB R5,@XOB ;Output the character .IFF ;EQ XL$PC MOVB R5,@DBUF ;Output the character .ENDC ;EQ XL$PC 10$: RETURN .SBTTL INPUT BUFFER AREA ; Reserve space for the input buffer and data to manage the input buffer XIBUF: .BLKB BUFSIZ ;Input buffer XIBIN: .WORD 0 ;'Next Character In' offset XIBOUT: .WORD 0 ;'Next Character Out' offset XIBFRE: .WORD BUFSIZ ;Number of free bytes in buffer ; Define areas for fork blocks used by the interrupt servicers DQFBLK: .WORD 0,0,0,0 .IF NE XL$MTY ; Multiterminal handler hooks pointers MTOENX: .BLKW ; : -> Output enable routine MTYBRX: .BLKW ; : -> Break control routine MTYCTX: .BLKW ; : -> Line control routine MTYSTX: .BLKW ; : -> Line status routine TCBADX: .BLKW ; : -> TCB we're attached to .ENDC ;NE XL$MTY ; Fake queue header for returning completed Qelements .WORD 0 ; : Handler hold = 0 XLFLQE: .BLKW ; : Fake last queue element XLFCQE: .BLKW ; : Fake current queue element .DRFIN XL .DREND XL .IF EQ XL$PC .SBTTL LOAD - Handler FETCH/LOAD code ;+ ; ; LOAD ; This routine is entered on FETCH or LOAD of the XL handler ; and is used 1) to verify use of the handler in the specific ; configuration and, if needed, 2) to establish the required ; connections between the handler and the interrupt service of ; a monitor with support for multiterminal handler hooks. ; ;- .ENABL LSB FETCH:: LOAD:: MOV R5,ENTRY$ ;Save entry point MOV R2,SLOT$ ; and table size MOV @R5,R5 ;R5 -> Base of handler (in memory) MOV @#$SYPTR,R0 ;R0 -> Base of RMON .IF NE XL$MTY TSTB (R5) ;Terminal hooks to be used? BEQ 20$ ;Then use normal DL MOV $THKPT(R0),R1 ;R1 -> Multiterminal handler hooks ; data structure in RMON BEQ 60$ ;Monitor doesn't have the support... TSTB (R1)+ ;Bypass structure size byte MOVB (R1)+,R2 ;R2 = Number of LUNs on system MOV (R1)+,R3 ;R3 -> TCB list MOV (R1)+,(R5) ;Set pointer to output enable routine MOV (R1)+,(R5) ;Set pointer to Break control routine MOV (R1)+,(R5) ;Set pointer to Control routine MOV (R1)+,(R5) ;Set pointer to Status routine MOVB (R5),R0 ;R0 = Line to attach to BMI 60$ ;Must be a positive number CMPB R0,R2 ;Is line in this configuration? BGE 60$ ;Nope, invalid line number ASL R0 ;Shift for word offset into TCB list ADD R0,R3 ;R3 -> TCB list entry MOV @R3,R3 ;R3 -> TCB for LUN TST T.CSR(R3) ;Is the line present in hardware? BEQ 60$ ;Nope... TST T.STAT(R3) ;Is the line a console? .Assume CONSL$ EQ 100000 BMI 60$ ;Yes... MOV R5,R0 ;R0 -> Handler hook routine ADD #,R0 ; ... TST T.OWNR(R3) ;Is the line already attached? BEQ 10$ ;Nope... CMP R0,T.OWNR(R3) ;Yes, to this handler? BNE 60$ ;Nope... 10$: MOV ENTRY$,R1 ;R1 -> $ENTRY entry SUB SLOT$,R1 ;R1 -> $PNAME ENTRY MOV @R1,-2(R0) ;Inform handler of its physical name, MOV R3,(R5) ; link the handler to the TCB BIS #,T.STAT(R3) ; declare line owned by handler ; and that handler will process modem, MOV R0,T.OWNR(R3) ; finally link the TCB to the handler BR 50$ .ENDC ;NE XL$MTY 20$: BIT #MTTY$,$SYSGE(R0) ;Is this a multiterminal monitor? BEQ 50$ ;Nope, then there can't be a conflict .ADDR #MTAREA,R0 ;R0 -> .MTSTAT EMT area .ADDR #MTSTAT,R1 ;R1 -> Status block .MTSTA R0,R1 ;Get info about multiterminal system BCS 60$ ;Errors? MOV @#$SYPTR,R0 ;R0 -> $RMON MOV MTSTAT,R1 ;R1 -> First TCB in system ADD R0,R1 ; ... MOV MTSTAT+MST.LU,R2 ;R2 = Highest LUN on the system ; (Number_of_LUNs - 1) 30$: TST T.CSR(R1) ;Is this a configured line? BEQ 40$ ;Nope... CMP (R5),T.CSR(R1) ;Will use of the CSR conflict? BEQ 60$ ;Yes, reject the load CMP (R5),T.VEC(R1) ;Will use of the VECTOR conflict? BEQ 60$ ;Yes, reject the load 40$: ADD MTSTAT+MST.ST,R1 ;On to next TCB DEC R2 ;More TCB's to check? BGE 30$ ;Yep... .BR 50$ ;Nope, use of interface won't conflict 50$: TST (PC)+ ;Success return 60$: SEC ;Error return RETURN ENTRY$: .BLKW ; : -> $ENTRY table entry SLOT$: .BLKW ; : Size of a monitor handler table MTAREA: .BLKW 3 ; : EMT area for .MTSTAT MTSTAT: .BLKW 8. ; : Status block from .MTSTAT .DSABL LSB .ENDC ;EQ XL$PC .SBTTL UNLOAD - UNLOAD/.RELEASE CODE ;+ ; UNLOAD ; On entry due to unload command, verifies interrupts have been ; disabled unless the handler is still in use, indicated by ; non-empty internal queues. ; ; On entry due to .RELEASE directive,disable interrupts ; ;- .ENABL LSB UNLOAD:: MOV @R5,R5 ;R5 -> Handler entry point (XLLQE) TST (R5) ;Is handler in use? BNE 10$ ;Nope, it can be unloaded... MOV (R5),-(SP) ;Check internal queues BIS (R5),(SP)+ ; ... BEQ RELEAS ;They're empty... .ADDR #NOUNLO,R0 ;R0 -> Error message string ; (KMON reports error) SEC ;Indicate error RETURN ; and return to KMON RELEAS:: MOV @R5,R5 ;R5 -> Handler entry point (XLLQE) 10$: .IF EQ XL$PC .IF NE XL$MTY TSTB (R5) ;Terminal hooks in use? BEQ 20$ ;Nope... MOV (R5),R1 ;R1 -> TCB we're hooked to BEQ 30$ ;We're not... CALL (R5) ;Disable input CALL (R5) ; and output interrupts CLR R0 ;Deassert all modem control bits CALL (R5) ; ... CLR T.OWNR(R1) ;Disconnect TCB from handler BIC #,T.STAT(R1) ; ... BR 30$ 20$: .ENDC ;NE XL$MTY MOV (R5),R1 ;R1->Device register base BIC #RC.IE,@R1 ;Turn off input and BIC #XC.IE,4(R1) ;Output interrupts BIC #RC.DTR,@R1 ;Now turn off DTR .IFF ;EQ XL$PC MOV #RPT.R1,@#XL$CSA ;Select csr A,write register 1 CLR @#XL$CSA ;Turn off input and output interrupts BIC #,@#XL$MC0 ;Now turn off DTR .ENDC ;EQ XL$PC 30$: CLC RETURN NOUNLO: .NLCSI TYPE=I,PART=PREFIX .ASCIZ "F-Handler may not be unloaded while in use" .DSABL LSB ; This file is .INCLUDED into XC.MAC to produce the handler version ; for the PRO-3xx. If the .END is present in this case, a problem ; will occur with the .MODULE, .AUDIT (and possibly other) macros. ; XC.MAC must provide the .END after the .INCLUDE. .IIF EQ XL$PC .END ;If non PRO-3xx support