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

📄 eepro.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Get the current statistics.	This may be called with the card open or   closed. */static struct enet_statistics *eepro_get_stats(struct device *dev){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	return &lp->stats;}/* Set or clear the multicast filter for this adaptor. */static voidset_multicast_list(struct device *dev){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	short ioaddr = dev->base_addr;	unsigned short mode;	struct dev_mc_list *dmi=dev->mc_list;		if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) 	{		/*		 *	We must make the kernel realise we had to move		 *	into promisc mode or we start all out war on		 *	the cable. If it was a promisc request the		 *	flag is already set. If not we assert it.		 */		dev->flags|=IFF_PROMISC;				outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */		mode = inb(ioaddr + REG2);		outb(mode | PRMSC_Mode, ioaddr + REG2);			mode = inb(ioaddr + REG3);		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */		printk("%s: promiscuous mode enabled.\n", dev->name);	} 		else if (dev->mc_count==0 ) 	{		outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */		mode = inb(ioaddr + REG2);		outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */		mode = inb(ioaddr + REG3);		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */	}		else 	{		unsigned short status, *eaddrs;		int i, boguscount = 0;				/* Disable RX and TX interrupts.  Necessary to avoid		   corruption of the HOST_ADDRESS_REG by interrupt		   service routines. */		outb(ALL_MASK, ioaddr + INT_MASK_REG);		outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */		mode = inb(ioaddr + REG2);		outb(mode | Multi_IA, ioaddr + REG2);			mode = inb(ioaddr + REG3);		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */		outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);		outw(MC_SETUP, ioaddr + IO_PORT);		outw(0, ioaddr + IO_PORT);		outw(0, ioaddr + IO_PORT);		outw(6*(dev->mc_count + 1), ioaddr + IO_PORT);			for (i = 0; i < dev->mc_count; i++) 		{			eaddrs=(unsigned short *)dmi->dmi_addr;			dmi=dmi->next;			outw(*eaddrs++, ioaddr + IO_PORT);			outw(*eaddrs++, ioaddr + IO_PORT);			outw(*eaddrs++, ioaddr + IO_PORT);		}			eaddrs = (unsigned short *) dev->dev_addr;		outw(eaddrs[0], ioaddr + IO_PORT);		outw(eaddrs[1], ioaddr + IO_PORT);		outw(eaddrs[2], ioaddr + IO_PORT);		outw(lp->tx_end, ioaddr + XMT_BAR);		outb(MC_SETUP, ioaddr);			/* Update the transmit queue */		i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1);			if (lp->tx_start != lp->tx_end) 		{ 			/* update the next address and the chain bit in the 			   last packet */			outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);			outw(i, ioaddr + IO_PORT);			outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);			status = inw(ioaddr + IO_PORT);			outw(status | CHAIN_BIT, ioaddr + IO_PORT);			lp->tx_end = i ;		}		else {			lp->tx_start = lp->tx_end = i ;		}			/* Acknowledge that the MC setup is done */		do { /* We should be doing this in the eepro_interrupt()! */			SLOW_DOWN_IO;			SLOW_DOWN_IO;				if (inb(ioaddr + STATUS_REG) & 0x08) 			{				i = inb(ioaddr);				outb(0x08, ioaddr + STATUS_REG);					if (i & 0x20) { /* command ABORTed */					printk("%s: multicast setup failed.\n", 						dev->name);					break;				} else if ((i & 0x0f) == 0x03)	{ /* MC-Done */					printk("%s: set Rx mode to %d addresses.\n", 						dev->name, dev->mc_count);					break;				}			}		} while (++boguscount < 100);			/* Re-enable RX and TX interrupts */		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 		}	outb(RCV_ENABLE_CMD, ioaddr);}/* The horrible routine to read a word from the serial EEPROM. *//* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read *//* The delay between EEPROM clock transitions. */#define eeprom_delay()	{ int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}#define EE_READ_CMD (6 << 6)intread_eeprom(int ioaddr, int location){	int i;	unsigned short retval = 0;	short ee_addr = ioaddr + EEPROM_REG;	int read_cmd = location | EE_READ_CMD;	short ctrl_val = EECS ;		outb(BANK2_SELECT, ioaddr);	outb(ctrl_val, ee_addr);		/* Shift the read command bits out. */	for (i = 8; i >= 0; i--) {		short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI			: ctrl_val;		outb(outval, ee_addr);		outb(outval | EESK, ee_addr);	/* EEPROM clock tick. */		eeprom_delay();		outb(outval, ee_addr);	/* Finish EEPROM a clock tick. */		eeprom_delay();	}	outb(ctrl_val, ee_addr);		for (i = 16; i > 0; i--) {		outb(ctrl_val | EESK, ee_addr);	 eeprom_delay();		retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);		outb(ctrl_val, ee_addr);  eeprom_delay();	}	/* Terminate the EEPROM access. */	ctrl_val &= ~EECS;	outb(ctrl_val | EESK, ee_addr);	eeprom_delay();	outb(ctrl_val, ee_addr);	eeprom_delay();	outb(BANK0_SELECT, ioaddr);	return retval;}static voidhardware_send_packet(struct device *dev, void *buf, short length){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	short ioaddr = dev->base_addr;	int rcv_ram = dev->mem_end;	unsigned status, tx_available, last, end, boguscount = 100;	if (net_debug > 5)		printk("eepro: entering hardware_send_packet routine.\n");		while (boguscount-- > 0) {			/* Disable RX and TX interrupts.  Necessary to avoid	   	corruption of the HOST_ADDRESS_REG by interrupt	   	service routines. */		outb(ALL_MASK, ioaddr + INT_MASK_REG);			if (dev->interrupt == 1) {  			/* Enable RX and TX interrupts */			outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 			continue;		}			/* determine how much of the transmit buffer space is available */		if (lp->tx_end > lp->tx_start)			tx_available = XMT_RAM - (lp->tx_end - lp->tx_start);		else if (lp->tx_end < lp->tx_start)			tx_available = lp->tx_start - lp->tx_end;		else tx_available = XMT_RAM;			if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) 			>= tx_available)   /* No space available ??? */			{			eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */			/* Enable RX and TX interrupts */			outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 			continue;		}			last = lp->tx_end;		end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;		if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */				if ((RAM_SIZE - last) <= XMT_HEADER) {				/* Arrrr!!!, must keep the xmt header together,			  several days were lost to chase this one down. */				last = rcv_ram;				end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;			}				else end = rcv_ram + (end - RAM_SIZE);		}		outw(last, ioaddr + HOST_ADDRESS_REG);		outw(XMT_CMD, ioaddr + IO_PORT);		outw(0, ioaddr + IO_PORT);		outw(end, ioaddr + IO_PORT);		outw(length, ioaddr + IO_PORT);			if (lp->version == LAN595)			outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);			else {	/* LAN595TX or LAN595FX, capable of 32-bit I/O processing */			unsigned short temp = inb(ioaddr + INT_MASK_REG);			outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);			outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);			outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);		}			/* A dummy read to flush the DRAM write pipeline */		status = inw(ioaddr + IO_PORT); 			if (lp->tx_start == lp->tx_end) {				outw(last, ioaddr + XMT_BAR);			outb(XMT_CMD, ioaddr);			lp->tx_start = last;   /* I don't like to change tx_start here */		}		else {			/* update the next address and the chain bit in the 		   	last packet */			if (lp->tx_end != last) {				outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);				outw(last, ioaddr + IO_PORT);			}				outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);			status = inw(ioaddr + IO_PORT);			outw(status | CHAIN_BIT, ioaddr + IO_PORT);				/* Continue the transmit command */			outb(RESUME_XMT_CMD, ioaddr);		}		lp->tx_last = last;		lp->tx_end = end;			/* Enable RX and TX interrupts */		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 			if (dev->tbusy) {			dev->tbusy = 0;		}			if (net_debug > 5)			printk("eepro: exiting hardware_send_packet routine.\n");			return;	}	dev->tbusy = 1;		if (net_debug > 5)		printk("eepro: exiting hardware_send_packet routine.\n");}static voideepro_rx(struct device *dev){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	short ioaddr = dev->base_addr, rcv_ram = dev->mem_end;	short boguscount = 20;	short rcv_car = lp->rx_start;	unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;	if (net_debug > 5)		printk("eepro: entering eepro_rx routine.\n");		/* Set the read pointer to the start of the RCV */	outw(rcv_car, ioaddr + HOST_ADDRESS_REG);		rcv_event = inw(ioaddr + IO_PORT);	while (rcv_event == RCV_DONE) {		rcv_status = inw(ioaddr + IO_PORT);		rcv_next_frame = inw(ioaddr + IO_PORT);		rcv_size = inw(ioaddr + IO_PORT);			if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {				/* Malloc up new buffer. */			struct sk_buff *skb;			rcv_size &= 0x3fff;			skb = dev_alloc_skb(rcv_size+5);				if (skb == NULL) {				printk("%s: Memory squeeze, dropping packet.\n", dev->name);				lp->stats.rx_dropped++;				break;			}				skb->dev = dev;			skb_reserve(skb,2);				if (lp->version == LAN595)				insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);				else {	/* LAN595TX or LAN595FX, capable of 32-bit I/O processing */				unsigned short temp = inb(ioaddr + INT_MASK_REG);				outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);				insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), (rcv_size + 3) >> 2);				outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);			}				skb->protocol = eth_type_trans(skb,dev);				netif_rx(skb);			lp->stats.rx_packets++;		}			else { /* Not sure will ever reach here, 			  I set the 595 to discard bad received frames */			lp->stats.rx_errors++;				if (rcv_status & 0x0100)				lp->stats.rx_over_errors++;				else if (rcv_status & 0x0400)				lp->stats.rx_frame_errors++;				else if (rcv_status & 0x0800)				lp->stats.rx_crc_errors++;				printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", 				dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);		}			if (rcv_status & 0x1000)			lp->stats.rx_length_errors++;			if (--boguscount == 0)			break;			rcv_car = lp->rx_start + RCV_HEADER + rcv_size;		lp->rx_start = rcv_next_frame;		outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);		rcv_event = inw(ioaddr + IO_PORT);	} 	if (rcv_car == 0)		rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff;		outw(rcv_car - 1, ioaddr + RCV_STOP);		if (net_debug > 5)		printk("eepro: exiting eepro_rx routine.\n");}static voideepro_transmit_interrupt(struct device *dev){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	short ioaddr = dev->base_addr;	short boguscount = 20; 	short xmt_status;	while (lp->tx_start != lp->tx_end) { 			outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);		xmt_status = inw(ioaddr+IO_PORT);			if ((xmt_status & TX_DONE_BIT) == 0) break;			xmt_status = inw(ioaddr+IO_PORT);		lp->tx_start = inw(ioaddr+IO_PORT);		dev->tbusy = 0;		mark_bh(NET_BH);			if (xmt_status & 0x2000)			lp->stats.tx_packets++; 		else {			lp->stats.tx_errors++;			if (xmt_status & 0x0400)				lp->stats.tx_carrier_errors++;			printk("%s: XMT status = %#x\n",				dev->name, xmt_status);		}			if (xmt_status & 0x000f) {			lp->stats.collisions += (xmt_status & 0x000f);		}			if ((xmt_status & 0x0040) == 0x0) {			lp->stats.tx_heartbeat_errors++;		}			if (--boguscount == 0)			break;  	}}#ifdef MODULEstatic char devicename[9] = { 0, };static struct device dev_eepro = {	devicename, /* device name is inserted by linux/drivers/net/net_init.c */	0, 0, 0, 0,	0, 0,	0, 0, 0, NULL, eepro_probe };static int io = 0x200;static int irq = 0;static int mem = (RCV_RAM/1024);	/* Size of the rx buffer in KB */int init_module(void){	if (io == 0)		printk("eepro: You should not use auto-probing with insmod!\n");	dev_eepro.base_addr = io;	dev_eepro.irq       = irq;	dev_eepro.mem_end   = mem;	if (register_netdev(&dev_eepro) != 0)		return -EIO;	return 0;}voidcleanup_module(void){	unregister_netdev(&dev_eepro);	kfree_s(dev_eepro.priv,sizeof(struct eepro_local));	dev_eepro.priv=NULL;	/* If we don't do this, we can't re-insmod it later. */	release_region(dev_eepro.base_addr, EEPRO_IO_EXTENT);}#endif /* MODULE */

⌨️ 快捷键说明

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