diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-07-30 07:13:46 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-09-29 11:20:24 -0400 |
commit | 00990e7ce0b0e596fe41d9c64d6933ea70084003 (patch) | |
tree | 189e0dd92860feba84231c66955749574cac5d6d /drivers/serial/serial_cs.c | |
parent | 440eed43e2a95bb842488755683716814da10f2b (diff) |
pcmcia: use autoconfiguration feature for ioports and iomem
When CONF_AUTO_SET_IO or CONF_AUTO_SET_IOMEM are set, the corresponding
fields in struct pcmcia_device *p_dev->resource[0,1,2] are set
accordinly. Drivers wishing to override certain settings may do so in
the callback function, but they no longer need to parse the CIS entries
stored in cistpl_cftable_entry_t themselves.
CC: netdev@vger.kernel.org
CC: linux-wireless@vger.kernel.org
CC: linux-ide@vger.kernel.org
CC: linux-usb@vger.kernel.org
CC: laforge@gnumonks.org
CC: linux-mtd@lists.infradead.org
CC: linux-bluetooth@vger.kernel.org
CC: alsa-devel@alsa-project.org
CC: linux-serial@vger.kernel.org
CC: Jiri Kosina <jkosina@suse.cz>
CC: linux-scsi@vger.kernel.org
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 | 132 |
1 files changed, 67 insertions, 65 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index a796a93fe39c..422520342936 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -424,41 +424,45 @@ static int pfc_config(struct pcmcia_device *p_dev) | |||
424 | return -ENODEV; | 424 | return -ENODEV; |
425 | } | 425 | } |
426 | 426 | ||
427 | static int simple_config_check(struct pcmcia_device *p_dev, | 427 | static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data) |
428 | cistpl_cftable_entry_t *cf, | ||
429 | cistpl_cftable_entry_t *dflt, | ||
430 | void *priv_data) | ||
431 | { | 428 | { |
432 | static const int size_table[2] = { 8, 16 }; | 429 | static const int size_table[2] = { 8, 16 }; |
433 | int *try = priv_data; | 430 | int *try = priv_data; |
434 | 431 | ||
435 | p_dev->io_lines = ((*try & 0x1) == 0) ? | 432 | if (p_dev->resource[0]->start == 0) |
436 | 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | 433 | return -ENODEV; |
437 | 434 | ||
438 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)]) | 435 | if ((*try & 0x1) == 0) |
439 | && (cf->io.win[0].base != 0)) { | 436 | p_dev->io_lines = 16; |
440 | p_dev->resource[0]->start = cf->io.win[0].base; | 437 | |
441 | if (!pcmcia_request_io(p_dev)) | 438 | if (p_dev->resource[0]->end != size_table[(*try >> 1)]) |
442 | return 0; | 439 | return -ENODEV; |
443 | } | 440 | |
444 | return -EINVAL; | 441 | p_dev->resource[0]->end = 8; |
442 | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; | ||
443 | p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; | ||
444 | |||
445 | return pcmcia_request_io(p_dev); | ||
445 | } | 446 | } |
446 | 447 | ||
447 | static int simple_config_check_notpicky(struct pcmcia_device *p_dev, | 448 | static int simple_config_check_notpicky(struct pcmcia_device *p_dev, |
448 | cistpl_cftable_entry_t *cf, | ||
449 | cistpl_cftable_entry_t *dflt, | ||
450 | void *priv_data) | 449 | void *priv_data) |
451 | { | 450 | { |
452 | static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | 451 | static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; |
453 | int j; | 452 | int j; |
454 | 453 | ||
455 | if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | 454 | if (p_dev->io_lines > 3) |
456 | for (j = 0; j < 5; j++) { | 455 | return -ENODEV; |
457 | p_dev->resource[0]->start = base[j]; | 456 | |
458 | p_dev->io_lines = base[j] ? 16 : 3; | 457 | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; |
459 | if (!pcmcia_request_io(p_dev)) | 458 | p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; |
460 | return 0; | 459 | p_dev->resource[0]->end = 8; |
461 | } | 460 | |
461 | for (j = 0; j < 5; j++) { | ||
462 | p_dev->resource[0]->start = base[j]; | ||
463 | p_dev->io_lines = base[j] ? 16 : 3; | ||
464 | if (!pcmcia_request_io(p_dev)) | ||
465 | return 0; | ||
462 | } | 466 | } |
463 | return -ENODEV; | 467 | return -ENODEV; |
464 | } | 468 | } |
@@ -468,12 +472,9 @@ static int simple_config(struct pcmcia_device *link) | |||
468 | struct serial_info *info = link->priv; | 472 | struct serial_info *info = link->priv; |
469 | int i = -ENODEV, try; | 473 | int i = -ENODEV, try; |
470 | 474 | ||
471 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; | ||
472 | link->resource[0]->end = 8; | ||
473 | |||
474 | /* First pass: look for a config entry that looks normal. | 475 | /* First pass: look for a config entry that looks normal. |
475 | * Two tries: without IO aliases, then with aliases */ | 476 | * Two tries: without IO aliases, then with aliases */ |
476 | link->config_flags |= CONF_AUTO_SET_VPP; | 477 | link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO; |
477 | for (try = 0; try < 4; try++) | 478 | for (try = 0; try < 4; try++) |
478 | if (!pcmcia_loop_config(link, simple_config_check, &try)) | 479 | if (!pcmcia_loop_config(link, simple_config_check, &try)) |
479 | goto found_port; | 480 | goto found_port; |
@@ -503,43 +504,44 @@ found_port: | |||
503 | return setup_serial(link, info, link->resource[0]->start, link->irq); | 504 | return setup_serial(link, info, link->resource[0]->start, link->irq); |
504 | } | 505 | } |
505 | 506 | ||
506 | static int multi_config_check(struct pcmcia_device *p_dev, | 507 | static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data) |
507 | cistpl_cftable_entry_t *cf, | ||
508 | cistpl_cftable_entry_t *dflt, | ||
509 | void *priv_data) | ||
510 | { | 508 | { |
511 | int *base2 = priv_data; | 509 | int *multi = priv_data; |
510 | |||
511 | if (p_dev->resource[1]->end) | ||
512 | return -EINVAL; | ||
512 | 513 | ||
513 | /* The quad port cards have bad CIS's, so just look for a | 514 | /* The quad port cards have bad CIS's, so just look for a |
514 | window larger than 8 ports and assume it will be right */ | 515 | window larger than 8 ports and assume it will be right */ |
515 | if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { | 516 | if (p_dev->resource[0]->end <= 8) |
516 | p_dev->resource[0]->start = cf->io.win[0].base; | 517 | return -EINVAL; |
517 | p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; | 518 | |
518 | if (!pcmcia_request_io(p_dev)) { | 519 | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; |
519 | *base2 = p_dev->resource[0]->start + 8; | 520 | p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; |
520 | return 0; | 521 | p_dev->resource[0]->end = *multi * 8; |
521 | } | 522 | |
522 | } | 523 | if (pcmcia_request_io(p_dev)) |
523 | return -ENODEV; | 524 | return -ENODEV; |
525 | return 0; | ||
524 | } | 526 | } |
525 | 527 | ||
526 | static int multi_config_check_notpicky(struct pcmcia_device *p_dev, | 528 | static int multi_config_check_notpicky(struct pcmcia_device *p_dev, |
527 | cistpl_cftable_entry_t *cf, | ||
528 | cistpl_cftable_entry_t *dflt, | ||
529 | void *priv_data) | 529 | void *priv_data) |
530 | { | 530 | { |
531 | int *base2 = priv_data; | 531 | int *base2 = priv_data; |
532 | 532 | ||
533 | if (cf->io.nwin == 2) { | 533 | if (!p_dev->resource[0]->end || !p_dev->resource[1]->end) |
534 | p_dev->resource[0]->start = cf->io.win[0].base; | 534 | return -ENODEV; |
535 | p_dev->resource[1]->start = cf->io.win[1].base; | 535 | |
536 | p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; | 536 | p_dev->resource[0]->end = p_dev->resource[1]->end = 8; |
537 | if (!pcmcia_request_io(p_dev)) { | 537 | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; |
538 | *base2 = p_dev->resource[1]->start; | 538 | p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; |
539 | return 0; | 539 | |
540 | } | 540 | if (pcmcia_request_io(p_dev)) |
541 | } | 541 | return -ENODEV; |
542 | return -ENODEV; | 542 | |
543 | *base2 = p_dev->resource[0]->start + 8; | ||
544 | return 0; | ||
543 | } | 545 | } |
544 | 546 | ||
545 | static int multi_config(struct pcmcia_device *link) | 547 | static int multi_config(struct pcmcia_device *link) |
@@ -547,12 +549,12 @@ static int multi_config(struct pcmcia_device *link) | |||
547 | struct serial_info *info = link->priv; | 549 | struct serial_info *info = link->priv; |
548 | int i, base2 = 0; | 550 | int i, base2 = 0; |
549 | 551 | ||
552 | link->config_flags |= CONF_AUTO_SET_IO; | ||
550 | /* First, look for a generic full-sized window */ | 553 | /* First, look for a generic full-sized window */ |
551 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; | 554 | if (!pcmcia_loop_config(link, multi_config_check, &info->multi)) |
552 | link->resource[0]->end = info->multi * 8; | 555 | base2 = link->resource[0]->start + 8; |
553 | if (pcmcia_loop_config(link, multi_config_check, &base2)) { | 556 | else { |
554 | /* If that didn't work, look for two windows */ | 557 | /* If that didn't work, look for two windows */ |
555 | link->resource[0]->end = link->resource[1]->end = 8; | ||
556 | info->multi = 2; | 558 | info->multi = 2; |
557 | if (pcmcia_loop_config(link, multi_config_check_notpicky, | 559 | if (pcmcia_loop_config(link, multi_config_check_notpicky, |
558 | &base2)) { | 560 | &base2)) { |
@@ -587,7 +589,7 @@ static int multi_config(struct pcmcia_device *link) | |||
587 | link->config_index == 3) { | 589 | link->config_index == 3) { |
588 | err = setup_serial(link, info, base2, | 590 | err = setup_serial(link, info, base2, |
589 | link->irq); | 591 | link->irq); |
590 | base2 = link->resource[0]->start;; | 592 | base2 = link->resource[0]->start; |
591 | } else { | 593 | } else { |
592 | err = setup_serial(link, info, link->resource[0]->start, | 594 | err = setup_serial(link, info, link->resource[0]->start, |
593 | link->irq); | 595 | link->irq); |
@@ -611,18 +613,18 @@ static int multi_config(struct pcmcia_device *link) | |||
611 | return 0; | 613 | return 0; |
612 | } | 614 | } |
613 | 615 | ||
614 | static int serial_check_for_multi(struct pcmcia_device *p_dev, | 616 | static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data) |
615 | cistpl_cftable_entry_t *cf, | ||
616 | cistpl_cftable_entry_t *dflt, | ||
617 | void *priv_data) | ||
618 | { | 617 | { |
619 | struct serial_info *info = p_dev->priv; | 618 | struct serial_info *info = p_dev->priv; |
620 | 619 | ||
621 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) | 620 | if (!p_dev->resource[0]->end) |
622 | info->multi = cf->io.win[0].len >> 3; | 621 | return -EINVAL; |
622 | |||
623 | if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0)) | ||
624 | info->multi = p_dev->resource[0]->end >> 3; | ||
623 | 625 | ||
624 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && | 626 | if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8) |
625 | (cf->io.win[1].len == 8)) | 627 | && (p_dev->resource[1]->end == 8)) |
626 | info->multi = 2; | 628 | info->multi = 2; |
627 | 629 | ||
628 | return 0; /* break */ | 630 | return 0; /* break */ |