diff options
Diffstat (limited to 'drivers/serial/serial_cs.c')
| -rw-r--r-- | drivers/serial/serial_cs.c | 173 |
1 files changed, 112 insertions, 61 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 9034f9ad37c7..6eeb48f6a482 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
| @@ -107,6 +107,13 @@ struct serial_info { | |||
| 107 | int line[4]; | 107 | int line[4]; |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | struct serial_cfg_mem { | ||
| 111 | tuple_t tuple; | ||
| 112 | cisparse_t parse; | ||
| 113 | u_char buf[256]; | ||
| 114 | }; | ||
| 115 | |||
| 116 | |||
| 110 | static void serial_config(dev_link_t * link); | 117 | static void serial_config(dev_link_t * link); |
| 111 | static int serial_event(event_t event, int priority, | 118 | static int serial_event(event_t event, int priority, |
| 112 | event_callback_args_t * args); | 119 | event_callback_args_t * args); |
| @@ -357,14 +364,24 @@ static int simple_config(dev_link_t *link) | |||
| 357 | static int size_table[2] = { 8, 16 }; | 364 | static int size_table[2] = { 8, 16 }; |
| 358 | client_handle_t handle = link->handle; | 365 | client_handle_t handle = link->handle; |
| 359 | struct serial_info *info = link->priv; | 366 | struct serial_info *info = link->priv; |
| 360 | tuple_t tuple; | 367 | struct serial_cfg_mem *cfg_mem; |
| 361 | u_char buf[256]; | 368 | tuple_t *tuple; |
| 362 | cisparse_t parse; | 369 | u_char *buf; |
| 363 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | 370 | cisparse_t *parse; |
| 371 | cistpl_cftable_entry_t *cf; | ||
| 364 | config_info_t config; | 372 | config_info_t config; |
| 365 | int i, j, try; | 373 | int i, j, try; |
| 366 | int s; | 374 | int s; |
| 367 | 375 | ||
| 376 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); | ||
| 377 | if (!cfg_mem) | ||
| 378 | return -1; | ||
| 379 | |||
| 380 | tuple = &cfg_mem->tuple; | ||
| 381 | parse = &cfg_mem->parse; | ||
| 382 | cf = &parse->cftable_entry; | ||
| 383 | buf = cfg_mem->buf; | ||
| 384 | |||
| 368 | /* If the card is already configured, look up the port and irq */ | 385 | /* If the card is already configured, look up the port and irq */ |
| 369 | i = pcmcia_get_configuration_info(handle, &config); | 386 | i = pcmcia_get_configuration_info(handle, &config); |
| 370 | if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { | 387 | if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { |
| @@ -377,21 +394,23 @@ static int simple_config(dev_link_t *link) | |||
| 377 | port = config.BasePort1 + 0x28; | 394 | port = config.BasePort1 + 0x28; |
| 378 | info->slave = 1; | 395 | info->slave = 1; |
| 379 | } | 396 | } |
| 380 | if (info->slave) | 397 | if (info->slave) { |
| 398 | kfree(cfg_mem); | ||
| 381 | return setup_serial(handle, info, port, config.AssignedIRQ); | 399 | return setup_serial(handle, info, port, config.AssignedIRQ); |
| 400 | } | ||
| 382 | } | 401 | } |
| 383 | link->conf.Vcc = config.Vcc; | 402 | link->conf.Vcc = config.Vcc; |
| 384 | 403 | ||
| 385 | /* First pass: look for a config entry that looks normal. */ | 404 | /* First pass: look for a config entry that looks normal. */ |
| 386 | tuple.TupleData = (cisdata_t *) buf; | 405 | tuple->TupleData = (cisdata_t *) buf; |
| 387 | tuple.TupleOffset = 0; | 406 | tuple->TupleOffset = 0; |
| 388 | tuple.TupleDataMax = 255; | 407 | tuple->TupleDataMax = 255; |
| 389 | tuple.Attributes = 0; | 408 | tuple->Attributes = 0; |
| 390 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 409 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; |
| 391 | /* Two tries: without IO aliases, then with aliases */ | 410 | /* Two tries: without IO aliases, then with aliases */ |
| 392 | for (s = 0; s < 2; s++) { | 411 | for (s = 0; s < 2; s++) { |
| 393 | for (try = 0; try < 2; try++) { | 412 | for (try = 0; try < 2; try++) { |
| 394 | i = first_tuple(handle, &tuple, &parse); | 413 | i = first_tuple(handle, tuple, parse); |
| 395 | while (i != CS_NO_MORE_ITEMS) { | 414 | while (i != CS_NO_MORE_ITEMS) { |
| 396 | if (i != CS_SUCCESS) | 415 | if (i != CS_SUCCESS) |
| 397 | goto next_entry; | 416 | goto next_entry; |
| @@ -409,14 +428,14 @@ static int simple_config(dev_link_t *link) | |||
| 409 | goto found_port; | 428 | goto found_port; |
| 410 | } | 429 | } |
| 411 | next_entry: | 430 | next_entry: |
| 412 | i = next_tuple(handle, &tuple, &parse); | 431 | i = next_tuple(handle, tuple, parse); |
| 413 | } | 432 | } |
| 414 | } | 433 | } |
| 415 | } | 434 | } |
| 416 | /* Second pass: try to find an entry that isn't picky about | 435 | /* Second pass: try to find an entry that isn't picky about |
| 417 | its base address, then try to grab any standard serial port | 436 | its base address, then try to grab any standard serial port |
| 418 | address, and finally try to get any free port. */ | 437 | address, and finally try to get any free port. */ |
| 419 | i = first_tuple(handle, &tuple, &parse); | 438 | i = first_tuple(handle, tuple, parse); |
| 420 | while (i != CS_NO_MORE_ITEMS) { | 439 | while (i != CS_NO_MORE_ITEMS) { |
| 421 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && | 440 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && |
| 422 | ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | 441 | ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { |
| @@ -429,7 +448,7 @@ next_entry: | |||
| 429 | goto found_port; | 448 | goto found_port; |
| 430 | } | 449 | } |
| 431 | } | 450 | } |
| 432 | i = next_tuple(handle, &tuple, &parse); | 451 | i = next_tuple(handle, tuple, parse); |
| 433 | } | 452 | } |
| 434 | 453 | ||
| 435 | found_port: | 454 | found_port: |
| @@ -437,6 +456,7 @@ next_entry: | |||
| 437 | printk(KERN_NOTICE | 456 | printk(KERN_NOTICE |
| 438 | "serial_cs: no usable port range found, giving up\n"); | 457 | "serial_cs: no usable port range found, giving up\n"); |
| 439 | cs_error(link->handle, RequestIO, i); | 458 | cs_error(link->handle, RequestIO, i); |
| 459 | kfree(cfg_mem); | ||
| 440 | return -1; | 460 | return -1; |
| 441 | } | 461 | } |
| 442 | 462 | ||
| @@ -450,9 +470,10 @@ next_entry: | |||
| 450 | i = pcmcia_request_configuration(link->handle, &link->conf); | 470 | i = pcmcia_request_configuration(link->handle, &link->conf); |
| 451 | if (i != CS_SUCCESS) { | 471 | if (i != CS_SUCCESS) { |
| 452 | cs_error(link->handle, RequestConfiguration, i); | 472 | cs_error(link->handle, RequestConfiguration, i); |
| 473 | kfree(cfg_mem); | ||
| 453 | return -1; | 474 | return -1; |
| 454 | } | 475 | } |
| 455 | 476 | kfree(cfg_mem); | |
| 456 | return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); | 477 | return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); |
| 457 | } | 478 | } |
| 458 | 479 | ||
| @@ -460,29 +481,39 @@ static int multi_config(dev_link_t * link) | |||
| 460 | { | 481 | { |
| 461 | client_handle_t handle = link->handle; | 482 | client_handle_t handle = link->handle; |
| 462 | struct serial_info *info = link->priv; | 483 | struct serial_info *info = link->priv; |
| 463 | tuple_t tuple; | 484 | struct serial_cfg_mem *cfg_mem; |
| 464 | u_char buf[256]; | 485 | tuple_t *tuple; |
| 465 | cisparse_t parse; | 486 | u_char *buf; |
| 466 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | 487 | cisparse_t *parse; |
| 488 | cistpl_cftable_entry_t *cf; | ||
| 467 | config_info_t config; | 489 | config_info_t config; |
| 468 | int i, base2 = 0; | 490 | int i, rc, base2 = 0; |
| 491 | |||
| 492 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); | ||
| 493 | if (!cfg_mem) | ||
| 494 | return -1; | ||
| 495 | tuple = &cfg_mem->tuple; | ||
| 496 | parse = &cfg_mem->parse; | ||
| 497 | cf = &parse->cftable_entry; | ||
| 498 | buf = cfg_mem->buf; | ||
| 469 | 499 | ||
| 470 | i = pcmcia_get_configuration_info(handle, &config); | 500 | i = pcmcia_get_configuration_info(handle, &config); |
| 471 | if (i != CS_SUCCESS) { | 501 | if (i != CS_SUCCESS) { |
| 472 | cs_error(handle, GetConfigurationInfo, i); | 502 | cs_error(handle, GetConfigurationInfo, i); |
| 473 | return -1; | 503 | rc = -1; |
| 504 | goto free_cfg_mem; | ||
| 474 | } | 505 | } |
| 475 | link->conf.Vcc = config.Vcc; | 506 | link->conf.Vcc = config.Vcc; |
| 476 | 507 | ||
| 477 | tuple.TupleData = (cisdata_t *) buf; | 508 | tuple->TupleData = (cisdata_t *) buf; |
| 478 | tuple.TupleOffset = 0; | 509 | tuple->TupleOffset = 0; |
| 479 | tuple.TupleDataMax = 255; | 510 | tuple->TupleDataMax = 255; |
| 480 | tuple.Attributes = 0; | 511 | tuple->Attributes = 0; |
| 481 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 512 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; |
| 482 | 513 | ||
| 483 | /* First, look for a generic full-sized window */ | 514 | /* First, look for a generic full-sized window */ |
| 484 | link->io.NumPorts1 = info->multi * 8; | 515 | link->io.NumPorts1 = info->multi * 8; |
| 485 | i = first_tuple(handle, &tuple, &parse); | 516 | i = first_tuple(handle, tuple, parse); |
| 486 | while (i != CS_NO_MORE_ITEMS) { | 517 | while (i != CS_NO_MORE_ITEMS) { |
| 487 | /* The quad port cards have bad CIS's, so just look for a | 518 | /* The quad port cards have bad CIS's, so just look for a |
| 488 | window larger than 8 ports and assume it will be right */ | 519 | window larger than 8 ports and assume it will be right */ |
| @@ -497,14 +528,14 @@ static int multi_config(dev_link_t * link) | |||
| 497 | if (i == CS_SUCCESS) | 528 | if (i == CS_SUCCESS) |
| 498 | break; | 529 | break; |
| 499 | } | 530 | } |
| 500 | i = next_tuple(handle, &tuple, &parse); | 531 | i = next_tuple(handle, tuple, parse); |
| 501 | } | 532 | } |
| 502 | 533 | ||
| 503 | /* If that didn't work, look for two windows */ | 534 | /* If that didn't work, look for two windows */ |
| 504 | if (i != CS_SUCCESS) { | 535 | if (i != CS_SUCCESS) { |
| 505 | link->io.NumPorts1 = link->io.NumPorts2 = 8; | 536 | link->io.NumPorts1 = link->io.NumPorts2 = 8; |
| 506 | info->multi = 2; | 537 | info->multi = 2; |
| 507 | i = first_tuple(handle, &tuple, &parse); | 538 | i = first_tuple(handle, tuple, parse); |
| 508 | while (i != CS_NO_MORE_ITEMS) { | 539 | while (i != CS_NO_MORE_ITEMS) { |
| 509 | if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { | 540 | if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { |
| 510 | link->conf.ConfigIndex = cf->index; | 541 | link->conf.ConfigIndex = cf->index; |
| @@ -517,13 +548,14 @@ static int multi_config(dev_link_t * link) | |||
| 517 | if (i == CS_SUCCESS) | 548 | if (i == CS_SUCCESS) |
| 518 | break; | 549 | break; |
| 519 | } | 550 | } |
| 520 | i = next_tuple(handle, &tuple, &parse); | 551 | i = next_tuple(handle, tuple, parse); |
| 521 | } | 552 | } |
| 522 | } | 553 | } |
| 523 | 554 | ||
| 524 | if (i != CS_SUCCESS) { | 555 | if (i != CS_SUCCESS) { |
| 525 | cs_error(link->handle, RequestIO, i); | 556 | cs_error(link->handle, RequestIO, i); |
| 526 | return -1; | 557 | rc = -1; |
| 558 | goto free_cfg_mem; | ||
| 527 | } | 559 | } |
| 528 | 560 | ||
| 529 | i = pcmcia_request_irq(link->handle, &link->irq); | 561 | i = pcmcia_request_irq(link->handle, &link->irq); |
| @@ -541,7 +573,8 @@ static int multi_config(dev_link_t * link) | |||
| 541 | i = pcmcia_request_configuration(link->handle, &link->conf); | 573 | i = pcmcia_request_configuration(link->handle, &link->conf); |
| 542 | if (i != CS_SUCCESS) { | 574 | if (i != CS_SUCCESS) { |
| 543 | cs_error(link->handle, RequestConfiguration, i); | 575 | cs_error(link->handle, RequestConfiguration, i); |
| 544 | return -1; | 576 | rc = -1; |
| 577 | goto free_cfg_mem; | ||
| 545 | } | 578 | } |
| 546 | 579 | ||
| 547 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: | 580 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: |
| @@ -554,17 +587,23 @@ static int multi_config(dev_link_t * link) | |||
| 554 | setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); | 587 | setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); |
| 555 | outb(12, base2 + 1); | 588 | outb(12, base2 + 1); |
| 556 | } | 589 | } |
| 557 | return 0; | 590 | rc = 0; |
| 591 | goto free_cfg_mem; | ||
| 558 | } | 592 | } |
| 559 | 593 | ||
| 560 | setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); | 594 | setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); |
| 561 | /* The Nokia cards are not really multiport cards */ | 595 | /* The Nokia cards are not really multiport cards */ |
| 562 | if (info->manfid == MANFID_NOKIA) | 596 | if (info->manfid == MANFID_NOKIA) { |
| 563 | return 0; | 597 | rc = 0; |
| 598 | goto free_cfg_mem; | ||
| 599 | } | ||
| 564 | for (i = 0; i < info->multi - 1; i++) | 600 | for (i = 0; i < info->multi - 1; i++) |
| 565 | setup_serial(handle, info, base2 + (8 * i), link->irq.AssignedIRQ); | 601 | setup_serial(handle, info, base2 + (8 * i), |
| 566 | 602 | link->irq.AssignedIRQ); | |
| 567 | return 0; | 603 | rc = 0; |
| 604 | free_cfg_mem: | ||
| 605 | kfree(cfg_mem); | ||
| 606 | return rc; | ||
| 568 | } | 607 | } |
| 569 | 608 | ||
| 570 | /*====================================================================== | 609 | /*====================================================================== |
| @@ -579,39 +618,49 @@ void serial_config(dev_link_t * link) | |||
| 579 | { | 618 | { |
| 580 | client_handle_t handle = link->handle; | 619 | client_handle_t handle = link->handle; |
| 581 | struct serial_info *info = link->priv; | 620 | struct serial_info *info = link->priv; |
| 582 | tuple_t tuple; | 621 | struct serial_cfg_mem *cfg_mem; |
| 583 | u_short buf[128]; | 622 | tuple_t *tuple; |
| 584 | cisparse_t parse; | 623 | u_char *buf; |
| 585 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | 624 | cisparse_t *parse; |
| 625 | cistpl_cftable_entry_t *cf; | ||
| 586 | int i, last_ret, last_fn; | 626 | int i, last_ret, last_fn; |
| 587 | 627 | ||
| 588 | DEBUG(0, "serial_config(0x%p)\n", link); | 628 | DEBUG(0, "serial_config(0x%p)\n", link); |
| 589 | 629 | ||
| 590 | tuple.TupleData = (cisdata_t *) buf; | 630 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); |
| 591 | tuple.TupleOffset = 0; | 631 | if (!cfg_mem) |
| 592 | tuple.TupleDataMax = 255; | 632 | goto failed; |
| 593 | tuple.Attributes = 0; | 633 | |
| 634 | tuple = &cfg_mem->tuple; | ||
| 635 | parse = &cfg_mem->parse; | ||
| 636 | cf = &parse->cftable_entry; | ||
| 637 | buf = cfg_mem->buf; | ||
| 638 | |||
| 639 | tuple->TupleData = (cisdata_t *) buf; | ||
| 640 | tuple->TupleOffset = 0; | ||
| 641 | tuple->TupleDataMax = 255; | ||
| 642 | tuple->Attributes = 0; | ||
| 594 | /* Get configuration register information */ | 643 | /* Get configuration register information */ |
| 595 | tuple.DesiredTuple = CISTPL_CONFIG; | 644 | tuple->DesiredTuple = CISTPL_CONFIG; |
| 596 | last_ret = first_tuple(handle, &tuple, &parse); | 645 | last_ret = first_tuple(handle, tuple, parse); |
| 597 | if (last_ret != CS_SUCCESS) { | 646 | if (last_ret != CS_SUCCESS) { |
| 598 | last_fn = ParseTuple; | 647 | last_fn = ParseTuple; |
| 599 | goto cs_failed; | 648 | goto cs_failed; |
| 600 | } | 649 | } |
| 601 | link->conf.ConfigBase = parse.config.base; | 650 | link->conf.ConfigBase = parse->config.base; |
| 602 | link->conf.Present = parse.config.rmask[0]; | 651 | link->conf.Present = parse->config.rmask[0]; |
| 603 | 652 | ||
| 604 | /* Configure card */ | 653 | /* Configure card */ |
| 605 | link->state |= DEV_CONFIG; | 654 | link->state |= DEV_CONFIG; |
| 606 | 655 | ||
| 607 | /* Is this a compliant multifunction card? */ | 656 | /* Is this a compliant multifunction card? */ |
| 608 | tuple.DesiredTuple = CISTPL_LONGLINK_MFC; | 657 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; |
| 609 | tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; | 658 | tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; |
| 610 | info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); | 659 | info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS); |
| 611 | 660 | ||
| 612 | /* Is this a multiport card? */ | 661 | /* Is this a multiport card? */ |
| 613 | tuple.DesiredTuple = CISTPL_MANFID; | 662 | tuple->DesiredTuple = CISTPL_MANFID; |
| 614 | if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { | 663 | if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { |
| 615 | info->manfid = le16_to_cpu(buf[0]); | 664 | info->manfid = le16_to_cpu(buf[0]); |
| 616 | for (i = 0; i < MULTI_COUNT; i++) | 665 | for (i = 0; i < MULTI_COUNT; i++) |
| 617 | if ((info->manfid == multi_id[i].manfid) && | 666 | if ((info->manfid == multi_id[i].manfid) && |
| @@ -623,13 +672,13 @@ void serial_config(dev_link_t * link) | |||
| 623 | 672 | ||
| 624 | /* Another check for dual-serial cards: look for either serial or | 673 | /* Another check for dual-serial cards: look for either serial or |
| 625 | multifunction cards that ask for appropriate IO port ranges */ | 674 | multifunction cards that ask for appropriate IO port ranges */ |
| 626 | tuple.DesiredTuple = CISTPL_FUNCID; | 675 | tuple->DesiredTuple = CISTPL_FUNCID; |
| 627 | if ((info->multi == 0) && | 676 | if ((info->multi == 0) && |
| 628 | ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || | 677 | ((first_tuple(handle, tuple, parse) != CS_SUCCESS) || |
| 629 | (parse.funcid.func == CISTPL_FUNCID_MULTI) || | 678 | (parse->funcid.func == CISTPL_FUNCID_MULTI) || |
| 630 | (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { | 679 | (parse->funcid.func == CISTPL_FUNCID_SERIAL))) { |
| 631 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 680 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; |
| 632 | if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { | 681 | if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { |
| 633 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) | 682 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) |
| 634 | info->multi = cf->io.win[0].len >> 3; | 683 | info->multi = cf->io.win[0].len >> 3; |
| 635 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && | 684 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && |
| @@ -664,6 +713,7 @@ void serial_config(dev_link_t * link) | |||
| 664 | 713 | ||
| 665 | link->dev = &info->node[0]; | 714 | link->dev = &info->node[0]; |
| 666 | link->state &= ~DEV_CONFIG_PENDING; | 715 | link->state &= ~DEV_CONFIG_PENDING; |
| 716 | kfree(cfg_mem); | ||
| 667 | return; | 717 | return; |
| 668 | 718 | ||
| 669 | cs_failed: | 719 | cs_failed: |
| @@ -671,6 +721,7 @@ void serial_config(dev_link_t * link) | |||
| 671 | failed: | 721 | failed: |
| 672 | serial_remove(link); | 722 | serial_remove(link); |
| 673 | link->state &= ~DEV_CONFIG_PENDING; | 723 | link->state &= ~DEV_CONFIG_PENDING; |
| 724 | kfree(cfg_mem); | ||
| 674 | } | 725 | } |
| 675 | 726 | ||
| 676 | /*====================================================================== | 727 | /*====================================================================== |
