static void atmel_detach(dev_link_t *link) { dev_link_t **linkp; DEBUG(0, "atmel_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) atmel_release(link); /* Break the link with Card Services */ if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; if (link->priv) kfree(link->priv); kfree(link); }
static void atmel_detach(struct pcmcia_device *link) { DEBUG(0, "atmel_detach(0x%p)\n", link); atmel_release(link); kfree(link->priv); }
static void atmel_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "atmel_detach\n"); atmel_release(link); kfree(link->priv); }
static int atmel_config(struct pcmcia_device *link) { local_info_t *dev; int ret; struct pcmcia_device_id *did; dev = link->priv; did = dev_get_drvdata(&link->dev); dev_dbg(&link->dev, "atmel_config\n"); /* 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. */ if (pcmcia_loop_config(link, atmel_config_check, NULL)) goto failed; if (!link->irq) { dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); goto failed; } /* 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. */ ret = pcmcia_request_configuration(link, &link->conf); if (ret) goto failed; ((local_info_t*)link->priv)->eth_dev = init_atmel_card(link->irq, link->io.BasePort1, did ? did->driver_info : ATMEL_FW_TYPE_NONE, &link->dev, card_present, link); if (!((local_info_t*)link->priv)->eth_dev) goto failed; return 0; failed: atmel_release(link); return -ENODEV; }
static void atmel_cs_cleanup(void) { pcmcia_unregister_driver(&atmel_driver); /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) atmel_release(dev_list); atmel_detach(dev_list); } }
static int atmel_config(struct pcmcia_device *link) { local_info_t *dev; int last_fn, last_ret; struct pcmcia_device_id *did; dev = link->priv; did = dev_get_drvdata(&handle_to_dev(link)); DEBUG(0, "atmel_config(0x%p)\n", link); if (pcmcia_loop_config(link, atmel_config_check, NULL)) goto failed; if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); if (link->irq.AssignedIRQ == 0) { printk(KERN_ALERT "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); goto cs_failed; } ((local_info_t*)link->priv)->eth_dev = init_atmel_card(link->irq.AssignedIRQ, link->io.BasePort1, did ? did->driver_info : ATMEL_FW_TYPE_NONE, &handle_to_dev(link), card_present, link); if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); dev->node.major = dev->node.minor = 0; link->dev_node = &dev->node; return 0; cs_failed: cs_error(link, last_fn, last_ret); failed: atmel_release(link); return -ENODEV; }
static int atmel_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; local_info_t *local = link->priv; DEBUG(1, "atmel_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_device_detach(local->eth_dev); atmel_release(link); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; atmel_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { netif_device_detach(local->eth_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) { pcmcia_request_configuration(link->handle, &link->conf); atmel_open(local->eth_dev); netif_device_attach(local->eth_dev); } break; } return 0; } /* atmel_event */
static int atmel_config(struct pcmcia_device *link) { tuple_t tuple; cisparse_t parse; local_info_t *dev; int last_fn, last_ret; u_char buf[64]; struct pcmcia_device_id *did; dev = link->priv; did = handle_to_dev(link).driver_data; DEBUG(0, "atmel_config(0x%p)\n", link); tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; /* This reads the card's CONFIG tuple to find its configuration registers. */ tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* 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(link, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); if (pcmcia_get_tuple_data(link, &tuple) != 0 || pcmcia_parse_tuple(link, &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->vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; /* Do we need to allocate an interrupt? */ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) 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.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, &link->io) != 0) goto next_entry; /* If we got this far, we're cool! */ break; next_entry: CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } /* 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. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* 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, &link->conf)); if (link->irq.AssignedIRQ == 0) { printk(KERN_ALERT "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); goto cs_failed; } ((local_info_t*)link->priv)->eth_dev = init_atmel_card(link->irq.AssignedIRQ, link->io.BasePort1, did ? did->driver_info : ATMEL_FW_TYPE_NONE, &handle_to_dev(link), card_present, link); if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; /* At this point, the dev_node_t structure(s) need to be initialized and arranged in a linked list at link->dev_node. */ strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); dev->node.major = dev->node.minor = 0; link->dev_node = &dev->node; return 0; cs_failed: cs_error(link, last_fn, last_ret); atmel_release(link); return -ENODEV; }
static void atmel_config(dev_link_t *link) { client_handle_t handle; tuple_t tuple; cisparse_t parse; local_info_t *dev; int last_fn, last_ret; u_char buf[64]; int card_index = -1, done = 0; handle = link->handle; dev = link->priv; DEBUG(0, "atmel_config(0x%p)\n", link); tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_MANFID; if (CardServices(GetFirstTuple, handle, &tuple) == 0) { int i; cistpl_manfid_t *manfid; CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); manfid = &(parse.manfid); for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { if (!card_table[i].ver1 && manfid->manf == card_table[i].manf && manfid->card == card_table[i].card) { card_index = i; done = 1; } } } tuple.DesiredTuple = CISTPL_VERS_1; if (!done && (CardServices(GetFirstTuple, handle, &tuple) == 0)) { int i, j, k; cistpl_vers_1_t *ver1; CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); ver1 = &(parse.version_1); for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { for (j = 0; j < ver1->ns; j++) { char *p = card_table[i].ver1; char *q = &ver1->str[ver1->ofs[j]]; if (!p) goto mismatch; for (k = 0; k < j; k++) { while ((*p != '\0') && (*p != '/')) p++; if (*p == '\0') { if (*q != '\0') goto mismatch; } else { p++; } } while((*q != '\0') && (*p != '\0') && (*p != '/') && (*p == *q)) p++, q++; if (((*p != '\0') && *p != '/') || *q != '\0') goto mismatch; } card_index = i; break; /* done */ mismatch: j = 0; /* dummy stmt to shut up compiler */ } } /* This reads the card's CONFIG tuple to find its configuration registers. */ 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]; /* Configure card */ link->state |= DEV_CONFIG; /* 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, handle, &tuple); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); 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)) link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; 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? */ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) 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.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 */ CFG_CHECK(RequestIO, link->handle, &link->io); /* If we got this far, we're cool! */ break; next_entry: CS_CHECK(GetNextTuple, handle, &tuple); } /* 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. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, link->handle, &link->irq); /* 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, link->handle, &link->conf); if (link->irq.AssignedIRQ == 0) { printk(KERN_ALERT "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); goto cs_failed; } ((local_info_t*)link->priv)->eth_dev = init_atmel_card(link->irq.AssignedIRQ, link->io.BasePort1, card_index == -1 ? NULL : card_table[card_index].firmware, card_index == -1 ? 0 : (card_table[card_index].manf == MANFID_3COM), &atmel_device, card_present, link); if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; /* At this point, the dev_node_t structure(s) need to be initialized and arranged in a linked list at link->dev. */ strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); dev->node.major = dev->node.minor = 0; link->dev = &dev->node; /* Finally, report what we've done */ printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d", dev->node.dev_name, card_index == -1 ? "" : card_table[card_index].name, card_index == -1 ? "" : " ", 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); if (link->conf.Attributes & CONF_ENABLE_IRQ) 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"); link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); atmel_release(link); }