⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ax88796.c

📁 含有完整TCP/IP PPP协议的嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2003-2005 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of *    contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * * -- * Initially taken from Marek Hummel's port of the Realtek driver. * * Revision 1.0  2004/07/20 17:29:08  MarekH *//* * $Log: ax88796.c,v $ * Revision 1.2  2005/10/22 08:55:47  haraldkipp * CPU specific headers moved to subdirectories for the CPU family. * * Revision 1.1  2005/07/26 18:02:26  haraldkipp * Moved from dev. * * Revision 1.1  2005/04/05 17:47:48  haraldkipp * Initial check in. For ARM only. * */#include <arch/arm/at91.h>#include <string.h>//#include <stdio.h>#include <sys/atom.h>#include <sys/heap.h>#include <sys/thread.h>#include <sys/event.h>#include <sys/timer.h>#include <sys/confnet.h>#include <dev/irqreg.h>#include <dev/ax88796.h>#include "reg_ax88796.h"#define ASIX_RESET_PIN 10static NICINFO dcb_eth0;/*! * \addtogroup xgNicAsix *//*@{*//*! * \brief Network interface information structure. * * Used to call. */static IFNET ifn_eth0 = {    IFT_ETHER,                  /*!< \brief Interface type. */    {0, 0, 0, 0, 0, 0},         /*!< \brief Hardware net address. */    0,                          /*!< \brief IP address. */    0,                          /*!< \brief Remote IP address for point to point. */    0,                          /*!< \brief IP network mask. */    ETHERMTU,                   /*!< \brief Maximum size of a transmission unit. */    0,                          /*!< \brief Packet identifier. */    0,                          /*!< \brief Linked list of arp entries. */    NutEtherInput,              /*!< \brief Routine to pass received data to, if_recv(). */    AsixOutput,                 /*!< \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 devAx88796 = {    0,                          /* Pointer to next device. */    {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        /* Unique device name. */    IFTYP_NET,                  /* Type of device. */    0,                          /* Base address. */    0,                          /* First interrupt number. */    &ifn_eth0,                  /* Interface control block. */    &dcb_eth0,                  /* Driver control block. */    AsixInit,                   /* Driver initialization routine. */    0,                          /* Driver specific control function. */    0,                          /* Read from device. */    0,                          /* Write to device. */    0,                          /* Open a device or file. */    0,                          /* Close a device or file. */    0                           /* Request file size. */};/*! * Asix packet header. */struct nic_pkt_header {    u_char ph_status;           /*!< \brief Status, contents of RSR register */    u_char ph_nextpg;           /*!< \brief Page for next packet */    u_short ph_size;            /*!< \brief Size of header and packet in octets */};/* * This delay has been added by Bengt Florin and is used to minimize  * the effect of the IORDY line during reads. Bengt contributed a * more versatile loop, which unfortunately wasn't portable to the * ImageCraft compiler. * * Both versions depend on the CPU clock and had been tested with * 14.7456 MHz. */void Delay16Cycles(void){    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");    asm volatile ("nop");}//==============================================================================/*! * \brief Read and write MII bus. * * */static u_short MIIPutGet(u_short data, u_char bitCount){    u_short rc = 0;    u_short mask;    u_char i;    mask = 1 << (bitCount - 1);    for (i = 0; i < bitCount; i++) {        /* send data to MII */        if (data & mask) {            Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDO));        } else {            Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDO)));        }        /* clock and data recieve from MII */        Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDC));        //clock up        Delay16Cycles();        data <<= 1;        rc <<= 1;        rc |= (Asix_Read(MII_EEP) & MII_EEP_MDI) != 0;  //read MII        Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDC)));     //clock down    }    return rc;}//==============================================================================/*! * \brief Read contents of internel PHY register on 0x10 adress. * * * \return Contents of the specified register. */u_short NicPhyRead(u_char reg){    u_short rc = 0;    /* Select Bank 0. */    Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));    /* Preamble. Send idle pattern, 32 '1's to synchronize MII. */    MIIPutGet(0xFFFF, 16);    MIIPutGet(0xFFFF, 16);    /* Start(01), Read(10), PhyAdr(10000) */    MIIPutGet(0xD0, 9);    /* Reg address<5:0> */    MIIPutGet(reg, 5);    /* TA(Z0), no support high-Z */    MIIPutGet(0x0, 1);    /* Read data from internel PHY */    rc = MIIPutGet(0, 16);    return rc;}//==============================================================================/*! * \brief Write value to PHY register. * * \note NIC interrupts must have been disabled before calling this routine. * * \param reg PHY register number. * \param val Value to write. */void NicPhyWrite(u_char reg, u_short val){    /* Select Bank 0. */    Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));    /* Preamble. Send idle pattern, 32 '1's to synchronize MII. */    MIIPutGet(0xFFFF, 16);    MIIPutGet(0xFFFF, 16);    /* Start(01), Write(01), PhyAdr(10000) */    MIIPutGet(0xB0, 9);    /* Reg address<5:0> */    MIIPutGet(reg, 5);    /* TA(01) */    MIIPutGet(0x02, 2);    /* Write data to internel PHY */    MIIPutGet(val, 16);}//==============================================================================/*! * Complete remote DMA. */static void NicCompleteDma(void){    u_char i;    /* Check that we have a DMA complete flag. */    do {        i = Asix_Read(PG0_ISR);    } while ((i & ISR_RDC) == 0);    /* Complete remote dma. */    Asix_Write(CR, CR_START | CR_RD2);    /* Reset remote dma complete flag. */    Asix_Write(PG0_ISR, ISR_RDC);    /* Wait for intterupt flag. */    Delay16Cycles();}//==============================================================================/*! * \brief Reset the Ethernet controller. * * \return 0 on success, -1 otherwise. */static int NicReset(void){    int tmp;    //u_short test;    //printf("NicReset()\n");    outr(PIO_PER, _BV(ASIX_RESET_PIN));  /* Set PIO Enable Register */    outr(PIO_OER, _BV(ASIX_RESET_PIN));  /* Set PIO Status Register */    outr(PIO_SODR, _BV(ASIX_RESET_PIN)); /* ASIX_RESET_PIN = 1 */    NutDelay(100);    outr(PIO_CODR, _BV(ASIX_RESET_PIN)); /* ASIX_RESET_PIN = 0 */    /* wait for PHY to come out of reset. */    tmp = 10;    while (1) {        NutDelay(255);        if (!(Asix_Read(TR) & TR_RST_B))            break;        if (tmp-- == 0)            return -1;    }    //test = NicPhyRead(PHY_MR2);    //printf("PHY_MR2 = 0x%.04x\n\r", test);    //test = NicPhyRead(PHY_MR3);    //printf("PHY_MR3 = 0x%.04x\n\r", test);/* Following actions will fix the problem of long auto negotiation. *///      NicPhyWrite(0x00,0x0800);//      NutSleep(2500);//      NicPhyWrite(0x00,0x1200); /* set speed to auto */    return 0;}//==============================================================================/* * Fires up the network interface. NIC interrupts * should have been disabled when calling this * function. * * \param mac Six byte unique MAC address. */static int NicStart(CONST u_char * mac){    u_char i;    //printf("NicStart()\n");    if (NicReset())        return -1;    /* Stop the NIC, abort DMA, page 0. */    Asix_Write(CR, (CR_RD2 | CR_STOP));    /* Selects word-wide DMA transfers. */    Asix_Write(PG0_DCR, DCR_WTS);    /* Load data byte count for remote DMA. */    Asix_Write(PG0_RBCR0, 0x00);    Asix_Write(PG0_RBCR1, 0x00);    /* Temporarily set receiver to monitor mode. */    Asix_Write(PG0_RCR, RCR_MON);    /* Transmitter set to internal loopback mode. */    Asix_Write(PG0_TCR, TCR_LB0);    /* Initialize Recieve Buffer Ring. */    Asix_Write(PG0_BNRY, RXSTART_INIT);    Asix_Write(PG0_PSTART, RXSTART_INIT);    Asix_Write(PG0_PSTOP, RXSTOP_INIT);    /* Clear interrupt status. */    Asix_Write(PG0_ISR, 0xFF);    /* Initialize interrupt mask. */    Asix_Write(PG0_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE);    /* Stop the NIC, abort DMA, page 1. */    Asix_Write(CR, (CR_PS0 | CR_RD2 | CR_STOP));    Delay16Cycles();    /* Set Physical address - MAC. */    for (i = 0; i < 6; i++) {        Asix_Write(PG1_PAR0 + i, mac[i]);    }    /* Set Multicast address. */    for (i = 0; i < 8; i++) {        Asix_Write(PG1_MAR0 + i, 0x00);    }    /* Set Current pointer point. */    Asix_Write(PG1_CPR, RXSTART_INIT + 1);    /* Start the NIC, Abort DMA, page 0. */    Asix_Write(CR, (CR_RD2 | CR_START));        // stop the NIC, abort DMA, page 0       Delay16Cycles();    /* Select media interfac. */    Asix_Write(GPOC, 0x10);    /* Check PHY speed setting 100base = full duplex, 10base > half duplex. */    if (Asix_Read(GPI) & 0x04) {        //printf("Full duplex\n");        Asix_Write(PG0_TCR, TCR_FDU);    }    else {        //printf("Half duplex\n");        Asix_Write(PG0_TCR, 0);    }    /* Enable receiver and set accept broadcast. */    //Asix_Write(PG0_RCR, (RCR_INTT | RCR_AB));    Asix_Write(PG0_RCR, RCR_AB);    return 0;}//==============================================================================/* * Write data block to the NIC. */static void NicWrite(u_char * buf, u_short len){    register u_short *wp = (u_short *) buf;    if (len & 1)        len++;    len >>= 1;    //printf("Write(%u): ", len);    while (len--) {        //printf("%04X ", *wp);        Asix_WriteWord(DATAPORT, *wp);        wp++;    }    //putchar('\n');}//==============================================================================/* * Read data block from the NIC. */static void NicRead(u_char * buf, u_short len){    register u_short *wp = (u_short *) buf;    if (len & 1)        len++;    len >>= 1;    //printf("Read(%u): ", len);    while (len--) {        *wp = Asix_ReadWord(DATAPORT);        //printf("%04X ", *wp);        wp++;    }    //putchar('\n');}//==============================================================================/*! * \brief Fetch the next packet out of the receive ring buffer. * * Nic interrupts must be disabled when calling this funtion. * * \return Pointer to an allocated ::NETBUF. If there is no *         no data available, then the function returns a *         null pointer. If the NIC's buffer seems to be *         corrupted, a pointer to 0xFFFF is returned. */static NETBUF *NicGetPacket(void){    NETBUF *nb = 0;    struct nic_pkt_header hdr;    u_short count;    u_char nextpg;    u_char bnry;    u_char curr;    u_char drop = 0;    /* we don't want to be interrupted by NIC owerflow */    NutEnterCritical();    /*     * Get the current page pointer. It points to the page where the NIC      * will start saving the next incoming packet.     */    curr = Asix_Read(PG0_CPR);    //printf("curr=%02X\n", curr);    /*     * Get the pointer to the last page we read from. The following page     * is the one where we start reading. If it's equal to the current     * page pointer, then there's nothing to read. In this case we return     * a null pointer.     */    if ((bnry = Asix_Read(PG0_BNRY) + 1) >= RXSTOP_INIT) {        //printf("bnry=%02X?\n", bnry);        bnry = RXSTART_INIT;    }    if (bnry == curr) {        //printf("bnry=%02X\n", bnry);        NutJumpOutCritical();        return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -