; ; 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): ; ; 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. ; 10/28/92 SWC Changed the INCLUDEs to a LOAD of StandardEqu.d. ; 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. ; 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 ; 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. ; 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 thru next 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
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 ;
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
; ₯₯₯₯₯₯₯₯ 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 ; DS.B Max_Pkt_Size+OneWdsSz+PtoL.Size ; memory for each xmit buffer ALIGN 4 ; make sure MOD 4 size Size EQU * ; ENDR ; AMaxDataSz EQU 768-EHdrSize ; Maximum data size for AppleTalk mode IntLockOut EQU $400 ; SR value to lock interrupts rb BlockMoveTrap EQU $A02E ; trap value for _BlockMove Configrsrc EQU 'ecfg' ; rsrc type for sonic config data rsrc
NeedDefer EQU 5 ; bit indicates VM is running
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 MOVE.L #gestaltVMAttr,D0 ; see if VM is running _Gestalt ; BNE.S @noVM ; it isn't if call failed MOVE.L A0,D0 ; BEQ.S @noVM ; zero result means no VM running BSET #NeedDefer,dCtlStorage(A1) ; indicate VM is running BSET #VMImmuneBit,dCtlFlags+1(A1) ; tell VM to leave our calls alone @noVM ; 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
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
; 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
@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 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?
BEQ.S @nolock ; no, don't lock memory
@haveMemDispatch MOVE.L A1,-(SP) ; save a1 MOVEA.L D5,A1 ; length of buffer MOVEQ #4,D0 ; LockMemoryContiguous _MemoryDispatch ; MemoryDispatch MOVEA.L (SP)+,A1 ; restore a1 BNE OpenError ; failed, so bail @nolock ;
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 MOVEQ #true32b,D0 ; _SwapMMUMode ; put us in 32-bit mode MOVE.B D0,-(SP) ; save prior MMU status BSR AddrPromAddr ; A0->address prom MOVEQ #0,D1 ; setup to checksum the PROM address MOVEQ #7,D0 ; do 8 bytes @Xor MOVE.B (A0)+,D2 ; get byte to XOR EOR.B D2,D1 DBRA D0,@Xor ; do them all SUBI.B #$FF,D1 ; end result should be $FF BEQ.S @GetAddr ; keep going if it is MOVE.B (SP)+,D0 ; _SwapMMUMode ; put back mmu MOVEQ #-1,D0 ; BRA OpenError ; return with generic error (D0=-1) @GetAddr ; ADDQ.W #EAddrSz,A1 ; go from last to first BSR AddrPromAddr ; A0->address prom 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 ; _SwapMMUMode ; put back mmu @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
SMOVE D0,Data_Config2(A0) ; set extended data config
MOVE.L SONICCfg.DataCfgLpBk(A2), D0 ; setup SONIC data config for loopback tests
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 ; MOVE.L A0,SONICinitParms.SONICbase(SP) ; BSR DataCacheOff ; turn off data cache on LC 030 BSR SONICINIT ; initialize sonic chip ADDA.W #SONICinitParms.ParmSize,SP ; strip parms BSR DataCacheOn ; turn data cache back on 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 ; thru next 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 ; 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<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
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
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?
BEQ.S @nophy ; no, no need to get physical address
@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 @nophy ;
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 ; 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
_SIntInstall ; install handler RTS ENDWITH SONICInterrupt MOVEM.L A0/D1-D3,-(SP) ; Mac OS assumes these are scratch BSR SONICAddr ; get SONIC address in A0 MOVE.L A0,-(SP) ; pass SONIC base address BSR DataCacheOff ; turn off data cache on LC 030 MOVEA.L SONIChandler,A1 ; JSR (A1) ; ADDQ.W #4,SP ; BSR DataCacheOn ; turn data cache back on MOVEM.L (SP)+,A0/D1-D3 ; 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 ; MOVE.L A0,CAMparms.SONICPtr(SP) ; pass SONIC base address BSR DataCacheOff ; turn off data cache on LC 030 BSR SONICCAMLOAD ; add this entry ADDA.W #CAMparms.ParmSize,SP BSR DataCacheOn ; turn data cache back on 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 ; MOVE.L A0,CAMparms.SONICPtr(SP) ; pass SONIC base address BSR DataCacheOff ; turn off data cache on LC 030 BSR SONICCAMLOAD ; delete this entry ADDA.W #CAMparms.ParmSize,SP BSR DataCacheOn ; turn data cache back on 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 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
CLR.W (A3) ; init len
MOVE.L D3,A4 ; A4-> caller's WDS
@x1 MOVEQ #0,D0 MOVE.W (A4)+,D0 ; get this frag length BEQ.S @x2 ; all done BMI.S @LenError ; negative values not allowed
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 ;
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
@LenError ; packet length is invalid MOVEA.L (SP)+,A4 ; restore this reg.
@30 MOVE.L (SP)+,A3 ; A3->buffer MOVE SR,-(SP) ORI.W #IntLockOut,SR ; 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
ADDI.L #Max_Pkt_Size,(SP) ; pass wds pointer
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 ; rb MOVE.L WrBuffHdr(A2),(A3) ; link buffer back to list MOVE.L A3,WrBuffHdr(A2) MOVE (SP)+,SR ; 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 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 ENDR XmitDone MOVEA.L OurVarPtr,A0 ; get ptr to our vars thru next 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 ; BSR.S GetDescPhAddr ; get physical write buffer address in D0 LEA @deferWrite,A0 ; routine to call when safe _DeferUserFn ; defer the routine RTS @deferWrite MOVEA.L A0,A1 ; A1->physical address of write buffer MOVEA.L OurVarPtr,A0 ; MOVEM.L A2/A3/D3,-(SP) ; save C regs BRA.S @findXmitBuffer ; @noVM ; 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 MOVEA.L D0,A1 ; A1->xmit buffer (physical address) @findXmitBuffer ; 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 ; 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
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)
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 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 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 ; thru next 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 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 MOVE.L A0,-(SP) ; pass SONIC base address BSR.S DataCacheOff ; turn off data cache on LC 030 BSR SONICHALT ; stop SONIC ADDQ.W #4,SP ; BSR DataCacheOn ; turn data cache back on 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
_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 ; _DisPosPtr ; 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 DataCacheOff MOVEA.L OurVarPtr,A0 TST.B SONICCfg.SmartMMU(A0) ; do we have smart MMU code?
BNE.S @done ; yes, memory is locked and non-cacheable
BTST #NeedDefer,([OurDCE,A0],dCtlStorage) BNE.S @done ; VM running, don't alter data cache MOVE SR,-(SP) ORI.W #IntLockOut,SR ; Disable interrupts 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?
BNE.S @done ; yes, memory is locked and non-cacheable
BTST #NeedDefer,([OurDCE,A0],dCtlStorage) BNE.S @done ; VM running, don't alter data cache MOVE SR,-(SP) ORI.W #IntLockOut,SR ; Disable interrupts 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
RTS SONICAddr LEA ([OurVarPtr],SONICCfg), A0 ;
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
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