sys7.1-doc-wip/Libs/InterfaceSrcs/piLAP.a

766 lines
27 KiB
Plaintext
Raw Normal View History

2019-07-27 14:37:48 +00:00
;
; File: piLAP.a
;
; Contains: xxx put contents here xxx
;
; Written by: xxx put writers here xxx
;
; Copyright: © 1993 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.
;
;
BLANKS ON
STRING ASIS
EJECT
;_______________________________________________________________________
;
; LAP Routines
;_______________________________________________________________________
;
;_______________________________________________________________________
;
; LAPOpenProtocol
;
; Installs a protocol handler into MPP protocol table. There are
; two protocol handler tables used in ABPasIntf; one is kept in .MPP
; containing the protocol's type number and the address of the protocol's
; handler; and another is kept here in the interface for use by the
; LAPRead call. It contains an async flag, and a pointer to a readBlock
; structure. (defined in LAPRead)
;
; A NIL value in protoPtr will automatically install this interfaces
; built-in protocol handler. My protocol table will only include types
; that use the default protocol handler.
;
; FUNCTION LAPOpenProtocol(theLAPType : HalfByte; protoPtr : Ptr): INTEGER;
;
; Stack upon entry:
;
; TOS => .LONG Return address
; .LONG Pointer to protocol handler (see above)
; .BYTE LAP type field (only 1..127 is valid)
; .BYTE pascal filler
; .WORD function result code
;
; Returns: .WORD Result code
;
; Possible errors:
; Invalid protocol type (must be 1..127)
; Protocol type already in table
; No room in protocol table
;
; Register usage: D0-D2/A0-A1
; D3 is saved/restored
;
; The IO queue element is allocated on the stack for the control call
;
; Modification History:
; 8/24/84 GRT Ready for alpha release
; 8/28/84 GRT general code crunching pass
; 1/9/85 GRT Error 'AttErr' changed to 'LAPProtErr'
;
;_______________________________________________________________________
LAPOpenProtocol PROC EXPORT
IMPORT LAPProtoHdlr
JSR RemoveHdlBlks ; check for disposable handles
MOVE.L (SP)+,D2 ; save return address
MOVE.L (SP)+,A1 ; get protocol handler ptr
LEA tmpHandler,A0
MOVE.L A1,(A0) ; save for later
MOVE.L A1,D1 ; is it zero??
BNE.S @10 ; if not then branch and continue
LEA LAPProtoHdlr,A1 ; get address of built-in hdlr
@10 MOVE.B (SP)+,D1 ; lap type field
MOVE.L D3,-(SP) ; save D3 register
MOVE #LAPProtErr,D0 ; assume error
MOVE.B D1,D3 ; transfer register over
BEQ.S @90 ; check for a zero
SUB #IOQElSize,SP ; allocate space for the IOQEl
MOVE.L SP,A0 ; A0 -> IO queue element block
MOVE.B D3,ProtType(A0) ; lap type
MOVE.L A1,Handler(A0) ; protocol handler
MOVE #AttachPH,CSCode(A0) ; code for attach proto hndlr
MOVE #MPPRefNum,IORefNum(A0) ; set refnum up
_Control
ADD #IOQElSize,SP ; deallocate the queue element
BNE.S @90 ; check to see if control call had error
; store the protocol address and type in my own table for use by the READ op,
; but only if the proto address passed to us was zero.
MOVE.L tmpHandler,D1 ; was the proto handler for us?
BNE.S @90
LEA myHndlrTable,A1 ; A1 -> table of pr handlers
MOVE #(maxHndlr-1)*entrySize,D1 ; start at the end of the list
@20 TST.B theHndlr(A1,D1) ; is there a free entry (zero?)
BEQ.S @30 ; if zero then free so branch
SUBQ #entrySize,D1 ; change index number
BPL.S @20 ; check again
MOVE #LAPProtErr,D0 ; no free entry in table (ERROR)
BRA.S @90
@30 CLR.L thePtr(A1,D1) ; no read blocks linked in yet
MOVE.B D3,theHndlr(A1,D1) ; store the LAP type
CLR.B theRcvFlag(A1,D1) ; zero out the pkt rcvd flag
@90 JMP ExitD3 ; restore D3, set func result and exit
ENDPROC
EJECT
;_______________________________________________________________________
;
; LAPCloseProtocol
;
; Detaches the protocol handler from the table(s). Error is returned if
; the LAP type was not found in the MPP table. My protocol table is also
; scanned to remove the protocol type, but if it's not found, it is
; ignored. It is then assumed that the protocol type was for a protocol
; handler other than mine and therefore it was never installed in my
; table in the first place.
;
; FUNCTION LAPCloseProtocol(theLAPType : HalfByte): INTEGER;
;
; Stack upon entry:
;
; TOS => .LONG Return address
; .BYTE LAP type
; .BYTE pascal filler
; .WORD function result code
;
; Returns: .WORD Result code
;
; Possible errors:
; Protocol type not found in table.
;
; The IO queue element is allocated on the stack for the control call
;
; Modification History:
; 8/24/84 GRT Ready for alpha release
; 8/28/84 GRT no longer using D3
; 10/1/84 RFA,GRT register fun (changing register usage)
;
;_______________________________________________________________________
LAPCloseProtocol PROC EXPORT
JSR RemoveHdlBlks ; check to see if handles need to be disposed
MOVE.L (SP)+,D2 ; save return address
MOVE.B (SP)+,D1 ; get LAP type
SUB #IOQElSize,SP ; allocate IOQElement
MOVE.L SP,A0 ; A0 -> IOQEl
MOVE.B D1,ProtType(A0) ; pass parameter to IOQ
MOVE #DetachPH,CSCode(A0) ; control code
MOVE #MPPRefNum,IORefNum(A0) ; set refnum up
_Control ; make the call
ADD #IOQElSize,SP ; deallocate the IOQ element
BNE.S @20 ; check for error in control call
; Scan through table until either an matched entry is found, or until
; the end of the table is reached.
; Note#1: At this point we have successfully removed it from MPP's variable
; area. If we can't find the type in our local table, we ignore the error
; since we accomplished what we wanted anyways. (Why it's not there is beyond
; me)
LEA myHndlrTable,A1 ; A1 -> table of pr handlers
MOVE #(maxHndlr-1)*entrySize,D0 ; start at the end of the list
@05 CMP.B theHndlr(A1,D0),D1 ; do they match?
BEQ.S @10 ; OK so exit
SUBQ #entrySize,D0 ; down one entry
BPL.S @05
BRA.S @15 ; not here, so just exit (see note#1)
@10 CLR.B theHndlr(A1,D0) ; zero out the field to nullify it
@15 CLR D0 ; no errors
@20 JMP ExitD0 ; set func result and exit
ENDPROC
EJECT
;_______________________________________________________________________
;
; LAPWrite
;
; 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 (currently eventCode #10) back to the application.
;
; The ABRecHandle is locked down during most of the call. As for all async
; calls, abResult will contain a 1 in it as long as the operation is still
; in progress.
;
; The WDS used by MPP for writing is allocated under the IOQ element block.
;
; FUNCTION LAPWrite(abRecord : ABRecHandle; async : BOOLEAN): INTEGER;
;
; Stack upon entry:
;
; TOS => .LONG Return address
; .BYTE async 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:
;
;
; Upon allocation of the IOQElement block, an additional n bytes are
; allocated at the end. The data structure looks like this:
;
; |=========================|
; : :
; : IOQElement blk : 50 bytes
; : :
; : :
; |=========================|
; : AB record handle : 4 byte handle to AB record
; |-------------------------|
; : Q Element handle : 4 byte handle to this queue element
; |-------------------------|
; : 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
; |=========================|
; | WDS dest node address | 1 byte (WDS element1 data; odd aligned)
; |-------------------------|
; | unused | 1 byte (LAP src address goes here)
; |-------------------------|
; | WDS lap type field | 1 byte
; |=========================|
;
; The pointer in WDS element1 will always point to the data portion of the
; element (stored under the async flag). This data is always 3 bytes long.
;
; Modification History:
; 8/24/84 GRT Ready for alpha release
; 8/29/84 GRT Code crunching
; 10/1/84 RFA GetHdlAndLock needs long word parameter instead of word
; 12/17/84 GRT CmpEventPost changed to Cmp1EventPost
; 2/7/85 GRT LAPProtType byte moved incorrectly into WDS header
; 4/30/86 GRT Saving queue element handle in the queue element
;_______________________________________________________________________
LAPWrite PROC EXPORT
JSR RemoveHdlBlks ; check to see if handles need to be disposed
MOVE.L (SP)+,D2 ; save return address
MOVE.B (SP)+,D1 ; save async flag
MOVE.L (SP),A0 ; copy of record handle
MOVE.L (SP)+,A1 ; another record handle copy made
MOVEM.L A2-A3,-(SP) ; save A2-A3
_HLock ; lock abRecord down
BNE @30 ; if not zero return an error
MOVE.L (A1),A2 ; A2 -> Ptr to ABRecord
MOVE #1,abResult(A2) ; 1 means we are currently in execution
MOVE.B #tLAPWrite,abOpCode(A2) ; put call type in record
; We are allocating an extra 22 bytes at the end of the IOQElement for storage
; of the misc data (see diagram)
MOVE.L #IOQElSize+WDSXtraLAPSize,D0 ; number of bytes to allocate
JSR GetHdlAndLock ; allocate the memory A0->IOQElement Hdl
BNE.S @30 ; error if didn't work
MOVE.L A0,D0 ; save handle
MOVE.L (A0),A0 ; A0 -> IOQElement blk (dereferenced)
MOVE.L D0,qElHdl(A0) ; save handle in the queue element
; A2 points to ABRecord. A0 points to IOQElement
MOVE.B D1,ABAsyncFlag(A0) ; async flag stored in IOQELBlk+18
MOVE.L A1,ABRecHdl(A0) ; save handle in IOQElement blk
LEA WDS1stEntry(A0),A3 ; address of the WDS header entry
; currently A3 is ODD aligned
; Fill up the WDS data at the end of the IOQ element block
LEA WDS1Start(A0),A1 ; start of WDS stuff
MOVE.L A1,WDSPointer(A0) ; move it into the IOQEl param area
MOVE #LAPHdSz,(A1)+ ; length is always 3 for the addr block
MOVE.L A3,(A1)+ ; stuff dest add ptr
MOVE lapReqCount(A2),(A1)+ ; buffer size to write out
MOVE.L lapDataPtr(A2),(A1)+ ; buffer data pointer
CLR (A1) ; zero means end of WDS
LEA lapAddress(A2),A1 ; address of the addr block
MOVE.B (A1),(A3) ; dest node into WDS header
MOVE.B 2(A1),2(A3) ; move proto type into WDS header
MOVE #WriteLAP,CSCode(A0) ; set control code
LEA WriteCompletion,A2 ; A2 -> our IO completion routine
JSR DoControlCall ; make the control call
@30 MOVEM.L (SP)+,A2-A3 ; restore A2-A3
JMP ExitD0 ; set func result and exit
;_______________________________________________________________________
; This routine is called when the IO has been completed
; A0 -> IOQElBlk
;_______________________________________________________________________
WriteCompletion
; on entry, A0 -> IOQElement block
MOVEM.L D0/A0-A2,-(SP) ; save registers
JSR CmpEntrance ; set up registers and unlock ab record hdl
JSR Cmp1EventPost ; post event if needed
MOVEM.L (SP)+,D0/A0-A2 ; restore registers
RTS
ENDPROC
EJECT
;_______________________________________________________________________
;
; LAPRead
;
; Read a packet coming in from the cable. If the call is sync, it will
; wait in a loop until a packet is recieved in its buffer. If made
; async, an event will be posted upon reception. Note that if two async
; calls are made and then a sync call is made, 3 packets must be received
; before control will return to the user! The sync call will only return
; when a packet has been recieved in the buffer that was used for the sync
; call.
;
; IMPORTANT: The LAPRead call can only be used with the built in protocol
; handler.
;
; The ABRecHandle is locked down until the call completes. The protocol
; handler is responsible for unlocking it. (unless an error occurs in the
; read queueing)
;
; FUNCTION LAPRead(abRecord : ABRecHandle; async : BOOLEAN): INTEGER;
;
; Stack upon entry:
;
; TOS => .LONG Return address
; .BYTE async 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:
;
;
; A 14 byte read block is allocated dynamically for every read call. This
; block is linked in a FIFO queue for every handler type. When a pkt is
; received, the first read block is taken and the packets data is put where
; the ptr points to. If the buffer is not big enough, the remaining part of
; the packet is discarded and an error is returned to the application. The
; packet up to the point of the end of the buffer, however, is returned intact.
;
; |=========================|
; | |
; | Link to next read blk | 4 byte pointer link
; | |
; | |
; |-------------------------|
; : AB record handle | 4 byte hdl to AB record
; |-------------------------|
; : Q element handle | 4 byte hdl to this queue element
; |-------------------------|
; | async flag | 1 byte
; |-------------------------|
; | unused | 1 byte
; |=========================|
;
; Modification History:
; 8/24/84 Ready for alpha release (GRT)
; 10/1/84 RFA GetHdlAndLock needs long word parameter
; 3/15/85 GRT Added RecoverHandle call
; 4/30/86 GRT Saving queue element handle in the queue element
;_______________________________________________________________________
LAPRead PROC EXPORT
ENTRY LAPProtoHdlr
JSR RemoveHdlBlks ; any handles to dispose of?
MOVE.L (SP)+,D2 ; save return address
MOVE.B (SP)+,D1 ; save async flag
MOVE.L (SP),A0 ; record handle copy made
MOVE.L (SP)+,A1 ; and another in A1
MOVEM.L A2-A4,-(SP) ; save A2-4 for later
_HLock ; lock it down
BNE ReadLExit ; if error then exit
MOVE.L A0,A4 ; save temporarily
MOVE.L (A4),A2 ; A2 -> Ptr to ABRecord
MOVE #1,abResult(A2) ; 1 means we are currently in execution
MOVE.B #tLAPRead,abOpCode(A2) ; put call type in
MOVEQ #rdBlkSize,D0 ; size of a read blk entry
JSR GetHdlAndLock ; get a handle to the memory
; A0 has handle to new memory block (to be used for the read block)
BNE.S ReadL1Exit ; 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) ; move handle to queue element
; A0 -> my read block A2 -> AB record
; first stuff the read blk full of data
CLR.L rbNxPtr(A0) ; zero out ptr to next element
MOVE.L A1,rbABHdl(A0) ; copy the AB rec hdl into it
MOVE.B D1,rbAFlag(A0) ; save the aysnc byte flag
; now check the hndlr table for the matching type field
MOVE.B lapAType(A2),D0 ; get the lap type
BEQ.S @06 ; zero type is invalid
LEA myHndlrTable,A1 ; A1 -> table of prot handlers
MOVE #(maxHndlr-1)*entrySize,D1 ; start at the end of the table
@05 CMP.B theHndlr(A1,D1),D0 ; do they match?
BEQ.S @10 ; OK so exit
SUBQ #entrySize,D1 ; down one entry
BPL.S @05
@06 MOVE.L A4,A0 ; recover the handle
JSR UnlockAndLinkHdl ; get rid of the read blk
MOVE #readQErr,D0 ; set error code
BRA.S ReadL1Exit
; 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
@10 CLR.B theRcvFlag(A1,D1) ; zero out the pkt recvd flag if sync
MOVE SR,-(SP) ; save status register on stack
ORI.W #SCCLockOut,SR ; lock out the SCC interrupts <SM2> rb
LEA thePtr(A1,D1),A4 ; A4 -> read element entry link
MOVE.L (A4),A3 ; A3 -> next read element
@15 MOVE.L A3,D0 ; is it the end of the link?
BEQ.S @20 ; if so, then we found the end
MOVE.L A3,A4 ; save previous ptr
MOVE.L (A3),A3 ; get next ptr in link
BRA.S @15 ; back and check
@20 MOVE.L A0,0(A4) ; put the read blk into link
MOVE (SP)+,SR ; restore interrupt status
CLR D0 ; no errors if we got here!
TST.B rbAFlag(A0) ; is this an async call?
BNE.S ReadLExit ; 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 theRcvFlag(A1,D1) ; has a packet been received?
BEQ.S @25 ; if not, then wait
MOVE abResult(A2),D0 ; get result of operation into D0
BRA.S ReadLExit
; If an error occurred, but we have already locked memory blk, unlock blk
ReadL1Exit MOVE D0,D1 ; save error code
MOVE.L A2,A0 ; get the abRecHandle
_RecoverHandle
_HUnlock ; unlock the handle if no call was made
MOVE D1,D0 ; recover error code
ReadLExit MOVEM.L (SP)+,A2-A4 ; restore registers
JMP ExitD0 ; set func result (D0) and exit
; The table entries in memory are organized by entries and not by types.
;
; ENTRY 1: | protoHdlr Type (1)| Pkt rcvd flag (1)| read block link ptr (4)|
; ENTRY 2: | protoHdlr Type (1)| Pkt rcvd flag (1)| read block link ptr (4)|
; ENTRY 3: | protoHdlr Type (1)| Pkt rcvd flag (1)| read block link ptr (4)|
; ENTRY 4: | protoHdlr Type (1)| Pkt rcvd flag (1)| read block link ptr (4)|
EJECT
;_______________________________________________________________________
;
; LAPProtoHdlr
;
; This is the LAP protocol handler used in reading straight LAP packets.
; It is called by the MPP driver when a packet has been received if the
; type field has been installed by the AttachPH routine.
;
; The first two data bytes of the LAP packet have already been read into
; the RHA. (actually the RHA also has the 3 byte LAP hdr in it too)
;
; If you didn't already know it, the first two bytes of the data field of
; the LAP packet must be the length bytes in order for this to work!!
;
; Call:
; A0,A1 .LONG SCC read/write addresses (preserve)
; A2 .LONG local vars (preserve)
; A3 .LONG ptr into the RHA (5 bytes already loaded in)
; A4 .LONG address of the ReadPacket routine
; A5 .LONG useable until ReadRest is called
; 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)
; 10/1/84 RFA,GRT Code crunching pass made
; 3/15/85 GRT RecoverHandle call added
; 4/30/86 GRT Getting rid of the _RecoverHandle traps
;_______________________________________________________________________
LAPProtoHdlr
; MPP subtracts two from the length bytes of the packet. We have to make sure
; that D1 contains at least one byte to read, else we skip this section
MOVEQ #4,D3 ; we want to read in at most 4 bytes
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 myRHALen,A5 ; address of storage area
MOVE D3,(A5) ; save 'bytes to read'
BEQ.S @03 ; dont read if zero bytes left
JSR (A4) ; read the bytes into the RHA and adjust
BNE.S @08 ; if error then exit
; now that we've bought some time, scan through the table to find a buffer
; A2 -> MPP vars
; A3 -> modified RHA ptr
; D1 = number of bytes left to read in
@03 MOVE.L A3,-(SP) ; save RHA ptr
MOVEM.L A0-A1,-(SP) ; save other registers
LEA myHndlrTable,A5 ; A5 -> table of pr handlers
MOVE #(maxHndlr-1)*entrySize,D2 ; start at the end of the list
LEA ToRHA(A2),A0 ; address of top of RHA
MOVE.B LAPType(A0),D3 ; get lap type of packet from RHA
; D2 = entry number in PHT
@05 CMP.B theHndlr(A5,D2),D3 ; do they match?
BEQ.S @10
SUBQ #entrySize,D2 ; next entry
BPL.S @05 ; go back and check the next one
; No valid type in table. Ignore packet
@07 MOVEM.L (SP)+,A0-A1 ; restore the registers back
MOVE.L (SP)+,A3 ; restore RHA ptr
MOVEQ #0,D3 ; tells MPP we don't want the pkt
JMP 2(A4) ; read in the rest of the packet; exit
; Exit point - it's here because we want short branches!
@08 RTS
; We have found the entry so get how many bytes to read and read them into buf
@10 LEA tmpHndlrEntry,A1
MOVE D2,(A1) ; save the entry offset in the table
MOVE.L thePtr(A5,D2),A0 ; A0 -> read block structure
CMP #0,A0 ; is there a buffer there?
BEQ.S @07 ; if not, ignore the pkt
MOVE.L rbABHdl(A0),A0 ; A1 -> AB record ptr
MOVE.L (A0),A1 ; dereference handle
MOVE.L lapDataPtr(A1),A3 ; A3 -> data buffer
MOVE myRHALen,D2 ; get length saved up
ADDQ #2,D2 ; add the length bytes
ADD D2,A3 ; modify ptr
MOVE lapReqCount(A1),D3 ; D3 = number of bytes want to read
SUB D2,D3 ; D3 = bytes to read - what I've already read
MOVEM.L (SP)+,A0-A1 ; restore them back
JSR 2(A4) ; read in rest of packet
; D3 = number of bytes read compared to the buffer length (if less than zero, the
; buffer was not big enough!
; after call 2(A4) [ReadRest], we are able to use all conventional registers again
MOVE.L (SP)+,A3 ; restore RHA ptr (CCs not affected)
BNE @40 ; if error, branch
TST D3 ; check length info
BGE.S @13 ; if buffer is OK then branch
MOVE #buf2SmallErr,D0 ; buffer was not big enough
; copy bytes from the RHA into the users buffer
@13 MOVE myRHALen,D2 ; get length of rha
ADDQ #2,D2 ; add length bytes
SUB D2,A3 ; point to beginning of RHA data (not lap hdr)
MOVE tmpHndlrEntry,D1 ; get offset
LEA myHndlrTable,A1 ; address of my prot handler table
MOVE.L thePtr(A1,D1),A1 ; get the read block ptr
MOVE.L rbABHdl(A1),A0 ; get the ab record handle
MOVE.L (A0),A0 ; and dereference
CMP lapReqCount(A0),D2 ; is buffer big enough to hold RHA?
BLE.S @14 ; yes, proceed
MOVE lapReqCount(A0),D2 ; no, only copy bufSize bytes
@14 MOVE (A3),lapActCount(A0) ; actual bytes read in
MOVE.L lapDataPtr(A0),A2 ; A2 -> input data buffer
@15 SUBQ #1,D2 ; dec counter
BLT.S @18 ; 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
; A0 -> ABrecord
@18 LEA myHndlrTable,A2 ; "wheres the table?"
MOVE D0,abResult(A0) ; set return result code
SUB #3,A3 ; A3 -> beginning of RHA!
MOVE.B (A3)+,lapADest(A0) ; move dst byte to record
MOVE.B (A3),lapASource(A0) ; move src node ID to record
MOVE.L rbABHdl(A1),A0 ; A0 = handle to AB record
_HUnlock ; unlock the ABRecord handle
TST.B rbAFlag(A1) ; test async flag
BEQ.S @20 ; if false branch
; it's async so post the event
MOVE.L A0,D0 ; event message (ABRecHandle)
MOVE #networkEvt,A0 ; event code
_PostEvent ; post event to caller; D0=err code
BRA.S @30
; it's sync so set the packet recvd flag
@20 ST theRcvFlag(A2,D1) ; set the pkt recvd flag to true
; unlink and unlock read block from the queue (has to be at the beginning)
@30 MOVE.L 0(A1),thePtr(A2,D1) ; unlink read blk
MOVE.L rbHdl(A1),A0 ; A0 = handle to read block
JSR UnlockAndLinkHdl ; dispose of the handle
@40 RTS
ENDPROC
EJECT
;_______________________________________________________________________
;
; LAPRdCancel
;
; Cancel a pending asynchronous LAPRead and free its associated data structures.
;
; IMPORTANT: The LAPRdCancel call can only be used with asynchronous LAPRead
; calls on a protocol type whose protocol handler 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 LAPRdCancel(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 Protocol Type (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:
;
; 12/20/84 GRT New today from code originally written by RFA for DDP
; 3/15/85 GRT RecoverHandle call added
;
;_______________________________________________________________________
LAPRdCancel PROC EXPORT
JSR RemoveHdlBlks ; check disposable handles
MOVEM.L (SP)+, D2/A0 ; D2 = return adr, A0 = abRec hdl
MOVEM.L D3/A2-A3, -(SP) ; save some registers
; first check my protocol handler table for the matching protocol type
MOVE #readQErr,D0 ; assume an error
MOVE.L (A0),A2 ; A2 -> ABRecord
MOVE.B lapAType(A2),D3 ; get the lap type
BEQ.S LRdCnclExit ; zero is invalid
; scan table: D3 = lap type; A2 = abRecord ptr
LEA myHndlrTable,A1 ; A1 -> table of pr handlers
MOVE #(maxHndlr-1)*entrySize,D1 ; start at the end of the list
@05 CMP.B theHndlr(A1,D1),D3 ; do they match?
BEQ.S @07 ; OK so exit
SUBQ #entrySize,D1 ; down one entry
BPL.S @05
BRA.S LRdCnclExit ; if not found then leave
; we found the type, so search list of Read Blocks for one that points to abRec
; A1 -> protocol handler table
@07 MOVE #recNotFnd, D0 ; assume an error
LEA thePtr(A1,D1), A1 ; A1 = head of Read Block queue
MOVE SR, -(SP) ; save old status
ORI.W #SCCLockout, SR ; disable interrupts <SM2> rb
; the first time through, the check for the next element is made in the table;
; from then on, the check is made through the queue
@10 MOVE.L rbNxPtr(A1), A3 ; check next element
MOVE.L A3,D3 ; is there a next element?
; check A3 for zero (in SR)
BNE.S @20 ; yes, continue checks
MOVE (SP)+, SR ; no, we're at the end & no match!
BRA.S LRdCnclExit ; restore interrupt state & return
@20 CMPA.L rbABHdl(A3), A0 ; is this the RdBlk for our abRec?
BEQ.S FoundLIt ; 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
FoundLIt 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
; A0 still contains the abRecHandle to remove; A3 -> read block to dispose of
_HUnlock ; unlock the abRecord
MOVE.L A3,A0
_RecoverHandle ; recover handle to Read Block
_HUnlock ; unlock it and dispose of it
_DisposHandle ; (hopefully clears D0 as well)
LRdCnclExit MOVEM.L (SP)+, D3/A2-A3 ; restore registers
JSR ExitD0
ENDPROC