📄 smc91c92_cs.c
字号:
return 0;}/*====================================================================== This verifies that the chip is some SMC91cXX variant, and returns the revision code if successful. Otherwise, it returns -ENODEV. ======================================================================*/static int check_sig(dev_link_t *link){ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; ioaddr_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); CardServices(ReleaseIO, link->handle, &link->io); link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; CardServices(RequestIO, 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 smc_private *smc = link->priv; struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_short buf[32]; char *name; int i, j, rev; ioaddr_t ioaddr; 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 = CardServices(RequestIRQ, link->handle, &link->irq); CS_EXIT_TEST(i, RequestIRQ, config_failed); i = CardServices(RequestConfiguration, 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"); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); goto config_undo; } 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"); link->state &= ~DEV_CONFIG_PENDING; goto config_undo; } strcpy(smc->node.dev_name, dev->name); link->dev = &smc->node; link->state &= ~DEV_CONFIG_PENDING; 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; } 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")); ioaddr = dev->base_addr; if (rev > 0) { u_long mir, 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)); if (mir & 0x3ff) printk(KERN_INFO " %lu byte", mir); else printk(KERN_INFO " %lu kb", mir>>10); 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; printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]); } if (smc->cfg & CFG_MII_SELECT) { SMC_SELECT_BANK(3); for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + MGMT, i, 1); if ((j != 0) && (j != 0xffff)) break; } smc->phy_id = (i < 32) ? i : -1; if (i < 32) { DEBUG(0, " MII transceiver at index %d, status %x.\n", i, j); } else { printk(KERN_NOTICE " No MII transceivers found!\n"); } SMC_SELECT_BANK(0); } return; config_undo: unregister_netdev(dev);config_failed: /* CS_EXIT_TEST() calls jump to here... */ smc91c92_release((u_long)link); } /* 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(u_long arg){ dev_link_t *link = (dev_link_t *)arg; struct smc_private *smc = link->priv; DEBUG(0, "smc91c92_release(0x%p)\n", link); if (link->open) { DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); if (link->win) { iounmap(smc->base); CardServices(ReleaseWindow, link->win); } link->state &= ~DEV_CONFIG;} /* smc91c92_release *//*====================================================================== 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 smc_private *smc = link->priv; struct net_device *dev = &smc->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); mod_timer(&link->release, jiffies + HZ/20); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT; 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); CardServices(ReleaseConfiguration, 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); CardServices(RequestConfiguration, 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(ioaddr_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(ioaddr_t addr, int phy_id, int loc){ 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(ioaddr_t addr, int phy_id, int loc, int value){ 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){ ioaddr_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);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -