?? altera_avalon_dm9000.c
字號(hào):
/******************************************************************************************
**--------------File Info-------------------------------------------------------------------------------
** File name: ctr_avalon_dm9000.c
** Modified by:duckfun
** Modified date:2006-10-20
** Version:
** Descriptions:
**
********************************************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "alt_types.h"
#include "altera_avalon_dm9000_regs.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "arch/perf.h"
#include "sys/alt_irq.h"
#include "altera_avalon_dm9000.h"
#include "io.h"
#include "altera_avalon_pio_regs.h"
#define USE_ARP_SEMAPHORE
#ifdef ALT_DEBUG
#define VERB(msg) printf msg
#else
#define VERB(msg) do { } while (0)
#endif
inline void dm9k_idxout(alt_avalon_dm9k_if * pdev, u_char val)
{
IOWR(pdev->base_addr, pdev->index_offset, val);
}
inline u_char dm9k_idxin(alt_avalon_dm9k_if * pdev)
{
return (u_char)(IORD(pdev->base_addr, pdev->index_offset) & 0xff);
}
inline void dm9k_datout(alt_avalon_dm9k_if * pdev, u_char val)
{
IOWR(pdev->base_addr, pdev->data_offset, val);
}
inline u_char dm9k_datin(alt_avalon_dm9k_if * pdev)
{
return (u_char)(IORD(pdev->base_addr, pdev->data_offset) & 0xff );
}
inline void dm9k_datoutw(alt_avalon_dm9k_if * pdev, u_short val)
{
IOWR(pdev->base_addr, pdev->data_offset, val);
}
inline u_short dm9k_datinw(alt_avalon_dm9k_if * pdev)
{
return (u_short)(IORD(pdev->base_addr, pdev->data_offset) & 0xffff );
}
inline void dm9k_datoutl(alt_avalon_dm9k_if * pdev, u_long val)
{
IOWR(pdev->base_addr, pdev->data_offset, val);
}
inline u_long dm9k_datinl(alt_avalon_dm9k_if * pdev)
{
return (u_long)(IORD(pdev->base_addr, pdev->data_offset));
}
inline u_char dm9k_regin(alt_avalon_dm9k_if * pdev, u_char regidx)
{
dm9k_idxout(pdev, regidx);
return dm9k_datin(pdev);
}
inline void dm9k_regout(alt_avalon_dm9k_if * pdev, u_char regidx, u_char val)
{
dm9k_idxout(pdev, regidx);
dm9k_datout(pdev, val);
}
inline void dm9k_meminw(alt_avalon_dm9k_if * pdev, u_short * pbuffer, int len)
{
dm9k_idxout(pdev, 0xf2);
for(len=(len+1)/2;len--;) *pbuffer++ = dm9k_datinw(pdev);
}
inline void dm9k_memoutw(alt_avalon_dm9k_if * pdev, u_short * pbuffer, int len)
{
dm9k_idxout(pdev, 0xf8);
for(len=(len+1)/2;len--;) dm9k_datoutw(pdev, *pbuffer++);
}
int dm9k_identify(alt_avalon_dm9k_if * pdev)
{
// vid(29:28) = 0A:46
if((dm9k_regin(pdev, 0x28) != 0x46) || (dm9k_regin(pdev, 0x29) != 0x0a)) return -1;
// pid(2B:2A) = 90:00
if((dm9k_regin(pdev, 0x2A) != 0x00) || (dm9k_regin(pdev, 0x2B) != 0x90)) return -1;
return 0;
}
err_t alt_avalon_dm9k_init(struct netif *netif)
{
int i;
alt_avalon_dm9k_if * pdev = (alt_avalon_dm9k_if*)netif->state;
pdev->lwip_dev_list.dev.netif = netif;
// check private data's availability
if (!pdev) return ERR_IF;
// identify our device
if(dm9k_identify(pdev) == -1) return ERR_IF;
// specify callback routines
netif->name[0] = 'd';
netif->name[1] = 'm';
netif->output = dm9k_output;
netif->linkoutput = dm9k_link_output;
// set physical address
//
pdev->hwaddr[5] = IORD(PIO_KEY_BASE, 0) & 0xFF;
for(i=0;i<(netif->hwaddr_len = 6);i++) netif->hwaddr[i] = pdev->hwaddr[i];
// dm9k initialization
if(dm9k_init(pdev) != ERR_OK ||
!(pdev->arp_semaphore = sys_sem_new(1)) ||
!(pdev->tx_semaphore = sys_sem_new(pdev->dm9k_tx_space))
)
{
free(netif->state);
return ERR_IF;
} // of dm9k initialization
etharp_init();
return ERR_OK;
}
void alt_avalon_dm9k_rx(alt_lwip_dev * paltdev)
{
alt_avalon_dm9k_if * pdev = (alt_avalon_dm9k_if*)(paltdev->netif->state);
// save current index register
volatile u_char idxold = dm9k_idxin(pdev);
for(;dm9k_input(paltdev->netif););
// resotre old idx register
dm9k_idxout(pdev, idxold);
}
err_t dm9k_init(alt_avalon_dm9k_if * pdev)
{
int i;
// 1. power on internal PHY
dm9k_regout(pdev, 0x1f, 0x00);
usleep(5000);
// 2. software reset
dm9k_regout(pdev, 0x00, 0x03);
usleep(5000);
// 3. clear Network Stautus Register(NSR) by reading out
dm9k_regin(pdev, 0x01);
// 4. set MAC address
for(i=0;i<6;i++) dm9k_regout(pdev, 0x10+i, pdev->hwaddr[i]);
// 4.1 set hash table
// for(i=0;i<6;i++) dm9k_regout(pdev, 0x16+i, 0xff);
// 5. clear Interrupt Status Register (NSR)
dm9k_regout(pdev, 0xfe, 0x00);
// 6. register interrupt handler
alt_irq_register(pdev->irq, (void*)pdev, (void*)dm9k_isr);
pdev->dm9k_linked = (dm9k_regin(pdev, 0x01) & 0x40) >> 6;
// 7. interrupt enable, 5: Link, 1: TX, 0: RX
dm9k_regout(pdev, 0xff, 0xbf);
//dm9k_regout(pdev, 0xff, ((1<<1)|(1<<0)));
// 8. RX start, 5: Discard long, 4: Discard CRC, 3: All multicast, 2: Runt, 1: Promiscuous, 0: RX enable
dm9k_regout(pdev, 0x05, ((1<<5)|(1<<4)|(1<<3)|(1<<0)));
return ERR_OK;
}
void dm9k_isr(void * pvoid)
{
volatile u_char ist, nsr;
u_char curridx;
alt_avalon_dm9k_if * pdev = (alt_avalon_dm9k_if*)pvoid;
// save current index port value
curridx = dm9k_idxin(pdev);
// 1. handle RX activity
// read/clear interrupt status register
dm9k_regout(pdev, 0xfe, (ist = dm9k_regin(pdev, 0xfe)));
{
if(ist & (1<<2)) VERB(("<ROS>"));
if(ist & (1<<3)) VERB(("<ROOS>"));
}
// check rx availability, roos(3), ros(2), rx(0)
if(ist & ((1<<3)|(1<<2)|(1<<0))) sys_mbox_post(rx_mbox, &(pdev->lwip_dev_list.dev));
// 2. check tx completeness
// read/clear network status register
dm9k_regout(pdev, 0x01, (nsr = dm9k_regin(pdev, 0x01)));
// update link status
pdev->dm9k_linked = (nsr & 0x40) >> 6;
// check completeness
if(nsr & 0x08) sys_sem_signal(pdev->tx_semaphore);
if(nsr & 0x04) sys_sem_signal(pdev->tx_semaphore);
// restore index register
dm9k_idxout(pdev, curridx);
} // void dm9k_isr()
err_t dm9k_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
{
err_t err;
alt_avalon_dm9k_if * pdev = (alt_avalon_dm9k_if*)netif->state;
/*
* resolve hardware address, then send (or queue) packet
* The code which updates the ARP tables does not appear to be thread safe
* so I've added a MUTEX around all calls to the arp code
*
*/
WAIT_ARP_SEMAPHORE(pdev);
err = etharp_output(netif, ipaddr, p);
SIGNAL_ARP_SEMAPHORE(pdev);
return err;
}
err_t dm9k_link_output(struct netif *netif, struct pbuf *p)
{
alt_avalon_dm9k_if * pdev = (alt_avalon_dm9k_if*)netif->state;
// wait tx resource availability
sys_sem_wait(pdev->tx_semaphore);
// fill packet to MAC
dm9k_memoutw(pdev, (u_short*)(p->payload), p->tot_len);
// specify the length
dm9k_regout(pdev, 0xfc, (u_char)(p->tot_len & 0xff));
dm9k_regout(pdev, 0xfd, (u_char)((p->tot_len & 0xff00) >> 8));
// kick start
dm9k_regout(pdev, 0x02, 0x01);
return ERR_OK;
}
int dm9k_input(struct netif *netif)
{
struct eth_hdr *ethhdr;
struct pbuf *p;
alt_avalon_dm9k_if * pdev = (alt_avalon_dm9k_if*)netif->state;
/* move received packet into a new pbuf */
if(!(p = dm9k_link_input(pdev))) return 0;
ethhdr = (struct eth_hdr*)(p->payload);
switch (htons(ethhdr->type)) {
/* IP packet? */
case ETHTYPE_IP:
/*
* update ARP table
*/
WAIT_ARP_SEMAPHORE(pdev);
etharp_ip_input(netif, p);
SIGNAL_ARP_SEMAPHORE(pdev);
/* skip Ethernet header */
pbuf_header(p, -(s16_t)sizeof(struct eth_hdr));
/* pass to network layer */
netif->input(p, netif);
break;
case ETHTYPE_ARP:
/*
* pass p to ARP module
*
*/
WAIT_ARP_SEMAPHORE(pdev);
etharp_arp_input(netif, (struct eth_addr *)&netif->hwaddr, p);
SIGNAL_ARP_SEMAPHORE(pdev);
break;
default:
pbuf_free(p);
p = NULL;
break;
} // of packet type switch
return 1;
} // of alt_avalon_dm9k_rx
struct pbuf * dm9k_link_input(alt_avalon_dm9k_if * pdev)
{
u_char saveidx;
struct pbuf *p, *q;
volatile u_short pklen, status;
u_short remains;
saveidx = dm9k_idxin(pdev);
// check RX availability
// first, dummy read
dm9k_idxout(pdev, 0xf0);
status = dm9k_datinw(pdev);
// re-read again
status = dm9k_datinw(pdev);
if((status & 0xff) != 0x01)
{
dm9k_idxout(pdev, saveidx);
return NULL;
}
// now, read status word and set pointer to increment automatically
dm9k_idxout(pdev, 0xf2);
status = dm9k_datinw(pdev);
// read packet length, eliminate 4 byte CRC
pklen = dm9k_datinw(pdev) - 4;
// allocate buffer
if(!(p = pbuf_alloc(PBUF_RAW, pklen, PBUF_POOL)))
{
// OOOPS!
// handle pointer adjustment, can add ptr directly, too
VERB(("<oop>"));
dm9k_idxout(pdev, 0xf2);
for(remains = (pklen+4+1)/2; remains--;) dm9k_datinw(pdev);
dm9k_idxout(pdev, saveidx);
return NULL;
}
// fill packet per chunk
for(remains=pklen, q = p; remains && q; q = q->next)
{
dm9k_meminw(pdev, q->payload, q->len);
remains -= q->len;
} // of fill loop
// finally, read out the 4-byte CRC
dm9k_datinw(pdev);
dm9k_datinw(pdev);
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
dm9k_idxout(pdev, saveidx);
return p;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -