📄 et9000if.c
字号:
hash_table[3] = 0x8000;
/* the multicast address in Hash Table : 64 bits */
for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
hash_val = cal_CRC((unsigned char *)mcptr->dmi_addr, 6, 0) & 0x3f;
hash_table[hash_val / 16] |= (u16_t) 1 << (hash_val % 16);
}
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
iow(oft++, hash_table[i] & 0xff);
iow(oft++, (hash_table[i] >> 8) & 0xff);
}
}
static void dm9000XmitDone(Dm9000if_t *db)
{
// int tx_status = ior(0x01); /* Got TX status */
// if (tx_status & 0xc) {
/* One packet sent complete */
db->tx_pkt_cnt--;
// Queue packet check & send
if (db->tx_pkt_cnt > 0) {
iow(0xfc, db->queue_pkt_len & 0xff);
iow(0xfd, (db->queue_pkt_len >> 8) & 0xff);
iow(0x2, 0x1);
}
// }
}
// DM9000 NIC low level functions___________________________________________________
static void dm9000Interrupt(Dm9000if_t *ethernetif)
{
int status;
u8_t savedReg;
// Save previous register address
savedReg = inb(DM9000_INDEX);
// Disable all interrupt
iow(0xff, 0x80);
// Got DM9000 interrupt status
status = ior(0xfe); // Got ISR
iow(0xfe, status); // Clear ISR status
// Received the coming packet
if (status & DM9000_RX_INTR) {
if (ethernetif->rxEmpty) {
ethernetif->rxEmpty = 0;
QPut(THREAD_LWIP, MSGPRIO_NORMAL, MSG_ETH_RECEIVE, 0);
}
}
// Transmit Interrupt check
if (status & DM9000_TX_INTR) {
dm9000XmitDone(ethernetif);
// QPut(THREAD_LWIP, MSGPRIO_NORMAL, MSG_ETH_TRANSMIT, 0);
}
// Re-enable interrupt mask
iow(0xff, 0x83);
// Restore previous register address
outb(savedReg, DM9000_INDEX);
}
static void dm9000if_low_level_init(struct netif *netif)
{
int i;
u8_t io_mode;
Dm9000if_t *ethernetif = (Dm9000if_t *)netif->state;
//set MAC hardware address length
netif->hwaddr_len = 6;
// set MAC hardware address
for(i = 0; i < 6; i++)
ethernetif->ethaddr.addr[i] =sys.mac[5 - i];
memcpy(netif->hwaddr, ethernetif->ethaddr.addr, netif->hwaddr_len);
// maximum transfer unit
netif->mtu = 1500;
// broadcast capability
netif->flags = NETIF_FLAG_BROADCAST;
/* RESET device */
iow(0, 1);
udelay(100); /* delay 100us */
/* Probe the board */
dmfe_probe(ethernetif);
/* I/O mode */
io_mode = ior(0xfe) >> 6; /* ISR bit7:6 keeps I/O mode */
/* NIC Type: FASTETHER, HOMERUN, LONGRUN */
identify_nic(ethernetif);
/* GPIO0 on pre-activate PHY */
iow(0x1f,0x00); /*REG_1F bit0 activate phyxcer*/
/* Set PHY */
ethernetif->op_mode = media_mode;
set_PHY_mode(ethernetif);
/* Program operating register */
iow(0x00, DM9000_REG00);
iow(0x02, 0); /* TX Polling clear */
iow(0x08, 0x3f); /* Less 3Kb, 200us */
iow(0x09, DM9000_REG09); /* Flow Control : High/Low Water */
iow(0x0a, DM9000_REG0A); /* Flow Control */
iow(0x2f, 0); /* Special Mode */
iow(0x01, 0x2c); /* clear TX status */
iow(0xfe, 0x0f); /* Clear interrupt status */
/* Set address filter table */
dm9000_hash_table(ethernetif);
/* Init Driver variable */
ethernetif->link_failed = 1;
ethernetif->tx_pkt_cnt = 0;
ethernetif->queue_pkt_len = 0;
ethernetif->rxEmpty = 1;
/* Set MAC address variable */
for (i = 0; i < 6; i++)
iow((0x10 + i), ethernetif->ethaddr.addr[i]);
/* Registry_interrupt */
at91RegisterInterrupt(IRQ_NIC, (void *)dm9000Interrupt, ethernetif);
at91.pio->PIO_PDR = PIOIRQ0;
at91.aic->AIC_SMR[IRQ_NIC] = AIC_SRCTYPE_INT_HIGH_LEVEL_SENSITIVE;
at91.aic->AIC_IECR = AIC_IRQ0;
/* Activate DM9000 */
iow(0x05, DM9000_REG05 | 1); /* RX enable */
iow(0xff, DM9000_REGFF); /* Enable TX/RX interrupt mask */
//dump(Set.lgp, (void *)0x30000fe, 2);
}
static err_t dm9000if_low_level_output(struct netif *netif, struct pbuf *p)
{
int i;
struct pbuf *q;
u8_t *pdata, *pbuff;
u8_t buffer[1024];
Dm9000if_t *ethernetif = (Dm9000if_t *)netif->state;
while (ethernetif->tx_pkt_cnt > 1);
// Disable all interrupt
iow(0xff, 0x80);
// Move data to DM9000 TX RAM
outb(0xf8, DM9000_INDEX);
// Word mode
pbuff = buffer;
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.
for (i = 0, pdata = (u8_t *)q->payload; i < q->len; i++)
*pbuff++ = *pdata++;
}
outsw((u16_t *)buffer, p->tot_len);
// TX control: First packet immediately send, second packet queue
if (ethernetif->tx_pkt_cnt == 0) {
// First Packet
ethernetif->tx_pkt_cnt++;
// Set TX length to DM9000
iow(0xfc, p->tot_len & 0xff);
iow(0xfd, (p->tot_len >> 8) & 0xff);
// Issue TX polling command
iow(0x2, 0x1); // Cleared after TX complete
}
else {
// Second packet
ethernetif->tx_pkt_cnt++;
ethernetif->queue_pkt_len = p->tot_len;
}
lwip_stats.link.xmit++;
// Re-enable resource check
// if (ethernetif->tx_pkt_cnt == 1)
// ;
// Re-enable interrupt
iow(0xff,0x83);
return 0;
}
static struct pbuf *dm9000if_low_level_input(struct netif *netif)
{
u8_t rxbyte;
u16_t i, RxStatus, RxLen, GoodPacket, tmplen, len;
struct pbuf *p;
struct pbuf *q;
Dm9000if_t *ethernetif = (Dm9000if_t *)netif->state;
// Disable all interrupt
iow(0xff, 0x80);
ior(0xf0); // Dummy read
rxbyte = inb(DM9000_DATA); // Got most updated data
// Status check: this byte must be 0 or 1
if (rxbyte > DM9000_PKT_RDY) {
iow(0xff, 0x80); // Stop INT request
iow(0xfe, 0x80); // Clear ISR status
iow(0x05, 0x00); // Stop Receive
ethernetif->device_wait_reset = true;
ethernetif->reset_rx_status++;
}
// packet ready to receive check
if (rxbyte == DM9000_PKT_RDY) {
// Re-enable interrupt
iow(0xff,0x83);
// A packet ready now & Get status/length
GoodPacket = true;
outb(0xf2, DM9000_INDEX);
// Word mode
RxStatus = inw(DM9000_DATA);
RxLen = inw(DM9000_DATA);
// Packet Status check
if (RxLen < 0x40) {
GoodPacket = false;
ethernetif->runt_length_counter++;
}
if (RxLen > DM9000_PKT_MAX) {
ethernetif->device_wait_reset = true;
ethernetif->long_length_counter++;
}
if (RxStatus & 0xbf00) {
GoodPacket = false;
}
// Move data from DM9000
if (!ethernetif->device_wait_reset) {
if (GoodPacket && ((p = pbuf_alloc(PBUF_LINK, RxLen, PBUF_POOL)) != NULL ) ) {
// Read received packet from RX SARM, Word mode
tmplen = (RxLen + 1) / 2;
// 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.
if (RxLen < q->len)
len = RxLen;
else
len = q->len;
insw((u16_t *)q->payload, len);
RxLen -=len;
}
return p;
}
else {
// Without buffer or error packet, Word mode
len = (RxLen + 1) / 2;
for (i = 0; i < len; i++)
inw(DM9000_DATA);
lwip_stats.link.drop++;
}
}
else // device_wait_reset
if(ethernetif->device_wait_reset)
dm9000if_low_level_init(netif);
}
// } while (rxbyte == DM9000_PKT_RDY && !db->device_wait_reset);
ethernetif->rxEmpty = 1;
// Re-enable interrupt
iow(0xff,0x83);
return NULL;
}
/*-----------------------------------------------------------------------------------*/
/*
* dm9000_output():
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actuall transmission of the packet.
*
*/
/*-----------------------------------------------------------------------------------*/
err_t dm9000if_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
{
p = etharp_output(netif, ipaddr, p);
return dm9000if_low_level_output(netif, p);
}
/*-----------------------------------------------------------------------------------*/
/*
* dm9000_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.
*
*/
/*-----------------------------------------------------------------------------------*/
void dm9000if_input(struct netif *netif)
{
Dm9000if_t *ethernetif = netif->state;
struct eth_hdr *ethhdr;
struct pbuf *p;
lwip_stats.link.recv++;
while ((p = dm9000if_low_level_input(netif))) {
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
case ETHTYPE_IP:
etharp_ip_input(netif, p);
pbuf_header(p, -14);
netif->input(p, netif);
break;
case ETHTYPE_ARP:
p = etharp_arp_input(netif, ðernetif->ethaddr, p);
if (p != NULL) {
dm9000if_low_level_output(netif, p);
pbuf_free(p);
}
break;
default:
pbuf_free(p);
break;
}
}
}
/*-----------------------------------------------------------------------------------*/
/*
* dm9000_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 dm9000if_init(struct netif *netif)
{
netif->name[0] = 'e';
netif->name[1] = 't';
netif->output = dm9000if_output;
netif->linkoutput = dm9000if_low_level_output;
dm9000if_low_level_init(netif);
etharp_init();
return ERR_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -