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

📄 dm9000e.c

📁 avr上的RTOS
💻 C
📖 第 1 页 / 共 2 页
字号:
    len = (len + 1) / 2;    while (len--) {        *wp++ = inw(NIC_DATA_ADDR);    }}/*! * \brief Fetch the next packet out of the receive ring buffer. * * \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 int NicGetPacket(NICINFO * ni, NETBUF ** nbp){    int rc = -1;    u_short fsw;    u_short fbc;    *nbp = NULL;    /* Disable NIC interrupts. */    NutIrqDisable(&NIC_SIGNAL);    /*      * Read the status word w/o auto increment. If zero, no packet is      * available. Otherwise it should be set to one. Any other value      * indicates a weird chip crying for reset.     */    nic_inb(NIC_MRCMDX);    fsw = inb(NIC_DATA_ADDR);    if (fsw > 1) {        ni->ni_insane = 1;    } else if (fsw) {        /* Now read status word and byte count with auto increment. */        outb(NIC_BASE_ADDR, NIC_MRCMD);        if (ni->ni_iomode == NIC_ISR_M16) {            fsw = inw(NIC_DATA_ADDR);            fbc = inw(NIC_DATA_ADDR);        } else {            fsw = inb(NIC_DATA_ADDR) + ((u_short) inb(NIC_DATA_ADDR) << 8);            fbc = inb(NIC_DATA_ADDR) + ((u_short) inb(NIC_DATA_ADDR) << 8);        }        /*         * Receiving long packets is unexpected, because we disabled          * this during initialization. Let's declare the chip insane.         * Short packets will be handled by the caller.         */        if (fbc > 1536) {            ni->ni_insane = 1;        } else {            /*             * The high byte of the status word contains a copy of the              * receiver status register.             */            fsw >>= 8;            fsw &= NIC_RSR_ERRORS;#ifdef NUT_PERMON            /* Update statistics. */            if (fsw) {                if (RxStatus & NIC_RSR_CE) {                    ni->ni_crc_errors++;                } else if (RxStatus & NIC_RSR_FOE) {                    ni->ni_overruns++;                } else {                    ni->ni_rx_missed_errors++;                }            } else {                ni->ni_rx_packets++;            }#endif            /*              * If we got an error packet or failed to allocated the             * buffer, then silently discard the packet.             */            if (fsw || (*nbp = NutNetBufAlloc(0, NBAF_DATALINK, fbc - 4)) == NULL) {                if (ni->ni_iomode == NIC_ISR_M16) {                    fbc = (fbc + 1) / 2;                    while (fbc--) {                        fsw = inw(NIC_DATA_ADDR);                    }                } else {                    while (fbc--) {                        fsw = inb(NIC_DATA_ADDR);                    }                }            } else {                if (ni->ni_iomode == NIC_ISR_M16) {                    /* Read packet data from 16 bit bus. */                    NicRead16((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);                    /* Read packet CRC. */                    fsw = inw(NIC_DATA_ADDR);                    fsw = inw(NIC_DATA_ADDR);                } else {                    /* Read packet data from 8 bit bus. */                    NicRead8((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);                    /* Read packet CRC. */                    fsw = inb(NIC_DATA_ADDR);                    fsw = inb(NIC_DATA_ADDR);                    fsw = inb(NIC_DATA_ADDR);                    fsw = inb(NIC_DATA_ADDR);                }                /* Return success. */                rc = 0;            }        }    }    /* Enable NIC interrupts if the chip is sane. */    if (ni->ni_insane == 0) {        NutIrqEnable(&NIC_SIGNAL);    }    return rc;}/*! * \brief Load a packet into the nic's transmit ring buffer. * * \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 NicPutPacket(NICINFO * ni, NETBUF * nb){    int rc = -1;    u_short sz;    /*     * 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 interrupts. */    NutIrqDisable(&NIC_SIGNAL);    /* TODO: Check for link. */    if (ni->ni_insane == 0) {        /* Enable data write. */        outb(NIC_BASE_ADDR, NIC_MWCMD);        /* Transfer the Ethernet frame. */        if (ni->ni_iomode == NIC_ISR_M16) {            NicWrite16(nb->nb_dl.vp, nb->nb_dl.sz);            NicWrite16(nb->nb_nw.vp, nb->nb_nw.sz);            NicWrite16(nb->nb_tp.vp, nb->nb_tp.sz);            NicWrite16(nb->nb_ap.vp, nb->nb_ap.sz);        } else {            NicWrite8(nb->nb_dl.vp, nb->nb_dl.sz);            NicWrite8(nb->nb_nw.vp, nb->nb_nw.sz);            NicWrite8(nb->nb_tp.vp, nb->nb_tp.sz);            NicWrite8(nb->nb_ap.vp, nb->nb_ap.sz);        }        /* If no packet is queued, start the transmission. */        if (ni->ni_tx_queued == 0) {            nic_outb(NIC_TXPL, (u_char) sz);            nic_outb(NIC_TXPL + 1, (u_char) (sz >> 8));            nic_outb(NIC_TCR, NIC_TCR_TXREQ);        }        /* ...otherwise mark this packet queued. */        else {            ni->ni_tx_quelen = sz;        }        ni->ni_tx_queued++;        rc = 0;#ifdef NUT_PERFMON        ni->ni_tx_packets++;#endif    }    /* Enable interrupts. */    NutIrqEnable(&NIC_SIGNAL);    /* If the controller buffer is filled with two packets, then       wait for the first being sent out. */    if (rc == 0 && ni->ni_tx_queued > 1) {        NutEventWait(&ni->ni_tx_rdy, 500);    }    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 NicStart(CONST u_char * mac){    int i;    int link_wait = 20;    /* Power up the PHY. */    nic_outb(NIC_GPR, 0);    NutDelay(5);    /* Software reset with MAC loopback. */    nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);    NutDelay(5);    nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);    NutDelay(5);    /*      * PHY power down followed by PHY power up. This should activate      * the auto sense link.     */    nic_outb(NIC_GPR, 1);    nic_outb(NIC_GPR, 0);    /* Set MAC address. */    for (i = 0; i < 6; i++) {        nic_outb(NIC_PAR + i, mac[i]);    }    /* Enable broadcast receive. */    for (i = 0; i < 7; i++) {        nic_outb(NIC_MAR + i, 0);    }    nic_outb(NIC_MAR + 7, 0x80);    /* Clear interrupts. */    nic_outb(NIC_ISR, NIC_ISR_ROOS | NIC_ISR_ROS | NIC_ISR_PTS | NIC_ISR_PRS);    /* Enable receiver. */    nic_outb(NIC_RCR, NIC_RCR_DIS_LONG | NIC_RCR_DIS_CRC | NIC_RCR_RXEN);    /* Wait for link. */    for (link_wait = 20;; link_wait--) {        if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {            break;        }        if (link_wait == 0) {            return -1;        }        NutSleep(200);    }    /* Enable interrupts. */    nic_outb(NIC_IMR, NIC_IMR_PAR | NIC_IMR_PTM | NIC_IMR_PRM);    return 0;}/*! \fn NicRxLanc(void *arg) * \brief NIC receiver thread. * */THREAD(NicRxLanc, arg){    NUTDEVICE *dev;    IFNET *ifn;    NICINFO *ni;    NETBUF *nb;    dev = arg;    ifn = (IFNET *) dev->dev_icb;    ni = (NICINFO *) 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 (;;) {        if (*((u_long *) (ifn->if_mac)) && *((u_long *) (ifn->if_mac)) != 0xFFFFFFFFUL) {            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 (NicStart(ifn->if_mac)) {        NutSleep(1000);    }    /* Initialize the access mutex. */    NutEventPost(&ni->ni_mutex);    /* Run at high priority. */    NutThreadSetPriority(9);    /* Enable interrupts for P10. */    outr(PIO_PDR, _BV(10));    NutIrqEnable(&NIC_SIGNAL);    for (;;) {        /*         * Wait for the arrival of new packets or poll the receiver          * every two seconds.         */        NutEventWait(&ni->ni_rx_rdy, 2000);        /*         * Fetch all packets from the NIC's internal buffer and pass          * them to the registered handler.         */        while (NicGetPacket(ni, &nb) == 0) {            /* Discard short packets. */            if (nb->nb_dl.sz < 60) {                NutNetBufFree(nb);            } else {                (*ifn->if_recv) (dev, nb);            }        }        /* We got a weird chip, try to restart it. */        while (ni->ni_insane) {            if (NicStart(ifn->if_mac) == 0) {                ni->ni_insane = 0;                ni->ni_tx_queued = 0;                ni->ni_tx_quelen = 0;                NutIrqEnable(&NIC_SIGNAL);            } 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 DmOutput(NUTDEVICE * dev, NETBUF * nb){    static u_long mx_wait = 5000;    int rc = -1;    NICINFO *ni = (NICINFO *) 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 (NutEventWait(&ni->ni_mutex, mx_wait)) {            break;        }        /* Check for packet queue space. */        if (ni->ni_tx_queued > 1) {            if (NutEventWait(&ni->ni_tx_rdy, 500)) {                /* No queue space. Release the lock and give up. */                NutEventPost(&ni->ni_mutex);                break;            }        } else if (NicPutPacket(ni, nb) == 0) {            /* Ethernet works. Set a long waiting time in case we               temporarly lose the link next time. */            rc = 0;            mx_wait = 5000;        }        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;    }    return rc;}/*! * \brief Initialize Ethernet hardware. * * Resets the LAN91C111 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 DmInit(NUTDEVICE * dev){    u_long id;    NICINFO *ni = (NICINFO *) dev->dev_dcb;    /* Probe chip by verifying the identifier registers. */    id = (u_long) nic_inb(NIC_VID);    id |= (u_long) nic_inb(NIC_VID + 1) << 8;    id |= (u_long) nic_inb(NIC_PID) << 16;    id |= (u_long) nic_inb(NIC_PID + 1) << 24;    if (id != 0x90000A46) {        return -1;    }    /* Reset chip. */    if (NicReset()) {        return -1;    }    /* Clear NICINFO structure. */    memset(ni, 0, sizeof(NICINFO));    /* Determine bus mode. We do not support 32 bit access. */    ni->ni_iomode = nic_inb(NIC_ISR) & NIC_ISR_IOM;    if (ni->ni_iomode == NIC_ISR_M32) {        return -1;    }    /* Register interrupt handler. */    if (NutRegisterIrqHandler(&NIC_SIGNAL, NicInterrupt, dev)) {        return -1;    }    /* Start the receiver thread. */    if (NutThreadCreate("rxi1", NicRxLanc, dev, NUT_THREAD_NICRXSTACK) == NULL) {        return -1;    }    return 0;}static NICINFO 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. */    NutEtherInput,              /*!< \brief Routine to pass received data to, if_recv(). */    DmOutput,                   /*!< \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 devDM9000E = {    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. */    DmInit,                     /*!< \brief Driver initialization routine. */    0,                          /*!< \brief Driver specific control function. */    0,                          /*!< \brief Read from device. */    0,                          /*!< \brief Write to device. */#ifdef __HARVARD_ARCH__    0,                          /*!< \brief Write from program space data to device. */#endif    0,                          /*!< \brief Open a device or file. */    0,                          /*!< \brief Close a device or file. */    0                           /*!< \brief Request file size. */};/*@}*/

⌨️ 快捷键说明

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