T168_111\device\EMAC文件:DevEmac.c

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值