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

📄 nicrtl.c

📁 含有完整TCP/IP PPP协议的嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
     * a null pointer.     */    if ((bnry = nic_read(NIC_PG0_BNRY) + 1) >= NIC_STOP_PAGE)        bnry = NIC_FIRST_RX_PAGE;    if (bnry == curr)        return 0;    /*     * Read the NIC specific packet header.     */    nic_write(NIC_PG0_RBCR0, sizeof(struct nic_pkt_header));    nic_write(NIC_PG0_RBCR1, 0);    nic_write(NIC_PG0_RSAR0, 0);    nic_write(NIC_PG0_RSAR1, bnry);    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD0);    buf = (u_short *) & hdr;    NicMcu16bitBus();           /* Switch MCU data bus to 16-bit mode */    *buf++ = nic_read_dma();    /* Read status byte and next page pointer */    *buf = nic_read_dma();      /* Read frame length */    NicMcu8bitBus();            /* Switch MCU data bus to 8-bit mode */    NicCompleteDma(base);#ifdef __BIG_ENDIAN__    hdr.ph_size = __byte_swap2(hdr.ph_size);#endif    /*     *  Check packet length.     */    if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1518 + sizeof(struct nic_pkt_header)) {        return dflg ? 0 : (NETBUF *) - 1;    }    /*     * Calculate the page of the next packet. If it differs from the     * pointer in the packet header, we discard the whole buffer     * and return a null pointer.     */    nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);    if (nextpg >= NIC_STOP_PAGE) {        nextpg -= NIC_STOP_PAGE;        nextpg += NIC_FIRST_RX_PAGE;    }    if (nextpg != hdr.ph_nextpg) {        u_char nextpg1 = nextpg + 1;        if (nextpg1 >= NIC_STOP_PAGE) {            nextpg1 -= NIC_STOP_PAGE;            nextpg1 += NIC_FIRST_RX_PAGE;        }        if (nextpg1 != hdr.ph_nextpg) {            return dflg ? 0 : (NETBUF *) - 1;        }        nextpg = nextpg1;    }    /*     * Check packet status. It should have set bit 0, but     * even without this bit packets seem to be OK.     */    if ((hdr.ph_status & 0x0E) == 0) {        /*         * Allocate a NETBUF.         */        count = hdr.ph_size - sizeof(struct nic_pkt_header);        if (dflg == 0) {            nb = NutNetBufAlloc(0, NBAF_DATALINK, count);        }        /*         * Set remote dma byte count and         * start address. Don't read the         * header again.         */        nic_write(NIC_PG0_RBCR0, count);        nic_write(NIC_PG0_RBCR1, count >> 8);        nic_write(NIC_PG0_RSAR0, sizeof(struct nic_pkt_header));        nic_write(NIC_PG0_RSAR1, bnry);        /*         * Perform the read.         */        nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD0);        /*         * Switch MCU data bus to 16-bit mode         */        NicMcu16bitBus();        count = (count + 1) >> 1;        if (nb) {            buf = nb->nb_dl.vp;            for (i = 0; i < count; i++)                *buf++ = nic_read_dma();        } else {            for (i = 0; i < count; i++)                nic_read_dma();        }        /*         * Switch MCU data bus to 8-bit mode         */        NicMcu8bitBus();        /*         * Complete remote dma.         */        NicCompleteDma(base);    }    /*     * Set boundary register to the last page we read.     */    if (--nextpg < NIC_FIRST_RX_PAGE)        nextpg = NIC_STOP_PAGE - 1;    nic_write(NIC_PG0_BNRY, nextpg);    return dflg ? (NETBUF *) ((uptr_t) dflg) : nb;}/* * When a receiver buffer overflow occurs, the NIC will defer any * subsequent action until properly restarted. */static int NicOverflow(volatile u_char * base){    u_char cr;    u_char resend;    /*     * Save the command register, so we can later determine, if NIC     * transmitter has been interrupted. Then stop the NIC and wait     * 5 ms for any transmission or reception in progress.     */    cr = nic_read(NIC_CR);    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);    NutDelay(WAIT5);    /*     * Clear remote byte count register.     */    nic_write(NIC_PG0_RBCR0, 0);    nic_write(NIC_PG0_RBCR1, 0);    /*     * Check for any incomplete transmission.     */    resend = 0;    if (cr & NIC_CR_TXP) {        if ((nic_read(NIC_PG0_ISR) & (NIC_ISR_PTX | NIC_ISR_TXE)) == 0)            resend = 1;    }    /*     * Enter loopback mode and restart the NIC.     */    nic_write(NIC_PG0_TCR, NIC_TCR_LB0);    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);    /*     * Discard all packets from the receiver buffer.     */    while (NicGetPacket(base, 1));    /*     * Switch from loopback to normal mode mode.     */    nic_write(NIC_PG0_TCR, 0);    /*     * Re-invoke any interrupted transmission.     */    if (resend) {        nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);    }    /* Finally clear the overflow flag. */    nic_write(NIC_PG0_ISR, NIC_ISR_OVW);    return resend;}/* * NIC interrupt entry. */static void NicInterrupt(void *arg){    u_char isr;    volatile u_char *base = (u_char *) (((NUTDEVICE *) arg)->dev_base);    NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;    ni->ni_interrupts++;    isr = nic_read(NIC_PG0_ISR);    nic_write(NIC_PG0_ISR, isr);    /*     * Recover from receive buffer overflow. This may take some     * time, so we enable global interrupts but keep NIC     * interrupts disabled.     */    if (isr & NIC_ISR_OVW) {        NicDisableInt();        NutEnableInt();        ni->ni_rx_pending++;        if (NicOverflow(base))            ni->ni_tx_bsy++;        else {            NutEventPostFromIrq(&ni->ni_tx_rdy);        }        ni->ni_overruns++;        NutDisableInt();        NicEnableInt();    } else {        /*         * If this is a transmit interrupt, then a packet has been sent.          * So we can clear the transmitter busy flag and wake up the          * transmitter thread.         */        if (isr & (NIC_ISR_PTX | NIC_ISR_TXE)) {            ni->ni_tx_bsy = 0;            NutEventPostFromIrq(&ni->ni_tx_rdy);        }        /*         * If this is a receive interrupt, then wake up the receiver          * thread.         */        if (isr & NIC_ISR_PRX) {            ni->ni_rx_pending++;            NutEventPostFromIrq(&ni->ni_rx_rdy);        }        if (isr & NIC_ISR_RXE) {            ni->ni_rx_frame_errors += nic_read(NIC_PG0_CNTR0);            ni->ni_rx_crc_errors += nic_read(NIC_PG0_CNTR1);            ni->ni_rx_missed_errors += nic_read(NIC_PG0_CNTR2);        }    }}/*! \fn NicRx(void *arg) * \brief NIC receiver thread. * *  * It runs with high priority. */THREAD(NicRx, arg){    NUTDEVICE *dev;    IFNET *ifn;    NICINFO *ni;    NETBUF *nb;    u_char rlcnt;    dev = arg;    ifn = (IFNET *) dev->dev_icb;    ni = (NICINFO *) dev->dev_dcb;    NutThreadSetPriority(9);    /*     * 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.     */    if ((ifn->if_mac[0] & ifn->if_mac[1] & ifn->if_mac[2]) == 0xFF) {        while ((ifn->if_mac[0] & ifn->if_mac[1] & ifn->if_mac[2]) == 0xFF)            NutSleep(125);        NicDisableInt();        NicStart((u_char *) (dev->dev_base), ifn->if_mac);        ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;        NicEnableInt();    }    for (;;) {        /*         * Wait for the arrival of new packets or check         * the receiver every two second.         */        if (ni->ni_rx_pending > 10) {            NicDisableInt();            if (NicStart((u_char *) (dev->dev_base), ifn->if_mac) == 0)                ni->ni_rx_pending = 0;            ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;            NicEnableInt();        }        NutEventWait(&ni->ni_rx_rdy, 2000);        /*         * Fetch all packets from the NIC's internal         * buffer and pass them to the registered handler.         */        rlcnt = 0;        NicDisableInt();        while (rlcnt++ < 10) {            if ((nb = NicGetPacket((u_char *) (dev->dev_base), 0)) == 0)                break;            /* The sanity check may fail because the controller is too busy.               try another read before giving up and restarting the NIC. */            if (nb == (void *) -1) {                if ((nb = NicGetPacket((u_char *) (dev->dev_base), 0)) == 0)                    break;            }            if (nb == (void *) -1) {                if (NicStart((u_char *) (dev->dev_base), ifn->if_mac) == 0)                    ni->ni_rx_pending = 0;                ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;                ni->ni_rx_pending = 0;            } else {                ni->ni_rx_pending = 0;                ni->ni_rx_packets++;                NicEnableInt();                (*ifn->if_recv) (dev, nb);                NicDisableInt();            }        }        NicEnableInt();    }}/*! * \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 NicOutput(NUTDEVICE * dev, NETBUF * nb){    int rc = -1;    NICINFO *ni;    u_char retries = 10;    u_char sigmod = 0;    ni = (NICINFO *) dev->dev_dcb;    while (ni->ni_tx_bsy && retries--) {        if (NutEventWait(&ni->ni_tx_rdy, 200)) {            volatile u_char *base = (u_char *) (dev->dev_base);            /*             * If hanging around here too long, there's something wrong              * with the transmit interrupt. Force sending the packet,              * if the transmitter has become inactive.             */            if (NicIntIsEnabled()) {                NicDisableInt();                sigmod = 1;            }            if ((nic_read(NIC_CR) & NIC_CR_TXP) == 0)                ni->ni_tx_bsy = 0;            if (sigmod) {                NicEnableInt();                sigmod = 0;            }        }    }    if (NicIntIsEnabled()) {        NicDisableInt();        sigmod = 1;    }    if (ni->ni_tx_bsy == 0) {        ni->ni_tx_bsy++;        if (NicPutPacket((u_char *) (dev->dev_base), nb) == 0) {            ni->ni_tx_packets++;            rc = 0;        }    }    if (sigmod)        NicEnableInt();    return rc;}/*! * \brief Initialize Ethernet hardware. * * Resets RTL8019AS Ethernet controller, initializes all required  * hardware registers and starts a background thread for incoming  * Ethernet traffic. * * Applications should do not directly call this function. It is  * automatically executed during during device registration by  * NutRegisterDevice(). * * If the network configuration hasn't been set by the application * before registering the specified device, this function will * call NutNetLoadConfig() to get the MAC address. * * \param dev Identifies the device to initialize. */int NicInit(NUTDEVICE * dev){    volatile u_char *base;    IFNET *ifn;    NICINFO *ni;    /*     * We need to know our MAC address. If no configuration is      * available, load it now.     */    if (confnet.cd_size == 0)        NutNetLoadConfig(dev->dev_name);    ifn = dev->dev_icb;    memcpy(ifn->if_mac, confnet.cdn_mac, 6);    ni = (NICINFO *) dev->dev_dcb;    memset(ni, 0, sizeof(NICINFO));    base = (u_char *) (dev->dev_base);    NicDisableInt();    NutInitSysIrq();    if (ifn->if_mac[0] | ifn->if_mac[1] | ifn->if_mac[2])        if (NicStart(base, ifn->if_mac))            return -1;    ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;    /*     * Start the receiver thread.     */    NutThreadCreate("rxi0", NicRx, dev, 640);    NutSleep(WAIT500);    /*     * Register interrupt handler and enable interrupts.     */    if (NutRegisterIrqHandler(&RTL_SIGNAL, NicInterrupt, dev))        return -1;    NicEnableInt();    return 0;}/*! * \brief Network interface device control block structure. * * Used to call. */static NICINFO dcb_eth0rtl;/*! * \brief Network interface information structure. * * Used to call. */static IFNET ifn_eth0rtl = {    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(). */    NicOutput,                  /*!< \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 devEth0 = {    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_eth0rtl,               /* Interface control block. */    &dcb_eth0rtl,               /* Driver control block. */    NicInit,                    /* Driver initialization routine. */    0,                          /* Driver specific control function. */    0,                          /* Read from device. */    0,                          /* Write to device. */    /* Write from program space data to device. */    0,                          /* Open a device or file. */    0,                          /* Close a device or file. */    0                           /* Request file size. */};/*@}*/

⌨️ 快捷键说明

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