.TITLE SRDRV ; ; ; SEND/RECEIVE DRIVER FOR RSX-11M ; ; .IDENT /01.1/ ; ; ; JOE SVENTEK ; COMPUTER SCIENCE AND APPLIED MATHEMATICS ; LAWRENCE BERKELEY LABORATORY ; BERKELEY, CA 94720 ; ; 15-AUG-80 ; ; 01.01 2-JUN-84 USE DDT$ MACRO SO DRIVER WILL WORK WITH RSX-11M-PLUS ; TONY SCANDORA ; ELECTRONICS DEPARTMENT, D205 ; ARGONNE NATIONAL LABORATORY ; ARGONNE, IL 60439 ; ; ; THIS DRIVER IMPLEMENTS A VARIABLE LENGTH SEND/RECEIVE CAPABILITY FOR ; RSX-11M. PACKETS ARE QUEUED IN INTERNAL BUFFERS FOR A TASK WHICH ; NEED NOT BE INSTALLED. A TIMEOUT IS ASSOCIATED WITH EACH MESSAGE, ; AND THE BUFFERS ARE RECYCLED IF THE TIME EXPIRES BEFORE THE MESSAGE ; IS READ. ; ; MACRO LIBRARY CALLS ; .MCALL PKTDF$,CLKDF$,TCBDF$,UCBDF$,QIOSY$ PKTDF$ ; DEFINE I/O PACKET OFFSETS CLKDF$ ; DEFINE CLOCK QUEUE BLOCK OFFSETS TCBDF$ ; DEFINE TASK CONTROL BLOCK OFFSETS UCBDF$ ; DEFINE UNIT CONTROL BLOCK OFFSETS QIOSY$ ; DEFINE QIO SYMBOLS LOCALLY .PAGE .SBTTL LOCAL SYMBOLS ; ; ; LOCAL SYMBOLS ; ; ; OFFSETS FOR HEADER BLOCKS ; .ASECT .=0 H$FLNK: .BLKW 1 ; FORWARD LINK H$BLNK: .BLKW 1 ; BACKWARD LINK H$STSK: .BLKW 2 ; SENDER TASK NAME (RAD50) H$RTSK: .BLKW 2 ; RECEIVER TASK NAME (RAD50) H$SIZE: .BLKW 1 ; SIZE OF MESSAGE IN BYTES H$TIME: .BLKW 1 ; SECONDS UNTIL PURGE OF MESSAGE H$BUFP: .BLKW 1 ; POINTER TO FIRST CHAINED DATA BUFFER H$LGTH=.-2 ; LENGTH OF BLOCK MINUS FLINK WORD .PSECT ; ; ; LOCAL OFFSET DEFINITION FOR CLOCK QUEUE BLOCK ; C.UCB=C.AR5+2 ; UCB ADDRESS OF SR: STORED HERE ; THIS WORD UNUSED IN CLOCK BLOCK C.CQID=C.TCB ; FIELD FOR CQID ; ; ; LOCAL OFFSET DEFINITIONS FOR U.CW2 AND U.CW3 IN UCB ; U.HDRF=U.CW2 ; POINTS TO MOST RECENTLY INSERTED HDR U.HDRB=U.CW3 ; POINTS TO LEAST RECENTLY INSERTED HDR ; ; ; LOCAL OFFSET DEFINITIONS FOR I/O REQUEST PACKET ; I.P1=I.PRM ; P1 I.P2=I.PRM+4 ; P2 I.P3=I.P2+2 ; P3 I.P4=I.P3+2 ; P4 I.P5=I.P4+2 ; P5 I.P6=I.P5+2 ; P6 ; ; ; DEFINITIONS FOR TIMER PROCESSING (ALL IN UNITS OF SECONDS) ; TDEFLT=30. ; DEFAULT TIMEOUT PERIOD FOR A PACKET TLOW=2*TINTPT ; MINIMUM TIMEOUT PERIOD THIGH=10.*60. ; MAXIMUM TIMEOUT PERIOD (10 MINUTES) .PAGE .SBTTL LOCAL MACROS ; ; ; LOCAL MACROS ; ; ; JCS - JUMP ON C BIT SET ; .MACRO JCS DEST,?LAB BCC LAB JMP DEST LAB: .ENDM JCS ; ; JEQ - JUMP ON EQUAL (Z BIT SET) ; .MACRO JEQ DEST,?LAB BNE LAB JMP DEST LAB: .ENDM JEQ ; ; PUSH - PUSH REGISTER ONTO STACK ; .MACRO PUSH REG MOV REG,-(SP) .ENDM PUSH ; ; ; POP - POP REGISTER FROM STACK ; .MACRO POP REG MOV (SP)+,REG .ENDM POP ; ; PUTNOD - PUT A NODE BACK ONTO FREE LIST ; .MACRO PUTNOD REG,LISTHD MOV LISTHD,('REG') MOV REG,LISTHD .ENDM PUTNOD ; ; ERROR - PLACE RETURN CODE IN R0 AND FINISH IO ; .MACRO ERROR REASON MOV #IE.'REASON'&377,R0 CALLR ZRFIN .ENDM ERROR .PAGE .SBTTL LOCAL DATA AND DISPATCH TABLE ; ; ; LOCAL DATA (EXCEPT FOR HEADERS AND BUFFERS, WHICH FOLLOW DRIVER CODE) ; ; HDRPT: .WORD HDR0 ; FREE LIST LISTHEAD FOR MSG HEADERS BUFPT: .WORD BUF0 ; FREE LIST LISTHEAD FOR BUFFERS ; ; ; DRIVER DISPATCH TABLE ; ; DDT$ SR,1 $SRINT = 0 $SRCTB = 0 .PAGE .SBTTL SRINI - INITIATE IO FOR SEND/RECEIVE DEVICE ;+ ; SRINI - SEND/RECEIVE DRIVER INITIATOR ; ; THIS ROUTINE IS ENTERED FROM DRQIO WHEN AN IO REQUEST IS QUEUED ; ; ALL OPERATIONS ARE HANDLED AT QUEUE LEVEL ; ; INPUTS ; R1 IRP OF REQUEST ; R5 UCB OF CONTROLLER ; ; OUTPUTS ; IF REQUEST IS A WRITE, MESSAGE IS QUEUED, IF BUFFER ; SPACE IS AVAILABLE ; ; IF REQUEST IS A READ, THE NEXT MESSAGE BUFFERED FOR THE ; REQUESTING TASK IS DEQUEUED ; ; FORMAT OF IRP FOR SEND/RECEIVE DRIVER ; ; WD 00 IO QUEUE THREAD WORD ; WD 01 REQUEST PRIORITY, EVENT FLAG NUMBER ; WD 02 TCB ADDRESS OF REQUESTOR ; WD 03 POINTER TO SECOND LUN WORD IN TASK HEADER ; WD 04 CONTENTS OF FIRST LUN WORD IN TASK HEADER ; WD 05 IO FUNCTION CODE (IO.RLB, IO.WLB) ; WD 06 VIRTUAL ADDRESS OF IO STATUS BLOCK ; WD 07 RELOCATION BIAS OF IO STATUS BLOCK ; WD 10 IO STATUS BLOCK ADDRESS (REAL OR DISPLACEMENT + 140000) ; WD 11 VIRTUAL ADDRESS OF AST SERVICE ROUTINE ; WD 12 RELOCATION BIAS OF IO BUFFER ; WD 13 BUFFER ADDRESS (REAL OR DISPLACEMENT + 140000) ; WD 14 NUMBER OF BYTES TO TRANSFER OR SIZE OF BUFFER ; WD 15 HIGH ORDER HALF OF RECEIVER TASK NAME (WLB) ; WD 16 LOW ORDER HALF (WLB) ; WD 17 TIME OUT PERIOD IN SECONDS (WLB) ; WD 20 IF NON-ZERO, ALL PACKETS QUEUED FOR THIS SENDER/RECEIVER ; PAIR ARE FLUSHED BEFORE THE CURRENT MESSAGE IS QUEUED ; WD 21 UNUSED ; ;- .ENABL LSB SRINI: MOV KISAR6,-(SP) ; SAVE CURRENT APR6 MAPPING MOV R1,R3 ; PLACE IRP IN R3 FOR DURATION MOV I.TCB(R3),R4 ; PLACE TCB ADDRESS FOR DURATION MOV I.P2(R3),U.CNT(R5) ; PLACE BYTE COUNT IN UCB MOVB I.FCN+1(R3),R0 ; FETCH FUNCTION CODE CMPB R0,#IO.WLB/256. ; WRITE LOGICAL BLOCK? JEQ WRITE ; YES, GO DO IT CMPB R0,#IO.RLB/256. ; READ LOGICAL BLOCK? JEQ READ ; YES, GO DO IT CMPB R0,#IO.STP/256. ; STOP TIMER? JEQ STOP ; YES, GO DO IT MOV #IE.IFC&377,R0 ; ILLEGAL FUNCTION CODE ZRFIN: CLR R1 ; IOSB(2) = 0 ON ERRORS SRFIN: MOV (SP)+,KISAR6 ; RESTORE MAPPING CALLR $IOFIN ; FINISH UP .DSABL LSB .PAGE .SBTTL PROCESS WRITE REQUESTS ;+ ; THIS ROUTINE ALOCATES A HEADER AND THE NECESSARY BUFFERS. ; IF ALL ARE SUCCESSFUL, THE USER'S DATA IS THEN ; COPIED INTO THE DRIVER BUFFERS, THE HEADER IS LINKED INTO THE UCB'S ; QUEUE. ; ; INPUTS ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ;- .ENABL LSB WRITE: TST I.P3(R3) ; SEE IF USER SUPPLIED NAME BNE 10$ ; IF !=, YES TST I.P4(R3) ; CHECK IF SECOND HALF IS NON-ZERO BNE 10$ ; IF !=, YES ERROR BAD ; BAD PARAMETERS 10$: TST I.P6(R3) ; FLUSH OLD MESSAGES? BEQ 20$ ; IF == 0, NO CALL MFLUSH ; FLUSH THEM 20$: MOV #HDRPT,R1 ; HEADER FREE LISTHEAD IN R1 CALL GETPKT ; GET A HEADER INTO R0 JCS HDRERR ; C SET => NO MORE HEADERS MOV R0,R2 ; NEED HEADER ADDRESS IN R2 MOV I.P2(R3),H$SIZE(R2) ; COPY MESSAGE SIZE INTO HEADER CALL GETBUF ; ALLOCATE BUFFERS FOR MESSAGE JCS BUFERR ; C SET => NO ROOM TO BUFFER MESSAGE MOV I.P3(R3),H$RTSK(R2) ; COPY RECEIVER TASKNAME INTO HEADER MOV I.P4(R3),H$RTSK+2(R2) MOV T.NAM(R4),H$STSK(R2) ; COPY SENDER TASKNAME INTO HEADER MOV T.NAM+2(R4),H$STSK+2(R2); CALL USRSYS ; COPY USER'S DATA INTO BUFFERS MOV I.P5(R3),R0 ; GET USER SUPPLIED TIMEOUT BNE 100$ ; IF !=, GOT ONE MOV #TDEFLT,R0 ; DEFAULT TIME LIMIT IN R0 100$: ; SEE IF TOO LARGE CMP R0,#THIGH BLE 110$ MOV #THIGH,R0 110$: ; SEE IF TOO SMALL CMP R0,#TLOW BGE 120$ MOV #TLOW,R0 120$: ; JUST RIGHT MOV R0,H$TIME(R2) ; STORE TIME LIMIT IN HEADER CALL INSHDR ; INSERT HEADER INTO UCB QUEUE MOV #IS.SUC&377,R0 ; SUCCESS RETURN MOV I.P2(R3),R1 ; RETURN BYTE COUNT CALLR SRFIN ; FINISH UP BUFERR: PUTNOD R2,HDRPT ; RETURN HEADER TO FREE LIST ERROR ALC ; BUFFERS EXHAUSTED HDRERR: ERROR NOD ; HEADERS EXHAUSTED .DSABL LSB .PAGE .SBTTL PROCESS READ REQUESTS ;+ ; SCAN THROUGH HEADER LIST FOR OLDEST PACKET MATCHING THE ; TASKNAME OF THE REQUESTOR. IF FOUND, COPY THE BUFFER TO THE USER'S ; BUFFER AND RECYCLE THE HEADER AND DRIVER BUFFERS ; ; INPUTS ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ;- .ENABL LSB READ: MOV U.HDRB(R5),R2 ; OLDEST HEADER BLOCK IN R2 10$: BEQ 50$ ; LAST MOVE == 0, NO MATCH CMP T.NAM(R4),H$RTSK(R2) ; COMPARE FIRST HALF OF TASK NAME BNE 20$ ; IF !=, TRY NEXT HEADER IN LIST CMP T.NAM+2(R4),H$RTSK+2(R2); COMPARE SECOND HALF OF TASK NAME BEQ 30$ ; IF ==, COPY MESSAGE 20$: MOV H$BLNK(R2),R2 ; GET NEXT HEADER BR 10$ ; TRY AGAIN 30$: CALL SYSUSR ; COPY TO USER'S BUFFER CALL PUTBUF ; RETURN BUFFERS TO FREE LIST CALL REMHDR ; REMOVE HEADER FROM UCB LIST PUTNOD R2,HDRPT ; RETURN HEADER TO FREE LIST MOV #IS.SUC&377,R0 ; RETURN SUCCESS STATUS MOV H$SIZE(R2),R1 ; BYTES COPIED CMP R1,I.P2(R3) ; SEE IF DATA OVERRUN BLE 40$ ; IF <=, NO MOV #IE.DAO&377,R0 ; RETURN DATA OVERRUN STATUS MOV I.P2(R3),R1 ; ONLY COPIED USERSIZE BYTES 40$: CALLR SRFIN ; DONE WITH REQUEST 50$: ERROR DNA ; DATA NOT AVAILABLE .DSABL LSB .PAGE .SBTTL STOP - STOP TIMER ;+ ; THIS ROUTINE, CALLED WHEN A TASK ISSUES A QIO WITH A FUNCTION ; CODE OF IO.STP, CANCELS THE CURRENT TIMER REQUEST FOR THE DRIVER. ; IT CHECKS THAT THE TERMINAL FOR WHICH THE CALLING TASK ; IS RUNNING IS PRIVELEGED. IF SO, IT PROCEEDS TO CANCEL THE TIMER. ; ; INPUTS: ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; ; OUTPUTS: ; THE CLOCK QUEUE ENTRY FOR THE DRIVER IS CANCELED AND ; THE CLOCK QUEUE CONTROL BLOCK IS RETURNED TO THE DSR ;- .ENABL LSB STOP: MOV T.UCB(R4),R0 ; GET TI: UCB ADDRESS BIT #U2.PRV,U.CW2(R0) ; SEE IF TTY IS PRIVELEGED BNE 10$ ; IF !=, YES - PROCEED ERROR PRI ; PRIVELEGE VIOLATION 10$: MOV U.CLQB(R5),R0 ; PLACE CLOCK BLOCK ADDR IN R0 BEQ 20$ ; IF == 0, TIMER NOT ACTIVE PUSH R3 ; SAVE R3 PUSH R5 ; SAVE R5 MOV #C.SYST,R4 ; CLOCK QUEUE REQUEST TYPE MOV R0,R5 ; CLOCK QUEUE ID IS BLOCK ADDRESS CALL $CLRSM ; REMOVE ENTRY FROM CLOCK QUEUE POP R5 ; RESTORE UCB ADDRESS MOV U.CLQB(R5),R0 ; ADDRESS OF BLOCK TO RETURN MOV #C.LGTH,R1 ; SIZE OF BLOCK CALL $DEACB ; RETURN BLOCK TO DSR CLR U.CLQB(R5) ; TIMER NO LONGER ACTIVE POP R3 ; RESTORE IRP ADDRESS 20$: MOV #IS.SUC&377,R0 ; RETURN SUCCESS STATUS CALLR ZRFIN ; FINISH UP .DSABL LSB .PAGE .SBTTL SRPWF - POWERFAIL ENTRY POINT ;+ ; THIS ROUTINE IS CALLED WHEN THE SYSTEM IS BOOTED, UPON RESTORATION ; OF POWER, AND WHEN THE DRIVER IS LOADED, SINCE THE UC.PWF BIT ; IS SET IN THE U.CTL FIELD OF THE UCB ; ; THIS ROUTINE ALLOCATES A CLOCK QUEUE CONTROL BLOCK FROM POOL ; IT THEN FILLS IT IN AND QUEUES IT ; THE INTERRUPT SERVICE ROUTINE PROPAGATES THIS INTERRUPT. ; ; IF THE BLOCK CANNOT BE ALLOCATED FROM POOL, THE DRIVER INDICATES ; THAT THE DEVICE IS OFFLINE BY SETTING THE BIT IN THE U.ST2 FIELD ; OF THE UCB AND HAVING TKTN ISSUE A DEVICE NOT READY MESSAGE ON ; THE CONSOLE. ; ; INPUTS: ; R3 CONTROLLER INDEX ; R4 SCB ADDRESS ; R5 UCB ADDRESS ; ; OUTPUTS: ; 1. THE DELTA TIME FOR EACH CLOCK INTERRUPT IS CALCULATED AND ; STORED IN THE UCB ; 2. THE ADDRESS OF THE ALLOCATED CLOCK BLOCK IS STORED IN THE UCB ; 3. A CLOCK INTERRUPT IS QUEUED FOR THE DRIVER ; ;- .ENABL LSB SRPWF: TST U.CLQB(R5) ; SEE IF TIMER ALREADY ACTIVE BNE 20$ ; IF !=, YES PUSH R0 ; SAVE ALL REGISTERS PUSH R1 PUSH R2 PUSH R3 PUSH R4 PUSH R5 MOV #TINTPT,R0 ; SECONDS BETWEEN CLOCK INTERRUPTS MOV $TKPS,R1 ; CLOCK TICKS/SECOND CALL $MUL ; DOUBLE WORD DELTA TIME IN R0,R1 MOV R0,U.TIM1(R5) ; SAVE IN UCB MOV R1,U.TIM2(R5) MOV #C.LGTH,R1 ; SIZE OF CLOCK QUEUE CORE BLOCK CALL $ALOCB ; ALLOCATE FROM POOL BCS CLKERR ; C SET => ALLOCATION FAILURE MOV R0,U.CLQB(R5) ; SAVE ADDRESS OF CLOCK BLOCK MOV R5,C.UCB(R0) ; SAVE UCB ADDR IN CLOCK BLOCK MOV #TIMER,C.SUB(R0) ; ADDRESS OF INTERRUPT SERVICE RTN MOV U.TIM1(R5),R1 ; DELTA TIME FOR $CLINS MOV U.TIM2(R5),R2 MOV #C.SYST,R4 ; CLOCK QUEUE REQUEST TYPE MOV R0,R5 ; CLOCK QUEUE ID IS BLOCK ADDRESS CALL $CLINS ; INSERT INTO CLOCK QUEUE BR 10$ CLKERR: BISB #US.OFL,U.ST2(R5) ; SET DEVICE OFFLINE MOV #T.NDNR,R0 ; ISSUE A DEVICE NOT READY CALL $DVMSG ; TO CONSOLE VIA TKTN 10$: POP R5 ; RESTORE REGISTERS POP R4 POP R3 POP R2 POP R1 POP R0 20$: RETURN .DSABL LSB .PAGE .SBTTL NOOP - CANCEL IO AND TIMEOUT ENTRY POINTS ;+ ; BOTH OF THESE ENTRY POINTS CORRESPOND TO A RETURN TO THE ; EXECUTIVE. ;- SRCAN: SROUT: RETURN .PAGE .SBTTL TIMER - PROCESS CLOCK QUEUE INTERRUPTS ;+ ; THIS ROUTINE IS ENTERED WHEN THE DRIVER'S CLOCK QUEUE ENTRY COMES ; DUE. IT TRAVERSES THE LIST OF MESSAGES, DECREMENTING THE TIMEOUT ; FIELD IN THE MESSAGE HEADERS. IF THE TIMEOUT FIELD DROPS BELOW 0, ; THE HEADER AND MESSAGE BUFFERS ARE RECYCLED. ANOTHER CLOCK QUEUE ; REQUEST IS THEN MADE, THUS PROPAGATING THIS SELF-CLEANSING PROCESS. ; ; INPUTS ; R4 ADDRESS OF CLOCK QUEUE CORE BLOCK ; ; OUTPUTS ; IF MATCHING HEADER IS FOUND, THAT MESSAGE IS PURGED FROM LIST ; ANOTHER CLOCK QUEUE REQUEST IS MADE ;- .ENABL LSB TIMER: PUSH R0 ; THIS REGISTER MANIPULATION IS PUSH R1 ; DONE TO PERMIT TIMER TO CALL PUSH R2 ; PUTBUF AND REMHDR, WHICH CONFORM PUSH R3 ; TO THE INTERNAL REGISTER STANDARD PUSH R4 ; OF THE DRIVER PUSH R5 MOV C.UCB(R4),R5 ; PLACE UCB ADDRESS IN R5 MOV U.HDRF(R5),R3 ; GET FIRST HEADER ADDRESS IN R3 10$: MOV R3,R2 ; GET NEXT HEADER ADDRESS BEQ 20$ ; IF LAST MOVE == 0, DONE SCANNING MOV H$FLNK(R2),R3 ; PLACE NEXT HEADER ADDR IN R3 SUB #TINTPT,H$TIME(R2) ; SUBTRACT NO OF SECONDS FROM LIMIT BGT 10$ ; IF > 0, TRY NEXT PACKET CALL PUTBUF ; RETURN BUFFERS CALL REMHDR ; REMOVE HEADER FROM QUEUE PUTNOD R2,HDRPT ; RETURN HEADER TO FREE LIST BR 10$ 20$: MOV U.CLQB(R5),R0 ; CLOCK BLOCK IN R0 MOV U.TIM1(R5),R1 ; DELTA TIME IN R1-R2 MOV U.TIM2(R5),R2 MOV #C.SYST,R4 ; REQUEST TYPE MOV R0,R5 ; CLOCK QUEUE ID IS ADDRESS OF BLOCK CALL $CLINS ; INSERT INTO CLOCK QUEUE POP R5 ; RESTORE REGISTERS POP R4 POP R3 POP R2 POP R1 POP R0 RETURN .DSABL LSB .PAGE .SBTTL MFLUSH - FLUSH OLD MESSAGES ;+ ; THIS ROUTINE TRAVERSES THE LIST OF MESSAGES, PURGING ANY MATCHING ; THE CURRENT SENDER-RECEIVER TASK PAIR. THE RECEIVER NAME IS IN THE ; I/O REQUEST PACKET, AND THE SENDER NAME IS IN THE TCB ; ; INPUTS ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; ; OUTPUTS ; OLD MESSAGES MATCHING THE CURRENT TASK PAIR ARE PURGED ;- .ENABL LSB MFLUSH: MOV U.HDRF(R5),R1 ; FIRST HEADER ADDRESS IN R1 10$: MOV R1,R2 ; NEXT HEADER ADDRESS IN R2 BEQ 20$ ; IF == 0, DONE SCANNING LIST MOV H$FLNK(R2),R1 ; NEXT HEADER ADDRESS IN R1 CMP I.P3(R3),H$RTSK(R2) ; FIRST HALF OF RCVR TASK? BNE 10$ ; NO, TRY NEXT MESSAGE CMP I.P4(R3),H$RTSK+2(R2) ; SECOND HALF OF RCVR TASK? BNE 10$ ; NO, TRY NEXT MESSAGE CMP T.NAM(R4),H$STSK(R2) ; FIRST HALF OF SENDER TASK? BNE 10$ ; NO, TRY NEXT MESSAGE CMP T.NAM+2(R4),H$STSK+2(R2); SECOND HALF OF SENDER TASK? BNE 10$ ; NO, TRY NEXT MESSAGE PUSH R1 ; SAVE VOLATILE REGISTER CALL PUTBUF ; RETURN MESSAGE BUFFERS CALL REMHDR ; REMOVE HEADER FROM LIST PUTNOD R2,HDRPT ; RETURN HEADER TO FREE LIST POP R1 ; RESTORE R1 BR 10$ ; TRY NEXT MESSAGE 20$: RETURN .DSABL LSB .PAGE .SBTTL GETBUF - GET BUFFERS NECESSARY TO STORE MESSAGE ;+ ; INPUTS: ; R2 HEADER BLOCK ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; R0,R1 FREE FOR USE ; ; OUTPUTS: ; C SET INSUFFICIENT BUFFER SPACE ; C CLEAR BUFFERS WERE ALLOCATED. H$BUFP HAS ADDRESS OF FIRST ;- .ENABL LSB GETBUF: PUSH R3 ; SAVE REGISTERS USED PUSH R4 MOV H$SIZE(R2),R0 ; GET NUMBER OF BYTES NEEDED CMP R0,U.CW4(R5) ; SEE IF WITHIN LIMITS BGT ERROUT ; TOO BIG, RETURN DEC R0 ; ((N-1)/B)+1 MOV #BUFSIZ,R1 ; DIVISOR IN R1 CALL $DIV ; DIVIDE R0 BY R1, QUOTIENT IN R0 INC R0 ; R0 = NUMBER OF BUFS NEEDED (>=1) MOV R0,R3 ; SAVE THIS NUMBER MOV #BUFPT,R1 ; BUFFER LISTHEAD 10$: MOV (R1),R1 ; GET NEXT BUFFER ADDRESS BEQ ERROUT ; IF == 0, NOT ENOUGH BUFFERS SOB R0,10$ ; DECREMENT COUNT AND TRY AGAIN ; ; AT THIS POINT, WE ARE ASSURED OF ENOUGH BUFFERS FOR MESSAGE ; MOV #BUFPT,R1 ; LISTHEAD AGAIN CLR R4 ; ADDRESS OF PREVIOUS NODE 20$: CALL GETPKT ; GET NODE ADDRESS IN R0 MOV R4,(R0) ; LINK IN PREVIOUS PACKETS MOV R0,R4 ; SAVE ADDRESS SOB R3,20$ ; DECREMENT COUNT AND TRY AGAIN MOV R4,H$BUFP(R2) ; PLACE FIRST BUF ADDR IN HEADER CLC ; C CLEAR => SUCCESS BR 30$ ERROUT: SEC ; C SET => ALLOCATION FAILURE 30$: POP R4 ; RESTORE REGISTERS - DOESN'T AFFECT C BIT POP R3 RETURN .DSABL LSB .PAGE .SBTTL PUTBUF - RETURN BUFFERS TO FREE LIST ;+ ; PUTBUF RESTORES THE BUFFERS POINTER TO BY THE HEADER BLOCK TO THE ; FREE LIST OF BUFFERS ; ; INPUTS ; R2 HEADER POINTING TO BUFFERS ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; R0,R1 FREE FOR USE ; ; OUTPUTS ; THE BUFFERS ARE RETURNED TO THE FREE LIST OF BUFFERS ;- .ENABL LSB PUTBUF: MOV H$BUFP(R2),R1 ; ADDRESS OF FIRST BUFFER IN R1 10$: MOV R1,R0 ; ADDRESS OF NEXT BUFFER IN R0 BEQ 20$ ; IF == 0, DONE MOV (R0),R1 ; NEXT BUFFER ADDRESS IN R1 PUTNOD R0,BUFPT ; RETURN NODE TO FREE LIST BR 10$ ; DO AGAIN 20$: RETURN .DSABL LSB .PAGE .SBTTL INSHDR - INSERTS HEADER INTO UCB QUEUE ;+ ; THIS ROUTINE INSERTS THE SPECIFIED HEADER INTO THE QUEUE POINTED ; TO BY THE UCB. THE HEADER IS INSERTED ON THE FORWARD LINK SIDE ; OF THE UCB. REFER TO THE DOCUMENTATION ON THE DRIVER FOR THE ; EXACT STRUCTURE OF THE HEADERS AND THE LINKAGES. ; ; INPUTS ; R2 HEADER TO INSERT ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; R0,R1 FREE FOR USE ; ; OUTPUTS ; HEADER IS LINKED INTO UCB QUEUE ;- .ENABL LSB INSHDR: MOV U.HDRF(R5),R0 ; MOST RECENTLY INSERTED HEADER BEQ 10$ ; QUEUE WAS EMPTY MOV R2,H$BLNK(R0) ; MAKE THAT NODE POINT TO THIS ONE CLR H$BLNK(R2) ; NEW NODE HAS NO BACKWARD LINK MOV R0,H$FLNK(R2) ; NEW NODE POINTS TO OLD FIRST NODE MOV R2,U.HDRF(R5) ; UCB QUEUE POINTS TO NEW NODE BR 20$ 10$: MOV R2,U.HDRF(R5) ; INITIALIZE NEW QUEUE MOV R2,U.HDRB(R5) CLR H$FLNK(R2) CLR H$BLNK(R2) 20$: RETURN .DSABL LSB .PAGE .SBTTL REMHDR - REMOVE HEADER FROM UCB QUEUE ;+ ; INPUTS ; R2 HEADER TO REMOVE ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; R0,R1 FREE FOR USE ; ; OUTPUTS ; HEADER IS REMOVED FROM QUEUE AND QUEUE IS RELINKED ;- .ENABL LSB REMHDR: MOV H$FLNK(R2),R0 ; GET FORWARD LINK OF ILL-FATED NODE BEQ 10$ ; IF == 0, THEN END OF LIST MOV H$BLNK(R2),H$BLNK(R0) ; REDO NEIGHBOR'S BLINK BR 20$ 10$: MOV H$BLNK(R2),U.HDRB(R5) ; REDO LISTHEAD'S BLINK 20$: MOV H$BLNK(R2),R0 ; GET BACKWARD LINK OF ILL-FATED NODE BEQ 30$ ; IF == 0, THEN END OF LIST MOV H$FLNK(R2),H$FLNK(R0) ; REDO NEIGHBOR'S FLINK BR 40$ 30$: MOV H$FLNK(R2),U.HDRF(R5) ; REDO LISTHEAD'S FLINK 40$: RETURN .DSABL LSB .PAGE .SBTTL SYSUSR - COPY CONTENTS OF DRIVER BUFFER TO USER ;+ ; THIS ROUTINE COPIES THE CONTENTS OF THE DRIVER BUFFER[S] INTO ; THE USER'S BUFFER. IF THE USER'S BUFFER IS SMALLER THAN THE ; AMOUNT OF DATA BUFFERED, THEN ONLY THAT MANY BYTES ARE COPIED. ; WHEN THIS OCCURS, THE USER RECEIVES THE CODE IE.DAO (DATA ; OVERRUN) IN IOSB(1). ; ; INPUTS: ; R2 HEADER ADDRESS ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; R0,R1 FREE FOR USE ; ; OUTPUTS: ; THE DATA HAS BEEN COPIED INTO THE USER'S BUFFER ;- .ENABL LSB SYSUSR: PUSH R4 ; SAVE REGISTERS PUSH R2 ; ... CMP H$SIZE(R2),U.CNT(R5) ; COMPARE SIZE OF MSG WITH USER'S BUF BGT 10$ ; MSG SIZE TOO BIG, LEAVE U.CNT AS IS MOV H$SIZE(R2),U.CNT(R5) ; ONLY MOVE BYTES 10$: TST U.CNT(R5) ; SEE IF ZERO LENGTH TRANSFER BEQ 30$ ; IF == 0, YES MOV H$BUFP(R2),R4 ; GET FIRST BUFFER ADDRESS MOV I.P1(R3),KISAR6 ; MAP TO USER'S BUFFER MOV I.P1+2(R3),R2 ; KERNEL VIRTUAL ADDRESS BR 25$ ; START COPY 20$: MOVB (R0)+,(R2)+ ; PLACE BYTE IN USER BUFFER DEC U.CNT(R5) ; DECREMENT COUNT BEQ 30$ ; IF == 0, ALL DONE SOB R1,20$ ; DECREMENT BYTES/BUFFER COUNT MOV (R4),R4 ; GET NEXT CHAINED BUFFER BEQ 30$ ; IF == 0, ALL DONE 25$: MOV R4,R0 ; NEED BUFFER ADDRESS IN R0 TST (R0)+ ; BUMP POINTER PAST LINK FIELD MOV #BUFSIZ,R1 ; BYTES/BUFFER COUNTER BR 20$ ; MOVE SOME MORE 30$: POP R2 ; RESTORE REGISTERS POP R4 ; ... RETURN .DSABL LSB .PAGE .SBTTL USRSYS - COPY CONTENTS OF USER BUFFER TO DRIVER ;+ ; THIS ROUTINE COPIES THE CONTENTS OF THE USER'S BUFFER INTO ; THE DRIVER'S INTERNAL BUFFER[S]. ; ; INPUTS: ; R2 HEADER ADDRESS ; R3 IRP ADDRESS ; R4 TCB ADDRESS ; R5 UCB ADDRESS ; R0,R1 FREE FOR USE ; ; OUTPUTS: ; THE CONTENTS OF THE USER'S BUFFER ARE COPIED INTO THE ; DRIVER'S BUFFER[S] ;- .ENABL LSB USRSYS: PUSH R4 ; SAVE REGISTERS PUSH R2 ; ... TST U.CNT(R5) ; SEE IF ZERO LENGTH TRANSFER BEQ 20$ ; IF == 0, YES MOV H$BUFP(R2),R4 ; ADDRESS OF FIRST BUFFER MOV I.P1(R3),KISAR6 ; MAP TO USER'S BUFFER MOV I.P1+2(R3),R2 ; KERNEL VIRTUAL ADDRESS BR 15$ ; START COPY 10$: MOVB (R2)+,(R0)+ ; COPY BYTE INTO DRIVER BUFFER DEC U.CNT(R5) ; DECREMENT COUNT BEQ 20$ ; IF == 0, ALL DONE SOB R1,10$ ; DECREMENT BYTE/BUFFER COUNTER MOV (R4),R4 ; ADDRESS OF NEXT CHAINED BUFFER BEQ 20$ ; IF == 0, ALL DONE 15$: MOV R4,R0 ; NEED ADDRESS IN R0 TST (R0)+ ; BUMP POINTER PAST LINK FIELD MOV #BUFSIZ,R1 ; BYTES/BUFFER BR 10$ ; COPY SOME MORE 20$: POP R2 ; RESTORE REGISTERS POP R4 ; ... RETURN .DSABL LSB .PAGE .SBTTL GETPKT - FETCH A NODE FROM A FREE LIST ;+ ; THIS ROUTINE FETCHES A SINGLE NODE FROM A SINGLY LINKED ; LIST. IT IS ASSUMED THAT THE FORWARD LINK FIELD IN EACH NODE IN THE ; LIST IS CONTAINED AT AN OFFSET OF 0 FROM THE NODE ADDRESS. ; ; INPUTS ; R1 LISTHEAD ADDRESS ; ; OUTPUTS ; R0 NODE FETCHED FROM LIST ; C SET IF NO MORE NODES LEFT ; C CLEAR IF SUCCESSFULLY FETCHED A NODE ;- .ENABL LSB GETPKT: MOV (R1),R0 ; ADDRESS OF NEXT NODE IN R0 BEQ 10$ ; IF == 0, NO MORE NODES MOV (R0),(R1) ; RELINK LIST CLC ; C CLEAR => SUCCESS BR 20$ 10$: SEC ; C SET => ALLOCATION FAILURE 20$: RETURN .DSABL LSB .PAGE .SBTTL FREE LISTS OF HEADERS AND BUFFERS ;+ ; THE FREE LIST OF BUFFERS AND HEADERS FILL UP THE REST OF THE ; DRIVER. ; THE APPROPRIATE CONSTANTS BELOW MAY BE CHANGED IF MORE OR LESS ; OF THESE DATA BLOCKS ARE NEEDED. ;- ; ; ; SYMBOLS ; ; BUFSIZ=32. ; NUMBER OF BYTES OF DATA IN EACH BUFFER AVNBUF=3 ; AVERAGE NUMBER OF BUFFERS PER MSG NBUFS=AVNBUF*NHDRS ; NUMBER OF BUFFERS ; ; ; MACROS FOR BUILDING LINKED LISTS ; ; .MACRO TRMN8R STR,NUM STR'NUM=0 .ENDM TRMN8R .MACRO BLDNOD STR,SIZE,NUM,NXT STR'NUM: .WORD STR'NXT .BLKB SIZE .ENDM BLDNOD ; ; ; BUILD HEADER LIST ; ; TRMN8R HDR,\NHDRS CTR=0 .REPT NHDRS BLDNOD HDR,H$LGTH,\CTR,\ CTR=CTR+1 .ENDR ; ; ; BUILD BUFFER LIST ; ; TRMN8R BUF,\NBUFS CTR=0 .REPT NBUFS BLDNOD BUF,BUFSIZ,\CTR,\ CTR=CTR+1 .ENDR .END