3c589_cs.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,010 行 · 第 1/3 页
C
1,010 行
if (register_netdev(dev) != 0) { printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); link->dev_node = NULL; goto failed; } strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ", dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); return 0;cs_failed: cs_error(link, last_fn, last_ret);failed: tc589_release(link); return -ENODEV;} /* tc589_config *//*====================================================================== After a card is removed, tc589_release() will unregister the net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/static void tc589_release(struct pcmcia_device *link){ pcmcia_disable_device(link);}static int tc589_suspend(struct pcmcia_device *link){ struct net_device *dev = link->priv; if (link->open) netif_device_detach(dev); return 0;}static int tc589_resume(struct pcmcia_device *link){ struct net_device *dev = link->priv; if (link->open) { tc589_reset(dev); netif_device_attach(dev); } return 0;}/*====================================================================*//* Use this for commands that may take time to finish*/static void tc589_wait_for_completion(struct net_device *dev, int cmd){ int i = 100; outw(cmd, dev->base_addr + EL3_CMD); while (--i > 0) if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; if (i == 0) printk(KERN_WARNING "%s: command 0x%04x did not complete!\n", dev->name, cmd);}/* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero.*/static u16 read_eeprom(kio_addr_t ioaddr, int index){ int i; outw(EEPROM_READ + index, ioaddr + 10); /* Reading the eeprom takes 162 us */ for (i = 1620; i >= 0; i--) if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) break; return inw(ioaddr + 12);}/* Set transceiver type, perhaps to something other than what the user specified in dev->if_port.*/static void tc589_set_xcvr(struct net_device *dev, int if_port){ struct el3_private *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; EL3WINDOW(0); switch (if_port) { case 0: case 1: outw(0, ioaddr + 6); break; case 2: outw(3<<14, ioaddr + 6); break; case 3: outw(1<<14, ioaddr + 6); break; } /* On PCMCIA, this just turns on the LED */ outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); /* 10baseT interface, enable link beat and jabber check. */ EL3WINDOW(4); outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); EL3WINDOW(1); if (if_port == 2) lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); else lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);}static void dump_status(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; EL3WINDOW(1); printk(KERN_INFO " irq status %04x, rx status %04x, tx status " "%02x tx free %04x\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); EL3WINDOW(4); printk(KERN_INFO " diagnostics: fifo %04x net %04x ethernet %04x" " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), inw(ioaddr+0x0a)); EL3WINDOW(1);}/* Reset and restore all of the 3c589 registers. */static void tc589_reset(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; int i; EL3WINDOW(0); outw(0x0001, ioaddr + 4); /* Activate board. */ outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ /* Set the station address in window 2. */ EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); tc589_set_xcvr(dev, dev->if_port); /* 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-cast and phys addr only. */ outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ 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 | RxComplete | StatsFull | AdapterFailure, ioaddr + EL3_CMD);}static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);}#ifdef PCMCIA_DEBUGstatic u32 netdev_get_msglevel(struct net_device *dev){ return pc_debug;}static void netdev_set_msglevel(struct net_device *dev, u32 level){ pc_debug = level;}#endif /* PCMCIA_DEBUG */static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo,#ifdef PCMCIA_DEBUG .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel,#endif /* PCMCIA_DEBUG */};static int el3_config(struct net_device *dev, struct ifmap *map){ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (map->port <= 3) { dev->if_port = map->port; printk(KERN_INFO "%s: switched to %s port\n", dev->name, if_names[dev->if_port]); tc589_set_xcvr(dev, dev->if_port); } else return -EINVAL; } return 0;}static int el3_open(struct net_device *dev){ struct el3_private *lp = netdev_priv(dev); struct pcmcia_device *link = lp->p_dev; if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; netif_start_queue(dev); tc589_reset(dev); init_timer(&lp->media); lp->media.function = &media_check; lp->media.data = (unsigned long) dev; lp->media.expires = jiffies + HZ; add_timer(&lp->media); DEBUG(1, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); return 0;}static void el3_tx_timeout(struct net_device *dev){ struct el3_private *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name); dump_status(dev); lp->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ tc589_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); netif_wake_queue(dev);}static void pop_tx_status(struct net_device *dev){ struct el3_private *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; int i; /* Clear the Tx status stack. */ for (i = 32; i > 0; i--) { u_char tx_status = inb(ioaddr + TX_STATUS); if (!(tx_status & 0x84)) break; /* reset transmitter on jabber error or underrun */ if (tx_status & 0x30) tc589_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 + TX_STATUS); /* Pop the status stack. */ }}static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; struct el3_private *priv = netdev_priv(dev); DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, inw(ioaddr + EL3_STATUS)); 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 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?