diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-08-30 02:18:54 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-09-15 11:56:32 -0400 |
commit | c494bc6c534c78fac2d308ad38073b9226448b0d (patch) | |
tree | 1ce2fc2404cb735aacf53a0256fd7cd51b6aad5b /drivers/serial/serial_cs.c | |
parent | 49553c2ef88749dd502687f4eb9c258bb10a4f44 (diff) |
pcmcia serial_cs.c: fix multifunction card handling
We shouldn't overwrite pre-set values, and we should also
set the port address to the beginning, and not the end of
the 8-port range.
CC: linux-serial@vger.kernel.org
Reported-by: Komuro <komurojun-mbn@nifty.com>
Hardware-supplied-by: Jochen Frieling <j.frieling@pengutronix.de>
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/serial/serial_cs.c')
-rw-r--r-- | drivers/serial/serial_cs.c | 62 |
1 files changed, 36 insertions, 26 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 141c69554bd4..7d475b2a79e8 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -335,8 +335,6 @@ static int serial_probe(struct pcmcia_device *link) | |||
335 | info->p_dev = link; | 335 | info->p_dev = link; |
336 | link->priv = info; | 336 | link->priv = info; |
337 | 337 | ||
338 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; | ||
339 | link->resource[0]->end = 8; | ||
340 | link->conf.Attributes = CONF_ENABLE_IRQ; | 338 | link->conf.Attributes = CONF_ENABLE_IRQ; |
341 | if (do_sound) { | 339 | if (do_sound) { |
342 | link->conf.Attributes |= CONF_ENABLE_SPKR; | 340 | link->conf.Attributes |= CONF_ENABLE_SPKR; |
@@ -411,6 +409,27 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, | |||
411 | 409 | ||
412 | /*====================================================================*/ | 410 | /*====================================================================*/ |
413 | 411 | ||
412 | static int pfc_config(struct pcmcia_device *p_dev) | ||
413 | { | ||
414 | unsigned int port = 0; | ||
415 | struct serial_info *info = p_dev->priv; | ||
416 | |||
417 | if ((p_dev->resource[1]->end != 0) && | ||
418 | (resource_size(p_dev->resource[1]) == 8)) { | ||
419 | port = p_dev->resource[1]->start; | ||
420 | info->slave = 1; | ||
421 | } else if ((info->manfid == MANFID_OSITECH) && | ||
422 | (resource_size(p_dev->resource[0]) == 0x40)) { | ||
423 | port = p_dev->resource[0]->start + 0x28; | ||
424 | info->slave = 1; | ||
425 | } | ||
426 | if (info->slave) | ||
427 | return setup_serial(p_dev, info, port, p_dev->irq); | ||
428 | |||
429 | dev_warn(&p_dev->dev, "no usable port range found, giving up\n"); | ||
430 | return -ENODEV; | ||
431 | } | ||
432 | |||
414 | static int simple_config_check(struct pcmcia_device *p_dev, | 433 | static int simple_config_check(struct pcmcia_device *p_dev, |
415 | cistpl_cftable_entry_t *cf, | 434 | cistpl_cftable_entry_t *cf, |
416 | cistpl_cftable_entry_t *dflt, | 435 | cistpl_cftable_entry_t *dflt, |
@@ -461,23 +480,8 @@ static int simple_config(struct pcmcia_device *link) | |||
461 | struct serial_info *info = link->priv; | 480 | struct serial_info *info = link->priv; |
462 | int i = -ENODEV, try; | 481 | int i = -ENODEV, try; |
463 | 482 | ||
464 | /* If the card is already configured, look up the port and irq */ | 483 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; |
465 | if (link->function_config) { | 484 | link->resource[0]->end = 8; |
466 | unsigned int port = 0; | ||
467 | if ((link->resource[1]->end != 0) && | ||
468 | (resource_size(link->resource[1]) == 8)) { | ||
469 | port = link->resource[1]->end; | ||
470 | info->slave = 1; | ||
471 | } else if ((info->manfid == MANFID_OSITECH) && | ||
472 | (resource_size(link->resource[0]) == 0x40)) { | ||
473 | port = link->resource[0]->start + 0x28; | ||
474 | info->slave = 1; | ||
475 | } | ||
476 | if (info->slave) { | ||
477 | return setup_serial(link, info, port, | ||
478 | link->irq); | ||
479 | } | ||
480 | } | ||
481 | 485 | ||
482 | /* First pass: look for a config entry that looks normal. | 486 | /* First pass: look for a config entry that looks normal. |
483 | * Two tries: without IO aliases, then with aliases */ | 487 | * Two tries: without IO aliases, then with aliases */ |
@@ -491,8 +495,7 @@ static int simple_config(struct pcmcia_device *link) | |||
491 | if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) | 495 | if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) |
492 | goto found_port; | 496 | goto found_port; |
493 | 497 | ||
494 | printk(KERN_NOTICE | 498 | dev_warn(&link->dev, "no usable port range found, giving up\n"); |
495 | "serial_cs: no usable port range found, giving up\n"); | ||
496 | return -1; | 499 | return -1; |
497 | 500 | ||
498 | found_port: | 501 | found_port: |
@@ -558,6 +561,7 @@ static int multi_config(struct pcmcia_device *link) | |||
558 | int i, base2 = 0; | 561 | int i, base2 = 0; |
559 | 562 | ||
560 | /* First, look for a generic full-sized window */ | 563 | /* First, look for a generic full-sized window */ |
564 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; | ||
561 | link->resource[0]->end = info->multi * 8; | 565 | link->resource[0]->end = info->multi * 8; |
562 | if (pcmcia_loop_config(link, multi_config_check, &base2)) { | 566 | if (pcmcia_loop_config(link, multi_config_check, &base2)) { |
563 | /* If that didn't work, look for two windows */ | 567 | /* If that didn't work, look for two windows */ |
@@ -565,15 +569,14 @@ static int multi_config(struct pcmcia_device *link) | |||
565 | info->multi = 2; | 569 | info->multi = 2; |
566 | if (pcmcia_loop_config(link, multi_config_check_notpicky, | 570 | if (pcmcia_loop_config(link, multi_config_check_notpicky, |
567 | &base2)) { | 571 | &base2)) { |
568 | printk(KERN_NOTICE "serial_cs: no usable port range" | 572 | dev_warn(&link->dev, "no usable port range " |
569 | "found, giving up\n"); | 573 | "found, giving up\n"); |
570 | return -ENODEV; | 574 | return -ENODEV; |
571 | } | 575 | } |
572 | } | 576 | } |
573 | 577 | ||
574 | if (!link->irq) | 578 | if (!link->irq) |
575 | dev_warn(&link->dev, | 579 | dev_warn(&link->dev, "no usable IRQ found, continuing...\n"); |
576 | "serial_cs: no usable IRQ found, continuing...\n"); | ||
577 | 580 | ||
578 | /* | 581 | /* |
579 | * Apply any configuration quirks. | 582 | * Apply any configuration quirks. |
@@ -675,6 +678,7 @@ static int serial_config(struct pcmcia_device * link) | |||
675 | multifunction cards that ask for appropriate IO port ranges */ | 678 | multifunction cards that ask for appropriate IO port ranges */ |
676 | if ((info->multi == 0) && | 679 | if ((info->multi == 0) && |
677 | (link->has_func_id) && | 680 | (link->has_func_id) && |
681 | (link->socket->pcmcia_pfc == 0) && | ||
678 | ((link->func_id == CISTPL_FUNCID_MULTI) || | 682 | ((link->func_id == CISTPL_FUNCID_MULTI) || |
679 | (link->func_id == CISTPL_FUNCID_SERIAL))) | 683 | (link->func_id == CISTPL_FUNCID_SERIAL))) |
680 | pcmcia_loop_config(link, serial_check_for_multi, info); | 684 | pcmcia_loop_config(link, serial_check_for_multi, info); |
@@ -685,7 +689,13 @@ static int serial_config(struct pcmcia_device * link) | |||
685 | if (info->quirk && info->quirk->multi != -1) | 689 | if (info->quirk && info->quirk->multi != -1) |
686 | info->multi = info->quirk->multi; | 690 | info->multi = info->quirk->multi; |
687 | 691 | ||
688 | if (info->multi > 1) | 692 | dev_info(&link->dev, |
693 | "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n", | ||
694 | link->manf_id, link->card_id, | ||
695 | link->socket->pcmcia_pfc, info->multi, info->quirk); | ||
696 | if (link->socket->pcmcia_pfc) | ||
697 | i = pfc_config(link); | ||
698 | else if (info->multi > 1) | ||
689 | i = multi_config(link); | 699 | i = multi_config(link); |
690 | else | 700 | else |
691 | i = simple_config(link); | 701 | i = simple_config(link); |
@@ -704,7 +714,7 @@ static int serial_config(struct pcmcia_device * link) | |||
704 | return 0; | 714 | return 0; |
705 | 715 | ||
706 | failed: | 716 | failed: |
707 | dev_warn(&link->dev, "serial_cs: failed to initialize\n"); | 717 | dev_warn(&link->dev, "failed to initialize\n"); |
708 | serial_remove(link); | 718 | serial_remove(link); |
709 | return -ENODEV; | 719 | return -ENODEV; |
710 | } | 720 | } |