aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/serial_cs.c
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2010-07-30 07:13:46 -0400
committerDominik Brodowski <linux@dominikbrodowski.net>2010-09-29 11:20:24 -0400
commit00990e7ce0b0e596fe41d9c64d6933ea70084003 (patch)
tree189e0dd92860feba84231c66955749574cac5d6d /drivers/serial/serial_cs.c
parent440eed43e2a95bb842488755683716814da10f2b (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.c132
1 files changed, 67 insertions, 65 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index a796a93fe39..42252034293 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
427static int simple_config_check(struct pcmcia_device *p_dev, 427static 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
447static int simple_config_check_notpicky(struct pcmcia_device *p_dev, 448static 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
506static int multi_config_check(struct pcmcia_device *p_dev, 507static 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
526static int multi_config_check_notpicky(struct pcmcia_device *p_dev, 528static 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
545static int multi_config(struct pcmcia_device *link) 547static 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
614static int serial_check_for_multi(struct pcmcia_device *p_dev, 616static 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 */