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

📄 3c589_cs.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);    }    dev_kfree_skb(skb);    pop_tx_status(dev);        return 0;}/* The EL3 interrupt handler. */static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs){    struct net_device *dev = (struct net_device *) dev_id;    struct el3_private *lp = netdev_priv(dev);    kio_addr_t ioaddr;    __u16 status;    int i = 0, handled = 1;        if (!netif_device_present(dev))	return IRQ_NONE;    ioaddr = dev->base_addr;    DEBUG(3, "%s: interrupt, status %4.4x.\n",	  dev->name, inw(ioaddr + EL3_STATUS));    spin_lock(&lp->lock);        while ((status = inw(ioaddr + EL3_STATUS)) &	(IntLatch | RxComplete | StatsFull)) {	if ((status & 0xe000) != 0x2000) {	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);	    handled = 0;	    break;	}		if (status & RxComplete)	    el3_rx(dev);		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)		/* Empty statistics. */		update_stats(dev);	    if (status & RxEarly) {		/* Rx early is unused. */		el3_rx(dev);		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);	    }	    if (status & AdapterFailure) {		u16 fifo_diag;		EL3WINDOW(4);		fifo_diag = inw(ioaddr + 4);		EL3WINDOW(1);		printk(KERN_WARNING "%s: adapter failure, FIFO diagnostic"		       " register %04x.\n", dev->name, fifo_diag);		if (fifo_diag & 0x0400) {		    /* Tx overrun */		    tc589_wait_for_completion(dev, TxReset);		    outw(TxEnable, ioaddr + EL3_CMD);		}		if (fifo_diag & 0x2000) {		    /* Rx underrun */		    tc589_wait_for_completion(dev, RxReset);		    set_multicast_list(dev);		    outw(RxEnable, ioaddr + EL3_CMD);		}		outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);	    }	}		if (++i > 10) {	    printk(KERN_ERR "%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);    }    lp->last_irq = jiffies;    spin_unlock(&lp->lock);        DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",	  dev->name, inw(ioaddr + EL3_STATUS));    return IRQ_RETVAL(handled);}static void media_check(unsigned long arg){    struct net_device *dev = (struct net_device *)(arg);    struct el3_private *lp = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    u16 media, errs;    unsigned long flags;    if (!netif_device_present(dev)) goto reschedule;    EL3WINDOW(1);    /* 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 + EL3_TIMER) == 0xff)) {	if (!lp->fast_poll)	    printk(KERN_WARNING "%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 + HZ/100;	add_timer(&lp->media);	return;    }    /* lp->lock guards the EL3 window. Window should always be 1 except       when the lock is held */    spin_lock_irqsave(&lp->lock, flags);        EL3WINDOW(4);    media = inw(ioaddr+WN4_MEDIA) & 0xc810;    /* Ignore collisions unless we've had no irq's recently */    if (jiffies - lp->last_irq < HZ) {	media &= ~0x0010;    } else {	/* Try harder to detect carrier errors */	EL3WINDOW(6);	outw(StatsDisable, ioaddr + EL3_CMD);	errs = inb(ioaddr + 0);	outw(StatsEnable, ioaddr + EL3_CMD);	lp->stats.tx_carrier_errors += errs;	if (errs || (lp->media_status & 0x0010)) media |= 0x0010;    }    if (media != lp->media_status) {	if ((media & lp->media_status & 0x8000) &&	    ((lp->media_status ^ media) & 0x0800))	    printk(KERN_INFO "%s: %s link beat\n", dev->name,		   (lp->media_status & 0x0800 ? "lost" : "found"));	else if ((media & lp->media_status & 0x4000) &&		 ((lp->media_status ^ media) & 0x0010))	    printk(KERN_INFO "%s: coax cable %s\n", dev->name,		   (lp->media_status & 0x0010 ? "ok" : "problem"));	if (dev->if_port == 0) {	    if (media & 0x8000) {		if (media & 0x0800)		    printk(KERN_INFO "%s: flipped to 10baseT\n",			   dev->name);		else		    tc589_set_xcvr(dev, 2);	    } else if (media & 0x4000) {		if (media & 0x0010)		    tc589_set_xcvr(dev, 1);		else		    printk(KERN_INFO "%s: flipped to 10base2\n",			   dev->name);	    }	}	lp->media_status = media;    }        EL3WINDOW(1);    spin_unlock_irqrestore(&lp->lock, flags);    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 = netdev_priv(dev);    unsigned long flags;    dev_link_t *link = &lp->link;    if (DEV_OK(link)) {    	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.    Caller must hold the lock for this*/static void update_stats(struct net_device *dev){    struct el3_private *lp = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    DEBUG(2, "%s: updating the statistics.\n", dev->name);    /* 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);    /* Rx octets */			inw(ioaddr + 10);    /* Tx octets */			inw(ioaddr + 12);        /* Back to window 1, and turn statistics back on. */    EL3WINDOW(1);    outw(StatsEnable, ioaddr + EL3_CMD);}static int el3_rx(struct net_device *dev){    struct el3_private *lp = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    int worklimit = 32;    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+RX_STATUS));    while (!((rx_status = inw(ioaddr + RX_STATUS)) & 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++;	    }	}	/* Pop the top of the Rx FIFO */	tc589_wait_for_completion(dev, RxDiscard);    }    if (worklimit == 0)	printk(KERN_WARNING "%s: too much work in el3_rx!\n", dev->name);    return 0;}static void set_multicast_list(struct net_device *dev){    struct el3_private *lp = netdev_priv(dev);    dev_link_t *link = &lp->link;    kio_addr_t ioaddr = dev->base_addr;    u16 opts = SetRxFilter | RxStation | RxBroadcast;    if (!(DEV_OK(link))) return;    if (dev->flags & IFF_PROMISC)	opts |= RxMulticast | RxProm;    else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))	opts |= RxMulticast;    outw(opts, ioaddr + EL3_CMD);}static int el3_close(struct net_device *dev){    struct el3_private *lp = netdev_priv(dev);    dev_link_t *link = &lp->link;    kio_addr_t ioaddr = dev->base_addr;        DEBUG(1, "%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);		if (dev->if_port == 2)	    /* Turn off thinnet power.  Green! */	    outw(StopCoax, ioaddr + EL3_CMD);	else if (dev->if_port == 1) {	    /* Disable link beat and jabber */	    EL3WINDOW(4);	    outw(0, ioaddr + WN4_MEDIA);	}		/* Switching back to window 0 disables the IRQ. */	EL3WINDOW(0);	/* But we explicitly zero the IRQ line select anyway. */	outw(0x0f00, ioaddr + WN0_IRQ);        	/* Check if the card still exists */	if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)	    update_stats(dev);    }    link->open--;    netif_stop_queue(dev);    del_timer_sync(&lp->media);        return 0;}static struct pcmcia_driver tc589_driver = {	.owner		= THIS_MODULE,	.drv		= {		.name	= "3c589_cs",	},	.attach		= tc589_attach,	.detach		= tc589_detach,};static int __init init_tc589(void){	return pcmcia_register_driver(&tc589_driver);}static void __exit exit_tc589(void){	pcmcia_unregister_driver(&tc589_driver);	BUG_ON(dev_list != NULL);}module_init(init_tc589);module_exit(exit_tc589);

⌨️ 快捷键说明

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