static dldwd_priv_t* airport_attach(struct device_node* of_node) { dldwd_priv_t *priv; struct net_device *ndev; dldwd_card_t* card; hermes_t *hw; TRACE_ENTER("dldwd"); if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); return NULL; } /* Allocate space for private device-specific data */ card = kmalloc(sizeof(*card), GFP_KERNEL); if (!card) { printk(KERN_ERR "airport: can't allocate device datas\n"); return NULL; } memset(card, 0, sizeof(*card)); priv = &(card->priv); priv->card = card; ndev = &priv->ndev; hw = &priv->hw; card->node = of_node; /* Setup the common part */ if (dldwd_setup(priv) < 0) { kfree(card); return NULL; } /* Overrides */ ndev->init = airport_init; ndev->open = airport_open; ndev->stop = airport_stop; /* Setup interrupts & base address */ ndev->irq = of_node->intrs[0].line; ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE; hermes_struct_init(hw, ndev->base_addr); /* Power up card */ feature_set_airport_power(card->node, 1); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); /* Reset it before we get the interrupt */ hermes_reset(hw); if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) { printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq); goto failed; } card->irq_requested = 1; /* register_netdev will give us an ethX name */ ndev->name[0] = '\0'; /* Tell the stack we exist */ if (register_netdev(ndev) != 0) { printk(KERN_ERR "airport: register_netdev() failed\n"); goto failed; } printk(KERN_DEBUG "airport: card registered for interface %s\n", ndev->name); card->ndev_registered = 1; SET_MODULE_OWNER(ndev); /* And give us the proc nodes for debugging */ if (dldwd_proc_dev_init(priv) != 0) printk(KERN_ERR "airport: Failed to create /proc node for %s\n", ndev->name); #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&airport_sleep_notifier); #endif return priv; failed: airport_detach(priv); return NULL; } /* airport_attach */
static void dldwd_cs_config(dev_link_t * link) { client_handle_t handle = link->handle; dldwd_priv_t *priv = link->priv; dldwd_card_t *card = (dldwd_card_t *)priv->card; hermes_t *hw = &priv->hw; struct net_device *ndev = &priv->ndev; tuple_t tuple; cisparse_t parse; int last_fn, last_ret; u_char buf[64]; config_info_t conf; cistpl_cftable_entry_t dflt = { 0 }; cisinfo_t info; TRACE_ENTER("dldwd"); CS_CHECK(ValidateCIS, 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, 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; /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, handle, &conf); link->conf.Vcc = conf.Vcc; DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", link->conf.ConfigBase, link->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, handle, &tuple); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n", cfg->index, cfg->flags); 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, "dldwd_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, "dldwd_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; DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n"); /* 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.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 */ CFG_CHECK(RequestIO, link->handle, &link->io); } /* If we got this far, we're cool! */ break; next_entry: if (link->io.NumPorts1) CardServices(ReleaseIO, link->handle, &link->io); 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) { int i; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i=0; i<4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = dldwd_interrupt; link->irq.Instance = priv; CS_CHECK(RequestIRQ, link->handle, &link->irq); } /* We initialize the hermes structure before completing PCMCIA configuration just in case the interrupt handler gets called. */ hermes_struct_init(hw, link->io.BasePort1); /* 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); ndev->base_addr = link->io.BasePort1; ndev->irq = link->irq.AssignedIRQ; /* register_netdev will give us an ethX name */ ndev->name[0] = '\0'; /* Tell the stack we exist */ if (register_netdev(ndev) != 0) { printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); goto failed; } strcpy(card->node.dev_name, ndev->name); /* Finally, report what we've done */ printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d", ndev->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); 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"); /* And give us the proc nodes for debugging */ if (dldwd_proc_dev_init(priv) != 0) { printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", ndev->name); goto failed; } /* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */ SET_MODULE_OWNER(ndev); /* Allow cor_reset, /proc & ioctls to act */ priv->hw_ready = 1; /* Do a Pcmcia soft reset of the card (optional) */ if(reset_cor) dldwd_cs_cor_reset(priv); /* At this point, the dev_node_t structure(s) need to be initialized and arranged in a linked list at link->dev. */ card->node.major = card->node.minor = 0; link->dev = &card->node; link->state &= ~DEV_CONFIG_PENDING; TRACE_EXIT("dldwd"); return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: dldwd_cs_release((u_long) link); TRACE_EXIT("dldwd"); } /* dldwd_cs_config */