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

📄 ne2000.c

📁 VRTX 商用嵌入式实时操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
	int isr;
	int ret = 0;
	static int intr_cnt=0;

	ENTRY("ne2000_rxtst");
	ne->in_intr = 1;

	/* Change to page 0 and read the intr status reg. */
	OUTB(e8390_base + E8390_CMD, E8390_NODMA+E8390_PAGE0);

	while ((isr = INPB(e8390_base + EN0_ISR)) & ENISR_ALL) {
		if (isr & ENISR_OVER) {
			ei_rx_overrun(ne);
		}

		if (isr & (ENISR_RX | ENISR_RX_ERR)) {
			/*
			 * Bug alert!  Reset ENISR_OVER to avoid 
			 * spurious overruns!
			 */
			ei_receive(ne);
#if 0
			OUTB(e8390_base+EN0_ISR, ENISR_RX+ENISR_RX_ERR+ENISR_OVER);
#else
			OUTB(e8390_base+EN0_ISR, ENISR_RX+ENISR_RX_ERR);
#endif
			ret = 1;
		}

		if (isr & (ENISR_TX | ENISR_TX_ERR)) {
			/*
			 * ei_tx_intr does the following:
			 * 1) Ack TX intr; 
			 * 2) start next TX;
			 * 3) Update TX statistics
			 */
			ei_tx_intr(ne);
		}

		/*
		 * Handle benign interrupt sources last ...
		 */

#if 0
		/* ACK Meaningless DMA complete. */
		if (isr & ENISR_RDC) {
			OUTB(e8390_base + EN0_ISR, ENISR_RDC);
		}
#endif

		/* Counter Overflow: msb of a network tally counter has been set */
		if (isr & ENISR_COUNTERS) {
			OUTB(e8390_base + EN0_ISR, ENISR_COUNTERS);
			update_stats(ne);
		}
	}


	if ((++intr_cnt & 0x0fff) == 0)
		update_stats(ne);

	ne->in_intr = 0;
	INTERRUPT_END(dev, INT_PKT_RX);
	EXIT2("ne2000_rxtst", ret);
	return ret;
}


/*************************************************************************
**
** ne2000_int_info_get
**
** This function returns interrupt information that tells the
** caller which interrupts are enabled for a particular device.
**
** Inputs:
**     dev          the ether_1 device descriptor
**     intrpt       which interrupt actually requested
** Outputs:
**     intrpt       flags field is updated
**
** Return codes:
**     LOGIO_STATUS_OK              The call succeeded
**
*/
logio_status_t
ne2000_int_info_get(ether_1_dev_desc_t *dev, logio_int_entry_t *intrpt)
{
	struct device *ne = (struct device *)dev->config.specific;

	ENTRY("ne2000_int_info_get");
	intrpt->flags = ne->shadow_int_flags;
	EXIT("ne2000_int_info_get");
	return( LOGIO_STATUS_OK );
}

/*************************************************************************
** ne2000_int_info_set
**
** This function controls a specific event/id pair by enabling or
** disabling the specific event requested.
**
** Inputs:
**     dev          the ether_1 device descriptor
**     intrpt       which event to set
** Outputs:
**     intrpt       flags field is updated to old value
**
** Return codes:
**     LOGIO_STATUS_OK              The call succeeded
**
*/
logio_status_t
ne2000_int_info_set(ether_1_dev_desc_t *dev, logio_int_entry_t *intrpt)
{
	int new_flags = intrpt->flags;
	struct device *ne = (struct device *)dev->config.specific;
	int e8390_base = ne->base_addr;

	ENTRY("ne2000_int_info_set");
	intrpt->flags = ne->shadow_int_flags;

	if (new_flags == LOGIO_INT_ENABLED) {
		BOARD_SPEC_INT_ENABLE(dev, intrpt);
		OUTB(e8390_base + EN0_IMR, ENISR_ALL);
	} else if (new_flags == LOGIO_INT_DISABLED) {
		BOARD_SPEC_INT_DISABLE(dev, intrpt);
		OUTB(e8390_base + EN0_IMR, 0x00);
	}

	ne->shadow_int_flags = new_flags;
	EXIT("ne2000_int_info_set");
	return( LOGIO_STATUS_OK );
}


/*****************************************************************/
/* Transmit logic                                                */
/*****************************************************************/

