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

📄 if_dp83902a.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 2 页
字号:
#if DEBUG & 5
    diag_printf("TX prep page %d len %d\n", start_page, pkt_len);
#endif

    DP_OUT(base, DP_ISR, DP_ISR_RDC);  // Clear end of DMA
    // Set these first, following the small print of the manual
    DP_OUT(base, DP_RBCL, 1);
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);

#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
    // Stall for a bit before continuing to work around random data
    // corruption problems on some platforms.
    CYGACC_CALL_IF_DELAY_US(1);
#endif

    // Send data to device buffer(s)
    DP_OUT(base, DP_RSAL, 0);
    DP_OUT(base, DP_RSAH, start_page);
    DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
    DP_OUT(base, DP_RBCH, pkt_len >> 8);
    DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);

    // Put data into buffer
    for (i = 0;  i < sg_len;  i++) {
        data = (unsigned char *)sg_list[i].buf;
        len = sg_list[i].len;
#if DEBUG & 4
        diag_printf(" sg buf %08x len %08x\n ", data, len);
        dx = 0;
#endif
        while (len > 0) {
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA
            cyg_uint16 tmp;
            tmp = *data++ << 8;
            len -= 2;
            if (len >= 0)
                tmp |= *data++;
            DP_OUT_DATA(dp->data, tmp);
#if DEBUG & 4
            diag_printf(" %04x", tmp);
            if (0 == (++dx % 8)) diag_printf("\n ");
#endif
#else
#if DEBUG & 4
            diag_printf(" %02x", *data);
            if (0 == (++dx % 16)) diag_printf("\n ");
#endif
            DP_OUT_DATA(dp->data, *data++);
            len--;
#endif
        }
#if DEBUG & 4
        diag_printf("\n");
#endif
    }
    if (total_len < pkt_len) {
#if DEBUG & 4
        diag_printf("  + %d bytes of padding\n", pkt_len - total_len);
#endif
        // Padding to 802.3 length was required
        for (i = total_len;  i < pkt_len;) {
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA
            i += 2;
#else
            i++;
#endif
            DP_OUT_DATA(dp->data, 0);
        }
    }

#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
    // After last data write, delay for a bit before accessing the
    // device again, or we may get random data corruption in the last
    // datum (on some platforms).
    CYGACC_CALL_IF_DELAY_US(1);
#endif

    // Wait for DMA to complete
    do {
        DP_IN(base, DP_ISR, isr);
    } while ((isr & DP_ISR_RDC) == 0);
    // Then disable DMA
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
    CR_DOWN();

    // Start transmit if not already going
    if (!dp->tx_started) {
        if (start_page == dp->tx1) {
            dp->tx_int = 1;  // Expecting interrupt from BUF1
        } else {
            dp->tx_int = 2;  // Expecting interrupt from BUF2
        }
        dp83902a_start_xmit(sc, start_page, pkt_len);
    }
}

//
// This function is called when a packet has been received.  It's job is
// to prepare to unload the packet from the hardware.  Once the length of
// the packet is known, the upper layer of the driver can be told.  When
// the upper layer is ready to unload the packet, the internal function
// 'dp83902a_recv' will be called to actually fetch it from the hardware.
//
static void
dp83902a_RxEvent(struct eth_drv_sc *sc, int stat)
{
    struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private;
    cyg_uint8 *base = dp->base;
    unsigned char rsr;
    unsigned char rcv_hdr[4];
    int i, len, pkt, cur;

    DEBUG_FUNCTION();

    DP_IN(base, DP_RSR, rsr);
    while (true) {
        CR_UP();
        // Read incoming packet header
        DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
        DP_IN(base, DP_P1_CURP, cur);
        DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
        DP_IN(base, DP_BNDRY, pkt);
        pkt += 1;
        if (pkt == cur) {
            CR_DOWN();
            break;
        }
        if (pkt == DP_RX_STOP) pkt = DP_RX_START;
        DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
        DP_OUT(base, DP_RBCH, 0);
        DP_OUT(base, DP_RSAL, 0);
        DP_OUT(base, DP_RSAH, pkt);
        if (dp->rx_next == pkt) {
            DP_OUT(base, DP_BNDRY, cur-1); // Update pointer
            CR_DOWN();
            return;
        }
        dp->rx_next = pkt;
        DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA
        DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);

        for (i = 0;  i < sizeof(rcv_hdr);) {
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA
            cyg_uint16 tmp;
            DP_IN_DATA(dp->data, tmp);
            rcv_hdr[i++] = (tmp >> 8) & 0xff;
            rcv_hdr[i++] = tmp & 0xff;
#else
            DP_IN_DATA(dp->data, rcv_hdr[i++]);
#endif
        }
        CR_DOWN();

#if DEBUG & 5
        diag_printf("rx hdr %02x %02x %02x %02x\n",
                    rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
#endif
        len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
        (sc->funs->eth_drv->recv)(sc, len);
        DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); // Update pointer
    }
}

