📄 smc91c92_cs.c
字号:
kio_addr_t ioaddr; u_long mir; DEBUG(0, "smc91c92_config(0x%p)\n", link); tuple.Attributes = tuple.TupleOffset = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.DesiredTuple = CISTPL_CONFIG; i = first_tuple(handle, &tuple, &parse); CS_EXIT_TEST(i, ParseTuple, config_failed); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { smc->manfid = parse.manfid.manf; smc->cardid = parse.manfid.card; } /* Configure card */ link->state |= DEV_CONFIG; if ((smc->manfid == MANFID_OSITECH) && (smc->cardid != PRODID_OSITECH_SEVEN)) { i = osi_config(link); } else if ((smc->manfid == MANFID_MOTOROLA) || ((smc->manfid == MANFID_MEGAHERTZ) && ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) || (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) { i = mhz_mfc_config(link); } else { i = smc_config(link); } CS_EXIT_TEST(i, RequestIO, config_failed); i = pcmcia_request_irq(link->handle, &link->irq); CS_EXIT_TEST(i, RequestIRQ, config_failed); i = pcmcia_request_configuration(link->handle, &link->conf); CS_EXIT_TEST(i, RequestConfiguration, config_failed); if (smc->manfid == MANFID_MOTOROLA) mot_config(link); dev->irq = link->irq.AssignedIRQ; if ((if_port >= 0) && (if_port <= 2)) dev->if_port = if_port; else printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n"); switch (smc->manfid) { case MANFID_OSITECH: case MANFID_PSION: i = osi_setup(link, smc->manfid, smc->cardid); break; case MANFID_SMC: case MANFID_NEW_MEDIA: i = smc_setup(link); break; case 0x128: /* For broken Megahertz cards */ case MANFID_MEGAHERTZ: i = mhz_setup(link); break; case MANFID_MOTOROLA: default: /* get the hw address from EEPROM */ i = mot_setup(link); break; } if (i != 0) { printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n"); goto config_undo; } smc->duplex = 0; smc->rx_ovrn = 0; rev = check_sig(link); name = "???"; if (rev > 0) switch (rev >> 4) { case 3: name = "92"; break; case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break; case 5: name = "95"; break; case 7: name = "100"; break; case 8: name = "100-FD"; break; case 9: name = "110"; break; } ioaddr = dev->base_addr; if (rev > 0) { u_long mcr; SMC_SELECT_BANK(0); mir = inw(ioaddr + MEMINFO) & 0xff; if (mir == 0xff) mir++; /* Get scale factor for memory size */ mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200; mir *= 128 * (1<<((mcr >> 9) & 7)); SMC_SELECT_BANK(1); smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC; if (smc->manfid == MANFID_OSITECH) smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0; if ((rev >> 4) >= 7) smc->cfg |= CFG_MII_SELECT; } else mir = 0; if (smc->cfg & CFG_MII_SELECT) { SMC_SELECT_BANK(3); for (i = 0; i < 32; i++) { j = mdio_read(dev, i, 1); if ((j != 0) && (j != 0xffff)) break; } smc->mii_if.phy_id = (i < 32) ? i : -1; SMC_SELECT_BANK(0); } link->dev = &smc->node; link->state &= ~DEV_CONFIG_PENDING; SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); link->dev = NULL; goto config_undo; } strcpy(smc->node.dev_name, dev->name); printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); if (rev > 0) { if (mir & 0x3ff) printk(KERN_INFO " %lu byte", mir); else printk(KERN_INFO " %lu kb", mir>>10); printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]); } if (smc->cfg & CFG_MII_SELECT) { if (smc->mii_if.phy_id != -1) { DEBUG(0, " MII transceiver at index %d, status %x.\n", smc->mii_if.phy_id, j); } else { printk(KERN_NOTICE " No MII transceivers found!\n"); } } return;config_undo: unregister_netdev(dev);config_failed: /* CS_EXIT_TEST() calls jump to here... */ smc91c92_release(link); link->state &= ~DEV_CONFIG_PENDING;} /* smc91c92_config *//*====================================================================== After a card is removed, smc91c92_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 smc91c92_release(dev_link_t *link){ DEBUG(0, "smc91c92_release(0x%p)\n", link); pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); if (link->win) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); iounmap(smc->base); pcmcia_release_window(link->win); } 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 smc91c92_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); int i; DEBUG(1, "smc91c92_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; smc91c92_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) { if ((smc->manfid == MANFID_MEGAHERTZ) && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); pcmcia_request_configuration(link->handle, &link->conf); if (smc->manfid == MANFID_MOTOROLA) mot_config(link); if ((smc->manfid == MANFID_OSITECH) && (smc->cardid != PRODID_OSITECH_SEVEN)) { /* Power up the card and enable interrupts */ set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); } if (((smc->manfid == MANFID_OSITECH) && (smc->cardid == PRODID_OSITECH_SEVEN)) || ((smc->manfid == MANFID_PSION) && (smc->cardid == PRODID_PSION_NET100))) { /* Download the Seven of Diamonds firmware */ for (i = 0; i < sizeof(__Xilinx7OD); i++) { outb(__Xilinx7OD[i], link->io.BasePort1+2); udelay(50); } } if (link->open) { smc_reset(dev); netif_device_attach(dev); } } break; } return 0;} /* smc91c92_event *//*====================================================================== MII interface support for SMC91cXX based cards======================================================================*/#define MDIO_SHIFT_CLK 0x04#define MDIO_DATA_OUT 0x01#define MDIO_DIR_WRITE 0x08#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE)#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)#define MDIO_DATA_READ 0x02static void mdio_sync(kio_addr_t addr){ int bits; for (bits = 0; bits < 32; bits++) { outb(MDIO_DATA_WRITE1, addr); outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); }}static int mdio_read(struct net_device *dev, int phy_id, int loc){ kio_addr_t addr = dev->base_addr + MGMT; u_int cmd = (0x06<<10)|(phy_id<<5)|loc; int i, retval = 0; mdio_sync(addr); for (i = 13; i >= 0; i--) { int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; outb(dat, addr); outb(dat | MDIO_SHIFT_CLK, addr); } for (i = 19; i > 0; i--) { outb(0, addr); retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0); outb(MDIO_SHIFT_CLK, addr); } return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int loc, int value){ kio_addr_t addr = dev->base_addr + MGMT; u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; int i; mdio_sync(addr); for (i = 31; i >= 0; i--) { int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; outb(dat, addr); outb(dat | MDIO_SHIFT_CLK, addr); } for (i = 1; i >= 0; i--) { outb(0, addr); outb(MDIO_SHIFT_CLK, addr); }}/*====================================================================== The driver core code, most of which should be common with a non-PCMCIA implementation.======================================================================*/#ifdef PCMCIA_DEBUGstatic void smc_dump(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; u_short i, w, save; save = inw(ioaddr + BANK_SELECT); for (w = 0; w < 4; w++) { SMC_SELECT_BANK(w); printk(KERN_DEBUG "bank %d: ", w); for (i = 0; i < 14; i += 2) printk(" %04x", inw(ioaddr + i)); printk("\n"); } outw(save, ioaddr + BANK_SELECT);}#endifstatic int smc_open(struct net_device *dev){ struct smc_private *smc = netdev_priv(dev); dev_link_t *link = &smc->link;#ifdef PCMCIA_DEBUG DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n", dev->name, dev, inw(dev->base_addr + BANK_SELECT)); if (pc_debug > 1) smc_dump(dev);#endif /* Check that the PCMCIA card is still here. */ if (!DEV_OK(link)) return -ENODEV; /* Physical device present signature. */ if (check_sig(link) < 0) { printk("smc91c92_cs: Yikes! Bad chip signature!\n"); return -ENODEV; } link->open++; netif_start_queue(dev); smc->saved_skb = NULL; smc->packets_waiting = 0; smc_reset(dev); init_timer(&smc->media); smc->media.function = &media_check; smc->media.data = (u_long) dev; smc->media.expires = jiffies + HZ; add_timer(&smc->media); return 0;} /* smc_open *//*====================================================================*/static int smc_close(struct net_device *dev){ struct smc_private *smc = netdev_priv(dev); dev_link_t *link = &smc->link; kio_addr_t ioaddr = dev->base_addr; DEBUG(0, "%s: smc_close(), status %4.4x.\n", dev->name, inw(ioaddr + BANK_SELECT)); netif_stop_queue(dev); /* Shut off all interrupts, and turn off the Tx and Rx sections. Don't bother to check for chip present. */ SMC_SELECT_BANK(2); /* Nominally paranoia, but do no assume... */ outw(0, ioaddr + INTERRUPT); SMC_SELECT_BANK(0); mask_bits(0xff00, ioaddr + RCR); mask_bits(0xff00, ioaddr + TCR); /* Put the chip into power-down mode. */ SMC_SELECT_BANK(1); outw(CTL_POWERDOWN, ioaddr + CONTROL ); link->open--; del_timer_sync(&smc->media); return 0;} /* smc_close *//*====================================================================== Transfer a packet to the hardware and trigger the packet send. This may be called at either from either the Tx queue code or the interrupt handler.======================================================================*/static void smc_hardware_send_packet(struct net_device * dev){ struct smc_private *smc = netdev_priv(dev); struct sk_buff *skb = smc->saved_skb; kio_addr_t ioaddr = dev->base_addr; u_char packet_no; if (!skb) { printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name); return; } /* There should be a packet slot waiting. */ packet_no = inw(ioaddr + PNR_ARR) >> 8; if (packet_no & 0x80) { /* If not, there is a hardware problem! Likely an ejected card. */ printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation" " failed, status %#2.2x.\n", dev->name, packet_no); dev_kfree_skb_irq(skb); smc->saved_skb = NULL; netif_start_queue(dev); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -