/*---------------------------------------------------------------- * prism2sta_release * * Half of the config/release pair. Usually called in response to * a card ejection event. Checks to make sure no higher layers * are still (or think they are) using the card via the link->open * field. * * NOTE: Don't forget to increment the link->open variable in the * device_open method, and decrement it in the device_close * method. * * Arguments: * arg a generic 32 bit variable. It's the value that * we assigned to link->release.data in sta_attach(). * * Returns: * nothing * * Side effects: * All resources should be released after this function * executes and finds the device !open. * * Call context: * Possibly in a timer context. Don't do anything that'll * block. ----------------------------------------------------------------*/ void prism2sta_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; DBFENTER; /* First thing we should do is get the MSD back to the * HWPRESENT state. I.e. everything quiescent. */ prism2sta_ifstate(link->priv, P80211ENUM_ifstate_disable); if (link->open) { /* TODO: I don't think we're even using this bit of code * and I don't think it's hurting us at the moment. */ WLAN_LOG_DEBUG(1, "prism2sta_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); DBFEXIT; }
static void sl811_cs_release(dev_link_t * link) { DBG(0, "sl811_cs_release(0x%p)\n", link); if (link->open) { DBG(1, "sl811_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } /* Unlink the device chain */ link->dev = NULL; platform_device_unregister(&platform_dev); pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) sl811_cs_detach(link); }
void ide_release(dev_link_t *link) { ide_info_t *info = link->priv; DEBUG(0, "ide_release(0x%p)\n", link); if (info->ndev) { /* FIXME: if this fails we need to queue the cleanup somehow -- need to investigate the required PCMCIA magic */ ide_unregister(info->hd); /* deal with brain dead IDE resource management */ request_region(link->io.BasePort1, link->io.NumPorts1, info->node.dev_name); if (link->io.NumPorts2) request_region(link->io.BasePort2, link->io.NumPorts2, info->node.dev_name); } info->ndev = 0; link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } /* ide_release */
static void serial_remove(dev_link_t *link) { struct serial_info *info = link->priv; int i; link->state &= ~DEV_PRESENT; DEBUG(0, "serial_release(0x%p)\n", link); /* * Recheck to see if the device is still configured. */ if (info->link.state & DEV_CONFIG) { for (i = 0; i < info->ndev; i++) serial8250_unregister_port(info->line[i]); info->link.dev = NULL; if (!info->slave) { pcmcia_release_configuration(info->link.handle); pcmcia_release_io(info->link.handle, &info->link.io); pcmcia_release_irq(info->link.handle, &info->link.irq); } info->link.state &= ~DEV_CONFIG; } }
static void vxpocket_release(dev_link_t *link) { if (link->state & DEV_CONFIG) { /* release cs resources */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } }
static void prism2_cs_remove(struct pcmcia_device *pdev) { struct wlandevice *wlandev; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) dev_link_t *link = dev_to_instance(pdev); #endif DBFENTER; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) wlandev = pdev->priv; #else wlandev = link->priv; #endif if (wlandev) { p80211netdev_hwremoved(wlandev); unregister_wlandev(wlandev); wlan_unsetup(wlandev); if (wlandev->priv) { hfa384x_t *hw = wlandev->priv; wlandev->priv = NULL; if (hw) { hfa384x_destroy(hw); kfree(hw); } } kfree(wlandev); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->priv = NULL; pcmcia_disable_device(pdev); #else if (link->state & DEV_CONFIG) { if (link->win) pcmcia_release_window(link->win); pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } link->priv = NULL; kfree(link); #endif DBFEXIT; return; }
/* ---------------------------------------------------------------------------- nmclan_release After a card is removed, nmclan_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 nmclan_release(dev_link_t *link) { DEBUG(0, "nmclan_release(0x%p)\n", link); pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; }
static void pdacf_config(dev_link_t *link) { client_handle_t handle = link->handle; struct snd_pdacf *pdacf = link->priv; tuple_t tuple; cisparse_t *parse = NULL; config_info_t conf; u_short buf[32]; int last_fn, last_ret; snd_printdd(KERN_DEBUG "pdacf_config called\n"); parse = kmalloc(sizeof(*parse), GFP_KERNEL); if (! parse) { snd_printk(KERN_ERR "pdacf_config: cannot allocate\n"); return; } tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse)); link->conf.ConfigBase = parse->config.base; link->conf.ConfigIndex = 0x5; kfree(parse); CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* Configure card */ link->state |= DEV_CONFIG; CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; link->dev = &pdacf->node; link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); }
static void aha152x_release_cs(dev_link_t *link) { scsi_info_t *info = link->priv; aha152x_release(info->host); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; }
static void vxpocket_release(dev_link_t *link) { if (link->state & DEV_CONFIG) { /* release cs resources */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } if (link->handle) { /* Break the link with Card Services */ pcmcia_deregister_client(link->handle); link->handle = NULL; } }
static void btuart_release(dev_link_t *link) { btuart_info_t *info = link->priv; if (link->state & DEV_PRESENT) btuart_close(info); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; }
static void bluecard_release(dev_link_t *link) { bluecard_info_t *info = link->priv; if (link->state & DEV_PRESENT) bluecard_close(info); del_timer(&(info->timer)); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; }
static void avmcs_release(dev_link_t *link) { b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); /* Unlink the device chain */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) avmcs_detach(link); } /* avmcs_release */
static void fdomain_release(dev_link_t *link) { scsi_info_t *info = link->priv; DEBUG(0, "fdomain_release(0x%p)\n", link); scsi_remove_host(info->host); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); scsi_unregister(info->host); link->state &= ~DEV_CONFIG; }
static void qlogic_release(dev_link_t *link) { scsi_info_t *info = link->priv; DEBUG(0, "qlogic_release(0x%p)\n", link); scsi_remove_host(info->host); link->dev = NULL; free_irq(link->irq.AssignedIRQ, info->host); pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); scsi_host_put(info->host); link->state &= ~DEV_CONFIG; }
static void atmel_release(dev_link_t *link) { struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; DEBUG(0, "atmel_release(0x%p)\n", link); /* Unlink the device chain */ link->dev = NULL; if (dev) stop_atmel_card(dev); ((local_info_t*)link->priv)->eth_dev = NULL; /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; }
void ide_release(dev_link_t *link) { ide_info_t *info = link->priv; DEBUG(0, "ide_release(0x%p)\n", link); if (info->ndev) { /* FIXME: if this fails we need to queue the cleanup somehow -- need to investigate the required PCMCIA magic */ ide_unregister(info->hd); } info->ndev = 0; link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } /* ide_release */
static void airo_release(dev_link_t *link) { DEBUG(0, "airo_release(0x%p)\n", link); /* Unlink the device chain */ link->dev = NULL; /* In a normal driver, additional code may be needed to release other kernel data structures associated with this device. */ /* Don't bother checking to see if these succeed or not */ if (link->win) pcmcia_release_window(link->win); pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; }
static void elsa_cs_release(dev_link_t *link) { local_info_t *local = link->priv; DEBUG(0, "elsa_cs_release(0x%p)\n", link); if (local) { if (local->cardnr >= 0) { /* no unregister function with hisax */ HiSax_closecard(local->cardnr); } } /* Unlink the device chain */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ if (link->win) pcmcia_release_window(link->win); pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } /* elsa_cs_release */
static void qlogic_config(dev_link_t * link) { client_handle_t handle = link->handle; scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; int i, last_ret, last_fn; unsigned short tuple_data[32]; struct Scsi_Host *host; DEBUG(0, "qlogic_config(0x%p)\n", link); tuple.TupleData = (cisdata_t *) tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; tuple.DesiredTuple = CISTPL_MANFID; if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) info->manf_id = le16_to_cpu(tuple.TupleData[0]); /* Configure card */ link->state |= DEV_CONFIG; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { if (pcmcia_get_tuple_data(handle, &tuple) != 0 || pcmcia_parse_tuple(handle, &tuple, &parse) != 0) goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; if (link->io.BasePort1 != 0) { i = pcmcia_request_io(handle, &link->io); if (i == CS_SUCCESS) break; } next_entry: CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { /* set ATAcmd */ outb(0xb4, link->io.BasePort1 + 0xd); outb(0x24, link->io.BasePort1 + 0x9); outb(0x04, link->io.BasePort1 + 0xd); } /* The KXL-810AN has a bigger IO port window */ if (link->io.NumPorts1 == 32) host = qlogic_detect(&qlogicfas_driver_template, link, link->io.BasePort1 + 16, link->irq.AssignedIRQ); else host = qlogic_detect(&qlogicfas_driver_template, link, link->io.BasePort1, link->irq.AssignedIRQ); if (!host) { printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); goto out; } sprintf(info->node.dev_name, "scsi%d", host->host_no); link->dev = &info->node; info->host = host; out: link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; return; } /* qlogic_config */
static void avmcs_config(dev_link_t *link) { client_handle_t handle; tuple_t tuple; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; local_info_t *dev; int i; u_char buf[64]; char devname[128]; int cardtype; int (*addcard)(unsigned int port, unsigned irq); handle = link->handle; dev = link->priv; /* This reads the card's CONFIG tuple to find its configuration registers. */ do { tuple.DesiredTuple = CISTPL_CONFIG; i = pcmcia_get_first_tuple(handle, &tuple); if (i != CS_SUCCESS) break; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; i = pcmcia_get_tuple_data(handle, &tuple); if (i != CS_SUCCESS) break; i = pcmcia_parse_tuple(handle, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); if (i != CS_SUCCESS) { cs_error(link->handle, ParseTuple, i); link->state &= ~DEV_CONFIG_PENDING; return; } /* Configure card */ link->state |= DEV_CONFIG; do { tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = 254; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_VERS_1; devname[0] = 0; if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], sizeof(devname)); } /* * find IO port */ tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; i = first_tuple(handle, &tuple, &parse); while (i == CS_SUCCESS) { if (cf->io.nwin > 0) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.NumPorts1 = cf->io.win[0].len; link->io.NumPorts2 = 0; printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } i = next_tuple(handle, &tuple, &parse); } found_port: if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); break; } /* * allocate an interrupt line */ i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); pcmcia_release_io(link->handle, &link->io); break; } /* * configure the PCMCIA socket */ i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); break; } } while (0); /* At this point, the dev_node_t structure(s) should be initialized and arranged in a linked list at link->dev. */ if (devname[0]) { char *s = strrchr(devname, ' '); if (!s) s = devname; else s++; strcpy(dev->node.dev_name, s); if (strcmp("M1", s) == 0) { cardtype = AVM_CARDTYPE_M1; } else if (strcmp("M2", s) == 0) { cardtype = AVM_CARDTYPE_M2; } else { cardtype = AVM_CARDTYPE_B1; } } else { strcpy(dev->node.dev_name, "b1"); cardtype = AVM_CARDTYPE_B1; } dev->node.major = 64; dev->node.minor = 0; link->dev = &dev->node; link->state &= ~DEV_CONFIG_PENDING; /* If any step failed, release any partially configured state */ if (i != 0) { avmcs_release(link); return; } switch (cardtype) { case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; default: case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; } if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) { printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); avmcs_release(link); return; } dev->node.minor = i; } /* avmcs_config */
static void orinoco_cs_config(dev_link_t *link) { struct net_device *dev = link->priv; client_handle_t handle = link->handle; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; u_char buf[64]; config_info_t conf; cisinfo_t info; tuple_t tuple; cisparse_t parse; void __iomem *mem; CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info)); /* * This reads the card's CONFIG tuple to find its * configuration registers. */ tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; /* * In this loop, we scan the CIS for configuration table * entries, each of which describes a valid card * configuration, including voltage, IO window, memory window, * and interrupt settings. * * We make no assumptions about the card to be configured: we * use just the information available in the CIS. In an ideal * world, this would work for any PCMCIA card, but it requires * a complete and accurate CIS. In practice, a driver usually * "knows" most of these things without consulting the CIS, * and most client drivers will only use the CIS to fill in * implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_cftable_entry_t dflt = { .index = 0 }; if ( (pcmcia_get_tuple_data(handle, &tuple) != 0) || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0)) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto next_entry; link->conf.ConfigIndex = cfg->index; /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); if(!ignore_cis_vcc) 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; /* Do we need to allocate an interrupt? */ link->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ link->io.NumPorts1 = link->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { link->io.Attributes2 = link->io.Attributes1; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } /* This reserves IO space but doesn't actually enable it */ if (pcmcia_request_io(link->handle, &link->io) != 0) goto next_entry; } /* If we got this far, we're cool! */ break; next_entry: if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); last_ret = pcmcia_get_next_tuple(handle, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); goto cs_failed; } } /* * Allocate an interrupt line. Note that this does not assign * a handler to the interrupt, unless the 'Handler' member of * the irq structure is initialized. */ CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); /* We initialize the hermes structure before completing PCMCIA * configuration just in case the interrupt handler gets * called. */ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); if (!mem) goto cs_failed; hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; dev->irq = link->irq.AssignedIRQ; SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; SET_NETDEV_DEV(dev, &handle_to_dev(handle)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR PFX "register_netdev() failed\n"); goto failed; } /* At this point, the dev_node_t structure(s) needs to be * initialized and arranged in a linked list at link->dev. */ strcpy(card->node.dev_name, dev->name); link->dev = &card->node; /* link->dev being non-NULL is also used to indicate that the net_device has been registered */ link->state &= ~DEV_CONFIG_PENDING; /* Finally, report what we've done */ printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d", dev->name, link->conf.ConfigIndex, link->conf.Vcc / 10, link->conf.Vcc % 10); if (link->conf.Vpp1) printk(", Vpp %d.%d", link->conf.Vpp1 / 10, link->conf.Vpp1 % 10); printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); if (link->io.NumPorts2) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2 + link->io.NumPorts2 - 1); printk("\n"); return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: orinoco_cs_release(link); } /* orinoco_cs_config */ /* * After a card is removed, orinoco_cs_release() will unregister the * device, and release the PCMCIA configuration. If the device is * still open, this will be postponed until it is closed. */ static void orinoco_cs_release(dev_link_t *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; /* We're committed to taking the device away now, so mark the * hardware as unavailable */ spin_lock_irqsave(&priv->lock, flags); priv->hw_unavailable++; spin_unlock_irqrestore(&priv->lock, flags); /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (priv->hw.iobase) ioport_unmap(priv->hw.iobase); } /* orinoco_cs_release */ /* * The card status event handler. Mostly, this schedules other stuff * to run after an event is received. */ static int orinoco_cs_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 orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; unsigned long flags; switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { unsigned long flags; spin_lock_irqsave(&priv->lock, flags); netif_device_detach(dev); priv->hw_unavailable++; spin_unlock_irqrestore(&priv->lock, flags); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; orinoco_cs_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ if (link->state & DEV_CONFIG) { /* This is probably racy, but I can't think of a better way, short of rewriting the PCMCIA layer to not suck :-( */ if (! test_bit(0, &card->hard_reset_in_progress)) { spin_lock_irqsave(&priv->lock, flags); err = __orinoco_down(dev); if (err) printk(KERN_WARNING "%s: %s: Error %d downing interface\n", dev->name, event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", err); netif_device_detach(dev); priv->hw_unavailable++; spin_unlock_irqrestore(&priv->lock, flags); } 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) { /* FIXME: should we double check that this is * the same card as we had before */ pcmcia_request_configuration(link->handle, &link->conf); if (! test_bit(0, &card->hard_reset_in_progress)) { err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware\n", dev->name, err); break; } spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); priv->hw_unavailable--; if (priv->open && ! priv->hw_unavailable) { err = __orinoco_up(dev); if (err) printk(KERN_ERR "%s: Error %d restarting card\n", dev->name, err); } spin_unlock_irqrestore(&priv->lock, flags); } } break; } return err; } /* orinoco_cs_event */
static void vxpocket_config(dev_link_t *link) { client_handle_t handle = link->handle; struct vx_core *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; tuple_t tuple; cisparse_t *parse; u_short buf[32]; int last_fn, last_ret; snd_printdd(KERN_DEBUG "vxpocket_config called\n"); parse = kmalloc(sizeof(*parse), GFP_KERNEL); if (! parse) { snd_printk(KERN_ERR "vx: cannot allocate\n"); return; } tuple.Attributes = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse)); link->conf.ConfigBase = parse->config.base; link->conf.Present = parse->config.rmask[0]; /* redefine hardware record according to the VERSION1 string */ tuple.DesiredTuple = CISTPL_VERS_1; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse)); if (! strcmp(parse->version_1.str + parse->version_1.ofs[1], "VX-POCKET")) { snd_printdd("VX-pocket is detected\n"); } else { snd_printdd("VX-pocket 440 is detected\n"); /* overwrite the hardware information */ chip->hw = &vxp440_hw; chip->type = vxp440_hw.type; strcpy(chip->card->driver, vxp440_hw.name); } /* Configure card */ link->state |= DEV_CONFIG; CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); chip->dev = &handle_to_dev(link->handle); snd_card_set_dev(chip->card, chip->dev); if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; link->dev = &vxp->node; link->state &= ~DEV_CONFIG_PENDING; kfree(parse); return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; kfree(parse); }