📄 smc91c92_cs.c
字号:
the revision code if successful. Otherwise, it returns -ENODEV.======================================================================*/static int check_sig(dev_link_t *link){ struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; int width; u_short s; SMC_SELECT_BANK(1); if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) { /* Try powering up the chip */ outw(0, ioaddr + CONTROL); mdelay(55); } /* Try setting bus width */ width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO); s = inb(ioaddr + CONFIG); if (width) s |= CFG_16BIT; else s &= ~CFG_16BIT; outb(s, ioaddr + CONFIG); /* Check Base Address Register to make sure bus width is OK */ s = inw(ioaddr + BASE_ADDR); if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) && ((s >> 8) != (s & 0xff))) { SMC_SELECT_BANK(3); s = inw(ioaddr + REVISION); return (s & 0xff); } if (width) { event_callback_args_t args; printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); args.client_data = link; smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args); pcmcia_release_io(link->handle, &link->io); link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; pcmcia_request_io(link->handle, &link->io); smc91c92_event(CS_EVENT_CARD_RESET, 0, &args); return check_sig(link); } return -ENODEV;}/*====================================================================== smc91c92_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system.======================================================================*/#define CS_EXIT_TEST(ret, svc, label) \if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; }static void smc91c92_config(dev_link_t *link){ client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); struct smc_cfg_mem *cfg_mem; tuple_t *tuple; cisparse_t *parse; u_char *buf; char *name; int i, j, rev; kio_addr_t ioaddr; u_long mir; DEBUG(0, "smc91c92_config(0x%p)\n", link); cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); if (!cfg_mem) goto config_failed; tuple = &cfg_mem->tuple; parse = &cfg_mem->parse; buf = cfg_mem->buf; tuple->Attributes = tuple->TupleOffset = 0; tuple->TupleData = (cisdata_t *)buf; tuple->TupleDataMax = 64; 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"); } } kfree(cfg_mem); return;config_undo: unregister_netdev(dev);config_failed: /* CS_EXIT_TEST() calls jump to here... */ smc91c92_release(link); link->state &= ~DEV_CONFIG_PENDING; kfree(cfg_mem);} /* 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -