int ide_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; DEBUG(1, "ide_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) ide_release(link); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ide_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) pcmcia_request_configuration(link->handle, &link->conf); break; } return 0; } /* ide_event */
static void ide_detach(dev_link_t *link) { dev_link_t **linkp; int ret; DEBUG(0, "ide_detach(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; if (link->state & DEV_CONFIG) ide_release(link); if (link->handle) { ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } /* Unlink, free device structure */ *linkp = link->next; kfree(link->priv); } /* ide_detach */
static int ide_config(struct pcmcia_device *link) { ide_info_t *info = link->priv; int ret = 0, is_kme = 0; unsigned long io_base, ctl_base; struct ide_host *host; dev_dbg(&link->dev, "ide_config(0x%p)\n", link); is_kme = ((link->manf_id == MANFID_KME) && ((link->card_id == PRODID_KME_KXLC005_A) || (link->card_id == PRODID_KME_KXLC005_B))); if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) { link->config_flags &= ~CONF_AUTO_CHECK_VCC; if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) goto failed; /* No suitable config found */ } io_base = link->resource[0]->start; if (link->resource[1]->end) ctl_base = link->resource[1]->start; else ctl_base = link->resource[0]->start + 0x0e; if (!link->irq) goto failed; ret = pcmcia_enable_device(link); if (ret) goto failed; /* disable drive interrupts during IDE probe */ outb(0x02, ctl_base); /* special setup for KXLC005 card */ if (is_kme) outb(0x81, ctl_base+1); host = idecs_register(io_base, ctl_base, link->irq, link); if (host == NULL && resource_size(link->resource[0]) == 0x20) { outb(0x02, ctl_base + 0x10); host = idecs_register(io_base + 0x10, ctl_base + 0x10, link->irq, link); } if (host == NULL) goto failed; info->ndev = 1; info->host = host; dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n", 'a' + host->ports[0]->index * 2, link->vpp / 10, link->vpp % 10); return 0; failed: ide_release(link); return -ENODEV; } /* ide_config */
static void ide_detach(struct pcmcia_device *link) { DEBUG(0, "ide_detach(0x%p)\n", link); ide_release(link); kfree(link->priv); } /* ide_detach */
static void ide_detach(struct pcmcia_device *link) { ide_info_t *info = link->priv; dev_dbg(&link->dev, "ide_detach(0x%p)\n", link); ide_release(link); kfree(info); } /* ide_detach */
static void ide_detach(struct pcmcia_device *link) { ide_info_t *info = link->priv; ide_hwif_t *hwif = info->host->ports[0]; unsigned long data_addr, ctl_addr; DEBUG(0, "ide_detach(0x%p)\n", link); data_addr = hwif->io_ports.data_addr; ctl_addr = hwif->io_ports.ctl_addr; ide_release(link); release_region(ctl_addr, 1); release_region(data_addr, 8); kfree(info); } /* ide_detach */
static int ide_config(struct pcmcia_device *link) { ide_info_t *info = link->priv; tuple_t tuple; struct { u_short buf[128]; cisparse_t parse; config_info_t conf; cistpl_cftable_entry_t dflt; } *stk = NULL; cistpl_cftable_entry_t *cfg; int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0; unsigned long io_base, ctl_base; DEBUG(0, "ide_config(0x%p)\n", link); stk = kzalloc(sizeof(*stk), GFP_KERNEL); if (!stk) goto err_mem; cfg = &stk->parse.cftable_entry; tuple.TupleData = (cisdata_t *)&stk->buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; is_kme = ((link->manf_id == MANFID_KME) && ((link->card_id == PRODID_KME_KXLC005_A) || (link->card_id == PRODID_KME_KXLC005_B))); /* Not sure if this is right... look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); pass = io_base = ctl_base = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry; if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry; /* Check for matching Vcc, unless we're desperate */ if (!pass) { if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) goto next_entry; } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) goto next_entry; } } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) link->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; link->conf.ConfigIndex = cfg->index; link->io.BasePort1 = io->win[0].base; link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; if (io->nwin == 2) { link->io.NumPorts1 = 8; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = (is_kme) ? 2 : 1; if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort2; } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { link->io.NumPorts1 = io->win[0].len; link->io.NumPorts2 = 0; if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort1 + 0x0e; } else goto next_entry; /* If we've got this far, we're done */ break; } next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); if (pass) { CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } else if (pcmcia_get_next_tuple(link, &tuple) != 0) { CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); memset(&stk->dflt, 0, sizeof(stk->dflt)); pass++; } } CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* disable drive interrupts during IDE probe */ outb(0x02, ctl_base); /* special setup for KXLC005 card */ if (is_kme) outb(0x81, ctl_base+1); /* retry registration in case device is still spinning up */ for (hd = -1, i = 0; i < 10; i++) { hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); hd = idecs_register(io_base + 0x10, ctl_base + 0x10, link->irq.AssignedIRQ, link); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; break; } } msleep(100); } if (hd < 0) { printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx" ", irq %u failed\n", io_base, ctl_base, link->irq.AssignedIRQ); goto failed; } info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2)); info->node.major = ide_major[hd]; info->node.minor = 0; info->hd = hd; link->dev_node = &info->node; printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n", info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10); kfree(stk); return 0; err_mem: printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); goto failed; cs_failed: cs_error(link, last_fn, last_ret); failed: kfree(stk); ide_release(link); return -ENODEV; } /* ide_config */
static int ide_config(struct pcmcia_device *link) { ide_info_t *info = link->priv; struct pcmcia_config_check *stk = NULL; int ret = 0, is_kme = 0; unsigned long io_base, ctl_base; struct ide_host *host; dev_dbg(&link->dev, "ide_config(0x%p)\n", link); is_kme = ((link->manf_id == MANFID_KME) && ((link->card_id == PRODID_KME_KXLC005_A) || (link->card_id == PRODID_KME_KXLC005_B))); stk = kzalloc(sizeof(*stk), GFP_KERNEL); if (!stk) goto err_mem; stk->is_kme = is_kme; stk->skip_vcc = io_base = ctl_base = 0; if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) { stk->skip_vcc = 1; if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) goto failed; /* No suitable config found */ } io_base = link->io.BasePort1; ctl_base = stk->ctl_base; ret = pcmcia_request_irq(link, &link->irq); if (ret) goto failed; ret = pcmcia_request_configuration(link, &link->conf); if (ret) goto failed; /* disable drive interrupts during IDE probe */ outb(0x02, ctl_base); /* special setup for KXLC005 card */ if (is_kme) outb(0x81, ctl_base+1); host = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); if (host == NULL && link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); host = idecs_register(io_base + 0x10, ctl_base + 0x10, link->irq.AssignedIRQ, link); } if (host == NULL) goto failed; info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a' + host->ports[0]->index * 2); info->node.major = host->ports[0]->major; info->node.minor = 0; info->host = host; link->dev_node = &info->node; printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n", info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10); kfree(stk); return 0; err_mem: printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); goto failed; failed: kfree(stk); ide_release(link); return -ENODEV; } /* ide_config */
void ide_config(dev_link_t *link) { client_handle_t handle = link->handle; ide_info_t *info = link->priv; tuple_t tuple; u_short buf[128]; cisparse_t parse; config_info_t conf; cistpl_cftable_entry_t *cfg = &parse.cftable_entry; cistpl_cftable_entry_t dflt = { 0 }; int i, pass, last_ret, last_fn, hd, is_kme = 0; unsigned long io_base, ctl_base; DEBUG(0, "ide_config(0x%p)\n", link); tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, handle, &tuple); CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; tuple.DesiredTuple = CISTPL_MANFID; if (!CardServices(GetFirstTuple, handle, &tuple) && !CardServices(GetTupleData, handle, &tuple) && !CardServices(ParseTuple, handle, &tuple, &parse)) is_kme = ((parse.manfid.manf == MANFID_KME) && ((parse.manfid.card == PRODID_KME_KXLC005_A) || (parse.manfid.card == PRODID_KME_KXLC005_B))); /* Configure card */ link->state |= DEV_CONFIG; /* Not sure if this is right... look up the current Vcc */ CS_CHECK(GetConfigurationInfo, handle, &conf); link->conf.Vcc = conf.Vcc; pass = io_base = ctl_base = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; CS_CHECK(GetFirstTuple, handle, &tuple); while (1) { CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); /* Check for matching Vcc, unless we're desperate */ if (!pass) { if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) goto next_entry; } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) { if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) goto next_entry; } } if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->conf.ConfigIndex = cfg->index; link->io.BasePort1 = io->win[0].base; link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; if (io->nwin == 2) { link->io.NumPorts1 = 8; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = (is_kme) ? 2 : 1; CFG_CHECK(RequestIO, link->handle, &link->io); io_base = link->io.BasePort1; ctl_base = link->io.BasePort2; } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { link->io.NumPorts1 = io->win[0].len; link->io.NumPorts2 = 0; CFG_CHECK(RequestIO, link->handle, &link->io); io_base = link->io.BasePort1; ctl_base = link->io.BasePort1+0x0e; } else goto next_entry; /* If we've got this far, we're done */ break; } next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (pass) { CS_CHECK(GetNextTuple, handle, &tuple); } else if (CardServices(GetNextTuple, handle, &tuple) != 0) { CS_CHECK(GetFirstTuple, handle, &tuple); memset(&dflt, 0, sizeof(dflt)); pass++; } } CS_CHECK(RequestIRQ, handle, &link->irq); CS_CHECK(RequestConfiguration, handle, &link->conf); /* deal with brain dead IDE resource management */ release_region(link->io.BasePort1, link->io.NumPorts1); if (link->io.NumPorts2) release_region(link->io.BasePort2, link->io.NumPorts2); /* disable drive interrupts during IDE probe */ outb(0x02, ctl_base); /* special setup for KXLC005 card */ if (is_kme) outb(0x81, ctl_base+1); /* retry registration in case device is still spinning up */ for (hd = -1, i = 0; i < 10; i++) { hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base+0x10); hd = idecs_register(io_base+0x10, ctl_base+0x10, link->irq.AssignedIRQ); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; break; } } __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); } if (hd < 0) { printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx" ", irq %u failed\n", io_base, ctl_base, link->irq.AssignedIRQ); goto failed; } MOD_INC_USE_COUNT; info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2)); info->node.major = ide_major[hd]; info->node.minor = 0; info->hd = hd; link->dev = &info->node; printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10, link->conf.Vpp1/10, link->conf.Vpp1%10); link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: ide_release(link); link->state &= ~DEV_CONFIG_PENDING; } /* ide_config */
static int ide_config(struct pcmcia_device *link) { ide_info_t *info = link->priv; struct pcmcia_config_check *stk = NULL; int last_ret = 0, last_fn = 0, is_kme = 0; unsigned long io_base, ctl_base; struct ide_host *host; DEBUG(0, "ide_config(0x%p)\n", link); is_kme = ((link->manf_id == MANFID_KME) && ((link->card_id == PRODID_KME_KXLC005_A) || (link->card_id == PRODID_KME_KXLC005_B))); stk = kzalloc(sizeof(*stk), GFP_KERNEL); if (!stk) goto err_mem; stk->is_kme = is_kme; stk->skip_vcc = io_base = ctl_base = 0; if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) { stk->skip_vcc = 1; if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) goto failed; } io_base = link->io.BasePort1; ctl_base = stk->ctl_base; CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); outb(0x02, ctl_base); if (is_kme) outb(0x81, ctl_base+1); host = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); if (host == NULL && link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); host = idecs_register(io_base + 0x10, ctl_base + 0x10, link->irq.AssignedIRQ, link); } if (host == NULL) goto failed; info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a' + host->ports[0]->index * 2); info->node.major = host->ports[0]->major; info->node.minor = 0; info->host = host; link->dev_node = &info->node; printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n", info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10); kfree(stk); return 0; err_mem: printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); goto failed; cs_failed: cs_error(link, last_fn, last_ret); failed: kfree(stk); ide_release(link); return -ENODEV; }