mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-02-05 07:31:15 +00:00
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1826 lines
64 KiB
Plaintext
1826 lines
64 KiB
Plaintext
;
|
||
; File: EtherNet.a -> SonicEnet.a
|
||
;
|
||
; Contains: Shell for Ethernet driver
|
||
;
|
||
; Written by: Sean Findley
|
||
;
|
||
; Copyright: © 1990-91 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM4> 1/29/93 RB Do not move #$2600 to the status register, always do an ORI.W
|
||
; with it so that NuKernel works and the stack is not changed.
|
||
; <SM3> 10/28/92 SWC Changed the INCLUDEs to a LOAD of StandardEqu.d.
|
||
; <SM2> 10/26/92 mal Updated controltable COMMENTS with correct snmp enet control
|
||
; codes, 238-242; note, these snmp enet control codes are still
|
||
; unimplemented and return controlerr.
|
||
; <1> 10/6/92 GDW New location for ROMLink tool.
|
||
; <SM2> 6/22/92 mal Changed Open so ptr and size to data passed to LOOPBACKTEST;
|
||
; added SNMP control calls to control table but don't support yet.
|
||
; <1> 6/12/92 RLM first checked in
|
||
; <P3> 5/13/92 KW (JC,H5) Change driver to support configuration information
|
||
; obtained from ecfg resource rather than from using boxflag
|
||
; driven tables.
|
||
; (JC,H4) Add support for new machines to boxflag driven tables.
|
||
; <P2> 02/07/92 jmp (jmp,H3/BG/SJF,Z12) Added fixes for the possible loss of
|
||
; transmit buffers. Also turn off interrupts around processing
|
||
; the CAM.
|
||
; <1> 2/4/92 mal first checked in
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; Pre-Pandora ROM comments begin here.
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; <11> 10/22/91 SAM Added Sean Findley's changes to correct an interaction problem
|
||
; with VM/Ethernet. From Zydeco-Terror ROM.
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; Pre-Zydeco ROM comments begin here.
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; <10> 5/22/91 BG Removed a _DetachResource in the driver that Sean says shouldn't
|
||
; be there. Also changed a BEQ to a BEQ.S to LoopError in Open.
|
||
; <9> 4/21/91 CCH Rolled in Sean Findley's changes.
|
||
; <8> 4/2/91 CCH Added a cache flush after the blockmove to the write buffer.
|
||
; <7> 3/19/91 BG Enabled the _MemoryDispatch call for logical-to-physical
|
||
; translation in TranslateAddress. Previously, it was returning
|
||
; the logical address since it knew that logical=physical in the
|
||
; Eclipse/Spike cases.
|
||
; <6> 3/14/91 BG (for SJF) A number of changes:
|
||
; - Driver variables now allocated via _NewPtr to save
|
||
; space on disk.
|
||
; - When installing/removing a SlotMgr interrupt routine
|
||
; the slot number is not hard-coded to 9.
|
||
; - Removed all calls to _SwapMMUMode since the Sonic
|
||
; base address is accessible in both 24- and 32-bit modes.
|
||
; - Implement VM support
|
||
; - Activate the "extended Motorola mode" for the AVF
|
||
; SONIC parts.
|
||
; <5> 2/26/91 JK Added extended Motorola mode code, and GetPhysical call.
|
||
; <4> 2/1/91 JK Rolled in Ethernet code review changes.
|
||
; <3> 1/31/91 JK Hacked in call to LockMemoryContiguous.
|
||
; <2> 1/9/91 JK Fixed to use Ethernet address PROM on Eclipse motherboard.
|
||
; <1> 12/14/90 JK Added to build
|
||
;
|
||
|
||
TITLE 'Ethernet Driver'
|
||
;___________________________________________________________________________
|
||
;
|
||
; Ethernet Data Link Level Driver
|
||
;
|
||
; Sean Findley
|
||
; January 1990
|
||
|
||
PRINT OFF
|
||
LOAD 'StandardEqu.d'
|
||
INCLUDE 'Slots.a' ; Slot interrupt equates
|
||
INCLUDE 'GestaltEqu.a'
|
||
|
||
INCLUDE 'ATalkMacros.a' ; Nifty Macros
|
||
|
||
PRINT NOGEN,NOMDIR,ON
|
||
INCLUDE 'ENETEqu.a' ; Driver definitions
|
||
INCLUDE 'SonicEqu.a' ; SONIC chip definitions
|
||
EJECT
|
||
|
||
RxParms RECORD {A6Link} ; stack frame for received packets <T6> thru next <T6>
|
||
Size EQU *
|
||
InUse EQU * ; in use flag (long)
|
||
A6Link DS.L 1
|
||
Return DS.L 1
|
||
Status DS.L 1 ; status of recv
|
||
Length DS.L 1 ; length of packet
|
||
Data DS.L 1 ; data pointer
|
||
DCE DS.L 1 ; DCE pointer
|
||
RxDesc DS.L 1 ; buffer descriptor pointer
|
||
ParmsSz EQU * - Status ; positive size of frame
|
||
ENDR
|
||
|
||
NumBuffers EQU 8 ; "optimal" number of buffers
|
||
|
||
; Sonic Configuration Record <H5 begin>
|
||
SCFG RECORD 0 ; Config values from config rsrc
|
||
SONICBase24 DS.L 1 ; Base address of SONIC in 24 bit mode
|
||
SONICBase32 DS.L 1 ; Base address of SONIC in 32 bit mode
|
||
EnetPROM DS.L 1 ; base address of Address Prom in 32 bit mode
|
||
DataCfgLpBk DS.L 1 ; DataConfig reg values during loopback tests
|
||
DataCfgRun DS.L 1 ; DataConfig reg values during normal operation
|
||
DataCfg2 DS.L 1 ; DataConfig 2 reg
|
||
SONICSlot DS.B 1 ; Logical slot of SONIC for the slot manager
|
||
SmartMMU DS.B 1 ; Non-zero if system has smart MMU code
|
||
; The following are optional values; ignored if zero
|
||
EnetAddr DS.B 6 ; Alternate Ethernet Address, overrides Address PROM
|
||
NumRxBuffs DS.W 1 ; Alternate number of receive buffers
|
||
NumTxBuffs DS.W 1 ; Alternate number of transmit buffers
|
||
CfgSize EQU *
|
||
ENDR ; <H5 end>
|
||
|
||
OurV RECORD 0 ; our variables
|
||
OurDCE DS.L 1 ; Offset to our DCE pointer in variables
|
||
InfoStart EQU * ; Start of returned info
|
||
OurAddr DS.B EAddrSz ; Our Ethernet address
|
||
OverWrtCnt DS.L 1 ; Count of number of overwrites (long)
|
||
TimeoutCnt DS.L 1 ; Count of timeouts on writes (long)
|
||
BadDestCnt DS.L 1 ; Count of packets received not to us (long)
|
||
InfoEnd EQU * ; End of returned info
|
||
MaxData DS.W 1 ; Max data size for write
|
||
RHA DS.B EHdrSize ; Read Header Area
|
||
;___________________________________________________________________________
|
||
;
|
||
; The LAP protocol handler table starts here. Format:
|
||
; .BYTE InUseFlag1,..., InUseFlagN ; Entry in use flag
|
||
; .WORD ProtCode1, ..., ProtCodeN ; Protocol type codes
|
||
; .LONG PHAddr1, ..., PHAddrN ; Protocol handler addresses
|
||
; .LONG RdQueueHd1, ..., RdQueueHdN ; Read queue heads
|
||
;___________________________________________________________________________
|
||
LAPTblSz EQU 16 ; Size of LAP protocol handler table (even)
|
||
InUseFlag DS.B LAPTblSz ; Entry in use flag
|
||
Protocols DS.W LAPTblSz ; List of active protocols
|
||
Handlers DS.L LAPTblSz ; List of handler addresses
|
||
RdQueueHd DS.L LAPTblSz ; Read queue heads
|
||
LAPTblEnd EQU * ; End of LAP table
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; Multicast address table. Entry format:
|
||
; Ethernet address (6 bytes)
|
||
; Use count (1 byte). Zero means entry free.
|
||
; Unused (1 byte)
|
||
;___________________________________________________________________________
|
||
|
||
MTblSz EQU 8 ; Size (in entries) of multicast address table (???)
|
||
MEntrySz EQU 8 ; Size of an entry (power of 2)
|
||
MUseCount EQU EAddrSz ; Offset to use count in entry
|
||
|
||
MultiCTbl DS.B MTblSz*MEntrySz ; A list of valid addresses
|
||
EtherStats DS NetStats ; SONIC network statistics
|
||
SONICmem DS.L 1 ; header to xmit buffer list
|
||
deferCtl DS.W 1 ; flag=true if deferring ctl call
|
||
VBLQEL DS.B 14 ; VBL for ctl call deferrals
|
||
AddrMask DS.L 1 ; 32 bit mask for addresses
|
||
BlockMove DS.L 1 ; trap address of block move
|
||
LastRxDesc DS.L 1 ; current rx descriptor address
|
||
WrBuffHdr DS.L 1 ; header to free xmit buffers
|
||
XmitWait DS.W 1 ; flag to indicate write waiting for buffers
|
||
XmitBuffs DS.L 1 ; # of xmit buffers
|
||
PLTable DS.L 1 ; ptr to address translation table
|
||
MachID DS.W 1 ; id of CPU (from Gestalt)
|
||
DataCache DS.L 1 ; stored value of data cache reg on LC 030
|
||
CacheCount DS.L 1 ; use count for cache
|
||
SONICCfg DS SCFG ; SONIC config data from config rsrc <H5>
|
||
; ¥¥¥¥¥¥¥¥ WARNING ¥¥¥¥¥¥¥¥¥
|
||
; The following array MUST be the LAST item in the vars list. It is used only if VM is
|
||
; running. If not, it is trimmed off the required memory for the driver.
|
||
RxDefBuffs DS.B RxParms.ParmsSz * NumBuffers ; if VM running, only Numbuffers max. allowed
|
||
|
||
DataSize EQU * ; End of variables
|
||
ENDR
|
||
|
||
;_______________________________________
|
||
;
|
||
; Other definitions
|
||
;_______________________________________
|
||
|
||
OneWdsSz EQU 8 ; single fragment wds size
|
||
|
||
PtoL RECORD 0
|
||
Physical DS.L 1 ; physical address of xmit buffer
|
||
Logical DS.L 1 ; associated logical addr
|
||
Size EQU *
|
||
ENDR
|
||
|
||
XmitRec RECORD 0 ; <Z12>
|
||
DS.B Max_Pkt_Size+OneWdsSz+PtoL.Size ; memory for each xmit buffer <Z12>
|
||
ALIGN 4 ; make sure MOD 4 size <Z12>
|
||
Size EQU * ; <Z12>
|
||
ENDR ; <Z12>
|
||
|
||
AMaxDataSz EQU 768-EHdrSize ; Maximum data size for AppleTalk mode
|
||
|
||
IntLockOut EQU $400 ; SR value to lock interrupts <SM4> rb
|
||
|
||
BlockMoveTrap EQU $A02E ; trap value for _BlockMove
|
||
|
||
|
||
Configrsrc EQU 'ecfg' ; rsrc type for sonic config data rsrc <H5>
|
||
|
||
|
||
NeedDefer EQU 5 ; bit indicates VM is running <H5>
|
||
EJECT
|
||
|
||
ENETDriver MAIN EXPORT
|
||
|
||
STRING PASCAL
|
||
MACHINE MC68020
|
||
|
||
IMPORT SONICINIT,SONICXMIT,SONICCAMLOAD,SONICFREEBUFF,SONICHALT
|
||
IMPORT ResetSONIC,RestartSONIC
|
||
IMPORT LOOPBACKTEST
|
||
|
||
WITH SONICRegs,OurV
|
||
|
||
; *****************************************
|
||
; * *
|
||
; * Start of ENET driver *
|
||
; * *
|
||
; *****************************************
|
||
ENET
|
||
;
|
||
; Driver header
|
||
;
|
||
DC.W $4400 ; Control, Locked, no Goodbye
|
||
DC.W 0,0 ; No time, no events
|
||
DC.W 0 ; No menu
|
||
|
||
;
|
||
; Entry points offset table
|
||
;
|
||
DC.W Open-ENET
|
||
DC.W AnRTS-ENET
|
||
DC.W Control-ENET
|
||
DC.W AnRTS-ENET
|
||
DC.W Close-ENET
|
||
|
||
DC.W '.ENET' ; Driver name
|
||
ALIGN 2
|
||
|
||
INCLUDE 'VersionEclipse.a'
|
||
|
||
;________________________________________________________________________
|
||
;
|
||
; Open - initialize the ENET driver
|
||
;
|
||
; Called:
|
||
; D0 = 0
|
||
; A0 -> queue element
|
||
; A1 -> DCE
|
||
;________________________________________________________________________
|
||
|
||
|
||
|
||
Open
|
||
LINK A6,#0 ; mark the stack for easy exit
|
||
|
||
MOVE.L A1,-(SP) ; save DCE pointer <T6>
|
||
|
||
MOVE.L #gestaltVMAttr,D0 ; see if VM is running <T6>
|
||
_Gestalt ; <T6>
|
||
BNE.S @noVM ; it isn't if call failed <T6>
|
||
MOVE.L A0,D0 ; <T6>
|
||
BEQ.S @noVM ; zero result means no VM running <T6>
|
||
|
||
BSET #NeedDefer,dCtlStorage(A1) ; indicate VM is running <T6>
|
||
BSET #VMImmuneBit,dCtlFlags+1(A1) ; tell VM to leave our calls alone <T6>
|
||
@noVM ; <T6>
|
||
|
||
LEA OurVarPtr,A3 ; A3 -> variable pointer
|
||
;
|
||
; Allocate our variables
|
||
;
|
||
MOVE.L #DataSize,D0 ; variables size
|
||
BTST #NeedDefer,dCtlStorage(A1) ; is VM running?
|
||
BNE.S @10 ; yes, get full memory
|
||
SUBI.L #RxParms.ParmsSz * NumBuffers,D0
|
||
; adjust memory requirement
|
||
@10
|
||
_NewPtr ,SYS,CLEAR ; get memory
|
||
BNE OpenError
|
||
|
||
MOVE.L A0,(A3) ; save variable pointer
|
||
MOVEA.L A0,A2 ; A2 -> variable space
|
||
|
||
MOVE.B SonicEnet,DCtlQueue+1(A1) ; Version number goes here
|
||
|
||
MOVE.L A1,D0
|
||
_StripAddress
|
||
MOVE.L D0,OurDCE(A2) ; Save our DCE address <H5>
|
||
|
||
MOVE.W #BlockMoveTrap,D0
|
||
_GetTrapAddress
|
||
MOVE.L A0,BlockMove(A2) ; save trap address in our vars
|
||
|
||
MOVE #EMaxDataSz,MaxData(A2) ; Set AppleTalk mode max data size
|
||
;
|
||
; Look for a SONIC configuration resource for this CPU <H5 begin>
|
||
;
|
||
MOVE.L #gestaltMachineType,D0
|
||
_Gestalt ; get our machine type
|
||
MOVE.L A0,D0
|
||
MOVE D0,MachID(A2) ; save our machine ID
|
||
|
||
SUBQ #4,SP ; Make room for handle
|
||
MOVE.L #Configrsrc,-(SP) ; Push resource type
|
||
MOVE D0,-(SP) ; Set machine ID as resource ID
|
||
_GetResource ; Get it from system file
|
||
MOVE.L (SP)+,D0 ; D0 = handle to config resource
|
||
BNE.S @21 ; Bra if we found it
|
||
|
||
SUBQ #4,SP ; Make room for handle
|
||
MOVE.L #Configrsrc,-(SP) ; Push resource type
|
||
MOVE MachID(A2),-(SP) ; Set machine ID as resource ID
|
||
MOVE #MapTrue,ROMMapInsert ; Look for resource in sys ROM
|
||
_GetResource ; Get it from ROM
|
||
MOVE.L (SP)+,D0 ; D0 = handle to config resource
|
||
BNE.S @21
|
||
MOVEQ #-1,D0 ; return with generic error (D0=-1)
|
||
BRA OpenError ; return, config rsrc not found
|
||
|
||
@21 MOVEA.L D0, A3 ; Save handle to resource
|
||
|
||
MOVEA.L (A3), A0 ; A0-> config resource
|
||
LEA SONICCfg(A2), A1 ; A1-> space in our vars
|
||
MOVE.L #SCFG.CfgSize, D0
|
||
_BlockMove ; Copy data from rsrc to our vars
|
||
|
||
MOVE.L A3, -(SP) ; push handle
|
||
_ReleaseResource ; We're thru with config resource
|
||
|
||
LEA SONICCfg.EnetAddr(A2), A0 ; A0-> alternate ethernet address
|
||
TST.L (A0) ; Check address
|
||
BNE.S @22
|
||
TST 4(A0)
|
||
BEQ.S @23 ; Ignore if all zeros
|
||
@22
|
||
BTST #0,(A0) ; Make sure it's not a multicast addr
|
||
BNE.S @23 ; Ignore it if it is
|
||
MOVE.L (A0)+,OurAddr(A2) ; Move four bytes to our address
|
||
MOVE (A0)+,OurAddr+4(A2) ; Move the last two bytes
|
||
@23
|
||
MOVEQ #NumBuffers,D2 ; set desired # of buffers
|
||
MOVE.L D2,D3 ; D2=xmit,D3=recv
|
||
|
||
MOVE SONICCfg.NumTxBuffs(A2),D0 ; get alternate # xmit buffers
|
||
BEQ.S @24 ; don't override if zero
|
||
MOVE D0, D2 ; override default # xmit buffers
|
||
@24
|
||
BTST #NeedDefer,([OurDCE,A2],dCtlStorage) ; is VM running?
|
||
BNE.S @25 ; Yes, don't override # recv buffers
|
||
|
||
MOVE SONICCfg.NumRxBuffs(A2),D0 ; get alternate # recv buffers
|
||
BEQ.S @25 ; don't override if zero
|
||
MOVE D0, D3 ; override default # recv buffers <H5 end>
|
||
@25
|
||
|
||
; D2=# xmit buffers to allocate, D3=# recv buffers to allocate
|
||
|
||
@GetMemory
|
||
CMPI.W #Min_Rx_Buffs,D3 ; have mininum number of buffers?
|
||
BLO.S @nomem ; no, get out
|
||
|
||
MOVE.L #Ctl_Mem_Size,D0 ; add up memory needed
|
||
|
||
MOVE.L #Rxpkt.RxRDAsize,D1
|
||
MULU D3,D1
|
||
ADD.L D1,D0 ; D0=memory for all descriptors
|
||
LSL.L #1,D0 ; times 2
|
||
|
||
MOVE.L #Max_Pkt_Size,D1
|
||
MULU D3,D1
|
||
ADD.L D1,D0 ; D0=memory for receive buffers
|
||
|
||
MOVE.L D0,D4 ; save SONIC memory size for later
|
||
|
||
MOVE.L D2,D1 ; D1=# xmit buffs
|
||
|
||
MULU #XmitRec.Size,D1 ; D1=memory needed for xmit buffs <Z12>
|
||
|
||
ADD.L D1,D0 ; D0=memory for recv and xmit buffs
|
||
|
||
MOVE.L D0,D5 ; remember size of Sonic memory
|
||
|
||
_NewPtr ,SYS,CLEAR ; get the memory
|
||
BEQ.S @haveMem ; use it
|
||
|
||
SUBQ.L #1,D2 ; adjust # xmit buffers first
|
||
BHI.S @GetMemory
|
||
MOVEQ #1,D2 ; set back to mininum of one
|
||
SUBQ.L #1,D3 ; adjust # recv buffers last
|
||
BHI.S @GetMemory
|
||
@nomem
|
||
MOVE.W #mFulErr,D0
|
||
BRA OpenError ; get out with error
|
||
@haveMem
|
||
BTST #NeedDefer,([OurDCE,A2],dCtlStorage)
|
||
BNE.S @haveMemDispatch ; VM is running, ok to call _VM
|
||
|
||
TST.B SONICCfg.SmartMMU(A2) ; no VM, do we have smart MMU code? <H5>
|
||
BEQ.S @nolock ; no, don't lock memory <H5>
|
||
|
||
@haveMemDispatch
|
||
MOVE.L A1,-(SP) ; save a1
|
||
MOVEA.L D5,A1 ; length of buffer
|
||
MOVEQ #4,D0 ; LockMemoryContiguous
|
||
_MemoryDispatch ; MemoryDispatch <T3><T6>
|
||
MOVEA.L (SP)+,A1 ; restore a1
|
||
BNE OpenError ; failed, so bail
|
||
|
||
@nolock ; <H5>
|
||
MOVE.L D2,XmitBuffs(A2) ; save # of xmit buffers
|
||
|
||
MOVE.L D1,D5 ; save xmit buffers size for later
|
||
|
||
MOVE.L A0,D0
|
||
_StripAddress
|
||
MOVEA.L D0,A0
|
||
MOVE.L D0,SONICmem(A2) ; save ptr in our vars
|
||
MOVE.L A0,WrBuffHdr(A2) ; set header pointer
|
||
|
||
MOVE.L D2,D0
|
||
SUBQ.W #1,D0 ; adjust loop count
|
||
BRA.S @db1
|
||
@setBufLink ; link together xmit buffers
|
||
PEA Max_Pkt_Size+OneWdsSz(A0)
|
||
MOVE.L (SP),(A0) ; set link to next buffer
|
||
MOVEA.L (SP)+,A0 ; point to next buffer
|
||
@db1
|
||
DBRA D0,@setBufLink ; do them all
|
||
CLR.L (A0) ; clear the last one
|
||
|
||
LEA Max_Pkt_Size+OneWdsSz(A0),A0 ; A0->Physical to Logical Table
|
||
|
||
MOVE.L A0,PLTable(A2) ; save address of translation table
|
||
MOVEA.L WrBuffHdr(A2),A1 ; A1->1st buffer
|
||
|
||
MOVE.L D2,D1 ; D1=# xmit buffs
|
||
BRA.S @db2
|
||
@setupWDS
|
||
MOVEM.L A0/D1,-(SP)
|
||
MOVE.L #Max_Pkt_Size+OneWdsSz,-(SP) ; logical size
|
||
MOVE.L A1,-(SP) ; logical address
|
||
BSR TranslateAddress ; get physical address in D0
|
||
MOVEA.L (SP)+,A1 ; get back buffer addr
|
||
ADDQ.W #4,SP ; trash length
|
||
MOVEM.L (SP)+,A0/D1
|
||
MOVE.L A1,PtoL.Logical(A0) ; save logical address
|
||
MOVE.L D0,PtoL.Physical(A0) ; save physical address
|
||
MOVE.L D0,Max_Pkt_Size+2(A1) ; in WDS too
|
||
LEA PtoL.Size(A0),A0 ; next table entry
|
||
LEA Max_Pkt_Size+OneWdsSz(A1),A1 ; next buffer
|
||
@db2
|
||
DBRA D1,@setupWDS ; translate all xmit buff addresses
|
||
|
||
LEA OurAddr(A2),A1
|
||
TST.L (A1)
|
||
BNE.S @45 ; already have an address
|
||
TST.W 4(A1)
|
||
BNE.S @45 ; already have an address
|
||
; Must be in 32 bit mode to examine Ethernet address PROM on an LC, doesn't matter for others <Z12>
|
||
MOVEQ #true32b,D0 ; <Z12>
|
||
_SwapMMUMode ; put us in 32-bit mode <Z12>
|
||
MOVE.B D0,-(SP) ; save prior MMU status <Z12>
|
||
|
||
BSR AddrPromAddr ; A0->address prom <Z12>
|
||
MOVEQ #0,D1 ; setup to checksum the PROM address<Z12>
|
||
MOVEQ #7,D0 ; do 8 bytes <Z12>
|
||
@Xor
|
||
MOVE.B (A0)+,D2 ; get byte to XOR
|
||
EOR.B D2,D1
|
||
DBRA D0,@Xor ; do them all <Z12>
|
||
SUBI.B #$FF,D1 ; end result should be $FF <Z12>
|
||
BEQ.S @GetAddr ; keep going if it is <Z12>
|
||
|
||
MOVE.B (SP)+,D0 ; <Z12>
|
||
_SwapMMUMode ; put back mmu <Z12>
|
||
MOVEQ #-1,D0 ; <Z12>
|
||
BRA OpenError ; return with generic error (D0=-1) <Z12>
|
||
@GetAddr ; <Z12>
|
||
ADDQ.W #EAddrSz,A1 ; go from last to first <Z12>
|
||
|
||
BSR AddrPromAddr ; A0->address prom <Z12>
|
||
MOVEQ #EAddrSz-1,D2 ; get 6 addr bytes
|
||
@35
|
||
MOVE.B (A0,D2.W),D0 ; D0=inverted address
|
||
BSR NormAddr ; normalize it
|
||
MOVE.B D0,-(A1) ; store in our vars
|
||
DBRA D2,@35
|
||
|
||
MOVE.B (SP)+,D0 ; <Z12>
|
||
_SwapMMUMode ; put back mmu <Z12>
|
||
@45
|
||
|
||
MOVEQ #-1,D0
|
||
_StripAddress
|
||
MOVE.L D0,AddrMask(A2) ; save cached 32 bit address mask
|
||
|
||
SUBA.W #SONICinitParms.ParmSize,SP ; make room for parms
|
||
PEA TranslateAddress ; addr of our log->phys addr translation
|
||
MOVE.L (SP)+,SONICinitParms.TransAddr(SP)
|
||
; translation table proc address
|
||
BSR SONICAddr ; A0->SONIC
|
||
|
||
; So far, only the Quadra's need this register set...
|
||
MOVE.L SONICCfg.DataCfg2(A2), D0 ; setup SONIC extended data config <H5>
|
||
SMOVE D0,Data_Config2(A0) ; set extended data config <H5>
|
||
|
||
MOVE.L SONICCfg.DataCfgLpBk(A2), D0 ; setup SONIC data config for loopback tests <H5>
|
||
|
||
MOVE.L D0,SONICinitParms.DataConfig(SP)
|
||
|
||
PEA EtherStats(A2) ; ptr to stats array
|
||
MOVE.L (SP)+,SONICinitParms.NetStatArray(SP)
|
||
|
||
PEA IntEnable ; interrupt enable routine
|
||
MOVE.L (SP)+,SONICinitParms.IntEnable(SP)
|
||
|
||
PEA IntDisable
|
||
MOVE.L (SP)+,SONICinitParms.IntDisable(SP)
|
||
; disable interrupts routine
|
||
|
||
MOVE.L D3,SONICinitParms.NumRxBuffs(SP)
|
||
; # of receive buffers
|
||
|
||
MOVE.L D4,SONICinitParms.MemSize(SP) ; size of sonic mem
|
||
|
||
MOVE.L SONICmem(A2),SONICinitParms.MemStart(SP)
|
||
ADD.L D5,SONICinitParms.MemStart(SP) ; ptr to sonic mem
|
||
|
||
MOVE.L A2,SONICinitParms.TRANPrms(SP) ; trans complete parms
|
||
|
||
PEA XmitDone
|
||
MOVE.L (SP)+,SONICinitParms.TRANRtn(SP)
|
||
; proc to call for xmit complete
|
||
|
||
MOVE.L OurDCE(A2),SONICinitParms.RECVPrms(SP)
|
||
; recv complete parms
|
||
PEA EtherRecv
|
||
MOVE.L (SP)+,SONICinitParms.RECVRtn(SP)
|
||
; proc to call for recvd packets
|
||
|
||
PEA IntInstallation
|
||
MOVE.L (SP)+,SONICinitParms.IntInstall(SP)
|
||
; interrupt proc installation routine
|
||
|
||
BSR SONICAddr ; <Z12>
|
||
MOVE.L A0,SONICinitParms.SONICbase(SP) ; <Z12>
|
||
|
||
BSR DataCacheOff ; turn off data cache on LC 030 <Z12>
|
||
|
||
BSR SONICINIT ; initialize sonic chip
|
||
ADDA.W #SONICinitParms.ParmSize,SP ; strip parms
|
||
|
||
BSR DataCacheOn ; turn data cache back on <Z12>
|
||
|
||
BLT OpenError ; init failed
|
||
BEQ.S @loadCAM
|
||
|
||
NEG.L D0
|
||
MOVE.L D0,-(SP) ; memory not used
|
||
MOVEA.L SONICmem(A2),A0 ; addr of SONIC memory
|
||
_GetPtrSize ,SYS
|
||
ADD.L (SP)+,D0 ; adjust pointer size
|
||
_SetPtrSize ,SYS
|
||
@loadCAM
|
||
SUBA.W #CAMparms.ParmSize,SP ; make room for CAM parms
|
||
MOVE.L #-1,CAMparms.LoadorClear(SP) ; add an entry
|
||
MOVE.L OurAddr+2(A2),CAMparms.EAddr+2(SP)
|
||
MOVE.W OurAddr(A2),CAMparms.EAddr(SP)
|
||
BSR SONICAddr ; <Z12> thru next <Z12>
|
||
MOVE.L A0,CAMparms.SONICPtr(SP) ; pass SONIC base address
|
||
|
||
BSR DataCacheOff ; turn off data cache on LC 030
|
||
BSR SONICCAMLOAD ; put our address in CAM
|
||
ADDA.W #CAMparms.ParmSize,SP
|
||
BSR DataCacheOn ; turn data cache back on <Z12>
|
||
; perform 3 SONIC loopback tests, if any fails, return an open error
|
||
|
||
|
||
Move.l #SonicEnetLongStrEnd-SonicEnetLongStr-1, -(SP) ; pass size of loopback
|
||
; data, minus 1 since pascal string
|
||
Pea SonicEnetLongStr+1 ; pass ptr to loopback data
|
||
PEA OurAddr(A2) ; pass ptr to our address
|
||
MOVEA.L OurDCE(A2),A1 ; get ptr to DCE
|
||
MOVE.W dCtlRefNum(A1),D0
|
||
MOVE.L D0,-(SP) ; pass our refnum for ctl calls
|
||
|
||
BSR SONICAddr
|
||
MOVEA.L A0,A3 ; SONIC base address
|
||
|
||
SMOVE Recv_Control(A3),D0 ; get recv_control reg
|
||
EORI.W #(1<<RecvErrors)+(1<<RecvRunts)+(1<<RecvBroadCast),D0
|
||
; turn off broadcast reception
|
||
|
||
ORI.W #MACLoopBack,D0
|
||
SMOVE D0,Recv_Control(A3) ; setup for MAC loopback test
|
||
BSR LOOPBACKTEST ; D0 0 if passed
|
||
BEQ LoopError ; failed
|
||
|
||
SMOVE Recv_Control(A3),D0 ; get recv_control reg
|
||
EORI.W #MACLoopBack,D0 ; turn off MAC loopback
|
||
ORI.W #ENDECLoopBack,D0
|
||
SMOVE D0,Recv_Control(A3) ; setup for ENDEC loopback test
|
||
BSR LOOPBACKTEST ; D0 0 if passed
|
||
BEQ.S LoopError ; failed
|
||
|
||
SMOVE Recv_Control(A3),D0 ; get recv_control reg
|
||
EORI.W #ENDECLoopBack,D0 ; turn off ENDEC loopback
|
||
ORI.W #TxRxLoopBack,D0
|
||
SMOVE D0,Recv_Control(A3) ; setup for TxRx loopback test
|
||
BSR LOOPBACKTEST ; D0 0 if passed
|
||
BEQ.S LoopError ; failed
|
||
|
||
SMOVE Recv_Control(A3),D0 ; get recv_control reg
|
||
EORI.W #TxRxLoopBack,D0 ; turn off TxRx loopback
|
||
ORI.W #(1<<RecvErrors)+(1<<RecvRunts)+(1<<RecvBroadCast),D0
|
||
; turn on broadcast reception
|
||
SMOVE D0,Recv_Control(A3) ; turn off loopback mode
|
||
|
||
EXG A2,A3 ; A2->SONIC Registers
|
||
BSR ResetSONIC ; get ready to change FIFO threshholds
|
||
SMOVE Data_Config(A2),D0 ; get current configuration data
|
||
MOVE.L SONICCfg.DataCfgLpBk(A3), D1 ; get loopback setup data configuration <H5>
|
||
ANDI.W #$000F,D1 ; access only FIFO settings
|
||
EOR.W D1,D0 ; clear initial FIFO threshholds
|
||
MOVE.L SONICCfg.DataCfgRun(A3), D1 ; get runtime setup data configuration <H5>
|
||
OR.W D1,D0 ; set runtime threshholds (requests bus less often)
|
||
SMOVE D0,Data_Config(A2)
|
||
BSR RestartSONIC ; start SONIC back up for loopback tests
|
||
EXG A2,A3 ; A3->SONIC Registers
|
||
|
||
ADDQ.W #8,SP ; strip loopback test parms
|
||
|
||
MOVEA.L (SP)+,A1 ; get back DCE
|
||
|
||
LEA VBLQEL(A2),A0
|
||
MOVE.W #vType,vblType(A0)
|
||
PEA ControlDefer
|
||
MOVE.L (SP)+,vblAddr(A0)
|
||
MOVE.W #32767,vblCount(A0) ; setup control call deferral timer
|
||
_VInstall
|
||
|
||
MOVEQ #noErr,D0 ; Indicate no error
|
||
UNLK A6
|
||
RTS ; And return
|
||
|
||
LoopError ; failed one of 3 loopback tests
|
||
ADDQ.W #8,SP ; strip loopback test parms
|
||
BSR Close ; shut down SONIC
|
||
MOVEA.L (SP)+,A1 ; get back DCE
|
||
MOVEQ #-1,D0
|
||
BRA.S OpenErrDone ; return with open error
|
||
;
|
||
; Open error - clear out variable pointer for next try
|
||
;
|
||
OpenError
|
||
MOVE.W D0,D3 ; save error code
|
||
|
||
MOVEA.L (SP)+,A1 ; A1->DCE
|
||
TST.L SONICmem(A2)
|
||
BEQ.S @55 ; mem not allocated
|
||
MOVEA.L SONICmem(A2),A0
|
||
_DisposPtr ; free it up
|
||
@55
|
||
LEA OurVarPtr,A3 ; A3 -> our variable pointer
|
||
CLR.L (A3) ; Clear it out
|
||
MOVE.W D3,D0
|
||
OpenErrDone
|
||
CMPI.W #-1,D0 ; translate generic error
|
||
BNE.S @60
|
||
MOVEQ #openErr,D0
|
||
@60
|
||
TST.W D0
|
||
UNLK A6
|
||
RTS ; Return with error
|
||
|
||
NormAddr ; convert IEEE address to normal format
|
||
MOVEM.L D2,-(SP)
|
||
CLR.B D1
|
||
MOVEQ #7,D2
|
||
@loop
|
||
LSL.B #1,D1 ; get ready for next bit
|
||
LSR.B #1,D0 ; get a bit from source
|
||
BCC.S @lb ; non there
|
||
ADDQ.B #1,D1
|
||
@lb
|
||
DBRA D2,@loop
|
||
MOVE.B D1,D0 ; D0=converted value
|
||
MOVEM.L (SP)+,D2
|
||
RTS
|
||
|
||
|
||
; Ptr TranslateAddress(laddr,lsize) ; translate logical to physical addrs
|
||
MemBlk RECORD 0
|
||
address DS.L 1
|
||
count DS.L 1
|
||
ENDR
|
||
|
||
TraAdd RECORD {A6Link}
|
||
LinkSz EQU *
|
||
logical DS MemBlk
|
||
physical DS MemBlk
|
||
A6Link DS.L 2 ; link and return addr
|
||
laddr DS.L 1 ; logical address
|
||
lsize DS.L 1 ; logical size
|
||
ENDR
|
||
TranslateAddress
|
||
WITH TraAdd
|
||
LINK A6,#LinkSz
|
||
MOVE.L laddr(A6),logical.address(A6)
|
||
MOVE.L laddr(A6),physical.address(A6)
|
||
|
||
MOVEA.L OurVarPtr,A0
|
||
BTST #NeedDefer,([OurDCE,A0],dCtlStorage)
|
||
BNE.S @haveMemDispatch ; VM is running, ok to call _VM
|
||
|
||
TST.B SONICCfg.SmartMMU(A0) ; no VM, do we have smart MMU code? <H5>
|
||
BEQ.S @nophy ; no, no need to get physical address <H5>
|
||
@haveMemDispatch
|
||
MOVE.L lsize(A6),logical.count(A6)
|
||
LEA logical(A6),A0 ; A0->translation table
|
||
LEA 1,A1 ; A1=count to translate
|
||
MOVEQ #5,D0 ; selector
|
||
|
||
_MemoryDispatch ; MemoryDispatch <T3><T6>
|
||
@nophy ; <H5>
|
||
MOVE.L physical.Address(A6),D0 ; return lowest physical address
|
||
|
||
UNLK A6
|
||
RTS
|
||
ENDWITH
|
||
|
||
; SR IntDisable(); ; disable interrupts and return SR
|
||
IntDisable
|
||
MOVE SR,D0
|
||
ORI.W #$600,SR ; <SM4> rb
|
||
RTS
|
||
|
||
; void IntEnable(SR) ; restore SR from prior disable call
|
||
IntEnable
|
||
MOVE.W 6(SP),SR ; do it
|
||
RTS
|
||
|
||
; IntInstallation(SONIChandler)
|
||
|
||
IntInstallation ; called by SONIC init
|
||
WITH SlotIntQElement
|
||
LEA SONIChandler,A0
|
||
MOVE.L 4(SP),(A0) ; store SONIC interrupt handler
|
||
LEA SONICintQ,A0 ; interrupt queue element
|
||
MOVE.W #sIQType,SQType(A0) ; set type
|
||
PEA SONICInterrupt ; addr of handler
|
||
MOVE.L (SP)+,SQAddr(A0)
|
||
MOVE.W #200,SQPrio(A0) ; priority for now
|
||
MOVEA.L OurVarPtr,A1
|
||
SUB.L D0,D0
|
||
MOVE.B SONICCfg.SONICSlot(A1), D0 ; setup slot from config values <H5>
|
||
_SIntInstall ; install handler
|
||
RTS
|
||
ENDWITH
|
||
SONICInterrupt
|
||
MOVEM.L A0/D1-D3,-(SP) ; Mac OS assumes these are scratch <Z12>
|
||
BSR SONICAddr ; get SONIC address in A0 <Z12>
|
||
MOVE.L A0,-(SP) ; pass SONIC base address <Z12>
|
||
BSR DataCacheOff ; turn off data cache on LC 030 <Z12>
|
||
MOVEA.L SONIChandler,A1 ; <Z12>
|
||
JSR (A1) ; <Z12>
|
||
ADDQ.W #4,SP ; <Z12>
|
||
BSR DataCacheOn ; turn data cache back on <Z12>
|
||
MOVEM.L (SP)+,A0/D1-D3 ; <Z12>
|
||
MOVEQ #-1,D0 ; indicate we processed this interrupt
|
||
RTS
|
||
|
||
;________________________________________________________________________
|
||
;
|
||
; Control - control requests to driver - all ENET calls come in here.
|
||
;
|
||
; Call: A0 -> I/O queue element
|
||
; A1 -> device control entry
|
||
;________________________________________________________________________
|
||
|
||
ControlDefer ; task to complete a deferred control call
|
||
MOVE.W #32767,vblCount(A0) ; next task is a long time maybe
|
||
_StackSpace ; D0 = avail. stack space
|
||
TST.L D0
|
||
BMI.S @defer ; defer if negative space
|
||
CMPI.L #512,D0 ; is there a little room?
|
||
BHS.S @doControl ; yes
|
||
@defer
|
||
MOVE.W #1,VBLCount(A0) ; restart fast timer
|
||
@exit
|
||
RTS ; and get out
|
||
@doControl
|
||
LEA -VBLQEL(A0),A2 ; A2->our vars
|
||
BCLR #0,deferCtl(A2)
|
||
BEQ.S @exit ; return to VBL if not really deferring
|
||
|
||
MOVEA.L OurDCE(A2),A1 ; A1->our DCE
|
||
MOVEA.L dCtlQHead(A1),A0 ; A0->param block in use
|
||
BRA.S doControl
|
||
Control
|
||
MOVE.W ioTrap(A0),D0 ; get trap word that called us
|
||
|
||
BTST #asyncTrpBit,D0 ; is this a synchronous call?
|
||
BEQ.S doControl ; yes, bypass stack check
|
||
|
||
_StackSpace ; D0 = avail. stack space
|
||
TST.L D0
|
||
BMI.S @defer ; defer if negative space
|
||
CMPI.L #512,D0 ; is there a little room?
|
||
BHS.S doControl ; yes
|
||
@defer
|
||
MOVEA.L OurVarPtr,A2 ; A2->our vars
|
||
BSET #0,deferCtl(A2) ; indicate we are deferring
|
||
MOVE.W #1,vblCount+VBLQEL(A2) ; set next vbl to tick fast
|
||
CRTS
|
||
MOVEQ #noErr,D0 ; good return for now
|
||
RTS ; get out and get stack back
|
||
doControl
|
||
MOVE.W CSCode(A0),D2 ; Pickup control code
|
||
SUBQ #KillCode,D2 ; Check for OS kill I/O call
|
||
BEQ.S CRTS ; return if so
|
||
|
||
MOVEQ #ControlErr,D0 ; Assume a control error
|
||
MOVE.L OurVarPtr,A2 ; A2 -> our variables
|
||
SUB #FirstENET-KillCode,D2 ; Subtract off lowest command
|
||
BLT ENETDone ; Return error if too low
|
||
CMP #LastENET-FirstENET,D2 ; Make sure not too high
|
||
BGT ENETDone ; Return error if too high
|
||
MOVE CSParam(A0),D1 ; D1 = 1st parameter word (protocol)
|
||
MOVE.L CSParam+2(A0),D3 ; D3 = 1st parameter longword (e.g. WDSP)
|
||
;
|
||
; Pick up routine address for this command and jump to routine
|
||
;
|
||
MOVE.W (ControlTable,D2.W*2),D2 ; get offset of routine
|
||
JMP (ControlTable,D2.W) ; go do the call
|
||
|
||
;_________________________________________________________________________
|
||
;
|
||
; Control dispatch table - must be in the same order as the ENET commands.
|
||
; Specifies offsets to the command-handling routines.
|
||
;_________________________________________________________________________
|
||
|
||
ControlTable
|
||
DC.w ENETDONE-ControlTable ; 238 LapGetDot3Entry
|
||
DC.w ENETDONE-ControlTable ; 239 LapSetDot3Entry
|
||
DC.w ENETDONE-ControlTable ; 240 LapDot3Stats
|
||
DC.w ENETDONE-ControlTable ; 241 LapDot3CollStats
|
||
DC.w ENETDONE-ControlTable ; 242 LapGetLinkStatus
|
||
DC.w ENETOK-ControlTable ; 243 CloseSAP
|
||
DC.w ENETOK-ControlTable ; 244 OpenSAP
|
||
DC.w DoDelMulti-ControlTable ; 245
|
||
DC.w DoAddMulti-ControlTable ; 246
|
||
DC.w DoAttachPH-ControlTable ; 247
|
||
DC.w DoDetachPH-ControlTable ; 248
|
||
DC.w DoWrite-ControlTable ; 249
|
||
DC.w DoRead-ControlTable ; 250
|
||
DC.w DoRdCancel-ControlTable ; 251
|
||
DC.w DoGetInfo-ControlTable ; 252
|
||
DC.w ENETOK-ControlTable ; 253 DoSetGeneral
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoAddMulti - add a multicast address to the list
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D1 = first two bytes of address
|
||
; D3 = last four bytes of address
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoAddMulti
|
||
MOVEQ #eMultiErr,D0 ; Assume invalid address or table full
|
||
BTST #8,D1 ; Make sure multicast bit is set
|
||
BEQ ENETDone ; Return error if invalid multicast address
|
||
BSR FindMEntry ; D2 = entry number for this address
|
||
BPL.S @40 ; Branch if found it
|
||
;
|
||
; Look for the first free one
|
||
;
|
||
MOVEQ #MTblSz-1,D2 ; D2 = no. of entries in multicast table
|
||
@30 TST.B (MultiCTbl+MUseCount,A2,D2*MEntrySz)
|
||
; This one free?
|
||
DBEQ D2,@30 ; Loop until checked them all or got one
|
||
@35 BNE ENETDone ; Error if none free
|
||
|
||
;
|
||
; Set in table, then compute and set hash bit in appropriate multicast address register (MAR)
|
||
;
|
||
@40 MOVE.L D3,(MultiCTbl+2,A2,D2*MEntrySz)
|
||
; Set second part of address
|
||
MOVE D1,(MultiCTbl,A2,D2*MEntrySz)
|
||
; Set first part of address
|
||
ADDQ.B #1,(MultiCTbl+MUseCount,A2,D2*MEntrySz)
|
||
CMPI.B #1,(MultiCTbl+MUseCount,A2,D2*MEntrySz)
|
||
BHI ENETOK
|
||
|
||
|
||
SUBA.W #CAMparms.ParmSize,SP ; make room for CAM parms
|
||
MOVE.L #-1,CAMparms.LoadorClear(SP) ; we are adding a CAM entry
|
||
MOVE.L D3,CAMparms.EAddr+2(SP) ; lower 32 bits
|
||
MOVE.W D1,CAMparms.EAddr(SP) ; upper 16 bits
|
||
BSR SONICAddr ; <Z12>
|
||
MOVE.L A0,CAMparms.SONICPtr(SP) ; pass SONIC base address <Z12>
|
||
BSR DataCacheOff ; turn off data cache on LC 030 <Z12>
|
||
BSR SONICCAMLOAD ; add this entry
|
||
ADDA.W #CAMparms.ParmSize,SP
|
||
BSR DataCacheOn ; turn data cache back on <Z12>
|
||
|
||
BRA ENETOK ; That's it
|
||
|
||
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoDelMulti - delete a multicast address to the list
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D1 = first two bytes of address
|
||
; D3 = last four bytes of address
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;
|
||
; Decrements the use count for the given address
|
||
;___________________________________________________________________________
|
||
|
||
DoDelMulti MOVEQ #eMultiErr,D0 ; Assume address not found
|
||
BSR.S FindMEntry ; D2 = entry number in table
|
||
BMI.S ENETDone ; Return error if not found
|
||
SUBQ.B #1,(MultiCTbl+MUseCount,A2,D2*MEntrySz)
|
||
; Decrement use count
|
||
BNE.S ENETOK
|
||
|
||
|
||
SUBA.W #CAMparms.ParmSize,SP ; make room for CAM parms
|
||
CLR.L CAMparms.LoadorClear(SP) ; we are deleting a CAM entry
|
||
MOVE.L D3,CAMparms.EAddr+2(SP) ; lower 32 bits
|
||
MOVE.W D1,CAMparms.EAddr(SP) ; upper 16 bits
|
||
BSR SONICAddr ; <Z12>
|
||
MOVE.L A0,CAMparms.SONICPtr(SP) ; pass SONIC base address <Z12>
|
||
BSR DataCacheOff ; turn off data cache on LC 030 <Z12>
|
||
BSR SONICCAMLOAD ; delete this entry
|
||
ADDA.W #CAMparms.ParmSize,SP
|
||
BSR DataCacheOn ; turn data cache back on <Z12>
|
||
|
||
BRA.S ENETOK ; Return no error
|
||
;
|
||
; FindMEntry - find this address's entry in the multicast table
|
||
;
|
||
; Call:
|
||
; D1 = high two bytes of address
|
||
; D3 = low four bytes of address
|
||
; A2 -> our variables
|
||
;
|
||
; Return:
|
||
; D2 = entry number within table (minus if not found). CCR set.
|
||
;
|
||
|
||
FindMEntry MOVEQ #MTblSz-1,D2 ; D2 = no. of entries in multicast table
|
||
@10 TST.B (MultiCTbl+MUseCount,A2,D2*MEntrySz)
|
||
; Is this entry in use?
|
||
BEQ.S @20 ; Branch if not
|
||
CMP (MultiCTbl,A2,D2*MEntrySz),D1
|
||
; This it?
|
||
BNE.S @20 ; Branch if not
|
||
CMP.L (MultiCTbl+2,A2,D2*MEntrySz),D3
|
||
; Is it?
|
||
BEQ.S @30 ; Branch if got it
|
||
@20 DBRA D2,@10 ; Loop until checked them all
|
||
@30 TST D2 ; Set CCR
|
||
RTS ; And return
|
||
|
||
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoAttachPH - attach protocol handler control call
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D3 = address of protocol handler's packet-receive code or zero
|
||
; D1 = protocol type code
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoAttachPH
|
||
AND.L AddrMask(A2),D3 ; 32 bit clean
|
||
|
||
MOVEQ #LAPProtErr,D0 ; Assume an invalid protocol error
|
||
;
|
||
; Read down the active protocol table, searching for a match
|
||
;
|
||
@10 BSR.S GetProt ; See if it's there
|
||
BPL.S ENETDone ; Return error if protocol already active
|
||
;
|
||
; Now scan for the first free one . . .
|
||
;
|
||
MOVEQ #LAPTblSz-1,D2 ; Index into active protocols list
|
||
@20 TST.B InUseFlag(A2,D2) ; Check this entry
|
||
DBEQ D2,@20 ; Loop until get one or end
|
||
BNE.S ENETDone ; Error if none
|
||
MOVE.L D3,(Handlers,A2,D2*4) ; Fill Handlers in first (in case of interrupt)
|
||
CLR.L (RdQueueHd,A2,D2*4) ; Clear out read queue head
|
||
MOVE D1,Protocols(A2,D2*2)
|
||
; Fill protocol type in
|
||
ST InUseFlag(A2,D2) ; Indicate in use
|
||
ENETOK CLR D0 ; Indicate no error
|
||
ENETDone
|
||
MOVE.L OurDCE(A2),A1 ; Make sure A1 has DCE address
|
||
MOVE.L JIODone,-(SP) ; This is how we exit (Prime, Control, Status)
|
||
RTS
|
||
|
||
;
|
||
; Lookup D1 in the protocol table. Return D2 = index to protocol (negative = error).
|
||
;
|
||
GetProt MOVEQ #LAPTblSz-1,D2 ; Index into active protocols list
|
||
@10 TST.B InUseFlag(A2,D2) ; In use?
|
||
BEQ.S @20 ; Branch if not
|
||
CMP Protocols(A2,D2*2),D1 ; Match?
|
||
BEQ.S @30 ; Branch if so
|
||
@20 DBRA D2,@10 ; Keep going until got one
|
||
@30 TST D2 ; Set CCR to D2
|
||
RTS ; Return (BPL for match)
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoDetachPH - detach protocol handler control call
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D1 = protocol type code
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
;
|
||
; Find the requested protocol
|
||
;
|
||
DoDetachPH
|
||
MOVEQ #LAPProtErr,D0 ; Assume no such protocol active
|
||
|
||
BSR.S GetProt ; D2 = index to protocol
|
||
BMI.S ENETDone ; Return error if at end of table
|
||
CLR.B InUseFlag(A2,D2) ; Indicate entry free
|
||
TST.L (Handlers,A2,D2*4) ; Default handler?
|
||
BNE.S @10 ; All done if not
|
||
BSR.S AbortAll ; Abort all active reads
|
||
@10 BRA.S ENETOK ; Complete this call
|
||
|
||
|
||
;
|
||
; AbortAll - abort all active read requests.
|
||
;
|
||
; A2 -> our variables
|
||
; D2 = flag offset into protocol table
|
||
; Uses D1,A0
|
||
;
|
||
; Assumes InUseFlag(A2,D2) cleared out already so no interrupts
|
||
;
|
||
|
||
AbortAll MOVE.L (RdQueueHd,A2,D2*4),D1 ; D1 -> first read, if any
|
||
BEQ.S @10 ; Branch if none
|
||
MOVE.L D1,A0 ; A0 -> queue element
|
||
MOVE.L (A0),(RdQueueHd,A2,D2*4) ; Remove from queue
|
||
MOVE #reqAborted,D0 ; Set error code
|
||
BSR CompleteReq ; Return error
|
||
BRA.S AbortAll ; And loop
|
||
|
||
@10 RTS
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoWrite - write out a packet on Ethernet
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D3 = WDS pointer
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoWrite
|
||
; D3=ptr to caller's wds
|
||
MOVE SR,-(SP)
|
||
ORI.W #IntLockOut,SR ; no interrupts <SM4> rb
|
||
|
||
MOVE.L WrBuffHdr(A2),D2 ; get a buffer pointer
|
||
BNE.S @haveBuff
|
||
|
||
ST XmitWait(A2) ; set waiting flag
|
||
MOVE (SP)+,SR
|
||
MOVEQ #noErr,D0
|
||
RTS ; return to caller
|
||
@haveBuff
|
||
CLR.B XmitWait(A2) ; no longer waiting
|
||
|
||
MOVEA.L D2,A1 ; A1->buffer
|
||
MOVE.L QLink(A1),WrBuffHdr(A2) ; unlink from buffer list
|
||
MOVE (SP)+,SR
|
||
|
||
MOVE.L A1,-(SP) ; save buffer pointer for later
|
||
|
||
MOVE.L D3,A0 ; A0 -> WDS
|
||
CMP #EHdrSize,(A0) ; First entry must have whole header
|
||
BLO.S @30 ; Error if not
|
||
MOVE.L 2(A0),A0 ; A0 -> first WDS entry
|
||
MOVE.L OurAddr(A2),ESrcAddr(A0) ; Set our address in it
|
||
MOVE OurAddr+4(A2),ESrcAddr+4(A0)
|
||
; (all six bytes)
|
||
|
||
MOVE.L A4,-(SP) ; save non-interrupt scratch reg.
|
||
|
||
LEA Max_Pkt_Size(A1),A3 ; A3->singe fragment wds (len field)
|
||
|
||
MOVEQ #-EHdrSize,D2 ; setup for len check <H5>
|
||
|
||
CLR.W (A3) ; init len <H5>
|
||
MOVE.L D3,A4 ; A4-> caller's WDS <H5>
|
||
@x1
|
||
MOVEQ #0,D0
|
||
MOVE.W (A4)+,D0 ; get this frag length
|
||
BEQ.S @x2 ; all done
|
||
BMI.S @LenError ; negative values not allowed <H5 begin>
|
||
|
||
ADD.W D0,D2 ; accum length
|
||
CMP.W MaxData(A2),D2 ; check length so far
|
||
BHI.S @LenError ; bad, get out with error
|
||
|
||
ADD.W D0,(A3) ; sum the length in WDS
|
||
MOVEA.L (A4)+,A0 ; get pointer to the data
|
||
;a0->source, a1->dest, d0=len
|
||
MOVEM.L A1/D0/D2,-(SP) ; save buff ptr and len
|
||
JSR ([BlockMove,A2]) ; move the data
|
||
MOVEM.L (SP)+,A1/D0/D2 ; <H5 end>
|
||
ADDA.L D0,A1 ; update buff ptr
|
||
BRA.S @x1 ; look for more
|
||
@x2
|
||
MOVEA.L (SP)+,A4 ; restore non-interrupt scratch reg.
|
||
BRA.S @sendit ; go and send it now <H5 begin>
|
||
|
||
@LenError ; packet length is invalid
|
||
MOVEA.L (SP)+,A4 ; restore this reg. <H5 end>
|
||
@30
|
||
MOVE.L (SP)+,A3 ; A3->buffer
|
||
MOVE SR,-(SP)
|
||
ORI.W #IntLockOut,SR ; <SM4> rb
|
||
|
||
MOVE.L WrBuffHdr(A2),(A3) ; link buffer back to list
|
||
MOVE.L A3,WrBuffHdr(A2)
|
||
|
||
MOVE (SP)+,SR
|
||
|
||
MOVEQ #eLenErr,D0 ; Set length error
|
||
BRA ENETDone ; Return it
|
||
|
||
@sendit
|
||
MOVE.L (SP),-(SP) ; dup TOS <H5>
|
||
ADDI.L #Max_Pkt_Size,(SP) ; pass wds pointer <H5>
|
||
BSR SONICAddr
|
||
MOVE.L A0,-(SP) ; pass base address of SONIC
|
||
|
||
BSR DataCacheOff ; turn off data cache on LC 030
|
||
BSR SONICXMIT ; send the packet
|
||
ADDQ.W #8,SP
|
||
BSR DataCacheOn ; turn data cache back on
|
||
|
||
BEQ.S @TxOK ; SONIC was able to handle xmit
|
||
|
||
MOVE.L (SP)+,A3 ; A3->buffer
|
||
MOVE SR,-(SP)
|
||
ORI.W #IntLockOut,SR ; <SM4> rb
|
||
|
||
MOVE.L WrBuffHdr(A2),(A3) ; link buffer back to list
|
||
MOVE.L A3,WrBuffHdr(A2)
|
||
|
||
MOVE (SP)+,SR ; <Z12>
|
||
|
||
BSET #0,deferCtl(A2) ; indicate we are deferring
|
||
MOVE.W #1,vblCount+VBLQEL(A2) ; set next vbl to tick fast
|
||
MOVEQ #noErr,D0
|
||
RTS
|
||
@TxOK
|
||
ADDQ.W #4,SP ; trash buffer pointer <Z12>
|
||
|
||
MOVEQ #noErr,D0
|
||
MOVEA.L ourDCE(A2),A1 ; A1->DCE
|
||
MOVEA.L JIODone,A0
|
||
JMP (A0) ; all done now
|
||
|
||
;
|
||
; Tramsmit Complete routine (called from SONICInterrupt):
|
||
|
||
TxPrm RECORD 4
|
||
TxDesc DS.L 1 ; ptr to Xmit descriptor
|
||
TxParms DS.L 1 ; ptr to OurVars
|
||
TxPrmSz EQU * ; size of record <T6>
|
||
ENDR
|
||
|
||
XmitDone
|
||
MOVEA.L OurVarPtr,A0 ; get ptr to our vars <T6> thru next <T6>
|
||
MOVEA.L OurDCE(A0),A1 ; get our DCE ptr
|
||
BTST #NeedDefer,dCtlStorage(A1) ; is VM running?
|
||
BEQ.S @noVM ; no, just proceed
|
||
|
||
MOVE.L TxPrm.TxDesc(SP),A1 ; <Z11>
|
||
BSR.S GetDescPhAddr ; get physical write buffer address in D0 <Z11>
|
||
LEA @deferWrite,A0 ; routine to call when safe
|
||
_DeferUserFn ; defer the routine
|
||
RTS
|
||
@deferWrite
|
||
MOVEA.L A0,A1 ; A1->physical address of write buffer <Z11>
|
||
MOVEA.L OurVarPtr,A0 ; <Z11>
|
||
MOVEM.L A2/A3/D3,-(SP) ; save C regs <Z11>
|
||
BRA.S @findXmitBuffer ; <Z11>
|
||
@noVM ; <Z11>
|
||
MOVE.L TxPrm.TxDesc(SP),A1 ; get ptr to descriptor
|
||
|
||
MOVEM.L A2/A3/D3,-(SP) ; save C regs
|
||
|
||
BSR.S GetDescPhAddr ; get physical write buffer address in D0 <Z11>
|
||
MOVEA.L D0,A1 ; A1->xmit buffer (physical address) <Z11>
|
||
@findXmitBuffer ; <Z11>
|
||
MOVEA.L PLTable(A0),A2 ; A2->translation table
|
||
MOVE.L XmitBuffs(A0),D0 ; D0=#xmit buffers
|
||
SUBQ.W #1,D0 ; base zero
|
||
@cmp
|
||
CMPA.L PtoL.Physical(A2),A1 ; found it?
|
||
ADDQ.W #PtoL.Size,A2
|
||
DBEQ D0,@cmp ; keep looking if not
|
||
|
||
BNE.S @done ; safety, should not happen
|
||
|
||
MOVEA.L PtoL.Logical-PtoL.Size(A2),A1 ; replace physical with logical address
|
||
|
||
MOVE SR,-(SP)
|
||
ORI.W #IntLockOut,SR ; <SM4> rb
|
||
|
||
MOVE.L WrBuffHdr(A0),(A1) ; link buffer back into list
|
||
MOVE.L A1,WrBuffHdr(A0)
|
||
|
||
MOVE (SP)+,SR
|
||
|
||
TST.B XmitWait(A0) ; any pending xmits?
|
||
BEQ.S @done ; leave if not
|
||
|
||
MOVEA.L A0,A2 ; A2->our vars
|
||
MOVEA.L OurDCE(A2),A1 ; A1->our DCE
|
||
MOVE.L dCtlQHead(A1),A0 ; A0->waiting write param blk
|
||
|
||
MOVE.L CSParam+2(A0),D3 ; D3 = 1st parameter longword (e.g. WDSP)
|
||
|
||
BSR DoWrite ; process the write
|
||
@done
|
||
MOVEM.L (SP)+,A2/A3/D3 ; restore C regs
|
||
RTS
|
||
|
||
GetDescPhAddr ; get physical address of descriptor in D0 <H5 begin>
|
||
SMOVE TxPkt.frag_ptr1(A1),D0 ; get upper 16 bits of buffer address
|
||
SWAP D0
|
||
SMOVE TxPkt.frag_ptr0(A1),D1 ; get lower 16 bits of buffer address
|
||
MOVE.W D1,D0 ; D0=xmit buffer (physical address) <H5 end>
|
||
RTS
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoRead - read a packet off the Ethernet
|
||
;
|
||
; Call:
|
||
; A0 -> queue element
|
||
; A1 -> our DCE
|
||
; A2 -> our variables
|
||
; D1 = protocol type code
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoRead MOVEQ #LAPProtErr,D0 ; Assume an error
|
||
BSR GetProt ; D2 = index into PH table
|
||
BMI ENETDone ; Error if not there
|
||
TST.L (Handlers,A2,D2*4) ; Is it the default?
|
||
BNE ENETDone ; Error if not
|
||
MOVE #buf2SmallErr,D0 ; Assume buffer not big enough
|
||
CMP #EHdrSize,EBuffSize(A0) ; Must hold at least header
|
||
BLO ENETDone ; Return error if not
|
||
;
|
||
; Dequeue the request from the system queue and queue it on ours (in order)
|
||
;
|
||
LEA (RdQueueHd,A2,D2*4),A3 ; A3 -> queue head
|
||
MOVE SR,-(SP) ; Save interrupt status
|
||
ORI.W #IntLockOut,SR ; Disable interrupts <SM4> rb
|
||
@10 TST.L (A3) ; Is there a next element?
|
||
BEQ.S @20 ; Branch if not
|
||
MOVE.L (A3),A3 ; Point to it if so
|
||
BRA.S @10 ; And keep going until end
|
||
|
||
@20
|
||
EXG D0,A0
|
||
AND.L AddrMask(A2),D0
|
||
EXG D0,A0 ; 32 bit clean
|
||
|
||
MOVE.L A0,(A3) ; Put queue element on our queue
|
||
BCLR #DrvrActive,DCtlFlags+1(A1)
|
||
; Clear driver active flag
|
||
MOVE.L IOLink(A0),DCtlQHead(A1) ; Set next element addr in head
|
||
BNE.S @30 ; Branch if there is none
|
||
CLR.L DCtlQTail(A1) ; Clear tail if not
|
||
@30 CLR.L IOLink(A0) ; Indicate it's last one on our queue
|
||
MOVE.L DCtlQHead(A1),D0 ; Any more requests?
|
||
BEQ.S @40 ; Branch if not
|
||
BSET #DrvrActive,DCtlFlags+1(A1)
|
||
; We're active again
|
||
MOVE (SP)+,SR ; Restore interrupt state
|
||
MOVE.L D0,A0 ; A0 -> new queue element
|
||
MOVEQ #0,D0 ; D0 should be clear
|
||
BSR Control ; Call ourselves
|
||
MOVEQ #0,D0 ; Return no error for previous call
|
||
RTS ; Return
|
||
|
||
@40 MOVE (SP)+,SR ; Restore interrupt state
|
||
RTS ; Return
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoRdCancel - abort a pending read call
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D3 = pointer to queue element to abort
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoRdCancel MOVE #CBNotFound,D0 ; Assume an error
|
||
AND.L AddrMask(A2),D3 ; 32 bit clean
|
||
MOVE.L D3,A1 ; A1 -> queue element
|
||
MOVE EProtType(A1),D1 ; D1 = protocol type
|
||
BSR GetProt ; D2 = index into PH table
|
||
BMI.S @60 ; Error if not there
|
||
TST.L (Handlers,A2,D2*4) ; Is it the default?
|
||
BNE.S @60 ; Error if not
|
||
LEA (RdQueueHd,A2,D2*4),A3 ; A3 -> queue head
|
||
MOVE SR,-(SP) ; Save interrupt status
|
||
ORI.W #IntLockOut,SR ; Disable interrupts <SM4> rb
|
||
@30 MOVE.L (A3),D3 ; D3 -> next element in queue
|
||
AND.L AddrMask(A2),D3 ; 32 bit clean
|
||
BEQ.S @50 ; Error if no more
|
||
SUB.L A1,D3 ; Subtract out desired one
|
||
BEQ.S @40 ; Branch if it's the one
|
||
MOVE.L (A3),A3 ; A3 -> next in queue
|
||
BRA.S @30 ; Keep looking
|
||
|
||
@40 MOVE.L (A1),(A3) ; Point previous to next
|
||
MOVE (SP)+,SR ; Restore interrupts
|
||
;
|
||
; Complete the ERead with an error, then the ERdCancel
|
||
;
|
||
MOVE.L A1,A0 ; A0 -> ERead queue element
|
||
MOVE #ReqAborted,D0 ; D0 = aborted error
|
||
BSR.S CompleteReq ; Complete it with error
|
||
BRA ENETOk ; Return no error for RdCancel
|
||
|
||
@50 MOVE (SP)+,SR ; Restore interrupt state
|
||
@60 BRA ENETDone ; Return not found error
|
||
|
||
|
||
;________________________________________________________________________
|
||
;
|
||
; CompleteReq - this code basically executes the parts of IODone necessary to
|
||
; complete the user's request (sets result code and executes the user's
|
||
; completion routine)
|
||
;
|
||
; Call:
|
||
; D0 = result code
|
||
; A0 -> I/O queue element
|
||
;________________________________________________________________________
|
||
|
||
CompleteReq MOVE.W D0,IOResult(A0) ; Set the result code
|
||
MOVEM.L D1-D3/A0-A3,-(SP) ; Save registers
|
||
MOVE.L IOCompletion(A0),D1 ; Check if there's a completion routine
|
||
BEQ.S @10 ; Branch if not - just return
|
||
MOVE.L D1,A1 ; Get it if so
|
||
TST.W D0 ; IODone does this
|
||
JSR (A1) ; Call completion routine
|
||
@10 MOVEM.L (SP)+,D1-D3/A0-A3 ; Restore registers
|
||
RTS ; Return
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoGetInfo - return our node address
|
||
;
|
||
; Call:
|
||
; A0 -> queue element
|
||
; A2 -> our variables
|
||
; D3 -> buffer for response
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoGetInfo
|
||
AND.L AddrMask(A2),D3 ; 32 bit clean
|
||
|
||
MOVEA.L A0,A3 ; save param blk ptr
|
||
MOVEQ #0,D0 ; Clear out D0
|
||
MOVE EBuffSize(A3),D0 ; D0 = buffer size
|
||
CMP #InfoEnd-InfoStart,D0 ; Asking for more than we have?
|
||
BLS.S @10 ; Branch if not
|
||
MOVEQ #InfoEnd-InfoStart,D0 ; If so, just return what we have
|
||
@10 MOVE.L D3,A1 ; A1 -> where to move to
|
||
LEA InfoStart(A2),A0 ; A0 -> where to move from
|
||
PEA (A1,D0.L) ; next spot to move to
|
||
MOVE.L D0,-(SP) ; current move len
|
||
_BlockMove ; Move it
|
||
MOVE.W EBuffSize(A3),D0
|
||
SUB.L (SP)+,D0 ; D0=len left in user buffer
|
||
MOVEA.L (SP)+,A1 ; A1->user buffer
|
||
BLS ENETOK ; no more user buffer
|
||
|
||
CMPI.L #NetStats.Size,D0
|
||
BLS.S @15 ; only move what is left
|
||
MOVE.L #NetStats.Size,D0
|
||
@15
|
||
LEA EtherStats(A2),A0 ; A0->stats
|
||
_BlockMove ; move them in
|
||
BRA ENETOK ; Return no error
|
||
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; EtherRecv - receive routine - called by slot manager
|
||
;
|
||
; Called:
|
||
; A1 = value passed in SIntInstall call (DCE pointer)
|
||
;
|
||
; Return:
|
||
; D0 <> 0 to indicate interrupt has been serviced
|
||
; A1 may be modified
|
||
;
|
||
; We disable AppleTalk interrupts, since incoming ATalk packet could cause a
|
||
; 20 msec hickup, whereas we'll generally take about 1/2 msec.
|
||
;___________________________________________________________________________
|
||
|
||
; EtherRecv(status,len,data,parms,buffdesc)
|
||
|
||
EtherRecv ; <T6> thru next <T6>
|
||
MOVEA.L OurVarPtr,A1
|
||
MOVEA.L OurDCE(A1),A1 ; A1->DCE
|
||
BTST #NeedDefer,dCtlStorage(A1) ; indicate VM is running
|
||
BEQ.S @noVM ; no, just continue
|
||
|
||
MOVEA.L OurVarPtr,A0 ; A0->our vars
|
||
LEA RxDefBuffs-RxParms.ParmsSz(A0),A1
|
||
; point at parameter storage
|
||
MOVEQ #NumBuffers-1,D0 ; loop to find an empty one
|
||
@findRxDef
|
||
LEA RxParms.ParmsSz(A1),A1 ; bump pointer to next one
|
||
TST.L RxParms.InUse(A1) ; find an available storage area
|
||
DBEQ D0,@findRxDef ; keep searching
|
||
BNE.S @noVM ; safety, should not happen
|
||
|
||
PEA (A1) ; save ptr to storage
|
||
LEA RxParms.Status(SP),A0 ; setup source addr (stack already aligned)
|
||
MOVEQ #RxParms.ParmsSz,D0 ; move size
|
||
_BlockMove ; save parameters
|
||
MOVE.L (SP)+,D0 ; param to pass to defer routine
|
||
LEA @deferRecv,A0 ; routine to defer
|
||
_DeferUserFn
|
||
RTS
|
||
@deferRecv
|
||
MOVE.L A0,-(SP) ; save frame storage ptr
|
||
SUBA.W #RxParms.ParmsSz,SP ; make param storage on stack
|
||
MOVEA.L SP,A1 ; A1->frame
|
||
MOVEQ #RxParms.ParmsSz,D0
|
||
_BlockMove ; set frame data
|
||
|
||
BSR.S @noVM ; now do the receive routine
|
||
|
||
ADDA.W #RxParms.ParmsSz,SP ; strip param storage
|
||
MOVEA.L (SP)+,A0 ; get back storage ptr
|
||
CLR.L RxParms.InUse(A0) ; mark entry as free
|
||
RTS ; done
|
||
@noVM
|
||
LINK A6,#RxParms.Size
|
||
|
||
MOVEM.L A2-A5/D3,-(SP) ; save C regs <T6>
|
||
|
||
MOVE.L OurVarPtr,A2 ; A2 -> our variables
|
||
MOVE.L RxParms.RxDesc(A6),LastRxDesc(A2)
|
||
; save descriptor pointer
|
||
;
|
||
; Process the receive interrupt
|
||
;
|
||
MOVEA.L RxParms.Data(A6),A0 ; A0->packet data
|
||
|
||
MOVE.L RxParms.Status(A6),D1 ; get packet status
|
||
BTST #ReceivedOK,D1 ; was packet received OK?
|
||
BEQ.S @85 ; don't process if not
|
||
|
||
MOVE.L RxParms.Length(A6),D1 ; d1=size of packet
|
||
SUBQ #4,D1 ; Subtract off FCS bytes
|
||
;
|
||
; Copy the Ethernet header from the packet into the RHA
|
||
;
|
||
LEA RHA(A2),A3 ; A3 -> RHA
|
||
MOVEQ #EHdrSize/2-1,D0 ; D0 = header count to move
|
||
@40 MOVE (A0)+,(A3)+ ; Move from card to RHA
|
||
DBRA D0,@40 ; Move them all
|
||
SUB #EHdrSize,D1 ; Subtract out header bytes from total
|
||
;
|
||
; Search the protocol handler table for this protocol
|
||
;
|
||
|
||
@50 MOVE EType-EHdrSize(A3),D0 ; D0 = protocol type or 802.3 length
|
||
CMP.W #EMaxDataSz,D0 ; is it an 802.3?
|
||
BHI.S @110 ; if not, try other protocols
|
||
|
||
CLR D0 ; Handler will be for type zero
|
||
EXG D0,D1 ; D1 = protocol type, D0 = old D1
|
||
BSR GetProt ; D2 = offset in table
|
||
EXG D0,D1 ; Restore D0, D1
|
||
BMI.S @85 ; Branch if not found
|
||
MOVE EType-EHdrSize(A3),D0 ; D0 = protocol type
|
||
|
||
@70 LEA EReadPacket,A4 ; A4 -> our ReadPacket routine
|
||
LEA DefaultPH,A5 ; use default maybe
|
||
MOVE.L (Handlers,A2,D2*4),D3 ; call the protocol handler
|
||
BEQ.S @80 ; use default
|
||
MOVEA.L D3,A5 ; use table entry address
|
||
@80
|
||
JSR (A5)
|
||
@85
|
||
MOVEA.L OurVarPtr,A2
|
||
MOVE.L LastRxDesc(A2),D0
|
||
BEQ.S @90 ; descriptor already freed
|
||
MOVE.L D0,-(SP)
|
||
BSR SONICFREEBUFF
|
||
ADDQ.W #4,SP
|
||
@90
|
||
MOVEM.L (SP)+,A2-A5/D3 ; Restore registers
|
||
UNLK A6
|
||
RTS ; That's it
|
||
;
|
||
; Find Protocol handler for non 802.3 packet
|
||
;
|
||
@110
|
||
EXG D0,D1 ; D1 = protocol type, D0 = old D1
|
||
BSR GetProt ; D2 = offset in table
|
||
EXG D0,D1 ; Restore D0, D1
|
||
BMI.S @85 ; Branch if not found
|
||
|
||
BRA.S @70 ; Process it
|
||
|
||
FreeDescriptor ; free current receive descriptor
|
||
MOVEM.L D0-D2/A2,-(SP) ; save regs
|
||
MOVEA.L OurVarPtr,A2 ; get our vars
|
||
MOVE.L LastRxDesc(A2),-(SP) ; pass descriptor pointer
|
||
CLR.L LastRxDesc(A2) ; inidicate it has been freed
|
||
BSR SONICFREEBUFF ; free this descriptor
|
||
ADDQ.W #4,SP
|
||
MOVEM.L (SP)+,D0-D2/A2
|
||
TST.W D0
|
||
RTS
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; EReadPacket - read in the specified number of bytes into the specified
|
||
; buffer. Asking for more than there is is an error.
|
||
;
|
||
; EReadRest - read in the rest of the packet, putting the specified number
|
||
; of bytes into the specified buffer, and ignoring the rest.
|
||
;
|
||
; Call:
|
||
; A0 -> current location in card memory
|
||
; A1 -> card registers
|
||
; A3 -> buffer to read into
|
||
; A4 -> start of ReadPacket
|
||
; D1 = number of bytes left to come in (caller may decrease)
|
||
; D3 = byte count to read
|
||
;
|
||
; Return:
|
||
; D0 = error byte (Z bit set in CCR)
|
||
; D1 updated (ReadPacket)
|
||
; D2 saved
|
||
; D3 = 0 if exact number of bytes requested were read
|
||
; > 0 indicates number of bytes requested but not read
|
||
; (packet smaller than requested maximum)
|
||
; < 0 indicates number of extra bytes read but not returned
|
||
; (packet larger than requested maximum)
|
||
; A0,A1 preserved by ReadPacket, modified by ReadRest
|
||
; A2 saved
|
||
; A3 -> one past where last character went
|
||
; A4,A5 saved (until packet's all in or error)
|
||
;___________________________________________________________________________
|
||
|
||
EReadPacket BRA.S EDoRP ; Need this for two entry points
|
||
|
||
EReadRest MOVE D3,D0 ; D0 = number of bytes to return
|
||
SUB D1,D0 ; D0 = remainder count
|
||
TST D3 ; Check for zero
|
||
BEQ.S @10 ; If so, don't waste our time
|
||
BSR.S MoveBytes ; Move the bytes in
|
||
@10 MOVE D0,D3 ; D3 = remainder count
|
||
MOVEQ #0,D0 ; No error no matter what
|
||
BRA.S FreeDescriptor ; let SONIC have descriptor back
|
||
|
||
EDoRP
|
||
CMP.W D3,D1
|
||
BLO.S @5 ; error in request
|
||
BSR.S MoveBytes ; Move in the bytes
|
||
TST D3 ; Moved them all?
|
||
BEQ.S @10 ; Branch if moved all ok
|
||
@5
|
||
MOVEQ #eLenErr,D0 ; Set length error
|
||
BRA.S FreeDescriptor ; let SONIC have descriptor back
|
||
@10 RTS ; Return
|
||
;___________________________________________________________________________
|
||
;
|
||
; DefaultPH - default protocol handler - complete an ERead call if there
|
||
;
|
||
; Called:
|
||
; A0,A1: preserve until ReadRest
|
||
; A2 -> local variables
|
||
; A4 -> EReadPacket
|
||
; A5 usable until ReadRest
|
||
; D0 = protocol type
|
||
; D2 = index into protocol table
|
||
; Interrupts are off
|
||
;
|
||
;___________________________________________________________________________
|
||
|
||
DefaultPH
|
||
MOVE.L (RdQueueHd,A2,D2*4),D0 ; D0 -> first ERead on queue
|
||
BEQ.S @20 ; Skip packet if none
|
||
MOVE.L D0,A5 ; A5 -> ERead queue element
|
||
MOVE.L (A5),(RdQueueHd,A2,D2*4) ; Remove from queue
|
||
MOVE.L D0,D2 ; D2 = queue element pointer
|
||
MOVE.L EBuffPtr(A5),A3 ; A3 -> buffer to read into
|
||
MOVE EBuffSize(A5),D3 ; D3 = maximum size to read
|
||
SUB #EHdrSize,D3 ; Adjust for header
|
||
LEA RHA(A2),A5 ; A5 -> header info
|
||
MOVE.L (A5)+,(A3)+ ; Move header into buffer
|
||
MOVE.L (A5)+,(A3)+ ; Hard code for speed
|
||
MOVE.L (A5)+,(A3)+ ; (AssumeEq?)
|
||
MOVE (A5)+,(A3)+ ; A3 -> buffer after header
|
||
JSR 2(A4) ; Read in the whole thing (D0=0)
|
||
MOVE.L D2,A0 ; A0 -> queue element again
|
||
MOVE EBuffSize(A0),D1 ; D1 = original request size
|
||
SUB D3,D1 ; D1 = total packet size
|
||
MOVE D1,EDataSize(A0) ; Set in queue element
|
||
TST D3 ; Check for buffer overflow
|
||
BPL.S @10 ; Branch if no overflow
|
||
MOVE #buf2SmallErr,D0 ; Set error
|
||
@10 BRA CompleteReq ; Complete request and return
|
||
|
||
@20 MOVEQ #0,D3 ; Indicate no buffer
|
||
JMP 2(A4) ; Ignore packet and return
|
||
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; MoveBytes - move bytes from card memory to desired place
|
||
;
|
||
; Call:
|
||
; A0 -> current location in card memory
|
||
; A3 -> place to move bytes to
|
||
; D1 = number of bytes left in packet
|
||
; D3 = number of bytes to move
|
||
;
|
||
; Return:
|
||
; A0 adjusted
|
||
; A3 adjusted past bytes moved in
|
||
; D1 adjusted
|
||
; D3 = zero if all could be moved, remainder otherwise
|
||
;___________________________________________________________________________
|
||
|
||
MoveBytes
|
||
|
||
MOVEM.L D0/D2/A1/A2,-(SP) ; Save registers
|
||
MOVE.L OurVarPtr,A2 ; A2 -> our variables
|
||
EXG D0,A3
|
||
AND.L AddrMask(A2),D0
|
||
EXG D0,A3 ; 32 bit clean
|
||
MOVE.L A3,A1 ; A1 -> where to move to
|
||
MOVEQ #0,D0 ; D0 = number of bytes to move
|
||
MOVE D3,D0 ; Assume we can move all asked for
|
||
CMP D1,D3 ; Can we move all asked for?
|
||
BLS.S @10 ; Branch if so
|
||
MOVE D1,D0 ; Else move all we can
|
||
@10 SUB D0,D1 ; Adjust count left to come in
|
||
SUB D0,D3 ; D3 = bytes not moved
|
||
ADDA.W D0,A3
|
||
|
||
MOVE.L D1,-(SP) ; save this one
|
||
MOVE.L A0,-(SP)
|
||
MOVE.L D0,-(SP)
|
||
JSR ([BlockMove,A2]) ; call block move routine
|
||
MOVEA.L (SP)+,A0
|
||
ADDA.L (SP)+,A0 ; adjust pointer
|
||
MOVE.L (SP)+,D1
|
||
|
||
@30 MOVEM.L (SP)+,D0/D2/A1/A2 ; Restore registers
|
||
RTS ; That's it
|
||
;________________________________________________________________________
|
||
;
|
||
; Close - close the ENET driver.
|
||
;
|
||
; A1 -> DCE
|
||
;________________________________________________________________________
|
||
|
||
Close
|
||
; This code is never really called because no use-count in implemented for the .ENET driver
|
||
; and multiple clients could be using it, e.g. MacTCP.
|
||
MOVE.L OurVarPtr,A2 ; A2 -> our variables
|
||
|
||
BSR SONICAddr ; get SONIC base in A0 <Z12>
|
||
MOVE.L A0,-(SP) ; pass SONIC base address <Z12>
|
||
BSR.S DataCacheOff ; turn off data cache on LC 030 <Z12>
|
||
BSR SONICHALT ; stop SONIC <Z12>
|
||
ADDQ.W #4,SP ; <Z12>
|
||
BSR DataCacheOn ; turn data cache back on <Z12>
|
||
|
||
MOVEA.L SONICmem(A2),A0
|
||
_DisPosPtr ; get rid of storage
|
||
|
||
MOVEQ #LAPTblSz-1,D2 ; D2 = Index into active protocols list
|
||
@10 TST.B InUseFlag(A2,D2) ; Active?
|
||
BEQ.S @20 ; Branch if not
|
||
TST.L (Handlers,A2,D2*4) ; Default handler
|
||
BNE.S @20 ; Branch if not
|
||
BSR AbortAll ; Abort all requests
|
||
@20 DBRA D2,@10 ; On to next
|
||
LEA SONICintQ,A0 ; interrupt queue element
|
||
MOVEQ #0,D0 ; Clear out D0
|
||
MOVE.B SONICCfg.SONICSlot(A2), D0 ; setup slot from config values <H5>
|
||
_SIntRemove ; Remove us from interrupt queue
|
||
|
||
LEA VBLQEL(A2),A0
|
||
TST.L vblAddr(A0) ; did we launch ctl call VBL?
|
||
BEQ.S @50
|
||
_VRemove ; remove VBL task if so
|
||
@50
|
||
MOVEA.L OurVarPtr,A0 ; <Z12>
|
||
_DisPosPtr ; <Z12>
|
||
|
||
LEA OurVarPtr,A2 ; A2 -> variable pointer
|
||
CLR.L (A2) ; Clear it out (no variables)
|
||
MOVEQ #0,D0 ; Indicate no error
|
||
AnRTS RTS ; And return
|
||
|
||
; for LC 030 not running VM, turn data caching off so SONIC can DMA and we see it <Z12>
|
||
DataCacheOff
|
||
MOVEA.L OurVarPtr,A0
|
||
TST.B SONICCfg.SmartMMU(A0) ; do we have smart MMU code? <H5>
|
||
BNE.S @done ; yes, memory is locked and non-cacheable<H5>
|
||
BTST #NeedDefer,([OurDCE,A0],dCtlStorage)
|
||
BNE.S @done ; VM running, don't alter data cache
|
||
MOVE SR,-(SP)
|
||
ORI.W #IntLockOut,SR ; Disable interrupts <SM4> rb
|
||
ADDQ.L #1,CacheCount(A0) ; bump use count
|
||
TST.L DataCache(A0)
|
||
BNE.S @done0 ; data cache already disabled
|
||
MOVEC CACR,D0
|
||
MOVE.L D0,DataCache(A0) ; save current CACR
|
||
BSET #11,D0 ; purge data in data cache
|
||
BCLR #8,D0 ; disable data caching
|
||
MOVEC D0,CACR ; do it
|
||
@done0
|
||
MOVE (SP)+,SR ; reenable interrupts
|
||
@done
|
||
RTS
|
||
|
||
DataCacheOn ; reenable data caching on LC030
|
||
MOVEM.L A0/D0,-(SP)
|
||
MOVE CCR,-(SP) ; save current condition flags
|
||
MOVEA.L OurVarPtr,A0
|
||
TST.B SONICCfg.SmartMMU(A0) ; do we have smart MMU code? <H5>
|
||
BNE.S @done ; yes, memory is locked and non-cacheable <H5>
|
||
BTST #NeedDefer,([OurDCE,A0],dCtlStorage)
|
||
BNE.S @done ; VM running, don't alter data cache
|
||
MOVE SR,-(SP)
|
||
ORI.W #IntLockOut,SR ; Disable interrupts <SM4> rb
|
||
SUBQ.L #1,CacheCount(A0) ; decrement use count
|
||
BNE.S @done0 ; not ready for reenable, nested disables
|
||
MOVE.L DataCache(A0),D0
|
||
CLR.L DataCache(A0)
|
||
MOVEC D0,CACR ; reenable data caching
|
||
@done0
|
||
MOVE (SP)+,SR ; reenable interrupts
|
||
@done
|
||
MOVE (SP)+,CCR ; restore condition flags
|
||
MOVEM.L (SP)+,A0/D0
|
||
RTS
|
||
|
||
AddrPromAddr ; return address of Ethernet PROM in A0
|
||
MOVEA.L SONICCfg.EnetPROM(A2), A0 ; obtain address <H5>
|
||
RTS
|
||
SONICAddr
|
||
LEA ([OurVarPtr],SONICCfg), A0 ; <H5 begin>
|
||
TST.B MMU32Bit
|
||
BEQ.S @setBase24 ; no adjustment for 24 bit
|
||
MOVEA.L SCFG.SONICbase32(A0), A0 ; obtain address for 32 bit
|
||
RTS
|
||
@setBase24
|
||
MOVEA.L SCFG.SONICbase24(A0), A0 ; obtain address for 24 bit <H5 end>
|
||
RTS
|
||
;
|
||
; Variable storage
|
||
;
|
||
OurVarPtr DC.L 0 ; Pointer to our variables
|
||
SONICintQ DCB.B SlotIntQElement.sqHDSize,0 ; queue element for interrupts
|
||
SONIChandler DC.L 0
|
||
END
|
||
|
||
|
||
|