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

📄 eexpress.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
		{			if ((jiffies-lp->init_time)>10)			{				unsigned short status = inw(ioaddr+SCB_STATUS);				printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",					dev->name, status);				eexp_hw_init586(dev);				dev->tbusy = 0;				mark_bh(NET_BH);			}		}	}	if (buf==NULL) 	{		unsigned short status = inw(ioaddr+SCB_STATUS);		unsigned short txstatus = eexp_hw_lasttxstat(dev);		if (SCB_CUdead(status)) 		{			printk(KERN_WARNING "%s: CU has died! status %04x %04x, attempting to restart...\n",				dev->name, status, txstatus);			lp->stats.tx_errors++;			eexp_hw_txrestart(dev);		}		dev_tint(dev);		outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);		dev_kfree_skb(buf, FREE_WRITE);		return 0;	}	if (set_bit(0,(void *)&dev->tbusy)) 	{		lp->stats.tx_dropped++;	}	else	{		unsigned short length = (ETH_ZLEN < buf->len) ? buf->len : ETH_ZLEN;		unsigned short *data = (unsigned short *)buf->data;		outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);		eexp_hw_tx(dev,data,length);		outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);	}	dev_kfree_skb(buf, FREE_WRITE);	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);	return 0;}/* * Handle an EtherExpress interrupt * If we've finished initializing, start the RU and CU up. * If we've already started, reap tx buffers, handle any received packets, * check to make sure we've not become wedged. */static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs){	struct device *dev = irq2dev_map[irq];	struct net_local *lp;	unsigned short ioaddr,status,ack_cmd;	unsigned short old_rp,old_wp;	if (dev==NULL) 	{		printk(KERN_WARNING "net_interrupt(): irq %d for unknown device caught by EExpress\n",irq);		return;	}#if NET_DEBUG > 6	printk(KERN_DEBUG "%s: interrupt\n", dev->name);#endif	dev->interrupt = 1; /* should this be reset on exit? */  	lp = (struct net_local *)dev->priv;	ioaddr = dev->base_addr;	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);	old_rp = inw(ioaddr+READ_PTR);	old_wp = inw(ioaddr+WRITE_PTR);	status = inw(ioaddr+SCB_STATUS);	ack_cmd = SCB_ack(status);	if (PRIV(dev)->started==0 && SCB_complete(status)) 	{#if NET_DEBUG > 4		printk(KERN_DEBUG "%s: SCBcomplete event received\n", dev->name);#endif		while (SCB_CUstat(status)==2)			status = inw_p(ioaddr+SCB_STATUS);#if NET_DEBUG > 4                printk(KERN_DEBUG "%s: CU went non-active (status = %08x)\n", dev->name, status);#endif		PRIV(dev)->started=1;		outw_p(lp->tx_link,ioaddr+SCB_CBL);		outw_p(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);		ack_cmd |= SCB_CUstart | SCB_RUstart;	}	else if (PRIV(dev)->started) 	{		unsigned short txstatus;		txstatus = eexp_hw_lasttxstat(dev);	}  	if (SCB_rxdframe(status)) 	{		eexp_hw_rx(dev);	}	if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4) 	{		printk(KERN_WARNING "%s: RU stopped status %04x, restarting...\n",			dev->name,status);		lp->stats.rx_errors++;		eexp_hw_rxinit(dev);		outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);		ack_cmd |= SCB_RUstart;	} 	else if (PRIV(dev)->started==1 && SCB_RUstat(status)==4) 		PRIV(dev)->started|=2;	outw(ack_cmd,ioaddr+SCB_CMD);	outb(0,ioaddr+SIGNAL_CA);	outw(old_rp,ioaddr+READ_PTR);	outw(old_wp,ioaddr+WRITE_PTR);	outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);	dev->interrupt = 0;#if NET_DEBUG > 6        printk(KERN_DEBUG "%s: leaving eexp_irq()\n", dev->name);#endif	return;}/* * Hardware access functions *//* * Check all the receive buffers, and hand any received packets * to the upper levels. Basic sanity check on each frame * descriptor */ static void eexp_hw_rx(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned short ioaddr = dev->base_addr;	unsigned short old_wp = inw(ioaddr+WRITE_PTR);	unsigned short old_rp = inw(ioaddr+READ_PTR);	unsigned short rx_block = lp->rx_first;	unsigned short boguscount = lp->num_rx_bufs;#if NET_DEBUG > 6	printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);#endif	while (outw(rx_block,ioaddr+READ_PTR),boguscount--) 	{		unsigned short status = inw(ioaddr);		unsigned short rfd_cmd = inw(ioaddr);		unsigned short rx_next = inw(ioaddr);		unsigned short pbuf = inw(ioaddr);		unsigned short pkt_len;		if (FD_Done(status)) 		{			outw(pbuf,ioaddr+READ_PTR);			pkt_len = inw(ioaddr);			if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16				|| (pkt_len & 0xc000)!=0xc000) 			{				printk(KERN_WARNING "%s: Rx frame at %04x corrupted, status %04x, cmd %04x, "					"next %04x, pbuf %04x, len %04x\n",dev->name,rx_block,					status,rfd_cmd,rx_next,pbuf,pkt_len);				boguscount++;				continue;			}			else if (!FD_OK(status)) 			{				lp->stats.rx_errors++;				if (FD_CRC(status)) 					lp->stats.rx_crc_errors++;				if (FD_Align(status))					lp->stats.rx_frame_errors++;				if (FD_Resrc(status))					lp->stats.rx_fifo_errors++;				if (FD_DMA(status))					lp->stats.rx_over_errors++;				if (FD_Short(status))					lp->stats.rx_length_errors++;			}			else			{				struct sk_buff *skb;				pkt_len &= 0x3fff;				skb = dev_alloc_skb(pkt_len+16);				if (skb == NULL) 				{					printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);					lp->stats.rx_dropped++;					break;				}				skb->dev = dev;				skb_reserve(skb, 2);				outw(pbuf+10,ioaddr+READ_PTR);				insw(ioaddr,skb_put(skb,pkt_len),(pkt_len+1)>>1);				skb->protocol = eth_type_trans(skb,dev);				netif_rx(skb);				lp->stats.rx_packets++;			}			outw(rx_block,ioaddr+WRITE_PTR);			outw(0x0000,ioaddr);			outw(0x0000,ioaddr);		}		rx_block = rx_next;	}	outw(old_rp,ioaddr+READ_PTR);	outw(old_wp,ioaddr+WRITE_PTR);}/* * Hand a packet to the card for transmission * If we get here, we MUST have already checked * to make sure there is room in the transmit * buffer region */static void eexp_hw_tx(struct device *dev, unsigned short *buf, unsigned short len){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned short ioaddr = dev->base_addr;	unsigned short old_wp = inw(ioaddr+WRITE_PTR);	outw(lp->tx_head,ioaddr+WRITE_PTR);	outw(0x0000,ioaddr);	outw(Cmd_INT|Cmd_Xmit,ioaddr);	outw(lp->tx_head+0x08,ioaddr);	outw(lp->tx_head+0x0e,ioaddr);	outw(0x0000,ioaddr);	outw(0x0000,ioaddr);	outw(lp->tx_head+0x08,ioaddr);	outw(0x8000|len,ioaddr);	outw(-1,ioaddr);	outw(lp->tx_head+0x16,ioaddr);	outw(0,ioaddr);	outsw(ioaddr,buf,(len+1)>>1);	outw(lp->tx_tail+0x0c,ioaddr+WRITE_PTR);	outw(lp->tx_head,ioaddr);	dev->trans_start = jiffies;	lp->tx_tail = lp->tx_head;	if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) 		lp->tx_head = TX_BUF_START;	else 		lp->tx_head += TX_BUF_SIZE;	if (lp->tx_head != lp->tx_reap) 		dev->tbusy = 0;	outw(old_wp,ioaddr+WRITE_PTR);}/* * Sanity check the suspected EtherExpress card * Read hardware address, reset card, size memory and * initialize buffer memory pointers. These should * probably be held in dev->priv, in case someone has 2 * differently configured cards in their box (Arghhh!) */static int eexp_hw_probe(struct device *dev, unsigned short ioaddr){	unsigned short hw_addr[3];	int i;	unsigned char *chw_addr = (unsigned char *)hw_addr;	printk("%s: EtherExpress at %#x, ",dev->name,ioaddr);	hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);	hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);	hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);	/* Standard Address or Compaq LTE Address */	if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||	      (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00)))) 	{		printk("rejected: invalid address %04x%04x%04x\n",			hw_addr[2],hw_addr[1],hw_addr[0]);		return -ENODEV;	}	dev->base_addr = ioaddr;	for ( i=0 ; i<6 ; i++ ) 		dev->dev_addr[i] = chw_addr[5-i];	{		char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0};		char *ifmap[]={"AUI", "BNC", "10baseT"};		enum iftype {AUI=0, BNC=1, TP=2};		unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);		dev->irq = irqmap[setupval>>13];		dev->if_port = !(setupval & 0x1000) ? AUI :			eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TP : BNC;		printk("IRQ %d, Interface %s, ",dev->irq,ifmap[dev->if_port]);		outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);		outb(0,ioaddr+SET_IRQ);	}	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);	if (!dev->priv) 		return -ENOMEM;	memset(dev->priv, 0, sizeof(struct net_local));	eexp_hw_ASICrst(dev);	{		unsigned short i586mso = 0x023e;		unsigned short old_wp,old_rp,old_a0,old_a1;		unsigned short a0_0,a1_0,a0_1,a1_1;		old_wp = inw(ioaddr+WRITE_PTR);		old_rp = inw(ioaddr+READ_PTR);		outw(0x8000+i586mso,ioaddr+READ_PTR);		old_a1 = inw(ioaddr);		outw(i586mso,ioaddr+READ_PTR);		old_a0 = inw(ioaddr);		outw(i586mso,ioaddr+WRITE_PTR);		outw(0x55aa,ioaddr);		outw(i586mso,ioaddr+READ_PTR);		a0_0 = inw(ioaddr);		outw(0x8000+i586mso,ioaddr+WRITE_PTR);		outw(0x5a5a,ioaddr);		outw(0x8000+i586mso,ioaddr+READ_PTR);		a1_0 = inw(ioaddr);		outw(i586mso,ioaddr+READ_PTR);		a0_1 = inw(ioaddr);		outw(i586mso,ioaddr+WRITE_PTR);		outw(0x1234,ioaddr);		outw(0x8000+i586mso,ioaddr+READ_PTR);		a1_1 = inw(ioaddr);		if ((a0_0 != a0_1) || (a1_0 != a1_1) ||			(a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) 		{			printk("32k\n");			PRIV(dev)->rx_buf_end = 0x7ff6;			PRIV(dev)->num_tx_bufs = 4;		}		else		{			printk("64k\n");			PRIV(dev)->num_tx_bufs = 8;			PRIV(dev)->rx_buf_start = TX_BUF_START + (PRIV(dev)->num_tx_bufs*TX_BUF_SIZE);			PRIV(dev)->rx_buf_end = 0xfff6;		}		outw(0x8000+i586mso,ioaddr+WRITE_PTR);		outw(old_a1,ioaddr);		outw(i586mso,ioaddr+WRITE_PTR);		outw(old_a0,ioaddr);		outw(old_wp,ioaddr+WRITE_PTR);		outw(old_rp,ioaddr+READ_PTR);	}  	if (net_debug) 		printk(version);	dev->open = eexp_open;	dev->stop = eexp_close;	dev->hard_start_xmit = eexp_xmit;	dev->get_stats = eexp_stats;	dev->set_multicast_list = &eexp_set_multicast;	ether_setup(dev);	return 0;}/* *	Read a word from eeprom location (0-63?) */static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location){	unsigned short cmd = 0x180|(location&0x7f);	unsigned short rval = 0,wval = EC_CS|i586_RST;	int i; 	outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);	for ( i=0x100 ; i ; i>>=1 ) 	{		if (cmd&i) 			wval |= EC_Wr;		else 			wval &= ~EC_Wr;		outb(wval,ioaddr+EEPROM_Ctrl);		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);		eeprom_delay();		outb(wval,ioaddr+EEPROM_Ctrl);		eeprom_delay();	}		wval &= ~EC_Wr;	outb(wval,ioaddr+EEPROM_Ctrl);	for ( i=0x8000 ; i ; i>>=1 ) 	{		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);		eeprom_delay();		if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd) 			rval |= i;		outb(wval,ioaddr+EEPROM_Ctrl);		eeprom_delay();	}	wval &= ~EC_CS;	outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);	eeprom_delay();	outb(wval,ioaddr+EEPROM_Ctrl);	eeprom_delay();	return rval;}/* * Reap tx buffers and return last transmit status. * if ==0 then either: *    a) we're not transmitting anything, so why are we here? *    b) we've died. * otherwise, Stat_Busy(return) means we've still got some packets * to transmit, Stat_Done(return) means our buffers should be empty * again */

⌨️ 快捷键说明

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