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

📄 ether1.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));		failures += 1;	}	timeout += HZ/10;	while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))			& STAT_COMPLETE) == 0) {		if (time_after(jiffies, timeout))			break;	}	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {		printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,			ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));		failures += 1;	}	timeout += HZ;	while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))			& STAT_COMPLETE) == 0) {		if (time_after(jiffies, timeout))			break;	}	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {		printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,			ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),			ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));	} else {		status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);		if (status & TDR_XCVRPROB)			printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);		else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {#ifdef FANCY			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,				(status & TDR_TIME) % 10);#else			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));#endif		}	}	if (failures)		ether1_reset (dev);	return failures ? 1 : 0;}/* ------------------------------------------------------------------------- */static intether1_txalloc (struct net_device *dev, int size){	int start, tail;	size = (size + 1) & ~1;	tail = priv(dev)->tx_tail;	if (priv(dev)->tx_head + size > TX_AREA_END) {		if (tail > priv(dev)->tx_head)			return -1;		start = TX_AREA_START;		if (start + size > tail)			return -1;		priv(dev)->tx_head = start + size;	} else {		if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail)			return -1;		start = priv(dev)->tx_head;		priv(dev)->tx_head += size;	}	return start;}static intether1_open (struct net_device *dev){	if (!is_valid_ether_addr(dev->dev_addr)) {		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",			dev->name);		return -EINVAL;	}	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))		return -EAGAIN;	memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));	if (ether1_init_for_open (dev)) {		free_irq (dev->irq, dev);		return -EAGAIN;	}	netif_start_queue(dev);	return 0;}static voidether1_timeout(struct net_device *dev){	printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",		dev->name);	printk(KERN_WARNING "%s: resetting device\n", dev->name);	ether1_reset (dev);	if (ether1_init_for_open (dev))		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);	priv(dev)->stats.tx_errors++;	netif_wake_queue(dev);}static intether1_sendpacket (struct sk_buff *skb, struct net_device *dev){	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;	unsigned long flags;	tx_t tx;	tbd_t tbd;	nop_t nop;	if (priv(dev)->restart) {		printk(KERN_WARNING "%s: resetting device\n", dev->name);		ether1_reset(dev);		if (ether1_init_for_open(dev))			printk(KERN_ERR "%s: unable to restart interface\n", dev->name);		else			priv(dev)->restart = 0;	}	if (skb->len < ETH_ZLEN) {		skb = skb_padto(skb, ETH_ZLEN);		if (skb == NULL)			goto out;	}	/*	 * insert packet followed by a nop	 */	txaddr = ether1_txalloc (dev, TX_SIZE);	tbdaddr = ether1_txalloc (dev, TBD_SIZE);	dataddr = ether1_txalloc (dev, skb->len);	nopaddr = ether1_txalloc (dev, NOP_SIZE);	tx.tx_status = 0;	tx.tx_command = CMD_TX | CMD_INTR;	tx.tx_link = nopaddr;	tx.tx_tbdoffset = tbdaddr;	tbd.tbd_opts = TBD_EOL | skb->len;	tbd.tbd_link = I82586_NULL;	tbd.tbd_bufl = dataddr;	tbd.tbd_bufh = 0;	nop.nop_status = 0;	nop.nop_command = CMD_NOP;	nop.nop_link = nopaddr;	local_irq_save(flags);	ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);	ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);	ether1_writebuffer (dev, skb->data, dataddr, skb->len);	ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);	tmp = priv(dev)->tx_link;	priv(dev)->tx_link = nopaddr;	/* now reset the previous nop pointer */	ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);	local_irq_restore(flags);	/* handle transmit */	dev->trans_start = jiffies;	/* check to see if we have room for a full sized ether frame */	tmp = priv(dev)->tx_head;	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);	priv(dev)->tx_head = tmp;	dev_kfree_skb (skb);	if (tst == -1)		netif_stop_queue(dev); out:	return 0;}static voidether1_xmit_done (struct net_device *dev){	nop_t nop;	int caddr, tst;	caddr = priv(dev)->tx_tail;again:	ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);	switch (nop.nop_command & CMD_MASK) {	case CMD_TDR:		/* special case */		if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)				!= (unsigned short)I82586_NULL) {			ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,				    scb_command, NORMALIRQS);			writeb(CTRL_CA, REG_CONTROL);		}		priv(dev)->tx_tail = NOP_ADDR;		return;	case CMD_NOP:		if (nop.nop_link == caddr) {			if (priv(dev)->initialising == 0)				printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);			else			        priv(dev)->initialising = 0;			return;		}		if (caddr == nop.nop_link)			return;		caddr = nop.nop_link;		goto again;	case CMD_TX:		if (nop.nop_status & STAT_COMPLETE)			break;		printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);		priv(dev)->restart = 1;		return;	default:		printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,			nop.nop_command & CMD_MASK, caddr);		priv(dev)->restart = 1;		return;	}	while (nop.nop_status & STAT_COMPLETE) {		if (nop.nop_status & STAT_OK) {			priv(dev)->stats.tx_packets ++;			priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS);		} else {			priv(dev)->stats.tx_errors ++;			if (nop.nop_status & STAT_COLLAFTERTX)				priv(dev)->stats.collisions ++;			if (nop.nop_status & STAT_NOCARRIER)				priv(dev)->stats.tx_carrier_errors ++;			if (nop.nop_status & STAT_TXLOSTCTS)				printk (KERN_WARNING "%s: cts lost\n", dev->name);			if (nop.nop_status & STAT_TXSLOWDMA)				priv(dev)->stats.tx_fifo_errors ++;			if (nop.nop_status & STAT_COLLEXCESSIVE)				priv(dev)->stats.collisions += 16;		}		if (nop.nop_link == caddr) {			printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);			break;		}		caddr = nop.nop_link;		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);		if ((nop.nop_command & CMD_MASK) != CMD_NOP) {			printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);			break;		}		if (caddr == nop.nop_link)			break;		caddr = nop.nop_link;		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);		if ((nop.nop_command & CMD_MASK) != CMD_TX) {			printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);			break;		}	}	priv(dev)->tx_tail = caddr;	caddr = priv(dev)->tx_head;	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);	priv(dev)->tx_head = caddr;	if (tst != -1)		netif_wake_queue(dev);}static voidether1_recv_done (struct net_device *dev){	int status;	int nexttail, rbdaddr;	rbd_t rbd;	do {		status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS);		if ((status & RFD_COMPLETE) == 0)			break;		rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);		ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);		if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {			int length = rbd.rbd_status & RBD_ACNT;			struct sk_buff *skb;			length = (length + 1) & ~1;			skb = dev_alloc_skb (length + 2);			if (skb) {				skb->dev = dev;				skb_reserve (skb, 2);				ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);				skb->protocol = eth_type_trans (skb, dev);				netif_rx (skb);				priv(dev)->stats.rx_packets ++;			} else				priv(dev)->stats.rx_dropped ++;		} else {			printk(KERN_WARNING "%s: %s\n", dev->name,				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");			priv(dev)->stats.rx_dropped ++;		}		nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);		/* nexttail should be rx_head */		if (nexttail != priv(dev)->rx_head)			printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",				dev->name, nexttail, priv(dev)->rx_head);		ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);		ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS);		ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS);		ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);			priv(dev)->rx_tail = nexttail;		priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS);	} while (1);}static irqreturn_tether1_interrupt (int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *)dev_id;	int status;	status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);	if (status) {		ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),			    SCB_ADDR, scb_t, scb_command, NORMALIRQS);		writeb(CTRL_CA | CTRL_ACK, REG_CONTROL);		if (status & SCB_STCX) {			ether1_xmit_done (dev);		}		if (status & SCB_STCNA) {			if (priv(dev)->resetting == 0)				printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);			else				priv(dev)->resetting += 1;			if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)					!= (unsigned short)I82586_NULL) {				ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);				writeb(CTRL_CA, REG_CONTROL);			}			if (priv(dev)->resetting == 2)				priv(dev)->resetting = 0;		}		if (status & SCB_STFR) {			ether1_recv_done (dev);		}		if (status & SCB_STRNR) {			if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);				ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);				writeb(CTRL_CA, REG_CONTROL);				priv(dev)->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */			} else				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,					ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));			printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset,						NORMALIRQS));		}	} else		writeb(CTRL_ACK, REG_CONTROL);	return IRQ_HANDLED;}static intether1_close (struct net_device *dev){	ether1_reset (dev);	free_irq(dev->irq, dev);	return 0;}static struct net_device_stats *ether1_getstats (struct net_device *dev){	return &priv(dev)->stats;}/* * Set or clear the multicast filter for this adaptor. * num_addrs == -1	Promiscuous mode, receive all packets. * num_addrs == 0	Normal mode, clear multicast list. * num_addrs > 0	Multicast mode, receive normal and MC packets, and do *			best-effort filtering. */static voidether1_setmulticastlist (struct net_device *dev){}/* ------------------------------------------------------------------------- */static void __init ether1_banner(void){	static unsigned int version_printed = 0;	if (net_debug && version_printed++ == 0)		printk(KERN_INFO "%s", version);}static int __devinitether1_probe(struct expansion_card *ec, const struct ecard_id *id){	struct net_device *dev;	int i, ret = 0;	ether1_banner();	ret = ecard_request_resources(ec);	if (ret)		goto out;	dev = alloc_etherdev(sizeof(struct ether1_priv));	if (!dev) {		ret = -ENOMEM;		goto release;	}	SET_MODULE_OWNER(dev);	SET_NETDEV_DEV(dev, &ec->dev);	dev->irq = ec->irq;	priv(dev)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),				  ecard_resource_len(ec, ECARD_RES_IOCFAST));	if (!priv(dev)->base) {		ret = -ENOMEM;		goto free;	}	if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) {		ret = -ENODEV;		goto free;	}	for (i = 0; i < 6; i++)		dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));	if (ether1_init_2(dev)) {		ret = -ENODEV;		goto free;	}	dev->open		= ether1_open;	dev->stop		= ether1_close;	dev->hard_start_xmit    = ether1_sendpacket;	dev->get_stats		= ether1_getstats;	dev->set_multicast_list = ether1_setmulticastlist;	dev->tx_timeout		= ether1_timeout;	dev->watchdog_timeo	= 5 * HZ / 100;	ret = register_netdev(dev);	if (ret)		goto free;	printk(KERN_INFO "%s: ether1 in slot %d, ",		dev->name, ec->slot_no);    	for (i = 0; i < 6; i++)		printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');	ecard_set_drvdata(ec, dev);	return 0; free:	if (priv(dev)->base)		iounmap(priv(dev)->base);	free_netdev(dev); release:	ecard_release_resources(ec); out:	return ret;}static void __devexit ether1_remove(struct expansion_card *ec){	struct net_device *dev = ecard_get_drvdata(ec);	ecard_set_drvdata(ec, NULL);		unregister_netdev(dev);	iounmap(priv(dev)->base);	free_netdev(dev);	ecard_release_resources(ec);}static const struct ecard_id ether1_ids[] = {	{ MANU_ACORN, PROD_ACORN_ETHER1 },	{ 0xffff, 0xffff }};static struct ecard_driver ether1_driver = {	.probe		= ether1_probe,	.remove		= __devexit_p(ether1_remove),	.id_table	= ether1_ids,	.drv = {		.name	= "ether1",	},};static int __init ether1_init(void){	return ecard_register_driver(&ether1_driver);}static void __exit ether1_exit(void){	ecard_remove_driver(&ether1_driver);}module_init(ether1_init);module_exit(ether1_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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