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

📄 am79c961a.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		memset(multi_hash, 0x00, sizeof(multi_hash));		for (dmi = dev->mc_list; dmi; dmi = dmi->next)			am79c961_mc_hash(dmi, multi_hash);	}	spin_lock_irqsave(priv->chip_lock, flags);	stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;	if (!stopped) {		/*		 * Put the chip into suspend mode		 */		write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);		/*		 * Spin waiting for chip to report suspend mode		 */		while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {			spin_unlock_irqrestore(priv->chip_lock, flags);			nop();			spin_lock_irqsave(priv->chip_lock, flags);		}	}	/*	 * Update the multicast hash table	 */	for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)		write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);	/*	 * Write the mode register	 */	write_rreg(dev->base_addr, MODE, mode);	if (!stopped) {		/*		 * Put the chip back into running mode		 */		write_rreg(dev->base_addr, CTRL1, 0);	}	spin_unlock_irqrestore(priv->chip_lock, flags);}static void am79c961_timeout(struct net_device *dev){	printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",		dev->name);	/*	 * ought to do some setup of the tx side here	 */	netif_wake_queue(dev);}/* * Transmit a packet */static intam79c961_sendpacket(struct sk_buff *skb, struct net_device *dev){	struct dev_priv *priv = netdev_priv(dev);	unsigned int hdraddr, bufaddr;	unsigned int head;	unsigned long flags;	head = priv->txhead;	hdraddr = priv->txhdr + (head << 3);	bufaddr = priv->txbuffer[head];	head += 1;	if (head >= TX_BUFFERS)		head = 0;	am_writebuffer (dev, bufaddr, skb->data, skb->len);	am_writeword (dev, hdraddr + 4, -skb->len);	am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);	priv->txhead = head;	spin_lock_irqsave(priv->chip_lock, flags);	write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);	dev->trans_start = jiffies;	spin_unlock_irqrestore(priv->chip_lock, flags);	/*	 * If the next packet is owned by the ethernet device,	 * then the tx ring is full and we can't add another	 * packet.	 */	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)		netif_stop_queue(dev);	dev_kfree_skb(skb);	return 0;}/* * If we have a good packet(s), get it/them out of the buffers. */static voidam79c961_rx(struct net_device *dev, struct dev_priv *priv){	do {		struct sk_buff *skb;		u_int hdraddr;		u_int pktaddr;		u_int status;		int len;		hdraddr = priv->rxhdr + (priv->rxtail << 3);		pktaddr = priv->rxbuffer[priv->rxtail];		status = am_readword (dev, hdraddr + 2);		if (status & RMD_OWN) /* do we own it? */			break;		priv->rxtail ++;		if (priv->rxtail >= RX_BUFFERS)			priv->rxtail = 0;		if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {			am_writeword (dev, hdraddr + 2, RMD_OWN);			priv->stats.rx_errors ++;			if (status & RMD_ERR) {				if (status & RMD_FRAM)					priv->stats.rx_frame_errors ++;				if (status & RMD_CRC)					priv->stats.rx_crc_errors ++;			} else if (status & RMD_STP)				priv->stats.rx_length_errors ++;			continue;		}		len = am_readword(dev, hdraddr + 6);		skb = dev_alloc_skb(len + 2);		if (skb) {			skb->dev = dev;			skb_reserve(skb, 2);			am_readbuffer(dev, pktaddr, skb_put(skb, len), len);			am_writeword(dev, hdraddr + 2, RMD_OWN);			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			dev->last_rx = jiffies;			priv->stats.rx_bytes += len;			priv->stats.rx_packets ++;		} else {			am_writeword (dev, hdraddr + 2, RMD_OWN);			printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);			priv->stats.rx_dropped ++;			break;		}	} while (1);}/* * Update stats for the transmitted packet */static voidam79c961_tx(struct net_device *dev, struct dev_priv *priv){	do {		short len;		u_int hdraddr;		u_int status;		hdraddr = priv->txhdr + (priv->txtail << 3);		status = am_readword (dev, hdraddr + 2);		if (status & TMD_OWN)			break;		priv->txtail ++;		if (priv->txtail >= TX_BUFFERS)			priv->txtail = 0;		if (status & TMD_ERR) {			u_int status2;			priv->stats.tx_errors ++;			status2 = am_readword (dev, hdraddr + 6);			/*			 * Clear the error byte			 */			am_writeword (dev, hdraddr + 6, 0);			if (status2 & TST_RTRY)				priv->stats.collisions += 16;			if (status2 & TST_LCOL)				priv->stats.tx_window_errors ++;			if (status2 & TST_LCAR)				priv->stats.tx_carrier_errors ++;			if (status2 & TST_UFLO)				priv->stats.tx_fifo_errors ++;			continue;		}		priv->stats.tx_packets ++;		len = am_readword (dev, hdraddr + 4);		priv->stats.tx_bytes += -len;	} while (priv->txtail != priv->txhead);	netif_wake_queue(dev);}static irqreturn_tam79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *)dev_id;	struct dev_priv *priv = netdev_priv(dev);	u_int status, n = 100;	int handled = 0;	do {		status = read_rreg(dev->base_addr, CSR0);		write_rreg(dev->base_addr, CSR0, status &			   (CSR0_IENA|CSR0_TINT|CSR0_RINT|			    CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL));		if (status & CSR0_RINT) {			handled = 1;			am79c961_rx(dev, priv);		}		if (status & CSR0_TINT) {			handled = 1;			am79c961_tx(dev, priv);		}		if (status & CSR0_MISS) {			handled = 1;			priv->stats.rx_dropped ++;		}		if (status & CSR0_CERR) {			handled = 1;			mod_timer(&priv->timer, jiffies);		}	} while (--n && status & (CSR0_RINT | CSR0_TINT));	return IRQ_RETVAL(handled);}#ifdef CONFIG_NET_POLL_CONTROLLERstatic void am79c961_poll_controller(struct net_device *dev){	unsigned long flags;	local_irq_save(flags);	am79c961_interrupt(dev->irq, dev, NULL);	local_irq_restore(flags);}#endif/* * Initialise the chip.  Note that we always expect * to be entered with interrupts enabled. */static intam79c961_hw_init(struct net_device *dev){	struct dev_priv *priv = netdev_priv(dev);	spin_lock_irq(&priv->chip_lock);	write_rreg (dev->base_addr, CSR0, CSR0_STOP);	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);	spin_unlock_irq(&priv->chip_lock);	am79c961_ramtest(dev, 0x66);	am79c961_ramtest(dev, 0x99);	return 0;}static void __init am79c961_banner(void){	static unsigned version_printed;	if (net_debug && version_printed++ == 0)		printk(KERN_INFO "%s", version);}static int __init am79c961_probe(struct device *_dev){	struct platform_device *pdev = to_platform_device(_dev);	struct resource *res;	struct net_device *dev;	struct dev_priv *priv;	int i, ret;	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	if (!res)		return -ENODEV;	dev = alloc_etherdev(sizeof(struct dev_priv));	ret = -ENOMEM;	if (!dev)		goto out;	SET_NETDEV_DEV(dev, &pdev->dev);	priv = netdev_priv(dev);	/*	 * Fixed address and IRQ lines here.	 * The PNP initialisation should have been	 * done by the ether bootp loader.	 */	dev->base_addr = res->start;	dev->irq = platform_get_irq(pdev, 0);    	ret = -ENODEV;	if (!request_region(dev->base_addr, 0x18, dev->name))		goto nodev;	/*	 * Reset the device.	 */	inb(dev->base_addr + NET_RESET);	udelay(5);	/*	 * Check the manufacturer part of the	 * ether address.	 */	if (inb(dev->base_addr) != 0x08 ||	    inb(dev->base_addr + 2) != 0x00 ||	    inb(dev->base_addr + 4) != 0x2b)	    	goto release;	for (i = 0; i < 6; i++)		dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;	am79c961_banner();	spin_lock_init(&priv->chip_lock);	init_timer(&priv->timer);	priv->timer.data = (unsigned long)dev;	priv->timer.function = am79c961_timer;	if (am79c961_hw_init(dev))		goto release;	dev->open		= am79c961_open;	dev->stop		= am79c961_close;	dev->hard_start_xmit	= am79c961_sendpacket;	dev->get_stats		= am79c961_getstats;	dev->set_multicast_list	= am79c961_setmulticastlist;	dev->tx_timeout		= am79c961_timeout;#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller	= am79c961_poll_controller;#endif	ret = register_netdev(dev);	if (ret == 0) {		printk(KERN_INFO "%s: ether address ", dev->name);		/* Retrive and print the ethernet address. */		for (i = 0; i < 6; i++)			printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);		return 0;	}release:	release_region(dev->base_addr, 0x18);nodev:	free_netdev(dev);out:	return ret;}static struct device_driver am79c961_driver = {	.name		= "am79c961",	.bus		= &platform_bus_type,	.probe		= am79c961_probe,};static int __init am79c961_init(void){	return driver_register(&am79c961_driver);}__initcall(am79c961_init);

⌨️ 快捷键说明

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