.TITLE TTINI .IDENT /06.06/ ; ; COPYRIGHT (c) 1986,1987 BY DIGITAL EQUIPMENT CORPORATION. ; ALL RIGHTS RESERVED. ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; ; 02-FEB-78 PETER WANNHEDEN ; ; PREVIOUSLY MODIFIED BY: ; ; P. WANNHEDEN ; C. F. SPITZ ; D. R. DONCHIN ; T. LEKAS ; S. C. ADAMS ; R. S. PHILPOTT ; ; ; MODIFIED BY: ; ; L. KOGAN 02-NOV-85 06.01 ; LK705 -- MAKE 11M AND 11M+ TTDRV MODULES IDENTICAL ; ; S. C. ADAMS 16-JUNE-86 06.02 ; SA460 -- ALLOW BROADCAST WRITE TO TI: OF NON-PRIVILEGED TASK ; AND CLEAN UP SOME COMMENTS ; ; S. C. ADAMS 20-AUGUST-86 06.03 ; SA464 -- ADD ROUTINE QPORG ; ; TODD SCHOELLER 12-DECEMBER-86 06.04 ; TMS051 -- CORRECT QPORG TO USE CORRECT BLOCKING BITS. ; ; B. S. MCCARTHY 31-DECEMBER-86 06.05 ; BM380 -- CORRECT QPORG SO THAT FORK CALL GOES TO CORRECT ; ROUTINE. ; ; T. M. SCHOELLER 14-AUG-87 06.06 ; TMS060 -- If a privilege violation occurs during an IO.HNG ; or an IO.ORG, pop the return address off the stack ; before jumping to error processing. ; ;+ ; ; ****** T T I N I ****** ; ; THIS MODULE CONTAINS THE ROUTINES TO INITIATE A NEW I/O REQUEST ; FOR A TERMINAL. THERE ARE THREE PARTS TO THIS. FIRST, THE I/O REQUESTS ; ARE VALIDATED PRIOR TO PLACING THEM IN THE DEVICE'S I/O PACKET QUEUE. ; THIS MUST OCCUR WHILE THE USER TASK WHICH ISSUED THE REQUEST IS STILL ; THE CURRENT TASK. NEXT, THE REQUEST IS PLACED IN THE REQUEST QUEUE FOR ; THE TERMINAL. FINALLY, ANY REQUEST IN THE QUEUE WHICH CAN BE INITIATED ; IS DEQUEUED AND PASSED TO A FUNCTION-DEPENDENT INITIATION ROUTINE. ;- ; .MCALL PKTDF$ PKTDF$ .PSECT MAP5 .PAGE .SBTTL TTINI - TERMINAL DRIVER I/O REQUEST INITIATION ENTRY POINT ; ;+ ; **-TTINI - REQUEST INITIATION ENTRY POINT. ; ; THIS ROUTINE IS CALLED FROM "DRQIO" WHEN A TASK HAS ISSUED AN I/O REQUEST ; FOR A TERMINAL. THE CALL IS MADE PRIOR TO QUEUEING THE I/O PACKET TO THE ; SCB QUEUE SINCE TERMINALS HAVE THE "UC.QUE" BIT SET IN THEIR UCB'S. THIS ; IS DONE WHILE THE TASK CONTEXT IS STILL VALID, SINCE MANY FUNCTIONS WILL ; NEED ADDITIONAL PARAMETER CHECKS NOT DONE BY THE EXECUTIVE. THIS ROUTINE ; WILL MAP THE DRIVER DATA AREA (SINCE WE WERE CALLED FROM THE EXEC) AND ; DISPATCH ON THE FUNCTION CODE TO VALIDATE THE I/O REQUEST. ; ; INPUTS: ; R1 => I/O REQUEST PACKET TO BE PROCESSED ; R4 => SCB FOR THE REQUESTED TERMINAL ; R5 => UCB FOR THE REQUESTED TERMINAL ; ; OUTPUTS: NONE. ; ; REGISTERS MODIFIED: R0, R1, R3 ;- ; TTINI:: CALL MAPD ;MAP DRIVER DATA AREA MOV R1,R3 ;COPY I/O PACKET POINTER MOVB I.FCN+1(R3),R0 ;GET THE I/O FUNCTION CODE ASL R0 ;CONVERT IT TO A WORD INDEX .IF DF R$$IIC CALLR @QPDSP(R0) ;DISPATCH TO PROCESS THIS REQUEST .IFF ;R$$IIC CALLR @QPDSP-2(R0) ;DISPATCH TO PROCESS THIS REQUEST .ENDC ;R$$IIC .IF DF T$$EIO&T$$OVL ;HERE IS THE STUB FOR TRANSFERING TO THE OVERLAY. QPEIO IS IN TTATT. QPEIO:: CALLR QPETRA ;BRANCH TO TRANSFER IN APR6 .ENDC ;T$$EIO&T$$OVL .PAGE .SBTTL FPGRQ - GET A REQUEST PACKET FROM THE REQUEST QUEUE ; ;+ ; FPGRQ - GET A REQUEST PACKET FROM THE I/O QUEUE. ; THIS SUBROUTINE IS ENTERED EITHER FROM THE REQUEST INITIATOR, ; OR FROM THE FORK DISPATCHER. ; ; INPUT: ; R5 POINTER TO U.TSTA ; S1.DSI 1 TO PREVENT PROCESSING OF INPUT ; ; OUTPUT: ; IF THERE IS AN IO.WBT PACKET IN THE QUEUE, A CTRL-Q IS ; SIMULATED. ; ; AS MANY PACKETS AS CAN BE DEQUEUED FROM THE IO QUEUE ; ARE STARTED. ; ; REGISTERS ALTERED: R0,R1,R2,R3,R4 ;- ; ; .ENABL LSB FPGRQ:: BIT #FR.PFP,U.TFRQ-U.TSTA(R5) ;POST-FORK PROCESSING REQUESTED? BNE FPRET ;IF NE, YES...MUST DO THAT FIRST. GRQPKT: .IF NDF T$$SPL MOV #DEUCBX,-(SP) ;IF TSTRQ OR $GSPKT FAILS, DEALLOCATE UCBX .IFTF ;NDF T$$SPL CALL TSTRQ ;TEST IF ANYTHING TO DEQUEUE ;IF NOT, DEALLOCATE UCBX AND RETURN TO CALLER MOV R3,-(SP) ;SAVE FLAGS IN CASE $GSPKT FAILS MOV #GRQAC,R2 ;POINT TO ACCEPTANCE ROUTINE SUB #U.TSTA,R5 ;POINT TO START OF UCB MOV R5,-(SP) ;SAVE POINTER TO UCB CALL $GSPKT ;GET A PACKET MOV (SP)+,R5 ;RESTORE POINTER TO UCB BCC 10$ ;IF CC, SUCCESSFULLY GOT A REQUEST...SKIP ; ; NOPKDQ - NO PACKET CAN CURRENTLY BE DEQUEUED. EITHER THERE WERE NO PACKETS ; OR THE ACCEPTANCE ROUTINE ABBORTED THE SCAN AND BRANCHED HERE DIRECTLY. ; NOPKDQ: ADD #U.TSTA,R5 ;POINT TO UCB STATUS WORD BIC (SP)+,2(R5) ;CLEAR FLAGS THAT WE SHOULD NOW IGNORE FPRET: RETURN ;ALL DONE ; ; FOUND A REQUEST PACKET THAT CAN BE PROCESSED. IT'S ADDRESS IS IN R1. ; 10$: .IFT ;NDF T$$SPL CMP (SP)+,(SP)+ ;CLEAN STACK OF FLAGS AND DEALLOCATE ROUTINE .IFF ;NDF T$$SPL TST (SP)+ ;CLEAN STACK OF FLAGS .ENDC ;NDF T$$SPL .IF DF T$$BTW MOV U.SCB(R5),R3 ;GET POINTER TO SCB 20$: MOV (R3),R3 ;GET POINTER TO NEXT I/O PACKET IN QUEUE BEQ 30$ ;IF EQ, NONE...SKIP CMP I.UCB(R3),R5 ;IS THAT PACKET FOR THIS UCB? BNE 20$ ;IF NE, NO...SKIP THIS PACKET CMPB I.PRI(R3),#251. ;IS REQUEST FOR A BREAKTHROUGH WRITE? BEQ 40$ ;IF EQ, YES...ACCEPT THE REQUEST 30$: BIC #S2.BRQ,U.TSTA+2(R5) ;OTHERWISE, SHOW NO MORE IO.WBTS IN QUEUE 40$: .ENDC ;T$$BTW ADD #U.TSTA,R5 ;POINT TO FIRST STATUS WORD MOV R1,R3 ;COPY PACKET POINTER CLR (R3) ;CLEAR LINK WORD USED TO HOLD COMPLETION STATUS MOVB I.FCN+1(R3),R1 ;GET I/O REQUEST FUNCTION CODE (HIGH BYTE) .IF DF T$$SPL MOV U.TAPR-U.TSTA(R5),@#KDSAR5 ;MAP THE UCBX MOV #120000,R4 ;SET VIRTUAL ADDRESS OF UCBX .IFTF ;T$$SPL .IIF NDF T$$SPL, N$$SPL=0 .IF DF T$$MOD!N$$SPL ; ; NOTE - HERE WE ASSUME NUMERIC VALUES FOR FUNCTION CODES ACCORDING ; TO WHAT IS DESCRIBED IN MODULE TTDAT! ; CMP R1,#IO.RPR/400 ;IS REQUEST ONE OF THE FOLLOWING: ; IO.RPR, IO.RTT, IO.EIO, IO.RSD, IO.WSD? BHIS 50$ ;IF HIS, YES...REQUIRE UCBX AND DO MODEM CHECK CMP R1,#IO.ATT/400 ;IS IT ONE OF THE FOLLOWING: ; IO.DET, IO.GTS, SF.GMC, SF.SMC? BHI 91$ ;IF HI, YES...DON'T NEED UCBX OR MODEM CHECK ;OTHERWISE, REQUEST IS IO.ATT, IO.WLB, OR IO.RLB .ENDC ;T$$MOD!N$$SPL .IF DF T$$MOD BEQ 60$ ;IF EQ, IO.ATT...NEED UCBX BUT NOT MODEM CHECK .IFTF ;T$$MOD 50$: .IFT ;T$$MOD BITB #US.DSB!US.CRW,U.STS-U.TSTA(R5) ;IS THE LINE DISABLED OR... ; ...WAITING FOR CARRIER (CHECKED ONLY ON... ; ...IO.RLB, IO.WLB, IO.RPR, IO.RTT, IO.EIO, ; ...IO.RSD, AND IO.WSD REQUESTS) BEQ 60$ ;IF EQ, NO...REQUEST CAN CONTINUE BIT #S4.DLO,6(R5) ;IS THIS A DIAL-OUT LINE? BNE 60$ ;IF NE, YES...LET THE REQUEST BE TRIED MOV #IE.DNR&377,R0 ;ELSE, RETURN "DEVICE NOT READY" ERROR JMP 910$ ;SKIP TO COMPLETE THE REQUEST 60$: .ENDC ;T$$MOD .IFF ;T$$SPL CALL ALUCBX ;ALLOCATE UCBX IF IT ISN'T THERE BCS 105$ ;IF CS, NO FREE POOL...RETURN ERROR .ENDC ;T$$SPL .IF DF T$$EIO CMP R1,#IO.EIO/400 ;IS THIS AN EXTENDED I/O FUNCTION? BNE 90$ ;IF NE, NO...CHECK NEXT FUNCTION MOV U.TIXL-U.TSTA(R5),R2 ;GET POINTER TO FIRST IOPX IN LIST 70$: CMP I.XIOP(R2),R3 ;IS THIS IOPX FOR THE CURRENT I/O PACKET? BEQ 73$ ;IF EQ, YES...EXIT THE LOOP ASSUME I.XLNK,0 MOV (R2),R2 ;GET POINTER TO NEXT IOPX BR 70$ ;CHECK THIS ONE (IT MUST BE HERE SOMEWHERE) 73$: BIT #TF.RDI,I.XMOD(R2) ;READ WITH DEFAULT INPUT SPECIFIED? BEQ 80$ ;IF EQ NO MOV I.XDBL(R2),U.TDIC(R4) ;SAVE DEFAULT INPUT BUFFER LENGTH MOV R1,-(SP) ;SAVE R1 IN CASE THIS IS USER TASK EIO CALL $TSTBF ;SHOULD WE ATTEMPT TO BUFFER THE DEFAULT INPUT? BCS 77$ ;IF CS NO ; ; ATTEMPT ALLOCATING AND FILLING TTDRV BUFFERS WITH DEFAULT INPUT DATA ; BIS #S1.IBF,@R5 ;ASSUME BUFFERED INPUT MOV R2,-(SP) ;SAVE IOPX POINTER ACROSS ALTB CALL CALL ALTB ;ALLOCATE A BUFFER TO STORE DEFAULT INPUT MOV R2,R0 ;PASS THE BUFFER ADDRESS TO R0 MOV (SP)+,R2 ;RESTORE IOPX ADDRESS TO R2 BCS 77$ ;IF CS, NO BUFFER IS AVAILABLE - JUMP MOV R0,U.TDIF(R4) ;SAVE FIRST DEFAULT INPUT BUFFER ADDRESS MOV #T$$BFL-4,U.TDIP(R4) ;SET SIZE OF DATA PORTION OF BUFFER MOV R0,U.TDIP+2(R4) ;SET DATA POINTER TO FIRST DATA BUFFER ADD #4,U.TDIP+2(R4) ;POINT PAST BUFFER HEADER TO DATA ITSELF 74$: CLR (R0)+ ;CLEAR BUFFER LINK WORD MOV R0,R1 ;SAVE POINTER TO BUFFER CHARACTER COUNT MOV #T$$BFL-4,(R0)+ ;SET MAXIMUM DATA THAT CAN BE STORED IN 1 BUFFER 75$: MOV I.XDBF(R2),KISAR6 ;MAP USER DEFAULT INPUT BUFFER MOVB @I.XDBF+2(R2),-(SP) ;GET CHARACTER FROM USER'S BUFFER MOV $DALED,KISAR6 ;REMAP DRIVER MOVB (SP)+,(R0)+ ;INSERT CHARACTER INTO OUR BUFFER INC I.XDBF+2(R2) ;UPDATE POINTER INTO USER'S BUFFER DEC I.XDBL(R2) ;ONE LESS CHARACTER TO GO BEQ 79$ ;IF EQ ALL DONE DEC (R1) ;MORE CHARACTERS YET TO GO - IS OUR BUFFER FULL? BNE 75$ ;IF NE NO - INSERT MORE CHARACTERS INTO BUFFER MOV R2,-(SP) ;YES - SAVE IOPX POINTER ACROSS ALTB CALL CALL ALTB ;ALLOCATE ANOTHER BUFFER TO STORE DEFAULT INPUT MOV R2,R0 ;PASS THE BUFFER ADDRESS TO R0 MOV (SP)+,R2 ;RESTORE IOPX ADDRESS TO R2 BCS 76$ ;IF CS, NO ADDITIONAL BUFFER IS AVAILABLE MOV R0,-(R1) ;LINK OLD BUFFER TO NEW ONE BR 74$ ;STUFF CHARACTERS INTO NEW BUFFER ; ; COME HERE IF NOT ENOUGH TTDRV BUFFERS COULD BE ALLOCATED TO CONTAIN ALL OF ; THE CHARACTERS OF THE USER'S DEFAULT INPUT ; 76$: MOV R2,-(SP) ;SAVE IOPX POINTER ACROSS DELTB CALL MOV U.TDIF(R4),R2 ;GET ADDRESS OF FIRST OF OUR BUFFERS CALL DELTB ;DEALLOCATE THEM MOV (SP)+,R2 ;RESTORE IOPX POINTER ; ; SAVE POINTERS TO USER'S DEFAULT INPUT BUFFER IN UCBX ; 77$: MOV I.XDBF(R2),U.TDIP(R4) ;SAVE APR BIAS OF USER'S BUFFER MOV I.XDBF+2(R2),U.TDIP+2(R4) ;SAVE VIRTUAL ADDRESS OF BUFFER CLR U.TDIF(R4) ;NO DEFAULT BUFFERS ALLOCATED BIC #S1.IBF,(R5) ;DO NON-BUFFERED INPUT ; ; PROCESS AN IO.RTT (TF.RTT) REQUEST, IF ANY ; 79$: MOV (SP)+,R1 ;RESTORE R1 80$: BIT #TF.RTT,I.XMOD(R2) ;READ W/TERMINATOR TABLE SPECIFIED? BEQ PKTDSP ;IF EQ, NO...SKIP TO DISPATCH PACKET MOV I.XTTB(R2),I.PRM+10(R3) ;COPY 1.ST ADDRESS DOUBLE WORD OF NEW TABLE MOV I.XTTB+2(R2),I.PRM+16(R3) ;COPY 2.ND ADDRESS DOUBLE WORD OF NEW TABLE MOV I.XTTL(R2),R0 ;COPY LENGTH OF TABLE CMP R0,#32. ;IS IT OVER 32 BYTES BHI 92$ ;YES, SET TO 32. BR 100$ ;JOIN COMMON CODE .ENDC ;T$$EIO 90$: CMP R1,#IO.RTT/400 ;IS THIS A READ W/TERMINATOR TABLE? BEQ 92$ ;IF EQ YES 91$: BR PKTDSP ;DISPATCH ON FUNCTION CODE 92$: MOV #32.,R0 ;COPY A 32. BYTE TABLE 100$: MOV R0,-(SP) CALL ALTB ;ALLOCATE A TABLE MOV (SP)+,R0 105$: BCS 900$ ;IF CS, ALLOCATION FAILED...RETURN ERROR MOV R2,U.TRTT(R4) ;SAVE TERMINATOR TABLE ADDRESS 110$: MOV I.PRM+10(R3),KISAR6 ;MAP USER'S TABLE MOVB @I.PRM+16(R3),-(SP) ;RETRIEVE AN ENTRY FROM IT MOV $DALED,KISAR6 ;RESTORE DRIVER MAPPING MOVB (SP)+,(R2)+ ;COPY ENTRY TO ALLOCATED TABLE INC I.PRM+16(R3) ;POINT TO NEXT ENTRY SOB R0,110$ ;LOOP TIL DONE MOV U.TRTT(R4),R0 ;FORM REMAINING COUNT ADD #32.,R0 ;... SUB R2,R0 ;... BEQ PKTDSP ;ALL DONE IF ZERO 115$: CLRB (R2)+ ;ZERO REST OF TABLE SOB R0,115$ ;... ; BR PKTDSP ;FALL THROUGH TO "PKTDSP" .PAGE .SBTTL PKTDSP - DISPATCH ON FUNCTION CODE TO INITIATE REQUEST ; ;+ ; **-PKTDSP - DISPATCH ON FUNCTION CODE TO INITIATE REQUEST ;- ; PKTDSP: ASL R1 ;CONVERT FUNCTION CODE TO WORD INDEX .IF DF T$$ACD MOV #UA.ALL,U.AFLG-U.TSTA(R5) ;SET DEFAULT PROCESSING FLAGS MOV U.ACB-U.TSTA(R5),R0 ;GET ACD CONTROL BLOCK ADDRESS BEQ 120$ ;IF EQ, NONE THERE...SKIP MOV R1,R2 ;COPY FUNCTION CODE CMPB R2,#30. ;FUNCTION CODE IN FIRST MASK WORD? BLOS 117$ ;Y - JUMP TST (R0)+ ;BUMP ACB POINTER TO CHECK SECOND MASK WORD SUB #32.,R2 ;REDUCE FUNCTION CODE 117$: BIT $BTMSK(R2),A.MAS(R0) ;IS THE ACD INTERESTED IN THIS FUNCTION? BEQ 120$ ;IF EQ, NO...SKIP MOV #A.DEQU,R0 ;SET I/O PACKET DEQUEUE ENTRY POINT CALL $SWACD ;CALL THE ACD BIT #UA.ALL,U.AFLG-U.TSTA(R5) ;ALLOW THIS I/O REQUEST? BNE 120$ ;IF NE, YES...CONTINUE ON MOV U.ACB-U.TSTA(R5),R0 ;GET ACD CONTROL BLOCK ADDRESS AGAIN MOV A.IOS(R0),R0 ;GET I/O ERROR CODE TO RETURN TO TASK BR 910$ ;FINISH I/O 120$: .ENDC ;T$$ACD .IF DF T$$OVL MOV PPDSP-2(R1),R1 ;GET ADDRESS TO WHICH TO DISPATCH ASL R1 ;CONVERT TO A REAL ADDRESS BCS 130$ ;AND SEE IF ROUTINE IS IN OVERLAY CALL MPEXT ;MAP AND CALL ROUTINE BR 140$ ; 130$: CALL (R1) ;IT'S NOT IN THE OVERLAY 140$: .IFF ;T$$OVL CALL @PPDSP-2(R1) ;DO OR START FUNCTION .ENDC ;T$$OVL JMP GRQPKT ;LOOP TO DEQUEUE ANYTHING ELSE WE CAN ; ; ERROR HANDLING FOR REQUEST INITIATION ROUTINE. ; 900$: MOV #IE.NOD&377,R0 ;RETURN ERROR FOR INSUFFICIENT DYNAMIC MEMORY 910$: .IF DF T$$EIO CMP R1,#IO.EIO/400 ;IS THIS AN IO.EIO? BNE 990$ ;IF NE, NO...JUST FINISH OFF PACKET WITH ERROR MOV R0,-(SP) ;SAVE RETURN STATUS MOV R5,R0 ;GET COPY OF UCB POINTER ADD #U.TIXL-U.TSTA,R0 ;MAKE POINTER TO U.TIXL (IOPX LISTHEAD) 980$: MOV R0,R1 ;CURRENT IOPX POINTER BECOMES BACKPOINTER ASSUME I.XLNK,0 MOV (R1),R0 ;POINT TO NEXT IOPX CMP I.XIOP(R0),R3 ;DOES THIS IOPX BELONG TO CURRENT I/O PACKET? BNE 980$ ;IF NE,NO...LOOP TILL WE FIND IT ASSUME I.XLNK,0 MOV (R0),(R1) ;REMOVE IOPX FROM LIST MOV R3,-(SP) ;SAVE POINTER TO IOPX MOV #I.XLEN,R1 ;GET SIZE OF IOPX CALL $DEACB ;DEALLOCATE IOPX MOV (SP)+,R3 ;RESTORE POINTER FOR IOFIN MOV U.TDIF(R4),R2 ;GET DEFAULT INPUT BUFFER LIST POINTER CALL DELTB ;DEALLOCATE THEM, IF ANY MOV (SP)+,R0 ;RESTORE ERROR CODE 990$: .ENDC ;T$$EIO CALL IOFIN ;FINISH THE I/O REQUEST JMP GRQPKT ;TRY FOR ANOTHER REQUEST .DSABL LSB .PAGE .SBTTL TTINI SUBROUTINES .SBTTL . GRQAC - $GSPKT ACCEPTANCE ROUTINE FOR GET RQST (FPGRQ) ; ;+ ; **-GRQAC - $GSPKT ACCEPTANCE ROUTINE FOR GETTING A NEW REQUEST PACKET (FPGRQ) ;- ; GRQAC: CMP I.UCB(R1),G$$SPA(SP) ;IS THIS PACKET FOR THE CURRENT UCB? SEC ;ASSUME ERROR BNE 10$ ;IF NE, NO...ASSUMPTION CORRECT ASSUME S2.IRQ,S1.IBY ASSUME S2.ORQ,S1.OBY BITB I.PRM+7(R1),U.TSTA(R5) ;CAN WE PROCESS THIS PACKET? BNE 20$ ;IF NE, NO...SKIP TO CHECK FOR SCAN ABORT ; IF TERMINAL IS IN TERMINAL MANAGEMENT MODE AND THE REQUEST IS AN INTERNAL ; I/O REQUEST, REJECT THIS PACKET. THIS IS A BIT OF A HACK. WHEN TIME ; PERMITS, WE COULD USE EVENT PACKETS TO TELL THE NET TO STOP SENDING I/O. ; .IF DF T$$SCA & R$$IIC BIT #S5.TMM,U.TST5(R5) ;IS TERMINAL IN TERM. MANAGEMENT MODE? BEQ 5$ ;IF NOT, SO FAR, SO GOOD BIT #1,I.IOSB+4(R1) ;IF TMM, IS IT ALSO INTERNAL I/O? BNE 10$ ;REJECT.. SEC STILL FROM ABOVE 5$: .ENDC ;T$$SCA & R$$IIC .IF DF T$$BTW ASSUME S3.FDX,200 TSTB U.TSTA+4(R5) ;IS THIS A FULL DUPLEX LINE? (CLEAR CC-C) BMI 10$ ;IF MI, YES...ACCEPT THIS PACKET BIT #S1.IBY!S1.OBY,U.TSTA(R5) ;IS ANYTHING BUSY? BEQ 10$ ;IF EQ, NO...ACCEPT THIS REQUEST ; ; THE LINE IS NOT IN FULL DUPLEX MODE, AND EITHER INPUT OR OUTPUT IS BUSY. ; IN THIS CASE, THE ONLY PACKET WE CAN ACCEPT IS IO.WBT. IO.WBT PACKETS HAVE ; PRIORITY 251., AND ALL OTHERS HAVE LOWER PRIORITY. IF THIS PACKET IS NOT ; AN IO.WBT, WE KNOW THAT THERE ARE NO IO.WBT'S FURTHER DOWN THE QUEUE EITHER, ; SO WE ABORT THE SCAN. ; CMPB I.PRI(R1),#251. ;IS THIS AN IO.WBT? (CLEAR CC-C IF YES) BNE 30$ ;IF NE, NO...ABORT THE SCAN ; ; ; DON'T BEGIN AN IO.WBT FUNCTION IF A READ IS ACTIVE THAT SPECIFIED TF.XOF. ; THIS IS NECESSARY TO PREVENT A COLLISION BETWEEN THE IO.WBT DATA AND THE ; XOF CHARACTER OUTPUT. ; BIT #S1.USI,U.TSTA(R5) ;UNSOLICITED INPUT IN PROGRESS? BNE 10$ ;Y - ACCEPT IO.WBT .IF DF T$$SPL MOV U.TAPR(R5),KDSAR5 ;MAP UCBX MOV #120000,R2 ;POINT TO UCBX .IFF ;T$$SPL MOV U.TUX(R5),R2 ;GET UCBX (THERE MUST BE ONE SINCE LINE IS BUSY) .ENDC ;T$$SPL TSTB U.TISV(R2) ; CHECK IF ^R AFTER IO.WBT IS IN PROGRESS ;LK705 BNE 30$ ; YES DO NOT TAKE ANOTHER IO.WBT ;LK705 MOV @R2,R2 ;GET CURRENT INPUT PACKET ;**-2 BEQ 10$ ;NONE - ACCEPT IO.WBT BIT #TF.XOF,I.FCN(R2) ;READ IS ACTIVE - TF.XOF SPECIFIED? BNE 30$ ;Y - REJECT IO.WBT AND STOP SCAN AT THIS POINT ; ; ACCEPT THE CURRENT REQUEST PACKET. ; .IFF ;T$$BTW CLC ;RETURN WITH CC-C CLEAR TO ACCEPT PACKET .ENDC ;T$$BTW 10$: RETURN ;ALL DONE ; ; IF PACKET REQUIRES BOTH INPUT AND OUTPUT TO BE FREE, ABORT THE SCAN. ; OTHERWISE JUST REJECT THE PACKET BY RETURNING WITH CC-C SET. ; ASSUME S2.ORQ,100 ASSUME S2.IRQ,200 20$: CMPB I.PRM+7(R1),#S1.IBY!S1.OBY ;ARE BOTH INPUT AND OUTPUT... ; ...REQUIRED TO BE FREE FOR THIS REQUEST? BLO 10$ ;IF LO, NO...RETURN TO REJECT THIS PACKET... ; ...CC-C WAS SET BY COMPARE INSTRUCTION ; ; WE FOUND A PACKET THAT REQUIRES BOTH INPUT AND OUTPUT TO BE FREE. ABORT THE ; SCAN SO THE PACKET WILL GET A CHANCE TO BE DEQUEUED ONCE ALL REQUESTS IN ; FRONT OF IT ARE DONE. ; 30$: ADD #G$$SPA,SP ;FLUSH STACK MOV (SP)+,R5 ;RESTORE POINTER TO UCB CLR (SP) ;DON'T CHANGE FLAGS IN U.TSTA+2 JMP NOPKDQ ;FINISH AS THOUGH NO PACKET TO DEQUEUE .PAGE .SBTTL . KILAC - $GSPKT ACCEPTANCE ROUTINE FOR KILL I/O (QPKIL) ; ;+ ; **-KILAC - KILL I/O ACCEPTANCE ROUTINE FOR $GSPKT ; ; "$GSPKT" CALLS THIS ROUTINE WITH AN I/O PACKET TO BE CHECKED AGAINST THE ; KILL I/O ACCEPTANCE CRITERIA: ; 1. THE I/O PACKET UCB ADDRESS MUST MATCH THE I/O KILL REQUEST UCB. ; 2. THE I/O PACKET TCB ADDRESS MUST MATCH THE I/O KILL REQUEST TCB. ; 3. IF THE I/O KILL SUBFUNCTION WAS TF.WLB, THE I/O PACKET FUNCTION ; CODE MUST BE "IO.EIO!TF.WLB" OR "IO.WLB". ; 4. IF THE I/O KILL SUBFUNCTION WAS TF.RLB, THE I/O PACKET FUNCTION ; CODE MUST BE "IO.EIO!TF.RLB", "IO.RLB", "IO.RPR", OR "IO.RTT". ; ; INPUTS: ; R1 => I/O REQUEST PACKET TO BE ACCEPTED/REJECTED. ; G$$SPA(SP) => UCB OF PACKETS TO ACCEPT ; G$$SPA+2 => I/O KILL REQUEST PACKET ; ; OUTPUTS: ; CC-C = 0 IF PACKET IS TO BE ACCEPTED ; = 1 IF PACKET IS TO BE REJECTED ; ; REGISTERS MODIFIED: R2, R3 ;- ; .IF DF R$$IIC KILAC: CMP I.UCB(R1),G$$SPA(SP) ;IS THIS PACKET FOR THE CORRECT UCB? BNE 30$ ;IF NE, NO...DON'T ACCEPT IT MOV G$$SPA+2(SP),R3 ;GET POINTER TO KILLER REQUEST PACKET CMP I.TCB(R1),I.TCB(R3) ;PACKET FOR THE CORRECT TCB? BNE 30$ ;IF NE, NO...DON'T ACCEPT IT MOVB I.FCN(R3),R3 ;GET KILLER PACKET SUBFUNCTION CODE MOVB I.FCN+1(R1),R2 ;GET PACKET SUBFUNCTION CODE .IF DF T$$EIO CMPB #IO.EIO/400,R2 ;IS THIS PACKET AN EXTENDED I/O REQUEST? BNE 5$ ;IF NOT, BR ;WARNING: THIS ASSUMES THAT IO.RLB/400,TF.RLB AND IO.WLB/400,TF.RLB MOVB I.FCN(R1),R2 ;GET NON-EXTENDED I/O REQUEST FUNCTION CODE 5$: .ENDC ;T$$EIO CMPB #IO.RPR/400,R2 ;IS THIS AN OLD-FASHIONED IO.RPR? BEQ 10$ ;IF EQ, YES...SKIP CMPB #IO.RTT/400,R2 ;IS THIS AN OLD-FASHIONED IO.RTT? BNE 20$ ;IF NE, NO...SKIP 10$: MOVB #TF.RLB,R2 ;MAKE THESE LOOK LIKE STRAIGHT READS 20$: CLC ;ASSUME WE ARE GOING TO ACCEPT THIS PACKET BITB R3,R2 ;IS THIS A PACKET TO BE KILLED? BNE 40$ ;IF NE, YES...ACCEPT IT 30$: SEC ;DON'T ACCEPT THIS PACKET 40$: RETURN ;ALL DONE .ENDC ;R$$IIC .PAGE .SBTTL I/O REQUEST PRE-QUEUE PROCESSING ROUTINES .SBTTL . QPKIL - INTERNAL I/O KILL REQUEST ; ;+ ; **-QPKIL - INTERNAL I/O KILL REQUEST (IO.KIL) ; ; THIS ROUTINE PROCESSES AN I/O REQUEST WITH A FUNCTION CODE OF ZERO. AN ; I/O PACKET WILL ONLY HAVE THIS FUNCTION CODE IF IT IS AN INTERNAL (SYSTEM ; STATE) I/O REQUEST. IT PERFORMS FUNCTIONS SIMILAR TO THE DRIVER'S CANCEL ; I/O ENTRY POINT "TTCAN". HOWEVER, IF CAN BE SPECIFIED THAT ONLY READ OR ; ONLY WRITE REQUESTS ARE TO BE CANCELLED. THIS IS DONE WITH THE REQUEST ; MODIFIERS "TF.WLB" AND "TF.RLB". A "$GSPKT" ACCEPTANCE ROUTINE IS USED TO ; FIND ALL SPECIFIED REQUESTS IN THE SCB QUEUE. AN I/O KILL REQUEST IS ALWAYS ; PROCESSED AND COMPLETED IMMEDIATELY, SO IT IS NEVER PLACED IN THE SCB QUEUE. ; ; INPUTS: ; R3 => I/O KILL REQUEST PACKET ; R4 => SCB FOR THE TERMINAL ; R5 => UCB FOR THE TERMINAL ; I.FCN = TF.WLB OR TF.RLB ; I.TCB => TCB OF TASK WHOSE REQUESTS ARE TO BE ABORTED ; ; OUTPUTS: ; SPECIFIED I/O REQUESTS ARE ABORTED WITH STATUS IE.ABO ; ; REGISTERS MODIFIED: R0, R1, R2 ;- ; .IF DF R$$IIC QPKIL:: .IF DF M$$PRO BIT S.URM(R4),@$CPURM ;ALREADY ON CORRECT CPU? BNE 5$ ;IF NE YES, CONTINUE ; CONVERT PARAMETER LIST PART OF I/O PACKET INTO A FORK ; BLOCK FOR INTERPROCESSOR FORK. ADD #I.PRM+12,R3 ;POINT TO KISAR5 FIELD MOV KINAR5,(R3) ;INSERT DRIVER I MAPPING MOV R4,-(R3) ;SAVE R4 IN FORK BLOCK MOV S.URM(R4),-10(R3) ;SET URM OF DEVICE IN FORK BLOCK MOV R3,R4 ;POINT R4 AT FORK BLOCK FOR $FORK1 CALL $FORK1 ;SWITCH TO CORRECT CPU SUB #I.PRM+4,R3 ;POINT BACK TO BEGINNING OF FORK BLOCK CALL MAPD ;RE-MAP DRIVER 5$: .ENDC ; DF M$$PRO MOV R3,-(SP) ;SAVE REQUEST PACKET POINTER MOV R5,-(SP) ;SAVE CURRENT UCB POINTER ;**NOTE: THESE ARE SAVED FOR INSPECTION... ; ...IN THE $GSPKT ACCEPTANCE ROUTINE MOV I.TCB(R3),R1 ;GET TCB OF TASK TO KILL REQUESTS FOR MOV I.FCN(R3),R3 ;GET FUNCTION CODE OF THINGS TO KILL IN R3 CALL TTCN1 ;CANCEL SELECTIVE I/O (DEPENDS ON TF.WLB/TF.RLB) 10$: MOV (SP),R5 ;RESTORE UCB ADDRESS MOV #KILAC,R2 ;SET POINTER TO ACCEPTANCE ROUTINE CALL $GSPKT ;GET A PACKET BCS 20$ ;IF CS, NO MORE PACKETS...ALL DONE MOV R1,R3 ;COPY KILLED PACKET ADDRESS FOR IOFIN MOV #IE.ABO&377,R0 ;SET REQUEST COMPLETION STATUS CALL IOFIN ;FINISH OFF THE I/O REQUEST BR 10$ ;LOOK FOR ANOTHER PACKET 20$: TST (SP)+ ;CLEAN STACK MOV (SP)+,R3 ;GET BACK ADDRESS OF I/O KILL REQUEST PACKET MOV #IS.SUC&377,R0 ;SUCCESSFUL I/O KILL JMP IOFIN ;FINISH I/O KILL .ENDC ;R$$IIC .PAGE .SBTTL . BUFFER ADDRESS CHECKING AND RELOCATION ROUTINES ; ;+ ; **-CKBFR - ADDRESS CHECK BUFFER FOR READ ACCESS ; **-CKBFRW - ADDRESS CHECK BUFFER FOR READ ACCESS AND WORD ALIGNMENT ; **-CKBFB - ADDRESS CHECK BUFFER FOR READ/WRITE ACCESS ; ; THESE ROUTINES PERFORM THE DESCRIBED ADDRESS CHECKING ON A USER BUFFER. ; ; INPUTS: ; R0 => USER BUFFER (VIRTUAL ADDRESS) ; R1 = LENGTH OF USER BUFFER ; ; OUTPUTS: ; CC-C = 0 IF ADDRESS CHECK WAS SUCCESSFUL ; CC-C = 1 IF ADDRESS CHECK FAILED ; R0 = ERROR CODE FOR ADDRESS CHECK FAILURE REASON: ; "IE.SPC" IF SPECIFIED BUFFER LENGTH IS ZERO ; "IE.SPC" IF BUFFER NOT WORD ALIGNED OR EXEC ADDRESS CHECK FAILS ; "IE.BAD" IF BUFFER SIZE IS GREATER THAN 8128. BYTES ; R1 = BIAS OF RELOCATED USER BUFFER ADDRESS ; R2 = DISPLACEMENT OF RELOCATED USER BUFFER ADDRESS ; ; REGISTERS MODIFIED: R0 ;- ; .IF DF A$$CHK .ENABL LSB CKBFRW: BIT #1,R0 ;DOES BUFFER START ON ODD ADDRESS? BNE 910$ ;IF NE, YES...RETURN INVALID BUFFER ERROR CKBFR:: .IF DF R$$MPL MOV #$CKBFR,-(SP) ;SET UP CALL FOR READ-ACCESS CHECK BR 10$ ;SKIP TO COMMON CODE .IFTF ;R$$MPL CKBFB:: .IFT ;R$$MPL MOV #$CKBFB,-(SP) ;SET UP CALL FOR WRITE-ACCESS CHECK 10$: .IFTF ;R$$MPL TST R1 ;IS BUFFER SIZE VALID? BEQ 900$ ;IF EQ, NO...RETURN INVALID BUFFER ERROR CMP R1,#20000-100 ;IS BUFFER BIGGER THAN 8128. BYTES? BHI 920$ ;IF HI, YES...RETURN BAD BUFFER SIZE ERROR .IFT ;R$$MPL .IF DF X$$HDR MOV (SP),-(SP) ;DUPLICATE MAPPING ROUTINE ADDRESS ON STACK MOV KISAR6,2(SP) ;SAVE CURRENT EXEC MAPPING MOV $SAHDB,KISAR6 ;MAP CURRENT TASK HEADER .IFTF ;X$$HDR CALL @(SP)+ ;CALL REQUESTED ADDRESS CHECK ROUTINE .IFT ;X$$HDR MOV (SP)+,KISAR6 ;RESTORE PREVIOUS MAPPING .ENDC ;X$$HDR .IFF ;R$$MPL CALL $ACHKB ;DO NORMAL ADDRESS CHECKING .ENDC ;R$$MPL BCS 910$ ;IF CS, IT FAILED...RETURN ERROR .IFF ;A$$CHK CKBRW: CKBFR:: CKBFB:: .IFTF ;A$$CHK CALL $RELOC ;RELOCATE ADDRESS AND CONVERT TO DOUBLEWORD RETURN ;ALL DONE .IFT ;A$$CHK 900$: .IIF DF R$$MPL, TST (SP)+ ;POP OFF CO-ROUTINE ADDRESS 910$: MOV #IE.SPC&377,R0 ;SET COMPLETION ERROR CODE FOR INVALID BUFFER BR 990$ ;SKIP 920$: .IIF DF R$$MPL, TST (SP)+ ;POP OFF CO-ROUTINE ADDRESS MOV #IE.BAD&377,R0 ;SET COMPLETION ERROR CODE FOR BAD SIZE 990$: SEC ;RETURN WITH ERROR FLAG RETURN ;ALL DONE .DSABL LSB .ENDC ;A$$CHK .PAGE .SBTTL . TSTRQ - CHECK I/O REQUEST QUEUE FOR PACKET TO DEQUEUE ; ;+ ; SUBROUTINE TSTRQ - TEST I/O QUEUE. ; ; INPUT: ; R5 POINTER TO U.TSTA ; ; OUTPUT: ; IF THERE IS (POTENTIALLY) A PACKET IN THE I/O QUEUE THAT ; CAN BE PROCESSED: ; RETURN TO CALLER WITH R3 = MASK OF BITS TO CLEAR IN U.TSTA+2 ; IF NO PACKET COULD BE DEQUEUED ; ; IF NOT: ; RETURN TO CALLER'S CALLER. ; ; REGISTERS ALTERED: R3 ;- ; TSTRQ:: MOV (R5),R3 ;GET FIRST TERMINAL STATUS WORD COM R3 ;INVERT IT BIC #^C,R3 ;CLEAR ALL TO SEE WHAT CAN BE DEQUEUED BIS #S2.SRQ,R3 ;OR WITH "SPECIAL REQUEST" FLAG BIT R3,2(R5) ;IS ANYTHING IN QUEUE THAT CAN BE PROCESSED? BEQ 10$ ;IF EQ, NO...POP OUR WAY OUT OF THIS ROUTINE BIT #S2.BRQ,2(R5) ;IS THERE A "BREAKTHROUGH WRITE" IN THE QUEUE? BNE 20$ ;IF NE, YES...IT CAN POSSIBLY BE PROCESSED ASSUME S3.FDX,200 TSTB 4(R5) ;USER ON A FULL DUPLEX LINE? BMI 20$ ;IF MI, YES...IT CAN POSSIBLY BE PROCESSED BIT #S1.IBY!S1.OBY,(R5) ;IS ANYTHING BUSY ON THE LINE? BEQ 20$ ;IF EQ, NO...RETURN TO PROCESS A REQUEST 10$: TST (SP)+ ;POP RETURN ADDRESS SO WE WON'T PROCESS REQUEST 20$: RETURN ;ALL DONE .PAGE .PSECT MAP5.6 .SBTTL . WRITE REQUEST PROCESSING .SBTTL . QPWSB - WRITE SPECIAL DATA ; ;+ ; **-QPWSD - WRITE SPECIAL DATA (IO.WSD) ;- ; .IF DF B$$MAP QPWSD:: BIC #^C,I.FCN(R3) ;CLEAR DISALLOWED BITS BIS #TF.WAL,I.FCN(R3) ;SET REQUIRED BIT CMP #T.RSDN,I.PRM+10(R3) ;IS THE DATA TYPE SPECIFIER LEGAL? BHIS QPWLB1 ;IF HIS, YES...CONTINUE BR EQPBAD ;ELSE, RETURN REQUEST WITH BAD PARAMENTERS .ENDC ;B$$MAP .SBTTL . QPWLB - WRITE LOGICAL BLOCK ; ;+ ; **-QPWLB - NORMAL WRITE REQUEST (IO.WLB) ;- ; QPWLB:: .IF DF T$$CUP MOV I.PRM+6(R3),I.PRM+10(R3) ;SAVE VFC/CURSOR-CONTROL FOR LATER .ENDC ;T$$CUP QPWLB1: MOV #S2.ORQ,R4 ;A WRITE MUST BLOCK IF OUTPUT IS ACTIVE .IF DF T$$BTW BITB #TF.WBT,I.FCN(R3) ;IS THIS A BREAKTHROUGH WRITE REQUEST? BEQ CKBFLN ;IF EQ, NO...CHECK BUFFER LENGTH AND QUEUE IT .IF DF M$$MUP MOV I.TCB(R3),R0 ;GET ISSUEING TASK TCB BIT #T3.PRV!T3.CLI,T.ST3(R0) ;IS TASK PRIVILEGED OR A CLI? BNE 10$ ;IF NE, YES...DO BREAKTHROUGH ;SA460 CMP T.UCB(R0),R5 ;IS THE IO.WBT TO OWN TI:? ;SA460 BNE EQPPRI ;IF NOT, DON'T ALLOW IT ;SA460 10$: ;SA460 ;**-1 .ENDC ;M$$MUP MOVB #251.,I.PRI(R3) ;CHANGE REQUEST TO PRIORITY 251. BIS #TF.CCO,I.FCN(R3) ;BREAKTHROUGH IMPLIES CANCEL CONTROL-O MOV #S2.ORQ!S2.BRQ,R4 ;FLAG BREAKTHROUGH REQUEST AND WAIT FOR WRITE .ENDC ;T$$BTW BR CKBFLN ;CHECK BUFFER LENGTH AND QUEUE THE REQUEST .PAGE .SBTTL . READ REQUEST PROCESSING .SBTTL . QPRSD - READ SPECIAL DATA ; ;+ ; **-QPRSD - READ SPECIAL DATA REQUEST (IO.RSD) ;- ; .IF DF B$$MAP QPRSD:: BIC #^C,I.FCN(R3) ;CLEAR DISALLOWED BITS BIS #,I.FCN(R3) ;FORCE REQUIRED BITS TST I.PRM+10(R3) ;IS THE DATA TYPE SPECIFIER LEGAL? BEQ EQPBAD ;ZERO IS NOT ALLOWED, BAD PARAMETERS CMP #T.RSDN,I.PRM+10(R3) ;IS THE DATA TYPE SPECIFIER LEGAL? BHIS CKBFLN ;IF HIS, YES...FINISH CHECKS AND QUEUE REQUEST BR EQPBAD ;BAD PARAMETERS .ENDC ;B$$MAP .SBTTL . QPRPR - READ AFTER PROMPT ; ;+ ; **-QPRPR - READ AFTER PROMPT REQUEST (IO.RPR) ;- ; .ENABL LSB .IF DF T$$RPR QPRPR:: MOV I.PRM+10(R3),R0 ;GET VIRTUAL ADDRESS OF PROMPT BUFFER MOV I.PRM+12(R3),R1 ;GET PROMPT BUFFER SIZE MOV #S2.IRQ!S2.ORQ,R4 ;PROMPT MUST BLOCK IF INPUT OR OUTPUT ACTIVE CALL CKBFR ;CHECK READ ACCESS AND RELOCATE PROMPT BUFFER BCC 10$ ;IF CC, OK...GO STORE ADDRESS AND QUEUE REQUEST BR IOFIN ;CHECK FAILED...COMPLETE REQUEST WITH THE ERROR .ENDC ;T$$RPR .SBTTL . QPRTT - READ WITH TERMINATOR TABLE ; ;+ ; **-QPRTT - READ WITH TERMINATOR TABLE REQUEST (IO.RTT) ;- ; QPRTT:: MOV #S2.IRQ,R4 ;READ W/TERMINATORS MUST BLOCK IF INPUT ACTIVE ; BIT #TF.PTT,I.FCN(R3) ;WANT TO USE PREVIOUSLY SPECIFIED TERM. TABLE? ; BNE CKBFLN ;IF NE, YES...DON'T BOTHER CHECKING PARAMETER MOV I.PRM+10(R3),R0 ;GET ADDRESS OF TERMINATOR TABLE MOV #32.,R1 ;LENGTH OF TABLE IS FIXED AT 32. BYTES CALL CKBFRW ;CHECK READ ACCESS AND RELOCATE TABLE ADDRESS BCS IOFIN ;IF CS, CHECK FAILED...RETURN WITH THE ERROR 10$: MOV R1,I.PRM+10(R3) ;SAVE FIRST WORD OF ADDRESS DOUBLE WORD MOV R2,I.PRM+16(R3) ;SAVE SECOND WORD OF ADDRESS DOUBLE WORD BR CKBFLN ;CHECK BUFFER LENGTH AND QUEUE THE REQUEST .DSABL LSB .SBTTL . QPRLB - READ LOGICAL BLOCK ; ;+ ; **-QPRLB - NORMAL READ REQUEST (IO.RLB) ;- ; QPRLB:: MOV #S2.IRQ,R4 ;NORMAL READ MUST WAIT FOR ACTIVE READ BR CKBFLN ;CHECK BUFFER LENGTH AND QUEUE THE REQUEST .PAGE .SBTTL . ERROR HANDLING ; ; EQPPRI - RETURN PRIVILEGE VIOLATION ERROR. ; EQPPRI: MOV #IE.PRI&377,R0 ;SET ERROR CODE FOR PRIVILEGE VIOLATION BR IOFIN ;FINISH I/O REQUEST (NO NEED TO RESTORE MAPPING) ; ; EQPBAD - RETURN ERROR FOR BAD PARAMETERS. ; EQPBAD:: MOV #IE.BAD&377,R0 ;SET ERROR FOR BAD PARAMETER SPECIFIED .IF DF A$$CHK BR EQPFIN ;FINISH REQUEST (REMAP DRIVER ON THE WAY) ; ; EQPSPC - RETURN ERROR BECAUSE OF INVALID BUFFER SPECIFICATION. ; EQPSPC: MOV #IE.SPC&377,R0 ;SET ERROR FOR ILLEGAL BUFFER SPECIFICATION ; BR EQPFIN ;RETURN THE ERROR (REMAP DRIVER ON THE WAY) .ENDC ;A$$CHK EQPFIN:: .IF DF T$$EIO MOV $DALED,KISAR6 ;RESTORE DRIVER MAPPING .ENDC ;T$$EIO IOFIN:: CLR R1 ;CLEAR SECOND WORD OF IOSB CALLR $IOFIN ;FINISH IO AND RETURN .PAGE .SBTTL . CKBFLN - FINAL BUFFER LENGTH CHECK ; ; CKBFLN - CHECK THAT BUFFER LENGTH IS WITHIN (1,8K-64) BYTES ; CKBFLN: .IF DF A$$CHK MOV I.PRM+4(R3),R1 ;GET LENGTH OF TRANSFER REQUEST BEQ EQPSPC ;IF EQ, RETURN ZERO BUFFER LENGTH ERROR CMP R1,#20000-100 ;IS BUFFER BIGGER THAN 8128. BYTES? BHI EQPBAD ;IF HI, BUFFER IS TOO BIG...RETURN ERROR .ENDC ;A$$CHK .SBTTL QUEUE - PLACE I/O REQUEST PACKET INTO TERMINAL QUEUE ; ; R4 NOW CONTAINS FLAGS TO BE USED BY THE ACCEPTANCE ROUTINE FO ; GETTING PACKETS FROM THE QUEUE VIA $GSPKT. SAVE THE FLAGS IN ; I.PRM+7 OF THE I/O PACKET. ; QUEUE:: ADD #U.TSTA,R5 ;POINT UCB POINTER TO THE FIRST STATUS WORD .IF DF T$$ACD MOV #UA.ALL,U.AFLG-U.TSTA(R5) ;SET DEFAULT PROCESSING MOV U.ACB-U.TSTA(R5),R0 ;GET ACB BEQ 10$ ;THERE IS NONE - JUMP MOVB I.FCN+1(R3),R1 ;GET FUNCTION CODE ASL R1 ;CONVERT TO A WORD INDEX CMPB R1,#30. ;FUNCTION CODE IN FIRST MASK WORD? BLOS 5$ ;Y - JUMP TST (R0)+ ;BUMP ACB POINTER TO CHECK SECOND MASK WORD SUB #32.,R1 ;REDUCE FUNCTION CODE 5$: BIT $BTMSK(R1),A.MAS(R0) ;IS THE ACD INTERESTED IN THIS FUNCTION? BEQ 10$ ;N - JUMP MOV #A.ACCE,R0 ;Y - SET TO I/O REQUEST ACCEPTANCE ENTRY POINT CALL $SWACD ;CALL ACD BIT #UA.ALL,U.AFLG-U.TSTA(R5) ;ALLOW THIS I/O REQUEST? BNE 10$ ;Y - JUMP SUB #U.TSTA,R5 ;POINT TO BEGINNING OF UCB MOV U.ACB(R5),R0 ;GET ACB MOV A.IOS(R0),R0 ;GET I/O ERROR CODE TO RETURN TO TASK BR IOFIN ;FINISH I/O 10$: .ENDC ;T$$ACD ASSUME ,0 MOVB R4,I.PRM+7(R3) ;SAVE FLAGS IN I/O PACKET BNE 20$ ;PACKET CANNOT BE PROCESSED ;IMMEDIATELY - JUMP .IF DF T$$GTS!T$$GMC CMPB #IO.HNG/256.,I.FCN+1(R3) ;IS THIS HANGUP OR GET CHAR.? BEQ 15$ ;IF EQ, IT'S A HANG - BRANCH .IF DF T$$OVL MOV #PPSPC1,R1 ;GET ADDRESS OF ROUTINE IN TTEXT CALLR MPEXT ;MAP IT AND CALL IT .IFF ;T$$OVL CALLR PPSPC1 ;PROCESS IMMEDIATELY .ENDC ;T$$OVL 15$: .ENDC ;T$$GTS!T$$GMC .IF DF T$$OVL MOV #PPHNG,R1 ;GET ADDRESS OF ROUTINE IN TTEXT CALLR MPEXT ;MAP IT AND CALL IT .IFF ;T$$OVL CALLR PPHNG ;PROCESS IMMEDIATELY .ENDC ;T$$OVL 20$: BICB #S2.SRQ!S2.BRQ,I.PRM+7(R3) ;CLEAR SRQ AND BRQ FLAGS IN PACKET MOV U.SCB-U.TSTA(R5),R0 ;GET I/O QUEUE LISTHEAD MOV R3,R1 ;GET PACKET POINTER CALL $QINSP ;INSERT PACKET BIT #S2.SRQ,R4 ;SPECIAL FUNCTION (IO.ATT, IO.DET, IO.SMC)? BEQ 30$ ;N - JUMP MOV #S2.SRQ,R4 ;Y - CLEAR ALL OTHER BITS 30$: BISB R4,2(R5) ;SET FLAGS TO INDICATE WHAT WE ;PUT IN THE QUEUE ;NOTE - MUST BE DONE A F T E R WE ;PUT PACKET IN THE QUEUE!! .IF DF M$$PRO MOV #FR.GRQ,R3 ;COME BACK AT FPGRQ CALL SWCPU ;SWITCH TO CORRECT CPU ; ; IF WE FALL THRU HERE, WE ARE ALREADY ON THE CORRECT CPU ; .ENDC ;M$$PRO CALL SETDSI ;DISABLE INPUT PROCESSING FRKBIT BIS,#FR.GRQ ;POST "GET REQUEST" FORK RETURN ;LET SETDSI DISPATCH IT. THAT'S WHAT ;IT GETS PAID FOR. .PAGE .SBTTL . QPATT/QPDET - ATTACH/DETACH REQUESTS ; ;+ ; **-QPATT - ATTACH TERMINAL REQUEST (IO.ATT) ; **-QPDET - DETACH TERMINAL REQUEST (IO.DET) ; ; ENTRY POINT "QPATT" PERFORMS UNSOLICITED INPUT AST ADDRESS ADJUSTMENT FOR ; SUPERVISOR MODE LIBRARIES (IF SUPPORTED) AND THEN FALLS THROUGH TO "QPDET". ; FROM QPDET, CONTROL IS TRANSFERRED TO THE PACKET QUEUEING ROUTINE WITH THE ; DEQUEUE BLOCKING FLAGS SET TO CHECK FOR ACTIVE INPUT AND OUTPUT. ; ; INPUTS: ; R3 => I/O PACKET FOR ATTACH/DETACH REQUEST ; R5 => UCB FOR THE TERMINAL ; ; OUTPUTS: ; R3 => I/O PACKET TO BE QUEUED ; R4 = REQUEST DEQUEUE BLOCKING FLAGS ; ; REGISTERS MODIFIED: R0, R1, R2 ;- ; QPATT:: .IF DF S$$LIB BITB #TF.AST,I.FCN(R3) ;ATTACH FOR UNSOLICITED INPUT AST? BEQ QPDET ;IF EQ NO MOV I.PRM(R3),R2 ;GET ALL CHARACTER AST ADDRESS CALL $CALTA ;ADJUST FOR SUPER/USER MODE MOV R2,I.PRM(R3) ;AND PUT IT BACK MOV I.PRM+4(R3),R2 ;GET CONTROL C AST ADDRESS CALL $CALTA ;ADJUST FOR SUPER/USER MODE MOV R2,I.PRM+4(R3) ;AND PUT IT BACK .ENDC ;S$$LIB QPDET:: MOV #S2.IRQ!S2.ORQ!S2.SRQ,R4 ;BLOCK REQUEST IF EITHER INPUT OR... ; ...OUTPUT ACTIVE AND MARK AS SPECIAL FUNCTION JMP QUEUE ;QUEUE UP THE REQUEST NOW .PAGE .SBTTL . QPSPC - "SPECIAL" REQUESTS ; ;+ ; **-QPSPC - HANDLE "SPECIAL" REQUESTS (IO.GTS/SF.GMC/SF.SMC) ; ; THIS ROUTINE CHECKS PARAMETERS FOR THE "GET TERMINAL SUPPORT" AND THE ; "GET/SET MULTIPLE CHARACTERISTICS" FUNCTIONS. THE USER BUFFER FOR THESE ; REQUESTS MUST BE WORD-ALIGNED. THE IO.GTS AND SF.GMC FUNCTIONS WILL BE ; PASSED TO "QUEUE" WITH NO DEQUEUE BLOCKING FLAGS SET. THIS ALLOWS THEM TO ; BE PROCESSED SYNCHRONOUSLY (NEVER QUEUED). AN SF.SMC FUNCTION MUST WAIT ; FOR ACTIVE INPUT AND OUTPUT REQUESTS TO FINISH BEFORE BEING DEQUEUED. ; ; INPUTS: ; R3 => I/O PACKET FOR THE REQUEST ; R5 => UCB FOR THE TERMINAL ; ; OUTPUTS: ; R3 => I/O PACKET TO BE QUEUED ; R4 = REQUEST DEQUEUE BLOCKING FLAGS ; ; REGISTERS MODIFIED: R0, R1, R2 ;- ; .IF DF T$$GTS!T$$GMC!T$$SMC QPSPC:: .IF DF T$$GTS!T$$GMC CLR R4 ;ASSUME REQUEST IS IO.GTS OR SF.GMC - IF SO... ; ...IT IS PROCESSED SYNCHRONOUSLY (NOT QUEUED) .ENDC ;T$$GTS!T$$GMC .IF DF T$$GTS CMP I.FCN(R3),#IO.GTS ;IO.GTS? ;GET TERMINAL DRIVER SUPPORT REQUEST? .IF DF T$$GMC!T$$SMC BEQ 20$ ;IF EQ, YES...CHECK BUFFER ALIGNMENT .IFF ;T$$GMC!T$$SMC BNE EQPIFC ;IF NE, NO...RETURN ILLEGAL FUNCTION ERROR .ENDC ;T$$GMC!T$$SMC .ENDC ;T$$GTS .IF DF T$$GMC CMP I.FCN(R3),#SF.GMC ;GET MULTIPLE CHARACTERISTICS REQUEST? .IF DF T$$SMC BEQ 20$ ;IF EQ, YES...CHECK BUFFER ALIGNMENT .IFF ;T$$SMC BNE EQPIFC ;IF NE, NO...RETURN ILLEGAL FUNCTION ERROR .ENDC ;T$$SMC .ENDC ;T$$GMC .IF DF T$$SMC CMP I.FCN(R3),#SF.SMC ;SET MULTIPLE CHARACTERISTICS REQUEST? BNE EQPIFC ;IF NE, NO...RETURN ILLEGAL FUNCTION ERROR MOV I.TCB(R3),R0 ;GET ISSUING TASK'S TCB CMP T.UCB(R0),R5 ;IS THIS TERMINAL HIS TI:? BEQ 10$ ;IF EQ, YES...REQUEST IS LEGAL BIT #T3.PRV,T.ST3(R0) ;IS THE TASK PRIVILEGED? BNE 10$ ;IF NE YES, OK JMP J2EQPR ;IF EQ, NO...CAN'T ALLOW USER TO DO THIS 10$: MOV #S2.IRQ!S2.ORQ!S2.SRQ,R4 ;SF.SMC MUST BLOCK IF INPUT OR OUTPUT ; ...IS ACTIVE. ALSO FLAG AS "SPECIAL" FUNCTION .ENDC ;T$$SMC 20$: .IF DF A$$CHK MOV I.PRM+2(R3),-(SP) ;GET BUFFER ADDRESS BIS I.PRM+4(R3),(SP) ;"OR" IN THE BUFFER LENGTH ROR (SP)+ ;IS EITHER THE ADDRESS OR THE LENGTH ODD? BCC 30$ ;IF CC, BUFFER IS WORD-ALIGNED...SKIP JMP EQPSPC ;RETURN ERROR FOR BUFFER NOT WORD-ALIGNED 30$: .ENDC ;A$$CHK JMP CKBFLN ;CHECK FOR VALID BUFFER LENGTH AND QUEUE REQUEST .ENDC ;T$$GTS!T$$GMC!T$$SMC ; ; EQPIFC - RETURN AN ERROR DUE TO ILLEGAL FUNCTION CODE OR INVALID MODIFIERS. ; .IF DF T$$GTS!T$$GMC!T$$SMC!T$$EIO EQPIFC:: MOV #IE.IFC&377,R0 ;SET ERROR FOR ILLEGAL FUNCTION CODE OR MODIFIER JMP EQPFIN ;FINISH OFF THE REQUEST (RESTORE MAPPING ALSO) .ENDC ;T$$GTS!T$$GMC!T$$SMC!T$$EIO .PAGE .PSECT MAP5 .SBTTL . QPHNG - HANGUP REQUEST ; ;+ ; **-QPHNG - HANGUP REQUEST (IO.HNG) ; ; THIS ROUTINE CHECKS AN IO.HNG REQUEST. A NON-PRIVILEGED TASK CAN HANG ;SA460 ; UP ONLY ITS "TI:" LINE. PRIVILEGED TASKS CAN HANG UP ANY LINE. A HANGUP ;SA460 ; REQUEST, LIKE AN IO.WBT OR GET CHARACTERISTICS, BREAKS THROUGH THE QUEUE. ;SA460 ; ;**-3 ; INPUTS: ; R3 => I/O PACKET FOR THE REQUEST ; R5 => UCB FOR THE TERMINAL ; ; OUTPUTS: ; R3 => I/O PACKET TO BE QUEUED ; R4 = REQUEST DEQUEUE BLOCKING FLAGS ; ; REGISTERS MODIFIED: R0 ;- ; QPHNG:: CALL PREQUE ;SET UP FOR QUEUEING ;TMS051 CLR R4 ;IO.HNG WAITS FOR NOTHING ;TMS051 JMP QUEUE ;QUEUE THE REQUEST ;TMS051 ;TMS051 .IF DF T$$LTH ;TMS051 ;TMS051 .SBTTL . QPORG - INITIATE A CONNECTION TO A TERMINAL SERVER ;TMS051 ; ;TMS051 ;+ ;TMS051 ; **-QPORG - ORIGINATE REQUEST (IO.ORG) ;TMS051 ; ;TMS051 ; THIS ROUTINE CHECKS AN IO.ORG REQUEST. ;TMS051 ; ;TMS051 ; INPUTS: ;TMS051 ; R3 => I/O PACKET FOR THE REQUEST ;TMS051 ; R5 => UCB FOR THE TERMINAL ;TMS051 ; ;TMS051 ; OUTPUTS: ;TMS051 ; R3 => I/O PACKET TO BE QUEUED ;TMS051 ; R4 = REQUEST DEQUEUE BLOCKING FLAGS ;TMS051 ; ;TMS051 ; REGISTERS MODIFIED: R0 ;TMS051 ;- ;TMS051 ; ;TMS051 QPORG:: ;TMS051 CALL PREQUE ;SET UP FOR QUEUEING ;TMS051 MOV #S2.IRQ!S2.ORQ,R4 ;ORIGINATE MUST WAIT FOR READ AND WRITE ;TMS051 JMP QUEUE ;QUEUE THE REQUEST ;TMS051 ;TMS051 .ENDC ;T$$LTH ;TMS051 ;TMS051 PREQUE: ;TMS051 MOV I.TCB(R3),R0 ;GET ISSUING TASK'S TCB ;**-1 CMP T.UCB(R0),R5 ;IS THIS TERMINAL HIS TI:? BEQ J2QUE ;IF EQ, YES...ALLOW THE HANGUP BIT #T3.PRV,T.ST3(R0) ;IS THE TASK PRIVILEGED? BEQ J2EQPR ;IF EQ, NO...RETURN PRIVILEGE VIOLATION ERROR J2QUE: .IF DF M$$PRO MOV U.SCB(R5),R4 ;GET SCB ADDRESS BIT S.URM(R4),@$CPURM ;ALREADY ON CORRECT CPU? BEQ 5$ ;IF EQ NO, FORK TO CORRECT CPU ; BM380 ; BM380 .IFTF ; DF M$$PRO ; BM380 ; BM380 RETURN ; BM380 ; BM380 .IFT ; DF M$$PRO ; BM380 ; BM380 ; CONVERT PARAMETER LIST PART OF I/O PACKET INTO A FORK BLOCK ; BM380 ; (AND THE RETURN ADDRESS) FOR INTERPROCESSOR FORK. SINCE THIS ; BM380 ; IS A SUBROUTINE, WE MUST REMEMBER CALLER ADDRESS IN FORK BLOCK ; BM380 ; OR THE INTERPROCESSOR FORK DOES NOTHING. ; BM380 ; ; BM380 5$: ADD #I.PRM+14,R3 ;POINT PAST KISAR5 FIELD IN FORK BLOCK ; BM380 MOV (SP)+,(R3) ;REMEMBER RETURN ADDRESS ; BM380 MOV KINAR5,-(R3) ;INSERT DRIVER I MAPPING IN KISAR5 FIELD ; BM380 CLR -(R3) ;CLEAR R4 IN FORK BLOCK ;**-7 MOV S.URM(R4),-10(R3) ;SET URM OF DEVICE IN FORK BLOCK MOV R3,R4 ;POINT R4 AT FORK BLOCK FOR $FORK1 CALL $FORK1 ;SWITCH TO CORRECT CPU SUB #I.PRM+4,R3 ;POINT BACK TO BEGINNING OF FORK BLOCK CALL MAPD ;RE-MAP DRIVER JMP @I.PRM+14(R3) ;DISPATCH TO ORIGINAL CALLER ; BM380 ;**-1 .ENDC ; DF M$$PRO J2EQPR: ;**-2 TST (SP)+ ;POP RETURN ADDRESS OFF STACK ;TMS060 JMP EQPPRI ;RETURN PRIVILEGE VIOLATION ERROR .END