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

📄 eth16i.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			       inb(ioaddr + 1), inb(ioaddr + 2), 			       inb(ioaddr + 3), inb(ioaddr + 4), 			       inb(ioaddr + 5),			       inb(ioaddr + 6), inb(ioaddr + 7));			printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",			       dev->name, inb(ioaddr + TRANSMIT_START_REG),			       inb(ioaddr + COL_16_REG));			printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);			printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);			printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);		}		lp->stats.tx_errors++;		eth16i_reset(dev);		dev->trans_start = jiffies;		outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);	}	/* 	   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) {#if LINUX_VERSION_CODE < 0x020100		dev_tint(dev);#endif		if(eth16i_debug > 0) 			printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);		return 0;	}	/* Block a timer based transmitter from overlapping. 	   This could better be done with atomic_swap(1, dev->tbusy), 	   but set_bit() works as well. */	set_bit(0, (void *)&lp->tx_buf_busy);		/* Turn off TX interrupts */	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);	if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);		status = -1;	}	else {		ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;		unsigned char *buf = skb->data;		if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {			if(eth16i_debug > 0) 				printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);  		} 		else {			outw(length, ioaddr + DATAPORT);			if( ioaddr < 0x1000 ) 				outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);			else {				unsigned char frag = length % 4;				outsl(ioaddr + DATAPORT, buf, length >> 2);				if( frag != 0 ) {					outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);					if( frag == 3 ) 						outsw(ioaddr + DATAPORT, 						      (buf + (length & 0xFFFC) + 2), 1);				}			}			lp->tx_buffered_packets++;			lp->tx_queue++;			lp->tx_queue_len += length + 2;					}				lp->tx_buf_busy = 0;		if(lp->tx_started == 0) {			/* If the transmitter is idle..always trigger a transmit */			outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);			lp->tx_queue = 0;			lp->tx_queue_len = 0;			dev->trans_start = jiffies;			lp->tx_started = 1;			dev->tbusy = 0;		}		else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {			/* There is still more room for one more packet in tx buffer */			dev->tbusy = 0;		}				outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);				/* Turn TX interrupts back on */		/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */		status = 0;	} #if LINUX_VERSION_CODE >= 0x020100	dev_kfree_skb(skb);#else	dev_kfree_skb(skb, FREE_WRITE);#endif	return status;}static void eth16i_rx(struct device *dev){	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;	int ioaddr = dev->base_addr;	int boguscount = MAX_RX_LOOP;	/* Loop until all packets have been read */	while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {		/* Read status byte from receive buffer */ 		ushort status = inw(ioaddr + DATAPORT);		/* Get the size of the packet from receive buffer */		ushort pkt_len = inw(ioaddr + DATAPORT);		if(eth16i_debug > 4)			printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n", 			       dev->name, 			       inb(ioaddr + RECEIVE_MODE_REG), status);				if( !(status & PKT_GOOD) ) {			lp->stats.rx_errors++;			if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {				lp->stats.rx_length_errors++;				eth16i_reset(dev);				return;					}			else { 				eth16i_skip_packet(dev);				lp->stats.rx_dropped++;			}			}		else {   /* Ok so now we should have a good packet */			struct sk_buff *skb;			skb = dev_alloc_skb(pkt_len + 3);			if( skb == NULL ) {				printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n", 				       dev->name, pkt_len);				eth16i_skip_packet(dev);				lp->stats.rx_dropped++;				break;			}			skb->dev = dev;			skb_reserve(skb,2);						/* 			   Now let's get the packet out of buffer.			   size is (pkt_len + 1) >> 1, cause we are now reading words			   and it have to be even aligned.			   */ 						if(ioaddr < 0x1000) 				insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), 				     (pkt_len + 1) >> 1);			else {					unsigned char *buf = skb_put(skb, pkt_len);				unsigned char frag = pkt_len % 4;				insl(ioaddr + DATAPORT, buf, pkt_len >> 2);				if(frag != 0) {					unsigned short rest[2];					rest[0] = inw( ioaddr + DATAPORT );					if(frag == 3)						rest[1] = inw( ioaddr + DATAPORT );					memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);				}			}			skb->protocol=eth_type_trans(skb, dev);			netif_rx(skb);			lp->stats.rx_packets++;			if( eth16i_debug > 5 ) {				int i;				printk(KERN_DEBUG "%s: Received packet of length %d.\n", 				       dev->name, pkt_len);				for(i = 0; i < 14; i++) 					printk(KERN_DEBUG " %02x", skb->data[i]);				printk(KERN_DEBUG ".\n");			}		} /* else */		if(--boguscount <= 0)			break;	} /* while */#if 0	{		int i;		for(i = 0; i < 20; i++) {			if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 			    RX_BUFFER_EMPTY)				break;			inw(ioaddr + DATAPORT);			outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);		}		if(eth16i_debug > 1)			printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);	}#endif	return;}static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct device *dev = dev_id;	struct eth16i_local *lp;	int ioaddr = 0,		status;	if(dev == NULL) {		printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);		return;	}	/* Turn off all interrupts from adapter */	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);	set_bit(0, (void *)&dev->tbusy);  	/* Set the device busy so that */	/* eth16i_tx wont be called */	if(dev->interrupt)		printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);	dev->interrupt = 1;	ioaddr = dev->base_addr;	lp = (struct eth16i_local *)dev->priv;	status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */	outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */	if(eth16i_debug > 3)		printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);	if( status & 0x7f00 ) {		lp->stats.rx_errors++;		if(status & (BUS_RD_ERR << 8) ) 			printk(KERN_WARNING "%s: Bus read error.\n",dev->name);		if(status & (SHORT_PKT_ERR << 8) )   lp->stats.rx_length_errors++;		if(status & (ALIGN_ERR << 8) )       lp->stats.rx_frame_errors++;		if(status & (CRC_ERR << 8) )	    lp->stats.rx_crc_errors++;		if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;	}	if( status & 0x001a) {		lp->stats.tx_errors++;		if(status & CR_LOST) lp->stats.tx_carrier_errors++;		if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;#if 0	       		if(status & COLLISION) {			lp->stats.collisions += 				((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);		}#endif		if(status & COLLISIONS_16) {			if(lp->col_16 < MAX_COL_16) { 				lp->col_16++;				lp->stats.collisions++;				/* Resume transmitting, skip failed packet */				outb(0x02, ioaddr + COL_16_REG);			}			else {				printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);			}		}	}	if( status & 0x00ff ) {          /* Let's check the transmit status reg */		if(status & TX_DONE) {         /* The transmit has been done */			lp->stats.tx_packets = lp->tx_buffered_packets;			lp->col_16 = 0;		   			if(lp->tx_queue) {           /* Is there still packets ? */				/* There was packet(s) so start transmitting and write also				   how many packets there is to be sended */				outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);				lp->tx_queue = 0;				lp->tx_queue_len = 0;				lp->tx_started = 1;				dev->trans_start = jiffies;				mark_bh(NET_BH); 			}			else {				lp->tx_started = 0;				mark_bh(NET_BH);			}		}	}	if( ( status & 0x8000 ) || 	    ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {		eth16i_rx(dev);  /* We have packet in receive buffer */	}  		dev->interrupt = 0;		/* Turn interrupts back on */	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);		if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {		/* There is still more room for one more packet in tx buffer */		dev->tbusy = 0;	}		return;}static void eth16i_skip_packet(struct device *dev){	 	int ioaddr = dev->base_addr;	inw(ioaddr + DATAPORT);	inw(ioaddr + DATAPORT);	inw(ioaddr + DATAPORT);	outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);	while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);}static void eth16i_reset(struct device *dev){	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;	int ioaddr = dev->base_addr;	if(eth16i_debug > 1) 		printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);	outw(0xffff, ioaddr + TX_STATUS_REG);    	eth16i_select_regbank(2, ioaddr);	lp->tx_started = 0;	lp->tx_buf_busy = 0;	lp->tx_queue = 0;	lp->tx_queue_len = 0;    	dev->interrupt = 0;	dev->start = 1;	dev->tbusy = 0;	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);}static void eth16i_multicast(struct device *dev){	int ioaddr = dev->base_addr;  	if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) 	{		dev->flags|=IFF_PROMISC;	/* Must do this */		outb(3, ioaddr + RECEIVE_MODE_REG);    	} else {		outb(2, ioaddr + RECEIVE_MODE_REG);	}}static struct enet_statistics *eth16i_get_stats(struct device *dev){	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;	return &lp->stats;}static void eth16i_select_regbank(unsigned char banknbr, int ioaddr){	unsigned char data;	data = inb(ioaddr + CONFIG_REG_1);	outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); }#ifdef MODULEstatic ushort eth16i_parse_mediatype(const char* s){	if(!s)		return E_PORT_FROM_EPROM;	        if (!strncmp(s, "bnc", 3))		return E_PORT_BNC;        else if (!strncmp(s, "tp", 2))                return E_PORT_TP;        else if (!strncmp(s, "dix", 3))                return E_PORT_DIX;        else if (!strncmp(s, "auto", 4))		return E_PORT_AUTO;	else		return E_PORT_FROM_EPROM;}#define MAX_ETH16I_CARDS 4  /* Max number of Eth16i cards per module */#define NAMELEN          8  /* number of chars for storing dev->name */static char namelist[NAMELEN * MAX_ETH16I_CARDS] = { 0, };static struct device dev_eth16i[MAX_ETH16I_CARDS] = {	{		NULL,		0, 0, 0, 0,		0, 0,		0, 0, 0, NULL, NULL	},};static int ioaddr[MAX_ETH16I_CARDS] = { 0, };#if 0static int irq[MAX_ETH16I_CARDS] = { 0, };#endifstatic char* mediatype[MAX_ETH16I_CARDS] = { 0, };static int debug = -1;#if (LINUX_VERSION_CODE >= 0x20115) MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");MODULE_PARM_DESC(ioaddr, "eth16i io base address");#if 0MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");MODULE_PARM_DESC(irq, "eth16i interrupt request number");#endifMODULE_PARM(mediatype, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "s");MODULE_PARM_DESC(mediatype, "eth16i interfaceport mediatype");MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "eth16i debug level (0-4)");#endifint init_module(void){	int this_dev, found = 0;	for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++)	{		struct device *dev = &dev_eth16i[this_dev];			dev->name = namelist + (NAMELEN*this_dev);		dev->irq = 0; /* irq[this_dev]; */		dev->base_addr = ioaddr[this_dev];		dev->init = eth16i_probe;	        if(debug != -1)			eth16i_debug = debug;		if(eth16i_debug > 1)			printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );		dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);		if(ioaddr[this_dev] == 0)		{			if(this_dev != 0) break; /* Only autoprobe 1st one */			printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");		}		if(register_netdev(dev) != 0)		{			printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",			       ioaddr[this_dev]);	    			if(found != 0) return 0;			return -ENXIO;		}		found++;	}	return 0;}	void cleanup_module(void){	int this_dev;	for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++)	{		struct device* dev = &dev_eth16i[this_dev];				if(dev->priv != NULL)		{			unregister_netdev(dev);			kfree(dev->priv);			dev->priv = NULL;						free_irq(dev->irq, dev);			release_region(dev->base_addr, ETH16I_IO_EXTENT);					}	}}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c" *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c" *  tab-width: 8 *  c-basic-offset: 8 *  c-indent-level: 8 * End: *//* End of file eth16i.c */

⌨️ 快捷键说明

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