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

📄 if_sc_lpe.c

📁 移植到WLIT项目的redboot源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static voidsc_lpe_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    int i;    regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_STOP;  // Brutal    regs->w.page0.dcr = DP8390_DCR_INIT;    regs->w.page0.rbch = 0;                 // Remote byte count    regs->w.page0.rbcl = 0;    regs->w.page0.rcr = DP8390_RCR_MON;     // Accept no packets    regs->w.page0.tcr = DP8390_TCR_LOCAL;   // Transmitter [virtually] off    regs->w.page0.tpsr = DP8390_TX_BUF1;    // Transmitter start page    dp->tx1 = dp->tx2 = 0;    dp->tx_next = DP8390_TX_BUF1;    dp->tx_started = false;    regs->w.page0.pstart = DP8390_RX_START; // Receive ring start page    regs->w.page0.bndry = DP8390_RX_STOP-1; // Receive ring boundary    regs->w.page0.pstop = DP8390_RX_STOP;   // Receive ring end page    dp->rx_next = DP8390_RX_START-1;    regs->w.page0.isr = 0xFF;               // Clear any pending interrupts    regs->w.page0.imr = DP8390_IMR_All;     // Enable all interrupts    regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_PAGE1;  // Select page 1    regs->w.page1.curp = DP8390_RX_START;   // Current page - next free page for Rx    for (i = 0;  i < ETHER_ADDR_LEN;  i++) {        regs->w.page1.par[i] = enaddr[i];    }    // Enable and start device    regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_START;      regs->w.page0.tcr = DP8390_TCR_NORMAL;   // Normal transmit operations    regs->w.page0.rcr = DP8390_RCR_AB;  // Accept broadcast, no errors, no multicast    dp->running = true;}//// This routine is called to perform special "control" opertions//static intsc_lpe_control(struct eth_drv_sc *sc, unsigned long key,               void *data, int data_len){    switch (key) {    case ETH_DRV_SET_MAC_ADDRESS:        return 0;        break;    default:        return 1;        break;    }}//// This routine is called to see if it is possible to send another packet.// It will return non-zero if a transmit is possible, zero otherwise.//static intsc_lpe_can_send(struct eth_drv_sc *sc){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    return ((dp->tx1 == 0) || (dp->tx2 == 0));}//// This routine is called to start the transmitter.  It is split out from the// data handling routine so it may be called either when data becomes first // available or when an Tx interrupt occurs//static voidsc_lpe_start_xmit(struct eth_drv_sc *sc, int start_page, int len){        struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START;    regs->w.page0.tbcl = len & 0xFF;    regs->w.page0.tbch = len >> 8;    regs->w.page0.tpsr = start_page;    regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_TXPKT | DP8390_CR_START;    dp->tx_started = true;}//// This routine is called to send data to the hardware.  It is known a-priori// that there is free buffer space (dp->tx_next).//static void sc_lpe_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,             int total_len, unsigned long key){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    int i, len, start_page, pkt_len;    unsigned char *data;    pkt_len = total_len;    if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME;    start_page = dp->tx_next;    if (dp->tx_next == DP8390_TX_BUF1) {        dp->tx1 = start_page;        dp->tx1_len = pkt_len;        dp->tx1_key = key;        dp->tx_next = DP8390_TX_BUF2;    } else {        dp->tx2 = start_page;        dp->tx2_len = pkt_len;        dp->tx2_key = key;        dp->tx_next = DP8390_TX_BUF1;    }    // Send data to device buffer(s)    regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START;    regs->w.page0.rbcl = pkt_len & 0xFF;    regs->w.page0.rbch = pkt_len >> 8;    regs->w.page0.rsal = 0;    regs->w.page0.rsah = start_page;    regs->w.page0.isr = DP8390_ISR_RDC;  // Clear end of DMA    regs->w.page0.cr = DP8390_CR_WDMA | DP8390_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;        while (len-- > 0) {            regs->w.page0.data = *data++;        }    }    if (total_len < pkt_len) {        // Padding to 802.3 length was required        for (i = total_len;  i < pkt_len;  i++) {            regs->w.page0.data = 0;        }    }    // Wait for DMA to complete    while ((regs->r.page0.isr & DP8390_ISR_RDC) == 0) ;    // 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        }        sc_lpe_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// 'sc_lpe_recv' will be called to actually fetch it from the hardware.//static voidsc_lpe_RxEvent(struct eth_drv_sc *sc, int stat){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    unsigned char rsr;    unsigned char rcv_hdr[4];    int i, len, pkt, cur;    rsr = regs->r.page0.rsr;    while (true) {        // Read incoming packet header        regs->w.page0.cr = DP8390_CR_PAGE1 | DP8390_CR_NODMA | DP8390_CR_START;        cur = regs->r.page1.curp;        regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START;        pkt = regs->r.page0.bndry + 1;        if (pkt == cur) break;        if (pkt == DP8390_RX_STOP) pkt = DP8390_RX_START;        regs->w.page0.rbcl = sizeof(rcv_hdr);        regs->w.page0.rbch = 0;        regs->w.page0.rsal = 0;        regs->w.page0.rsah = pkt;        if (dp->rx_next == pkt) {//            printf("sc_lpe - receiver confused, stat: %x, , rsr: %x\n", stat, rsr);            regs->w.page0.bndry = cur-1;  // Update pointer            return;        }        dp->rx_next = pkt;        regs->w.page0.isr = DP8390_ISR_RDC;  // Clear end of DMA        regs->w.page0.cr = DP8390_CR_RDMA | DP8390_CR_START;        for (i = 0;  i < sizeof(rcv_hdr);  i++) {            rcv_hdr[i] = regs->r.page0.data;        }        len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);        (sc->funs->eth_drv->recv)(sc, len);        regs->w.page0.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 voidsc_lpe_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    int i, mlen, len;    unsigned char *data;    // Compute total packet length    len = 0;    for (i = 0;  i < sg_len;  i++) {        len += sg_list[i].len;    }    // Read incoming packet data    regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START;    regs->w.page0.rbcl = len & 0xFF;    regs->w.page0.rbch = len >> 8;    regs->w.page0.rsal = 4;  // Past header    regs->w.page0.rsah = dp->rx_next;    regs->w.page0.isr = DP8390_ISR_RDC;  // Clear end of DMA    regs->w.page0.cr = DP8390_CR_RDMA | DP8390_CR_START;    for (i = 0;  i < sg_len;  i++) {        data = (unsigned char *)sg_list[i].buf;        if (data) {            mlen = sg_list[i].len;            while (mlen >= sizeof(*data)) {                *data++ = regs->r.page0.data;                mlen -= sizeof(*data);            }        }    }}static voidsc_lpe_TxEvent(struct eth_drv_sc *sc, int stat){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    unsigned char tsr;    unsigned long key;    tsr = regs->r.page0.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) {        sc_lpe_start_xmit(sc, dp->tx1, dp->tx1_len);        dp->tx_int = 1;    } else if (dp->tx2) {        sc_lpe_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 voidsc_lpe_BufEvent(struct eth_drv_sc *sc, int stat){    // What to do if the receive buffers overflow?    if (stat & DP8390_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 voidsc_lpe_int(struct eth_drv_sc *sc){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    dp8390_regs *regs = dp->regs;    unsigned char isr;    regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_PAGE0 | DP8390_CR_START;    while ((isr = regs->r.page0.isr) != 0) {        regs->w.page0.isr = isr;  // Clear set bits        if (!dp->running) break;  // Is this necessary?        if (isr & (DP8390_ISR_TxP|DP8390_ISR_TxE)) {            sc_lpe_TxEvent(sc, isr);        }        if (isr & (DP8390_ISR_RxP|DP8390_ISR_RxE)) {            sc_lpe_RxEvent(sc, isr);        }        if (isr & (DP8390_ISR_OFLW|DP8390_ISR_CNT)) {            sc_lpe_BufEvent(sc, isr);        }    }    cf_clear_interrupt(dp->slot);}static intsc_lpe_int_vector(struct eth_drv_sc *sc){    struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private;    return dp->slot->int_num;}

⌨️ 快捷键说明

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