mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
929 lines
33 KiB
Plaintext
929 lines
33 KiB
Plaintext
|
;
|
|||
|
; File: piDDP.a
|
|||
|
;
|
|||
|
; Contains: xxx put contents here xxx
|
|||
|
;
|
|||
|
; Written by: xxx put writers here xxx
|
|||
|
;
|
|||
|
; Copyright: <09> 1992 by Apple Computer, Inc., all rights reserved.
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <SM3> 1/29/93 RB Do not move the SCCLockout value to the status register, always
|
|||
|
; do an ORI.W with it so that NuKernel works and the stack is not
|
|||
|
; changed.
|
|||
|
; <2> 10/13/92 DCL Steve Bollinger (4-2122) 9/24/92
|
|||
|
; Network events don't work anymore, so we always set the packet
|
|||
|
; recvd flag. The caller can just poll this to see when we are
|
|||
|
; done. set the packet recvd flag
|
|||
|
;
|
|||
|
;
|
|||
|
BLANKS ON
|
|||
|
STRING ASIS
|
|||
|
|
|||
|
EJECT
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDP Routines
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Socket Listener
|
|||
|
;
|
|||
|
; This socket listener is called from MPP.
|
|||
|
;
|
|||
|
; Upon entering the socket listener, the LAP header bytes, and the
|
|||
|
; appropriate DDP header bytes have been written into the RHA and the
|
|||
|
; RHA's ptr will point past the last byte in the RHA.
|
|||
|
;
|
|||
|
; A4 and A5 are usable until ReadRest 2(A4) is called. After that,
|
|||
|
; the normal interrupt conventions (A0-A3,D0-D3) apply. D2 is
|
|||
|
; preserved across ReadPacket and ReadRest.
|
|||
|
;
|
|||
|
; The RHA contains enough room for LAP and long DDP headers, plus 8
|
|||
|
; extra bytes. This socket listener moves as many as 4 bytes into the
|
|||
|
; RHA in order to prevent the SCC from overflowing.
|
|||
|
;
|
|||
|
; If the buffer is to small to hold the incoming packet, it will be
|
|||
|
; truncated to fit and a buf2small error will be returned. When this
|
|||
|
; happens, checksums and the RetCksErr flag are ignored, so that even
|
|||
|
; if the caller specified "don't return checksum errors" he could
|
|||
|
; potentially be returned a packet with a checksum error if the buffer
|
|||
|
; was too small.
|
|||
|
;
|
|||
|
; Call:
|
|||
|
; A0,A1 .LONG SCC read/write addresses (preserve)
|
|||
|
; A2 .LONG local vars (preserve)
|
|||
|
; A3 .LONG ptr into the RHA (hdr bytes already loaded in)
|
|||
|
; A4 .LONG address of the ReadPacket routine
|
|||
|
; D0 .BYTE socket number for this read
|
|||
|
; D1 .WORD length still left to read (preserve)
|
|||
|
;
|
|||
|
;
|
|||
|
; Return:
|
|||
|
; D0 .WORD error result
|
|||
|
;
|
|||
|
; Possible errors:
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 8/24/84 Ready for alpha release (GRT)
|
|||
|
; 8/24/84 Checksum routine added (ABO)
|
|||
|
; 10/11/84 Code-crunching and speedup (RFA)
|
|||
|
; 3/15/85 RecoverHandle call added (GRT)
|
|||
|
; 5/1/86 GRT Not using _RecoverHandle anymore
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
tmpOffset EQU 0 ; entry num of the handler we are using
|
|||
|
tmpRHAPtr EQU tmpOffset+2 ; pointer into RHA at end of DDP hdr
|
|||
|
|
|||
|
SocketListener PROC
|
|||
|
MOVEQ #4,D3 ; max number of bytes to read
|
|||
|
CMP D3,D1 ; check to see how many bytes are left
|
|||
|
BHS.S @02 ; if more then just use the 4 bytes
|
|||
|
MOVE D1,D3 ; else its less, so read however many left
|
|||
|
@02 LEA saveArea,A5 ; save A3 because we need it later
|
|||
|
MOVE.L A3,tmpRHAPtr(A5) ; (12) save ptr to RHA
|
|||
|
MOVE D3,D2 ; remember # of bytes & check for zero
|
|||
|
SWAP D2 ; move into upper word for now
|
|||
|
MOVE.B D0,D2 ; save socket number in D2 also
|
|||
|
TST D3 ; how many bytes to read?
|
|||
|
BEQ.S @03 ; if zero, branch around ReadPacket
|
|||
|
JSR (A4) ; read the bytes into the RHA and adjust
|
|||
|
|
|||
|
******************************************************************************
|
|||
|
*** BEGINNING OF MAIN TIME CRITICAL SECTION **********************************
|
|||
|
|
|||
|
BNE.S @08 ; if error, exit
|
|||
|
|
|||
|
; A4 and A5 are restored upon completion of the ReadPacket call.
|
|||
|
; A5 -> ptr to my save area
|
|||
|
|
|||
|
@03 LEA theSocketTable,A3 ; A3 -> my socket table
|
|||
|
MOVEQ #maxSkts-1,D3 ; start at end of list
|
|||
|
@05 CMP.B aSktNum(A3,D3),D2 ; match?
|
|||
|
DBEQ D3,@05 ; no, check next one
|
|||
|
BNE.S @11 ; if not found, goto @11
|
|||
|
|
|||
|
; If we have reached here, we have found the socket entry in our table, and we
|
|||
|
; will now get the buffer ptr stored in the AB record. If a Read call has not
|
|||
|
; been issued, we will throw the packet away.
|
|||
|
|
|||
|
LSL #2,D3 ; get offset into RBPtr field
|
|||
|
MOVE D3,tmpOffset(A5) ; save offset * 4
|
|||
|
MOVE.L aRBPtr(A3,D3),A3 ; get read block ptr
|
|||
|
MOVE.L A3,D0 ; set CCR to see if read buf was NIL
|
|||
|
BEQ.S @11 ; if no read buffer, ignore packet
|
|||
|
|
|||
|
MOVE.L rbABHdl(A3),A3 ; A3 = AB record handle
|
|||
|
MOVE.L (A3),A3 ; deref it
|
|||
|
MOVE ddpReqCount(A3),D3 ; D3 = number of bytes want to read
|
|||
|
MOVE.L ddpDataPtr(A3),A3 ; A3 -> buffer ptr for packet
|
|||
|
SWAP D2 ; restore byte count into low word
|
|||
|
ADD D2,A3 ; modify ptr
|
|||
|
SUB D2,D3 ; D3 = bytes to read - what I've already read
|
|||
|
|
|||
|
JSR 2(A4) ; read in rest of packet
|
|||
|
|
|||
|
*** END OF TIME CRITICAL SECTION **********************************************
|
|||
|
*******************************************************************************
|
|||
|
|
|||
|
BNE.S @08 ; if error, just exit
|
|||
|
BRA.S @12 ; else go on
|
|||
|
|
|||
|
@08 RTS ; short branch exit point
|
|||
|
|
|||
|
; Error exit section - This will exit the socket listener and call MPP (which
|
|||
|
; will read the rest of the packet and ignore it.
|
|||
|
|
|||
|
@11 MOVEQ #0,D3 ; tell MPP we dont want the packet
|
|||
|
JMP 2(A4) ; and call MPP
|
|||
|
|
|||
|
; OK, the packet is now hopefully where it is supposed to be so we can now pass
|
|||
|
; other information back to the user.
|
|||
|
;
|
|||
|
; D3 = number of bytes Read in compared to the number of bytes in the buffer
|
|||
|
; (if D3 < 0 then the users buffer was not big enough, so report an error)
|
|||
|
;
|
|||
|
; Registers D0-D3 and A0-A3 are now usuable
|
|||
|
|
|||
|
@12 TST D3 ; check to see if we overflowed buffer
|
|||
|
BGE.S @13 ; if not then branch
|
|||
|
|
|||
|
MOVE #buf2SmallErr,D0 ; set error code
|
|||
|
|
|||
|
; Copy any bytes I temporarily stored in the RHA back into the user's buffer
|
|||
|
; A0 -> ABRecord, A1 -> save area, A3 -> 1st DDP data byte in RHA
|
|||
|
|
|||
|
@13 MOVE.L A2,-(SP) ; save local var ptr
|
|||
|
LEA saveArea,A1 ; get save area start point
|
|||
|
LEA theSocketTable,A2 ; point to socket table
|
|||
|
MOVE tmpOffset(A1),D1 ; restore table offset
|
|||
|
MOVE.L aRBPtr(A2,D1),A2 ; A2 -> Read Block
|
|||
|
MOVE.L rbABHdl(A2),A0 ; A0 = ABRecord handle
|
|||
|
MOVE.L (A0),A0 ; deref it
|
|||
|
MOVE ddpReqCount(A0),D1 ; get requested number of bytes
|
|||
|
SUB D3,D1 ; get how many we actually read
|
|||
|
MOVE D1,ddpActCount(A0) ; actual bytes read in
|
|||
|
|
|||
|
MOVE.L tmpRHAPtr(A1),A3 ; get saved RHA pointer
|
|||
|
MOVE.L ddpDataPtr(A0),A2 ; A2 -> input data buffer
|
|||
|
|
|||
|
CMP ddpReqCount(A0),D2 ; is buffer big enough to hold 'em?
|
|||
|
BLE.S @15 ; yes, proceed
|
|||
|
MOVE ddpReqCount(A0),D2 ; no, only copy what will fit
|
|||
|
|
|||
|
@15 SUBQ #1,D2 ; dec counter
|
|||
|
BLT.S @17 ; if neg then exit
|
|||
|
MOVE.B 0(A3,D2),0(A2,D2) ; copy RHA bytes into buffer
|
|||
|
BRA.S @15 ; do it again until done
|
|||
|
|
|||
|
; Move any pertinant data to the AB record to send back to the caller.
|
|||
|
; We return the dest node ID to the user to let him know if it was a broadcast
|
|||
|
; or directed. A $FF means broadcast, else it will be this node's ID
|
|||
|
|
|||
|
@17 MOVE.L (SP)+,A2 ; restore A2 MPP local vars
|
|||
|
MOVE D0,abResult(A0) ; set return result code
|
|||
|
CLR.B ddpTypeField-1(A0) ; clear junk byte for Pascal
|
|||
|
MOVE.B DDPType-DDPHSzLong(A3),ddpTypeField(A0) ; ddp type
|
|||
|
MOVE.B DDPSrcSkt-DDPHSzLong(A3),ddpAddrSkt(A0) ; 'from' skt num
|
|||
|
CLR.B ddpNodeID-1(A0) ; clear junk byte for Pascal
|
|||
|
MOVE.B ToRHA+LAPDstAdr(A2),ddpNodeID(A0) ; dest node ID
|
|||
|
|
|||
|
; Set up A1 -> Socket Table, D1 and D2 are offsets into that table
|
|||
|
|
|||
|
MOVE tmpOffset(A1),D2 ; D2 = entry offset in table * 4
|
|||
|
MOVE D2,D1 ; D1 has it too!
|
|||
|
LSR #2,D1 ; get actual offset into socket field
|
|||
|
LEA theSocketTable,A1 ; A1 -> theSocketTable of info
|
|||
|
|
|||
|
CMP.B #shortDDP,ToRHA+LAPType(A2) ; is this a short DDP hdr?
|
|||
|
BNE.S @18 ; branch for long header
|
|||
|
|
|||
|
MOVE.B ToRHA+LAPSrcAdr(A2),ddpAddrID(A0) ; stuff source node ID
|
|||
|
CLR ddpAddrNet(A0) ; clear network number
|
|||
|
MOVE.L aRBPtr(A1,D2),A3 ; get read block ptr
|
|||
|
BRA.S @23 ; all done - go clean up
|
|||
|
|
|||
|
; If DDP long header, we return extended header info in addr blk to user
|
|||
|
|
|||
|
@18 MOVE.B DDPSrcNode-DDPHSzLong(A3),ddpAddrID(A0) ; 'from' xtend hdr ID
|
|||
|
MOVE DDPSrcNet-DDPHSzLong(A3),ddpAddrNet(A0) ; 'from' xtend net ID
|
|||
|
TST DDPChecksum-DDPHSzLong(A3) ; examine checksum in packet
|
|||
|
MOVE.L aRBPtr(A1,D2),A3 ; get read block ptr
|
|||
|
BEQ.S @23 ; if cksum zero, nothing to calculate
|
|||
|
|
|||
|
TST D0 ; any errors so far (buf2small)?
|
|||
|
BNE.S @23 ; if so, forget checksum
|
|||
|
BSR CalcCheckSum ; calculate checksum (D3 = error)
|
|||
|
BEQ.S @23 ; checksums match
|
|||
|
TST.B rbRetCksErr(A3) ; does user want Cksum errs returned?
|
|||
|
BEQ.S @40 ; no, ignore this packet
|
|||
|
MOVE #ckSumErr,abResult(A0) ; else report the error
|
|||
|
|
|||
|
@23 MOVE.L rbABHdl(A3),A0 ; A0 = AB rec handle
|
|||
|
_HUnlock ; unlock the ABRecord handle
|
|||
|
|
|||
|
; Steve Bollinger (4-2122) 9/24/92
|
|||
|
; Network events don't work anymore, so we always set the packet recvd
|
|||
|
; flag. The caller can just poll this to see when we are done.
|
|||
|
; set the packet recvd flag
|
|||
|
|
|||
|
ST aRcvFlag(A1,D1) ; set the pkt recvd flag to true
|
|||
|
|
|||
|
; unlink and unlock read block from the queue (has to be at the beginning)
|
|||
|
; A3 -> read block
|
|||
|
|
|||
|
@30 MOVE.L 0(A3),aRBPtr(A1,D2) ; unlink read blk
|
|||
|
MOVE.L rbHdl(A3),A0 ; A0 = read block handle
|
|||
|
JSR UnlockAndLinkHdl ; dispose of the handle
|
|||
|
@40 RTS
|
|||
|
|
|||
|
EJECT
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; CalcCheckSum
|
|||
|
;
|
|||
|
; Calculate the checksum of the DDP packet. This checksum includes
|
|||
|
; the DDP header bytes (starting from Dst Net field) and the data bytes.
|
|||
|
;
|
|||
|
; Call:
|
|||
|
; A0 -> ABRecord
|
|||
|
; A2 -> MPP variables
|
|||
|
;
|
|||
|
; Return:
|
|||
|
; D3 = 0 if checksum match, non-zero otherwise
|
|||
|
; D1 and A1 are saved/restored, D0 is trashed
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 8/24/84 ABO Ready for alpha release
|
|||
|
; 9/11/84 GRT Saved register A1
|
|||
|
; 10/12/84 RFA Code crunch, saved D1
|
|||
|
; 11/6/84 GRT If checksum calculated to be zero, then set to -1
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
CalcCheckSum MOVEM.L D1/A1,-(SP) ; save registers
|
|||
|
CLR D3 ; start from scratch
|
|||
|
LEA ToRHA+LAPHdSz+DDPDstNet(A2),A1 ; A1 -> Dest Net field
|
|||
|
MOVEQ #DDPHSzLong-DDPDstNet,D1 ; size of DDP header to cksum
|
|||
|
BSR.S DoCheckSum ; Checksum DDP header fields
|
|||
|
|
|||
|
MOVE.L ddpDataPtr(A0),A1 ; A1 -> user data
|
|||
|
MOVE ddpActCount(A0),D1 ; D1 = user data count
|
|||
|
BSR.S DoCheckSum ; Checksum user data
|
|||
|
|
|||
|
TST D3 ; check final result of checksum
|
|||
|
BNE.S @10 ; if not zero then branch
|
|||
|
SUBQ #1,D3 ; however, if it was, then force to -1
|
|||
|
|
|||
|
@10 SUB ToRHA+LAPHdSz+DDPChecksum(A2),D3 ; Subtract off pkt's cksum
|
|||
|
MOVEM.L (SP)+,D1/A1 ; restore registers
|
|||
|
RTS ; D3 zero if all ok, CCR set
|
|||
|
|
|||
|
;_____________________________
|
|||
|
;
|
|||
|
; DoCheckSum - accumulate ongoing checksum
|
|||
|
;
|
|||
|
; Call:
|
|||
|
; D1 = number of bytes to checksum
|
|||
|
; D3 = current checksum
|
|||
|
; A1 -> bytes to checksum
|
|||
|
;
|
|||
|
; Return:
|
|||
|
; Uses D0
|
|||
|
; D3 = accumulated checksum
|
|||
|
;_____________________________
|
|||
|
|
|||
|
DoChecksum CLR D0 ; Clear D0 high byte
|
|||
|
SUBQ #1,D1 ; Decrement count by 1 for DBRA
|
|||
|
@10 MOVE.B (A1)+,D0 ; D0 (word) = next byte
|
|||
|
ADD D0,D3 ; Accumulate checksum
|
|||
|
ROL #1,D3 ; Rotate checksum
|
|||
|
DBRA D1,@10 ; And keep going
|
|||
|
RTS
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; LookUpSkt
|
|||
|
;
|
|||
|
; This routine looks up a socket in my socket table. It is called by
|
|||
|
; both DDPCloseSocket and DDPRead.
|
|||
|
;
|
|||
|
; Entry:
|
|||
|
; D3 = socket number to find in table
|
|||
|
;
|
|||
|
; Exit
|
|||
|
; D1 = offset value in table
|
|||
|
; z-bit set in CCR if found else cleared
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
LookUpSkt PROC
|
|||
|
LEA theSocketTable,A1 ; point to start of socket table
|
|||
|
MOVEQ #maxSkts-1,D1 ; start at end of table
|
|||
|
@10 CMP.B aSktNum(A1,D1),D3 ; check for match
|
|||
|
DBEQ D1,@10 ; found it?
|
|||
|
RTS
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
EJECT
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDPOpenSocket
|
|||
|
;
|
|||
|
; Opens a socket for DDP and optionally installs a socket listener
|
|||
|
; for the requested socket. Socket number 0 means ephemeral. Socket
|
|||
|
; number 1 owned by the RTMP socket listener (automatically attached
|
|||
|
; when MPP initializes.
|
|||
|
;
|
|||
|
; This interface maintains its own socket table, apart from MPP's.
|
|||
|
; This table holds info for all sockets opened by DDPOpenSocket for
|
|||
|
; which the default socket listener was specified.
|
|||
|
;
|
|||
|
; A NIL value in sktListener will automatically install this interfaces
|
|||
|
; built-in socket listener into my socket table.
|
|||
|
;
|
|||
|
; FUNCTION DDPOpenSocket(VAR theSocket : Byte; sktListener : Ptr): INTEGER;
|
|||
|
;
|
|||
|
; Stack upon entry:
|
|||
|
;
|
|||
|
; TOS => .LONG Return address
|
|||
|
; .LONG Pointer to socket listener (see above)
|
|||
|
; .LONG address of the sockets variable
|
|||
|
; .WORD function result code
|
|||
|
;
|
|||
|
; Returns: .WORD Result code
|
|||
|
;
|
|||
|
; Possible errors: No more sockets
|
|||
|
;
|
|||
|
; The IO queue element is allocated on the stack for the control call.
|
|||
|
; This call is made synchronously.
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 8/24/84 GRT Ready for alpha release
|
|||
|
; 10/12/84 RFA Code-crunch
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
DDPOpenSocket PROC EXPORT
|
|||
|
JSR RemoveHdlBlks ; check to see if handles need to be disposed
|
|||
|
MOVE.L (SP)+,D2 ; save return address
|
|||
|
MOVE.L (SP)+,A1 ; get socket listener ptr
|
|||
|
MOVE.L A1,D1 ; set ccr; is it zero??
|
|||
|
BNE.S @10 ; if not then branch and continue
|
|||
|
LEA SocketListener,A1 ; get address of built-in listener
|
|||
|
MOVE.L A1, D1 ; save it away in D1
|
|||
|
@10 MOVE.L (SP)+,A1 ; address of socket variable
|
|||
|
MOVE.L D3,-(SP) ; save D3 register
|
|||
|
MOVE.B 1(A1),D3 ; get socket number
|
|||
|
|
|||
|
SUB #IOQElSize,SP ; allocate space for the IOQEl
|
|||
|
MOVE.L SP,A0 ; A0 -> IO queue element block
|
|||
|
MOVE.B D3,socket(A0) ; socket number
|
|||
|
MOVE.L D1,listener(A0) ; socket listener
|
|||
|
|
|||
|
MOVE #OpenSkt,CSCode(A0) ; code for attach proto hndlr
|
|||
|
MOVE #MPPRefNum,IORefNum(A0) ; set refnum up
|
|||
|
_Control
|
|||
|
TST D0 ; check D0 - CCR doesn't get set right by _Control
|
|||
|
BNE.S @90 ; if error, branch and exit
|
|||
|
|
|||
|
; Return the socket number to the user. Check skt listener address to see if
|
|||
|
; we need to add it to our table. If it was not sent as NIL then don't add it.
|
|||
|
|
|||
|
MOVE.B Socket(A0),D3 ; get the (possibly) new socket
|
|||
|
MOVE.B D3,1(A1) ; return skt num to user
|
|||
|
LEA SocketListener,A0 ; see if we're using the default
|
|||
|
CMPA.L D1,A0 ; socket listener
|
|||
|
BNE.S @90 ; if not, then don't add to our table
|
|||
|
|
|||
|
; Caller wants to use the default socket listener, so store the socket number
|
|||
|
; in my own table for use by DDPRead and the socket listener.
|
|||
|
|
|||
|
LEA theSocketTable,A1 ; A1 -> my table of skt listeners
|
|||
|
MOVE #maxSkts-1,D1 ; start at the end of the list
|
|||
|
@20 TST.B aSktNum(A1,D1) ; test for zero
|
|||
|
DBEQ D1,@20 ; find it?
|
|||
|
BNE.S @80 ; if not found then branch with error
|
|||
|
|
|||
|
; Found an entry so set up info in the socket table
|
|||
|
|
|||
|
@30 MOVE.B D3,aSktNum(A1,D1) ; store the socket number
|
|||
|
CLR.B aRcvFlag(A1,D1) ; zero out the pkt rcvd flag
|
|||
|
LSL #2,D1 ; offset to actual place in table
|
|||
|
CLR.L aRBPtr(A1,D1) ; no read blocks linked in yet
|
|||
|
BRA.S @90
|
|||
|
|
|||
|
@80 MOVE #ddpSktErr,D0 ; no free entry in table (ERROR)
|
|||
|
|
|||
|
@90 ADD #IOQElSize,SP ; deallocate the queue element
|
|||
|
JMP ExitD3 ; restore D3 and exit
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
EJECT
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDPCloseSkt
|
|||
|
;
|
|||
|
; Detaches the socket listener and socket number from the table. Unlocks
|
|||
|
; all Read Blocks associated with the socket and queues them for disposal.
|
|||
|
; Unlocks all ABRecords associated with the Read Blocks. Error
|
|||
|
; is returned by MPP if the socket was not found in the table.
|
|||
|
;
|
|||
|
; FUNCTION DDPCloseSocket(theSocket : Byte): INTEGER;
|
|||
|
;
|
|||
|
; Stack upon entry:
|
|||
|
;
|
|||
|
; TOS => .LONG Return address
|
|||
|
; .BYTE pascal filler
|
|||
|
; .BYTE socket number
|
|||
|
; .WORD function result code
|
|||
|
;
|
|||
|
; Returns: .WORD Result code
|
|||
|
;
|
|||
|
; Possible errors: MPP errors: Socket not found
|
|||
|
;
|
|||
|
; The IO queue element is allocated on the stack for the control call.
|
|||
|
; This call is made synchronously.
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 8/24/84 GRT Ready for alpha release
|
|||
|
; 10/12/84 RFA Code-crunch
|
|||
|
; 10/16/84 RFA Clean up all Read Blocks and unlock all ABRecs
|
|||
|
; 3/15/85 GRT RecoverHandle call added
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
DDPCloseSocket PROC EXPORT
|
|||
|
JSR RemoveHdlBlks ; memory handles to be disposed?
|
|||
|
MOVE.L (SP)+,D2 ; save return address
|
|||
|
MOVE (SP)+,D0 ; get socket number (stored in word order)
|
|||
|
MOVE.L D3,-(SP) ; save register
|
|||
|
MOVE.B D0,D3 ; skt number
|
|||
|
SUB #IOQElSize,SP ; allocate IOQElement
|
|||
|
MOVE.L SP,A0 ; A0 -> IOQEl
|
|||
|
MOVE.B D3,socket(A0) ; pass parameter to IOQ
|
|||
|
MOVE #CloseSkt,CSCode(A0) ; control code
|
|||
|
MOVE #MPPRefNum,IORefNum(A0) ; set refnum up
|
|||
|
_Control ; make the call
|
|||
|
ADD #IOQElSize,SP ; deallocate the IOQ element
|
|||
|
TST.B D0 ; did we get an error
|
|||
|
BNE.S @15 ; if so then branch
|
|||
|
|
|||
|
; Scan through table until either an matched entry is found, or until
|
|||
|
; the end of the table is reached. If the entry is not found, we can't assume
|
|||
|
; an error since the socket might have not been for our socket table.
|
|||
|
|
|||
|
JSR LookUpSkt ; check for socket
|
|||
|
BNE.S @15 ; if not found then just exit
|
|||
|
CLR.B aSktNum(A1,D1) ; zero out the field to nullify it
|
|||
|
CLR.B aRcvFlag(A1,D1) ; just to be on the safe side
|
|||
|
|
|||
|
LSL #2,D1 ; get offset into RBPtrs
|
|||
|
MOVE.L aRBPtr(A1,D1),A0 ; get first Read Block
|
|||
|
CLR.L aRBPtr(A1,D1) ; zero it out for cleanup
|
|||
|
MOVE.L A0,A1 ; A1 -> Read Block
|
|||
|
|
|||
|
@10 MOVE.L A1,D0 ; is it nil?
|
|||
|
BEQ.S @15 ; if so, we're done
|
|||
|
MOVE.L rbABHdl(A1),A0 ; A0 = AB rec handle
|
|||
|
_HUnlock ; and unlock it
|
|||
|
|
|||
|
MOVE.L A1,A0
|
|||
|
_RecoverHandle ; recover handle to read block
|
|||
|
MOVE.L (A1),A1 ; but first, get ptr to next RdBlk
|
|||
|
JSR UnlockAndLinkHdl ; unlock and queue it up for disposal
|
|||
|
BRA.S @10
|
|||
|
|
|||
|
@15 JMP ExitD3 ; return
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
EJECT
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDPWrite
|
|||
|
;
|
|||
|
; Write a packet out to the cable either synchronously or asynchronously.
|
|||
|
; If sync, do the operation and return when completed. If async, pass
|
|||
|
; control back after queueing the call, and when completed, post a network
|
|||
|
; event back to the application with a message consisting of the ABRecHandle.
|
|||
|
;
|
|||
|
; The ABRecHandle is locked down during most of the call. abResult will
|
|||
|
; contain a 1 in it as long as the operation is still in progress (ASYNC
|
|||
|
; only)
|
|||
|
;
|
|||
|
; FUNCTION DDPWrite(abRecord : ABRecHandle; doCheckSum : BOOLEAN;
|
|||
|
; async : BOOLEAN): INTEGER;
|
|||
|
;
|
|||
|
; Stack upon entry:
|
|||
|
;
|
|||
|
; TOS => .LONG Return address
|
|||
|
; .BYTE pascal filler
|
|||
|
; .BYTE async flag
|
|||
|
; .BYTE pascal filler
|
|||
|
; .BYTE checkSum flag
|
|||
|
; .LONG handle to record data structure
|
|||
|
; .WORD function result code
|
|||
|
;
|
|||
|
; Returns: .WORD Result code
|
|||
|
; Additional data in record structure
|
|||
|
;
|
|||
|
; Possible errors:
|
|||
|
;
|
|||
|
;
|
|||
|
; Upon allocation of the IOQElement block, an additional 36 bytes are
|
|||
|
; allocated at the end. The data structure looks like this:
|
|||
|
;
|
|||
|
; |=========================|
|
|||
|
; : :
|
|||
|
; : IOQElement blk : 50 bytes
|
|||
|
; : :
|
|||
|
; : :
|
|||
|
; |=========================|
|
|||
|
; : AB record hdl : 4 byte hdl to AB record
|
|||
|
; |-------------------------|
|
|||
|
; : Q element hdl : 4 byte hdl to this queue element
|
|||
|
; |-------------------------| <----------- WDS1Start
|
|||
|
; : WDS element1 (hdr info) : 6 bytes (2 byte length, 4 byte ptr)
|
|||
|
; |-------------------------|
|
|||
|
; : WDS element2 (write) : 6 bytes (points to data to write)
|
|||
|
; |-------------------------|
|
|||
|
; |_ WDS Termination _| 2 bytes
|
|||
|
; | Word |
|
|||
|
; |-------------------------|
|
|||
|
; | async flag | 1 byte
|
|||
|
; |=========================| <----------- WDS1stEntry
|
|||
|
; : 7 bytes for LAP : 7 bytes (THIS IS ODD ALIGNED!)
|
|||
|
; : header, DDP length :
|
|||
|
; : and checksum fields :
|
|||
|
; |-------------------------|
|
|||
|
; |_ Destination Network _| 2 Bytes
|
|||
|
; | Number |
|
|||
|
; |-------------------------|
|
|||
|
; |_ _| 2 Bytes unused in call
|
|||
|
; | |
|
|||
|
; |-------------------------|
|
|||
|
; | Dest Node Address | 1 Byte
|
|||
|
; |-------------------------|
|
|||
|
; | | 1 Byte unused in call
|
|||
|
; |-------------------------|
|
|||
|
; | Dest Skt Number | 1 Byte
|
|||
|
; |-------------------------|
|
|||
|
; | | 1 Byte unused in call
|
|||
|
; |-------------------------|
|
|||
|
; | Level 2 Type | 1 Byte
|
|||
|
; |-------------------------|
|
|||
|
; | | 1 Byte unused in call
|
|||
|
; |=========================|
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 8/24/84 GRT Ready for alpha release
|
|||
|
; 10/12/84 RFA D0 must be .long when calling GetHdlAndLock
|
|||
|
; 12/17/84 GRT CmpEventPost changed to Cmp1EventPost
|
|||
|
; 4/30/86 GRT Saving Q element handle in the queue element
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
DDPWrite PROC EXPORT
|
|||
|
JSR RemoveHdlBlks ; check for disposable handles
|
|||
|
LEA retAddr,A1 ; save place for ret address
|
|||
|
MOVE.L (SP)+,(A1) ; save return address; A1 available now
|
|||
|
MOVE.B (SP)+,D1 ; save async flag
|
|||
|
MOVE.B (SP)+,D2 ; save checksum flag
|
|||
|
MOVE.L (SP)+,A0 ; abRecord handle
|
|||
|
MOVEM.L A2-A3,-(SP) ; save A2/3
|
|||
|
_HLock ; lock abRecord down
|
|||
|
TST D0 ; check error - MUST DO THIS!
|
|||
|
BNE @90 ; if not zero return an error
|
|||
|
MOVE.L (A0),A2 ; A2 -> Ptr to ABRecord
|
|||
|
MOVE.L A0,A1 ; save another copy of handle for later
|
|||
|
MOVE #1,abResult(A2) ; still in execution
|
|||
|
MOVE.B #tDDPWrite,abOpCode(A2) ; put call type in record
|
|||
|
|
|||
|
; We are allocating an extra n bytes at the end of the IOQElement for storage
|
|||
|
; of the misc data (see diagram)
|
|||
|
|
|||
|
MOVE.L #IOQElSize+WDSXtraDDPSize,D0 ; number of bytes to allocate
|
|||
|
JSR GetHdlAndLock ; allocate the memory A0->IOQElement Hdl
|
|||
|
BNE.S @90 ; error if didn't work
|
|||
|
MOVE.L A0,D0 ; save handle in D0
|
|||
|
MOVE.L (A0),A0 ; A0 -> IOQElement blk (dereferenced)
|
|||
|
MOVE.L D0,qElHdl(A0) ; save handle in queue element
|
|||
|
|
|||
|
; A2 -> ABRecord. A0 -> IOQElement
|
|||
|
|
|||
|
MOVE.L A1,abRecHdl(A0) ; save hdl in IOQElement
|
|||
|
|
|||
|
LEA WDS1Start(A0),A3 ; start of our vars in IOQ blk
|
|||
|
MOVE #16,(A3)+ ; length is always 16 for the WDS hdr
|
|||
|
LEA WDS1stEntry(A0),A1 ; address of the WDS header entry
|
|||
|
MOVE.L A1,(A3)+ ; A1 = WDS entry 1 ptr
|
|||
|
MOVE ddpReqCount(A2),(A3)+ ; buffer size to write out
|
|||
|
MOVE.L ddpDataPtr(A2),(A3)+; buffer data pointer
|
|||
|
CLR (A3)+ ; zero means end of WDS
|
|||
|
MOVE.B D1,(A3) ; async flag stored in IOQELBlk
|
|||
|
|
|||
|
; Fill in the parameters of the IO Q element
|
|||
|
|
|||
|
MOVE.B ddpTypeField(A2),dType(A0) ; store ddp type field
|
|||
|
MOVE.B ddpSocket(A2),Socket(A0) ; store source socket
|
|||
|
MOVE ddpAddrNet(A2),dDstNet(A0) ; store dest network
|
|||
|
MOVE.B ddpAddrID(A2),dDstNodeAddr(A0); store dest node address
|
|||
|
MOVE.B ddpAddrSkt(A2),dDstSkt(A0) ; store dest socket number
|
|||
|
|
|||
|
LEA WDS1Start(A0),A2 ; get pointer to WDS block
|
|||
|
MOVE.L A2,WDSPointer(A0) ; move it into the IOQElement
|
|||
|
MOVE.B D2,ChecksumFlag(A0) ; pass checksum flag to DDP
|
|||
|
MOVE #WriteDDP,CSCode(A0) ; set control code
|
|||
|
|
|||
|
LEA DDPWrteCompletion,A2 ; A2 -> our IO completion routine
|
|||
|
JSR DoControlCall ; make the control call
|
|||
|
|
|||
|
@90 MOVEM.L (SP)+,A2-A3 ; restore A2/3
|
|||
|
MOVE.L retAddr,D2 ; get back return address
|
|||
|
JMP ExitD0 ; and exit
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDPWrteCompletion
|
|||
|
;
|
|||
|
; This routine is called when the IO has been completed
|
|||
|
; A0 -> IOQElBlk
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
DDPWrteCompletion
|
|||
|
|
|||
|
MOVEM.L D0/A0-A2,-(SP) ; save registers
|
|||
|
|
|||
|
JSR CmpEntrance ; set up registers and unlock ab record hdl
|
|||
|
JSR Cmp1EventPost ; if event needs to be posted, do it
|
|||
|
|
|||
|
MOVEM.L (SP)+,D0/A0-A2 ; restore registers
|
|||
|
RTS
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
EJECT
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDPRead
|
|||
|
;
|
|||
|
; Read a packet coming in from the cable.
|
|||
|
;
|
|||
|
; IMPORTANT: The DDPRead call can only be used with the built in socket
|
|||
|
; listener.
|
|||
|
;
|
|||
|
; The ABRecHandle is locked down until the call completes. The socket
|
|||
|
; listener is responsible for unlocking it. (unless an error occurs in the
|
|||
|
; read queueing, in which case its unlocked by this routine)
|
|||
|
;
|
|||
|
; All packets received with a long DDP header are examined to see if they
|
|||
|
; contain a valid checksum. If so, we calculate the checksum and see if they
|
|||
|
; match. If they don't, the retCksumErrs flag is checked to see if the user
|
|||
|
; wants packets with checksum errors returned to him/her. If they do, we
|
|||
|
; return the packet but with a ckSumErr error. If not, the packet is thrown
|
|||
|
; away and the Read does not complete.
|
|||
|
;
|
|||
|
; FUNCTION DDPRead(abRecord : ABRecHandle; retCksumErrs : BOOLEAN;
|
|||
|
; async : BOOLEAN): INTEGER;
|
|||
|
;
|
|||
|
; Stack upon entry:
|
|||
|
;
|
|||
|
; TOS => .LONG Return address
|
|||
|
; .BYTE async flag
|
|||
|
; .BYTE pascal filler
|
|||
|
; .BYTE return checksum errs flag
|
|||
|
; .BYTE pascal filler
|
|||
|
; .LONG handle to record data structure
|
|||
|
; .WORD function result code
|
|||
|
;
|
|||
|
; Returns: .WORD Result code
|
|||
|
; Additional data in record structure
|
|||
|
;
|
|||
|
; Possible errors: Bad socket (zero or not open)
|
|||
|
;
|
|||
|
;
|
|||
|
; A 14 byte read block is allocated dynamically for every read call. This
|
|||
|
; block is linked in a FIFO queue for every active socket number . When a
|
|||
|
; pkt is received, the first read block data in the link is read and the
|
|||
|
; socket listener attempts to read the packet into the buffer pointed to by
|
|||
|
; the ddpDataPtr parameter in the ABRecord.
|
|||
|
;
|
|||
|
; |-------------------------|
|
|||
|
; | Link to next | 4 byte pointer link
|
|||
|
; | read block |
|
|||
|
; | |
|
|||
|
; |-------------------------|
|
|||
|
; | AB record handle | 4 byte hdl to AB record
|
|||
|
; | |
|
|||
|
; | |
|
|||
|
; |-------------------------|
|
|||
|
; | async flag | 1 byte
|
|||
|
; |-------------------------|
|
|||
|
; | return cksum errs flag | 1 byte
|
|||
|
; |-------------------------|
|
|||
|
; | read block hdl | 4 byte hdl to this read block
|
|||
|
; | |
|
|||
|
; | |
|
|||
|
; |-------------------------|
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 8/24/84 GRT Ready for alpha release
|
|||
|
; 10/12/84 RFA Code-crunch, D0 must be .long when calling GetHdlAndLock,
|
|||
|
; & handles being recovered wrong under error conditions
|
|||
|
; 3/15/85 GRT RecoverHandle call added
|
|||
|
; 4/30/86 GRT Read block handle saved in the read block
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
DDPRead PROC EXPORT
|
|||
|
JSR RemoveHdlBlks ; check disposable handles
|
|||
|
LEA returnAddr,A1 ; address of save longword
|
|||
|
MOVE.L (SP)+,(A1) ; save return address
|
|||
|
MOVE.B (SP)+,D2 ; save async flag
|
|||
|
SWAP D2 ; in upper word of D2
|
|||
|
MOVE.B (SP)+,D2 ; save checksum errs flag
|
|||
|
MOVE.L (SP)+,A0 ; record handle
|
|||
|
MOVEM.L D3/A2-A3,-(SP) ; save registers for later
|
|||
|
MOVE.L A0,A3 ; save ABRecHdl in A3
|
|||
|
_HLock ; lock abRecord down
|
|||
|
TST D0 ; test result of the lock operation
|
|||
|
BNE ReadExit ; if not zero return an error
|
|||
|
|
|||
|
; first check my socket listener table for the matching socket number
|
|||
|
|
|||
|
MOVE #readQErr,D0 ; assume an error
|
|||
|
MOVE.L (A0),A2 ; A2 -> ABRecord
|
|||
|
MOVE.B ddpSocket(A2),D3 ; get the socket number
|
|||
|
BEQ.S Read1Exit ; zero type is invalid
|
|||
|
|
|||
|
JSR LookUpSkt ; check for socket number in table
|
|||
|
BNE.S Read1Exit ; if not found then leave
|
|||
|
|
|||
|
; we found the socket, so get a Read Block and set it up
|
|||
|
|
|||
|
MOVE #1,abResult(A2) ; in execution
|
|||
|
MOVE.B #tDDPRead,abOpCode(A2) ; put call type in
|
|||
|
MOVEQ #rdBlkSize,D0 ; size of a read blk entry
|
|||
|
JSR GetHdlAndLock ; get a handle to the memory
|
|||
|
BNE.S Read1Exit ; exit if error (must clean up)
|
|||
|
MOVE.L A0,D0 ; save handle in D0
|
|||
|
MOVE.L (A0),A0 ; A0 -> my read block (dereference)
|
|||
|
MOVE.L D0,rbHdl(A0) ; put handle in read block
|
|||
|
|
|||
|
; A0 -> my read block A2 -> AB record stuff the read blk full of data
|
|||
|
|
|||
|
CLR.L rbNxPtr(A0) ; zero out ptr to next element
|
|||
|
MOVE.L A3,rbABHdl(A0) ; copy the AB rec hdl into it
|
|||
|
MOVE.B D2,rbRetCksErr(A0) ; save the checksum flag
|
|||
|
SWAP D2 ; get the async flag
|
|||
|
MOVE.B D2,rbAFlag(A0) ; save the async byte flag
|
|||
|
|
|||
|
; must reset the pkt recvd flag before the read buffer is linked in
|
|||
|
; SCC interrupts are being turned off while linking the block in
|
|||
|
; A0 -> read blk, A1 -> theSocketTable (set up by LookUpSkt)
|
|||
|
|
|||
|
@10 CLR.B aRcvFlag(A1,D1) ; zero out the pkt recvd flag
|
|||
|
MOVE D1,D2 ; D1,D2 has offset
|
|||
|
LSL #2,D2 ; D2 * 4 = actual offset in table
|
|||
|
MOVE SR,-(SP) ; save status register on stack
|
|||
|
ORI.W #SCCLockOut,SR ; lock out the SCC interrupts <SM2> rb
|
|||
|
LEA aRBPtr(A1,D2),A3 ; A3 -> read element entry link
|
|||
|
@15 TST.L (A3) ; is next link empty?
|
|||
|
BEQ.S @20 ; yes, we're at then end
|
|||
|
MOVE.L (A3),A3 ; no, step to next link
|
|||
|
BRA.S @15 ; and repeat
|
|||
|
@20 MOVE.L A0, (A3) ; put Read Block at end of list
|
|||
|
MOVE (SP)+,SR ; restore interrupt status
|
|||
|
CLR D0 ; I guess that there are no errors!
|
|||
|
TST.B rbAFlag(A0) ; is this an async call?
|
|||
|
BNE.S ReadExit ; if so exit (don't unlock the handle)
|
|||
|
|
|||
|
; Since the call is sync, we wait until the pkt recvd flag says one has come in
|
|||
|
; The result code will have been put in the record by the protocol handler.
|
|||
|
|
|||
|
@25 TST.B aRcvFlag(A1,D1) ; has a packet been received?
|
|||
|
BEQ.S @25 ; if not, then wait
|
|||
|
MOVE abResult(A2),D0 ; pick the result code out of the record
|
|||
|
BRA.S ReadExit ; exit
|
|||
|
|
|||
|
; If an error occurred we must unlock the ABRecord block
|
|||
|
|
|||
|
Read1Exit MOVE D0,D1 ; save error code
|
|||
|
MOVE.L A2,A0
|
|||
|
_RecoverHandle ; recover handle to abRec
|
|||
|
_HUnlock ; unlock the handle
|
|||
|
MOVE D1,D0 ; recover error code
|
|||
|
|
|||
|
ReadExit MOVEM.L (SP)+,D3/A2-A3 ; restore registers
|
|||
|
MOVE D0,(SP) ; stuff function result
|
|||
|
MOVE.L returnAddr,A1 ; get return address
|
|||
|
JMP (A1) ; return
|
|||
|
|
|||
|
EJECT
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
EJECT
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; DDPRdCancel
|
|||
|
;
|
|||
|
; Cancel a pending asynchronous DDPRead and free its associated data structures.
|
|||
|
;
|
|||
|
; IMPORTANT: The DDPRdCancel call can only be used with asynchronous DDPRead
|
|||
|
; calls on a socket whose socket listener is the default.
|
|||
|
;
|
|||
|
; The ABRecord is unlocked, and the associated Read Block is dequeued from
|
|||
|
; the list of pending Read requests and marked for disposal. This call can
|
|||
|
; only be made synchronously.
|
|||
|
;
|
|||
|
; FUNCTION DDPRdCancel(abRecord : ABRecHandle): INTEGER;
|
|||
|
;
|
|||
|
; Stack upon entry:
|
|||
|
;
|
|||
|
; TOS => .LONG Return address
|
|||
|
; .LONG handle to record data structure
|
|||
|
; .WORD function result code
|
|||
|
;
|
|||
|
; Returns: .WORD Result code
|
|||
|
; The abResult field of the abRecord is set to zero
|
|||
|
;
|
|||
|
; Possible errors: Bad socket (zero or not open)
|
|||
|
; abRecord not found
|
|||
|
;
|
|||
|
; Note that by the time the Read request queue is searched for the Read Block
|
|||
|
; pointing to the specified abRecord, a packet may arrive and satisfy the
|
|||
|
; request. An "abRecord not found" error will then be returned. In such a
|
|||
|
; case, the caller should check the abResult field of the abRecord to see
|
|||
|
; if it indeed has completed. If it did, it will contain zero or a negative
|
|||
|
; error indication. If it is equal to 1, then something is seriously wrong.
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 10/23/84 RFA New today
|
|||
|
; 3/15/85 GRT RecoverHandle call added
|
|||
|
; 5/1/86 GRT changed rbABPtr to rbABHdl
|
|||
|
; 12/10/86 SJF fixed _RecoverHandle Bug
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
DDPRdCancel PROC EXPORT
|
|||
|
JSR RemoveHdlBlks ; check disposable handles
|
|||
|
MOVEM.L (SP)+, D2/A0 ; D2 = return adr, A0 = abRec hdl
|
|||
|
MOVEM.L D3/A2-A4, -(SP) ; save some registers
|
|||
|
|
|||
|
; first check my socket listener table for the matching socket number
|
|||
|
|
|||
|
MOVE #readQErr,D0 ; assume an error
|
|||
|
MOVE.L (A0),A2 ; A2 -> ABRecord
|
|||
|
MOVE.B ddpSocket(A2),D3 ; get the socket number
|
|||
|
BEQ.S RdCnclExit ; zero is invalid
|
|||
|
|
|||
|
JSR LookUpSkt ; check for socket number in table
|
|||
|
BNE.S RdCnclExit ; if not found then leave
|
|||
|
|
|||
|
; we found the socket, so search list of Read Blocks for one that points to abRec
|
|||
|
|
|||
|
MOVE #recNotFnd, D0 ; assume an error
|
|||
|
LSL #2, D1 ; get offset into Read Blocks
|
|||
|
LEA aRBPtr(A1,D1), A1 ; A1 = Read Block queue header
|
|||
|
MOVE SR, -(SP) ; save old status
|
|||
|
ORI.W #SCCLockout, SR ; disable interrupts <SM2> rb
|
|||
|
|
|||
|
@10 MOVE.L 0(A1), A3 ; check next element
|
|||
|
CMP.L #0, A3 ; is there a next element?
|
|||
|
BNE.S @20 ; yes, continue checks
|
|||
|
MOVE (SP)+, SR ; no, we're at the end & no match!
|
|||
|
BRA.S RdCnclExit ; restore interrupt state & return
|
|||
|
|
|||
|
@20 MOVE.L rbABHdl(A3),A4 ; get handle to ABRecord
|
|||
|
CMP.L (A4),A2 ; is this the RdBlk for our abRec?
|
|||
|
|
|||
|
BEQ.S FoundIt ; yes!
|
|||
|
MOVE.L A3, A1 ; no, skip down to next Read Block
|
|||
|
BRA.S @10 ; and check it
|
|||
|
|
|||
|
; we found the right Read Block, so dequeue it and dispose of it
|
|||
|
|
|||
|
FoundIt MOVE.L (A3), (A1) ; dequeue the Read Block
|
|||
|
MOVE (SP)+, SR ; safe now to re-enable interrupts
|
|||
|
CLR abResult(A2) ; clear result field in abRecord
|
|||
|
_HUnlock ; unlock the abRecord
|
|||
|
MOVE.L A3,A0
|
|||
|
_RecoverHandle ; recover read block handle
|
|||
|
_HUnlock ; unlock it and dispose of it
|
|||
|
_DisposHandle ; (hopefully clears D0 as well)
|
|||
|
|
|||
|
RdCnclExit MOVEM.L (SP)+, D3/A2-A4 ; restore registers
|
|||
|
MOVE D0, (SP) ; set function result
|
|||
|
MOVE.L D2, A0 ; restore return address
|
|||
|
JMP (A0) ; and return
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|