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

📄 3c574_cs.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (tx_status & 0x30)			tc574_wait_for_completion(dev, TxReset);		if (tx_status & 0x38) {			DEBUG(1, "%s: transmit error: status 0x%02x\n",				  dev->name, tx_status);			outw(TxEnable, ioaddr + EL3_CMD);			lp->stats.tx_aborted_errors++;		}		outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */    }}static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev){	ioaddr_t ioaddr = dev->base_addr;	DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "		  "status %4.4x.\n", dev->name, (long)skb->len,		  inw(ioaddr + EL3_STATUS));	outw(skb->len, ioaddr + TX_FIFO);	outw(0, ioaddr + TX_FIFO);	outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);	dev->trans_start = jiffies;	/* TxFree appears only in Window 1, not offset 0x1c. */	if (inw(ioaddr + TxFree) <= 1536) {		netif_stop_queue(dev);		/* Interrupt us when the FIFO has room for max-sized packet. 		   The threshold is in units of dwords. */		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);	}	dev_kfree_skb (skb);	pop_tx_status(dev);	return 0;}/* The EL3 interrupt handler. */static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct el3_private *lp = dev_id;	struct net_device *dev = &lp->dev;	ioaddr_t ioaddr, status;	int work_budget = max_interrupt_work;	if (!netif_device_present(dev))		return;	ioaddr = dev->base_addr;	DEBUG(3, "%s: interrupt, status %4.4x.\n",		  dev->name, inw(ioaddr + EL3_STATUS));	while ((status = inw(ioaddr + EL3_STATUS)) &		   (IntLatch | RxComplete | RxEarly | StatsFull)) {		if (!netif_device_present(dev) ||			((status & 0xe000) != 0x2000)) {			DEBUG(1, "%s: Interrupt from dead card\n", dev->name);			break;		}		if (status & RxComplete)			work_budget = el3_rx(dev, work_budget);		if (status & TxAvailable) {			DEBUG(3, "  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 & TxComplete)			pop_tx_status(dev);		if (status & (AdapterFailure | RxEarly | StatsFull)) {			/* Handle all uncommon interrupts. */			if (status & StatsFull)				update_stats(dev);			if (status & RxEarly) {				work_budget = el3_rx(dev, work_budget);				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);			}			if (status & AdapterFailure) {				u16 fifo_diag;				EL3WINDOW(4);				fifo_diag = inw(ioaddr + Wn4_FIFODiag);				EL3WINDOW(1);				printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"					   " register %04x.\n", dev->name, fifo_diag);				if (fifo_diag & 0x0400) {					/* Tx overrun */					tc574_wait_for_completion(dev, TxReset);					outw(TxEnable, ioaddr + EL3_CMD);				}				if (fifo_diag & 0x2000) {					/* Rx underrun */					tc574_wait_for_completion(dev, RxReset);					set_rx_mode(dev);					outw(RxEnable, ioaddr + EL3_CMD);				}				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);			}		}		if (--work_budget < 0) {			DEBUG(0, "%s: Too much work 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);	}	DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",		  dev->name, inw(ioaddr + EL3_STATUS));	return;}/*    This timer serves two purposes: to check for missed interrupts	(and as a last resort, poll the NIC for events), and to monitor	the MII, reporting changes in cable status.*/static void media_check(u_long arg){    struct el3_private *lp = (struct el3_private *)arg;    struct net_device *dev = &lp->dev;    ioaddr_t ioaddr = dev->base_addr;    u_long flags;	u_short /* cable, */ media, partner;	if (!netif_device_present(dev))		goto reschedule;	    /* Check for pending interrupt with expired latency timer: with       this, we can limp along even if the interrupt is blocked */    if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&		(inb(ioaddr + Timer) == 0xff)) {		if (!lp->fast_poll)			printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);		el3_interrupt(dev->irq, lp, NULL);		lp->fast_poll = HZ;    }    if (lp->fast_poll) {		lp->fast_poll--;		lp->media.expires = jiffies + 2;		add_timer(&lp->media);		return;    }	save_flags(flags);	cli();	EL3WINDOW(4);	media = mdio_read(ioaddr, lp->phys, 1);	partner = mdio_read(ioaddr, lp->phys, 5);	EL3WINDOW(1);	restore_flags(flags);	if (media != lp->media_status) {		if ((media ^ lp->media_status) & 0x0004)			printk(KERN_INFO "%s: %s link beat\n", dev->name,				   (lp->media_status & 0x0004) ? "lost" : "found");		if ((media ^ lp->media_status) & 0x0020) {			lp->partner = 0;			if (lp->media_status & 0x0020) {				printk(KERN_INFO "%s: autonegotiation restarted\n",					   dev->name);			} else if (partner) {				partner &= lp->advertising;				lp->partner = partner;				printk(KERN_INFO "%s: autonegotiation complete: "					   "%sbaseT-%cD selected\n", dev->name,					   ((partner & 0x0180) ? "100" : "10"),					   ((partner & 0x0140) ? 'F' : 'H'));			} else {				printk(KERN_INFO "%s: link partner did not autonegotiate\n",					   dev->name);			}			EL3WINDOW(3);			outb((partner & 0x0140 ? 0x20 : 0) |				 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);			EL3WINDOW(1);		}		if (media & 0x0010)			printk(KERN_INFO "%s: remote fault detected\n",				   dev->name);		if (media & 0x0002)			printk(KERN_INFO "%s: jabber detected\n", dev->name);		lp->media_status = media;	}reschedule:    lp->media.expires = jiffies + HZ;    add_timer(&lp->media);}static struct net_device_stats *el3_get_stats(struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	if (netif_device_present(dev))		update_stats(dev);	return &lp->stats;}/*  Update statistics.	Suprisingly this need not be run single-threaded, but it effectively is.	The counters clear when read, so the adds must merely be atomic. */static void update_stats(struct net_device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	ioaddr_t ioaddr = dev->base_addr;	u8 rx, tx, up;	DEBUG(2, "%s: updating the statistics.\n", dev->name);	if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */		return;	/* Unlike the 3c509 we need not turn off stats updates while reading. */	/* 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);	up		 						 = inb(ioaddr + 9);	lp->stats.tx_packets			+= (up&0x30) << 4;	/* Rx packets   */				   inb(ioaddr + 7);	/* Tx deferrals */				   inb(ioaddr + 8);	rx		 						 = inw(ioaddr + 10);	tx								 = inw(ioaddr + 12);	EL3WINDOW(4);	/* BadSSD */					   inb(ioaddr + 12);	up								 = inb(ioaddr + 13);	lp->stats.tx_bytes += tx + ((up & 0xf0) << 12);	EL3WINDOW(1);}static int el3_rx(struct net_device *dev, int worklimit){	struct el3_private *lp = (struct el3_private *)dev->priv;	ioaddr_t ioaddr = dev->base_addr;	short rx_status;		DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",		  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));    while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&		   (--worklimit >= 0)) {		if (rx_status & 0x4000) { /* Error, update stats. */			short error = rx_status & 0x3800;			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);			DEBUG(3, "  Receiving packet size %d status %4.4x.\n",				  pkt_len, rx_status);			if (skb != NULL) {				skb->dev = dev;				skb_reserve(skb, 2);				insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),						((pkt_len+3)>>2));				skb->protocol = eth_type_trans(skb, dev);				netif_rx(skb);				dev->last_rx = jiffies;				lp->stats.rx_packets++;				lp->stats.rx_bytes += pkt_len;			} else {				DEBUG(1, "%s: couldn't allocate a sk_buff of"					  " size %d.\n", dev->name, pkt_len);				lp->stats.rx_dropped++;			}		}		tc574_wait_for_completion(dev, RxDiscard);	}	return worklimit;}/* Provide ioctl() calls to examine the MII xcvr state. */static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct el3_private *lp = (struct el3_private *)dev->priv;	ioaddr_t ioaddr = dev->base_addr;	u16 *data = (u16 *)&rq->ifr_data;	int phy = lp->phys & 0x1f;	DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",		  dev->name, rq->ifr_ifrn.ifrn_name, cmd,		  data[0], data[1], data[2], data[3]);    switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */		data[0] = phy;	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		{			int saved_window;			long flags;			save_flags(flags);			cli();			saved_window = inw(ioaddr + EL3_CMD) >> 13;			EL3WINDOW(4);			data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);			EL3WINDOW(saved_window);			restore_flags(flags);			return 0;		}	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		{			int saved_window;			long flags;			if (!capable(CAP_NET_ADMIN))				return -EPERM;			save_flags(flags);			cli();			saved_window = inw(ioaddr + EL3_CMD) >> 13;			EL3WINDOW(4);			mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);			EL3WINDOW(saved_window);			restore_flags(flags);			return 0;		}	default:		return -EOPNOTSUPP;	}}/* The Odie chip has a 64 bin multicast filter, but the bit layout is not   documented.  Until it is we revert to receiving all multicast frames when   any multicast reception is desired.   Note: My other drivers emit a log message whenever promiscuous mode is   entered to help detect password sniffers.  This is less desirable on   typical PC card machines, so we omit the message.   */static void set_rx_mode(struct net_device *dev){	ioaddr_t ioaddr = dev->base_addr;	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);}static int el3_close(struct net_device *dev){	ioaddr_t ioaddr = dev->base_addr;	struct el3_private *lp = dev->priv;	dev_link_t *link = &lp->link;	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);		if (DEV_OK(link)) {		/* 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);				/* Note: Switching to window 0 may disable the IRQ. */		EL3WINDOW(0);				update_stats(dev);	}	link->open--;	netif_stop_queue(dev);	del_timer(&lp->media);	if (link->state & DEV_STALE_CONFIG)		mod_timer(&link->release, jiffies + HZ/20);	MOD_DEC_USE_COUNT;	return 0;}static int __init init_3c574_cs(void){	servinfo_t serv;	DEBUG(0, "%s\n", version);	CardServices(GetCardServicesInfo, &serv);	if (serv.Revision != CS_RELEASE_CODE) {		printk(KERN_NOTICE "3c574_cs: Card Services release "			   "does not match!\n");		return -1;	}	register_pccard_driver(&dev_info, &tc574_attach, &tc574_detach);	return 0;}static void __exit exit_3c574_cs(void){	DEBUG(0, "3c574_cs: unloading\n");	unregister_pccard_driver(&dev_info);	while (dev_list != NULL)		tc574_detach(dev_list);}module_init(init_3c574_cs);module_exit(exit_3c574_cs);/* * Local variables: *  compile-command: "make 3c574_cs.o" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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