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

📄 3c589_cs.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	    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 + -