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

📄 am79c961a.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		idx = crc >> 30;		bit = (crc >> 26) & 15;		hash[idx] |= 1 << bit;	}}/* * Set or clear promiscuous/multicast mode filter for this adaptor. */static void am79c961_setmulticastlist (struct net_device *dev){	struct dev_priv *priv = (struct dev_priv *)dev->priv;	unsigned long flags;	unsigned short multi_hash[4], mode;	int i, stopped;	mode = MODE_PORT_10BT;	if (dev->flags & IFF_PROMISC) {		mode |= MODE_PROMISC;	} else if (dev->flags & IFF_ALLMULTI) {		memset(multi_hash, 0xff, sizeof(multi_hash));	} else {		struct dev_mc_list *dmi;		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 = (struct dev_priv *)dev->priv;	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;	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, length);	am_writeword (dev, hdraddr + 4, -length);	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) {		printk(KERN_DEBUG"tx ring full, stopping queue\n");		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 {		u_int hdraddr;		u_int status;int bufnum;bufnum = priv->txtail;		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 ++;	} while (priv->txtail != priv->txhead);	netif_wake_queue(dev);}static voidam79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *)dev_id;	struct dev_priv *priv = (struct dev_priv *)dev->priv;	u_int status;	status = read_rreg(dev->base_addr, CSR0);	write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));	if (status & CSR0_RINT)		am79c961_rx(dev, priv);	if (status & CSR0_TINT)		am79c961_tx(dev, priv);	if (status & CSR0_MISS)		priv->stats.rx_dropped ++;}/* * 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 = (struct dev_priv *)dev->priv;	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 = 0;	if (net_debug && version_printed++ == 0)		printk(KERN_INFO "%s", version);}static int __init am79c961_init(void){	struct net_device *dev;	struct dev_priv *priv;	int i, ret;	dev = init_etherdev(NULL, sizeof(struct dev_priv));	ret = -ENOMEM;	if (!dev)		goto out;	SET_MODULE_OWNER(dev);	priv = dev->priv;	/*	 * Fixed address and IRQ lines here.	 * The PNP initialisation should have been	 * done by the ether bootp loader.	 */	dev->base_addr = 0x220;	dev->irq = IRQ_EBSA110_ETHERNET;	/*	 * Reset the device.	 */	inb((dev->base_addr + NET_RESET) >> 1);	udelay(5);	/*	 * Check the manufacturer part of the	 * ether address.	 */    	ret = -ENODEV;	if (inb(dev->base_addr >> 1) != 0x08 ||	    inb((dev->base_addr >> 1) + 1) != 00 ||	    inb((dev->base_addr >> 1) + 2) != 0x2b)	    	goto nodev;	if (!request_region(dev->base_addr, 0x18, dev->name))		goto nodev;	am79c961_banner();	printk(KERN_INFO "%s: am79c961 found at %08lx, IRQ%d, ether address ",		dev->name, dev->base_addr, dev->irq);	/* Retrive and print the ethernet address. */	for (i = 0; i < 6; i++) {		dev->dev_addr[i] = inb((dev->base_addr >> 1) + i) & 0xff;		printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);	}	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;	return 0;release:	release_region(dev->base_addr, 0x18);nodev:	unregister_netdev(dev);	kfree(dev);out:	return ret;}module_init(am79c961_init);

⌨️ 快捷键说明

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