📄 freedev_lan91c111.c
字号:
*
*/
if (alt_irq_register ( dev->irq, dev,
freedev_lan91c111_irq))
{
ret_code = ERR_IF;
goto exit;
}
else
{
#if LINK_STATS
IOWR_FREEDEV_LAN91C111_MSK(dev->base_addr,
FREEDEV_LAN91C111_INT_RCV_INT_MSK |
FREEDEV_LAN91C111_INT_RX_OVRN_INT_MSK);
#else
IOWR_FREEDEV_LAN91C111_MSK(dev->base_addr,
FREEDEV_LAN91C111_INT_RCV_INT_MSK);
#endif /* LINK_STATS */
}
exit:
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_init() exit = %d\n", ret_code));
return ret_code;
}
/*
* Register definitions for the Rtl8019as ethernet chip used on the Nios II
* FreeDev2.1 development boards
* Create by Free-electron
* author:liu-jun-sheng
* address:MoGanShan road HangZhou ZheJiang China
* tel:0571-88846603
* www.Free-Electron.com.cn
* date:2005/12/02
*/
/*-----------------------------------------------------------------------------------*
*
* 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.
*
*
* This funciton should be changed to use all the available transmit
* packets in the Lan91C111
*-----------------------------------------------------------------------------------*/
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
int total_length_sent = 0;
int i, unaligned, end, base;
alt_u8 irq_value, *datap;
alt_u16 mmu_status, ptr_status;
freedev_lan91c111_if *dev = netif->state;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_output ( %#x)\n",p));
/* Wait for the last Tx to complete */
do
{
irq_value = IORD_FREEDEV_LAN91C111_IST(dev->base_addr);
}while(!(irq_value & FREEDEV_LAN91C111_INT_TX_EMPTY_INT_MSK));
/* Clear the interrupt */
IOWR_FREEDEV_LAN91C111_ACK( dev->base_addr,
FREEDEV_LAN91C111_INT_TX_EMPTY_INT_MSK);
/* Always re-use the same packet */
IOWR_FREEDEV_LAN91C111_PNR( dev->base_addr,
dev->tx_packet_no);
/*
* The Pointer Register and the MMUCR register are used in both TX and RX and are context sensitive, so
* protect them with a semaphore
*/
sys_sem_wait(dev->semaphore);
do
{
ptr_status = IORD_FREEDEV_LAN91C111_PTR( dev->base_addr);
}while (ptr_status & FREEDEV_LAN91C111_PTR_NOT_EMPTY_MSK);
IOWR_FREEDEV_LAN91C111_PTR( dev->base_addr,
FREEDEV_LAN91C111_PTR_AUTO_INCR_MSK);
/* The status word */
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr, 0);
/*
* The byte count including the 6 control bytes
*
* Bit odd this, but the length is always written as even, if the frame is an odd length
* then the byte is written as one of the control words and an appropriate bit is set
*
*/
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr, ((p->tot_len & ~1) + 6));
for(q = p; q != NULL; q = q->next)
{
/*
* Write each buffer of data to the device
*
* Nios requres accesses to be aligned on the correct boundary
*
* You could just do this with
* for(i=0;i<q->len;i++)
* write_register8( dev, DATA_OFFSET, *(alt_u8*)(q->payload+i));
*
* But this is more efficient
*/
unaligned = ((int)q->payload) % 4;
unaligned = (4 - unaligned) % 4;
switch (unaligned)
{
case 3:
IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
*(alt_u8*)q->payload);
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
*((alt_u16*)((alt_u8*)q->payload + 1)));
break;
case 2:
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
*(alt_u16*)q->payload);
break;
case 1:
IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
*(alt_u8*)q->payload);
break;
}
datap = q->payload;
end = q->len-3 ;
base = dev->base_addr;
for (i=unaligned;i<end;i+=4) {
IOWR_FREEDEV_LAN91C111_DATA_WORD( base,
*((u32_t *)(datap+i)));
}
switch (q->len - i){
case 3:
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
*((alt_u16*)((alt_u8*)q->payload + q->len - 3)));
IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
*((alt_u8*)((alt_u8*)q->payload + q->len -1)));
break;
case 2:
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
*((alt_u16*)((alt_u8*)q->payload + q->len - 2)));
break;
case 1:
IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
*((alt_u8*)((alt_u8*)q->payload + q->len -1)));
break;
}
total_length_sent += q->len;
/*
* Last buffer in the packet?
*/
if (total_length_sent == p->tot_len)
{
if (p->tot_len & 1)
{
IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
FREEDEV_LAN91C111_CONTROL_ODD_MSK);
}
else
{
IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr, 0);
}
}
}
/* Wait for any pending commands to complete */
do
{
mmu_status = IORD_FREEDEV_LAN91C111_MMUCR(dev->base_addr);
}while (mmu_status & FREEDEV_LAN91C111_MMUCR_BUSY_MSK);
/* Queue the packet */
IOWR_FREEDEV_LAN91C111_MMUCR( dev->base_addr,
FREEDEV_LAN91C111_MMUCR_ENQUEUE_MSK);
sys_sem_signal(dev->semaphore);
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_ouptput () return OK\n"));
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*
*
* 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(freedev_lan91c111_if *dev)
{
struct pbuf *p=NULL, *q;
alt_u32 status;
alt_u16 packet_number, mmu_status, ptr_status;
int length, i, unaligned, end, base;
alt_u8 *data_ptr;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_input()\n"));
packet_number = IORD_FREEDEV_LAN91C111_RX_FIFO(
dev->base_addr);
if ( packet_number & FREEDEV_LAN91C111_RX_FIFO_REMPTY_MSK )
{
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_input (exits p =0)\n"));
return 0;
}
/*
* The Pointer Register and the MMUCR register are used in both TX and RX and are context sensitive, so
* protect them with a semaphore
*/
sys_sem_wait(dev->semaphore);
do
{
ptr_status = IORD_FREEDEV_LAN91C111_PTR( dev->base_addr);
}while (ptr_status & FREEDEV_LAN91C111_PTR_NOT_EMPTY_MSK);
IOWR_FREEDEV_LAN91C111_PTR( dev->base_addr,
FREEDEV_LAN91C111_PTR_READ_MSK |
FREEDEV_LAN91C111_PTR_AUTO_INCR_MSK |
FREEDEV_LAN91C111_PTR_RCV_MSK);
/* The first two half-words are status and byte count */
status = IORD_FREEDEV_LAN91C111_DATA_WORD(dev->base_addr);
length = (status & 0xffff0000ul) >> 16;
status &= 0xffff;
if (status & (FREEDEV_LAN91C111_RS_TOO_SHORT_MSK |
FREEDEV_LAN91C111_RS_TOO_LONG_MSK |
FREEDEV_LAN91C111_RS_BAD_CRC_MSK |
FREEDEV_LAN91C111_RS_ALGN_ERR_MSK))
{
#if LINK_STATS
lwip_stats.link.drop++;
#endif /* LINK_STATS */
}
else
{
/* We've already read two of the words */
length -= 4;
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
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)
{
/*
* Fill each buffer in the chain
*
* On Nios all the memory accesses must be aligned
*/
unaligned = (int)q->payload % 4;
unaligned = (4 - unaligned) % 4;
switch (unaligned)
{
case 3:
*((alt_u8*)q->payload) =
IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
*((alt_u16*)((alt_u8*)q->payload+1)) =
IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
break;
case 2:
*((alt_u16*)q->payload) =
IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
break;
case 1:
*((alt_u8*)q->payload) =
IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
break;
}
end = q->len-3;
data_ptr = q->payload;
base = dev->base_addr;
for (i = unaligned; i < end; i+= 4)
{
*((u32_t*)((alt_u8*)data_ptr + i)) =
IORD_FREEDEV_LAN91C111_DATA_WORD(base);
}
switch (q->len - i)
{
case 3:
*((alt_u16*)((alt_u8*)q->payload + i)) =
IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
*((alt_u8*)((alt_u8*)q->payload + i + 2)) =
IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
break;
case 2:
*((alt_u16*)((alt_u8*)q->payload + i)) =
IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
break;
case 1:
*((alt_u8*)((alt_u8*)q->payload + i)) =
IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
break;
}
}
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
}
else
{
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif /* LINK_STATS */
}
}
/* Wait for any pending commands to complete */
do
{
mmu_status = IORD_FREEDEV_LAN91C111_MMUCR(dev->base_addr);
}while (mmu_status & FREEDEV_LAN91C111_MMUCR_BUSY_MSK);
/* Just get rid of the packet */
IOWR_FREEDEV_LAN91C111_MMUCR(dev->base_addr,
FREEDEV_LAN91C111_MMUCR_REMOVE_RELEASE_MSK);
sys_sem_signal(dev->semaphore);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_input (exits p =%#x)\n", p));
return p;
}
/*-----------------------------------------------------------------------------------*
*
* freedev_lan91c111_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.
*
*
*-----------------------------------------------------------------------------------*/
static err_t
freedev_lan91c111_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
err_t err;
freedev_lan91c111_if* dev = (freedev_lan91c111_if*)netif->state;
sys_sem_wait(dev->arp_semaphore);
/*
* 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
*
*/
err = etharp_output(netif, ipaddr, p);
sys_sem_signal(dev->arp_semaphore);
return err;
}
/*
* Register definitions for the Rtl8019as ethernet chip used on the Nios II
* FreeDev2.1 development boards
* Create by Free-electron
* author:liu-jun-sheng
* address:MoGanShan road HangZhou ZheJiang China
* tel:0571-88846603
* www.Free-Electron.com.cn
* date:2005/12/02
*/
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -