diff options
Diffstat (limited to 'drivers/net/wireless/airo_cs.c')
-rw-r--r-- | drivers/net/wireless/airo_cs.c | 230 |
1 files changed, 119 insertions, 111 deletions
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index f12355398fe7..4fbe811bebfc 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c | |||
@@ -206,126 +206,131 @@ static void airo_detach(struct pcmcia_device *link) | |||
206 | #define CS_CHECK(fn, ret) \ | 206 | #define CS_CHECK(fn, ret) \ |
207 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | 207 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) |
208 | 208 | ||
209 | struct airo_cs_config_data { | ||
210 | cistpl_cftable_entry_t dflt; | ||
211 | win_req_t req; | ||
212 | }; | ||
213 | |||
214 | static int airo_cs_config_check(struct pcmcia_device *p_dev, | ||
215 | cistpl_cftable_entry_t *cfg, | ||
216 | void *priv_data) | ||
217 | { | ||
218 | struct airo_cs_config_data *cfg_mem = priv_data; | ||
219 | |||
220 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
221 | cfg_mem->dflt = *cfg; | ||
222 | |||
223 | if (cfg->index == 0) | ||
224 | return -ENODEV; | ||
225 | |||
226 | p_dev->conf.ConfigIndex = cfg->index; | ||
227 | |||
228 | /* Does this card need audio output? */ | ||
229 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
230 | p_dev->conf.Attributes |= CONF_ENABLE_SPKR; | ||
231 | p_dev->conf.Status = CCSR_AUDIO_ENA; | ||
232 | } | ||
233 | |||
234 | /* Use power settings for Vcc and Vpp if present */ | ||
235 | /* Note that the CIS values need to be rescaled */ | ||
236 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
237 | p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
238 | else if (cfg_mem->dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
239 | p_dev->conf.Vpp = cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
240 | |||
241 | /* Do we need to allocate an interrupt? */ | ||
242 | if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1) | ||
243 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; | ||
244 | |||
245 | /* IO window settings */ | ||
246 | p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; | ||
247 | if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { | ||
248 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; | ||
249 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
250 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
251 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
252 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
253 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
254 | p_dev->io.BasePort1 = io->win[0].base; | ||
255 | p_dev->io.NumPorts1 = io->win[0].len; | ||
256 | if (io->nwin > 1) { | ||
257 | p_dev->io.Attributes2 = p_dev->io.Attributes1; | ||
258 | p_dev->io.BasePort2 = io->win[1].base; | ||
259 | p_dev->io.NumPorts2 = io->win[1].len; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | /* This reserves IO space but doesn't actually enable it */ | ||
264 | if (pcmcia_request_io(p_dev, &p_dev->io) != 0) | ||
265 | return -ENODEV; | ||
266 | |||
267 | /* | ||
268 | Now set up a common memory window, if needed. There is room | ||
269 | in the struct pcmcia_device structure for one memory window handle, | ||
270 | but if the base addresses need to be saved, or if multiple | ||
271 | windows are needed, the info should go in the private data | ||
272 | structure for this device. | ||
273 | |||
274 | Note that the memory window base is a physical address, and | ||
275 | needs to be mapped to virtual space with ioremap() before it | ||
276 | is used. | ||
277 | */ | ||
278 | if ((cfg->mem.nwin > 0) || (cfg_mem->dflt.mem.nwin > 0)) { | ||
279 | cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &cfg_mem->dflt.mem; | ||
280 | memreq_t map; | ||
281 | cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; | ||
282 | cfg_mem->req.Base = mem->win[0].host_addr; | ||
283 | cfg_mem->req.Size = mem->win[0].len; | ||
284 | cfg_mem->req.AccessSpeed = 0; | ||
285 | if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0) | ||
286 | return -ENODEV; | ||
287 | map.Page = 0; | ||
288 | map.CardOffset = mem->win[0].card_addr; | ||
289 | if (pcmcia_map_mem_page(p_dev->win, &map) != 0) | ||
290 | return -ENODEV; | ||
291 | } | ||
292 | /* If we got this far, we're cool! */ | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | |||
209 | static int airo_config(struct pcmcia_device *link) | 297 | static int airo_config(struct pcmcia_device *link) |
210 | { | 298 | { |
211 | tuple_t tuple; | ||
212 | cisparse_t parse; | ||
213 | local_info_t *dev; | 299 | local_info_t *dev; |
300 | struct airo_cs_config_data *cfg_mem; | ||
214 | int last_fn, last_ret; | 301 | int last_fn, last_ret; |
215 | u_char buf[64]; | ||
216 | win_req_t req; | ||
217 | memreq_t map; | ||
218 | 302 | ||
219 | dev = link->priv; | 303 | dev = link->priv; |
220 | 304 | ||
221 | DEBUG(0, "airo_config(0x%p)\n", link); | 305 | DEBUG(0, "airo_config(0x%p)\n", link); |
222 | 306 | ||
307 | cfg_mem = kzalloc(sizeof(struct airo_cs_config_data), GFP_KERNEL); | ||
308 | if (!cfg_mem) | ||
309 | return -ENOMEM; | ||
310 | |||
223 | /* | 311 | /* |
224 | In this loop, we scan the CIS for configuration table entries, | 312 | * In this loop, we scan the CIS for configuration table |
225 | each of which describes a valid card configuration, including | 313 | * entries, each of which describes a valid card |
226 | voltage, IO window, memory window, and interrupt settings. | 314 | * configuration, including voltage, IO window, memory window, |
227 | 315 | * and interrupt settings. | |
228 | We make no assumptions about the card to be configured: we use | 316 | * |
229 | just the information available in the CIS. In an ideal world, | 317 | * We make no assumptions about the card to be configured: we |
230 | this would work for any PCMCIA card, but it requires a complete | 318 | * use just the information available in the CIS. In an ideal |
231 | and accurate CIS. In practice, a driver usually "knows" most of | 319 | * world, this would work for any PCMCIA card, but it requires |
232 | these things without consulting the CIS, and most client drivers | 320 | * a complete and accurate CIS. In practice, a driver usually |
233 | will only use the CIS to fill in implementation-defined details. | 321 | * "knows" most of these things without consulting the CIS, |
322 | * and most client drivers will only use the CIS to fill in | ||
323 | * implementation-defined details. | ||
324 | */ | ||
325 | last_ret = pcmcia_loop_config(link, airo_cs_config_check, cfg_mem); | ||
326 | if (last_ret) | ||
327 | goto failed; | ||
328 | |||
329 | /* | ||
330 | Allocate an interrupt line. Note that this does not assign a | ||
331 | handler to the interrupt, unless the 'Handler' member of the | ||
332 | irq structure is initialized. | ||
234 | */ | 333 | */ |
235 | tuple.Attributes = 0; | ||
236 | tuple.TupleData = buf; | ||
237 | tuple.TupleDataMax = sizeof(buf); | ||
238 | tuple.TupleOffset = 0; | ||
239 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
240 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
241 | while (1) { | ||
242 | cistpl_cftable_entry_t dflt = { 0 }; | ||
243 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
244 | if (pcmcia_get_tuple_data(link, &tuple) != 0 || | ||
245 | pcmcia_parse_tuple(link, &tuple, &parse) != 0) | ||
246 | goto next_entry; | ||
247 | |||
248 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; | ||
249 | if (cfg->index == 0) goto next_entry; | ||
250 | link->conf.ConfigIndex = cfg->index; | ||
251 | |||
252 | /* Does this card need audio output? */ | ||
253 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
254 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
255 | link->conf.Status = CCSR_AUDIO_ENA; | ||
256 | } | ||
257 | |||
258 | /* Use power settings for Vcc and Vpp if present */ | ||
259 | /* Note that the CIS values need to be rescaled */ | ||
260 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
261 | link->conf.Vpp = | ||
262 | cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
263 | else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
264 | link->conf.Vpp = | ||
265 | dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
266 | |||
267 | /* Do we need to allocate an interrupt? */ | ||
268 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
269 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
270 | |||
271 | /* IO window settings */ | ||
272 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
273 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
274 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
275 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
276 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
277 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
278 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
279 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
280 | link->io.BasePort1 = io->win[0].base; | ||
281 | link->io.NumPorts1 = io->win[0].len; | ||
282 | if (io->nwin > 1) { | ||
283 | link->io.Attributes2 = link->io.Attributes1; | ||
284 | link->io.BasePort2 = io->win[1].base; | ||
285 | link->io.NumPorts2 = io->win[1].len; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* This reserves IO space but doesn't actually enable it */ | ||
290 | if (pcmcia_request_io(link, &link->io) != 0) | ||
291 | goto next_entry; | ||
292 | |||
293 | /* | ||
294 | Now set up a common memory window, if needed. There is room | ||
295 | in the struct pcmcia_device structure for one memory window handle, | ||
296 | but if the base addresses need to be saved, or if multiple | ||
297 | windows are needed, the info should go in the private data | ||
298 | structure for this device. | ||
299 | |||
300 | Note that the memory window base is a physical address, and | ||
301 | needs to be mapped to virtual space with ioremap() before it | ||
302 | is used. | ||
303 | */ | ||
304 | if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { | ||
305 | cistpl_mem_t *mem = | ||
306 | (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; | ||
307 | req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; | ||
308 | req.Base = mem->win[0].host_addr; | ||
309 | req.Size = mem->win[0].len; | ||
310 | req.AccessSpeed = 0; | ||
311 | if (pcmcia_request_window(&link, &req, &link->win) != 0) | ||
312 | goto next_entry; | ||
313 | map.Page = 0; map.CardOffset = mem->win[0].card_addr; | ||
314 | if (pcmcia_map_mem_page(link->win, &map) != 0) | ||
315 | goto next_entry; | ||
316 | } | ||
317 | /* If we got this far, we're cool! */ | ||
318 | break; | ||
319 | |||
320 | next_entry: | ||
321 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | Allocate an interrupt line. Note that this does not assign a | ||
326 | handler to the interrupt, unless the 'Handler' member of the | ||
327 | irq structure is initialized. | ||
328 | */ | ||
329 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | 334 | if (link->conf.Attributes & CONF_ENABLE_IRQ) |
330 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); | 335 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); |
331 | 336 | ||
@@ -362,14 +367,17 @@ static int airo_config(struct pcmcia_device *link) | |||
362 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | 367 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, |
363 | link->io.BasePort2+link->io.NumPorts2-1); | 368 | link->io.BasePort2+link->io.NumPorts2-1); |
364 | if (link->win) | 369 | if (link->win) |
365 | printk(", mem 0x%06lx-0x%06lx", req.Base, | 370 | printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base, |
366 | req.Base+req.Size-1); | 371 | cfg_mem->req.Base+cfg_mem->req.Size-1); |
367 | printk("\n"); | 372 | printk("\n"); |
373 | kfree(cfg_mem); | ||
368 | return 0; | 374 | return 0; |
369 | 375 | ||
370 | cs_failed: | 376 | cs_failed: |
371 | cs_error(link, last_fn, last_ret); | 377 | cs_error(link, last_fn, last_ret); |
378 | failed: | ||
372 | airo_release(link); | 379 | airo_release(link); |
380 | kfree(cfg_mem); | ||
373 | return -ENODEV; | 381 | return -ENODEV; |
374 | } /* airo_config */ | 382 | } /* airo_config */ |
375 | 383 | ||