mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-12 04:29:09 +00:00
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
|
|
|
|
|
|
|