mac-rom/Libs/InterfaceSrcs/piATP.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

1257 lines
42 KiB
Plaintext

;
; File: piATP.a
;
; Contains: xxx put contents here xxx
;
; Written by: xxx put writers here xxx
;
; Copyright: © 1991-1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM2> 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.
; <4> 11/21/91 JL Changed JSR StripAddress to the trap call itself. I've been
; informed that System 6 and greater has StripAddress implemented
; as a trap so I don't need to worry about it being there or not.
; <3> 11/21/91 JL Added import of StripAddress or else we can't build.
; <2> 11/20/91 JL Changed CLR.B (SP) to JSR StripAddress for 32 bit clean code in
; ListDequeue.
;
;
BLANKS ON
STRING ASIS
EJECT
;_______________________________________________________________________
;
; ATP Routines
;_______________________________________________________________________
;
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
; MISCELLANEOUS calls
;
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;___________________________________________________________________________
;
; ATPLoad - open the ATP driver
;
; FUNCTION ATPLoad : OSErr; OSErr is an INTEGER;
;
; Returns: Result code
;
; Operation: Opens the .ATP driver. Always synchronous
;
; Stack setup upon entry:
; .LONG Return address
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 3 Sep 84 GSS Moved ATPEnter and ATPCompFin code into this function
; 14 Dec 84 GRT Check is now made at beginning to make sure MPP and
; ATP drivers are not already open; if MPP is not open
; then go try to open it.
; 4 Jan 85 RFA Added ListEnqueue and ListDequeue for cancel calls
; 9 Jan 85 GRT Now using low memory variables to check if ATP is open
; Also calling MPPOpen to open MPP
; 10 Jan 85 RFA ListEnqueue and ListDequeue disable interrupts now
; 15 Mar 85 GRT In ATPCompFin, RecoverHandle call added
; 1 May 86 GRT ATPEnter: queue element handle saved in queue element
; No more _RecoverHandle
; MakeBDS now returns BDS handle in A2
; Dec. 86 SJF Added routine ATPEnter2, Fixed ATPReqCancel and ATPRspCancel
; so that they always execute syncronously.
;_____________________________________________________________________________
ATPLoad PROC EXPORT
JSR RemoveHdlBlks
; check to make sure the MPP driver is opened; if not, then open it anyways
CLR -(SP) ; space for func result
JSR MPPOpen ; open the MPP driver if necessary
TST (SP)+ ; check result
@90 MOVE D0,4(SP) ; Set return code for caller
RTS ; Return
ENDPROC
EJECT
;_____________________________________________________________________________
;
; This is the common entry point code used by ATPSndRequest, ATPGetRequest,
; and ATPSndRsponse
;
ATPEnter PROC
JSR RemoveHdlBlks
MOVE.L (SP)+, D1 ; D1 = addr of caller to ATPEnter
MOVE.L (SP)+, D2 ; D2 = return address one step back
; Get a chunk of memory for the I/O queue element and temp storage and set it up.
; The abRecord handle and async boolean are saved below the normal I/O queue
; element so the completion routine can access them.
MOVEQ #IOPBEnd,D0 ; D0 = size of param blk needed
JSR GetHdlAndLock ; A0 = handle to IO param blk
BEQ.S @10 ; no error -- so continue
; no memory for pblk -- so report error and clean up stack
TST (SP)+ ; remove async boolean from stk
MOVE.L (SP)+, A0 ; pop the abrecord handle from stk
MOVE.L (A0),A1 ; dereference it
MOVE D0, abResult(A1) ; write result into abRecord
MOVE D0, (SP) ; write func result to stk
MOVE.L D2, A1 ; A1 = return address
JMP (A1) ; return to caller one step back
@10 MOVE.L A0,D0 ; save handle in D0
MOVE.L (A0), A0 ; deref handle to param blk
MOVE.L D0,qElHdl(A0) ; save Q element hdl in queue element
MOVE.B (SP)+,asyncFlg(A0) ; save caller's async flag
MOVE.L (SP)+, A1 ; A1 = abRecord handle
MOVE.L A1, abRecHdl(A0) ; save handle to ABRecord in param blk
EXG A0,A1 ; A0 = abRec handle, A1 -> IOParamblk
_HLock ; lock the abRecord
EXG A0,A1 ; A1 = abRec handle, A0 -> IOParamblk
MOVE.L (A1),A1 ; A1 -> abRecord (dereference the handle)
MOVE #1,abResult(A1) ; mark abRecord as op in progress
CLR.B ATPFlags(A0) ; clear all flags in param blk
MOVE #ATPRefNum, IORefNum(A0) ; .ATP driver's ref num
MOVE.L D1, -(SP) ; push return address on stack
RTS ; return from ATPEnter
ENDPROC
EJECT
; ATPEnter2 - this is the common entry point code used by ATPReqCancel, ATPRspCancel
; There is no Abrecord except the one we're aborting.
ATPEnter2 PROC
BSR RemoveHdlBlks
MOVE.L (SP)+,D1 ;D1 = addr of caller to ATPEnter
MOVE.L (SP)+,D2 ;D2 = return addr one step back
; Get a chunk of memory for the I/O queue element and temp storage and set it up.
; The ABrecord handle and async boolean are saved below in the normal I/O queue element
; so the completion routine can access them.
MOVEQ #IOPBEnd,D0 ;size of parm block
BSR GetHdlAndLock ;A0 is handle to IO Param blk
BEQ.S @10 ;no errs
TST.W (SP)+ ;trash boolean
MOVEA.L (SP)+,A0 ;A0 is ABrecord handle
MOVEA.L (A0),A1 ;deref
MOVE.W D0,(SP) ;set func rslt
MOVEA.L D2,A1 ;A1 is return addr
JMP (A1) ;exit one step back
@10
MOVE.L A0,D0 ;save handle
MOVEA.L (A0),A0 ;deref, (A0)->parm blk
MOVE.L D0,qElHdl(A0) ;save queue element hndl
TST.B (SP)+ ;trash async flag, always sync
MOVEA.L (SP)+,A1 ;A1 is ABrecord hndl
MOVEA.L (A1),A1 ;deref, (A1)->Abrecord
MOVE #ATPRefNum, IORefNum(A0) ; .ATP driver's ref num
MOVE.L D1, -(SP) ; push return address on stack
RTS ; return from ATPEnter
ENDPROC
EJECT
; This is the common part of all ATP completion routines (It consists of code for
; unlocking the abRecord, posting an event, and for linking the IOPblk to the free queue)
ATPCompFin PROC
; unlock the abRecord
EXG D1, A0 ; D1 = pblk ptr, A0 = abRec handle
_HUnlock
EXG D1, A0 ; A0 = pblk ptr, D1 = abRec handle
TST.B asyncflg(A0) ; was it an async call?
BEQ.S @10 ; no it wasn't
; async call -- post an event
MOVE.L A0,-(SP) ; iopblk ptr saved across PostEvent
MOVE #networkEvt,A0 ; A0 = event number
MOVE.L D1, D0 ; D0 = event message = abRec Handle
_PostEvent ; Post the event
MOVE.L (SP)+,A0 ; Restore A0
; put the IO param blk on the free queue
@10 MOVE.L qElHdl(A0),A0 ; recover handle to param block
JSR UnlockAndLinkHdl ; put IOPBlk on the free blks queue
RTS
ENDPROC
EJECT
;
; MakeBDS
;
; This routine makes a BDS and fills in the various fields
;
; It is shared by ATPRequest and ATPResponse
;
; On entry:
; A1 -> abRecord
; D1 = length of response message buffer
; atpRspBuf(A1) -> response message buffer
; atpRspUData(A1) = response user bytes (relevant
; only for ATPResponse)
;
; Returns: A2 = BDS Handle
; D0 = error code (condition codes set upon exit)
; atpNumBufs(A1) = number of BDS entries
; atpRspBDSPtr(A1) -> response BDS
;
MakeBDS PROC
MOVEM.L D3/A0/A3, -(SP) ; save regs on stack
MOVE #maxATPBuf, D3 ; max size of a resp pkt
MOVE.L atpRspBuf(A1), A3 ; A3 -> rsp buffer
MOVE D1, D0 ; move length into D0
BEQ.S @10 ; if zero, alloc 1 BDS entry
DIVU D3, D0 ; D0.W = # of full pkts
CMP.L #$FFFF, D0 ; last piece length <> 0 ?
BLE.S @40 ; only full size pieces
@10 ADDQ #1, D0 ; count the last piece in
@40 MOVE.B D0, atpNumBufs(A1) ; write buffer count into abRecord
MULU #BDSEntrySz, D0 ; BDS = # entries * entry size
JSR GetHdlAndLock ; A0 = BDS handle
BNE.S @100 ; error exit
MOVE.L A0,A2 ; save handle in A2
MOVE.L (A0), A0 ; A0 -> BDS
MOVE.L A0, atpRspBDSPtr(A1) ; put BDS pointer into abRecord
MOVE D1, D0 ; D0 = byte count
@60 MOVE D3, (A0)+ ; size of piece
CMP D3, D0 ; how much buffer left ?
BGE.S @70 ; at least full size pkt
MOVE D0, -2(A0) ; adjust size to remaining part
@70 MOVE.L A3, (A0)+ ; BDS.bufptr
CLR (A0)+ ; skip bdsDataSz
MOVE.L atpRspUData(A1), (A0)+ ; user bytes into BDS
ADD D3, A3 ; advance buffer ptr
SUB D3, D0 ; decrement count of bytes left
BGT.S @60 ; still not done
MOVEQ #0, D0 ; clear D0 to indicate no error
@100 MOVEM.L (SP)+, D3/A0/A3 ; restore regs
TST D0 ; set CCs for caller
RTS
ENDPROC
EJECT
;
; ListEnqueue
;
; This utility is used to queue the IOQElements of all asynchronous ATPGetRequest,
; ATPSndResponse, and ATPResponse calls so that if the user tries to close an ATP
; socket, the interface can clean up any data structures it had allocated for calls
; involving that socket. The element to be queued is pointed to by A0. A1 is used.
ListEnqueue PROC
MOVE SR, -(SP) ; save old SR
ORI.W #SCCLockOut, SR ; and disable interrupts for now <SM2> rb
LEA SktQElList, A1 ; get head of list
MOVE.L (A1), ListLink(A0) ; new element points to first element
MOVE.L A0, (A1) ; head points to new element
MOVE (SP)+,SR
RTS ; re-enable interrupts and return
ENDPROC
;
; ListDequeue
;
; This utility is used to dequeue an IOQElement of one of the above mentioned calls.
; It is given a pointer to the element to be dequeued in A0, but it must look
; through the list from the start because the list is not doubly-linked so it must
; find the element's predecessor. Note that the code is special-cased if the element
; we are looking for is the first in the list. This is unavoidable because the link
; field is not at the start of the data structure, so I cannot make the head "look"
; like a predecessor.
; No error is returned if the element is not found - if this happens, I assume it
; is because of the race condition between an ATPRspCancel and the completion of
; the Response call (both of which will try to dequeue the IOQElement).
ListDequeue PROC
MOVE SR, -(SP) ; save old status
ORI.W #SCCLockOut, SR ; disable interrupts now <SM2> rb
MOVEM.L A1-A2, -(SP) ; save some registers
LEA SktQElList, A1 ; get head of list
MOVE.L (A1), D0 ; get pointer to next element
_StripAddress ;mask out high bits of addr
MOVEA.L D0,A2
MOVE.L A0,D0 ; get pointer to next element
_StripAddress ;mask out high bits of addr
MOVEA.L D0,A0
CMP.L A0, A2 ; is this our IOQEl?
BNE.S @20 ; no, check next one
MOVE.L ListLink(A2), (A1) ; yes, head now points to next element
BRA.S @30 ; and we're done
@20 CMP.L #0, A2 ; are we at the end of the list?
BEQ.S @30 ; quit if so
MOVEA.L A2, A1 ; skip down list
MOVE.L ListLink(A1),D0 ; get pointer to next element
_StripAddress ;mask out high bits of addr
MOVEA.L D0,A2
CMP.L A0, A2 ; is this our IOQEl?
BNE.S @20 ; no, check next one
MOVE.L ListLink(A2), ListLink(A1) ; yes, remove element from list
@30 MOVEM.L (SP)+, A1-A2 ; restore registers
MOVE (SP)+,SR
RTS ; re-enable interrupts and return
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPUnload - close the ATP driver only if we are working on a 128K system
; else ignore the call.
;
; FUNCTION ATPUnload : INTEGER;
;
; Returns: Result code
;
; Operation: Closes the .ATP driver. Always synchronous
;
; Stack setup upon entry:
; .LONG Return address
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 14 Dec 84 GRT Checks to see if system is 128k; if not, just ignore
; the call (NOP).
;
;_____________________________________________________________________________
ATPUnload PROC EXPORT
JSR RemoveHdlBlks
CLR.W 4(SP) ;good result for caller
RTS
ENDPROC
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
; ATP REQUESTING END calls
;
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;___________________________________________________________________________
;
; ATPSndRqst - send an ATP request and wait for the response
;
; FUNCTION ATPSndRequest(abRecord: ABRecHandle; async: BOOLEAN): INTEGER;
;
;
; where: async = TRUE if calls is to be made asynchronously
; abRecord is the handle to the user provided atp abus Record
;
; Returns: in the abus record
; atpNumRsp = number of responses
; atpEOM = true if EOM was set in response
; abResult = Result code
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 24 Aug 84 GRT atpRefNum is MOVE.W not MOVE.L.
; 3 Sep 84 GSS code crunch -- use ATPEnter and ATPCompFin
; 17 Oct 84 RFA code crunch
; 20 Oct 84 GSS added label ATPSReq1 and a test branch in ATPRqComp
; to allow code sharing with ATPRequest. Also added
; the appropriate .DEF for ATPSReq1
; 13 Nov 84 GRT changed SUBQ.W to SUBQ.B in ATPRqComp's BDS testing loop
; 14 Nov 84 GRT BTST should test bit 0 and not 1 @ ATPSReq1
; 28 Nov 84 GRT Clearing high byte of atpNumRsp field before returning to user
; 4 Jan 85 RFA Added use of TIDValid bit to permit ATPReqCancel to work
; 10 Jan 85 RFA wrong field name: atpTID instead of atpTransID
; 15 Mar 85 GRT RecoverHandle call added
; 20 Feb 86 GRT ATPRequest part of completion munged the BDS ptr if more than
; one packet was received.
; 1 May 86 GRT No more _RecoverHandle
;_____________________________________________________________________________
ATPSndRequest PROC EXPORT
ENTRY ATPSReq1
JSR ATPEnter ; do preprocessing
; A0 -> IO param blk, A1 -> abRecord, D2 = return address
MOVE.B #tATPSndRequest,abOpCode(A1) ; write op code to abRecord
CLR.B atpEOM(A1) ; clear EOM indication in abRecord
; now prepare the IO param blk for the call to ATP. Set the XO flag in the IOparamblk
ATPSReq1 BTST #0, atpXO(A1) ; (V1.1E)test XO boolean in abRecord
BEQ.S @20 ; branch if not XO
BSET #ATPXOBit,ATPFlags(A0) ; set XO flag in paramblk
; now put the rest of the params into the param blk
@20 MOVE.L atpAddress(A1), AddrBlock(A0) ; destination address
CLR.B NumofResps(A0) ; clear number of responses field
MOVE.B atpTimeOut(A1), TimeOutVal(A0)
MOVE.B atpRetries(A1), RetryCount(A0)
MOVE.B atpNumBufs(A1), NumofBuffs(A0)
MOVE.L atpUserBytes(A1),UserData(A0)
MOVE atpRCount(A1), ReqLength(A0)
MOVE.L atpDataPtr(A1), ReqPointer(A0)
MOVE.L atpRspBDSPtr(A1), BDSPointer(A0)
; set up control calls code
MOVE #SendRequest, CSCode(A0) ; control calls op code
; test to see if the request is for an async call
TST.B asyncFlg(A0) ; async call?
BEQ.S @30 ; No -- make synch call
MOVE.L A1, D1 ; Yes -- asynch call, save A1 for now
LEA ATPRqComp, A1
MOVE.L A1,IOCompletion(A0) ; set completion routine address
MOVE.L D1, A1 ; restore A1
BCLR #TIDValid,ATPFlags(A0) ; clear TID Valid flag in paramblk
_Control ,ASYNC ;
MOVE D0,(SP) ; save result of function call
BNE.S @50 ; if immediate error returned then exit
@25 BTST #TIDValid,ATPFlags(A0) ; has driver set the TID yet?
BEQ.S @25 ; loop here until that happens
MOVE ReqTID(A0),atpTID(A1) ; save TID in abRec for cancels
BRA.S @50 ; now return to the caller
@30 _Control ; synch call
; we return here after the synch transaction is over. Call completion routine
; to free up param blk and unlock abRecord; then return to the caller
MOVE D0,(SP) ; save result of function call
BSR ATPRqComp
@50 MOVE.L D2, A1 ; A1 = return address
JMP (A1) ; return to caller
; I/O completion routine
;
; A0 -> I/O queue element
; abRecHdl(A0) = handle to abRecord for this request
; asyncflg(A0) = async boolean provided by the caller
ATPRqComp MOVE.L abRecHdl(A0), A1 ; A1 = abRecord handle
MOVE.L A1, D1 ; save handle in D1
MOVE.L (A1),A1 ; deref the handle
MOVE IOResult(A0),abResult(A1) ; Save the result
CLR atpNumRsp-1(A1) ; clear high byte of word (V1.1E)
MOVE.B NumOfResps(A0),atpNumRsp(A1) ; Set number of responses
BTST #ATPEOMBit,ATPFlags(A0) ; See if got EOM
SNE atpEOM(A1) ; Set EOM flag if got it
CMP.B #tATPSndRequest,abOpCode(A1) ; was it a SndRequest call?
BEQ.S @10 ; Yes -- skip ATPRequest part
; ATPRequest part of completion
;
; -- set up A3 to point to the BDS
; -- fix abRecord values of atpRspSize and atpRspUData
; -- free the BDS
MOVE.L A3, -(SP) ; save A3 on stack
MOVE.L atpRspBDSPtr(A1),A3 ; A3 -> BDS
MOVE.L bdsUserData(A3),atpRspUData(A1) ; move user bytes to abRecord
CLR D0 ; clear accumulated message size
TST abResult(A1) ; Error?
BNE.S @08 ; Yes -- skip BDS check
;
; if there is no error (ie if we get here) then there is at least one
; BDS entry
;
MOVE.L A3,-(SP) ; preserve BDS ptr
@05 ADD bdsDataSz(A3), D0 ; accumulate size of rsp msg
SUBQ.B #1,NumofResps(A0) ; (V1.1D) decrement resp pkts count
BGT.S @06 ; if not done then branch
MOVE.L (SP)+,A3 ; restore BDS ptr
BRA.S @08 ; exit this routine
@06 CMP #maxATPBuf,bdsDataSz(A3) ; check size = maxATPBuf ?
BEQ.S @07 ; size OK
;
; intermediate piece of bad size -- report error
;
MOVE #atpBadRsp,abResult(A1) ; indicate resp bad structure
;
; if a synch call then must fix function result on stack
;
TST.B asyncFlg(A0) ; Synch call ?
BNE.S @07 ; No -- skip next instruction
MOVE #atpBadRsp, 8(SP) ; Synch call: fix func result
;
; move on to next BDS entry
@07 ADD #bdsEntrySz,A3 ; point to next BDS entry
BRA.S @05 ; go check it
;
; now free the BDS
;
@08 MOVE D0, atpActCount(A1) ; stuff message length
EXG A0, A3 ; save A0 in A3 and A0 -> BDS
MOVE.L bdsHdl(A3),A0 ; get handle to BDS
JSR UnlockAndLinkHdl ; put BDS on the free blks queue
EXG A0, A3 ; restore A0
MOVEA.L (SP)+,A3 ;restore A3
@10 LEA ATPCompFin,A1
JMP (A1) ; jump to the common part of the
; completion routine
ENDPROC
EJECT
;___________________________________________________________________________
;
; - send an ATP request and wait for the response
;
; FUNCTION ATPRequest(abRecord: ABRecHandle; async: BOOLEAN): INTEGER;
;
;
; where: async = TRUE if calls is to be made asynchronously
; abRecord is the handle to the user provided atp abus Record
;
; Returns: in the abus record
; atpActCount = size in bytes of the response message
; atpRspUData = user bytes from response ATP header
; atpEOM = true if EOM was set in response
; abResult = Result code
; abOpCode = tATPRequest
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Modification History:
;
; 19 Oct 84 GSS New today
; 20 Oct 84 GSS Put in the BDS part and the completion path fixes
; 22 Oct 84 GSS modified to share MakeBDS code with ATPResponse
; 15 Mar 85 GRT RecoverHandle call added
; 1 May 86 GRT Saving bds handle in queue element
;_____________________________________________________________________________
ATPRequest PROC EXPORT
JSR ATPEnter ; do preprocessing
; A0 -> IO param blk , A1 -> abRecord , D2 = return address
MOVE.B #tATPRequest,abOpCode(A1) ; write op code to abRecord
CLR.B atpEOM(A1) ; clear EOM indication in abRecord
; set up the BDS
; first adjust the buffer length to be at most maxATPBuf
MOVEQ #0, D1 ; clear D1
MOVE atpRspSize(A1), D1 ; read response buffer size
CMP #maxATPBuf*8, D1 ; Is it too big ?
BLE.S @05 ; No -- go on
MOVE #maxATPBuf*8, D1 ; Yes --too big. Set to 8*maxATPBuf
@05 MOVE.L A2,-(SP) ; save A2
JSR MakeBDS ; go build the BDS
MOVE.L A2,bdsHdl(A0) ; save BDS handle in queue element
MOVE.L (SP)+,A2 ; restore A2
TST D0 ; any errors from MakeBDS?
BNE.S @09 ; no error -- so continue
; call the common code in ATPSndRquest
JMP ATPSReq1
; no memory for BDS -- so report error, unlock abRecord and free param blk
@09 MOVE D0, abResult(A1) ; write result into abRecord
MOVE D0, 4(SP) ; write function result onto stk
MOVE.L (SP), A0 ; get the param blk pointer from stk
MOVE.L abRecHdl(A0), A0 ; handle to abRecord
_HUnlock ; unlock abRecord
MOVE.L (SP)+, A0 ; pop paramblk ptr from stk
_RecoverHandle ; recover hdl to paramblk
_HUnlock
_DisposHandle ; free up the paramblk
MOVE.L D2, A0 ; return addr into A0
JMP (A0) ; return to the caller
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPReqCancel - cancel a pending asynchronous ATPSndRqst or ATPRequest call
;
; FUNCTION ATPReqCancel(abRecord: ABRecHandle; async: BOOLEAN): INTEGER;
;
; This call is used to cancel any pending asynchronous ATPSndRqst or
; ATPRequest call from the Requesting End
;
; where: abRecord is the handle to the user provided ATP abus Record
;
; Returns: in the abRecord:
; abResult = error code
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Note: The .ATP driver will call the completion routine for the Request call,
; and a ReqAborted error will be returned to the original call.
;
; Modification History:
;
; 23 Oct 84 RFA New today
; 10 Jan 85 RFA wrong field name: atpTID instead of atpTransID
;
;_____________________________________________________________________________
ATPReqCancel PROC EXPORT
ENTRY CnclCommon
JSR ATPEnter2 ; standard entry
; A0 -> IO param blk, A1 -> abRecord, D2 = return address
; To abort, we must search for the queue element whose abrechndl matches
MOVE.W #RelTCB,CSCode(A0) ;cancel req code
CnclCommon
MOVE.W #atpRefNum,IORefNum(A0) ;set drvr refnum
MOVE.L atpAddress(A1),AddrBlock(A0) ;set dest addr
MOVE.W atpTID(A1),TransID(A0) ;set transaction ID
_Control ;always a sync call
MOVE.W D0,(SP) ;set return code
MOVE.L QElHdl(A0),A0 ;A0 is qel handle
JSR UnlockAndLinkHdl ;unlock it
MOVEA.L D2,A1 ;A1=return addr
JMP (A1)
ENDPROC
EJECT
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
; RESPONDING END calls
;
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;___________________________________________________________________________
;
; ATPOpenSkt
;
; FUNCTION ATPOpenSocket : (addrRcvd : AddrBlock;
; VAR atpSocket : Byte) : INTEGER;
;
; where: atpSocket - number of the socket to open (zero <=> dynamic)
; addrRcvd - four byte block with internet socket address
; from which requests are to be accepted
; (0 field == anyone)
; Returns: atpSocket - number of the socket opened
; Result code (function value)
;
; Operation: Opens an ATP responding socket for the purpose of receiving
; transaction requests. [Always synchronous call]
;
; Stack setup upon entry:
; .LONG Return address
; .LONG memory address of atpSkt var
; .LONG internet socket address of fromWhom
; .WORD Function result (result code, i.e., function value)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 17 Oct 84 RFA Cleanup
;_____________________________________________________________________________
ATPOpenSocket PROC EXPORT
JSR RemoveHdlBlks
MOVE.L (SP)+,D2 ; Save return address in D2
;
; get parameters off stack
;
MOVE.L (SP)+, A1 ; A1 = address of atpSkt
MOVE.L (SP)+, D1 ; D1 = address filter
;
; make IOParamBlk for Control call on the stack and fill in
;
SUB #IOQElSize,SP ; Allocate queue element
MOVE.L SP,A0 ; A0 -> I/O queue element
MOVE #OpenATPSkt,CSCode(A0) ; Code for "Open ATP Responding Socket"
MOVE #atpRefNum,IORefNum(A0) ; Set refnum of ATP driver
MOVE.B 1(A1), ATPSocket(A0) ; stuff socket number
MOVE.L D1, AddrBlock(A0) ; stuff address filter
_Control ; Issue the call
MOVE.B ATPSocket(A0),1(A1) ; Return socket number to caller
ADD #IOQElSize,SP ; Deallocate queue element
MOVE D0,(SP) ; Set return code for caller
MOVE.L D2,A1 ; put return address in A1
JMP (A1) ; Return to caller
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPCloseSkt
;
; FUNCTION ATPCloseSocket (atpSkt : Byte) : INTEGER;
;
; where atpSkt - number of socket to close
; Returns: Result code
;
; Operation: Close the specified ATP responding socket, and abort all
; outstanding async ATPGetRqst, ATPSndRsp, and ATPResponse calls
; involving that socket. [Always synchronous call]
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE <junk>
; .BYTE atpSkt
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1 (in completion routines), D2
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 17 Oct 84 RFA Cleanup
; 4 Jan 85 RFA Find all IOQEls for this socket and call their
; completion routines to clean up data structures
; 10 Jan 85 RFA Lock out interrupts while stepping through IOQEl list,
; and return an error to all aborted async calls.
; 11 Feb 85 GRT Removing RTE instructions
;_____________________________________________________________________________
ATPCloseSocket PROC EXPORT
JSR RemoveHdlBlks ; Go release old/free IOParamBlks
MOVE.L (SP)+,A1 ; save return address in A1
MOVE (SP)+,D2 ; get the socket number
MOVE.L A1, -(SP) ; put return address back on stack
; get space on stack for IOParamBlk for Control call
SUB #IOQElSize, SP ; Allocate queue element
MOVE.L SP, A0 ; A0 -> I/O queue element
MOVE #CloseATPSkt,CSCode(A0) ; Set code for Close Receive Socket
MOVE #atpRefNum, IORefNum(A0) ; Set refnum of ATP driver
MOVE.B D2, ATPSocket(A0) ; stuff socket number
_Control ; Issue the call
ADD #IOQElSize, SP ; remove param blk from stack
MOVE D0, 4(SP) ; Set return code for caller
; go through list of IOQEls and complete all that were associated with this socket
LEA SktQElList, A0 ; get head of list
MOVE SR, -(SP) ; save old status
MOVE #SCCLockOut, SR ; disable interrupts
MOVE.L (A0), A0 ; get first element
@10 CMP.L #0, A0 ; is the list empty?
BEQ.S @30 ; skip if empty
MOVE.L ListLink(A0), -(SP) ; get pointer to next element
CMP.B ATPSocket(A0), D2 ; is IOQEl for our socket?
BNE.S @20 ; no, check next one
MOVE #sktClosedErr, IOResult(A0) ; yes, flag it as an error
MOVE.L IOCompletion(A0),A1 ; get address of completion routine
JSR (A1) ; call its completion routine
@20 MOVE.L (SP)+, A0 ; restore pointer to next element
BRA.S @10 ; and keep searching list
@30 MOVE (SP)+,SR
RTS ; re-enable interrupts and return
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPGetRqst - specify an ATP request is to be asynchronously received
;
; FUNCTION ATPGetRequest (abRecord: ABRecHandle; async: Boolean) : INTEGER;
;
;
; where: async = TRUE if call is to be made asynchronously
; abRecord is the handle to the user-provided atp abus Record
;
; Returns: in the abus record
; atpAddress = request sender's internet skt address
; atpActCount = actual size of request's data
; atpUserBytes = the user bytes received in the request packet
; atpXO = was the request an XO request
; atpBitMap = the bit map received in the request
; atpTID = transaction ID of the request received
; abResult = Result code
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 3 Sep 84 GSS code crunch -- use ATPEnter and ATPCompFin
; 17 Oct 84 RFA Cleanup
; 4 Jan 85 RFA If async, put IOQEl on list so ATPCloseSkt can clean up
; 10 Jan 85 RFA ListDequeue no longer returns error code
;_____________________________________________________________________________
ATPGetRequest PROC EXPORT
JSR ATPEnter
; A0 -> IO param blk, A1 -> abRecord, D2 = return address
MOVE.B #tATPGetRequest,abOpCode(A1) ; write op code to abRecord
CLR.B atpEOM(A1) ; clear EOM indication in abRecord
; now prepare the IO param blk for the call to ATP
CLR.B Bitmap(A0) ; clear bitmap field
CLR TransID(A0) ; clear transaction ID field
MOVE.B atpSktNum(A1), ATPSocket(A0)
MOVE atpRCount(A1), ReqLength(A0)
MOVE.L atpDataPtr(A1), ReqPointer(A0)
; set up control calls code
MOVE #GetRequest,CSCode(A0) ; Set code for Get Request
; test to see if the request is for an async call
TST.B asyncFlg(A0) ; async call?
BEQ.S @30 ; No -- make synch call
LEA ATPGRqComp, A1 ; Yes -- asynch call
MOVE.L A1,IOCompletion(A0) ; set completion routine address
JSR ListEnqueue ; queue it up in case of cancels
_Control ,ASYNC
MOVE D0,(SP) ; return result code
BRA.S @50 ; now return to the caller
@30 _Control ; synch call
; we return here after the synch transaction is over. Call completion routine
; to free up param blk and unlock abRecord; then return to the caller
MOVE D0,(SP) ; return result code
BSR ATPGRqComp
@50 MOVE.L D2, A1 ; return address to A1
JMP (A1) ; return to caller
; I/O completion routine
;
; A0 -> I/O queue element
; abRecHdl(A0) = handle to abRecord for this request
; asyncflg(A0) = async boolean provided by the caller
ATPGRqComp MOVE.L abRecHdl(A0), A1 ; A1 = abRecord handle
MOVE.L A1, D1 ; save handle in D1
MOVE.L (A1),A1 ; deref the handle
MOVE IOResult(A0),abResult(A1) ; Save the result
BTST #ATPXOBit,ATPFlags(A0) ; See if got XO
SNE atpXO(A1) ; Set XO flag if got it
MOVE.L AddrBlock(A0),atpAddress(A1) ; requester's address
MOVE ReqLength(A0),atpActCount(A1) ; length of received request's data
MOVE.L UserData(A0),atpUserBytes(A1) ; user bytes from request
MOVE.B Bitmap(A0), atpBmap(A1) ; Set bitmap in abRecord
MOVE TransID(A0), atpTID(A1) ; trans ID received
TST.B asyncFlg(A0) ; was this an async call?
BEQ.S @10 ; no, just jump to common
JSR ListDequeue ; yes, go take IOQEl off list
@10 LEA ATPCompFin,A1 ; jump to the common part of the
JMP (A1) ; completion routine
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPSndRsp - send (part of) a response to an ATP request
;
; FUNCTION ATPSndRsp (abRecord: ABRecHandle; async: Boolean) : INTEGER;
;
;
; where: async = TRUE if call is to be made asynchronously
; abRecord is the handle to the user-provided atp abus Record
;
; Returns: in the abus record
; abResult = Result code
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 3 Sep 84 GSS Code crunch -- use ATPEnter and ATPCompFin
; 17 Oct 84 RFA Code crunch
; 22 Oct 84 RFA Added alternate entry point for ATPResponse, and
; test in completion routine so that code can be shared.
; 14 Nov 84 GRT BTST should test bit 0 and not bit 1 @ SndRspAltEntry
; 4 Jan 85 RFA If async, put IOQEl on list so ATPCloseSkt can clean up
; 10 Jan 85 RFA ListDequeue no longer returns error code
; 15 Mar 85 GRT RecoverHandle call added
; 1 May 86 GRT No more _RecoverHandle
;_____________________________________________________________________________
ATPSndRsp PROC EXPORT
ENTRY SndRspAltEntry
JSR ATPEnter
; A0 -> IO param blk, A1 -> abRecord, D2 = return address
MOVE.B #tATPSdRsp,abOpCode(A1) ; write op code to abRecord
; now prepare the IO param blk for the call to ATP. Set the EOM flag in the IOPBlk
SndRspAltEntry BTST #0, atpEOM(A1) ; (V1.1E)test EOM boolean in abRecord
BEQ.S @20 ; branch if not EOM
BSET #ATPEOMBit,ATPFlags(A0) ; set EOM flag in paramblk
; and put the rest of the params into the param blk
@20 MOVE.B atpSktNum(A1), ATPSocket(A0)
MOVE.L atpAddress(A1),AddrBlock(A0) ; requester's address
MOVE.L atpRspBDSPtr(A1), BDSPointer(A0)
MOVE.B atpNumBufs(A1),NumofBuffs(A0)
MOVE.B atpBDSSize(A1),BDSSize(A0)
MOVE atpTID(A1), TransID(A0)
; set up control call code
MOVE #SendResponse,CSCode(A0) ; Set code for Send Response
; test to see if the request is for an async call
TST.B asyncFlg(A0) ; async call?
BEQ.S @30 ; No -- make synch call
LEA ATPSdComp, A1 ; Yes -- asynch call
MOVE.L A1,IOCompletion(A0) ; set completion routine address
JSR ListEnqueue ; queue it up in case of cancels
_Control ,ASYNC
MOVE D0,(SP) ; return function code to user
BRA.S @50 ; now return to the caller
@30 _Control ; synch call
; we return here after the synch transaction is over. Call completion routine
; to free up param blk and unlock abRecord; then return to the caller
MOVE D0,(SP) ; return function code to user
BSR ATPSdComp
@50 MOVE.L D2, A1 ; A1 = return address
JMP (A1) ; return to caller
; I/O completion routine
;
; A0 -> I/O queue element
; abRecHdl(A0) = handle to abRecord for this request
; asyncflg(A0) = async boolean provided by the caller
ATPSdComp MOVE.L abRecHdl(A0), A1 ; A1 = abRecord handle
MOVE.L A1, D1 ; save handle in D1
MOVE.L (A1),A1 ; deref the handle
MOVE IOResult(A0),abResult(A1) ; Save the result
CMP.B #tATPResponse,abOpCode(A1) ; was this a ATPResponse call?
BNE.S @10 ; no, go on
; here if the call was an ATPResponse. special handling required
MOVE.L A0, -(SP) ; save IOPBlk pointer on stack
MOVE.L bdsHdl(A0),A0 ; A0 = bds handle
JSR UnlockAndLinkHdl ; queue it for disposal
MOVE.L (SP)+, A0 ; restore A0
@10 TST.B asyncFlg(A0) ; was this an async call?
BEQ.S @20 ; no, just jump to common
JSR ListDequeue ; yes, go take IOQEl off list
@20 LEA ATPCompFin, A1
JMP (A1) ; jump to the common part of the
; completion routine
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPAddRsp - add a response to a ongoing transaction [always synchronous]
;
; FUNCTION ATPAddRsp (abRecord: ABRecHandle) : INTEGER;
;
; where: abRecord = handle to Abus Record
;
; Returns: Result code in abResult field of abRecord
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .LONG abRecord handle
; .WORD Function result (return code)
;
; Register Usage:
;
; Uses registers A0, A1, D0, D1
;
; Modification History:
;
; 16 Aug 84 GSS New today
; 17 Oct 84 RFA Cleanup
; 14 Nov 84 GRT BTST should test bit 0 and not 1 of EOM pascal boolean
;_____________________________________________________________________________
ATPAddRsp PROC EXPORT
JSR RemoveHdlBlks
MOVE.L 4(SP), A0 ; get the abrecord handle from stk
_HLock ; lock the abRecord
MOVE.L A0,A1 ; A0 = abRec handle
MOVE.L (A1), A1 ; dereference handle
; Get a chunk of memory on stack for the I/O queue element
SUB #IOQElSize,SP
MOVE.L SP,A0 ; A0 -> IO param blk
; A0 -> IO param blk, A1 -> abRecord
MOVE.B #tATPAddRsp,abOpCode(A1) ; write op code to abRecord
MOVE #1,abResult(A1) ; mark abRecord as op in progress
; now prepare the IO param blk for the call to ATP. Set the EOM flag in the IOPBlk
CLR.B ATPFlags(A0) ; clear all flags in param blk
BTST #0, atpEOM(A1) ; (V1.1E)test EOM boolean in abRecord
BEQ.S @10 ; branch if not EOM
BSET #ATPEOMBit,ATPFlags(A0) ; set EOM flag in paramblk
@10
; now put the rest of the params into the param blk
MOVE.B atpSktNum(A1), ATPSocket(A0)
MOVE.L atpAddress(A1),AddrBlock(A0) ; requester's address
MOVE.B atpNumRsp(A1), RspNum(A0) ; response's seq number
MOVE atpTID(A1), TransID(A0) ; response's Transaction ID
MOVE.L atpUserBytes(A1), UserData(A0) ; user bytes for response
MOVE atpRCount(A1),ReqLength(A0) ; length of response data
MOVE.L atpDataPtr(A1),ReqPointer(A0) ; response's data buffer
; set up control calls code and the driver ref num
MOVE #AddResponse,CSCode(A0) ; Set code for Send Response
MOVE #atpRefNum, IORefNum(A0) ; .ATP driver's ref num
_Control ; always a synch call
MOVE D0, abResult(A1) ; write result into abRecord
ADD #IOQElSize,SP ; remove IO param blk from stk
MOVE.L (SP)+,A1 ; return address off stack
MOVE.L (SP)+,A0 ; abRecord handle off stack
MOVE D0, (SP) ; write func result to stk
_HUnlock ; unlock the abRecord
JMP (A1) ; return to caller
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPResponse - send a response to an ATP request - special higher-level call
; allowing the caller to specify the response as a single,
; large buffer. This code breaks that into packet-sized
; chunks for transmission. It is the inverse of ATPRequest,
; which assembles a transaction's response packets into
; one large buffer.
;
; FUNCTION ATPResponse (abRecord: ABRecHandle; async: Boolean) : INTEGER;
;
;
; where: async = TRUE if call is to be made asynchronously
; abRecord is the handle to the user-provided atp abus Record
;
; Returns: in the abus record
; abResult = Result code
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D1
;
; Notes:
; I assume that if the caller specifies a zero-length buffer,
; this means that s/he wants to send only the UserData and no
; ATP data, so I must send one packet to transmit this.
;
; Modification History:
;
; 18 Oct 84 RFA New today
; 22 Oct 84 RFA Created MakeBDS common to this call & ATPRequest
; 15 Mar 85 GRT RecoverHandle call added
; 1 May 86 GRT Saving BDS handle in queue element
;_____________________________________________________________________________
ATPResponse PROC EXPORT
JSR ATPEnter
; A0 -> IO param blk, A1 -> abRecord, D2 = return address
MOVE.B #tATPResponse, abOpCode(A1) ; write opcode to abRecord
MOVEQ #0, D1 ; clear entire register
MOVE atpRspSize(A1), D1 ; D1 = size of response buffer
CMP #maxATPBuf*8, D1 ; trying to send too much data?
BLE.S @20 ; no, continue
MOVE #atpLenErr, D0 ; yes, flag an error
; Error detected - cleanup IO parameter block and unlock abRecord
@10 MOVE D0, (SP) ; report an error in func result
MOVE D0, abResult(A1) ; report same error in abRecord
_RecoverHandle ; recover iopblk handle
_HUnlock ; unlock it
_DisposHandle ; and dispose of it
MOVE.L A1,A0
_RecoverHandle ; recover ABRec handle
_HUnlock ; just unlock it
MOVE.L D2, A0 ; recover return address
JMP (A0) ; and return to caller
; create BDS and fill it in
@20 MOVE.L A2,-(SP) ; save A2
JSR MakeBDS
MOVE.L A2,bdsHdl(A0) ; put bds handle into queue element
MOVE.L (SP)+,A2 ; restore A2
TST D0 ; any errors from MakeBDS?
BNE.S @10 ; quit if any error
MOVE.B atpNumBufs(A1), D1 ; get number of resps from abRec
MOVE.B D1, atpBDSSize(A1) ; BDS Size = number of responses
; and from here on it looks like an ordinary ATPSndRsp call, so share code
JMP SndRspAltEntry
ENDPROC
EJECT
;___________________________________________________________________________
;
; ATPRspCancel - cancels a transaction from the Responding End
;
; FUNCTION ATPRspCancel(abRecord: ABRecHandle; async: Boolean): INTEGER;
;
; This call can be used by the transaction responder to clean up ATP's
; internal data structures associated with a not-yet-completed transaction.
; One way in which this call may be used: Requester and Responder agree
; that there will be only one outstanding request between them at any time.
; They want to use XO but don't want the extra overhead of the Release
; packets. Whenever the Responder receives a new request, he assumes that
; the Requester received the previous transaction's response, so he (Responder)
; issues this call to cancel the previous transaction.
;
; where: abRecord is the handle to the user provided ATP abus Record
;
; Returns: in the abRecord:
; abResult = error code
; function result = abResult in synchronous case
;
; Stack setup upon entry:
; .LONG Return address
; .BYTE async
; .BYTE <junk> (Pascal filler)
; .LONG abRecord (handle)
; .WORD Function result (return code)
;
; Register Usage:
; Uses A0, A1, D0, D1, D2
;
; Note: The .ATP driver will call the completion routine for the Response call,
; but noErr (0) will be returned to the original call, since previous
; response packets for this transaction have probably been returned to
; the requester already.
;
; Modification History:
;
; 23 Oct 84 RFA New today
;
;_____________________________________________________________________________
ATPRspCancel PROC EXPORT
JSR ATPEnter2 ; standard entry
; A0 -> IO param blk, A1 -> abRecord, D2 = return address
MOVE #RelRspCB, CSCode(A0) ; code for "cancel response"
MOVE.B atpSktNum(A1), ATPSocket(A0) ; put skt num in IOQElement
JMP CnclCommon ; share code with ATPReqCncl
ENDPROC