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:
@@ -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.
|
||||
BIN
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+922
@@ -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 */
|
||||
Executable
+1778
File diff suppressed because it is too large
Load Diff
Executable
+253
@@ -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 */
|
||||
Executable
+471
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Executable
+575
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -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
|
||||
Executable
+759
@@ -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*/
|
||||
|
||||
@@ -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
|
||||
#
|
||||
#####################################################################
|
||||
|
||||
@@ -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*/
|
||||
|
||||
Reference in New Issue
Block a user