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

📄 3c589_cs.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	    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 + TX_STATUS); /* 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));    ((struct el3_private *)dev->priv)->stats.tx_bytes += skb->len;    /* Put out the doubleword header... */    outw(skb->len, ioaddr + TX_FIFO);    outw(0x00, ioaddr + TX_FIFO);    /* ... and the packet rounded to a doubleword. */    outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);    dev->trans_start = jiffies;    if (inw(ioaddr + TX_FREE) <= 1536) {	netif_stop_queue(dev);	/* Interrupt us when the FIFO has room for max-sized packet. */	outw(SetTxThreshold + 1536, 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 i = 0;        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 | StatsFull)) {	if (!netif_device_present(dev) ||	    ((status & 0xe000) != 0x2000)) {	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);	    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_NOTICE "%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_NOTICE "%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;    DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",	  dev->name, inw(ioaddr + EL3_STATUS));    return;}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_short media, errs;    u_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_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 + 1;	add_timer(&lp->media);	return;    }        save_flags(flags);    cli();    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);    restore_flags(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 = (struct el3_private *)dev->priv;    unsigned long flags;    dev_link_t *link = &lp->link;    if (DEV_OK(link)) {	save_flags(flags);	cli();	update_stats(dev);	restore_flags(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;    ioaddr_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 = (struct el3_private *)dev->priv;    ioaddr_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_NOTICE "%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 = dev->priv;    dev_link_t *link = &lp->link;    ioaddr_t ioaddr = dev->base_addr;    u_short 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 = dev->priv;    dev_link_t *link = &lp->link;    ioaddr_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(&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_3c589_cs(void){    servinfo_t serv;    DEBUG(0, "%s\n", version);    CardServices(GetCardServicesInfo, &serv);    if (serv.Revision != CS_RELEASE_CODE) {	printk(KERN_NOTICE "3c589_cs: Card Services release "	       "does not match!\n");	return -1;    }    register_pccard_driver(&dev_info, &tc589_attach, &tc589_detach);    return 0;}static void __exit exit_3c589_cs(void){    DEBUG(0, "3c589_cs: unloading\n");    unregister_pccard_driver(&dev_info);    while (dev_list != NULL)	tc589_detach(dev_list);}module_init(init_3c589_cs);module_exit(exit_3c589_cs);

⌨️ 快捷键说明

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