📄 ne2000.c
字号:
sc = ne_device_for_irno (irq->name); if (sc != NULL) outport_byte (sc->port + IMR, 0);}/* Return whether NE2000 interrupts are on. */static intne_interrupt_is_on (const rtems_irq_connect_data *irq){ return BSP_irq_enabled_at_i8259s (irq->name);}/* Initialize the NE2000 hardware. */static voidne_init_hardware (struct ne_softc *sc){ unsigned int port = sc->port; int i;#ifdef DEBUG_NE2000 printk ("ne_init_hardware()\n");#endif /* Initialize registers. */ /* Set interface for page 0, Remote DMA complete, Stopped */ outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP); /* Set FIFO threshold to 8, No auto-init Remote DMA, byte order=80x86 */ /* byte-wide DMA xfers */ if (sc->byte_transfers) outport_byte (port + DCR, MSK_FT10 | MSK_BMS); /* word-wide DMA xfers */ else outport_byte (port + DCR, MSK_FT10 | MSK_BMS | MSK_WTS); /* Clear Remote Byte Count Registers */ outport_byte (port + RBCR0, 0); outport_byte (port + RBCR1, 0); /* For the moment, don't store incoming packets in memory. */ outport_byte (port + RCR, MSK_MON); /* Place NIC in internal loopback mode */ outport_byte (port + TCR, MSK_LOOP); /* Initialize transmit/receive (ring-buffer) Page Start */ outport_byte (port + TPSR, NE_FIRST_TX_PAGE); outport_byte (port + PSTART, NE_FIRST_RX_PAGE); /* Initialize Receiver (ring-buffer) Page Stop and Boundry */ outport_byte (port + PSTOP, NE_STOP_PAGE); outport_byte (port + BNRY, NE_STOP_PAGE - 1); /* Clear all interrupts */ outport_byte (port + ISR, 0xff); /* Disable all interrupts */ outport_byte (port + IMR, 0); /* Program Command Register for page 1 */ outport_byte (port + CMDR, MSK_PG1 | MSK_RD2 | MSK_STP); /* Set the Ethernet hardware address. */ for (i = 0; i < ETHER_ADDR_LEN; ++i) outport_byte (port + PAR + i, sc->arpcom.ac_enaddr[i]); /* Set Current Page pointer to next_packet */ outport_byte (port + CURR, NE_FIRST_RX_PAGE); /* Clear the multicast address. */ for (i = 0; i < MARsize; ++i) outport_byte (port + MAR + i, 0); /* Set page 0 registers */ outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP); /* accept broadcast */ outport_byte (port + RCR, (sc->accept_broadcasts ? MSK_AB : 0)); /* Start interface */ outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STA); /* Take interface out of loopback */ outport_byte (port + TCR, 0);}/* Set up interrupts.*/static voidne_init_irq_handler(int irno){ rtems_irq_connect_data irq;#ifdef DEBUG_NE printk("ne_init_irq_handler(%d)\n", irno);#endif irq.name = irno; irq.hdl = (rtems_irq_hdl)ne_interrupt_handler; irq.on = ne_interrupt_on; irq.off = ne_interrupt_off; irq.isOn = ne_interrupt_is_on; if (!BSP_install_rtems_irq_handler (&irq)) rtems_panic ("Can't attach NE interrupt handler for irq %d\n", irno);}/* The NE2000 packet receive daemon. This task is started when the NE2000 driver is initialized. */#ifdef DEBUG_NEstatic int ccc = 0; /* experinent! */#endifstatic voidne_rx_daemon (void *arg){ struct ne_softc *sc = (struct ne_softc *) arg; struct ifnet *ifp = &sc->arpcom.ac_if; unsigned int port = sc->port; while (1) { rtems_event_set events; /* Wait for the interrupt handler to tell us that there is a packet ready to receive. */ rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); /* Don't let the device interrupt us now. */ outport_byte (port + IMR, 0); while (1) { unsigned char startpage, currpage; unsigned short len; unsigned char next, stat, cnt1, cnt2; struct mbuf *m; unsigned char *p; int startaddr; int toend; struct ether_header *eh; struct ne_ring hdr; /* ring buffer header */ int reset; inport_byte (port + BNRY, startpage); outport_byte (port + CMDR, MSK_PG1 | MSK_RD2); inport_byte (port + CURR, currpage); outport_byte (port + CMDR, MSK_PG0 | MSK_RD2); ++startpage; if (startpage >= NE_STOP_PAGE) startpage = NE_FIRST_RX_PAGE; if (startpage == currpage) break;#ifdef DEBUG_NE2000 printk ("ne_rx_daemon: start page %x; current page %x\n", startpage, currpage);#endif reset = 0; /* Read the buffer header */ startaddr = startpage * NE_PAGE_SIZE; ne_read_data(sc, startaddr, sizeof(hdr), (unsigned char *)&hdr); next = hdr.next; if (next >= NE_STOP_PAGE) next = NE_FIRST_RX_PAGE; /* check packet length */ len = hdr.count; if (currpage < startpage) cnt1 = currpage + (NE_STOP_PAGE - NE_FIRST_RX_PAGE) - startpage; else cnt1 = currpage - startpage; cnt2 = len / NE_PAGE_SIZE; if (len % NE_PAGE_SIZE) cnt2++; if (cnt1 < cnt2) {#ifdef DEBUG_NE printk("(%x<%x:%x)", cnt1, cnt2, len);/* printk("start page 0x%x; current page 0x%x\n", startpage, currpage); printk("cnt1 < cnt2 (0x%x, 0x%x); len 0x%x\n", cnt1, cnt2, len);*/#endif reset = 1; } if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN + sizeof(struct ne_ring)) || len < (ETHER_MIN_LEN - ETHER_CRC_LEN + sizeof(struct ne_ring)) || len > MCLBYTES) {#ifdef DEBUG_NE printk("(%x)", len);/* printk("start page 0x%x; current page 0x%x\n", startpage, currpage); printk("len out of range: 0x%x\n", len); printk("stat: 0x%x, next: 0x%x\n", hdr.rsr, hdr.next);*/#endif reset = 1; }#ifdef DEBUG_NE if (++ccc == 100) { ccc = 0; reset = 1; printk("T"); }#endif /* reset interface */ if (reset) { ne_reset(sc); goto Next; } stat = hdr.rsr; /* The first four bytes of the length are the buffer header. */ len -= sizeof(struct ne_ring); startaddr += sizeof(struct ne_ring); MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; p = mtod (m, unsigned char *); m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); toend = NE_STOP_PAGE * NE_PAGE_SIZE - startaddr; if (toend < len) { ne_read_data (sc, startaddr, toend, p); p += toend; len -= toend; startaddr = NE_FIRST_RX_PAGE * NE_PAGE_SIZE; } if (len > 0) ne_read_data (sc, startaddr, len, p); eh = mtod (m, struct ether_header *); m->m_data += sizeof (struct ether_header);#ifdef DEBUG_NE /* printk("[r%d]", hdr.count - sizeof(hdr)); */ printk("<");#endif ether_input (ifp, eh, m); ++sc->stats.rx_packets; outport_byte (port + BNRY, next - 1); } if (sc->overrun) { outport_byte (port + ISR, MSK_OVW); outport_byte (port + TCR, 0); if (sc->resend) outport_byte (port + CMDR, MSK_PG0 | MSK_TXP | MSK_RD2 | MSK_STA); sc->resend = 0; sc->overrun = 0; } Next: /* Reenable device interrupts. */ outport_byte (port + IMR, NE_INTERRUPTS); }}/* Load an NE2000 packet onto the device. */static voidne_loadpacket (struct ne_softc *sc, struct mbuf *m){ unsigned int port = sc->port; unsigned int dport = port + DATAPORT; struct mbuf *mhold = m; int leftover; unsigned char leftover_data; int timeout; int send_cnt = 0;#ifdef DEBUG_NE2000 printk ("Uploading NE2000 packet\n");#endif /* Reset remote DMA complete flag. */ outport_byte (port + ISR, MSK_RDC); /* Write out the count. */ outport_byte (port + RBCR0, m->m_pkthdr.len); outport_byte (port + RBCR1, m->m_pkthdr.len >> 8); sc->sendlen[sc->nextavail] = m->m_pkthdr.len; /* Tell the device which address we want to write to. */ outport_byte (port + RSAR0, 0); outport_byte (port + RSAR1, NE_FIRST_TX_PAGE + (sc->nextavail * NE_TX_PAGES)); /* Set up the write. */ outport_byte (port + CMDR, MSK_PG0 | MSK_RWR | MSK_STA); /* Transfer the mbuf chain to device memory. NE2000 devices require that the data be transferred as words, so we need to handle odd length mbufs. Never occurs if we force byte transfers. */ leftover = 0; leftover_data = '\0'; for (; m != NULL; m = m->m_next) { int len; unsigned char *data; len = m->m_len; if (len == 0) continue; data = mtod (m, unsigned char *); if (leftover) { unsigned char next; /* Data left over from previous mbuf in chain. */ next = *data++; --len; outport_word (dport, leftover_data | (next << 8)); send_cnt += 2; leftover = 0; } /* If using byte transfers, len always ends up as zero so there are no leftovers. */ if (sc->byte_transfers) while (len > 0) { outport_byte (dport, *data++); len--; } else while (len > 1) { outport_word (dport, data[0] | (data[1] << 8)); data += 2; len -= 2; send_cnt += 2; } if (len > 0) { leftover = 1; leftover_data = *data++; } } if (leftover) { outport_word (dport, leftover_data); send_cnt += 2; }#ifdef DEBUG_NE /* printk("{l%d|%d}", send_cnt, sc->nextavail); */ printk("v");#endif m_freem (mhold); /* Wait for the device to complete accepting the data, with a limiting counter so that we don't wait too long. */ for (timeout = 0; timeout < 100; ++timeout) { unsigned char status; inport_byte (port + ISR, status);#ifdef DEBUG_NE2000 if ((status &~ MSK_RDC) != 0) printk ("Status 0x%x while waiting for acknowledgement of uploaded packet\n", status);#endif if ((status & MSK_RDC) != 0) { outport_byte (port + ISR, MSK_RDC); break; } } if (timeout >= 100) printk ("Timed out waiting for acknowledgement of uploaded NE2000 packet\n"); ++sc->nextavail; if (sc->nextavail == NE_TX_BUFS) sc->nextavail = 0;}/* Tell the NE2000 to transmit a buffer whose contents we have already loaded onto the device. */static voidne_transmit (struct ne_softc *sc){ struct ifnet *ifp = &sc->arpcom.ac_if; unsigned int port = sc->port; int len;#ifdef DEBUG_NE2000 printk ("Transmitting NE2000 packet\n");#endif len = sc->sendlen[sc->nextsend]; if (len < ET_MINLEN) len = ET_MINLEN; outport_byte (port + TBCR0, len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -