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

📄 rtl8139.c

📁 8139 network card linux driver
💻 C
📖 第 1 页 / 共 2 页
字号:
}/* Serial EEPROM section. *//*  EEPROM_Ctrl bits. */#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */#define EE_CS		0x08	/* EEPROM chip select. */#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */#define EE_WRITE_0	0x00#define EE_WRITE_1	0x02#define EE_DATA_READ	0x01	/* EEPROM chip data out. */#define EE_ENB		(0x80 | EE_CS)/*	Delay between EEPROM clock transitions.	No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.*/#define eeprom_delay()	inl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD	(5)#define EE_READ_CMD	(6)#define EE_ERASE_CMD	(7)static int read_eeprom(int location, int addr_len){	int i;	unsigned int retval = 0;	long ee_addr = ioaddr + Cfg9346;	int read_cmd = location | (EE_READ_CMD << addr_len);	outb(EE_ENB & ~EE_CS, ee_addr);	outb(EE_ENB, ee_addr);	eeprom_delay();	/* Shift the read command bits out. */	for (i = 4 + addr_len; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;		outb(EE_ENB | dataval, ee_addr);		eeprom_delay();		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);		eeprom_delay();	}	outb(EE_ENB, ee_addr);	eeprom_delay();	for (i = 16; i > 0; i--) {		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);		eeprom_delay();		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);		outb(EE_ENB, ee_addr);		eeprom_delay();	}	/* Terminate the EEPROM access. */	outb(~EE_CS, ee_addr);	eeprom_delay();	return retval;}static const unsigned int rtl8139_rx_config =	(RX_BUF_LEN_IDX << 11) |	(RX_FIFO_THRESH << 13) |	(RX_DMA_BURST << 8);static void set_rx_mode(struct eth_device *dev) {	unsigned int mc_filter[2];	int rx_mode;	/* !IFF_PROMISC */	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;	mc_filter[1] = mc_filter[0] = 0xffffffff;	outl(rtl8139_rx_config | rx_mode, ioaddr + RxConfig);	outl(mc_filter[0], ioaddr + MAR0 + 0);	outl(mc_filter[1], ioaddr + MAR0 + 4);}static void rtl_reset(struct eth_device *dev){	int i;	outb(CmdReset, ioaddr + ChipCmd);	cur_rx = 0;	cur_tx = 0;	/* Give the chip 10ms to finish the reset. */	for (i=0; i<100; ++i){		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;		udelay (100); /* wait 100us */	}	for (i = 0; i < ETH_ALEN; i++)		outb(dev->enetaddr[i], ioaddr + MAC0 + i);	/* Must enable Tx/Rx before setting transfer thresholds! */	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),		ioaddr + RxConfig);		/* accept no frames yet!  */	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);	/* 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.  */#ifdef	DEBUG_RX	printf("rx ring address is %X\n",(unsigned long)rx_ring);#endif	outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);	/* 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.	*/	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	outl(rtl8139_rx_config, ioaddr + RxConfig);	/* Start the chip's Tx and Rx process. */	outl(0, ioaddr + RxMissed);	/* set_rx_mode */	set_rx_mode(dev);	/* Disable all known interrupts by setting the interrupt mask. */	outw(0, ioaddr + IntrMask);}static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length){	unsigned int status, to;	unsigned long txstatus;	unsigned int len = length;	ioaddr = dev->iobase;	memcpy((char *)tx_buffer, (char *)packet, (int)length);#ifdef	DEBUG_TX	printf("sending %d bytes\n", len);#endif	/* 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';	}	outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);	outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,		ioaddr + TxStatus0 + cur_tx*4);	to = currticks() + RTL_TIMEOUT;	do {		status = inw(ioaddr + IntrStatus);		/* Only acknlowledge interrupt sources we can properly handle		 * here - the RxOverflow/RxFIFOOver MUST be handled in the		 * rtl_poll() function.	 */		outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);		if ((status & (TxOK | TxErr | PCIErr)) != 0) break;	} while (currticks() < to);	txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);	if (status & TxOK) {		cur_tx = (cur_tx + 1) % NUM_TX_DESC;#ifdef	DEBUG_TX		printf("tx done (%d ticks), status %hX txstatus %X\n",			to-currticks(), status, txstatus);#endif		return length;	} else {#ifdef	DEBUG_TX		printf("tx timeout/error (%d ticks), status %hX txstatus %X\n",			currticks()-to, status, txstatus);#endif		rtl_reset(dev);		return 0;	}}static int rtl_poll(struct eth_device *dev){	unsigned int status;	unsigned int ring_offs;	unsigned int rx_size, rx_status;	int length=0;	ioaddr = dev->iobase;	if (inb(ioaddr + ChipCmd) & RxBufEmpty) {		return 0;	}	status = inw(ioaddr + IntrStatus);	/* See below for the rest of the interrupt acknowledges.  */	outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);#ifdef	DEBUG_RX	printf("rtl_poll: int %hX ", status);#endif	ring_offs = cur_rx % RX_BUF_LEN;	rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs));	rx_size = rx_status >> 16;	rx_status &= 0xffff;	if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) ||	    (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) {		printf("rx error %hX\n", rx_status);		rtl_reset(dev); /* this clears all interrupts still pending */		return 0;	}	/* Received a good packet */	length = rx_size - 4;	/* no one cares about the FCS */	if (ring_offs+4+rx_size-4 > RX_BUF_LEN) {		int semi_count = RX_BUF_LEN - ring_offs - 4;		unsigned char rxdata[RX_BUF_LEN];		memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);		memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count);		NetReceive(rxdata, length);#ifdef	DEBUG_RX		printf("rx packet %d+%d bytes", semi_count,rx_size-4-semi_count);#endif	} else {		NetReceive(rx_ring + ring_offs + 4, length);#ifdef	DEBUG_RX		printf("rx packet %d bytes", rx_size-4);#endif	}	cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;	outw(cur_rx - 16, ioaddr + RxBufPtr);	/* See RTL8139 Programming Guide V0.1 for the official handling of	 * Rx overflow situations.  The document itself contains basically no	 * usable information, except for a few exception handling rules.  */	outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);	return length;}static void rtl_disable(struct eth_device *dev){	int i;	ioaddr = dev->iobase;	/* reset the chip */	outb(CmdReset, ioaddr + ChipCmd);	/* Give the chip 10ms to finish the reset. */	for (i=0; i<100; ++i){		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;		udelay (100); /* wait 100us */	}}#endif	/* CFG_CMD_NET && CONFIG_NET_MULTI && CONFIG_RTL8139 */

⌨️ 快捷键说明

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