diff options
Diffstat (limited to 'drivers/net/wireless/orinoco_cs.c')
| -rw-r--r-- | drivers/net/wireless/orinoco_cs.c | 176 | 
1 files changed, 85 insertions, 91 deletions
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1c216e015f6..473370c9e0d 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -164,23 +164,96 @@ static void orinoco_cs_detach(struct pcmcia_device *link)  		last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \  	} while (0) +struct orinoco_cs_config_data { +	cistpl_cftable_entry_t dflt; +	config_info_t conf; +}; + +static int orinoco_cs_config_check(struct pcmcia_device *p_dev, +				   cistpl_cftable_entry_t *cfg, +				   void *priv_data) +{ +	struct orinoco_cs_config_data *cfg_mem = priv_data; + +	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) +		cfg_mem->dflt = *cfg; +	if (cfg->index == 0) +		goto next_entry; +	p_dev->conf.ConfigIndex = cfg->index; + +	/* 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 (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { +			DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n",  cfg_mem->conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); +			if (!ignore_cis_vcc) +				goto next_entry; +		} +	} else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { +		if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { +			DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n",  cfg_mem->conf.Vcc, cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); +			if (!ignore_cis_vcc) +				goto next_entry; +		} +	} + +	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) +		p_dev->conf.Vpp = +			cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; +	else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) +		p_dev->conf.Vpp = +			cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + +	/* Do we need to allocate an interrupt? */ +	p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + +	/* IO window settings */ +	p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; +	if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { +		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; +		p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; +		if (!(io->flags & CISTPL_IO_8BIT)) +			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; +		if (!(io->flags & CISTPL_IO_16BIT)) +			p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; +		p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; +		p_dev->io.BasePort1 = io->win[0].base; +		p_dev->io.NumPorts1 = io->win[0].len; +		if (io->nwin > 1) { +			p_dev->io.Attributes2 = p_dev->io.Attributes1; +			p_dev->io.BasePort2 = io->win[1].base; +			p_dev->io.NumPorts2 = io->win[1].len; +		} + +		/* This reserves IO space but doesn't actually enable it */ +		if (pcmcia_request_io(p_dev, &p_dev->io) != 0) +			goto next_entry; +	} +	return 0; + +next_entry: +	pcmcia_disable_device(p_dev); +	return -ENODEV; +}; +  static int  orinoco_cs_config(struct pcmcia_device *link)  { +	struct orinoco_cs_config_data *cfg_mem;  	struct net_device *dev = link->priv;  	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; -	tuple_t tuple; -	cisparse_t parse;  	void __iomem *mem; +	cfg_mem = kzalloc(sizeof(struct orinoco_cs_config_data), GFP_KERNEL); +	if (!cfg_mem) +		return -ENOMEM; +  	/* Look up the current Vcc */  	CS_CHECK(GetConfigurationInfo, -		 pcmcia_get_configuration_info(link, &conf)); +		 pcmcia_get_configuration_info(link, &cfg_mem->conf));  	/*  	 * In this loop, we scan the CIS for configuration table @@ -196,94 +269,14 @@ orinoco_cs_config(struct pcmcia_device *link)  	 * and most client drivers will only use the CIS to fill in  	 * implementation-defined details.  	 */ -	tuple.Attributes = 0; -	tuple.TupleData = buf; -	tuple.TupleDataMax = sizeof(buf); -	tuple.TupleOffset = 0; -	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; -	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); -	while (1) { -		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); -		cistpl_cftable_entry_t dflt = { .index = 0 }; - -		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; - -		/* 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, cfg 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, dflt 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.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? */ -		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, &link->io) != 0) -				goto next_entry; -		} - - -		/* If we got this far, we're cool! */ - -		break; -		 -	next_entry: -		pcmcia_disable_device(link); -		last_ret = pcmcia_get_next_tuple(link, &tuple); -		if (last_ret  == CS_NO_MORE_ITEMS) { +	last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, cfg_mem); +	if (last_ret) { +		if (!ignore_cis_vcc)  			printk(KERN_ERR PFX "GetNextTuple(): No matching "  			       "CIS configuration.  Maybe you need the "  			       "ignore_cis_vcc=1 parameter.\n"); -			goto cs_failed; -		} +		cs_error(link, RequestIO, last_ret); +		goto failed;  	}  	/* @@ -334,7 +327,7 @@ orinoco_cs_config(struct pcmcia_device *link)  	       "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,  	       link->irq.AssignedIRQ, link->io.BasePort1,  	       link->io.BasePort1 + link->io.NumPorts1 - 1); - +	kfree(cfg_mem);  	return 0;   cs_failed: @@ -342,6 +335,7 @@ orinoco_cs_config(struct pcmcia_device *link)   failed:  	orinoco_cs_release(link); +	kfree(cfg_mem);  	return -ENODEV;  }				/* orinoco_cs_config */  |