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

📄 rtl8139.c

📁 i386的bootloader源码grub
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 << 6)#define EE_READ_CMD     (6 << 6)#define EE_ERASE_CMD    (7 << 6)static int read_eeprom(int location){	int i;	unsigned int retval = 0;	long ee_addr = ioaddr + Cfg9346;	int read_cmd = location | EE_READ_CMD;	outb(EE_ENB & ~EE_CS, ee_addr);	outb(EE_ENB, ee_addr);	/* Shift the read command bits out. */	for (i = 10; 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);	return retval;}static void rtl_reset(struct nic* nic){	int i;	outb(CmdReset, ioaddr + ChipCmd);	cur_rx = 0;	cur_tx = 0;	/* Give the chip 10ms to finish the reset. */	load_timer2(10*TICKS_PER_MS);	while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running())		/* wait */;	for (i = 0; i < ETH_ALEN; i++)		outb(nic->node_addr[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((unsigned long)rx_ring, ioaddr + RxBuf);	/* Start the chip's Tx and Rx process. */	outl(0, ioaddr + RxMissed);	/* set_rx_mode */	outb(AcceptBroadcast|AcceptMyPhys, ioaddr + RxConfig);	/* 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);	/* Disable all known interrupts by setting the interrupt mask. */	outw(0, ioaddr + IntrMask);}static void rtl_transmit(struct nic *nic, const char *destaddr,	unsigned int type, unsigned int len, const char *data){	unsigned int status, to, nstype;	unsigned long txstatus;	memcpy(tx_buffer, destaddr, ETH_ALEN);	memcpy(tx_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN);	nstype = htons(type);	memcpy(tx_buffer + 2 * ETH_ALEN, (char*)&nstype, 2);	memcpy(tx_buffer + ETH_HLEN, data, len);	len += ETH_HLEN;#ifdef	DEBUG_TX	printf("sending %d bytes ethtype %hX\n", len, type);#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((unsigned long)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	} else {#ifdef	DEBUG_TX		printf("tx timeout/error (%d ticks), status %hX txstatus %X\n",			currticks()-to, status, txstatus);#endif		rtl_reset(nic);	}}static int rtl_poll(struct nic *nic){	unsigned int status;	unsigned int ring_offs;	unsigned int rx_size, rx_status;	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*)(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(nic);	/* this clears all interrupts still pending */		return 0;	}	/* Received a good packet */	nic->packetlen = 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;		memcpy(nic->packet, rx_ring + ring_offs + 4, semi_count);		memcpy(nic->packet+semi_count, rx_ring, rx_size-4-semi_count);#ifdef	DEBUG_RX		printf("rx packet %d+%d bytes", semi_count,rx_size-4-semi_count);#endif	} else {		memcpy(nic->packet, rx_ring + ring_offs + 4, nic->packetlen);#ifdef	DEBUG_RX		printf("rx packet %d bytes", rx_size-4);#endif	}#ifdef	DEBUG_RX	printf(" at %X type %hhX%hhX rxstatus %hX\n",		(unsigned long)(rx_ring+ring_offs+4),		nic->packet[12], nic->packet[13], rx_status);#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 1;}static void rtl_disable(struct nic *nic){	/* reset the chip */	outb(CmdReset, ioaddr + ChipCmd);	/* 10 ms timeout */	load_timer2(10*TICKS_PER_MS);	while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running())		/* wait */;}

⌨️ 快捷键说明

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