📄 rtl8019.c
字号:
/*
* File : rtl8019.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://openlab.rt-thread.com/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2006-10-10 Qiu Yi The init version
* 2008-07-20 Bernard Modified to RT-Thread Device interface
*/
#include <rtthread.h>
#include <rtl8019.h>
#include <netif/ethernetif.h>
#define RTL8019_DEBUG(...) \
do { \
rt_kprintf("[%s:%d]", __FUNCTION__, __LINE__); \
rt_kprintf(__VA_ARGS__);rt_kprintf("\n"); \
} while(0)
struct net_device_stats
{
unsigned long rx_packets; /* total packets received */
unsigned long tx_packets; /* total packets transmitted */
unsigned long rx_errors; /* receive bad packets */
unsigned long tx_errors; /* transmit bad packets */
};
#define MAX_ADDR_LEN 6 /* Largest hardware address length */
struct rtl8019_device
{
/* inherit from ethernet device */
struct eth_device parent;
/* interface address info. */
unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */
struct net_device_stats stats;
};
struct rtl8019_device rtl8019_device;
#define ETH_ALEN 6 /* Octets in one ethernet addr */
#define ETH_HLEN 14 /* Total octets in header. */
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
static void ne_copyin(rt_uint16_t count, rt_uint8_t *buf);
static void ne_copyout(rt_uint16_t count, rt_uint8_t *buf);
static void ne_discard(rt_uint16_t count);
static rt_err_t rtl8019_init(rt_device_t dev);
static rt_err_t rtl8019_open(rt_device_t dev);
static rt_err_t rtl8019_close(rt_device_t dev);
static rt_err_t rtl8019_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
static rt_err_t rtl8019_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);
static rt_err_t rtl8019_control(rt_device_t dev, rt_uint8_t cmd, void *args);
static void rtl8019_isr(int irqno);
/*
* Read the specified number of bytes from the device DMA port into
* the supplied buffer.
*/
static void ne_copyin(rt_uint16_t count, rt_uint8_t *buf)
{
while(count--) *buf++ = NE_DMA;
}
/*
* Write the specified number of bytes from the device DMA port into
* the supplied buffer.
*/
static void ne_copyout(rt_uint16_t count, rt_uint8_t *buf)
{
while(count--) NE_DMA = *buf++;
}
/*
* Pull the specified number of bytes from the device DMA port,
* and throw them away.
*/
static void ne_discard(rt_uint16_t count)
{
rt_uint8_t value;
while(count--) value = NE_DMA;
}
/*
* RT-Thread Device Interface
*/
rt_err_t rtl8019_init(rt_device_t dev)
{
/* config in PAGE0 */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
NE_RBCR0 = 0x0;
NE_RBCR1 = 0x0;
NE_TPSR = 0x40;
NE_PSTART = 0x4c;
NE_BNRY = 0x4c;
NE_PSTOP = 0x80;
NE_ISR = 0xff;
NE_RCR = 0xcc;
NE_TCR = 0xe0;
#if DMA16
NE_DCR = 0xc9;
#else
NE_DCR = 0xc8;
#endif
NE_IMR = ISR_OVW | ISR_TXE | ISR_PTX | ISR_PRX;
/* clear all interrupts */
NE_ISR = 0xff;
/* config in PAGE1 */
NE_CR = CMD_PAGE1 | CMD_NODMA | CMD_STOP;
NE_CURR = 0x4c;
/* set MAC address */
NE_PAR0 = rtl8019_device.dev_addr[0];
NE_PAR1 = rtl8019_device.dev_addr[1];
NE_PAR2 = rtl8019_device.dev_addr[2];
NE_PAR3 = rtl8019_device.dev_addr[3];
NE_PAR4 = rtl8019_device.dev_addr[4];
NE_PAR5 = rtl8019_device.dev_addr[5];
/* get mac addr */
rtl8019_device.dev_addr[0] = NE_PAR0;
rtl8019_device.dev_addr[1] = NE_PAR1;
rtl8019_device.dev_addr[2] = NE_PAR2;
rtl8019_device.dev_addr[3] = NE_PAR3;
rtl8019_device.dev_addr[4] = NE_PAR4;
rtl8019_device.dev_addr[5] = NE_PAR5;
/* clear multicast filters (reject all multicast) */
NE_MAR0 = 0x0;
NE_MAR1 = 0x0;
NE_MAR2 = 0x0;
NE_MAR3 = 0x0;
NE_MAR4 = 0x0;
NE_MAR5 = 0x0;
NE_MAR6 = 0x0;
NE_MAR7 = 0x0;
rt_hw_interrupt_install(INT_NE, rtl8019_isr, RT_NULL);
rt_hw_interrupt_umask(INT_NE);
NE_CR = CMD_PAGE1 | CMD_NODMA | CMD_RUN;
return RT_EOK;
}
rt_err_t rtl8019_open(rt_device_t dev)
{
return RT_EOK;
}
rt_err_t rtl8019_close(rt_device_t dev)
{
/* mask all interrupts */
NE_IMR = 0;
/* clear ISR */
NE_ISR = 0xff;
/* stop nic */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
return RT_EOK;
}
struct pbuf* rtl8019_rx(rt_device_t eth)
{
rt_ubase_t level;
struct pbuf *p = RT_NULL;
rt_uint8_t curr, bnry;
rt_uint16_t packet_length, len;
rt_uint8_t pld_header[18], *payload;
/* lock interrupt */
level = rt_hw_interrupt_disable();
NE_CR = CMD_PAGE1 | CMD_NODMA | CMD_STOP;
curr = NE_CURR;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
bnry = NE_BNRY;
if(bnry > 0x7f) bnry = 0x4c;
packet_length = 0;
/* receive packet */
if (curr != bnry)
{
/* clear ISR status */
NE_ISR = ISR_RDC;
NE_RBCR1 = 0x0f;
NE_CR = CMD_PAGE0 | CMD_SEND | CMD_RUN;
NE_RSAR0 = 0;
NE_RSAR1 = bnry;
/* get the first 18 bytes from nic */
ne_copyin(18, pld_header);
/* store real length, set len to packet length - header */
/* ethernet packet header */
packet_length = ((unsigned int) pld_header[2] | (pld_header[3] << 8 ));
/* allocate pbuf from lwip mem pool */
p = pbuf_alloc(PBUF_LINK, packet_length, PBUF_POOL);
if(p != RT_NULL)
{
struct pbuf *q;
/* We iterate over the pbuf chain until we have read the entire
* packet into the pbuf.
* This assumes a minimum pbuf size of 14 ... a good assumption
*/
rt_memcpy(p->payload, pld_header + 4, 14);
for(q = p; q != RT_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. */
payload = q->payload;
len = q->len;
if (q == p)
{
/* First 14 bytes are already there, skip them */
payload += 14;
len -=14;
}
ne_copyin(len,payload);
}
}
else
{
rt_kprintf("no pbuf\n");
/* no more PBUF resource, Discard packet in buffer. */
ne_discard(packet_length-14);
}
++rtl8019_device.stats.rx_packets;
/* RTL8019_DEBUG("received %d size network packet, total %d network packets\n",
packet_length, rtl8019_device.stats.rx_packets); */
bnry = pld_header[1];
if(bnry < 0x4c) bnry = 0x7f;
NE_BNRY = bnry;
}
else
{
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
NE_ISR = ISR_PRX; /* clear interrupt */
/* open nic for next packet */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
return p;
}
rt_err_t rtl8019_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{
rt_ubase_t level;
rt_uint8_t curr, bnry;
rt_uint16_t packet_length;
rt_uint8_t pld_header[18]; /* temp storage for ethernet headers */
/* lock interrupt */
level = rt_hw_interrupt_disable();
NE_CR = CMD_PAGE1 | CMD_NODMA | CMD_STOP;
curr = NE_CURR;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
bnry = NE_BNRY;
if(bnry > 0x7f) bnry = 0x4c;
packet_length = 0;
/* receive packet */
if (curr != bnry)
{
/* clear ISR status */
NE_ISR = ISR_RDC;
NE_RBCR1 = 0x0f;
NE_CR = CMD_PAGE0 | CMD_SEND | CMD_RUN;
NE_RSAR0 = 0;
NE_RSAR1 = bnry;
/* get the first 18 bytes from nic */
ne_copyin(18, pld_header);
/* store real length, set len to packet length - header */
/* ethernet packet header */
packet_length = ((unsigned int) pld_header[2] | (pld_header[3] << 8 ));
if (packet_length > size )
{
/* no more PBUF resource, Discard packet in buffer. */
ne_discard(packet_length-14);
return -RT_ERROR;
}
// This assumes a minimum pbuf size of 14 ... a good assumption
rt_memcpy(buffer, pld_header + 4, 14);
ne_copyin(packet_length - 14, buffer + 14);
++rtl8019_device.stats.rx_packets;
/* RTL8019_DEBUG("received %d size network packet, total %d network packets\n",
packet_length, rtl8019_device.stats.rx_packets); */
bnry = pld_header[1];
if(bnry < 0x4c) bnry = 0x7f;
NE_BNRY = bnry;
}
else
{
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
NE_ISR = ISR_PRX; /* clear interrupt */
/* open nic for next packet */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
return packet_length;
}
rt_err_t rtl8019_tx(rt_device_t eth, struct pbuf* p)
{
rt_uint8_t isr;
rt_uint32_t count;
rt_ubase_t level;
struct pbuf* q;
level = rt_hw_interrupt_disable();
/* set up to transfer the packet contents to the NIC RAM. */
/* count: add pading to the size, if size < 64 */
count = p->tot_len < 64? 64 : p->tot_len;
/* close receive interrupt */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
isr = NE_IMR;
isr &= ~ISR_PRX;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
NE_IMR = isr;
NE_ISR = ISR_RDC;
/* set the length of send */
NE_RBCR0 = count & 0xff;
NE_RBCR1 = (count >> 8) & 0xff;
/* the address on NIC to store */
NE_RSAR0 = 0;
NE_RSAR1 = 0x40;
/* start to transmit */
NE_CR = CMD_PAGE0 | CMD_WRITE | CMD_RUN;
for (q = p; q != NULL; q = q->next)
ne_copyout(q->len, q->payload);
/* padding */
if (p->tot_len < 64)
{
rt_uint32_t size = p->tot_len;
/* write padding */
while (size++ < count)
{
NE_DMA = 0;
}
}
/* wait for remote dma to complete */
while((rt_uint8_t)(NE_ISR & ISR_RDC) == 0 );
/* clear RDC */
NE_ISR = ISR_RDC;
/* issue the transmit command.(start local dma) */
NE_TPSR = 0x40;
NE_TBCR0 = count & 0xff;
NE_TBCR1 = (count >> 8) & 0xff;
/* start transmission */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_XMIT | CMD_RUN;
/* reopen receive interrupt */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
isr = NE_IMR;
isr |= ISR_PRX;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
NE_IMR = isr;
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t rtl8019_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{
rt_uint8_t isr;
rt_uint32_t count;
rt_ubase_t level;
rt_kprintf("rtl8019 write buffer, size:%d\n", size);
level = rt_hw_interrupt_disable();
/* set up to transfer the packet contents to the NIC RAM. */
/* count: add pading to the size, if size < 64 */
count = size < 64? 64 : size;
/* close receive interrupt */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
isr = NE_IMR;
isr &= ~ISR_PRX;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
NE_IMR = isr;
NE_ISR = ISR_RDC;
/* set the length of send */
NE_RBCR0 = count & 0xff;
NE_RBCR1 = (count >> 8) & 0xff;
/* the address on NIC to store */
NE_RSAR0 = 0;
NE_RSAR1 = 0x40;
/* start to transmit */
NE_CR = CMD_PAGE0 | CMD_WRITE | CMD_RUN;
ne_copyout(size, (rt_uint8_t*)buffer);
if (size < 64)
{
/* write padding */
while (size++ < count)
{
NE_DMA = 0;
}
}
/* wait for remote dma to complete */
while((rt_uint8_t)(NE_ISR & ISR_RDC) == 0 );
/* clear RDC */
NE_ISR = ISR_RDC;
/* issue the transmit command.(start local dma) */
NE_TPSR = 0x40;
NE_TBCR0 = count & 0xff;
NE_TBCR1 = (count >> 8) & 0xff;
/* start transmission */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_XMIT | CMD_RUN;
/* reopen receive interrupt */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
isr = NE_IMR;
isr |= ISR_PRX;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
NE_IMR = isr;
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t rtl8019_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
switch(cmd)
{
case NIOCTL_GADDR:
/* get mac address */
if(args) rt_memcpy(args, rtl8019_device.dev_addr, 6);
else return -RT_ERROR;
break;
default :
break;
}
return RT_EOK;
}
/**
* This function will register realtek 8019 ethernet interface
*/
int rtl8019_device_register(char* name)
{
rt_err_t result;
/* init rt-thread device interface */
rtl8019_device.parent.parent.init = rtl8019_init;
rtl8019_device.parent.parent.open = rtl8019_open;
rtl8019_device.parent.parent.close = rtl8019_close;
rtl8019_device.parent.parent.read = rtl8019_read;
rtl8019_device.parent.parent.write = rtl8019_write;
rtl8019_device.parent.parent.control = rtl8019_control;
rtl8019_device.parent.eth_rx = rtl8019_rx;
rtl8019_device.parent.eth_tx = rtl8019_tx;
/* set MAC address */
rtl8019_device.dev_addr[0] = 0x0;
rtl8019_device.dev_addr[1] = 0x1;
rtl8019_device.dev_addr[2] = 0x2;
rtl8019_device.dev_addr[3] = 0x3;
rtl8019_device.dev_addr[4] = 0x4;
rtl8019_device.dev_addr[5] = 0x5;
/* init rtl8019 device as ethernet interface */
result = eth_device_init(&(rtl8019_device.parent), (char*)name);
RT_ASSERT(result == RT_EOK);
return result;
}
/*
* The realtek 8019 ethernet interface interrupt service rountine
*/
static void rtl8019_isr(int irqno)
{
rt_uint8_t isr, curr;
/* close nic */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
isr = NE_ISR;
//RTL8019_DEBUG("rtl8019 ISR coming\n");
/* if ram overflow interrupt */
if (isr & ISR_OVW )
{
RTL8019_DEBUG("overflow");
/* clear interrupt */
NE_ISR = ISR_OVW;
}
/* if Tx error, NIC abort tx due to excessive collisions */
if (isr & ISR_TXE)
{
RTL8019_DEBUG("Tx error");
/* clear interrupt */
NE_ISR = ISR_TXE;
rtl8019_device.stats.tx_errors ++;
}
/* if Rx error , reset BNRY pointer to CURR (use SEND PACKET mode) */
if (isr & ISR_RXE)
{
RTL8019_DEBUG("Rx error");
/* clear interrupt */
NE_ISR = ISR_RXE;
NE_CR = CMD_PAGE1 | CMD_NODMA | CMD_STOP;
curr = NE_CURR;
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
NE_BNRY = curr;
rtl8019_device.stats.rx_errors ++;
}
/* no errors */
if (isr & ISR_PRX)
{
//RTL8019_DEBUG("Receive a packet, add a net task job");
NE_ISR = ISR_PRX; /* clear interrupt */
/* notify device ready to ethernet task */
eth_device_ready((struct rt_device*)&rtl8019_device);
}
/* Transfer complete, do nothing here */
if( isr & ISR_PTX)
{
//RTL8019_DEBUG("Transfer complete");
/* clear interrupt */
NE_ISR = ISR_PTX;
rtl8019_device.stats.tx_packets++;
}
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_STOP;
/* clear interrupt */
NE_ISR = 0xff;
/* open nic for next packet */
NE_CR = CMD_PAGE0 | CMD_NODMA | CMD_RUN;
// RTL8019_DEBUG("Open rtl8019 ISR again");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -