DevEmac.c 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define DEVEMAC_C
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include <string.h>
#include <stdio.h>
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"
#include "XEthernet.h"
#include "DevEmac.h"
#if defined(NUTOS) && defined(AT91SAM9260)
/******************************************************************************
* *
* L O C A L D E F I N E S *
* *
******************************************************************************/
#ifndef EMAC_RX_BUFFERS
#define EMAC_RX_BUFFERS 32
#endif
#define EMAC_RX_BUFSIZ 128
#define EMAC_TX_BUFFERS 2
#ifndef EMAC_TX_BUFSIZ
#define EMAC_TX_BUFSIZ 1536
#endif
#ifndef EMAC_LINK_LOOPS
#define EMAC_LINK_LOOPS 1000000
#endif
#define NIC_PHY_BMCR 0x00 /*!< \brief Basic mode control register. */
#define NIC_PHY_BMCR_COLTEST 0x0080 /*!< \brief Collision test. */
#define NIC_PHY_BMCR_FDUPLEX 0x0100 /*!< \brief Full duplex mode. */
#define NIC_PHY_BMCR_ANEGSTART 0x0200 /*!< \brief Restart auto negotiation. */
#define NIC_PHY_BMCR_ISOLATE 0x0400 /*!< \brief Isolate from MII. */
#define NIC_PHY_BMCR_PWRDN 0x0800 /*!< \brief Power-down. */
#define NIC_PHY_BMCR_ANEGENA 0x1000 /*!< \brief Enable auto negotiation. */
#define NIC_PHY_BMCR_100MBPS 0x2000 /*!< \brief Select 100 Mbps. */
#define NIC_PHY_BMCR_LOOPBACK 0x4000 /*!< \brief Enable loopback mode. */
#define NIC_PHY_BMCR_RESET 0x8000 /*!< \brief Software reset. */
#define NIC_PHY_BMSR 0x01 /*!< \brief Basic mode status register. */
#define NIC_PHY_BMSR_ANCOMPL 0x0020 /*!< \brief Auto negotiation complete. */
#define NIC_PHY_BMSR_LINKSTAT 0x0004 /*!< \brief Link status. */
#define NIC_PHY_ID1 0x02 /*!< \brief PHY identifier register 1. */
#define NIC_PHY_ID2 0x03 /*!< \brief PHY identifier register 2. */
#define NIC_PHY_ANAR 0x04 /*!< \brief Auto negotiation advertisement register. */
#define NIC_PHY_ANLPAR 0x05 /*!< \brief Auto negotiation link partner availability register. */
#define NIC_PHY_ANEG_NP 0x8000 /*!< \brief Next page available. */
#define NIC_PHY_ANEG_ACK 0x4000 /*!< \brief Ability data reception acknowledged. */
#define NIC_PHY_ANEG_RF 0x2000 /*!< \brief Remote fault. */
#define NIC_PHY_ANEG_FCS 0x0400 /*!< \brief Flow control supported. */
#define NIC_PHY_ANEG_T4 0x0200 /*!< \brief 100BASE-T4 supported. */
#define NIC_PHY_ANEG_TX_FDX 0x0100 /*!< \brief 100BASE-T full duplex supported. */
#define NIC_PHY_ANEG_TX_HDX 0x0080 /*!< \brief 100BASE-T half duplex supported. */
#define NIC_PHY_ANEG_10_FDX 0x0040 /*!< \brief 10BASE-T full duplex supported. */
#define NIC_PHY_ANEG_10_HDX 0x0020 /*!< \brief 10BASE-T half duplex supported. */
#define NIC_PHY_ANEG_BINSEL 0x001F /*!< \brief Binary encoded protocol selector. */
#define NIC_PHY_ANER 0x06 /*!< \brief Auto negotiation expansion register. */
#define RXBUF_OWNERSHIP 0x00000001
#define RXBUF_WRAP 0x00000002
#define RXBUF_ADDRMASK 0xFFFFFFFC
#define RXS_BROADCAST_ADDR 0x80000000 /*!< \brief Broadcast address detected. */
#define RXS_MULTICAST_HASH 0x40000000 /*!< \brief Multicast hash match. */
#define RXS_UNICAST_HASH 0x20000000 /*!< \brief Unicast hash match. */
#define RXS_EXTERNAL_ADDR 0x10000000 /*!< \brief External address match. */
#define RXS_SA1_ADDR 0x04000000 /*!< \brief Specific address register 1 match. */
#define RXS_SA2_ADDR 0x02000000 /*!< \brief Specific address register 2 match. */
#define RXS_SA3_ADDR 0x01000000 /*!< \brief Specific address register 3 match. */
#define RXS_SA4_ADDR 0x00800000 /*!< \brief Specific address register 4 match. */
#define RXS_TYPE_ID 0x00400000 /*!< \brief Type ID match. */
#define RXS_VLAN_TAG 0x00200000 /*!< \brief VLAN tag detected. */
#define RXS_PRIORITY_TAG 0x00100000 /*!< \brief Priority tag detected. */
#define RXS_VLAN_PRIORITY 0x000E0000 /*!< \brief VLAN priority. */
#define RXS_CFI_IND 0x00010000 /*!< \brief Concatenation format indicator. */
#define RXS_EOF 0x00008000 /*!< \brief End of frame. */
#define RXS_SOF 0x00004000 /*!< \brief Start of frame. */
#define RXS_RBF_OFFSET 0x00003000 /*!< \brief Receive buffer offset mask. */
#define RXS_LENGTH_FRAME 0x000007FF /*!< \brief Length of frame including FCS. */
#define TXS_USED 0x80000000 /*!< \brief Used buffer. */
#define TXS_WRAP 0x40000000 /*!< \brief Last descriptor. */
#define TXS_ERROR 0x20000000 /*!< \brief Retry limit exceeded. */
#define TXS_UNDERRUN 0x10000000 /*!< \brief Transmit underrun. */
#define TXS_NO_BUFFER 0x08000000 /*!< \brief Buffer exhausted. */
#define TXS_NO_CRC 0x00010000 /*!< \brief CRC not appended. */
#define TXS_LAST_BUFF 0x00008000 /*!< \brief Last buffer of frame. */
/******************************************************************************
* *
* L O C A L T Y P E D E F S *
* *
******************************************************************************/
/*!
* \brief Network interface controller information structure.
*/
struct _EMACINFO {
#ifdef NUT_PERFMON
u_long ni_rx_packets; /*!< Number of packets received. */
u_long ni_tx_packets; /*!< Number of packets sent. */
u_long ni_overruns; /*!< Number of packet overruns. */
u_long ni_rx_frame_errors; /*!< Number of frame errors. */
u_long ni_rx_crc_errors; /*!< Number of CRC errors. */
u_long ni_rx_missed_errors; /*!< Number of missed packets. */
#endif
NUTHANDLE volatile ni_rx_rdy; /*!< Receiver event queue. */
NUTHANDLE volatile ni_tx_rdy; /*!< Transmitter event queue. */
NUTHANDLE ni_mutex; /*!< Access mutex semaphore. */
volatile int ni_tx_queued; /*!< Number of packets in transmission queue. */
volatile int ni_tx_quelen; /*!< Number of bytes in transmission queue not sent. */
volatile int ni_insane; /*!< Set by error detection. */
int ni_iomode; /*!< 8 or 16 bit access. 32 bit is not supported. */
};
/*!
* \brief Network interface controller information type.
*/
typedef struct _EMACINFO EMACINFO;
/*
* TODO: Buffers and their descriptors should be part of the EMACINFO
* structure. Actually there will be no dual Ethernet chip (sure?),
* but just to keep the code clean.
*/
typedef struct _BufDescriptor {
u_int addr;
u_int stat;
} BufDescriptor;
/******************************************************************************
* *
* L O C A L F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
int EmacOutput(NUTDEVICE * dev, NETBUF * nb);
int EmacInit(NUTDEVICE * dev);
/******************************************************************************
* *
* L O C A L I N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
static EMACINFO dcb_eth0;
/*!
* \brief Network interface information structure.
*
* Used to call.
*/
static IFNET ifn_eth0 = {
IFT_ETHER, /*!< \brief Interface type, if_type. */
{0, 0, 0, 0, 0, 0}, /*!< \brief Hardware net address, if_mac. */
0, /*!< \brief IP address, if_local_ip. */
0, /*!< \brief Remote IP address for point to point, if_remote_ip. */
0, /*!< \brief IP network mask, if_mask. */
ETHERMTU, /*!< \brief Maximum size of a transmission unit, if_mtu. */
0, /*!< \brief Packet identifier, if_pkt_id. */
0, /*!< \brief Linked list of arp entries, arpTable. */
0, /*!< \brief Linked list of multicast address entries, if_mcast. */
NutEtherInput, /*!< \brief Routine to pass received data to, if_recv(). */
EmacOutput, /*!< \brief Driver output routine, if_send(). */
NutEtherOutput /*!< \brief Media output routine, if_output(). */
};
/*!
* \brief Device information structure.
*
* A pointer to this structure must be passed to NutRegisterDevice()
* to bind this Ethernet device driver to the Nut/OS kernel.
* An application may then call NutNetIfConfig() with the name \em eth0
* of this driver to initialize the network interface.
*
*/
NUTDEVICE devEMAC = {
0, /*!< \brief Pointer to next device. */
{'e', 't', 'h', '0', 0, 0, 0, 0, 0}, /*!< \brief Unique device name. */
IFTYP_NET, /*!< \brief Type of device. */
0, /*!< \brief Base address. */
0, /*!< \brief First interrupt number. */
&ifn_eth0, /*!< \brief Interface control block. */
&dcb_eth0, /*!< \brief Driver control block. */
EmacInit, /*!< \brief Driver initialization routine. */
0, /*!< \brief Driver specific control function. */
0, /*!< \brief Read from device. */
0, /*!< \brief Write to device. */
0, /*!< \brief Open a device or file. */
0, /*!< \brief Close a device or file. */
0 /*!< \brief Request file size. */
};
/******************************************************************************
* *
* L O C A L U N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
static void *IntArg;
#ifdef __ICCARM__
#pragma object_attribute = __no_init
#pragma location = "SRAM0"
#endif
static volatile BufDescriptor txBufTab[EMAC_TX_BUFFERS];
#ifdef __ICCARM__
#pragma data_alignment = 8
#pragma object_attribute = __no_init
#pragma location = "SRAM0"
#endif
static volatile u_char txBuf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] __attribute__ ((aligned(8)));
static u_int txBufIdx;
#ifdef __ICCARM__
#pragma object_attribute = __no_init
#pragma location = "SRAM0"
#endif
static volatile BufDescriptor rxBufTab[EMAC_RX_BUFFERS];
#ifdef __ICCARM__
#pragma data_alignment = 8
#pragma object_attribute = __no_init
#pragma location = "SRAM1"
#endif
static volatile u_char rxBuf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] __attribute__ ((aligned(8)));
static u_int rxBufIdx;
/*!
* \brief Read contents of PHY register.
*
* \param reg PHY register number.
*
* \return Contents of the specified register.
*/
static u_short phy_inw(u_char addr, u_char reg)
{
/* PHY read command. */
AT91C_BASE_EMACB->EMAC_MAN = (AT91C_EMAC_SOF & (0x1 << 30)) | // Fixed value.
(AT91C_EMAC_RW & (0x2 << 28)) | // PHY read
(AT91C_EMAC_CODE & (0x2 << 16)) | // Fixed value.
(AT91C_EMAC_PHYA & (addr << 23)) |
(AT91C_EMAC_REGA & (reg << 18));
/* Wait until PHY logic completed. */
while ((AT91C_BASE_EMACB->EMAC_NSR & AT91C_EMAC_IDLE) == 0);
/* Get data from PHY maintenance register. */
return (u_short) (AT91C_BASE_EMACB->EMAC_MAN & AT91C_EMAC_DATA);
}
/*!
* \brief Write value to PHY register.
*
* \param reg PHY register number.
* \param val Value to write.
*/
static void phy_outw(u_char addr, u_char reg, u_short val)
{
/* PHY write command. */
AT91C_BASE_EMACB->EMAC_MAN = (AT91C_EMAC_SOF & (0x1 << 30)) | // Fixed value.
(AT91C_EMAC_RW & (0x1 << 28)) | // PHY write
(AT91C_EMAC_CODE & (0x2 << 16)) | // Fixed value.
(AT91C_EMAC_PHYA & (addr << 23)) |
(AT91C_EMAC_REGA & (reg << 18)) |
(AT91C_EMAC_DATA & (val << 0));
/* Wait until PHY logic completed. */
while ((AT91C_BASE_EMACB->EMAC_NSR & AT91C_EMAC_IDLE) == 0);
}
/*!
* \brief Reset the Ethernet controller.
*
* \return 0 on success, -1 otherwise.
*/
u_int phyval_bak;
static int EmacReset(u_long tmo)
{
u_short phyval;
u_char phyaddr;
/* Enable receive and transmit clocks and set MII mode. */
AT91C_BASE_EMACB->EMAC_USRIO = (AT91C_EMAC_RMII | AT91C_EMAC_CLKEN);
/* Enable management port. */
AT91C_BASE_EMACB->EMAC_NCR |= AT91C_EMAC_MPE;
AT91C_BASE_EMACB->EMAC_NCFGR |= AT91C_EMAC_CLK_HCLK_64;
/* Wait for PHY ready. */
NutDelay(255);
for (phyaddr = 0; phyaddr < 32; phyaddr++) {
/* For some unknown reason it seems to be required to read the ID registers first. */
#if defined(T045_PCB) ||defined(T40_PCB)
if (phy_inw(phyaddr, NIC_PHY_ID1) == 0X0243 && phy_inw(phyaddr, NIC_PHY_ID2)== 0X0C54)
#else
if (phy_inw(phyaddr, NIC_PHY_ID1) == 0x0181 && (phy_inw(phyaddr, NIC_PHY_ID2) & 0xFF00) == 0xB800)
#endif
{
debug_printf("ID_addr:%d\n",phyaddr);
/* Sets the status and controls the PHY registers to their default states. */
phy_outw(phyaddr, NIC_PHY_BMCR, NIC_PHY_BMCR_RESET);
NutSleep(10);
/* Handle auto negotiation if configured. */
phyval = phy_inw(phyaddr, NIC_PHY_BMCR);
if (phyval & NIC_PHY_BMCR_ANEGENA) {
/* Wait for auto negotiation completed. */
phyval = phy_inw(phyaddr, NIC_PHY_BMSR); /* Discard previously latched status. */
while (--tmo) {
phyval = phy_inw(phyaddr, NIC_PHY_BMSR);
if ((phyval & NIC_PHY_BMSR_ANCOMPL) && (phyval & NIC_PHY_BMSR_LINKSTAT)) {
debug_printf("2,%d,0x%x\n",tmo,phyval);
break;
}
else if(phyval_bak != phyval)
{
debug_printf("1,%d,0x%x\n",tmo,phyval);
phyval_bak = phyval;
}
NutSleep(1000);
}
/* Return error on link timeout. */
if (tmo == 0) {
debug_printf("Return error on link timeout\n");
break;
}
/*
* Read link partner abilities and configure EMAC.
*/
phyval = phy_inw(phyaddr, NIC_PHY_ANLPAR);
if (phyval & NIC_PHY_ANEG_TX_FDX) {
/* 100Mb full duplex. */
AT91C_BASE_EMACB->EMAC_NCFGR |= (AT91C_EMAC_SPD | AT91C_EMAC_FD);
}
else if (phyval & NIC_PHY_ANEG_TX_HDX) {
/* 100Mb half duplex. */
AT91C_BASE_EMACB->EMAC_NCFGR |= AT91C_EMAC_SPD;
AT91C_BASE_EMACB->EMAC_NCFGR &= ~AT91C_EMAC_FD;
}
else if (phyval & NIC_PHY_ANEG_10_FDX) {
/* 10Mb full duplex. */
AT91C_BASE_EMACB->EMAC_NCFGR &= ~AT91C_EMAC_SPD;
AT91C_BASE_EMACB->EMAC_NCFGR |= AT91C_EMAC_FD;
}
else {
/* 10Mb half duplex. */
AT91C_BASE_EMACB->EMAC_NCFGR &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
}
}
/* Disable management port. */
AT91C_BASE_EMACB->EMAC_NCR &= ~AT91C_EMAC_MPE;
return 0;
}
}
/* Disable management port. */
AT91C_BASE_EMACB->EMAC_NCR &= ~AT91C_EMAC_MPE;
return -1;
}
/*
* NIC interrupt entry.
*/
static void EmacInterrupt(void)
{
u_int isr;
EMACINFO *ni = (EMACINFO *) ((NUTDEVICE *) IntArg)->dev_dcb;
/* Read interrupt status and disable interrupts. */
isr = AT91C_BASE_EMACB->EMAC_ISR;
/* Receiver interrupt. */
//if ((isr & AT91C_EMAC_RCOMP) != 0 || (isr & AT91C_EMAC_ROVR) != 0 || (AT91C_BASE_EMACB->EMAC_RSR & EMAC_REC) != 0) {
if ((isr & (AT91C_EMAC_RCOMP | AT91C_EMAC_ROVR | AT91C_EMAC_RXUBR)) != 0) {
//AT91C_BASE_EMACB->EMAC_RSR = AT91C_EMAC_REC;
AT91C_BASE_EMACB->EMAC_IDR = AT91C_EMAC_RCOMP | AT91C_EMAC_ROVR | AT91C_EMAC_RXUBR;
NutEventPostFromIrq(&ni->ni_rx_rdy);
}
/* Transmitter interrupt. */
if ((isr & AT91C_EMAC_TCOMP) != 0 || (AT91C_BASE_EMACB->EMAC_TSR & AT91C_EMAC_COMP) != 0) {
//AT91C_BASE_EMACB->EMAC_TSR = AT91C_EMAC_COMP;
NutEventPostFromIrq(&ni->ni_tx_rdy);
}
}
/*!
* \brief Fetch the next packet out of the receive buffers.
*
* \return 0 on success, -1 otherwise.
*/
static int EmacGetPacket(EMACINFO * ni, NETBUF ** nbp)
{
int rc = -1;
u_int fbc = 0;
u_int i;
*nbp = NULL;
/*
* Search the next frame start. Release any fragment.
*/
while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0) {
rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
rxBufIdx++;
if (rxBufIdx >= EMAC_RX_BUFFERS) {
rxBufIdx = 0;
}
}
/*
* Determine the size of the next frame.
*/
i = rxBufIdx;
while (rxBufTab[i].addr & RXBUF_OWNERSHIP) {
if (i != rxBufIdx && (rxBufTab[i].stat & RXS_SOF) != 0) {
do {
rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
rxBufIdx++;
if (rxBufIdx >= EMAC_RX_BUFFERS) {
rxBufIdx = 0;
}
} while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0);
break;
}
if ((fbc = rxBufTab[i].stat & RXS_LENGTH_FRAME) != 0) {
break;
}
i++;
if (i >= EMAC_RX_BUFFERS) {
i = 0;
}
}
if (fbc) {
/*
* Receiving long packets is unexpected. Let's declare the
* chip insane. Short packets will be handled by the caller.
*/
if (fbc > 1536) {
ni->ni_insane = 1;
} else {
*nbp = NutNetBufAlloc(0, NBAF_DATALINK, (u_short)fbc);
if (*nbp != NULL) {
u_char *bp = (u_char *) (* nbp)->nb_dl.vp;
u_int len;
while (fbc) {
if (fbc > EMAC_RX_BUFSIZ) {
len = EMAC_RX_BUFSIZ;
} else {
len = fbc;
}
memcpy(bp, (void *) (rxBufTab[rxBufIdx].addr & RXBUF_ADDRMASK), len);
rxBufTab[rxBufIdx].addr &= ~RXBUF_OWNERSHIP;
rxBufIdx++;
if (rxBufIdx >= EMAC_RX_BUFFERS) {
rxBufIdx = 0;
}
fbc -= len;
bp += len;
}
rc = 0;
}
}
}
return rc;
}
/*!
* \brief Load a packet into the nic's transmit ring buffer.
*
* \todo This routine simply does not work. Any idea?
*
* \param nb Network buffer structure containing the packet to be sent.
* The structure must have been allocated by a previous
* call NutNetBufAlloc(). This routine will automatically
* release the buffer in case of an error.
*
* \return 0 on success, -1 in case of any errors. Errors
* will automatically release the network buffer
* structure.
*/
static int EmacPutPacket(int bufnum, EMACINFO * ni, NETBUF * nb)
{
int rc = -1;
u_int sz;
u_char *buf;
/*
* Calculate the number of bytes to be send. Do not send packets
* larger than the Ethernet maximum transfer unit. The MTU
* consist of 1500 data bytes plus the 14 byte Ethernet header
* plus 4 bytes CRC. We check the data bytes only.
*/
if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
return -1;
}
sz += nb->nb_dl.sz;
if (sz & 1) {
sz++;
}
/* Disable EMAC interrupts. */
AT91C_BASE_AIC->AIC_IDCR = (0x1 << AT91C_ID_EMAC);
/* TODO: Check for link. */
if (ni->ni_insane == 0) {
buf = (u_char *) txBufTab[bufnum].addr;
memcpy(buf, nb->nb_dl.vp, nb->nb_dl.sz);
buf += nb->nb_dl.sz;
memcpy(buf, nb->nb_nw.vp, nb->nb_nw.sz);
buf += nb->nb_nw.sz;
memcpy(buf, nb->nb_tp.vp, nb->nb_tp.sz);
buf += nb->nb_tp.sz;
memcpy(buf, nb->nb_ap.vp, nb->nb_ap.sz);
sz |= TXS_LAST_BUFF;
if (bufnum) {
sz |= TXS_WRAP;
}
txBufTab[bufnum].stat = sz;
AT91C_BASE_EMACB->EMAC_NCR |= AT91C_EMAC_TSTART;
rc = 0;
#ifdef NUT_PERFMON
ni->ni_tx_packets++;
#endif
}
/* Enable EMAC interrupts. */
AT91C_BASE_AIC->AIC_IECR = (0x1 << AT91C_ID_EMAC);
return rc;
}
/*!
* \brief Fire up the network interface.
*
* NIC interrupts must be disabled when calling this function.
*
* \param mac Six byte unique MAC address.
*/
static int EmacStart(CONST u_char * mac)
{
u_int i;
/* Set local MAC address. */
AT91C_BASE_EMACB->EMAC_SA1L = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0];
AT91C_BASE_EMACB->EMAC_SA1H = (mac[5] << 8) | mac[4];
/* Initialize receive buffer descriptors. */
memset((void *)rxBuf, 0, sizeof(rxBuf));
for (i = 0; i < EMAC_RX_BUFFERS - 1; i++) {
rxBufTab[i].addr = (u_int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK;
rxBufTab[i].stat = 0;
}
rxBufTab[i].addr = ((u_int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK) | RXBUF_WRAP;
rxBufTab[i].stat = 0;
AT91C_BASE_EMACB->EMAC_RBQP = (u_int) rxBufTab;
/* Initialize transmit buffer descriptors. */
memset((void *)txBuf, 0, sizeof(txBuf));
txBufTab[0].addr = (u_int) (&txBuf[0]);
txBufTab[0].stat = TXS_USED;
txBufTab[1].addr = (u_int) (&txBuf[EMAC_TX_BUFSIZ]);
txBufTab[1].stat = TXS_USED | TXS_WRAP;
AT91C_BASE_EMACB->EMAC_TBQP = (u_int) txBufTab;
/* Clear receiver status. */
AT91C_BASE_EMACB->EMAC_RSR = AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA;
/* Copy all frames and discard FCS. */
AT91C_BASE_EMACB->EMAC_NCFGR |= AT91C_EMAC_CAF | AT91C_EMAC_DRFCS;
/* Enable receiver, transmitter and statistics. */
AT91C_BASE_EMACB->EMAC_NCR |= AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT;
return 0;
}
/*! \fn EmacRxThread(void *arg)
* \brief NIC receiver thread.
*
*/
THREAD(EmacRxThread, arg)
{
NUTDEVICE *dev;
IFNET *ifn;
EMACINFO *ni;
NETBUF *nb;
dev = arg;
ifn = (IFNET *) dev->dev_icb;
ni = (EMACINFO *) dev->dev_dcb;
/*
* This is a temporary hack. Due to a change in initialization,
* we may not have got a MAC address yet. Wait until one has been
* set.
*/
for (;;) {
int i;
for (i = 0; i < sizeof(ifn->if_mac); i++) {
if (ifn->if_mac[i] && ifn->if_mac[i] != 0xFF) {
break;
}
}
if (i < sizeof(ifn->if_mac)) {
break;
}
NutSleep(63);
}
/*
* Do not continue unless we managed to start the NIC. We are
* trapped here if the Ethernet link cannot be established.
* This happens, for example, if no Ethernet cable is plugged
* in.
*/
while (EmacStart(ifn->if_mac)) {
EmacReset(EMAC_LINK_LOOPS);
NutSleep(1000);
}
/* Initialize the access mutex. */
NutEventPost(&ni->ni_mutex);
/* Run at high priority. */
NutThreadSetPriority(NUT_THREAD_NICRX_PRIORITY);
/* Enable receive and transmit interrupts. */
AT91C_BASE_EMACB->EMAC_IER = AT91C_EMAC_ROVR | AT91C_EMAC_TCOMP | AT91C_EMAC_TUNDR | AT91C_EMAC_RXUBR | AT91C_EMAC_RCOMP;
AT91C_BASE_AIC->AIC_IECR = (0x1 << AT91C_ID_EMAC);
for (;;) {
/*
* Wait for the arrival of new packets or poll the receiver every
* 200 milliseconds. This short timeout helps a bit to deal with
* the SAM9260 Ethernet problem.
*/
NutEventWait(&ni->ni_rx_rdy, 200);
/*
* Fetch all packets from the NIC's internal buffer and pass
* them to the registered handler.
*/
while (EmacGetPacket(ni, &nb) == 0) {
/* Discard short packets. */
if (nb->nb_dl.sz < 60) {
NutNetBufFree(nb);
} else {
(*ifn->if_recv) (dev, nb);
}
}
AT91C_BASE_EMACB->EMAC_IER = AT91C_EMAC_ROVR | AT91C_EMAC_RXUBR | AT91C_EMAC_RCOMP;
/* We got a weird chip, try to restart it. */
while (ni->ni_insane) {
EmacReset(EMAC_LINK_LOOPS);
if (EmacStart(ifn->if_mac) == 0) {
ni->ni_insane = 0;
ni->ni_tx_queued = 0;
ni->ni_tx_quelen = 0;
AT91C_BASE_AIC->AIC_IECR = (0x1 << AT91C_ID_EMAC);
} else {
NutSleep(1000);
}
}
}
}
/*!
* \brief Send Ethernet packet.
*
* \param dev Identifies the device to use.
* \param nb Network buffer structure containing the packet to be sent.
* The structure must have been allocated by a previous
* call NutNetBufAlloc().
*
* \return 0 on success, -1 in case of any errors.
*/
int EmacOutput(NUTDEVICE * dev, NETBUF * nb)
{
static u_long mx_wait = 5000;
int rc = -1;
EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
/*
* After initialization we are waiting for a long time to give
* the PHY a chance to establish an Ethernet link.
*/
while (rc) {
if (ni->ni_insane) {
break;
}
if (NutEventWait(&ni->ni_mutex, mx_wait)) {
break;
}
/* Check for packet queue space. */
if ((txBufTab[txBufIdx].stat & TXS_USED) == 0) {
if (NutEventWait(&ni->ni_tx_rdy, 500) && (txBufTab[txBufIdx].stat & TXS_USED) == 0) {
/* No queue space. Release the lock and give up. */
txBufTab[txBufIdx].stat |= TXS_USED;
txBufIdx++;
txBufIdx &= 1;
NutEventPost(&ni->ni_mutex);
break;
}
} else {
if (AT91C_BASE_EMACB->EMAC_TSR & AT91C_EMAC_UND) {
txBufIdx = 0;
AT91C_BASE_EMACB->EMAC_TSR = AT91C_EMAC_UND;
}
if (AT91C_BASE_EMACB->EMAC_TSR & AT91C_EMAC_COMP) {
AT91C_BASE_EMACB->EMAC_TSR = AT91C_EMAC_COMP;
}
if ((rc = EmacPutPacket(txBufIdx, ni, nb)) == 0) {
txBufIdx++;
txBufIdx &= 1;
}
}
NutEventPost(&ni->ni_mutex);
}
/*
* Probably no Ethernet link. Significantly reduce the waiting
* time, so following transmission will soon return an error.
*/
if (rc) {
mx_wait = 500;
} else {
/* Ethernet works. Set a long waiting time in case we
temporarly lose the link next time. */
mx_wait = 5000;
}
return rc;
}
/*!
* \brief Initialize Ethernet hardware.
*
* Applications should do not directly call this function. It is
* automatically executed during during device registration by
* NutRegisterDevice().
*
* \param dev Identifies the device to initialize.
*/
int EmacInit(NUTDEVICE * dev)
{
EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
/* Reset the controller. */
if (EmacReset(EMAC_LINK_LOOPS)) {
if (EmacReset(EMAC_LINK_LOOPS)) {
//debug_printf("Init 1\n");
return -1;
}
}
/* Clear EMACINFO structure. */
memset(ni, 0, sizeof(EMACINFO));
/* Register interrupt handler. */
AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, // AIC base address
AT91C_ID_EMAC, // Peripheral ID
EMAC_PRIORITY, // Priority
AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED, // Level sensitive
EmacInterrupt );
/* Set the interrupt argument. */
IntArg = (void *) dev;
/* Start the receiver thread. */
if (NutThreadCreate("emacrx", EmacRxThread, dev, NUT_THREAD_NICRX_STACK) == NULL) {//THREAD(EmacRxThread, arg)
//debug_printf("Init 2\n");
return -1;
}
//debug_printf("Co");
return 0;
}
#endif
DevEmac.h。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#ifndef DEVEMAC_H
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define DEVEMAC_H
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
/******************************************************************************
* *
* G L O B A L D E F I N E S *
* *
******************************************************************************/
#ifndef DEV_ETHER
#define DEV_ETHER devEMAC
#endif
#ifndef DEV_ETHER_NAME
#define DEV_ETHER_NAME "eth0"
#endif
/******************************************************************************
* *
* S T R U C T U R E D E F I N I T I O N S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - N O I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - I N I T I A L I Z E R S *
* *
******************************************************************************/
/*
* Available drivers.
*/
extern NUTDEVICE devEMAC;
/******************************************************************************
* *
* F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
#ifdef __cplusplus
} /* End of extern "C" { */
#endif /* __cplusplus */
#endif