diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2008-08-02 08:28:43 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2008-08-22 19:21:28 -0400 |
commit | b54bf94bf91e4ca2a489eb02bca0424ddb55242a (patch) | |
tree | 4a5383d29173e24dd1fe71ce3ee4d010e60f391c /drivers | |
parent | 5fcd4da0090828bd34a1956cb322a483c6bf163c (diff) |
pcmcia: use pcmcia_loop_config in net pcmcia drivers
Use the config loop helper in (some) net pcmcia drivers.
CC: netdev@vger.kernel.org
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/pcmcia/axnet_cs.c | 71 | ||||
-rw-r--r-- | drivers/net/pcmcia/pcnet_cs.c | 79 | ||||
-rw-r--r-- | drivers/net/pcmcia/smc91c92_cs.c | 96 | ||||
-rw-r--r-- | drivers/net/pcmcia/xirc2ps_cs.c | 73 | ||||
-rw-r--r-- | drivers/net/wireless/airo_cs.c | 230 | ||||
-rw-r--r-- | drivers/net/wireless/atmel_cs.c | 123 | ||||
-rw-r--r-- | drivers/net/wireless/hostap/hostap_cs.c | 227 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_cs.c | 176 | ||||
-rw-r--r-- | drivers/net/wireless/spectrum_cs.c | 175 |
9 files changed, 596 insertions, 654 deletions
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3f682d49a4e6..04ece0b77d1d 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c | |||
@@ -284,58 +284,47 @@ static int try_io_port(struct pcmcia_device *link) | |||
284 | } | 284 | } |
285 | } | 285 | } |
286 | 286 | ||
287 | static int axnet_configcheck(struct pcmcia_device *p_dev, | ||
288 | cistpl_cftable_entry_t *cfg, | ||
289 | void *priv_data) | ||
290 | { | ||
291 | int i; | ||
292 | cistpl_io_t *io = &cfg->io; | ||
293 | |||
294 | if (cfg->index == 0 || cfg->io.nwin == 0) | ||
295 | return -ENODEV; | ||
296 | |||
297 | p_dev->conf.ConfigIndex = 0x05; | ||
298 | /* For multifunction cards, by convention, we configure the | ||
299 | network function with window 0, and serial with window 1 */ | ||
300 | if (io->nwin > 1) { | ||
301 | i = (io->win[1].len > io->win[0].len); | ||
302 | p_dev->io.BasePort2 = io->win[1-i].base; | ||
303 | p_dev->io.NumPorts2 = io->win[1-i].len; | ||
304 | } else { | ||
305 | i = p_dev->io.NumPorts2 = 0; | ||
306 | } | ||
307 | p_dev->io.BasePort1 = io->win[i].base; | ||
308 | p_dev->io.NumPorts1 = io->win[i].len; | ||
309 | p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
310 | if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32) | ||
311 | return try_io_port(p_dev); | ||
312 | |||
313 | return -ENODEV; | ||
314 | } | ||
315 | |||
287 | static int axnet_config(struct pcmcia_device *link) | 316 | static int axnet_config(struct pcmcia_device *link) |
288 | { | 317 | { |
289 | struct net_device *dev = link->priv; | 318 | struct net_device *dev = link->priv; |
290 | axnet_dev_t *info = PRIV(dev); | 319 | axnet_dev_t *info = PRIV(dev); |
291 | tuple_t tuple; | ||
292 | cisparse_t parse; | ||
293 | int i, j, last_ret, last_fn; | 320 | int i, j, last_ret, last_fn; |
294 | u_short buf[64]; | ||
295 | DECLARE_MAC_BUF(mac); | 321 | DECLARE_MAC_BUF(mac); |
296 | 322 | ||
297 | DEBUG(0, "axnet_config(0x%p)\n", link); | 323 | DEBUG(0, "axnet_config(0x%p)\n", link); |
298 | 324 | ||
299 | tuple.Attributes = 0; | ||
300 | tuple.TupleData = (cisdata_t *)buf; | ||
301 | tuple.TupleDataMax = sizeof(buf); | ||
302 | tuple.TupleOffset = 0; | ||
303 | |||
304 | /* don't trust the CIS on this; Linksys got it wrong */ | 325 | /* don't trust the CIS on this; Linksys got it wrong */ |
305 | link->conf.Present = 0x63; | 326 | link->conf.Present = 0x63; |
306 | 327 | last_ret = pcmcia_loop_config(link, axnet_configcheck, NULL); | |
307 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
308 | tuple.Attributes = 0; | ||
309 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
310 | while (last_ret == CS_SUCCESS) { | ||
311 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
312 | cistpl_io_t *io = &(parse.cftable_entry.io); | ||
313 | |||
314 | if (pcmcia_get_tuple_data(link, &tuple) != 0 || | ||
315 | pcmcia_parse_tuple(link, &tuple, &parse) != 0 || | ||
316 | cfg->index == 0 || cfg->io.nwin == 0) | ||
317 | goto next_entry; | ||
318 | |||
319 | link->conf.ConfigIndex = 0x05; | ||
320 | /* For multifunction cards, by convention, we configure the | ||
321 | network function with window 0, and serial with window 1 */ | ||
322 | if (io->nwin > 1) { | ||
323 | i = (io->win[1].len > io->win[0].len); | ||
324 | link->io.BasePort2 = io->win[1-i].base; | ||
325 | link->io.NumPorts2 = io->win[1-i].len; | ||
326 | } else { | ||
327 | i = link->io.NumPorts2 = 0; | ||
328 | } | ||
329 | link->io.BasePort1 = io->win[i].base; | ||
330 | link->io.NumPorts1 = io->win[i].len; | ||
331 | link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
332 | if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) { | ||
333 | last_ret = try_io_port(link); | ||
334 | if (last_ret == CS_SUCCESS) break; | ||
335 | } | ||
336 | next_entry: | ||
337 | last_ret = pcmcia_get_next_tuple(link, &tuple); | ||
338 | } | ||
339 | if (last_ret != CS_SUCCESS) { | 328 | if (last_ret != CS_SUCCESS) { |
340 | cs_error(link, RequestIO, last_ret); | 329 | cs_error(link, RequestIO, last_ret); |
341 | goto failed; | 330 | goto failed; |
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 2d4c4ad89b8d..7a9eeca6adc2 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c | |||
@@ -512,58 +512,53 @@ static int try_io_port(struct pcmcia_device *link) | |||
512 | } | 512 | } |
513 | } | 513 | } |
514 | 514 | ||
515 | static int pcnet_confcheck(struct pcmcia_device *p_dev, | ||
516 | cistpl_cftable_entry_t *cfg, | ||
517 | void *priv_data) | ||
518 | { | ||
519 | int *has_shmem = priv_data; | ||
520 | int i; | ||
521 | cistpl_io_t *io = &cfg->io; | ||
522 | |||
523 | if (cfg->index == 0 || cfg->io.nwin == 0) | ||
524 | return -EINVAL; | ||
525 | |||
526 | p_dev->conf.ConfigIndex = cfg->index; | ||
527 | |||
528 | /* For multifunction cards, by convention, we configure the | ||
529 | network function with window 0, and serial with window 1 */ | ||
530 | if (io->nwin > 1) { | ||
531 | i = (io->win[1].len > io->win[0].len); | ||
532 | p_dev->io.BasePort2 = io->win[1-i].base; | ||
533 | p_dev->io.NumPorts2 = io->win[1-i].len; | ||
534 | } else { | ||
535 | i = p_dev->io.NumPorts2 = 0; | ||
536 | } | ||
537 | |||
538 | *has_shmem = ((cfg->mem.nwin == 1) && | ||
539 | (cfg->mem.win[0].len >= 0x4000)); | ||
540 | p_dev->io.BasePort1 = io->win[i].base; | ||
541 | p_dev->io.NumPorts1 = io->win[i].len; | ||
542 | p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
543 | if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32) | ||
544 | return try_io_port(p_dev); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
515 | static int pcnet_config(struct pcmcia_device *link) | 549 | static int pcnet_config(struct pcmcia_device *link) |
516 | { | 550 | { |
517 | struct net_device *dev = link->priv; | 551 | struct net_device *dev = link->priv; |
518 | pcnet_dev_t *info = PRIV(dev); | 552 | pcnet_dev_t *info = PRIV(dev); |
519 | tuple_t tuple; | 553 | int last_ret, last_fn, start_pg, stop_pg, cm_offset; |
520 | cisparse_t parse; | ||
521 | int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; | ||
522 | int has_shmem = 0; | 554 | int has_shmem = 0; |
523 | u_short buf[64]; | ||
524 | hw_info_t *local_hw_info; | 555 | hw_info_t *local_hw_info; |
525 | DECLARE_MAC_BUF(mac); | 556 | DECLARE_MAC_BUF(mac); |
526 | 557 | ||
527 | DEBUG(0, "pcnet_config(0x%p)\n", link); | 558 | DEBUG(0, "pcnet_config(0x%p)\n", link); |
528 | 559 | ||
529 | tuple.TupleData = (cisdata_t *)buf; | 560 | last_ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem); |
530 | tuple.TupleDataMax = sizeof(buf); | 561 | if (last_ret) { |
531 | tuple.TupleOffset = 0; | ||
532 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
533 | tuple.Attributes = 0; | ||
534 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
535 | while (last_ret == CS_SUCCESS) { | ||
536 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
537 | cistpl_io_t *io = &(parse.cftable_entry.io); | ||
538 | |||
539 | if (pcmcia_get_tuple_data(link, &tuple) != 0 || | ||
540 | pcmcia_parse_tuple(link, &tuple, &parse) != 0 || | ||
541 | cfg->index == 0 || cfg->io.nwin == 0) | ||
542 | goto next_entry; | ||
543 | |||
544 | link->conf.ConfigIndex = cfg->index; | ||
545 | /* For multifunction cards, by convention, we configure the | ||
546 | network function with window 0, and serial with window 1 */ | ||
547 | if (io->nwin > 1) { | ||
548 | i = (io->win[1].len > io->win[0].len); | ||
549 | link->io.BasePort2 = io->win[1-i].base; | ||
550 | link->io.NumPorts2 = io->win[1-i].len; | ||
551 | } else { | ||
552 | i = link->io.NumPorts2 = 0; | ||
553 | } | ||
554 | has_shmem = ((cfg->mem.nwin == 1) && | ||
555 | (cfg->mem.win[0].len >= 0x4000)); | ||
556 | link->io.BasePort1 = io->win[i].base; | ||
557 | link->io.NumPorts1 = io->win[i].len; | ||
558 | link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
559 | if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) { | ||
560 | last_ret = try_io_port(link); | ||
561 | if (last_ret == CS_SUCCESS) break; | ||
562 | } | ||
563 | next_entry: | ||
564 | last_ret = pcmcia_get_next_tuple(link, &tuple); | ||
565 | } | ||
566 | if (last_ret != CS_SUCCESS) { | ||
567 | cs_error(link, RequestIO, last_ret); | 562 | cs_error(link, RequestIO, last_ret); |
568 | goto failed; | 563 | goto failed; |
569 | } | 564 | } |
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 250eb1954c34..c012e3400736 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c | |||
@@ -459,28 +459,36 @@ static int mhz_3288_power(struct pcmcia_device *link) | |||
459 | return 0; | 459 | return 0; |
460 | } | 460 | } |
461 | 461 | ||
462 | static int mhz_mfc_config_check(struct pcmcia_device *p_dev, | ||
463 | cistpl_cftable_entry_t *cf, | ||
464 | void *priv_data) | ||
465 | { | ||
466 | int k; | ||
467 | p_dev->conf.ConfigIndex = cf->index; | ||
468 | p_dev->io.BasePort2 = cf->io.win[0].base; | ||
469 | for (k = 0; k < 0x400; k += 0x10) { | ||
470 | if (k & 0x80) | ||
471 | continue; | ||
472 | p_dev->io.BasePort1 = k ^ 0x300; | ||
473 | if (!pcmcia_request_io(p_dev, &p_dev->io)) | ||
474 | return 0; | ||
475 | } | ||
476 | return -ENODEV; | ||
477 | } | ||
478 | |||
462 | static int mhz_mfc_config(struct pcmcia_device *link) | 479 | static int mhz_mfc_config(struct pcmcia_device *link) |
463 | { | 480 | { |
464 | struct net_device *dev = link->priv; | 481 | struct net_device *dev = link->priv; |
465 | struct smc_private *smc = netdev_priv(dev); | 482 | struct smc_private *smc = netdev_priv(dev); |
466 | struct smc_cfg_mem *cfg_mem; | 483 | struct smc_cfg_mem *cfg_mem; |
467 | tuple_t *tuple; | ||
468 | cisparse_t *parse; | ||
469 | cistpl_cftable_entry_t *cf; | ||
470 | u_char *buf; | ||
471 | win_req_t req; | 484 | win_req_t req; |
472 | memreq_t mem; | 485 | memreq_t mem; |
473 | int i, k; | 486 | int i; |
474 | 487 | ||
475 | cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); | 488 | cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); |
476 | if (!cfg_mem) | 489 | if (!cfg_mem) |
477 | return CS_OUT_OF_RESOURCE; | 490 | return CS_OUT_OF_RESOURCE; |
478 | 491 | ||
479 | tuple = &cfg_mem->tuple; | ||
480 | parse = &cfg_mem->parse; | ||
481 | cf = &parse->cftable_entry; | ||
482 | buf = cfg_mem->buf; | ||
483 | |||
484 | link->conf.Attributes |= CONF_ENABLE_SPKR; | 492 | link->conf.Attributes |= CONF_ENABLE_SPKR; |
485 | link->conf.Status = CCSR_AUDIO_ENA; | 493 | link->conf.Status = CCSR_AUDIO_ENA; |
486 | link->irq.Attributes = | 494 | link->irq.Attributes = |
@@ -489,27 +497,9 @@ static int mhz_mfc_config(struct pcmcia_device *link) | |||
489 | link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; | 497 | link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; |
490 | link->io.NumPorts2 = 8; | 498 | link->io.NumPorts2 = 8; |
491 | 499 | ||
492 | tuple->Attributes = tuple->TupleOffset = 0; | ||
493 | tuple->TupleData = (cisdata_t *)buf; | ||
494 | tuple->TupleDataMax = 255; | ||
495 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
496 | |||
497 | i = first_tuple(link, tuple, parse); | ||
498 | /* The Megahertz combo cards have modem-like CIS entries, so | 500 | /* The Megahertz combo cards have modem-like CIS entries, so |
499 | we have to explicitly try a bunch of port combinations. */ | 501 | we have to explicitly try a bunch of port combinations. */ |
500 | while (i == CS_SUCCESS) { | 502 | if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL)) |
501 | link->conf.ConfigIndex = cf->index; | ||
502 | link->io.BasePort2 = cf->io.win[0].base; | ||
503 | for (k = 0; k < 0x400; k += 0x10) { | ||
504 | if (k & 0x80) continue; | ||
505 | link->io.BasePort1 = k ^ 0x300; | ||
506 | i = pcmcia_request_io(link, &link->io); | ||
507 | if (i == CS_SUCCESS) break; | ||
508 | } | ||
509 | if (i == CS_SUCCESS) break; | ||
510 | i = next_tuple(link, tuple, parse); | ||
511 | } | ||
512 | if (i != CS_SUCCESS) | ||
513 | goto free_cfg_mem; | 503 | goto free_cfg_mem; |
514 | dev->base_addr = link->io.BasePort1; | 504 | dev->base_addr = link->io.BasePort1; |
515 | 505 | ||
@@ -533,7 +523,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) | |||
533 | 523 | ||
534 | free_cfg_mem: | 524 | free_cfg_mem: |
535 | kfree(cfg_mem); | 525 | kfree(cfg_mem); |
536 | return i; | 526 | return -ENODEV; |
537 | } | 527 | } |
538 | 528 | ||
539 | static int mhz_setup(struct pcmcia_device *link) | 529 | static int mhz_setup(struct pcmcia_device *link) |
@@ -660,46 +650,26 @@ static int mot_setup(struct pcmcia_device *link) | |||
660 | 650 | ||
661 | /*====================================================================*/ | 651 | /*====================================================================*/ |
662 | 652 | ||
653 | static int smc_configcheck(struct pcmcia_device *p_dev, | ||
654 | cistpl_cftable_entry_t *cf, | ||
655 | void *priv_data) | ||
656 | { | ||
657 | p_dev->conf.ConfigIndex = cf->index; | ||
658 | p_dev->io.BasePort1 = cf->io.win[0].base; | ||
659 | p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; | ||
660 | return pcmcia_request_io(p_dev, &p_dev->io); | ||
661 | } | ||
662 | |||
663 | static int smc_config(struct pcmcia_device *link) | 663 | static int smc_config(struct pcmcia_device *link) |
664 | { | 664 | { |
665 | struct net_device *dev = link->priv; | 665 | struct net_device *dev = link->priv; |
666 | struct smc_cfg_mem *cfg_mem; | ||
667 | tuple_t *tuple; | ||
668 | cisparse_t *parse; | ||
669 | cistpl_cftable_entry_t *cf; | ||
670 | u_char *buf; | ||
671 | int i; | 666 | int i; |
672 | 667 | ||
673 | cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); | ||
674 | if (!cfg_mem) | ||
675 | return CS_OUT_OF_RESOURCE; | ||
676 | |||
677 | tuple = &cfg_mem->tuple; | ||
678 | parse = &cfg_mem->parse; | ||
679 | cf = &parse->cftable_entry; | ||
680 | buf = cfg_mem->buf; | ||
681 | |||
682 | tuple->Attributes = tuple->TupleOffset = 0; | ||
683 | tuple->TupleData = (cisdata_t *)buf; | ||
684 | tuple->TupleDataMax = 255; | ||
685 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
686 | |||
687 | link->io.NumPorts1 = 16; | 668 | link->io.NumPorts1 = 16; |
688 | i = first_tuple(link, tuple, parse); | 669 | i = pcmcia_loop_config(link, smc_configcheck, NULL); |
689 | while (i != CS_NO_MORE_ITEMS) { | 670 | if (!i) |
690 | if (i == CS_SUCCESS) { | 671 | dev->base_addr = link->io.BasePort1; |
691 | link->conf.ConfigIndex = cf->index; | ||
692 | link->io.BasePort1 = cf->io.win[0].base; | ||
693 | link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; | ||
694 | i = pcmcia_request_io(link, &link->io); | ||
695 | if (i == CS_SUCCESS) break; | ||
696 | } | ||
697 | i = next_tuple(link, tuple, parse); | ||
698 | } | ||
699 | if (i == CS_SUCCESS) | ||
700 | dev->base_addr = link->io.BasePort1; | ||
701 | 672 | ||
702 | kfree(cfg_mem); | ||
703 | return i; | 673 | return i; |
704 | } | 674 | } |
705 | 675 | ||
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index f6c4698ce738..b57f022952b4 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c | |||
@@ -715,6 +715,45 @@ has_ce2_string(struct pcmcia_device * p_dev) | |||
715 | return 0; | 715 | return 0; |
716 | } | 716 | } |
717 | 717 | ||
718 | static int | ||
719 | xirc2ps_config_modem(struct pcmcia_device *p_dev, | ||
720 | cistpl_cftable_entry_t *cf, | ||
721 | void *priv_data) | ||
722 | { | ||
723 | unsigned int ioaddr; | ||
724 | |||
725 | if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { | ||
726 | for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { | ||
727 | p_dev->conf.ConfigIndex = cf->index ; | ||
728 | p_dev->io.BasePort2 = cf->io.win[0].base; | ||
729 | p_dev->io.BasePort1 = ioaddr; | ||
730 | if (!pcmcia_request_io(p_dev, &p_dev->io)) | ||
731 | return 0; | ||
732 | } | ||
733 | } | ||
734 | return -ENODEV; | ||
735 | } | ||
736 | |||
737 | static int | ||
738 | xirc2ps_config_check(struct pcmcia_device *p_dev, | ||
739 | cistpl_cftable_entry_t *cf, | ||
740 | void *priv_data) | ||
741 | { | ||
742 | int *pass = priv_data; | ||
743 | |||
744 | if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { | ||
745 | p_dev->conf.ConfigIndex = cf->index ; | ||
746 | p_dev->io.BasePort2 = cf->io.win[0].base; | ||
747 | p_dev->io.BasePort1 = p_dev->io.BasePort2 | ||
748 | + (*pass ? (cf->index & 0x20 ? -24:8) | ||
749 | : (cf->index & 0x20 ? 8:-24)); | ||
750 | if (!pcmcia_request_io(p_dev, &p_dev->io)) | ||
751 | return 0; | ||
752 | } | ||
753 | return -ENODEV; | ||
754 | |||
755 | } | ||
756 | |||
718 | /**************** | 757 | /**************** |
719 | * xirc2ps_config() is scheduled to run after a CARD_INSERTION event | 758 | * xirc2ps_config() is scheduled to run after a CARD_INSERTION event |
720 | * is received, to configure the PCMCIA socket, and to make the | 759 | * is received, to configure the PCMCIA socket, and to make the |
@@ -725,13 +764,12 @@ xirc2ps_config(struct pcmcia_device * link) | |||
725 | { | 764 | { |
726 | struct net_device *dev = link->priv; | 765 | struct net_device *dev = link->priv; |
727 | local_info_t *local = netdev_priv(dev); | 766 | local_info_t *local = netdev_priv(dev); |
767 | unsigned int ioaddr; | ||
728 | tuple_t tuple; | 768 | tuple_t tuple; |
729 | cisparse_t parse; | 769 | cisparse_t parse; |
730 | unsigned int ioaddr; | ||
731 | int err, i; | 770 | int err, i; |
732 | u_char buf[64]; | 771 | u_char buf[64]; |
733 | cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; | 772 | cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; |
734 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | ||
735 | DECLARE_MAC_BUF(mac); | 773 | DECLARE_MAC_BUF(mac); |
736 | 774 | ||
737 | local->dingo_ccr = NULL; | 775 | local->dingo_ccr = NULL; |
@@ -846,19 +884,8 @@ xirc2ps_config(struct pcmcia_device * link) | |||
846 | /* Take the Modem IO port from the CIS and scan for a free | 884 | /* Take the Modem IO port from the CIS and scan for a free |
847 | * Ethernet port */ | 885 | * Ethernet port */ |
848 | link->io.NumPorts1 = 16; /* no Mako stuff anymore */ | 886 | link->io.NumPorts1 = 16; /* no Mako stuff anymore */ |
849 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 887 | if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL)) |
850 | for (err = first_tuple(link, &tuple, &parse); !err; | 888 | goto port_found; |
851 | err = next_tuple(link, &tuple, &parse)) { | ||
852 | if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { | ||
853 | for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { | ||
854 | link->conf.ConfigIndex = cf->index ; | ||
855 | link->io.BasePort2 = cf->io.win[0].base; | ||
856 | link->io.BasePort1 = ioaddr; | ||
857 | if (!(err=pcmcia_request_io(link, &link->io))) | ||
858 | goto port_found; | ||
859 | } | ||
860 | } | ||
861 | } | ||
862 | } else { | 889 | } else { |
863 | link->io.NumPorts1 = 18; | 890 | link->io.NumPorts1 = 18; |
864 | /* We do 2 passes here: The first one uses the regular mapping and | 891 | /* We do 2 passes here: The first one uses the regular mapping and |
@@ -866,21 +893,9 @@ xirc2ps_config(struct pcmcia_device * link) | |||
866 | * mirrored every 32 bytes. Actually we use a mirrored port for | 893 | * mirrored every 32 bytes. Actually we use a mirrored port for |
867 | * the Mako if (on the first pass) the COR bit 5 is set. | 894 | * the Mako if (on the first pass) the COR bit 5 is set. |
868 | */ | 895 | */ |
869 | for (pass=0; pass < 2; pass++) { | 896 | for (pass=0; pass < 2; pass++) |
870 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 897 | if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass)) |
871 | for (err = first_tuple(link, &tuple, &parse); !err; | ||
872 | err = next_tuple(link, &tuple, &parse)){ | ||
873 | if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8){ | ||
874 | link->conf.ConfigIndex = cf->index ; | ||
875 | link->io.BasePort2 = cf->io.win[0].base; | ||
876 | link->io.BasePort1 = link->io.BasePort2 | ||
877 | + (pass ? (cf->index & 0x20 ? -24:8) | ||
878 | : (cf->index & 0x20 ? 8:-24)); | ||
879 | if (!(err=pcmcia_request_io(link, &link->io))) | ||
880 | goto port_found; | 898 | goto port_found; |
881 | } | ||
882 | } | ||
883 | } | ||
884 | /* if special option: | 899 | /* if special option: |
885 | * try to configure as Ethernet only. | 900 | * try to configure as Ethernet only. |
886 | * .... */ | 901 | * .... */ |
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 | ||
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 12617cd0b78e..263c36f7ee22 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c | |||
@@ -224,25 +224,69 @@ static int card_present(void *arg) | |||
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | static int atmel_config_check(struct pcmcia_device *p_dev, | ||
228 | cistpl_cftable_entry_t *cfg, | ||
229 | void *priv_data) | ||
230 | { | ||
231 | cistpl_cftable_entry_t *dflt = priv_data; | ||
232 | |||
233 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
234 | *dflt = *cfg; | ||
235 | if (cfg->index == 0) | ||
236 | return -ENODEV; | ||
237 | p_dev->conf.ConfigIndex = cfg->index; | ||
238 | |||
239 | /* Does this card need audio output? */ | ||
240 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
241 | p_dev->conf.Attributes |= CONF_ENABLE_SPKR; | ||
242 | p_dev->conf.Status = CCSR_AUDIO_ENA; | ||
243 | } | ||
244 | |||
245 | /* Use power settings for Vcc and Vpp if present */ | ||
246 | /* Note that the CIS values need to be rescaled */ | ||
247 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
248 | p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
249 | else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
250 | p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
251 | |||
252 | /* Do we need to allocate an interrupt? */ | ||
253 | if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) | ||
254 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; | ||
255 | |||
256 | /* IO window settings */ | ||
257 | p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; | ||
258 | if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { | ||
259 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; | ||
260 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
261 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
262 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
263 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
264 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
265 | p_dev->io.BasePort1 = io->win[0].base; | ||
266 | p_dev->io.NumPorts1 = io->win[0].len; | ||
267 | if (io->nwin > 1) { | ||
268 | p_dev->io.Attributes2 = p_dev->io.Attributes1; | ||
269 | p_dev->io.BasePort2 = io->win[1].base; | ||
270 | p_dev->io.NumPorts2 = io->win[1].len; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* This reserves IO space but doesn't actually enable it */ | ||
275 | return pcmcia_request_io(p_dev, &p_dev->io); | ||
276 | } | ||
277 | |||
227 | static int atmel_config(struct pcmcia_device *link) | 278 | static int atmel_config(struct pcmcia_device *link) |
228 | { | 279 | { |
229 | tuple_t tuple; | ||
230 | cisparse_t parse; | ||
231 | local_info_t *dev; | 280 | local_info_t *dev; |
232 | int last_fn, last_ret; | 281 | int last_fn, last_ret; |
233 | u_char buf[64]; | ||
234 | struct pcmcia_device_id *did; | 282 | struct pcmcia_device_id *did; |
283 | cistpl_cftable_entry_t dflt = { 0 }; | ||
235 | 284 | ||
236 | dev = link->priv; | 285 | dev = link->priv; |
237 | did = handle_to_dev(link).driver_data; | 286 | did = handle_to_dev(link).driver_data; |
238 | 287 | ||
239 | DEBUG(0, "atmel_config(0x%p)\n", link); | 288 | DEBUG(0, "atmel_config(0x%p)\n", link); |
240 | 289 | ||
241 | tuple.Attributes = 0; | ||
242 | tuple.TupleData = buf; | ||
243 | tuple.TupleDataMax = sizeof(buf); | ||
244 | tuple.TupleOffset = 0; | ||
245 | |||
246 | /* | 290 | /* |
247 | In this loop, we scan the CIS for configuration table entries, | 291 | In this loop, we scan the CIS for configuration table entries, |
248 | each of which describes a valid card configuration, including | 292 | each of which describes a valid card configuration, including |
@@ -255,66 +299,8 @@ static int atmel_config(struct pcmcia_device *link) | |||
255 | these things without consulting the CIS, and most client drivers | 299 | these things without consulting the CIS, and most client drivers |
256 | will only use the CIS to fill in implementation-defined details. | 300 | will only use the CIS to fill in implementation-defined details. |
257 | */ | 301 | */ |
258 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 302 | if (pcmcia_loop_config(link, atmel_config_check, &dflt)) |
259 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | 303 | goto failed; |
260 | while (1) { | ||
261 | cistpl_cftable_entry_t dflt = { 0 }; | ||
262 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
263 | if (pcmcia_get_tuple_data(link, &tuple) != 0 || | ||
264 | pcmcia_parse_tuple(link, &tuple, &parse) != 0) | ||
265 | goto next_entry; | ||
266 | |||
267 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; | ||
268 | if (cfg->index == 0) goto next_entry; | ||
269 | link->conf.ConfigIndex = cfg->index; | ||
270 | |||
271 | /* Does this card need audio output? */ | ||
272 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
273 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
274 | link->conf.Status = CCSR_AUDIO_ENA; | ||
275 | } | ||
276 | |||
277 | /* Use power settings for Vcc and Vpp if present */ | ||
278 | /* Note that the CIS values need to be rescaled */ | ||
279 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
280 | link->conf.Vpp = | ||
281 | cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
282 | else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) | ||
283 | link->conf.Vpp = | ||
284 | dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; | ||
285 | |||
286 | /* Do we need to allocate an interrupt? */ | ||
287 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
288 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
289 | |||
290 | /* IO window settings */ | ||
291 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
292 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
293 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
294 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
295 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
296 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
297 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
298 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
299 | link->io.BasePort1 = io->win[0].base; | ||
300 | link->io.NumPorts1 = io->win[0].len; | ||
301 | if (io->nwin > 1) { | ||
302 | link->io.Attributes2 = link->io.Attributes1; | ||
303 | link->io.BasePort2 = io->win[1].base; | ||
304 | link->io.NumPorts2 = io->win[1].len; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | /* This reserves IO space but doesn't actually enable it */ | ||
309 | if (pcmcia_request_io(link, &link->io) != 0) | ||
310 | goto next_entry; | ||
311 | |||
312 | /* If we got this far, we're cool! */ | ||
313 | break; | ||
314 | |||
315 | next_entry: | ||
316 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); | ||
317 | } | ||
318 | 304 | ||
319 | /* | 305 | /* |
320 | Allocate an interrupt line. Note that this does not assign a | 306 | Allocate an interrupt line. Note that this does not assign a |
@@ -360,6 +346,7 @@ static int atmel_config(struct pcmcia_device *link) | |||
360 | 346 | ||
361 | cs_failed: | 347 | cs_failed: |
362 | cs_error(link, last_fn, last_ret); | 348 | cs_error(link, last_fn, last_ret); |
349 | failed: | ||
363 | atmel_release(link); | 350 | atmel_release(link); |
364 | return -ENODEV; | 351 | return -ENODEV; |
365 | } | 352 | } |
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 3b4e55cf33cd..3d914dde5de0 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
@@ -532,145 +532,134 @@ static void prism2_detach(struct pcmcia_device *link) | |||
532 | #define CS_CHECK(fn, ret) \ | 532 | #define CS_CHECK(fn, ret) \ |
533 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | 533 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) |
534 | 534 | ||
535 | #define CFG_CHECK2(fn, retf) \ | ||
536 | do { int _ret = (retf); \ | ||
537 | if (_ret != 0) { \ | ||
538 | PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \ | ||
539 | cs_error(link, fn, _ret); \ | ||
540 | goto next_entry; \ | ||
541 | } \ | ||
542 | } while (0) | ||
543 | |||
544 | 535 | ||
545 | /* run after a CARD_INSERTION event is received to configure the PCMCIA | 536 | /* run after a CARD_INSERTION event is received to configure the PCMCIA |
546 | * socket and make the device available to the system */ | 537 | * socket and make the device available to the system */ |
538 | |||
539 | struct prism2_config_data { | ||
540 | cistpl_cftable_entry_t dflt; | ||
541 | config_info_t conf; | ||
542 | }; | ||
543 | |||
544 | static int prism2_config_check(struct pcmcia_device *p_dev, | ||
545 | cistpl_cftable_entry_t *cfg, | ||
546 | void *priv_data) | ||
547 | { | ||
548 | struct prism2_config_data *cfg_mem = priv_data; | ||
549 | |||
550 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
551 | cfg_mem->dflt = *cfg; | ||
552 | if (cfg->index == 0) | ||
553 | return -ENODEV; | ||
554 | |||
555 | p_dev->conf.ConfigIndex = cfg->index; | ||
556 | PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " | ||
557 | "(default 0x%02X)\n", cfg->index, cfg_mem->dflt.index); | ||
558 | |||
559 | /* Does this card need audio output? */ | ||
560 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
561 | p_dev->conf.Attributes |= CONF_ENABLE_SPKR; | ||
562 | p_dev->conf.Status = CCSR_AUDIO_ENA; | ||
563 | } | ||
564 | |||
565 | /* Use power settings for Vcc and Vpp if present */ | ||
566 | /* Note that the CIS values need to be rescaled */ | ||
567 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
568 | if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / | ||
569 | 10000 && !ignore_cis_vcc) { | ||
570 | PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" | ||
571 | " this entry\n"); | ||
572 | return -ENODEV; | ||
573 | } | ||
574 | } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
575 | if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / | ||
576 | 10000 && !ignore_cis_vcc) { | ||
577 | PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " | ||
578 | "- skipping this entry\n"); | ||
579 | return -ENODEV; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
584 | p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
585 | else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
586 | p_dev->conf.Vpp = cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
587 | |||
588 | /* Do we need to allocate an interrupt? */ | ||
589 | if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1) | ||
590 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; | ||
591 | else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) { | ||
592 | /* At least Compaq WL200 does not have IRQInfo1 set, | ||
593 | * but it does not work without interrupts.. */ | ||
594 | printk(KERN_WARNING "Config has no IRQ info, but trying to " | ||
595 | "enable IRQ anyway..\n"); | ||
596 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; | ||
597 | } | ||
598 | |||
599 | /* IO window settings */ | ||
600 | PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " | ||
601 | "cfg_mem->dflt.io.nwin=%d\n", | ||
602 | cfg->io.nwin, cfg_mem->dflt.io.nwin); | ||
603 | p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; | ||
604 | if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { | ||
605 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; | ||
606 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
607 | PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " | ||
608 | "io.base=0x%04x, len=%d\n", io->flags, | ||
609 | io->win[0].base, io->win[0].len); | ||
610 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
611 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
612 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
613 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
614 | p_dev->io.IOAddrLines = io->flags & | ||
615 | CISTPL_IO_LINES_MASK; | ||
616 | p_dev->io.BasePort1 = io->win[0].base; | ||
617 | p_dev->io.NumPorts1 = io->win[0].len; | ||
618 | if (io->nwin > 1) { | ||
619 | p_dev->io.Attributes2 = p_dev->io.Attributes1; | ||
620 | p_dev->io.BasePort2 = io->win[1].base; | ||
621 | p_dev->io.NumPorts2 = io->win[1].len; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | /* This reserves IO space but doesn't actually enable it */ | ||
626 | return pcmcia_request_io(p_dev, &p_dev->io); | ||
627 | } | ||
628 | |||
547 | static int prism2_config(struct pcmcia_device *link) | 629 | static int prism2_config(struct pcmcia_device *link) |
548 | { | 630 | { |
549 | struct net_device *dev; | 631 | struct net_device *dev; |
550 | struct hostap_interface *iface; | 632 | struct hostap_interface *iface; |
633 | struct prism2_config_data *cfg_mem; | ||
551 | local_info_t *local; | 634 | local_info_t *local; |
552 | int ret = 1; | 635 | int ret = 1; |
553 | tuple_t tuple; | ||
554 | cisparse_t *parse; | ||
555 | int last_fn, last_ret; | 636 | int last_fn, last_ret; |
556 | u_char buf[64]; | ||
557 | config_info_t conf; | ||
558 | cistpl_cftable_entry_t dflt = { 0 }; | ||
559 | struct hostap_cs_priv *hw_priv; | 637 | struct hostap_cs_priv *hw_priv; |
560 | 638 | ||
561 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); | 639 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); |
562 | 640 | ||
563 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | 641 | cfg_mem = kzalloc(sizeof(struct prism2_config_data), GFP_KERNEL); |
642 | if (!cfg_mem) | ||
643 | return -ENOMEM; | ||
644 | |||
564 | hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); | 645 | hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); |
565 | if (parse == NULL || hw_priv == NULL) { | 646 | if (hw_priv == NULL) { |
566 | ret = -ENOMEM; | 647 | ret = -ENOMEM; |
567 | goto failed; | 648 | goto failed; |
568 | } | 649 | } |
569 | 650 | ||
570 | tuple.Attributes = 0; | ||
571 | tuple.TupleData = buf; | ||
572 | tuple.TupleDataMax = sizeof(buf); | ||
573 | tuple.TupleOffset = 0; | ||
574 | |||
575 | CS_CHECK(GetConfigurationInfo, | 651 | CS_CHECK(GetConfigurationInfo, |
576 | pcmcia_get_configuration_info(link, &conf)); | 652 | pcmcia_get_configuration_info(link, &cfg_mem->conf)); |
577 | 653 | ||
578 | /* Look for an appropriate configuration table entry in the CIS */ | 654 | /* Look for an appropriate configuration table entry in the CIS */ |
579 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 655 | last_ret = pcmcia_loop_config(link, prism2_config_check, cfg_mem); |
580 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | 656 | if (last_ret) { |
581 | for (;;) { | 657 | if (!ignore_cis_vcc) |
582 | cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); | 658 | printk(KERN_ERR "GetNextTuple(): No matching " |
583 | CFG_CHECK2(GetTupleData, | 659 | "CIS configuration. Maybe you need the " |
584 | pcmcia_get_tuple_data(link, &tuple)); | 660 | "ignore_cis_vcc=1 parameter.\n"); |
585 | CFG_CHECK2(ParseTuple, | 661 | cs_error(link, RequestIO, last_ret); |
586 | pcmcia_parse_tuple(link, &tuple, parse)); | 662 | goto failed; |
587 | |||
588 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
589 | dflt = *cfg; | ||
590 | if (cfg->index == 0) | ||
591 | goto next_entry; | ||
592 | link->conf.ConfigIndex = cfg->index; | ||
593 | PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " | ||
594 | "(default 0x%02X)\n", cfg->index, dflt.index); | ||
595 | |||
596 | /* Does this card need audio output? */ | ||
597 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
598 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
599 | link->conf.Status = CCSR_AUDIO_ENA; | ||
600 | } | ||
601 | |||
602 | /* Use power settings for Vcc and Vpp if present */ | ||
603 | /* Note that the CIS values need to be rescaled */ | ||
604 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
605 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / | ||
606 | 10000 && !ignore_cis_vcc) { | ||
607 | PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" | ||
608 | " this entry\n"); | ||
609 | goto next_entry; | ||
610 | } | ||
611 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
612 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / | ||
613 | 10000 && !ignore_cis_vcc) { | ||
614 | PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " | ||
615 | "- skipping this entry\n"); | ||
616 | goto next_entry; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
621 | link->conf.Vpp = | ||
622 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
623 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
624 | link->conf.Vpp = | ||
625 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
626 | |||
627 | /* Do we need to allocate an interrupt? */ | ||
628 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
629 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
630 | else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { | ||
631 | /* At least Compaq WL200 does not have IRQInfo1 set, | ||
632 | * but it does not work without interrupts.. */ | ||
633 | printk("Config has no IRQ info, but trying to enable " | ||
634 | "IRQ anyway..\n"); | ||
635 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
636 | } | ||
637 | |||
638 | /* IO window settings */ | ||
639 | PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " | ||
640 | "dflt.io.nwin=%d\n", | ||
641 | cfg->io.nwin, dflt.io.nwin); | ||
642 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
643 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
644 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
645 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
646 | PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " | ||
647 | "io.base=0x%04x, len=%d\n", io->flags, | ||
648 | io->win[0].base, io->win[0].len); | ||
649 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
650 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
651 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
652 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
653 | link->io.IOAddrLines = io->flags & | ||
654 | CISTPL_IO_LINES_MASK; | ||
655 | link->io.BasePort1 = io->win[0].base; | ||
656 | link->io.NumPorts1 = io->win[0].len; | ||
657 | if (io->nwin > 1) { | ||
658 | link->io.Attributes2 = link->io.Attributes1; | ||
659 | link->io.BasePort2 = io->win[1].base; | ||
660 | link->io.NumPorts2 = io->win[1].len; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | /* This reserves IO space but doesn't actually enable it */ | ||
665 | CFG_CHECK2(RequestIO, | ||
666 | pcmcia_request_io(link, &link->io)); | ||
667 | |||
668 | /* This configuration table entry is OK */ | ||
669 | break; | ||
670 | |||
671 | next_entry: | ||
672 | CS_CHECK(GetNextTuple, | ||
673 | pcmcia_get_next_tuple(link, &tuple)); | ||
674 | } | 663 | } |
675 | 664 | ||
676 | /* Need to allocate net_device before requesting IRQ handler */ | 665 | /* Need to allocate net_device before requesting IRQ handler */ |
@@ -738,15 +727,15 @@ static int prism2_config(struct pcmcia_device *link) | |||
738 | if (ret == 0 && local->ddev) | 727 | if (ret == 0 && local->ddev) |
739 | strcpy(hw_priv->node.dev_name, local->ddev->name); | 728 | strcpy(hw_priv->node.dev_name, local->ddev->name); |
740 | } | 729 | } |
741 | kfree(parse); | 730 | kfree(cfg_mem); |
742 | return ret; | 731 | return ret; |
743 | 732 | ||
744 | cs_failed: | 733 | cs_failed: |
745 | cs_error(link, last_fn, last_ret); | 734 | cs_error(link, last_fn, last_ret); |
746 | 735 | ||
747 | failed: | 736 | failed: |
748 | kfree(parse); | ||
749 | kfree(hw_priv); | 737 | kfree(hw_priv); |
738 | kfree(cfg_mem); | ||
750 | prism2_release((u_long)link); | 739 | prism2_release((u_long)link); |
751 | return ret; | 740 | return ret; |
752 | } | 741 | } |
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1c216e015f64..473370c9e0d6 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) | |||
164 | last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ | 164 | last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ |
165 | } while (0) | 165 | } while (0) |
166 | 166 | ||
167 | struct orinoco_cs_config_data { | ||
168 | cistpl_cftable_entry_t dflt; | ||
169 | config_info_t conf; | ||
170 | }; | ||
171 | |||
172 | static int orinoco_cs_config_check(struct pcmcia_device *p_dev, | ||
173 | cistpl_cftable_entry_t *cfg, | ||
174 | void *priv_data) | ||
175 | { | ||
176 | struct orinoco_cs_config_data *cfg_mem = priv_data; | ||
177 | |||
178 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
179 | cfg_mem->dflt = *cfg; | ||
180 | if (cfg->index == 0) | ||
181 | goto next_entry; | ||
182 | p_dev->conf.ConfigIndex = cfg->index; | ||
183 | |||
184 | /* Use power settings for Vcc and Vpp if present */ | ||
185 | /* Note that the CIS values need to be rescaled */ | ||
186 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
187 | if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
188 | 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); | ||
189 | if (!ignore_cis_vcc) | ||
190 | goto next_entry; | ||
191 | } | ||
192 | } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
193 | if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
194 | 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); | ||
195 | if (!ignore_cis_vcc) | ||
196 | goto next_entry; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
201 | p_dev->conf.Vpp = | ||
202 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
203 | else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
204 | p_dev->conf.Vpp = | ||
205 | cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
206 | |||
207 | /* Do we need to allocate an interrupt? */ | ||
208 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; | ||
209 | |||
210 | /* IO window settings */ | ||
211 | p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; | ||
212 | if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { | ||
213 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; | ||
214 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
215 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
216 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
217 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
218 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
219 | p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
220 | p_dev->io.BasePort1 = io->win[0].base; | ||
221 | p_dev->io.NumPorts1 = io->win[0].len; | ||
222 | if (io->nwin > 1) { | ||
223 | p_dev->io.Attributes2 = p_dev->io.Attributes1; | ||
224 | p_dev->io.BasePort2 = io->win[1].base; | ||
225 | p_dev->io.NumPorts2 = io->win[1].len; | ||
226 | } | ||
227 | |||
228 | /* This reserves IO space but doesn't actually enable it */ | ||
229 | if (pcmcia_request_io(p_dev, &p_dev->io) != 0) | ||
230 | goto next_entry; | ||
231 | } | ||
232 | return 0; | ||
233 | |||
234 | next_entry: | ||
235 | pcmcia_disable_device(p_dev); | ||
236 | return -ENODEV; | ||
237 | }; | ||
238 | |||
167 | static int | 239 | static int |
168 | orinoco_cs_config(struct pcmcia_device *link) | 240 | orinoco_cs_config(struct pcmcia_device *link) |
169 | { | 241 | { |
242 | struct orinoco_cs_config_data *cfg_mem; | ||
170 | struct net_device *dev = link->priv; | 243 | struct net_device *dev = link->priv; |
171 | struct orinoco_private *priv = netdev_priv(dev); | 244 | struct orinoco_private *priv = netdev_priv(dev); |
172 | struct orinoco_pccard *card = priv->card; | 245 | struct orinoco_pccard *card = priv->card; |
173 | hermes_t *hw = &priv->hw; | 246 | hermes_t *hw = &priv->hw; |
174 | int last_fn, last_ret; | 247 | int last_fn, last_ret; |
175 | u_char buf[64]; | ||
176 | config_info_t conf; | ||
177 | tuple_t tuple; | ||
178 | cisparse_t parse; | ||
179 | void __iomem *mem; | 248 | void __iomem *mem; |
180 | 249 | ||
250 | cfg_mem = kzalloc(sizeof(struct orinoco_cs_config_data), GFP_KERNEL); | ||
251 | if (!cfg_mem) | ||
252 | return -ENOMEM; | ||
253 | |||
181 | /* Look up the current Vcc */ | 254 | /* Look up the current Vcc */ |
182 | CS_CHECK(GetConfigurationInfo, | 255 | CS_CHECK(GetConfigurationInfo, |
183 | pcmcia_get_configuration_info(link, &conf)); | 256 | pcmcia_get_configuration_info(link, &cfg_mem->conf)); |
184 | 257 | ||
185 | /* | 258 | /* |
186 | * In this loop, we scan the CIS for configuration table | 259 | * In this loop, we scan the CIS for configuration table |
@@ -196,94 +269,14 @@ orinoco_cs_config(struct pcmcia_device *link) | |||
196 | * and most client drivers will only use the CIS to fill in | 269 | * and most client drivers will only use the CIS to fill in |
197 | * implementation-defined details. | 270 | * implementation-defined details. |
198 | */ | 271 | */ |
199 | tuple.Attributes = 0; | 272 | last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, cfg_mem); |
200 | tuple.TupleData = buf; | 273 | if (last_ret) { |
201 | tuple.TupleDataMax = sizeof(buf); | 274 | if (!ignore_cis_vcc) |
202 | tuple.TupleOffset = 0; | ||
203 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
204 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
205 | while (1) { | ||
206 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
207 | cistpl_cftable_entry_t dflt = { .index = 0 }; | ||
208 | |||
209 | if ( (pcmcia_get_tuple_data(link, &tuple) != 0) | ||
210 | || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) | ||
211 | goto next_entry; | ||
212 | |||
213 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
214 | dflt = *cfg; | ||
215 | if (cfg->index == 0) | ||
216 | goto next_entry; | ||
217 | link->conf.ConfigIndex = cfg->index; | ||
218 | |||
219 | /* Use power settings for Vcc and Vpp if present */ | ||
220 | /* Note that the CIS values need to be rescaled */ | ||
221 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
222 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
223 | DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); | ||
224 | if (!ignore_cis_vcc) | ||
225 | goto next_entry; | ||
226 | } | ||
227 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
228 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
229 | DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); | ||
230 | if(!ignore_cis_vcc) | ||
231 | goto next_entry; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
236 | link->conf.Vpp = | ||
237 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
238 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
239 | link->conf.Vpp = | ||
240 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
241 | |||
242 | /* Do we need to allocate an interrupt? */ | ||
243 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
244 | |||
245 | /* IO window settings */ | ||
246 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
247 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
248 | cistpl_io_t *io = | ||
249 | (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
250 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
251 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
252 | link->io.Attributes1 = | ||
253 | IO_DATA_PATH_WIDTH_16; | ||
254 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
255 | link->io.Attributes1 = | ||
256 | IO_DATA_PATH_WIDTH_8; | ||
257 | link->io.IOAddrLines = | ||
258 | io->flags & CISTPL_IO_LINES_MASK; | ||
259 | link->io.BasePort1 = io->win[0].base; | ||
260 | link->io.NumPorts1 = io->win[0].len; | ||
261 | if (io->nwin > 1) { | ||
262 | link->io.Attributes2 = | ||
263 | link->io.Attributes1; | ||
264 | link->io.BasePort2 = io->win[1].base; | ||
265 | link->io.NumPorts2 = io->win[1].len; | ||
266 | } | ||
267 | |||
268 | /* This reserves IO space but doesn't actually enable it */ | ||
269 | if (pcmcia_request_io(link, &link->io) != 0) | ||
270 | goto next_entry; | ||
271 | } | ||
272 | |||
273 | |||
274 | /* If we got this far, we're cool! */ | ||
275 | |||
276 | break; | ||
277 | |||
278 | next_entry: | ||
279 | pcmcia_disable_device(link); | ||
280 | last_ret = pcmcia_get_next_tuple(link, &tuple); | ||
281 | if (last_ret == CS_NO_MORE_ITEMS) { | ||
282 | printk(KERN_ERR PFX "GetNextTuple(): No matching " | 275 | printk(KERN_ERR PFX "GetNextTuple(): No matching " |
283 | "CIS configuration. Maybe you need the " | 276 | "CIS configuration. Maybe you need the " |
284 | "ignore_cis_vcc=1 parameter.\n"); | 277 | "ignore_cis_vcc=1 parameter.\n"); |
285 | goto cs_failed; | 278 | cs_error(link, RequestIO, last_ret); |
286 | } | 279 | goto failed; |
287 | } | 280 | } |
288 | 281 | ||
289 | /* | 282 | /* |
@@ -334,7 +327,7 @@ orinoco_cs_config(struct pcmcia_device *link) | |||
334 | "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, | 327 | "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, |
335 | link->irq.AssignedIRQ, link->io.BasePort1, | 328 | link->irq.AssignedIRQ, link->io.BasePort1, |
336 | link->io.BasePort1 + link->io.NumPorts1 - 1); | 329 | link->io.BasePort1 + link->io.NumPorts1 - 1); |
337 | 330 | kfree(cfg_mem); | |
338 | return 0; | 331 | return 0; |
339 | 332 | ||
340 | cs_failed: | 333 | cs_failed: |
@@ -342,6 +335,7 @@ orinoco_cs_config(struct pcmcia_device *link) | |||
342 | 335 | ||
343 | failed: | 336 | failed: |
344 | orinoco_cs_release(link); | 337 | orinoco_cs_release(link); |
338 | kfree(cfg_mem); | ||
345 | return -ENODEV; | 339 | return -ENODEV; |
346 | } /* orinoco_cs_config */ | 340 | } /* orinoco_cs_config */ |
347 | 341 | ||
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 98df9bc7836a..8e1951cfc152 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c | |||
@@ -633,23 +633,96 @@ static void spectrum_cs_detach(struct pcmcia_device *link) | |||
633 | * device available to the system. | 633 | * device available to the system. |
634 | */ | 634 | */ |
635 | 635 | ||
636 | struct spectrum_cs_config_data { | ||
637 | cistpl_cftable_entry_t dflt; | ||
638 | config_info_t conf; | ||
639 | }; | ||
640 | |||
641 | static int spectrum_cs_config_check(struct pcmcia_device *p_dev, | ||
642 | cistpl_cftable_entry_t *cfg, | ||
643 | void *priv_data) | ||
644 | { | ||
645 | struct spectrum_cs_config_data *cfg_mem = priv_data; | ||
646 | |||
647 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
648 | cfg_mem->dflt = *cfg; | ||
649 | if (cfg->index == 0) | ||
650 | goto next_entry; | ||
651 | p_dev->conf.ConfigIndex = cfg->index; | ||
652 | |||
653 | /* Use power settings for Vcc and Vpp if present */ | ||
654 | /* Note that the CIS values need to be rescaled */ | ||
655 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
656 | if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
657 | 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); | ||
658 | if (!ignore_cis_vcc) | ||
659 | goto next_entry; | ||
660 | } | ||
661 | } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
662 | if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
663 | 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); | ||
664 | if (!ignore_cis_vcc) | ||
665 | goto next_entry; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
670 | p_dev->conf.Vpp = | ||
671 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
672 | else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
673 | p_dev->conf.Vpp = | ||
674 | cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
675 | |||
676 | /* Do we need to allocate an interrupt? */ | ||
677 | p_dev->conf.Attributes |= CONF_ENABLE_IRQ; | ||
678 | |||
679 | /* IO window settings */ | ||
680 | p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; | ||
681 | if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { | ||
682 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; | ||
683 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
684 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
685 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
686 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
687 | p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
688 | p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
689 | p_dev->io.BasePort1 = io->win[0].base; | ||
690 | p_dev->io.NumPorts1 = io->win[0].len; | ||
691 | if (io->nwin > 1) { | ||
692 | p_dev->io.Attributes2 = p_dev->io.Attributes1; | ||
693 | p_dev->io.BasePort2 = io->win[1].base; | ||
694 | p_dev->io.NumPorts2 = io->win[1].len; | ||
695 | } | ||
696 | |||
697 | /* This reserves IO space but doesn't actually enable it */ | ||
698 | if (pcmcia_request_io(p_dev, &p_dev->io) != 0) | ||
699 | goto next_entry; | ||
700 | } | ||
701 | return 0; | ||
702 | |||
703 | next_entry: | ||
704 | pcmcia_disable_device(p_dev); | ||
705 | return -ENODEV; | ||
706 | }; | ||
707 | |||
636 | static int | 708 | static int |
637 | spectrum_cs_config(struct pcmcia_device *link) | 709 | spectrum_cs_config(struct pcmcia_device *link) |
638 | { | 710 | { |
711 | struct spectrum_cs_config_data *cfg_mem; | ||
639 | struct net_device *dev = link->priv; | 712 | struct net_device *dev = link->priv; |
640 | struct orinoco_private *priv = netdev_priv(dev); | 713 | struct orinoco_private *priv = netdev_priv(dev); |
641 | struct orinoco_pccard *card = priv->card; | 714 | struct orinoco_pccard *card = priv->card; |
642 | hermes_t *hw = &priv->hw; | 715 | hermes_t *hw = &priv->hw; |
643 | int last_fn, last_ret; | 716 | int last_fn, last_ret; |
644 | u_char buf[64]; | ||
645 | config_info_t conf; | ||
646 | tuple_t tuple; | ||
647 | cisparse_t parse; | ||
648 | void __iomem *mem; | 717 | void __iomem *mem; |
649 | 718 | ||
719 | cfg_mem = kzalloc(sizeof(struct spectrum_cs_config_data), GFP_KERNEL); | ||
720 | if (!cfg_mem) | ||
721 | return -ENOMEM; | ||
722 | |||
650 | /* Look up the current Vcc */ | 723 | /* Look up the current Vcc */ |
651 | CS_CHECK(GetConfigurationInfo, | 724 | CS_CHECK(GetConfigurationInfo, |
652 | pcmcia_get_configuration_info(link, &conf)); | 725 | pcmcia_get_configuration_info(link, &cfg_mem->conf)); |
653 | 726 | ||
654 | /* | 727 | /* |
655 | * In this loop, we scan the CIS for configuration table | 728 | * In this loop, we scan the CIS for configuration table |
@@ -665,94 +738,14 @@ spectrum_cs_config(struct pcmcia_device *link) | |||
665 | * and most client drivers will only use the CIS to fill in | 738 | * and most client drivers will only use the CIS to fill in |
666 | * implementation-defined details. | 739 | * implementation-defined details. |
667 | */ | 740 | */ |
668 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 741 | last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, cfg_mem); |
669 | tuple.Attributes = 0; | 742 | if (last_ret) { |
670 | tuple.TupleData = buf; | 743 | if (!ignore_cis_vcc) |
671 | tuple.TupleDataMax = sizeof(buf); | ||
672 | tuple.TupleOffset = 0; | ||
673 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
674 | while (1) { | ||
675 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | ||
676 | cistpl_cftable_entry_t dflt = { .index = 0 }; | ||
677 | |||
678 | if ( (pcmcia_get_tuple_data(link, &tuple) != 0) | ||
679 | || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) | ||
680 | goto next_entry; | ||
681 | |||
682 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
683 | dflt = *cfg; | ||
684 | if (cfg->index == 0) | ||
685 | goto next_entry; | ||
686 | link->conf.ConfigIndex = cfg->index; | ||
687 | |||
688 | /* Use power settings for Vcc and Vpp if present */ | ||
689 | /* Note that the CIS values need to be rescaled */ | ||
690 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
691 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
692 | DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); | ||
693 | if (!ignore_cis_vcc) | ||
694 | goto next_entry; | ||
695 | } | ||
696 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
697 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { | ||
698 | DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); | ||
699 | if(!ignore_cis_vcc) | ||
700 | goto next_entry; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
705 | link->conf.Vpp = | ||
706 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
707 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
708 | link->conf.Vpp = | ||
709 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
710 | |||
711 | /* Do we need to allocate an interrupt? */ | ||
712 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
713 | |||
714 | /* IO window settings */ | ||
715 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
716 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
717 | cistpl_io_t *io = | ||
718 | (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
719 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
720 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
721 | link->io.Attributes1 = | ||
722 | IO_DATA_PATH_WIDTH_16; | ||
723 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
724 | link->io.Attributes1 = | ||
725 | IO_DATA_PATH_WIDTH_8; | ||
726 | link->io.IOAddrLines = | ||
727 | io->flags & CISTPL_IO_LINES_MASK; | ||
728 | link->io.BasePort1 = io->win[0].base; | ||
729 | link->io.NumPorts1 = io->win[0].len; | ||
730 | if (io->nwin > 1) { | ||
731 | link->io.Attributes2 = | ||
732 | link->io.Attributes1; | ||
733 | link->io.BasePort2 = io->win[1].base; | ||
734 | link->io.NumPorts2 = io->win[1].len; | ||
735 | } | ||
736 | |||
737 | /* This reserves IO space but doesn't actually enable it */ | ||
738 | if (pcmcia_request_io(link, &link->io) != 0) | ||
739 | goto next_entry; | ||
740 | } | ||
741 | |||
742 | |||
743 | /* If we got this far, we're cool! */ | ||
744 | |||
745 | break; | ||
746 | |||
747 | next_entry: | ||
748 | pcmcia_disable_device(link); | ||
749 | last_ret = pcmcia_get_next_tuple(link, &tuple); | ||
750 | if (last_ret == CS_NO_MORE_ITEMS) { | ||
751 | printk(KERN_ERR PFX "GetNextTuple(): No matching " | 744 | printk(KERN_ERR PFX "GetNextTuple(): No matching " |
752 | "CIS configuration. Maybe you need the " | 745 | "CIS configuration. Maybe you need the " |
753 | "ignore_cis_vcc=1 parameter.\n"); | 746 | "ignore_cis_vcc=1 parameter.\n"); |
754 | goto cs_failed; | 747 | cs_error(link, RequestIO, last_ret); |
755 | } | 748 | goto failed; |
756 | } | 749 | } |
757 | 750 | ||
758 | /* | 751 | /* |
@@ -809,6 +802,7 @@ spectrum_cs_config(struct pcmcia_device *link) | |||
809 | link->irq.AssignedIRQ, link->io.BasePort1, | 802 | link->irq.AssignedIRQ, link->io.BasePort1, |
810 | link->io.BasePort1 + link->io.NumPorts1 - 1); | 803 | link->io.BasePort1 + link->io.NumPorts1 - 1); |
811 | 804 | ||
805 | kfree(cfg_mem); | ||
812 | return 0; | 806 | return 0; |
813 | 807 | ||
814 | cs_failed: | 808 | cs_failed: |
@@ -816,6 +810,7 @@ spectrum_cs_config(struct pcmcia_device *link) | |||
816 | 810 | ||
817 | failed: | 811 | failed: |
818 | spectrum_cs_release(link); | 812 | spectrum_cs_release(link); |
813 | kfree(cfg_mem); | ||
819 | return -ENODEV; | 814 | return -ENODEV; |
820 | } /* spectrum_cs_config */ | 815 | } /* spectrum_cs_config */ |
821 | 816 | ||