aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/serial_cs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 12:13:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 12:13:29 -0400
commit6f3a28f7d1f0a65a78443c273b6e8ec01becf301 (patch)
treeea57276725b31ba115f44cb5267a7d85b133e6fb /drivers/serial/serial_cs.c
parent6ebfc0e20b409f13e62bbb84ce70102b49945cfd (diff)
parent75fde2eddcfcd1dcc87a72dc6cd3c859420b6148 (diff)
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-serial
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-serial: (21 commits) [SERIAL] add PNP IDs for FPI based touchscreens [SERIAL] Magic SysRq SAK does nothing on serial consoles [SERIAL] tickle NMI watchdog on serial output. [SERIAL] Fix oops when removing suspended serial port [SERIAL] Fix resume handling bug [SERIAL] Remove wrong asm/serial.h inclusions [SERIAL] CONFIG_PM=n slim: drivers/serial/8250_pci.c [SERIAL] OMAP1510 serial fix for 115200 baud [SERIAL] returning proper error from serial core driver [SERIAL] Make uart_line_info() correctly tell MMIO from I/O port [SERIAL] suspend/resume handlers don't have level arg anymore [SERIAL] 8250 resourse management fixes [SERIAL] serial_cs: Add quirk for brainboxes 2-port RS232 card [SERIAL] serial_cs: handle Nokia multi->single port bodge via config quirk [SERIAL] serial_cs: add configuration quirk [SERIAL] serial_cs: Convert Oxford 950 / Possio GCC wakeup quirk [SERIAL] serial_cs: convert IBM post-init handling to a quirk [SERIAL] serial_cs: allow wildcarded quirks [SERIAL] serial_cs: convert multi-port table to quirk table [SERIAL] serial_cs: Use clean up multiport card detection ...
Diffstat (limited to 'drivers/serial/serial_cs.c')
-rw-r--r--drivers/serial/serial_cs.c292
1 files changed, 215 insertions, 77 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index cbf260bc225d..00f9ffd69489 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -80,23 +80,16 @@ module_param(buggy_uart, int, 0444);
80 80
81/* Table of multi-port card ID's */ 81/* Table of multi-port card ID's */
82 82
83struct multi_id { 83struct serial_quirk {
84 u_short manfid; 84 unsigned int manfid;
85 u_short prodid; 85 unsigned int prodid;
86 int multi; /* 1 = multifunction, > 1 = # ports */ 86 int multi; /* 1 = multifunction, > 1 = # ports */
87 void (*config)(struct pcmcia_device *);
88 void (*setup)(struct pcmcia_device *, struct uart_port *);
89 void (*wakeup)(struct pcmcia_device *);
90 int (*post)(struct pcmcia_device *);
87}; 91};
88 92
89static const struct multi_id multi_id[] = {
90 { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
91 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
92 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
93 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
94 { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
95 { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
96 { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
97};
98#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
99
100struct serial_info { 93struct serial_info {
101 struct pcmcia_device *p_dev; 94 struct pcmcia_device *p_dev;
102 int ndev; 95 int ndev;
@@ -107,6 +100,7 @@ struct serial_info {
107 int c950ctrl; 100 int c950ctrl;
108 dev_node_t node[4]; 101 dev_node_t node[4];
109 int line[4]; 102 int line[4];
103 const struct serial_quirk *quirk;
110}; 104};
111 105
112struct serial_cfg_mem { 106struct serial_cfg_mem {
@@ -115,37 +109,165 @@ struct serial_cfg_mem {
115 u_char buf[256]; 109 u_char buf[256];
116}; 110};
117 111
112/*
113 * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
114 * manfid 0x0160, 0x0104
115 * This card appears to have a 14.7456MHz clock.
116 */
117static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
118{
119 port->uartclk = 14745600;
120}
118 121
119static int serial_config(struct pcmcia_device * link); 122static int quirk_post_ibm(struct pcmcia_device *link)
123{
124 conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
125 int last_ret, last_fn;
120 126
127 last_ret = pcmcia_access_configuration_register(link, &reg);
128 if (last_ret) {
129 last_fn = AccessConfigurationRegister;
130 goto cs_failed;
131 }
132 reg.Action = CS_WRITE;
133 reg.Value = reg.Value | 1;
134 last_ret = pcmcia_access_configuration_register(link, &reg);
135 if (last_ret) {
136 last_fn = AccessConfigurationRegister;
137 goto cs_failed;
138 }
139 return 0;
121 140
122static void wakeup_card(struct serial_info *info) 141 cs_failed:
142 cs_error(link, last_fn, last_ret);
143 return -ENODEV;
144}
145
146/*
147 * Nokia cards are not really multiport cards. Shouldn't this
148 * be handled by setting the quirk entry .multi = 0 | 1 ?
149 */
150static void quirk_config_nokia(struct pcmcia_device *link)
123{ 151{
124 int ctrl = info->c950ctrl; 152 struct serial_info *info = link->priv;
125 153
126 if (info->manfid == MANFID_OXSEMI) { 154 if (info->multi > 1)
127 outb(12, ctrl + 1); 155 info->multi = 1;
128 } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) { 156}
129 /* request_region? oxsemi branch does no request_region too... */ 157
130 /* This sequence is needed to properly initialize MC45 attached to OXCF950. 158static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
131 * I tried decreasing these msleep()s, but it worked properly (survived 159{
132 * 1000 stop/start operations) with these timeouts (or bigger). */ 160 struct serial_info *info = link->priv;
133 outb(0xA, ctrl + 1); 161
134 msleep(100); 162 outb(12, info->c950ctrl + 1);
135 outb(0xE, ctrl + 1); 163}
136 msleep(300); 164
137 outb(0xC, ctrl + 1); 165/* request_region? oxsemi branch does no request_region too... */
138 msleep(100); 166/*
139 outb(0xE, ctrl + 1); 167 * This sequence is needed to properly initialize MC45 attached to OXCF950.
140 msleep(200); 168 * I tried decreasing these msleep()s, but it worked properly (survived
141 outb(0xF, ctrl + 1); 169 * 1000 stop/start operations) with these timeouts (or bigger).
142 msleep(100); 170 */
143 outb(0xE, ctrl + 1); 171static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
144 msleep(100); 172{
145 outb(0xC, ctrl + 1); 173 struct serial_info *info = link->priv;
174 unsigned int ctrl = info->c950ctrl;
175
176 outb(0xA, ctrl + 1);
177 msleep(100);
178 outb(0xE, ctrl + 1);
179 msleep(300);
180 outb(0xC, ctrl + 1);
181 msleep(100);
182 outb(0xE, ctrl + 1);
183 msleep(200);
184 outb(0xF, ctrl + 1);
185 msleep(100);
186 outb(0xE, ctrl + 1);
187 msleep(100);
188 outb(0xC, ctrl + 1);
189}
190
191/*
192 * Socket Dual IO: this enables irq's for second port
193 */
194static void quirk_config_socket(struct pcmcia_device *link)
195{
196 struct serial_info *info = link->priv;
197
198 if (info->multi) {
199 link->conf.Present |= PRESENT_EXT_STATUS;
200 link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
146 } 201 }
147} 202}
148 203
204static const struct serial_quirk quirks[] = {
205 {
206 .manfid = 0x0160,
207 .prodid = 0x0104,
208 .multi = -1,
209 .setup = quirk_setup_brainboxes_0104,
210 }, {
211 .manfid = MANFID_IBM,
212 .prodid = ~0,
213 .multi = -1,
214 .post = quirk_post_ibm,
215 }, {
216 .manfid = MANFID_INTEL,
217 .prodid = PRODID_INTEL_DUAL_RS232,
218 .multi = 2,
219 }, {
220 .manfid = MANFID_NATINST,
221 .prodid = PRODID_NATINST_QUAD_RS232,
222 .multi = 4,
223 }, {
224 .manfid = MANFID_NOKIA,
225 .prodid = ~0,
226 .multi = -1,
227 .config = quirk_config_nokia,
228 }, {
229 .manfid = MANFID_OMEGA,
230 .prodid = PRODID_OMEGA_QSP_100,
231 .multi = 4,
232 }, {
233 .manfid = MANFID_OXSEMI,
234 .prodid = ~0,
235 .multi = -1,
236 .wakeup = quirk_wakeup_oxsemi,
237 }, {
238 .manfid = MANFID_POSSIO,
239 .prodid = PRODID_POSSIO_GCC,
240 .multi = -1,
241 .wakeup = quirk_wakeup_possio_gcc,
242 }, {
243 .manfid = MANFID_QUATECH,
244 .prodid = PRODID_QUATECH_DUAL_RS232,
245 .multi = 2,
246 }, {
247 .manfid = MANFID_QUATECH,
248 .prodid = PRODID_QUATECH_DUAL_RS232_D1,
249 .multi = 2,
250 }, {
251 .manfid = MANFID_QUATECH,
252 .prodid = PRODID_QUATECH_QUAD_RS232,
253 .multi = 4,
254 }, {
255 .manfid = MANFID_SOCKET,
256 .prodid = PRODID_SOCKET_DUAL_RS232,
257 .multi = 2,
258 .config = quirk_config_socket,
259 }, {
260 .manfid = MANFID_SOCKET,
261 .prodid = ~0,
262 .multi = -1,
263 .config = quirk_config_socket,
264 }
265};
266
267
268static int serial_config(struct pcmcia_device * link);
269
270
149/*====================================================================== 271/*======================================================================
150 272
151 After a card is removed, serial_remove() will unregister 273 After a card is removed, serial_remove() will unregister
@@ -185,14 +307,14 @@ static int serial_suspend(struct pcmcia_device *link)
185 307
186static int serial_resume(struct pcmcia_device *link) 308static int serial_resume(struct pcmcia_device *link)
187{ 309{
188 if (pcmcia_dev_present(link)) { 310 struct serial_info *info = link->priv;
189 struct serial_info *info = link->priv; 311 int i;
190 int i;
191 312
192 for (i = 0; i < info->ndev; i++) 313 for (i = 0; i < info->ndev; i++)
193 serial8250_resume_port(info->line[i]); 314 serial8250_resume_port(info->line[i]);
194 wakeup_card(info); 315
195 } 316 if (info->quirk && info->quirk->wakeup)
317 info->quirk->wakeup(link);
196 318
197 return 0; 319 return 0;
198} 320}
@@ -278,6 +400,10 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
278 port.dev = &handle_to_dev(handle); 400 port.dev = &handle_to_dev(handle);
279 if (buggy_uart) 401 if (buggy_uart)
280 port.flags |= UPF_BUGGY_UART; 402 port.flags |= UPF_BUGGY_UART;
403
404 if (info->quirk && info->quirk->setup)
405 info->quirk->setup(handle, &port);
406
281 line = serial8250_register_port(&port); 407 line = serial8250_register_port(&port);
282 if (line < 0) { 408 if (line < 0) {
283 printk(KERN_NOTICE "serial_cs: serial8250_register_port() at " 409 printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
@@ -433,6 +559,13 @@ next_entry:
433 } 559 }
434 if (info->multi && (info->manfid == MANFID_3COM)) 560 if (info->multi && (info->manfid == MANFID_3COM))
435 link->conf.ConfigIndex &= ~(0x08); 561 link->conf.ConfigIndex &= ~(0x08);
562
563 /*
564 * Apply any configuration quirks.
565 */
566 if (info->quirk && info->quirk->config)
567 info->quirk->config(link);
568
436 i = pcmcia_request_configuration(link, &link->conf); 569 i = pcmcia_request_configuration(link, &link->conf);
437 if (i != CS_SUCCESS) { 570 if (i != CS_SUCCESS) {
438 cs_error(link, RequestConfiguration, i); 571 cs_error(link, RequestConfiguration, i);
@@ -521,11 +654,13 @@ static int multi_config(struct pcmcia_device * link)
521 cs_error(link, RequestIRQ, i); 654 cs_error(link, RequestIRQ, i);
522 link->irq.AssignedIRQ = 0; 655 link->irq.AssignedIRQ = 0;
523 } 656 }
524 /* Socket Dual IO: this enables irq's for second port */ 657
525 if (info->multi && (info->manfid == MANFID_SOCKET)) { 658 /*
526 link->conf.Present |= PRESENT_EXT_STATUS; 659 * Apply any configuration quirks.
527 link->conf.ExtStatus = ESR_REQ_ATTN_ENA; 660 */
528 } 661 if (info->quirk && info->quirk->config)
662 info->quirk->config(link);
663
529 i = pcmcia_request_configuration(link, &link->conf); 664 i = pcmcia_request_configuration(link, &link->conf);
530 if (i != CS_SUCCESS) { 665 if (i != CS_SUCCESS) {
531 cs_error(link, RequestConfiguration, i); 666 cs_error(link, RequestConfiguration, i);
@@ -550,17 +685,19 @@ static int multi_config(struct pcmcia_device * link)
550 link->irq.AssignedIRQ); 685 link->irq.AssignedIRQ);
551 } 686 }
552 info->c950ctrl = base2; 687 info->c950ctrl = base2;
553 wakeup_card(info); 688
689 /*
690 * FIXME: We really should wake up the port prior to
691 * handing it over to the serial layer.
692 */
693 if (info->quirk && info->quirk->wakeup)
694 info->quirk->wakeup(link);
695
554 rc = 0; 696 rc = 0;
555 goto free_cfg_mem; 697 goto free_cfg_mem;
556 } 698 }
557 699
558 setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); 700 setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
559 /* The Nokia cards are not really multiport cards */
560 if (info->manfid == MANFID_NOKIA) {
561 rc = 0;
562 goto free_cfg_mem;
563 }
564 for (i = 0; i < info->multi - 1; i++) 701 for (i = 0; i < info->multi - 1; i++)
565 setup_serial(link, info, base2 + (8 * i), 702 setup_serial(link, info, base2 + (8 * i),
566 link->irq.AssignedIRQ); 703 link->irq.AssignedIRQ);
@@ -622,13 +759,16 @@ static int serial_config(struct pcmcia_device * link)
622 tuple->DesiredTuple = CISTPL_MANFID; 759 tuple->DesiredTuple = CISTPL_MANFID;
623 if (first_tuple(link, tuple, parse) == CS_SUCCESS) { 760 if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
624 info->manfid = parse->manfid.manf; 761 info->manfid = parse->manfid.manf;
625 info->prodid = le16_to_cpu(buf[1]); 762 info->prodid = parse->manfid.card;
626 for (i = 0; i < MULTI_COUNT; i++) 763
627 if ((info->manfid == multi_id[i].manfid) && 764 for (i = 0; i < ARRAY_SIZE(quirks); i++)
628 (parse->manfid.card == multi_id[i].prodid)) 765 if ((quirks[i].manfid == ~0 ||
766 quirks[i].manfid == info->manfid) &&
767 (quirks[i].prodid == ~0 ||
768 quirks[i].prodid == info->prodid)) {
769 info->quirk = &quirks[i];
629 break; 770 break;
630 if (i < MULTI_COUNT) 771 }
631 info->multi = multi_id[i].multi;
632 } 772 }
633 773
634 /* Another check for dual-serial cards: look for either serial or 774 /* Another check for dual-serial cards: look for either serial or
@@ -648,6 +788,12 @@ static int serial_config(struct pcmcia_device * link)
648 } 788 }
649 } 789 }
650 790
791 /*
792 * Apply any multi-port quirk.
793 */
794 if (info->quirk && info->quirk->multi != -1)
795 info->multi = info->quirk->multi;
796
651 if (info->multi > 1) 797 if (info->multi > 1)
652 multi_config(link); 798 multi_config(link);
653 else 799 else
@@ -656,21 +802,13 @@ static int serial_config(struct pcmcia_device * link)
656 if (info->ndev == 0) 802 if (info->ndev == 0)
657 goto failed; 803 goto failed;
658 804
659 if (info->manfid == MANFID_IBM) { 805 /*
660 conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; 806 * Apply any post-init quirk. FIXME: This should really happen
661 last_ret = pcmcia_access_configuration_register(link, &reg); 807 * before we register the port, since it might already be in use.
662 if (last_ret) { 808 */
663 last_fn = AccessConfigurationRegister; 809 if (info->quirk && info->quirk->post)
664 goto cs_failed; 810 if (info->quirk->post(link))
665 } 811 goto failed;
666 reg.Action = CS_WRITE;
667 reg.Value = reg.Value | 1;
668 last_ret = pcmcia_access_configuration_register(link, &reg);
669 if (last_ret) {
670 last_fn = AccessConfigurationRegister;
671 goto cs_failed;
672 }
673 }
674 812
675 link->dev_node = &info->node[0]; 813 link->dev_node = &info->node[0];
676 kfree(cfg_mem); 814 kfree(cfg_mem);