|
#define NE2000_PORT 0xc100 |
|
#define NE2000_CR NE2000_PORT+0 |
|
#define NE2000_PSTART NE2000_PORT+1 |
|
#define NE2000_PSTOP NE2000_PORT+2 |
|
#define NE2000_BNRY NE2000_PORT+3 |
|
#define NE2000_TPSR NE2000_PORT+4 |
|
#define NE2000_TBCR0 NE2000_PORT+5 |
|
#define NE2000_TBCR1 NE2000_PORT+6 |
|
#define NE2000_ISR NE2000_PORT+7 |
|
#define NE2000_CURR NE2000_PORT+7 // (!) Page:1 |
|
#define NE2000_RSAR0 NE2000_PORT+8 |
|
#define NE2000_RSAR1 NE2000_PORT+9 |
|
#define NE2000_RBCR0 NE2000_PORT+10 |
|
#define NE2000_RBCR1 NE2000_PORT+11 |
|
#define NE2000_RCR NE2000_PORT+12 |
|
#define NE2000_RSR NE2000_PORT+12 |
|
#define NE2000_TCR NE2000_PORT+13 |
|
#define NE2000_DCR NE2000_PORT+14 |
|
#define NE2000_IMR NE2000_PORT+15 |
|
#define NE2000_DATA_PORT NE2000_PORT+16 |
|
|
|
|
|
struct NE2000_RecvInfo{ |
|
|
|
u8_t status; |
|
u8_t nextPacket; |
|
u16_t length; |
|
u32_t bnry; |
|
u32_t curr; |
|
|
|
}; |
|
|
|
#if 0 |
|
typedef unsigned char u8_t; |
|
typedef unsigned short u16_t; |
|
typedef unsigned long u32_t; |
|
|
|
typedef unsigned char bool; |
|
#define true 1 |
|
#define false 0 |
|
|
|
#endif |
|
|
|
|
|
void NE2000_init (u8_t *MACAddress){ |
|
|
|
unsigned int i; |
|
|
|
|
|
// initialize |
|
asm_out8(NE2000_CR, 0x21); |
|
asm_out8(NE2000_DCR, 0x5c); |
|
asm_out8(NE2000_RBCR0, 0x00); |
|
asm_out8(NE2000_RBCR1, 0x00); |
|
asm_out8(NE2000_IMR, 0xff); |
|
asm_out8(NE2000_ISR, 0xff); |
|
asm_out8(NE2000_TCR, 0x02); |
|
asm_out8(NE2000_RCR, 0x20); |
|
asm_out8(NE2000_PSTART, 0x64); |
|
asm_out8(NE2000_PSTOP, 0x80); |
|
asm_out8(NE2000_BNRY, 0x46); |
|
asm_out8(NE2000_CR, 0x61); |
|
asm_out8(NE2000_CURR, 0x47); |
|
asm_out8(NE2000_CR, 0x21); |
|
|
|
asm_out8(NE2000_RSAR0, 0x00); |
|
asm_out8(NE2000_RSAR1, 0x00); |
|
asm_out8(NE2000_RBCR0, 12); |
|
asm_out8(NE2000_RBCR1, 0x00); |
|
asm_out8(NE2000_CR, 0x0a); |
|
|
|
// get MAC address |
|
for(i=0; i < 6; i++){ |
|
|
|
MACAddress[i] = asm_in8(NE2000_DATA_PORT); |
|
|
|
// read unnecessary data |
|
asm_in8(NE2000_DATA_PORT); |
|
} |
|
|
|
// re-initialize |
|
asm_out8(NE2000_TCR, 0x00); |
|
asm_out8(NE2000_RCR, 0x1c); |
|
asm_out8(NE2000_DCR, 0x58); |
|
|
|
return; |
|
} |
|
|
|
|
|
|
|
|
|
static void NE2000_writeBuffer (void* dataP, u16_t size, u16_t page){ |
|
|
|
int i; |
|
u8_t *data = (u8_t *) dataP; |
|
|
|
|
|
// clear RDC in ISR |
|
asm_out8(NE2000_ISR, asm_in8(NE2000_ISR)&0xbf); |
|
|
|
// write size of data to RBCR |
|
asm_out8(NE2000_RBCR0, size & 0xff); |
|
asm_out8(NE2000_RBCR1, (size>>8) & 0xff); |
|
|
|
// write page to RSAR |
|
asm_out8(NE2000_RSAR0, page & 0xff); |
|
asm_out8(NE2000_RSAR1, (page>>8) & 0xff); |
|
|
|
// set RD1 in CR |
|
asm_out8(NE2000_CR, 0x12); |
|
|
|
// write data to the buffer |
|
for(i=0; i < size; i++){ |
|
|
|
asm_out8(NE2000_DATA_PORT, data[i]); |
|
} |
|
|
|
return; |
|
} |
|
|
|
|
|
static void NE2000_readBuffer (void *dataP, u16_t size, u16_t page){ |
|
|
|
int i; |
|
u8_t *data = (u8_t *) dataP; |
|
|
|
|
|
// write size of data to RBCR |
|
asm_out8(NE2000_RBCR0, size & 0xff); |
|
asm_out8(NE2000_RBCR1, (size>>8) & 0xff); |
|
|
|
// write page to RSAR |
|
asm_out8(NE2000_RSAR0, page & 0xff); |
|
asm_out8(NE2000_RSAR1, (page>>8) & 0xff); |
|
|
|
// set RD1 to CR |
|
asm_out8(NE2000_CR, 0x0a); |
|
|
|
// read data from the buffer |
|
for(i=0; i < size; i++){ |
|
|
|
data[i] = asm_in8(NE2000_DATA_PORT); |
|
} |
|
|
|
return; |
|
} |
|
|
|
|
|
void NE2000_send (void *frame, u32 size){ |
|
|
|
|
|
// wait until transmission completed |
|
while((asm_in8(NE2000_CR))&0x04); |
|
|
|
// write frame to the buffer |
|
NE2000_writeBuffer(frame, size, 0x4000); |
|
|
|
// write origin address of written data to TPSR |
|
asm_out8(NE2000_TPSR, 0x40); |
|
|
|
// write size of frame to TBCR |
|
asm_out8(NE2000_TBCR0, size & 0xff); |
|
asm_out8(NE2000_TBCR1, (size>>8) & 0xff); |
|
|
|
// send frame |
|
asm_out8(NE2000_CR, asm_in8(NE2000_CR)|0x04); |
|
|
|
return; |
|
} |
|
|
|
|
|
static bool NE2000_receive (struct NE2000_RecvInfo *RecvInfo){ |
|
|
|
u8 curr, bnry; |
|
u8 status; |
|
u16 length; |
|
u8 nextPacket; |
|
u8 buf[1024]; |
|
|
|
asm_out8(NE2000_CR, 0x4a); |
|
curr = asm_in8(NE2000_CURR); |
|
asm_out8(NE2000_CR, 0x0a); |
|
bnry = asm_in8(NE2000_BNRY); |
|
|
|
|
|
// if BNRY+1 is not CURR, there is no received frames. |
|
if(curr == bnry+1) |
|
return false; |
|
|
|
|
|
asm_out8(NE2000_CR, 0x0a); |
|
|
|
// read first 4 bytes in the BNRY+1 page |
|
NE2000_readBuffer(buf, 4, (bnry+1)<<8); |
|
|
|
// get status, etc. |
|
status = *((u8 *) buf); |
|
nextPacket = *((u8 *) ((void *) buf+1)); |
|
length = *((u16 *) ((void *) buf+2)); |
|
|
|
// check receive status |
|
if((status&1) != 1) |
|
return false; |
|
|
|
// check length is valid |
|
if((length < 64) || (length > 1518)) |
|
return false; |
|
|
|
// update BNRY |
|
asm_out8(NE2000_BNRY, curr-1); |
|
|
|
// accept new interrupt (probably this code is not neccesary) |
|
asm_out8(NE2000_ISR, 0xff); |
|
|
|
|
|
RecvInfo->nextPacket = nextPacket; |
|
RecvInfo->status = status; |
|
RecvInfo->length = length; |
|
RecvInfo->curr = curr; |
|
RecvInfo->bnry = bnry+1; |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
void NE2000_interruptHandler (void){ |
|
|
|
char buf[1700]; |
|
unsigned int i; |
|
struct NE2000_RecvInfo RecvInfo; |
|
|
|
|
|
while(NE2000_receive(&RecvInfo)){ |
|
|
|
for(i=RecvInfo.bnry; (i < RecvInfo.nextPacket) && (i < RecvInfo.curr); i++){ |
|
|
|
NE2000_readBuffer((void *) &buf+((i-RecvInfo.bnry)*256), 256, ((i)<<8)+4); |
|
} |
|
|
|
// |
|
// |
|
// |
|
// Received Packet is in "buf". |
|
// |
|
// |
|
// |
|
|
|
} |
|
|
|
// accept new interrupt |
|
asm_out8(NE2000_ISR, 0xff); |
|
return; |
|
} |