ENC264J600 driver

- initial prototype, based on Plipbox framework
  - handles some oddities with the current CPLD by software
    workarounds, i.e. needs future changes to go along
    with updated JED
  - lots of TODO still pending
This commit is contained in:
HenrykRichter
2017-12-20 23:08:21 +01:00
parent 8e2723cc99
commit a46badc542
24 changed files with 6165 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
ENC624J6net
SANA-II Driver for Matze/Scrat ZII IDE LAN CP card
author: Henryk Richter <henryk.richter@gmx.net>
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.
Binary file not shown.
+33
View File
@@ -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
+33
View File
@@ -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
+8
View File
@@ -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
+11
View File
@@ -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
+922
View File
@@ -0,0 +1,922 @@
#define DEBUG 0
/*F*/ /* includes */
#ifndef CLIB_ALIB_PROTOS_H
#include <clib/alib_protos.h>
#endif
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#endif
#ifndef CLIB_DOS_PROTOS_H
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#endif
#ifndef CLIB_CIA_PROTOS_H
#include <clib/cia_protos.h>
#include <pragmas/cia_pragmas.h>
#endif
#ifndef CLIB_MISC_PROTOS_H
#include <clib/misc_protos.h>
#include <pragmas/misc_pragmas.h>
#endif
#ifndef CLIB_UTILITY_PROTOS_H
#include <clib/utility_protos.h>
#include <pragmas/utility_pragmas.h>
#endif
#ifndef CLIB_TIME_PROTOS_H
#include <clib/timer_protos.h>
#include <pragmas/timer_pragmas.h>
#endif
#ifndef DEVICES_SANA2_H
#include <devices/sana2.h>
#endif
#ifndef HARDWARE_CIA_H
#include <hardware/cia.h>
#endif
#ifndef DOS_DOSTAGS_H
#include <dos/dostags.h>
#endif
#ifndef RESOURCES_MISC_H
#include <resources/misc.h>
#endif
#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef _STRING_H
#include <string.h>
#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 <proto/vampire.h>
#include <vampire/vampire.h>
#endif
#ifdef PROTO_ENC624NET
#define ENC_MANUFACTURER 2588
#define ENC_BOARD 123
#include <clib/expansion_protos.h>
#include <pragmas/expansion_pragmas.h>
#include <libraries/configvars.h>
#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 ; i<HW_MAXBOARDS ; i++ )
{
cfg = FindConfigDev( cfg, ENC_MANUFACTURER, ENC_BOARD );
if( !cfg )
break;
pb->pb_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 <TetiSoft@apg.lahn.de>
** 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<<sigb);
Signal((struct Task*)pb->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*/
@@ -0,0 +1,46 @@
/*
asminterface.h
Henryk Richter <henryk.richter@gmx.net>
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 */
File diff suppressed because it is too large Load Diff
+253
View File
@@ -0,0 +1,253 @@
/*
enc624j6l.h
author: Henryk Richter <henryk.richter@gmx.net>
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 */
+471
View File
@@ -0,0 +1,471 @@
/*
* hw.c - hardware dependent part of driver
*/
#define DEBUG 0
/* 15 */
/*F*/ /* includes */
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#endif
#ifndef CLIB_DOS_PROTOS_H
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#endif
#ifndef CLIB_CIA_PROTOS_H
#include <clib/cia_protos.h>
#include <pragmas/cia_pragmas.h>
#endif
#ifndef CLIB_MISC_PROTOS_H
#include <clib/misc_protos.h>
#include <pragmas/misc_pragmas.h>
#endif
#ifndef CLIB_TIME_PROTOS_H
#include <clib/timer_protos.h>
#include <pragmas/timer_pragmas.h>
#endif
#ifndef CLIB_UTILITY_PROTOS_H
#include <clib/utility_protos.h>
#include <pragmas/utility_pragmas.h>
#endif
#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef EXEC_INTERRUPTS_H
#include <exec/interrupts.h>
#endif
#ifndef EXEC_DEVICES_H
#include <exec/devices.h>
#endif
#ifndef EXEC_IO_H
#include <exec/io.h>
#endif
#ifndef DEVICES_SANA2_H
#include <devices/sana2.h>
#endif
#ifndef HARDWARE_CIA_H
#include <hardware/cia.h>
#endif
#include <hardware/intbits.h>
#ifndef RESOURCES_MISC_H
#include <resources/misc.h>
#endif
#ifndef _STRING_H
#include <string.h>
#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;
}
+73
View File
@@ -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
@@ -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
@@ -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 <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <devices/timer.h>
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 */
@@ -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
+575
View File
@@ -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)
+188
View File
@@ -0,0 +1,188 @@
#ifndef __GLOBAL_H
#define __GLOBAL_H
/* system header files */
#ifndef DEVICES_SANA2_H
#include <devices/sana2.h>
#endif
#ifndef EXEC_SEMAPHORES_H
#include <exec/semaphores.h>
#endif
#ifndef EXEC_LISTS_H
#include <exec/lists.h>
#endif
#ifndef EXEC_INTERRUPTS_H
#include <exec/interrupts.h>
#endif
#ifndef EXEC_LIBRARIES_H
#include <exec/libraries.h>
#endif
#ifndef DOS_DOS_H
#include <dos/dos.h>
#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<<PLIPB_REPLYSS)
#define PLIPF_EXCLUSIVE (1<<PLIPB_EXCLUSIVE)
#define PLIPF_OFFLINE (1<<PLIPB_OFFLINE)
#define PLIPF_SERVERSTOPPED (1<<PLIPB_SERVERSTOPPED)
/*
** Values for PLIPBase->pb_ExtFlags
*/
#define PLIPEB_NOSPECIALSTATS 0 /* don't report special stats */
#define PLIPEF_NOSPECIALSTATS (1<<PLIPEB_NOSPECIALSTATS)
#endif
+60
View File
@@ -0,0 +1,60 @@
/* hw.h - hardware module of plihwbox.device */
#ifndef __HW_H
#define __HW_H
/* ----- hardware frame structure ----- */
/* magic packet types */
#define HW_MAGIC_ONLINE 0xffff
#define HW_MAGIC_OFFLINE 0xfffe
#define HW_MAGIC_LOOPBACK 0xfffd
/* transport ethernet addresses */
#define HW_ADDRFIELDSIZE 6
#define HW_ETH_HDR_SIZE 14 /* ethernet header: dst, src, type */
#define HW_ETH_MTU 1500
struct HWFrame {
USHORT hwf_Size;
/* use layout of ethernet header here */
UBYTE hwf_DstAddr[HW_ADDRFIELDSIZE];
UBYTE hwf_SrcAddr[HW_ADDRFIELDSIZE];
USHORT hwf_Type;
/*UBYTE hwf_Data[MTU];*/
};
/* ----- config stuff ----- */
#define COMMON_TEMPLATE "NOSPECIALSTATS/S,PRIORITY=PRI/K/N,BPS/K/N,MTU/K/N,"
struct CommonConfig {
ULONG nospecialstats;
LONG *priority;
ULONG *bps;
ULONG *mtu;
};
/* fetch device specific device base */
#include "hwbase.h"
struct PLIPBase;
/* hw API */
GLOBAL REGARGS BOOL hw_init(struct PLIPBase *pb);
GLOBAL REGARGS VOID hw_cleanup(struct PLIPBase *pb);
GLOBAL REGARGS BOOL hw_attach(struct PLIPBase *pb);
GLOBAL REGARGS VOID hw_detach(struct PLIPBase *pb);
GLOBAL REGARGS BOOL hw_send_frame(struct PLIPBase *pb, struct HWFrame *frame);
GLOBAL REGARGS BOOL hw_send_magic_pkt(struct PLIPBase *pb, USHORT magic);
GLOBAL REGARGS ULONG hw_recv_sigmask(struct PLIPBase *pb);
GLOBAL REGARGS BOOL hw_recv_pending(struct PLIPBase *pb);
GLOBAL REGARGS BOOL hw_recv_frame(struct PLIPBase *pb, struct HWFrame *frame);
GLOBAL REGARGS void hw_config_init(struct PLIPBase *pb);
GLOBAL REGARGS void hw_config_update(struct PLIPBase *pb, struct TemplateConfig *cfg);
GLOBAL REGARGS void hw_config_dump(struct PLIPBase *pb);
#endif
+8
View File
@@ -0,0 +1,8 @@
#include <stdio.h>
#include "global.h"
int main(int argc, char **argv)
{
printf("libsize equ %d\n", sizeof(struct PLIPBase));
return 0;
}
BIN
View File
Binary file not shown.
+88
View File
@@ -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
+759
View File
@@ -0,0 +1,759 @@
#define DEBUG 0
/*F*/ /* includes */
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#endif
#ifndef CLIB_DOS_PROTOS_H
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#endif
#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef DEVICES_SANA2_H
#include <devices/sana2.h>
#endif
#ifndef CLIB_TIME_PROTOS_H
#include <clib/timer_protos.h>
#include <pragmas/timer_pragmas.h>
#endif
#ifndef _STRING_H
#include <string.h>
#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;i<HW_ADDRFIELDSIZE;i++) {
if(frame->hwf_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*/
+247
View File
@@ -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
#
#####################################################################
+143
View File
@@ -0,0 +1,143 @@
/*F*/ /* includes */
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#endif
#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef EXEC_LISTS_H
#include <exec/lists.h>
#endif
#ifndef EXEC_NODES_H
#include <exec/nodes.h>
#endif
#ifndef _STRING_H
#include <string.h>
#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*/