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

📄 3c509.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
	return word;}static intel3_open(struct net_device *dev){	int ioaddr = dev->base_addr;	int i;	outw(TxReset, ioaddr + EL3_CMD);	outw(RxReset, ioaddr + EL3_CMD);	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);	i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev);	if (i) return i;	EL3WINDOW(0);	if (el3_debug > 3)		printk("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));	/* Activate board: this is probably unnecessary. */	outw(0x0001, ioaddr + 4);	/* Set the IRQ line. */	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);	/* Set the station address in window 2 each time opened. */	EL3WINDOW(2);	for (i = 0; i < 6; i++)		outb(dev->dev_addr[i], ioaddr + i);	if (dev->if_port == 3)		/* Start the thinnet transceiver. We should really wait 50ms...*/		outw(StartCoax, ioaddr + EL3_CMD);	else if (dev->if_port == 0) {		/* 10baseT interface, enabled link beat and jabber check. */		EL3WINDOW(4);		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);	}	/* Switch to the stats window, and clear all stats by reading. */	outw(StatsDisable, ioaddr + EL3_CMD);	EL3WINDOW(6);	for (i = 0; i < 9; i++)		inb(ioaddr + i);	inw(ioaddr + 10);	inw(ioaddr + 12);	/* Switch to register set 1 for normal use. */	EL3WINDOW(1);	/* Accept b-case and phys addr only. */	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */	netif_start_queue(dev);	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */	/* Allow status bits to be seen. */	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);	/* Ack all pending events, and set active indicator mask. */	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,		 ioaddr + EL3_CMD);	outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,		 ioaddr + EL3_CMD);	if (el3_debug > 3)		printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));	return 0;}static voidel3_tx_timeout (struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	/* Transmitter timeout, serious problems. */	printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "		   "Tx FIFO room %d.\n",		   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),		   inw(ioaddr + TX_FREE));	lp->stats.tx_errors++;	dev->trans_start = jiffies;	/* Issue TX_RESET and TX_START commands. */	outw(TxReset, ioaddr + EL3_CMD);	outw(TxEnable, ioaddr + EL3_CMD);	netif_wake_queue(dev);}static intel3_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;	netif_stop_queue (dev);	lp->stats.tx_bytes += skb->len;		if (el3_debug > 4) {		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));	}#if 0#ifndef final_version	{	/* Error-checking code, delete someday. */		ushort status = inw(ioaddr + EL3_STATUS);		if (status & 0x0001 		/* IRQ line active, missed one. */			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */			printk("%s: Missed interrupt, status then %04x now %04x"				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),				   inw(ioaddr + RX_STATUS));			/* Fake interrupt trigger by masking, acknowledge interrupts. */			outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);			outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,				 ioaddr + EL3_CMD);			outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);		}	}#endif#endif	/*	 *	We lock the driver against other processors. Note	 *	we don't need to lock versus the IRQ as we suspended	 *	that. This means that we lose the ability to take	 *	an RX during a TX upload. That sucks a bit with SMP	 *	on an original 3c509 (2K buffer)	 *	 *	Using disable_irq stops us crapping on other	 *	time sensitive devices.	 */    	spin_lock_irqsave(&lp->lock, flags);	    	/* Put out the doubleword header... */	outw(skb->len, ioaddr + TX_FIFO);	outw(0x00, ioaddr + TX_FIFO);	/* ... and the packet rounded to a doubleword. */#ifdef  __powerpc__	outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);#else	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);#endif	dev->trans_start = jiffies;	if (inw(ioaddr + TX_FREE) > 1536)		netif_start_queue(dev);	else		/* Interrupt us when the FIFO has room for max-sized packet. */		outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);	spin_unlock_irqrestore(&lp->lock, flags);	dev_kfree_skb (skb);	/* Clear the Tx status stack. */	{		short tx_status;		int i = 4;		while (--i > 0	&&	(tx_status = inb(ioaddr + TX_STATUS)) > 0) {			if (tx_status & 0x38) lp->stats.tx_aborted_errors++;			if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);			if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);			outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */		}	}	return 0;}/* The EL3 interrupt handler. */static voidel3_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *)dev_id;	struct el3_private *lp;	int ioaddr, status;	int i = max_interrupt_work;	if (dev == NULL) {		printk ("el3_interrupt(): irq %d for unknown device.\n", irq);		return;	}	lp = (struct el3_private *)dev->priv;	spin_lock(&lp->lock);	ioaddr = dev->base_addr;	if (el3_debug > 4) {		status = inw(ioaddr + EL3_STATUS);		printk("%s: interrupt, status %4.4x.\n", dev->name, status);	}	while ((status = inw(ioaddr + EL3_STATUS)) &		   (IntLatch | RxComplete | StatsFull)) {		if (status & RxComplete)			el3_rx(dev);		if (status & TxAvailable) {			if (el3_debug > 5)				printk("	TX room bit was handled.\n");			/* There's room in the FIFO for a full-sized packet. */			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);			netif_wake_queue (dev);		}		if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) {			/* Handle all uncommon interrupts. */			if (status & StatsFull)				/* Empty statistics. */				update_stats(dev);			if (status & RxEarly) {				/* Rx early is unused. */				el3_rx(dev);				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);			}			if (status & TxComplete) {			/* Really Tx error. */				struct el3_private *lp = (struct el3_private *)dev->priv;				short tx_status;				int i = 4;				while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {					if (tx_status & 0x38) lp->stats.tx_aborted_errors++;					if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);					if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);					outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */				}			}			if (status & AdapterFailure) {				/* Adapter failure requires Rx reset and reinit. */				outw(RxReset, ioaddr + EL3_CMD);				/* Set the Rx filter to the current state. */				outw(SetRxFilter | RxStation | RxBroadcast					 | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)					 | (dev->flags & IFF_PROMISC ? RxProm : 0),					 ioaddr + EL3_CMD);				outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);			}		}		if (--i < 0) {			printk("%s: Infinite loop in interrupt, status %4.4x.\n",				   dev->name, status);			/* Clear all interrupts. */			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);			break;		}		/* Acknowledge the IRQ. */		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */	}	if (el3_debug > 4) {		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,			   inw(ioaddr + EL3_STATUS));	}	spin_unlock(&lp->lock);	return;}static struct net_device_stats *el3_get_stats(struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	unsigned long flags;	/*	 *	This is fast enough not to bother with disable IRQ	 *	stuff.	 */	 	spin_lock_irqsave(&lp->lock, flags);	update_stats(dev);	spin_unlock_irqrestore(&lp->lock, flags);	return &lp->stats;}/*  Update statistics.  We change to register window 6, so this should be run	single-threaded if the device is active. This is expected to be a rare	operation, and it's simpler for the rest of the driver to assume that	window 1 is always valid rather than use a special window-state variable.	*/static void update_stats(struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	if (el3_debug > 5)		printk("   Updating the statistics.\n");	/* Turn off statistics updates while reading. */	outw(StatsDisable, ioaddr + EL3_CMD);	/* Switch to the stats window, and read everything. */	EL3WINDOW(6);	lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);	lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);	/* Multiple collisions. */	   inb(ioaddr + 2);	lp->stats.collisions		+= inb(ioaddr + 3);	lp->stats.tx_window_errors	+= inb(ioaddr + 4);	lp->stats.rx_fifo_errors	+= inb(ioaddr + 5);	lp->stats.tx_packets		+= inb(ioaddr + 6);	/* Rx packets	*/		   inb(ioaddr + 7);	/* Tx deferrals */		   inb(ioaddr + 8);	inw(ioaddr + 10);	/* Total Rx and Tx octets. */	inw(ioaddr + 12);	/* Back to window 1, and turn statistics back on. */	EL3WINDOW(1);	outw(StatsEnable, ioaddr + EL3_CMD);	return;}static intel3_rx(struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	short rx_status;	if (el3_debug > 5)		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {		if (rx_status & 0x4000) { /* Error, update stats. */			short error = rx_status & 0x3800;			outw(RxDiscard, ioaddr + EL3_CMD);			lp->stats.rx_errors++;			switch (error) {			case 0x0000:		lp->stats.rx_over_errors++; break;			case 0x0800:		lp->stats.rx_length_errors++; break;			case 0x1000:		lp->stats.rx_frame_errors++; break;			case 0x1800:		lp->stats.rx_length_errors++; break;			case 0x2000:		lp->stats.rx_frame_errors++; break;			case 0x2800:		lp->stats.rx_crc_errors++; break;			}		} else {			short pkt_len = rx_status & 0x7ff;			struct sk_buff *skb;			skb = dev_alloc_skb(pkt_len+5);			lp->stats.rx_bytes += pkt_len;			if (el3_debug > 4)				printk("Receiving packet size %d status %4.4x.\n",					   pkt_len, rx_status);			if (skb != NULL) {				skb->dev = dev;				skb_reserve(skb, 2);     /* Align IP on 16 byte */				/* 'skb->data' points to the start of sk_buff data area. */#ifdef  __powerpc__				insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len),							   (pkt_len + 3) >> 2);#else				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),					 (pkt_len + 3) >> 2);#endif				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */				skb->protocol = eth_type_trans(skb,dev);				netif_rx(skb);				lp->stats.rx_packets++;				continue;			}			outw(RxDiscard, ioaddr + EL3_CMD);			lp->stats.rx_dropped++;			if (el3_debug)				printk("%s: Couldn't allocate a sk_buff of size %d.\n",					   dev->name, pkt_len);		}		inw(ioaddr + EL3_STATUS); 				/* Delay. */		while (inw(ioaddr + EL3_STATUS) & 0x1000)			printk(KERN_DEBUG "	Waiting for 3c509 to discard packet, status %x.\n",				   inw(ioaddr + EL3_STATUS) );	}	return 0;}/* *     Set or clear the multicast filter for this adaptor. */static voidset_multicast_list(struct net_device *dev){	unsigned long flags;	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	if (el3_debug > 1) {		static int old = 0;		if (old != dev->mc_count) {			old = dev->mc_count;			printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);		}	}	spin_lock_irqsave(&lp->lock, flags);	if (dev->flags&IFF_PROMISC) {		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,			 ioaddr + EL3_CMD);	}	else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);	}	else                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);	spin_unlock_irqrestore(&lp->lock, flags);}static intel3_close(struct net_device *dev){	int ioaddr = dev->base_addr;	if (el3_debug > 2)		printk("%s: Shutting down ethercard.\n", dev->name);	netif_stop_queue(dev);	/* Turn off statistics ASAP.  We update lp->stats below. */	outw(StatsDisable, ioaddr + EL3_CMD);	/* Disable the receiver and transmitter. */	outw(RxDisable, ioaddr + EL3_CMD);	outw(TxDisable, ioaddr + EL3_CMD);	if (dev->if_port == 3)		/* Turn off thinnet power.  Green! */		outw(StopCoax, ioaddr + EL3_CMD);	else if (dev->if_port == 0) {		/* Disable link beat and jabber, if_port may change ere next open(). */		EL3WINDOW(4);		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);	}	free_irq(dev->irq, dev);	/* Switching back to window 0 disables the IRQ. */	EL3WINDOW(0);	/* But we explicitly zero the IRQ line select anyway. */	outw(0x0f00, ioaddr + WN0_IRQ);	update_stats(dev);	return 0;}#ifdef MODULE/* Parameters that may be passed into the module. */static int debug = -1;static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1};MODULE_PARM(debug,"i");MODULE_PARM(irq,"1-8i");MODULE_PARM(xcvr,"1-8i");MODULE_PARM(max_interrupt_work, "i");#ifdef __ISAPNP__MODULE_PARM(nopnp, "i");#endifintinit_module(void){	int el3_cards = 0;	if (debug >= 0)		el3_debug = debug;	el3_root_dev = NULL;	while (el3_probe(0) == 0) {		if (irq[el3_cards] > 1)			el3_root_dev->irq = irq[el3_cards];		if (xcvr[el3_cards] >= 0)			el3_root_dev->if_port = xcvr[el3_cards];		el3_cards++;	}	return el3_cards ? 0 : -ENODEV;}voidcleanup_module(void){	struct net_device *next_dev;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (el3_root_dev) {		struct el3_private *lp = (struct el3_private *)el3_root_dev->priv;#ifdef CONFIG_MCA				if(lp->mca_slot!=-1)			mca_mark_as_unused(lp->mca_slot);#endif					next_dev = lp->next_dev;		unregister_netdev(el3_root_dev);		release_region(el3_root_dev->base_addr, EL3_IO_EXTENT);		kfree(el3_root_dev);		el3_root_dev = next_dev;	}}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c" *  version-control: t *  kept-new-versions: 5 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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