diff options
-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 | /*====================================================================== |