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

📄 rtl8139.c

📁 在ucos_ii基础上加上网络功能
💻 C
📖 第 1 页 / 共 2 页
字号:
{
	unsigned long dirty_tx, tx_left;
	struct rtl_private_data *rp = private_data;
	struct nic *nic = rp->nic;
	dirty_tx = rp->dirty_tx;
	tx_left = rp->cur_tx - dirty_tx;



	while (tx_left > 0) {
		int entry = dirty_tx % NUM_TX_DESC;
		int txstatus;

		txstatus = RTL_R32 (TxStatus0 + (entry * 4));

		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
			break;	/* It still hasn't been Txed */

		/* Note: TxCarrierLost is always asserted at 100mbps. */
		if (txstatus & (TxOutOfWindow | TxAborted)) {
			if (txstatus & TxAborted) {
				RTL_W32 (TxConfig, TxClearAbt);
				RTL_W16 (IntrStatus, TxErr);
			}
		} else {
			if (txstatus & TxUnderrun) {
				/* Add 64 to the Tx FIFO threshold. */
				if (rp->tx_flag < 0x00300000)
					rp->tx_flag += 0x00020000;
			}
		}

		dirty_tx++;
		tx_left--;
	}

	/* only wake the queue if we did work, and the queue is stopped */
	if (rp->dirty_tx != dirty_tx) {
		rp->dirty_tx = dirty_tx;
		nic->t_busy = 0;	
	}

	return;
}

