Switched Driver to baxnet-structure
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Common.mk
|
||||
#
|
||||
# author: Henryk Richter <henryk.richter@gmx.net>
|
||||
#
|
||||
# note: when switching between different hardware targets, don`t forget
|
||||
# "make clean" in between
|
||||
#
|
||||
# tools required:
|
||||
# GNU Make, either VBCC or GCC for AmigaOS/68k, VASM
|
||||
# recent sana2.h , e.g. from RoadShow SDK
|
||||
#
|
||||
# porting:
|
||||
# you might need to adapt the paths (prefix for Compiler/Includes)
|
||||
# Some installations have ADE: instead of GG: on Amigaos
|
||||
# Recent work on AmigaOS cross toolchains suggest /opt/m68k-amigaos/sys-include
|
||||
# instead of the traditional os-include
|
||||
#
|
||||
###############################################################################
|
||||
# debug = 1 will include string debugging for terminal/sushi/sashimi
|
||||
debug = 0
|
||||
# compiler_vcc = 1 will trigger VBCC, else GCC
|
||||
compiler_vcc = 0
|
||||
|
||||
###############################################################################
|
||||
# prefix for system includes (ASM)
|
||||
#
|
||||
###############################################################################
|
||||
PREFX = /opt/amigaos-68k/
|
||||
PREFX = gg:
|
||||
SYSINC = $(PREFX)os-include
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# compiler executables (choice of gcc or vbcc)
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(compiler_vcc),1)
|
||||
|
||||
# VBCC (use explicit vlink line for LINK= if complaints about R_PC happen)
|
||||
CCX = vc
|
||||
LINK = vlink -bamigahunk -x -s -mrel -Cvbcc -Bstatic -nostdlib #-Rshort
|
||||
#LINK = $(CCX) -nostdlib
|
||||
CFLAGS = -Os -+ -sc -c99 -cpu=68020
|
||||
|
||||
else
|
||||
|
||||
# GCC
|
||||
CCX = m68k-amigaos-gcc
|
||||
LINK = $(CCX) -nostartfiles -s
|
||||
CFLAGS = -O3 -s -m68020 -Wall -noixemul -mregparm=4 -fomit-frame-pointer -msoft-float -noixemul
|
||||
|
||||
endif
|
||||
|
||||
VASM = vasmm68k_mot
|
||||
VASMFORMAT = -m68020 -Fhunk -nowarn=2064 -quiet -I$(SYSINC)
|
||||
|
||||
# unused here
|
||||
#HOST = $(shell uname)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# paths to the local includes
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
IPATH =
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# compile-level feature definitions
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(compiler_vcc),1)
|
||||
# skip quotes with VCC, the AmigaOS native version doesn't like them
|
||||
DEFINES += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
DEFINES += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME="$(DEVICEID)"
|
||||
DEFINES += -DDEVICEEXTRA=$(DEVICEEXTRA)
|
||||
ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
#ASMDEFS += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME=$(DEVICEID)
|
||||
|
||||
DEFINES2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
DEFINES2 += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME="$(DEVICEID2)"
|
||||
DEFINES2 += -DDEVICEEXTRA=$(DEVICEEXTRA)
|
||||
ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
|
||||
else
|
||||
|
||||
DEFINES += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
|
||||
DEFINES += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID)""
|
||||
DEFINES += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
|
||||
ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
#ASMDEFS += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME=$(DEVICEID)
|
||||
|
||||
DEFINES2 += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
|
||||
DEFINES2 += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID2)""
|
||||
DEFINES2 += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
|
||||
ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
|
||||
endif
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# debug
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(debug),1)
|
||||
CFLAGS += -DDEBUG -g
|
||||
LINKLIBS = -L$(PREFX)/lib -ldebug
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# compiler flags and optimization levels
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I$(SUBDIR)
|
||||
LDFLAGS =
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# objects to build
|
||||
#
|
||||
###############################################################################
|
||||
# ASM based alternative to deviceheader.o would be romtag.o
|
||||
|
||||
OBJECTS = deviceheader.o deviceinit.o device.o server.o $(SUBDIR)/hw.o
|
||||
OBJECTS += $(ASMOBJECTS)
|
||||
|
||||
# used for secondary build
|
||||
OBJECTS2 = $(patsubst %.o,%.2o,$(OBJECTS))
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# rules and commands
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
all: $(DEVICEID) $(DEVICEID2)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(OBJECTS2)
|
||||
rm -f $(DEVICEID) $(DEVICEID2)
|
||||
|
||||
# not for cross compile :-)
|
||||
install: $(DEVICEID) $(DEVICEID2)
|
||||
copy $(DEVICEID) $(DEVICEID2) DEVS:Networks
|
||||
|
||||
|
||||
#sdnet: $(DEVICEID)
|
||||
#expnet: $(DEVICEID2)
|
||||
|
||||
$(DEVICEID) : $(OBJECTS)
|
||||
$(LINK) $(LDFLAGS) -o $@ $(OBJECTS) $(LINKLIBS) $(LINKOPTS)
|
||||
|
||||
|
||||
# separate ruleset for each subdirectory, ./src overrides all other paths for priority
|
||||
# of platform-optimized routines
|
||||
%.o : %.c
|
||||
$(CCX) -c $(CFLAGS) $(DEFINES) $(IPATH) $< -o $@
|
||||
|
||||
%.o : %.asm
|
||||
${VASM} $(VASMFORMAT) $(ASMDEFS) -o $@ $<
|
||||
|
||||
|
||||
# secondary ruleset (used for expnet, will be ignored if DEVICEID2 is empty)
|
||||
$(DEVICEID2) : $(OBJECTS2)
|
||||
$(LINK) $(LDFLAGS) -o $@ $(OBJECTS2) $(LINKLIBS)
|
||||
|
||||
%.2o : %.c
|
||||
$(CCX) -c $(CFLAGS) $(DEFINES2) $(IPATH) $< -o $@
|
||||
|
||||
%.2o : %.asm
|
||||
${VASM} $(VASMFORMAT) $(ASMDEFS2) -o $@ $<
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Common.mk
|
||||
#
|
||||
# author: Henryk Richter <henryk.richter@gmx.net>
|
||||
#
|
||||
# note: when switching between different hardware targets, don`t forget
|
||||
# "make clean" in between
|
||||
#
|
||||
# tools required:
|
||||
# GNU Make, either VBCC or GCC for AmigaOS/68k, VASM
|
||||
# recent sana2.h , e.g. from RoadShow SDK
|
||||
#
|
||||
# porting:
|
||||
# you might need to adapt the paths (prefix for Compiler/Includes)
|
||||
# Some installations have ADE: instead of GG: on Amigaos
|
||||
# Recent work on AmigaOS cross toolchains suggest /opt/m68k-amigaos/sys-include
|
||||
# instead of the traditional os-include
|
||||
#
|
||||
###############################################################################
|
||||
debug = 0
|
||||
compiler_vcc = 1
|
||||
|
||||
###############################################################################
|
||||
# prefix for system includes (ASM)
|
||||
#
|
||||
###############################################################################
|
||||
PREFX = /opt/amigaos-68k/
|
||||
PREFX = gg:
|
||||
SYSINC = $(PREFX)os-include
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# compiler executables (choice of gcc or vbcc)
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(compiler_vcc),1)
|
||||
|
||||
# VBCC (use explicit vlink line for LINK= if complaints about R_PC happen)
|
||||
CCX = vc
|
||||
LINK = vlink -bamigahunk -x -s -mrel -Cvbcc -Bstatic -nostdlib #-Rshort
|
||||
#LINK = $(CCX) -nostdlib
|
||||
CFLAGS = -Os -+ -sc -c99 -cpu=68020
|
||||
|
||||
else
|
||||
|
||||
# GCC
|
||||
CCX = m68k-amigaos-gcc
|
||||
LINK = $(CCX) -nostartfiles -s
|
||||
CFLAGS = -O3 -s -m68060 -Wall -noixemul -mregparm=4 -fomit-frame-pointer -msoft-float -noixemul
|
||||
|
||||
endif
|
||||
|
||||
VASM = vasmm68k_mot
|
||||
VASMFORMAT = -m68020 -Fhunk -nowarn=2064 -quiet -I$(SYSINC)
|
||||
|
||||
# unused here
|
||||
#HOST = $(shell uname)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# paths to the local includes
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
IPATH =
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# compile-level feature definitions
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(compiler_vcc),1)
|
||||
|
||||
DEFINES += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
DEFINES += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME="$(DEVICEID)"
|
||||
DEFINES += -DDEVICEEXTRA=$(DEVICEEXTRA)
|
||||
ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
#ASMDEFS += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME=$(DEVICEID)
|
||||
|
||||
DEFINES2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
DEFINES2 += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME="$(DEVICEID2)"
|
||||
DEFINES2 += -DDEVICEEXTRA=$(DEVICEEXTRA)
|
||||
ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
|
||||
else
|
||||
|
||||
DEFINES += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
|
||||
DEFINES += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID)""
|
||||
DEFINES += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
|
||||
ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
#ASMDEFS += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME=$(DEVICEID)
|
||||
|
||||
DEFINES2 += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
|
||||
DEFINES2 += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID2)""
|
||||
DEFINES2 += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
|
||||
ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
|
||||
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# debug
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(debug),1)
|
||||
CFLAGS += -DDEBUG -g
|
||||
LINKLIBS = -L$(PREFX)/lib -ldebug
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# compiler flags and optimization levels
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I$(SUBDIR)
|
||||
LDFLAGS =
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# objects to build
|
||||
#
|
||||
###############################################################################
|
||||
# ASM based alternative to deviceheader.o would be romtag.o
|
||||
|
||||
OBJECTS = deviceheader.o deviceinit.o device.o server.o $(SUBDIR)/hw.o
|
||||
OBJECTS += $(ASMOBJECTS)
|
||||
|
||||
# used for secondary build
|
||||
OBJECTS2 = $(patsubst %.o,%.2o,$(OBJECTS))
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# rules and commands
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
all: $(DEVICEID) $(DEVICEID2)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(OBJECTS2)
|
||||
rm -f $(DEVICEID) $(DEVICEID2)
|
||||
|
||||
#sdnet: $(DEVICEID)
|
||||
#expnet: $(DEVICEID2)
|
||||
|
||||
$(DEVICEID) : $(OBJECTS)
|
||||
$(LINK) $(LDFLAGS) -o $@ $(OBJECTS) $(LINKLIBS) $(LINKOPTS)
|
||||
|
||||
|
||||
# separate ruleset for each subdirectory, ./src overrides all other paths for priority
|
||||
# of platform-optimized routines
|
||||
%.o : %.c
|
||||
$(CCX) -c $(CFLAGS) $(DEFINES) $(IPATH) $< -o $@
|
||||
|
||||
%.o : %.asm
|
||||
${VASM} $(VASMFORMAT) $(ASMDEFS) -o $@ $<
|
||||
|
||||
|
||||
# secondary ruleset (used for expnet, will be ignored if DEVICEID2 is empty)
|
||||
$(DEVICEID2) : $(OBJECTS2)
|
||||
$(LINK) $(LDFLAGS) -o $@ $(OBJECTS2) $(LINKLIBS)
|
||||
|
||||
%.2o : %.c
|
||||
$(CCX) -c $(CFLAGS) $(DEFINES2) $(IPATH) $< -o $@
|
||||
|
||||
%.2o : %.asm
|
||||
${VASM} $(VASMFORMAT) $(ASMDEFS2) -o $@ $<
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
###############################################################################
|
||||
#
|
||||
# VAMPIREGFX makefile for vbcc
|
||||
#
|
||||
# author: Henryk Richter <henryk.richter@gmx.net>
|
||||
#
|
||||
# concept:
|
||||
#
|
||||
# tools required:
|
||||
# - vbcc, defaulting to m68k-amigaos
|
||||
# - vlink
|
||||
# - vasm
|
||||
#
|
||||
# porting:
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Name, version
|
||||
#
|
||||
###############################################################################
|
||||
DEVICEVERSION=1
|
||||
DEVICEREVISION=91
|
||||
DEVICEDATE=06.06.2018
|
||||
ASMOBJECTS = $(SUBDIR)/enc624j6l.o $(SUBDIR)/intervaltimer.o
|
||||
SUBDIR=enc624j6net
|
||||
|
||||
DEVICEID=enc624j6net.device
|
||||
DEFINES = # -DPROTO_V2EXPNET
|
||||
ASMDEFS = # -DPROTO_V2EXPNET
|
||||
|
||||
|
||||
###############################################################################
|
||||
# import generic ruleset
|
||||
#
|
||||
###############################################################################
|
||||
include Common.mk
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
###############################################################################
|
||||
#
|
||||
# SDNet and V2EXPETH build instructions
|
||||
#
|
||||
# author: Henryk Richter <henryk.richter@gmx.net>
|
||||
#
|
||||
# concept:
|
||||
#
|
||||
# tools required:
|
||||
# - vbcc or m68k-amigaos-gcc (Default: gcc)
|
||||
# - vlink or GNU ld
|
||||
# - vasm (vasmm68k_mot)
|
||||
# - system headers (default: /opt/amigaos-68k/os-include, see Common.mk)
|
||||
#
|
||||
# porting:
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Name, version
|
||||
#
|
||||
###############################################################################
|
||||
DEVICEVERSION=1
|
||||
DEVICEREVISION=91
|
||||
DEVICEDATE=06.06.2018
|
||||
DEVICEEXTRA=Beta
|
||||
ASMOBJECTS = $(SUBDIR)/vampuuid.o $(SUBDIR)/intervaltimer.o $(SUBDIR)/enc28j60.o $(SUBDIR)/enc28j60l.o
|
||||
SUBDIR=sdnet
|
||||
|
||||
# two flavours of the same code base may be build with this setup
|
||||
# leave DEVICEID2 empty to disable second build
|
||||
DEVICEID=sdnet.device
|
||||
DEFINES = # -DPROTO_V2EXPNET
|
||||
ASMDEFS = # -DPROTO_V2EXPNET
|
||||
|
||||
DEVICEID2=v2expeth.device
|
||||
DEFINES2 = -DPROTO_V2EXPNET
|
||||
ASMDEFS2 = -DPROTO_V2EXPNET
|
||||
|
||||
|
||||
###############################################################################
|
||||
# import generic ruleset
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
include Common.mk
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
compiler.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Interface macros for ASM subroutines for VBCC, 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
|
||||
#define STRUCTOFFSET OFFSET /* exec/initializers.h */
|
||||
#define INLINE __inline static
|
||||
|
||||
#else /* __SASC */
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define ASM
|
||||
#define ASMR(x) register
|
||||
#define ASMREG(x) __asm("" #x "")
|
||||
#define SAVEDS __saveds
|
||||
#define STRUCTOFFSET OFFSET /* exec/initializers.h */
|
||||
#define INLINE static inline
|
||||
|
||||
#else /* __GNUC__ */
|
||||
|
||||
#ifdef __VBCC__
|
||||
|
||||
#define ASM
|
||||
#define ASMR(x) __reg("" #x "")
|
||||
#define ASMREG(x)
|
||||
#define SAVEDS __saveds
|
||||
#define STRUCTOFFSET(_a_,_b_) offsetof(struct _a_, _b_) /* stddef.h */
|
||||
#include <stddef.h>
|
||||
/* sorry, I ran into some issues inlining stuff with VBCC, disabling it */
|
||||
#define INLINE
|
||||
|
||||
#else /* __VBCC__ */
|
||||
|
||||
#error "Compiler not supported yet in asminterface.h"
|
||||
|
||||
#endif /* __VBCC__ */
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* __SASC */
|
||||
|
||||
|
||||
#endif /* _INC_ASMINTERFACE_H */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
debug.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Debugging Macros
|
||||
|
||||
|
||||
*/
|
||||
#ifndef _INC_DEBUG_H
|
||||
#define _INC_DEBUG_H
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void KPrintF(char *, ...), KGetChar(void);
|
||||
|
||||
#define D(_x_) do { KPrintF("%s:%ld:",__FILE__,__LINE__); KPrintF _x_; } while(0)
|
||||
|
||||
#else /* DEBUG */
|
||||
|
||||
#define D(x)
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
||||
#endif /* _INC_DEBUG_H */
|
||||
@@ -0,0 +1,995 @@
|
||||
/*
|
||||
device.c
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Device Functions
|
||||
|
||||
the device core consists of three files, to be linked
|
||||
in the following order
|
||||
- deviceheader.c - ROMTAG
|
||||
- deviceinit.c - strings and init tables
|
||||
- device.c - functions
|
||||
I've had seen quite creative ways the different compilers
|
||||
handled the order of objects in the linked result and that's
|
||||
why I've chosen to break it down in the way you see here.
|
||||
|
||||
The request handling and hardware interaction is carried out
|
||||
in server.c as a separate process. Interrupts are forwarded
|
||||
as signals to server.c as well (depending on target hardware).
|
||||
|
||||
*/
|
||||
#define DEVICE_MAIN
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/utility.h>
|
||||
#include <proto/dos.h>
|
||||
#include <dos/dostags.h>
|
||||
#include <utility/tagitem.h>
|
||||
#include <exec/lists.h>
|
||||
#include "device.h"
|
||||
#include "hw.h"
|
||||
#include "macros.h"
|
||||
|
||||
|
||||
ASM SAVEDS struct Device *DevInit( ASMR(d0) DEVBASEP ASMREG(d0),
|
||||
ASMR(a0) BPTR seglist ASMREG(a0),
|
||||
ASMR(a6) struct Library *_SysBase ASMREG(a6) )
|
||||
{
|
||||
UBYTE*p;
|
||||
ULONG i;
|
||||
LONG ok;
|
||||
|
||||
p = ((UBYTE*)db) + sizeof(struct Library);
|
||||
i = sizeof(DEVBASETYPE)-sizeof(struct Library);
|
||||
while( i-- )
|
||||
*p++ = 0;
|
||||
|
||||
db->db_SysBase = _SysBase;
|
||||
db->db_SegList = seglist;
|
||||
db->db_Flags = 0;
|
||||
|
||||
dbNewList( &db->db_BufferManagement );
|
||||
|
||||
for(i=0 ; i < MAX_UNITS ; i++ )
|
||||
{
|
||||
dbNewList( (struct List*)&db->db_Units[i].du_ReadTypes );
|
||||
dbNewList( (struct List*)&db->db_Units[i].du_ReadOrphans );
|
||||
dbNewList( (struct List*)&db->db_Units[i].du_WriteQueue );
|
||||
dbNewList( (struct List*)&db->db_Units[i].du_EventQueue );
|
||||
InitSemaphore( &db->db_Units[i].du_Sem );
|
||||
db->db_Units[i].du_MTU = DEF_MTU;
|
||||
db->db_Units[i].du_BitPerSec = DEF_BPS;
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
if( (DOSBase = OpenLibrary("dos.library", 36)) )
|
||||
{
|
||||
if( (UtilityBase = OpenLibrary("utility.library", 37)) )
|
||||
{
|
||||
/* Search HW */
|
||||
ok = hw_Find_Boards( db );
|
||||
if( ok > MAX_UNITS )
|
||||
ok = MAX_UNITS;
|
||||
if( !ok )
|
||||
{
|
||||
D(("No Hardware\n"));
|
||||
CloseLibrary(DOSBase);
|
||||
CloseLibrary(UtilityBase);
|
||||
}
|
||||
db->db_NBoards = ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
D(("No Utility\n"));
|
||||
CloseLibrary(DOSBase);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
D(("No DOS\n"));
|
||||
}
|
||||
|
||||
/* no hardware found, reject init */
|
||||
return (ok > 0) ? (struct Device*)db : (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ASM SAVEDS LONG DevOpen( ASMR(a1) struct IOSana2Req *ioreq ASMREG(a1),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(d1) ULONG flags ASMREG(d1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) )
|
||||
{
|
||||
LONG ok,ret = IOERR_OPENFAIL;
|
||||
|
||||
D(("DevOpen for %ld\n",unit));
|
||||
|
||||
db->db_Lib.lib_OpenCnt++; /* avoid Expunge, see below for separate "unit" open count */
|
||||
db->db_ID++; /* opener ID (always >0) */
|
||||
|
||||
if( unit < db->db_NBoards )
|
||||
{
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem ); /* lock current board */
|
||||
|
||||
ok = 1;
|
||||
if( (db->db_Units[unit].du_OpenCount > 0) &&
|
||||
(flags & SANA2OPF_MINE) )
|
||||
ok = 0;
|
||||
|
||||
if( (db->db_Units[unit].du_OpenCount > 0) &&
|
||||
(flags & SANA2OPF_PROM) )
|
||||
ok = 0;
|
||||
|
||||
|
||||
if( db->db_Units[unit].du_Flags & DUF_EXCLUSIVE )
|
||||
ok = 0;
|
||||
|
||||
if( ok )
|
||||
ok = hw_AllocBoard( db, unit );
|
||||
|
||||
if( ok )
|
||||
{
|
||||
struct db_BufferManagement *dbm;
|
||||
|
||||
db->db_Units[unit].du_OpenCount++;
|
||||
db->db_Units[unit].du_Flags &= ~DUF_EXCLUSIVE;
|
||||
if( flags & SANA2OPF_MINE )
|
||||
db->db_Units[unit].du_Flags |= DUF_EXCLUSIVE;
|
||||
if( flags & SANA2OPF_PROM ) /* implies _MINE by spec */
|
||||
db->db_Units[unit].du_Flags |= DUF_PROMISC;
|
||||
|
||||
hw_GetMacAddress( db, unit, &db->db_Units[unit].du_HWAddr[0] );
|
||||
hw_GetMacAddress( db, unit, &db->db_Units[unit].du_CFGAddr[0] );
|
||||
|
||||
ok = 0;
|
||||
dbm = (struct db_BufferManagement *)AllocMem( sizeof(struct db_BufferManagement),MEMF_ANY|MEMF_CLEAR);
|
||||
if( dbm )
|
||||
{
|
||||
dbm->dbm_CopyToBuffer = (BMCALL)((void (*)())(GetTagData(S2_CopyToBuff, 0,
|
||||
(struct TagItem *)ioreq->ios2_BufferManagement)));
|
||||
dbm->dbm_CopyFromBuffer = (BMCALL)((void (*)())(GetTagData(S2_CopyFromBuff, 0,
|
||||
(struct TagItem *)ioreq->ios2_BufferManagement)));
|
||||
#if 0
|
||||
dbm->dbm_CopyToBuffer32 = (0); /* DEBUG */
|
||||
dbm->dbm_CopyFromBuffer32 = (0);
|
||||
#else
|
||||
dbm->dbm_CopyToBuffer32 = (BMCALL)((void (*)())(GetTagData(S2_CopyToBuff32, 0,
|
||||
(struct TagItem *)ioreq->ios2_BufferManagement)));
|
||||
dbm->dbm_CopyFromBuffer32 = (BMCALL)((void (*)())(GetTagData(S2_CopyFromBuff32, 0,
|
||||
(struct TagItem *)ioreq->ios2_BufferManagement)));
|
||||
#endif
|
||||
if( !dbm->dbm_CopyToBuffer32 )
|
||||
dbm->dbm_CopyToBuffer32 = dbm->dbm_CopyToBuffer;
|
||||
if( !dbm->dbm_CopyFromBuffer32 )
|
||||
dbm->dbm_CopyFromBuffer32 = dbm->dbm_CopyFromBuffer;
|
||||
|
||||
dbm->dbm_ID = db->db_ID;
|
||||
ok = 1;
|
||||
}
|
||||
if( ok )
|
||||
{
|
||||
/* start server if necessary */
|
||||
ok = dbStartServer( db, unit );
|
||||
}
|
||||
if( ok )
|
||||
{
|
||||
ret = 0;
|
||||
AddTail((struct List *)&db->db_BufferManagement,(struct Node *)dbm);
|
||||
db->db_Lib.lib_Flags &= ~LIBF_DELEXP;
|
||||
ioreq->ios2_BufferManagement = (VOID *)dbm;
|
||||
ioreq->ios2_Req.io_Error = 0;
|
||||
ioreq->ios2_Req.io_Unit = (struct Unit *)unit;
|
||||
ioreq->ios2_Req.io_Device = (struct Device *)db;
|
||||
|
||||
dbAddType( db, unit, 0x800 ); /* register IP by default */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
db->db_Units[unit].du_OpenCount--;
|
||||
db->db_Units[unit].du_Flags &= ~DUF_EXCLUSIVE;
|
||||
hw_ReleaseBoard( db, unit );
|
||||
if( dbm ) FreeMem( dbm, sizeof(struct db_BufferManagement) );
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
}
|
||||
|
||||
if( ret == IOERR_OPENFAIL )
|
||||
{
|
||||
ioreq->ios2_Req.io_Unit = (0);
|
||||
ioreq->ios2_Req.io_Device = (0);
|
||||
ioreq->ios2_Req.io_Error = ret;
|
||||
db->db_Lib.lib_OpenCnt--;
|
||||
}
|
||||
ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS BPTR DevClose( ASMR(a1) struct IOSana2Req *ioreq ASMREG(a1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) )
|
||||
{
|
||||
ULONG unit;
|
||||
BPTR ret = (0);
|
||||
|
||||
D(("DevClose open count %ld\n",db->db_Lib.lib_OpenCnt));
|
||||
|
||||
/* request valid ? */
|
||||
if( !ioreq )
|
||||
return ret;
|
||||
if( (unit = (ULONG)ioreq->ios2_Req.io_Unit) > db->db_NBoards)
|
||||
return ret;
|
||||
|
||||
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem ); /* lock current board */
|
||||
|
||||
dbDeleteBuffers( db, ioreq ); /* buffer management and internal buffers */
|
||||
|
||||
db->db_Lib.lib_OpenCnt--;
|
||||
|
||||
if( db->db_Units[unit].du_OpenCount ) /* sanity */
|
||||
db->db_Units[unit].du_OpenCount--;
|
||||
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
|
||||
/* give server time to offline down the hardware */
|
||||
if( (db->db_ServerProc) &&
|
||||
!(db->db_Units[unit].du_OpenCount) &&
|
||||
(db->db_Units[unit].du_Flags & DUF_ONLINE )
|
||||
)
|
||||
{
|
||||
Signal( (struct Task*)db->db_ServerProc, SIGBREAKF_CTRL_D);
|
||||
Delay(1);
|
||||
}
|
||||
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem ); /* lock current board */
|
||||
|
||||
hw_ReleaseBoard( db, unit );
|
||||
|
||||
ioreq->ios2_Req.io_Device = (0);
|
||||
ioreq->ios2_Req.io_Unit = (struct Unit *)(-1);
|
||||
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
|
||||
if (db->db_Lib.lib_Flags & LIBF_DELEXP)
|
||||
ret = DevExpunge(db);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS BPTR DevExpunge( ASMR(a6) DEVBASEP ASMREG(a6) )
|
||||
{
|
||||
BPTR seglist = db->db_SegList;
|
||||
ULONG i;
|
||||
struct SanaReadType *type;
|
||||
|
||||
if( db->db_Lib.lib_OpenCnt )
|
||||
{
|
||||
db->db_Lib.lib_Flags |= LIBF_DELEXP;
|
||||
return (0);
|
||||
}
|
||||
|
||||
Forbid();
|
||||
Remove((struct Node*)db); /* remove device node from system */
|
||||
Permit();
|
||||
|
||||
dbStopServer(db,0);
|
||||
|
||||
for( i=0 ; i < db->db_NBoards ; i++ )
|
||||
{
|
||||
while( (type = GetHead( &db->db_Units[i].du_ReadTypes ) ))
|
||||
{
|
||||
dbDeleteType( db, i, type->srt_Type );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* last steps: libraries */
|
||||
CloseLibrary(DOSBase);
|
||||
CloseLibrary(UtilityBase);
|
||||
FreeMem( ((BYTE*)db)-db->db_Lib.lib_NegSize,(ULONG)(db->db_Lib.lib_PosSize + db->db_Lib.lib_NegSize));
|
||||
|
||||
return seglist;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS VOID DevBeginIO( ASMR(a1) struct IOSana2Req *ioreq ASMREG(a1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) )
|
||||
{
|
||||
ULONG unit = (ULONG)ioreq->ios2_Req.io_Unit;
|
||||
|
||||
ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
|
||||
/*ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;*/
|
||||
|
||||
D(("BeginIO command %ld unit %ld\n",(LONG)ioreq->ios2_Req.io_Command,unit));
|
||||
|
||||
switch( ioreq->ios2_Req.io_Command )
|
||||
{
|
||||
case CMD_READ:
|
||||
if( !ioreq->ios2_BufferManagement )
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
|
||||
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !(db->db_Units[unit].du_Flags & DUF_ONLINE ))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
|
||||
ioreq->ios2_WireError = S2WERR_UNIT_OFFLINE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
|
||||
ObtainSemaphore(&db->db_Units[unit].du_Sem);
|
||||
dbAddReadReq( db, unit, ioreq );
|
||||
ReleaseSemaphore(&db->db_Units[unit].du_Sem);
|
||||
ioreq = (0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Note: Orphans are not distributed to all listeners.
|
||||
Strictly speaking, nobody actually asked for these
|
||||
frame types, anyway. */
|
||||
case S2_READORPHAN:
|
||||
if( !ioreq->ios2_BufferManagement )
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
|
||||
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !(db->db_Units[unit].du_Flags & DUF_ONLINE ))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
|
||||
ioreq->ios2_WireError = S2WERR_UNIT_OFFLINE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
|
||||
ObtainSemaphore(&db->db_Units[unit].du_Sem);
|
||||
ADDTAIL((struct List*)&db->db_Units[unit].du_ReadOrphans,(struct Node*)ioreq);
|
||||
ReleaseSemaphore(&db->db_Units[unit].du_Sem);
|
||||
ioreq = (0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* same routine for BC, MC, UC */
|
||||
case S2_BROADCAST:
|
||||
{
|
||||
UWORD *ptr = (UWORD*)ioreq->ios2_DstAddr;
|
||||
ptr[0] = ptr[1] = ptr[2] = 0xffff;
|
||||
}
|
||||
case S2_MULTICAST:
|
||||
case CMD_WRITE:
|
||||
{
|
||||
ULONG mtu = db->db_Units[unit].du_MTU;
|
||||
|
||||
if(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW)
|
||||
mtu += 18; /* DEST MAC, SRC MAC, Type/Length, CRC */
|
||||
if(ioreq->ios2_DataLength > mtu)
|
||||
ioreq->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
|
||||
else
|
||||
{
|
||||
if( !ioreq->ios2_BufferManagement )
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
|
||||
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !(db->db_Units[unit].du_Flags & DUF_ONLINE ))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
|
||||
ioreq->ios2_WireError = S2WERR_UNIT_OFFLINE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
|
||||
ObtainSemaphore(&db->db_Units[unit].du_Sem);
|
||||
ADDTAIL((struct List*)&db->db_Units[unit].du_WriteQueue,(struct Node*)ioreq);
|
||||
ReleaseSemaphore(&db->db_Units[unit].du_Sem);
|
||||
Signal( (struct Task*)db->db_ServerProc, SIGBREAKF_CTRL_F );
|
||||
ioreq = (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case S2_ONEVENT:
|
||||
if (((ioreq->ios2_WireError&S2EVENT_ONLINE)&&(db->db_Units[unit].du_Flags&DUF_ONLINE)) ||
|
||||
((ioreq->ios2_WireError&S2EVENT_OFFLINE)&&!(db->db_Units[unit].du_Flags&DUF_ONLINE)))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = 0;
|
||||
ioreq->ios2_WireError &= (S2EVENT_ONLINE|S2EVENT_OFFLINE);
|
||||
dbTermIO(db,ioreq);
|
||||
ioreq = (0);
|
||||
}
|
||||
else if ((ioreq->ios2_WireError & (S2EVENT_ERROR|S2EVENT_TX|S2EVENT_RX|S2EVENT_ONLINE|
|
||||
S2EVENT_OFFLINE|S2EVENT_BUFF|S2EVENT_HARDWARE|S2EVENT_SOFTWARE))
|
||||
!= ioreq->ios2_WireError)
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
|
||||
ioreq->ios2_WireError = S2WERR_BAD_EVENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* handle request in Server task */
|
||||
ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
|
||||
ObtainSemaphore(&db->db_Units[unit].du_Sem);
|
||||
AddTail((struct List*)&db->db_Units[unit].du_EventQueue, (struct Node*)ioreq);
|
||||
ReleaseSemaphore(&db->db_Units[unit].du_Sem);
|
||||
Signal((struct Task*)db->db_ServerProc, SIGBREAKF_CTRL_F );
|
||||
ioreq = (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case S2_ONLINE:
|
||||
case S2_OFFLINE:
|
||||
case S2_CONFIGINTERFACE:
|
||||
dbForwardIO( db, ioreq );
|
||||
ioreq = (0);
|
||||
break;
|
||||
|
||||
case S2_GETSTATIONADDRESS:
|
||||
D(("CFGAddr0 %lx %lx %lx...\n",\
|
||||
(LONG)db->db_Units[unit].du_CFGAddr[0],\
|
||||
(LONG)db->db_Units[unit].du_CFGAddr[1],\
|
||||
(LONG)db->db_Units[unit].du_CFGAddr[2] ));
|
||||
|
||||
CopyMem( db->db_Units[unit].du_CFGAddr, ioreq->ios2_SrcAddr, 6);
|
||||
CopyMem( db->db_Units[unit].du_HWAddr, ioreq->ios2_DstAddr, 6);
|
||||
|
||||
D(("CFGAddr1 %lx %lx %lx...\n",(LONG)*(ioreq->ios2_SrcAddr), (LONG)*(ioreq->ios2_SrcAddr+1), (LONG)*(ioreq->ios2_SrcAddr+2)));
|
||||
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
break;
|
||||
|
||||
case S2_DEVICEQUERY:
|
||||
{
|
||||
struct Sana2DeviceQuery *query = ioreq->ios2_StatData;
|
||||
|
||||
query->DevQueryFormat = 0;
|
||||
query->DeviceLevel = 0;
|
||||
|
||||
D(("DeviceQuery size %ld\n",query->SizeAvailable));
|
||||
|
||||
if(query->SizeAvailable >= 18) query->AddrFieldSize = 48;
|
||||
if(query->SizeAvailable >= 22) query->MTU = db->db_Units[unit].du_MTU;
|
||||
if(query->SizeAvailable >= 26) query->BPS = db->db_Units[unit].du_BitPerSec;
|
||||
if(query->SizeAvailable >= 30) query->HardwareType = S2WireType_Ethernet;
|
||||
if(query->SizeAvailable >= 34)
|
||||
{ /* RawMTU */
|
||||
ULONG *tmp = (ULONG*)&query->HardwareType;
|
||||
*(tmp+1) = 1518; /* DMAC,SMAC,TYPE,1500,CRC32 */
|
||||
}
|
||||
query->SizeSupplied = min( (ULONG)query->SizeAvailable, 34);
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case S2_TRACKTYPE:
|
||||
if( !dbTrackType( db, unit, ioreq->ios2_PacketType, 1 ))
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
|
||||
else ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
break;
|
||||
case S2_UNTRACKTYPE:
|
||||
if( !dbTrackType( db, unit, ioreq->ios2_PacketType, 0 ))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_BAD_STATE;
|
||||
ioreq->ios2_WireError = S2WERR_NOT_TRACKED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case S2_GETTYPESTATS:
|
||||
if( !dbTrackTypeStats( db, unit, ioreq->ios2_PacketType, (struct Sana2PacketTypeStats *)ioreq->ios2_StatData ))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_BAD_STATE;
|
||||
ioreq->ios2_WireError = S2WERR_NOT_TRACKED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case S2_GETGLOBALSTATS:
|
||||
CopyMem( &db->db_Units[unit].du_DevStats, ioreq->ios2_StatData, sizeof(struct Sana2DeviceStats) );
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
break;
|
||||
|
||||
case CMD_RESET:
|
||||
case CMD_UPDATE:
|
||||
case CMD_CLEAR:
|
||||
case CMD_STOP:
|
||||
case CMD_START:
|
||||
case CMD_FLUSH:
|
||||
ioreq->ios2_Req.io_Error = IOERR_NOCMD;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
break;
|
||||
|
||||
case S2_ADDMULTICASTADDRESS:
|
||||
case S2_DELMULTICASTADDRESS:
|
||||
#if 1
|
||||
dbForwardIO( db, ioreq );
|
||||
ioreq = (0);
|
||||
#else
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
#endif
|
||||
break;
|
||||
|
||||
/*case S2_GETEXTENDEDGLOBALSTATS: */ /* S2R4 */
|
||||
case S2_GETSPECIALSTATS:
|
||||
default:
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if( ioreq )
|
||||
dbTermIO( db, ioreq );
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG DevAbortIO( ASMR(a1) struct IOSana2Req *ioreq ASMREG(a1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) )
|
||||
{
|
||||
/* we store ioreqs in various places, search them all */
|
||||
struct SanaReadType *type;
|
||||
struct SanaReader *rd;
|
||||
LONG ret = 0;
|
||||
|
||||
ULONG unit = (ULONG)ioreq->ios2_Req.io_Unit;
|
||||
|
||||
ObtainSemaphore(&db->db_Units[unit].du_Sem);
|
||||
|
||||
/* start with the read list -> types -> readers -> reqlist */
|
||||
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
rd = (struct SanaReader *)GetHead( &type->srt_Readers );
|
||||
while( rd )
|
||||
{
|
||||
if( dbIsInList( &rd->snr_Requests, (struct Node*)ioreq ))
|
||||
goto abort;
|
||||
|
||||
rd = GetSucc( rd );
|
||||
}
|
||||
type = GetSucc( type );
|
||||
}
|
||||
|
||||
if( dbIsInList( (struct List*)&db->db_Units[unit].du_WriteQueue, (struct Node*)ioreq ))
|
||||
goto abort;
|
||||
if( dbIsInList( (struct List*)&db->db_Units[unit].du_EventQueue, (struct Node*)ioreq ))
|
||||
goto abort;
|
||||
if( dbIsInList( (struct List*)&db->db_Units[unit].du_ReadOrphans, (struct Node*)ioreq ))
|
||||
goto abort;
|
||||
|
||||
ret = -1;
|
||||
goto end;
|
||||
abort:
|
||||
Remove( (struct Node*)ioreq );
|
||||
ioreq->ios2_Req.io_Error = IOERR_ABORTED;
|
||||
ioreq->ios2_WireError = 0;
|
||||
ReplyMsg((struct Message*)ioreq);
|
||||
end:
|
||||
ReleaseSemaphore(&db->db_Units[unit].du_Sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void dbTermIO( DEVBASEP, struct IOSana2Req *ioreq )
|
||||
{
|
||||
D(("dbTermIO flags %ld\n",(LONG)ioreq->ios2_Req.io_Flags));
|
||||
|
||||
if( ioreq->ios2_Req.io_Flags & SANA2IOF_QUICK )
|
||||
ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
|
||||
else
|
||||
ReplyMsg( (struct Message *)ioreq );
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
static void dbForwardIO( DEVBASEP, struct IOSana2Req *ioreq )
|
||||
{
|
||||
ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
|
||||
PutMsg(db->db_ServerPort, (struct Message*)ioreq);
|
||||
|
||||
D(("Forward Request %ld\n",ioreq->ios2_Req.io_Command));
|
||||
}
|
||||
|
||||
|
||||
static void dbNewList( struct List *l )
|
||||
{
|
||||
l->lh_TailPred = (struct Node *)l;
|
||||
l->lh_Head = (struct Node *)&l->lh_Tail;
|
||||
l->lh_Tail = 0;
|
||||
}
|
||||
|
||||
static LONG dbIsInList( struct List *l, struct Node *entry )
|
||||
{
|
||||
struct Node *nd;
|
||||
|
||||
nd = GetHead( l );
|
||||
while( nd )
|
||||
{
|
||||
if( nd == entry )
|
||||
return 1;
|
||||
|
||||
nd = GetSucc(nd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* start Server function and keep it up */
|
||||
/* note: server is global right now */
|
||||
static LONG dbStartServer( DEVBASEP, LONG unit )
|
||||
{
|
||||
struct MsgPort *port;
|
||||
LONG ret = 0,i;
|
||||
struct TagItem sv_tags[5];
|
||||
|
||||
/* server running ? */
|
||||
if( db->db_ServerProc )
|
||||
return 1;
|
||||
|
||||
if(!(port = CreateMsgPort() ))
|
||||
return 0;
|
||||
|
||||
sv_tags[i=0].ti_Tag = NP_Entry;
|
||||
sv_tags[i++].ti_Data = (ULONG)ServerTask;
|
||||
sv_tags[i ].ti_Tag = NP_Name;
|
||||
sv_tags[i++].ti_Data = (ULONG)db->db_Lib.lib_Node.ln_Name;
|
||||
sv_tags[i ].ti_Tag = NP_Priority;
|
||||
sv_tags[i++].ti_Data = (ULONG)0;
|
||||
sv_tags[i ].ti_Tag = TAG_DONE;
|
||||
|
||||
if( (db->db_ServerProc = CreateNewProc(sv_tags)))
|
||||
{
|
||||
/* server is running, wait for response */
|
||||
volatile struct ServerMsg msg;
|
||||
|
||||
msg.sm_devbase = db;
|
||||
msg.sm_result = 0;
|
||||
msg.sm_msg.mn_Length = sizeof(msg);
|
||||
msg.sm_msg.mn_ReplyPort = port;
|
||||
PutMsg( (struct MsgPort*)&db->db_ServerProc->pr_MsgPort, (struct Message*)&msg.sm_msg );
|
||||
WaitPort( port );
|
||||
ret = msg.sm_result; /* should be 1 */
|
||||
D(("Server answered with %ld\n",ret));
|
||||
}
|
||||
if( !ret )
|
||||
db->db_ServerProc = (0);
|
||||
|
||||
DeleteMsgPort( port );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* stop Server function */
|
||||
/* note: server is global right now */
|
||||
static LONG dbStopServer( DEVBASEP, LONG unit )
|
||||
{
|
||||
ULONG i=1;
|
||||
volatile struct Task *P;
|
||||
|
||||
/* server deletes itself from devbase */
|
||||
while( (P=(volatile struct Task*)db->db_ServerProc) )
|
||||
{
|
||||
Signal( (struct Task*)P, SIGBREAKF_CTRL_C);
|
||||
Delay(i);
|
||||
i = (i & 0xf) + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
delete all buffers (type references) associated with device opener
|
||||
*/
|
||||
static void dbDeleteBuffers( DEVBASEP, struct IOSana2Req *ioreq )
|
||||
{
|
||||
struct db_BufferManagement *dbm;
|
||||
ULONG ID = 0;
|
||||
|
||||
for( dbm = (struct db_BufferManagement *)db->db_BufferManagement.lh_Head;
|
||||
(dbm->dbm_n.mln_Succ) && (ioreq->ios2_BufferManagement != (VOID*)dbm);
|
||||
dbm = (struct db_BufferManagement *)dbm->dbm_n.mln_Succ ) {}
|
||||
|
||||
/* delete BufferManagement structure if it was allocated by us (should be) */
|
||||
if( dbm->dbm_n.mln_Succ )
|
||||
{
|
||||
ID = dbm->dbm_ID;
|
||||
Forbid();
|
||||
REMOVE( dbm );
|
||||
Permit();
|
||||
FreeMem( dbm, sizeof(struct db_BufferManagement) );
|
||||
ioreq->ios2_BufferManagement = (0);
|
||||
}
|
||||
|
||||
/* scan all buffers of current unit for opener ID and discard associated data */
|
||||
if( ID )
|
||||
{
|
||||
ULONG unit = (ULONG)ioreq->ios2_Req.io_Unit;
|
||||
|
||||
dbDeleteReader( db, unit, ID );
|
||||
}
|
||||
/* we assume that no requests were left in the queues -> TODO: add some debug info to verify */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
before calling:
|
||||
- get Semaphore
|
||||
- check BufferManagement
|
||||
- make sure ioreq is != NULL
|
||||
*/
|
||||
static void dbAddReadReq( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq )
|
||||
{
|
||||
struct SanaReadType *type;
|
||||
struct SanaReader *rd;
|
||||
ULONG frametype = ioreq->ios2_PacketType;
|
||||
ULONG ID = ((struct db_BufferManagement*)ioreq->ios2_BufferManagement)->dbm_ID;
|
||||
|
||||
/* find type or add it (typically 2 types present: IP,ARP) */
|
||||
type = (struct SanaReadType *)db->db_Units[unit].du_ReadTypes.lh_Head;
|
||||
while( (type->srt_Node.mln_Succ) )
|
||||
{
|
||||
if( type->srt_Type == frametype )
|
||||
goto havetype;
|
||||
|
||||
type = (struct SanaReadType *)type->srt_Node.mln_Succ;
|
||||
}
|
||||
#if 0
|
||||
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
if( type->srt_Type == frametype )
|
||||
goto havetype;
|
||||
type = GetSucc( type );
|
||||
}
|
||||
#endif
|
||||
if( !(type = dbAddType( db, unit, frametype ) ))
|
||||
return; /* bail out, no mem left */
|
||||
havetype:
|
||||
|
||||
/* traverse readers on type (usually 1 reader) */
|
||||
rd = (struct SanaReader *)GetHead( &type->srt_Readers );
|
||||
while( rd )
|
||||
{
|
||||
if( rd->snr_ID == ID )
|
||||
goto havereader;
|
||||
rd = GetSucc(rd);
|
||||
}
|
||||
if( !(rd = dbAddReader(db,unit,frametype,type,ID ) ))
|
||||
return; /* bail out, no mem left */
|
||||
havereader:
|
||||
|
||||
ADDTAIL( &rd->snr_Requests , (struct Node*)ioreq );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* add reader for frame type or directly to a type's list */
|
||||
static struct SanaReader *dbAddReader( DEVBASEP, ULONG unit, ULONG frametype, struct SanaReadType *type, ULONG ID )
|
||||
{
|
||||
struct SanaReader *rd;
|
||||
|
||||
if( !type ) /* search types for ID if not explicitly given */
|
||||
{
|
||||
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
if( type->srt_Type == frametype )
|
||||
break;
|
||||
type = GetSucc( type );
|
||||
}
|
||||
|
||||
if( !type )
|
||||
return (0); /* error: no such type */
|
||||
}
|
||||
|
||||
rd = (struct SanaReader *)GetHead( &type->srt_Readers );
|
||||
while( rd )
|
||||
{
|
||||
if( rd->snr_ID == ID )
|
||||
{
|
||||
return rd;
|
||||
}
|
||||
rd = GetSucc(rd);
|
||||
}
|
||||
|
||||
rd = (struct SanaReader *)AllocMem( sizeof( struct SanaReader ), MEMF_PUBLIC|MEMF_CLEAR );
|
||||
if( !rd )
|
||||
return (0);
|
||||
|
||||
rd->snr_ID = ID;
|
||||
dbNewList( &rd->snr_Requests );
|
||||
|
||||
if( (GetHead( &type->srt_Readers ) ))
|
||||
type->srt_Flags |= SRTF_MULTREADER;
|
||||
else type->srt_Flags |= SRTF_ONEREADER;
|
||||
|
||||
AddTail( &type->srt_Readers, (struct Node*)rd );
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
|
||||
/* delete all references to reader among all types of specified unit */
|
||||
static void dbDeleteReader( DEVBASEP, ULONG unit, ULONG ID )
|
||||
{
|
||||
/* traverse types */
|
||||
struct SanaReadType *type,*t2;
|
||||
struct SanaReader *rd;
|
||||
|
||||
type = (struct SanaReadType*)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
rd = (struct SanaReader *)GetHead( &type->srt_Readers );
|
||||
while( rd )
|
||||
{
|
||||
if( rd->snr_ID == ID )
|
||||
{
|
||||
REMOVE(rd);
|
||||
FreeMem(rd, sizeof( struct SanaReader ) );
|
||||
|
||||
if( (t2 = GetHead( &type->srt_Readers ) ) )
|
||||
{
|
||||
if( !(GetSucc(t2) ))
|
||||
t2->srt_Flags &= ~SRTF_MULTREADER;
|
||||
}
|
||||
else t2->srt_Flags &= ~(SRTF_ONEREADER|SRTF_MULTREADER);
|
||||
|
||||
break;
|
||||
}
|
||||
rd = GetSucc(rd);
|
||||
}
|
||||
type = GetSucc( type );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add frame type to Read Queue
|
||||
|
||||
note: the lifetime of read types is "infinite" right now, the
|
||||
type queues are deleted only on Device Expunge
|
||||
*/
|
||||
static struct SanaReadType *dbAddType( DEVBASEP, ULONG unit, ULONG frametype )
|
||||
{
|
||||
struct SanaReadType *type;
|
||||
|
||||
D(("dbAddType %ld to unit %ld\n",frametype,unit));
|
||||
|
||||
/* check whether type is existing */
|
||||
type = (struct SanaReadType*)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
if( type->srt_Type == frametype ) /* type present: do nothing */
|
||||
return type;
|
||||
|
||||
type = GetSucc( type );
|
||||
}
|
||||
|
||||
/* */
|
||||
type = (struct SanaReadType*)AllocMem( sizeof( struct SanaReadType ), MEMF_PUBLIC|MEMF_CLEAR );
|
||||
if( type )
|
||||
{
|
||||
D(("dbAddType new type %ld to unit %ld\n",frametype,unit));
|
||||
type->srt_Type = frametype;
|
||||
dbNewList( &type->srt_Readers );
|
||||
AddTail( (struct List*)&db->db_Units[unit].du_ReadTypes, (struct Node*)type );
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Delete Type and readers on that type
|
||||
*/
|
||||
static void dbDeleteType( DEVBASEP, ULONG unit, ULONG frametype )
|
||||
{
|
||||
struct SanaReadType *type;
|
||||
struct SanaReader *rd;
|
||||
|
||||
type = (struct SanaReadType*)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
if( type->srt_Type == frametype )
|
||||
break;
|
||||
|
||||
type = GetSucc( type );
|
||||
}
|
||||
|
||||
if( !type )
|
||||
return;
|
||||
|
||||
while( (rd = GetHead( &type->srt_Readers ) ))
|
||||
{
|
||||
REMOVE(rd);
|
||||
FreeMem(rd, sizeof( struct SanaReader ) );
|
||||
}
|
||||
|
||||
REMOVE(type);
|
||||
FreeMem( type, sizeof( struct SanaReadType ) );
|
||||
}
|
||||
|
||||
|
||||
/* do track type statistics (1) or toggle (0) */
|
||||
static LONG dbTrackType( DEVBASEP, ULONG unit, ULONG frametype, ULONG onoff )
|
||||
{
|
||||
struct SanaReadType *type = dbAddType( db, unit, frametype );
|
||||
LONG ret = 1;
|
||||
ULONG flg = 0;
|
||||
|
||||
if( !type )
|
||||
return 0;
|
||||
|
||||
if( onoff )
|
||||
{
|
||||
type->srt_Flags |= SRTF_TRACKTYPE;
|
||||
db->db_Units[unit].du_Flags |= DUF_TYPETRACK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if( !(type->srt_Flags & SRTF_TRACKTYPE ) )
|
||||
ret = 0;
|
||||
else
|
||||
type->srt_Flags ^= SRTF_TRACKTYPE;
|
||||
|
||||
/* set TYPETRACK flag if any type on unit is still tracked */
|
||||
/* well, actually this breaks if more than one stack is active. Duh. */
|
||||
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
if( type->srt_Flags & SRTF_TRACKTYPE )
|
||||
flg = DUF_TYPETRACK;
|
||||
type = GetSucc( type );
|
||||
}
|
||||
db->db_Units[unit].du_Flags &= ~DUF_TYPETRACK;
|
||||
db->db_Units[unit].du_Flags |= flg;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* return type statistics */
|
||||
static LONG dbTrackTypeStats( DEVBASEP, ULONG unit, ULONG frametype, struct Sana2PacketTypeStats *statptr )
|
||||
{
|
||||
struct SanaReadType *type = dbAddType( db, unit, frametype );
|
||||
if( !type )
|
||||
return 0;
|
||||
if( !(type->srt_Flags & SRTF_TRACKTYPE ) )
|
||||
return 0;
|
||||
|
||||
CopyMem( &type->srt_Sana2PacketTypeStats, statptr, sizeof(struct Sana2PacketTypeStats) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
device.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Device Functions and Definitions
|
||||
|
||||
|
||||
*/
|
||||
#ifndef _INC_DEVICE_H
|
||||
#define _INC_DEVICE_H
|
||||
|
||||
|
||||
/* defaults */
|
||||
#define MAX_UNITS 4
|
||||
#define DEF_BPS 10000000
|
||||
#define DEF_MTU 1500
|
||||
|
||||
|
||||
/* includes */
|
||||
#include "compiler.h"
|
||||
#include <dos/dos.h>
|
||||
#include <exec/lists.h>
|
||||
#include <exec/libraries.h>
|
||||
#include <exec/devices.h>
|
||||
#include <exec/semaphores.h>
|
||||
#include <devices/sana2.h>
|
||||
#include "hw.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/* reassign Library bases from global definitions to own struct */
|
||||
#define SysBase db->db_SysBase
|
||||
#define DOSBase db->db_DOSBase
|
||||
#define UtilityBase db->db_UtilityBase
|
||||
//#define VampireBase db->db_VampireBase
|
||||
|
||||
/* old sana2.h ? */
|
||||
#ifndef S2_CopyToBuff32
|
||||
#define S2_CopyToBuff32 (S2_Dummy + 6)
|
||||
#endif
|
||||
|
||||
#ifndef S2_CopyFromBuff32
|
||||
#define S2_CopyFromBuff32 (S2_Dummy + 7)
|
||||
#endif
|
||||
|
||||
struct ServerData {
|
||||
ULONG sv_flags;
|
||||
UBYTE *sv_frame; /* temporary frame for rx/tx */
|
||||
ULONG sv_framesize; /* allocated bytes */
|
||||
struct List sv_mclist; /* list of multicast addresses to accept */
|
||||
};
|
||||
|
||||
|
||||
#define DUB_OPEN 0
|
||||
#define DUB_EXCLUSIVE 1
|
||||
#define DUB_ONLINE 2
|
||||
#define DUB_TYPETRACK 3
|
||||
#define DUB_PROMISC 4
|
||||
#define DUF_OPEN (1<<DUB_OPEN)
|
||||
#define DUF_EXCLUSIVE (1<<DUB_EXCLUSIVE)
|
||||
#define DUF_ONLINE (1<<DUB_ONLINE)
|
||||
#define DUF_TYPETRACK (1<<DUB_TYPETRACK)
|
||||
#define DUF_PROMISC (1<<DUB_PROMISC)
|
||||
|
||||
|
||||
struct DevUnit {
|
||||
volatile struct List du_ReadTypes; /* RX queues are sorted by type: find RX buffers
|
||||
by type, afterwards traverse active readers =
|
||||
networking stacks */
|
||||
volatile struct List du_ReadOrphans; /* not claimed by RX types or no buffers available -> orphan */
|
||||
|
||||
volatile struct List du_WriteQueue; /* TX queue */
|
||||
volatile struct List du_EventQueue; /* Event queue */
|
||||
|
||||
struct SignalSemaphore du_Sem; /* list locking (global per unit) */
|
||||
|
||||
ULONG du_OpenCount; /* unit openers */
|
||||
ULONG du_Flags; /* unit flags */
|
||||
ULONG du_MTU; /* maximum transmission unit (1500 for regular Ethernet) */
|
||||
ULONG du_BitPerSec; /* speed in BPS */
|
||||
UBYTE du_HWAddr[6]; /* default MAC address */
|
||||
UBYTE du_CFGAddr[6]; /* configured MAC address */
|
||||
|
||||
struct Sana2DeviceStats du_DevStats; /* collect device stats per unit */
|
||||
|
||||
/* HW Data (generic for now) */
|
||||
ULONG du_hwl0;
|
||||
ULONG du_hwl1;
|
||||
ULONG du_hwl2;
|
||||
APTR du_hwp0;
|
||||
APTR du_hwp1;
|
||||
APTR du_hwp2;
|
||||
};
|
||||
|
||||
|
||||
struct devbase {
|
||||
struct Library db_Lib;
|
||||
BPTR db_SegList; /* from Device Init */
|
||||
|
||||
ULONG db_Flags; /* misc */
|
||||
struct Library *db_SysBase; /* Exec Base */
|
||||
struct Library *db_DOSBase;
|
||||
struct Library *db_UtilityBase;
|
||||
ULONG db_NBoards;
|
||||
ULONG db_ID; /* device opener ID enumeration */
|
||||
|
||||
struct DevUnit db_Units[MAX_UNITS]; /* don't bother with lists, who's gonna have more
|
||||
than 1 network card of the same type, anyway ? */
|
||||
|
||||
/* server process data */
|
||||
volatile struct Process *db_ServerProc; /* process of main queue server */
|
||||
struct Task *db_Task; /* server shutdown task address (non permanently available) */
|
||||
ULONG db_ServerSigMask; /* shutdown signal */
|
||||
struct MsgPort *db_ServerPort; /* request forwarding (initialized by server) */
|
||||
|
||||
/* housekeeping */
|
||||
struct List db_BufferManagement; /* remember allocated instances */
|
||||
|
||||
/* services for other instances (server task, hw.c) */
|
||||
struct ServerData db_svdat; /* private data for main server */
|
||||
struct HWData db_hwdat; /* private data for hardware interface */
|
||||
};
|
||||
|
||||
|
||||
typedef BOOL (* ASM BMCALL)( ASMR(a0) void * ASMREG(a0), ASMR(a1) void * ASMREG(a1), ASMR(d0) LONG ASMREG(d0) );
|
||||
|
||||
struct db_BufferManagement {
|
||||
struct MinNode dbm_n;
|
||||
BMCALL dbm_CopyFromBuffer32;
|
||||
BMCALL dbm_CopyToBuffer32;
|
||||
BMCALL dbm_CopyFromBuffer;
|
||||
BMCALL dbm_CopyToBuffer;
|
||||
ULONG dbm_ID;
|
||||
};
|
||||
|
||||
#ifndef DEVBASETYPE
|
||||
#define DEVBASETYPE struct devbase
|
||||
#endif
|
||||
#ifndef DEVBASEP
|
||||
#define DEVBASEP DEVBASETYPE *db
|
||||
#endif
|
||||
|
||||
struct ServerMsg {
|
||||
struct Message sm_msg;
|
||||
DEVBASETYPE *sm_devbase;
|
||||
LONG sm_result;
|
||||
};
|
||||
|
||||
|
||||
/* frame type management:
|
||||
- every network stack who is interested in a specific type gets a "reader" assigned to
|
||||
that type. The ID tracked here is the same that is assigned on OpenDevice and stored
|
||||
in the buffer management
|
||||
-
|
||||
*/
|
||||
struct SanaReader
|
||||
{
|
||||
struct MinNode snr_Node;
|
||||
ULONG snr_ID; /* assigned to any reader on Device open */
|
||||
struct List snr_Requests;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
read list(s)
|
||||
- multiple readers supported (i.e. multiple active Networking stacks)
|
||||
- one read list per type (shouldn't be too many)
|
||||
- two major thoughts behind this
|
||||
- track type statistics without additional search
|
||||
- received frame copy to additional reader(s) without searching through
|
||||
their read request lists
|
||||
+ avoid long searches for orphans (unexpected received frames)
|
||||
*/
|
||||
struct SanaReadType
|
||||
{
|
||||
struct MinNode srt_Node;
|
||||
ULONG srt_Type; /* Type ID - matches Ethernet Types */
|
||||
ULONG srt_Flags; /* Flags: multiple reader mode, do track type */
|
||||
|
||||
struct List srt_Readers; /* active readers */
|
||||
|
||||
/* SANA-II Type statistics */
|
||||
struct Sana2PacketTypeStats srt_Sana2PacketTypeStats;
|
||||
|
||||
ULONG srt_FramesSent;
|
||||
ULONG srt_FramesRcvd;
|
||||
ULONG srt_BytesSent;
|
||||
ULONG srt_BytesRcvd;
|
||||
ULONG srt_FramesDropped;
|
||||
};
|
||||
|
||||
/* SanaReadList flags */
|
||||
#define SRTB_ONEREADER 0 /* at least one reader present ? */
|
||||
#define SRTB_MULTREADER 1 /* more than one reader */
|
||||
#define SRTB_TRACKTYPE 2 /* perform track type statistics */
|
||||
#define SRTF_ONEREADER (1<<SRTB_ONEREADER)
|
||||
#define SRTF_MULTREADER (1<<SRTB_MULTREADER)
|
||||
#define SRTF_TRACKTYPE (1<<SRTB_TRACKTYPE)
|
||||
|
||||
/* server maintains list of multicast addresses */
|
||||
struct MCastEntry
|
||||
{
|
||||
struct MinNode mce_Node;
|
||||
UBYTE mce_start[6];
|
||||
UBYTE mce_stop[6];
|
||||
ULONG mce_refcount; /* ok, this is poor. Proper would mean "track by caller". */
|
||||
/* But hey, how much multicast do you encounter on Amiga? */
|
||||
};
|
||||
|
||||
/* PROTOS */
|
||||
|
||||
ASM LONG LibNull( void );
|
||||
|
||||
ASM SAVEDS struct Device *DevInit(ASMR(d0) DEVBASEP ASMREG(d0),
|
||||
ASMR(a0) BPTR seglist ASMREG(a0),
|
||||
ASMR(a6) struct Library *_SysBase ASMREG(a6) );
|
||||
|
||||
ASM SAVEDS LONG DevOpen( ASMR(a1) struct IOSana2Req *ios2 ASMREG(a1),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(d1) ULONG flags ASMREG(d1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) );
|
||||
|
||||
ASM SAVEDS BPTR DevClose( ASMR(a1) struct IOSana2Req *ios2 ASMREG(a1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) );
|
||||
|
||||
ASM SAVEDS BPTR DevExpunge( ASMR(a6) DEVBASEP ASMREG(a6) );
|
||||
|
||||
ASM SAVEDS VOID DevBeginIO( ASMR(a1) struct IOSana2Req *ios2 ASMREG(a1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) );
|
||||
|
||||
ASM SAVEDS LONG DevAbortIO( ASMR(a1) struct IOSana2Req *ios2 ASMREG(a1),
|
||||
ASMR(a6) DEVBASEP ASMREG(a6) );
|
||||
|
||||
void dbTermIO( DEVBASETYPE*, struct IOSana2Req * );
|
||||
|
||||
/* server.c */
|
||||
VOID SAVEDS ServerTask(void);
|
||||
|
||||
/* private functions */
|
||||
#ifdef DEVICE_MAIN
|
||||
|
||||
static void dbNewList( struct List * );
|
||||
static LONG dbIsInList( struct List *, struct Node * );
|
||||
|
||||
static LONG dbStartServer( DEVBASETYPE*, LONG );
|
||||
static LONG dbStopServer( DEVBASETYPE*, LONG );
|
||||
|
||||
static void dbDeleteBuffers( DEVBASETYPE*, struct IOSana2Req * );
|
||||
|
||||
static void dbAddReadReq( DEVBASETYPE*, ULONG , struct IOSana2Req * );
|
||||
|
||||
static struct SanaReader*dbAddReader( DEVBASETYPE*, ULONG, ULONG, struct SanaReadType *, ULONG );
|
||||
static void dbDeleteReader( DEVBASETYPE*, ULONG, ULONG );
|
||||
|
||||
static struct SanaReadType *dbAddType( DEVBASETYPE*, ULONG, ULONG );
|
||||
static void dbDeleteType( DEVBASETYPE*, ULONG, ULONG );
|
||||
|
||||
static void dbForwardIO( DEVBASETYPE*, struct IOSana2Req * );
|
||||
|
||||
static LONG dbTrackType(DEVBASETYPE*, ULONG, ULONG, ULONG );
|
||||
static LONG dbTrackTypeStats( DEVBASETYPE*, ULONG, ULONG, struct Sana2PacketTypeStats *);
|
||||
#endif /* DEVICE_MAIN */
|
||||
|
||||
|
||||
#endif /* _INC_DEVICE_H */
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Device Header - ROMTAG
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
taken from commandline (compiler options)
|
||||
-DDEVICENAME=blah.device
|
||||
-DDEVICEVERSION=45
|
||||
-DDEVICEREVISION=36
|
||||
-DDEVICEDATE=2.12.2012
|
||||
|
||||
*/
|
||||
|
||||
#include <exec/resident.h>
|
||||
#include <exec/nodes.h>
|
||||
#include <exec/initializers.h>
|
||||
#include <exec/libraries.h>
|
||||
#include "compiler.h"
|
||||
#include "device.h"
|
||||
|
||||
/* Enable this if you want pure C for the device. (disable compilation of romtag.asm in that case)
|
||||
I personally prefer the small ASM blob to steer away from linking challenges.
|
||||
*/
|
||||
#if 1
|
||||
|
||||
ASM LONG LibNull( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern const BYTE DeviceName[];
|
||||
extern const BYTE DeviceVersionString[];
|
||||
extern const APTR DeviceInitTab[];
|
||||
|
||||
const struct Resident _00RomTag = {
|
||||
RTC_MATCHWORD,
|
||||
( struct Resident* ) &_00RomTag,
|
||||
( struct Resident* ) &_00RomTag + 1,
|
||||
RTF_AUTOINIT,
|
||||
DEVICEVERSION,
|
||||
NT_DEVICE,
|
||||
0,
|
||||
(BYTE*)DeviceName,
|
||||
(BYTE*)DeviceVersionString+6,
|
||||
(APTR)DeviceInitTab
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
devinit.c
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
initialization structures and data
|
||||
|
||||
*/
|
||||
#include <proto/exec.h>
|
||||
#include <proto/utility.h>
|
||||
#include <proto/dos.h>
|
||||
#include <dos/dostags.h>
|
||||
#include <utility/tagitem.h>
|
||||
#include <exec/lists.h>
|
||||
#include "device.h"
|
||||
#include "hw.h"
|
||||
#include "macros.h"
|
||||
#include <exec/initializers.h>
|
||||
|
||||
#define xstr(a) str(a)
|
||||
#define str(a) #a
|
||||
|
||||
#ifndef DEVICEEXTRA
|
||||
#define DEVICEEXTRA
|
||||
#endif
|
||||
|
||||
const BYTE DeviceVersionString[] = "$VER: " xstr(DEVICENAME) " " xstr(DEVICEVERSION) "." xstr(DEVICEREVISION) xstr(DEVICEEXTRA) " (" xstr(DEVICEDATE) ")";
|
||||
const BYTE DeviceName[] = xstr(DEVICENAME);
|
||||
|
||||
|
||||
const APTR DeviceFunctions[] = {
|
||||
(APTR) DevOpen,
|
||||
(APTR) DevClose,
|
||||
(APTR) DevExpunge,
|
||||
(APTR) LibNull,
|
||||
(APTR) DevBeginIO,
|
||||
(APTR) DevAbortIO,
|
||||
(APTR) -1
|
||||
};
|
||||
|
||||
|
||||
#define WORDINIT(_a_) UWORD _a_ ##W1; UWORD _a_ ##W2; UWORD _a_ ##ARG;
|
||||
#define LONGINIT(_a_) UBYTE _a_ ##A1; UBYTE _a_ ##A2; ULONG _a_ ##ARG;
|
||||
struct DeviceInitData
|
||||
{
|
||||
WORDINIT(w1)
|
||||
LONGINIT(l1)
|
||||
WORDINIT(w2)
|
||||
WORDINIT(w3)
|
||||
WORDINIT(w4)
|
||||
LONGINIT(l2)
|
||||
ULONG end_initlist;
|
||||
} DeviceInitializers =
|
||||
{
|
||||
INITBYTE( STRUCTOFFSET( Node, ln_Type), NT_DEVICE),
|
||||
0x80, (UBYTE) STRUCTOFFSET( Node, ln_Name), (ULONG) &DeviceName[0],
|
||||
INITBYTE( STRUCTOFFSET(Library,lib_Flags), LIBF_SUMUSED|LIBF_CHANGED ),
|
||||
INITWORD( STRUCTOFFSET(Library,lib_Version), DEVICEVERSION ),
|
||||
INITWORD( STRUCTOFFSET(Library,lib_Revision), DEVICEREVISION ),
|
||||
0x80, (UBYTE) STRUCTOFFSET(Library,lib_IdString), (ULONG) &DeviceVersionString[6],
|
||||
(ULONG) 0
|
||||
};
|
||||
|
||||
|
||||
const APTR DeviceInitTab[] = {
|
||||
(APTR) sizeof( DEVBASETYPE ),
|
||||
(APTR) &DeviceFunctions,
|
||||
(APTR) &DeviceInitializers,
|
||||
(APTR) DevInit
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Device Header
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
taken from commandline (compiler options)
|
||||
-DDEVICENAME=blah.device
|
||||
-DDEVICEVERSION=45
|
||||
-DDEVICEREVISION=36
|
||||
-DDEVICEDATE=2.12.2012
|
||||
|
||||
*/
|
||||
|
||||
#include <exec/resident.h>
|
||||
#include <exec/nodes.h>
|
||||
#include <exec/initializers.h>
|
||||
#include <exec/libraries.h>
|
||||
#include "compiler.h"
|
||||
#include "device.h"
|
||||
|
||||
#define xstr(a) str(a)
|
||||
#define str(a) #a
|
||||
|
||||
#if 1
|
||||
|
||||
/* Enable this if you want pure C for the device. (disable compilation of romtag.asm in that case)
|
||||
I personally prefer the small ASM blob to steer away from linking challenges.
|
||||
*/
|
||||
const BYTE DeviceName[];
|
||||
const BYTE DeviceVersionString[];
|
||||
const APTR DeviceInitTab[];
|
||||
|
||||
|
||||
const struct Resident RomTag = {
|
||||
RTC_MATCHWORD,
|
||||
( struct Resident* ) &RomTag,
|
||||
( struct Resident* ) &RomTag + 1,
|
||||
RTF_AUTOINIT,
|
||||
DEVICEVERSION,
|
||||
NT_DEVICE,
|
||||
0,
|
||||
(BYTE*)DeviceName,
|
||||
(BYTE*)DeviceVersionString+6,
|
||||
(APTR)DeviceInitTab
|
||||
};
|
||||
#endif
|
||||
|
||||
const BYTE DeviceVersionString[] = "$VER: " xstr(DEVICENAME) " " xstr(DEVICEVERSION) "." xstr(DEVICEREVISION) " (" xstr(DEVICEDATE) ")";
|
||||
const BYTE DeviceName[] = xstr(DEVICENAME);
|
||||
|
||||
const APTR DeviceFunctions[] = {
|
||||
(APTR) DevOpen,
|
||||
(APTR) DevClose,
|
||||
(APTR) DevExpunge,
|
||||
(APTR) LibNull,
|
||||
(APTR) DevBeginIO,
|
||||
(APTR) DevAbortIO,
|
||||
(APTR) -1
|
||||
};
|
||||
|
||||
|
||||
#define WORDINIT(_a_) UWORD _a_ ##W1; UWORD _a_ ##W2; UWORD _a_ ##ARG;
|
||||
#define LONGINIT(_a_) UBYTE _a_ ##A1; UBYTE _a_ ##A2; ULONG _a_ ##ARG;
|
||||
struct DeviceInitData
|
||||
{
|
||||
WORDINIT(w1)
|
||||
LONGINIT(l1)
|
||||
WORDINIT(w2)
|
||||
WORDINIT(w3)
|
||||
WORDINIT(w4)
|
||||
LONGINIT(l2)
|
||||
ULONG end_initlist;
|
||||
} DeviceInitializers =
|
||||
{
|
||||
INITBYTE( STRUCTOFFSET( Node, ln_Type), NT_DEVICE),
|
||||
0x80, (UBYTE) STRUCTOFFSET( Node, ln_Name), (ULONG) &DeviceName[0],
|
||||
INITBYTE( STRUCTOFFSET(Library,lib_Flags), LIBF_SUMUSED|LIBF_CHANGED ),
|
||||
INITWORD( STRUCTOFFSET(Library,lib_Version), DEVICEVERSION ),
|
||||
INITWORD( STRUCTOFFSET(Library,lib_Revision), DEVICEREVISION ),
|
||||
0x80, (UBYTE) STRUCTOFFSET(Library,lib_IdString), (ULONG) &DeviceVersionString[6],
|
||||
(ULONG) 0
|
||||
};
|
||||
|
||||
|
||||
const APTR DeviceInitTab[] = {
|
||||
(APTR) sizeof( DEVBASETYPE ),
|
||||
(APTR) &DeviceFunctions,
|
||||
(APTR) &DeviceInitializers,
|
||||
(APTR) DevInit
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
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 "compiler.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
|
||||
|
||||
/*-- --*/
|
||||
/*------------- <DANGER! APPLY CHANGES IN HERE ALSO TO enc624j6l.asm !!> ----------*/
|
||||
/*-- --*/
|
||||
/* buffers and locations */
|
||||
#define PSTART_INIT 0x0BF0 /* 16 Bytes private storage for driver */
|
||||
#define PSTOP_INIT 0x0BFF /* (see below for definitions) */
|
||||
|
||||
#define RXSTART_INIT 0x2000 /* start of RX buffer, room for 14 packets */
|
||||
#define RXSTOP_INIT 0x5fff /* end of RX buffer */
|
||||
|
||||
#define TXSTART_INIT 0x0000 /* start of TX buffer, room for 2 packets */
|
||||
#define TXSTOP_INIT 0x0BEF /* end of TX buffer (1536+1520 bytes) */
|
||||
|
||||
/* max frame length which the conroller will accept:
|
||||
(note: maximum ethernet frame length would be 1518 w/o 802.1Q) */
|
||||
#define MAX_FRAMELEN 1518
|
||||
|
||||
/* ------------ driver private storage ------------------------------ */
|
||||
#define PNextPacket PSTART_INIT /* 2 Bytes - private "next packet" pointer for RX */
|
||||
#define PNextTX PSTART_INIT+2 /* 2 Bytes - private "next packet" pointer for TX (init as 0) */
|
||||
#define PSigBit PSTART_INIT+4 /* 2 Bytes interrupt bit */
|
||||
#define PSigTask PSTART_INIT+6 /* 4 Bytes signaled task */
|
||||
#define PLinkChange PSTART_INIT+10 /* 2 Bytes Link Change (Bit0 used right now) */
|
||||
#define Punused PSTART_INIT+12 /* */
|
||||
|
||||
/* ------------- TX: double buffering -------------------------------- */
|
||||
#define PSwapTX 0x600 /* swap between two TX buffers (one active, one activated after last TX done) */
|
||||
/*-- --*/
|
||||
/*------------- </DANGER! APPLY CHANGES IN HERE ALSO TO enc624j6l.asm !!> ---------*/
|
||||
/*-- --*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
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: enable global HW interrupt flag on the LAN-Chip
|
||||
|
||||
input: board - mmapped board base address
|
||||
|
||||
|
||||
notes:
|
||||
*/
|
||||
ASM SAVEDS void enc624j6l_EnableGlobalInterrupt( ASMR(a0) void *board ASMREG(a0) );
|
||||
|
||||
|
||||
/*
|
||||
Purpose: disable global HW interrupt flag on the LAN-Chip
|
||||
|
||||
input: board - mmapped board base address
|
||||
|
||||
notes:
|
||||
*/
|
||||
ASM SAVEDS void enc624j6l_DisableGlobalInterrupt( 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_List( void );
|
||||
|
||||
/*
|
||||
Purpose: check for link change events
|
||||
|
||||
input: board - mmapped board base address
|
||||
|
||||
output: <0 - error
|
||||
0 - ok, no link change handled
|
||||
>0 - ok, link change handled
|
||||
|
||||
notes:
|
||||
|
||||
*/
|
||||
ASM SAVEDS int enc624j6l_CheckLinkChange( ASMR(a0) void *board ASMREG(a0) );
|
||||
|
||||
|
||||
|
||||
#endif /* _INC_ENC624J6L_H */
|
||||
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
hw.c
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
SDNet hardware interface to device
|
||||
|
||||
|
||||
*/
|
||||
#include <exec/libraries.h>
|
||||
#include <proto/exec.h>
|
||||
|
||||
/*#include <clib/expansion_protos.h>
|
||||
#include <pragmas/expansion_pragmas.h>*/
|
||||
#include <proto/expansion.h>
|
||||
#include <libraries/configvars.h>
|
||||
#include <hardware/intbits.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "hw.h"
|
||||
|
||||
#include "enc624j6l.h"
|
||||
#include "registers.h"
|
||||
|
||||
extern const BYTE DeviceName[];
|
||||
|
||||
#define ENC_MANUFACTURER 2588
|
||||
#define ENC_BOARD 123
|
||||
|
||||
/* use generic board fields in current unit */
|
||||
#define duh_online du_hwl0
|
||||
#define duh_BASE du_hwp0
|
||||
|
||||
#define HW_INTERVALDEF 100000L
|
||||
|
||||
/* 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 */ /* Int 6 */
|
||||
#define HW_INTSOURCE INTB_PORTS /* Int 2 */
|
||||
|
||||
#define READREG(_x_,_off_) *( (volatile USHORT*)( (volatile UBYTE*)(_x_) + (_off_)) )
|
||||
#define WRITEREG(_x_,_off_,_y_) *( (volatile USHORT*)( (volatile UBYTE*)(_x_) + (_off_)) ) = (_y_);
|
||||
#define SETREG(_x_,_off_,_y_) *( (volatile USHORT*)( (volatile UBYTE*)(_x_) + (_off_) + SET_OFFSET )) = (_y_);
|
||||
#define CLRREG(_x_,_off_,_y_) *( (volatile USHORT*)( (volatile UBYTE*)(_x_) + (_off_) + CLR_OFFSET )) = (_y_);
|
||||
|
||||
void myhw_ControlInterrupts( DEVBASEP );
|
||||
void myhw_ControlIntervalTimer( DEVBASEP );
|
||||
|
||||
|
||||
/* these calls might not run within the context of a process and
|
||||
will be called from varying tasks and without prior init:
|
||||
hw_Find_Boards()
|
||||
hw_AllocBoard()
|
||||
hw_ReleaseBoard()
|
||||
hw_GetMacAddress()
|
||||
|
||||
these calls are in the context of the server task:
|
||||
hw_Setup() - general init (board allocated already)
|
||||
hw_Shutdown() - general shutdown (board still allocated)
|
||||
hw_Attach() - make hardware ready for action (online)
|
||||
hw_Detach() - put hardware into sleep mode (offline)
|
||||
|
||||
hw_recv_sigmask() - get signals for hardware (if any)
|
||||
hw_recv_pending() - check for pending receive frames
|
||||
|
||||
hw_recv_frame() - receive one frame
|
||||
hw_send_frame() - send one frame
|
||||
hw_check_link_change() - check if HW link parameters need update
|
||||
and apply them (called only when no RX/TX
|
||||
in progress)
|
||||
|
||||
hw_config_init() - set defaults for HW
|
||||
hw_config_update() - update config of HW
|
||||
*/
|
||||
|
||||
const BYTE exp_name[] = "expansion.library";
|
||||
const BYTE intname[] = "enc264j6net SanaII driver";
|
||||
|
||||
/* return number of boards present in system */
|
||||
ASM SAVEDS LONG hw_Find_Boards( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
LONG i,ret = 0;
|
||||
struct Library *ExpansionBase;
|
||||
struct ConfigDev *cfg = (0);
|
||||
|
||||
if( (ExpansionBase = OpenLibrary( exp_name, 37 )) )
|
||||
{
|
||||
/* TODO: check for expansion port, i.e. distinguish V500/V600 */
|
||||
/* TODO: actually verify that we have a module here */
|
||||
ret = 1;
|
||||
|
||||
for( i=0 ; i < MAX_UNITS ; i++ )
|
||||
{
|
||||
cfg = FindConfigDev( cfg, ENC_MANUFACTURER, ENC_BOARD );
|
||||
if( !cfg )
|
||||
break;
|
||||
db->db_Units[i].duh_BASE = (APTR)cfg->cd_BoardAddr;
|
||||
D(("Board at %lx\n",(ULONG)cfg->cd_BoardAddr ));
|
||||
}
|
||||
ret = i;
|
||||
D(("%ld boards found\n",ret));
|
||||
CloseLibrary( ExpansionBase );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_AllocBoard( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
/* is there a way to lock a ZII Board ? */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_ReleaseBoard( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* store MAC address at "mac", 6 Bytes */
|
||||
ASM SAVEDS LONG hw_GetMacAddress( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *mac ASMREG(a1)
|
||||
)
|
||||
{
|
||||
APTR boardbase = db->db_Units[unit].duh_BASE;
|
||||
|
||||
enc624j6l_GetMAC( boardbase, mac );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* prepare all boards such that a hw_attach() will succeed */
|
||||
ASM SAVEDS LONG hw_Setup( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
LONG ret = 0;
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
InitSemaphore( &hwd->hwd_Sem );
|
||||
|
||||
hwd->hwd_IntSig = AllocSignal(-1);
|
||||
hwd->hwd_Interrupt.is_Data = (0);
|
||||
|
||||
if( InitIntervalTimer( &hwd->ivtimer ) > 0 )
|
||||
{
|
||||
hwd->hwd_SigMask = hwd->ivtimer.IVT_SigMask | (1<<(hwd->hwd_IntSig)) ;
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* free resources, server is quitting */
|
||||
ASM SAVEDS void hw_Shutdown( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
LONG i;
|
||||
|
||||
/* safety measure */
|
||||
for( i=0 ; i < db->db_NBoards ; i++ )
|
||||
db->db_Units[i].duh_online = 0;
|
||||
myhw_ControlInterrupts( db );
|
||||
myhw_ControlIntervalTimer( db );
|
||||
|
||||
|
||||
if( hwd->hwd_IntSig >= 0 )
|
||||
FreeSignal( hwd->hwd_IntSig );
|
||||
|
||||
ExitIntervalTimer( &hwd->ivtimer );
|
||||
}
|
||||
|
||||
|
||||
/* bring hardware online */
|
||||
ASM SAVEDS LONG hw_Attach( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0))
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
APTR boardbase = db->db_Units[unit].duh_BASE;
|
||||
LONG ret = 1;
|
||||
ULONG flags;
|
||||
|
||||
|
||||
flags = PIO_INIT_BROAD_CAST;
|
||||
if( hwd->multicast )
|
||||
flags |= PIO_INIT_MULTI_CAST;
|
||||
|
||||
if( hwd->fullduplex )
|
||||
flags |= PIO_INIT_FULL_DUPLEX;
|
||||
|
||||
if( hwd->flowcontrol )
|
||||
flags |= PIO_INIT_FLOW_CONTROL;
|
||||
|
||||
if( enc624j6l_Init( boardbase, flags ) <= 0 )
|
||||
ret = 0; /* ERROR IN CASE OF DEVICE NOT FOUND */
|
||||
else
|
||||
{
|
||||
enc624j6l_SetMAC( boardbase, db->db_Units[unit].du_CFGAddr );
|
||||
enc624j6l_SetOnline( boardbase );
|
||||
|
||||
db->db_Units[unit].duh_online = 1; /* used for int server and interval timer setup */
|
||||
|
||||
myhw_ControlInterrupts( db ); /* start and/or stop (based on duh_online) */
|
||||
myhw_ControlIntervalTimer( db ); /* start and/or stop timer (based on duh_online) */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* put hardware into sleep mode (offline) */
|
||||
ASM SAVEDS void hw_Detach( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0))
|
||||
{
|
||||
APTR boardbase = db->db_Units[unit].duh_BASE;
|
||||
|
||||
db->db_Units[unit].duh_online = 0; /* used for int server and interval timer setup */
|
||||
|
||||
myhw_ControlInterrupts( db ); /* start and/or stop (based on duh_online) */
|
||||
myhw_ControlIntervalTimer( db ); /* start and/or stop timer (based on duh_online) */
|
||||
|
||||
enc624j6l_SetOffline( boardbase );
|
||||
enc624j6l_Shutdown( boardbase );
|
||||
}
|
||||
|
||||
|
||||
|
||||
ASM SAVEDS void hw_ConfigInit( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
hwd->timervalue = HW_INTERVALDEF;
|
||||
hwd->fullduplex = 0;
|
||||
hwd->flowcontrol = 0;
|
||||
hwd->multicast = 0;
|
||||
#if 0
|
||||
USHORT i;
|
||||
for( i=0 ; i < (USHORT)db->db_NBoards ; i++ )
|
||||
{ /* no need, these are defaults */
|
||||
db->db_Units[i].du_MTU = 1500;
|
||||
db->db_Units[i].du_BitPerSec = 10000000;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
ASM SAVEDS void hw_ConfigUpdate( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(a1) void*argsv ASMREG(a1))
|
||||
{
|
||||
struct HWConfig *args = (struct HWConfig *)argsv; /* see hwprivate.h */
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
if( args->timervalue )
|
||||
hwd->timervalue = *args->timervalue;
|
||||
if( args->fullduplex )
|
||||
hwd->fullduplex = 1;
|
||||
if( args->flowcontrol )
|
||||
hwd->flowcontrol = 1;
|
||||
if( args->multicast )
|
||||
hwd->multicast = 1;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_send_frame( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *frame ASMREG(a1),
|
||||
ASMR(d1) ULONG framesize ASMREG(d1) )
|
||||
{
|
||||
enc624j6l_TransmitFrame( db->db_Units[unit].duh_BASE, frame, framesize );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_recv_pending( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
APTR board = db->db_Units[unit].duh_BASE;
|
||||
|
||||
return enc624j6l_HaveRecv( board );
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_recv_frame( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *frame ASMREG(a1))
|
||||
{
|
||||
LONG len;
|
||||
APTR board = db->db_Units[unit].duh_BASE;
|
||||
|
||||
len = enc624j6l_RecvFrame( board, frame, 1522 );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS ULONG hw_recv_sigmask( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
return hwd->hwd_SigMask;
|
||||
}
|
||||
|
||||
/* check if HW link parameters need update -> only when board is idle otherwise (no RX/TX) */
|
||||
/* re-enables hardware interrupt */
|
||||
ASM SAVEDS LONG hw_check_link_change( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
APTR boardbase = db->db_Units[unit].duh_BASE;
|
||||
|
||||
enc624j6l_CheckLinkChange( boardbase ); /* somewhere $e90000 and beyond */
|
||||
|
||||
if( db->db_Units[unit].duh_online )
|
||||
enc624j6l_EnableGlobalInterrupt( boardbase );
|
||||
|
||||
return 1; /* don't signal panic to the outside, everything is under control */
|
||||
}
|
||||
|
||||
ASM SAVEDS LONG hw_change_multicast( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(a0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) struct List *mclist ASMREG(a1) )
|
||||
{
|
||||
|
||||
/* TODO: implement Multicast hashing */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* global for all boards (relies on hwd_online) */
|
||||
void myhw_ControlInterrupts( DEVBASEP )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
LONG i,flag;
|
||||
|
||||
ObtainSemaphore( &hwd->hwd_Sem ); /* redundant here: server is a single task -> but it looks good :-) */
|
||||
|
||||
flag = 0;
|
||||
for( i=0 ; i < db->db_NBoards ; i++ )
|
||||
{
|
||||
if( db->db_Units[i].duh_online )
|
||||
{
|
||||
hwd->hwd_act_boards[flag] = db->db_Units[i].duh_BASE;
|
||||
flag++;
|
||||
}
|
||||
}
|
||||
hwd->hwd_act_boards[flag] = (0); /* NULL-terminate */
|
||||
hwd->hwd_act_boards[flag+1] = (APTR)FindTask(0); /* append task */
|
||||
hwd->hwd_act_boards[flag+2] = (APTR)hwd->hwd_IntSig; /* append sigbit */
|
||||
|
||||
if( flag ) /* determine on/off switch */
|
||||
{
|
||||
/* at least 1 board is online */
|
||||
if( hwd->hwd_Interrupt.is_Data )
|
||||
flag = 0; /* no change */
|
||||
else flag = 1; /* start timer */
|
||||
}
|
||||
else
|
||||
{
|
||||
if( hwd->hwd_Interrupt.is_Data )
|
||||
flag = -1; /* stop timer */
|
||||
else flag = 0; /* no change */
|
||||
}
|
||||
|
||||
/* flag is >0 = start, <0 = stop or 0 = no change */
|
||||
if( flag > 0 )
|
||||
{
|
||||
hwd->hwd_Interrupt.is_Code = (void(*)())enc624j6l_IntServer_List;
|
||||
hwd->hwd_Interrupt.is_Data = &hwd->hwd_act_boards[0];
|
||||
hwd->hwd_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
|
||||
hwd->hwd_Interrupt.is_Node.ln_Pri = 51;
|
||||
hwd->hwd_Interrupt.is_Node.ln_Name = (char*)intname;
|
||||
AddIntServer( HW_INTSOURCE, &hwd->hwd_Interrupt );
|
||||
}
|
||||
|
||||
for( i=0 ; i < db->db_NBoards ; i++ )
|
||||
{
|
||||
if( db->db_Units[i].duh_online )
|
||||
enc624j6l_EnableInterrupt( db->db_Units[i].duh_BASE, FindTask(0), (int)hwd->hwd_IntSig, 0 );
|
||||
else
|
||||
enc624j6l_DisableInterrupt( db->db_Units[i].duh_BASE );
|
||||
}
|
||||
|
||||
if( flag < 0 )
|
||||
{
|
||||
hwd->hwd_Interrupt.is_Data = (0);
|
||||
RemIntServer( HW_INTSOURCE, &hwd->hwd_Interrupt );
|
||||
hwd->hwd_Interrupt.is_Code = (0);
|
||||
}
|
||||
|
||||
ReleaseSemaphore( &hwd->hwd_Sem );
|
||||
}
|
||||
|
||||
|
||||
/* global for all boards (relies on hwd_online) */
|
||||
void myhw_ControlIntervalTimer( DEVBASEP )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
LONG i,flag;
|
||||
|
||||
ObtainSemaphore( &hwd->hwd_Sem );
|
||||
|
||||
flag = 0;
|
||||
for( i=0 ; i < db->db_NBoards ; i++ )
|
||||
{
|
||||
if( db->db_Units[i].duh_online )
|
||||
flag = 1;
|
||||
}
|
||||
if( flag )
|
||||
{
|
||||
/* at least 1 board is online */
|
||||
if( hwd->ivtimer.IVT_Runflag )
|
||||
flag = 0; /* no change */
|
||||
else flag = 1; /* start timer */
|
||||
}
|
||||
else
|
||||
{
|
||||
if( hwd->ivtimer.IVT_Runflag )
|
||||
flag = -1; /* stop timer */
|
||||
else flag = 0; /* no change */
|
||||
}
|
||||
|
||||
if( flag > 0 )
|
||||
StartIntervalTimer( &hwd->ivtimer, hwd->timervalue );
|
||||
if( flag < 0 )
|
||||
StopIntervalTimer( &hwd->ivtimer );
|
||||
|
||||
ReleaseSemaphore( &hwd->hwd_Sem );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
hwprivate.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
private structures for hardware instance
|
||||
|
||||
|
||||
*/
|
||||
#ifndef _INC_HWPRIVATE_H
|
||||
#define _INC_HWPRIVATE_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* sdnet/v2expnet specific: polling timer */
|
||||
#include "intervaltimer.h"
|
||||
|
||||
/* this struct is available in devicebase and should carry global information */
|
||||
struct HWData {
|
||||
struct Interrupt hwd_Interrupt; /* keep the interrupt at top of HWData !! */
|
||||
struct SignalSemaphore hwd_Sem; /* list locking (global per unit) */
|
||||
APTR hwd_act_boards[MAX_UNITS+1+2]; /* poll all active boards by ptr in interrupt, NULL terminated, followed by SigTask,Sigbit */
|
||||
|
||||
ULONG hwd_SigMask; /* signal mask to wait for in server main instance */
|
||||
|
||||
struct IVT_TimerStruct ivtimer; /* Timer interval handling (via Interrupt) */
|
||||
LONG TimerUsed; /* number of instances running */
|
||||
LONG hwd_IntSig;
|
||||
|
||||
/* config options */
|
||||
ULONG timervalue; /* polling interval in ms */
|
||||
ULONG fullduplex; /* force full duplex */
|
||||
ULONG multicast; /* multicast recv enable */
|
||||
ULONG flowcontrol; /* enable RX flow control */
|
||||
};
|
||||
|
||||
#define HW_CONFIGFILE "ENV:SANA2/enc624j6net.config"
|
||||
|
||||
/* appended to COMMON_TEMPLATE */
|
||||
#define HW_CONFIGTEMPLATE "TIMER/K/N,FULLDUPLEX/S,MULTICAST/S,FLOWCONTROL/S"
|
||||
|
||||
/* referenced by server.c, hw.c */
|
||||
struct HWConfig
|
||||
{
|
||||
struct CommonConfig common; /* import from hw.h, expected in server.c */
|
||||
ULONG *timervalue;
|
||||
ULONG fullduplex;
|
||||
ULONG multicast;
|
||||
ULONG flowcontrol;
|
||||
};
|
||||
|
||||
#endif /* _INC_HWPRIVATE_H */
|
||||
@@ -0,0 +1,341 @@
|
||||
******************************************************************************
|
||||
* 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
|
||||
|
||||
DO_TEST EQU 0
|
||||
|
||||
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
|
||||
ULONG IVT_SigMask
|
||||
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
|
||||
|
||||
ifne DO_TEST
|
||||
|
||||
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
|
||||
|
||||
ENDC ;DO_TEST
|
||||
|
||||
|
||||
; 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_SigMask(a2),d0 ;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) ; <0 ? error, valid are 0..31
|
||||
blt .error ; error: have to go (shouldn't happen)
|
||||
moveq #0,d1
|
||||
bset d0,d1
|
||||
move.l d1,IVT_SigMask(a2)
|
||||
|
||||
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
|
||||
not.l d0 ;if( d0 == -1 ) d0 = 0
|
||||
beq.s .nosig
|
||||
not.l d0 ; swap back
|
||||
CALLEXEC FreeSignal
|
||||
moveq #-1,d0
|
||||
move.l d0,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
|
||||
|
||||
VBtimer_name: dc.b "timer.device",0
|
||||
ifne DO_TEST
|
||||
dos_name: dc.b "dos.library",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
|
||||
ENDC ;DO_TEST
|
||||
END
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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;
|
||||
unsigned long IVT_SigMask;
|
||||
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 "compiler.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,27 @@
|
||||
******************************************************************************
|
||||
* 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
|
||||
ULONG IVT_SigMask ;signal mask
|
||||
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
|
||||
@@ -0,0 +1,126 @@
|
||||
; ------------------------------------------------------------------------------
|
||||
; | Lowlevel Access to memory mapped ENC624J600 in PSP mode |
|
||||
; | Henryk Richter <henryk.richter@gmx.net> |
|
||||
; ------------------------------------------------------------------------------
|
||||
; macro section
|
||||
|
||||
;------------------ options, some depend on hardware (CPLD) configuration -------------------------
|
||||
_OPT_BUFFER_SWAP EQU 0 ;perform byte swap on buffer ops (1) or assume native endian (0)
|
||||
_OPT_REG_SWAP EQU 0 ;perform byte swap on register ops (1) or assume native endian (0)
|
||||
_OPT_ADR_QUIRK EQU 0 ;address lines 12/13 are swapped (1) or linear addressing (0)
|
||||
_OPT_FLOWCONTROL EQU 0 ;perform flow control on RX (1) or not (0)
|
||||
_OPT_RECV EQU 1 ;faster recv (1) or generic (0)
|
||||
_OPT_CHECKLINK_TX EQU 0 ;check for link changes in TX (1) or expect from outside (0) -> see server.c
|
||||
|
||||
;\1 register offset (without CLEAR offset)
|
||||
;\2 address register of board I/O base
|
||||
;\3 register with clear mask
|
||||
ifne _OPT_REG_SWAP
|
||||
|
||||
CLRREG macro
|
||||
rol.w #8,\3
|
||||
move.w \3,\1+CLR_OFFSET(\2)
|
||||
rol.w #8,\3
|
||||
endm
|
||||
;\1 register offset (without SET offset)
|
||||
;\2 address register of board I/O base
|
||||
;\3 register with set mask
|
||||
SETREG macro
|
||||
rol.w #8,\3
|
||||
move.w \3,\1+SET_OFFSET(\2)
|
||||
rol.w #8,\3
|
||||
endm
|
||||
;\1 register offset (e.g. ESTAT)
|
||||
;\2 address register of board I/O base (e.g. a0)
|
||||
;\3 destination register to be written (e.g. d0)
|
||||
;
|
||||
;important: when changing this, make sure the flags
|
||||
;are set according to the return value
|
||||
READREG macro
|
||||
rol.w #8,\3
|
||||
move.w \1(\2),\3
|
||||
rol.w #8,\3
|
||||
endm
|
||||
;\1 register offset (e.g. ESTAT)
|
||||
;\2 address register of board I/O base (e.g. a0)
|
||||
;\3 soure register copied to HW register (e.g. d0)
|
||||
WRITEREG macro
|
||||
rol.w #8,\3
|
||||
move.w \3,\1(\2)
|
||||
rol.w #8,\3
|
||||
endm
|
||||
|
||||
|
||||
else
|
||||
|
||||
CLRREG macro
|
||||
move.w \3,\1+CLR_OFFSET(\2)
|
||||
endm
|
||||
;\1 register offset (without SET offset)
|
||||
;\2 address register of board I/O base
|
||||
;\3 register with set mask
|
||||
SETREG macro
|
||||
move.w \3,\1+SET_OFFSET(\2)
|
||||
endm
|
||||
;\1 register offset (e.g. ESTAT)
|
||||
;\2 address register of board I/O base (e.g. a0)
|
||||
;\3 destination register to be written (e.g. d0)
|
||||
;
|
||||
;important: when changing this, make sure the flags
|
||||
;are set according to the return value
|
||||
READREG macro
|
||||
move.w \1(\2),\3
|
||||
endm
|
||||
;\1 register offset (e.g. ESTAT)
|
||||
;\2 address register of board I/O base (e.g. a0)
|
||||
;\3 soure register copied to HW register (e.g. d0)
|
||||
WRITEREG macro
|
||||
move.w \3,\1(\2)
|
||||
endm
|
||||
|
||||
endc
|
||||
|
||||
;read with address shuffling or direct from SRAM (affects $2000-$5000)
|
||||
ifne _OPT_ADR_QUIRK
|
||||
;\1 = address register
|
||||
;\2 = data register, offset
|
||||
;\3 = destination
|
||||
READSRAM macro
|
||||
eor.w #$6000,\2
|
||||
move.w (\1,\2.w),\3
|
||||
eor.w #$6000,\2
|
||||
endm
|
||||
else
|
||||
READSRAM macro
|
||||
move.w (\1,\2),\3
|
||||
endm
|
||||
endc
|
||||
|
||||
;read with address shuffling or direct from SRAM (affects $2000-$5000)
|
||||
ifne _OPT_ADR_QUIRK
|
||||
;\1 = address register
|
||||
;\2 = data register, offset
|
||||
;\3 = destination
|
||||
READSRAM_LONG macro
|
||||
eor.w #$6000,\2
|
||||
move.l (\1,\2.w),\3
|
||||
eor.w #$6000,\2
|
||||
endm
|
||||
else
|
||||
READSRAM_LONG macro
|
||||
move.l (\1,\2),\3
|
||||
endm
|
||||
endc
|
||||
|
||||
|
||||
; wrap position index (in bytes) \1 (data register .w)
|
||||
;
|
||||
; if position >RXSTOP_INIT-1
|
||||
; position = (position-RXSTOP_INIT+RXSTART_INIT)
|
||||
; endif
|
||||
WRAPINDEX macro
|
||||
cmp.w #RXSTOP_INIT&$fffe,\1 ;wrap Dn if beyond buffer
|
||||
ble.s .nowrap\0\@
|
||||
add.w #RXSTART_INIT-RXSTOP_INIT-1,\1
|
||||
.nowrap\0\@
|
||||
endm
|
||||
@@ -0,0 +1,606 @@
|
||||
/* ------------------------------------------------------------------------------ */
|
||||
/* | Lowlevel Access to memory mapped ENC624J600 in PSP mode | */
|
||||
/* | Henryk Richter <henryk.richter@gmx.net> | */
|
||||
/* ------------------------------------------------------------------------------ */
|
||||
/* register definition section */
|
||||
#ifndef _REGISTERS_H_
|
||||
#define _REGISTERS_H_
|
||||
|
||||
/* set/clr register offsets */
|
||||
#define SET_OFFSET 0x0100
|
||||
#define CLR_OFFSET 0x0180
|
||||
|
||||
/* Register definitions */
|
||||
|
||||
/* SPI Bank 0 registers -------- */
|
||||
#define ETXST 0x7E00
|
||||
#define ETXSTL 0x7E00
|
||||
#define ETXSTH 0x7E01
|
||||
#define ETXLEN 0x7E02
|
||||
#define ETXLENL 0x7E02
|
||||
#define ETXLENH 0x7E03
|
||||
#define ERXST 0x7E04
|
||||
#define ERXSTL 0x7E04
|
||||
#define ERXSTH 0x7E05
|
||||
#define ERXTAIL 0x7E06
|
||||
#define ERXTAILL 0x7E06
|
||||
#define ERXTAILH 0x7E07
|
||||
#define ERXHEAD 0x7E08
|
||||
#define ERXHEADL 0x7E08
|
||||
#define ERXHEADH 0x7E09
|
||||
#define EDMAST 0x7E0A
|
||||
#define EDMASTL 0x7E0A
|
||||
#define EDMASTH 0x7E0B
|
||||
#define EDMALEN 0x7E0C
|
||||
#define EDMALENL 0x7E0C
|
||||
#define EDMALENH 0x7E0D
|
||||
#define EDMADST 0x7E0E
|
||||
#define EDMADSTL 0x7E0E
|
||||
#define EDMADSTH 0x7E0F
|
||||
#define EDMACS 0x7E10
|
||||
#define EDMACSL 0x7E10
|
||||
#define EDMACSH 0x7E11
|
||||
#define ETXSTAT 0x7E12
|
||||
#define ETXSTATL 0x7E12
|
||||
#define ETXSTATH 0x7E13
|
||||
#define ETXWIRE 0x7E14
|
||||
#define ETXWIREL 0x7E14
|
||||
#define ETXWIREH 0x7E15
|
||||
|
||||
/* SPI all bank registers */
|
||||
#define EUDAST 0x7E16
|
||||
#define EUDASTL 0x7E16
|
||||
#define EUDASTH 0x7E17
|
||||
#define EUDAND 0x7E18
|
||||
#define EUDANDL 0x7E18
|
||||
#define EUDANDH 0x7E19
|
||||
#define ESTAT 0x7E1A
|
||||
#define ESTATL 0x7E1A
|
||||
#define ESTATH 0x7E1B
|
||||
#define EIR 0x7E1C
|
||||
#define EIRL 0x7E1C
|
||||
#define EIRH 0x7E1D
|
||||
#define ECON1 0x7E1E
|
||||
#define ECON1L 0x7E1E
|
||||
#define ECON1H 0x7E1F
|
||||
|
||||
|
||||
/* SPI Bank 1 registers ----- */
|
||||
#define EHT1 0x7E20
|
||||
#define EHT1L 0x7E20
|
||||
#define EHT1H 0x7E21
|
||||
#define EHT2 0x7E22
|
||||
#define EHT2L 0x7E22
|
||||
#define EHT2H 0x7E23
|
||||
#define EHT3 0x7E24
|
||||
#define EHT3L 0x7E24
|
||||
#define EHT3H 0x7E25
|
||||
#define EHT4 0x7E26
|
||||
#define EHT4L 0x7E26
|
||||
#define EHT4H 0x7E27
|
||||
#define EPMM1 0x7E28
|
||||
#define EPMM1L 0x7E28
|
||||
#define EPMM1H 0x7E29
|
||||
#define EPMM2 0x7E2A
|
||||
#define EPMM2L 0x7E2A
|
||||
#define EPMM2H 0x7E2B
|
||||
#define EPMM3 0x7E2C
|
||||
#define EPMM3L 0x7E2C
|
||||
#define EPMM3H 0x7E2D
|
||||
#define EPMM4 0x7E2E
|
||||
#define EPMM4L 0x7E2E
|
||||
#define EPMM4H 0x7E2F
|
||||
#define EPMCS 0x7E30
|
||||
#define EPMCSL 0x7E30
|
||||
#define EPMCSH 0x7E31
|
||||
#define EPMO 0x7E32
|
||||
#define EPMOL 0x7E32
|
||||
#define EPMOH 0x7E33
|
||||
#define ERXFCON 0x7E34
|
||||
#define ERXFCONL 0x7E34
|
||||
#define ERXFCONH 0x7E35
|
||||
|
||||
/* SPI all bank registers from 0x36 to 0x3F */
|
||||
/* SPI Bank 2 registers ----- */
|
||||
#define MACON1 0x7E40
|
||||
#define MACON1L 0x7E40
|
||||
#define MACON1H 0x7E41
|
||||
#define MACON2 0x7E42
|
||||
#define MACON2L 0x7E42
|
||||
#define MACON2H 0x7E43
|
||||
#define MABBIPG 0x7E44
|
||||
#define MABBIPGL 0x7E44
|
||||
#define MABBIPGH 0x7E45
|
||||
#define MAIPG 0x7E46
|
||||
#define MAIPGL 0x7E46
|
||||
#define MAIPGH 0x7E47
|
||||
#define MACLCON 0x7E48
|
||||
#define MACLCONL 0x7E48
|
||||
#define MACLCONH 0x7E49
|
||||
#define MAMXFL 0x7E4A
|
||||
#define MAMXFLL 0x7E4A
|
||||
#define MAMXFLH 0x7E4B
|
||||
#define MICMD 0x7E52
|
||||
#define MICMDL 0x7E52
|
||||
#define MICMDH 0x7E53
|
||||
#define MIREGADR 0x7E54
|
||||
#define MIREGADRL 0x7E54
|
||||
#define MIREGADRH 0x7E55
|
||||
|
||||
/* SPI all bank registers from 0x56 to 0x5F */
|
||||
/* SPI Bank 3 registers ----- */
|
||||
#define MAADR3 0x7E60
|
||||
#define MAADR3L 0x7E60
|
||||
#define MAADR3H 0x7E61
|
||||
#define MAADR2 0x7E62
|
||||
#define MAADR2L 0x7E62
|
||||
#define MAADR2H 0x7E63
|
||||
#define MAADR1 0x7E64
|
||||
#define MAADR1L 0x7E64
|
||||
#define MAADR1H 0x7E65
|
||||
#define MIWR 0x7E66
|
||||
#define MIWRL 0x7E66
|
||||
#define MIWRH 0x7E67
|
||||
#define MIRD 0x7E68
|
||||
#define MIRDL 0x7E68
|
||||
#define MIRDH 0x7E69
|
||||
#define MISTAT 0x7E6A
|
||||
#define MISTATL 0x7E6A
|
||||
#define MISTATH 0x7E6B
|
||||
#define EPAUS 0x7E6C
|
||||
#define EPAUSL 0x7E6C
|
||||
#define EPAUSH 0x7E6D
|
||||
#define ECON2 0x7E6E
|
||||
#define ECON2L 0x7E6E
|
||||
#define ECON2H 0x7E6F
|
||||
#define ERXWM 0x7E70
|
||||
#define ERXWML 0x7E70
|
||||
#define ERXWMH 0x7E71
|
||||
#define EIE 0x7E72
|
||||
#define EIEL 0x7E72
|
||||
#define EIEH 0x7E73
|
||||
#define EIDLED 0x7E74
|
||||
#define EIDLEDL 0x7E74
|
||||
#define EIDLEDH 0x7E75
|
||||
|
||||
/* SPI all bank registers from 0x66 to 0x6F */
|
||||
|
||||
/* SPI Non-banked Special Function Registers */
|
||||
#define EGPDATA 0x7E80
|
||||
#define EGPDATAL 0x7E80
|
||||
#define ERXDATA 0x7E82
|
||||
#define ERXDATAL 0x7E82
|
||||
#define EUDADATA 0x7E84
|
||||
#define EUDADATAL 0x7E84
|
||||
#define EGPRDPT 0x7E86
|
||||
#define EGPRDPTL 0x7E86
|
||||
#define EGPRDPTH 0x7E87
|
||||
#define EGPWRPT 0x7E88
|
||||
#define EGPWRPTL 0x7E88
|
||||
#define EGPWRPTH 0x7E89
|
||||
#define ERXRDPT 0x7E8A
|
||||
#define ERXRDPTL 0x7E8A
|
||||
#define ERXRDPTH 0x7E8B
|
||||
#define ERXWRPT 0x7E8C
|
||||
#define ERXWRPTL 0x7E8C
|
||||
#define ERXWRPTH 0x7E8D
|
||||
#define EUDARDPT 0x7E8E
|
||||
#define EUDARDPTL 0x7E8E
|
||||
#define EUDARDPTH 0x7E8F
|
||||
#define EUDAWRPT 0x7E90
|
||||
#define EUDAWRPTL 0x7E90
|
||||
#define EUDAWRPTH 0x7E91
|
||||
|
||||
/* ;;;;;;;;;;;;;;;;;;;;;;;;; */
|
||||
/* ENC424J600/624J600 register bits */
|
||||
/* ;;;;;;;;;;;;;;;;;;;;;;;;; */
|
||||
/* ESTAT bits ---------- */
|
||||
#define ESTAT_INT (1<<15)
|
||||
#define ESTAT_FCIDLE (1<<14)
|
||||
#define ESTAT_RXBUSY (1<<13)
|
||||
#define ESTAT_CLKRDY (1<<12)
|
||||
#define ESTAT_RSTDONE (1<<11)
|
||||
#define ESTAT_PHYDPX (1<<10)
|
||||
#define ESTAT_PHYRDY (1<<9)
|
||||
#define ESTAT_PHYLNK (1<<8)
|
||||
#define ESTAT_PKTCNT7 (1<<7)
|
||||
#define ESTAT_PKTCNT6 (1<<6)
|
||||
#define ESTAT_PKTCNT5 (1<<5)
|
||||
#define ESTAT_PKTCNT4 (1<<4)
|
||||
#define ESTAT_PKTCNT3 (1<<3)
|
||||
#define ESTAT_PKTCNT2 (1<<2)
|
||||
#define ESTAT_PKTCNT1 (1<<1)
|
||||
#define ESTAT_PKTCNT0 (1)
|
||||
|
||||
/* EIR bits ------------ */
|
||||
#define EIR_CRYPTEN (1<<15)
|
||||
#define EIR_MODEXIF (1<<14)
|
||||
#define EIR_HASHIF (1<<13)
|
||||
#define EIR_AESIF (1<<12)
|
||||
#define EIR_LINKIF (1<<11)
|
||||
#define EIR_PRDYIF (1<<10)
|
||||
#define EIR_r9 (1<<9)
|
||||
#define EIR_r8 (1<<8)
|
||||
#define EIR_r7 (1<<7)
|
||||
#define EIR_PKTIF (1<<6)
|
||||
#define EIR_DMAIF (1<<5)
|
||||
#define EIR_r4 (1<<4)
|
||||
#define EIR_TXIF (1<<3)
|
||||
#define EIR_TXABTIF (1<<2)
|
||||
#define EIR_RXABTIF (1<<1)
|
||||
#define EIR_PCFULIF (1)
|
||||
|
||||
/* ECON1 bits ---------- */
|
||||
#define ECON1_MODEXST (1<<15)
|
||||
#define ECON1_HASHEN (1<<14)
|
||||
#define ECON1_HASHOP (1<<13)
|
||||
#define ECON1_HASHLST (1<<12)
|
||||
#define ECON1_AESST (1<<11)
|
||||
#define ECON1_AESOP1 (1<<10)
|
||||
#define ECON1_AESOP0 (1<<9)
|
||||
#define ECON1_PKTDEC (1<<8)
|
||||
#define ECON1_FCOP1 (1<<7)
|
||||
#define ECON1_FCOP0 (1<<6)
|
||||
#define ECON1_DMAST (1<<5)
|
||||
#define ECON1_DMACPY (1<<4)
|
||||
#define ECON1_DMACSSD (1<<3)
|
||||
#define ECON1_DMANOCS (1<<2)
|
||||
#define ECON1_TXRTS (1<<1)
|
||||
#define ECON1_RXEN (1)
|
||||
|
||||
/* ETXSTAT bits -------- */
|
||||
#define ETXSTAT_r12 (1<<12)
|
||||
#define ETXSTAT_r11 (1<<11)
|
||||
#define ETXSTAT_LATECOL (1<<10)
|
||||
#define ETXSTAT_MAXCOL (1<<9)
|
||||
#define ETXSTAT_EXDEFER (1<<8)
|
||||
#define ETXSTAT_DEFER (1<<7)
|
||||
#define ETXSTAT_r6 (1<<6)
|
||||
#define ETXSTAT_r5 (1<<5)
|
||||
#define ETXSTAT_CRCBAD (1<<4)
|
||||
#define ETXSTAT_COLCNT3 (1<<3)
|
||||
#define ETXSTAT_COLCNT2 (1<<2)
|
||||
#define ETXSTAT_COLCNT1 (1<<1)
|
||||
#define ETXSTAT_COLCNT0 (1)
|
||||
|
||||
/* ERXFCON bits -------- */
|
||||
#define ERXFCON_HTEN (1<<15)
|
||||
#define ERXFCON_MPEN (1<<14)
|
||||
#define ERXFCON_NOTPM (1<<12)
|
||||
#define ERXFCON_PMEN3 (1<<11)
|
||||
#define ERXFCON_PMEN2 (1<<10)
|
||||
#define ERXFCON_PMEN1 (1<<9)
|
||||
#define ERXFCON_PMEN0 (1<<8)
|
||||
#define ERXFCON_CRCEEN (1<<7)
|
||||
#define ERXFCON_CRCEN (1<<6)
|
||||
#define ERXFCON_RUNTEEN (1<<5)
|
||||
#define ERXFCON_RUNTEN (1<<4)
|
||||
#define ERXFCON_UCEN (1<<3)
|
||||
#define ERXFCON_NOTMEEN (1<<2)
|
||||
#define ERXFCON_MCEN (1<<1)
|
||||
#define ERXFCON_BCEN (1)
|
||||
|
||||
/* MACON1 bits --------- */
|
||||
#define MACON1_r15 (1<<15)
|
||||
#define MACON1_r14 (1<<14)
|
||||
#define MACON1_r11 (1<<11)
|
||||
#define MACON1_r10 (1<<10)
|
||||
#define MACON1_r9 (1<<9)
|
||||
#define MACON1_r8 (1<<8)
|
||||
#define MACON1_LOOPBK (1<<4)
|
||||
#define MACON1_r3 (1<<3)
|
||||
#define MACON1_RXPAUS (1<<2)
|
||||
#define MACON1_PASSALL (1<<1)
|
||||
#define MACON1_r0 (1)
|
||||
|
||||
/* MACON2 bits --------- */
|
||||
#define MACON2_DEFER (1<<14)
|
||||
#define MACON2_BPEN (1<<13)
|
||||
#define MACON2_NOBKOFF (1<<12)
|
||||
#define MACON2_r9 (1<<9)
|
||||
#define MACON2_r8 (1<<8)
|
||||
#define MACON2_PADCFG2 (1<<7)
|
||||
#define MACON2_PADCFG1 (1<<6)
|
||||
#define MACON2_PADCFG0 (1<<5)
|
||||
#define MACON2_TXCRCEN (1<<4)
|
||||
#define MACON2_PHDREN (1<<3)
|
||||
#define MACON2_HFRMEN (1<<2)
|
||||
#define MACON2_r1 (1<<1)
|
||||
#define MACON2_FULDPX (1)
|
||||
|
||||
/* MABBIPG bits -------- */
|
||||
#define MABBIPG_BBIPG6 (1<<6)
|
||||
#define MABBIPG_BBIPG5 (1<<5)
|
||||
#define MABBIPG_BBIPG4 (1<<4)
|
||||
#define MABBIPG_BBIPG3 (1<<3)
|
||||
#define MABBIPG_BBIPG2 (1<<2)
|
||||
#define MABBIPG_BBIPG1 (1<<1)
|
||||
#define MABBIPG_BBIPG0 (1)
|
||||
|
||||
/* MAIPG bits ---------- */
|
||||
#define MAIPG_r14 (1<<14)
|
||||
#define MAIPG_r13 (1<<13)
|
||||
#define MAIPG_r12 (1<<12)
|
||||
#define MAIPG_r11 (1<<11)
|
||||
#define MAIPG_r10 (1<<10)
|
||||
#define MAIPG_r9 (1<<9)
|
||||
#define MAIPG_r8 (1<<8)
|
||||
#define MAIPG_IPG6 (1<<6)
|
||||
#define MAIPG_IPG5 (1<<5)
|
||||
#define MAIPG_IPG4 (1<<4)
|
||||
#define MAIPG_IPG3 (1<<3)
|
||||
#define MAIPG_IPG2 (1<<2)
|
||||
#define MAIPG_IPG1 (1<<1)
|
||||
#define MAIPG_IPG0 (1)
|
||||
|
||||
/* MACLCON bits -------- */
|
||||
#define MACLCON_r13 (1<<13)
|
||||
#define MACLCON_r12 (1<<12)
|
||||
#define MACLCON_r11 (1<<11)
|
||||
#define MACLCON_r10 (1<<10)
|
||||
#define MACLCON_r9 (1<<9)
|
||||
#define MACLCON_r8 (1<<8)
|
||||
#define MACLCON_MAXRET3 (1<<3)
|
||||
#define MACLCON_MAXRET2 (1<<2)
|
||||
#define MACLCON_MAXRET1 (1<<1)
|
||||
#define MACLCON_MAXRET0 (1)
|
||||
|
||||
/* MICMD bits ---------- */
|
||||
#define MICMD_MIISCAN (1<<1)
|
||||
#define MICMD_MIIRD (1)
|
||||
|
||||
/* MIREGADR bits ------- */
|
||||
#define MIREGADR_r12 (1<<12)
|
||||
#define MIREGADR_r11 (1<<11)
|
||||
#define MIREGADR_r10 (1<<10)
|
||||
#define MIREGADR_r9 (1<<9)
|
||||
#define MIREGADR_r8 (1<<8)
|
||||
#define MIREGADR_PHREG4 (1<<4)
|
||||
#define MIREGADR_PHREG3 (1<<3)
|
||||
#define MIREGADR_PHREG2 (1<<2)
|
||||
#define MIREGADR_PHREG1 (1<<1)
|
||||
#define MIREGADR_PHREG0 (1)
|
||||
|
||||
/* MISTAT bits --------- */
|
||||
#define MISTAT_r3 (1<<3)
|
||||
#define MISTAT_NVALID (1<<2)
|
||||
#define MISTAT_SCAN (1<<1)
|
||||
#define MISTAT_BUSY (1)
|
||||
|
||||
/* ECON2 bits ---------- */
|
||||
#define ECON2_ETHEN (1<<15)
|
||||
#define ECON2_STRCH (1<<14)
|
||||
#define ECON2_TXMAC (1<<13)
|
||||
#define ECON2_SHA1MD5 (1<<12)
|
||||
#define ECON2_COCON3 (1<<11)
|
||||
#define ECON2_COCON2 (1<<10)
|
||||
#define ECON2_COCON1 (1<<9)
|
||||
#define ECON2_COCON0 (1<<8)
|
||||
#define ECON2_AUTOFC (1<<7)
|
||||
#define ECON2_TXRST (1<<6)
|
||||
#define ECON2_RXRST (1<<5)
|
||||
#define ECON2_ETHRST (1<<4)
|
||||
#define ECON2_MODLEN1 (1<<3)
|
||||
#define ECON2_MODLEN0 (1<<2)
|
||||
#define ECON2_AESLEN1 (1<<1)
|
||||
#define ECON2_AESLEN0 (1)
|
||||
|
||||
/* ERXWM bits ---------- */
|
||||
#define ERXWM_RXFWM7 (1<<15)
|
||||
#define ERXWM_RXFWM6 (1<<14)
|
||||
#define ERXWM_RXFWM5 (1<<13)
|
||||
#define ERXWM_RXFWM4 (1<<12)
|
||||
#define ERXWM_RXFWM3 (1<<11)
|
||||
#define ERXWM_RXFWM2 (1<<10)
|
||||
#define ERXWM_RXFWM1 (1<<9)
|
||||
#define ERXWM_RXFWM0 (1<<8)
|
||||
#define ERXWM_RXEWM7 (1<<7)
|
||||
#define ERXWM_RXEWM6 (1<<6)
|
||||
#define ERXWM_RXEWM5 (1<<5)
|
||||
#define ERXWM_RXEWM4 (1<<4)
|
||||
#define ERXWM_RXEWM3 (1<<3)
|
||||
#define ERXWM_RXEWM2 (1<<2)
|
||||
#define ERXWM_RXEWM1 (1<<1)
|
||||
#define ERXWM_RXEWM0 (1)
|
||||
|
||||
/* EIE bits ------------ */
|
||||
#define EIE_INTIE (1<<15)
|
||||
#define EIE_MODEXIE (1<<14)
|
||||
#define EIE_HASHIE (1<<13)
|
||||
#define EIE_AESIE (1<<12)
|
||||
#define EIE_LINKIE (1<<11)
|
||||
#define EIE_PRDYIE (1<<10)
|
||||
#define EIE_r9 (1<<9)
|
||||
#define EIE_r8 (1<<8)
|
||||
#define EIE_r7 (1<<7)
|
||||
#define EIE_PKTIE (1<<6)
|
||||
#define EIE_DMAIE (1<<5)
|
||||
#define EIE_r4 (1<<4)
|
||||
#define EIE_TXIE (1<<3)
|
||||
#define EIE_TXABTIE (1<<2)
|
||||
#define EIE_RXABTIE (1<<1)
|
||||
#define EIE_PCFULIE (1)
|
||||
|
||||
/* EIDLED bits --------- */
|
||||
#define EIDLED_LACFG3 (1<<15)
|
||||
#define EIDLED_LACFG2 (1<<14)
|
||||
#define EIDLED_LACFG1 (1<<13)
|
||||
#define EIDLED_LACFG0 (1<<12)
|
||||
#define EIDLED_LBCFG3 (1<<11)
|
||||
#define EIDLED_LBCFG2 (1<<10)
|
||||
#define EIDLED_LBCFG1 (1<<9)
|
||||
#define EIDLED_LBCFG0 (1<<8)
|
||||
#define EIDLED_DEVID2 (1<<7)
|
||||
#define EIDLED_DEVID1 (1<<6)
|
||||
#define EIDLED_DEVID0 (1<<5)
|
||||
#define EIDLED_REVID4 (1<<4)
|
||||
#define EIDLED_REVID3 (1<<3)
|
||||
#define EIDLED_REVID2 (1<<2)
|
||||
#define EIDLED_REVID1 (1<<1)
|
||||
#define EIDLED_REVID0 (1)
|
||||
|
||||
/* PHCON1 bits --------- */
|
||||
#define PHCON1_PRST (1<<15)
|
||||
#define PHCON1_PLOOPBK (1<<14)
|
||||
#define PHCON1_SPD100 (1<<13)
|
||||
#define PHCON1_ANEN (1<<12)
|
||||
#define PHCON1_PSLEEP (1<<11)
|
||||
#define PHCON1_r10 (1<<10)
|
||||
#define PHCON1_RENEG (1<<9)
|
||||
#define PHCON1_PFULDPX (1<<8)
|
||||
#define PHCON1_r7 (1<<7)
|
||||
#define PHCON1_r6 (1<<6)
|
||||
#define PHCON1_r5 (1<<5)
|
||||
#define PHCON1_r4 (1<<4)
|
||||
#define PHCON1_r3 (1<<3)
|
||||
#define PHCON1_r2 (1<<2)
|
||||
#define PHCON1_r1 (1<<1)
|
||||
#define PHCON1_r0 (1)
|
||||
|
||||
/* PHSTAT1 bits -------- */
|
||||
#define PHSTAT1_r15 (1<<15)
|
||||
#define PHSTAT1_FULL100 (1<<14)
|
||||
#define PHSTAT1_HALF100 (1<<13)
|
||||
#define PHSTAT1_FULL10 (1<<12)
|
||||
#define PHSTAT1_HALF10 (1<<11)
|
||||
#define PHSTAT1_r10 (1<<10)
|
||||
#define PHSTAT1_r9 (1<<9)
|
||||
#define PHSTAT1_r8 (1<<8)
|
||||
#define PHSTAT1_r7 (1<<7)
|
||||
#define PHSTAT1_r6 (1<<6)
|
||||
#define PHSTAT1_ANDONE (1<<5)
|
||||
#define PHSTAT1_LRFAULT (1<<4)
|
||||
#define PHSTAT1_ANABLE (1<<3)
|
||||
#define PHSTAT1_LLSTAT (1<<2)
|
||||
#define PHSTAT1_r1 (1<<1)
|
||||
#define PHSTAT1_EXTREGS (1)
|
||||
|
||||
/* PHANA bits ---------- */
|
||||
#define PHANA_ADNP (1<<15)
|
||||
#define PHANA_r14 (1<<14)
|
||||
#define PHANA_ADFAULT (1<<13)
|
||||
#define PHANA_r12 (1<<12)
|
||||
#define PHANA_ADPAUS1 (1<<11)
|
||||
#define PHANA_ADPAUS0 (1<<10)
|
||||
#define PHANA_r9 (1<<9)
|
||||
#define PHANA_AD100FD (1<<8)
|
||||
#define PHANA_AD100 (1<<7)
|
||||
#define PHANA_AD10FD (1<<6)
|
||||
#define PHANA_AD10 (1<<5)
|
||||
#define PHANA_ADIEEE4 (1<<4)
|
||||
#define PHANA_ADIEEE3 (1<<3)
|
||||
#define PHANA_ADIEEE2 (1<<2)
|
||||
#define PHANA_ADIEEE1 (1<<1)
|
||||
#define PHANA_ADIEEE0 (1)
|
||||
|
||||
/* PHANLPA bits -------- */
|
||||
#define PHANLPA_LPNP (1<<15)
|
||||
#define PHANLPA_LPACK (1<<14)
|
||||
#define PHANLPA_LPFAULT (1<<13)
|
||||
#define PHANLPA_r12 (1<<12)
|
||||
#define PHANLPA_LPPAUS1 (1<<11)
|
||||
#define PHANLPA_LPPAUS0 (1<<10)
|
||||
#define PHANLPA_LP100T4 (1<<9)
|
||||
#define PHANLPA_LP100FD (1<<8)
|
||||
#define PHANLPA_LP100 (1<<7)
|
||||
#define PHANLPA_LP10FD (1<<6)
|
||||
#define PHANLPA_LP10 (1<<5)
|
||||
#define PHANLPA_LPIEEE4 (1<<4)
|
||||
#define PHANLPA_LPIEEE3 (1<<3)
|
||||
#define PHANLPA_LPIEEE2 (1<<2)
|
||||
#define PHANLPA_LPIEEE1 (1<<1)
|
||||
#define PHANLPA_LPIEEE0 (1)
|
||||
|
||||
/* PHANE bits ---------- */
|
||||
#define PHANE_r15 (1<<15)
|
||||
#define PHANE_r14 (1<<14)
|
||||
#define PHANE_r13 (1<<13)
|
||||
#define PHANE_r12 (1<<12)
|
||||
#define PHANE_r11 (1<<11)
|
||||
#define PHANE_r10 (1<<10)
|
||||
#define PHANE_r9 (1<<9)
|
||||
#define PHANE_r8 (1<<8)
|
||||
#define PHANE_r7 (1<<7)
|
||||
#define PHANE_r6 (1<<6)
|
||||
#define PHANE_r5 (1<<5)
|
||||
#define PHANE_PDFLT (1<<4)
|
||||
#define PHANE_r3 (1<<3)
|
||||
#define PHANE_r2 (1<<2)
|
||||
#define PHANE_LPARCD (1<<1)
|
||||
#define PHANA_LPANABL (1)
|
||||
|
||||
/* PHCON2 bits --------- */
|
||||
#define PHCON2_r15 (1<<15)
|
||||
#define PHCON2_r14 (1<<14)
|
||||
#define PHCON2_EDPWRDN (1<<13)
|
||||
#define PHCON2_r12 (1<<12)
|
||||
#define PHCON2_EDTHRES (1<<11)
|
||||
#define PHCON2_r10 (1<<10)
|
||||
#define PHCON2_r9 (1<<9)
|
||||
#define PHCON2_r8 (1<<8)
|
||||
#define PHCON2_r7 (1<<7)
|
||||
#define PHCON2_r6 (1<<6)
|
||||
#define PHCON2_r5 (1<<5)
|
||||
#define PHCON2_r4 (1<<4)
|
||||
#define PHCON2_r3 (1<<3)
|
||||
#define PHCON2_FRCLNK (1<<2)
|
||||
#define PHCON2_EDSTAT (1<<1)
|
||||
#define PHCON2_r0 (1)
|
||||
|
||||
/* PHSTAT2 bits --------- */
|
||||
#define PHSTAT2_r15 (1<<15)
|
||||
#define PHSTAT2_r14 (1<<14)
|
||||
#define PHSTAT2_r13 (1<<13)
|
||||
#define PHSTAT2_r12 (1<<12)
|
||||
#define PHSTAT2_r11 (1<<11)
|
||||
#define PHSTAT2_r10 (1<<10)
|
||||
#define PHSTAT2_r9 (1<<9)
|
||||
#define PHSTAT2_r8 (1<<8)
|
||||
#define PHSTAT2_r7 (1<<7)
|
||||
#define PHSTAT2_r6 (1<<6)
|
||||
#define PHSTAT2_r5 (1<<5)
|
||||
#define PHSTAT2_PLRITY (1<<4)
|
||||
#define PHSTAT2_r3 (1<<3)
|
||||
#define PHSTAT2_r2 (1<<2)
|
||||
#define PHSTAT2_r1 (1<<1)
|
||||
#define PHSTAT2_r0 (1)
|
||||
|
||||
/* PHSTAT3 bits -------- */
|
||||
#define PHSTAT3_r15 (1<<15)
|
||||
#define PHSTAT3_r14 (1<<14)
|
||||
#define PHSTAT3_r13 (1<<13)
|
||||
#define PHSTAT3_r12 (1<<12)
|
||||
#define PHSTAT3_r11 (1<<11)
|
||||
#define PHSTAT3_r10 (1<<10)
|
||||
#define PHSTAT3_r9 (1<<9)
|
||||
#define PHSTAT3_r8 (1<<8)
|
||||
#define PHSTAT3_r7 (1<<7)
|
||||
#define PHSTAT3_r6 (1<<6)
|
||||
#define PHSTAT3_r5 (1<<5)
|
||||
#define PHSTAT3_SPDDPX2 (1<<4)
|
||||
#define PHSTAT3_SPDDPX1 (1<<3)
|
||||
#define PHSTAT3_SPDDPX0 (1<<2)
|
||||
#define PHSTAT3_r1 (1<<1)
|
||||
#define PHSTAT3_r0 (1)
|
||||
|
||||
/* ------------------------------ internal defaults ---------------------------------- */
|
||||
/* 33.333Mhz clock out frequency */
|
||||
#define CLOCK_33_CLR (ECON2_COCON3|ECON2_COCON2|ECON2_COCON1) /* clr mask */
|
||||
#define CLOCK_33_SET (ECON2_COCON0) /* set mask */
|
||||
/* 25 MHz */
|
||||
#define CLOCK_25_CLR (ECON2_COCON3|ECON2_COCON2|ECON2_COCON0) /* clr mask */
|
||||
#define CLOCK_25_SET (ECON2_COCON1) /* set mask */
|
||||
/* 20 MHz */
|
||||
#define CLOCK_20_CLR (ECON2_COCON3|ECON2_COCON2) /* clr mask */
|
||||
#define CLOCK_20_SET (ECON2_COCON1|ECON2_COCON0) /* set mask */
|
||||
/* 16 MHz */
|
||||
#define CLOCK_16_CLR (ECON2_COCON3|ECON2_COCON0|ECON2_COCON1) /* clr mask */
|
||||
#define CLOCK_16_SET (ECON2_COCON2) /* set mask */
|
||||
/* 4 MHz (after reset) */
|
||||
#define CLOCK_4_CLR (ECON2_COCON2) /* clr mask */
|
||||
#define CLOCK_4_SET (ECON2_COCON3|ECON2_COCON0|ECON2_COCON1) /* set mask */
|
||||
|
||||
#define CLOCK_DEF_CLR CLOCK_33_CLR
|
||||
#define CLOCK_DEF_SET CLOCK_33_SET
|
||||
|
||||
#endif /* _REGISTERS_H_ */
|
||||
@@ -0,0 +1,602 @@
|
||||
; ------------------------------------------------------------------------------
|
||||
; | Lowlevel Access to memory mapped ENC624J600 in PSP mode |
|
||||
; | Henryk Richter <henryk.richter@gmx.net> |
|
||||
; ------------------------------------------------------------------------------
|
||||
; register definition section
|
||||
|
||||
; set/clr register offsets
|
||||
SET_OFFSET EQU $0100
|
||||
CLR_OFFSET EQU $0180
|
||||
|
||||
; Register definitions
|
||||
|
||||
; SPI Bank 0 registers --------
|
||||
ETXST EQU $7E00
|
||||
ETXSTL EQU $7E00
|
||||
ETXSTH EQU $7E01
|
||||
ETXLEN EQU $7E02
|
||||
ETXLENL EQU $7E02
|
||||
ETXLENH EQU $7E03
|
||||
ERXST EQU $7E04
|
||||
ERXSTL EQU $7E04
|
||||
ERXSTH EQU $7E05
|
||||
ERXTAIL EQU $7E06
|
||||
ERXTAILL EQU $7E06
|
||||
ERXTAILH EQU $7E07
|
||||
ERXHEAD EQU $7E08
|
||||
ERXHEADL EQU $7E08
|
||||
ERXHEADH EQU $7E09
|
||||
EDMAST EQU $7E0A
|
||||
EDMASTL EQU $7E0A
|
||||
EDMASTH EQU $7E0B
|
||||
EDMALEN EQU $7E0C
|
||||
EDMALENL EQU $7E0C
|
||||
EDMALENH EQU $7E0D
|
||||
EDMADST EQU $7E0E
|
||||
EDMADSTL EQU $7E0E
|
||||
EDMADSTH EQU $7E0F
|
||||
EDMACS EQU $7E10
|
||||
EDMACSL EQU $7E10
|
||||
EDMACSH EQU $7E11
|
||||
ETXSTAT EQU $7E12
|
||||
ETXSTATL EQU $7E12
|
||||
ETXSTATH EQU $7E13
|
||||
ETXWIRE EQU $7E14
|
||||
ETXWIREL EQU $7E14
|
||||
ETXWIREH EQU $7E15
|
||||
|
||||
; SPI all bank registers
|
||||
EUDAST EQU $7E16
|
||||
EUDASTL EQU $7E16
|
||||
EUDASTH EQU $7E17
|
||||
EUDAND EQU $7E18
|
||||
EUDANDL EQU $7E18
|
||||
EUDANDH EQU $7E19
|
||||
ESTAT EQU $7E1A
|
||||
ESTATL EQU $7E1A
|
||||
ESTATH EQU $7E1B
|
||||
EIR EQU $7E1C
|
||||
EIRL EQU $7E1C
|
||||
EIRH EQU $7E1D
|
||||
ECON1 EQU $7E1E
|
||||
ECON1L EQU $7E1E
|
||||
ECON1H EQU $7E1F
|
||||
|
||||
|
||||
; SPI Bank 1 registers -----
|
||||
EHT1 EQU $7E20
|
||||
EHT1L EQU $7E20
|
||||
EHT1H EQU $7E21
|
||||
EHT2 EQU $7E22
|
||||
EHT2L EQU $7E22
|
||||
EHT2H EQU $7E23
|
||||
EHT3 EQU $7E24
|
||||
EHT3L EQU $7E24
|
||||
EHT3H EQU $7E25
|
||||
EHT4 EQU $7E26
|
||||
EHT4L EQU $7E26
|
||||
EHT4H EQU $7E27
|
||||
EPMM1 EQU $7E28
|
||||
EPMM1L EQU $7E28
|
||||
EPMM1H EQU $7E29
|
||||
EPMM2 EQU $7E2A
|
||||
EPMM2L EQU $7E2A
|
||||
EPMM2H EQU $7E2B
|
||||
EPMM3 EQU $7E2C
|
||||
EPMM3L EQU $7E2C
|
||||
EPMM3H EQU $7E2D
|
||||
EPMM4 EQU $7E2E
|
||||
EPMM4L EQU $7E2E
|
||||
EPMM4H EQU $7E2F
|
||||
EPMCS EQU $7E30
|
||||
EPMCSL EQU $7E30
|
||||
EPMCSH EQU $7E31
|
||||
EPMO EQU $7E32
|
||||
EPMOL EQU $7E32
|
||||
EPMOH EQU $7E33
|
||||
ERXFCON EQU $7E34
|
||||
ERXFCONL EQU $7E34
|
||||
ERXFCONH EQU $7E35
|
||||
|
||||
; SPI all bank registers from 0x36 to 0x3F
|
||||
; SPI Bank 2 registers -----
|
||||
MACON1 EQU $7E40
|
||||
MACON1L EQU $7E40
|
||||
MACON1H EQU $7E41
|
||||
MACON2 EQU $7E42
|
||||
MACON2L EQU $7E42
|
||||
MACON2H EQU $7E43
|
||||
MABBIPG EQU $7E44
|
||||
MABBIPGL EQU $7E44
|
||||
MABBIPGH EQU $7E45
|
||||
MAIPG EQU $7E46
|
||||
MAIPGL EQU $7E46
|
||||
MAIPGH EQU $7E47
|
||||
MACLCON EQU $7E48
|
||||
MACLCONL EQU $7E48
|
||||
MACLCONH EQU $7E49
|
||||
MAMXFL EQU $7E4A
|
||||
MAMXFLL EQU $7E4A
|
||||
MAMXFLH EQU $7E4B
|
||||
MICMD EQU $7E52
|
||||
MICMDL EQU $7E52
|
||||
MICMDH EQU $7E53
|
||||
MIREGADR EQU $7E54
|
||||
MIREGADRL EQU $7E54
|
||||
MIREGADRH EQU $7E55
|
||||
|
||||
; SPI all bank registers from 0x56 to 0x5F
|
||||
; SPI Bank 3 registers -----
|
||||
MAADR3 EQU $7E60
|
||||
MAADR3L EQU $7E60
|
||||
MAADR3H EQU $7E61
|
||||
MAADR2 EQU $7E62
|
||||
MAADR2L EQU $7E62
|
||||
MAADR2H EQU $7E63
|
||||
MAADR1 EQU $7E64
|
||||
MAADR1L EQU $7E64
|
||||
MAADR1H EQU $7E65
|
||||
MIWR EQU $7E66
|
||||
MIWRL EQU $7E66
|
||||
MIWRH EQU $7E67
|
||||
MIRD EQU $7E68
|
||||
MIRDL EQU $7E68
|
||||
MIRDH EQU $7E69
|
||||
MISTAT EQU $7E6A
|
||||
MISTATL EQU $7E6A
|
||||
MISTATH EQU $7E6B
|
||||
EPAUS EQU $7E6C
|
||||
EPAUSL EQU $7E6C
|
||||
EPAUSH EQU $7E6D
|
||||
ECON2 EQU $7E6E
|
||||
ECON2L EQU $7E6E
|
||||
ECON2H EQU $7E6F
|
||||
ERXWM EQU $7E70
|
||||
ERXWML EQU $7E70
|
||||
ERXWMH EQU $7E71
|
||||
EIE EQU $7E72
|
||||
EIEL EQU $7E72
|
||||
EIEH EQU $7E73
|
||||
EIDLED EQU $7E74
|
||||
EIDLEDL EQU $7E74
|
||||
EIDLEDH EQU $7E75
|
||||
|
||||
; SPI all bank registers from 0x66 to 0x6F
|
||||
|
||||
; SPI Non-banked Special Function Registers
|
||||
EGPDATA EQU $7E80
|
||||
EGPDATAL EQU $7E80
|
||||
ERXDATA EQU $7E82
|
||||
ERXDATAL EQU $7E82
|
||||
EUDADATA EQU $7E84
|
||||
EUDADATAL EQU $7E84
|
||||
EGPRDPT EQU $7E86
|
||||
EGPRDPTL EQU $7E86
|
||||
EGPRDPTH EQU $7E87
|
||||
EGPWRPT EQU $7E88
|
||||
EGPWRPTL EQU $7E88
|
||||
EGPWRPTH EQU $7E89
|
||||
ERXRDPT EQU $7E8A
|
||||
ERXRDPTL EQU $7E8A
|
||||
ERXRDPTH EQU $7E8B
|
||||
ERXWRPT EQU $7E8C
|
||||
ERXWRPTL EQU $7E8C
|
||||
ERXWRPTH EQU $7E8D
|
||||
EUDARDPT EQU $7E8E
|
||||
EUDARDPTL EQU $7E8E
|
||||
EUDARDPTH EQU $7E8F
|
||||
EUDAWRPT EQU $7E90
|
||||
EUDAWRPTL EQU $7E90
|
||||
EUDAWRPTH EQU $7E91
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ENC424J600/624J600 register bits
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ESTAT bits ----------
|
||||
ESTAT_INT EQU (1<<15)
|
||||
ESTAT_FCIDLE EQU (1<<14)
|
||||
ESTAT_RXBUSY EQU (1<<13)
|
||||
ESTAT_CLKRDY EQU (1<<12)
|
||||
ESTAT_RSTDONE EQU (1<<11)
|
||||
ESTAT_PHYDPX EQU (1<<10)
|
||||
ESTAT_PHYRDY EQU (1<<9)
|
||||
ESTAT_PHYLNK EQU (1<<8)
|
||||
ESTAT_PKTCNT7 EQU (1<<7)
|
||||
ESTAT_PKTCNT6 EQU (1<<6)
|
||||
ESTAT_PKTCNT5 EQU (1<<5)
|
||||
ESTAT_PKTCNT4 EQU (1<<4)
|
||||
ESTAT_PKTCNT3 EQU (1<<3)
|
||||
ESTAT_PKTCNT2 EQU (1<<2)
|
||||
ESTAT_PKTCNT1 EQU (1<<1)
|
||||
ESTAT_PKTCNT0 EQU (1)
|
||||
|
||||
; EIR bits ------------
|
||||
EIR_CRYPTEN EQU (1<<15)
|
||||
EIR_MODEXIF EQU (1<<14)
|
||||
EIR_HASHIF EQU (1<<13)
|
||||
EIR_AESIF EQU (1<<12)
|
||||
EIR_LINKIF EQU (1<<11)
|
||||
EIR_PRDYIF EQU (1<<10)
|
||||
EIR_r9 EQU (1<<9)
|
||||
EIR_r8 EQU (1<<8)
|
||||
EIR_r7 EQU (1<<7)
|
||||
EIR_PKTIF EQU (1<<6)
|
||||
EIR_DMAIF EQU (1<<5)
|
||||
EIR_r4 EQU (1<<4)
|
||||
EIR_TXIF EQU (1<<3)
|
||||
EIR_TXABTIF EQU (1<<2)
|
||||
EIR_RXABTIF EQU (1<<1)
|
||||
EIR_PCFULIF EQU (1)
|
||||
|
||||
; ECON1 bits ----------
|
||||
ECON1_MODEXST EQU (1<<15)
|
||||
ECON1_HASHEN EQU (1<<14)
|
||||
ECON1_HASHOP EQU (1<<13)
|
||||
ECON1_HASHLST EQU (1<<12)
|
||||
ECON1_AESST EQU (1<<11)
|
||||
ECON1_AESOP1 EQU (1<<10)
|
||||
ECON1_AESOP0 EQU (1<<9)
|
||||
ECON1_PKTDEC EQU (1<<8)
|
||||
ECON1_FCOP1 EQU (1<<7)
|
||||
ECON1_FCOP0 EQU (1<<6)
|
||||
ECON1_DMAST EQU (1<<5)
|
||||
ECON1_DMACPY EQU (1<<4)
|
||||
ECON1_DMACSSD EQU (1<<3)
|
||||
ECON1_DMANOCS EQU (1<<2)
|
||||
ECON1_TXRTS EQU (1<<1)
|
||||
ECON1_RXEN EQU (1)
|
||||
|
||||
; ETXSTAT bits --------
|
||||
ETXSTAT_r12 EQU (1<<12)
|
||||
ETXSTAT_r11 EQU (1<<11)
|
||||
ETXSTAT_LATECOL EQU (1<<10)
|
||||
ETXSTAT_MAXCOL EQU (1<<9)
|
||||
ETXSTAT_EXDEFER EQU (1<<8)
|
||||
ETXSTAT_DEFER EQU (1<<7)
|
||||
ETXSTAT_r6 EQU (1<<6)
|
||||
ETXSTAT_r5 EQU (1<<5)
|
||||
ETXSTAT_CRCBAD EQU (1<<4)
|
||||
ETXSTAT_COLCNT3 EQU (1<<3)
|
||||
ETXSTAT_COLCNT2 EQU (1<<2)
|
||||
ETXSTAT_COLCNT1 EQU (1<<1)
|
||||
ETXSTAT_COLCNT0 EQU (1)
|
||||
|
||||
; ERXFCON bits --------
|
||||
ERXFCON_HTEN EQU (1<<15)
|
||||
ERXFCON_MPEN EQU (1<<14)
|
||||
ERXFCON_NOTPM EQU (1<<12)
|
||||
ERXFCON_PMEN3 EQU (1<<11)
|
||||
ERXFCON_PMEN2 EQU (1<<10)
|
||||
ERXFCON_PMEN1 EQU (1<<9)
|
||||
ERXFCON_PMEN0 EQU (1<<8)
|
||||
ERXFCON_CRCEEN EQU (1<<7)
|
||||
ERXFCON_CRCEN EQU (1<<6)
|
||||
ERXFCON_RUNTEEN EQU (1<<5)
|
||||
ERXFCON_RUNTEN EQU (1<<4)
|
||||
ERXFCON_UCEN EQU (1<<3)
|
||||
ERXFCON_NOTMEEN EQU (1<<2)
|
||||
ERXFCON_MCEN EQU (1<<1)
|
||||
ERXFCON_BCEN EQU (1)
|
||||
|
||||
; MACON1 bits ---------
|
||||
MACON1_r15 EQU (1<<15)
|
||||
MACON1_r14 EQU (1<<14)
|
||||
MACON1_r11 EQU (1<<11)
|
||||
MACON1_r10 EQU (1<<10)
|
||||
MACON1_r9 EQU (1<<9)
|
||||
MACON1_r8 EQU (1<<8)
|
||||
MACON1_LOOPBK EQU (1<<4)
|
||||
MACON1_r3 EQU (1<<3)
|
||||
MACON1_RXPAUS EQU (1<<2)
|
||||
MACON1_PASSALL EQU (1<<1)
|
||||
MACON1_r0 EQU (1)
|
||||
|
||||
; MACON2 bits ---------
|
||||
MACON2_DEFER EQU (1<<14)
|
||||
MACON2_BPEN EQU (1<<13)
|
||||
MACON2_NOBKOFF EQU (1<<12)
|
||||
MACON2_r9 EQU (1<<9)
|
||||
MACON2_r8 EQU (1<<8)
|
||||
MACON2_PADCFG2 EQU (1<<7)
|
||||
MACON2_PADCFG1 EQU (1<<6)
|
||||
MACON2_PADCFG0 EQU (1<<5)
|
||||
MACON2_TXCRCEN EQU (1<<4)
|
||||
MACON2_PHDREN EQU (1<<3)
|
||||
MACON2_HFRMEN EQU (1<<2)
|
||||
MACON2_r1 EQU (1<<1)
|
||||
MACON2_FULDPX EQU (1)
|
||||
|
||||
; MABBIPG bits --------
|
||||
MABBIPG_BBIPG6 EQU (1<<6)
|
||||
MABBIPG_BBIPG5 EQU (1<<5)
|
||||
MABBIPG_BBIPG4 EQU (1<<4)
|
||||
MABBIPG_BBIPG3 EQU (1<<3)
|
||||
MABBIPG_BBIPG2 EQU (1<<2)
|
||||
MABBIPG_BBIPG1 EQU (1<<1)
|
||||
MABBIPG_BBIPG0 EQU (1)
|
||||
|
||||
; MAIPG bits ----------
|
||||
MAIPG_r14 EQU (1<<14)
|
||||
MAIPG_r13 EQU (1<<13)
|
||||
MAIPG_r12 EQU (1<<12)
|
||||
MAIPG_r11 EQU (1<<11)
|
||||
MAIPG_r10 EQU (1<<10)
|
||||
MAIPG_r9 EQU (1<<9)
|
||||
MAIPG_r8 EQU (1<<8)
|
||||
MAIPG_IPG6 EQU (1<<6)
|
||||
MAIPG_IPG5 EQU (1<<5)
|
||||
MAIPG_IPG4 EQU (1<<4)
|
||||
MAIPG_IPG3 EQU (1<<3)
|
||||
MAIPG_IPG2 EQU (1<<2)
|
||||
MAIPG_IPG1 EQU (1<<1)
|
||||
MAIPG_IPG0 EQU (1)
|
||||
|
||||
; MACLCON bits --------
|
||||
MACLCON_r13 EQU (1<<13)
|
||||
MACLCON_r12 EQU (1<<12)
|
||||
MACLCON_r11 EQU (1<<11)
|
||||
MACLCON_r10 EQU (1<<10)
|
||||
MACLCON_r9 EQU (1<<9)
|
||||
MACLCON_r8 EQU (1<<8)
|
||||
MACLCON_MAXRET3 EQU (1<<3)
|
||||
MACLCON_MAXRET2 EQU (1<<2)
|
||||
MACLCON_MAXRET1 EQU (1<<1)
|
||||
MACLCON_MAXRET0 EQU (1)
|
||||
|
||||
; MICMD bits ----------
|
||||
MICMD_MIISCAN EQU (1<<1)
|
||||
MICMD_MIIRD EQU (1)
|
||||
|
||||
; MIREGADR bits -------
|
||||
MIREGADR_r12 EQU (1<<12)
|
||||
MIREGADR_r11 EQU (1<<11)
|
||||
MIREGADR_r10 EQU (1<<10)
|
||||
MIREGADR_r9 EQU (1<<9)
|
||||
MIREGADR_r8 EQU (1<<8)
|
||||
MIREGADR_PHREG4 EQU (1<<4)
|
||||
MIREGADR_PHREG3 EQU (1<<3)
|
||||
MIREGADR_PHREG2 EQU (1<<2)
|
||||
MIREGADR_PHREG1 EQU (1<<1)
|
||||
MIREGADR_PHREG0 EQU (1)
|
||||
|
||||
; MISTAT bits ---------
|
||||
MISTAT_r3 EQU (1<<3)
|
||||
MISTAT_NVALID EQU (1<<2)
|
||||
MISTAT_SCAN EQU (1<<1)
|
||||
MISTAT_BUSY EQU (1)
|
||||
|
||||
; ECON2 bits ----------
|
||||
ECON2_ETHEN EQU (1<<15)
|
||||
ECON2_STRCH EQU (1<<14)
|
||||
ECON2_TXMAC EQU (1<<13)
|
||||
ECON2_SHA1MD5 EQU (1<<12)
|
||||
ECON2_COCON3 EQU (1<<11)
|
||||
ECON2_COCON2 EQU (1<<10)
|
||||
ECON2_COCON1 EQU (1<<9)
|
||||
ECON2_COCON0 EQU (1<<8)
|
||||
ECON2_AUTOFC EQU (1<<7)
|
||||
ECON2_TXRST EQU (1<<6)
|
||||
ECON2_RXRST EQU (1<<5)
|
||||
ECON2_ETHRST EQU (1<<4)
|
||||
ECON2_MODLEN1 EQU (1<<3)
|
||||
ECON2_MODLEN0 EQU (1<<2)
|
||||
ECON2_AESLEN1 EQU (1<<1)
|
||||
ECON2_AESLEN0 EQU (1)
|
||||
|
||||
; ERXWM bits ----------
|
||||
ERXWM_RXFWM7 EQU (1<<15)
|
||||
ERXWM_RXFWM6 EQU (1<<14)
|
||||
ERXWM_RXFWM5 EQU (1<<13)
|
||||
ERXWM_RXFWM4 EQU (1<<12)
|
||||
ERXWM_RXFWM3 EQU (1<<11)
|
||||
ERXWM_RXFWM2 EQU (1<<10)
|
||||
ERXWM_RXFWM1 EQU (1<<9)
|
||||
ERXWM_RXFWM0 EQU (1<<8)
|
||||
ERXWM_RXEWM7 EQU (1<<7)
|
||||
ERXWM_RXEWM6 EQU (1<<6)
|
||||
ERXWM_RXEWM5 EQU (1<<5)
|
||||
ERXWM_RXEWM4 EQU (1<<4)
|
||||
ERXWM_RXEWM3 EQU (1<<3)
|
||||
ERXWM_RXEWM2 EQU (1<<2)
|
||||
ERXWM_RXEWM1 EQU (1<<1)
|
||||
ERXWM_RXEWM0 EQU (1)
|
||||
|
||||
; EIE bits ------------
|
||||
EIE_INTIE EQU (1<<15)
|
||||
EIE_MODEXIE EQU (1<<14)
|
||||
EIE_HASHIE EQU (1<<13)
|
||||
EIE_AESIE EQU (1<<12)
|
||||
EIE_LINKIE EQU (1<<11)
|
||||
EIE_PRDYIE EQU (1<<10)
|
||||
EIE_r9 EQU (1<<9)
|
||||
EIE_r8 EQU (1<<8)
|
||||
EIE_r7 EQU (1<<7)
|
||||
EIE_PKTIE EQU (1<<6)
|
||||
EIE_DMAIE EQU (1<<5)
|
||||
EIE_r4 EQU (1<<4)
|
||||
EIE_TXIE EQU (1<<3)
|
||||
EIE_TXABTIE EQU (1<<2)
|
||||
EIE_RXABTIE EQU (1<<1)
|
||||
EIE_PCFULIE EQU (1)
|
||||
|
||||
; EIDLED bits ---------
|
||||
EIDLED_LACFG3 EQU (1<<15)
|
||||
EIDLED_LACFG2 EQU (1<<14)
|
||||
EIDLED_LACFG1 EQU (1<<13)
|
||||
EIDLED_LACFG0 EQU (1<<12)
|
||||
EIDLED_LBCFG3 EQU (1<<11)
|
||||
EIDLED_LBCFG2 EQU (1<<10)
|
||||
EIDLED_LBCFG1 EQU (1<<9)
|
||||
EIDLED_LBCFG0 EQU (1<<8)
|
||||
EIDLED_DEVID2 EQU (1<<7)
|
||||
EIDLED_DEVID1 EQU (1<<6)
|
||||
EIDLED_DEVID0 EQU (1<<5)
|
||||
EIDLED_REVID4 EQU (1<<4)
|
||||
EIDLED_REVID3 EQU (1<<3)
|
||||
EIDLED_REVID2 EQU (1<<2)
|
||||
EIDLED_REVID1 EQU (1<<1)
|
||||
EIDLED_REVID0 EQU (1)
|
||||
|
||||
; PHCON1 bits ---------
|
||||
PHCON1_PRST EQU (1<<15)
|
||||
PHCON1_PLOOPBK EQU (1<<14)
|
||||
PHCON1_SPD100 EQU (1<<13)
|
||||
PHCON1_ANEN EQU (1<<12)
|
||||
PHCON1_PSLEEP EQU (1<<11)
|
||||
PHCON1_r10 EQU (1<<10)
|
||||
PHCON1_RENEG EQU (1<<9)
|
||||
PHCON1_PFULDPX EQU (1<<8)
|
||||
PHCON1_r7 EQU (1<<7)
|
||||
PHCON1_r6 EQU (1<<6)
|
||||
PHCON1_r5 EQU (1<<5)
|
||||
PHCON1_r4 EQU (1<<4)
|
||||
PHCON1_r3 EQU (1<<3)
|
||||
PHCON1_r2 EQU (1<<2)
|
||||
PHCON1_r1 EQU (1<<1)
|
||||
PHCON1_r0 EQU (1)
|
||||
|
||||
; PHSTAT1 bits --------
|
||||
PHSTAT1_r15 EQU (1<<15)
|
||||
PHSTAT1_FULL100 EQU (1<<14)
|
||||
PHSTAT1_HALF100 EQU (1<<13)
|
||||
PHSTAT1_FULL10 EQU (1<<12)
|
||||
PHSTAT1_HALF10 EQU (1<<11)
|
||||
PHSTAT1_r10 EQU (1<<10)
|
||||
PHSTAT1_r9 EQU (1<<9)
|
||||
PHSTAT1_r8 EQU (1<<8)
|
||||
PHSTAT1_r7 EQU (1<<7)
|
||||
PHSTAT1_r6 EQU (1<<6)
|
||||
PHSTAT1_ANDONE EQU (1<<5)
|
||||
PHSTAT1_LRFAULT EQU (1<<4)
|
||||
PHSTAT1_ANABLE EQU (1<<3)
|
||||
PHSTAT1_LLSTAT EQU (1<<2)
|
||||
PHSTAT1_r1 EQU (1<<1)
|
||||
PHSTAT1_EXTREGS EQU (1)
|
||||
|
||||
; PHANA bits ----------
|
||||
PHANA_ADNP EQU (1<<15)
|
||||
PHANA_r14 EQU (1<<14)
|
||||
PHANA_ADFAULT EQU (1<<13)
|
||||
PHANA_r12 EQU (1<<12)
|
||||
PHANA_ADPAUS1 EQU (1<<11)
|
||||
PHANA_ADPAUS0 EQU (1<<10)
|
||||
PHANA_r9 EQU (1<<9)
|
||||
PHANA_AD100FD EQU (1<<8)
|
||||
PHANA_AD100 EQU (1<<7)
|
||||
PHANA_AD10FD EQU (1<<6)
|
||||
PHANA_AD10 EQU (1<<5)
|
||||
PHANA_ADIEEE4 EQU (1<<4)
|
||||
PHANA_ADIEEE3 EQU (1<<3)
|
||||
PHANA_ADIEEE2 EQU (1<<2)
|
||||
PHANA_ADIEEE1 EQU (1<<1)
|
||||
PHANA_ADIEEE0 EQU (1)
|
||||
|
||||
; PHANLPA bits --------
|
||||
PHANLPA_LPNP EQU (1<<15)
|
||||
PHANLPA_LPACK EQU (1<<14)
|
||||
PHANLPA_LPFAULT EQU (1<<13)
|
||||
PHANLPA_r12 EQU (1<<12)
|
||||
PHANLPA_LPPAUS1 EQU (1<<11)
|
||||
PHANLPA_LPPAUS0 EQU (1<<10)
|
||||
PHANLPA_LP100T4 EQU (1<<9)
|
||||
PHANLPA_LP100FD EQU (1<<8)
|
||||
PHANLPA_LP100 EQU (1<<7)
|
||||
PHANLPA_LP10FD EQU (1<<6)
|
||||
PHANLPA_LP10 EQU (1<<5)
|
||||
PHANLPA_LPIEEE4 EQU (1<<4)
|
||||
PHANLPA_LPIEEE3 EQU (1<<3)
|
||||
PHANLPA_LPIEEE2 EQU (1<<2)
|
||||
PHANLPA_LPIEEE1 EQU (1<<1)
|
||||
PHANLPA_LPIEEE0 EQU (1)
|
||||
|
||||
; PHANE bits ----------
|
||||
PHANE_r15 EQU (1<<15)
|
||||
PHANE_r14 EQU (1<<14)
|
||||
PHANE_r13 EQU (1<<13)
|
||||
PHANE_r12 EQU (1<<12)
|
||||
PHANE_r11 EQU (1<<11)
|
||||
PHANE_r10 EQU (1<<10)
|
||||
PHANE_r9 EQU (1<<9)
|
||||
PHANE_r8 EQU (1<<8)
|
||||
PHANE_r7 EQU (1<<7)
|
||||
PHANE_r6 EQU (1<<6)
|
||||
PHANE_r5 EQU (1<<5)
|
||||
PHANE_PDFLT EQU (1<<4)
|
||||
PHANE_r3 EQU (1<<3)
|
||||
PHANE_r2 EQU (1<<2)
|
||||
PHANE_LPARCD EQU (1<<1)
|
||||
PHANA_LPANABL EQU (1)
|
||||
|
||||
; PHCON2 bits ---------
|
||||
PHCON2_r15 EQU (1<<15)
|
||||
PHCON2_r14 EQU (1<<14)
|
||||
PHCON2_EDPWRDN EQU (1<<13)
|
||||
PHCON2_r12 EQU (1<<12)
|
||||
PHCON2_EDTHRES EQU (1<<11)
|
||||
PHCON2_r10 EQU (1<<10)
|
||||
PHCON2_r9 EQU (1<<9)
|
||||
PHCON2_r8 EQU (1<<8)
|
||||
PHCON2_r7 EQU (1<<7)
|
||||
PHCON2_r6 EQU (1<<6)
|
||||
PHCON2_r5 EQU (1<<5)
|
||||
PHCON2_r4 EQU (1<<4)
|
||||
PHCON2_r3 EQU (1<<3)
|
||||
PHCON2_FRCLNK EQU (1<<2)
|
||||
PHCON2_EDSTAT EQU (1<<1)
|
||||
PHCON2_r0 EQU (1)
|
||||
|
||||
; PHSTAT2 bits ---------
|
||||
PHSTAT2_r15 EQU (1<<15)
|
||||
PHSTAT2_r14 EQU (1<<14)
|
||||
PHSTAT2_r13 EQU (1<<13)
|
||||
PHSTAT2_r12 EQU (1<<12)
|
||||
PHSTAT2_r11 EQU (1<<11)
|
||||
PHSTAT2_r10 EQU (1<<10)
|
||||
PHSTAT2_r9 EQU (1<<9)
|
||||
PHSTAT2_r8 EQU (1<<8)
|
||||
PHSTAT2_r7 EQU (1<<7)
|
||||
PHSTAT2_r6 EQU (1<<6)
|
||||
PHSTAT2_r5 EQU (1<<5)
|
||||
PHSTAT2_PLRITY EQU (1<<4)
|
||||
PHSTAT2_r3 EQU (1<<3)
|
||||
PHSTAT2_r2 EQU (1<<2)
|
||||
PHSTAT2_r1 EQU (1<<1)
|
||||
PHSTAT2_r0 EQU (1)
|
||||
|
||||
; PHSTAT3 bits --------
|
||||
PHSTAT3_r15 EQU (1<<15)
|
||||
PHSTAT3_r14 EQU (1<<14)
|
||||
PHSTAT3_r13 EQU (1<<13)
|
||||
PHSTAT3_r12 EQU (1<<12)
|
||||
PHSTAT3_r11 EQU (1<<11)
|
||||
PHSTAT3_r10 EQU (1<<10)
|
||||
PHSTAT3_r9 EQU (1<<9)
|
||||
PHSTAT3_r8 EQU (1<<8)
|
||||
PHSTAT3_r7 EQU (1<<7)
|
||||
PHSTAT3_r6 EQU (1<<6)
|
||||
PHSTAT3_r5 EQU (1<<5)
|
||||
PHSTAT3_SPDDPX2 EQU (1<<4)
|
||||
PHSTAT3_SPDDPX1 EQU (1<<3)
|
||||
PHSTAT3_SPDDPX0 EQU (1<<2)
|
||||
PHSTAT3_r1 EQU (1<<1)
|
||||
PHSTAT3_r0 EQU (1)
|
||||
|
||||
;------------------------------ internal defaults ----------------------------------
|
||||
;33.333Mhz clock out frequency
|
||||
CLOCK_33_CLR EQU (ECON2_COCON3|ECON2_COCON2|ECON2_COCON1) ;clr mask
|
||||
CLOCK_33_SET EQU (ECON2_COCON0) ;set mask
|
||||
;25 MHz
|
||||
CLOCK_25_CLR EQU (ECON2_COCON3|ECON2_COCON2|ECON2_COCON0) ;clr mask
|
||||
CLOCK_25_SET EQU (ECON2_COCON1) ;set mask
|
||||
;20 MHz
|
||||
CLOCK_20_CLR EQU (ECON2_COCON3|ECON2_COCON2) ;clr mask
|
||||
CLOCK_20_SET EQU (ECON2_COCON1|ECON2_COCON0) ;set mask
|
||||
;16 MHz
|
||||
CLOCK_16_CLR EQU (ECON2_COCON3|ECON2_COCON0|ECON2_COCON1) ;clr mask
|
||||
CLOCK_16_SET EQU (ECON2_COCON2) ;set mask
|
||||
;4 MHz (after reset)
|
||||
CLOCK_4_CLR EQU (ECON2_COCON2) ;clr mask
|
||||
CLOCK_4_SET EQU (ECON2_COCON3|ECON2_COCON0|ECON2_COCON1) ;set mask
|
||||
|
||||
CLOCK_DEF_CLR EQU CLOCK_33_CLR
|
||||
CLOCK_DEF_SET EQU CLOCK_33_SET
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
hw.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Hardware dependent functions
|
||||
|
||||
|
||||
*/
|
||||
#ifndef _INC_HW_H
|
||||
#define _INC_HW_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
#ifndef DEVBASETYPE
|
||||
struct devbase;
|
||||
#define DEVBASETYPE struct devbase
|
||||
#endif
|
||||
#ifndef DEVBASEP
|
||||
#define DEVBASEP DEVBASETYPE *db
|
||||
#endif
|
||||
|
||||
|
||||
/* find number of boards (stateless) */
|
||||
ASM SAVEDS LONG hw_Find_Boards( ASMR(a0) DEVBASEP ASMREG(a0) );
|
||||
|
||||
/* allocate / release a board
|
||||
note: alloc may be called more than once, keep track of number of openings
|
||||
*/
|
||||
ASM SAVEDS LONG hw_AllocBoard( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) );
|
||||
ASM SAVEDS LONG hw_ReleaseBoard( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) );
|
||||
|
||||
ASM SAVEDS LONG hw_GetMacAddress(ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *mac ASMREG(a1) );
|
||||
|
||||
/* initialize global management stuff for hardware (called once on server startup) */
|
||||
/*
|
||||
Call order
|
||||
- hw_Setup
|
||||
hw_ConfigInit
|
||||
hw_ConfigUpdate
|
||||
hw_Attach
|
||||
main loop: send/recv
|
||||
hw_Detach
|
||||
- hw_Shutdown
|
||||
*/
|
||||
ASM SAVEDS LONG hw_Setup( ASMR(a0) DEVBASEP ASMREG(a0) );
|
||||
ASM SAVEDS void hw_Shutdown( ASMR(a0) DEVBASEP ASMREG(a0) );
|
||||
|
||||
ASM SAVEDS LONG hw_Attach( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0));
|
||||
ASM SAVEDS void hw_Detach( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0));
|
||||
|
||||
ASM SAVEDS void hw_ConfigInit( ASMR(a0) DEVBASEP ASMREG(a0) );
|
||||
ASM SAVEDS void hw_ConfigUpdate( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(a1) void * ASMREG(a1) );
|
||||
|
||||
ASM SAVEDS LONG hw_send_frame( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *frame ASMREG(a1),
|
||||
ASMR(d1) ULONG framesize ASMREG(d1) );
|
||||
|
||||
ASM SAVEDS LONG hw_recv_frame( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *frame ASMREG(a1) );
|
||||
|
||||
ASM SAVEDS LONG hw_recv_pending( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) );
|
||||
|
||||
ASM SAVEDS LONG hw_check_link_change( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) );
|
||||
|
||||
ASM SAVEDS LONG hw_change_multicast( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(a0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) struct List * ASMREG(a1) );
|
||||
|
||||
|
||||
/* kept this global for now: Z-II/Z-III boards share the same interrupt */
|
||||
ASM SAVEDS ULONG hw_recv_sigmask( ASMR(a0) DEVBASEP ASMREG(a0) );
|
||||
|
||||
|
||||
|
||||
/* Configuration template: straight replica of Plipbox general options */
|
||||
struct CommonConfig {
|
||||
ULONG nospecialstats;
|
||||
LONG *priority;
|
||||
ULONG *bps;
|
||||
ULONG *mtu;
|
||||
};
|
||||
|
||||
#define COMMON_TEMPLATE "NOSPECIALSTATS/S,PRIORITY=PRI/K/N,BPS/K/N,MTU/K/N,"
|
||||
|
||||
/* additional definitions */
|
||||
#include "hwprivate.h"
|
||||
|
||||
|
||||
#endif /* _INC_HW_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
macros.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
useful macros
|
||||
|
||||
*/
|
||||
#ifndef _INC_MACROS_H
|
||||
#define _INC_MACROS_H
|
||||
|
||||
#define GetHead(l) (void *)(((struct List *)l)->lh_Head->ln_Succ \
|
||||
? ((struct List *)l)->lh_Head \
|
||||
: (struct Node *)0)
|
||||
#define GetTail(l) (void *)(((struct List *)l)->lh_TailPred->ln_Pred \
|
||||
? ((struct List *)l)->lh_TailPred \
|
||||
: (struct Node *)0)
|
||||
#define GetSucc(n) (void *)(((struct Node *)n)->ln_Succ->ln_Succ \
|
||||
? ((struct Node *)n)->ln_Succ \
|
||||
: (struct Node *)0)
|
||||
#define GetPred(n) (void *)(((struct Node *)n)->ln_Pred->ln_Pred \
|
||||
? ((struct Node *)n)->ln_Pred \
|
||||
: (struct Node *)0)
|
||||
|
||||
#define REMOVE(n) ((void)(\
|
||||
((struct Node *)n)->ln_Pred->ln_Succ = ((struct Node *)n)->ln_Succ,\
|
||||
((struct Node *)n)->ln_Succ->ln_Pred = ((struct Node *)n)->ln_Pred ))
|
||||
|
||||
#define ADDHEAD(l,n) ((void)(\
|
||||
((struct Node *)n)->ln_Succ = ((struct List *)l)->lh_Head, \
|
||||
((struct Node *)n)->ln_Pred = (struct Node *)&((struct List *)l)->lh_Head, \
|
||||
((struct List *)l)->lh_Head->ln_Pred = ((struct Node *)n), \
|
||||
((struct List *)l)->lh_Head = ((struct Node *)n)))
|
||||
|
||||
#define ADDTAIL(l,n) ((void)(\
|
||||
((struct Node *)n)->ln_Succ = (struct Node *)&((struct List *)l)->lh_Tail, \
|
||||
((struct Node *)n)->ln_Pred = ((struct List *)l)->lh_TailPred, \
|
||||
((struct List *)l)->lh_TailPred->ln_Succ = ((struct Node *)n), \
|
||||
((struct List *)l)->lh_TailPred = ((struct Node *)n) ))
|
||||
|
||||
#define NEWLIST(l) (((struct List *)l)->lh_TailPred = (struct Node *)(l), \
|
||||
((struct List *)l)->lh_Tail = 0, \
|
||||
((struct List *)l)->lh_Head = (struct Node *)&(((struct List *)l)->lh_Tail))
|
||||
|
||||
|
||||
#define min(_a_,_b_) ( (_a_) > (_b_) ) ? _b_ : _a_
|
||||
#define max(_a_,_b_) ( (_a_) < (_b_) ) ? _b_ : _a_
|
||||
#define BOUNDS(_val_,_min_,_max_) ( (_val_) < (_min_) ) ? _min_ : ( (_val_) > (_max_) ) ? _max_ : _val_
|
||||
|
||||
|
||||
#endif /* _INC_MACROS_H */
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
TODO-List:
|
||||
|
||||
Nospecialstats in server.c ?
|
||||
Interrupt on V500 Expansion port ?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
SDNet - A SANA-II driver for ENC28J60 10BaseT ethernet modules
|
||||
|
||||
Written in 2016-2018 by Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
This driver is supposed to support ENC28J60 modules hooked up to the MicroSD
|
||||
slot of Vampire 500/600 cards or the expansion port of Vampire 500V2+ cards.
|
||||
|
||||
|
||||
Installation:
|
||||
-------------
|
||||
|
||||
Installation of the driver is straightforward.
|
||||
Just copy the sdnet.device and v2expeth.device to devs:networks and enable
|
||||
the interface in your favorite TCP/IP stack as usual. So far, successful
|
||||
tests have been done with the free AmiTCP/IP 3.0b2, AmiTCP4.0-4.2, Genesis,
|
||||
MiamiDX and RoadShow.
|
||||
|
||||
devs:networks/sdnet.device - SD card slot of V600/V500
|
||||
devs:networks/v2expeth.device - expansion port of V500V2+
|
||||
|
||||
From version 0.8, the driver will require vampire.resource which is included
|
||||
in the ROM of Vampire Cards since the Gold2.5 release.
|
||||
|
||||
Also, make sure that the Vampire SD Card driver (sagasd.device) is not present
|
||||
in the system or at least inactive when using sdnet.device. Both pieces of
|
||||
software bang the same hardware registers. v2expeth.device may be used safely
|
||||
in conjunction with the SD card driver.
|
||||
|
||||
|
||||
Vampire500 Expansion port Hardware
|
||||
-----------------------------------
|
||||
|
||||
Please see http://wiki.apollo-accelerators.com/doku.php/expansionport for
|
||||
guidance.
|
||||
|
||||
|
||||
MicroSD Slot Hardware:
|
||||
----------------------
|
||||
|
||||
In terms of required hardware, you need the following:
|
||||
- ready-to-use ENC28J60 module (a 3.3V part, DON'T USE an _unmodified_ 5V
|
||||
module!)
|
||||
- MicroSD breakout, e.g.
|
||||
- a TF to SD extension cable where you rip off the full size SD slot and
|
||||
solder on short extension cables towards the ENC28J60 module
|
||||
- MicroSD breakout board (that comes directly with pin headers)
|
||||
|
||||
!!ATTENTION!!
|
||||
Be extremely careful with your SD breakout board. Many conveniently looking
|
||||
breakouts are made of thick and/or sharp edged PCB material that will likely
|
||||
damage your Vampire SD slot. Such breakouts could be made working - but only
|
||||
after patient sanding. Some people in the beta test team have destroyed
|
||||
their SD slot already. If you don't have the required mechanical skills and
|
||||
patience, I'd advise against DIY building.
|
||||
!!ATTENTION!!
|
||||
|
||||
You need to connect the SD breakout pins as follows (microSD card sketch
|
||||
looking at the connectors) to the ENC28J60 module:
|
||||
|
||||
----------------------- ENC28J60
|
||||
| 8 ----
|
||||
| 7 ---- SO -------------------- SO
|
||||
| 6 ----- GND -------------------- GND
|
||||
| 5 ---- SCK -------------------- SCK
|
||||
| 4 ----- +3.3V ------ +3.3V ----- VCC (see below)
|
||||
| 3 ---- SI -------------------- SI
|
||||
| 2 ---- /CS -------------------- /CS
|
||||
| 1 ---- /INT -- __________ -- /INT
|
||||
------ ------------- \_| 3.3 kOhm |_/
|
||||
\___| `----------´
|
||||
|
||||
As there is a myriad of ENC28J60 modules available, the naming scheme on
|
||||
a particular board might differ. Please be aware the some of the boards
|
||||
have a "CLK" pin as well as an "SCK" pin. Use the latter.
|
||||
|
||||
My test setup uses a separate 5V to 3.3V DC-DC converter. I got confirmation
|
||||
from Igor Majstorovic (majsta) that the 3.3V line on his V500 Vampire designs
|
||||
should be able to handle the max. 200 mA required by the module. To be on the
|
||||
safe side, I recommend to use a conveniently placed 5V to 3.3V converter
|
||||
(hint: the Floppy power connector is easily accessible).
|
||||
|
||||
Speaking of power: the reason why I didn't recommend 5V ENC28J60 boards
|
||||
is that at least some of them have pullups from /CS and /RST to +5V. Your 3.3V
|
||||
Vampire SD slot will quite likely not be happy with that.
|
||||
|
||||
Please put a 3.3 kOhm resistor into the connection from /INT of the ENC28J60 to
|
||||
pin 1 of the MicroSD breakout.
|
||||
|
||||
|
||||
Testing a new module:
|
||||
---------------------
|
||||
|
||||
I've included two small test programs: sdnettest and v2expethtest. Both will
|
||||
require the TCP/IP stack to be off(!) The program will perform a series of tests
|
||||
to check for module presence and communication results at various clock rates. Don't
|
||||
be alarmed when the slowest (biggest clock divider) mode is commented with a "fail".
|
||||
This is intentional. What matters is that SPI clock dividers 1, 2 and 3 are working
|
||||
properly. In case that sdnettest shows a failure for divider 1, see below how
|
||||
to set a higher clock divider.
|
||||
|
||||
Use sdnettest for the SD slot and v2expethtest for the V500 expansion connector.
|
||||
|
||||
|
||||
Software notes:
|
||||
---------------
|
||||
|
||||
|
||||
- The SD slot doesn't feature an interrupt. I had to implement polling
|
||||
for incoming data. The current default interval is 10ms. (configurable via
|
||||
echo "TIMER=20000" >ENVARC:sana2/sdnet.config, value in microseconds,
|
||||
don't forget Makedir ENVARC:Sana2 if it didn't exist yet, you may also
|
||||
consider "setenv")
|
||||
|
||||
- SPI speed is set to a safe level supporting higher core speeds than
|
||||
x11 (see released x12 cores). Therefore this default of "SPISPEED=2"
|
||||
is not providing maximum performance on x10 or x11 cores. For max
|
||||
speed you may set echo "SPISPEED=1" >ENVARC:sana2/sdnet.config or
|
||||
echo "SPISPEED=1" >ENVARC:sana2/v2expeth.config, respectively. I'd
|
||||
suggest to run the test tool to determine the maximum reliable
|
||||
speed setting.
|
||||
|
||||
- The required vampire.resource is unavailable with older versions of the
|
||||
Vampire Kick Rom (anything before Gold2.5).
|
||||
To load vampire.resource manually, copy the file to SYS:devs/ and
|
||||
add the following near the top of your startup-sequence
|
||||
C:VERSION >nil: vampire.resource 42
|
||||
IF WARN
|
||||
LoadModule >nil: DEVS:vampire.resource
|
||||
ENDIF
|
||||
In case of OS3.9, you can add the "noreboot" keyword to the loadmodule
|
||||
line if you call the sniplet above before setpatch.
|
||||
|
||||
- If you want to use multiple options in the SANA-II config, concatenate them
|
||||
in the "echo" command (alternatively "setenv") or use a text editor.
|
||||
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
Below you find the options accepted by the drivers. Please note that no special
|
||||
configuration is necessary for normal operation. What you find documented below
|
||||
is available for tuning purposes.
|
||||
|
||||
The options template for the config files
|
||||
ENVARC:sana2/sdnet.config
|
||||
ENVARC:sana2/v2expeth.config
|
||||
|
||||
is as follows:
|
||||
|
||||
NOSPECIALSTATS/S,PRIORITY=PRI/K/N,BPS/K/N,MTU/K/N,FULLDUPLEX/S,SPISPEED/K/N,
|
||||
TIMER/K/N,MULTICAST/S
|
||||
|
||||
SPISPEED - SPI clock divider (1-10, default 2), controls maximum
|
||||
clock of SPI bus. Actual I/O clock is Core_Clock/(3+SPISPEED).
|
||||
|
||||
FULLDUPLEX - change Ethernet module into full duplex mode,
|
||||
caution: requires manual configuration of duplex mode
|
||||
on the switch, too.
|
||||
|
||||
PRIORITY - server task priority (default 1)
|
||||
|
||||
BPS - bit per seconds for statistics purposes
|
||||
|
||||
MTU - maximum transmission unit (default 1500)
|
||||
|
||||
NOSPECIALSTATS - obsolete, kept for config file backwards compatibility with
|
||||
old driver
|
||||
|
||||
MULTICAST - obsolete, kept for config file backwards compatibility with
|
||||
old driver
|
||||
|
||||
example (useful for DSL via PPPoE on x11 core with AmiTCP):
|
||||
echo "MTU=1492 SPISPEED=1 PRIORITY=6" >ENVARC:sana2/sdnet.config
|
||||
|
||||
|
||||
Changelog:
|
||||
----------
|
||||
|
||||
1.90 - first Beta of completely rewritten driver
|
||||
- support for concurrent IP stacks
|
||||
- faster handling of statistics
|
||||
- multiple board support where applicable (not for sdnet)
|
||||
- workaround for Shapeshifter network plugin bug
|
||||
- GCC or VBCC as compiler
|
||||
- faster lowlevel read/write
|
||||
|
||||
1.03 - small fixes in sdnettest/v2expethtest, graceful exit when not run
|
||||
on Vampire Gold 2.5 or later core
|
||||
- fixed a minor bug in signal handling
|
||||
|
||||
1.02 - added build variant for V500V2+ expansion port, same config options
|
||||
but distinct config file (ENV:SANA2/v2expeth.config), see
|
||||
http://wiki.apollo-accelerators.com/doku.php/expansionport for pinout
|
||||
- some more work on robustness (TX robustness and more error handling
|
||||
this time)
|
||||
- reworked test utilities to send valid BOOTP/DHCP requests while
|
||||
doing TX/RX testing, increases chance of received frames within
|
||||
testing interval
|
||||
|
||||
1.01 - some more fine tuning
|
||||
- adjustments for Gold 2.7 x12, i.e. SPISPEED=2 by default
|
||||
(see above for reverting to clock divider 1)
|
||||
|
||||
1.0 - some modest performance improvements
|
||||
- reworked lowlevel code for higher robustness
|
||||
- LED blinking modified: green LED will blink on RX,
|
||||
orange LED blinks on TX
|
||||
|
||||
0.81 - sdnettest added
|
||||
|
||||
0.8 - proper hardware allocation by means of vampire.resource
|
||||
- check for ENC28J60 hardware presence
|
||||
|
||||
0.7 - cleanups
|
||||
|
||||
0.6 - SPI speed setting support
|
||||
- removal of spi.c,spi.h
|
||||
|
||||
0.5 - auto-generated MAC address, based on the Vampire FPGA serial
|
||||
- busy waiting moved entirely to lowlevel asm source
|
||||
- optimized compilation now produces working binaries
|
||||
- more cleanups
|
||||
|
||||
0.4 - cleanups, config variables added
|
||||
|
||||
0.3 - first version shared with the Apollo team
|
||||
|
||||
|
||||
Copyrights:
|
||||
-----------
|
||||
|
||||
The SDNet 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.
|
||||
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
Microchip ENC28J60 Ethernet Interface Driver
|
||||
Author: Henryk Richter
|
||||
Copyright: GPL V2
|
||||
|
||||
Notes: when I ran into timing issues in early development, I moved over to quickly
|
||||
testable ASM code for SPI communication. I didn't bother porting that stuff
|
||||
back into C code. So this file now references enc28j60l.asm for lowlevel direct
|
||||
hardware access.
|
||||
As a consequence, the only functions needed from spi.c are the spi_init() and
|
||||
spi_disable_eth().
|
||||
|
||||
TODO: - support for power down when unused, i.e. offline
|
||||
- replace busy waiting loop after reset
|
||||
|
||||
Based on work by
|
||||
Christian Vogelgsaang
|
||||
Guido Socher
|
||||
Pascal Stang (see enc28j60.c in AVRlib library for the original file)
|
||||
*/
|
||||
#undef _DO_DUMP
|
||||
|
||||
/* used for Delay() */
|
||||
#include <dos/dos.h>
|
||||
#include <proto/dos.h>
|
||||
|
||||
#ifdef _DO_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "compiler.h"
|
||||
#include "enc28j60.h"
|
||||
#include "enc28j60l.h" /* import lowlevel asm functions */
|
||||
/* #include "spi.h" */ /* no direct use anymore, just for init purposes) */
|
||||
#include "device.h"
|
||||
|
||||
/*
|
||||
The RXSTART_INIT must be zero. See Rev. B4 Silicon Errata point 5.
|
||||
Buffer boundaries applied to internal 8K ram
|
||||
the entire available packet buffer space is allocated
|
||||
|
||||
rx packet layout
|
||||
6 byte heaader
|
||||
1518
|
||||
sum: 1524
|
||||
*/
|
||||
|
||||
#define RXSTART_INIT 0x0000 /* start of RX buffer, room for 4 packets */
|
||||
#define RXSTOP_INIT 0x19FF /* end of RX buffer */
|
||||
|
||||
#define TXSTART_INIT 0x1A00 /* start of TX buffer, room for 1 packet */
|
||||
#define TXSTOP_INIT 0x1FFF /* end of TX buffer */
|
||||
|
||||
/* max frame length which the conroller will accept: */
|
||||
/* (note: maximum ethernet frame length would be 1518 when VLAN tagging is unused) */
|
||||
#define MAX_FRAMELEN 1518
|
||||
|
||||
static u16 gNextPacketPtr;
|
||||
static u08 is_full_duplex;
|
||||
static u08 rev;
|
||||
|
||||
struct enc28j60_initvars {
|
||||
u16 have_recv;
|
||||
u08 last_mac[6];
|
||||
u08 macon1;
|
||||
u08 macon2;
|
||||
u08 macon3;
|
||||
u08 macon4;
|
||||
};
|
||||
static struct enc28j60_initvars initvars;
|
||||
|
||||
|
||||
static void enc28j60_recv_reset( struct enc28j60_initvars *iv, u08 restart );
|
||||
static int enc28j60_check_config( struct enc28j60_initvars *iv );
|
||||
|
||||
|
||||
static uint8_t readOp (uint8_t op, uint8_t address)
|
||||
{
|
||||
return enc28j60l_ReadOp( op, address );
|
||||
}
|
||||
|
||||
static void writeOp (uint8_t op, uint8_t address, uint8_t data)
|
||||
{
|
||||
enc28j60l_WriteOp( op, address,data );
|
||||
}
|
||||
|
||||
static void readBuf(uint16_t len, uint8_t* data)
|
||||
{
|
||||
enc28j60l_ReadBuffer( data, (unsigned int)len );
|
||||
}
|
||||
|
||||
void SetBank (uint8_t address)
|
||||
{
|
||||
enc28j60l_SetBank(address);
|
||||
}
|
||||
|
||||
static uint8_t readRegByte (uint8_t address)
|
||||
{
|
||||
return enc28j60l_ReadRegByte( address );
|
||||
}
|
||||
|
||||
#if 0
|
||||
static uint16_t readReg(uint8_t address) {
|
||||
return readRegByte(address) + (readRegByte(address+1) << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void writeRegByte (uint8_t address, uint8_t data)
|
||||
{
|
||||
enc28j60l_WriteRegByte( address, data );
|
||||
}
|
||||
|
||||
static void writeReg(uint8_t address, uint16_t data)
|
||||
{
|
||||
enc28j60l_WriteReg( address, data );
|
||||
}
|
||||
|
||||
/*
|
||||
the PHY registers require special care
|
||||
*/
|
||||
static uint16_t readPhyByte (uint8_t address) {
|
||||
writeRegByte(MIREGADR, address);
|
||||
writeRegByte(MICMD, MICMD_MIIRD);
|
||||
while (readRegByte(MISTAT) & MISTAT_BUSY)
|
||||
;
|
||||
writeRegByte(MICMD, 0x00);
|
||||
return readRegByte(MIRD+1);
|
||||
}
|
||||
|
||||
static void writePhy (uint8_t address, uint16_t data) {
|
||||
writeRegByte(MIREGADR, address);
|
||||
writeReg(MIWR, data);
|
||||
while (readRegByte(MISTAT) & MISTAT_BUSY)
|
||||
;
|
||||
}
|
||||
|
||||
/* just a pass-through to the lowlevel routines */
|
||||
void enc28j60_SetSPISpeed( unsigned long clock_divider )
|
||||
{
|
||||
enc28j60l_SetSPISpeed( clock_divider );
|
||||
}
|
||||
|
||||
/* ---------- init ---------- */
|
||||
|
||||
/* Functions to enable/disable broadcast filter bits */
|
||||
/* With the bit set, broadcast packets are filtered. */
|
||||
void enc28j60_broadcast_multicast_filter( u08 flags )
|
||||
{
|
||||
u08 val = ERXFCON_UCEN|ERXFCON_CRCEN; /* default: crc check and unicast */
|
||||
|
||||
if( flags & PIO_INIT_PROMISC )
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( flags & PIO_INIT_BROAD_CAST )
|
||||
val |= ERXFCON_BCEN;
|
||||
if( flags & PIO_INIT_MULTI_CAST )
|
||||
val |= ERXFCON_MCEN;
|
||||
}
|
||||
writeRegByte(ERXFCON, val );
|
||||
}
|
||||
|
||||
static void enc28j60_recv_reset( struct enc28j60_initvars *iv, u08 restart )
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ESTAT, ESTAT_TXABRT);
|
||||
|
||||
gNextPacketPtr = RXSTART_INIT;
|
||||
writeReg(ERXST, RXSTART_INIT);
|
||||
writeReg(ERXRDPT, RXSTOP_INIT );
|
||||
writeReg(ERXND, RXSTOP_INIT);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF|EIR_RXERIF );
|
||||
writeReg(MAMXFL, MAX_FRAMELEN);
|
||||
|
||||
writeRegByte(MACON4, iv->macon4 ); /* DEFER bit */
|
||||
writeRegByte(MACON3, iv->macon3 );
|
||||
writeRegByte(MACON2, iv->macon2 );
|
||||
writeRegByte(MACON1, iv->macon1 );
|
||||
|
||||
enc28j60_setMAC( iv->last_mac );
|
||||
|
||||
writePhy(PHIE, PHIE_PGEIE|PHIE_LNKIE );
|
||||
writePhy(PHLCON, 0x3c12 ); /* 3(fixed) C(LinkStat+RX Act) 1(TX Act) 2(Stretch enable) */
|
||||
|
||||
/* prepare flow control */
|
||||
writeReg(EPAUS, 20 * 100); /* 100ms */
|
||||
|
||||
if( restart )
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
|
||||
iv->have_recv = 0;
|
||||
}
|
||||
|
||||
|
||||
static int enc28j60_check_config( struct enc28j60_initvars *iv )
|
||||
{
|
||||
int ret = 1; /* def: be optimistic */
|
||||
|
||||
/* check RX registers */
|
||||
if( !(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_RXEN ) )
|
||||
ret = 0;
|
||||
if( (readRegByte(MACON1)&iv->macon1) != iv->macon1 )
|
||||
ret = 0;
|
||||
if( (readRegByte(MACON2)&iv->macon2) != iv->macon2 )
|
||||
ret = 0;
|
||||
if( (readRegByte(MACON3)&iv->macon3) != iv->macon3 )
|
||||
ret = 0;
|
||||
|
||||
/* check TX problems */
|
||||
if( readRegByte(ESTAT) & ESTAT_TXABRT )
|
||||
ret = 0;
|
||||
if( readRegByte(EIR) & EIR_TXERIF )
|
||||
ret = 0;
|
||||
|
||||
/* Verify MAC */
|
||||
if( readRegByte(MAADR5) != iv->last_mac[0] )
|
||||
ret = 0;
|
||||
if( readRegByte(MAADR4) != iv->last_mac[1] )
|
||||
ret = 0;
|
||||
if( readRegByte(MAADR3) != iv->last_mac[2] )
|
||||
ret = 0;
|
||||
if( readRegByte(MAADR2) != iv->last_mac[3] )
|
||||
ret = 0;
|
||||
if( readRegByte(MAADR1) != iv->last_mac[4] )
|
||||
ret = 0;
|
||||
if( readRegByte(MAADR0) != iv->last_mac[5] )
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
u08 enc28j60_init(const u08 macaddr[6], u08 flags)
|
||||
{
|
||||
unsigned int count;
|
||||
u08 mac3val;
|
||||
struct enc28j60_initvars *iv = &initvars;
|
||||
|
||||
enc28j60l_Init(); /* spi_init(); spi_disable_eth(); */
|
||||
|
||||
{
|
||||
int i;
|
||||
for(i=0 ; i < 6 ; i++ )
|
||||
iv->last_mac[i] = macaddr[i];
|
||||
}
|
||||
|
||||
is_full_duplex = (flags & PIO_INIT_FULL_DUPLEX) == PIO_INIT_FULL_DUPLEX;
|
||||
|
||||
/* soft reset cpu */
|
||||
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
|
||||
#if 1
|
||||
enc28j60l_UMinDelay( 2000 ); /* wait 2 ms */
|
||||
#else
|
||||
/* Delay(1);*/ /* _delay_ms(2); // errata B7/2 */
|
||||
/* hard-coded delay right now (TODO: import timer functions) */
|
||||
for( count = 0 ; count < 20000 ; count++ )
|
||||
{
|
||||
mac3val |= (u08)*((volatile unsigned short*)(0x00DE0004));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* wait or error */
|
||||
count = 0;
|
||||
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) {
|
||||
count ++;
|
||||
if(count == 0xfff) {
|
||||
return PIO_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
writeOp(ENC28J60_WRITE_CTRL_REG, ECON1, 0);
|
||||
|
||||
/* return rev */
|
||||
rev = readRegByte(EREVID);
|
||||
/* microchip forgot to step the number on the silcon when they */
|
||||
/* released the revision B7. 6 is now rev B7. We still have */
|
||||
/* to see what they do when they release B8. At the moment */
|
||||
/* there is no B8 out yet */
|
||||
if ( (rev < 1) || (rev > 10) ) /* I don't expect a rev > 10 (+1), so I use it to check for module presence */
|
||||
return PIO_NOT_FOUND; /* important: check this before any writePhy -> no module gets us 0xff back */
|
||||
|
||||
if (rev > 5) ++rev;
|
||||
|
||||
writeReg(ETXST, TXSTART_INIT);
|
||||
writeReg(ETXND, TXSTOP_INIT);
|
||||
|
||||
/* set packet filter */
|
||||
enc28j60_broadcast_multicast_filter( flags );/* flags & (PIO_INIT_BROAD_CAST|PIO_INIT_MULTI_CAST) ); */
|
||||
|
||||
/* BIST pattern generator? */
|
||||
writeReg(EPMM0, 0x303f);
|
||||
writeReg(EPMCS, 0xf7f9);
|
||||
|
||||
if(is_full_duplex) {
|
||||
writeRegByte(MABBIPG, 0x15);
|
||||
writeReg(MAIPG, 0x0012);
|
||||
} else {
|
||||
writeRegByte(MABBIPG, 0x12);
|
||||
writeReg(MAIPG, 0x0C12);
|
||||
}
|
||||
|
||||
/* MAC init (with flow control) */
|
||||
mac3val = MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN;
|
||||
if(is_full_duplex) {
|
||||
mac3val |= MACON3_FULDPX;
|
||||
iv->macon4=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
iv->macon4 = 1<<6; /* DEFER bit */
|
||||
}
|
||||
iv->macon3 = mac3val;
|
||||
iv->macon2 = 0x00;
|
||||
iv->macon1 = MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS;
|
||||
|
||||
/* set packet pointers */
|
||||
enc28j60_recv_reset( iv, 0 );
|
||||
|
||||
|
||||
/* PHY init */
|
||||
if(is_full_duplex) {
|
||||
writePhy(PHCON1, PHCON1_PDPXMD);
|
||||
writePhy(PHCON2, 0);
|
||||
} else {
|
||||
writePhy(PHCON1, 0);
|
||||
writePhy(PHCON2, PHCON2_HDLDIS);
|
||||
}
|
||||
|
||||
writePhy(PHLCON, 0x3c12 ); /* 3(fixed) C(LinkStat+RX Act) 1(TX Act) 2(Stretch enable) */
|
||||
|
||||
SetBank(EIR);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_DMAIF|EIR_LINKIF|EIR_TXIF|EIR_TXERIF|EIR_RXERIF|EIR_PKTIF);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE|EIE_LINKIE|EIE_TXIE|EIE_TXERIE|EIE_RXERIE);
|
||||
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
|
||||
/* wait a while for "LINK UP" -> break after 200 ms */
|
||||
{
|
||||
unsigned char status;
|
||||
int runs = 100;
|
||||
|
||||
while( runs-- )
|
||||
{
|
||||
enc28j60_status( PIO_STATUS_LINK_UP, &status );
|
||||
if( status )
|
||||
break;
|
||||
|
||||
enc28j60l_UMinDelay( 2000 ); /* wait 2+ ms */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return PIO_OK;
|
||||
}
|
||||
|
||||
/* ---------- exit ---------- */
|
||||
|
||||
void enc28j60_exit(void)
|
||||
{
|
||||
enc28j60_setOffline();
|
||||
enc28j60l_Shutdown();
|
||||
}
|
||||
|
||||
u08 enc28j60_setOnline( void )
|
||||
{
|
||||
SetBank(EIR);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
u08 enc28j60_setOffline( void )
|
||||
{
|
||||
SetBank(EIR);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void enc28j60_setMAC( const u08 macaddr[6] )
|
||||
{
|
||||
/* set mac */
|
||||
writeRegByte(MAADR5, macaddr[0]);
|
||||
writeRegByte(MAADR4, macaddr[1]);
|
||||
writeRegByte(MAADR3, macaddr[2]);
|
||||
writeRegByte(MAADR2, macaddr[3]);
|
||||
writeRegByte(MAADR1, macaddr[4]);
|
||||
writeRegByte(MAADR0, macaddr[5]);
|
||||
SetBank(EIR);
|
||||
}
|
||||
|
||||
void enc28j60_getMAC( u08 macaddr[6] ) /* mainly for debug */
|
||||
{
|
||||
/* set mac */
|
||||
macaddr[0] = readRegByte(MAADR5);
|
||||
macaddr[1] = readRegByte(MAADR4);
|
||||
macaddr[2] = readRegByte(MAADR3);
|
||||
macaddr[3] = readRegByte(MAADR2);
|
||||
macaddr[4] = readRegByte(MAADR1);
|
||||
macaddr[5] = readRegByte(MAADR0);
|
||||
}
|
||||
|
||||
|
||||
/* ---------- control ---------- */
|
||||
|
||||
u08 enc28j60_control(u08 control_id, u08 value)
|
||||
{
|
||||
switch(control_id) {
|
||||
case PIO_CONTROL_FLOW:
|
||||
{
|
||||
u08 flag;
|
||||
if(is_full_duplex) {
|
||||
flag = value ? 2 : 3;
|
||||
} else {
|
||||
flag = value ? 1 : 0;
|
||||
}
|
||||
writeRegByte(EFLOCON, flag);
|
||||
return PIO_OK;
|
||||
}
|
||||
default:
|
||||
return PIO_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------- status ---------- */
|
||||
|
||||
u08 enc28j60_status(u08 status_id, u08 *value)
|
||||
{
|
||||
switch(status_id) {
|
||||
case PIO_STATUS_VERSION:
|
||||
*value = rev;
|
||||
return PIO_OK;
|
||||
case PIO_STATUS_LINK_UP:
|
||||
*value = (readPhyByte(PHSTAT2) >> 2) & 1;
|
||||
return PIO_OK;
|
||||
default:
|
||||
*value = 0;
|
||||
return PIO_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- send ---------- */
|
||||
|
||||
u08 enc28j60_send(const u08 *data, u16 size)
|
||||
{
|
||||
/* wait for tx ready */
|
||||
/* We can't do it here like on ATMEL MCUs, simply because
|
||||
the Vampire SPI is way faster than 10 MBit/s so that
|
||||
we would overwrite a frame still being sent out
|
||||
-> wait first, then fill buffer
|
||||
*/
|
||||
while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)
|
||||
{
|
||||
/* errata sheet issue 12 -> TXRTS never becomes 0 */
|
||||
/* ignores errata issue 13 -> frame loss due to late collision */
|
||||
/* eworks around errata sheet issue 15 -> ESTAT.LATECOL not set */
|
||||
if (readRegByte(EIR) & EIR_TXERIF) {
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
|
||||
}
|
||||
}
|
||||
|
||||
/* write buffer */
|
||||
enc28j60l_WriteBuffer( (u08*)data, size, TXSTART_INIT );
|
||||
|
||||
/* initiate send */
|
||||
writeReg(ETXND, TXSTART_INIT+size);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
|
||||
return PIO_OK;
|
||||
}
|
||||
|
||||
/* ---------- recv ---------- */
|
||||
|
||||
/*
|
||||
unrecoverable error in receiving, bad pointer or other causes
|
||||
- reset the complete receive logic in order to start receiving anew
|
||||
|
||||
input: restart - 0 = don't re-enable RX automatically
|
||||
1 = re-enable RX after resetting
|
||||
*/
|
||||
|
||||
INLINE void next_pkt(void)
|
||||
{
|
||||
|
||||
if (gNextPacketPtr - 1 > RXSTOP_INIT)
|
||||
{
|
||||
#if 1
|
||||
enc28j60_recv_reset( &initvars, 1 );
|
||||
#else
|
||||
writeReg(ERXRDPT, RXSTOP_INIT);
|
||||
gNextPacketPtr = 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
writeReg(ERXRDPT, gNextPacketPtr - 1);
|
||||
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
|
||||
}
|
||||
|
||||
/* endian agnostic version of header read */
|
||||
static u08 read_hdr(u16 *got_size)
|
||||
{
|
||||
struct {
|
||||
uint8_t nextPacketL;
|
||||
uint8_t nextPacketH;
|
||||
uint8_t byteCountL;
|
||||
uint8_t byteCountH;
|
||||
uint8_t statusL;
|
||||
uint8_t statusH;
|
||||
} header;
|
||||
|
||||
readBuf(sizeof header, (uint8_t*) &header);
|
||||
|
||||
gNextPacketPtr = (u16)header.nextPacketL + (((u16)header.nextPacketH)<<8);
|
||||
*got_size = (u16)header.byteCountL + (((u16)header.byteCountH)<<8); /* - 4;*//* -4: remove the CRC count */
|
||||
|
||||
return header.statusL;
|
||||
}
|
||||
|
||||
|
||||
u08 enc28j60_recv(u08 *data, u16 max_size, u16 *got_size)
|
||||
{
|
||||
u08 status,result;
|
||||
u16 len;
|
||||
|
||||
/* EIR->PKTIF would be faster but errata sheet says "unreliable" */
|
||||
u08 pcnt = 1+readRegByte(EPKTCNT); /* wraps to 0 for 0xff = unconnected module */
|
||||
if( pcnt < 2 ) /* 0xff+1=0x00, 0x00+1=0x01, 0x01+1=0x02 */
|
||||
return PIO_NOT_FOUND;
|
||||
|
||||
writeReg(ERDPT, gNextPacketPtr);
|
||||
|
||||
/* read chip's packet header */
|
||||
status = read_hdr(got_size);
|
||||
|
||||
/* was a receive error? */
|
||||
if ((status & 0x80)==0)
|
||||
{
|
||||
/* TODO: recv reset ? */
|
||||
next_pkt();
|
||||
return PIO_IO_ERR;
|
||||
}
|
||||
|
||||
/* check size */
|
||||
len = *got_size;
|
||||
result = PIO_OK;
|
||||
if(len > max_size) {
|
||||
len = max_size;
|
||||
result = PIO_TOO_LARGE;
|
||||
}
|
||||
|
||||
/* read packet */
|
||||
readBuf(len, data);
|
||||
|
||||
next_pkt();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---------- has_recv ---------- */
|
||||
|
||||
u08 enc28j60_has_recv(void)
|
||||
{
|
||||
u08 ret = readRegByte(EPKTCNT);
|
||||
|
||||
if( !ret )
|
||||
{
|
||||
initvars.have_recv++;
|
||||
if( initvars.have_recv > 10 )
|
||||
{
|
||||
/* check for bad config vars and reset hw if that is the case */
|
||||
if( !enc28j60_check_config( &initvars ) )
|
||||
{
|
||||
enc28j60_recv_reset( &initvars, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
initvars.have_recv = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void enc28j60_dump_regs(void)
|
||||
{
|
||||
/* this will work only with DOSBase known globally, not when it's redirected to Plipbase */
|
||||
#ifdef _DO_DUMP
|
||||
u08 val,eir,eie,econ1,econ2,estat;
|
||||
u16 erxrdpt,erxwrpt,erxst,erxnd,mamxfll;
|
||||
u16 macon1,macon3,macon4;
|
||||
|
||||
eir = readRegByte(EIR);
|
||||
eie = readRegByte(EIE);
|
||||
econ1 = readRegByte(ECON1);
|
||||
econ2 = readRegByte(ECON2);
|
||||
estat = readRegByte(ESTAT);
|
||||
printf("EIR EIE ECON1 ECON2 ESTAT\n");
|
||||
printf("%02x %02x %02x %02x %02x\n",
|
||||
eir,eie,econ1,econ2,estat);
|
||||
|
||||
erxrdpt = readRegByte(ERXRDPT) + (((u16)readRegByte(ERXRDPT+1))<<8);
|
||||
erxwrpt = readRegByte(ERXWRPT) + (((u16)readRegByte(ERXWRPT+1))<<8);
|
||||
erxst = readRegByte(ERXST) + (((u16)readRegByte(ERXST+1))<<8);
|
||||
erxnd = readRegByte(ERXND) + (((u16)readRegByte(ERXND+1))<<8);
|
||||
mamxfll = readRegByte(MAMXFL) + (((u16)readRegByte(MAMXFL+1))<<8);
|
||||
printf("ERXRDPT ERXWRPT ERXST ERXND MAMXFL\n");
|
||||
printf("%04x %04x %04x %04x %04x\n",
|
||||
erxrdpt,erxwrpt,erxst,erxnd,mamxfll);
|
||||
|
||||
macon1 = readRegByte(MACON1);/* + (((u16)readRegByte(MACON1+1))<<8); */
|
||||
macon3 = readRegByte(MACON3);/* + (((u16)readRegByte(MACON1+3))<<8); */
|
||||
macon4 = readRegByte(MACON4);/* + (((u16)readRegByte(MACON1+4))<<8); */
|
||||
printf("MACON1 MACON3 MACON4\n");
|
||||
printf("%02x %02x %02x\n",
|
||||
macon1,macon3,macon4);
|
||||
printf("MAADR\n");
|
||||
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
(int)readRegByte(MAADR5),
|
||||
(int)readRegByte(MAADR4),
|
||||
(int)readRegByte(MAADR3),
|
||||
(int)readRegByte(MAADR2),
|
||||
(int)readRegByte(MAADR1),
|
||||
(int)readRegByte(MAADR0) );
|
||||
|
||||
val = readRegByte(EIR);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Contributed by Alex M. Based on code from: http://blog.derouineau.fr */
|
||||
/* /2011/07/putting-enc28j60-ethernet-controler-in-sleep-mode/ */
|
||||
void enc28j60_power_down( void )
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
|
||||
while(readRegByte(ESTAT) & ESTAT_RXBUSY);
|
||||
while(readRegByte(ECON1) & ECON1_TXRTS);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
|
||||
}
|
||||
|
||||
void enc28j60_power_up( void )
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
|
||||
while(!readRegByte(ESTAT) & ESTAT_CLKRDY);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
}
|
||||
|
||||
uint8_t enc28j60_do_BIST ( void )
|
||||
{
|
||||
#define RANDOM_FILL 0b0000
|
||||
#define ADDRESS_FILL 0b0100
|
||||
#define PATTERN_SHIFT 0b1000
|
||||
#define RANDOM_RACE 0b1100
|
||||
|
||||
/* init */
|
||||
spi_disable_eth();
|
||||
|
||||
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
_delay_ms(2); /* errata B7/2 */
|
||||
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ;
|
||||
|
||||
/* now we can start the memory test */
|
||||
uint16_t macResult;
|
||||
uint16_t bitsResult;
|
||||
|
||||
/* clear some of the registers registers */
|
||||
writeRegByte(ECON1, 0);
|
||||
writeReg(EDMAST, 0);
|
||||
|
||||
/* Set up necessary pointers for the DMA to calculate over the entire memory */
|
||||
writeReg(EDMAND, 0x1FFFu);
|
||||
writeReg(ERXND, 0x1FFFu);
|
||||
|
||||
/* Enable Test Mode and do an Address Fill */
|
||||
SetBank(EBSTCON);
|
||||
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_BISTST | ADDRESS_FILL);
|
||||
|
||||
/* wait for BISTST to be reset, only after that are we actually ready to */
|
||||
/* start the test */
|
||||
/* this was undocumented :( */
|
||||
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||
|
||||
/* now start the actual reading an calculating the checksum until the end is */
|
||||
/* reached */
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
|
||||
SetBank(EDMACS);
|
||||
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||
macResult = readReg(EDMACS);
|
||||
bitsResult = readReg(EBSTCS);
|
||||
/* Compare the results */
|
||||
/* 0xF807 should always be generated in Address fill mode */
|
||||
if ((macResult != bitsResult) || (bitsResult != 0xF807)) {
|
||||
return 0;
|
||||
}
|
||||
/* reset test flag */
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||
|
||||
|
||||
/* Now start the BIST with random data test, and also keep on swapping the */
|
||||
/* DMA/BIST memory ports. */
|
||||
writeRegByte(EBSTSD, 0b10101010 /* | millis()*/);
|
||||
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_PSEL | EBSTCON_BISTST | RANDOM_FILL);
|
||||
|
||||
|
||||
/* wait for BISTST to be reset, only after that are we actually ready to */
|
||||
/* start the test */
|
||||
/* this was undocumented :( */
|
||||
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||
|
||||
|
||||
/* now start the actual reading an calculating the checksum until the end is */
|
||||
/* reached */
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
|
||||
SetBank(EDMACS);
|
||||
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||
|
||||
macResult = readReg(EDMACS);
|
||||
bitsResult = readReg(EBSTCS);
|
||||
/* The checksum should be equal */
|
||||
return macResult == bitsResult;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* enc28j60.h - Microchip ENC28J60 interface
|
||||
*
|
||||
* Written by
|
||||
* Henryk Richter <henryk.richter@gmx.net>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INC_ENC28J60_H
|
||||
#define _INC_ENC28J60_H
|
||||
|
||||
/* 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
|
||||
|
||||
/* sigh, old gcc does not have stdint.h */
|
||||
typedef unsigned char u08;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
|
||||
/* API functions */
|
||||
u08 enc28j60_init(const u08 macaddr[6], u08 flags);
|
||||
void enc28j60_exit(void);
|
||||
u08 enc28j60_setOnline( void );
|
||||
u08 enc28j60_setOffline( void );
|
||||
void enc28j60_SetSPISpeed( unsigned long clock_divider );
|
||||
|
||||
u08 enc28j60_send(const u08 *data, u16 size);
|
||||
u08 enc28j60_recv(u08 *data, u16 max_size, u16 *got_size);
|
||||
u08 enc28j60_status( u08 status_id, u08 *value);
|
||||
u08 enc28j60_has_recv(void);
|
||||
void enc28j60_setMAC( const u08 macaddr[6] );
|
||||
void enc28j60_getMAC( u08 macaddr[6] ); /* mainly for debug */
|
||||
void enc28j60_dump_regs(void);
|
||||
void enc28j60_broadcast_multicast_filter( u08 flags );
|
||||
|
||||
#endif /* _INC_ENC28J60_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
enc28j60l.h
|
||||
|
||||
author: Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
purpose: header for low-level register and SPI access
|
||||
to ENC28J60 networking device
|
||||
|
||||
*/
|
||||
#ifndef _INC_ENC28J60L_H
|
||||
#define _INC_ENC28J60L_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/*
|
||||
Purpose: prepare SPI for use
|
||||
input: -
|
||||
output: success/failure
|
||||
>0 - all fine, ready to work
|
||||
<=0 - init problem (codes undefined yet)
|
||||
*/
|
||||
ASM SAVEDS int enc28j60l_Init( void );
|
||||
|
||||
/*
|
||||
Purpose: shutdown SPI
|
||||
input: -
|
||||
output: -
|
||||
*/
|
||||
ASM SAVEDS void enc28j60l_Shutdown( void );
|
||||
|
||||
|
||||
/*
|
||||
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: set SPI clock divider
|
||||
input: clock divider 1...n
|
||||
output: -
|
||||
*/
|
||||
ASM SAVEDS void enc28j60l_SetSPISpeed(
|
||||
ASMR(d0) unsigned long divider ASMREG(d0) );
|
||||
|
||||
|
||||
/*
|
||||
purpose: read one byte from a custom register
|
||||
input: op = ENC28J60_READ_CTRL_REG
|
||||
address = register address, including bits denoting the bank
|
||||
data = data byte
|
||||
*/
|
||||
ASM SAVEDS unsigned char enc28j60l_ReadOp(
|
||||
ASMR(d3) unsigned char op ASMREG(d3),
|
||||
ASMR(d0) unsigned char address ASMREG(d0) );
|
||||
|
||||
|
||||
/*
|
||||
purpose: write one byte to a custom register
|
||||
input: op = ENC28J60_WRITE_CTRL_REG,
|
||||
ENC28J60_BIT_FIELD_SET,
|
||||
ENC28J60_BIT_FIELD_CLR
|
||||
address = register address, including bits denoting the bank
|
||||
data = data byte
|
||||
*/
|
||||
ASM void enc28j60l_WriteOp( ASMR(d3) unsigned char op ASMREG(d3),
|
||||
ASMR(d0) unsigned char address ASMREG(d0),
|
||||
ASMR(d1) unsigned char data ASMREG(d1));
|
||||
|
||||
|
||||
/*
|
||||
purpose: select register bank based on given address
|
||||
input:
|
||||
address = register address, including bits denoting the bank
|
||||
*/
|
||||
ASM SAVEDS void enc28j60l_SetBank( ASMR(d0) unsigned char address ASMREG(d0) );
|
||||
|
||||
|
||||
|
||||
/*
|
||||
purpose: read one short from a custom register
|
||||
input: address = register address, including bits denoting the bank
|
||||
data = data word (unsigned short)
|
||||
*/
|
||||
ASM SAVEDS unsigned short enc28j60l_ReadReg( ASMR(d0) unsigned char address ASMREG(d0) );
|
||||
|
||||
|
||||
/*
|
||||
purpose: write one short to a custom register
|
||||
input: address = register address, including bits denoting the bank
|
||||
data = data word (unsigned short)
|
||||
*/
|
||||
ASM void enc28j60l_WriteReg( ASMR(d0) unsigned char address ASMREG(d0),
|
||||
ASMR(d1) unsigned short data ASMREG(d1));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
purpose: read one byte from a custom register
|
||||
input: address = register address, including bits denoting the bank
|
||||
*/
|
||||
ASM SAVEDS unsigned char enc28j60l_ReadRegByte(
|
||||
ASMR(d0) unsigned char address ASMREG(d0));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
purpose: write one byte to a custom register
|
||||
input: address = register address, including bits denoting the bank
|
||||
data = data word (unsigned short)
|
||||
*/
|
||||
ASM void enc28j60l_WriteRegByte( ASMR(d0) unsigned char address ASMREG(d0),
|
||||
ASMR(d1) unsigned char data ASMREG(d1));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
purpose: Read buffer from device to computer
|
||||
input: buffer = buffer to read into
|
||||
size = length of buffer
|
||||
*/
|
||||
ASM void enc28j60l_ReadBuffer( ASMR(a1) unsigned char *buffer ASMREG(a1),
|
||||
ASMR(d0) unsigned int size ASMREG(d0));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
purpose: Write buffer from computer to device
|
||||
input: buffer = buffer to write
|
||||
size = length of buffer
|
||||
destptr = destination pointer in device
|
||||
*/
|
||||
ASM void enc28j60l_WriteBuffer( ASMR(a1) unsigned char *buffer ASMREG(a1),
|
||||
ASMR(d0) unsigned int size ASMREG(d0),
|
||||
ASMR(d1) unsigned short destptr ASMREG(d1));
|
||||
|
||||
|
||||
/*
|
||||
Definitions based on the enc28j60.c file from the AVRlib library by Pascal Stang.
|
||||
|
||||
ENC28J60 Control Registers
|
||||
Control register definitions are a combination of address,
|
||||
bank number, and Ethernet/MAC/PHY indicator bits.
|
||||
- Register address (bits 0-4)
|
||||
- Bank number (bits 5-6)
|
||||
- MAC/PHY indicator (bit 7)
|
||||
*/
|
||||
#define ADDR_MASK 0x1F
|
||||
#define BANK_MASK 0x60
|
||||
#define SPRD_MASK 0x80
|
||||
/* All-bank registers */
|
||||
#define EIE 0x1B
|
||||
#define EIR 0x1C
|
||||
#define ESTAT 0x1D
|
||||
#define ECON2 0x1E
|
||||
#define ECON1 0x1F
|
||||
/* Bank 0 registers */
|
||||
#define ERDPT (0x00|0x00)
|
||||
#define EWRPT (0x02|0x00)
|
||||
#define ETXST (0x04|0x00)
|
||||
#define ETXND (0x06|0x00)
|
||||
#define ERXST (0x08|0x00)
|
||||
#define ERXND (0x0A|0x00)
|
||||
#define ERXRDPT (0x0C|0x00)
|
||||
#define ERXWRPT (0x0E|0x00)
|
||||
#define EDMAST (0x10|0x00)
|
||||
#define EDMAND (0x12|0x00)
|
||||
/* #define EDMADST (0x14|0x00) */
|
||||
#define EDMACS (0x16|0x00)
|
||||
/* Bank 1 registers */
|
||||
#define EHT0 (0x00|0x20)
|
||||
#define EHT1 (0x01|0x20)
|
||||
#define EHT2 (0x02|0x20)
|
||||
#define EHT3 (0x03|0x20)
|
||||
#define EHT4 (0x04|0x20)
|
||||
#define EHT5 (0x05|0x20)
|
||||
#define EHT6 (0x06|0x20)
|
||||
#define EHT7 (0x07|0x20)
|
||||
#define EPMM0 (0x08|0x20)
|
||||
#define EPMM1 (0x09|0x20)
|
||||
#define EPMM2 (0x0A|0x20)
|
||||
#define EPMM3 (0x0B|0x20)
|
||||
#define EPMM4 (0x0C|0x20)
|
||||
#define EPMM5 (0x0D|0x20)
|
||||
#define EPMM6 (0x0E|0x20)
|
||||
#define EPMM7 (0x0F|0x20)
|
||||
#define EPMCS (0x10|0x20)
|
||||
/* #define EPMO (0x14|0x20) */
|
||||
#define EWOLIE (0x16|0x20)
|
||||
#define EWOLIR (0x17|0x20)
|
||||
#define ERXFCON (0x18|0x20)
|
||||
#define EPKTCNT (0x19|0x20)
|
||||
/* Bank 2 registers */
|
||||
#define MACON1 (0x00|0x40|0x80)
|
||||
#define MACON2 (0x01|0x40|0x80)
|
||||
#define MACON3 (0x02|0x40|0x80)
|
||||
#define MACON4 (0x03|0x40|0x80)
|
||||
#define MABBIPG (0x04|0x40|0x80)
|
||||
#define MAIPG (0x06|0x40|0x80)
|
||||
#define MACLCON1 (0x08|0x40|0x80)
|
||||
#define MACLCON2 (0x09|0x40|0x80)
|
||||
#define MAMXFL (0x0A|0x40|0x80)
|
||||
#define MAPHSUP (0x0D|0x40|0x80)
|
||||
#define MICON (0x11|0x40|0x80)
|
||||
#define MICMD (0x12|0x40|0x80)
|
||||
#define MIREGADR (0x14|0x40|0x80)
|
||||
#define MIWR (0x16|0x40|0x80)
|
||||
#define MIRD (0x18|0x40|0x80)
|
||||
/* Bank 3 registers */
|
||||
#define MAADR1 (0x00|0x60|0x80)
|
||||
#define MAADR0 (0x01|0x60|0x80)
|
||||
#define MAADR3 (0x02|0x60|0x80)
|
||||
#define MAADR2 (0x03|0x60|0x80)
|
||||
#define MAADR5 (0x04|0x60|0x80)
|
||||
#define MAADR4 (0x05|0x60|0x80)
|
||||
#define EBSTSD (0x06|0x60)
|
||||
#define EBSTCON (0x07|0x60)
|
||||
#define EBSTCS (0x08|0x60)
|
||||
#define MISTAT (0x0A|0x60|0x80)
|
||||
#define EREVID (0x12|0x60)
|
||||
#define ECOCON (0x15|0x60)
|
||||
#define EFLOCON (0x17|0x60)
|
||||
#define EPAUS (0x18|0x60)
|
||||
|
||||
/* ENC28J60 ERXFCON Register Bit Definitions */
|
||||
#define ERXFCON_UCEN 0x80
|
||||
#define ERXFCON_ANDOR 0x40
|
||||
#define ERXFCON_CRCEN 0x20
|
||||
#define ERXFCON_PMEN 0x10
|
||||
#define ERXFCON_MPEN 0x08
|
||||
#define ERXFCON_HTEN 0x04
|
||||
#define ERXFCON_MCEN 0x02
|
||||
#define ERXFCON_BCEN 0x01
|
||||
/* ENC28J60 EIE Register Bit Definitions */
|
||||
#define EIE_INTIE 0x80
|
||||
#define EIE_PKTIE 0x40
|
||||
#define EIE_DMAIE 0x20
|
||||
#define EIE_LINKIE 0x10
|
||||
#define EIE_TXIE 0x08
|
||||
#define EIE_WOLIE 0x04
|
||||
#define EIE_TXERIE 0x02
|
||||
#define EIE_RXERIE 0x01
|
||||
/* ENC28J60 EIR Register Bit Definitions */
|
||||
#define EIR_PKTIF 0x40
|
||||
#define EIR_DMAIF 0x20
|
||||
#define EIR_LINKIF 0x10
|
||||
#define EIR_TXIF 0x08
|
||||
#define EIR_WOLIF 0x04
|
||||
#define EIR_TXERIF 0x02
|
||||
#define EIR_RXERIF 0x01
|
||||
/* ENC28J60 ESTAT Register Bit Definitions */
|
||||
#define ESTAT_INT 0x80
|
||||
#define ESTAT_LATECOL 0x10
|
||||
#define ESTAT_RXBUSY 0x04
|
||||
#define ESTAT_TXABRT 0x02
|
||||
#define ESTAT_CLKRDY 0x01
|
||||
/* ENC28J60 ECON2 Register Bit Definitions */
|
||||
#define ECON2_AUTOINC 0x80
|
||||
#define ECON2_PKTDEC 0x40
|
||||
#define ECON2_PWRSV 0x20
|
||||
#define ECON2_VRPS 0x08
|
||||
/* ENC28J60 ECON1 Register Bit Definitions */
|
||||
#define ECON1_TXRST 0x80
|
||||
#define ECON1_RXRST 0x40
|
||||
#define ECON1_DMAST 0x20
|
||||
#define ECON1_CSUMEN 0x10
|
||||
#define ECON1_TXRTS 0x08
|
||||
#define ECON1_RXEN 0x04
|
||||
#define ECON1_BSEL1 0x02
|
||||
#define ECON1_BSEL0 0x01
|
||||
/* ENC28J60 MACON1 Register Bit Definitions */
|
||||
#define MACON1_LOOPBK 0x10
|
||||
#define MACON1_TXPAUS 0x08
|
||||
#define MACON1_RXPAUS 0x04
|
||||
#define MACON1_PASSALL 0x02
|
||||
#define MACON1_MARXEN 0x01
|
||||
/* ENC28J60 MACON2 Register Bit Definitions */
|
||||
#define MACON2_MARST 0x80
|
||||
#define MACON2_RNDRST 0x40
|
||||
#define MACON2_MARXRST 0x08
|
||||
#define MACON2_RFUNRST 0x04
|
||||
#define MACON2_MATXRST 0x02
|
||||
#define MACON2_TFUNRST 0x01
|
||||
/* ENC28J60 MACON3 Register Bit Definitions */
|
||||
#define MACON3_PADCFG2 0x80
|
||||
#define MACON3_PADCFG1 0x40
|
||||
#define MACON3_PADCFG0 0x20
|
||||
#define MACON3_TXCRCEN 0x10
|
||||
#define MACON3_PHDRLEN 0x08
|
||||
#define MACON3_HFRMLEN 0x04
|
||||
#define MACON3_FRMLNEN 0x02
|
||||
#define MACON3_FULDPX 0x01
|
||||
/* ENC28J60 MICMD Register Bit Definitions */
|
||||
#define MICMD_MIISCAN 0x02
|
||||
#define MICMD_MIIRD 0x01
|
||||
/* ENC28J60 MISTAT Register Bit Definitions */
|
||||
#define MISTAT_NVALID 0x04
|
||||
#define MISTAT_SCAN 0x02
|
||||
#define MISTAT_BUSY 0x01
|
||||
|
||||
/* ENC28J60 EBSTCON Register Bit Definitions */
|
||||
#define EBSTCON_PSV2 0x80
|
||||
#define EBSTCON_PSV1 0x40
|
||||
#define EBSTCON_PSV0 0x20
|
||||
#define EBSTCON_PSEL 0x10
|
||||
#define EBSTCON_TMSEL1 0x08
|
||||
#define EBSTCON_TMSEL0 0x04
|
||||
#define EBSTCON_TME 0x02
|
||||
#define EBSTCON_BISTST 0x01
|
||||
|
||||
/* PHY registers */
|
||||
#define PHCON1 0x00
|
||||
#define PHSTAT1 0x01
|
||||
#define PHHID1 0x02
|
||||
#define PHHID2 0x03
|
||||
#define PHCON2 0x10
|
||||
#define PHSTAT2 0x11
|
||||
#define PHIE 0x12
|
||||
#define PHIR 0x13
|
||||
#define PHLCON 0x14
|
||||
|
||||
/* ENC28J60 PHY PHCON1 Register Bit Definitions */
|
||||
#define PHCON1_PRST 0x8000
|
||||
#define PHCON1_PLOOPBK 0x4000
|
||||
#define PHCON1_PPWRSV 0x0800
|
||||
#define PHCON1_PDPXMD 0x0100
|
||||
/* ENC28J60 PHY PHSTAT1 Register Bit Definitions */
|
||||
#define PHSTAT1_PFDPX 0x1000
|
||||
#define PHSTAT1_PHDPX 0x0800
|
||||
#define PHSTAT1_LLSTAT 0x0004
|
||||
#define PHSTAT1_JBSTAT 0x0002
|
||||
/* ENC28J60 PHY PHCON2 Register Bit Definitions */
|
||||
#define PHCON2_FRCLINK 0x4000
|
||||
#define PHCON2_TXDIS 0x2000
|
||||
#define PHCON2_JABBER 0x0400
|
||||
#define PHCON2_HDLDIS 0x0100
|
||||
|
||||
/* PHIE Register */
|
||||
#define PHIE_PGEIE (1<<1)
|
||||
#define PHIE_LNKIE (1<<4)
|
||||
|
||||
|
||||
/* ENC28J60 Packet Control Byte Bit Definitions */
|
||||
#define PKTCTRL_PHUGEEN 0x08
|
||||
#define PKTCTRL_PPADEN 0x04
|
||||
#define PKTCTRL_PCRCEN 0x02
|
||||
#define PKTCTRL_POVERRIDE 0x01
|
||||
|
||||
/* SPI operation codes */
|
||||
#define ENC28J60_READ_CTRL_REG 0x00
|
||||
#define ENC28J60_READ_BUF_MEM 0x3A
|
||||
#define ENC28J60_WRITE_CTRL_REG 0x40
|
||||
#define ENC28J60_WRITE_BUF_MEM 0x7A
|
||||
#define ENC28J60_BIT_FIELD_SET 0x80
|
||||
#define ENC28J60_BIT_FIELD_CLR 0xA0
|
||||
#define ENC28J60_SOFT_RESET 0xFF
|
||||
|
||||
|
||||
#endif /* _INC_ENC28J60L_H */
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
hw.c
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
SDNet hardware interface to device
|
||||
|
||||
|
||||
*/
|
||||
#include <exec/libraries.h>
|
||||
#include <proto/exec.h>
|
||||
#include "device.h"
|
||||
#include "hw.h"
|
||||
|
||||
#include <proto/vampire.h>
|
||||
#include <vampire/vampire.h>
|
||||
#include "vampuuid.h"
|
||||
#include "enc28j60.h"
|
||||
|
||||
#ifndef PROTO_V2EXPNET
|
||||
#define PORTID V_SDPORT
|
||||
#else
|
||||
#define PORTID V_WIFIPORT
|
||||
#endif
|
||||
|
||||
extern const BYTE DeviceName[];
|
||||
|
||||
/* use generic board fields in current unit */
|
||||
#define hw_allocated du_hwl0
|
||||
|
||||
#define HW_INTERVALDEF 10000
|
||||
#define HW_DEFSPI 2
|
||||
|
||||
|
||||
/* these calls might not run within the context of a process and
|
||||
will be called from varying tasks and without prior init:
|
||||
hw_Find_Boards()
|
||||
hw_AllocBoard()
|
||||
hw_ReleaseBoard()
|
||||
hw_GetMacAddress()
|
||||
|
||||
these calls are in the context of the server task:
|
||||
hw_Setup() - general init (board allocated already)
|
||||
hw_Shutdown() - general shutdown (board still allocated)
|
||||
hw_Attach() - make hardware ready for action (online)
|
||||
hw_Detach() - put hardware into sleep mode (offline)
|
||||
|
||||
hw_recv_sigmask() - get signals for hardware (if any)
|
||||
hw_recv_pending() - check for pending receive frames
|
||||
|
||||
hw_recv_frame() - receive one frame
|
||||
hw_send_frame() - send one frame
|
||||
hw_check_link_change() - check if HW link parameters need update
|
||||
and apply them (called only when no RX/TX
|
||||
in progress)
|
||||
|
||||
hw_config_init() - set defaults for HW
|
||||
hw_config_update() - update config of HW
|
||||
*/
|
||||
|
||||
const BYTE vres_name[] = V_VAMPIRENAME;
|
||||
|
||||
/* return number of boards present in system */
|
||||
ASM SAVEDS LONG hw_Find_Boards( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
LONG ret = 0;
|
||||
struct Library *VampireBase;
|
||||
|
||||
if( (VampireBase = OpenResource( (BYTE*)vres_name )) )
|
||||
{
|
||||
/* TODO: check for expansion port, i.e. distinguish V500/V600 */
|
||||
/* TODO: actually verify that we have a module here */
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_AllocBoard( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
LONG ret = 0;
|
||||
struct Library *VampireBase;
|
||||
|
||||
if( (VampireBase = OpenResource( (BYTE*)vres_name )) ) /* OpenResource is probably redundant */
|
||||
{
|
||||
if( unit == 0 )
|
||||
{
|
||||
ret = 1; /* def: looks good */
|
||||
if( db->db_Units[unit].hw_allocated == 0 )
|
||||
{
|
||||
if( V_AllocExpansionPort( PORTID, (BYTE*)DeviceName ) )
|
||||
ret = 0;
|
||||
}
|
||||
if( ret )
|
||||
db->db_Units[unit].hw_allocated++;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_ReleaseBoard( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
LONG ret = 0;
|
||||
struct Library *VampireBase;
|
||||
|
||||
if( (VampireBase = OpenResource( (BYTE*)vres_name )) ) /* OpenResource is probably redundant */
|
||||
{
|
||||
if( unit == 0) /* only one device supported */
|
||||
{
|
||||
ret = 1; /* def: looks good */
|
||||
if( db->db_Units[unit].hw_allocated > 0 )
|
||||
{
|
||||
db->db_Units[unit].hw_allocated--;
|
||||
if( !db->db_Units[unit].hw_allocated )
|
||||
{
|
||||
V_FreeExpansionPort( PORTID );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* store MAC address at "mac", 6 Bytes */
|
||||
ASM SAVEDS LONG hw_GetMacAddress( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *mac ASMREG(a1)
|
||||
)
|
||||
{
|
||||
static UBYTE addr[6] = { 0x02,0x80,0x10,0x0b,0x0a,0xff};
|
||||
UBYTE vsn[8];
|
||||
LONG i;
|
||||
|
||||
if( vampire_UUID( vsn ) > 0 )
|
||||
{
|
||||
for(i=0 ; i<3 ; i++ )
|
||||
{
|
||||
addr[3+i] = vsn[i] ^ vsn[i+5];
|
||||
}
|
||||
}
|
||||
for( i=0 ; i<6 ; i++ )
|
||||
mac[i] = addr[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prepare all boards such that a hw_attach() will succeed */
|
||||
ASM SAVEDS LONG hw_Setup( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
LONG ret = 0;
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
hwd->IntSig = -1;
|
||||
|
||||
if( InitIntervalTimer( &hwd->ivtimer ) > 0 )
|
||||
{
|
||||
hwd->SigMask = hwd->ivtimer.IVT_SigMask;
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* free resources, server is quitting */
|
||||
ASM SAVEDS void hw_Shutdown( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
if( hwd->IntSig >= 0 )
|
||||
FreeSignal( hwd->IntSig );
|
||||
|
||||
ExitIntervalTimer( &hwd->ivtimer );
|
||||
}
|
||||
|
||||
/* make hardware ready for action (online) */
|
||||
ASM SAVEDS LONG hw_Attach( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0))
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
LONG ret = 1;
|
||||
u08 flags;
|
||||
|
||||
if( unit > 0 )
|
||||
return 0;
|
||||
|
||||
flags = PIO_INIT_BROAD_CAST;
|
||||
if( hwd->multicast )
|
||||
flags |= PIO_INIT_MULTI_CAST;
|
||||
|
||||
if( hwd->fullduplex )
|
||||
flags |= PIO_INIT_FULL_DUPLEX;
|
||||
|
||||
if( db->db_Units[0].du_Flags & DUF_PROMISC )
|
||||
flags |= PIO_INIT_PROMISC;
|
||||
|
||||
enc28j60_SetSPISpeed( hwd->spispeed );
|
||||
|
||||
if( enc28j60_init( db->db_Units[0].du_CFGAddr, flags ) != PIO_OK )
|
||||
ret = 0;
|
||||
else
|
||||
{
|
||||
enc28j60_SetSPISpeed( hwd->spispeed );
|
||||
StartIntervalTimer( &hwd->ivtimer, hwd->timervalue );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* put hardware into sleep mode (offline) */
|
||||
ASM SAVEDS void hw_Detach( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0))
|
||||
{
|
||||
if( !unit )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
StopIntervalTimer( &hwd->ivtimer );
|
||||
enc28j60_exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ASM SAVEDS void hw_ConfigInit( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
hwd->timervalue = HW_INTERVALDEF;
|
||||
hwd->fullduplex = 0;
|
||||
hwd->spispeed = HW_DEFSPI; /* default (see above) */
|
||||
hwd->multicast = 0;
|
||||
|
||||
#if 0
|
||||
USHORT i;
|
||||
for( i=0 ; i < (USHORT)db->db_NBoards ; i++ )
|
||||
{ /* no need, these are defaults */
|
||||
db->db_Units[i].du_MTU = 1500;
|
||||
db->db_Units[i].du_BitPerSec = 10000000;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
ASM SAVEDS void hw_ConfigUpdate( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(a1) void*argsv ASMREG(a1))
|
||||
{
|
||||
struct HWConfig *args = (struct HWConfig *)argsv; /* see hwprivate.h */
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
if( args->timervalue )
|
||||
hwd->timervalue = *args->timervalue;
|
||||
if( args->fullduplex )
|
||||
hwd->fullduplex = 1;
|
||||
if( args->spispeed )
|
||||
hwd->spispeed = *args->spispeed;
|
||||
if( args->multicast )
|
||||
hwd->multicast = 1;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_send_frame( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *frame ASMREG(a1),
|
||||
ASMR(d1) ULONG framesize ASMREG(d1) )
|
||||
{
|
||||
enc28j60_send( frame, framesize );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_recv_pending( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
return (LONG)enc28j60_has_recv();
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS LONG hw_recv_frame( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) UBYTE *frame ASMREG(a1))
|
||||
{
|
||||
volatile SHORT sz;
|
||||
LONG ret;
|
||||
|
||||
/* important: don't call this without enc28j60_has_recv() > 0 check */
|
||||
if( PIO_OK != enc28j60_recv( frame, 1518, (short*)&sz ) )
|
||||
ret = 0;
|
||||
else
|
||||
ret = (LONG)sz;
|
||||
|
||||
return (LONG)ret;
|
||||
}
|
||||
|
||||
|
||||
ASM SAVEDS ULONG hw_recv_sigmask( ASMR(a0) DEVBASEP ASMREG(a0) )
|
||||
{
|
||||
struct HWData *hwd = &db->db_hwdat;
|
||||
|
||||
return hwd->SigMask;
|
||||
}
|
||||
|
||||
|
||||
/* check if HW link parameters need update */
|
||||
ASM SAVEDS LONG hw_check_link_change( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(d0) ULONG unit ASMREG(d0) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* process the list of multicast addresses for an appropriate
|
||||
filtering list on the hardware
|
||||
|
||||
the server preprocesses active multicast listeners such that
|
||||
this call can decide whether to enable multicast altogether,
|
||||
filter with hashes etc.
|
||||
*/
|
||||
ASM SAVEDS LONG hw_change_multicast( ASMR(a0) DEVBASEP ASMREG(a0),
|
||||
ASMR(a0) ULONG unit ASMREG(d0),
|
||||
ASMR(a1) struct List *mcastlist ASMREG(a1) )
|
||||
{
|
||||
u08 flags;
|
||||
|
||||
flags = PIO_INIT_BROAD_CAST;
|
||||
|
||||
if( db->db_Units[0].du_Flags & DUF_PROMISC )
|
||||
flags |= PIO_INIT_PROMISC;
|
||||
|
||||
/* list non-empty ? (sufficient for ENC28J60 -> it doesn`t have hashing) */
|
||||
if( mcastlist->lh_Head->ln_Succ )
|
||||
flags |= PIO_INIT_MULTI_CAST;
|
||||
|
||||
enc28j60_broadcast_multicast_filter( flags );/* flags & (PIO_INIT_BROAD_CAST|PIO_INIT_MULTI_CAST) ); */
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
hwprivate.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
private structures for hardware instance
|
||||
|
||||
|
||||
*/
|
||||
#ifndef _INC_HWPRIVATE_H
|
||||
#define _INC_HWPRIVATE_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* sdnet/v2expnet specific: polling timer */
|
||||
#include "intervaltimer.h"
|
||||
|
||||
/* this struct is available in devicebase and should carry global information */
|
||||
struct HWData {
|
||||
ULONG SigMask; /* signal mask to wait for in server main instance */
|
||||
|
||||
struct IVT_TimerStruct ivtimer; /* Timer interval handling (via Interrupt) */
|
||||
LONG IntSig;
|
||||
|
||||
/* config options */
|
||||
ULONG timervalue; /* polling interval in ms */
|
||||
ULONG fullduplex; /* force full duplex */
|
||||
ULONG spispeed; /* SPI clock divider (>=1) */
|
||||
ULONG multicast; /* multicast recv enable */
|
||||
};
|
||||
|
||||
/* referenced from server.c */
|
||||
#if (defined PROTO_V2EXPNET)
|
||||
#define HW_CONFIGFILE "ENV:SANA2/v2expeth.config"
|
||||
#else
|
||||
#define HW_CONFIGFILE "ENV:SANA2/sdnet.config"
|
||||
#endif
|
||||
|
||||
/* appended to COMMON_TEMPLATE */
|
||||
#define HW_CONFIGTEMPLATE "TIMER/K/N,FULLDUPLEX/S,SPISPEED/K/N,MULTICAST/S"
|
||||
|
||||
/* referenced by server.c, hw.c */
|
||||
struct HWConfig
|
||||
{
|
||||
struct CommonConfig common; /* import from hw.h, expected in server.c */
|
||||
ULONG *timervalue;
|
||||
ULONG fullduplex;
|
||||
ULONG *spispeed;
|
||||
ULONG multicast;
|
||||
};
|
||||
|
||||
#endif /* _INC_HWPRIVATE_H */
|
||||
@@ -0,0 +1,341 @@
|
||||
******************************************************************************
|
||||
* 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
|
||||
|
||||
DO_TEST EQU 0
|
||||
|
||||
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
|
||||
ULONG IVT_SigMask
|
||||
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
|
||||
|
||||
ifne DO_TEST
|
||||
|
||||
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
|
||||
|
||||
ENDC ;DO_TEST
|
||||
|
||||
|
||||
; 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_SigMask(a2),d0 ;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) ; <0 ? error, valid are 0..31
|
||||
blt .error ; error: have to go (shouldn't happen)
|
||||
moveq #0,d1
|
||||
bset d0,d1
|
||||
move.l d1,IVT_SigMask(a2)
|
||||
|
||||
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
|
||||
not.l d0 ;if( d0 == -1 ) d0 = 0
|
||||
beq.s .nosig
|
||||
not.l d0 ; swap back
|
||||
CALLEXEC FreeSignal
|
||||
moveq #-1,d0
|
||||
move.l d0,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
|
||||
|
||||
VBtimer_name: dc.b "timer.device",0
|
||||
ifne DO_TEST
|
||||
dos_name: dc.b "dos.library",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
|
||||
ENDC ;DO_TEST
|
||||
END
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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;
|
||||
unsigned long IVT_SigMask;
|
||||
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 "compiler.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,27 @@
|
||||
******************************************************************************
|
||||
* 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
|
||||
ULONG IVT_SigMask ;signal mask
|
||||
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
|
||||
@@ -0,0 +1,126 @@
|
||||
; ------------------------------------------------------------------------------
|
||||
; | Flash ROM Read Serial Number |
|
||||
; | Copyright (c) 2016 APOLLO TEAM |
|
||||
; | Christoph Höhne, modifications by Henryk Richter |
|
||||
; ------------------------------------------------------------------------------
|
||||
|
||||
FLASH_ID EQU $14 ;cmd=0xAB
|
||||
|
||||
FLASH_ADR_W EQU $00DFF1F8
|
||||
FLASH_ADR_R EQU $00DFF1FA
|
||||
FLASH_MAGIC EQU $42420000
|
||||
FLASH_CS EQU $1
|
||||
FLASH_CSn EQU $0
|
||||
FLASH_CLK EQU $2
|
||||
FLASH_CLKn EQU $0
|
||||
FLASH_MOSI EQU $4
|
||||
FLASH_MOSIn EQU $0
|
||||
FLASH_MISO EQU $1
|
||||
FLASH_MISOn EQU $0
|
||||
|
||||
;VAMPIRE_MAGIC EQU ascii "Vamp"
|
||||
VAMPIRE_MAGIC EQU $56616D70
|
||||
|
||||
xdef _vampire_UUID
|
||||
|
||||
;-------- Get 64 Bit unique ID --------------------
|
||||
; Input
|
||||
; A1 - pointer to 8 Bytes storage
|
||||
; Output
|
||||
; D0 = 0 - failure
|
||||
; >0 - success
|
||||
_vampire_UUID:
|
||||
movem.l d1-a6,-(sp) ;lazy register store
|
||||
|
||||
bsr flashreadid
|
||||
cmpi.b #FLASH_ID,d0
|
||||
bne.s error$
|
||||
|
||||
bsr flashuniqueid
|
||||
|
||||
move.l d0,(a1)
|
||||
move.l d1,4(a1)
|
||||
|
||||
moveq #1,d0
|
||||
bra.s return$
|
||||
|
||||
error$:
|
||||
moveq #0,d0
|
||||
return$
|
||||
movem.l (sp)+,d1-a6
|
||||
rts
|
||||
|
||||
; uint8_t flashreadid(void)
|
||||
; D0
|
||||
flashreadid:
|
||||
move.b #$AB,d1
|
||||
bsr flashbyte
|
||||
bsr flashbyte
|
||||
bsr flashbyte
|
||||
bsr flashbyte
|
||||
bsr flashbyte
|
||||
bsr flashdeselect
|
||||
rts
|
||||
|
||||
; uint64_t flashuniqueid(void)
|
||||
; D0/D1
|
||||
flashuniqueid:
|
||||
move.b #$5A,d1
|
||||
bsr flashbyte
|
||||
clr d1
|
||||
bsr flashbyte
|
||||
clr d1
|
||||
bsr flashbyte
|
||||
move.b #$F8,d1
|
||||
bsr flashbyte
|
||||
bsr flashbyte
|
||||
bsr flashbyte
|
||||
lsl.l #8,d1
|
||||
bsr flashbyte
|
||||
lsl.l #8,d1
|
||||
bsr flashbyte
|
||||
lsl.l #8,d1
|
||||
bsr flashbyte
|
||||
move.l d1,d3
|
||||
bsr flashbyte
|
||||
lsl.l #8,d1
|
||||
bsr flashbyte
|
||||
lsl.l #8,d1
|
||||
bsr flashbyte
|
||||
lsl.l #8,d1
|
||||
bsr flashbyte
|
||||
move.l d3,d0
|
||||
bsr flashdeselect
|
||||
rts
|
||||
|
||||
; void flashselect(void)
|
||||
;flashselect:
|
||||
; move.l #FLASH_MAGIC+FLASH_CSn+FLASH_CLKn,d0
|
||||
; move.l d0,FLASH_ADR_W
|
||||
; rts
|
||||
|
||||
; void flashdeselect(void)
|
||||
flashdeselect:
|
||||
move.l #FLASH_MAGIC+FLASH_CS+FLASH_CLK,d3
|
||||
move.l d3,FLASH_ADR_W
|
||||
rts
|
||||
|
||||
; uint8_t flashbyte(uint8_t)
|
||||
; D0 D1
|
||||
flashbyte:
|
||||
moveq #7,d2
|
||||
;bsr flashselect
|
||||
move.l #FLASH_MAGIC+FLASH_CSn+FLASH_CLKn,d0
|
||||
move.l d0,FLASH_ADR_W
|
||||
flashbyteloop:
|
||||
lsl.b #1,d1
|
||||
scs.b d0
|
||||
andi.w #FLASH_MOSI,d0
|
||||
move.l d0,FLASH_ADR_W
|
||||
ori.w #FLASH_CLK,d0
|
||||
move.l d0,FLASH_ADR_W
|
||||
or.w FLASH_ADR_R,d1
|
||||
dbra d2,flashbyteloop
|
||||
move.b d1,d0
|
||||
rts
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
vampuuid.h
|
||||
|
||||
author: Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
purpose: Vampire UUID reading prototypes
|
||||
|
||||
*/
|
||||
#ifndef _INC_vampuuid_H
|
||||
#define _INC_vampuuid_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/*
|
||||
Purpose: Read UUID of Vampire cards
|
||||
input: buffer - storage for the returned UUID (8 Bytes)
|
||||
output: success/failure
|
||||
>0 - all fine, ready to work
|
||||
<=0 - init problem (codes undefined yet)
|
||||
*/
|
||||
ASM SAVEDS int vampire_UUID( ASMR(a1) unsigned char *buffer ASMREG(a1) );
|
||||
|
||||
|
||||
#endif /* __INC_vampuuid_H */
|
||||
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
server.c
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Main Dispatcher
|
||||
|
||||
TODO: sort multicast addresses and ranges
|
||||
|
||||
*/
|
||||
#include <proto/exec.h>
|
||||
#include <proto/utility.h>
|
||||
#include <proto/dos.h>
|
||||
#include <proto/timer.h>
|
||||
#include <dos/dostags.h>
|
||||
#include <devices/timer.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "hw.h"
|
||||
#include "macros.h"
|
||||
#include "server.h"
|
||||
|
||||
|
||||
/* (avoid external link libraries) this call is not time critical */
|
||||
static void MemSet( void *a, ULONG val, ULONG size )
|
||||
{
|
||||
UBYTE *p = (UBYTE*)a;
|
||||
while( size-- )
|
||||
*p++ = (UBYTE)val;
|
||||
}
|
||||
|
||||
|
||||
static void server_AbortList( DEVBASEP, struct List*list )
|
||||
{
|
||||
struct IOSana2Req *ioreq;
|
||||
|
||||
while( (ioreq = (struct IOSana2Req *)GetHead( list )) )
|
||||
{
|
||||
Remove( (struct Node*)ioreq );
|
||||
ioreq->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
|
||||
ioreq->ios2_WireError = S2WERR_UNIT_OFFLINE;
|
||||
svTermIO( db, ioreq );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cancel all pending requests */
|
||||
static void server_Offline_CancelRequests( DEVBASEP , ULONG unit )
|
||||
{
|
||||
struct SanaReadType *type;
|
||||
struct SanaReader *rd;
|
||||
|
||||
D(("server_Offline_CancelRequests for unit %ld\n",unit));
|
||||
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem );
|
||||
/* start with the read list -> types -> readers -> reqlist */
|
||||
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
rd = (struct SanaReader *)GetHead( &type->srt_Readers );
|
||||
while( rd )
|
||||
{
|
||||
server_AbortList( db, &rd->snr_Requests );
|
||||
rd = GetSucc( rd );
|
||||
}
|
||||
type = GetSucc( type );
|
||||
}
|
||||
|
||||
server_AbortList( db, (struct List*)&db->db_Units[unit].du_WriteQueue );
|
||||
server_AbortList( db, (struct List*)&db->db_Units[unit].du_EventQueue );
|
||||
server_AbortList( db, (struct List*)&db->db_Units[unit].du_ReadOrphans );
|
||||
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
|
||||
/* clear Multicast list, TODO: subroutine */
|
||||
{
|
||||
struct MCastEntry *entry;
|
||||
|
||||
while(1)
|
||||
{
|
||||
entry = (struct MCastEntry *)db->db_svdat.sv_mclist.lh_Head;
|
||||
if( !entry->mce_Node.mln_Succ )
|
||||
break;
|
||||
REMOVE(entry);
|
||||
FreeMem(entry,sizeof(struct MCastEntry));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
D(("server_Offline_CancelRequests done\n"));
|
||||
}
|
||||
|
||||
|
||||
static LONG server_setOnline( DEVBASEP , ULONG unit, ULONG evt )
|
||||
{
|
||||
D(("Unit %ld online command\n",unit));
|
||||
|
||||
if( db->db_Units[unit].du_Flags & DUF_ONLINE )
|
||||
{
|
||||
D(("Was Online already\n"));
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
if( !hw_Attach( db, unit ) )
|
||||
{
|
||||
D(("Hardware hw_attach Fail\n"));
|
||||
return SERR_ERROR;
|
||||
}
|
||||
D(("hw_attach success\n"));
|
||||
|
||||
{ /* track last opening time */
|
||||
struct timerequest timereq;
|
||||
struct Library *TimerBase;
|
||||
|
||||
MemSet( &timereq, 0, sizeof(struct timerequest));
|
||||
OpenDevice("timer.device", 0, (struct IORequest*)&timereq, 0);
|
||||
TimerBase = (struct Library *)timereq.tr_node.io_Device;
|
||||
GetSysTime( &db->db_Units[unit].du_DevStats.LastStart );
|
||||
CloseDevice( (struct IORequest*)&timereq);
|
||||
}
|
||||
db->db_Units[unit].du_Flags |= DUF_ONLINE;
|
||||
|
||||
if( evt )
|
||||
{
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem );
|
||||
server_SendEvent(db, unit, S2EVENT_ONLINE );
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
}
|
||||
|
||||
D(("Unit %ld online\n",unit));
|
||||
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
static void server_setOffline( DEVBASEP , ULONG unit, ULONG evt )
|
||||
{
|
||||
D(("Unit %ld offline command\n",unit));
|
||||
|
||||
if( !(db->db_Units[unit].du_Flags & DUF_ONLINE ))
|
||||
return;
|
||||
|
||||
hw_Detach( db,unit );
|
||||
|
||||
db->db_Units[unit].du_Flags &= ~(DUF_ONLINE);
|
||||
|
||||
if( evt )
|
||||
{
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem );
|
||||
server_SendEvent(db, unit, S2EVENT_OFFLINE );
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
}
|
||||
D(("Unit %ld offline\n",unit));
|
||||
}
|
||||
|
||||
|
||||
/* check for online status following closeDevice */
|
||||
static void server_CloseDevice_offline( DEVBASEP )
|
||||
{
|
||||
LONG unit;
|
||||
|
||||
unit=0;BOARDLOOP( ( ; unit < db->db_NBoards ; unit++ ) )
|
||||
{
|
||||
/* bring unit offline if no opener left */
|
||||
if( !db->db_Units[unit].du_OpenCount )
|
||||
{
|
||||
if( db->db_Units[unit].du_Flags & DUF_ONLINE )
|
||||
{
|
||||
server_setOffline( db, unit, 0 );
|
||||
server_Offline_CancelRequests( db, unit );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* IMPORTANT: base pointer is unavailable here until
|
||||
retrieved from incoming message */
|
||||
static struct ServerMsg *server_startup(void)
|
||||
{
|
||||
struct ServerMsg *msg;
|
||||
struct Process *self;
|
||||
|
||||
struct { struct Library *db_SysBase; } *db = (void*)0x4;
|
||||
|
||||
self = (struct Process*)FindTask(NULL);
|
||||
|
||||
D(("Waiting for Message from Device\n"));
|
||||
|
||||
WaitPort( &self->pr_MsgPort);
|
||||
|
||||
msg = (struct ServerMsg *)GetMsg( &self->pr_MsgPort );
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
/* real init, now with active device base */
|
||||
static LONG server_init( DEVBASEP )
|
||||
{
|
||||
LONG ret = SERR_ERROR;
|
||||
|
||||
NEWLIST( &db->db_svdat.sv_mclist ); /* list of multicast addresses to accept on RX */
|
||||
|
||||
db->db_ServerPort = CreateMsgPort(); /* forwarded IO Requests */
|
||||
if( db->db_ServerPort )
|
||||
{
|
||||
if( hw_Setup( db ) ) /* management stuff for hardware: interrupts, timers, memory etc. */
|
||||
{
|
||||
db->db_svdat.sv_framesize = ETH_MTU+18+8; /* 1514 = RAW IEE802.2, 1518 = with VLAN TAG, +8 for safety */
|
||||
db->db_svdat.sv_frame = AllocMem( db->db_svdat.sv_framesize, MEMF_PUBLIC );
|
||||
if( db->db_svdat.sv_frame )
|
||||
ret = SERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void server_up( DEVBASEP , struct ServerMsg *msg, LONG updown )
|
||||
{
|
||||
msg->sm_result = updown;
|
||||
ReplyMsg( &msg->sm_msg );
|
||||
D(("Replied to Startup Message with %ld\n",updown));
|
||||
}
|
||||
|
||||
|
||||
static LONG server_shutdown( DEVBASEP )
|
||||
{
|
||||
|
||||
hw_Shutdown( db );
|
||||
|
||||
if( (db->db_svdat.sv_framesize) && (db->db_svdat.sv_frame) )
|
||||
FreeMem( db->db_svdat.sv_frame, db->db_svdat.sv_framesize );
|
||||
db->db_svdat.sv_frame = (0);
|
||||
|
||||
if( db->db_ServerPort )
|
||||
DeleteMsgPort(db->db_ServerPort);
|
||||
db->db_ServerPort = (0);
|
||||
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* read config file (if present) and reconfigure HW parameters */
|
||||
const BYTE configtemplate[] = COMMON_TEMPLATE HW_CONFIGTEMPLATE;
|
||||
static LONG server_Config( DEVBASEP )
|
||||
{
|
||||
BPTR cfgfile;
|
||||
LONG i;
|
||||
|
||||
hw_ConfigInit( db ); /* hw defaults */
|
||||
|
||||
if((cfgfile = Open(HW_CONFIGFILE, MODE_OLDFILE))) /* see hwprivate.h for CONFIGFILE */
|
||||
{
|
||||
struct HWConfig args; /* see hwprivate.h */
|
||||
struct RDArgs *readargs;
|
||||
|
||||
cfgfile = SelectInput(cfgfile); /* get default Input */
|
||||
|
||||
MemSet( &args, 0, sizeof( args ) );
|
||||
|
||||
readargs = ReadArgs( (BYTE*)configtemplate, (LONG *)&args, NULL);
|
||||
|
||||
Close( SelectInput( cfgfile ) ); /* restore default input and retrieve cfgfile */
|
||||
|
||||
if( readargs )
|
||||
{
|
||||
/* copy common variables */
|
||||
if(args.common.priority)
|
||||
SetTaskPri((struct Task*)db->db_ServerProc,BOUNDS(*args.common.priority, MINPRIORITY, MAXPRIORITY));
|
||||
|
||||
i=0;BOARDLOOP( ( ; i < db->db_NBoards ; i++ ) )
|
||||
{
|
||||
if( args.common.bps )
|
||||
db->db_Units[i].du_BitPerSec = *args.common.bps;
|
||||
if( args.common.mtu )
|
||||
db->db_Units[i].du_MTU = *args.common.mtu;
|
||||
}
|
||||
|
||||
#if 0 /* ignored for now but kept in template for compatibility with old codebase */
|
||||
if(args.common.nospecialstats)
|
||||
#endif
|
||||
hw_ConfigUpdate( db, &args );
|
||||
|
||||
FreeArgs( readargs );
|
||||
}
|
||||
}
|
||||
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
static LONG CMPeqMAC( BYTE *a, BYTE *b )
|
||||
{
|
||||
LONG i;
|
||||
for( i=0 ; i<6 ; i++ )
|
||||
{
|
||||
if( a[i] != b[i] )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static LONG server_changeMulticast( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, ULONG add_del )
|
||||
{
|
||||
/* step 1: find start address in active list */
|
||||
struct MCastEntry *entry;
|
||||
LONG ret = 1;
|
||||
|
||||
entry = (struct MCastEntry *)db->db_svdat.sv_mclist.lh_Head;
|
||||
while( entry->mce_Node.mln_Succ )
|
||||
{
|
||||
if( CMPeqMAC( entry->mce_start, ioreq->ios2_SrcAddr ) )
|
||||
break;
|
||||
entry = (struct MCastEntry *)entry->mce_Node.mln_Succ;
|
||||
}
|
||||
|
||||
/* did we have a prior entry ? */
|
||||
if( entry->mce_Node.mln_Succ )
|
||||
{
|
||||
if( add_del )
|
||||
{
|
||||
entry->mce_refcount++;
|
||||
goto apply;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( entry->mce_refcount > 1 )
|
||||
{
|
||||
entry->mce_refcount--;
|
||||
goto apply;
|
||||
}
|
||||
else
|
||||
{
|
||||
REMOVE(entry);
|
||||
FreeMem( entry, sizeof( struct MCastEntry ) );
|
||||
goto apply;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* prior not found */
|
||||
if( !add_del )
|
||||
{
|
||||
ret = 0; /* ERROR: CAN`T DELETE NONEXISTENT ENTRY */
|
||||
goto donothing;
|
||||
}
|
||||
|
||||
/* add new entry */
|
||||
entry = (struct MCastEntry*)AllocMem( sizeof( struct MCastEntry ), MEMF_PUBLIC|MEMF_CLEAR );
|
||||
if( !entry )
|
||||
{
|
||||
ret = 0;
|
||||
goto donothing;
|
||||
}
|
||||
|
||||
entry->mce_refcount = 1;
|
||||
COPYMAC( entry->mce_start, ioreq->ios2_SrcAddr );
|
||||
COPYMAC( entry->mce_stop, ioreq->ios2_SrcAddr );
|
||||
|
||||
ADDTAIL( &db->db_svdat.sv_mclist, entry );
|
||||
|
||||
apply:
|
||||
hw_change_multicast( db, unit, &db->db_svdat.sv_mclist );
|
||||
|
||||
donothing:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* forwarded commands (online/offline etc.) */
|
||||
static LONG server_HandleS2Commands( DEVBASEP )
|
||||
{
|
||||
ULONG unit;
|
||||
struct IOSana2Req *ioreq;
|
||||
|
||||
while( (ioreq = (struct IOSana2Req *)GetMsg(db->db_ServerPort)) )
|
||||
{
|
||||
unit = (ULONG)ioreq->ios2_Req.io_Unit;
|
||||
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
|
||||
switch( ioreq->ios2_Req.io_Command)
|
||||
{
|
||||
case S2_ONLINE:
|
||||
if( server_setOnline(db,unit,1 ) != SERR_OK )
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
break;
|
||||
case S2_OFFLINE:
|
||||
server_setOffline( db, unit, 1 ); /* ,1: send event to opener */
|
||||
server_Offline_CancelRequests( db, unit );
|
||||
break;
|
||||
case S2_CONFIGINTERFACE:
|
||||
COPYMAC( db->db_Units[unit].du_CFGAddr, ioreq->ios2_SrcAddr );
|
||||
|
||||
if( db->db_Units[unit].du_Flags & DUF_ONLINE )
|
||||
server_setOffline( db, unit,0 );
|
||||
|
||||
server_setOnline( db, unit,0 );
|
||||
break;
|
||||
|
||||
case S2_ADDMULTICASTADDRESS:
|
||||
if( server_changeMulticast( db, unit, ioreq, 1 ) )
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case S2_DELMULTICASTADDRESS:
|
||||
if( server_changeMulticast( db, unit, ioreq, 0 ) )
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* shouldn't happen */
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
break;
|
||||
}
|
||||
svTermIO( db, ioreq );
|
||||
}
|
||||
|
||||
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* error conditions sent via EventQueue */
|
||||
static LONG server_SendEvent( DEVBASEP, ULONG unit, ULONG evtmask )
|
||||
{
|
||||
struct IOSana2Req *ioreq;
|
||||
|
||||
/* Semaphore is locked outside */
|
||||
/* ObtainSemaphore( &db->db_Units[unit].du_Sem ); */
|
||||
|
||||
for( ioreq = (struct IOSana2Req *)db->db_Units[unit].du_EventQueue.lh_Head;
|
||||
(ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
|
||||
ioreq = (struct IOSana2Req *)ioreq->ios2_Req.io_Message.mn_Node.ln_Succ )
|
||||
{
|
||||
if( ioreq->ios2_WireError & evtmask )
|
||||
{
|
||||
Remove( (struct Node*)ioreq );
|
||||
svTermIO( db, ioreq );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* ReleaseSemaphore( &db->db_Units[unit].du_Sem ); */
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* handle write errors */
|
||||
LONG server_writeerror( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, LONG code )
|
||||
{
|
||||
if (code == SERR_BUFFER_ERROR) /* no buffer management callback or copy error */
|
||||
{
|
||||
D(("buffer error (TX)\n"));
|
||||
server_SendEvent(db, unit, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
|
||||
/* db->db_SpecialStats[S2SS_TXERRORS].Count++; */
|
||||
|
||||
ioreq->ios2_Req.io_Error = S2ERR_SOFTWARE;
|
||||
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
|
||||
}
|
||||
else /* if (code != SERR_OK) */
|
||||
{
|
||||
D(("TX error\n"));
|
||||
server_SendEvent(db, unit, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
|
||||
/* db->db_SpecialStats[S2SS_TXERRORS].Count++; */
|
||||
|
||||
ioreq->ios2_Req.io_Error = S2ERR_TX_FAILURE;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
Remove((struct Node*)ioreq);
|
||||
svTermIO( db, ioreq ); /* SANA2IOF_QUICK is off for write queue, just ReplyMsg */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef EXTERNAL_WRITE_FRAME
|
||||
/* note: entering here with locked semaphore */
|
||||
static LONG write_frame( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq )
|
||||
{
|
||||
LONG ret = SERR_OK;
|
||||
UBYTE *copy_ptr,*frame;
|
||||
ULONG framesize;
|
||||
struct db_BufferManagement *dbm;
|
||||
|
||||
D(("write: type %08lx, size %ld\n",ioreq->ios2_PacketType,
|
||||
ioreq->ios2_DataLength));
|
||||
|
||||
frame = db->db_svdat.sv_frame;
|
||||
framesize = ioreq->ios2_DataLength;
|
||||
copy_ptr = frame;
|
||||
|
||||
/* copy raw frame: simply overwrite ethernet frame part of plip packet */
|
||||
if( !(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) )
|
||||
{
|
||||
COPYMAC( frame, ioreq->ios2_DstAddr ); /* macro in server.h */
|
||||
COPYMAC( frame+6, db->db_Units[unit].du_CFGAddr );
|
||||
*( (USHORT*)(frame+12)) = ioreq->ios2_PacketType;
|
||||
copy_ptr += 14;
|
||||
framesize += 14;
|
||||
}
|
||||
|
||||
dbm = (struct db_BufferManagement *)ioreq->ios2_BufferManagement;
|
||||
|
||||
/* copy32 is valid ptr, even if the stack offers only regular CopyFromBuffer */
|
||||
if( (*dbm->dbm_CopyFromBuffer32)(copy_ptr,ioreq->ios2_Data, ioreq->ios2_DataLength) )
|
||||
{
|
||||
send:
|
||||
D(("+hw_send\n"));
|
||||
ret = hw_send_frame(db, unit, frame, framesize) ? SERR_OK : SERR_ERROR;
|
||||
D(("-hw_send\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if copy32 fails, try regular call */
|
||||
if( (*dbm->dbm_CopyFromBuffer)(copy_ptr,ioreq->ios2_Data, ioreq->ios2_DataLength) )
|
||||
goto send;
|
||||
else
|
||||
ret = SERR_BUFFER_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static LONG server_writequeue( DEVBASEP, ULONG unit )
|
||||
{
|
||||
LONG code;
|
||||
struct IOSana2Req *ioreq,*nextio;
|
||||
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem );
|
||||
|
||||
#if 1
|
||||
/* whole queue per call */
|
||||
for( ioreq = (struct IOSana2Req *)db->db_Units[unit].du_WriteQueue.lh_Head;
|
||||
(nextio= (struct IOSana2Req *)ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
|
||||
ioreq = nextio )
|
||||
#else
|
||||
/* single write per call */
|
||||
ioreq = (struct IOSana2Req *)db->db_Units[unit].du_WriteQueue.lh_Head;
|
||||
if( ioreq->ios2_Req.io_Message.mn_Node.ln_Succ )
|
||||
#endif
|
||||
{
|
||||
code = write_frame( db, unit, ioreq );
|
||||
if( code >= 0 )
|
||||
{
|
||||
/* statistics ? */
|
||||
if( db->db_Units[unit].du_Flags & DUF_TYPETRACK )
|
||||
{
|
||||
struct SanaReadType *type;
|
||||
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
|
||||
while( type )
|
||||
{
|
||||
if( type->srt_Type == ioreq->ios2_PacketType )
|
||||
{
|
||||
type->srt_Sana2PacketTypeStats.PacketsSent++;
|
||||
type->srt_Sana2PacketTypeStats.BytesSent += ioreq->ios2_DataLength;
|
||||
break;
|
||||
}
|
||||
type = GetSucc( type );
|
||||
}
|
||||
}
|
||||
|
||||
db->db_Units[unit].du_DevStats.PacketsSent++;
|
||||
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
|
||||
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
|
||||
REMOVE( (struct Node*)ioreq );
|
||||
svTermIO( db, ioreq ); /* SANA2IOF_QUICK is off for write queue, just ReplyMsg */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* error handling */
|
||||
server_writeerror( db, unit, ioreq, code );
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* note: entering here with locked semaphore */
|
||||
static void server_read_frame( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, UBYTE *frame, ULONG framesize )
|
||||
{
|
||||
struct db_BufferManagement *dbm;
|
||||
ULONG bcflag = 0;
|
||||
|
||||
COPYMAC( ioreq->ios2_DstAddr, frame ); /* macro in server.h */
|
||||
COPYMAC( ioreq->ios2_SrcAddr, frame+6 );
|
||||
|
||||
if( *frame & 1 ) /* just check Ethernet MULTICAST flag */
|
||||
{
|
||||
ULONG mac = *((ULONG*)frame );
|
||||
|
||||
bcflag = SANA2IOF_MCAST;
|
||||
if( mac == 0xffffffff ) /* evil: ignore the lower 16 bit... */
|
||||
bcflag = SANA2IOF_BCAST; /* special case of multicast, actually */
|
||||
#if 0
|
||||
mac >>= 8;
|
||||
if( mac == 0x0001005e ) /* IPv4 MCAST */
|
||||
bcflag = SANA2IOF_MCAST;
|
||||
#endif
|
||||
}
|
||||
|
||||
if( !(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) )
|
||||
{
|
||||
frame += 14; /* skip DST,SRC,Type */
|
||||
framesize -= 18; /* also remove CRC */
|
||||
D(("plain mode: frame flags %ld\n",bcflag));
|
||||
}
|
||||
ioreq->ios2_Req.io_Flags &= SANA2IOF_RAW; /* ignore all other flags */
|
||||
ioreq->ios2_Req.io_Flags |= bcflag;
|
||||
ioreq->ios2_Req.io_Error = 0;
|
||||
ioreq->ios2_WireError = 0;
|
||||
|
||||
dbm = (struct db_BufferManagement *)ioreq->ios2_BufferManagement;
|
||||
D(("ReadFrm IO %lx, DBM %lx frm %lx frmsz %ld\n",(ULONG)ioreq,(ULONG)dbm,(ULONG)frame,framesize));
|
||||
if(!(*dbm->dbm_CopyToBuffer32)(ioreq->ios2_Data, frame, framesize ))
|
||||
{
|
||||
if(!(*dbm->dbm_CopyToBuffer)(ioreq->ios2_Data, frame, framesize ))
|
||||
{
|
||||
ioreq->ios2_Req.io_Error = S2ERR_SOFTWARE;
|
||||
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
|
||||
}
|
||||
}
|
||||
D(("Copied io_Error %ld\n",(LONG)ioreq->ios2_Req.io_Error));
|
||||
|
||||
Remove( (struct Node*)ioreq );
|
||||
svTermIO( db, ioreq );
|
||||
}
|
||||
|
||||
|
||||
/* it is assumed that hw_recv_pending() was called before entering here */
|
||||
static LONG server_readqueue( DEVBASEP, ULONG unit )
|
||||
{
|
||||
struct SanaReadType *type;
|
||||
struct SanaReader *rd;
|
||||
struct IOSana2Req *ioreq;
|
||||
UBYTE *frame = db->db_svdat.sv_frame;
|
||||
LONG framesize;
|
||||
LONG frametype;
|
||||
LONG dropflag;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if( (framesize = hw_recv_frame(db, unit, frame) ) > 0 )
|
||||
{
|
||||
/* TODO: devstats */
|
||||
frametype = *( (USHORT*)(frame+12) );
|
||||
|
||||
D(("Have Frame size %ld type %ld\n",framesize,frametype));
|
||||
|
||||
ObtainSemaphore( &db->db_Units[unit].du_Sem );
|
||||
|
||||
type = (struct SanaReadType *)db->db_Units[unit].du_ReadTypes.lh_Head;
|
||||
while( (type->srt_Node.mln_Succ) )
|
||||
{
|
||||
if( type->srt_Type == frametype )
|
||||
goto havetype;
|
||||
type = (struct SanaReadType *)type->srt_Node.mln_Succ;
|
||||
}
|
||||
|
||||
/* desired type not found, get orphan list */
|
||||
db->db_Units[unit].du_DevStats.UnknownTypesReceived++;
|
||||
orphan:
|
||||
ioreq = (struct IOSana2Req *)GetHead( (struct List*)&db->db_Units[unit].du_ReadOrphans );
|
||||
if( ioreq )
|
||||
{
|
||||
D(("Orphaned Frame\n"));
|
||||
|
||||
ioreq->ios2_PacketType = frametype;
|
||||
server_read_frame( db, unit, ioreq, frame, framesize );
|
||||
}
|
||||
else
|
||||
{
|
||||
D(("No ioreq for orphaned frame\n"));
|
||||
}
|
||||
|
||||
goto nextframe;
|
||||
|
||||
havetype:
|
||||
/* push frame to all readers */
|
||||
/*if( type->srt_Flags & SRTF_TRACKTYPE )*/ /* stats ? */
|
||||
{
|
||||
/* type->srt_Sana2PacketTypeStats.PacketsSent++; */
|
||||
/* type->srt_Sana2PacketTypeStats.BytesSent++; */
|
||||
/* type->srt_Sana2PacketTypeStats.PacketsDropped++; */
|
||||
|
||||
type->srt_Sana2PacketTypeStats.PacketsReceived++;
|
||||
type->srt_Sana2PacketTypeStats.BytesReceived += framesize;
|
||||
}
|
||||
db->db_Units[unit].du_DevStats.PacketsReceived++;
|
||||
|
||||
rd = (struct SanaReader *)type->srt_Readers.lh_Head;
|
||||
dropflag = 1;
|
||||
while( rd->snr_Node.mln_Succ )
|
||||
{
|
||||
ioreq = (struct IOSana2Req *)rd->snr_Requests.lh_Head;
|
||||
if( ioreq->ios2_Req.io_Message.mn_Node.ln_Succ )
|
||||
{
|
||||
server_read_frame( db, unit, ioreq, frame, framesize );
|
||||
dropflag = 0;
|
||||
}
|
||||
rd = (struct SanaReader *)rd->snr_Node.mln_Succ;
|
||||
}
|
||||
if( dropflag )
|
||||
{
|
||||
db->db_Units[unit].du_DevStats.Overruns++;
|
||||
type->srt_Sana2PacketTypeStats.PacketsDropped++;
|
||||
D(("No Reader for frame\n"));
|
||||
goto orphan; /* does it help if we give the frame to the orphan list? */
|
||||
}
|
||||
nextframe:
|
||||
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: check for error, send S2EVENT_HARDWARE|S2EVENT_ERROR|S2EVENT_RX along with stats db_DevStats.BadData */
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
end:
|
||||
return SERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID SAVEDS ServerTask(void)
|
||||
{
|
||||
struct ServerMsg *msg;
|
||||
ULONG wmask,gotmask,spcmask,portsigmask,recvmask,i=0,action;
|
||||
struct IOSana2Req*wr;
|
||||
struct DevUnit *curunit;
|
||||
DEVBASEP = (0); /* Don`t call Libraries until server_startup() succeeds! */
|
||||
|
||||
msg = server_startup();
|
||||
if( !msg )
|
||||
goto QuitServer; /* unlikely */
|
||||
db = msg->sm_devbase;
|
||||
|
||||
if( !server_init( db ) )
|
||||
{
|
||||
server_up( db, msg, 0 );
|
||||
goto QuitServer;
|
||||
}
|
||||
|
||||
server_Config( db ); /* load config (if present) */
|
||||
server_up( db, msg, 1 ); /* init done, server is active */
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/*-------------------------- MAIN LOOP --------------------------------*/
|
||||
/*----------------------------------------------------------------------*/
|
||||
portsigmask = 1<<db->db_ServerPort->mp_SigBit;
|
||||
recvmask = hw_recv_sigmask( db );
|
||||
wmask = SIGBREAKF_CTRL_F|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|portsigmask|recvmask;
|
||||
spcmask= SIGBREAKF_CTRL_C|portsigmask|SIGBREAKF_CTRL_D;
|
||||
|
||||
D(("Portsigmask %ld RecvMask %ld wmask %ld\n",portsigmask,recvmask,wmask));
|
||||
|
||||
action = 0;
|
||||
gotmask = 0;
|
||||
while(1)
|
||||
{
|
||||
if( !action ) /* queues quiet ? -> sleep */
|
||||
{
|
||||
i=0;BOARDLOOP( ( ; i < db->db_NBoards ; i++ ) )
|
||||
{ /* housekeeping -> check for link change on idle, re-enable interrupts etc. */
|
||||
hw_check_link_change(db,i);
|
||||
}
|
||||
gotmask = Wait(wmask);
|
||||
}
|
||||
|
||||
action = 0; /* any action on the queues ? */
|
||||
curunit = &db->db_Units[0];
|
||||
i=0;BOARDLOOP( (; i < db->db_NBoards ; i++ ) ) /* skip the for() when just a single device is supported */
|
||||
{
|
||||
if( curunit->du_Flags & DUF_ONLINE )
|
||||
{
|
||||
/* D(("BoardLoop %ld\n",i)); */
|
||||
wr = (struct IOSana2Req *)curunit->du_WriteQueue.lh_Head; /* don't bother with semaphore, lh_Head is always !=0 */
|
||||
if( wr->ios2_Req.io_Message.mn_Node.ln_Succ ) /* quick check for write reqs */
|
||||
{
|
||||
server_writequeue( db, i );
|
||||
action = 1;
|
||||
}
|
||||
if( hw_recv_pending(db,i) )
|
||||
{
|
||||
D(("Read on unit %ld start\n",i));
|
||||
server_readqueue( db, i );
|
||||
D(("Read on unit %ld stop\n",i));
|
||||
action = 1;
|
||||
}
|
||||
}
|
||||
curunit++;
|
||||
}
|
||||
|
||||
if( gotmask & spcmask ) /* rare flags */
|
||||
{
|
||||
if( gotmask & portsigmask )
|
||||
{
|
||||
D(("SANA-II request handling commencing\n"));
|
||||
server_HandleS2Commands( db );
|
||||
gotmask &= ~portsigmask;
|
||||
}
|
||||
if( gotmask & SIGBREAKF_CTRL_D )
|
||||
{
|
||||
D(("Got CTRL-D in Server. Checking Online status\n"));
|
||||
gotmask &= ~SIGBREAKF_CTRL_D;
|
||||
server_CloseDevice_offline( db );
|
||||
}
|
||||
if( gotmask & SIGBREAKF_CTRL_C )
|
||||
{
|
||||
D(("Got CTRL-C in Server. leaving.\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server_shutdown( db );
|
||||
|
||||
QuitServer:
|
||||
if( db )
|
||||
db->db_ServerProc = (0);
|
||||
|
||||
{ /* revert to "real" execbase, in case that we never got the startup msg */
|
||||
struct { struct Library *db_SysBase; } *db = (void*)0x4;
|
||||
D(("Server exiting"));
|
||||
Forbid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
server.h
|
||||
|
||||
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
|
||||
|
||||
Main Dispatcher defs and protos
|
||||
|
||||
*/
|
||||
#ifndef _INC_SERVER_H
|
||||
#define _INC_SERVER_H
|
||||
|
||||
#define ETH_MTU 1500
|
||||
#define MINPRIORITY -120
|
||||
#define MAXPRIORITY 120
|
||||
|
||||
#define SERR_OK 1
|
||||
#define SERR_ERROR 0
|
||||
#define SERR_BUFFER_ERROR -1
|
||||
#define SERR_TX_ERROR -2
|
||||
#define SERR_RX_ERROR -3
|
||||
|
||||
#if (MAX_UNITS > 1)
|
||||
#define BOARDLOOP( _a_ ) for _a_
|
||||
#else
|
||||
#define BOARDLOOP( _a_ )
|
||||
#endif
|
||||
|
||||
|
||||
static void MemSet( void *a, ULONG val, ULONG size );
|
||||
static struct ServerMsg *server_startup(void);
|
||||
static LONG server_init( DEVBASEP );
|
||||
static void server_up( DEVBASEP , struct ServerMsg *msg, LONG updown );
|
||||
static LONG server_shutdown( DEVBASEP );
|
||||
static LONG server_Config( DEVBASEP );
|
||||
static LONG server_writequeue( DEVBASEP, ULONG unit );
|
||||
static LONG server_HandleS2Commands( DEVBASEP );
|
||||
static LONG server_SendEvent( DEVBASEP, ULONG unit, ULONG evtmask );
|
||||
LONG server_writeerror( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, LONG code );
|
||||
#ifdef EXTERNAL_WRITE_FRAME
|
||||
LONG write_frame( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq );
|
||||
#else
|
||||
static LONG write_frame( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq );
|
||||
#endif
|
||||
|
||||
static LONG server_writequeue( DEVBASETYPE*, ULONG );
|
||||
|
||||
static LONG server_setOnline( DEVBASETYPE* , ULONG, ULONG );
|
||||
static void server_setOffline( DEVBASETYPE* , ULONG, ULONG );
|
||||
static void server_CloseDevice_offline( DEVBASETYPE * );
|
||||
|
||||
#define svTermIO(_a_,_b_) ReplyMsg( (struct Message*)_b_)
|
||||
|
||||
#define COPYMAC( _d_, _s_ ) \
|
||||
{\
|
||||
USHORT *dst = (USHORT*)(_d_);\
|
||||
USHORT *src = (USHORT*)(_s_);\
|
||||
*dst++ = *src++;\
|
||||
*dst++ = *src++;\
|
||||
*dst = *src;\
|
||||
}
|
||||
|
||||
#endif /* _INC_SERVER_H */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user