diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/serial_cs.c | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 389d847cd1b4..2c70773543e0 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/timer.h> | 42 | #include <linux/timer.h> |
43 | #include <linux/serial_core.h> | 43 | #include <linux/serial_core.h> |
44 | #include <linux/delay.h> | ||
44 | #include <linux/major.h> | 45 | #include <linux/major.h> |
45 | #include <asm/io.h> | 46 | #include <asm/io.h> |
46 | #include <asm/system.h> | 47 | #include <asm/system.h> |
@@ -102,6 +103,8 @@ struct serial_info { | |||
102 | int multi; | 103 | int multi; |
103 | int slave; | 104 | int slave; |
104 | int manfid; | 105 | int manfid; |
106 | int prodid; | ||
107 | int c950ctrl; | ||
105 | dev_node_t node[4]; | 108 | dev_node_t node[4]; |
106 | int line[4]; | 109 | int line[4]; |
107 | }; | 110 | }; |
@@ -116,6 +119,33 @@ struct serial_cfg_mem { | |||
116 | static int serial_config(struct pcmcia_device * link); | 119 | static int serial_config(struct pcmcia_device * link); |
117 | 120 | ||
118 | 121 | ||
122 | static void wakeup_card(struct serial_info *info) | ||
123 | { | ||
124 | int ctrl = info->c950ctrl; | ||
125 | |||
126 | if (info->manfid == MANFID_OXSEMI) { | ||
127 | outb(12, ctrl + 1); | ||
128 | } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) { | ||
129 | /* request_region? oxsemi branch does no request_region too... */ | ||
130 | /* This sequence is needed to properly initialize MC45 attached to OXCF950. | ||
131 | * I tried decreasing these msleep()s, but it worked properly (survived | ||
132 | * 1000 stop/start operations) with these timeouts (or bigger). */ | ||
133 | outb(0xA, ctrl + 1); | ||
134 | msleep(100); | ||
135 | outb(0xE, ctrl + 1); | ||
136 | msleep(300); | ||
137 | outb(0xC, ctrl + 1); | ||
138 | msleep(100); | ||
139 | outb(0xE, ctrl + 1); | ||
140 | msleep(200); | ||
141 | outb(0xF, ctrl + 1); | ||
142 | msleep(100); | ||
143 | outb(0xE, ctrl + 1); | ||
144 | msleep(100); | ||
145 | outb(0xC, ctrl + 1); | ||
146 | } | ||
147 | } | ||
148 | |||
119 | /*====================================================================== | 149 | /*====================================================================== |
120 | 150 | ||
121 | After a card is removed, serial_remove() will unregister | 151 | After a card is removed, serial_remove() will unregister |
@@ -161,6 +191,7 @@ static int serial_resume(struct pcmcia_device *link) | |||
161 | 191 | ||
162 | for (i = 0; i < info->ndev; i++) | 192 | for (i = 0; i < info->ndev; i++) |
163 | serial8250_resume_port(info->line[i]); | 193 | serial8250_resume_port(info->line[i]); |
194 | wakeup_card(info); | ||
164 | } | 195 | } |
165 | 196 | ||
166 | return 0; | 197 | return 0; |
@@ -503,15 +534,23 @@ static int multi_config(struct pcmcia_device * link) | |||
503 | } | 534 | } |
504 | 535 | ||
505 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: | 536 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: |
506 | 8 registers are for the UART, the others are extra registers */ | 537 | * 8 registers are for the UART, the others are extra registers. |
507 | if (info->manfid == MANFID_OXSEMI) { | 538 | * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too. |
539 | */ | ||
540 | if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && | ||
541 | info->prodid == PRODID_POSSIO_GCC)) { | ||
542 | int err; | ||
543 | |||
508 | if (cf->index == 1 || cf->index == 3) { | 544 | if (cf->index == 1 || cf->index == 3) { |
509 | setup_serial(link, info, base2, link->irq.AssignedIRQ); | 545 | err = setup_serial(link, info, base2, |
510 | outb(12, link->io.BasePort1 + 1); | 546 | link->irq.AssignedIRQ); |
547 | base2 = link->io.BasePort1; | ||
511 | } else { | 548 | } else { |
512 | setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); | 549 | err = setup_serial(link, info, link->io.BasePort1, |
513 | outb(12, base2 + 1); | 550 | link->irq.AssignedIRQ); |
514 | } | 551 | } |
552 | info->c950ctrl = base2; | ||
553 | wakeup_card(info); | ||
515 | rc = 0; | 554 | rc = 0; |
516 | goto free_cfg_mem; | 555 | goto free_cfg_mem; |
517 | } | 556 | } |
@@ -583,6 +622,7 @@ static int serial_config(struct pcmcia_device * link) | |||
583 | tuple->DesiredTuple = CISTPL_MANFID; | 622 | tuple->DesiredTuple = CISTPL_MANFID; |
584 | if (first_tuple(link, tuple, parse) == CS_SUCCESS) { | 623 | if (first_tuple(link, tuple, parse) == CS_SUCCESS) { |
585 | info->manfid = parse->manfid.manf; | 624 | info->manfid = parse->manfid.manf; |
625 | info->prodid = le16_to_cpu(buf[1]); | ||
586 | for (i = 0; i < MULTI_COUNT; i++) | 626 | for (i = 0; i < MULTI_COUNT; i++) |
587 | if ((info->manfid == multi_id[i].manfid) && | 627 | if ((info->manfid == multi_id[i].manfid) && |
588 | (parse->manfid.card == multi_id[i].prodid)) | 628 | (parse->manfid.card == multi_id[i].prodid)) |