vbsp_return_t
ei_start_xmit(struct device *dev)
{
    struct ei_device *ei_local = (struct ei_device *) dev->priv;
	vbuf_t *list, *bptr;
    int len, current_offset;
	int output_page = ei_local->tx_start_page;
	IFDEBUG( static char funcname[] = "ei_start_xmit"; )

	ENTRY(funcname);

	list = dev->tx_head;
	if (!list)
		return VBSP_SUCCESS;
	len = vbuf_get_msgcnt(list);
	bptr = list;
	while (bptr = vbuf_get_nextbuf(bptr))
		len += vbuf_get_msgcnt(bptr);

    if (ei_local->pingpong) {
		if (ei_local->tx1 == 0) {
			ei_local->tx1 = len;
		#if EI_DEBUG > 0
			if (ei_local->tx2 > 0)
				printf("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
					   dev->name, ei_local->tx2, ei_local->lasttx,
					   ei_local->txing);
		#endif
		} else if (ei_local->tx2 == 0) {
			output_page += 6;
			ei_local->tx2 = len;
		#if EI_DEBUG > 0
			if (ei_local->tx1 > 0)
				printf("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
					   dev->name, ei_local->tx1, ei_local->lasttx,
					   ei_local->txing);
		#endif
		} else {	/* We should never get here. */
#if EI_DEBUG > 0
			printf("%s: No packet buffer space for ping-pong use.\n",
			dev->name);
#endif
			dev->tbusy = 1;
			EXIT2(funcname, VBSP_NO_DEVICE_BUFS);
			return VBSP_NO_DEVICE_BUFS;
		}
    } else {  /* No pingpong, just a single Tx buffer. */
		if (dev->tbusy) {
			EXIT2(funcname, VBSP_NO_DEVICE_BUFS);
			return VBSP_NO_DEVICE_BUFS;
		}
	}

	/*
	 * Copy the packet to the board's RAM.
	 */
	current_offset = output_page << 8;
	ne_block_output(dev, vbuf_get_msgcnt(list), vbuf_get_dataptr(list),
		current_offset);
	bptr = list;
	current_offset += vbuf_get_msgcnt(bptr);
	while ((bptr = vbuf_get_nextbuf(bptr)) != (vbuf_t *)0) {
		ne_block_output(dev, vbuf_get_msgcnt(bptr), vbuf_get_dataptr(bptr),
			current_offset);
		current_offset += vbuf_get_msgcnt(bptr);
	}

#if EI_DEBUG > 1 /* Read back and display the data we just sent to the board */
	{
		char buf[ 300 ];
		ne_block_input(dev, 256, buf, ei_local->tx_start_page << 8);
		printf("ei_start_xmit: read the data back before the xmit:\n");
		dump(buf, 80);
	}
#endif 

#ifdef RWS /* debug */
		{
			static int n;
			if ((++n & 0xf) == 0)
				printf(">");
		}
#endif

	/*
	 * Start the transmission.
	 */
    if (ei_local->pingpong) {
		if (! ei_local->txing) {
			NS8390_trigger_send(dev, len, output_page);
			if (output_page == ei_local->tx_start_page)
				ei_local->tx1 = -1, ei_local->lasttx = -1;
			else
				ei_local->tx2 = -1, ei_local->lasttx = -2;
			ei_local->txing = 1;
		} else
			ei_local->txqueue++;

		dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);
    } else {  /* No pingpong, just a single Tx buffer. */
		NS8390_trigger_send(dev, len, ei_local->tx_start_page);
		dev->tbusy = 1;
    }

	/*
	 * Since we've copied the packet to the board's memory,
	 * we're finished with this vbuf -- free it.
	 * First, we have to remove it from the TX queue.
	 */
	dev->tx_head = vbuf_get_nextpkt(list);
	vbuf_set_nextpkt(list, (vbuf_t *)0);
	logio_release_list(/*dummy*/0, list); 
	#if 0
	(*list->free)(list); /* release this buffer */
	#endif

	EXIT2(funcname, VBSP_SUCCESS);
	return VBSP_SUCCESS;
}


/* We have finished a transmit: check for errors and then trigger the next
   packet to be sent. */
void
ei_tx_intr(struct device *dev)
{
    int e8390_base = dev->base_addr;
    int status = INPB(e8390_base + EN0_TSR);
    struct ei_device *ei_local = (struct ei_device *) dev->priv;
    
	ENTRY("ei_tx_intr");

	/* ++COUNTDOWN; */

	OUTB(e8390_base + EN0_ISR, (ENISR_TX | ENISR_TX_ERR));

	if (ei_local->pingpong) {
		ei_local->txqueue--;
		if (ei_local->tx1 < 0) {
			if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
				printf("%s: bogus last_tx_buffer %d, tx1=%d.\n",
					   ei_local->name, ei_local->lasttx, ei_local->tx1);
			ei_local->tx1 = 0;
			dev->tbusy = 0;
			if (ei_local->tx2 > 0) {
				NS8390_trigger_send(dev, ei_local->tx2,
					ei_local->tx_start_page + 6);
				ei_local->txing = 1;
				ei_local->tx2 = -1,
				ei_local->lasttx = 2;
			} else {
				ei_local->lasttx = 20, ei_local->txing = 0;
				if (dev->tx_head)
					ei_start_xmit(dev); /* keep TX busy */
			}
		} else if (ei_local->tx2 < 0) {
			if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
				printf("%s: bogus last_tx_buffer %d, tx2=%d.\n",
					   ei_local->name, ei_local->lasttx, ei_local->tx2);
			ei_local->tx2 = 0;
			dev->tbusy = 0;
			if (ei_local->tx1 > 0) {
				NS8390_trigger_send(dev, ei_local->tx1,
					ei_local->tx_start_page);
				ei_local->txing = 1;
				ei_local->tx1 = -1;
				ei_local->lasttx = 1;
			} else {
				ei_local->lasttx = 10, ei_local->txing = 0;
				if (dev->tx_head)
					ei_start_xmit(dev); /* keep TX busy */
			}
		} else
			printf("%s: unexpected TX-done interrupt, lasttx=%d.\n",
				   dev->name, ei_local->lasttx);
	} else {
		ei_local->txing = 0;
		dev->tbusy = 0;
		if (dev->tx_head)
			ei_start_xmit(dev); /* keep TX busy */
	}

    /* Minimize Tx latency: update the statistics after we restart TXing. */
	if (status & ENTSR_COL)
		ei_local->stat.collisions++;
    if (status & ENTSR_PTX)
		ei_local->stat.tx_packets++;
    else {
		ei_local->stat.tx_errors++;
		if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;
		if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
		if (status & ENTSR_FU)  ei_local->stat.tx_fifo_errors++;
		if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
		if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
	}

	EXIT("ei_tx_intr");
}


