lwip-contrib-mac/ports/old/ti_c6711/netif/ne2kif.c
2007-06-14 12:33:39 +00:00

637 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*********************************************************************************************************
* lwIP TCP/IP Stack
* port for uC/OS-II RTOS on TIC6711 DSK
*
* File : tcp_ip.c
* By : ZengMing @ DEP,Tsinghua University,Beijing,China
* Reference: YangYe's source code for SkyEye project
*********************************************************************************************************
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include <lwip/stats.h>
#include "netif/etharp.h"
#include "netif/ne2kif.h"
/* define this to use QDMA, which is much faster! */
#define QDMA_Enabled
/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 't'
struct ne2k_if {
struct eth_addr *ethaddr; //MAC Address
};
struct netif *ne2k_if_netif;
/*----------------------------------------------------------------------------------------
****************************************************************************************
----------------------------------------------------------------------------------------*/
/*
* ethernetif_init():
*
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
*/
err_t ne2k_init(struct netif *netif)
{
struct ne2k_if *ne2k_if;
ne2k_if = mem_malloc(sizeof(struct ne2k_if));//MAC Address
if (ne2k_if == NULL)
{
LWIP_DEBUGF(NETIF_DEBUG,("ne2k_init: out of memory!\n"));
return ERR_MEM;
}
netif->state = ne2k_if;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = etharp_output;
netif->linkoutput = low_level_output;
ne2k_if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
low_level_init(netif);
etharp_init();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
return ERR_OK;
}
/**
* arp_timer.
*/
static void arp_timer(void *arg)
{
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL);
}
/**
* Initialize the ne2k ethernet chip, resetting the interface and getting the ethernet
* address.
*/
static void low_level_init(struct netif * netif)
{
u16_t i;
struct ne2k_if *ne2k_if;
ne2k_if = netif->state;
// the meaning of "netif->state" can be defined in drivers, here for MAC address!
netif->hwaddr_len=6;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST;
// ---------- start -------------
*(u32_t *)EMIF_CE2 = 0x11D4C714; // Set CE2 to 16bits mode,
// AX88796 required no less than 160ns period
i = EN_RESET; //this instruction let NE2K chip soft reset
for (i=0;i<DELAY_MS;i++); //wait
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP);
EN0_DCFG = (u8_t) 0x01;
/* Clear the remote byte count registers. */
EN0_RCNTHI = (u8_t) 0x00; /* MSB remote byte count reg */
EN0_RCNTLO = (u8_t) 0x00; /* LSB remote byte count reg */
/* RX configuration reg Monitor mode (no packet receive) */
EN0_RXCR = (u8_t) ENRXCR_MON;
/* TX configuration reg set internal loopback mode */
EN0_TXCR = (u8_t) ENTXCR_LOOP;
EN0_TPSR = (u8_t) 0x40; //<2F><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD>׵<EFBFBD>ַ <20><>СΪ6ҳ<36><D2B3><EFBFBD>պ<EFBFBD><D5BA><EFBFBD>1<EFBFBD><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//Ϊ0x40-0x46
EN0_STARTPG = (u8_t) 0x46 ; /* <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD> 47<34><37>Starting page of ring buffer. First page of Rx ring buffer 46h*/
EN0_BOUNDARY = (u8_t) 0x46 ; /* Boundary page of ring buffer 0x46*/
EN0_STOPPG = (u8_t) 0x80 ; /* Ending page of ring buffer ,0x80*/
EN0_ISR = (u8_t) 0xff; /* clear the all flag bits in EN0_ISR */
EN0_IMR = (u8_t) 0x00; /* Disable all Interrupt */
EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_STOP);
EN1_CURR = (u8_t) 0x47; /* keep curr=boundary+1 means no new packet */
EN1_PAR0 = (u8_t)0x12;// MAC_addr.addr[0]; //<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>mac<61><63>ַ
EN1_PAR1 = (u8_t)0x34;// MAC_addr.addr[1];
EN1_PAR2 = (u8_t)0x56;// MAC_addr.addr[2];
EN1_PAR3 = (u8_t)0x78;// MAC_addr.addr[3];
EN1_PAR4 = (u8_t)0x9a;// MAC_addr.addr[4];
EN1_PAR5 = (u8_t)0xe0;// MAC_addr.addr[5];
/* make up an address. */
ne2k_if->ethaddr->addr[0] = (u8_t) 0x12;//MAC_addr.addr[0];
ne2k_if->ethaddr->addr[1] = (u8_t) 0x34;//MAC_addr.addr[1];
ne2k_if->ethaddr->addr[2] = (u8_t) 0x56;//MAC_addr.addr[2];
ne2k_if->ethaddr->addr[3] = (u8_t) 0x78;//MAC_addr.addr[3];
ne2k_if->ethaddr->addr[4] = (u8_t) 0x9a;//MAC_addr.addr[4];
ne2k_if->ethaddr->addr[5] = (u8_t) 0xe0;//MAC_addr.addr[5];
/* Initialize the multicast list to reject-all.
If we enable multicast the higher levels can do the filtering.
<multicast filter mask array (8 bytes)> */
EN1_MAR0 = (u8_t) 0x00;
EN1_MAR1 = (u8_t) 0x00;
EN1_MAR2 = (u8_t) 0x00;
EN1_MAR3 = (u8_t) 0x00;
EN1_MAR4 = (u8_t) 0x00;
EN1_MAR5 = (u8_t) 0x00;
EN1_MAR6 = (u8_t) 0x00;
EN1_MAR7 = (u8_t) 0x00;
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP);
EN0_IMR = (u8_t) (ENISR_OVER + ENISR_RX + ENISR_RX_ERR);
EN0_TXCR = (u8_t) 0x00; //E0 //TCR
EN0_RXCR = (u8_t) 0x44; //CC //RCR
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START);
EN0_ISR = (u8_t) 0xff; // clear the all flag bits in EN0_ISR
ne2k_if_netif = netif;
}
/*----------------------------------------------------------------------------------------
****************************************************************************************
----------------------------------------------------------------------------------------*/
/*
* low_level_output():
*
* Should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
*/
static err_t low_level_output(struct netif * netif, struct pbuf *p)
{
struct pbuf *q;
u16_t packetLength,remote_Addr,Count;
u8_t *buf;
packetLength = p->tot_len - ETH_PAD_SIZE; //05 01 millin
if ((packetLength) < 64) packetLength = 64; //add pad by the AX88796 automatically
// turn off RX int
EN0_IMR = (u8_t) (ENISR_OVER);
/* We should already be in page 0, but to be safe... */
EN_CMD = (u8_t) (EN_PAGE0 + EN_START + EN_NODMA);
// clear the RDC bit
EN0_ISR = (u8_t) ENISR_RDC;
remote_Addr = (u16_t)(TX_START_PG<<8);
/*
* Write packet to ring buffers.
*/
for(q = p; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
Count = q->len;
buf = q->payload;
if (q == p){
buf += ETH_PAD_SIZE;
Count -= ETH_PAD_SIZE;//Pad in Eth_hdr struct
}
// Write data to AX88796
remote_Addr = write_AX88796(buf, remote_Addr, Count);
} //for
/* Just send it, and does not check */
while (EN_CMD & EN_TRANS);
EN0_TPSR = (u8_t) TX_START_PG;
EN0_TCNTLO = (u8_t) (packetLength & 0xff);
EN0_TCNTHI = (u8_t) (packetLength >> 8);
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_TRANS + EN_START);
EN0_IMR = (u8_t) (ENISR_OVER + ENISR_RX + ENISR_RX_ERR);
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
return ERR_OK;
}
/**
* write_AX88796.
*/
u16_t write_AX88796(u8_t * buf, u16_t remote_Addr, u16_t Count)
{
#ifndef QDMA_Enabled
u16_t loop;
#endif
/* AX88796. */
EN0_RCNTLO = (u8_t) ( Count & 0xff);
EN0_RCNTHI = (u8_t) ( Count >> 8);
EN0_RSARLO = (u8_t) ( remote_Addr & 0xff);
EN0_RSARHI = (u8_t) ( remote_Addr >> 8);
EN_CMD = (u8_t) (EN_RWRITE + EN_START + EN_PAGE0);
// Add for next loop...
remote_Addr += Count;
Count = (Count + 1) >> 1; // Turn to 16bits count. <Must add 1 first!>
#ifdef QDMA_Enabled
*(u32_t *)QDMA_SRC = (u32_t) buf;
*(u32_t *)QDMA_DST = (u32_t) &EN_DATA;
*(u32_t *)QDMA_CNT = (u32_t) Count;
*(u32_t *)QDMA_IDX = 0x00000000;
*(u32_t *)QDMA_S_OPT = 0x29000001;
#else
for (loop=0;loop < Count ;loop++){
EN_DATA = *(u16_t *)buf;
buf += 2;
}
#endif //QDMA_Enabled
while ((EN0_ISR & ENISR_RDC) == 0);
EN0_ISR = (u8_t) ENISR_RDC;
return remote_Addr;
}
/*----------------------------------------------------------------------------------------
****************************************************************************************
----------------------------------------------------------------------------------------*/
/*
* ethernetif_input():
*
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface.
*
*/
static void
ne2k_input(struct netif *netif)
{
struct ne2k_if *ne2k_if;
struct eth_hdr *ethhdr;
struct pbuf *p;
ne2k_if = netif->state;
/* move received packet into a new pbuf */
p = low_level_input(netif);
/* no packet could be read, silently ignore this */
if (p == NULL) return;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
switch(htons(ethhdr->type)) {
/* IP packet? */
case ETHTYPE_IP:
/* update ARP table */
etharp_ip_input(netif, p);
/* skip Ethernet header */
pbuf_header(p, -(14+ETH_PAD_SIZE));
/* pass to network layer */
netif->input(p, netif);
break;
case ETHTYPE_ARP:
/* pass p to ARP module */
etharp_arp_input(netif, ne2k_if->ethaddr, p);
break;
default:
pbuf_free(p);
p = NULL;
break;
}
}
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
static struct pbuf *
low_level_input(struct netif *netif)
{
u16_t packetLength, Count, remote_Addr;
u8_t *buf, PDHeader[4];
u8_t curr, this_frame, next_frame;
struct pbuf *p, *q, *r;
EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_START);
curr = (u8_t) EN1_CURR;
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START);
this_frame = (u8_t) EN0_BOUNDARY + 1;
if (this_frame >= RX_STOP_PG)
this_frame = RX_START_PG;
//---------- get the first 4 bytes from AX88796 ---------
(void) read_AX88796(PDHeader, (u16_t)(this_frame<<8), 4);
//----- Store real length, set len to packet length - header ---------
packetLength = ((unsigned) PDHeader[2] | (PDHeader[3] << 8 )) - 4; // minus PDHeader[4]
next_frame = (u8_t) (this_frame + 1 + ((packetLength + 4) >> 8));
// Bad frame!
if ((PDHeader[1] != (u8_t)next_frame) && (PDHeader[1] != (u8_t)(next_frame + 1))
&& (PDHeader[1] != (u8_t)(next_frame - RX_STOP_PG + RX_START_PG))
&& (PDHeader[1] != (u8_t)(next_frame + 1 - RX_STOP_PG + RX_START_PG)))
{
EN0_BOUNDARY = (u8_t) (curr - 1);
return NULL;
}
// Bogus Packet Size
if (packetLength > MAX_PACKET_SIZE || packetLength < MIN_PACKET_SIZE)
{
next_frame = PDHeader[1];
EN0_BOUNDARY = (u8_t) (next_frame-1);
return NULL;
}
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START);
EN0_ISR = (u8_t) ENISR_RDC; // clear the RDC bit
remote_Addr = (u16_t)((this_frame << 8) + 4);
if ((remote_Addr + packetLength + ETH_PAD_SIZE) > (u16_t)(RX_STOP_PG<<8)) {
p = pbuf_alloc(PBUF_RAW, (u16_t)(RX_STOP_PG<<8) - remote_Addr, PBUF_POOL); /* length of buf */
packetLength -= (u16_t)(RX_STOP_PG<<8) - remote_Addr - ETH_PAD_SIZE;
} else {
p = pbuf_alloc(PBUF_RAW, packetLength+ETH_PAD_SIZE, PBUF_POOL); /* length of buf */
packetLength = 0;
}
if(p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */
for(q = p; q != NULL; q= q->next){ /* Read enough bytes to fill this pbuf in the chain. The avaliable data in the pbuf is given by the q->len variable. */
buf = q->payload;
Count = q->len;
if (q == p){ // if it's the first pbuf in chain...
buf += ETH_PAD_SIZE;
Count -= ETH_PAD_SIZE; // pad in Eth_hdr struct
}
remote_Addr = read_AX88796(buf, remote_Addr, Count);
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
} //for(q = p; q != NULL; q= q->next)
} //if(p != NULL)
else
{ // p == NULL
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif /* LINK_STATS */
}
if (packetLength) // ring buffer cycled
{
remote_Addr = (u16_t)(RX_START_PG << 8);
r = pbuf_alloc(PBUF_RAW, packetLength, PBUF_POOL); /* length of buf */
if(r != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */
for(q = r; q != NULL; q= q->next){ /* Read enough bytes to fill this pbuf in the chain. The avaliable data in the pbuf is given by the q->len variable. */
buf = q->payload;
Count = q->len;
remote_Addr = read_AX88796(buf, remote_Addr, Count);
} //for
// link pbuf p & r
pbuf_cat(p, r);
}
else // r == NULL
{
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
}
} // if (packetLength)
next_frame = PDHeader[1];
EN0_BOUNDARY = (u8_t) (next_frame-1);
return p;
}
/**
* read_AX88796.
*/
u16_t read_AX88796(u8_t * buf, u16_t remote_Addr, u16_t Count)
{
u8_t flagOdd=0;
#ifndef QDMA_Enabled
u16_t loop;
#endif
flagOdd = (Count & 0x0001); // set Flag if Count is odd.
Count -= flagOdd;
EN0_RCNTLO = (u8_t) (Count & 0xff);
EN0_RCNTHI = (u8_t) (Count >> 8);
EN0_RSARLO = (u8_t) (remote_Addr & 0xff);
EN0_RSARHI = (u8_t) (remote_Addr >> 8);
EN_CMD = (u8_t) (EN_PAGE0 + EN_RREAD + EN_START);
remote_Addr += Count;
Count = Count>>1;
#ifdef QDMA_Enabled
*(u32_t *)QDMA_SRC = (u32_t) &EN_DATA;
*(u32_t *)QDMA_DST = (u32_t) buf;
*(u32_t *)QDMA_CNT = (u32_t) Count;
*(u32_t *)QDMA_IDX = 0x00000000;
*(u32_t *)QDMA_S_OPT = 0x28200001;
buf += Count*2;
#else
for (loop=0;loop < Count ;loop++){
*(u16_t *)buf = EN_DATA ;
buf += 2;
}
#endif //QDMA_Enabled
while ((EN0_ISR & ENISR_RDC) == 0);
EN0_ISR = (u8_t) ENISR_RDC;
if (flagOdd) {
EN0_RCNTLO = 0x01;
EN0_RCNTHI = 0x00;
EN0_RSARLO = (u8_t) (remote_Addr & 0xff);
EN0_RSARHI = (u8_t) (remote_Addr >> 8);
EN_CMD = (u8_t) (EN_PAGE0 + EN_RREAD + EN_START);
remote_Addr += 1;
*(u8_t *)buf = *(u8_t *)(Base_ADDR+0x10) ;
while ((EN0_ISR & ENISR_RDC) == 0);
EN0_ISR = (u8_t) ENISR_RDC;
}
return remote_Addr;
}
/*----------------------------------------------------------------------------------------
****************************************************************************************
----------------------------------------------------------------------------------------*/
/**
* ne2k_rx_err.
*/
void ne2k_rx_err(void)
{
u8_t curr;
EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_STOP);
curr = (u8_t) EN1_CURR;
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP);
EN0_BOUNDARY = (u8_t) curr-1;
}
/**
* ne2k_rx.
*/
void ne2k_rx(void)
{
u8_t curr,bnry,loopCnt = 0;
while(loopCnt < 10) {
EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_STOP);
curr = (u8_t) EN1_CURR;
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP);
bnry = (u8_t) EN0_BOUNDARY + 1;
if (bnry >= RX_STOP_PG)
bnry = RX_START_PG;
if (curr == bnry) break;
ne2k_input(ne2k_if_netif);
loopCnt++;
}
}
/*---*---*---*---*---*---*---*
* void ne2k_isr(void)
* can be int 4 5 6 or 7
*---*---*---*---*---*---*---*/
void ne2k_isr(void)
{
DSP_C6x_Save();
OSIntEnter();
if (OSIntNesting == 1)
{
OSTCBCur->OSTCBStkPtr = (OS_STK *) DSP_C6x_GetCurrentSP();
}
/* You can enable Interrupt again here,
if want to use nested interrupt..... */
//------------------------------------------------------------
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP);
//outb(CMD_PAGE0 | CMD_NODMA | CMD_STOP,NE_CR);
EN0_IMR = (u8_t) 0x00;//close
// ram overflow interrupt
if (EN0_ISR & ENISR_OVER) {
EN0_ISR = (u8_t) ENISR_OVER; // clear interrupt
}
// error transfer interrupt ,NIC abort tx due to excessive collisions
if (EN0_ISR & ENISR_TX_ERR) {
EN0_ISR = (u8_t) ENISR_TX_ERR; // clear interrupt
//temporarily do nothing
}
// Rx error , reset BNRY pointer to CURR (use SEND PACKET mode)
if (EN0_ISR & ENISR_RX_ERR) {
EN0_ISR = (u8_t) ENISR_RX_ERR; // clear interrupt
ne2k_rx_err();
}
//got packet with no errors
if (EN0_ISR & ENISR_RX) {
EN0_ISR = (u8_t) ENISR_RX;
ne2k_rx();
}
//Transfer complelte, do nothing here
if (EN0_ISR & ENISR_TX){
EN0_ISR = (u8_t) ENISR_TX; // clear interrupt
}
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP);
EN0_ISR = (u8_t) 0xff; // clear ISR
EN0_IMR = (u8_t) (ENISR_OVER + ENISR_RX + ENISR_RX_ERR);
//open nic for next packet
EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START);
if (led_stat & 0x04) {LED3_on;}
else {LED3_off;}
//--------------------------------------------------------
OSIntExit();
DSP_C6x_Resume();
asm (" nop 5"); //important!
// this can avoid a stack error when compile with the optimization!
}