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

📄 ax88796.c

📁 avr上的RTOS
💻 C
📖 第 1 页 / 共 2 页
字号:
    }    /*     * Read the NIC specific packet header (4 bytes).     */    Asix_Write(PG0_RBCR0, sizeof(struct nic_pkt_header));    Asix_Write(PG0_RBCR1, 0);    Asix_Write(PG0_RSAR0, 0);    Asix_Write(PG0_RSAR1, bnry);    Asix_Write(CR, CR_START | CR_RD0);    Delay16Cycles();    NicRead((u_char *) & hdr, sizeof(struct nic_pkt_header));    NicCompleteDma();    //printf("[S=%02X N=%02X L=%u]", hdr.ph_status, hdr.ph_nextpg, hdr.ph_size);    /*     *  Check packet length. Silently discard packets of illegal size.     */    if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1514 + sizeof(struct nic_pkt_header)) {        //printf("Drop\n");        drop = 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 = hdr.ph_nextpg;//  bnry = hdr.ph_nextpg - 1;//      if(bnry < RXSTART_INIT) bnry = RXSTOP_INIT - 1; //  printf("hdr.ph_size = %02u\n\r",hdr.ph_size);//  printf("hdr.ph_nextpg = %02x\n\r",hdr.ph_nextpg);    nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);    //printf("[nextpg = %02x ->", nextpg);    if (nextpg >= RXSTOP_INIT) {        nextpg -= RXSTOP_INIT;        nextpg += RXSTART_INIT;    }    if (nextpg != hdr.ph_nextpg) {        u_char nextpg1 = nextpg + 1;        if (nextpg1 >= RXSTOP_INIT) {            nextpg1 -= RXSTOP_INIT;            nextpg1 += RXSTART_INIT;        }        //HK if (nextpg1 != hdr.ph_nextpg) {        //HK    return (NETBUF *) 0xFFFF;        //HK }        nextpg = nextpg1;    }    //printf("%02x]", nextpg);    /*     * Check packet status. It should have set bit 0, but     * even without this bit packets seem to be OK.     */    //printf("Drop=%u Status=%02X\n", drop, hdr.ph_status & 0x0E);    if (!drop && ((hdr.ph_status & 0x0E) == 0)) {        /* Allocate a NETBUF. */        count = hdr.ph_size - sizeof(struct nic_pkt_header);        //printf("Count=%u\n", count);        if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, count))) {            /*             * Set remote dma byte count and             * start address. Don't read the             * header again.             */            Asix_Write(PG0_RBCR0, count);            Asix_Write(PG0_RBCR1, count >> 8);            Asix_Write(PG0_RSAR0, sizeof(struct nic_pkt_header));            Asix_Write(PG0_RSAR1, bnry);            /*             * Perform the read.             */            Asix_Write(CR, CR_START | CR_RD0);            Delay16Cycles();            NicRead(nb->nb_dl.vp, count);            NicCompleteDma();        }    }    /*     * Set boundary register to the last page we read.     * This also drops packets with errors     */    if (--nextpg < RXSTART_INIT)        nextpg = RXSTOP_INIT - 1;    Asix_Write(PG0_BNRY, nextpg);    NutExitCritical();    return nb;}//==============================================================================/* * \brief Handle NIC overflows. * * When a receiver buffer overflow occurs, the NIC will defer any subsequent  * action until properly restarted. * * This routine is called within interrupt context, which introduces a big * problem. It waits for the last transmission to finish, which may take * several milliseconds. Since Nut/OS 3.5, we do not support nested interrupts * on AVR systems anymore. So this routine may now increase interrupt * latency in an unacceptable way. The solution might be to handle overflows * in the receiver thread. * * In any case, this routines needs a major redesign. But it has been * tested in its current form to gracefully withstand ping floods. Thanks * to Bengt Florin for contributing his code, which provides much more * stability than its predecessor. */static u_char NicOverflow(volatile u_char * base){    u_int cr;    u_int resend = 0;    u_int curr;    /*     * Wait for any transmission in progress. Save the command register,      * so we can later determine, if NIC transmitter has been interrupted.      * or reception in progress.     */    while (Asix_Read(CR) & CR_TXP);    cr = Asix_Read(CR);    /*     * Get the current page pointer. It points to the page where the NIC      * will start saving the next incoming packet.     */    Asix_Write(CR, CR_STOP | CR_RD2 | CR_PS0);    curr = Asix_Read(PG1_CPR);    Asix_Write(CR, CR_STOP | CR_RD2);    /* Clear remote byte count register. */    Asix_Write(PG0_RBCR0, 0);    Asix_Write(PG0_RBCR1, 0);    /* Check for any incomplete transmission. */    if ((cr & CR_TXP) && ((Asix_Read(PG0_ISR) & (ISR_PTX | ISR_TXE)) == 0)) {        resend = 1;    }    /* Enter loopback mode and restart the NIC. */    Asix_Write(PG0_TCR, TCR_LB0);    Asix_Write(CR, CR_START | CR_RD2);    /*      * Discard all packets from the receiver buffer. Set boundary      * register to the last page we read.      */    if (--curr < TXSTART_INIT) {        curr = RXSTOP_INIT - 1;    }    Asix_Write(PG0_BNRY, curr);    /* Switch from loopback to normal mode mode. */    Asix_Write(PG0_TCR, 0);    /* Re-invoke any interrupted transmission. */    if (resend) {        Asix_Write(CR, CR_START | CR_TXP | CR_RD2);    }    /* Finally clear the overflow flag */    Asix_Write(PG0_ISR, ISR_OVW);    return resend;}//==============================================================================static int NicPutPacket(NETBUF * nb){    u_short sz;                 // packed size    u_short send_sz;            // send packed size, min 60    static u_char first_put = 0;    int tmp;    /*     * Fix problem after power on.     */    if (first_put != 1) {        Asix_Write(CR, 0x21);        NutDelay(1);        Asix_Write(CR, 0x22);        first_put = 1;    }    /*     * Calculate the number of bytes to be send. Do not     * send packets larger than 1518 bytes.     */    sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;    if (sz > 1518)        return -1;    //printf("Asix Send %u\n", sz);    /*     * Calculate the number of min bytes. Pad will be     * added when packet lenght less than 60. Enable in TCR reg. PD = 0.      */    send_sz = sz;    if (sz <= 60)        send_sz = 60;    /* Disable Asix interrupts. */    NutEnterCritical();    /* start the NIC */    Asix_Write(CR, (CR_RD2 | CR_START));    /*     * Bengt Florin introduces polling mode for the transmitter. Be     * aware, that this may introduce other problems. If a high     * priority thread is waiting for the transmitter, it may hold     * the CPU for more than 1.2 milliseconds in worst cases.     */    tmp = 120;    while ((Asix_Read(CR) & CR_TXP) && tmp--)        NutDelay(1);    /* set start address for remote DMA operation */    Asix_Write(PG0_RSAR0, 0x00);    Asix_Write(PG0_RSAR1, TXSTART_INIT);    /* load data byte count for remote DMA */    Asix_Write(PG0_RBCR0, (unsigned char) (sz));    Asix_Write(PG0_RBCR1, (unsigned char) (sz >> 8));    /* do remote write operation */    Asix_Write(CR, (CR_RD1 | CR_START));    /* Transfer the Ethernet frame. */    NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);    NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);    NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);    NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);    /* Complete remote dma. */    NicCompleteDma();    /* Clear interrupt flags. */    Asix_Write(PG0_ISR, (ISR_PTX | ISR_TXE));    Delay16Cycles();    /* Set size and pointer to data. */    Asix_Write(CR, CR_START | CR_RD2);    //printf("Asix Start Send\n");    Asix_Write(PG0_TBCR0, (unsigned char) (send_sz));    Asix_Write(PG0_TBCR1, (unsigned char) ((send_sz) >> 8));    Asix_Write(PG0_TPSR, TXSTART_INIT);    /* Start transmission. */    Asix_Write(CR, CR_START | CR_TXP | CR_RD2);    /* Enable Asix interrupts. */    NutExitCritical();    return 0;}//==============================================================================/*! * \brief NIC receiver thread. * */THREAD(NicRxAsix, arg){    NUTDEVICE *dev;    IFNET *ifn;    NICINFO *ni;    NETBUF *nb;    /* Hack! Unfortunately no parameter passing with ARM */    dev = &devAx88796;    ifn = (IFNET *) dev->dev_icb;    ni = (NICINFO *) dev->dev_dcb;    for (;;) {        if (*((u_long *) (ifn->if_mac)) && *((u_long *) (ifn->if_mac)) != 0xFFFFFFFFUL) {            break;        }        NutSleep(63);    }    NutEnterCritical();    NicStart(ifn->if_mac);    NutExitCritical();    /* Run at high priority. */    //printf("Increase prio\n");    NutThreadSetPriority(9);    while (1) {        //printf("-------- Wait rx\n");        NutEventWait(&ni->ni_rx_rdy, 0);        //printf("-------- Got rx\n");        /*         * Fetch all packets from the NIC's internal         * buffer and pass them to the registered handler.         */        do {            nb = NicGetPacket();            /* The sanity check may fail because the controller is too busy.               restart the NIC. */            if (0) {            //HK if ((u_short)nb == 0xFFFF) {                NicStart(ifn->if_mac);//                ni->ni_rx_size_errors++;            } else if (nb) {                ni->ni_rx_packets++;                (*ifn->if_recv) (dev, nb);            }        } while (nb);    }}//==============================================================================/* * 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 = Asix_Read(PG0_ISR);    Delay16Cycles();    Asix_Write(PG0_ISR, isr);    //if(isr)    //    printf("%02X\n", isr);    //else    //    return;    /*     * Recover from receive buffer overflow. This may take some     * time, so we enable global interrupts but keep NIC     * interrupts disabled.     */    if (isr & ISR_OVW) {        ni->ni_rx_pending++;        if (NicOverflow(base))            ni->ni_tx_bsy++;        else {            NutEventPostAsync(&ni->ni_tx_rdy);        }        ni->ni_overruns++;    } 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 & (ISR_PTX | ISR_TXE)) {            ni->ni_tx_bsy = 0;        }        /*         * If this is a receive interrupt, then wake up the receiver          * thread.         */        if (isr & ISR_PRX) {            ni->ni_rx_pending++;            //printf("Post %lX\n", (u_long) ni->ni_rx_rdy);            NutEventPostFromIrq(&ni->ni_rx_rdy);        }        /* Rx error. */        if (isr & ISR_RXE) {            if (Asix_Read(PG0_RSR) & RSR_FAE)                ni->ni_rx_frame_errors++;            if (Asix_Read(PG0_RSR) & RSR_CR)                ni->ni_rx_crc_errors++;            if (Asix_Read(PG0_RSR) & RSR_MPA)                ni->ni_rx_missed_errors++;        }    }}void NicInterruptEntry(void) __attribute__ ((naked));void NicInterruptEntry(void){    IRQ_ENTRY();    //putchar('i');    NicInterrupt(&devAx88796);    IRQ_EXIT();}//==============================================================================/*! * \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 AsixOutput(NUTDEVICE * dev, NETBUF * nb){    int rc = -1;    NICINFO *ni = (NICINFO *) dev->dev_dcb;    if (NicPutPacket(nb) == 0) {        ni->ni_tx_packets++;        rc = 0;    }    return rc;}CONFNET confnet;int NutNetSaveConfig(void){    return 0;}int NutNetLoadConfig(CONST char *name){    return -1;}//==============================================================================/*! * \brief Initialize Ethernet hardware. * * Resets the Asix Asix_L 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 AsixInit(NUTDEVICE * dev){    //printf("Set confnet\n");    confnet.cd_size = sizeof(CONFNET);    strcpy(confnet.cd_name, "eth0");    memset(confnet.cdn_mac, 0xFF, 6);    /* Disable NIC interrupt and clear NICINFO structure. */    //printf("Clear nicinfo\n");    memset(dev->dev_dcb, 0, sizeof(NICINFO));    /*     * Start the receiver thread.     */    //printf("Create rxi5(%lX)\n", (u_long) dev);    NutThreadCreate("rxi5", NicRxAsix, dev, 1024);    outr(PIO_PDR, _BV(9));    /* Register interrupt handler and enable interrupts. */    /* Disable timer 0 interrupts. */    outr(AIC_IDCR, _BV(IRQ0_ID));    /* Set the TC0 IRQ handler address */    outr(AIC_SVR(IRQ0_ID), (unsigned int) NicInterruptEntry);    /* Set the trigg and priority for timer 0 interrupt */    /* Level 7 is highest, level 0 lowest. */    outr(AIC_SMR(IRQ0_ID), (AIC_SRCTYPE_EXT_NEGATIVE_EDGE | 5));    /* Clear timer 0 interrupt */    outr(AIC_ICCR, _BV(IRQ0_ID));    /* Enable timer 0 interrupts */    outr(AIC_IECR, _BV(IRQ0_ID));    //printf("======== AsixcInit done ========\n");    return 0;}/*@}*/

⌨️ 快捷键说明

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