New driver

This commit is contained in:
MHeinrichs
2019-01-03 00:43:32 +01:00
parent eecd6c8918
commit e42f097a6c
44 changed files with 1639 additions and 110 deletions
+19 -1
View File
@@ -337,7 +337,7 @@ u08 enc28j60_init(const u08 macaddr[6], u08 flags)
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, EIE, EIE_INTIE|EIE_PKTIE); /* |EIE_LINKIE|EIE_TXIE|EIE_TXERIE|EIE_RXERIE); */
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
@@ -441,6 +441,9 @@ u08 enc28j60_status(u08 status_id, u08 *value)
case PIO_STATUS_LINK_UP:
*value = (readPhyByte(PHSTAT2) >> 2) & 1;
return PIO_OK;
case PIO_STATUS_FULLDPX:
*value = (readRegByte(MACON3) & MACON3_FULDPX) ? 1 : 0;/* + (((u16)readRegByte(MACON1+3))<<8); */
return PIO_OK;
default:
*value = 0;
return PIO_NOT_FOUND;
@@ -469,6 +472,13 @@ u08 enc28j60_send(const u08 *data, u16 size)
}
/* write buffer */
#if 0
if(0)
{ u08* d = (u08*)data;
d[size]=0;
size=(size+1)&0xfffe;
}
#endif
enc28j60l_WriteBuffer( (u08*)data, size, TXSTART_INIT );
/* initiate send */
@@ -559,6 +569,14 @@ u08 enc28j60_recv(u08 *data, u16 max_size, u16 *got_size)
/* read packet */
readBuf(len, data);
#if 0
{
data[len]=0;
data[len+1]=0;
data[len+2]=0;
data[len+3]=0;
}
#endif
next_pkt();
return result;
+1
View File
@@ -42,6 +42,7 @@
/* status flags */
#define PIO_STATUS_VERSION 0
#define PIO_STATUS_LINK_UP 1
#define PIO_STATUS_FULLDPX 2
/* control ids */
#define PIO_CONTROL_FLOW 0
+112
View File
@@ -6,6 +6,9 @@
; Note: This code is in some places intentionally saving more registers than
; required by the AmigaOS ABI.
;
ifnd _LVOSignal
_LVOSignal EQU -324
endc
; enable debugging code block
DEBUG EQU 0
@@ -32,6 +35,12 @@ _OPT_SHORT_DELAY EQU 1 ;small delays by a single CIA read
XDEF _enc28j60l_Shutdown
XDEF _enc28j60l_SetSPISpeed
ifd PROTO_V2EXPNET
; interrupt stuff, used only with V2EXPETH right now
XDEF _enc28j60l_IntServer_List
XDEF _enc28j60l_EnableInterrupt
XDEF _enc28j60l_DisableInterrupt
endc
;
;
; hardware support functions without SPI register banging
@@ -300,6 +309,7 @@ SDCARD_DATA_R EQU $00DE0010
SDCARD_CFG_W EQU $00DE0014
SDCARD_STATUS_R EQU $00DE0016
SDCARD_CFG_SPEED EQU $00DE001C
SDCARD_INT_ENABLE EQU $00DE0018
else ;PROTO_V2EXPNET
; PROTO_SDNET
SDCARD_DATA_W EQU $00DE0000
@@ -307,6 +317,7 @@ SDCARD_DATA_R EQU $00DE0000
SDCARD_CFG_W EQU $00DE0004
SDCARD_STATUS_R EQU $00DE0006
SDCARD_CFG_SPEED EQU $00DE000C
SDCARD_INT_ENABLE EQU $00DE0008
endc ;PROTO_V2EXPNET
SDCARD_SPEED EQU $20 ;this one is obsolete
@@ -999,6 +1010,107 @@ skip$
rts$
rts
;-----------------------------------------------------------------------
ifd PROTO_V2EXPNET
;---------------------------------------------------------------------------------------
;
; Hardware interrupt service routine for a list of boards
;
; In: A1 - is_data = board base address list
;
; Out: -
;
; Notes: - assumes that init() was called before
; - process list of board addresses and check for active interrupt(s)
; list layout:
; ULONG enableflag
; APTR board1,
; APTR board2,...
; APTR (0)
; APTR sigtask
; ULONG sigbit
;
_enc28j60l_IntServer_List:
movem.l d3/a6,-(sp)
move.l a1,d0 ;no pointer supplied ? -> return
beq.s .rts
move.l a1,a6
tst.l (a1)+ ;interrupt processing enabled ?
beq.s .rts_disable ;
moveq #0,d1
.boardloop:
move.l (a1)+,d0 ;next entry from list
beq.s .done ;
move.l d0,a0 ;current board
move.b #EPKTCNT,d0
bsr _enc28j60l_ReadRegByte
or.b d0,d1
bra.s .boardloop
.done:
tst.w d1
beq.s .rts
clr.l (a6)+ ;disable interrupt processing further on
; clear EIE_INTIE in all active boards directly from here
.intdis_loop:
move.l (a6)+,d0
beq.s .boardsdone
move.w #$0000,SDCARD_INT_ENABLE
;
;move.w #ENC28J60_BIT_FIELD_CLR,d3
;moveq #EIE,d0
;moveq #EIE_INTIE|EIE_PKTIE,d1
;bsr _enc28j60l_WriteOp
bra.s .intdis_loop
.boardsdone:
move.l (a6)+,d0 ;Sigtask
beq.s .rts
move.l d0,a1
moveq #0,d0
move.l (a6)+,d1 ;Sigbit
bset d1,d0
move.l 4.w,a6
jsr _LVOSignal(a6)
.rts:
movem.l (sp)+,d3/a6
moveq #0,d0 ;set Z flag
rts
.rts_disable: ;
move.w #$0000,SDCARD_INT_ENABLE
bra.s .rts
; TODO: enable/disable interrupt on board
_enc28j60l_EnableInterrupt:
move.w #$8000,SDCARD_INT_ENABLE
rts
_enc28j60l_DisableInterrupt:
move.w #$0000,SDCARD_INT_ENABLE
rts
endc ;ifd PROTO_V2EXPNET
;-----------------------------------------------------------------------
; DEBUG
;ifd PROTO_V2EXPNET
;dc.b "exp net variant built."
;endc
; section data,data
+43
View File
@@ -12,6 +12,49 @@
#include "compiler.h"
/*
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 enc28j60l_IntServer_List( void );
/*
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 enc28j60l_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 enc28j60l_DisableInterrupt( ASMR(a0) void *board ASMREG(a0) );
/*
Purpose: prepare SPI for use
input: -
+189 -4
View File
@@ -16,6 +16,8 @@
#include <vampire/vampire.h>
#include "vampuuid.h"
#include "enc28j60.h"
#include <hardware/intbits.h>
#include "enc28j60l.h"
#ifndef PROTO_V2EXPNET
#define PORTID V_SDPORT
@@ -27,6 +29,9 @@ extern const BYTE DeviceName[];
/* use generic board fields in current unit */
#define hw_allocated du_hwl0
#define duh_online du_hwl1
#define duh_BASE du_hwp0
#define HW_INTERVALDEF 10000
#define HW_DEFSPI 2
@@ -58,6 +63,21 @@ extern const BYTE DeviceName[];
hw_config_update() - update config of HW
*/
#ifdef PROTO_V2EXPNET
#define USE_INTERRUPT
/* used only if interrupts are in play (currently V2ExpETH) */
void myhw_ControlInterrupts( DEVBASEP );
const BYTE intname[] = "v2expeth SanaII driver";
#define HW_INTSOURCE INTB_PORTS /* Int 2 */
#else
#define myhw_ControlInterrupts( _a_ )
#endif
const BYTE vres_name[] = V_VAMPIRENAME;
/* return number of boards present in system */
@@ -156,12 +176,25 @@ ASM SAVEDS LONG hw_Setup( ASMR(a0) DEVBASEP ASMREG(a0) )
LONG ret = 0;
struct HWData *hwd = &db->db_hwdat;
#ifdef USE_INTERRUPT
hwd->IntSig = AllocSignal(-1);
hwd->hwd_Interrupt.is_Data = (0);
#ifdef PROTO_V2EXPNET
db->db_Units[0].duh_BASE = (void*)0xDE0010;
#else
db->db_Units[0].duh_BASE = (void*)0xDE0000;
#endif
#else
hwd->IntSig = -1;
#endif
if( InitIntervalTimer( &hwd->ivtimer ) > 0 )
{
hwd->SigMask = hwd->ivtimer.IVT_SigMask;
#ifdef USE_INTERRUPT
hwd->SigMask |= (1<<(hwd->IntSig));
#endif
ret = 1;
}
@@ -173,6 +206,9 @@ ASM SAVEDS void hw_Shutdown( ASMR(a0) DEVBASEP ASMREG(a0) )
{
struct HWData *hwd = &db->db_hwdat;
db->db_Units[0].duh_online = 0;
myhw_ControlInterrupts( db );
if( hwd->IntSig >= 0 )
FreeSignal( hwd->IntSig );
@@ -206,8 +242,14 @@ ASM SAVEDS LONG hw_Attach( ASMR(a0) DEVBASEP ASMREG(a0),
ret = 0;
else
{
db->db_Units[0].duh_online = 1; /* used for int server and interval timer setup */
enc28j60_SetSPISpeed( hwd->spispeed );
StartIntervalTimer( &hwd->ivtimer, hwd->timervalue );
myhw_ControlInterrupts( db );
if( hwd->timervalue > 0 )
StartIntervalTimer( &hwd->ivtimer, hwd->timervalue );
}
return ret;
@@ -220,7 +262,13 @@ ASM SAVEDS void hw_Detach( ASMR(a0) DEVBASEP ASMREG(a0),
if( !unit )
{
struct HWData *hwd = &db->db_hwdat;
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) */
StopIntervalTimer( &hwd->ivtimer );
myhw_ControlInterrupts( db ); /* start and/or stop (based on duh_online) */
enc28j60_exit();
}
}
@@ -235,6 +283,7 @@ ASM SAVEDS void hw_ConfigInit( ASMR(a0) DEVBASEP ASMREG(a0) )
hwd->fullduplex = 0;
hwd->spispeed = HW_DEFSPI; /* default (see above) */
hwd->multicast = 0;
hwd->interrupt = 0; /* def: don`t enable interrupt */
#if 0
USHORT i;
@@ -262,6 +311,8 @@ ASM SAVEDS void hw_ConfigUpdate( ASMR(a0) DEVBASEP ASMREG(a0),
hwd->spispeed = *args->spispeed;
if( args->multicast )
hwd->multicast = 1;
if( args->interrupt )
hwd->interrupt = 1;
}
@@ -270,6 +321,12 @@ ASM SAVEDS LONG hw_send_frame( ASMR(a0) DEVBASEP ASMREG(a0),
ASMR(a1) UBYTE *frame ASMREG(a1),
ASMR(d1) ULONG framesize ASMREG(d1) )
{
#ifdef USE_INTERRUPT
struct HWData *hwd = &db->db_hwdat;
hwd->hwd_act_boards[0] = (void*)(0); /* disable interrupt processing */
#endif
enc28j60_send( frame, framesize );
return 1;
}
@@ -278,7 +335,21 @@ ASM SAVEDS LONG hw_send_frame( ASMR(a0) DEVBASEP ASMREG(a0),
ASM SAVEDS LONG hw_recv_pending( ASMR(a0) DEVBASEP ASMREG(a0),
ASMR(d0) ULONG unit ASMREG(d0) )
{
#ifdef USE_INTERRUPT
LONG ret;
struct HWData *hwd = &db->db_hwdat;
void *tmp = hwd->hwd_act_boards[0];
hwd->hwd_act_boards[0] = (void*)(0); /* disable interrupt processing */
ret = (LONG)enc28j60_has_recv();
hwd->hwd_act_boards[0] = tmp; /* restore interrupt processing enable flag */
return ret;
#else
return (LONG)enc28j60_has_recv();
#endif
}
@@ -288,9 +359,14 @@ ASM SAVEDS LONG hw_recv_frame( ASMR(a0) DEVBASEP ASMREG(a0),
{
volatile SHORT sz;
LONG ret;
#ifdef USE_INTERRUPT
struct HWData *hwd = &db->db_hwdat;
hwd->hwd_act_boards[0] = (void*)(0); /* disable interrupt processing */
#endif
/* important: don't call this without enc28j60_has_recv() > 0 check */
if( PIO_OK != enc28j60_recv( frame, 1518, (short*)&sz ) )
if( PIO_OK != enc28j60_recv( frame, 1518, (unsigned short*)&sz ) )
ret = 0;
else
ret = (LONG)sz;
@@ -311,9 +387,43 @@ ASM SAVEDS ULONG hw_recv_sigmask( ASMR(a0) DEVBASEP ASMREG(a0)
ASM SAVEDS LONG hw_check_link_change( ASMR(a0) DEVBASEP ASMREG(a0),
ASMR(d0) ULONG unit ASMREG(d0) )
{
#ifdef USE_INTERRUPT
struct HWData *hwd = &db->db_hwdat;
if( hwd->hwd_Interrupt.is_Data ) /* interrupt running ? */
{
hwd->hwd_act_boards[0] = (void*)(1); /* re-enable interrupt processing */
/* re-enable interrupt when server goes to sleep */
enc28j60l_EnableInterrupt( db->db_Units[unit].duh_BASE, FindTask(0), (int)hwd->IntSig, 0 );
}
#endif
return 0;
}
/* obtain running parameters of Ethernet MAC: link up/down, Speed, Duplex */
/* note: */
/* if this call is unsupported then return HW_MAC_INVALID */
ASM SAVEDS LONG hw_get_mac_status( ASMR(a0) DEVBASEP ASMREG(a0),
ASMR(d0) ULONG unit ASMREG(d0) )
{
LONG ret = 0; /* def: link down */
UBYTE status;
enc28j60_status( PIO_STATUS_LINK_UP, &status );
if( status )
{
ret = HW_MAC_LINK_UP; /* LINK_UP may be redundant */
enc28j60_status( PIO_STATUS_FULLDPX, &status );
if( status )
ret |= HW_MAC_ON_FDX<<HW_MACB_SPEED10;
else
ret |= HW_MAC_ON<<HW_MACB_SPEED10;
}
return ret;
}
/* process the list of multicast addresses for an appropriate
filtering list on the hardware
@@ -323,7 +433,7 @@ ASM SAVEDS LONG hw_check_link_change( ASMR(a0) DEVBASEP ASMREG(
filter with hashes etc.
*/
ASM SAVEDS LONG hw_change_multicast( ASMR(a0) DEVBASEP ASMREG(a0),
ASMR(a0) ULONG unit ASMREG(d0),
ASMR(d0) ULONG unit ASMREG(d0),
ASMR(a1) struct List *mcastlist ASMREG(a1) )
{
u08 flags;
@@ -341,3 +451,78 @@ ASM SAVEDS LONG hw_change_multicast( ASMR(a0) DEVBASEP ASMREG(
return 1;
}
#ifdef USE_INTERRUPT
/* relies on hwd_online */
void myhw_ControlInterrupts( DEVBASEP )
{
struct HWData *hwd = &db->db_hwdat;
LONG i,flag;
if( !hwd->interrupt )
return;
flag = 0;
for( i=0 ; i < db->db_NBoards ; i++ )
{
if( db->db_Units[i].duh_online )
{
hwd->hwd_act_boards[flag+1] = db->db_Units[i].duh_BASE;
flag++;
}
}
hwd->hwd_act_boards[flag+1] = (0); /* NULL-terminate */
hwd->hwd_act_boards[flag+2] = (APTR)FindTask(0); /* append task */
hwd->hwd_act_boards[flag+3] = (APTR)hwd->IntSig; /* append sigbit */
if( flag ) /* determine on/off switch */
{
/* at least 1 board is online */
hwd->hwd_act_boards[0] = (void*)(1); /* enable interrupt processing */
if( hwd->hwd_Interrupt.is_Data )
flag = 0; /* no change */
else flag = 1; /* start interrupt */
}
else
{
hwd->hwd_act_boards[0] = 0; /* disable interrupt processing */
if( hwd->hwd_Interrupt.is_Data )
flag = -1; /* stop interrupt */
else flag = 0; /* no change */
}
/* flag is >0 = start, <0 = stop or 0 = no change */
if( flag > 0 )
{
hwd->hwd_Interrupt.is_Code = (void(*)())enc28j60l_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 )
{
enc28j60l_EnableInterrupt( db->db_Units[i].duh_BASE, FindTask(0), (int)hwd->IntSig, 0 );
}
else
{
enc28j60l_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);
}
}
#endif
+26 -5
View File
@@ -15,29 +15,49 @@
/* sdnet/v2expnet specific: polling timer */
#include "intervaltimer.h"
#define HW_VENDOR "Henryk Richter"
/* 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 Interrupt hwd_Interrupt; /* keep the interrupt at top of HWData !! */
APTR hwd_act_boards[MAX_UNITS+1+2+1]; /* poll all active boards by ptr in interrupt, NULL terminated, followed by SigTask,Sigbit */
/* contents of hwd_act_boards:
1 ULONG processing ENABLE (1) or DISABLE (0)
n ULONG BOARD LIST, NULL terminated
1 ULONG SigTask
1 ULONG SigBit
*/
struct IVT_TimerStruct ivtimer; /* Timer interval handling (via Interrupt) */
LONG IntSig;
ULONG SigMask; /* signal mask to wait for in server main instance */
/* config options */
ULONG timervalue; /* polling interval in ms */
ULONG fullduplex; /* force full duplex */
ULONG spispeed; /* SPI clock divider (>=1) */
ULONG multicast; /* multicast recv enable */
ULONG interrupt; /* enable interrupt */
};
/* referenced from server.c */
#if (defined PROTO_V2EXPNET)
#define HW_CONFIGFILE "ENV:SANA2/v2expeth.config"
#else
#define HW_CONFIGFILE "ENV:SANA2/sdnet.config"
#endif
#define HW_CONFIGFILE "ENV:SANA2/v2expeth.config"
/* appended to COMMON_TEMPLATE */
#define HW_CONFIGTEMPLATE "TIMER/K/N,FULLDUPLEX/S,SPISPEED/K/N,MULTICAST/S,INTERRUPT/S"
#define HW_PRODUCT "VampireV500V2 ENC28J60 ExpansionPort"
#else
#define HW_CONFIGFILE "ENV:SANA2/sdnet.config"
/* appended to COMMON_TEMPLATE */
#define HW_CONFIGTEMPLATE "TIMER/K/N,FULLDUPLEX/S,SPISPEED/K/N,MULTICAST/S"
#define HW_PRODUCT "Vampire SDNet ENC28J60"
/* appended to COMMON_TEMPLATE */
#endif
/* referenced by server.c, hw.c */
struct HWConfig
@@ -47,6 +67,7 @@ struct HWConfig
ULONG fullduplex;
ULONG *spispeed;
ULONG multicast;
ULONG interrupt;
};
#endif /* _INC_HWPRIVATE_H */