diff --git a/Driver/enc624j6net/README.txt b/Driver/enc624j6net/README.txt new file mode 100644 index 0000000..30a5676 --- /dev/null +++ b/Driver/enc624j6net/README.txt @@ -0,0 +1,59 @@ +ENC624J6net + +SANA-II Driver for Matze/Scrat ZII IDE LAN CP card + +author: Henryk Richter + + + + +Installation: +------------- + +The driver (enc624j6net.device) needs to be copied into Devs:Networks. The configuration +depends on the TCP/IP stack of choice. Please refer to the respective documentation +how to configure a network interface. + +Use the supplied GUI for stacks like Genesis or Miami and add a regular ethernet card +within those by referring to the enc624j6net.device, unit 0. + +The recent RoadShow stack is commandline-based. Please add a new file in devs:NetInterfaces, +such as a copy of the PlipBox interface specification with the device entry replaced by +enc624j6net.device. The command AddNetInterface with the filename of your interface spec +as argument will then activate the driver for RoadShow. + + +Technical notes: +---------------- + +Matze's card does selective byte swapping for different areas of the chip within +the CPLD. This step enables Big Endian reads/writes to the hardware registers. Since +the SRAM would be byte-swapped as well, the latest (WIP) version of the CPLD presents +TX and RX frames in Big Endian (network order) as well. As a consequence, the +low-level part of the driver won't work out of the box with with other approaches +towards 16 Bit parallel connections of the ENC624J600 chip. + + +Copyrights and Acknowledgements: +-------------------------------- + +My deepest respects go to Christian Vogelgsang (lafalla) for his plipbox project. +His invaluable work on further cleanups and abstractions to the already well written +magPLIP made a quick swap of low-level functions quite easily possible. + +The ENC624J6 source is heavily based on plipbox, which is in turn based on the magPLIP +driver found on aminet.net: + +http://lallafa.de/blog/amiga-projects/plipbox/ +http://aminet.net/package/comm/net/magPLIP38.1 + +magPLIP - SANA II compliant PLIP device driver for AmiTCP/IP, Envoy, + AS225 and other networking packages + + (C) Copyright 1993-1994 Oliver Wagner, Michael Balzer + (C) Copyright 1995 Jan Kratochvil & Martin Mares + (C) Copyright 1995-1996 Marius Groeger + All Rights Reserved. + + Changes have been made by Stéphane Zermatten to the driver to connect + a LinuxBox to an Amiga via a LapLing cable, based on the release 37.8. diff --git a/Driver/enc624j6net/build/enc624j6net.device.020 b/Driver/enc624j6net/build/enc624j6net.device.020 new file mode 100755 index 0000000..832c5de Binary files /dev/null and b/Driver/enc624j6net/build/enc624j6net.device.020 differ diff --git a/Driver/enc624j6net/compiler.h b/Driver/enc624j6net/compiler.h new file mode 100644 index 0000000..7a2c1d1 --- /dev/null +++ b/Driver/enc624j6net/compiler.h @@ -0,0 +1,33 @@ +#ifndef __COMPILER_H +#define __COMPILER_H + +#ifdef __SASC +/* Implementation notes: +** +** SAS/C complains if a module contains only "static" and "extern" functions +** that there would be no exported symbol. Therefore, the PUBLIC macro +** is defined empty for SAS/C but should be "extern" if possible (for +** instance with GNU CC). +*/ +# define ASM __asm /* define registers for function args */ +# define REG(x) register __ ## x /* specify a register in arglist */ +# define INLINE __inline /* inline this function */ +# define STDARGS __stdargs /* pass args to this function on stack */ +# define REGARGS __regargs /* pass args to this function in regs */ +# define SAVEDS __saveds /* setup data segment reg. on entry */ +# define FAR __far /* reference this object in far mode */ +# define MIN __builtin_min /* min{} function */ +# define MAX __builtin_max /* max{} function */ +# define PUTREG __builtin_putreg /* set a register to a certain value */ +# define REG_D0 0 /* reg. number for PUTREG() */ +# define REG_D1 1 /* reg. number for PUTREG() */ +extern void PUTREG(int, long); /* prototype */ +# define PUBLIC /* define a globally visible function */ +# define PRIVATE static /* define a locally visible function */ +# define GLOBAL extern +#else +# error Please define the above macros for your compiler +#endif + +#endif + diff --git a/Driver/enc624j6net/debug.h b/Driver/enc624j6net/debug.h new file mode 100644 index 0000000..600a74a --- /dev/null +++ b/Driver/enc624j6net/debug.h @@ -0,0 +1,33 @@ +#ifndef __DEBUG_H +#define __DEBUG_H + +#if (DEBUG != 0) +extern void KPrintF(char *, ...), KGetChar(void); +#endif + +#if (DEBUG & 1) +# define d(x) do { KPrintF("%s:%s:%ld:",__FILE__,__FUNC__,__LINE__); KPrintF x; } while(0) +#else +# define d(x) +#endif + +#if (DEBUG & 2) +# define d2(x) do { KPrintF("%s:%s:%ld:",__FILE__,__FUNC__,__LINE__); KPrintF x; } while(0) +#else +# define d2(x) +#endif + +#if (DEBUG & 4) +# define d4(x) do { KPrintF("%s:%s:%ld:",__FILE__,__FUNC__,__LINE__); KPrintF x; } while(0) +#else +# define d4(x) +#endif + +#if (DEBUG & 8) +# define d8(x) do { KPrintF("%s:%s:%ld:",__FILE__,__FUNC__,__LINE__); KPrintF x; } while(0) +#else +# define d8(x) +#endif + +#endif + diff --git a/Driver/enc624j6net/dev_info.h b/Driver/enc624j6net/dev_info.h new file mode 100644 index 0000000..14683a7 --- /dev/null +++ b/Driver/enc624j6net/dev_info.h @@ -0,0 +1,8 @@ +#ifndef _DEV_INFO_H +#define _DEV_INFO_H +#define DEVICE_NAME "enc624j6net" +#define DEVICE_DATE "18.12.2017" +#define DEVICE_VER "0.1" +#define DEVICE_VERSION 0 +#define DEVICE_REVISION 1 +#endif diff --git a/Driver/enc624j6net/dev_info.i b/Driver/enc624j6net/dev_info.i new file mode 100644 index 0000000..29b3006 --- /dev/null +++ b/Driver/enc624j6net/dev_info.i @@ -0,0 +1,11 @@ +DEVICE_NAME MACRO + dc.b 'enc624j6net' + ENDM +DEVICE_DATE MACRO + dc.b '18.12.2017' + ENDM +DEVICE_VER MACRO + dc.b '0.1' + ENDM +DEVICE_VERSION equ 0 +DEVICE_REVISION equ 1 diff --git a/Driver/enc624j6net/device.c b/Driver/enc624j6net/device.c new file mode 100755 index 0000000..989ea63 --- /dev/null +++ b/Driver/enc624j6net/device.c @@ -0,0 +1,922 @@ +#define DEBUG 0 + +/*F*/ /* includes */ +#ifndef CLIB_ALIB_PROTOS_H +#include +#endif +#ifndef CLIB_EXEC_PROTOS_H +#include +#include +#endif +#ifndef CLIB_DOS_PROTOS_H +#include +#include +#endif +#ifndef CLIB_CIA_PROTOS_H +#include +#include +#endif +#ifndef CLIB_MISC_PROTOS_H +#include +#include +#endif +#ifndef CLIB_UTILITY_PROTOS_H +#include +#include +#endif +#ifndef CLIB_TIME_PROTOS_H +#include +#include +#endif +#ifndef DEVICES_SANA2_H +#include +#endif + +#ifndef HARDWARE_CIA_H +#include +#endif + +#ifndef DOS_DOSTAGS_H +#include +#endif + +#ifndef RESOURCES_MISC_H +#include +#endif + +#ifndef EXEC_MEMORY_H +#include +#endif + +#ifndef _STRING_H +#include +#endif + +#ifndef __GLOBAL_H +#include "global.h" +#endif +#ifndef __DEBUG_H +#include "debug.h" +#endif +#ifndef __COMPILER_H +#include "compiler.h" +#endif + +#ifdef PROTO_SDNET +#include "vampuuid.h" +#define __NOLIBBASE__ +#include +#include +#endif + +#ifdef PROTO_ENC624NET +#define ENC_MANUFACTURER 2588 +#define ENC_BOARD 123 +#include +#include +#include + +#include "enc624j6l.h" /* for MAC retrieval */ +#endif + +#define INVALID_SDNET_UNIT 0x33 /* used by both sdnet and encnet */ + +/*E*/ + +/*F*/ /* imports */ +PUBLIC VOID SAVEDS ServerTask(VOID); +PUBLIC BOOL remtracktype(BASEPTR, ULONG type); +PUBLIC BOOL addtracktype(BASEPTR, ULONG type); +PUBLIC BOOL gettrackrec(BASEPTR, ULONG type, struct Sana2PacketTypeStats *info); +PUBLIC VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd); +PUBLIC VOID freetracktypes(BASEPTR); +#define min __builtin_min +/*E*/ +/*F*/ /* exports */ +PUBLIC ASM SAVEDS struct Device *DevInit(REG(d0) BASEPTR, REG(a0) BPTR seglist, REG(a6) struct Library *_SysBase); +PUBLIC ASM SAVEDS LONG DevOpen(REG(a1) struct IOSana2Req *ios2, REG(d0) ULONG unit, REG(d1) ULONG flags, REG(a6) BASEPTR); +PUBLIC ASM SAVEDS BPTR DevExpunge(REG(a6) BASEPTR); +PUBLIC ASM SAVEDS BPTR DevClose( REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR); +PUBLIC VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2); +PUBLIC ASM SAVEDS VOID DevBeginIO(REG(a1) struct IOSana2Req *ios2, REG(a6) BASEPTR); +PUBLIC ASM SAVEDS LONG DevAbortIO(REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR); +/*E*/ +/*F*/ /* private */ +PRIVATE BOOL isinlist(struct Node *n, struct List *l); +PRIVATE VOID abort(BASEPTR, struct IOSana2Req *ior); +/*E*/ + +#ifdef PROTO_SDNET + +PRIVATE void pb_FreeExpansion(BASEPTR ); +PRIVATE APTR pb_AllocExpansion( ULONG portid, BASEPTR ); + +PRIVATE void pb_FreeExpansion(BASEPTR ) +{ + if( pb->pb_ExpansionPort >= 0 ) + { + V_FreeExpansionPort( pb->pb_ExpansionPort ); + pb->pb_ExpansionPort = -1; + } +} + +PRIVATE APTR pb_AllocExpansion( ULONG portid, BASEPTR ) +{ + return V_AllocExpansionPort( portid, SERVERTASKNAME ); +} + +#endif /* PROTO_SDNET */ + + /* + ** various support routines + */ +/*F*/ PRIVATE BOOL isinlist(struct Node *n, struct List *l) +{ + struct Node *cmp; + + for(cmp = l->lh_Head; cmp->ln_Succ; cmp = cmp->ln_Succ) + if (cmp == n) return TRUE; + + return FALSE; +} +/*E*/ +/*F*/ PRIVATE VOID abort(BASEPTR, struct IOSana2Req *ior) +{ + Remove((struct Node*)ior); + ior->ios2_Req.io_Error = IOERR_ABORTED; + ior->ios2_WireError = 0; + ReplyMsg((struct Message*)ior); +} +/*E*/ + + /* + ** initialise device + */ +/*F*/ PUBLIC ASM SAVEDS struct Device *DevInit(REG(d0) BASEPTR, REG(a0) BPTR seglist, REG(a6) struct Library *_SysBase) +{ + BOOL ok; + UBYTE *p; + UWORD i; + + d(("entered device, initialising PLIPBase...\n")); + + /* clear data base */ + for(p = ((UBYTE*)pb) + sizeof(struct Library), i = sizeof(struct PLIPBase)-sizeof(struct Library); i; i--) + *p++ = 0; + + SysBase = _SysBase; + + pb->pb_SegList = seglist; /* store DOS segment list */ + + /* init some default values */ + pb->pb_Flags = PLIPF_OFFLINE; + pb->pb_BPS = HW_BPS; + pb->pb_MTU = HW_ETH_MTU; + /* initialise the lists */ + NewList((struct List*)&pb->pb_ReadList); + NewList((struct List*)&pb->pb_WriteList); + NewList((struct List*)&pb->pb_EventList); + NewList((struct List*)&pb->pb_ReadOrphanList); + NewList((struct List*)&pb->pb_TrackList); + NewList((struct List*)&pb->pb_BufferManagement); + + /* initialise the access protection semaphores */ + InitSemaphore(&pb->pb_ReadListSem); + InitSemaphore(&pb->pb_ReadOrphanListSem); + InitSemaphore(&pb->pb_EventListSem); + InitSemaphore(&pb->pb_WriteListSem); + InitSemaphore(&pb->pb_TrackListSem); + InitSemaphore(&pb->pb_Lock); + + pb->pb_SpecialStats[S2SS_TXERRORS].Type = S2SS_PLIP_TXERRORS; + pb->pb_SpecialStats[S2SS_TXERRORS].Count = 0; + pb->pb_SpecialStats[S2SS_TXERRORS].String = "TX Errors"; + pb->pb_SpecialStats[S2SS_COLLISIONS].Type = S2SS_PLIP_COLLISIONS; + pb->pb_SpecialStats[S2SS_COLLISIONS].Count = 0; + pb->pb_SpecialStats[S2SS_COLLISIONS].String = "Collisions"; + + ok = FALSE; + + if (UtilityBase = OpenLibrary("utility.library", 37)) + { + if (DOSBase = OpenLibrary("dos.library", 37)) + { +#ifdef PROTO_ENC624NET + if( ExpansionBase = OpenLibrary("expansion.library", 37)) + { + int i; + + ok = TRUE; + + for( i=0 ; i<(HW_MAXBOARDS+1) ; i++ ) + pb->pb_HWBase.hwb_boards[i]=0; /* clear whole array */ + } + else + { + d(("no expansion.library\n")); + } +#endif +#ifdef PROTO_SDNET + if( VampireBase = OpenResource( V_VAMPIRENAME ) ) + { + pb->pb_ExpansionPort = -1; + ok = TRUE; + } + else + { + d(("no vampire.resource\n")); + } +#endif + } + else + { + d(("no dos\n")); + } + + if (!ok) CloseLibrary(UtilityBase); + } + else + { + d(("no utility\n")); + } + + d(("left %ld\n",ok)); + + return (struct Device *)(ok ? pb : NULL); +} +/*E*/ + + /* + ** open device + */ +/*F*/ PUBLIC ASM SAVEDS LONG DevOpen(REG(a1) struct IOSana2Req *ios2, REG(d0) ULONG unit, REG(d1) ULONG flags, REG(a6) BASEPTR) +{ + BOOL ok = FALSE; + struct BufferManagement *bm; + LONG rv = 0; /* get rid of warning with opt build */ + + d(("entered\n")); + + /* Make sure our open remains single-threaded. */ + ObtainSemaphore(&pb->pb_Lock); + + pb->pb_DevNode.lib_OpenCnt++; + +#ifdef PROTO_SDNET + if( !VampireBase ) + { + unit = INVALID_SDNET_UNIT; /* no vampire.resource -> illegal unit */ + } + else + { + unsigned long portid = V_WIFIPORT; + + if( !unit ) + portid = V_SDPORT; + + + /* if( !pb->pb_DevNode.lib_OpenCnt ) disabled, maybe doesn't open because of other reasons */ + if( pb->pb_ExpansionPort < 0 ) + { + APTR allocator = pb_AllocExpansion( portid, pb ); + if( allocator ) + unit = INVALID_SDNET_UNIT; /* illegal unit, cannot obtain Expansion Port */ + else + pb->pb_ExpansionPort = portid; + } + else + { + /* sorry, I currently don't support more than one port at a time */ + if( portid != pb->pb_ExpansionPort ) + unit = INVALID_SDNET_UNIT; + } + } +#endif +#ifdef PROTO_ENC624NET + if( !(pb->pb_HWBase.hwb_boards[0]) ) + { + struct ConfigDev *cfg = (0); + int i; + + for( i=0 ; ipb_HWBase.hwb_boards[i] = cfg->cd_BoardAddr; + } + pb->pb_HWBase.hwb_boards[i] = (0); + } + + if( unit >= HW_MAXBOARDS ) + unit = INVALID_SDNET_UNIT; + else + { + if( !pb->pb_HWBase.hwb_boards[unit] ) + unit = INVALID_SDNET_UNIT; + } +#endif + /* not promiscouos mode and unit valid ? (unit0 = SD Slot, unit1 = Extension header) */ +#ifdef PROTO_SDNET + if (!(flags & SANA2OPF_PROM) && (unit <= 1)) +#else /* PROTO_SDNET */ + if (!(flags & SANA2OPF_PROM) && (unit < HW_MAXBOARDS)) +#endif + { + /* Allow access only if NOT: + ** + ** Anybody else has already opened it AND + ** the current access is exclusive + ** OR the first access was exclusive + ** OR this access wants a different unit + */ + + if (!((pb->pb_DevNode.lib_OpenCnt > 1) && + ((flags & SANA2OPF_MINE) + || (pb->pb_Flags & PLIPF_EXCLUSIVE) + || (unit != pb->pb_Unit)))) + { + if (flags & SANA2OPF_MINE) + pb->pb_Flags |= PLIPF_EXCLUSIVE; + else + pb->pb_Flags &= ~PLIPF_EXCLUSIVE; + + /* + ** 13.05.96: Detlef Wuerkner + ** Rememer unit of 1st OpenDevice() + */ + if (pb->pb_DevNode.lib_OpenCnt == 1) + pb->pb_Unit = unit; + + /* setup default mac */ + { + /* */ +#ifdef PROTO_ENC624NET + unsigned char addr[6] = { 0x02,0x80,0x10,0x0b,0x0a,0xff}; + APTR board = pb->pb_HWBase.hwb_boards[unit]; + + enc624j6l_GetMAC( board, addr ); + + memcpy(pb->pb_CfgAddr, addr, HW_ADDRFIELDSIZE); + memcpy(pb->pb_DefAddr, addr, HW_ADDRFIELDSIZE); +#else /* PROTO_ENC624NET */ +#ifdef PROTO_SDNET + /* OUI: Commodore, but "local" */ + /* valid "locally administered" MAC addresses: + x2-xx-xx-xx-xx-xx + x6-xx-xx-xx-xx-xx + xA-xx-xx-xx-xx-xx + xE-xx-xx-xx-xx-xx + */ + unsigned char addr[6] = { 0x02,0x80,0x10,0x0b,0x0a,0xff}; + unsigned char vsn[8]; + + if( vampire_UUID( vsn ) > 0 ) + { + /* generate Interface ID from Vampire serial */ + int i; + for(i=0 ; i<3 ; i++ ) + { + addr[3+i] = vsn[i] ^ vsn[i+5]; + } + + } +#else /* PROTO_SDNET */ + unsigned char addr[6] = { 0x1a,0x11,0xaf,0xa0,0x47,0x11 }; +#endif /* PROTO_SDNET */ +#endif /* PROTO_ENC624NET */ + memcpy(pb->pb_CfgAddr, addr, HW_ADDRFIELDSIZE); + memcpy(pb->pb_DefAddr, addr, HW_ADDRFIELDSIZE); + } + + /* + ** Each opnener get's it's own BufferManagement. This is neccessary + ** since we want to allow several protocol stacks to use PLIP + ** simultaneously. + */ + if (bm = AllocVec(sizeof(struct BufferManagement),MEMF_CLEAR|MEMF_PUBLIC)) + { + /* + ** We don't care if there actually are buffer management functions, + ** because there might be openers who just want some statistics + ** from us. + */ +#if defined(__SASC) && (__VERSION__ == 6) && (__REVISION__ >= 56) + /* Jippieee! */ + bm->bm_CopyToBuffer = (BMFunc)GetTagData(S2_CopyToBuff, NULL, + (struct TagItem *)ios2->ios2_BufferManagement); + bm->bm_CopyFromBuffer = (BMFunc)GetTagData(S2_CopyFromBuff, NULL, + (struct TagItem *)ios2->ios2_BufferManagement); +#else + /* + ** The type casting below is very beautiful. This is a SAS/C bug: + ** I have to cast the ULONG that I got from GetTagData() to a + ** (void (*)(void)) function pointer. Now I may cast it to (BMFunc), + ** which defines the __asm and register stuff. + ** + ** I would call this a cast with ``soft force'', as it seems that + ** I slowly have to make the ULONG being used to the fact of + ** becoming a pointer (``Look, old mathematical chap: didn't you + ** always want to be a pointer? Did you know how less it takes, how + ** mighty the dark side of the force really is?''). + */ + bm->bm_CopyToBuffer = (BMFunc)((void (*)())(GetTagData(S2_CopyToBuff, NULL, + (struct TagItem *)ios2->ios2_BufferManagement))); + bm->bm_CopyFromBuffer = (BMFunc)((void (*)())(GetTagData(S2_CopyFromBuff, NULL, + (struct TagItem *)ios2->ios2_BufferManagement))); +#endif + d(("starting servertask\n")); + if (!pb->pb_Server) + { + volatile struct ServerStartup ss; + struct MsgPort *port; + +#ifdef PROTO_SDNET + /* before we can run the server, check if we can access the hardware */ +#endif + if (port = CreateMsgPort()) + { + d(("starting server")); + if (pb->pb_Server = CreateNewProcTags(NP_Entry, ServerTask, NP_Name, + NP_Priority, 9, SERVERTASKNAME, TAG_DONE)) + { + ss.ss_Error = 1; + ss.ss_PLIPBase = pb; + ss.ss_Msg.mn_Length = sizeof(ss); + ss.ss_Msg.mn_ReplyPort = port; + d(("passing startup msg, pb is %lx\n", pb)); + PutMsg(&pb->pb_Server->pr_MsgPort, (struct Message*)&ss); + WaitPort(port); + + if (!ss.ss_Error) + ok = TRUE; + else + { + d(("server task failed\n")); + } + } + else + { + d(("couldn't launch server task\n")); + } + DeleteMsgPort(port); + } + else + { + d(("no temp-message port for server startup\n")); + } + } + else ok = TRUE; + + if (!ok) + FreeVec(bm); + else + { + /* enqueue buffer management into list + */ + AddTail((struct List *)&pb->pb_BufferManagement,(struct Node *)bm); + pb->pb_DevNode.lib_OpenCnt++; + pb->pb_DevNode.lib_Flags &= ~LIBF_DELEXP; + ios2->ios2_BufferManagement = (VOID *)bm; + ios2->ios2_Req.io_Error = 0; + ios2->ios2_Req.io_Unit = (struct Unit *)unit; + ios2->ios2_Req.io_Device = (struct Device *)pb; + rv = 0; + } + } + } + } + + /* See if something went wrong. */ + if(!ok) + { + if( pb->pb_DevNode.lib_OpenCnt == 1 ) + { +#ifdef PROTO_SDNET + pb_FreeExpansion(pb); +#endif + } + + ios2->ios2_Req.io_Error = IOERR_OPENFAIL; + ios2->ios2_Req.io_Unit = (struct Unit *) 0; + ios2->ios2_Req.io_Device = (struct Device *) 0; + rv = IOERR_OPENFAIL; + } + ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG; + + pb->pb_DevNode.lib_OpenCnt--; + ReleaseSemaphore(&pb->pb_Lock); + + return rv; +} + +/*E*/ + + /* + ** close device + */ +/*F*/ PUBLIC ASM SAVEDS BPTR DevClose(REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR) +{ + BPTR seglist; + struct BufferManagement *bm; + + d2(("entered\n")); + + ObtainSemaphore(&pb->pb_Lock); + + /* invalidate IO request block */ + ior->ios2_Req.io_Device = (struct Device *)-1; + ior->ios2_Req.io_Unit = (struct Unit *)-1; + + /* search and free BuffMgmt structure */ + for(bm = (struct BufferManagement *)pb->pb_BufferManagement.lh_Head; + bm->bm_Node.mln_Succ; bm = (struct BufferManagement *)bm->bm_Node.mln_Succ) + if (bm == ior->ios2_BufferManagement) + { + Remove((struct Node*)bm); + FreeVec(bm); + break; + } + + pb->pb_DevNode.lib_OpenCnt--; + if( !pb->pb_DevNode.lib_OpenCnt ) + { +#ifdef PROTO_SDNET + pb_FreeExpansion(pb); +#endif + } + ReleaseSemaphore(&pb->pb_Lock); + + if (pb->pb_DevNode.lib_Flags & LIBF_DELEXP) + seglist = DevExpunge(pb); + else + seglist = 0; + + return seglist; +} +/*E*/ + + +/*F*/ PUBLIC ASM SAVEDS BPTR DevExpunge(REG(a6) BASEPTR) +{ + BPTR seglist; + ULONG sigb; + + d2(("entered\n")); + + if (pb->pb_DevNode.lib_OpenCnt) + { + pb->pb_DevNode.lib_Flags |= LIBF_DELEXP; + seglist = 0; + } + else + { + /* detach device from system list */ + Remove((struct Node*)pb); + + /* stop the servr task */ + d2(("killing server task\n")); + pb->pb_Task = FindTask(0L); + /* We must allocate a new signal, as we don't know in whose + ** context we're running. If we get no signal, we poll + ** for the server-exits flag. + */ + sigb = AllocSignal(-1); + pb->pb_ServerStoppedSigMask = (sigb == -1) ? 0 : (1<pb_Server, SIGBREAKF_CTRL_C); + if (pb->pb_ServerStoppedSigMask) + { + Wait(pb->pb_ServerStoppedSigMask); + FreeSignal(sigb); + } + else + { + while(!(pb->pb_Flags & PLIPF_SERVERSTOPPED)) + Delay(10); + } + d2(("server task has gone\n")); + + /* clean up track */ + freetracktypes(pb); + + CloseLibrary(UtilityBase); + CloseLibrary(DOSBase); + + /* save seglist for return value */ + seglist = (long)pb->pb_SegList; + + /* return memory + ** + ** NO FURTHER ACCESS TO PLIPBase ALLOWED! + */ + FreeMem( ((char *) pb) - pb->pb_DevNode.lib_NegSize, + (ULONG)(pb->pb_DevNode.lib_PosSize + pb->pb_DevNode.lib_NegSize)); + } + + return seglist; +} +/*E*/ + + /* + ** initiate io command (1st level dispatcher) + */ +/*F*/ static INLINE VOID DevForwardIO(BASEPTR, struct IOSana2Req *ios2) +{ + d(("forwarding request %ld\n", ios2->ios2_Req.io_Command)); + + /* request is no longer of type "quick i/o" */ + ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK; + PutMsg(pb->pb_ServerPort, (struct Message*)ios2); +} +/*E*/ +/*F*/ PUBLIC VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2) +{ + d(("cmd = %ld, error = %ld, wireerror = %ld\n", ios2->ios2_Req.io_Command, ios2->ios2_Req.io_Error,ios2->ios2_WireError)); + + /* if this command was done asynchonously, we must + ** reply the request + */ + if(!(ios2->ios2_Req.io_Flags & SANA2IOF_QUICK)) + ReplyMsg((struct Message *)ios2); + else /* otherwise just mark it as done */ + ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG; +} +/*E*/ +/*F*/ PUBLIC ASM SAVEDS VOID DevBeginIO(REG(a1) struct IOSana2Req *ios2, REG(a6) BASEPTR) +{ + ULONG mtu; + + /* mark request as active */ + ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE; + ios2->ios2_Req.io_Error = S2ERR_NO_ERROR; + ios2->ios2_WireError = S2WERR_GENERIC_ERROR; + + d(("cmd = %ld\n",ios2->ios2_Req.io_Command)); + + /* + ** 1st level command dispatcher + ** + ** Here we decide wether we can process the request immediately avoiding + ** a task switch. This is called "Quick I/O" and signalled to DoIO() + ** by setting the node type of the request to NT_REPLYMSG (see TermIO()). + ** + ** Otherwise, we clear the SANA2IOF_QUICK flag and forward the request to + ** the server. We may NEVER again access the request structure after + ** the PutMsg()! The server - running at a high priority - will peempt + ** us and might complety satisfy the request before we will be wakened up + ** again. + ** The same goes for those requests that we put into the server's queue. + */ + switch(ios2->ios2_Req.io_Command) + { + case CMD_READ: + if (pb->pb_Flags & PLIPF_OFFLINE) + { + ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE; + ios2->ios2_WireError = S2WERR_UNIT_OFFLINE; + } + else if (ios2->ios2_BufferManagement == NULL) + { + ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT; + ios2->ios2_WireError = S2WERR_BUFF_ERROR; + } + else + { + ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK; + ObtainSemaphore(&pb->pb_ReadListSem); + AddTail((struct List*)&pb->pb_ReadList, (struct Node*)ios2); + ReleaseSemaphore(&pb->pb_ReadListSem); + ios2 = NULL; + } + break; + + case S2_BROADCAST: + /* set broadcast addr: ff:ff:ff:ff:ff:ff */ + memset(ios2->ios2_DstAddr, 0xff, HW_ADDRFIELDSIZE); + /* fall through */ + case CMD_WRITE: + /* determine max valid size */ + mtu = pb->pb_MTU; + if(ios2->ios2_Req.io_Flags & SANA2IOF_RAW) { + mtu += HW_ETH_HDR_SIZE; + } + if(ios2->ios2_DataLength > mtu) + { + ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED; + } + else if (ios2->ios2_BufferManagement == NULL) + { + ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT; + ios2->ios2_WireError = S2WERR_BUFF_ERROR; + } + else if (pb->pb_Flags & PLIPF_OFFLINE) + { + ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE; + ios2->ios2_WireError = S2WERR_UNIT_OFFLINE; + } + else + { + ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK; + ios2->ios2_Req.io_Error = 0; + ObtainSemaphore(&pb->pb_WriteListSem); + AddTail((struct List*)&pb->pb_WriteList, (struct Node*)ios2); + ReleaseSemaphore(&pb->pb_WriteListSem); + Signal((struct Task*)pb->pb_Server, SIGBREAKF_CTRL_F); + ios2 = NULL; + } + break; + + case S2_ONLINE: + case S2_OFFLINE: + case S2_CONFIGINTERFACE: /* forward request */ + DevForwardIO(pb, ios2); + ios2 = NULL; + break; + + case S2_GETSTATIONADDRESS: + memcpy(ios2->ios2_SrcAddr, pb->pb_CfgAddr, HW_ADDRFIELDSIZE); /* current */ + memcpy(ios2->ios2_DstAddr, pb->pb_DefAddr, HW_ADDRFIELDSIZE); /* default */ + break; + + case S2_DEVICEQUERY: + { + struct Sana2DeviceQuery *devquery; + + devquery = ios2->ios2_StatData; + devquery->DevQueryFormat = 0; /* "this is format 0" */ + devquery->DeviceLevel = 0; /* "this spec defines level 0" */ + + if (devquery->SizeAvailable >= 18) devquery->AddrFieldSize = HW_ADDRFIELDSIZE * 8; /* Bits! */ + if (devquery->SizeAvailable >= 22) devquery->MTU = pb->pb_MTU; + if (devquery->SizeAvailable >= 26) devquery->BPS = pb->pb_BPS; + if (devquery->SizeAvailable >= 30) devquery->HardwareType = S2WireType_Ethernet; + + devquery->SizeSupplied = min((int)devquery->SizeAvailable, 30); + } + break; + + case S2_ONEVENT: + /* Two special cases. S2EVENT_ONLINE and S2EVENT_OFFLINE are supposed to + retun immediately if we are already in the state that they are waiting + for. */ + if (((ios2->ios2_WireError & S2EVENT_ONLINE) && !(pb->pb_Flags & PLIPF_OFFLINE)) || + ((ios2->ios2_WireError & S2EVENT_OFFLINE) && (pb->pb_Flags & PLIPF_OFFLINE))) + { + ios2->ios2_Req.io_Error = 0; + ios2->ios2_WireError &= (S2EVENT_ONLINE|S2EVENT_OFFLINE); + DevTermIO(pb,ios2); + ios2 = NULL; + } + else if ((ios2->ios2_WireError & (S2EVENT_ERROR|S2EVENT_TX|S2EVENT_RX|S2EVENT_ONLINE| + S2EVENT_OFFLINE|S2EVENT_BUFF|S2EVENT_HARDWARE|S2EVENT_SOFTWARE)) + != ios2->ios2_WireError) + { + /* we cannot handle such events */ + ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED; + ios2->ios2_WireError = S2WERR_BAD_EVENT; + } + else + { + /* Queue anything else */ + ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK; + ObtainSemaphore(&pb->pb_EventListSem); + AddTail((struct List*)&pb->pb_EventList, (struct Node*)ios2); + ReleaseSemaphore(&pb->pb_EventListSem); + ios2 = NULL; + } + break; + + /* --------------- stats support ----------------------- */ + + case S2_TRACKTYPE: + if (!addtracktype(pb, ios2->ios2_PacketType)) + { + ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES; + } + break; + + case S2_UNTRACKTYPE: + if (!remtracktype(pb, ios2->ios2_PacketType)) + { + ios2->ios2_Req.io_Error = S2ERR_BAD_STATE; + ios2->ios2_WireError = S2WERR_NOT_TRACKED; + } + break; + + case S2_GETTYPESTATS: + if (!gettrackrec(pb, ios2->ios2_PacketType, (struct Sana2PacketTypeStats *)ios2->ios2_StatData)) + { + ios2->ios2_Req.io_Error = S2ERR_BAD_STATE; + ios2->ios2_WireError = S2WERR_NOT_TRACKED; + } + break; + + case S2_READORPHAN: + if (pb->pb_Flags & PLIPF_OFFLINE) + { + ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE; + ios2->ios2_WireError = S2WERR_UNIT_OFFLINE; + } + else if (ios2->ios2_BufferManagement == NULL) + { + ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT; + ios2->ios2_WireError = S2WERR_BUFF_ERROR; + } + else + { /* Enqueue it to the orphan-reader-list */ + ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK; + ObtainSemaphore(&pb->pb_ReadOrphanListSem); + AddTail((struct List*)&pb->pb_ReadOrphanList, (struct Node*)ios2); + ReleaseSemaphore(&pb->pb_ReadOrphanListSem); + ios2 = NULL; + } + break; + + case S2_GETGLOBALSTATS: + memcpy(ios2->ios2_StatData, &pb->pb_DevStats, sizeof(struct Sana2DeviceStats)); + break; + + case S2_GETSPECIALSTATS: + { + struct Sana2SpecialStatHeader *s2ssh = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData; + + if (pb->pb_ExtFlags & PLIPEF_NOSPECIALSTATS) + { + s2ssh->RecordCountSupplied = 0; + } + else + { + s2ssh->RecordCountSupplied = s2ssh->RecordCountMax > S2SS_COUNT ? + S2SS_COUNT : s2ssh->RecordCountMax; + CopyMem(pb->pb_SpecialStats, (void*)(s2ssh+1), + s2ssh->RecordCountSupplied*sizeof(struct Sana2SpecialStatRecord)); + } + } + break; + + /* --------------- unsupported requests -------------------- */ + + /* all standard commands we don't support */ + case CMD_RESET: + case CMD_UPDATE: + case CMD_CLEAR: + case CMD_STOP: + case CMD_START: + case CMD_FLUSH: + ios2->ios2_Req.io_Error = IOERR_NOCMD; + ios2->ios2_WireError = S2WERR_GENERIC_ERROR; + break; + + /* other commands (SANA-2) we don't support */ + /*case S2_ADDMULTICASTADDRESS:*/ + /*case S2_DELMULTICASTADDRESS:*/ + /*case S2_MULTICAST:*/ + default: + ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED; + ios2->ios2_WireError = S2WERR_GENERIC_ERROR; + break; + } + + if (ios2) DevTermIO(pb, ios2); + + return; +} +/*E*/ + + /* + ** stop io-command + */ +/*F*/ PUBLIC ASM SAVEDS LONG DevAbortIO(REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR) +{ + BOOL is; + LONG rc = 0; + + d(("cmd = %ld\n",ior->ios2_Req.io_Command)); + + ObtainSemaphore(&pb->pb_WriteListSem); + if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_WriteList)) abort(pb,ior); + ReleaseSemaphore(&pb->pb_WriteListSem); + if (is) goto leave; + + ObtainSemaphore(&pb->pb_ReadListSem); + if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_ReadList)) abort(pb,ior); + ReleaseSemaphore(&pb->pb_ReadListSem); + if (is) goto leave; + + ObtainSemaphore(&pb->pb_EventListSem); + if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_EventList)) abort(pb,ior); + ReleaseSemaphore(&pb->pb_EventListSem); + if (is) goto leave; + + ObtainSemaphore(&pb->pb_ReadOrphanListSem); + if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_ReadOrphanList)) abort(pb,ior); + ReleaseSemaphore(&pb->pb_ReadOrphanListSem); + if (is) goto leave; + + rc = -1; + +leave: + return rc; +} +/*E*/ + diff --git a/Driver/enc624j6net/enc624j6net/asminterface.h b/Driver/enc624j6net/enc624j6net/asminterface.h new file mode 100644 index 0000000..f064f62 --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/asminterface.h @@ -0,0 +1,46 @@ +/* + asminterface.h + + Henryk Richter + + Interface macros for ASM subroutines for GCC and SAS/C + + syntax: + ASM SAVEDS int some_asm_subroutine( + ASMR(d3) unsigned int some_data ASMREG(d3), + ASMR(a0) unsigned char *some_address ASMREG(a0) + ); + + Reason for the double spec of An/Dn: some compilers (SAS) require the register + on the left hand side, gcc on the right hand side. I wanted to avoid a big macro + for the whole argument and moved the stuff into two macros per argument. + +*/ +#ifndef _INC_ASMINTERFACE_H +#define _INC_ASMINTERFACE_H + +#ifdef __SASC + +#define ASM __asm +#define ASMR(x) register __ ## x +#define ASMREG(x) +#define SAVEDS __saveds + +#else /* __SASC */ + +#ifdef __GNUC__ + +#define ASM +#define ASMR(x) register +#define ASMREG(x) __asm("" #x "") +#define SAVEDS __saveds + +#else /* __GNUC__ */ + +#error "Compiler not supported yet in asminterface.h" + +#endif /* __GNUC__ */ +#endif /* __SASC */ + + +#endif /* _INC_ASMINTERFACE_H */ diff --git a/Driver/enc624j6net/enc624j6net/enc624j6l.asm b/Driver/enc624j6net/enc624j6net/enc624j6l.asm new file mode 100755 index 0000000..c6bcc72 --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/enc624j6l.asm @@ -0,0 +1,1778 @@ +; ------------------------------------------------------------------------------ +; | Lowlevel Access to memory mapped ENC624J600 in PSP mode | +; | Henryk Richter | +; ------------------------------------------------------------------------------ +; Currently, the following assumptions are implemented: +; - device in Mode 3, i.e. 16 Bit access +; - register addresses shifted by 1 left, i.e. register base * 2 compared +; to 16 Bit mode of ENC624J600 documentation (8 Bit mode alike) +; - some byte shuffling required - which currently is in a state of flux +; +; Note: This code is in some places intentionally saving more registers than +; required by the AmigaOS ABI. +; +; HW BUG: +; possible address line mismatch (see RXSTART_INIT) +; $5000 was set -> frame appears at $3000 +; $4000 was set -> frame appears at $2000 +; $3000 was set -> frame appears at $5000 +; $2000 was set -> frame appears at $4000 +; +;TODO: +; - setMAC/getMAC endianess awareness +; - Pattern Matching, MC/MC filtering: Multicast,Broadcast,Unicast(self),MagicPacket,correct CRC,"not me" Unicast +; - _enc624j6l_RXReset -> won't recover from totally unresponsive chip (but exits gracefully) +; - put includes out (for now, self-contained ASM file) +; - RXSTART_INIT = $0c00 -> currently $2000 due to location bug + +; enable debugging code block +DEBUG EQU 1 +; + +; FIXME: needs verification +; also: either swap buffer or registers/pointers etc. +_OPT_BUFFER_SWAP EQU 1 ;perform byte swap on buffer ops (1) or assume native endian (0) +_OPT_REG_SWAP EQU 0 ;perform byte swap on register ops (1) or assume native endian (0) +_OPT_ADR_QUIRK EQU 1 ;address lines 12/13 are swapped (1) or linear addressing (0) + +; +; options for buffer memory configuration, please reserve some space for private variables +; +PSTART_INIT EQU $0BF0 ; 16 Bytes private storage for driver +PSTOP_INIT EQU $0BFF ; (see below for definitions) + +RXSTART_INIT EQU $2000 ; start of RX buffer, room for 14 packets +RXSTOP_INIT EQU $5fff ; end of RX buffer + +TXSTART_INIT EQU $0000 ; start of TX buffer, room for 2 packets +TXSTOP_INIT EQU $0BEF ; end of TX buffer (1536+1520 bytes) + +; max frame length which the conroller will accept: +; (note: maximum ethernet frame length would be 1518 w/o 802.1Q) +MAX_FRAMELEN EQU 1518 + +;------------ driver private storage ------------------------------ +PNextPacket EQU PSTART_INIT ;2 Bytes - private "next packet" pointer for RX +PNextTX EQU PSTART_INIT+2 ;2 Bytes - private "next packet" pointer for TX (init as 0) +PSigBit EQU PSTART_INIT+4 ;2 Bytes interrupt bit +PSigTask EQU PSTART_INIT+6 ;4 Bytes signaled task +Punused EQU PSTART_INIT+10 ; + +;------------- TX: double buffering -------------------------------- +PSwapTX EQU $600 ;swap between two TX buffers (one active, one activated after last TX done) +; +; + ifne DEBUG +; +; these are only for the debug code +; +ENC_MANUFACTURER EQU 2588 ;a1k +ENC_BOARDID EQU 123 ;ZII-IDE-LAN-CP + endc + + ; + ; + ; Hardware dependent routines, exported globals + ; + ; + XDEF _enc624j6l_CheckBoard ;check whether board is operating correctly + + ; get/set MAC address + XDEF _enc624j6l_GetMAC ;current state, not necessarily burned in MAC + XDEF _enc624j6l_SetMAC ;set user defined MAC address + + ;delay min. D0 microseconds (<= $0fffffff) + XDEF _enc624j6l_UMinDelay + + ;init/shut down board (CheckBoard is not allowed between those two) + XDEF _enc624j6l_Init + XDEF _enc624j6l_Shutdown + + ;online/offline + XDEF _enc624j6l_SetOffline + XDEF _enc624j6l_SetOnline + + ;transmit/receive functions + XDEF _enc624j6l_HaveRecv ; + XDEF _enc624j6l_RecvFrame ; + XDEF _enc624j6l_TransmitFrame ; + + XDEF _enc624j6l_IntServer + XDEF _enc624j6l_EnableInterrupt + XDEF _enc624j6l_DisableInterrupt + + ; + ; System includes + ; + + ifnd _LVOSignal +_LVOSignal EQU -324 + endc + + ;machine 68020 + + section code,code + +;------------------------ UGH! this belongs into a proper .i ------------------------------ + +; set/clr register offsets +SET_OFFSET EQU $0100 +CLR_OFFSET EQU $0180 + +; Register definitions + +; SPI Bank 0 registers -------- +ETXST EQU $7E00 +ETXSTL EQU $7E00 +ETXSTH EQU $7E01 +ETXLEN EQU $7E02 +ETXLENL EQU $7E02 +ETXLENH EQU $7E03 +ERXST EQU $7E04 +ERXSTL EQU $7E04 +ERXSTH EQU $7E05 +ERXTAIL EQU $7E06 +ERXTAILL EQU $7E06 +ERXTAILH EQU $7E07 +ERXHEAD EQU $7E08 +ERXHEADL EQU $7E08 +ERXHEADH EQU $7E09 +EDMAST EQU $7E0A +EDMASTL EQU $7E0A +EDMASTH EQU $7E0B +EDMALEN EQU $7E0C +EDMALENL EQU $7E0C +EDMALENH EQU $7E0D +EDMADST EQU $7E0E +EDMADSTL EQU $7E0E +EDMADSTH EQU $7E0F +EDMACS EQU $7E10 +EDMACSL EQU $7E10 +EDMACSH EQU $7E11 +ETXSTAT EQU $7E12 +ETXSTATL EQU $7E12 +ETXSTATH EQU $7E13 +ETXWIRE EQU $7E14 +ETXWIREL EQU $7E14 +ETXWIREH EQU $7E15 + +; SPI all bank registers +EUDAST EQU $7E16 +EUDASTL EQU $7E16 +EUDASTH EQU $7E17 +EUDAND EQU $7E18 +EUDANDL EQU $7E18 +EUDANDH EQU $7E19 +ESTAT EQU $7E1A +ESTATL EQU $7E1A +ESTATH EQU $7E1B +EIR EQU $7E1C +EIRL EQU $7E1C +EIRH EQU $7E1D +ECON1 EQU $7E1E +ECON1L EQU $7E1E +ECON1H EQU $7E1F + + +; SPI Bank 1 registers ----- +EHT1 EQU $7E20 +EHT1L EQU $7E20 +EHT1H EQU $7E21 +EHT2 EQU $7E22 +EHT2L EQU $7E22 +EHT2H EQU $7E23 +EHT3 EQU $7E24 +EHT3L EQU $7E24 +EHT3H EQU $7E25 +EHT4 EQU $7E26 +EHT4L EQU $7E26 +EHT4H EQU $7E27 +EPMM1 EQU $7E28 +EPMM1L EQU $7E28 +EPMM1H EQU $7E29 +EPMM2 EQU $7E2A +EPMM2L EQU $7E2A +EPMM2H EQU $7E2B +EPMM3 EQU $7E2C +EPMM3L EQU $7E2C +EPMM3H EQU $7E2D +EPMM4 EQU $7E2E +EPMM4L EQU $7E2E +EPMM4H EQU $7E2F +EPMCS EQU $7E30 +EPMCSL EQU $7E30 +EPMCSH EQU $7E31 +EPMO EQU $7E32 +EPMOL EQU $7E32 +EPMOH EQU $7E33 +ERXFCON EQU $7E34 +ERXFCONL EQU $7E34 +ERXFCONH EQU $7E35 + +; SPI all bank registers from 0x36 to 0x3F +; SPI Bank 2 registers ----- +MACON1 EQU $7E40 +MACON1L EQU $7E40 +MACON1H EQU $7E41 +MACON2 EQU $7E42 +MACON2L EQU $7E42 +MACON2H EQU $7E43 +MABBIPG EQU $7E44 +MABBIPGL EQU $7E44 +MABBIPGH EQU $7E45 +MAIPG EQU $7E46 +MAIPGL EQU $7E46 +MAIPGH EQU $7E47 +MACLCON EQU $7E48 +MACLCONL EQU $7E48 +MACLCONH EQU $7E49 +MAMXFL EQU $7E4A +MAMXFLL EQU $7E4A +MAMXFLH EQU $7E4B +MICMD EQU $7E52 +MICMDL EQU $7E52 +MICMDH EQU $7E53 +MIREGADR EQU $7E54 +MIREGADRL EQU $7E54 +MIREGADRH EQU $7E55 + +; SPI all bank registers from 0x56 to 0x5F +; SPI Bank 3 registers ----- +MAADR3 EQU $7E60 +MAADR3L EQU $7E60 +MAADR3H EQU $7E61 +MAADR2 EQU $7E62 +MAADR2L EQU $7E62 +MAADR2H EQU $7E63 +MAADR1 EQU $7E64 +MAADR1L EQU $7E64 +MAADR1H EQU $7E65 +MIWR EQU $7E66 +MIWRL EQU $7E66 +MIWRH EQU $7E67 +MIRD EQU $7E68 +MIRDL EQU $7E68 +MIRDH EQU $7E69 +MISTAT EQU $7E6A +MISTATL EQU $7E6A +MISTATH EQU $7E6B +EPAUS EQU $7E6C +EPAUSL EQU $7E6C +EPAUSH EQU $7E6D +ECON2 EQU $7E6E +ECON2L EQU $7E6E +ECON2H EQU $7E6F +ERXWM EQU $7E70 +ERXWML EQU $7E70 +ERXWMH EQU $7E71 +EIE EQU $7E72 +EIEL EQU $7E72 +EIEH EQU $7E73 +EIDLED EQU $7E74 +EIDLEDL EQU $7E74 +EIDLEDH EQU $7E75 + +; SPI all bank registers from 0x66 to 0x6F + +; SPI Non-banked Special Function Registers +EGPDATA EQU $7E80 +EGPDATAL EQU $7E80 +ERXDATA EQU $7E82 +ERXDATAL EQU $7E82 +EUDADATA EQU $7E84 +EUDADATAL EQU $7E84 +EGPRDPT EQU $7E86 +EGPRDPTL EQU $7E86 +EGPRDPTH EQU $7E87 +EGPWRPT EQU $7E88 +EGPWRPTL EQU $7E88 +EGPWRPTH EQU $7E89 +ERXRDPT EQU $7E8A +ERXRDPTL EQU $7E8A +ERXRDPTH EQU $7E8B +ERXWRPT EQU $7E8C +ERXWRPTL EQU $7E8C +ERXWRPTH EQU $7E8D +EUDARDPT EQU $7E8E +EUDARDPTL EQU $7E8E +EUDARDPTH EQU $7E8F +EUDAWRPT EQU $7E90 +EUDAWRPTL EQU $7E90 +EUDAWRPTH EQU $7E91 + +;;;;;;;;;;;;;;;;;;;;;;;;;; +; ENC424J600/624J600 register bits +;;;;;;;;;;;;;;;;;;;;;;;;;; +; ESTAT bits ---------- +ESTAT_INT EQU (1<<15) +ESTAT_FCIDLE EQU (1<<14) +ESTAT_RXBUSY EQU (1<<13) +ESTAT_CLKRDY EQU (1<<12) +ESTAT_RSTDONE EQU (1<<11) +ESTAT_PHYDPX EQU (1<<10) +ESTAT_PHYRDY EQU (1<<9) +ESTAT_PHYLNK EQU (1<<8) +ESTAT_PKTCNT7 EQU (1<<7) +ESTAT_PKTCNT6 EQU (1<<6) +ESTAT_PKTCNT5 EQU (1<<5) +ESTAT_PKTCNT4 EQU (1<<4) +ESTAT_PKTCNT3 EQU (1<<3) +ESTAT_PKTCNT2 EQU (1<<2) +ESTAT_PKTCNT1 EQU (1<<1) +ESTAT_PKTCNT0 EQU (1) + +; EIR bits ------------ +EIR_CRYPTEN EQU (1<<15) +EIR_MODEXIF EQU (1<<14) +EIR_HASHIF EQU (1<<13) +EIR_AESIF EQU (1<<12) +EIR_LINKIF EQU (1<<11) +EIR_PRDYIF EQU (1<<10) +EIR_r9 EQU (1<<9) +EIR_r8 EQU (1<<8) +EIR_r7 EQU (1<<7) +EIR_PKTIF EQU (1<<6) +EIR_DMAIF EQU (1<<5) +EIR_r4 EQU (1<<4) +EIR_TXIF EQU (1<<3) +EIR_TXABTIF EQU (1<<2) +EIR_RXABTIF EQU (1<<1) +EIR_PCFULIF EQU (1) + +; ECON1 bits ---------- +ECON1_MODEXST EQU (1<<15) +ECON1_HASHEN EQU (1<<14) +ECON1_HASHOP EQU (1<<13) +ECON1_HASHLST EQU (1<<12) +ECON1_AESST EQU (1<<11) +ECON1_AESOP1 EQU (1<<10) +ECON1_AESOP0 EQU (1<<9) +ECON1_PKTDEC EQU (1<<8) +ECON1_FCOP1 EQU (1<<7) +ECON1_FCOP0 EQU (1<<6) +ECON1_DMAST EQU (1<<5) +ECON1_DMACPY EQU (1<<4) +ECON1_DMACSSD EQU (1<<3) +ECON1_DMANOCS EQU (1<<2) +ECON1_TXRTS EQU (1<<1) +ECON1_RXEN EQU (1) + +; ETXSTAT bits -------- +ETXSTAT_r12 EQU (1<<12) +ETXSTAT_r11 EQU (1<<11) +ETXSTAT_LATECOL EQU (1<<10) +ETXSTAT_MAXCOL EQU (1<<9) +ETXSTAT_EXDEFER EQU (1<<8) +ETXSTAT_DEFER EQU (1<<7) +ETXSTAT_r6 EQU (1<<6) +ETXSTAT_r5 EQU (1<<5) +ETXSTAT_CRCBAD EQU (1<<4) +ETXSTAT_COLCNT3 EQU (1<<3) +ETXSTAT_COLCNT2 EQU (1<<2) +ETXSTAT_COLCNT1 EQU (1<<1) +ETXSTAT_COLCNT0 EQU (1) + +; ERXFCON bits -------- +ERXFCON_HTEN EQU (1<<15) +ERXFCON_MPEN EQU (1<<14) +ERXFCON_NOTPM EQU (1<<12) +ERXFCON_PMEN3 EQU (1<<11) +ERXFCON_PMEN2 EQU (1<<10) +ERXFCON_PMEN1 EQU (1<<9) +ERXFCON_PMEN0 EQU (1<<8) +ERXFCON_CRCEEN EQU (1<<7) +ERXFCON_CRCEN EQU (1<<6) +ERXFCON_RUNTEEN EQU (1<<5) +ERXFCON_RUNTEN EQU (1<<4) +ERXFCON_UCEN EQU (1<<3) +ERXFCON_NOTMEEN EQU (1<<2) +ERXFCON_MCEN EQU (1<<1) +ERXFCON_BCEN EQU (1) + +; MACON1 bits --------- +MACON1_r15 EQU (1<<15) +MACON1_r14 EQU (1<<14) +MACON1_r11 EQU (1<<11) +MACON1_r10 EQU (1<<10) +MACON1_r9 EQU (1<<9) +MACON1_r8 EQU (1<<8) +MACON1_LOOPBK EQU (1<<4) +MACON1_r3 EQU (1<<3) +MACON1_RXPAUS EQU (1<<2) +MACON1_PASSALL EQU (1<<1) +MACON1_r0 EQU (1) + +; MACON2 bits --------- +MACON2_DEFER EQU (1<<14) +MACON2_BPEN EQU (1<<13) +MACON2_NOBKOFF EQU (1<<12) +MACON2_r9 EQU (1<<9) +MACON2_r8 EQU (1<<8) +MACON2_PADCFG2 EQU (1<<7) +MACON2_PADCFG1 EQU (1<<6) +MACON2_PADCFG0 EQU (1<<5) +MACON2_TXCRCEN EQU (1<<4) +MACON2_PHDREN EQU (1<<3) +MACON2_HFRMEN EQU (1<<2) +MACON2_r1 EQU (1<<1) +MACON2_FULDPX EQU (1) + +; MABBIPG bits -------- +MABBIPG_BBIPG6 EQU (1<<6) +MABBIPG_BBIPG5 EQU (1<<5) +MABBIPG_BBIPG4 EQU (1<<4) +MABBIPG_BBIPG3 EQU (1<<3) +MABBIPG_BBIPG2 EQU (1<<2) +MABBIPG_BBIPG1 EQU (1<<1) +MABBIPG_BBIPG0 EQU (1) + +; MAIPG bits ---------- +MAIPG_r14 EQU (1<<14) +MAIPG_r13 EQU (1<<13) +MAIPG_r12 EQU (1<<12) +MAIPG_r11 EQU (1<<11) +MAIPG_r10 EQU (1<<10) +MAIPG_r9 EQU (1<<9) +MAIPG_r8 EQU (1<<8) +MAIPG_IPG6 EQU (1<<6) +MAIPG_IPG5 EQU (1<<5) +MAIPG_IPG4 EQU (1<<4) +MAIPG_IPG3 EQU (1<<3) +MAIPG_IPG2 EQU (1<<2) +MAIPG_IPG1 EQU (1<<1) +MAIPG_IPG0 EQU (1) + +; MACLCON bits -------- +MACLCON_r13 EQU (1<<13) +MACLCON_r12 EQU (1<<12) +MACLCON_r11 EQU (1<<11) +MACLCON_r10 EQU (1<<10) +MACLCON_r9 EQU (1<<9) +MACLCON_r8 EQU (1<<8) +MACLCON_MAXRET3 EQU (1<<3) +MACLCON_MAXRET2 EQU (1<<2) +MACLCON_MAXRET1 EQU (1<<1) +MACLCON_MAXRET0 EQU (1) + +; MICMD bits ---------- +MICMD_MIISCAN EQU (1<<1) +MICMD_MIIRD EQU (1) + +; MIREGADR bits ------- +MIREGADR_r12 EQU (1<<12) +MIREGADR_r11 EQU (1<<11) +MIREGADR_r10 EQU (1<<10) +MIREGADR_r9 EQU (1<<9) +MIREGADR_r8 EQU (1<<8) +MIREGADR_PHREG4 EQU (1<<4) +MIREGADR_PHREG3 EQU (1<<3) +MIREGADR_PHREG2 EQU (1<<2) +MIREGADR_PHREG1 EQU (1<<1) +MIREGADR_PHREG0 EQU (1) + +; MISTAT bits --------- +MISTAT_r3 EQU (1<<3) +MISTAT_NVALID EQU (1<<2) +MISTAT_SCAN EQU (1<<1) +MISTAT_BUSY EQU (1) + +; ECON2 bits ---------- +ECON2_ETHEN EQU (1<<15) +ECON2_STRCH EQU (1<<14) +ECON2_TXMAC EQU (1<<13) +ECON2_SHA1MD5 EQU (1<<12) +ECON2_COCON3 EQU (1<<11) +ECON2_COCON2 EQU (1<<10) +ECON2_COCON1 EQU (1<<9) +ECON2_COCON0 EQU (1<<8) +ECON2_AUTOFC EQU (1<<7) +ECON2_TXRST EQU (1<<6) +ECON2_RXRST EQU (1<<5) +ECON2_ETHRST EQU (1<<4) +ECON2_MODLEN1 EQU (1<<3) +ECON2_MODLEN0 EQU (1<<2) +ECON2_AESLEN1 EQU (1<<1) +ECON2_AESLEN0 EQU (1) + +; ERXWM bits ---------- +ERXWM_RXFWM7 EQU (1<<15) +ERXWM_RXFWM6 EQU (1<<14) +ERXWM_RXFWM5 EQU (1<<13) +ERXWM_RXFWM4 EQU (1<<12) +ERXWM_RXFWM3 EQU (1<<11) +ERXWM_RXFWM2 EQU (1<<10) +ERXWM_RXFWM1 EQU (1<<9) +ERXWM_RXFWM0 EQU (1<<8) +ERXWM_RXEWM7 EQU (1<<7) +ERXWM_RXEWM6 EQU (1<<6) +ERXWM_RXEWM5 EQU (1<<5) +ERXWM_RXEWM4 EQU (1<<4) +ERXWM_RXEWM3 EQU (1<<3) +ERXWM_RXEWM2 EQU (1<<2) +ERXWM_RXEWM1 EQU (1<<1) +ERXWM_RXEWM0 EQU (1) + +; EIE bits ------------ +EIE_INTIE EQU (1<<15) +EIE_MODEXIE EQU (1<<14) +EIE_HASHIE EQU (1<<13) +EIE_AESIE EQU (1<<12) +EIE_LINKIE EQU (1<<11) +EIE_PRDYIE EQU (1<<10) +EIE_r9 EQU (1<<9) +EIE_r8 EQU (1<<8) +EIE_r7 EQU (1<<7) +EIE_PKTIE EQU (1<<6) +EIE_DMAIE EQU (1<<5) +EIE_r4 EQU (1<<4) +EIE_TXIE EQU (1<<3) +EIE_TXABTIE EQU (1<<2) +EIE_RXABTIE EQU (1<<1) +EIE_PCFULIE EQU (1) + +; EIDLED bits --------- +EIDLED_LACFG3 EQU (1<<15) +EIDLED_LACFG2 EQU (1<<14) +EIDLED_LACFG1 EQU (1<<13) +EIDLED_LACFG0 EQU (1<<12) +EIDLED_LBCFG3 EQU (1<<11) +EIDLED_LBCFG2 EQU (1<<10) +EIDLED_LBCFG1 EQU (1<<9) +EIDLED_LBCFG0 EQU (1<<8) +EIDLED_DEVID2 EQU (1<<7) +EIDLED_DEVID1 EQU (1<<6) +EIDLED_DEVID0 EQU (1<<5) +EIDLED_REVID4 EQU (1<<4) +EIDLED_REVID3 EQU (1<<3) +EIDLED_REVID2 EQU (1<<2) +EIDLED_REVID1 EQU (1<<1) +EIDLED_REVID0 EQU (1) + +; PHCON1 bits --------- +PHCON1_PRST EQU (1<<15) +PHCON1_PLOOPBK EQU (1<<14) +PHCON1_SPD100 EQU (1<<13) +PHCON1_ANEN EQU (1<<12) +PHCON1_PSLEEP EQU (1<<11) +PHCON1_r10 EQU (1<<10) +PHCON1_RENEG EQU (1<<9) +PHCON1_PFULDPX EQU (1<<8) +PHCON1_r7 EQU (1<<7) +PHCON1_r6 EQU (1<<6) +PHCON1_r5 EQU (1<<5) +PHCON1_r4 EQU (1<<4) +PHCON1_r3 EQU (1<<3) +PHCON1_r2 EQU (1<<2) +PHCON1_r1 EQU (1<<1) +PHCON1_r0 EQU (1) + +; PHSTAT1 bits -------- +PHSTAT1_r15 EQU (1<<15) +PHSTAT1_FULL100 EQU (1<<14) +PHSTAT1_HALF100 EQU (1<<13) +PHSTAT1_FULL10 EQU (1<<12) +PHSTAT1_HALF10 EQU (1<<11) +PHSTAT1_r10 EQU (1<<10) +PHSTAT1_r9 EQU (1<<9) +PHSTAT1_r8 EQU (1<<8) +PHSTAT1_r7 EQU (1<<7) +PHSTAT1_r6 EQU (1<<6) +PHSTAT1_ANDONE EQU (1<<5) +PHSTAT1_LRFAULT EQU (1<<4) +PHSTAT1_ANABLE EQU (1<<3) +PHSTAT1_LLSTAT EQU (1<<2) +PHSTAT1_r1 EQU (1<<1) +PHSTAT1_EXTREGS EQU (1) + +; PHANA bits ---------- +PHANA_ADNP EQU (1<<15) +PHANA_r14 EQU (1<<14) +PHANA_ADFAULT EQU (1<<13) +PHANA_r12 EQU (1<<12) +PHANA_ADPAUS1 EQU (1<<11) +PHANA_ADPAUS0 EQU (1<<10) +PHANA_r9 EQU (1<<9) +PHANA_AD100FD EQU (1<<8) +PHANA_AD100 EQU (1<<7) +PHANA_AD10FD EQU (1<<6) +PHANA_AD10 EQU (1<<5) +PHANA_ADIEEE4 EQU (1<<4) +PHANA_ADIEEE3 EQU (1<<3) +PHANA_ADIEEE2 EQU (1<<2) +PHANA_ADIEEE1 EQU (1<<1) +PHANA_ADIEEE0 EQU (1) + +; PHANLPA bits -------- +PHANLPA_LPNP EQU (1<<15) +PHANLPA_LPACK EQU (1<<14) +PHANLPA_LPFAULT EQU (1<<13) +PHANLPA_r12 EQU (1<<12) +PHANLPA_LPPAUS1 EQU (1<<11) +PHANLPA_LPPAUS0 EQU (1<<10) +PHANLPA_LP100T4 EQU (1<<9) +PHANLPA_LP100FD EQU (1<<8) +PHANLPA_LP100 EQU (1<<7) +PHANLPA_LP10FD EQU (1<<6) +PHANLPA_LP10 EQU (1<<5) +PHANLPA_LPIEEE4 EQU (1<<4) +PHANLPA_LPIEEE3 EQU (1<<3) +PHANLPA_LPIEEE2 EQU (1<<2) +PHANLPA_LPIEEE1 EQU (1<<1) +PHANLPA_LPIEEE0 EQU (1) + +; PHANE bits ---------- +PHANE_r15 EQU (1<<15) +PHANE_r14 EQU (1<<14) +PHANE_r13 EQU (1<<13) +PHANE_r12 EQU (1<<12) +PHANE_r11 EQU (1<<11) +PHANE_r10 EQU (1<<10) +PHANE_r9 EQU (1<<9) +PHANE_r8 EQU (1<<8) +PHANE_r7 EQU (1<<7) +PHANE_r6 EQU (1<<6) +PHANE_r5 EQU (1<<5) +PHANE_PDFLT EQU (1<<4) +PHANE_r3 EQU (1<<3) +PHANE_r2 EQU (1<<2) +PHANE_LPARCD EQU (1<<1) +PHANA_LPANABL EQU (1) + +; PHCON2 bits --------- +PHCON2_r15 EQU (1<<15) +PHCON2_r14 EQU (1<<14) +PHCON2_EDPWRDN EQU (1<<13) +PHCON2_r12 EQU (1<<12) +PHCON2_EDTHRES EQU (1<<11) +PHCON2_r10 EQU (1<<10) +PHCON2_r9 EQU (1<<9) +PHCON2_r8 EQU (1<<8) +PHCON2_r7 EQU (1<<7) +PHCON2_r6 EQU (1<<6) +PHCON2_r5 EQU (1<<5) +PHCON2_r4 EQU (1<<4) +PHCON2_r3 EQU (1<<3) +PHCON2_FRCLNK EQU (1<<2) +PHCON2_EDSTAT EQU (1<<1) +PHCON2_r0 EQU (1) + +; PHSTAT2 bits --------- +PHSTAT2_r15 EQU (1<<15) +PHSTAT2_r14 EQU (1<<14) +PHSTAT2_r13 EQU (1<<13) +PHSTAT2_r12 EQU (1<<12) +PHSTAT2_r11 EQU (1<<11) +PHSTAT2_r10 EQU (1<<10) +PHSTAT2_r9 EQU (1<<9) +PHSTAT2_r8 EQU (1<<8) +PHSTAT2_r7 EQU (1<<7) +PHSTAT2_r6 EQU (1<<6) +PHSTAT2_r5 EQU (1<<5) +PHSTAT2_PLRITY EQU (1<<4) +PHSTAT2_r3 EQU (1<<3) +PHSTAT2_r2 EQU (1<<2) +PHSTAT2_r1 EQU (1<<1) +PHSTAT2_r0 EQU (1) + +; PHSTAT3 bits -------- +PHSTAT3_r15 EQU (1<<15) +PHSTAT3_r14 EQU (1<<14) +PHSTAT3_r13 EQU (1<<13) +PHSTAT3_r12 EQU (1<<12) +PHSTAT3_r11 EQU (1<<11) +PHSTAT3_r10 EQU (1<<10) +PHSTAT3_r9 EQU (1<<9) +PHSTAT3_r8 EQU (1<<8) +PHSTAT3_r7 EQU (1<<7) +PHSTAT3_r6 EQU (1<<6) +PHSTAT3_r5 EQU (1<<5) +PHSTAT3_SPDDPX2 EQU (1<<4) +PHSTAT3_SPDDPX1 EQU (1<<3) +PHSTAT3_SPDDPX0 EQU (1<<2) +PHSTAT3_r1 EQU (1<<1) +PHSTAT3_r0 EQU (1) + +;------------------------------ internal defaults ---------------------------------- +;33.333Mhz clock out frequency +CLOCK_33_CLR EQU (ECON2_COCON3|ECON2_COCON2|ECON2_COCON1) ;clr mask +CLOCK_33_SET EQU (ECON2_COCON0) ;set mask +;25 MHz +CLOCK_25_CLR EQU (ECON2_COCON3|ECON2_COCON2|ECON2_COCON0) ;clr mask +CLOCK_25_SET EQU (ECON2_COCON1) ;set mask +;20 MHz +CLOCK_20_CLR EQU (ECON2_COCON3|ECON2_COCON2) ;clr mask +CLOCK_20_SET EQU (ECON2_COCON1|ECON2_COCON0) ;set mask +;16 MHz +CLOCK_16_CLR EQU (ECON2_COCON3|ECON2_COCON0|ECON2_COCON1) ;clr mask +CLOCK_16_SET EQU (ECON2_COCON2) ;set mask +;4 MHz (after reset) +CLOCK_4_CLR EQU (ECON2_COCON2) ;clr mask +CLOCK_4_SET EQU (ECON2_COCON3|ECON2_COCON0|ECON2_COCON1) ;set mask + +CLOCK_DEF_CLR EQU CLOCK_33_CLR +CLOCK_DEF_SET EQU CLOCK_33_SET + +;\1 register offset (without CLEAR offset) +;\2 address register of board I/O base +;\3 register with clear mask +CLRREG macro + move.w \3,\1+CLR_OFFSET(\2) + endm +;\1 register offset (without SET offset) +;\2 address register of board I/O base +;\3 register with set mask +SETREG macro + move.w \3,\1+SET_OFFSET(\2) + endm +;\1 register offset (e.g. ESTAT) +;\2 address register of board I/O base (e.g. a0) +;\3 destination register to be written (e.g. d0) +READREG macro + move.w \1(\2),\3 + endm +;\1 register offset (e.g. ESTAT) +;\2 address register of board I/O base (e.g. a0) +;\3 soure register copied to HW register (e.g. d0) +WRITEREG macro + move.w \3,\1(\2) + endm + + ;read with address shuffling or direct from SRAM (affects $2000-$5000) + ifne _OPT_ADR_QUIRK +;\1 = address register +;\2 = data register, offset +;\3 = destination +READSRAM macro + eor.w #$6000,\2 + move.w (\1,\2.w),\3 + eor.w #$6000,\2 + endm + else +READSRAM macro + move.w (\1,\2),\3 + endm + endc + + +; wrap position index (in bytes) \1 (data register .w) +; +; if position >RXSTOP_INIT-1 +; position = (position-RXSTOP_INIT+RXSTART_INIT) +; endif +WRAPINDEX macro + cmp.w #RXSTOP_INIT&$fffe,\1 ;wrap Dn if beyond buffer + ble.s .nowrap\0\@ + add.w #RXSTART_INIT-RXSTOP_INIT,\1 +.nowrap\0\@ + endm + + + + + +; ----------------------------------------------------------------------------- +; | | +; | Test/Debug code | +; | | +; ----------------------------------------------------------------------------- + ifne DEBUG +ExecBase EQU 4 ; Exec.Base() +OpenLibrary EQU -552 ; D0:Base=OpenLibrary(A1:libName,D0:version) +CloseLibrary EQU -414 ; Exec.CloseLibrary(A1:libBase) +PutStr EQU -948 ; DOS.PutStr(D1:str) +_LVODelay EQU -198 +_LVOFindConfigDev EQU -72 ; expansion +cd_BoardAddr EQU 32 ; structure ConfigDev + +START: +opendos: + ;libs + move.l ExecBase,a6 + lea DosLibrary(pc),a1 + moveq #0,d0 + jsr OpenLibrary(a6) + move.l d0,_dosbase + beq error + + lea ExpansionLibrary(pc),a1 + moveq #36,d0 + jsr OpenLibrary(a6) + move.l d0,_expansionbase + + ;expansion scan for first board + move.l _expansionbase(pc),a6 + suba.l a0,a0 ;find first board + move.l #ENC_MANUFACTURER,d0 + moveq #ENC_BOARDID,d1 + jsr _LVOFindConfigDev(a6) + tst.l d0 + beq error + move.l d0,a5 ;board + move.l cd_BoardAddr(A5),d0 ;base address + beq error + move.l d0,_boardbase + + ;tests + move.l _dosbase(pc),a6 + moveq #0,d7 ;no error + + ;Board test + move.l _boardbase(pc),a0 + bsr _enc624j6l_CheckBoard + move.b d0,board_status + + ; MAC address test + move.l _boardbase(pc),a0 + lea mactestr(pc),a1 + bsr _enc624j6l_GetMAC + + move.l _boardbase(pc),a0 + lea mactest(pc),a1 + bsr _enc624j6l_SetMAC + + lea macdest(pc),a1 + move.l _boardbase(pc),a0 + bsr _enc624j6l_GetMAC ;verify + + lea mactest(pc),a0 ;verify MAC r/w + lea macdest(pc),a1 + move.l (a0)+,d0 + sub.l (a1)+,d0 + moveq #0,d1 + move.w (a0)+,d1 + sub.w (a1)+,d1 + move.b #1,mac_status ;OK + or.l d1,d0 + beq.s .macok + st mac_status ;error +.macok: + + move.l _boardbase(pc),a0 + lea mactestr(pc),a1 + bsr _enc624j6l_SetMAC ;restore default MAC + + ; Initialize board for sending/receiving + move.l _boardbase(pc),a0 + bsr _enc624j6l_Init + tst.l d0 + ble error + + ;---------- transmit test stuff --------------- + moveq #100,d2 +.txtest: + move.l _boardbase(pc),a0 + lea txtestframe(pc),a1 + move #txtestlen,d0 + bsr _enc624j6l_TransmitFrame ; + dbf d2,.txtest + + ;----------- receive text stuff --------------- +.loop + move.l _boardbase(pc),a0 + ;READREG ESTAT,a0,d0 + bsr _enc624j6l_HaveRecv + tst.l d0 + blt error ;bail out if error + beq .noframe ;nothing received + + ;debug: disable recv + ;move.l _boardbase(pc),a0 + ;moveq #ECON1_RXEN,d0 + ;CLRREG ECON1,a0,d0 + + move.l _boardbase(pc),a0 + lea readframe,a1 + move #MAX_FRAMELEN,d0 + bsr _enc624j6l_RecvFrame + + +.noframe: + btst #6,$bfe001 + bne.s .loop + +error: + rts + +DosLibrary: dc.b "dos.library",0 +ExpansionLibrary: dc.b "expansion.library",0 + cnop 0,4 +_expansionbase: dc.l 0 +_dosbase: dc.l 0 +_boardbase: dc.l 0 + +mactest: dc.b $00,$80,$10,$b,$a,$ff ;we write this as test MAC +mactestr: dc.b 0,0,0,0,0,0 ;HW MAC +macdest: dc.b 0,0,0,0,0,0 ;MAC verify + +status: +board_status: dc.b 0 ;ok +mac_status: dc.b 0 ;ok + cnop 0,4 + +readframe: ds.b 1536 +endf: + +txtestframe: + dc.b $ff,$ff,$ff,$ff,$ff,$ff ;, /* broadcast */ + dc.b $00,$80,$10,$0b,$0a,$ff ;, /* own MAC */ + dc.b $08,$00 ;, /* Type IPv4 */ + ; /* */ + dc.b $45,$00 ; /* VER, DSCP */ + dc.b $00,$54 ;, /* length */ + dc.b $A0,$0A ;, /* id */ + dc.b $00,$00 ;, /* flags, fragment offset */ + dc.b $40 ;, /* TTL */ + dc.b $01 ;, /* ICMP */ + dc.b $00,$00 ;, /* header checksum */ + dc.b 192,168,10,12 ;, /* SRC IP */ + dc.b 192,168,10,255 ;, /* dest IP */ + ; /* */ + dc.b $08,$00 ;, /* Type, Code = ICMP Echo */ + dc.b $00,$00 ;, /* Checksum */ + dc.b $DE,$AD ;, /* Identifier */ + dc.b $00,$01 ;, /* SeqNum */ + + dc.b $41,$41,$41,$41,$41,$41,$41,$41 + dc.b $41,$41,$41,$41,$41,$41,$41,$41 + dc.b $41,$41,$41,$41,$41,$41,$41,$41 + dc.b $41,$41,$41,$41,$41,$41,$41,$41 + dc.b $41,$41,$41,$41,$41,$41,$41,$41 + dc.b $41,$41,$41,$41,$41,$41,$41,$41 + dc.b $41,$41,$41,$41,$41,$41,$41,$41 +txtestlen EQU *-txtestframe + + cnop 0,4 + + endc +; ----------------------------------------------------------------------------- +; | | +; | END Test/Debug code | +; | | +; ----------------------------------------------------------------------------- + + + + +;------------------------------------------------------------------------------ +;------------------------------------------------------------------------------ +; +; HW dependent functions +; +;------------------------------------------------------------------------------ +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; +; Purpose: check whether the board is operating as needed; +; +; input: A0 - mmapped board base address +; +; output: success/failure +; >0 - all fine +; <=0 - problem (codes undefined yet) +; +; notes: The Olimex module on the Matze/Scrat ZII IDE LAN CP prototype +; tends to boot in SPI mode instead of PSP (parallel) mode. +; That case is detected by writing/reading data. If both bytes +; of the words are equal to the last written byte, the board is likely +; showing this issue. +; Please note that this call will overwrite Board registers and +; buffer memory. Call before initialization. +_enc624j6l_CheckBoard: ;check whether board is operating correctly + movem.l d1-d2/a0-a1,-(sp) + + move.l a0,d0 + beq .err + + moveq #60,d0 ;let the board settle in if there was + bsr _enc624j6l_UMinDelay ;a reset or POR (unlikely) + + + ; ----------------- quick check for operational mode ------------------ + move.w #$1234,d1 + WRITEREG EUDAST,a0,d1 ;write data + tst.l 4.w ;clear BUS + READREG EUDAST,a0,d0 + cmp.w d0,d1 ;do we get the register back ? + bne.s .err ;no -> complain + + + ; ------------------------- reset device ------------------------------ + moveq #ECON2_ETHRST,d0 + WRITEREG ECON2,a0,d0 ;reset board + + moveq #64-1,d1 ;number of loops to test (max. 7.6 ms) +.loop: + moveq #120,d0 ;wait patiently + bsr _enc624j6l_UMinDelay ; + + READREG ESTAT,a0,d0 + and #(ESTAT_CLKRDY|ESTAT_RSTDONE|ESTAT_PHYRDY),d0 + cmp #(ESTAT_CLKRDY|ESTAT_RSTDONE|ESTAT_PHYRDY),d0 + beq .rstsuccess + + dbf d1,.loop + bra.s .err ;error: device gone after reset + +.rstsuccess: + READREG EUDAST,A0,d0 + tst.w d0 ;should have gone to 0 after reset + bne.s .err ;(see above, we've written $1234) + + ;---------- short RAM check - write phase ---------------------------- + ;---------- (device is not receiving after reset) -------------------- + moveq #3,d1 + move.w #$3000-1,d0 + lea (a0),a1 +.wrloop +; move.w d1,(a1)+ + clr.w (a1)+ + rol.l d1 + eor.b #3,d1 + dbf d0,.wrloop + + + ;---------- short RAM check - read phase ------------------------------ + moveq #3,d1 + move.w #$3000-1,d0 + lea (a0),a1 +.rdloop + move.w (a1)+,d2 + eor.w d1,d2 +; bne.s .err + rol.l d1 + eor.b #3,d1 + dbf d0,.rdloop + + ;---------- satisfied, return our sincere happiness ------------------- + + moveq #1,d0 ;all fine + bra.s .ret +.err: + moveq #0,d0 +.ret + movem.l (sp)+,d1-d2/a0-a1 + rts + + +;------------------------------------------------------------------------------ +; +; Get current MAC address of board +; +; return the 6 Bytes of the MAC address in buffer at A1. Please note that this +; call either returns the burned in Address (if unchanged) or the current +; user-set address if the registers were modified before. +; +; In: A0 - Board base address +; A1 - Pointer to buffer where to store 48 Bit +; +; Out: +; D0 <= 0 - failure +; 1 +; +; Trash: A0/A1 +; +_enc624j6l_GetMAC: ;current state, not necessarily burned in MAC + move.l a0,d0 + beq.s .err + lea MAADR1L+2(a0),a0 ;after first pair of bytes + + rept 3 + move.w -(a0),d0 + rol.w #8,d0 + move.w d0,(a1)+ + endr + + moveq #1,d0 ;success +.err: ; we land at .err with d0 == 0 + rts + + +;--------------------------------------------------------------------------------------- +; +; Set current MAC address of board +; +; set the 6 Bytes of the MAC address from buffer at A1. +; +; In: A0 - Board base address +; A1 - Pointer to buffer where to read 48 Bit from +; +; Out: +; D0 <= 0 - failure +; 1 +; +; Trash: A0/A1 +; +_enc624j6l_SetMAC: ;set user defined MAC address + move.l a0,d0 + beq.s .err + lea MAADR1L+2(a0),a0 ;after first pair of bytes + + move (a1)+,d0 + rol.w #8,d0 + move.w d0,-(a0) + + move (a1)+,d0 + rol.w #8,d0 + move.w d0,-(a0) + + move (a1)+,d0 + rol.w #8,d0 + move.w d0,-(a0) + + moveq #1,d0 +.err: + rts + + +;--------------------------------------------------------------------------------------- +; +; Initialize hardware for send/recv +; +; This call could/should have been done in C. My reason for doing this in ASM was easy +; testing with low turnaround time. +; +; In: A0 - Board base address +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +; Notes: +; +_enc624j6l_Init: + move.l a0,d0 + beq .err + + READREG ESTAT,a0,d0 + and #(ESTAT_CLKRDY|ESTAT_PHYRDY),d0 + cmp #(ESTAT_CLKRDY|ESTAT_PHYRDY),d0 + beq.s .goon ;this state is ok for us + + bsr _enc624j6l_CheckBoard ;preserves all regs + tst.l d0 ;board reset unsuccessful ? + ble.s .err ;-> bail out +.goon: + ;-------------- configure clockout ---------------------- + moveq #ECON1_RXEN,d0 ;no RX, my dear (yet) + CLRREG ECON1,a0,d0 ; + + ;33.333Mhz clock out frequency (see defines above) + move.w #CLOCK_DEF_CLR,d0 ;clr mask + move.w #CLOCK_DEF_SET,d1 ;set mask + CLRREG ECON2,a0,d0 + SETREG ECON2,a0,d1 + + ; disable crypto engine and all interrupts + move #EIR_CRYPTEN|EIR_MODEXIF|EIR_HASHIF|EIR_AESIF|EIR_LINKIF|EIR_PRDYIF|EIR_PKTIF|EIR_DMAIF|EIR_TXIF|EIR_TXABTIF|EIR_RXABTIF|EIR_PCFULIF,d0 + CLRREG EIR,a0,d0 + + ;--------------- RX configuration ----------------------- + move #RXSTART_INIT,d0 + WRITEREG ERXST,a0,d0 ;set RX start pointer (end will be $5fff) + WRITEREG PNextPacket,a0,d0 ;set user read pointer + + ;Multicast,Broadcast,Unicast(self),MagicPacket,correct CRC,filter runts + ;"not me" Unicast == |ERXFCON_NOTMEEN + move #ERXFCON_MCEN|ERXFCON_BCEN|ERXFCON_UCEN|ERXFCON_MPEN|ERXFCON_CRCEN|ERXFCON_RUNTEN,d0 + WRITEREG ERXFCON,a0,d0 ;set filter TODO: pattern matching stuff + move #RXSTOP_INIT&$fffe,d0 + WRITEREG ERXTAIL,a0,d0 ;tail pointer in buffer = rx-2, wraparound + + ;--------------- TX configuration ----------------------- + ; no padding, no proprietary header + move #MACON2_PADCFG2|MACON2_PADCFG1|MACON2_PADCFG0|MACON2_PHDREN,d0 + CLRREG MACON2,a0,d0 + ; add CRC by ENC Chip + move #MACON2_PADCFG1|MACON2_PADCFG0|MACON2_TXCRCEN,d0 + SETREG MACON2,a0,d0 + + move #MAX_FRAMELEN,d0 + WRITEREG MAMXFL,a0,d0 ;set maximum frame length + moveq #0,d0 + WRITEREG PNextTX,a0,d0 ;private pointer, "last written, maybe still pending frame" + + + ;--------------- DONE: enable reception ----------------- + moveq #ECON1_RXEN,d0 + SETREG ECON1,a0,d0 + + moveq #1,d0 +.err: + rts + + +;--------------------------------------------------------------------------------------- +; +; Shutdown hardware +; +; This call could/should have been done in C. My reason for doing this in ASM was easy +; testing with low turnaround time. +; +; In: A0 - Board base address +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +_enc624j6l_Shutdown: + move.l a0,d0 + beq .err + + bsr _enc624j6l_SetOffline + + moveq #1,d0 +.err: + rts + + +;--------------------------------------------------------------------------------------- +; +; Bring device online +; +; In: A0 - Board base address +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +; Notes: - assumes that init() was called before, also please note that init +; will bring the device online by itself +; - it will take a while until the device is properly configured (several hundred +; milliseconds), therefore a delay is advised after calling this (preferably Delay() in DOS) +; +_enc624j6l_SetOnline: + move.l a0,d0 + beq.s .err + + move #ECON2_ETHEN|ECON2_STRCH,d0 + SETREG ECON2,a0,d0 + +; move #PHCON1_PSLEEP,d0 +; CLRREG PHCON1,a0,d0 + + moveq #ECON1_RXEN,d0 + SETREG ECON1,a0,d0 + + moveq #1,d0 +.err + rts + + +;--------------------------------------------------------------------------------------- +; +; Bring device offline +; +; In: A0 - Board base address +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +; Notes: assumes that init() was called before +; +_enc624j6l_SetOffline: + move.l a0,d0 + beq.s .err + + ; disable crypto engine and all interrupts + move #EIR_CRYPTEN|EIR_MODEXIF|EIR_HASHIF|EIR_AESIF|EIR_LINKIF|EIR_PRDYIF|EIR_PKTIF|EIR_DMAIF|EIR_TXIF|EIR_TXABTIF|EIR_RXABTIF|EIR_PCFULIF,d0 + CLRREG EIR,a0,d0 + + moveq #ECON1_RXEN,d0 + CLRREG ECON1,a0,d0 + +; move #PHCON1_PSLEEP,d0 +; SETREG PHCON1,a0,d0 + + move #ECON2_ETHEN|ECON2_STRCH,d0 + CLRREG ECON2,a0,d0 + + moveq #1,d0 +.err: + rts + + +;--------------------------------------------------------------------------------------- +; +; Enable Hardware Interrupt +; +; In: A0 - Board base address +; A1 - Signal Task - task to receive signal +; D0 - Signal Bit - the interrupt will send a signal to the given task (BIT, NOT SIGNAL MASK!!) +; D1 - Interrupt mask (pass 0 for now) +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +; Notes: assumes that init() was called before +; +_enc624j6l_EnableInterrupt: + move.l a0,d1 + beq.s .err + + WRITEREG PSigBit,a0,d0 ;save signal bit + + move.l a1,d0 + WRITEREG PSigTask+2,a0,d0 ;lower two bytes + swap d0 ; + WRITEREG PSigTask,a0,d0 ;upper two bytes + + ; enable interrupt for incoming packet + move #EIR_PKTIF,d0 + SETREG EIR,a0,d0 + + moveq #1,d0 +.rts + rts +.err: + moveq #0,d0 + bra.s .rts + + +;--------------------------------------------------------------------------------------- +; +; Disable Hardware Interrupt +; +; In: A0 - Board base address +; A1 - Signal Task - task to receive signal +; D0 - Signal Bit - the interrupt will send a signal to the given task (BIT, NOT SIGNAL MASK!!) +; D1 - Interrupt mask (pass 0 for now) +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +; Notes: assumes that init() was called before +; +_enc624j6l_DisableInterrupt: + move.l a0,d0 + beq.s .err + + ;disables all interrupts + move #EIR_CRYPTEN|EIR_MODEXIF|EIR_HASHIF|EIR_AESIF|EIR_LINKIF|EIR_PRDYIF|EIR_PKTIF|EIR_DMAIF|EIR_TXIF|EIR_TXABTIF|EIR_RXABTIF|EIR_PCFULIF,d0 + CLRREG EIR,a0,d0 + + moveq #0,d0 + WRITEREG PSigTask+2,a0,d0 ;lower two bytes + WRITEREG PSigTask,a0,d0 ;upper two bytes + + moveq #1,d0 +.err: + rts + + +;--------------------------------------------------------------------------------------- +; +; Hardware interrupt service routine +; +; In: A1 - is_data = board base address +; +; Out: - +; +; Notes: assumes that init() was called before +; +_enc624j6l_IntServer: + move.l a1,d0 ;no pointer supplied ? -> return + beq.s .rts + + moveq #EIR_PKTIF,d1 + READREG EIR,a1,d0 ;get interrupt status reg + and d1,d0 + beq.s .rts ;exit quickly when no packet pending + ;CLRREG EIR,a1,d1 ;clear interrupt bit + + READREG PSigTask,a1,d0 ;upper two bytes + swap d0 ; + READREG PSigTask+2,a1,d0 ;lower two bytes + tst.l d0 ; no task ? + beq.s .rts + move.l d0,a0 ; signaled task + + moveq #0,d0 + READREG PSigBit,a1,d1 ;get signal bit + bset d1,d0 ;signal mask + move.l a0,a1 ;task + + move.l 4.w,a6 + jsr _LVOSignal(a6) + +.rts + moveq #0,d0 ;set Z flag + rts + +;--------------------------------------------------------------------------------------- +; +; Reset Receive pointers +; +; INTERNAL: re-initialize receive buffer in case of problems (limited testing so far!) +; +; In: A0 - Board base address +; D1 - flags +; +; Out: +; D0 <= 0 - failure +; 1 - OK +; +; Notes: - Doesn't check for Board Pointer (!) +; - doesn't re-enable RX (!) +; +_enc624j6l_RXReset: + + moveq #ECON2_RXRST,d0 ;RX Reset, clears RXEN + SETREG ECON2,a0,d0 ; + ;moveq #ECON1_RXEN,d0 ;done by RX reset + ;CLRREG ECON1,a0,d0 ; + + ;-------------- manually decrement ESTAT packet count --------------- + move.w #$100,d1 ;max. loops +.clearESTAT + READREG ESTAT,a0,d0 + tst.b d0 ;ESTAT_PKTCNT7...ESTAT_PKTCNT0 + beq.s .empty + move #ECON1_PKTDEC,d0 + SETREG ECON1,a0,d0 ;set packet decrement ("frame", actually) + dbf d1,.clearESTAT + + ;oh. ESTAT didn't move. This is bad. Full Reset needed + ;(unimplemented yet, pretend we're good) +.empty + ;----------------- restart RX with proper pointers ----------------- + moveq #ECON2_RXRST,d0 ;bring RX out of reset (RXEN still off) + CLRREG ECON2,a0,d0 ; + + move #RXSTART_INIT,d0 + WRITEREG ERXST,a0,d0 ;set RX start pointer (end will be $5fff) + WRITEREG PNextPacket,a0,d0 ;set user read pointer + + ;Multicast,Broadcast,Unicast(self),MagicPacket,correct CRC,"not me" Unicast + move #ERXFCON_MCEN|ERXFCON_BCEN|ERXFCON_UCEN|ERXFCON_MPEN|ERXFCON_CRCEN|ERXFCON_NOTMEEN,d0 + WRITEREG ERXFCON,a0,d0 ;set filter TODO: pattern matching stuff + move #RXSTOP_INIT&$fffe,d0 + WRITEREG ERXTAIL,a0,d0 ;tail pointer in buffer = rx-2, wraparound + + move #MAX_FRAMELEN,d0 + WRITEREG MAMXFL,a0,d0 ;set maximum frame length + + ;moveq #ECON1_RXEN,d0 ;uncomment these for Auto RX re-enabling + ;SETREG ECON1,a0,d0 + + rts + +;--------------------------------------------------------------------------------------- +; +; check for pending receive frames +; +; input: A0 - mmapped board base address +; +; output: D0 <0 - error +; 0 - no pending frames +; >0 - number of pending frames +; +; trash: - +; +; notes: Interrupt-safe, meant to return quickly +; +_enc624j6l_HaveRecv: + move.l a0,d0 + beq.s .err + + READREG ESTAT,a0,d0 + and.l #$ff,d0 ;ESTAT_PKTCNT7...ESTAT_PKTCNT0 +.rts: + rts +.err: moveq #-1,d0 + bra.s .rts + + +;--------------------------------------------------------------------------------------- +; +; receive single frame from HW into supplied memory buffer +; +; input: A0 - APTR mmapped board base address +; A1 - APTR buffer for received frame +; D0 - SHORT maximum size in buffer +; +; output: D0 <0 - error (i.e. frame too large) +; 0 - no pending frames +; >0 - size of received frame in buffer +; +; trash: - +; +; notes: +; +_enc624j6l_RecvFrame: ; + movem.l d2-d7/a1-a3,-(sp) + move.l a0,d1 + beq .err + + READREG ESTAT,a0,d0 ;number of pending frames + and.l #$ff,d0 ;clear out count (ESTAT_PKTCNT7...ESTAT_PKTCNT0) + beq .rts ;nothing in buffer, return sheer emptiness + ;at least one frame in buffer + + READREG ERXHEAD,A0,d4 + READREG ERXTAIL,A0,d5 + + ;----------- check next packet pointer and verify expected state ----------- + READREG PNextPacket,a0,d7 ;get user read pointer from private space + ;lea (a0,d7.w),a2 ;read ptr for next packet address + ;READREG 0,a2,d0 ;next packet pointer + READSRAM a0,d7,d0 ;move (a0,d7.w),d0 + ;verify next packet pointer, re-initialize recv if this is invalid + cmp #RXSTOP_INIT,d0 ;bad pointer (<0 or >end of memory) + bhi.w .recv_err + cmp d0,d7 + bgt.s .maybewrap + ;unwrapped next packet + move d0,d1 + bra.s .ptrcheck +.maybewrap: + ;wrapped next packet ? + move #RXSTOP_INIT+1-RXSTART_INIT,d1 ;unwrap distance + add.w d0,d1 ;next pkt + unwrap distance +.ptrcheck: + sub.w d7,d1 ;length of pkt + cmp #MAX_FRAMELEN+2+6,d1 ;must be smaller than max framelen + ptr + status vector + bhi .recv_err ;-> reinit recv (am I paranoid ? -> try ENC28J60, then you know why...) + + ;debug: collect packet positions + ;move.l recvptr,a2 + ;move d0,(a2)+ + ;move.l a2,recvptr + ;addq.l #1,recvcount + ;cmp.l #65536,recvcount + ;bgt .recv_err + + WRITEREG PNextPacket,a0,d0 ;write pointer for next packet + + ;------------------ check receive status vector ----------------------------- + addq.w #2,d7 ;increment pointer + WRAPINDEX d7 ;wrap D7 if beyond buffer + ;lea (a0,d7.w),a2 ;read ptr for first control word + ;READREG 0,a2,d0 ;last control word = length (byte count) + READSRAM a0,d7,d0 ;move (a0,d7.w),d0 + + and.w #$f800,d0 ;verify (should be all zeros in upper 9 bits) + bne .recv_err ;receive buffer is wrong -> re-initialize + + addq.w #4,d7 ;increment pointer + WRAPINDEX d7 ;wrap D7 if beyond buffer + ;lea (a0,d7.w),a2 ;new read pointer for length + ;READREG 0,a2,d0 ;last control word = length (byte count) + READSRAM a0,d7,d0 ;move (a0,d7.w),d0 + + ifne 1 + ;D1 is the distance to the next frame = stored length + recv vevtor + sub #6+2,d1 ;STATUS VECTOR, Pointer + move d1,d0 ; + + else + cmp #2,d0 + blt .recv_err ;can't be: SRC MAC 6 DST MAC 6 LEN/TYPE 2 CRC 4 (discounting variable data) + cmp #MAX_FRAMELEN,d0 + bgt .recv_err + endc + + subq #4,d0 ;subtract CRC length + + addq.w #2,d7 ;increment pointer (skip status vector length field) + WRAPINDEX d7 ;wrap D7 if beyond buffer + + ;d0.w: length (without crc) + ;d7.w: read position (beginning of frame, dest MAC) + ;a0: board I/O + ;a1: dest pointer + move.l a1,a3 + + ;generic loop: check for position overflows with each word + move d0,d1 ;byte count + lsr #1,d1 ;converted to word count + bcs.s .generic_read ;read 1 byte more if impair byte count + subq #1,d1 ;words - 1 +.generic_read: + READSRAM a0,d7,d2 ;get current word + ;move (a0,d7.w),d2 ;get current word + addq #2,d7 ;increment position + ifne _OPT_BUFFER_SWAP + rol.w #8,d2 ;swap buffer to Big Endian + endc + WRAPINDEX d7 ;wrap D7 if beyond buffer + move d2,(a1)+ + dbf d1,.generic_read + + ;frame copied, now advance HW pointer + READREG PNextPacket,a0,d1 ;write pointer for next packet + cmp #RXSTART_INIT,d1 + bne.s .tail_nowrap + move #(RXSTOP_INIT&$fffe)+2,d1 +.tail_nowrap: + subq #2,d1 + WRITEREG ERXTAIL,a0,d1 ;tail pointer in buffer = rx-2, wraparound + + move #ECON1_PKTDEC,d1 + SETREG ECON1,a0,d1 ;set packet decrement ("frame", actually) + + ext.l d0 + cmp.w #14,d0 + bge.s .rts + + moveq #0,d0 + +; cmp.l #$d8803977,6(a3) +; beq .rts +; moveq #0,d0 +; clr.l 6(a3) + +.rts: + movem.l (sp)+,d2-d7/a1-a3 + rts +.err: moveq #-1,d0 ;receive error + bra.s .rts +.recv_err: + ;serious problem: we need to re-initialize the recv buffer here + bsr _enc624j6l_RXReset + + moveq #ECON1_RXEN,d0 ;re-enable reception + SETREG ECON1,a0,d0 + + moveq #0,d0 + bra.s .rts + + +;--------------------------------------------------------------------------------------- +; +; send single frame from HW +; +; input: A0 - APTR mmapped board base address +; A1 - APTR buffer for sent frame (without CRC, appended by the ENC) +; D0 - SHORT size of frame in buffer +; +; output: D0 <0 - error (i.e. frame too large) +; 0 - no pending frames +; >0 - size of received frame in buffer +; +; trash: - +; +; notes: +; +_enc624j6l_TransmitFrame: + movem.l d2-d4/a2,-(sp) + + ;---------------- parameter check ------------------------------------- + + move.l a0,d1 ;no base PTR + beq.s .err ;exit + + move.l a1,d1 ;no send frame ? + beq.s .err ;exit + + move.w d0,d4 ;still need length later + addq #1,d0 ;round up + asr.w #1,d0 ;size/2 = words + subq.w #1,d0 ;dbf... + blt.s .err ;size<2 ? bail out + + moveq #MACON2_FULDPX,d1 + SETREG MACON2,a0,d1 + ;moveq #$15,d1 + ;WRITEREG MABBIPG,a0,d1 + + ;------ double-buffered frame copy to send buffer --------------------- + READREG PNextTX,a0,d2 ;"last written, maybe still pending frame" + and.w #PSwapTX,d2 ;sanity, leave only desired bits + eor.w #PSwapTX,d2 ;swap buffer + WRITEREG PNextTX,a0,d2 ;remember pointer (d2 also for ETXST later) + + lea (a0,d2.w),a2 ;write pointer for frame +.txcopy: + move (a1)+,d1 ;get word + ifne _OPT_BUFFER_SWAP + rol.w #8,d1 ;swap buffer to Big Endian (if necessary) + endc + move d1,(a2)+ ;save to SRAM + dbf d0,.txcopy + + ;---------------- wait on last frame ---------------------------------- + moveq #100,d3 +.txwait: + READREG ECON1,a0,d1 + and.w #ECON1_TXRTS,d1 + beq.s .txrdy + ;100 MBit/s frame time is max. 0.12 ms (without inter-frame spacing) + + ;wait 50 us via CIA + moveq #50,d0 + bsr _enc624j6l_UMinDelay + dbf d3,.txwait ;approx. 5ms max. wait + + ;hmpf. abort last transmission + move #ECON1_TXRTS,d1 ; + CLRREG ECON1,a0,d1 ; + +.txrdy: + ;----------------- set new frame parameters --------------------------- + + WRITEREG ETXST,a0,d2 ;set new TX pointer + WRITEREG ETXLEN,a0,d4 ;set TX length + + move #ECON1_TXRTS,d1 ;issue "send" command on ENC chip + SETREG ECON1,a0,d1 ; + +.err: + movem.l (sp)+,d2-d4/a2 + rts + + +;------------------------------------------------------------------------------------------------ +;------------------------------------------------------------------------------------------------ +; +; Generic HW independent functions +; +;------------------------------------------------------------------------------------------------ +;------------------------------------------------------------------------------------------------ + +; +;delay at least D0 microseconds (<= $0fffffff or ~268.000.000) +; +; Important: +; No guarantee can be given right now by how much the given delay time is exceeded. +; All this function tries to achieve is to wait long enough in order to meet certain +; mimimal hardware delay requirements +; +; Notes: +; clipping/saturation of input argument included +; +;Input: D0 = delay in microseconds +; +;Output: void +; +_enc624j6l_UMinDelay: + movem.l d0/d1,-(sp) + + moveq #-1,d1 + lsr.l #4,d1 ;$0fffffff + cmp.l d1,d0 + blo.s .ok ;unsigned compare + move.l d1,d0 ;268 seconds +.ok + lsl.l #3,d0 ;us * 8 + + moveq #12,d1 ;1.5 +.loop + eor.b #7,d1 ;switch between 12/8 and 11/8 -> 1.4375 effective count per CIA access + tst.b $BFE301 ;1 CIA access = 1.4 us + sub.l d1,d0 ;us*8 - (1.5 or 1.375)*8 + bgt.s .loop + + movem.l (sp)+,d0/d1 + rts + +;debug: collect packet positions +;recvptr: dc.l recvlist +;recvcount: dc.l 0 +;recvlist: ds.w 65536 + + END diff --git a/Driver/enc624j6net/enc624j6net/enc624j6l.h b/Driver/enc624j6net/enc624j6net/enc624j6l.h new file mode 100755 index 0000000..a5f1ab7 --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/enc624j6l.h @@ -0,0 +1,253 @@ +/* + enc624j6l.h + + author: Henryk Richter + + purpose: header for low-level board access + to memory mapped ENC624J600 networking + device + + note: all functions are relative to the base pointer, + determine IO space by a respective expansion.library + call +*/ +#ifndef _INC_ENC624J6L_H +#define _INC_ENC624J6L_H + +#include "asminterface.h" + +/* + Defines: flags copied from PlipBox +*/ +/* result values */ +#define PIO_OK 0 +#define PIO_NOT_FOUND 1 +#define PIO_TOO_LARGE 2 +#define PIO_IO_ERR 3 + +/* init flags */ +#define PIO_INIT_FULL_DUPLEX 1 +#define PIO_INIT_LOOP_BACK 2 +#define PIO_INIT_BROAD_CAST 4 +#define PIO_INIT_FLOW_CONTROL 8 +#define PIO_INIT_MULTI_CAST 16 +#define PIO_INIT_PROMISC 32 + +/* status flags */ +#define PIO_STATUS_VERSION 0 +#define PIO_STATUS_LINK_UP 1 + +/* control ids */ +#define PIO_CONTROL_FLOW 0 + + + +/* + Purpose: check whether the board is operating as needed + + input: board - mmapped board base address + + output: success/failure + >0 - all fine + <=0 - problem (codes undefined yet) + + notes: The Olimex module on the Matze/Scrat ZII IDE LAN CP prototype + tends to boot in SPI mode instead of PSP (parallel) mode. + That case is detected by writing/reading data. If both bytes + of the words are equal to the last written byte, the board is likely + showing this issue. + + Please note that this call will overwrite Board registers and + buffer memory. Call before initialization. +*/ +ASM SAVEDS int enc624j6l_CheckBoard( ASMR(a0) void *board ASMREG(a0) ); + + +/* + Purpose: obtain current MAC address + input: board - mmapped board base address + buffer - 6 bytes space to write into (network notation, big endian) + output: success/failure + >0 - all fine + <=0 - problem (codes undefined yet) +*/ +ASM SAVEDS int enc624j6l_GetMAC( ASMR(a0) void *board ASMREG(a0), + ASMR(a1) unsigned char *buffer ASMREG(a1) ); + +/* + Purpose: change current MAC address + input: board - mmapped board base address + buffer - 6 bytes space to read from (network notation, big endian) + output: success/failure + >0 - all fine + <=0 - problem (codes undefined yet) +*/ +ASM SAVEDS int enc624j6l_SetMAC( ASMR(a0) void *board ASMREG(a0), + ASMR(a1) unsigned char *buffer ASMREG(a1) ); + +/* + Purpose: delay at least the given amount of microseconds + input: delay time in microseconds + output: - +*/ +ASM SAVEDS void enc28j60l_UMinDelay( + ASMR(d0) unsigned long udelay ASMREG(d0) ); + + +/* + Purpose: initialize a board + + input: board - mmapped board base address + flags - init flags (0 if in doubt) + + output: success/failure + >0 - all fine + <=0 - problem (codes undefined yet) + + notes: +*/ +ASM SAVEDS int enc624j6l_Init( ASMR(a0) void *board ASMREG(a0), + ASMR(d1) unsigned long flags ASMREG(d1) ); + + +/* + Purpose: stop a board + + input: board - mmapped board base address + + output: success/failure + >0 - all fine + <=0 - problem (codes undefined yet) + + notes: Shutdown means to disconnect the PHY, put the chip + into low power mode and disable interrupts + +*/ +ASM SAVEDS int enc624j6l_Shutdown( ASMR(a0) void *board ASMREG(a0) ); + + +/* + Purpose: check for pending receive frames + + input: board - mmapped board base address + + output: <0 - error + 0 - no pending frames + >0 - number of pending frames + + notes: + +*/ +ASM SAVEDS int enc624j6l_HaveRecv( ASMR(a0) void *board ASMREG(a0) ); + +/* + Purpose: copy received frame to supplied buffer + + input: board - mmapped board base address + buffer - output buffer (should have >=1514 bytes) + buffersize - size of buffer + + output: <0 - error + 0 - nothing in receive buffer + >0 - size of received frame + + notes: + +*/ +ASM SAVEDS int enc624j6l_RecvFrame( ASMR(a0) void *board ASMREG(a0), + ASMR(a1) unsigned char* buffer ASMREG(a1), + ASMR(d0) short buffersize ASMREG(d0) ); + + +/* + Purpose: send single frame out + + input: board - mmapped board base address + buffer - output buffer (should have >=1514 bytes) + sendsize - size of buffer in bytes ( no CRC appended (!) ) + + output: <0 - error + 0 - nothing in receive buffer + >0 - size of received frame + + notes: + +*/ +ASM SAVEDS int enc624j6l_TransmitFrame( ASMR(a0) void *board ASMREG(a0), + ASMR(a1) unsigned char* buffer ASMREG(a1), + ASMR(d0) short sendsize ASMREG(d0) ); + + +/* + Purpose: enable RX/TX, perform autonegotiation etc. + + input: board - mmapped board base address + + output: <0 - error + >=0 - OK + + notes: in current implementation, enc624j6l_Init() will + also attach the card to the line. So this + call is not exactly needed in the init phase. +*/ +ASM SAVEDS int enc624j6l_SetOnline( ASMR(a0) void *board ASMREG(a0) ); + + +/* + Purpose: disable RX/TX, power down + + input: board - mmapped board base address + + output: <0 - error + >=0 - OK + + notes: +*/ +ASM SAVEDS int enc624j6l_SetOffline( ASMR(a0) void *board ASMREG(a0) ); + + +/* + Purpose: enable HW interrupt + + input: board - mmapped board base address + SigTask - task to signal upon interrupt (or NULL) + SigBit - Signal bit to send upon interrupt (or -1) + IntMask - ENC HW interrupts to enable (set 0, for now) = RX PACKET only + + output: <0 - error + >=0 - OK + + notes: +*/ +ASM SAVEDS int enc624j6l_EnableInterrupt( ASMR(a0) void *board ASMREG(a0), + ASMR(a1) void* SigTask ASMREG(a1), + ASMR(d0) int SigBit ASMREG(d0), + ASMR(d1) unsigned int IntMask ASMREG(d1) ); + + +/* + Purpose: disable HW interrupt + + input: board - mmapped board base address + + output: <0 - error + >=0 - OK + + notes: +*/ +ASM SAVEDS int enc624j6l_DisableInterrupt( ASMR(a0) void *board ASMREG(a0) ); + + +/* + Purpose: interrupt service routine ( after EnableInterrupt() ) + + This function will signal the task passed at EnableInterrupt time with + the given sigbit when at least one frame is pending. + + input: - + output: - +*/ +ASM SAVEDS void enc624j6l_IntServer( void ); + + +#endif /* _INC_ENC624J6L_H */ diff --git a/Driver/enc624j6net/enc624j6net/hw.c b/Driver/enc624j6net/enc624j6net/hw.c new file mode 100755 index 0000000..f277184 --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/hw.c @@ -0,0 +1,471 @@ +/* + * hw.c - hardware dependent part of driver + */ + +#define DEBUG 0 +/* 15 */ + +/*F*/ /* includes */ +#ifndef CLIB_EXEC_PROTOS_H +#include +#include +#endif +#ifndef CLIB_DOS_PROTOS_H +#include +#include +#endif +#ifndef CLIB_CIA_PROTOS_H +#include +#include +#endif +#ifndef CLIB_MISC_PROTOS_H +#include +#include +#endif +#ifndef CLIB_TIME_PROTOS_H +#include +#include +#endif +#ifndef CLIB_UTILITY_PROTOS_H +#include +#include +#endif + +#ifndef EXEC_MEMORY_H +#include +#endif +#ifndef EXEC_INTERRUPTS_H +#include +#endif +#ifndef EXEC_DEVICES_H +#include +#endif +#ifndef EXEC_IO_H +#include +#endif + +#ifndef DEVICES_SANA2_H +#include +#endif + +#ifndef HARDWARE_CIA_H +#include +#endif + +#include + +#ifndef RESOURCES_MISC_H +#include +#endif + +#ifndef _STRING_H +#include +#endif + +#ifndef __GLOBAL_H +#include "global.h" +#endif +#ifndef __DEBUG_H +#include "debug.h" +#endif +#ifndef __COMPILER_H +#include "compiler.h" +#endif +#ifndef __HW_H +#include "hw.h" +#endif +#include "dev_info.h" + +#ifdef PROTO_SDNET +#include "enc28j60.h" +#define HW_INTERVALDEF 10000L +#endif +#ifdef PROTO_ENC624NET +#include "enc624j6l.h" + +/* 10000 without HW interrupt 100000 with HW interrupt */ +#define HW_INTERVALDEF 50000L + +/* this is a BIG TODO! Make plipbox source multi-board aware */ +#define BOARD hwb->hwb_boards[0] + +/* interrupt (choice here is INTB_EXTER or INTB_PORTS, depending on solder blob */ +/*#define HW_INTSOURCE INTB_EXTER*/ +#define HW_INTSOURCE INTB_PORTS + +#endif + +/* this is currently necessary on Apollo Core. We don't have an interrupt on the SD card slot */ +/* used also with ENC624 (albeit with 10x longer default waiting) should we miss some interrupts */ +#include "intervaltimer.h" +#define HW_INTERVAL +#define HW_INTERVALMIN 2500L +#define HW_INTERVALMAX 500000L + +/* TODO: remove. I think I won't need this for the SDnet */ +PRIVATE ULONG ASM SAVEDS exceptcode(REG(d0) ULONG sigmask, REG(a1) struct PLIPBase *hwb); + +const char *intname = "ENC624Net_HWInterrupt"; + + +/* just to make SAS/C happy, no other function */ +int _avoid_sasc_warning_about_global_symbols( void ); +int _avoid_sasc_warning_about_global_symbols( void ) +{ + return 0; +} + +#ifdef PROTO_ENC624NET +PRIVATE void stopInt(struct PLIPBase *pb, struct HWBase *hwb, APTR board ) +{ + if( hwb->hwb_Interrupt.is_Data ) + { + hwb->hwb_Interrupt.is_Data = (0); + enc624j6l_DisableInterrupt( board ); + + RemIntServer( HW_INTSOURCE, &hwb->hwb_Interrupt ); + hwb->hwb_Interrupt.is_Code = (0); + } +} + +PRIVATE void startInt(struct PLIPBase *pb, struct HWBase *hwb, APTR board ) +{ + if( hwb->hwb_Interrupt.is_Data ) + stopInt( pb, hwb, board ); + + enc624j6l_EnableInterrupt( BOARD, FindTask(0), (int)hwb->hwb_IntSig, 0 ); + + hwb->hwb_Interrupt.is_Code = (void(*)())enc624j6l_IntServer; + hwb->hwb_Interrupt.is_Data = board; + hwb->hwb_Interrupt.is_Node.ln_Type = NT_INTERRUPT; + hwb->hwb_Interrupt.is_Node.ln_Pri = 51; + hwb->hwb_Interrupt.is_Node.ln_Name = (char*)intname; + AddIntServer( HW_INTSOURCE, &hwb->hwb_Interrupt ); +} +#endif + +/* + magic: HW_MAGIC_OFFLINE, HW_MAGIC_ONLINE + return TRUE/FALSE +*/ +GLOBAL REGARGS BOOL hw_send_magic_pkt(struct PLIPBase *pb, USHORT magic) +{ + struct HWBase *hwb = &pb->pb_HWBase; + + if( magic == HW_MAGIC_ONLINE ) + { +#ifdef PROTO_ENC624NET + enc624j6l_SetMAC( BOARD, pb->pb_CfgAddr ); + enc624j6l_SetOnline( BOARD ); + startInt(pb, hwb, BOARD ); +#else + enc28j60_setMAC( pb->pb_CfgAddr ); /* update MAC address (just in case) */ + enc28j60_setOnline(); /* acticate RX */ +#endif +#ifdef HW_INTERVAL + StartIntervalTimer( &hwb->hwb_ivtimer, hwb->hwb_timervalue ); /* 10000L */ +#endif + } + if( magic == HW_MAGIC_OFFLINE ) + { +#ifdef PROTO_ENC624NET + stopInt(pb, hwb, BOARD ); + enc624j6l_SetOffline( BOARD ); +#else + enc28j60_setOffline(); /* stop RX */ +#endif +#ifdef HW_INTERVAL + StopIntervalTimer( &hwb->hwb_ivtimer ); +#endif + } + + return TRUE; +} + +/* + setup defaults in plipbase +*/ +GLOBAL REGARGS void hw_config_init(struct PLIPBase *pb) +{ + struct HWBase *hwb = &pb->pb_HWBase; + + hwb->hwb_timervalue = HW_INTERVALDEF; + hwb->hwb_fullduplex = 0; + hwb->hwb_spispeed = 1; /* optimistic default */ + hwb->hwb_multicast = 0; +} + + +GLOBAL REGARGS void hw_config_update(struct PLIPBase *pb, struct TemplateConfig *args) +{ + struct HWBase *hwb = &pb->pb_HWBase; + + if( args->timervalue ) + { + hwb->hwb_timervalue = BOUNDS(*args->timervalue, HW_INTERVALMIN, HW_INTERVALMAX ); + } + if( args->spispeed ) + { + hwb->hwb_spispeed = BOUNDS(*args->spispeed, 1, 20 ); + } + if( args->fullduplex ) + { + hwb->hwb_fullduplex = 1; + } + if( args->multicast ) + { + hwb->hwb_multicast = 1; + } +} + + + +GLOBAL REGARGS void hw_config_dump(struct PLIPBase *pb) +{ +/* +#if DEBUG & 1 + struct HWBase *hwb = &pb->pb_HWBase; +#endif + d(("timeOut %ld.%ld\n", hwb->hwb_TimeOutSecs, hwb->hwb_TimeOutMicros)); + d(("burstSize %ld\n", (ULONG)hwb->hwb_BurstSize)); +*/ +} + + + +GLOBAL REGARGS BOOL hw_init(struct PLIPBase *pb) +{ + struct HWBase *hwb = &pb->pb_HWBase; + + BOOL rc = FALSE; + + /* clone sys base, process */ + hwb->hwb_SysBase = pb->pb_SysBase; + hwb->hwb_Server = pb->pb_Server; + hwb->hwb_MaxFrameSize = (UWORD)pb->pb_MTU + HW_ETH_HDR_SIZE; + d2(("sysbase=%08lx, server=%08lx, hwb=%08lx, maxFrameSize=%ld\n", + hwb->hwb_SysBase, hwb->hwb_Server, hwb, (ULONG)hwb->hwb_MaxFrameSize)); + + hwb->hwb_Interrupt.is_Data = (0); /* prepare interrupt */ + hwb->hwb_Interrupt.is_Code = (0); + if ((hwb->hwb_IntSig = AllocSignal(-1)) != -1) + { + hwb->hwb_IntSigMask = 1L << hwb->hwb_IntSig; + d2(("int sigmask=%08lx\n",hwb->hwb_IntSigMask)); + + if ((hwb->hwb_TimeoutPort = CreateMsgPort())) + { + ULONG sigmask; + struct Process *proc = pb->pb_Server; + + /* save old exception setup */ + hwb->hwb_OldExcept = SetExcept(0, 0xffffffff); /* turn'em off */ + hwb->hwb_OldExceptCode = proc->pr_Task.tc_ExceptCode; + hwb->hwb_OldExceptData = proc->pr_Task.tc_ExceptData; + + /* create new exception setup */ + proc->pr_Task.tc_ExceptCode = (APTR)&exceptcode; + proc->pr_Task.tc_ExceptData = (APTR)pb; + sigmask = 1 << hwb->hwb_TimeoutPort->mp_SigBit; + SetSignal(0, sigmask); + SetExcept(sigmask, sigmask); + + /* enter port address */ + hwb->hwb_TimeoutReq.tr_node.io_Message.mn_ReplyPort = hwb->hwb_TimeoutPort; + if (!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)&hwb->hwb_TimeoutReq, 0)) + { + TimerBase = (struct Library *)hwb->hwb_TimeoutReq.tr_node.io_Device; + + /* setup the timeout stuff */ + hwb->hwb_TimeoutReq.tr_node.io_Flags = IOF_QUICK; + hwb->hwb_TimeoutReq.tr_node.io_Command = TR_ADDREQUEST; + hwb->hwb_TimeoutSet = 0xff; +#ifdef HW_INTERVAL + if( InitIntervalTimer( &hwb->hwb_ivtimer ) > 0 ) + { + hwb->hwb_IntervalSigMask = hwb->hwb_ivtimer.IVT_Signal; + } + else + { + d(("couldn't open Interval Timer")); + } +#endif + rc = TRUE; + } + else + { + d(("couldn't open timer.device")); + } + } + else + { + d(("no port for timeout handling\n")); + } + } + else + { + d(("no interrupt signal\n",rc)); + } + + return rc; +} + + +GLOBAL REGARGS VOID hw_cleanup(struct PLIPBase *pb) +{ + struct HWBase *hwb = &pb->pb_HWBase; + +#ifdef HW_INTERVAL + ExitIntervalTimer( &hwb->hwb_ivtimer ); +#endif + + if (hwb->hwb_TimeoutPort) + { + struct Process *proc = pb->pb_Server; + + /* restore old exception setup */ + SetExcept(0, 0xffffffff); /* turn'em off */ + proc->pr_Task.tc_ExceptCode = hwb->hwb_OldExceptCode; + proc->pr_Task.tc_ExceptData = hwb->hwb_OldExceptData; + SetExcept(hwb->hwb_OldExcept, 0xffffffff); + + if (TimerBase) + { + WaitIO((struct IORequest*)&hwb->hwb_TimeoutReq); + CloseDevice((struct IORequest*)&hwb->hwb_TimeoutReq); + } + DeleteMsgPort(hwb->hwb_TimeoutPort); + } + + if (hwb->hwb_IntSig != -1) { + FreeSignal(hwb->hwb_IntSig); + } +} + + +/* + * hwattach - setup hardware if device gets online + */ +GLOBAL REGARGS BOOL hw_attach(struct PLIPBase *pb) +{ + struct HWBase *hwb = &pb->pb_HWBase; + BOOL rc = TRUE; + unsigned char flags; + + flags = PIO_INIT_BROAD_CAST; + if( hwb->hwb_multicast ) + flags |= PIO_INIT_MULTI_CAST; + + if( hwb->hwb_fullduplex ) + flags |= PIO_INIT_FULL_DUPLEX; +#ifdef PROTO_ENC624NET + if( enc624j6l_Init( BOARD, (unsigned long)flags ) <= 0 ) + rc = FALSE; /* ERROR IN CASE OF DEVICE NOT FOUND */ +#else + if( enc28j60_init( pb->pb_CfgAddr, flags ) != PIO_OK ) + rc = FALSE; /* ERROR IN CASE OF DEVICE NOT FOUND */ + enc28j60_SetSPISpeed( (unsigned long)hwb->hwb_spispeed ); +#endif + + return rc; +} + +/* + * shutdown hardware if device gets offline + */ +GLOBAL REGARGS VOID hw_detach(struct PLIPBase *pb) +{ +#ifdef PROTO_ENC624NET + struct HWBase *hwb = &pb->pb_HWBase; + + stopInt(pb, hwb, BOARD ); + enc624j6l_Shutdown( BOARD ); +#else + enc28j60_exit(); +#endif +} + +PRIVATE ULONG ASM SAVEDS exceptcode(REG(d0) ULONG sigmask, REG(a1) struct PLIPBase *pb) +{ + struct HWBase *hwb = &pb->pb_HWBase; + + d8(("+ex\n")); + + /*extern void KPrintF(char *,...); + KPrintF("exceptcode\n");*/ + + /* remove the I/O Block from the port */ + WaitIO((struct IORequest*)&hwb->hwb_TimeoutReq); + + /* this tells the xfer routines to cease polling */ + hwb->hwb_TimeoutSet = 0xff; + + d8(("-ex\n")); + return sigmask; /* re-enable the signal */ +} + + +GLOBAL REGARGS BOOL hw_send_frame(struct PLIPBase *pb, struct HWFrame *frame) +{ + BOOL rc = TRUE; +#ifdef PROTO_ENC624NET + struct HWBase *hwb = &pb->pb_HWBase; + unsigned char *frm = (unsigned char*)frame; + enc624j6l_TransmitFrame( BOARD, frm+sizeof(USHORT), frame->hwf_Size ); +; frame->hwf_Size = 0; +#else + const u08 *frm = (const u08*)frame; + enc28j60_send(frm+sizeof(USHORT), frame->hwf_Size ); +#endif + return rc; +} + + +GLOBAL REGARGS BOOL hw_recv_pending(struct PLIPBase *pb) +{ +#ifdef PROTO_ENC624NET + struct HWBase *hwb = &pb->pb_HWBase; + int num = enc624j6l_HaveRecv( BOARD ); +#else + u08 num; + num = enc28j60_has_recv(); +#endif + if( num > 0 ) + return TRUE; + else + return FALSE; +} + +/* important: don't call this without enc28j60_has_recv() > 0 check */ +GLOBAL REGARGS BOOL hw_recv_frame(struct PLIPBase *pb, struct HWFrame *frame) +{ +#ifdef PROTO_ENC624NET + int len; + BOOL rc = FALSE; + unsigned char *ptr = (unsigned char*)frame; + struct HWBase *hwb = &pb->pb_HWBase; + + len = enc624j6l_RecvFrame( BOARD, ptr+sizeof(USHORT), 1518 ); + + frame->hwf_Size = len; + + if( len > 0 ) + rc = TRUE; + else + frame->hwf_Size = 0; +#else + BOOL rc = FALSE; + u08 *ptr = (u08*)frame; + + if( PIO_OK == enc28j60_recv( ptr+sizeof(USHORT), 1518, &frame->hwf_Size ) ) + rc = TRUE; + +#endif + return rc; +} + +GLOBAL REGARGS ULONG hw_recv_sigmask(struct PLIPBase *pb) +{ + struct HWBase *hwb = &pb->pb_HWBase; + return hwb->hwb_IntSigMask | hwb->hwb_IntervalSigMask; +} diff --git a/Driver/enc624j6net/enc624j6net/hwbase.h b/Driver/enc624j6net/enc624j6net/hwbase.h new file mode 100644 index 0000000..74970cb --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/hwbase.h @@ -0,0 +1,73 @@ +/* hwbase.h - hardware specific part of driver structure */ +#ifndef __HWBASE_H +#define __HWBASE_H + +#include "intervaltimer.h" + +/* ----- base structure for hardware ----- */ + +/* reported BPS (bits! per second) for this device */ +#define HW_BPS (10000000L) /* 10 MBit/s */ + +/* ENC624: MAX. Zorro Boards (untested, probably doesn't work) */ +#define HW_MAXBOARDS 3 + +struct HWBase +{ + /* used in asm module */ + struct Library * hwb_SysBase; + struct Process * hwb_Server; + ULONG hwb_IntSigMask; + UWORD hwb_MaxFrameSize; + volatile UBYTE hwb_TimeoutSet;/* if != 0, a timeout occurred */ + volatile UBYTE hwb_Flags; + /* NOT used in asm */ + ULONG hwb_IntSig; /* sent from int to server */ + ULONG hwb_IntervalSigMask; + struct MsgPort * hwb_TimeoutPort; /* for timeout handling */ + struct Library * hwb_TimerBase; + struct Library * hwb_MiscBase; /* various libs & res. */ + APTR hwb_OldExceptCode; + APTR hwb_OldExceptData; + ULONG hwb_OldExcept; + struct Interrupt hwb_Interrupt; /* for AddICRVector() */ + struct timerequest hwb_TimeoutReq; /* for timeout handling */ + ULONG hwb_AllocFlags; + APTR hwb_boards[HW_MAXBOARDS+1]; /* 0-terminated */ + + struct IVT_TimerStruct hwb_ivtimer; /* Timer interval handling (via Interrupt) */ + + /* config options */ + ULONG hwb_timervalue; /* timer speed */ + ULONG hwb_fullduplex; /* full duplex */ + ULONG hwb_spispeed; /* SPI speed */ + ULONG hwb_multicast; /* multicast enable */ +}; + +#define HWB_RECV_PENDING 0 +#define HWB_COLL_TIMER_RUNNING 1 + +#define HWF_RECV_PENDING (1 << HWB_RECV_PENDING) + +/* transparently map proto lib bases to structure */ +#define MiscBase hwb->hwb_MiscBase +#define CIAABase hwb->hwb_CIAABase +#define CiaBase hwb->hwb_CIAABase +#define TimerBase hwb->hwb_TimerBase + +/* ----- config ----- */ + +#define CONFIGFILE "ENV:SANA2/sdnet.config" +#define TEMPLATE "TIMER/K/N,FULLDUPLEX/S,SPISPEED/K/N,MULTICAST/S" + +/* structure to be filled by ReadArgs template */ +struct TemplateConfig +{ + struct CommonConfig common; + ULONG *timervalue; + ULONG fullduplex; + ULONG *spispeed; + ULONG multicast; +}; + +#endif diff --git a/Driver/enc624j6net/enc624j6net/intervaltimer.asm b/Driver/enc624j6net/enc624j6net/intervaltimer.asm new file mode 100644 index 0000000..7f88175 --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/intervaltimer.asm @@ -0,0 +1,328 @@ +****************************************************************************** +* Name: intervaltimer.s * +* Date: $Date: 2016-12-18 22:20:04 +0100 (So, 18. Dez 2016) $ * +* Authors: Henryk Richter * +****************************************************************************** + + ;MACHINE MC68040 + + include exec/types.i + include lvo/exec_lib.i + include lvo/dos_lib.i + include lvo/timer_lib.i + include exec/exec.i + include dos/dos.i + include dos/dostags.i + include exec/io.i + include dos/dosextens.i + include exec/lists.i + + ifne 1 + include "intervaltimer.i" + else + STRUCTURE IVT_TimerStruct,0 + ULONG IVT_Interval ;<1e6 in microseconds + LONG IVT_Signal ;Signal that is sent back to task from interrupt + APTR IVT_SigTask ;Task that is signaled + APTR IVT_Port + APTR IVT_IORequest + APTR IVT_Device + STRUCT IVT_Int,IS_SIZE ; + BYTE IVT_Init ; !=0 - initialized + BYTE IVT_Runflag ; current status ( !=0 = running ) + BYTE IVT_Stopflag ; stop request if != 0 + BYTE IVT_Unused ; + ULONG IVT_Counter ; Counter (statistics) + LABEL IVT_Size + endc + + xdef _InterruptIntervalTimer + xdef _InitIntervalTimer + xdef _ExitIntervalTimer + xdef _StartIntervalTimer + xdef _StopIntervalTimer + +CALLEXEC macro + move.l 4.w,a6 + jsr _LVO\1(a6) + endm + + section code,text + +TestTimer: + lea dos_name,a1 ;string base + moveq #0,d0 + move.l 4.w,a6 + jsr _LVOOpenLibrary(a6) + move.l d0,dosbase + beq .nodos + + move.l dosbase,a6 + jsr _LVOOutput(a6) ;get stdout + move.l d0,stdout + + lea timerbase,a1 + bsr _InitIntervalTimer + tst.l d0 + bge .ok + + move.l stdout,d0 + move.l #failtimer,d1 + move.l dosbase,16 + jsr _LVOPutStr(a6) + bra .error + +.ok + lea timerbase,a1 + move.l #10000,d1 + bsr _StartIntervalTimer + + moveq #0,d3 +.loop + cmp.l #10,d3 + bgt.s .exitloop + + move.l dosbase,A6 + moveq #10,d1 + jsr _LVODelay(a6) + + addq.l #1,d3 + lea timerbase,a1 + cmp.l #100,IVT_Counter(a1) + blt.s .loop +.exitloop: + + move.l #succname,d1 + cmp.l #10,d3 + ble.s .succ + move.l #failname,d1 +.succ: + jsr _LVOVPrintf(a6) + + + lea timerbase,a1 + bsr _StopIntervalTimer +.error + lea timerbase,a1 + bsr _ExitIntervalTimer + + move.l dosbase,d0 + beq.s .nodos + move.l d0,a1 + move.l 4.w,a6 + jsr _LVOCloseLibrary(a6) +.nodos: + rts + +; A1 = IVT_TimerStruct +_InterruptIntervalTimer: + movem.l d1-a6,-(sp) + ;<- basic Timer.device ops -> + move.l a1,a2 + + move.l IVT_Port(a2),a0 + CALLEXEC GetMsg + tst.l d0 + beq.s .error + + move.l IVT_Signal(a2),d0 + move.l IVT_SigTask(a2),a1 + CALLEXEC Signal + + tst.b IVT_Stopflag(a2) + bne.s .error ;not exactly an error but same consequence + + move.l a2,a1 + bsr _RestartIntervalTimer + + ;<- end basic Timer.device ops -> + + ;<- useful stuff -> + addq.l #1,IVT_Counter(a2) + + ;<- useful stuff -> + + bra.s .endintroutine +.error: + clr.b IVT_Runflag(a2) +.endintroutine: + movem.l (sp)+,d1-a6 + rts + + +_InitIntervalTimer: ;prepare timer.device for buffer swap interrupt + movem.l d1-a6,-(sp) + move.l a1,a2 + move #IVT_Size-1,d0 +.clr + clr.b (a1)+ ; + dbf d0,.clr + + sf IVT_Init(a2) + sf IVT_Runflag(a2) + ;signal to wait for from timer output if output queue full + moveq #-1,d0 + CALLEXEC AllocSignal + move.l d0,IVT_Signal(a2) + not.l d0 ; if( d0 == -1 ) d0 = 0 + beq .error ; error: have to go (shouldn't happen) + + suba.l a1,a1 + CALLEXEC FindTask + move.l d0,IVT_SigTask(a2) + + CALLEXEC CreateMsgPort ;Create MsgPort for timing... + move.l d0,IVT_Port(a2) + beq .error ;0=error + + move.l IVT_Port(a2),a0 + move.l #IOTV_SIZE,d0 + CALLEXEC CreateIORequest + move.l d0,IVT_IORequest(a2) + beq .error ;0=error + + lea.l IVT_Int(a2),a0 + lea _InterruptIntervalTimer(pc),a1 + move.l a1,IS_CODE(a0) + move.l a2,IS_DATA(a0) + move.b #NT_INTERRUPT,LN_TYPE(a0) + move.b #0,LN_PRI(a0) ;-32,-16,0,16,32 + + move.l IVT_Port(a2),a1 + ;move.b #NT_MSGPORT,LN_TYPE(a1) + move.b #PA_SOFTINT,MP_FLAGS(a1) + move.l a0,MP_SIGTASK(a1) ;Softint eintragen + + lea VBtimer_name,a0 + moveq #UNIT_MICROHZ,d0 + move.l IVT_IORequest(a2),a1 + moveq #0,d1 + CALLEXEC OpenDevice + tst.l d0 + beq.s .ok + moveq #0,d0 + bra.s .error +.ok ;OK, timer device is ready + st IVT_Init(a2) + moveq #1,d0 ;OK +.error + movem.l (sp)+,d1-a6 + ;ret 0 <= err, >0 = ok + rts + +_ExitIntervalTimer: + ;stop timer.device + movem.l d0-a6,-(sp) + move.l a1,a2 + + sf IVT_Init(a2) + + move.l IVT_IORequest(a2),d5 + beq.s .noIO + tst.b IVT_Runflag(a2) + beq.s .noAbort + st IVT_Stopflag(a2) + ifne 0 + move.l d5,a1 + CALLEXEC WaitIO + else + move.l d5,a1 + move.l IO_DEVICE(a1),a6 + jsr DEV_ABORTIO(A6) ;clear pending requests + endc +.noAbort: + move.l d5,a1 + CALLEXEC CloseDevice + move.l d5,a0 + CALLEXEC DeleteIORequest + clr.l IVT_IORequest(a2) +.noIO: + move.l IVT_Port(a2),d0 + beq.s .noPort + move.l d0,a0 + CALLEXEC DeleteMsgPort + clr.l IVT_Port(a2) +.noPort: + move.l IVT_Signal(a2),d0 + cmp.l #-1,d0 + beq .nosig + CALLEXEC FreeSignal + move.l #-1,IVT_Signal(a2) +.nosig: + movem.l (sp)+,d0-a6 + rts + + +; input: +; A1 = IVT Structure (after init) +; D1 = Number of Microseconds +_StartIntervalTimer: + movem.l d0/a1/a2/a6,-(Sp) + move.l a1,a2 + move.l d1,IVT_Interval(A2) + sf IVT_Stopflag(a2) + + tst.b IVT_Runflag(a2) ;running already ? -> keep it running + bne.s .notimer + move.l a2,a1 + bsr _RestartIntervalTimer +.notimer + movem.l (sp)+,d0/a1/a2/a6 + rts + +; Non-Public +; A1 - IVT Structure +_RestartIntervalTimer: + movem.l d0/a1/a2/a6,-(sp) + move.l a1,a2 + + move.l IVT_IORequest(a2),d0 + beq.s .notimer + + move.l d0,a1 + move.w #TR_ADDREQUEST,IO_COMMAND(a1) + clr.b IO_FLAGS(a1) + clr.l IOTV_TIME+EV_HI(a1) + move.l IVT_Interval(A2),IOTV_TIME+EV_LO(a1) + + move.l IO_DEVICE(a1),a6 + jsr DEV_BEGINIO(A6) + + st IVT_Runflag(a2) +.notimer + movem.l (sp)+,d0/a1/a2/a6 + rts + +_StopIntervalTimer: + movem.l d0-a6,-(Sp) + move.l a1,a2 + + st IVT_Stopflag(a2) + + tst.b IVT_Runflag(a2) + beq.s .noIO + move.l IVT_IORequest(a2),d5 + beq.s .noIO + + move.l d5,a1 + move.l IO_DEVICE(a1),a6 + jsr DEV_ABORTIO(A6) ;clear pending requests + sf IVT_Runflag(a2) +.noIO: + movem.l (sp)+,d0-a6 + rts + + + section data,data +dosbase: dc.l 0 +stdout: dc.l 0 +timerbase: ds.b IVT_Size + +dos_name: dc.b "dos.library",0 +VBtimer_name: dc.b "timer.device",0 +succname: dc.b "success: timer worked",10,0 +failname: dc.b "failure: timer didn't work",10,0 +failtimer: dc.b "timer open failure",10,0 + + END + diff --git a/Driver/enc624j6net/enc624j6net/intervaltimer.h b/Driver/enc624j6net/enc624j6net/intervaltimer.h new file mode 100644 index 0000000..6efd9a2 --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/intervaltimer.h @@ -0,0 +1,56 @@ +/* +****************************************************************************** +* Name: intervaltimer.h * +* Date: $Date: 2016-12-18 22:20:04 +0100 (So, 18. Dez 2016) $ * +* Authors: Henryk Richter * +****************************************************************************** +*/ +#ifndef _INC_INTERVALTIMER_H +#define _INC_INTERVALTIMER_H + +#include +#include +#include +#include +#include + +struct IVT_TimerStruct { + unsigned long IVT_Interval; + long IVT_Signal; + struct Task *IVT_SigTask; + struct MsgPort *IVT_Port; + struct IORequest *IVT_IORequest; + struct Device *IVT_Device; + struct Interrupt IVT_Int; + unsigned char IVT_Init; + unsigned char IVT_Runflag; + unsigned char IVT_Stopflag; + unsigned char IVT_Unused; + unsigned long IVT_Counter; +}; + +#if 1 +#include "asminterface.h" +#else +/* self-contained in here as well */ +#ifdef __SASC +#define ASM __asm +#define ASMR(x) register __ ## x +#define ASMREG(x) +#define SAVEDS __saveds +#else +#define ASM +#define ASMR(x) register +#define ASMREG(x) __asm("" #x "") +#define SAVEDS __saveds +#endif +#endif + +ASM SAVEDS int InitIntervalTimer( ASMR(a1) struct IVT_TimerStruct* IntervalTimer ASMREG(a1) ); +ASM SAVEDS int StartIntervalTimer( ASMR(a1) struct IVT_TimerStruct* IntervalTimer ASMREG(a1), + ASMR(d1) unsigned long Microsecs ASMREG(d1) ); +ASM SAVEDS int StopIntervalTimer( ASMR(a1) struct IVT_TimerStruct* IntervalTimer ASMREG(a1) ); +ASM SAVEDS int ExitIntervalTimer( ASMR(a1) struct IVT_TimerStruct* IntervalTimer ASMREG(a1) ); + + +#endif /* _INC_INTERVALTIMER_H */ diff --git a/Driver/enc624j6net/enc624j6net/intervaltimer.i b/Driver/enc624j6net/enc624j6net/intervaltimer.i new file mode 100644 index 0000000..1a157ec --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/intervaltimer.i @@ -0,0 +1,26 @@ +****************************************************************************** +* Name: intervaltimer.i * +* Date: $Date: 2016-12-18 22:20:04 +0100 (So, 18. Dez 2016) $ * +* Authors: Henryk Richter * +****************************************************************************** + ifnd _INC_INTERVALTIMER_I +_INC_INTERVALTIMER_I EQU 1 + + include exec/types.i + + STRUCTURE IVT_TimerStruct,0 + ULONG IVT_Interval ;<1e6 in microseconds + LONG IVT_Signal ;Signal that is sent back to task from interrupt + APTR IVT_SigTask ;Task that is signaled + APTR IVT_Port + APTR IVT_IORequest + APTR IVT_Device + STRUCT IVT_Int,IS_SIZE ; + BYTE IVT_Init ; !=0 - initialized + BYTE IVT_Runflag ; current status ( !=0 = running ) + BYTE IVT_Stopflag ; stop request if != 0 + BYTE IVT_Unused ; + ULONG IVT_Counter ; Counter (statistics) + LABEL IVT_Size + + endc ;_INC_TIMERTEST_I diff --git a/Driver/enc624j6net/enc624j6net/registers.i b/Driver/enc624j6net/enc624j6net/registers.i new file mode 100755 index 0000000..3d4a01d --- /dev/null +++ b/Driver/enc624j6net/enc624j6net/registers.i @@ -0,0 +1,575 @@ +//////////////////////////////////////////////////// +// ENC424J600/624J600 register addresses // +//////////////////////////////////////////////////// + +; SPI Bank 0 registers -------- +ETXST EQU $7E00 +ETXSTL EQU $7E00 +ETXSTH EQU $7E01 +ETXLEN EQU $7E02 +ETXLENL EQU $7E02 +ETXLENH EQU $7E03 +ERXST EQU $7E04 +ERXSTL EQU $7E04 +ERXSTH EQU $7E05 +ERXTAIL EQU $7E06 +ERXTAILL EQU $7E06 +ERXTAILH EQU $7E07 +ERXHEAD EQU $7E08 +ERXHEADL EQU $7E08 +ERXHEADH EQU $7E09 +EDMAST EQU $7E0A +EDMASTL EQU $7E0A +EDMASTH EQU $7E0B +EDMALEN EQU $7E0C +EDMALENL EQU $7E0C +EDMALENH EQU $7E0D +EDMADST EQU $7E0E +EDMADSTL EQU $7E0E +EDMADSTH EQU $7E0F +EDMACS EQU $7E10 +EDMACSL EQU $7E10 +EDMACSH EQU $7E11 +ETXSTAT EQU $7E12 +ETXSTATL EQU $7E12 +ETXSTATH EQU $7E13 +ETXWIRE EQU $7E14 +ETXWIREL EQU $7E14 +ETXWIREH EQU $7E15 + +; SPI all bank registers +EUDAST EQU $7E16 +EUDASTL EQU $7E16 +EUDASTH EQU $7E17 +EUDAND EQU $7E18 +EUDANDL EQU $7E18 +EUDANDH EQU $7E19 +ESTAT EQU $7E1A +ESTATL EQU $7E1A +ESTATH EQU $7E1B +EIR EQU $7E1C +EIRL EQU $7E1C +EIRH EQU $7E1D +ECON1 EQU $7E1E +ECON1L EQU $7E1E +ECON1H EQU $7E1F + + +; SPI Bank 1 registers ----- +EHT1 EQU $7E20 +EHT1L EQU $7E20 +EHT1H EQU $7E21 +EHT2 EQU $7E22 +EHT2L EQU $7E22 +EHT2H EQU $7E23 +EHT3 EQU $7E24 +EHT3L EQU $7E24 +EHT3H EQU $7E25 +EHT4 EQU $7E26 +EHT4L EQU $7E26 +EHT4H EQU $7E27 +EPMM1 EQU $7E28 +EPMM1L EQU $7E28 +EPMM1H EQU $7E29 +EPMM2 EQU $7E2A +EPMM2L EQU $7E2A +EPMM2H EQU $7E2B +EPMM3 EQU $7E2C +EPMM3L EQU $7E2C +EPMM3H EQU $7E2D +EPMM4 EQU $7E2E +EPMM4L EQU $7E2E +EPMM4H EQU $7E2F +EPMCS EQU $7E30 +EPMCSL EQU $7E30 +EPMCSH EQU $7E31 +EPMO EQU $7E32 +EPMOL EQU $7E32 +EPMOH EQU $7E33 +ERXFCON EQU $7E34 +ERXFCONL EQU $7E34 +ERXFCONH EQU $7E35 + +; SPI all bank registers from 0x36 to 0x3F +; SPI Bank 2 registers ----- +MACON1 EQU $7E40 +MACON1L EQU $7E40 +MACON1H EQU $7E41 +MACON2 EQU $7E42 +MACON2L EQU $7E42 +MACON2H EQU $7E43 +MABBIPG EQU $7E44 +MABBIPGL EQU $7E44 +MABBIPGH EQU $7E45 +MAIPG EQU $7E46 +MAIPGL EQU $7E46 +MAIPGH EQU $7E47 +MACLCON EQU $7E48 +MACLCONL EQU $7E48 +MACLCONH EQU $7E49 +MAMXFL EQU $7E4A +MAMXFLL EQU $7E4A +MAMXFLH EQU $7E4B +MICMD EQU $7E52 +MICMDL EQU $7E52 +MICMDH EQU $7E53 +MIREGADR EQU $7E54 +MIREGADRL EQU $7E54 +MIREGADRH EQU $7E55 + +; SPI all bank registers from 0x56 to 0x5F +; SPI Bank 3 registers ----- +MAADR3 EQU $7E60 +MAADR3L EQU $7E60 +MAADR3H EQU $7E61 +MAADR2 EQU $7E62 +MAADR2L EQU $7E62 +MAADR2H EQU $7E63 +MAADR1 EQU $7E64 +MAADR1L EQU $7E64 +MAADR1H EQU $7E65 +MIWR EQU $7E66 +MIWRL EQU $7E66 +MIWRH EQU $7E67 +MIRD EQU $7E68 +MIRDL EQU $7E68 +MIRDH EQU $7E69 +MISTAT EQU $7E6A +MISTATL EQU $7E6A +MISTATH EQU $7E6B +EPAUS EQU $7E6C +EPAUSL EQU $7E6C +EPAUSH EQU $7E6D +ECON2 EQU $7E6E +ECON2L EQU $7E6E +ECON2H EQU $7E6F +ERXWM EQU $7E70 +ERXWML EQU $7E70 +ERXWMH EQU $7E71 +EIE EQU $7E72 +EIEL EQU $7E72 +EIEH EQU $7E73 +EIDLED EQU $7E74 +EIDLEDL EQU $7E74 +EIDLEDH EQU $7E75 + +; SPI all bank registers from 0x66 to 0x6F + +; SPI Non-banked Special Function Registers +EGPDATA EQU $7E80 +EGPDATAL EQU $7E80 +ERXDATA EQU $7E82 +ERXDATAL EQU $7E82 +EUDADATA EQU $7E84 +EUDADATAL EQU $7E84 +EGPRDPT EQU $7E86 +EGPRDPTL EQU $7E86 +EGPRDPTH EQU $7E87 +EGPWRPT EQU $7E88 +EGPWRPTL EQU $7E88 +EGPWRPTH EQU $7E89 +ERXRDPT EQU $7E8A +ERXRDPTL EQU $7E8A +ERXRDPTH EQU $7E8B +ERXWRPT EQU $7E8C +ERXWRPTL EQU $7E8C +ERXWRPTH EQU $7E8D +EUDARDPT EQU $7E8E +EUDARDPTL EQU $7E8E +EUDARDPTH EQU $7E8F +EUDAWRPT EQU $7E90 +EUDAWRPTL EQU $7E90 +EUDAWRPTH EQU $7E91 + + +;;;;;;;;;;;;;;;;;;;;;;;;;; +; ENC424J600/624J600 register bits +;;;;;;;;;;;;;;;;;;;;;;;;;; +; ESTAT bits ---------- +ESTAT_INT EQU (1<<15) +ESTAT_FCIDLE EQU (1<<14) +ESTAT_RXBUSY EQU (1<<13) +ESTAT_CLKRDY EQU (1<<12) +ESTAT_RSTDONE EQU (1<<11) +ESTAT_PHYDPX EQU (1<<10) +ESTAT_PHYRDY EQU (1<<9) +ESTAT_PHYLNK EQU (1<<8) +ESTAT_PKTCNT7 EQU (1<<7) +ESTAT_PKTCNT6 EQU (1<<6) +ESTAT_PKTCNT5 EQU (1<<5) +ESTAT_PKTCNT4 EQU (1<<4) +ESTAT_PKTCNT3 EQU (1<<3) +ESTAT_PKTCNT2 EQU (1<<2) +ESTAT_PKTCNT1 EQU (1<<1) +ESTAT_PKTCNT0 EQU (1) + +; EIR bits ------------ +EIR_CRYPTEN EQU (1<<15) +EIR_MODEXIF EQU (1<<14) +EIR_HASHIF EQU (1<<13) +EIR_AESIF EQU (1<<12) +EIR_LINKIF EQU (1<<11) +EIR_PRDYIF EQU (1<<10) +EIR_r9 EQU (1<<9) +EIR_r8 EQU (1<<8) +EIR_r7 EQU (1<<7) +EIR_PKTIF EQU (1<<6) +EIR_DMAIF EQU (1<<5) +EIR_r4 EQU (1<<4) +EIR_TXIF EQU (1<<3) +EIR_TXABTIF EQU (1<<2) +EIR_RXABTIF EQU (1<<1) +EIR_PCFULIF EQU (1) + +; ECON1 bits ---------- +ECON1_MODEXST EQU (1<<15) +ECON1_HASHEN EQU (1<<14) +ECON1_HASHOP EQU (1<<13) +ECON1_HASHLST EQU (1<<12) +ECON1_AESST EQU (1<<11) +ECON1_AESOP1 EQU (1<<10) +ECON1_AESOP0 EQU (1<<9) +ECON1_PKTDEC EQU (1<<8) +ECON1_FCOP1 EQU (1<<7) +ECON1_FCOP0 EQU (1<<6) +ECON1_DMAST EQU (1<<5) +ECON1_DMACPY EQU (1<<4) +ECON1_DMACSSD EQU (1<<3) +ECON1_DMANOCS EQU (1<<2) +ECON1_TXRTS EQU (1<<1) +ECON1_RXEN EQU (1) + +; ETXSTAT bits -------- +ETXSTAT_r12 EQU (1<<12) +ETXSTAT_r11 EQU (1<<11) +ETXSTAT_LATECOL EQU (1<<10) +ETXSTAT_MAXCOL EQU (1<<9) +ETXSTAT_EXDEFER EQU (1<<8) +ETXSTAT_DEFER EQU (1<<7) +ETXSTAT_r6 EQU (1<<6) +ETXSTAT_r5 EQU (1<<5) +ETXSTAT_CRCBAD EQU (1<<4) +ETXSTAT_COLCNT3 EQU (1<<3) +ETXSTAT_COLCNT2 EQU (1<<2) +ETXSTAT_COLCNT1 EQU (1<<1) +ETXSTAT_COLCNT0 EQU (1) + +; ERXFCON bits -------- +ERXFCON_HTEN EQU (1<<15) +ERXFCON_MPEN EQU (1<<14) +ERXFCON_NOTPM EQU (1<<12) +ERXFCON_PMEN3 EQU (1<<11) +ERXFCON_PMEN2 EQU (1<<10) +ERXFCON_PMEN1 EQU (1<<9) +ERXFCON_PMEN0 EQU (1<<8) +ERXFCON_CRCEEN EQU (1<<7) +ERXFCON_CRCEN EQU (1<<6) +ERXFCON_RUNTEEN EQU (1<<5) +ERXFCON_RUNTEN EQU (1<<4) +ERXFCON_UCEN EQU (1<<3) +ERXFCON_NOTMEEN EQU (1<<2) +ERXFCON_MCEN EQU (1<<1) +ERXFCON_BCEN EQU (1) + +; MACON1 bits --------- +MACON1_r15 EQU (1<<15) +MACON1_r14 EQU (1<<14) +MACON1_r11 EQU (1<<11) +MACON1_r10 EQU (1<<10) +MACON1_r9 EQU (1<<9) +MACON1_r8 EQU (1<<8) +MACON1_LOOPBK EQU (1<<4) +MACON1_r3 EQU (1<<3) +#define MACON1_RXPAUS EQU (1<<2) +#define MACON1_PASSALL EQU (1<<1) +MACON1_r0 EQU (1) + +; MACON2 bits --------- +#define MACON2_DEFER EQU (1<<14) +#define MACON2_BPEN EQU (1<<13) +#define MACON2_NOBKOFF EQU (1<<12) +MACON2_r9 EQU (1<<9) +MACON2_r8 EQU (1<<8) +#define MACON2_PADCFG2 EQU (1<<7) +#define MACON2_PADCFG1 EQU (1<<6) +#define MACON2_PADCFG0 EQU (1<<5) +#define MACON2_TXCRCEN EQU (1<<4) +#define MACON2_PHDREN EQU (1<<3) +#define MACON2_HFRMEN EQU (1<<2) +MACON2_r1 EQU (1<<1) +#define MACON2_FULDPX EQU (1) + +; MABBIPG bits -------- +MABBIPG_BBIPG6 EQU (1<<6) +MABBIPG_BBIPG5 EQU (1<<5) +MABBIPG_BBIPG4 EQU (1<<4) +MABBIPG_BBIPG3 EQU (1<<3) +MABBIPG_BBIPG2 EQU (1<<2) +MABBIPG_BBIPG1 EQU (1<<1) +MABBIPG_BBIPG0 EQU (1) + +; MAIPG bits ---------- +MAIPG_r14 EQU (1<<14) +MAIPG_r13 EQU (1<<13) +MAIPG_r12 EQU (1<<12) +MAIPG_r11 EQU (1<<11) +MAIPG_r10 EQU (1<<10) +MAIPG_r9 EQU (1<<9) +MAIPG_r8 EQU (1<<8) +MAIPG_IPG6 EQU (1<<6) +MAIPG_IPG5 EQU (1<<5) +MAIPG_IPG4 EQU (1<<4) +MAIPG_IPG3 EQU (1<<3) +MAIPG_IPG2 EQU (1<<2) +MAIPG_IPG1 EQU (1<<1) +MAIPG_IPG0 EQU (1) + +; MACLCON bits -------- +MACLCON_r13 EQU (1<<13) +MACLCON_r12 EQU (1<<12) +MACLCON_r11 EQU (1<<11) +MACLCON_r10 EQU (1<<10) +MACLCON_r9 EQU (1<<9) +MACLCON_r8 EQU (1<<8) +MACLCON_MAXRET3 EQU (1<<3) +MACLCON_MAXRET2 EQU (1<<2) +MACLCON_MAXRET1 EQU (1<<1) +MACLCON_MAXRET0 EQU (1) + +; MICMD bits ---------- +#define MICMD_MIISCAN EQU (1<<1) +#define MICMD_MIIRD EQU (1) + +; MIREGADR bits ------- +MIREGADR_r12 EQU (1<<12) +MIREGADR_r11 EQU (1<<11) +MIREGADR_r10 EQU (1<<10) +MIREGADR_r9 EQU (1<<9) +MIREGADR_r8 EQU (1<<8) +MIREGADR_PHREG4 EQU (1<<4) +MIREGADR_PHREG3 EQU (1<<3) +MIREGADR_PHREG2 EQU (1<<2) +MIREGADR_PHREG1 EQU (1<<1) +MIREGADR_PHREG0 EQU (1) + +; MISTAT bits --------- +MISTAT_r3 EQU (1<<3) +#define MISTAT_NVALID EQU (1<<2) +#define MISTAT_SCAN EQU (1<<1) +#define MISTAT_BUSY EQU (1) + +; ECON2 bits ---------- +ECON2_ETHEN EQU (1<<15) +ECON2_STRCH EQU (1<<14) +ECON2_TXMAC EQU (1<<13) +ECON2_SHA1MD5 EQU (1<<12) +ECON2_COCON3 EQU (1<<11) +ECON2_COCON2 EQU (1<<10) +ECON2_COCON1 EQU (1<<9) +ECON2_COCON0 EQU (1<<8) +ECON2_AUTOFC EQU (1<<7) +ECON2_TXRST EQU (1<<6) +ECON2_RXRST EQU (1<<5) +ECON2_ETHRST EQU (1<<4) +ECON2_MODLEN1 EQU (1<<3) +ECON2_MODLEN0 EQU (1<<2) +ECON2_AESLEN1 EQU (1<<1) +ECON2_AESLEN0 EQU (1) + +; ERXWM bits ---------- +ERXWM_RXFWM7 EQU (1<<15) +ERXWM_RXFWM6 EQU (1<<14) +ERXWM_RXFWM5 EQU (1<<13) +ERXWM_RXFWM4 EQU (1<<12) +ERXWM_RXFWM3 EQU (1<<11) +ERXWM_RXFWM2 EQU (1<<10) +ERXWM_RXFWM1 EQU (1<<9) +ERXWM_RXFWM0 EQU (1<<8) +ERXWM_RXEWM7 EQU (1<<7) +ERXWM_RXEWM6 EQU (1<<6) +ERXWM_RXEWM5 EQU (1<<5) +ERXWM_RXEWM4 EQU (1<<4) +ERXWM_RXEWM3 EQU (1<<3) +ERXWM_RXEWM2 EQU (1<<2) +ERXWM_RXEWM1 EQU (1<<1) +ERXWM_RXEWM0 EQU (1) + +; EIE bits ------------ +EIE_INTIE EQU (1<<15) +EIE_MODEXIE EQU (1<<14) +EIE_HASHIE EQU (1<<13) +EIE_AESIE EQU (1<<12) +EIE_LINKIE EQU (1<<11) +EIE_PRDYIE EQU (1<<10) +EIE_r9 EQU (1<<9) +EIE_r8 EQU (1<<8) +EIE_r7 EQU (1<<7) +EIE_PKTIE EQU (1<<6) +EIE_DMAIE EQU (1<<5) +EIE_r4 EQU (1<<4) +EIE_TXIE EQU (1<<3) +EIE_TXABTIE EQU (1<<2) +EIE_RXABTIE EQU (1<<1) +EIE_PCFULIE EQU (1) + +; EIDLED bits --------- +EIDLED_LACFG3 EQU (1<<15) +EIDLED_LACFG2 EQU (1<<14) +EIDLED_LACFG1 EQU (1<<13) +EIDLED_LACFG0 EQU (1<<12) +EIDLED_LBCFG3 EQU (1<<11) +EIDLED_LBCFG2 EQU (1<<10) +EIDLED_LBCFG1 EQU (1<<9) +EIDLED_LBCFG0 EQU (1<<8) +EIDLED_DEVID2 EQU (1<<7) +EIDLED_DEVID1 EQU (1<<6) +EIDLED_DEVID0 EQU (1<<5) +EIDLED_REVID4 EQU (1<<4) +EIDLED_REVID3 EQU (1<<3) +EIDLED_REVID2 EQU (1<<2) +EIDLED_REVID1 EQU (1<<1) +EIDLED_REVID0 EQU (1) + +; PHCON1 bits --------- +PHCON1_PRST EQU (1<<15) +PHCON1_PLOOPBK EQU (1<<14) +PHCON1_SPD100 EQU (1<<13) +PHCON1_ANEN EQU (1<<12) +PHCON1_PSLEEP EQU (1<<11) +PHCON1_r10 EQU (1<<10) +PHCON1_RENEG EQU (1<<9) +PHCON1_PFULDPX EQU (1<<8) +PHCON1_r7 EQU (1<<7) +PHCON1_r6 EQU (1<<6) +PHCON1_r5 EQU (1<<5) +PHCON1_r4 EQU (1<<4) +PHCON1_r3 EQU (1<<3) +PHCON1_r2 EQU (1<<2) +PHCON1_r1 EQU (1<<1) +PHCON1_r0 EQU (1) + +; PHSTAT1 bits -------- +PHSTAT1_r15 EQU (1<<15) +PHSTAT1_FULL100 EQU (1<<14) +PHSTAT1_HALF100 EQU (1<<13) +PHSTAT1_FULL10 EQU (1<<12) +PHSTAT1_HALF10 EQU (1<<11) +PHSTAT1_r10 EQU (1<<10) +PHSTAT1_r9 EQU (1<<9) +PHSTAT1_r8 EQU (1<<8) +PHSTAT1_r7 EQU (1<<7) +PHSTAT1_r6 EQU (1<<6) +PHSTAT1_ANDONE EQU (1<<5) +PHSTAT1_LRFAULT EQU (1<<4) +PHSTAT1_ANABLE EQU (1<<3) +PHSTAT1_LLSTAT EQU (1<<2) +PHSTAT1_r1 EQU (1<<1) +PHSTAT1_EXTREGS EQU (1) + +; PHANA bits ---------- +PHANA_ADNP EQU (1<<15) +PHANA_r14 EQU (1<<14) +PHANA_ADFAULT EQU (1<<13) +PHANA_r12 EQU (1<<12) +PHANA_ADPAUS1 EQU (1<<11) +PHANA_ADPAUS0 EQU (1<<10) +PHANA_r9 EQU (1<<9) +PHANA_AD100FD EQU (1<<8) +PHANA_AD100 EQU (1<<7) +PHANA_AD10FD EQU (1<<6) +PHANA_AD10 EQU (1<<5) +PHANA_ADIEEE4 EQU (1<<4) +PHANA_ADIEEE3 EQU (1<<3) +PHANA_ADIEEE2 EQU (1<<2) +PHANA_ADIEEE1 EQU (1<<1) +PHANA_ADIEEE0 EQU (1) + +; PHANLPA bits -------- +PHANLPA_LPNP EQU (1<<15) +PHANLPA_LPACK EQU (1<<14) +PHANLPA_LPFAULT EQU (1<<13) +PHANLPA_r12 EQU (1<<12) +PHANLPA_LPPAUS1 EQU (1<<11) +PHANLPA_LPPAUS0 EQU (1<<10) +PHANLPA_LP100T4 EQU (1<<9) +PHANLPA_LP100FD EQU (1<<8) +PHANLPA_LP100 EQU (1<<7) +PHANLPA_LP10FD EQU (1<<6) +PHANLPA_LP10 EQU (1<<5) +PHANLPA_LPIEEE4 EQU (1<<4) +PHANLPA_LPIEEE3 EQU (1<<3) +PHANLPA_LPIEEE2 EQU (1<<2) +PHANLPA_LPIEEE1 EQU (1<<1) +PHANLPA_LPIEEE0 EQU (1) + +; PHANE bits ---------- +PHANE_r15 EQU (1<<15) +PHANE_r14 EQU (1<<14) +PHANE_r13 EQU (1<<13) +PHANE_r12 EQU (1<<12) +PHANE_r11 EQU (1<<11) +PHANE_r10 EQU (1<<10) +PHANE_r9 EQU (1<<9) +PHANE_r8 EQU (1<<8) +PHANE_r7 EQU (1<<7) +PHANE_r6 EQU (1<<6) +PHANE_r5 EQU (1<<5) +PHANE_PDFLT EQU (1<<4) +PHANE_r3 EQU (1<<3) +PHANE_r2 EQU (1<<2) +PHANE_LPARCD EQU (1<<1) +PHANA_LPANABL EQU (1) + +; PHCON2 bits --------- +PHCON2_r15 EQU (1<<15) +PHCON2_r14 EQU (1<<14) +PHCON2_EDPWRDN EQU (1<<13) +PHCON2_r12 EQU (1<<12) +PHCON2_EDTHRES EQU (1<<11) +PHCON2_r10 EQU (1<<10) +PHCON2_r9 EQU (1<<9) +PHCON2_r8 EQU (1<<8) +PHCON2_r7 EQU (1<<7) +PHCON2_r6 EQU (1<<6) +PHCON2_r5 EQU (1<<5) +PHCON2_r4 EQU (1<<4) +PHCON2_r3 EQU (1<<3) +PHCON2_FRCLNK EQU (1<<2) +PHCON2_EDSTAT EQU (1<<1) +PHCON2_r0 EQU (1) + +; PHSTAT2 bits --------- +PHSTAT2_r15 EQU (1<<15) +PHSTAT2_r14 EQU (1<<14) +PHSTAT2_r13 EQU (1<<13) +PHSTAT2_r12 EQU (1<<12) +PHSTAT2_r11 EQU (1<<11) +PHSTAT2_r10 EQU (1<<10) +PHSTAT2_r9 EQU (1<<9) +PHSTAT2_r8 EQU (1<<8) +PHSTAT2_r7 EQU (1<<7) +PHSTAT2_r6 EQU (1<<6) +PHSTAT2_r5 EQU (1<<5) +PHSTAT2_PLRITY EQU (1<<4) +PHSTAT2_r3 EQU (1<<3) +PHSTAT2_r2 EQU (1<<2) +PHSTAT2_r1 EQU (1<<1) +PHSTAT2_r0 EQU (1) + +; PHSTAT3 bits -------- +PHSTAT3_r15 EQU (1<<15) +PHSTAT3_r14 EQU (1<<14) +PHSTAT3_r13 EQU (1<<13) +PHSTAT3_r12 EQU (1<<12) +PHSTAT3_r11 EQU (1<<11) +PHSTAT3_r10 EQU (1<<10) +PHSTAT3_r9 EQU (1<<9) +PHSTAT3_r8 EQU (1<<8) +PHSTAT3_r7 EQU (1<<7) +PHSTAT3_r6 EQU (1<<6) +PHSTAT3_r5 EQU (1<<5) +PHSTAT3_SPDDPX2 EQU (1<<4) +PHSTAT3_SPDDPX1 EQU (1<<3) +PHSTAT3_SPDDPX0 EQU (1<<2) +PHSTAT3_r1 EQU (1<<1) +PHSTAT3_r0 EQU (1) diff --git a/Driver/enc624j6net/global.h b/Driver/enc624j6net/global.h new file mode 100644 index 0000000..fd431ee --- /dev/null +++ b/Driver/enc624j6net/global.h @@ -0,0 +1,188 @@ +#ifndef __GLOBAL_H +#define __GLOBAL_H + + /* system header files */ +#ifndef DEVICES_SANA2_H +#include +#endif +#ifndef EXEC_SEMAPHORES_H +#include +#endif +#ifndef EXEC_LISTS_H +#include +#endif +#ifndef EXEC_INTERRUPTS_H +#include +#endif +#ifndef EXEC_LIBRARIES_H +#include +#endif +#ifndef DOS_DOS_H +#include +#endif + +#ifndef __COMPILER_H +#include "compiler.h" +#endif +#ifndef __HW_H +#include "hw.h" +#endif + + +/****************************************************************************/ + + /* return val, cut to min or max if exceeding range */ +#define BOUNDS(val, min, max) ((val) <= (max) ? ((val) >= (min) ? (val) :\ + (min)) : (max)) + + /* memory economy is *everything* :-) */ +#define SERVERTASKNAME pb->pb_DevNode.lib_Node.ln_Name + +struct TrackRec { + struct MinNode tr_Link; + ULONG tr_PacketType; + ULONG tr_Count; + struct Sana2PacketTypeStats tr_Sana2PacketTypeStats; +}; + + +/****************************************************************************/ + + +typedef BOOL (* ASM BMFunc)(REG(a0) void *, REG(a1) void *, REG(d0) LONG); + +struct BufferManagement +{ + struct MinNode bm_Node; + BMFunc bm_CopyFromBuffer; + BMFunc bm_CopyToBuffer; +}; + + +/****************************************************************************/ + + + /* + ** sent to the server task after being CreateNewProc()ed + */ +struct ServerStartup +{ + struct Message ss_Msg; + struct PLIPBase *ss_PLIPBase; + BOOL ss_Error; + UBYTE ss_Pad[2]; +}; + + + +/****************************************************************************/ + + +enum { S2SS_TXERRORS, S2SS_COLLISIONS, S2SS_COUNT }; + + + /* + ** This count will record the number of packets that failed + ** to be transmitted. + */ +#define S2SS_PLIP_TXERRORS ((((S2WireType_Ethernet) & 0xffff) << 16) | (S2SS_TXERRORS)) + + /* + ** This count will record the number of line arbitration collisions + */ +#define S2SS_PLIP_COLLISIONS ((((S2WireType_Ethernet) & 0xffff) << 16) | (S2SS_COLLISIONS)) + + +/****************************************************************************/ + + +struct PLIPBase +{ + struct Library pb_DevNode; /* basic device structure */ + UBYTE pb_Unit; /* unit of 1st OpenDevice() */ + UBYTE pb_pad1; /* make the following long alligned */ + BPTR pb_SegList; /* pointer to code */ + struct Library * pb_VampireBase; + struct Library * pb_ExpansionBase; + struct Library * pb_UtilityBase; + struct Library * pb_DOSBase; + struct Library * pb_SysBase; + struct ServerStartup * pb_Startup; /* main server proces */ + struct Process * pb_Server; /* main server proces */ + struct Task * pb_Task; /* used for server shutdown */ + ULONG pb_ServerStoppedSigMask; /* for shutdown */ + struct MsgPort * pb_ServerPort; /* for IOReq forwarding */ + struct Sana2DeviceStats pb_DevStats; /* SANA-2 wants this */ + struct Sana2SpecialStatRecord + pb_SpecialStats[S2SS_COUNT]; + volatile struct List pb_ReadList, /* the readers */ + pb_WriteList, /* the writers */ + pb_EventList, /* event tracking */ + pb_ReadOrphanList, /* for spurious packets */ + pb_TrackList, /* track type */ + pb_BufferManagement; /* Copy-In/Out */ + struct SignalSemaphore pb_EventListSem, /* protection for lists */ + pb_ReadListSem, + pb_WriteListSem, + pb_TrackListSem, + pb_ReadOrphanListSem, + pb_Lock; + + LONG pb_ExpansionPort; /* allocated expansion port */ + volatile UBYTE pb_Flags; /* see below */ + UBYTE pb_pad2; + volatile UWORD pb_ExtFlags; /* see below */ + UBYTE pb_CfgAddr[HW_ADDRFIELDSIZE]; + UBYTE pb_DefAddr[HW_ADDRFIELDSIZE]; + struct HWBase pb_HWBase; + struct HWFrame * pb_Frame; + ULONG pb_BPS; + ULONG pb_MTU; +}; + +#ifdef __SASC + /* + ** redirect all shared library bases to our device base. + */ +# define SysBase pb->pb_SysBase +# define DOSBase pb->pb_DOSBase +# define UtilityBase pb->pb_UtilityBase +# define VampireBase pb->pb_VampireBase +# define ExpansionBase pb->pb_ExpansionBase + /* + ** This macro declares a local variable which temporary gets + ** SysBase directly from AbsExecBase. + */ +# define LOCALSYSBASE struct { void *pb_SysBase; } *pb = (void*)0x4 + /* + ** Use this macro as argument for all functions which need to + ** have access to your data base. + */ +# define BASEPTR struct PLIPBase *pb +#else +# error Please define library bases for your compiler +#endif + + /* + ** Values for PLIPBase->pb_Flags + ** Note that the Flags field is intentionally only 8 bits wide so that + ** the ASM parts may use the bit functions. + */ +#define PLIPB_REPLYSS 0 /* server-startup must be replied */ +#define PLIPB_EXCLUSIVE 1 /* current opener is exclusive */ +#define PLIPB_OFFLINE 2 /* currently not online (sic!) */ +#define PLIPB_SERVERSTOPPED 3 /* set by server while passing away */ + +#define PLIPF_REPLYSS (1<pb_ExtFlags + */ +#define PLIPEB_NOSPECIALSTATS 0 /* don't report special stats */ +#define PLIPEF_NOSPECIALSTATS (1< +#include "global.h" + +int main(int argc, char **argv) +{ + printf("libsize equ %d\n", sizeof(struct PLIPBase)); + return 0; +} diff --git a/Driver/enc624j6net/libsize.exe b/Driver/enc624j6net/libsize.exe new file mode 100755 index 0000000..e397fa4 Binary files /dev/null and b/Driver/enc624j6net/libsize.exe differ diff --git a/Driver/enc624j6net/rt.asm b/Driver/enc624j6net/rt.asm new file mode 100644 index 0000000..f9caf5e --- /dev/null +++ b/Driver/enc624j6net/rt.asm @@ -0,0 +1,88 @@ + IFND EXEC_NODES_I + INCLUDE "exec/nodes.i" + ENDC + IFND EXEC_RESIDENT_I + INCLUDE "exec/resident.i" + ENDC + IFND EXEC_INITIALIZERS_I + INCLUDE "exec/initializers.i" + ENDC + IFND EXEC_LIBRARIES_I + INCLUDE "exec/libraries.i" + ENDC + IFND DOS_DOS_I + INCLUDE "dos/dos.i" + ENDC + + include "libsize.auto.i" + include "dev_info.i" + + xref _DevInit + + xref _DevOpen + xref _DevClose + xref _DevExpunge + xref _DevExtFunc + xref _DevBeginIO + xref _DevAbortIO + + section "text",code + + moveq #RETURN_FAIL,d0 + rts + +romtag: + dc.w RTC_MATCHWORD + dc.l romtag + dc.l endskip + dc.b RTF_AUTOINIT + dc.b DEVICE_VERSION + dc.b NT_DEVICE + dc.b 0 ; priority + dc.l devname + dc.l devid + dc.l inittable + +devname: + DEVICE_NAME + dc.b ".device",0 + dc.b 0,'$VER: ' +devid: + DEVICE_NAME + dc.b " " + DEVICE_VER + dc.b " (" + DEVICE_DATE + dc.b ")",13,10,0 + + cnop 0,2 + +inittable: + dc.l libsize + dc.l functable,datatable,_DevInit + +functable: + dc.l _DevOpen + dc.l _DevClose + dc.l _DevExpunge + dc.l stub + dc.l _DevBeginIO + dc.l _DevAbortIO + dc.l -1 + +datatable: + INITBYTE LN_TYPE,NT_DEVICE + INITLONG LN_NAME,devname + INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED + INITWORD LIB_VERSION,DEVICE_VERSION + INITWORD LIB_REVISION,DEVICE_REVISION + INITLONG LIB_IDSTRING,devid + dc.w 0 + +stub: + moveq #0,d0 + rts + +endskip: + + END diff --git a/Driver/enc624j6net/server.c b/Driver/enc624j6net/server.c new file mode 100755 index 0000000..3c04e50 --- /dev/null +++ b/Driver/enc624j6net/server.c @@ -0,0 +1,759 @@ +#define DEBUG 0 + +/*F*/ /* includes */ +#ifndef CLIB_EXEC_PROTOS_H +#include +#include +#endif +#ifndef CLIB_DOS_PROTOS_H +#include +#include +#endif + +#ifndef EXEC_MEMORY_H +#include +#endif + +#ifndef DEVICES_SANA2_H +#include +#endif + +#ifndef CLIB_TIME_PROTOS_H +#include +#include +#endif + +#ifndef _STRING_H +#include +#endif + +#ifndef __GLOBAL_H +#include "global.h" +#endif +#ifndef __DEBUG_H +#include "debug.h" +#endif +#ifndef __COMPILER_H +#include "compiler.h" +#endif +#ifndef __HW_H +#include "hw.h" +#endif +/*E*/ + +/*F*/ /* defines, types and enums */ + + /* + ** return codes for write_frame() + */ +typedef enum { AW_OK, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT; + +/*E*/ +/*F*/ /* imports */ + /* external functions */ +GLOBAL VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd); +GLOBAL VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2); +/*E*/ +/*F*/ /* exports */ +PUBLIC VOID SAVEDS ServerTask(void); +/*E*/ +/*F*/ /* private */ +PRIVATE struct PLIPBase *startup(void); +PRIVATE REGARGS VOID DoEvent(BASEPTR, long event); +PRIVATE VOID readargs(BASEPTR); +PRIVATE BOOL init(BASEPTR); +PRIVATE REGARGS BOOL goonline(BASEPTR); +PRIVATE REGARGS VOID gooffline(BASEPTR); +PRIVATE REGARGS AW_RESULT write_frame(BASEPTR, struct IOSana2Req *ios2); +PRIVATE REGARGS VOID dowritereqs(BASEPTR); +PRIVATE REGARGS VOID doreadreqs(BASEPTR); +PRIVATE REGARGS VOID dos2reqs(BASEPTR); +/*E*/ + + /* + ** functions to go online/offline + */ +/*F*/ PRIVATE REGARGS VOID rejectpackets(BASEPTR) +{ + struct IOSana2Req *ios2; + + ObtainSemaphore(&pb->pb_WriteListSem); + while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList)) + { + ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE; + ios2->ios2_WireError = S2WERR_UNIT_OFFLINE; + DevTermIO(pb,ios2); + } + ReleaseSemaphore(&pb->pb_WriteListSem); + + ObtainSemaphore(&pb->pb_ReadListSem); + while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList)) + { + ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE; + ios2->ios2_WireError = S2WERR_UNIT_OFFLINE; + DevTermIO(pb,ios2); + } + ReleaseSemaphore(&pb->pb_ReadListSem); + + ObtainSemaphore(&pb->pb_ReadOrphanListSem); + while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList)) + { + ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE; + ios2->ios2_WireError = S2WERR_UNIT_OFFLINE; + DevTermIO(pb,ios2); + } + ReleaseSemaphore(&pb->pb_ReadOrphanListSem); +} +/*E*/ + +/*F*/ PRIVATE REGARGS BOOL goonline(BASEPTR) +{ + BOOL rc = TRUE; + + d(("trying to go online\n")); + + if (pb->pb_Flags & PLIPF_OFFLINE) + { + if (!hw_attach(pb)) + { + d(("error going online\n")); + rc = FALSE; + } + else + { + struct HWBase *hwb = &pb->pb_HWBase; + + /* send magic */ + hw_send_magic_pkt(pb, HW_MAGIC_ONLINE); + + GetSysTime(&pb->pb_DevStats.LastStart); + pb->pb_Flags &= ~PLIPF_OFFLINE; + DoEvent(pb, S2EVENT_ONLINE); + d(("i'm now online!\n")); + } + } + + return rc; +} +/*E*/ +/*F*/ PRIVATE REGARGS VOID gooffline(BASEPTR) +{ + if (!(pb->pb_Flags & PLIPF_OFFLINE)) + { + hw_send_magic_pkt(pb, HW_MAGIC_OFFLINE); + + hw_detach(pb); + + pb->pb_Flags |= PLIPF_OFFLINE; + + DoEvent(pb, S2EVENT_OFFLINE); + } + d(("ok!\n")); +} +/*E*/ + + /* + ** SANA-2 Event management + */ +/*F*/ PRIVATE REGARGS VOID DoEvent(BASEPTR, long event) +{ + struct IOSana2Req *ior, *ior2; + + d(("event is %lx\n",event)); + + ObtainSemaphore(&pb->pb_EventListSem ); + + for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head; + ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ; + ior = ior2 ) + { + if (ior->ios2_WireError & event) + { + Remove((struct Node*)ior); + DevTermIO(pb, ior); + } + } + + ReleaseSemaphore(&pb->pb_EventListSem ); +} +/*E*/ + + /* + ** writing packets + */ +/*F*/ PRIVATE REGARGS AW_RESULT write_frame(BASEPTR, struct IOSana2Req *ios2) +{ + AW_RESULT rc; + struct HWFrame *frame = pb->pb_Frame; + struct BufferManagement *bm; + UBYTE *frame_ptr; + + d(("write: type %08lx, size %ld\n",ios2->ios2_PacketType, + ios2->ios2_DataLength)); + + /* copy raw frame: simply overwrite ethernet frame part of plip packet */ + if(ios2->ios2_Req.io_Flags & SANA2IOF_RAW) { + frame->hwf_Size = ios2->ios2_DataLength; + frame_ptr = &frame->hwf_DstAddr[0]; + } else { + frame->hwf_Size = ios2->ios2_DataLength + HW_ETH_HDR_SIZE; + frame->hwf_Type = (USHORT)ios2->ios2_PacketType; + memcpy(frame->hwf_SrcAddr, pb->pb_CfgAddr, HW_ADDRFIELDSIZE); + memcpy(frame->hwf_DstAddr, ios2->ios2_DstAddr, HW_ADDRFIELDSIZE); + frame_ptr = (UBYTE *)(frame + 1); + } + + bm = (struct BufferManagement *)ios2->ios2_BufferManagement; + + if (!(*bm->bm_CopyFromBuffer)(frame_ptr, + ios2->ios2_Data, ios2->ios2_DataLength)) + { + rc = AW_BUFFER_ERROR; + } + else + { + d8(("+hw_send\n")); + rc = hw_send_frame(pb, frame) ? AW_OK : AW_ERROR; + d8(("-hw_send\n")); +#if DEBUG&8 + if(rc==AW_ERROR) d8(("Error sending packet (size=%ld)\n", (LONG)pb->pb_Frame->hwf_Size)); +#endif + } + + return rc; +} +/*E*/ +/*F*/ PRIVATE REGARGS VOID dowritereqs(BASEPTR) +{ + struct IOSana2Req *currentwrite, *nextwrite; + AW_RESULT code; + + ObtainSemaphore(&pb->pb_WriteListSem); + + for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head; + nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ; + currentwrite = nextwrite ) + { +/* + if (hw_recv_pending(pb)) + { + d(("incoming data!")); + break; + } +*/ + code = write_frame(pb, currentwrite); + + if (code == AW_BUFFER_ERROR) /* BufferManagement callback error */ + { + d(("buffer error\n")); + DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE); + pb->pb_SpecialStats[S2SS_TXERRORS].Count++; + d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count)); + currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE; + currentwrite->ios2_WireError = S2WERR_BUFF_ERROR; + Remove((struct Node*)currentwrite); + DevTermIO(pb, currentwrite); + } + else if (code == AW_ERROR) + { + /* + ** this is a real line error, upper levels (e.g. Internet TCP) have + ** to care for reliability! + */ + d(("error while transmitting packet\n")); + DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE); + pb->pb_SpecialStats[S2SS_TXERRORS].Count++; + d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count)); + currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE; + currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR; + Remove((struct Node*)currentwrite); + DevTermIO(pb, currentwrite); + } + else /*if (code == AW_OK)*/ /* well done! */ + { + d(("packet transmitted successfully\n")); + pb->pb_DevStats.PacketsSent++; + dotracktype(pb, (ULONG) pb->pb_Frame->hwf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0); + currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR; + currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR; + Remove((struct Node*)currentwrite); + DevTermIO(pb, currentwrite); + } + } + + ReleaseSemaphore(&pb->pb_WriteListSem); +} +/*E*/ + +PRIVATE REGARGS BOOL read_frame(struct IOSana2Req *req, struct HWFrame *frame) +{ + int i; + BOOL broadcast; + LONG datasize; + BYTE *frame_ptr; + struct BufferManagement *bm; + BOOL ok; + + /* deliver a raw frame: copy data right into ethernet header */ + if(req->ios2_Req.io_Flags & SANA2IOF_RAW) { + frame_ptr = &frame->hwf_DstAddr[0]; + datasize = frame->hwf_Size; + req->ios2_Req.io_Flags = SANA2IOF_RAW; + } + else { + frame_ptr = (UBYTE *)(frame + 1); + datasize = frame->hwf_Size - HW_ETH_HDR_SIZE; + req->ios2_Req.io_Flags = 0; + } + + req->ios2_DataLength = datasize; + + /* copy packet buffer */ + bm = (struct BufferManagement *)req->ios2_BufferManagement; + if (!(*bm->bm_CopyToBuffer)(req->ios2_Data, frame_ptr, datasize)) + { + d(("CopyToBuffer: error\n")); + req->ios2_Req.io_Error = S2ERR_SOFTWARE; + req->ios2_WireError = S2WERR_BUFF_ERROR; + ok = FALSE; + } + else + { + req->ios2_Req.io_Error = req->ios2_WireError = 0; + ok = TRUE; + } + + /* now extract addresses from ethernet header */ + memcpy(req->ios2_SrcAddr, frame->hwf_SrcAddr, HW_ADDRFIELDSIZE); + memcpy(req->ios2_DstAddr, frame->hwf_DstAddr, HW_ADDRFIELDSIZE); + + /* need to set broadcast flag? */ + broadcast = TRUE; + for(i=0;ihwf_DstAddr[i] != 0xff) { + broadcast = FALSE; + break; + } + } + if(broadcast) { + req->ios2_Req.io_Flags |= SANA2IOF_BCAST; + } + + /* store packet type */ + req->ios2_PacketType = (USHORT)frame->hwf_Type; + + return ok; +} + + /* + ** reading packets + */ +/*F*/ PRIVATE REGARGS VOID doreadreqs(BASEPTR) +{ + LONG datasize; + struct IOSana2Req *got; + ULONG pkttyp = 0; /* just to avoid warning with opt build, irrelevant otherwise */ + BOOL rv; + struct HWFrame *frame = pb->pb_Frame; + + d8(("+hw_recv\n")); + rv = hw_recv_frame(pb, frame); + d8(("-hw_recv\n")); + if (rv) + { + pb->pb_DevStats.PacketsReceived++; + + pkttyp = frame->hwf_Type; + +#if 0 + /* perform internal loop back of magic packets of type 0xfffd */ + if(pkttyp == HW_MAGIC_LOOPBACK) { + d(("loop back packet (size %ld)\n",frame->hwf_Size)); + hw_send_frame(pb, frame); + return; + } + + /* plipbox requests online magic (again) */ + if(pkttyp == HW_MAGIC_ONLINE) { + d(("request online magic")); + hw_send_magic_pkt(pb, HW_MAGIC_ONLINE); + return; + } +#endif + + datasize = frame->hwf_Size - HW_ETH_HDR_SIZE; + + dotracktype(pb, pkttyp, 0, 1, 0, datasize, 0); + + d(("packet %08lx, size %ld received\n",pkttyp,datasize)); + + ObtainSemaphore(&pb->pb_ReadListSem); + + /* traverse the list of read-requests */ + for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head; + got->ios2_Req.io_Message.mn_Node.ln_Succ; + got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ ) + { + /* check if this one requests for the new packet we got */ + if (got->ios2_PacketType == pkttyp ) + { + BOOL ok; + + Remove((struct Node*)got); + + /* deliver packet */ + ok = read_frame(got, frame); + if(!ok) { + DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE); + } + + d(("packet received, satisfying S2Request\n")); + DevTermIO(pb, got); + got = NULL; + break; + } + } + + ReleaseSemaphore(&pb->pb_ReadListSem); + } + else + { + d(("Error receiving (%ld. len=%ld)\n", rv, frame->hwf_Size)); + /* something went wrong during receipt */ + DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX); + got = NULL; + pb->pb_DevStats.BadData++; + } + + /* If no one wanted this packet explicitely, there is one chance + ** left: somebody waiting for orphaned packets. If this fails, too, + ** we will drop it. + */ + if (got) + { + d(("unknown packet\n")); + + pb->pb_DevStats.UnknownTypesReceived++; + + ObtainSemaphore(&pb->pb_ReadOrphanListSem); + got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList); + ReleaseSemaphore(&pb->pb_ReadOrphanListSem); + + if (got) + { + BOOL ok = read_frame(got, frame); + if(!ok) { + DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE); + } + + d(("orphan read\n")); + + DevTermIO(pb, got); + } + else + { + dotracktype(pb, pkttyp, 0, 0, 0, 0, 1); + d(("packet thrown away...\n")); + } + } +} +/*E*/ + + /* + ** 2nd level device command dispatcher (~SANA2IOF_QUICK) + */ +/*F*/ PRIVATE REGARGS VOID dos2reqs(BASEPTR) +{ + struct IOSana2Req *ios2; + + /* + ** Every pending IO message will be GetMsg()'ed and processed. At the + ** end of the loop it will be DevTermIO()'ed back to the sender, + ** _but_only_if_ it is non-NULL. In such cases the message has been + ** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs + ** and similar stuff). + ** You find the same mimique in the 1st level dispatcher (device.c) + */ + while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort)) + { + if (hw_recv_pending(pb)) + { + d(("incoming data!")); + break; + } + + d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command)); + + switch (ios2->ios2_Req.io_Command) + { + case S2_ONLINE: + if (!goonline(pb)) + { + ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES; + ios2->ios2_WireError = S2WERR_GENERIC_ERROR; + } + break; + + case S2_OFFLINE: + gooffline(pb); + rejectpackets(pb); /* reject all pending requests */ + break; + + case S2_CONFIGINTERFACE: + /* copy address from src addr */ + memcpy(pb->pb_CfgAddr, ios2->ios2_SrcAddr, HW_ADDRFIELDSIZE); + + /* if already online then first go offline */ + if(!(pb->pb_Flags & PLIPF_OFFLINE)) { + gooffline(pb); + } + + /* now go online */ + if (!goonline(pb)) + { + ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES; + ios2->ios2_WireError = S2WERR_GENERIC_ERROR; + } + break; + } + + if (ios2) DevTermIO(pb,ios2); + } +} +/*E*/ + + /* + ** startup,initialisation and termination functions + */ +/*F*/ PRIVATE struct PLIPBase *startup(void) +{ + struct ServerStartup *ss; + struct Process *we; + struct PLIPBase *base; + LOCALSYSBASE; + + we = (struct Process*)FindTask(NULL); + + d(("waiting for startup msg...\n")); + WaitPort(&we->pr_MsgPort); + ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort); + base = ss->ss_PLIPBase; + base->pb_Startup = ss; + d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase)); + + /* we will keep the startup message, to inform mother if we + ** really could come up or if we failed to obtain some + ** resource. + */ + return base; +} +/*E*/ + +#define PLIP_MINPRIORITY -128 +#define PLIP_MAXPRIORITY 127 + +/*F*/ PRIVATE VOID readargs(BASEPTR) +{ + struct RDArgs *rda; + struct TemplateConfig args = { 0 }; + BPTR cfginput, oldinput; + + d(("entered\n")); + + hw_config_init(pb); + + if (cfginput = Open(CONFIGFILE, MODE_OLDFILE)) + { + d(("opened cfg\n")); + oldinput = SelectInput(cfginput); + rda = ReadArgs(COMMON_TEMPLATE TEMPLATE, (LONG *)&args, NULL); + if(rda) + { + d(("got args\n")); + + /* common options */ + if (args.common.priority) + SetTaskPri((struct Task*)pb->pb_Server, + BOUNDS(*args.common.priority, PLIP_MINPRIORITY, PLIP_MAXPRIORITY)); + + if (args.common.nospecialstats) + pb->pb_ExtFlags |= PLIPEF_NOSPECIALSTATS; + + if(args.common.mtu) + pb->pb_MTU = *args.common.mtu; + + if(args.common.bps) + pb->pb_BPS = *args.common.bps; + + /* special config */ + hw_config_update(pb, &args); + + FreeArgs(rda); + } + + Close(SelectInput(oldinput)); + } + + /* dump default config options */ + d(("pri %ld, flags %08lx\n", (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_Flags)); + hw_config_dump(pb); + + d(("left\n")); +} +/*E*/ +/*F*/ PRIVATE BOOL init(BASEPTR) +{ + BOOL rc = FALSE; + + readargs(pb); + + if ((pb->pb_ServerPort = CreateMsgPort())) + { + /* init hardware */ + if(hw_init(pb)) { + ULONG size = (ULONG)sizeof(struct HWFrame); + + if( pb->pb_MTU > 1518 ) + size += pb->pb_MTU + 16; + else size += 1518 + 4; + + d(("allocating 0x%lx/%ld bytes frame buffer\n",size,size)); + if ((pb->pb_Frame = AllocVec(size, MEMF_CLEAR|MEMF_ANY))) + { + rc = TRUE; + } + else + { + d(("couldn't allocate frame buffer\n")); + } + } + else + { + d(("hw init failed\n")); + } + } + else + { + d(("no server port\n")); + } + + d(("left %ld\n",rc)); + + return rc; +} +/*E*/ +/*F*/ PRIVATE VOID cleanup(BASEPTR) +{ + struct BufferManagement *bm; + + gooffline(pb); + + while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement)) + FreeVec(bm); + + if (pb->pb_Frame) FreeVec(pb->pb_Frame); + + hw_cleanup(pb); + + if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort); + + if (pb->pb_Flags & PLIPF_REPLYSS) + { + Forbid(); + ReplyMsg((struct Message*)pb->pb_Startup); + } +} +/*E*/ + + /* + ** entry point, mainloop + */ +/*F*/ PUBLIC VOID SAVEDS ServerTask(void) +{ + BASEPTR; + + d(("server running\n")); + + if (pb = startup()) + { + /* if we fail to allocate all resources, this flag reminds cleanup() + ** to ReplyMsg() the startup message + */ + pb->pb_Flags |= PLIPF_REPLYSS; + + if (init(pb)) + { + ULONG recv=0, portsigmask, recvsigmask, wmask; + BOOL running; + + /* Ok, we are fine and will tell this mother personally :-) */ + pb->pb_Startup->ss_Error = 0; + /* don't forget this, or we will have to keep a warm place */ + /* in our coffin for the system */ + pb->pb_Flags &= ~PLIPF_REPLYSS; + ReplyMsg((struct Message*)pb->pb_Startup); + + portsigmask = 1 << pb->pb_ServerPort->mp_SigBit; + recvsigmask = hw_recv_sigmask(pb); + + wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | portsigmask | recvsigmask; + + /* main loop of server task */ + d(("--- server main loop: %08lx ---\n", wmask)); + for(running=TRUE;running;) + { + d4(("** wmask is 0x%08lx\n", wmask)); + + /* if no recv is pending then wait for incoming signals */ + if (!hw_recv_pending(pb)) { + d2(("**> wait\n")); + recv = Wait(wmask); + d2(("**> wait: got 0x%08lx\n", recv)); + } + + /* accept pending receive and start reading */ + if (hw_recv_pending(pb)) + { + d2(("*+ do_read\n")); + doreadreqs(pb); + d2(("*- do_read\n")); + } + + /* send packets if any */ + d2(("*+ do_write\n")); + dowritereqs(pb); + d2(("*- do_write\n")); + + /* handle SANA-II send requests */ + if (recv & portsigmask) + { + d(("SANA-II request(s)\n")); + dos2reqs(pb); + } + + /* stop server task */ + if (recv & SIGBREAKF_CTRL_C) + { + d(("received break signal\n")); + running = FALSE; + } + } + } + else + d(("init() failed\n")); + + d(("--- server exit main loop ---\n")); + cleanup(pb); + + /* Exec will enable it's scheduler after we're dead. */ + Forbid(); + /* signal mother we're done */ + if (pb->pb_ServerStoppedSigMask) + Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask); + pb->pb_Flags |= PLIPF_SERVERSTOPPED; + } + else + d(("no startup packet\n")); +} +/*E*/ + diff --git a/Driver/enc624j6net/smakefile b/Driver/enc624j6net/smakefile new file mode 100644 index 0000000..56e3061 --- /dev/null +++ b/Driver/enc624j6net/smakefile @@ -0,0 +1,247 @@ +#sc:c/smake +# +##################################################################### +# +# $VER: smakefile 0.8 (09-Jan-2017) +# Henryk Richter +# +# based on Magplip build file +##################################################################### +# +DEVICE_DATE = 18.12.2017 +DEVICE_VERSION = 0 +DEVICE_REVISION = 1 + +# see below for EXTRAOBJ, disable for plipbox, enable for sdnet/enc624j6net +HWSRCDIR = enc624j6net +DEVICE_NAME = enc624j6net +DEFS = DEFINE PROTO_ENC624NET=1 + +##################################################################### +# +# I keep various include trees, so for this project I directly reference +# the SAS/C installation for include paths +# The ASM stuff assumes the library offsets in "lvo/*", change if +# desired +# +LIBS = LIB sc:LIB/amiga.lib LIB sc:lib/sc.lib LIB sc:lib/debug.lib +CINCLUDES = INCDIR="sc:include" INCDIR="sc:netinclude" INCDIR="$(HWSRCDIR)" +#ASMINCLUDES = INCDIR="INCLUDE:" $(CINCLUDES) +ASMINCLUDES = -Isc:include -I$(HWSRCDIR) +CPUSUFFIX = 020 # 020 030 040 060 (note: asm sources use 020+ code in some places) +CPUCCOPT = CPU=68$(CPUSUFFIX) +CP = C:Copy +MV = C:Rename +RM = C:Delete >NIL: +LD = sc:c/slink +CC = sc:c/sc +AS = vasmm68k_mot +MAKE = sc:c/smake +ECHO = Echo +SUFFIX = $(PRSUFFIX)$(CPUSUFFIX) +# +##################################################################### + +##################################################################### +# +# naming +# +DEVICE_DIR = build +BASENAME = $(DEVICE_NAME) +NAME = $(DEVICE_NAME).device +TESTNAME = enc624j6test + +# +##################################################################### + + +##################################################################### +# +# assembler/compiler flags +# +# this applies to normal and optimized compilation: +# +STDFLAGS = $(CINCLUDES) NOMULTIPLEINCLUDES ERRREXX COMMENTNEST NOSTKCHK NOCHKABORT\ + SMALLCODE SMALLDATA VERBOSE NOICONS STRICT ANSI $(DEFS) +# +# this applies only to normal compilation: +# +NORMCFLAGS = $(STDFLAGS) +# +# this applies only to optimized compilation: +# +OPTCFLAGS = $(STDFLAGS) $(CPUCCOPT) PARAMETERS=REGISTERS OPT OPTTIME OPTINLINE\ + OPTSCHEDULE STRINGMERGE STRUCTUREEQUIVALENCE +# +# this applies to assembler compilation +# +#AFLAGS = CPU=68020 VERBOSE DEFINE $(PROTOCOL)PLIP=1 +AFLAGS = -Fhunk -devpac -m68020 -quiet +# +##################################################################### + +##################################################################### +# +# linkage flags +# +#LDFLAGS = NOICONS SC MAP bla.map $(LIBS) TO +LDFLAGS = NOICONS SC $(LIBS) TO +OPTLDFLAGS = NOICONS SC SD ND $(LIBS) TO +# +##################################################################### + +##################################################################### +# +# the object files +# +# these are extra files for ENC624J6Net, disable for plipbox build +EXTRAOBJ=$(HWSRCDIR)/enc624j6l.o $(HWSRCDIR)/intervaltimer.o + +EXTRAOBJOPT=$(HWSRCDIR)/enc624j6l.o $(HWSRCDIR)/intervaltimer.o + +# these are for Plipbox build +#EXTRAOBJ=$(HWSRCDIR)/hwpar.o +#EXTRAOBJOPT=$(HWSRCDIR)/hwpar.o +# +# device support files +NORMOBJ=rt.o device.no server.no track.no $(HWSRCDIR)/hw.no $(EXTRAOBJ) +OPTOBJ=rt.o device.opt$(CPUSUFFIX) server.opt$(CPUSUFFIX) track.opt$(CPUSUFFIX) \ + $(HWSRCDIR)/hw.opt$(CPUSUFFIX) $(EXTRAOBJOPT) +# +# Auto-generated includes +DEVINFO_INC=dev_info.i +DEVINFO_HINC=dev_info.h +BUILDDEPS=libsize.auto.i $(DEVINFO_INC) $(DEVINFO_HINC) +# +# +##################################################################### + +##################################################################### +# +# rules +# +# compile a file normally +# +.c.no: $(BUILDDEPS) + $(CC) $(NORMCFLAGS) OBJECTNAME $@ $*.c + +# +# compile a file optimizing +# +.c.opt$(SUFFIX): $(BUILDDEPS) + $(CC) $(OPTCFLAGS) OBJECTNAME $@ $*.c +# +# assemble a file +# +#.asm.o: $(BUILDDEPS) +# $(AS) $(AFLAGS) OBJECTNAME $@ $*.asm +.asm.o: $(BUILDDEPS) + $(AS) $(AFLAGS) $(ASMINCLUDES) -o $@ $*.asm +.s.o: $(BUILDDEPS) + $(AS) $(AFLAGS) $(ASMINCLUDES) -o $@ $*.asm +# +##################################################################### + +##################################################################### +# +# targets +# +help: + -@Echo "Usage:" + -@Echo "To make an unoptimized version" + -@Echo " $(MAKE) all" + -@Echo "To make an optimized version" + -@Echo " $(MAKE) all_opt" + -@Echo "To %remove all intermediate files" + -@Echo " %$(MAKE) clean" + +all: $(DEVICE_DIR)/$(NAME) +# $(TESTNAME) +all_opt: $(DEVICE_DIR)/$(NAME).$(CPUSUFFIX) + +clean_norm: + -@$(RM) *.o + -@$(RM) *.no + -@$(RM) $(DEVICE_DIR)/$(NAME) + -@$(RM) $(HWSRCDIR)/*.no + -@$(RM) $(HWSRCDIR)/*.o + +clean_opt: + -@$(RM) *.o + -@$(RM) *.opt* $(HWSRCDIR)/*.opt* + -@$(RM) $(HWSRCDIR)/*.o $(EXTRAOBJOPT) + -@$(RM) $(DEVICE_DIR)/$(NAME).$(CPUSUFFIX) + +clean: clean_norm clean_opt + -@$(RM) $(DEVINFO_HINC) $(DEVINFO_INC) $(EXTRAOBJ) libsize.auto.i libsize.exe + +$(DEVICE_DIR)/$(NAME).$(CPUSUFFIX): $(OPTOBJ) $(BUILDDEPS) + $(LD) $(OPTOBJ) $(OPTLDFLAGS) $@ + +$(DEVICE_DIR)/$(NAME): $(NORMOBJ) + $(LD) $(NORMOBJ) $(LDFLAGS) $@ + +$(TESTNAME) : $(NORMOBJ) sdnettest.no + $(LD) sc:lib/c.o sdnettest.no $(NORMOBJ) LIB sc:lib/scnb.lib $(LDFLAGS) $@ + +# +# libsize.auto.i is used in rt.asm, this is an extra step (needing an AmigaOS +# environment) but ensures that the hwbase and plipbase sizes are "current" +# +libsize.auto.i : libsize.exe + -@libsize.exe >$@ + +libsize.exe : libsize.c global.h $(HWSRCDIR)/hwbase.h + -@$(CC) $(NORMCFLAGS) OBJECTNAME t:libsize.o libsize.c + -@$(LD) sc:lib/c.o t:libsize.o LIB sc:lib/scnb.lib $(LDFLAGS) $@ + -@$(RM) t:libsize.o + +# --- dev_info.i --- +$(DEVINFO_INC): smakefile + @Echo "DEVICE_NAME MACRO" > $(DEVINFO_INC) + @Echo " dc.b '$(DEVICE_NAME)'" >> $(DEVINFO_INC) + @Echo " ENDM" >> $(DEVINFO_INC) + @Echo "DEVICE_DATE MACRO" >> $(DEVINFO_INC) + @Echo " dc.b '$(DEVICE_DATE)'" >> $(DEVINFO_INC) + @Echo " ENDM" >> $(DEVINFO_INC) + @Echo "DEVICE_VER MACRO" >> $(DEVINFO_INC) + @Echo " dc.b '$(DEVICE_VERSION).$(DEVICE_REVISION)'" >> $(DEVINFO_INC) + @Echo " ENDM" >> $(DEVINFO_INC) + @Echo "DEVICE_VERSION equ $(DEVICE_VERSION)" >> $(DEVINFO_INC) + @Echo "DEVICE_REVISION equ $(DEVICE_REVISION)" >> $(DEVINFO_INC) + +# --- dev_info.h --- +$(DEVINFO_HINC): smakefile + -@Echo "\#ifndef _DEV_INFO_H" > $(DEVINFO_HINC) + -@Echo "\#define _DEV_INFO_H" >> $(DEVINFO_HINC) + -@Echo "\#define DEVICE_NAME " NOLINE >> $(DEVINFO_HINC) + -@Echo >> $(DEVINFO_HINC) !" NOLINE FIRST=2 + -@Echo NOLINE "$(DEVICE_NAME)" >> $(DEVINFO_HINC) + -@Echo >> $(DEVINFO_HINC) !" FIRST=2 + -@Echo "\#define DEVICE_DATE " NOLINE >> $(DEVINFO_HINC) + -@Echo >> $(DEVINFO_HINC) !" NOLINE FIRST=2 + -@Echo NOLINE "$(DEVICE_DATE)" >> $(DEVINFO_HINC) + -@Echo >> $(DEVINFO_HINC) !" FIRST=2 + -@Echo "\#define DEVICE_VER " NOLINE >> $(DEVINFO_HINC) + -@Echo >> $(DEVINFO_HINC) !" NOLINE FIRST=2 + -@Echo NOLINE "$(DEVICE_VERSION).$(DEVICE_REVISION)" >> $(DEVINFO_HINC) + -@Echo >> $(DEVINFO_HINC) !" FIRST=2 + -@Echo "\#define DEVICE_VERSION $(DEVICE_VERSION)" >> $(DEVINFO_HINC) + -@Echo "\#define DEVICE_REVISION $(DEVICE_REVISION)" >> $(DEVINFO_HINC) + -@Echo "\#endif" >> $(DEVINFO_HINC) + + +# +##################################################################### + +##################################################################### +# +# various dependencies (most from Magplip, unmodified so far) +# +rt.o: rt.asm $(DEVINFO_HINC) $(DEVINFO_INC) libsize.auto.i +$(PROTOCOL)device.opt$(SUFFIX) device.no: device.c global.h +$(PROTOCOL)server.opt$(SUFFIX) server.no: server.c global.h +$(PROTOCOL)track.opt$(SUFFIX) track.no: track.c global.h +# +##################################################################### + diff --git a/Driver/enc624j6net/track.c b/Driver/enc624j6net/track.c new file mode 100644 index 0000000..05129f3 --- /dev/null +++ b/Driver/enc624j6net/track.c @@ -0,0 +1,143 @@ +/*F*/ /* includes */ +#ifndef CLIB_EXEC_PROTOS_H +#include +#include +#endif + +#ifndef EXEC_MEMORY_H +#include +#endif +#ifndef EXEC_LISTS_H +#include +#endif +#ifndef EXEC_NODES_H +#include +#endif + +#ifndef _STRING_H +#include +#endif + +#ifndef __GLOBAL_H +#include "global.h" +#endif + +#ifndef __DEBUG_H +#include "debug.h" +#endif + +/*E*/ +/*F*/ /* exports */ +PUBLIC BOOL addtracktype(BASEPTR, ULONG type); +PUBLIC BOOL remtracktype(BASEPTR, ULONG type); +PUBLIC VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd); +PUBLIC BOOL gettrackrec(BASEPTR, ULONG type, APTR info); +PUBLIC VOID freetracktypes(BASEPTR); +/*E*/ +/*F*/ /* private */ +PRIVATE struct TrackRec *findtracktype(BASEPTR, ULONG type); +/*E*/ + +/*F*/ PRIVATE INLINE struct TrackRec *findtracktype(BASEPTR, ULONG type) +{ + struct TrackRec * tr; + + for (tr = (struct TrackRec *) pb->pb_TrackList.lh_Head; tr->tr_Link.mln_Succ; + tr = (struct TrackRec *) tr->tr_Link.mln_Succ) + { + if( tr->tr_PacketType == type ) + return( tr ); + } + + return( NULL ); +} +/*E*/ +/*F*/ PUBLIC BOOL addtracktype(BASEPTR, ULONG type) +{ + struct TrackRec *tr; + BOOL rv = FALSE; + + ObtainSemaphore(&pb->pb_TrackListSem); + if (!(tr = findtracktype(pb, type))) + { + if (tr = AllocVec(sizeof(*tr), MEMF_CLEAR)) + { + tr->tr_Count = 1; + tr->tr_PacketType = type; + AddTail((struct List*)&pb->pb_TrackList, (struct Node *)tr); + rv = TRUE; + } + } + else + { + ++tr->tr_Count; + rv = TRUE; + } + ReleaseSemaphore(&pb->pb_TrackListSem); + + return rv; +} +/*E*/ +/*F*/ PUBLIC BOOL remtracktype(BASEPTR, ULONG type) +{ + struct TrackRec *tr; + BOOL rv = FALSE; + + ObtainSemaphore( &pb->pb_TrackListSem ); + if (tr = findtracktype(pb, type)) + { + if (!(--tr->tr_Count)) + { + Remove((struct Node *)tr); + FreeVec(tr); + } + rv = TRUE; + } + ReleaseSemaphore( &pb->pb_TrackListSem ); + + return rv; +} +/*E*/ +/*F*/ PUBLIC VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd) +{ + struct TrackRec * tr; + + ObtainSemaphore(&pb->pb_TrackListSem); + if (tr = findtracktype(pb, type)) + { + tr->tr_Sana2PacketTypeStats.PacketsSent += ps; + tr->tr_Sana2PacketTypeStats.PacketsReceived += pr; + tr->tr_Sana2PacketTypeStats.BytesSent += bs; + tr->tr_Sana2PacketTypeStats.BytesReceived += br; + tr->tr_Sana2PacketTypeStats.PacketsDropped += pd; + } + ReleaseSemaphore(&pb->pb_TrackListSem); +} +/*E*/ +/*F*/ PUBLIC BOOL gettrackrec(BASEPTR, ULONG type, struct Sana2PacketTypeStats *info) +{ + struct TrackRec * tr; + BOOL rv = FALSE; + + ObtainSemaphoreShared( &pb->pb_TrackListSem ); + if (tr = findtracktype(pb, type)) + { + *info = tr->tr_Sana2PacketTypeStats; + rv = TRUE; + } + ReleaseSemaphore( &pb->pb_TrackListSem ); + + return rv; +} +/*E*/ +/*F*/ PUBLIC VOID freetracktypes(BASEPTR) +{ + struct Node *tr; + + ObtainSemaphore(&pb->pb_TrackListSem); + while(tr = RemHead((struct List*)&pb->pb_TrackList)) + FreeVec(tr); + ReleaseSemaphore(&pb->pb_TrackListSem); +} +/*E*/ +