int rtl_interrupt(void *arg)
{
	struct rtl_private_data *private_data = (struct rtl_private_data *)arg;
	struct nic *nic = private_data->nic;
	int ackstat, status;
	int boguscnt = max_interrupt_work;
	int link_changed = 0; /* avoid bogus "uninit" warning */

	/* Mask the bit that says "this is an io addr" */
	ioaddr = nic->ioaddr;
	
	do {
		status = RTL_R16 (IntrStatus);

		/* h/w no longer present (hotplug?) or major error, bail */
		if (status == 0xFFFF)
			break;

		if ((status &
		     (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
			break;
		/* Acknowledge all of the current interrupt sources ASAP, but
		   an first get an additional status bit from CSCR. */
		if (status & RxUnderrun)
			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;


		ackstat = status & ~(RxAckBits | TxErr);
		RTL_W16 (IntrStatus, ackstat);
#ifdef	DEBUG_RTL8139
		debug_print("interrupt  status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\r\n",
			   status,ackstat, RTL_R16 (IntrStatus));
#endif
		if (status & RxAckBits)
			rtl8139_rx_interrupt (private_data);

		/* Check uncommon events with one test. */
		if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
		  	      RxFIFOOver | RxErr))
			rtl8139_weird_interrupt (private_data);

		if (status & (TxOK | TxErr)) {
			rtl8139_tx_interrupt (private_data);
			if (status & TxErr)
				RTL_W16 (IntrStatus, TxErr);
		}

		boguscnt--;
	}while (boguscnt > 0);

	if (boguscnt <= 0) {
#ifdef	DEBUG_RTL8139
		debug_print ("Too much work at interrupt, "
			"IntrStatus=0x%4.4x.\n", status);
#endif
		/* Clear all interrupt sources. */
		RTL_W16 (IntrStatus, 0xffff);
	}
	
	_outp( ICR_A, EOI );
	_outp( ICR_B, EOI );

	return 0;
}



int 
rtl8139_probe(struct nic *nic)
{
	int i;
	struct pci_device *p = NULL;
	int speed10, fullduplex;
	int found = 0;
	p = lookup_pci_device(PCI_VENDOR_ID_REALTEK,PCI_DEVICE_ID_REALTEK_8139);
	while(p&& found < N_RTL8139){
	
		nic->pci_data = p;
#ifdef USE_IO_OPS
		nic->ioaddr = p->ioaddr & ~3;
#else
		nic->ioaddr = p->membase;
#endif

		nic->irq = p->irq;
		nic->device = p->device;
		nic->vendor = p->vendor;
	
	
		/*
		 * This bit below is not necessary at all since the pci.c subsystem
		 * is supposed to find the NIC, but I will leave it in since it
		 * hardly will ever execute this test.
		 */
		if (nic->ioaddr == 0) {
			return -1;
		}

		/* Mask the bit that says "this is an io addr" */
		ioaddr = nic->ioaddr;

		/* Bring the chip out of low-power mode. */
		RTL_W8(Cfg9346,0x00);

		if (read_eeprom(0) != 0xffff) {
			unsigned short *ap = (unsigned short*)nic->node_addr;
			for (i = 0; i < 3; i++)
				*ap++ = read_eeprom(i + 7);
		} else {
			unsigned char *ap = (unsigned char*)nic->node_addr;
			for (i = 0; i < ETH_ALEN; i++)
				*ap++ = RTL_R8(MAC0 + i);
		}

		speed10 = RTL_R8(MediaStatus) & MSRSpeed10;
		fullduplex = RTL_R16(MII_BMCR) & BMCRDuplex;
		debug_print("ioaddr %lX, addr %02x:%02x:%02x:%02x:%02x:%02x  %sMbps %s-duplex\r\n", 
			     ioaddr,
			     nic->node_addr[0],
			     nic->node_addr[1],
			     nic->node_addr[2],
			     nic->node_addr[3],
			     nic->node_addr[4],
			     nic->node_addr[5],
			     speed10 ? "10" : "100",
			     fullduplex ? "full" : "half");


		rtl_reset(nic);

		IRQ_REQUEST(nic->irq,rtl_interrupt,&private_datas[found]);

		private_datas[found].nic = nic;
		nic->private_data = &private_datas[found];
		nic->watchdog = rtl_reset;
		nic->transmit = rtl_transmit;
		nic->ioctl = rtl_ioctl;
		found ++;
		nic ++;
		p = p->next;

	}

	return found;
}




static void rtl_reset(struct nic* nic)
{
	int i;
	struct rtl_private_data *rp = nic->private_data;	

	/* Mask the bit that says "this is an io addr" */
	ioaddr = nic->ioaddr;

	RTL_W8(ChipCmd,CmdReset);

	/* Give the chip 10ms to finish the reset. */
	load_timer2(10*TICKS_PER_MS);
	while ((RTL_R8(ChipCmd) & CmdReset) != 0 && timer2_running())
		/* wait */;

	for (i = 0; i < ETH_ALEN; i++)
		RTL_W8(MAC0 + i,nic->node_addr[i]);

	/* Must enable Tx/Rx before setting transfer thresholds! */
	RTL_W8(ChipCmd,CmdRxEnb | CmdTxEnb);
	RTL_W32(RxConfig,(RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8));		/* accept no frames yet!  */
	RTL_W32(TxConfig,(TX_DMA_BURST<<8)|0x03000000);

	/* The Linux driver changes Config1 here to use a different LED pattern
	 * for half duplex or full/autodetect duplex (for full/autodetect, the
	 * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
	 * TX/RX, Link100, Link10).  This is messy, because it doesn't match
	 * the inscription on the mounting bracket.  It should not be changed
	 * from the configuration EEPROM default, because the card manufacturer
	 * should have set that to match the card.  */


	/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
	rp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
	rp->cur_rx = 0;
	rp->cur_tx = 0;
	rp->dirty_tx = 0;
	nic->t_busy = 0;

	for (i = 0; i < NUM_TX_DESC; i++)
		rp->tx_buf[i] = &tx_buffer[i * TX_BUF_SIZE];


	/* init Rx ring buffer DMA address */
	RTL_W32_F(RxBuf, (unsigned long)rx_ring);

	/* init Tx buffer DMA addresses */
	for (i = 0; i < NUM_TX_DESC; i++)
		RTL_W32_F (TxAddr0 + (i * 4), rp->tx_buf);




	/* Start the chip's Tx and Rx process. */
	RTL_W32(RxMissed,0);
	/* set_rx_mode */
	RTL_W8(RxConfig,AcceptBroadcast|AcceptMyPhys/*|AcceptAllPhys*/);

	
	/* no early-rx interrupts */
//	RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);

	
	/* If we add multicast support, the MAR0 register would have to be
	 * initialized to 0xffffffffffffffff (two 32 bit accesses).  Etherboot
	 * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast.  */
	RTL_W8(ChipCmd,CmdRxEnb | CmdTxEnb);

	/* Disable all known interrupts by setting the interrupt mask. */
	RTL_W16(IntrMask,0);

	RTL_W16(IntrMask,rtl8139_intr_mask);

	/* Clear watchdog timer */
	nic->timeout = 0;
}

static int rtl_transmit(struct nic *nic,  char *data,int len)
{
#if 1
	unsigned int entry;
	struct rtl_private_data *rp = nic->private_data;
	/* Calculate the next Tx descriptor entry. */
	entry = rp->cur_tx % NUM_TX_DESC;

	
	if(len > TX_BUF_SIZE) {
		return -1;
	}


	/* Mask the bit that says "this is an io addr" */
	ioaddr = nic->ioaddr;
	
	/* Wait ... */	
	if(nic->t_busy == 1)
		return -1;

	

	memcpy(rp->tx_buf[entry] ,data, len);

	
	/* Note: the chip doesn't have auto-pad! */
	RTL_W32_F (TxStatus0 + (entry * 4),rp->tx_flag | (len >= ETH_ZLEN ? len : ETH_ZLEN));


	/* Set a timer just in case we never hear from the board again . */
	nic->timeout = TX_TIMEOUT;
	rp->cur_tx ++;

	if ((rp->cur_tx - NUM_TX_DESC) == rp->dirty_tx)
		nic->t_busy = 1;

	
	return len;

#else
	/* Mask the bit that says "this is an io addr" */
	ioaddr = nic->ioaddr;
	
	/* Wait ... */	
	while(nic->timeout > 0) {
		;
	}

	memcpy(tx_buffer ,data, len);

	/* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
	 * bytes are sent automatically for the FCS, totalling to 64 bytes). */
	while (len < ETH_ZLEN) {
		tx_buffer[len++] = '\0';
	}

	RTL_W32(TxAddr0 ,(unsigned long)tx_buffer);
	RTL_W32(TxStatus0 ,((TX_FIFO_THRESH<<11) & 0x003f0000) | len);


	/* Set a timer just in case we never hear from the board again . */
	nic->timeout = TX_TIMEOUT;



	return len;

#endif
}

int
rtl_ioctl(struct nic *nic,u_long cmd,caddr_t data)
{
	/* Mask the bit that says "this is an io addr" */
	ioaddr = nic->ioaddr;
	return 0;
}




/* 
 * $Log: rtl8139.c,v $
 * Revision 1.10  2002/02/21 08:25:00  linfusheng
 * update
 *
 * Revision 1.9  2002/02/07 10:25:35  linfusheng
 * update
 *
 * Revision 1.8  2002/02/07 01:08:53  linfusheng
 * update
 *
 * Revision 1.7  2002/02/06 07:59:04  linfusheng
 * update
 *
 * Revision 1.6  2002/02/06 07:42:18  linfusheng
 * update
 *
 * Revision 1.5  2002/02/06 07:28:51  linfusheng
 * update
 *
 * Revision 1.4  2002/02/06 02:16:25  linfusheng
 * update
 *
 * Revision 1.3  2002/01/28 01:13:52  linfusheng
 * update
 *
 * Revision 1.2  2002/01/28 00:46:25  linfusheng
 * update
 *
 */

⌨️ 快捷键说明

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