diff options
Diffstat (limited to 'drivers/serial/serial_cs.c')
-rw-r--r-- | drivers/serial/serial_cs.c | 302 |
1 files changed, 129 insertions, 173 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 164d2a42eb59..7546aa887fa7 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -431,131 +431,103 @@ first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) | |||
431 | { | 431 | { |
432 | int i; | 432 | int i; |
433 | i = pcmcia_get_first_tuple(handle, tuple); | 433 | i = pcmcia_get_first_tuple(handle, tuple); |
434 | if (i != CS_SUCCESS) | 434 | if (i != 0) |
435 | return CS_NO_MORE_ITEMS; | ||
436 | i = pcmcia_get_tuple_data(handle, tuple); | ||
437 | if (i != CS_SUCCESS) | ||
438 | return i; | 435 | return i; |
439 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
440 | } | ||
441 | |||
442 | static int | ||
443 | next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) | ||
444 | { | ||
445 | int i; | ||
446 | i = pcmcia_get_next_tuple(handle, tuple); | ||
447 | if (i != CS_SUCCESS) | ||
448 | return CS_NO_MORE_ITEMS; | ||
449 | i = pcmcia_get_tuple_data(handle, tuple); | 436 | i = pcmcia_get_tuple_data(handle, tuple); |
450 | if (i != CS_SUCCESS) | 437 | if (i != 0) |
451 | return i; | 438 | return i; |
452 | return pcmcia_parse_tuple(handle, tuple, parse); | 439 | return pcmcia_parse_tuple(tuple, parse); |
453 | } | 440 | } |
454 | 441 | ||
455 | /*====================================================================*/ | 442 | /*====================================================================*/ |
456 | 443 | ||
457 | static int simple_config(struct pcmcia_device *link) | 444 | static int simple_config_check(struct pcmcia_device *p_dev, |
445 | cistpl_cftable_entry_t *cf, | ||
446 | cistpl_cftable_entry_t *dflt, | ||
447 | unsigned int vcc, | ||
448 | void *priv_data) | ||
458 | { | 449 | { |
459 | static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | ||
460 | static const int size_table[2] = { 8, 16 }; | 450 | static const int size_table[2] = { 8, 16 }; |
461 | struct serial_info *info = link->priv; | 451 | int *try = priv_data; |
462 | struct serial_cfg_mem *cfg_mem; | 452 | |
463 | tuple_t *tuple; | 453 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) |
464 | u_char *buf; | 454 | p_dev->conf.Vpp = |
465 | cisparse_t *parse; | 455 | cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; |
466 | cistpl_cftable_entry_t *cf; | 456 | |
467 | config_info_t config; | 457 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)]) |
468 | int i, j, try; | 458 | && (cf->io.win[0].base != 0)) { |
469 | int s; | 459 | p_dev->io.BasePort1 = cf->io.win[0].base; |
460 | p_dev->io.IOAddrLines = ((*try & 0x1) == 0) ? | ||
461 | 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | ||
462 | if (!pcmcia_request_io(p_dev, &p_dev->io)) | ||
463 | return 0; | ||
464 | } | ||
465 | return -EINVAL; | ||
466 | } | ||
470 | 467 | ||
471 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); | 468 | static int simple_config_check_notpicky(struct pcmcia_device *p_dev, |
472 | if (!cfg_mem) | 469 | cistpl_cftable_entry_t *cf, |
473 | return -1; | 470 | cistpl_cftable_entry_t *dflt, |
471 | unsigned int vcc, | ||
472 | void *priv_data) | ||
473 | { | ||
474 | static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | ||
475 | int j; | ||
476 | |||
477 | if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | ||
478 | for (j = 0; j < 5; j++) { | ||
479 | p_dev->io.BasePort1 = base[j]; | ||
480 | p_dev->io.IOAddrLines = base[j] ? 16 : 3; | ||
481 | if (!pcmcia_request_io(p_dev, &p_dev->io)) | ||
482 | return 0; | ||
483 | } | ||
484 | } | ||
485 | return -ENODEV; | ||
486 | } | ||
474 | 487 | ||
475 | tuple = &cfg_mem->tuple; | 488 | static int simple_config(struct pcmcia_device *link) |
476 | parse = &cfg_mem->parse; | 489 | { |
477 | cf = &parse->cftable_entry; | 490 | struct serial_info *info = link->priv; |
478 | buf = cfg_mem->buf; | 491 | int i = -ENODEV, try; |
479 | 492 | ||
480 | /* If the card is already configured, look up the port and irq */ | 493 | /* If the card is already configured, look up the port and irq */ |
481 | i = pcmcia_get_configuration_info(link, &config); | 494 | if (link->function_config) { |
482 | if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { | ||
483 | unsigned int port = 0; | 495 | unsigned int port = 0; |
484 | if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { | 496 | if ((link->io.BasePort2 != 0) && |
485 | port = config.BasePort2; | 497 | (link->io.NumPorts2 == 8)) { |
498 | port = link->io.BasePort2; | ||
486 | info->slave = 1; | 499 | info->slave = 1; |
487 | } else if ((info->manfid == MANFID_OSITECH) && | 500 | } else if ((info->manfid == MANFID_OSITECH) && |
488 | (config.NumPorts1 == 0x40)) { | 501 | (link->io.NumPorts1 == 0x40)) { |
489 | port = config.BasePort1 + 0x28; | 502 | port = link->io.BasePort1 + 0x28; |
490 | info->slave = 1; | 503 | info->slave = 1; |
491 | } | 504 | } |
492 | if (info->slave) { | 505 | if (info->slave) { |
493 | kfree(cfg_mem); | 506 | return setup_serial(link, info, port, |
494 | return setup_serial(link, info, port, config.AssignedIRQ); | 507 | link->irq.AssignedIRQ); |
495 | } | 508 | } |
496 | } | 509 | } |
497 | 510 | ||
498 | /* First pass: look for a config entry that looks normal. */ | 511 | /* First pass: look for a config entry that looks normal. |
499 | tuple->TupleData = (cisdata_t *) buf; | 512 | * Two tries: without IO aliases, then with aliases */ |
500 | tuple->TupleOffset = 0; | 513 | for (try = 0; try < 4; try++) |
501 | tuple->TupleDataMax = 255; | 514 | if (!pcmcia_loop_config(link, simple_config_check, &try)) |
502 | tuple->Attributes = 0; | 515 | goto found_port; |
503 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; | 516 | |
504 | /* Two tries: without IO aliases, then with aliases */ | ||
505 | for (s = 0; s < 2; s++) { | ||
506 | for (try = 0; try < 2; try++) { | ||
507 | i = first_tuple(link, tuple, parse); | ||
508 | while (i != CS_NO_MORE_ITEMS) { | ||
509 | if (i != CS_SUCCESS) | ||
510 | goto next_entry; | ||
511 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
512 | link->conf.Vpp = | ||
513 | cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
514 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && | ||
515 | (cf->io.win[0].base != 0)) { | ||
516 | link->conf.ConfigIndex = cf->index; | ||
517 | link->io.BasePort1 = cf->io.win[0].base; | ||
518 | link->io.IOAddrLines = (try == 0) ? | ||
519 | 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | ||
520 | i = pcmcia_request_io(link, &link->io); | ||
521 | if (i == CS_SUCCESS) | ||
522 | goto found_port; | ||
523 | } | ||
524 | next_entry: | ||
525 | i = next_tuple(link, tuple, parse); | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | /* Second pass: try to find an entry that isn't picky about | 517 | /* Second pass: try to find an entry that isn't picky about |
530 | its base address, then try to grab any standard serial port | 518 | its base address, then try to grab any standard serial port |
531 | address, and finally try to get any free port. */ | 519 | address, and finally try to get any free port. */ |
532 | i = first_tuple(link, tuple, parse); | 520 | if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) |
533 | while (i != CS_NO_MORE_ITEMS) { | 521 | goto found_port; |
534 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && | ||
535 | ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | ||
536 | link->conf.ConfigIndex = cf->index; | ||
537 | for (j = 0; j < 5; j++) { | ||
538 | link->io.BasePort1 = base[j]; | ||
539 | link->io.IOAddrLines = base[j] ? 16 : 3; | ||
540 | i = pcmcia_request_io(link, &link->io); | ||
541 | if (i == CS_SUCCESS) | ||
542 | goto found_port; | ||
543 | } | ||
544 | } | ||
545 | i = next_tuple(link, tuple, parse); | ||
546 | } | ||
547 | 522 | ||
548 | found_port: | 523 | printk(KERN_NOTICE |
549 | if (i != CS_SUCCESS) { | 524 | "serial_cs: no usable port range found, giving up\n"); |
550 | printk(KERN_NOTICE | 525 | cs_error(link, RequestIO, i); |
551 | "serial_cs: no usable port range found, giving up\n"); | 526 | return -1; |
552 | cs_error(link, RequestIO, i); | ||
553 | kfree(cfg_mem); | ||
554 | return -1; | ||
555 | } | ||
556 | 527 | ||
528 | found_port: | ||
557 | i = pcmcia_request_irq(link, &link->irq); | 529 | i = pcmcia_request_irq(link, &link->irq); |
558 | if (i != CS_SUCCESS) { | 530 | if (i != 0) { |
559 | cs_error(link, RequestIRQ, i); | 531 | cs_error(link, RequestIRQ, i); |
560 | link->irq.AssignedIRQ = 0; | 532 | link->irq.AssignedIRQ = 0; |
561 | } | 533 | } |
@@ -569,88 +541,76 @@ next_entry: | |||
569 | info->quirk->config(link); | 541 | info->quirk->config(link); |
570 | 542 | ||
571 | i = pcmcia_request_configuration(link, &link->conf); | 543 | i = pcmcia_request_configuration(link, &link->conf); |
572 | if (i != CS_SUCCESS) { | 544 | if (i != 0) { |
573 | cs_error(link, RequestConfiguration, i); | 545 | cs_error(link, RequestConfiguration, i); |
574 | kfree(cfg_mem); | ||
575 | return -1; | 546 | return -1; |
576 | } | 547 | } |
577 | kfree(cfg_mem); | ||
578 | return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); | 548 | return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); |
579 | } | 549 | } |
580 | 550 | ||
581 | static int multi_config(struct pcmcia_device * link) | 551 | static int multi_config_check(struct pcmcia_device *p_dev, |
552 | cistpl_cftable_entry_t *cf, | ||
553 | cistpl_cftable_entry_t *dflt, | ||
554 | unsigned int vcc, | ||
555 | void *priv_data) | ||
582 | { | 556 | { |
583 | struct serial_info *info = link->priv; | 557 | int *base2 = priv_data; |
584 | struct serial_cfg_mem *cfg_mem; | 558 | |
585 | tuple_t *tuple; | 559 | /* The quad port cards have bad CIS's, so just look for a |
586 | u_char *buf; | 560 | window larger than 8 ports and assume it will be right */ |
587 | cisparse_t *parse; | 561 | if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { |
588 | cistpl_cftable_entry_t *cf; | 562 | p_dev->io.BasePort1 = cf->io.win[0].base; |
589 | int i, rc, base2 = 0; | 563 | p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; |
564 | if (!pcmcia_request_io(p_dev, &p_dev->io)) { | ||
565 | *base2 = p_dev->io.BasePort1 + 8; | ||
566 | return 0; | ||
567 | } | ||
568 | } | ||
569 | return -ENODEV; | ||
570 | } | ||
590 | 571 | ||
591 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); | 572 | static int multi_config_check_notpicky(struct pcmcia_device *p_dev, |
592 | if (!cfg_mem) | 573 | cistpl_cftable_entry_t *cf, |
593 | return -1; | 574 | cistpl_cftable_entry_t *dflt, |
594 | tuple = &cfg_mem->tuple; | 575 | unsigned int vcc, |
595 | parse = &cfg_mem->parse; | 576 | void *priv_data) |
596 | cf = &parse->cftable_entry; | 577 | { |
597 | buf = cfg_mem->buf; | 578 | int *base2 = priv_data; |
579 | |||
580 | if (cf->io.nwin == 2) { | ||
581 | p_dev->io.BasePort1 = cf->io.win[0].base; | ||
582 | p_dev->io.BasePort2 = cf->io.win[1].base; | ||
583 | p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; | ||
584 | if (!pcmcia_request_io(p_dev, &p_dev->io)) { | ||
585 | *base2 = p_dev->io.BasePort2; | ||
586 | return 0; | ||
587 | } | ||
588 | } | ||
589 | return -ENODEV; | ||
590 | } | ||
598 | 591 | ||
599 | tuple->TupleData = (cisdata_t *) buf; | 592 | static int multi_config(struct pcmcia_device *link) |
600 | tuple->TupleOffset = 0; | 593 | { |
601 | tuple->TupleDataMax = 255; | 594 | struct serial_info *info = link->priv; |
602 | tuple->Attributes = 0; | 595 | int i, base2 = 0; |
603 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
604 | 596 | ||
605 | /* First, look for a generic full-sized window */ | 597 | /* First, look for a generic full-sized window */ |
606 | link->io.NumPorts1 = info->multi * 8; | 598 | link->io.NumPorts1 = info->multi * 8; |
607 | i = first_tuple(link, tuple, parse); | 599 | if (pcmcia_loop_config(link, multi_config_check, &base2)) { |
608 | while (i != CS_NO_MORE_ITEMS) { | 600 | /* If that didn't work, look for two windows */ |
609 | /* The quad port cards have bad CIS's, so just look for a | ||
610 | window larger than 8 ports and assume it will be right */ | ||
611 | if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && | ||
612 | (cf->io.win[0].len > 8)) { | ||
613 | link->conf.ConfigIndex = cf->index; | ||
614 | link->io.BasePort1 = cf->io.win[0].base; | ||
615 | link->io.IOAddrLines = | ||
616 | cf->io.flags & CISTPL_IO_LINES_MASK; | ||
617 | i = pcmcia_request_io(link, &link->io); | ||
618 | base2 = link->io.BasePort1 + 8; | ||
619 | if (i == CS_SUCCESS) | ||
620 | break; | ||
621 | } | ||
622 | i = next_tuple(link, tuple, parse); | ||
623 | } | ||
624 | |||
625 | /* If that didn't work, look for two windows */ | ||
626 | if (i != CS_SUCCESS) { | ||
627 | link->io.NumPorts1 = link->io.NumPorts2 = 8; | 601 | link->io.NumPorts1 = link->io.NumPorts2 = 8; |
628 | info->multi = 2; | 602 | info->multi = 2; |
629 | i = first_tuple(link, tuple, parse); | 603 | if (pcmcia_loop_config(link, multi_config_check_notpicky, |
630 | while (i != CS_NO_MORE_ITEMS) { | 604 | &base2)) { |
631 | if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { | 605 | printk(KERN_NOTICE "serial_cs: no usable port range" |
632 | link->conf.ConfigIndex = cf->index; | 606 | "found, giving up\n"); |
633 | link->io.BasePort1 = cf->io.win[0].base; | 607 | return -ENODEV; |
634 | link->io.BasePort2 = cf->io.win[1].base; | ||
635 | link->io.IOAddrLines = | ||
636 | cf->io.flags & CISTPL_IO_LINES_MASK; | ||
637 | i = pcmcia_request_io(link, &link->io); | ||
638 | base2 = link->io.BasePort2; | ||
639 | if (i == CS_SUCCESS) | ||
640 | break; | ||
641 | } | ||
642 | i = next_tuple(link, tuple, parse); | ||
643 | } | 608 | } |
644 | } | 609 | } |
645 | 610 | ||
646 | if (i != CS_SUCCESS) { | ||
647 | cs_error(link, RequestIO, i); | ||
648 | rc = -1; | ||
649 | goto free_cfg_mem; | ||
650 | } | ||
651 | |||
652 | i = pcmcia_request_irq(link, &link->irq); | 611 | i = pcmcia_request_irq(link, &link->irq); |
653 | if (i != CS_SUCCESS) { | 612 | if (i != 0) { |
613 | /* FIXME: comment does not fit, error handling does not fit */ | ||
654 | printk(KERN_NOTICE | 614 | printk(KERN_NOTICE |
655 | "serial_cs: no usable port range found, giving up\n"); | 615 | "serial_cs: no usable port range found, giving up\n"); |
656 | cs_error(link, RequestIRQ, i); | 616 | cs_error(link, RequestIRQ, i); |
@@ -664,10 +624,9 @@ static int multi_config(struct pcmcia_device * link) | |||
664 | info->quirk->config(link); | 624 | info->quirk->config(link); |
665 | 625 | ||
666 | i = pcmcia_request_configuration(link, &link->conf); | 626 | i = pcmcia_request_configuration(link, &link->conf); |
667 | if (i != CS_SUCCESS) { | 627 | if (i != 0) { |
668 | cs_error(link, RequestConfiguration, i); | 628 | cs_error(link, RequestConfiguration, i); |
669 | rc = -1; | 629 | return -ENODEV; |
670 | goto free_cfg_mem; | ||
671 | } | 630 | } |
672 | 631 | ||
673 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: | 632 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: |
@@ -678,7 +637,8 @@ static int multi_config(struct pcmcia_device * link) | |||
678 | info->prodid == PRODID_POSSIO_GCC)) { | 637 | info->prodid == PRODID_POSSIO_GCC)) { |
679 | int err; | 638 | int err; |
680 | 639 | ||
681 | if (cf->index == 1 || cf->index == 3) { | 640 | if (link->conf.ConfigIndex == 1 || |
641 | link->conf.ConfigIndex == 3) { | ||
682 | err = setup_serial(link, info, base2, | 642 | err = setup_serial(link, info, base2, |
683 | link->irq.AssignedIRQ); | 643 | link->irq.AssignedIRQ); |
684 | base2 = link->io.BasePort1; | 644 | base2 = link->io.BasePort1; |
@@ -695,18 +655,14 @@ static int multi_config(struct pcmcia_device * link) | |||
695 | if (info->quirk && info->quirk->wakeup) | 655 | if (info->quirk && info->quirk->wakeup) |
696 | info->quirk->wakeup(link); | 656 | info->quirk->wakeup(link); |
697 | 657 | ||
698 | rc = 0; | 658 | return 0; |
699 | goto free_cfg_mem; | ||
700 | } | 659 | } |
701 | 660 | ||
702 | setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); | 661 | setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); |
703 | for (i = 0; i < info->multi - 1; i++) | 662 | for (i = 0; i < info->multi - 1; i++) |
704 | setup_serial(link, info, base2 + (8 * i), | 663 | setup_serial(link, info, base2 + (8 * i), |
705 | link->irq.AssignedIRQ); | 664 | link->irq.AssignedIRQ); |
706 | rc = 0; | 665 | return 0; |
707 | free_cfg_mem: | ||
708 | kfree(cfg_mem); | ||
709 | return rc; | ||
710 | } | 666 | } |
711 | 667 | ||
712 | /*====================================================================== | 668 | /*====================================================================== |
@@ -746,7 +702,7 @@ static int serial_config(struct pcmcia_device * link) | |||
746 | /* Is this a compliant multifunction card? */ | 702 | /* Is this a compliant multifunction card? */ |
747 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; | 703 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; |
748 | tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; | 704 | tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; |
749 | info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS); | 705 | info->multi = (first_tuple(link, tuple, parse) == 0); |
750 | 706 | ||
751 | /* Is this a multiport card? */ | 707 | /* Is this a multiport card? */ |
752 | tuple->DesiredTuple = CISTPL_MANFID; | 708 | tuple->DesiredTuple = CISTPL_MANFID; |
@@ -770,7 +726,7 @@ static int serial_config(struct pcmcia_device * link) | |||
770 | ((link->func_id == CISTPL_FUNCID_MULTI) || | 726 | ((link->func_id == CISTPL_FUNCID_MULTI) || |
771 | (link->func_id == CISTPL_FUNCID_SERIAL))) { | 727 | (link->func_id == CISTPL_FUNCID_SERIAL))) { |
772 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; | 728 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; |
773 | if (first_tuple(link, tuple, parse) == CS_SUCCESS) { | 729 | if (first_tuple(link, tuple, parse) == 0) { |
774 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) | 730 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) |
775 | info->multi = cf->io.win[0].len >> 3; | 731 | info->multi = cf->io.win[0].len >> 3; |
776 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && | 732 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && |