; ; File: PDMMaceEnet.a ; ; Contains: Ethernet Data Link level driver for builtin MACE Ethernet on PDM. ; ; Converted for PDM ; by Dave Calvert November 18,1992 ; ; Based on the Cyclone ENET driver ; 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): ; ; 7/1/93 GMR Make the receive handler ignore the packet if there was a Mace ; overrun error. ; 6/10/93 GMR Changed the handling transmit deferrals. ; 6/2/93 GMR Minor changes to the receive handler. ; 5/27/93 dwc Added support for AMIC work-around code. ; 5/25/93 dwc Clean up for Alpha. ; 5/4/93 dwc Added debug code to work around AMIC's returning FF's on the ; first read and removed some obsolete code and equates. ; 4/6/93 dwc Updated for level #4 DMA interrupts. ; 3/24/93 dwc Remove obsolete code and added code to try to recover from ; lowered interrupt level during packet handling. ; 3/5/93 dwc Removed some obsolete code and comments. ; 2/25/93 dwc Enabled receive and loopbacktests. ; 2/24/93 dwc Removed some debug code and checked in for the PDM D5 ROM build. ; 2/4/93 dwc first checked in ; ; To Do: ; ; Replace BIT24 with Supports24Bit ; Remove some unused equates ; 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 0 ; Promiscous mode support Logging EQU 1 ; PRINT NOGEN,NOMDIR,ON INCLUDE 'PDMMaceEqu.a' ; Mace definitions INCLUDE 'AMICEqu.a' ; AMIC 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 MACEBase DS.l 1 ; MACE base address 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 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 ORBuffrsrc EQU 'ebfr' ; res type for buffer count override 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, AddToLog WITH MACERegs,OurV 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 'VersionPDMMaceEnet.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 Move.l A1,OurDCE(A2) ; Save our DCE address Move.w #BlockMoveTrap,D0 _GetTrapAddress Move.l A0,MemMove(A2) ; save trap address in our vars ; ; 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 Move.b dCtlSlot(A1),D0 ; Get the slot number Move D0,-(SP) ; Set slot number as resource ID _GetResource ; Get it MoveQ #-1, D0 ; Assume error Move.l (SP)+,D1 ; D1 = handle to resource Beq @30 ; Do nothing, if not there Move.l D1,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 OpenError ; EXIT, if it is Move.l (A0)+,OurAddr(A2) ; Move four bytes to our address Move (A0)+,OurAddr+4(A2) ; Move the last two bytes @30 Clr.l -(SP) ; room for result Move.l #ORBuffrsrc,-(SP) MoveQ #0,D0 ; Clear out D0 Move.b dCtlSlot(A1),D0 Move D0,-(SP) ; Set slot number as resource ID _GetResource Move.l (SP)+,D0 Beq.s @31 ; no buff override rsrc, branch MoveA.l D0,A0 MoveA.l (A0),A0 @31 ; ; Determine our Ethernet Address from Address Prom, if address not provided ; via EAddrRType resource ; Lea OurAddr(A2),A1 Tst.l (A1) Bne.s @45 ; already have an address Tst.w 4(A1) Bne.s @45 ; already have an address Move.l D3, -(SP) Lea AddrPROM, 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 Move.l (SP)+, D3 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 Move.l D3, -(SP) 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 Move.l (SP)+, D3 @45 WITH MACEInitParms SubA #IPSize, SP ; make room for parms Move.l UnivInfoPtr, A0 ; Get ptr to ProductInfo Add.l ProductInfo.DecoderInfoPtr(A0), A0 ; Point to the base address table Move.l DecoderInfo.MACEAddr(A0), MACEBase(A2) ; Save base address of Mace Pea EtherRecv ; addr of packet reception rtn Move.l (SP)+, RecvRtn(SP) Move.l A2, RecvPrms(SP) Lea XmitBuffAvail, A0 ; xmit completion rtn Move.l A0, XmitRtn(SP) Move.l A2, XmitPrms(SP) clr.l MACECfgPtr(SP) ; ptr to MACE config record (none) 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 ; ; 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 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 nop 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 nop ; Allow write to complete Bsr LOOPBACKTEST ; D0 ­ 0 if passed Beq LoopError ; failed Move.b #EXTLPB, MACE_USER_TEST_REG(A3) ; perform external loopback nop ; Allow write to complete 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 Move.b MACE_MAC_CNFG(A3), D0 ; get current config OrI.b #(1< 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 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 #iso88023_csmacd, LAPStats.ifType(A2) ; indicate we're an 802.3 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).w -> mem options requested ; 10(A6).l -> mem size requested ; ; Return: ; D0.w < 0 -> ERROR, couldn't get mem or couldn't lockmemcontig it ; D0.l = Ptr to locked, contig, non-cacheable mem ; CC's are set ;___________________________________________________________________________ GetMem RECORD {A6Link} LinkSz EQU * A6Link DS.l 2 ; link and return addr memoptions DS.w 1 ; requested options memsize DS.l 1 ; requested size ENDR GetMemory WITH GetMem Link A6,#LinkSz Move.l memsize(A6), D0 _NewPtr ,SYS,CLEAR ; get the memory Blt.s @exit ; error, exit Move.l A0, -(SP) ; save ptr to new mem Move memoptions(A6), D1 ; want mem locked, contiguous, or non-cacheable? AndI #(1< mem options ; 10(A6).l -> mem address to free ; 14(A6).l -> mem size to free ; ; Return: ; D0 = noErr ; CC's are set ;___________________________________________________________________________ FreeMem RECORD {A6Link} LinkSz EQU * A6Link DS.l 2 ; link and return addr memoptions DS.w 1 ; requested options memaddr DS.l 1 ; address of mem to free memsize DS.l 1 ; size of mem to UN-(lock,contig,noncache) ENDR FreeMemory WITH FreeMem Link A6,#LinkSz Move memoptions(A6), D1 ; get mem options ; was mem locked,contiguous,or non-cacheable? AndI #(1< 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 MoveQ #eLenErr, D0 ; Assume length error 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) IF Logging THEN move.l #'DoWr',-(sp) move.l ESrcAddr(A0),-(sp) move.l ESrcAddr+4(A0),-(sp) bsr AddToLog add.w #12,sp ENDIF 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 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 ;___________________________________________________________________________ ; ; XmitBuffAvail - xmit completion routine ; ; Call: ; d0 - transmit waiting flag (!=0 means a write is pending) ; ; 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 IF Logging THEN move.l #'WrDn',-(sp) clr.l -(sp) clr.l -(sp) bsr AddToLog add.w #12,sp ENDIF 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 d0 ; 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 Move.l dCtlQHead(A1),d0 beq.s @done move.l d0,A0 ; A0->waiting write param blk Move.l CSParam+2(A0), D3 ; D3 = 1st parameter longword (e.g. WDSP) Bsr DoWrite ; process the write @done MoveM.l (SP)+, 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 IF Logging THEN move.l #'DoRd',-(sp) move.l a0,-(sp) clr.l -(sp) bsr AddToLog add.w #12,sp ENDIF 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 IF Logging THEN move.l #'COMP',-(sp) move.l a0,-(sp) clr.l -(sp) bsr AddToLog add.w #12,sp ENDIF 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 IF Logging THEN move.l #'Ethr',-(sp) move.l #'Recv',-(sp) move.l PktStat(A6),-(sp) bsr AddToLog add.w #12,sp ENDIF Move.l PktStat(A6), D0 ; get packet status AndI.w #(1< RHA MoveA.l PktData(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 ;___________________________________________________________________________ ; ; 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 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