📄 3c589_cs.c
字号:
phys_addr[i] = htons(read_eeprom(ioaddr, i)); if (phys_addr[0] == 0x6060) { printk(KERN_ERR "3c589_cs: IO port conflict at 0x%03lx" "-0x%03lx\n", dev->base_addr, dev->base_addr+15); goto failed; } } /* The address and resource configuration register aren't loaded from the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ outw(0x3f00, ioaddr + 8); fifo = inl(ioaddr); /* The if_port symbol can be set when the module is loaded */ if ((if_port >= 0) && (if_port <= 3)) dev->if_port = if_port; else printk(KERN_ERR "3c589_cs: invalid if_port requested\n"); link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); link->dev = 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;cs_failed: cs_error(link->handle, last_fn, last_ret);failed: tc589_release(link); return; } /* 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(dev_link_t *link){ DEBUG(0, "3c589_release(0x%p)\n", link); pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG;}/*====================================================================== The card status event handler. Mostly, this schedules other stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the net drivers from trying to talk to the card any more. ======================================================================*/static int tc589_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; struct net_device *dev = link->priv; DEBUG(1, "3c589_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) netif_device_detach(dev); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; tc589_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { tc589_reset(dev); netif_device_attach(dev); } } break; } return 0;} /* tc589_event *//*====================================================================*//* 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); dev_link_t *link = &lp->link; if (!DEV_OK(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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -