mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-13 11:29:15 +00:00
766 lines
27 KiB
Plaintext
766 lines
27 KiB
Plaintext
|
;
|
||
|
; 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
|