移植网络驱动程序。在netif文件夹下有ethernetif.c,就是网络芯片的驱动程序,需要对照实际使用的网络芯片修改。下面是DM9000A的在lwip下的驱动的程序。
/* Define those to better describe your network interface. */
#define IFNAME0 ‘d’
#define IFNAME1 ‘m’
#define NIC_BASE 0x82000000
#define NIC_REG_ADDR (*(volatile u8_t *) 0x82000000)
/* if cmd link to system bus A2 */
#define NIC_REG_DATA_byte (*(volatile u8_t *) 0x82000004)
#define NIC_REG_DATA_word (*(volatile u16_t *) 0x82000004)
/* for dm9000a function setting */
#define Fix_Note_Address
#define DM9000A_FLOW_CONTROL
#define Rx_Int_enable
static void low_level_init(struct netif * netif);
static err_t low_level_output(struct netif * netif,struct pbuf *p);
static void ethernetif_input(struct netif *netif);
struct pbuf * low_level_input(struct netif *netif);
u16_t DM9000A_Phy_Read (u8_t offset);
void udelay(u32_t time)
{
//wait_1us(time);
while (–time > 0);
}
u8_t ior(u8_t reg_addr)
{
NIC_REG_ADDR = reg_addr;
return (NIC_REG_DATA_byte);
}
Void iow(u8_t reg_addr, u8_t reg_data)
{
NIC_REG_ADDR = reg_addr;
NIC_REG_DATA_byte = reg_data;
}
/*
* 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 ethernetif_init(struct netif *netif)
{
IO0SET = (1 << DM9000A_RST); //硬件复位
udelay(30);
IO0CLR = (1 << DM9000A_RST);
udelay(30000);
IO0SET = (1 << DM9000A_RST);
udelay(1000);
if(!dm9k_found())
{
LWIP_DEBUGF(NETIF_DEBUG,(“ethernetif_init: no device can use !\n”));
return ERR_MEM;
}
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = etharp_output;
netif->linkoutput = low_level_output;
netif->hwaddr[0] = my_mac[0];
netif->hwaddr[1] = my_mac[1];
netif->hwaddr[2] = my_mac[2];
netif->hwaddr[3] = my_mac[3];
netif->hwaddr[4] = my_mac[4];
netif->hwaddr[5] = my_mac[5];
netif->hwaddr_len = 6;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
low_level_init(netif);
return ERR_OK;
}
/**
* dm9k ethernet chip found
*/
u8_t dm9k_found(void)
{
u32_t check_id;
check_id = ior(DM9000_REG_VID_L);
check_id |= ior(DM9000_REG_VID_H) << 8;
check_id |= ior(DM9000_REG_PID_L) << 16;
check_id |= ior(DM9000_REG_PID_H) << 24;
LWIP_DEBUGF(NETIF_DEBUG,(“dm9k_debug : check_id = %0x , vid = %0x !\n”, check_id , DM9000_ID));
if(check_id != DM9000_ID)
{
LWIP_DEBUGF(NETIF_DEBUG,(“dm9k_found: not found device !\n”));
return 0;
}
else
{
LWIP_DEBUGF(NETIF_DEBUG,(“dm9k_found: found device !!\n”));
return 1;
}
}
/**
* Initialize the dm9k ethernet chip, resetting the interface and getting the ethernet
* address.
*/
static void low_level_init(struct netif * netif)
{
u8_t i;
u16_t reg_val,j;
/* soft reset device 2 time*/
iow(DM9000_REG_NCR, DM9000_REG_RESET);
udelay(20); /* delay 10us */
iow(DM9000_REG_NCR, DM9000_REG_RESET);
udelay(20); /* delay 10us */
for(i = 0; i < 6; i++)
{
iow(DM9000_REG_PAR + i, my_mac[i]);
}
for(i = 0; i < 8; i++)
{
if(i < 7)
iow(DM9000_REG_MAR + i, 0x00);
else
iow(DM9000_REG_MAR + i, 0x80);
}
dm9k_reset();
iow(DM9000_REG_GPCR, 0x01);
iow(DM9000_REG_GPR, DM9000_PHY_OFF);
udelay(500000); /* dealy 0.5s */
iow(DM9000_REG_GPR, DM9000_PHY_ON);
udelay(500000); /* delay 0.5s */
dm9k_phy_write(0x00, 0x8000);
#ifdef DM9000A_FLOW_CONTROL
dm9k_phy_write(0x04, 0x01e1 | 0x0400);
#else
dm9k_phy_write(0x04, 0x01e1);
#endif
dm9k_phy_write(0x00, 0x1200);
iow(DM9000_REG_GPR, DM9000_PHY_ON);
}
/**
* dm9k ethernet chip soft_reset
*/
Void dm9k_reset(void)
{
LWIP_DEBUGF(NETIF_DEBUG,(“dm9k_reset: dm9k ethernet chip soft_reset !\n”));
/* soft reset device 2 time*/
iow(DM9000_REG_NCR, DM9000_REG_RESET);
udelay(20); /* delay 10us */
iow(DM9000_REG_NCR, DM9000_REG_RESET);
udelay(20); /* delay 10us */
/* Program operating register */
iow(DM9000_REG_TCR, 0x00); /* TX Polling clear */
iow(DM9000_REG_SMCR, 0x00); /* Special Mode */
iow(DM9000_REG_NSR, 0x2c); /* clear TX status */
iow(DM9000_REG_ISR, 0x0f); /* Clear interrupt status */
iow(DM9000_REG_TCR2, DM9000_TCR2_SET); /* LED mode */
iow(0x31, 0x07);
#ifdef DM9000A_FLOW_CONTROL
iow(DM9000_REG_BPTR, DM9000_BPTR_SET); /* Less 3Kb, 200us */
iow(DM9000_REG_FCTR, DM9000_FCTR_SET); /* Flow Control : High/Low Water */
iow(DM9000_REG_FCR, DM9000_FCR_SET); /* Flow Control */
#endif
/* Activate DM9000 */
iow(DM9000_REG_IMR, DM9000_IMR_OFF); /* Set FIFO AUTO_RETURN */
iow(DM9000_REG_RCR, DM9000_RCR_SET); /* RX enable */
#ifdef Rx_Int_enable
iow(DM9000_REG_IMR, DM9000_IMR_SET); /* Enable TX/RX interrupt mask */
#endif
}
/**
* phy write regisger data
*
*/
void dm9k_phy_write(u8_t phy_reg, u16_t reg_data)
{
u8_t t = 0;
iow(DM9000_REG_EPAR, phy_reg | DM9000_PHY);
/* 设置写入PHY寄存器的值 */
iow(DM9000_REG_EPDRH, (reg_data >> 8) & 0xff);
iow(DM9000_REG_EPDRL, reg_data & 0xff);
iow(DM9000_REG_EPCR, 0x0a);
while(ior(DM9000_REG_EPCR) & 0x01)
{
if( t++ > 200)
{
break;
}
udelay(100);
};
iow(DM9000_REG_EPCR, 0x08);
}
/*
* 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;
u8_t *tx_buf;
u16_t tx_count,calc_MWR;
u8_t mwrl,mwrh,mwrl1,mwrh1;
/* Disable all interrupt*/
iow(DM9000_REG_IMR, DM9000_IMR_OFF);
while(ior(DM9000_REG_TCR) & DM9000_TCR_SET)
{
LWIP_DEBUGF(NETIF_DEBUG,(“low_level_output: wait to TX complete !\n”));
udelay(10);
};
packetLength = p->tot_len – ETH_PAD_SIZE;
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.*/
tx_buf = q->payload;
tx_count = q->len;
if (ETH_PAD_SIZE)
{
if(q == p)
{
tx_buf += ETH_PAD_SIZE;
tx_count -= ETH_PAD_SIZE;
}
}
outsw((u16_t *)tx_buf, tx_count);
}
/* Set TX length to DM9000 */
iow(DM9000_REG_TXPLH, (packetLength >> 8) & 0xff);
iow(DM9000_REG_TXPLL, packetLength & 0xff);
iow(DM9000_REG_TCR, DM9000_TCR_SET); /* Cleared after TX complete */
/* Enable interrupt*/
iow(DM9000_REG_IMR, DM9000_IMR_SET);
return ERR_OK;
}
/**
* outsw
*/
void outsw(u16_t* p, u16_t len)
{
u16_t i, j;
len = (len + 1) >> 1;
NIC_REG_ADDR = DM9000_REG_MWCMD;
for (i = 0; i < len; i++)
{
j = *p++;
NIC_REG_DATA_word = j;
// udelay(10);
}
}
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
struct pbuf * low_level_input(struct netif *netif)
{
u8_t rx_checkbyte;
u16_t rx_status, rx_len;
u8_t mrrh, mrrl;
u16_t calc_mrr;
struct pbuf *p, *q;
u8_t *rx_buf;
u16_t rx_count;
/* Disable all interrupt*/
iow(DM9000_REG_IMR, DM9000_IMR_OFF);
ior(DM9000_REG_MRCMDX);
mrrh = ior(DM9000_REG_MRRH);
mrrl = ior(DM9000_REG_MRRL);
rx_checkbyte = ior(DM9000_REG_MRCMDX);
if(rx_checkbyte == DM9000_PKT_RDY)
{
NIC_REG_ADDR = DM9000_REG_MRCMD;
rx_status = NIC_REG_DATA_word;
rx_len = NIC_REG_DATA_word;
if(rx_len > DM9000_PKT_MAX || rx_status & 0xbf00)
{
dm9k_reset();
iow(DM9000_REG_IMR, DM9000_IMR_SET);
return NULL;
}
calc_mrr = (mrrh << 8) | mrrl;
calc_mrr += (rx_len + 4);
if(rx_len & 0x01) calc_mrr++;
if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;
p = pbuf_alloc(PBUF_RAW, rx_len +ETH_PAD_SIZE, PBUF_POOL);
if(p == NULL)
{
/* 将指针移到下一个包的包头位置 */
iow (DM9000_REG_MRRH, (calc_mrr >> 8) & 0xff);
iow (DM9000_REG_MRRL, calc_mrr & 0xff );
iow(DM9000_REG_IMR, DM9000_IMR_SET);
return NULL;
}
else
{
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.
*/
rx_buf = q->payload;
if (rx_len < q->len)
rx_count = rx_len;
else
rx_count = q->len;
if (ETH_PAD_SIZE)
{
if (q == p)
{
rx_buf += ETH_PAD_SIZE;
if (q->next != NULL) rx_count -= ETH_PAD_SIZE;
}
}
insw((u16_t *)rx_buf, rx_count); // 从DM9008A中读入数据包
rx_len -= rx_count;
}
iow(DM9000_REG_IMR, DM9000_IMR_SET);
return p;
}
}
else
{
if(rx_checkbyte == DM9000_PKT_NORDY)
{
iow(DM9000_REG_ISR, 0x3f); /* Clear ISR status */
}
else
{
dm9k_reset();
}
iow(DM9000_REG_IMR, DM9000_IMR_SET);
return NULL;
}
}
/**
* insw
*/
Void insw(u16_t* p, u16_t len)
{
u16_t i, j;
len = (len + 1) >> 1;
NIC_REG_ADDR = DM9000_REG_MRCMD;
for (i = 0; i < len; i++)
{
j = NIC_REG_DATA_word;
*p++ = j;
}
}
/*
* dm9k_Interrupt():
*
*/
void dm9000a_Interrupt(void)
{
u8_t isr_status, savedReg;
/* Save previous register address*/
savedReg = NIC_REG_ADDR;
/* Disable all interrupt*/
iow(DM9000_REG_IMR, DM9000_IMR_OFF);
/* Got DM9000 interrupt status*/
isr_status = ior(DM9000_REG_ISR); /* Got ISR*/
iow(DM9000_REG_ISR, isr_status); /* Clear ISR status */
/* Received the coming packet*/
if (isr_status & DM9000_RX_INTR)
{
OSSemPost(SemEthernetInt); //接收到中断,发送信号量
}
iow(DM9000_REG_IMR, DM9000_IMR_SET);
NIC_REG_ADDR = savedReg;
}