mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-07 20:29:52 +00:00
4325cdcc78
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.
1984 lines
66 KiB
Plaintext
1984 lines
66 KiB
Plaintext
;
|
||
; File: MaceEnet.a
|
||
;
|
||
; Contains: Ethernet Data Link level driver for builtin MACE Ethernet on Cyclone.
|
||
;
|
||
; Written by: Mark A. Law ,3-March-92
|
||
;
|
||
; Copyright: © 1991-1993 by Apple Computer, Inc. All rights reserved.
|
||
;
|
||
; This file is used in these builds: Mac32
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM9> 6/14/93 kc Roll in Ludwig.
|
||
; <LW4> 5/1/93 mal #1082434 Changed GetMem/FreeMem so extra memory is grabbed, then
|
||
; some of it deleted, when locking down pages so we don't lock
|
||
; memory that doesn't belong to us. Also changed snmp stat
|
||
; 'ifType' to indicate we're and Ethernet, not 802.3, link to
|
||
; match current Quadra drvrs.
|
||
; <LW3> 3/21/93 mal Added back 'eadr' support.
|
||
; <2> 1/27/93 mal Added MACEecfg rsrc support. Changed promiscuous mode support to
|
||
; lower main codepath risk.
|
||
; <SM8> 12/4/92 mal Turned off debug code; stopped using time mgr task for xmit
|
||
; deferrals; Promiscuous mode changes to EtherRecv().
|
||
; <SM7> 11/19/92 mal Added Promiscous mode support; check for VM correctly; install
|
||
; VBL and TimeMgr rtns before loopback; correct addr size in SNMP
|
||
; stats.
|
||
; <SM6> 10/30/92 mal Translate/Get/Free mem error condition improvement and made
|
||
; exported; 32BIT clean conditionally asm out; misc globals
|
||
; cleanup; misc comment cleanup.
|
||
; <SM5> 10/28/92 SWC Changed the INCLUDEs to a LOAD of StandardEqu.d.
|
||
; <SM4> 10/26/92 mal Updated to ESD's latest SNMP stats equs.
|
||
; <SM3> 10/26/92 mal Updated 2 and added 1 SNMP statistics control calls.
|
||
; <SM2> 10/13/92 mal -changed status that is recv'd in EtherRecv to lw and ignore
|
||
; pkts with bad status; -added debug code to get/free mem rtns.
|
||
; <SM7> 9/14/92 mal -fixed SNMP var storage and retrieval
|
||
; <SM6> 8/24/92 PN Take out CycloneboxEVT1 stuff
|
||
; <SM5> 7/25/92 mal Added support so # of recv chains can be changed via 'ebfr'.
|
||
; Removed _Debugger statements from LoopBack tests failure path.
|
||
; <SM4> 6/26/92 mal Fixed GetStats so it returns correct stats.
|
||
; <SM3> 6/23/92 mal Added runtime check so we'll always fail the open on PSC1 (EVT1)
|
||
; systems.
|
||
; <SM2> 6/22/92 mal New drvr to support PSC2's (EVT2) Ethernet DMA receive model.
|
||
; <SM1> 5/21/92 RB Removed the inclusion of VMCalls.a
|
||
; <P10> 5/5/92 mal Removed unused global vars.
|
||
; <P9> 4/30/92 mal Expanded interface between with Mace.a: now pass ptrs to
|
||
; TranslateAddress, GetMemory, and Blockmove rtns via MaceInit.
|
||
; Replaced XmitDone with rtn called via TimeMgr task.
|
||
; <P8> 4/28/92 mal Moved Mace specific tasks to Mace.a
|
||
; <P7> 3/26/92 mal Changed WriteLAF algorithm, now flush MACE and PSC FIFOs and
|
||
; drop packet(s) if packets present in MACE FIFO.
|
||
; <P6> 3/23/92 mal Added Multicast Add/Delete support; Removed TWISTER conditional
|
||
; sections; Cleaned up src.
|
||
; <P5> 3/5/92 mal Now get Ethernet Address from Prom if no 'eadr' resource in
|
||
; system file.
|
||
; <P4> 3/4/92 mal For no free recv buffs case; clear int. in DoRecv and added code
|
||
; in EtherRecv to reprime reg sets.
|
||
; <P3> 3/3/92 mal Made "DEBUG" conditional false.
|
||
; <P2> 3/3/92 mal Removed debug statements for non-error conditions.
|
||
;
|
||
; To Do:
|
||
;
|
||
; Notes:
|
||
; -based on Ethernet driver for Eclipse/Spike by Sean Findley, January 1990
|
||
;
|
||
;
|
||
|
||
PRINT OFF
|
||
LOAD 'StandardEqu.d'
|
||
INCLUDE 'Slots.a' ; Slot interrupt equates
|
||
INCLUDE 'GestaltEqu.a'
|
||
INCLUDE 'HardwarePrivateEqu.a'
|
||
INCLUDE 'UniversalEqu.a' ; lowmem global records
|
||
INCLUDE 'ATalkMacros.a' ; Nifty Macros
|
||
|
||
; Conditional compile equates
|
||
COUNTERS EQU 0
|
||
BUFDEBUG EQU 0
|
||
BIT24 EQU 0 ; SuperMario always 32-bit
|
||
DEBUG EQU 0
|
||
PROM EQU 1 ; Promiscous mode support
|
||
PRIMEDEFER EQU 0 ; Use Time Mgr for xmit defferals
|
||
|
||
PRINT NOGEN,NOMDIR,ON
|
||
INCLUDE 'MaceEqu.a' ; Mace definitions
|
||
INCLUDE 'PSCEqu.a' ; Mace definitions
|
||
INCLUDE 'ENETEqu.a' ; Driver definitions
|
||
INCLUDE 'SNMPLAP.a' ; SNMP definitions
|
||
EJECT
|
||
|
||
NumTxBuffers EQU 8 ; "optimal" number of xmit buffers
|
||
NumRxBuffers EQU 16 ; "optimal" number of recv buffers
|
||
NumRxChains EQU 4 ; "optimal" number of recv buffer chains
|
||
|
||
OurV RECORD 0 ; our variables
|
||
OurDCE DS.l 1 ; Offset to our DCE pointer in variables
|
||
IF PROM THEN
|
||
PromiscRHA DS.l 1 ; Contains status lw when in promiscuous mode
|
||
; ¥¥¥ WARNING: do not separate from RHA!
|
||
ENDIF
|
||
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 16 ; 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
|
||
|
||
ALIGN 4
|
||
MultiCTbl DS.b MTblSz*MEntrySz ; A list of valid addresses
|
||
ALIGN 4
|
||
XmitWait DS.b 1 ; non-zero = DoWrite waiting for buffers
|
||
IF PROM THEN
|
||
Promiscflg DS.b 1 ; non-zero = Promiscuous operation mode
|
||
ENDIF
|
||
deferCtl DS.b 1 ; non-zero = deferring control call
|
||
ALIGN 2
|
||
VBLQEL DS.b 14 ; VBL for control call deferrals
|
||
IF PRIMEDEFER THEN
|
||
ALIGN 4
|
||
DoWriteQEL DS.b tmQSize ; TimeMgr task for DoWrite deferrals
|
||
ENDIF
|
||
ALIGN 4
|
||
IF BIT24 THEN
|
||
AddrMask DS.l 1 ; 32 bit mask for addresses
|
||
ENDIF
|
||
MemMove DS.l 1 ; trap address of block move
|
||
IF COUNTERS THEN
|
||
EtherRcvCnt DS.l 1 ; # of times Deferred Recv Task called
|
||
XmitPend DS.l 1 ; Cnt of DoWrite calls from TimeMgr task
|
||
ENDIF
|
||
IF BUFDEBUG THEN
|
||
XmtDnActive DS.l 1
|
||
ENDIF
|
||
MCfg DS MACECfg ; MACE config data from config rsrc
|
||
ALIGN 4
|
||
InfoStart EQU * ; Old "GetInfo" network statistics start
|
||
OurAddr DS.b EAddrSz ; Our Ethernet address
|
||
DS.l 3 ; fill for compatibility with old getinfo
|
||
EtherStats DS NetStats
|
||
InfoEnd EQU * ; End of returned info
|
||
MultiRecvd DS.l 1 ; # of multicast pkts received
|
||
BcastRecvd DS.l 1 ; # of broadcast pkts received
|
||
; SNMP vars
|
||
LAPStats DS LAPMIBStats ; SNMP MIB stats for any link access protocol
|
||
Dt3Entry DS Dot3Entry ; SNMP status info and control vars
|
||
Dt3Stats DS Dot3StatsEntry ; SNMP stats for an 802.3 link
|
||
OurVarSz EQU * ; End of variables
|
||
ENDR
|
||
|
||
;_______________________________________
|
||
;
|
||
; Other definitions
|
||
;_______________________________________
|
||
|
||
AMaxDataSz EQU 768-EHdrSize ; Maximum data size for AppleTalk mode
|
||
|
||
INTLockOut EQU $0700 ; SR value to disable ALL interrupts
|
||
DMALockOut EQU $0400 ; SR value to disable PSC DMA interrupts
|
||
|
||
BlockMoveTrap EQU $A02E ; trap value for _BlockMove
|
||
|
||
IF PROM THEN
|
||
Promiscuous EQU 1 ; Bit #1 of Open()'s paramblk->ioFlags
|
||
ENDIF
|
||
EJECT
|
||
|
||
EJECT
|
||
|
||
ENETDriver MAIN EXPORT
|
||
STRING PASCAL
|
||
MACHINE MC68020
|
||
|
||
EXPORT TranslateAddress, GetMemory, FreeMemory
|
||
IMPORT MACEInit,MACEXmit,MACEAddMulti,MACEDelMulti,MACEHalt,NormAddr
|
||
IMPORT LOOPBACKTEST,MACESetProm,MACEXmitProm
|
||
WITH MACERegs,OurV,PSC_DMA_CHNL,PSC_INT_TBL
|
||
WITH LAPMIBStats,Dot3StatsEntry,Dot3Entry
|
||
|
||
; *****************************************
|
||
; * *
|
||
; * 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 'VersionMaceEnet.a'
|
||
|
||
;________________________________________________________________________
|
||
;
|
||
; Open - initialize the ENET driver
|
||
;
|
||
; Call:
|
||
; D0 = 0
|
||
; A0 -> queue element
|
||
; A1 -> DCE
|
||
;
|
||
; Return:
|
||
; D0 = 0, no error
|
||
; D0 != 0, if error
|
||
;________________________________________________________________________
|
||
|
||
OpenRec RECORD {A6Link}
|
||
LinkSz EQU *
|
||
pbblkptr DS.l 1 ; copy of parameter block ptr
|
||
A6Link DS.l 2 ; link and return addr
|
||
ENDR
|
||
Open
|
||
Link A6,#OpenRec.LinkSz ; mark the stack for easy exit
|
||
|
||
Move.l A0,OpenRec.pbblkptr(A6) ; Save paramblock ptr for later access
|
||
|
||
Move.l #gestaltVMAttr,D0 ; see if VM is running
|
||
_Gestalt
|
||
Bne.s @noVM ; it is'nt if call failed
|
||
Move.l A0,D0
|
||
Btst #gestaltVMPresent,D0
|
||
Beq.s @noVM ; zero result means no VM 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 #OurVarSz,D0 ; variables size
|
||
_NewPtr ,SYS,CLEAR ; get memory for our variables
|
||
Bne OpenError
|
||
|
||
Move.l A0,(A3) ; save variable pointer
|
||
MoveA.l A0, A2 ; A2 -> our vars
|
||
|
||
Move.b MaceEnet,DCtlQueue+1(A1) ; Version number goes here
|
||
IF BIT24 THEN
|
||
Move.l A1,D0
|
||
_StripAddress
|
||
Move.l D0,OurDCE(A2) ; Save our DCE address
|
||
ELSE
|
||
Move.l A1,OurDCE(A2) ; Save our DCE address
|
||
ENDIF
|
||
Move.w #BlockMoveTrap,D0
|
||
_GetTrapAddress
|
||
Move.l A0,MemMove(A2) ; save trap address in our vars
|
||
;
|
||
; Look for a MACE configuration resource for this CPU
|
||
;
|
||
|
||
Move.l #gestaltMachineType,D0
|
||
_Gestalt ; get our machine type
|
||
Tst D0 ; any errors?
|
||
Bne OpenError ; yes, return with error
|
||
Move A0,D3 ; save our machine ID
|
||
|
||
SubQ #4,SP ; Make room for handle
|
||
Move.l #Configrsrc,-(SP) ; Push resource type
|
||
Move D3,-(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 D3,-(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 #-23,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 MCfg(A2), A1 ; A1-> space in our vars
|
||
Move.l #MACECFG.CfgSize, D0
|
||
_BlockMove ; Copy data from rsrc to our vars
|
||
|
||
Move.l A3, -(SP) ; push handle
|
||
_ReleaseResource ; We're thru with config resource
|
||
|
||
Lea MCfg.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
|
||
;
|
||
; Look for an alternate address resource for this slot
|
||
;
|
||
SubQ #4,SP ; Make room for handle
|
||
Move.l #EAddrRType, -(SP) ; Push resource type
|
||
MoveQ #0,D0 ; Clear out D0
|
||
MoveA.l OurDCE(A2),A1 ; A1 -> our DCE
|
||
Move.b dCtlSlot(A1),D0 ; D0 = slot
|
||
Move D0,-(SP) ; Set slot number as resource ID
|
||
_GetResource ; Get it
|
||
Move.l (SP)+,D0 ; D0 = handle to resource
|
||
Beq.s @25 ; Branch if not there
|
||
Move.l D0,A0 ; A0 = handle to resource
|
||
Move.l (A0),A0 ; A0 = pointer to resource
|
||
BTst #0,(A0) ; Make sure it's not a multicast addr
|
||
Bne.s @24 ; 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
|
||
@24 Move.l D0, -(SP) ; push handle
|
||
_ReleaseResource ; We're thru with alternate address resource
|
||
@25
|
||
;
|
||
; Determine our Ethernet Address from Address Prom, if address not provided
|
||
; via 'ecfg' or 'eadr' resource
|
||
;
|
||
Lea OurAddr(A2), A1 ; A1-> storage for address
|
||
Tst.l (A1) ; Do we already have an address?
|
||
Bne.s @45 ; yes, ignore address prom
|
||
Tst 4(A1)
|
||
Bne.s @45 ; yes, ignore address prom
|
||
|
||
MoveA.l MCfg.EnetPROM(A2), A0 ; Address of Ethernet Address PROM
|
||
MoveQ #0, D1 ; Setup to checksum the PROM address
|
||
MoveQ #7, D0 ; Do 8 bytes
|
||
MoveQ #1, D3 ; Offset to address byte
|
||
; Checksum the addresss PROM
|
||
@Xor Move.b (A0,D3.w), D2 ; get byte to XOR
|
||
Eor.b D2, D1
|
||
AddI #$10, D3 ; Inc offset to next byte
|
||
DBra D0, @Xor ; do them all
|
||
CmpI.b #$FF, D1 ; end result should be $FF
|
||
Bne OpenError ; return with generic error (D0=-1)
|
||
; Get our Ethernet addresss from the PROM
|
||
AddQ #EAddrSz, A1 ; go from last to first
|
||
MoveQ #EAddrSz-1, D2 ; Get 6 addr bytes
|
||
MoveQ #$51, D3 ; Offset to last address byte
|
||
|
||
@35 Move.b (A0,D3.w), D0 ; D0=inverted address
|
||
Bsr NormAddr ; Normalize it
|
||
Move.b D0, -(A1) ; Store in our vars
|
||
SubI #$10, D3 ; Dec offset to previous byte
|
||
DBra D2, @35
|
||
@45
|
||
IF BIT24 THEN
|
||
MoveQ #-1,D0
|
||
_StripAddress
|
||
Move.l D0,AddrMask(A2) ; save cached 32 bit address mask
|
||
ENDIF
|
||
WITH MACEInitParms
|
||
SubA #IPSize, SP ; make room for parms
|
||
Pea EtherRecv ; addr of packet reception rtn
|
||
Move.l (SP)+, RecvRtn(SP)
|
||
Move.l A2, RecvPrms(SP)
|
||
IF PRIMEDEFER THEN
|
||
Move.l #0, A0 ; no xmit completion rtn
|
||
ELSE
|
||
Lea XmitBuffAvail, A0 ; xmit completion rtn
|
||
ENDIF
|
||
Move.l A0, XmitRtn(SP)
|
||
Move.l A2, XmitPrms(SP)
|
||
Pea MCfg(A2)
|
||
Move.l (SP)+, MACECfgPtr(SP) ; ptr to MACE config record
|
||
Pea Dt3Stats(A2)
|
||
Move.l (SP)+, Dot3NetStats(SP) ; where to store 802.3 stats
|
||
Pea LAPStats(A2)
|
||
Move.l (SP)+, LAPMIBNetStats(SP) ; where to store LAP MIB stats
|
||
Pea OurAddr(A2)
|
||
Move.l (SP)+, EnetAddr(SP) ; ptr to our Ethernet address
|
||
Move.l MemMove(A2), FastMoveRtn(SP) ; addr of fast move memory rtn
|
||
|
||
Bsr MACEInit
|
||
Bne OpenError
|
||
|
||
AddA #IPSize, SP ; Strip parms
|
||
ENDWITH
|
||
|
||
Lea VBLQEL(A2),A0
|
||
Move #vType,vblType(A0)
|
||
Pea ControlDefer
|
||
Move.l (SP)+,vblAddr(A0)
|
||
Move #32767,vblCount(A0) ; setup control call deferral timer
|
||
_VInstall
|
||
|
||
IF PRIMEDEFER THEN
|
||
Lea DoWriteQEL(A2),A0
|
||
Move #0, tmCount(A0)
|
||
Pea XmitBuffAvail
|
||
Move.l (SP)+, tmAddr(A0)
|
||
_InsTime ; setup xmit buffer full deferral
|
||
ENDIF
|
||
;
|
||
; Perform 3 MACE loopback tests, if any fails, return an open error
|
||
;
|
||
Move.l #MaceEnetLongStrEnd-MaceEnetLongStr-1, -(SP) ; pass size of loopback
|
||
; data, minus 1 since pascal string
|
||
Pea MaceEnetLongStr+1 ; pass ptr to loopback data
|
||
Pea OurAddr(A2) ; pass ptr to our address
|
||
MoveA.l OurDCE(A2),A1 ; get ptr to DCE
|
||
Move dCtlRefNum(A1),D0
|
||
Move.l D0,-(SP) ; pass our refnum for ctl calls
|
||
|
||
MoveA.l MCfg.MACEBase(A2),A3 ; MACE base address
|
||
|
||
; Perform Internal, no MENDEC, Lpbk
|
||
; Note: network packet reception disabled
|
||
Move.b #INTLPB, MACE_USER_TEST_REG(A3) ; set user test reg
|
||
Bsr LOOPBACKTEST ; D0 0 if passed
|
||
Beq LoopError ; failed
|
||
|
||
; Perform Internal, with MENDEC, Lpbk
|
||
; Note: network packet reception disabled
|
||
Move.b #MENDECLPB, MACE_USER_TEST_REG(A3) ; set user test reg
|
||
Bsr LOOPBACKTEST ; D0 0 if passed
|
||
Beq LoopError ; failed
|
||
|
||
Move.b #EXTLPB, MACE_USER_TEST_REG(A3) ; perform external loopback
|
||
Bsr LOOPBACKTEST ; D0 0 if passed
|
||
Beq LoopError ; failed
|
||
|
||
Move.b #NOLPB, MACE_USER_TEST_REG(A3) ; disable loopback
|
||
|
||
Bsr.s InitSNMP
|
||
IF PROM THEN
|
||
;
|
||
; Check if we're opened in promiscuous mode
|
||
;
|
||
Move.l OpenRec.pbblkptr(A6), A0 ; Restore paramblock ptr
|
||
BTst.b #Promiscuous, ioFlags+1(A0) ; Are we being opened in Promiscuous mode?
|
||
Beq.s @notprm
|
||
ST Promiscflg(A2) ; Yes, indicate we're in promiscuous mode
|
||
Pea EtherRecvProm
|
||
Bsr MACESetProm ; turn on promiscuous in hw drvr
|
||
AddQ #4, SP ; clean up parms
|
||
@notprm
|
||
ENDIF
|
||
MoveQ #noErr,D0 ; Indicate no error
|
||
Unlk A6
|
||
Rts ; And return
|
||
|
||
;
|
||
; Loopback test error - 1 of 3 loopback tests failed
|
||
;
|
||
LoopError
|
||
AddQ #8,SP ; strip loopback test parms
|
||
Bsr Close ; shut down MACE
|
||
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
|
||
|
||
Lea OurVarPtr, A3
|
||
Tst.l (A3) ; Our variable pointer
|
||
Beq.s @56 ; Mem not allocated
|
||
MoveA.l (A3), A0
|
||
_DisposPtr ; Free it up
|
||
Clr.l (A3) ; Clear it out
|
||
@56
|
||
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
|
||
|
||
Align 2
|
||
; Strings used when building LAPStats.ifdescr string
|
||
RevStrStart Equ *
|
||
RevStr DC.B '. Hardware Revision: '
|
||
RevStrEnd Equ *
|
||
RevStrLen Equ RevStrEnd-(RevStrStart+1) ; str length, minus length byte
|
||
Align 2
|
||
;________________________________________________________________________
|
||
;
|
||
; Initialize SNMP statistic arrays
|
||
;
|
||
; Call: A2 - globals
|
||
;
|
||
; Return: none
|
||
;
|
||
; Destroys: A0,A1,D0,D3
|
||
;________________________________________________________________________
|
||
|
||
InitSNMP
|
||
|
||
; Initialize LAPStats
|
||
; Copy Pascal String MaceEnetLongStr
|
||
Lea LAPStats.ifDescr(A2), A1 ; A1 -> ifDescr
|
||
Lea MaceEnetLongStr, A0 ; A0 -> where to move from
|
||
MoveQ #0, D3 ; Init for BlockMove
|
||
Move.b (A0), D3 ; D0.B = strlen of MaceEnetLongStr
|
||
Cmp #255, D3 ; is str be greater than 255?
|
||
Bls @doit ; no
|
||
Move #255, D3 ; yes, move what we can
|
||
@doit AddQ #1, D3 ; move len byte too
|
||
Move.l D3, D0
|
||
_BlockMove ; Move it
|
||
Add.l D3, A1 ; A1 -> new end of ifDescr
|
||
|
||
Add.l #RevStrLen, D3 ; ifDescr + RevStr
|
||
Cmp #255, D3 ; would new str be greater than 255?
|
||
Bgt.s @cont ; yes, done with ifDescr
|
||
|
||
; get MACE Chip ID and convert to ascii
|
||
Lea RevStrEnd, A0
|
||
MoveA.l MCfg.MACEBase(A2), A3 ; MACE base address
|
||
MoveQ #0, D0
|
||
Move.b MACE_CHIP_ID_HIGH(A3), D0 ; get high byte MACE Chip ID
|
||
Ror.l #4, D0 ; get high nibble
|
||
Add.b #$30, D0 ; convert to ascii
|
||
Move.b D0, -4(A0) ; save it in RevStr
|
||
Clr.b D0
|
||
Rol.l #4, D0 ; get low nibble
|
||
Add.b #$30, D0 ; convert to ascii
|
||
Move.b D0, -3(A0) ; save it in RevStr
|
||
Move.b MACE_CHIP_ID_LOW(A3), D0 ; get low byte MACE Chip ID
|
||
Ror.l #4, D0 ; get high nibble
|
||
Add.b #$30, D0 ; convert to ascii
|
||
Move.b D0, -2(A0) ; save it in RevStr
|
||
Clr.b D0
|
||
Rol.l #4, D0 ; get low nibble
|
||
Add.b #$30, D0 ; convert to ascii
|
||
Move.b D0, -1(A0) ; save it in RevStr
|
||
|
||
; Append RevStr, minus len byte, to ifDescr
|
||
Lea RevStrStart+1, A0 ; A0 -> where to move from, will skip length byte
|
||
; A1 -> current end of ifDescr
|
||
Move.l #RevStrLen, D0 ; D0.l = strlen of RevStr
|
||
_BlockMove ; Move it
|
||
|
||
Lea LAPStats.ifDescr(A2), A1 ; A1 -> ifDescr
|
||
Add.b #RevStrLen, (A1) ; Set final string length
|
||
@cont
|
||
|
||
Move.l #SNMPVersion, LAPStats.ifVersion(A2) ; Set version to 1.0.0
|
||
Move.l #ethernet_csmacd, LAPStats.ifType(A2) ; indicate we're an Ethernet link
|
||
Move.l #EMaxDataSz, LAPStats.ifMaxMTU(A2)
|
||
Move.l #ESpeed, LAPStats.ifSpeed(A2)
|
||
|
||
Move.b #EAddrSz, LAPStats.ifPhysAddress(A2) ; set len of ifPhyAddr to #6
|
||
Move.l OurAddr(A2), LAPStats.ifPhysAddress+1(A2) ; copy first 4 bytes of address
|
||
Move OurAddr+4(A2), LAPStats.ifPhysAddress+5(A2) ; copy last 2 bytes of address
|
||
Move.l #ifStatusUp, LAPStats.ifAdminStatus(A2)
|
||
Move.l #ifStatusUp, LAPStats.ifOperStatus(A2)
|
||
Move.l Ticks, LAPStats.ifLastChange(A2)
|
||
|
||
; Initialize Dt3Stats
|
||
|
||
Move.l #SNMPVersion, Dt3Stats.dot3StatsVersion(A2) ; Set version to 1.0.0
|
||
Move.l #0, Dt3Stats.dot3StatsIndex(A2) ; Set index to 0
|
||
|
||
; Initialize Dt3Entry
|
||
|
||
Move.l #SNMPVersion, Dt3Entry.dot3Version(A2) ; Set version = 1.0.0
|
||
Move.l #$0, Dt3Entry.dot3Index(A2)
|
||
Move.l #2, Dt3Entry.dot3InitializeMac(A2)
|
||
Move.l #1, Dt3Entry.dot3SubLayerStatus(A2)
|
||
Move.l #1, Dt3Entry.dot3MulticastReceiveStatus(A2)
|
||
Move.l #1, Dt3Entry.dot3TxEnabled(A2)
|
||
Move.l #0, Dt3Entry.dot3TestTdrValue(A2)
|
||
|
||
Rts
|
||
|
||
;________________________________________________________________________
|
||
;
|
||
; Translate Logical to Physical Address Routine
|
||
;
|
||
; Call:
|
||
; 8(A6).l -> logical address
|
||
; 12(A6).l -> logical size
|
||
;
|
||
; Return:
|
||
; D0.w < 0 -> ERROR
|
||
; D0.l = physical address
|
||
; CC's are set
|
||
;________________________________________________________________________
|
||
|
||
; 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 lsize(A6),logical.count(A6)
|
||
Lea logical(A6),A0 ; A0->translation table
|
||
Lea 1,A1 ; A1=count to translate
|
||
MoveQ #5,D0 ; GetPhysical
|
||
|
||
_MemoryDispatch
|
||
IF BUFDEBUG THEN
|
||
Beq.s @cont ; success
|
||
_Debugger ; failure ?!?
|
||
@cont
|
||
ELSE
|
||
Blt.s @exit ; error, exit
|
||
ENDIF
|
||
|
||
Move.l physical.Address(A6),D0 ; return lowest physical address
|
||
@exit Unlk A6
|
||
Rts
|
||
|
||
ENDWITH
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; GetMemory - Get mem and then, optionally, make it contiguous & locked &
|
||
; non-cacheable
|
||
;
|
||
; Call:
|
||
; 8(A6).l -> mem size requested
|
||
; 12(A6).l -> mem options requested
|
||
; 16(A6).l -> address of storage for memory mgr block ptr (a handle)
|
||
; 20(A6).l -> address of storage for aligned memory region ptr (a handle)
|
||
; 24(A6).l -> address of storage for aligned memory region size (a ptr)
|
||
;
|
||
; Return:
|
||
; (16(A6)).l -> memory mgr block ptr
|
||
; (20(A6)).l -> aligned block of memory ptr
|
||
; (24(A6)).l -> aligned block of memory size
|
||
; D0.w < 0 -> ERROR, couldn't get mem or couldn't lockmemcontig it
|
||
; CC's are set
|
||
;___________________________________________________________________________
|
||
|
||
GetMemPs RECORD {A6Link}
|
||
LinkSz EQU *
|
||
A6Link DS.l 2 ; link and return addr
|
||
GMparms DS GetMem ; passed in parms
|
||
ENDR
|
||
|
||
kDefaultPageSize EQU $2000 ; default page size = 32k (same as Gestalt's)
|
||
|
||
GetMemory
|
||
WITH GetMemPs,GMparms
|
||
Link A6,#LinkSz
|
||
Movem.l A0-A1/D1-D4, -(SP) ; save registers
|
||
|
||
Move.l memsize(A6), D2 ; D2 = requested memory size
|
||
Move.l memoptions(A6), D1 ; D1 = requested memory options
|
||
; want mem locked, contiguous, or non-cacheable?
|
||
AndI.l #(1<<Locked)+(1<<Contig)+(1<<CacheOff), D1
|
||
Beq.s @doneal ; if not, then branch
|
||
;
|
||
; Compute the actual memory to be acquired
|
||
; actual memory size = x + (2 * PageSize)
|
||
;
|
||
Move.l #kDefaultPageSize, D3 ; D3 = Default Page Size
|
||
Move.l #gestaltLogicalPageSize, D0 ; Get the logical page size
|
||
_Gestalt
|
||
Tst D0 ; error on Gestalt call?
|
||
Bne.s @useDefaultPSize ; if so, then leave page size at default value
|
||
Move.l A0, D3 ; D3 = new Page Size
|
||
|
||
@useDefaultPSize
|
||
Add.l D3, D2 ; add page size
|
||
Add.l D3, D2 ; add page size. D2 = req mem size + (2 * PageSize)
|
||
|
||
@doneal
|
||
Move.L D2, D0
|
||
_NewPtr ,SYS,CLEAR ; get the memory
|
||
Blt @exit ; if error, exit
|
||
Move.l A0, ([memhndl,A6]) ; save ptr to new memory block
|
||
Tst.l D1 ; want mem locked, contiguous, or non-cacheable?
|
||
Beq.s @done ; no, so leave
|
||
|
||
;
|
||
; Create a page aligned mem region of page aligned size inside the non page aligned memory mgr blk.
|
||
; Do this 'cuz once we lockmemcontig it, we've potentially locked more than we want 'cuz
|
||
; lockmemcontig rounds down the start and up the end to page boundaries.
|
||
; Algorthm:
|
||
; a = requested block size
|
||
; b = a + alignment slop
|
||
; c = newptr(count=b)
|
||
; d = "c" aligned up to next page
|
||
; e = "a" aligned up to next page
|
||
; lockmemorycontiguous(address=d, count=e)
|
||
; setptrsize(address=c, count=(b - (top of mmgr blk - top of aligned region)))
|
||
; Return:
|
||
; mmgr blk ptr = c
|
||
; page aligned mem region ptr = d
|
||
; page aligned mem region size = e
|
||
;
|
||
; Expect:
|
||
; A0 -> new memory block
|
||
; A1 = scratch register
|
||
; D2 = memory block size
|
||
; D3 = Logical Page Size
|
||
; D4 = scratch register
|
||
|
||
Move.l A0, D1 ; D1 = address of new memory block to be aligned
|
||
Move.l D3, D4 ; D4 = Page Size
|
||
SubQ.l #1, D4 ; D4 = (Page Size - 1)
|
||
Add.l D4, D1 ; D1 = starting address + (Page Size - 1)
|
||
EorI.l #$FFFFFFFF, D4 ; Compute mask
|
||
And.l D4, D1 ; mask out lower bits to get page boundary
|
||
Move.l D1, ([memhndla,A6]) ; save aligned ptr
|
||
|
||
MoveA.l D1, A0 ; A0 -> ptr to aligned buffer
|
||
Move.l memsize(A6), D1 ; D1 = req. buffer len
|
||
Move.l D3, D4 ; D4 = Page Size
|
||
SubQ.l #1, D4 ; D4 = Page Size - 1
|
||
Add.l D4, D1 ; add to req buffer len
|
||
EorI.l #$FFFFFFFF, D4 ; Compute mask
|
||
And.l D4, D1 ; mask out lower bits to get page boundary
|
||
Move.l D1, ([memhndlasz,A6]) ; save aligned memory size
|
||
|
||
MoveA.l D1, A1 ; A1 -> length of buffer to Lock, A0 -> start address to Lock
|
||
MoveQ #4, D0 ; LockMemoryContiguous
|
||
_MemoryDispatch
|
||
Beq.s @donelock ; if no errors, then branch
|
||
;
|
||
; LockMemoryContiguous failed, so try to get rid of the memory block and leave with error
|
||
;
|
||
MoveA.l ([memhndl,A6]), A0 ; A0 -> memory block allocated
|
||
Move D0, -(SP) ; save err code
|
||
_DisposPtr ; failure, get rid of memory block
|
||
Move.l #0, ([memhndl,A6]) ; zero out addr
|
||
Move.l #0, ([memhndla,A6]) ; zero out addr
|
||
Move.l #0, ([memhndlasz,A6]) ; zero out size
|
||
Move (SP)+, D0 ; restore err code
|
||
Bra.s @exit ; return err
|
||
|
||
@donelock
|
||
MoveA.l ([memhndl,A6]), A0 ; A0 -> memory block
|
||
Move.l D2, D0 ; D0 = saved memory block size
|
||
Add.l A0, D2 ; D2 = addr of top of memory blk
|
||
Add.l ([memhndla,A6]), D1 ; D1 = addr of top of aligned mem region
|
||
Sub.l D1, D2 ; get unused space at top of mmgr blk
|
||
Sub.l D2, D0 ; get new mmgr blk size
|
||
_SetPtrSize ; decrease mmgr blk size
|
||
|
||
@done MoveQ #0, D0 ; set no error
|
||
@exit Movem.L (SP)+, A0-A1/D1-D4 ; restore registers
|
||
Unlk A6
|
||
Rts
|
||
ENDWITH
|
||
|
||
EJECT
|
||
;___________________________________________________________________________
|
||
;
|
||
; FreeMemory - Free mem and then, optionally, UN-make it contiguous & locked &
|
||
; non-cacheable
|
||
;
|
||
; Call:
|
||
; 8(A6).l -> memory options
|
||
; 12(A6).l -> memory mgr block ptr to free
|
||
; 16(A6).l -> aligned memory region ptr to unlock
|
||
; 20(A6).l -> size of aligned memory region
|
||
;
|
||
; Return:
|
||
; D0 = noErr
|
||
; CC's are set
|
||
;___________________________________________________________________________
|
||
|
||
FreeMemPs RECORD {A6Link}
|
||
LinkSz EQU *
|
||
A6Link DS.l 2 ; link and return addr
|
||
FMparms DS FreeMem ; passed in parms
|
||
ENDR
|
||
|
||
FreeMemory
|
||
WITH FreeMemPs,FMparms
|
||
Link A6,#LinkSz
|
||
|
||
Move.l memoptions(A6), D1 ; get mem options
|
||
; was mem locked,contiguous,or non-cacheable?
|
||
AndI.l #(1<<Locked)+(1<<Contig)+(1<<CacheOff), D1
|
||
Beq.s @free ; no
|
||
|
||
MoveA.l memptra(A6), A0 ; address of buffer
|
||
MoveA.l memptrasz(A6), A1 ; length of buffer
|
||
MoveQ #3, D0 ; UnLockMemory
|
||
_MemoryDispatch
|
||
IF BUFDEBUG THEN
|
||
Beq @ok ; success
|
||
_Debugger ; failure ?!?
|
||
@ok
|
||
ENDIF
|
||
@free MoveA.l memptr(A6), A0 ; address of buffer
|
||
_DisposPtr ; free the memory
|
||
IF BUFDEBUG THEN
|
||
Tst D0
|
||
Beq @ok1 ; success
|
||
_Debugger ; failure ?!?
|
||
@ok1
|
||
ENDIF
|
||
MoveQ #0, D0 ; no error
|
||
Unlk A6
|
||
Rts
|
||
ENDWITH
|
||
|
||
EJECT
|
||
|
||
;________________________________________________________________________
|
||
;
|
||
; 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.l OurVarPtr,A2 ; A2 -> our variables
|
||
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
|
||
Move.l CSParam+2(A0),D3 ; D3 = 1st parameter longword
|
||
;
|
||
; 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 LapGetDot3Entry-ControlTable ; 238
|
||
DC.w ENETDONE-ControlTable ; 239 LapSetDot3Entry
|
||
DC.w LapDot3Stats-ControlTable ; 240
|
||
DC.w ENETDONE-ControlTable ; 241 LapDot3CollStats
|
||
DC.w LapGetLinkStatus-ControlTable ; 242
|
||
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
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; LapGetDot3Entry - Get Dt3Entry
|
||
;
|
||
; Call:
|
||
; A0 -> queue element
|
||
; A2 -> our variables
|
||
; D3 = Link Stats Pointer
|
||
;
|
||
; Return:
|
||
; D0 = noErr
|
||
; EBuffSize(A0) = bytes returned
|
||
;___________________________________________________________________________
|
||
|
||
LapGetDot3Entry
|
||
Move.l #0, D0 ; Clear out D0
|
||
Move EBuffSize(A0), D0 ; D0 = # of bytes to move
|
||
Cmp #Dot3EntrySz, D0 ; Asking for more than we have?
|
||
Bls.s @OKsize ; no
|
||
Move #Dot3EntrySz, D0 ; yes, just return what we have
|
||
@OKsize
|
||
Move D0, EDataSize(A0) ; Return eDataSize
|
||
Move.l D3, A1 ; A1 -> user's Dot3Entry buffer
|
||
LEA Dt3Entry(A2), A0
|
||
_BlockMove
|
||
|
||
Bra ENETOK
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; LapGetLinkStatus - Return LAPMIBStats record info
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D3 = Link Stats Pointer
|
||
;
|
||
; Return:
|
||
; D0 = noErr
|
||
; EBuffSize(A0) = bytes returned
|
||
;___________________________________________________________________________
|
||
|
||
LapGetLinkStatus
|
||
Move.l MultiRecvd(A2), D0
|
||
Add.l BcastRecvd(A2), D0
|
||
Move.l D0, LAPStats.ifInNUcastPkts(A2) ; update non-unicast cnt
|
||
|
||
Move.l #0, D0 ; Clear out D0
|
||
Move EBuffSize(A0), D0 ; D0 = # of bytes to move
|
||
Cmp #LAPMIBStatsSz, D0 ; Asking for more than we have?
|
||
Bls.s @OKsize ; no
|
||
Move #LAPMIBStatsSz, D0 ; yes, just return what we have
|
||
@OKsize
|
||
Move D0, EDataSize(A0) ; Return eDataSize
|
||
MoveA.l D3, A1 ; A1 -> user's LAPMIBStats buffer
|
||
Lea LAPStats(A2), A0
|
||
_BlockMove
|
||
|
||
Bra ENETOK
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; LapDot3Stats - return Dot3Stats record info
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D3 = 802.3 Stats Pointer
|
||
;
|
||
; Return:
|
||
; D0 = noErr
|
||
; EBuffSize(A0) = bytes returned
|
||
;___________________________________________________________________________
|
||
|
||
LapDot3Stats
|
||
Move.l #0, D0 ; Clear out D0
|
||
Move EBuffSize(A0), D0 ; D0 = # of bytes to move
|
||
Cmp #Dot3StatsEntrySz, D0 ; Asking for more than we have?
|
||
Bls.s @OKsize ; no
|
||
Move #Dot3StatsEntrySz, D0 ; yes, just return what we have
|
||
@OKsize
|
||
Move D0, EDataSize(A0) ; Return eDataSize
|
||
MoveA.l D3, A1 ; A1 -> user's Dot3Stats buffer
|
||
Lea Dt3Stats(A2), A0
|
||
_BlockMove
|
||
|
||
Bra ENETOK
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; 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
|
||
;
|
||
; Finds a free entry in the Multicast Table, stores the multicast address,
|
||
; and increments the use count. Calls Mace rtn to update Mace Logical
|
||
; Address Filter (LAF).
|
||
;___________________________________________________________________________
|
||
|
||
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 Logical Address Filter (LAF)
|
||
;
|
||
@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)
|
||
|
||
Bsr.l MACEAddMulti ; Let Mace update LAF
|
||
|
||
Bra ENETOK
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; DoDelMulti - delete a multicast address from the list
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D1 = first two bytes of address
|
||
; D3 = last four bytes of address
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;
|
||
; Finds the multicast address in the Multicast Table and decrements the use
|
||
; count. Calls Mace rtn to update Mace Logical Address Filter (LAF).
|
||
;___________________________________________________________________________
|
||
|
||
DoDelMulti MoveQ #eMultiErr,D0 ; Assume address not found
|
||
Bsr.s FindMEntry ; D2 = entry number in table
|
||
Bmi ENETDone ; Return error if not found
|
||
SubQ.b #1,(MultiCTbl+MUseCount,A2,D2*MEntrySz) ; Decrement use count
|
||
|
||
Bsr.l MACEDelMulti ; Let Mace update LAF
|
||
|
||
Bra ENETOK
|
||
|
||
;
|
||
; 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.l = address of protocol handler's packet-receive code or zero
|
||
; D1.w = protocol type code
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoAttachPH
|
||
IF BIT24 THEN
|
||
And.l AddrMask(A2),D3 ; 32 bit clean
|
||
ENDIF
|
||
MoveQ #LAPProtErr,D0 ; Assume an invalid protocol error
|
||
|
||
IF PROM THEN
|
||
Tst.B Promiscflg(A2) ; Are we in Promiscuous mode?
|
||
Beq.S @10 ; No, Note: not set until pass lpbk test
|
||
Tst.w D1
|
||
Bne.s ENETDone ; Force attach to ONLY prot type 0
|
||
@10
|
||
ENDIF
|
||
;
|
||
; Read down the active protocol table, searching for a match
|
||
;
|
||
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
|
||
MoveA.l JIODone,A0
|
||
Jmp (A0) ; all done now
|
||
|
||
;
|
||
; 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.w = protocol type code
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoDetachPH
|
||
MoveQ #LAPProtErr,D0 ; Assume no such protocol active
|
||
|
||
IF PROM THEN
|
||
Tst.B Promiscflg(A2) ; Are we in Promiscuous mode?
|
||
Beq.S @5 ; No, Note: not set until pass lpbk test
|
||
Tst.w D1
|
||
Bne.s ENETDone ; Force deattach to ONLY prot type 0
|
||
@5
|
||
ENDIF
|
||
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.
|
||
;
|
||
; Call:
|
||
; 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
|
||
;
|
||
; Called:
|
||
; A2 -> our variables
|
||
; D3 = WDS pointer
|
||
;
|
||
; Return:
|
||
; D0 = error code; nobuff => chip drvr out of xmit buffers
|
||
; eLenErr => sum of data in WDS > max. pkt size
|
||
; noErr => chip drvr gave pkt to chip or put pkt
|
||
; in xmit queue for transmission
|
||
;
|
||
; Notes: Depends on MACEXmit to check maximum WDS length
|
||
;
|
||
;___________________________________________________________________________
|
||
|
||
DoWrite
|
||
IF PROM THEN
|
||
Tst.b Promiscflg(A2) ; Are we in promiscuous mode?
|
||
Bne.s WritePromisc ; yes, only do promiscuous writes
|
||
ENDIF
|
||
MoveQ #eLenErr, D0 ; Assume length error
|
||
Clr.b XmitWait(A2) ; Clear waiting flag
|
||
Move.l D3,A0 ; A0 -> WDS
|
||
Cmp #EHdrSize,(A0) ; First entry must have whole header
|
||
Blo ENETDone ; 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)
|
||
|
||
Move.l D3, -(SP) ; Push WDS ptr
|
||
Bsr MACEXmit ; send the packet
|
||
AddQ #4, SP ; Strip parms
|
||
Tst.l D0 ; Error?
|
||
Bne.s @xmitfail ; yes, check it
|
||
Bra ENETDone ; no, complete write req. w/no error
|
||
|
||
@xmitfail Cmp.l #nobuff, D0 ; temporarily out of xmit buffs?
|
||
IF BUFDEBUG THEN
|
||
Bne.s @chklenerr ; no, it must be a len err; lets chk
|
||
ELSE
|
||
Bne ENETDone ; no, its a len err; return err
|
||
ENDIF
|
||
ST XmitWait(A2) ; yes, set waiting flag
|
||
IF PRIMEDEFER THEN
|
||
Lea DoWriteQEL(A2), A0 ; A0-> TimeMgr task element
|
||
Move.l #-200, D0 ; delay 200 microseconds
|
||
_PrimeTime ; install task to try again later
|
||
ENDIF
|
||
MoveQ #noErr,D0
|
||
Rts ; Return, don't complete write yet
|
||
|
||
IF BUFDEBUG THEN
|
||
@chklenerr Cmp.l #eLenErr, D0 ; WDS length error?
|
||
Beq.s @ok ; yes
|
||
_Debugger ; no, what the heck?
|
||
@ok Bra ENETDone ; complete write req. w/error
|
||
ENDIF
|
||
|
||
IF PROM THEN
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; WritePromisc - write out a packet on Ethernet when DIRECTLY from user buffer
|
||
; ¥¥¥¥ user buffer MUST BE locked, contiguous, non-cached
|
||
; ¥¥¥¥ user MUST fully specify Ethernet Header
|
||
; ¥¥¥¥ FCS generation controlled via Xmit Frame Cntrl register
|
||
; ¥¥¥¥ which is changeable via 'ecfg' rsrc
|
||
;
|
||
; Called:
|
||
; A2 -> our variables
|
||
; D3 = SINGLE entry WDS ptr
|
||
;
|
||
; Return:
|
||
; noErr
|
||
;
|
||
; Notes:
|
||
;
|
||
;___________________________________________________________________________
|
||
|
||
WritePromisc
|
||
Move.l D3, A0 ; user WDS ptr
|
||
Move (A0), -(SP) ; Push user buffer len
|
||
Move.l 4(A0), -(SP) ; Push user buffer ptr
|
||
Bsr MACEXmitProm ; send the packet
|
||
AddQ #6, SP ; Strip parms
|
||
Bra ENETOK ; complete write req. w/no error
|
||
|
||
ENDIF
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; XmitBuffAvail - IF PRIMEDEFER, transmit deferral routine
|
||
; ELSE, xmit completion routine
|
||
;
|
||
; Call:
|
||
; IF PRIMEDEFER
|
||
; A1 - time manager queue element
|
||
;
|
||
; Return:
|
||
; no return value/status
|
||
;
|
||
; Notes: called via time manager after DoWrite gets no buff available error
|
||
; from MACEXmit call.
|
||
;___________________________________________________________________________
|
||
TxPrm RECORD 4
|
||
TxParm DS.l 1 ; my xmitdone parm
|
||
TxPrmSz EQU *
|
||
ENDR
|
||
|
||
XmitBuffAvail
|
||
MoveA.l OurVarPtr, A0 ; get ptr to our vars
|
||
|
||
IF BUFDEBUG THEN
|
||
AddQ.l #1, XmtDnActive(A0)
|
||
CmpI.l #1, XmtDnActive(A0)
|
||
Beq.s @ok
|
||
_Debugger ; oooppppsss!
|
||
@ok
|
||
ENDIF
|
||
|
||
Tst.b XmitWait(A0) ; waiting for xmit buffs?
|
||
Beq.s @exit ; no
|
||
|
||
IF COUNTERS THEN
|
||
AddQ.l #1, XmitPend(A0)
|
||
ENDIF
|
||
|
||
MoveM.l A0/A2/A3/D3, -(SP) ; save C regs
|
||
|
||
MoveA.l A0, A2 ; A2->our vars
|
||
MoveA.l OurDCE(A2), A1 ; A1->our DCE
|
||
MoveA.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
|
||
|
||
MoveM.l (SP)+, A0/A2/A3/D3 ; restore C regs
|
||
|
||
IF BUFDEBUG THEN
|
||
SubQ.l #1, XmtDnActive(A0)
|
||
ENDIF
|
||
@exit Rts
|
||
|
||
EJECT
|
||
;___________________________________________________________________________
|
||
;
|
||
; 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
|
||
Move #DMALockOut, D1
|
||
_SETINTMASK D1
|
||
@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
|
||
IF BIT24 THEN
|
||
Exg D0,A0
|
||
And.l AddrMask(A2),D0
|
||
Exg D0,A0 ; 32 bit clean
|
||
ENDIF
|
||
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
|
||
IF BIT24 THEN
|
||
And.l AddrMask(A2),D3 ; 32 bit clean
|
||
ENDIF
|
||
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
|
||
Move #DMALockOut, D1
|
||
_SETINTMASK D1
|
||
@30 Move.l (A3),D3 ; D3 -> next element in queue
|
||
IF BIT24 THEN
|
||
And.l AddrMask(A2),D3 ; 32 bit clean
|
||
ENDIF
|
||
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 stats in the following form:
|
||
; Our address, 3 lw's of 0's, Netstats record
|
||
;
|
||
; Call:
|
||
; A0 -> queue element
|
||
; A2 -> our variables
|
||
; D3 -> buffer for response
|
||
;
|
||
; Return:
|
||
; D0 = error code
|
||
;___________________________________________________________________________
|
||
|
||
DoGetInfo
|
||
IF BIT24 THEN
|
||
And.l AddrMask(A2),D3 ; 32 bit clean
|
||
ENDIF
|
||
Move #buf2SmallErr,D0 ; Assume buffer not big enough
|
||
Cmp #6,EBuffSize(A0) ; Must hold at least address
|
||
Blo ENETDone ; Return error if not
|
||
|
||
MoveQ #0, D0
|
||
Move EBuffSize(A0),D0 ; D0 = buffer size
|
||
Cmp #InfoEnd-InfoStart,D0 ; Asking for more than we have?
|
||
Bls.s @10 ; no, branch
|
||
MoveQ #InfoEnd-InfoStart,D0 ; yes, just return what we have
|
||
@10 Move.l D3,A1 ; A1 -> where to move to
|
||
Lea InfoStart(A2),A0 ; A0 -> where to move from
|
||
|
||
;
|
||
; Copy netstat info from Dot2stat and LAPMIBstat areas to "old" getinfo area
|
||
;
|
||
Move.l (LAPStats.ifOutUcastPkts,A2), D1
|
||
Add.l (LAPStats.ifOutNUcastPkts,A2), D1
|
||
Move.l D1, (EtherStats.TxOK,A2)
|
||
Move.l (Dt3Stats.dot3StatsSingleCollisionFrames,A2), (EtherStats.sCollFrame,A2)
|
||
Move.l (Dt3Stats.dot3StatsMultipleCollisionFrames,A2), (EtherStats.mCollFrame,A2)
|
||
; EtherStats.CollFrame doesn't make sense and is left 0
|
||
Move.l (Dt3Stats.dot3StatsDeferredTransmissions,A2), (EtherStats.DefTx,A2)
|
||
Move.l (Dt3Stats.dot3StatsLateCollisions,A2), (EtherStats.LateColl,A2)
|
||
Move.l (Dt3Stats.dot3StatsExcessiveCollisions,A2), (EtherStats.ExcessColl,A2)
|
||
Move.l (Dt3Stats.dot3StatsExcessiveDeferrals,A2), (EtherStats.ExcessDef,A2)
|
||
Move.l (Dt3Stats.dot3StatsInternalMacTransmitErrors,A2), (EtherStats.InMACTxErr,A2)
|
||
Move.l (LAPStats.ifInUcastPkts,A2), (EtherStats.RxOK,A2)
|
||
Move.l MultiRecvd(A2), (EtherStats.MultiRxOK,A2)
|
||
Move.l BcastRecvd(A2), (EtherStats.BroadRxOK,A2)
|
||
Move.l (Dt3Stats.dot3StatsFCSErrors,A2), (EtherStats.FCSerr,A2)
|
||
Move.l (Dt3Stats.dot3StatsAlignmentErrors,A2), (EtherStats.FAerr,A2)
|
||
Move.l (LAPStats.ifInErrors,A2), (EtherStats.MPerr,A2)
|
||
|
||
_BlockMove ; Move it
|
||
Bra ENETOK ; Return no error
|
||
|
||
;___________________________________________________________________________
|
||
;
|
||
; EtherRecv - .ENET packet receive routine
|
||
;
|
||
; Call:
|
||
; Received packet(s) pointed to by buffer(s) on InUse Queue
|
||
;
|
||
; Return:
|
||
; Empty InUse Queue
|
||
;
|
||
; Destroys:
|
||
; Notes:
|
||
; EtherRecv is called by the MACE since we passed a ptr to EtherRecv
|
||
; as the RecvRtn in the MACEInit call.
|
||
;
|
||
; Calls:
|
||
; Upper layer handler, or Default Handler, to receive packet.
|
||
;___________________________________________________________________________
|
||
|
||
EtherRecv
|
||
WITH RcvParms
|
||
Link A6, #Size
|
||
|
||
Move.l Stat(A6), D0 ; get packet status
|
||
AndI.w #(1<<RcvCLSN)+(1<<RcvFRAM)+(1<<RcvFCS), D0 ; packet with error?
|
||
Bne @86 ; ignore packet with error
|
||
|
||
MoveM.l A2-A5/D3,-(SP) ; save used C regs
|
||
|
||
MoveA.l Parm(A6), A2 ; Our variables
|
||
IF COUNTERS THEN
|
||
AddQ.l #1, EtherRcvCnt(A2)
|
||
ENDIF
|
||
Move Len(A6),D1 ; D1=size of packet, including FCS
|
||
Sub #EHdrSize+4,D1 ; Subtract out header & FCS bytes from total
|
||
;
|
||
; Copy the Ethernet header from the packet into the RHA
|
||
;
|
||
Lea RHA(A2), A3 ; A3 -> RHA
|
||
MoveA.l Pkt(A6), A0 ; A0 -> packet data
|
||
Move.l (A0)+, (A3)+ ; Move header into buffer
|
||
Move.l (A0)+, (A3)+ ; Hard code for speed
|
||
Move.l (A0)+, (A3)+
|
||
Move (A0)+, (A3)+ ; A3 -> buffer after header
|
||
;
|
||
; Check if dest. addr. a broadcast or one of our multicasts
|
||
;
|
||
Move RHA(A2), D3 ; D3 = first 2 bytes of dest address
|
||
BTst #8, D3 ; Is it a broadcast or multicast?
|
||
Beq.s @45 ; Branch if not, it must be our physical address
|
||
MoveQ #-1, D2 ; D2 = $FFFFFFFF
|
||
Cmp D2, D3 ; Is packet a broadcast?
|
||
Beq.s @last4 ; Maybe, check last 4 bytes of dest address
|
||
Move.l RHA+2(A2), D3 ; No, D3 = last 4 bytes of dest address
|
||
Bra @120 ; Go check if one of our registered multicasts
|
||
@last4 Move.l RHA+2(A2), D3 ; D3 = last 4 bytes of dest address
|
||
Cmp.l D2, D3 ; Is packet a broadcast?
|
||
Bne @120 ; No, go check if one of our registered multicasts
|
||
AddQ.l #1, BcastRecvd(A2) ; Yes, inc. broadcast pkt cntr
|
||
Bra.s @50
|
||
|
||
@45 AddQ.l #1, (LAPStats.ifInUcastPkts,A2) ; inc. non-multi/bcast pkt cntr
|
||
|
||
;
|
||
; 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 @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 @90 ; 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 ; get the protocol handler
|
||
Beq.s @80 ; use default
|
||
MoveA.l D3,A5 ; use table entry's protocol handler
|
||
|
||
@80
|
||
Jsr (A5) ; Call protocol handler
|
||
|
||
@85 MoveM.l (SP)+, A2-A5/D3 ; Restore registers
|
||
@86 Unlk A6
|
||
Rts ; That's it
|
||
|
||
@90 AddQ.l #1, LAPStats.ifInUnknownProtos(A2)
|
||
Bra.s @85
|
||
;
|
||
; 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 @90 ; Branch if not found
|
||
|
||
Bra.s @70 ; Process it
|
||
|
||
;
|
||
; Packet is a multicast. Check if it matches one of our multicast addresses.
|
||
;
|
||
; Call:
|
||
; A2 -> our variables
|
||
; D3 = last 4 bytes of destination address
|
||
;
|
||
@120 Move D1,D0 ; Save length in case packet's for us
|
||
Move RHA(A2),D1 ; D1 = high two bytes of address
|
||
Bsr FindMEntry ; D2 = entry within multicast table
|
||
Bmi.s @150 ; Ignore it if not found
|
||
AddQ.l #1, MultiRecvd(A2) ; Inc count of multicast pkts recv'd
|
||
Move D0,D1 ; Restore packet length
|
||
Bra @50 ; And process packet
|
||
|
||
@150 AddQ.l #1, LAPStats.ifInDiscards(A2) ; Increment count of packets not for us
|
||
Bra.s @85 ; Ignore this packet
|
||
|
||
IF PROM THEN
|
||
;___________________________________________________________________________
|
||
;
|
||
; EtherRecvProm - Promiscuous .ENET packet receive routine
|
||
;
|
||
; Call:
|
||
; Received packet(s) pointed to by buffer(s) on InUse Queue
|
||
;
|
||
; Return:
|
||
; Empty InUse Queue
|
||
;
|
||
; Destroys:
|
||
; Notes:
|
||
; EtherRecvProm is called by the MACE since we passed a ptr to it
|
||
; as the RecvRtn in the MACEInit call.
|
||
;
|
||
; Calls:
|
||
; Upper layer handler, or Default Handler, to receive packet.
|
||
;___________________________________________________________________________
|
||
|
||
EtherRecvProm
|
||
WITH RcvParms
|
||
Link A6, #Size
|
||
MoveM.l A2-A5/D3,-(SP) ; save used C regs
|
||
|
||
MoveA.l Parm(A6), A2 ; Our variables
|
||
IF COUNTERS THEN
|
||
AddQ.l #1, EtherRcvCnt(A2)
|
||
ENDIF
|
||
Move Len(A6), D1 ; D1=size of packet, including FCS
|
||
Sub #EHdrSize, D1 ; Subtract header from, leave 4 FCS in total
|
||
;
|
||
; Copy the Ethernet header from the packet into the RHA
|
||
;
|
||
Lea PromiscRHA(A2), A3 ; A3 -> PromiscRHA
|
||
Move.l Stat(A6), D0 ; get packet status
|
||
Move.l D0, (A3)+ ; Put pkt status at -4(RHA(A2))
|
||
MoveA.l Pkt(A6), A0 ; A0 -> packet data
|
||
Move.l (A0)+, (A3)+ ; Move header into buffer
|
||
Move.l (A0)+, (A3)+ ; Hard code for speed
|
||
Move.l (A0)+, (A3)+
|
||
Move (A0)+, (A3)+ ; A3 -> buffer after header
|
||
|
||
AndI.w #(1<<RcvCLSN)+(1<<RcvFRAM)+(1<<RcvFCS), D0 ; packet with error?
|
||
Bne.s @50 ; yes, go try to deliver it
|
||
;
|
||
; Check if dest. addr. a broadcast or one of our multicasts
|
||
;
|
||
Move RHA(A2), D3 ; D3 = first 2 bytes of dest address
|
||
BTst #8, D3 ; Is it a broadcast or multicast?
|
||
Beq.s @45 ; Branch if not, it must be our physical address
|
||
MoveQ #-1, D2 ; D2 = $FFFFFFFF
|
||
Cmp D2, D3 ; Is packet a broadcast?
|
||
Bne @30 ; No, go inc. cntr
|
||
Move.l RHA+2(A2), D3 ; D3 = last 4 bytes of dest address
|
||
Cmp.l D2, D3 ; Is packet a broadcast?
|
||
Beq @40 ; Yes, go inc. cntr
|
||
@30 AddQ.l #1, MultiRecvd(A2) ; No, inc. multicast pkt cntr
|
||
Bra.s @50 ; go try to deliver pkt
|
||
@40 AddQ.l #1, BcastRecvd(A2) ; Yes, inc. broadcast pkt cntr
|
||
Bra.s @50 ; go try to deliver pkt
|
||
|
||
@45 AddQ.l #1, (LAPStats.ifInUcastPkts,A2) ; inc. non-multi/bcast pkt cntr
|
||
;
|
||
; Search the protocol handler table for this protocol
|
||
;
|
||
|
||
@50 MoveQ #LAPTblSz-1,D2 ; Index to promiscuous LAP table entries
|
||
Tst.b InUseFlag(A2,D2) ; In use?
|
||
Beq.s @85 ; no, ignore pkt
|
||
|
||
Lea EReadPacket,A4 ; A4 -> our ReadPacket routine
|
||
Lea DefaultPH,A5 ; use default maybe
|
||
Move.l (Handlers,A2,D2*4),D3 ; get the protocol handler
|
||
Beq.s @80 ; use default
|
||
MoveA.l D3,A5 ; use table entry's protocol handler
|
||
|
||
@80
|
||
Jsr (A5) ; Call protocol handler
|
||
|
||
@85 MoveM.l (SP)+, A2-A5/D3 ; Restore registers
|
||
Unlk A6
|
||
Rts ; That's it
|
||
|
||
;@90 AddQ.l #1, LAPStats.ifInUnknownProtos(A2)
|
||
|
||
ENDIF ; PROM
|
||
;___________________________________________________________________________
|
||
;
|
||
; 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
|
||
Rts
|
||
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
|
||
@10 Rts ; Return
|
||
;___________________________________________________________________________
|
||
;
|
||
; DefaultPH - default protocol handler - complete an ERead call if there
|
||
;
|
||
; Call:
|
||
; A0,A1: preserve until ReadRest
|
||
; A2 -> local variables
|
||
; A4 -> EReadPacket
|
||
; A5 usable until ReadRest
|
||
; D0 = protocol type
|
||
; D2 = index into protocol table
|
||
;
|
||
; Notes: 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
|
||
IF PROM THEN
|
||
Tst.B Promiscflg(A2) ; Are we in Promiscuous mode?
|
||
Beq.S @5 ; No, Note: not set until pass lpbk test
|
||
Lea PromiscRHA(A2), A5 ; A5 -> header info including pkt status lw
|
||
Move.l (A5)+,(A3)+ ; Move pkt status into buffer
|
||
Bra.s @6
|
||
@5 Lea RHA(A2),A5 ; A5 -> header info
|
||
@6
|
||
ELSE
|
||
Lea RHA(A2),A5 ; A5 -> header info
|
||
ENDIF
|
||
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
|
||
IF BIT24 THEN
|
||
Exg D0,A3
|
||
And.l AddrMask(A2),D0
|
||
Exg D0,A3 ; 32 bit clean
|
||
ENDIF
|
||
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 ([MemMove,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.
|
||
;
|
||
; Call:
|
||
; A1 -> DCE
|
||
;________________________________________________________________________
|
||
|
||
Close
|
||
; This code is only called if one of the LoopBack tests failed. Closing is
|
||
; not a supported function since there is no way for me to know how many
|
||
; clients are using the driver; ie. AppleTalk using 802.3 and MacTCP using
|
||
; Ethernet. If the Device Manager passed all open calls to the driver a
|
||
; use-count could be implemented and I could truely support Close.
|
||
MoveA.l OurVarPtr, A2 ; A2 -> our variables
|
||
|
||
Bsr MACEHalt ; stop MACE
|
||
|
||
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 VBLQEL(A2),A0
|
||
Tst.l vblAddr(A0) ; did we launch ctl call VBL?
|
||
Beq.s @50
|
||
_VRemove ; remove VBL task if so
|
||
@50
|
||
IF PRIMEDEFER THEN
|
||
Lea DoWriteQEL(A2),A0
|
||
Tst.l tmAddr(A0) ; did we install xmit buff full deferral?
|
||
Beq.s @60 ; no, do nothing
|
||
Tst.b XmitWait(A2) ; have we prime'd task?
|
||
Beq.s @55 ; no, remove task
|
||
_Debugger ; rmvtime doesn't really remove an active task ?!?
|
||
; need method to handle this case
|
||
@55
|
||
_RmvTime ; remove TimeMgr task if so
|
||
@60
|
||
ENDIF
|
||
MoveA.L OurVarPtr,A0
|
||
_DisPosPtr ; free our var mem
|
||
|
||
Lea OurVarPtr,A2 ; A2 -> variable pointer
|
||
Clr.l (A2) ; Clear it out (no variables)
|
||
MoveQ #0,D0 ; Indicate no error
|
||
AnRts Rts ; And return
|
||
|
||
;
|
||
; Variable storage
|
||
;
|
||
OurVarPtr DC.l 0 ; Pointer to our variables
|
||
END
|
||
|
||
|
||
|