📄 smc91c92_cs.c
字号:
/* Pause 200ms... */ mdelay(200); /* Now read and write the COR... */ tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR); udelay(5); writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR); return 0;}static int mhz_mfc_config(dev_link_t *link){ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_char buf[255]; cistpl_cftable_entry_t *cf = &parse.cftable_entry; win_req_t req; memreq_t mem; int i, k; link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; link->io.IOAddrLines = 16; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; tuple.Attributes = tuple.TupleOffset = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; i = first_tuple(link->handle, &tuple, &parse); /* The Megahertz combo cards have modem-like CIS entries, so we have to explicitly try a bunch of port combinations. */ while (i == CS_SUCCESS) { link->conf.ConfigIndex = cf->index; link->io.BasePort2 = cf->io.win[0].base; for (k = 0; k < 0x400; k += 0x10) { if (k & 0x80) continue; link->io.BasePort1 = k ^ 0x300; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i == CS_SUCCESS) break; i = next_tuple(link->handle, &tuple, &parse); } if (i != CS_SUCCESS) return i; dev->base_addr = link->io.BasePort1; /* Allocate a memory window, for accessing the ISR */ req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; link->win = (window_handle_t)link->handle; i = CardServices(RequestWindow, &link->win, &req); if (i != CS_SUCCESS) return i; smc->base = ioremap(req.Base, req.Size); mem.CardOffset = mem.Page = 0; if (smc->manfid == MANFID_MOTOROLA) mem.CardOffset = link->conf.ConfigBase; i = CardServices(MapMemPage, link->win, &mem); if ((i == CS_SUCCESS) && (smc->manfid == MANFID_MEGAHERTZ) && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); return i;}static int mhz_setup(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_char buf[255], *station_addr; tuple.Attributes = tuple.TupleOffset = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); /* Read the station address from the CIS. It is stored as the last (fourth) string in the Version 1 Version/ID tuple. */ tuple.DesiredTuple = CISTPL_VERS_1; if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS) return -1; /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS) first_tuple(handle, &tuple, &parse); if (parse.version_1.ns > 3) { station_addr = parse.version_1.str + parse.version_1.ofs[3]; if (cvt_ascii_address(dev, station_addr) == 0) return 0; } /* Another possibility: for the EM3288, in a special tuple */ tuple.DesiredTuple = 0x81; if (CardServices(GetFirstTuple, handle, &tuple) != CS_SUCCESS) return -1; if (CardServices(GetTupleData, handle, &tuple) != CS_SUCCESS) return -1; buf[12] = '\0'; if (cvt_ascii_address(dev, buf) == 0) return 0; return -1;}/*====================================================================== Configuration stuff for the Motorola Mariner mot_config() writes directly to the Mariner configuration registers because the CIS is just bogus. ======================================================================*/static void mot_config(dev_link_t *link){ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; ioaddr_t iouart = link->io.BasePort2; /* Set UART base address and force map with COR bit 1 */ writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0); writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1); writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR); /* Set SMC base address and force map with COR bit 1 */ writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0); writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1); writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR); /* Wait for things to settle down */ mdelay(100);}static int mot_setup(dev_link_t *link){ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; int i, wait, loop; u_int addr; /* Read Ethernet address from Serial EEPROM */ for (i = 0; i < 3; i++) { SMC_SELECT_BANK(2); outw(MOT_EEPROM + i, ioaddr + POINTER); SMC_SELECT_BANK(1); outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL); for (loop = wait = 0; loop < 200; loop++) { udelay(10); wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL)); if (wait == 0) break; } if (wait) return -1; addr = inw(ioaddr + GENERAL); dev->dev_addr[2*i] = addr & 0xff; dev->dev_addr[2*i+1] = (addr >> 8) & 0xff; } return 0;}/*====================================================================*/static int smc_config(dev_link_t *link){ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_char buf[255]; cistpl_cftable_entry_t *cf = &parse.cftable_entry; int i; tuple.Attributes = tuple.TupleOffset = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; link->io.NumPorts1 = 16; i = first_tuple(link->handle, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if (i == CS_SUCCESS) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } i = next_tuple(link->handle, &tuple, &parse); } if (i == CS_SUCCESS) dev->base_addr = link->io.BasePort1; return i;}static int smc_setup(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; cistpl_lan_node_id_t *node_id; u_char buf[255], *station_addr; int i; tuple.Attributes = tuple.TupleOffset = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); /* Check for a LAN function extension tuple */ tuple.DesiredTuple = CISTPL_FUNCE; i = first_tuple(handle, &tuple, &parse); while (i == CS_SUCCESS) { if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID) break; i = next_tuple(handle, &tuple, &parse); } if (i == CS_SUCCESS) { node_id = (cistpl_lan_node_id_t *)parse.funce.data; if (node_id->nb == 6) { for (i = 0; i < 6; i++) dev->dev_addr[i] = node_id->id[i]; return 0; } } /* Try the third string in the Version 1 Version/ID tuple. */ tuple.DesiredTuple = CISTPL_VERS_1; if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS) return -1; station_addr = parse.version_1.str + parse.version_1.ofs[2]; if (cvt_ascii_address(dev, station_addr) == 0) return 0; return -1;}/*====================================================================*/static int osi_config(dev_link_t *link){ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; int i, j; link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; link->io.NumPorts1 = 64; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; link->io.IOAddrLines = 16; /* Enable Hard Decode, LAN, Modem */ link->conf.ConfigIndex = 0x23; for (i = j = 0; j < 4; j++) { link->io.BasePort2 = com[j]; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { /* Fallback: turn off hard decode */ link->conf.ConfigIndex = 0x03; link->io.NumPorts2 = 0; i = CardServices(RequestIO, link->handle, &link->io); } dev->base_addr = link->io.BasePort1 + 0x10; return i;}static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid){ client_handle_t handle = link->handle; struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; tuple_t tuple; u_char buf[255]; int i; tuple.Attributes = TUPLE_RETURN_COMMON; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; /* Read the station address from tuple 0x90, subtuple 0x04 */ tuple.DesiredTuple = 0x90; i = CardServices(GetFirstTuple, handle, &tuple); while (i == CS_SUCCESS) { i = CardServices(GetTupleData, handle, &tuple); if ((i != CS_SUCCESS) || (buf[0] == 0x04)) break; i = CardServices(GetNextTuple, handle, &tuple); } if (i != CS_SUCCESS) return -1; for (i = 0; i < 6; i++) dev->dev_addr[i] = buf[i+2]; if (((manfid == MANFID_OSITECH) && (cardid == PRODID_OSITECH_SEVEN)) || ((manfid == MANFID_PSION) && (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); } } else if (manfid == MANFID_OSITECH) { /* Make sure both functions are powered up */ set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR); /* Now, turn on the interrupt for both card functions */ set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR); DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", inw(link->io.BasePort1 + OSITECH_AUI_PWR), inw(link->io.BasePort1 + OSITECH_RESET_ISR)); } 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, rev; 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -