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

📄 eepro.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	for (i=0; i < 6; i++) 		outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); 				temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */	outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */		| RCV_Discard_BadFrame, ioaddr + REG1);  	temp_reg = inb(ioaddr + REG2); /* Match broadcast */	outb(temp_reg | 0x14, ioaddr + REG2);	temp_reg = inb(ioaddr + REG3);	outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */	/* Set the receiving mode */	outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */	/* Set the interrupt vector */		temp_reg = inb(ioaddr + INT_NO_REG);	if (lp->eepro == 2)		outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);	else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); 	temp_reg = inb(ioaddr + INT_NO_REG);	if (lp->eepro == 2)		outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);	else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);	if (net_debug > 3)		printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);	/* Initialize the RCV and XMT upper and lower limits */	outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); 	outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); 	outb(XMT_LOWER_LIMIT, ioaddr + XMT_LOWER_LIMIT_REG); 	outb(XMT_UPPER_LIMIT, ioaddr + XMT_UPPER_LIMIT_REG); 	/* Enable the interrupt line. */	temp_reg = inb(ioaddr + REG1);	outb(temp_reg | INT_ENABLE, ioaddr + REG1); 	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */	/* Let RX and TX events to interrupt */	outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 	/* clear all interrupts */	outb(ALL_MASK, ioaddr + STATUS_REG); 	/* Initialize RCV */	outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); 	lp->rx_start = (RCV_LOWER_LIMIT << 8) ;	outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); 	/* Initialize XMT */	outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR); 	/* Check for the i82595TX and i82595FX */	old8 = inb(ioaddr + 8);	outb(~old8, ioaddr + 8);	if ((temp_reg = inb(ioaddr + 8)) == old8) {		if (net_debug > 3)			printk(KERN_DEBUG "i82595 detected!\n");		lp->version = LAN595;	}	else {		lp->version = LAN595TX;		outb(old8, ioaddr + 8);		old9 = inb(ioaddr + 9);		/*outb(~old9, ioaddr + 9);		if (((temp_reg = inb(ioaddr + 9)) == ( (~old9)&0xff) )) {*/				if (irqMask==ee_FX_INT2IRQ) {			enum iftype { AUI=0, BNC=1, TPE=2 };			if (net_debug > 3) {				printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);				printk(KERN_DEBUG "i82595FX detected!\n");			}			lp->version = LAN595FX;			outb(old9, ioaddr + 9);			if (dev->if_port != TPE) {	/* Hopefully, this will fix the							problem of using Pentiums and							pro/10 w/ BNC. */				outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */				temp_reg = inb(ioaddr + REG13);				/* disable the full duplex mode since it is not				applicable with the 10Base2 cable. */				outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);				outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */			}		}		else if (net_debug > 3) {			printk(KERN_DEBUG "temp_reg: %#x  ~old9: %#x\n",temp_reg,((~old9)&0xff));			printk(KERN_DEBUG "i82595TX detected!\n");		}	}		outb(SEL_RESET_CMD, ioaddr);	/* We are supposed to wait for 2 us after a SEL_RESET */	SLOW_DOWN;	SLOW_DOWN;	lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */	lp->tx_last = 0;		dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	if (net_debug > 3)		printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);	outb(RCV_ENABLE_CMD, ioaddr);	MOD_INC_USE_COUNT;	return 0;}static int eepro_send_packet(struct sk_buff *skb, struct device *dev){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	int ioaddr = dev->base_addr;	int rcv_ram = dev->mem_end;#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155	unsigned long flags;#endif		if (net_debug > 5)		printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);		if (dev->tbusy) {		/* If we get here, some higher level has decided we are broken.		   There should really be a "kick me" function call instead. */		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 40)			return 1;			/* if (net_debug > 1) */		printk(KERN_ERR "%s: transmit timed out, %s?\n", dev->name, 			"network cable problem");		/* This is not a duplicate. One message for the console, 		   one for the the log file  */		printk(KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,			"network cable problem");		lp->stats.tx_errors++;		/* Try to restart the adaptor. */		outb(SEL_RESET_CMD, ioaddr); 		/* We are supposed to wait for 2 us after a SEL_RESET */		SLOW_DOWN;		SLOW_DOWN;		/* Do I also need to flush the transmit buffers here? YES? */		lp->tx_start = lp->tx_end = rcv_ram; 		lp->tx_last = 0;			dev->tbusy=0;		dev->trans_start = jiffies;		outb(RCV_ENABLE_CMD, ioaddr);	}#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20155	/* If some higher layer thinks we've missed an tx-done interrupt	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()	   itself. */	/*	if (skb == NULL) {		dev_tint(dev);	  	return 0;	}*/	/* according to A. Cox, this is obsolete since 1.0 */#endif#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155	spin_lock_irqsave(&lp->lock, flags);#endif	/* Block a timer-based transmit from overlapping. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155		spin_unlock_irqrestore(&lp->lock, flags);#endif	} else {		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;		unsigned char *buf = skb->data;#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155		lp->stats.tx_bytes+=skb->len;#endif		hardware_send_packet(dev, buf, length);		dev->trans_start = jiffies;	}	compat_dev_kfree_skb (skb, FREE_WRITE);	/* You might need to clean up and record Tx statistics here. */	/* lp->stats.tx_aborted_errors++; */	if (net_debug > 5)		printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155	spin_unlock_irqrestore(&lp->lock, flags);#endif		return 0;}/*	The typical workload of the driver:	Handle the network interface interrupts. */static voideepro_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct device *dev =  (struct device *)dev_id;	                      /* (struct device *)(irq2dev_map[irq]);*/	struct eepro_local *lp = (struct eepro_local *)dev->priv;	int ioaddr, status, boguscount = 20;	if (dev == NULL) {                printk (KERN_ERR "eepro_interrupt(): irq %d for unknown device.\\n", irq);                return;        }#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155        spin_lock(&lp->lock);#endif	if (dev->interrupt) {		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155		spin_unlock(&lp->lock);		/* FIXME : with the lock, could this ever happen ? */#endif		return;	}	dev->interrupt = 1;	if (net_debug > 5)		printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);		ioaddr = dev->base_addr;	do { 		status = inb(ioaddr + STATUS_REG);				if (status & RX_INT) {			if (net_debug > 4)			printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);			/* Acknowledge the RX_INT */			outb(RX_INT, ioaddr + STATUS_REG);			/* Get the received packets */			eepro_rx(dev);		}		else if (status & TX_INT) {			if (net_debug > 4)			printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);			/* Acknowledge the TX_INT */			outb(TX_INT, ioaddr + STATUS_REG); 			/* Process the status of transmitted packets */			eepro_transmit_interrupt(dev);		}		} while ((boguscount-- > 0) && (status & 0x06));	dev->interrupt = 0; 	if (net_debug > 5)		printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155	spin_unlock(&lp->lock);#endif	return;}static int eepro_close(struct device *dev){	struct eepro_local *lp = (struct eepro_local *)dev->priv;	int ioaddr = dev->base_addr;	int rcv_ram = dev->mem_end;	short temp_reg;	dev->tbusy = 1;	dev->start = 0;	outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */	/* Disable the physical interrupt line. */	temp_reg = inb(ioaddr + REG1);	outb(temp_reg & 0x7f, ioaddr + REG1); 	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */	/* Flush the Tx and disable Rx. */	outb(STOP_RCV_CMD, ioaddr); 	lp->tx_start = lp->tx_end = rcv_ram ;	lp->tx_last = 0;	/* Mask all the interrupts. */	outb(ALL_MASK, ioaddr + INT_MASK_REG); 	/* clear all interrupts */	outb(ALL_MASK, ioaddr + STATUS_REG); 	/* Reset the 82595 */	outb(RESET_CMD, ioaddr); 	/* release the interrupt */	free_irq(dev->irq, dev);#ifdef irq2dev_map	irq2dev_map[dev->irq] = 0;#endif	/* Update the statistics here. What statistics? */	/* We are supposed to wait for 200 us after a RESET */	SLOW_DOWN;	SLOW_DOWN; /* May not be enough? */	MOD_DEC_USE_COUNT;	return 0;}/* 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);		

⌨️ 快捷键说明

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