//
// This function is called as a result of the "eth_drv_recv()" call above.
// It's job is to actually fetch data for a packet from the hardware once
// memory buffers have been allocated for the packet.  Note that the buffers
// may come in pieces, using a scatter-gather list.  This allows for more
// efficient processing in the upper layers of the stack.
//
static void
dp83902a_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
{
    struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private;
    cyg_uint8 *base = dp->base;
    int i, mlen, len;
    unsigned char *data;
    cyg_uint8 saved_char = 0;
    bool saved;
#if DEBUG & 4
    int dx;
#endif

    DEBUG_FUNCTION();

    // Compute total packet length
    len = 0;
    for (i = 0;  i < sg_len;  i++) {
        len += sg_list[i].len;
    }

#if DEBUG & 5
    diag_printf("Rx packet %d length %d\n", dp->rx_next, len);
#endif

    CR_UP();

    // Read incoming packet data
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
    DP_OUT(base, DP_RBCL, len & 0xFF);
    DP_OUT(base, DP_RBCH, len >> 8);
    DP_OUT(base, DP_RSAL, 4);           // Past header
    DP_OUT(base, DP_RSAH, dp->rx_next);
    DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA
    DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);

    saved = false;
    for (i = 0;  i < sg_len;  i++) {
        data = (unsigned char *)sg_list[i].buf;
        if (data) {
            mlen = sg_list[i].len;
#if DEBUG & 4
            diag_printf(" sg buf %08x len %08x \n", data, mlen);
            dx = 0;
#endif
            while (0 < mlen) {
                // Saved byte from previous loop?
                if (saved) {
                    *data++ = saved_char;
                    mlen--;
                    saved = false;
                    continue;
                }

#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA
                {
                    cyg_uint16 tmp;
                    DP_IN_DATA(dp->data, tmp);
#if DEBUG & 4
                    diag_printf(" %04x", tmp);
                    if (0 == (++dx % 8)) diag_printf("\n ");
#endif
                    *data++ = (tmp >> 8) & 0xff;
                    mlen--;
                    if (0 == mlen) {
                        saved_char = tmp & 0xff;
                        saved = true;
                    } else {
                        *data++ = tmp & 0xff;
                        mlen--;
                    }
                }
#else
                {
                    cyg_uint8 tmp;
                    DP_IN_DATA(dp->data, tmp);
#if DEBUG & 4
                    diag_printf(" %02x", tmp);
                    if (0 == (++dx % 16)) diag_printf("\n ");
#endif
                    *data++ = tmp;;
                    mlen--;
                }
#endif
            }
#if DEBUG & 4
            diag_printf("\n");
#endif
        }
    }
    CR_DOWN();
}

static void
dp83902a_TxEvent(struct eth_drv_sc *sc, int stat)
{
    struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private;
    cyg_uint8 *base = dp->base;
    unsigned char tsr;
    unsigned long key;

    DEBUG_FUNCTION();

    DP_IN(base, DP_TSR, tsr);
    if (dp->tx_int == 1) {
        key = dp->tx1_key;
        dp->tx1 = 0;
    } else {
        key = dp->tx2_key;
        dp->tx2 = 0;
    }
    // Start next packet if one is ready
    dp->tx_started = false;
    if (dp->tx1) {
        dp83902a_start_xmit(sc, dp->tx1, dp->tx1_len);
        dp->tx_int = 1;
    } else if (dp->tx2) {
        dp83902a_start_xmit(sc, dp->tx2, dp->tx2_len);
        dp->tx_int = 2;
    } else {
        dp->tx_int = 0;
    }
    // Tell higher level we sent this packet
    (sc->funs->eth_drv->tx_done)(sc, key, 0);
}

static void
dp83902a_BufEvent(struct eth_drv_sc *sc, int stat)
{
    // What to do if the receive buffers overflow?
    if (stat & DP_ISR_OFLW) {
        // Note: [so far] it seems safe to just ignore this condition
        // The Linux driver goes through extraordinary pains to handle
        // it, including totally shutting down the chip and restarting.
    }
}

static void
dp83902a_poll(struct eth_drv_sc *sc)
{
    struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private;
    cyg_uint8 *base = dp->base;
    unsigned char isr;

//    DEBUG_FUNCTION();

    CR_UP();
    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
    CR_DOWN();
    DP_IN(base, DP_ISR, isr);
    while (0 != isr) {
        DP_OUT(base, DP_ISR, isr);      // Clear set bits
        if (!dp->running) break;        // Is this necessary?
        // Check for tx_started on TX event since these may happen
        // spuriously it seems.
        if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
            dp83902a_TxEvent(sc, isr);
        }
        if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
            dp83902a_RxEvent(sc, isr);
        }
        if (isr & (DP_ISR_OFLW|DP_ISR_CNT)) {
            dp83902a_BufEvent(sc, isr);
        }
        DP_IN(base, DP_ISR, isr);
    }

    CYGHWR_NS_DP83902A_PLF_INT_CLEAR(dp);
}

static int
dp83902a_int_vector(struct eth_drv_sc *sc)
{
    struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private;
    return dp->interrupt;
}

⌨️ 快捷键说明

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