sys7.1-doc-wip/Libs/InterfaceSrcs/piATP.a
2019-07-27 22:37:48 +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