.TITLE QTDRV - CATCH I/O PACKETS .SBTTL DISCUSSION ; WRITTEN BY: JOHN WOOD ; LAWRENCE BERKELEY LABORATORY ; BERKELEY, CALIFORNIA 94720 ; (415) 486-5972 ; ; THIS DRIVER AND ASSOCIATED DATA BASE, QTTAB, ALLOWS THE USER TO ; CAPTURE I/O PACKETS AS THEY ARE QUEUED TO ANOTHER DRIVER. THIS ; MAGIC IS VERY SIMPLY PERFORMED BY REPLACING TOW LOCATIONS IN THE ; TARGET DRIVER'S DATA BASE WITH OUR OWN. ONCE THE QT DRIVER HAS ; RECEIVED A PACKET FROM THE TARGET DRIVER IT COPIES CERTAIN LOCATIONS ; TO A SEND PACKET WHICH IT THEN QUEUES TO THE RECEIVE QUEUE OF A ; COOPERATING TASK. A SHORT PIECE OF CODE IN THE QT DRIVER'S DCB ; REMAPS TO THE TARGET DRIVER AND JUMPS TO IT. ; ; THERE ARE TWO FUNCTION CODES DEFINED FOR THE QT DRIVER WHICH CAN ; BE ISSUED FROM ANY TASK. THEY ARE IO.BGN AND IO.END. OBVIOUSLY ; THEY BEGIN AND END THE PROCESS. ; ; THE PROCESS WILL ALSO BE ENDED IF ANY OF THE BLOCKING BITS ARE SET ; IN THE TCB OF THE COOPERATING TASK. ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ASSEMBLE AND TASK BUILD AS PER INSTRUCTIONS IN, 'GUIDE TO WRITING ; AN I/O DRIVER'. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .PAGE .SBTTL DEFINITIONS .MCALL HWDDF$,PCBDF$,DCBDF$,UCBDF$,PKTDF$,TCBDF$,IOERR$ HWDDF$ ;DEFINE THE HARDWARE REGISTERS ETC. PCBDF$ ;DEFINE THE PARTITION CONTROL BLOCK OFFSETS DCBDF$ ;DEFINE THE DEVICE CONTROL BLOCK OFFSETS UCBDF$ ;DEFINE THE UNIT CONTROL BLOCK OFFSETS PKTDF$ ;DEFINE THE PACKET OFFSETS TCBDF$ ;DEFINE THE TASK CONTROL BLOCK OFFSETS IOERR$ ;DEFINE THE ERROR CODES LD$QT= 0 ;DRIVER IS LOADABLE CNBR= 1 ;NUMBER OF UNITS ; ERROR CODES IE.DNF= 200 ;DRIVER NOT FOUND IE.AIU= 201 ;ALREADY IN USE ; FUNCTION CODES IO.BGN= 401 ;START PROCESS IO.END= 402 ;END PROCESS .PAGE .SBTTL LOCAL VARIABLES CNTBL: .BLKW CNBR ;STORAGE FOR UCB ADDRESS OF QT: DSPTCB: .WORD 0 ;TCB OF DISPLAY TASK ; TARGET DRIVER VALUES TARDDT: .WORD 0 ;DRIVER DISPATCH TABLE POINTER TARPCB: .WORD 0 ;PCB ADDRESS TARDCB: .WORD 0 ;DCB ADDRESS TARUCB: .WORD 0 ;UCB ADDRESS TARSCB: .WORD 0 ;SCB (I/O PACKET LISTHEAD TARNAM: .WORD 0 ;TWO CHARACTER DEVICE NAME TARNUM: .WORD 0 ;DEVICE NUMBER (BINARY VALUE) .PAGE .SBTTL DRIVER DISPATCH TABLES ; THIS IS THE REAL ONE. THIS TABLE IS ENTERED WHEN THE QT: DRIVER ; IS CALLED BY THE EXECUTIVE. $QTTBL::.WORD QTINI ;INITIATE .WORD QTCAN ;CANCEL .WORD QTOUT ;TIMEOUT .WORD QTPWF ;POWERFAIL ; THIS IS A PHONEY ONE. IT IS ENTERED BY TH EXECUTIVE BECAUSE THE ; POINTERS IN THE TARGET DRIVER HAS BEEN CHANGED TO VECTOR THE ; CONTROL TO QT:. TARTBL: .WORD TARINI ;INITIATE .WORD TARCAN ;CANCEL .WORD TAROUT ;TIMEOUT .WORD TARPWF ;POWERFAIL ;DUMMY ENTRY POINTS FOR THE REAL QT: DRIVER. QTPWF: MOV R5,CNTBL ;SAVE THE UCB ADDRESS QTCAN: ;DO NOTHING QTOUT: ;DO NOTHING RETURN ; ; INTERRUPT ENTRY POINT FOR QT:. $QTINT:: ;DO NOTHING BUT RETURN RETURN ; .PAGE .SBTTL QTINI - START THE PROCESS QTINI: CALL $GTPKT ;ANY WORK TO DO? BCC 10$ ;BRANCH IF YES RETURN ;NOTHING TO DO ; CHECK THE FUNCTION CODE 10$: CMP #IO.BGN,I.FCN(R1) ;START THE PROCESS? BNE 20$ ;BRANCH IF NO TST DSPTCB ;ALREADY STARTED? BEQ 15$ ;BRANCH IF NO MOV TARNAM,R1 ;TELL THEM WHICH DEVICE IS BEING WATCHED MOV #IE.AIU,R0 ;'ALREADY IN USE' JMP EXIT1 ;FINISH I/O 15$: JMP STRT ;BEGIN THE PROCESS 20$: CMP #IO.END,I.FCN(R1) ;END THE PROCESS? BNE 30$ ;BRANCH IF NO JMP DONE ;END THE PROCESS 30$: MOV #IE.IFC,R0 ;'ILLEGAL FUNCTION CODE' JMP EXIT ;FINISH I/O .PAGE ; THIS ROUTINE SAVES VARIOUS FIELD OF THE I/O PACKET, FINDS THE ; TARGET DRIVER AND LINKS ITSELF BY CHANGING 'D.PCB' AND 'D.DSP' IN ; THE TARGET DRIVER'S DCB. STRT: MOV I.TCB(R1),DSPTCB ;SAVE TCB ADDRESS MOV I.PRM(R1),TARNAM ;SAVE THE TARGET NAME MOV I.PRM+2(R1),TARNUM ;SAVE THE TARGET UNIT NUMBER CALL FIND ;FIND THE TARGET DRIVER BCC 20$ ;BRANCH IF NOT FOUND MOV #IE.DNF,R0 ;'DRIVER NOT FOUND' JMP EXIT ;FINISH I/O 20$: MOV TARDCB,R0 ;POINT AT TARGET DCB MOV U.DCB(R5),R3 ;POINT AT MY DCB MTPS #PR7 ;;;INHIBIT INTERRUPTS MOV D.PCB(R3),D.PCB(R0) ;;;GIVE HIM MY PCB ADDRESS MOV #TARTBL,D.DSP(R0) ;;;GIVE HIM MY DDT ADDRESS MOV TARDDT,D.DDT(R3) ;;;WHERE TO GO WHEN I'M DONE ;;;CALCULATE ADDRESS OFFSET FOR D.APR MOV #KISAR5,R2 ;;;GET APR5 ADDRESS SUB R3,R2 ;;;SUBTRACT DCB ADDRESS SUB #D.APR+2,R2 ;;;SUBTRACT OFFSET TO NEXT WORD AFTER D.APR MOV R2,D.APR(R3) ;;;INSERT THE ADDRESS OFFSET MTPS #PR0 ;ALLOW INTERRUPTS AGAIN MOV #IS.SUC,R0 ;RETURN SUCCESS EXIT: CLR R1 ; EXIT1: CALL $IODON ;FINISH I/O BR QTINI ;LOOK FOR MORE WORK .PAGE ; END THE PROCESS BY RESTORING THE LOCATIONS WHICH WERE CHANGED IN ; THE TARGET DCB. ALSO CLEAR 'DSPTCB' SO THAT THE NEXT TASK CAN USE IT. DONE: MTPS #PR7 ;;;DISABLE INTERRUPTS MOV TARDCB,R0 ;;;POINT AT TARGET DCB MOV TARPCB,D.PCB(R0) ;;;RESTORE THE PCB POINTER MOV TARDDT,D.DSP(R0) ;;;RESTORE THE DDT POINTER MTPS #PR0 ;ENABLE INTERRUPTS AGAIN CLR DSPTCB ;ALLOW NEXT STARTUP CALL MOV #IS.SUC,R0 ;SHOW SUCCESS JMP EXIT ;FINISH I/O .PAGE .SBTTL FIND THE TARGET DRIVER DATA BASE FIND: MOV #$DEVHD,R0 ;GET DEVICE LISTHEAD 10$: MOV (R0),R0 ;GET NEXT DEVICE BNE 30$ ;BRANCH IF NOT END OF LIST 20$: SEC ;MARK FAILURE RETURN ; 30$: CMP TARNAM,D.NAM(R0) ;LOOK FOR NAME MATCH BNE 10$ ;BRANCH IF NONE CMPB TARNUM,D.UNIT(R0) ;MAKE SURE THE UNIT NUMBER IS IN RANGE BLT 10$ ;BRANCH IF LOW CMPB TARNUM,D.UNIT+1(R0) ; BGT 10$ ;BRANCH IF HIGH MOV R0,TARDCB ;SAVE TARGET DCB ADDRESS MOV D.DSP(R0),TARDDT ;SAVE TARGET DRIVER DISPATCH TABLE POINTER MOV D.PCB(R0),TARPCB ;SAVE TARGET PCB POINTER ; FIND TARGET UCB AND SCB MOV D.UCBL(R0),R2 ;GET UCB LENGTH MOV TARNUM,R3 ;GET UNIT NUMBER MOVB D.UNIT(R0),R4 ;GET LOW UNIT NUMBER SUB R4,R3 ;CORRECT THE UNIT NUMBER CLR R4 ; TST R3 ;SPECIAL CASE UNIT 0 BEQ 50$ ;BRANCH IF UNIT 0 40$: ADD R2,R4 ;BUMP BY UCB LENGTH SOB R3,40$ ;LOOP TILL DONE 50$: ADD D.UCB(R0),R4 ;ADD UNIT 0 UCB ADDRESS MOV R4,TARUCB ;SAVE UCB ADDRESS MOV U.SCB(R4),TARSCB ;SAVE I/O PACKET LISTHEAD CLC ;TELL THEM 'OK' RETURN ; .PAGE .SBTTL PHONEY DRIVER ROUTINES ; THE FOLLOWING CODE IS USED WHENEVER A QIO IS TO BE PROCESSED BY ; THE TARGET DRIVER AND CONTROL IS VECTORED HERE. ; CANCEL ENTRY POINT TARCAN: MOV #2,-(SP) ;OFFSET IS 2 BR LEAVE ; ; TIMEOUT ENTRY POINT TAROUT: MOV #4,-(SP) ;OFFSET IS 4 BR LEAVE ; ; POWERFAIL ENTRY POINT TARPWF: MOV #6,-(SP) ;OFFSET IS 6 ; ALL 4 ENTRY POINTS RETURN HERE LEAVE: MOV TARPCB,-(SP) ;TARGET DRIVER'S PCB MOV CNTBL,R0 ;POINT AT OUR UCB MOV (R0),R0 ;PONT AT OUR DCB JMP D.COD(R0) ;JUMP TO CODE IN OUR DCB .PAGE ; INITIATOR ENTRY POINT TARINI: CMP R5,TARUCB ;IS IT THE CORRECT UNIT? BEQ 10$ ;BRANCH IF YES 5$: CLR -(SP) ;OFFSET IS 0 BR LEAVE ;NOTHING TO DO - WRONG UNIT 10$: MOV R1,-(SP) ;SAVE THE REGISTERS MOV R2,-(SP) ; MOV R3,-(SP) ; MOV R4,-(SP) ; MOV R5,-(SP) ; ; TEST FOR BLOCKING BITS IN CALLING TASK. ; RESTORE TARGET TASK POINTERS IS ANY SET. MOV DSPTCB,R0 ;POINT AT CALLING TCB BIT #TS.BLK,T.STAT(R0) ;ANY BLOCKING BITS SET? BEQ 15$ ;BRANCH IF NONE MOV TARDCB,R0 ;POINT AT TARGET DCB MTPS #PR7 ;;;INHIBIT INTERRUPTS MOV TARDDT,D.DSP(R0) ;;;RESTORE ORIGINAL DDT POINTER MOV TARPCB,D.PCB(R0) ;;;RESTORE ORIGINAL PCB POINTER CLR DSPTCB ;;; ALLOW NEW COMMAND MTPS #PR0 ;ALLOW INTERRUPTS AGAIN BR 30$ ;LEAVE 15$: MOV TARUCB,R5 ;GET TARGET UCB ADDRESS BITB #UC.QUE,U.CTL(R5) ;TEST IF DRIVER WAS CALLED BEFORE QUEUEING BNE 25$ ;BRANCH IF YES MOV TARSCB,R4 ;POINT AT TARGET DRIVER'S I/O LISTHEAD 20$: MOV (R4),R4 ;GET NEXT I/O PACKET ADDRESS BEQ 30$ ;BRANCH WHEN NO MORE PACKETS CALL CPYPKT ;COPY AND QUEUE ANOTHER PACKET TO THE DISPLAY ; TASK. BR 20$ ;BRANCH TILL DONE ; UC.QUE IS SET SO TAKE PACKET FROM R1 25$: MOV R1,R4 ;GET PACKET ADDRSS INTO R4 CALL CPYPKT ;COPY AND QUEUE PACKET TO CALLING TASK 30$: MOV (SP)+,R5 ;RESTORE THE REGISTERS MOV (SP)+,R4 ; MOV (SP)+,R3 ; MOV (SP)+,R2 ; MOV (SP)+,R1 ; BR 5$ ;RETURN CONTROL TO TARGET DRIVER .PAGE ; CPYPKT - THIS ROUTINE ALLOCATES A PACKET, FILLS IT AS A SEND PACKET ; FROM SELECTED FIELDS OF THE PACKET FROM THE TARGET DRIVER AND QUEUES ; IT TO THE RECEIVE QUEUE OF THE DISPLAY TASK. ; ; ENTRY R4 = TARGET TASK PACKET ADDRESS ; ; EXIT THE SEND PACKET IS QUEUED ; CPYPKT: MOV R4,R5 ;SAVE THE PACKET ADDRESS CALL $ALPKT ;ALLOCATE A SECOND PACKET MOV R0,-(SP) ;SAVE THE NEW PACKET ADDRESS CLR (R0)+ ;ZERO THE FIRST WORD MOV DSPTCB,R2 ;POINT AT THE DISPLAY TASK'S TCB MOV T.NAM(R2),(R0)+ ;INSERT DISPLAY TASK'S NAME MOV T.NAM+2(R2),(R0)+ ; MOV I.TCB(R5),R1 ;GET TCB OF TARGET TASK MOV T.NAM(R1),(R0)+ ;INSERT TASK NAME MOV T.NAM+2(R1),(R0)+ ; MOV I.FCN(R5),(R0)+ ;SAVE FUNCTION CODE MOV I.PRM(R5),(R0)+ ;SAVE THE EIGHT PARAMETERS MOV I.PRM+2(R5),(R0)+ ; MOV I.PRM+4(R5),(R0)+ ; MOV I.PRM+6(R5),(R0)+ ; MOV I.PRM+10(R5),(R0)+; MOV I.PRM+12(R5),(R0)+; MOV I.PRM+14(R5),(R0)+; MOV I.PRM+16(R5),(R0)+; MOV (SP)+,R1 ;RESTORE ADDRESS OF NEW PACKET MOV DSPTCB,R0 ;POINT AT DISPLAY TCB ADD #T.RCVL,R0 ;POINT AT RECEIVE LIST CALL $QINSF ;QUEUE THE PACKET FIFO RETURN .END