/*****************************************************************/
/* Receive logic                                                 */
/*****************************************************************/

/* We have a good packet(s), get them out of the buffers. */

vbsp_return_t
ei_receive(struct device *dev)
{
    int e8390_base = dev->base_addr;
    struct ei_device *ei_local = (struct ei_device *) dev->priv;
    int rxing_page, this_frame, next_frame, current_offset;
    struct e8390_pkt_hdr rx_frame;
    int num_rx_pages = ei_local->stop_page - ei_local->rx_start_page;
    int pkt_len;
	vbsp_return_t rv = VBSP_SUCCESS;
	vbuf_t *new_bufs, *bptr;
	int dummy = 0;
#ifdef RWS /* debug */
	static int most;
#endif

	for (;;) {
		/* Get the rx page (incoming packet pointer). */
		OUTB(e8390_base + E8390_CMD, E8390_NODMA+E8390_PAGE1);
		rxing_page = INPB(e8390_base + EN1_CURPAG);
		OUTB(e8390_base + E8390_CMD, E8390_NODMA+E8390_PAGE0);
		
		/* Remove one frame from the ring.  Boundary is alway a page behind. */
		this_frame = INPB(e8390_base + EN0_BOUNDARY) + 1;
		if (this_frame >= ei_local->stop_page)
			this_frame = ei_local->rx_start_page;
		
#if EI_DEBUG > 0
		if (this_frame != ei_local->current_page)
			printf("%s: mismatched read page pointers %2x vs %2x.\n",
				   dev->name, this_frame, ei_local->current_page);
#endif
		
		if (this_frame == rxing_page) {	/* Read all the frames? */
			break;
		}
		
		current_offset = this_frame << 8;
		ne_block_input(dev, sizeof(rx_frame), (char *)&rx_frame,
					   current_offset);
		current_offset += sizeof(rx_frame);
		
		pkt_len = rx_frame.count - 4;	/* Remove CRC size */
		
		next_frame = this_frame + ((pkt_len+4+4+255)>>8);
		if (next_frame >= ei_local->stop_page)
			next_frame -= num_rx_pages;
		
		/* Check for bogosity warned by 3c503 book: the status byte is never
		   written.  This happened a lot during testing! This code should be
		   cleaned up someday. */
		if (rx_frame.next != next_frame) {
#if 0
			&& rx_frame.next != next_frame + 1
			&& rx_frame.next != next_frame - num_rx_pages
			&& rx_frame.next != next_frame + 1 - num_rx_pages) {
#endif
#if EI_DEBUG > 0
			printf("%s: warning rx_frame.next=%#x next_frame=%#x\n",
				rx_frame.next, next_frame);
			printf("\t\tpkt_len=%#x num_rx_pages=%#x\n",
				pkt_len, num_rx_pages);
#endif
			ei_local->current_page = rxing_page;
			if (rxing_page > ei_local->rx_start_page)
				OUTB(e8390_base+EN0_BOUNDARY, rxing_page-1);
			else
				OUTB(e8390_base+EN0_BOUNDARY, ei_local->stop_page-1);
			ei_local->stat.rx_errors++;
			continue;
		}

		if (pkt_len < 60 || pkt_len > 1518) {
		#if EI_DEBUG > 0
			printf("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
				dev->name, rx_frame.count, rx_frame.status,
				rx_frame.next);
		#endif
			ei_local->stat.rx_errors++;
		} else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
			/*
			 * We should need only 1 vbuf, but we also handle cases
			 * where vbufs are smaller than our packet (not likely
			 * since default vbuf data size is 1600), requiring
			 * multiple vbufs.
			 */
			int num_bufs = 1;
#if VBUFMAX < 1600
			if (pkt_len > VBUFMAX)
					num_bufs = (pkt_len + VBUFMAX - 1) / VBUFMAX;
#endif /* VBUFMAX < 1600 */

			dummy++; /* count # of good packets */

			if (logio_get_free_list(dummy, num_bufs, &new_bufs) == 0) {
				bptr = new_bufs;
#if VBUFMAX < 1600
				while (pkt_len > VBUFMAX) {
					/*
					 * Copy all but the last vbuf worth of data in from

⌨️ 快捷键说明

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