aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/serial_cs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/serial/serial_cs.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/serial/serial_cs.c')
-rw-r--r--drivers/serial/serial_cs.c747
1 files changed, 747 insertions, 0 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
new file mode 100644
index 000000000000..9034f9ad37c7
--- /dev/null
+++ b/drivers/serial/serial_cs.c
@@ -0,0 +1,747 @@
1/*======================================================================
2
3 A driver for PCMCIA serial devices
4
5 serial_cs.c 1.134 2002/05/04 05:48:53
6
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
11
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
16
17 The initial developer of the original code is David A. Hinds
18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU General Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
31
32======================================================================*/
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/kernel.h>
37#include <linux/init.h>
38#include <linux/sched.h>
39#include <linux/ptrace.h>
40#include <linux/slab.h>
41#include <linux/string.h>
42#include <linux/timer.h>
43#include <linux/serial_core.h>
44#include <linux/major.h>
45#include <asm/io.h>
46#include <asm/system.h>
47
48#include <pcmcia/version.h>
49#include <pcmcia/cs_types.h>
50#include <pcmcia/cs.h>
51#include <pcmcia/cistpl.h>
52#include <pcmcia/ciscode.h>
53#include <pcmcia/ds.h>
54#include <pcmcia/cisreg.h>
55
56#include "8250.h"
57
58#ifdef PCMCIA_DEBUG
59static int pc_debug = PCMCIA_DEBUG;
60module_param(pc_debug, int, 0644);
61#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
62static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
63#else
64#define DEBUG(n, args...)
65#endif
66
67/*====================================================================*/
68
69/* Parameters that can be set with 'insmod' */
70
71/* Enable the speaker? */
72static int do_sound = 1;
73/* Skip strict UART tests? */
74static int buggy_uart;
75
76module_param(do_sound, int, 0444);
77module_param(buggy_uart, int, 0444);
78
79/*====================================================================*/
80
81/* Table of multi-port card ID's */
82
83struct multi_id {
84 u_short manfid;
85 u_short prodid;
86 int multi; /* 1 = multifunction, > 1 = # ports */
87};
88
89static 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 {
101 dev_link_t link;
102 int ndev;
103 int multi;
104 int slave;
105 int manfid;
106 dev_node_t node[4];
107 int line[4];
108};
109
110static void serial_config(dev_link_t * link);
111static int serial_event(event_t event, int priority,
112 event_callback_args_t * args);
113
114static dev_info_t dev_info = "serial_cs";
115
116static dev_link_t *serial_attach(void);
117static void serial_detach(dev_link_t *);
118
119static dev_link_t *dev_list = NULL;
120
121/*======================================================================
122
123 After a card is removed, serial_remove() will unregister
124 the serial device(s), and release the PCMCIA configuration.
125
126======================================================================*/
127
128static void serial_remove(dev_link_t *link)
129{
130 struct serial_info *info = link->priv;
131 int i;
132
133 link->state &= ~DEV_PRESENT;
134
135 DEBUG(0, "serial_release(0x%p)\n", link);
136
137 /*
138 * Recheck to see if the device is still configured.
139 */
140 if (info->link.state & DEV_CONFIG) {
141 for (i = 0; i < info->ndev; i++)
142 serial8250_unregister_port(info->line[i]);
143
144 info->link.dev = NULL;
145
146 if (!info->slave) {
147 pcmcia_release_configuration(info->link.handle);
148 pcmcia_release_io(info->link.handle, &info->link.io);
149 pcmcia_release_irq(info->link.handle, &info->link.irq);
150 }
151
152 info->link.state &= ~DEV_CONFIG;
153 }
154}
155
156static void serial_suspend(dev_link_t *link)
157{
158 link->state |= DEV_SUSPEND;
159
160 if (link->state & DEV_CONFIG) {
161 struct serial_info *info = link->priv;
162 int i;
163
164 for (i = 0; i < info->ndev; i++)
165 serial8250_suspend_port(info->line[i]);
166
167 if (!info->slave)
168 pcmcia_release_configuration(link->handle);
169 }
170}
171
172static void serial_resume(dev_link_t *link)
173{
174 link->state &= ~DEV_SUSPEND;
175
176 if (DEV_OK(link)) {
177 struct serial_info *info = link->priv;
178 int i;
179
180 if (!info->slave)
181 pcmcia_request_configuration(link->handle, &link->conf);
182
183 for (i = 0; i < info->ndev; i++)
184 serial8250_resume_port(info->line[i]);
185 }
186}
187
188/*======================================================================
189
190 serial_attach() creates an "instance" of the driver, allocating
191 local data structures for one device. The device is registered
192 with Card Services.
193
194======================================================================*/
195
196static dev_link_t *serial_attach(void)
197{
198 struct serial_info *info;
199 client_reg_t client_reg;
200 dev_link_t *link;
201 int ret;
202
203 DEBUG(0, "serial_attach()\n");
204
205 /* Create new serial device */
206 info = kmalloc(sizeof (*info), GFP_KERNEL);
207 if (!info)
208 return NULL;
209 memset(info, 0, sizeof (*info));
210 link = &info->link;
211 link->priv = info;
212
213 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
214 link->io.NumPorts1 = 8;
215 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
216 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
217 link->conf.Attributes = CONF_ENABLE_IRQ;
218 if (do_sound) {
219 link->conf.Attributes |= CONF_ENABLE_SPKR;
220 link->conf.Status = CCSR_AUDIO_ENA;
221 }
222 link->conf.IntType = INT_MEMORY_AND_IO;
223
224 /* Register with Card Services */
225 link->next = dev_list;
226 dev_list = link;
227 client_reg.dev_info = &dev_info;
228 client_reg.EventMask =
229 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
230 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
231 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
232 client_reg.event_handler = &serial_event;
233 client_reg.Version = 0x0210;
234 client_reg.event_callback_args.client_data = link;
235 ret = pcmcia_register_client(&link->handle, &client_reg);
236 if (ret != CS_SUCCESS) {
237 cs_error(link->handle, RegisterClient, ret);
238 serial_detach(link);
239 return NULL;
240 }
241
242 return link;
243}
244
245/*======================================================================
246
247 This deletes a driver "instance". The device is de-registered
248 with Card Services. If it has been released, all local data
249 structures are freed. Otherwise, the structures will be freed
250 when the device is released.
251
252======================================================================*/
253
254static void serial_detach(dev_link_t * link)
255{
256 struct serial_info *info = link->priv;
257 dev_link_t **linkp;
258 int ret;
259
260 DEBUG(0, "serial_detach(0x%p)\n", link);
261
262 /* Locate device structure */
263 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
264 if (*linkp == link)
265 break;
266 if (*linkp == NULL)
267 return;
268
269 /*
270 * Ensure any outstanding scheduled tasks are completed.
271 */
272 flush_scheduled_work();
273
274 /*
275 * Ensure that the ports have been released.
276 */
277 serial_remove(link);
278
279 if (link->handle) {
280 ret = pcmcia_deregister_client(link->handle);
281 if (ret != CS_SUCCESS)
282 cs_error(link->handle, DeregisterClient, ret);
283 }
284
285 /* Unlink device structure, free bits */
286 *linkp = link->next;
287 kfree(info);
288}
289
290/*====================================================================*/
291
292static int setup_serial(client_handle_t handle, struct serial_info * info,
293 kio_addr_t iobase, int irq)
294{
295 struct uart_port port;
296 int line;
297
298 memset(&port, 0, sizeof (struct uart_port));
299 port.iobase = iobase;
300 port.irq = irq;
301 port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
302 port.uartclk = 1843200;
303 port.dev = &handle_to_dev(handle);
304 if (buggy_uart)
305 port.flags |= UPF_BUGGY_UART;
306 line = serial8250_register_port(&port);
307 if (line < 0) {
308 printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
309 "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
310 return -EINVAL;
311 }
312
313 info->line[info->ndev] = line;
314 sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
315 info->node[info->ndev].major = TTY_MAJOR;
316 info->node[info->ndev].minor = 0x40 + line;
317 if (info->ndev > 0)
318 info->node[info->ndev - 1].next = &info->node[info->ndev];
319 info->ndev++;
320
321 return 0;
322}
323
324/*====================================================================*/
325
326static int
327first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
328{
329 int i;
330 i = pcmcia_get_first_tuple(handle, tuple);
331 if (i != CS_SUCCESS)
332 return CS_NO_MORE_ITEMS;
333 i = pcmcia_get_tuple_data(handle, tuple);
334 if (i != CS_SUCCESS)
335 return i;
336 return pcmcia_parse_tuple(handle, tuple, parse);
337}
338
339static int
340next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
341{
342 int i;
343 i = pcmcia_get_next_tuple(handle, tuple);
344 if (i != CS_SUCCESS)
345 return CS_NO_MORE_ITEMS;
346 i = pcmcia_get_tuple_data(handle, tuple);
347 if (i != CS_SUCCESS)
348 return i;
349 return pcmcia_parse_tuple(handle, tuple, parse);
350}
351
352/*====================================================================*/
353
354static int simple_config(dev_link_t *link)
355{
356 static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
357 static int size_table[2] = { 8, 16 };
358 client_handle_t handle = link->handle;
359 struct serial_info *info = link->priv;
360 tuple_t tuple;
361 u_char buf[256];
362 cisparse_t parse;
363 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
364 config_info_t config;
365 int i, j, try;
366 int s;
367
368 /* If the card is already configured, look up the port and irq */
369 i = pcmcia_get_configuration_info(handle, &config);
370 if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
371 kio_addr_t port = 0;
372 if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
373 port = config.BasePort2;
374 info->slave = 1;
375 } else if ((info->manfid == MANFID_OSITECH) &&
376 (config.NumPorts1 == 0x40)) {
377 port = config.BasePort1 + 0x28;
378 info->slave = 1;
379 }
380 if (info->slave)
381 return setup_serial(handle, info, port, config.AssignedIRQ);
382 }
383 link->conf.Vcc = config.Vcc;
384
385 /* First pass: look for a config entry that looks normal. */
386 tuple.TupleData = (cisdata_t *) buf;
387 tuple.TupleOffset = 0;
388 tuple.TupleDataMax = 255;
389 tuple.Attributes = 0;
390 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
391 /* Two tries: without IO aliases, then with aliases */
392 for (s = 0; s < 2; s++) {
393 for (try = 0; try < 2; try++) {
394 i = first_tuple(handle, &tuple, &parse);
395 while (i != CS_NO_MORE_ITEMS) {
396 if (i != CS_SUCCESS)
397 goto next_entry;
398 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
399 link->conf.Vpp1 = link->conf.Vpp2 =
400 cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
401 if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
402 (cf->io.win[0].base != 0)) {
403 link->conf.ConfigIndex = cf->index;
404 link->io.BasePort1 = cf->io.win[0].base;
405 link->io.IOAddrLines = (try == 0) ?
406 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
407 i = pcmcia_request_io(link->handle, &link->io);
408 if (i == CS_SUCCESS)
409 goto found_port;
410 }
411next_entry:
412 i = next_tuple(handle, &tuple, &parse);
413 }
414 }
415 }
416 /* Second pass: try to find an entry that isn't picky about
417 its base address, then try to grab any standard serial port
418 address, and finally try to get any free port. */
419 i = first_tuple(handle, &tuple, &parse);
420 while (i != CS_NO_MORE_ITEMS) {
421 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
422 ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
423 link->conf.ConfigIndex = cf->index;
424 for (j = 0; j < 5; j++) {
425 link->io.BasePort1 = base[j];
426 link->io.IOAddrLines = base[j] ? 16 : 3;
427 i = pcmcia_request_io(link->handle, &link->io);
428 if (i == CS_SUCCESS)
429 goto found_port;
430 }
431 }
432 i = next_tuple(handle, &tuple, &parse);
433 }
434
435 found_port:
436 if (i != CS_SUCCESS) {
437 printk(KERN_NOTICE
438 "serial_cs: no usable port range found, giving up\n");
439 cs_error(link->handle, RequestIO, i);
440 return -1;
441 }
442
443 i = pcmcia_request_irq(link->handle, &link->irq);
444 if (i != CS_SUCCESS) {
445 cs_error(link->handle, RequestIRQ, i);
446 link->irq.AssignedIRQ = 0;
447 }
448 if (info->multi && (info->manfid == MANFID_3COM))
449 link->conf.ConfigIndex &= ~(0x08);
450 i = pcmcia_request_configuration(link->handle, &link->conf);
451 if (i != CS_SUCCESS) {
452 cs_error(link->handle, RequestConfiguration, i);
453 return -1;
454 }
455
456 return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
457}
458
459static int multi_config(dev_link_t * link)
460{
461 client_handle_t handle = link->handle;
462 struct serial_info *info = link->priv;
463 tuple_t tuple;
464 u_char buf[256];
465 cisparse_t parse;
466 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
467 config_info_t config;
468 int i, base2 = 0;
469
470 i = pcmcia_get_configuration_info(handle, &config);
471 if (i != CS_SUCCESS) {
472 cs_error(handle, GetConfigurationInfo, i);
473 return -1;
474 }
475 link->conf.Vcc = config.Vcc;
476
477 tuple.TupleData = (cisdata_t *) buf;
478 tuple.TupleOffset = 0;
479 tuple.TupleDataMax = 255;
480 tuple.Attributes = 0;
481 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
482
483 /* First, look for a generic full-sized window */
484 link->io.NumPorts1 = info->multi * 8;
485 i = first_tuple(handle, &tuple, &parse);
486 while (i != CS_NO_MORE_ITEMS) {
487 /* 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 */
489 if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
490 (cf->io.win[0].len > 8)) {
491 link->conf.ConfigIndex = cf->index;
492 link->io.BasePort1 = cf->io.win[0].base;
493 link->io.IOAddrLines =
494 cf->io.flags & CISTPL_IO_LINES_MASK;
495 i = pcmcia_request_io(link->handle, &link->io);
496 base2 = link->io.BasePort1 + 8;
497 if (i == CS_SUCCESS)
498 break;
499 }
500 i = next_tuple(handle, &tuple, &parse);
501 }
502
503 /* If that didn't work, look for two windows */
504 if (i != CS_SUCCESS) {
505 link->io.NumPorts1 = link->io.NumPorts2 = 8;
506 info->multi = 2;
507 i = first_tuple(handle, &tuple, &parse);
508 while (i != CS_NO_MORE_ITEMS) {
509 if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
510 link->conf.ConfigIndex = cf->index;
511 link->io.BasePort1 = cf->io.win[0].base;
512 link->io.BasePort2 = cf->io.win[1].base;
513 link->io.IOAddrLines =
514 cf->io.flags & CISTPL_IO_LINES_MASK;
515 i = pcmcia_request_io(link->handle, &link->io);
516 base2 = link->io.BasePort2;
517 if (i == CS_SUCCESS)
518 break;
519 }
520 i = next_tuple(handle, &tuple, &parse);
521 }
522 }
523
524 if (i != CS_SUCCESS) {
525 cs_error(link->handle, RequestIO, i);
526 return -1;
527 }
528
529 i = pcmcia_request_irq(link->handle, &link->irq);
530 if (i != CS_SUCCESS) {
531 printk(KERN_NOTICE
532 "serial_cs: no usable port range found, giving up\n");
533 cs_error(link->handle, RequestIRQ, i);
534 link->irq.AssignedIRQ = 0;
535 }
536 /* Socket Dual IO: this enables irq's for second port */
537 if (info->multi && (info->manfid == MANFID_SOCKET)) {
538 link->conf.Present |= PRESENT_EXT_STATUS;
539 link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
540 }
541 i = pcmcia_request_configuration(link->handle, &link->conf);
542 if (i != CS_SUCCESS) {
543 cs_error(link->handle, RequestConfiguration, i);
544 return -1;
545 }
546
547 /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
548 8 registers are for the UART, the others are extra registers */
549 if (info->manfid == MANFID_OXSEMI) {
550 if (cf->index == 1 || cf->index == 3) {
551 setup_serial(handle, info, base2, link->irq.AssignedIRQ);
552 outb(12, link->io.BasePort1 + 1);
553 } else {
554 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
555 outb(12, base2 + 1);
556 }
557 return 0;
558 }
559
560 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
561 /* The Nokia cards are not really multiport cards */
562 if (info->manfid == MANFID_NOKIA)
563 return 0;
564 for (i = 0; i < info->multi - 1; i++)
565 setup_serial(handle, info, base2 + (8 * i), link->irq.AssignedIRQ);
566
567 return 0;
568}
569
570/*======================================================================
571
572 serial_config() is scheduled to run after a CARD_INSERTION event
573 is received, to configure the PCMCIA socket, and to make the
574 serial device available to the system.
575
576======================================================================*/
577
578void serial_config(dev_link_t * link)
579{
580 client_handle_t handle = link->handle;
581 struct serial_info *info = link->priv;
582 tuple_t tuple;
583 u_short buf[128];
584 cisparse_t parse;
585 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
586 int i, last_ret, last_fn;
587
588 DEBUG(0, "serial_config(0x%p)\n", link);
589
590 tuple.TupleData = (cisdata_t *) buf;
591 tuple.TupleOffset = 0;
592 tuple.TupleDataMax = 255;
593 tuple.Attributes = 0;
594 /* Get configuration register information */
595 tuple.DesiredTuple = CISTPL_CONFIG;
596 last_ret = first_tuple(handle, &tuple, &parse);
597 if (last_ret != CS_SUCCESS) {
598 last_fn = ParseTuple;
599 goto cs_failed;
600 }
601 link->conf.ConfigBase = parse.config.base;
602 link->conf.Present = parse.config.rmask[0];
603
604 /* Configure card */
605 link->state |= DEV_CONFIG;
606
607 /* Is this a compliant multifunction card? */
608 tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
609 tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
610 info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
611
612 /* Is this a multiport card? */
613 tuple.DesiredTuple = CISTPL_MANFID;
614 if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
615 info->manfid = le16_to_cpu(buf[0]);
616 for (i = 0; i < MULTI_COUNT; i++)
617 if ((info->manfid == multi_id[i].manfid) &&
618 (le16_to_cpu(buf[1]) == multi_id[i].prodid))
619 break;
620 if (i < MULTI_COUNT)
621 info->multi = multi_id[i].multi;
622 }
623
624 /* Another check for dual-serial cards: look for either serial or
625 multifunction cards that ask for appropriate IO port ranges */
626 tuple.DesiredTuple = CISTPL_FUNCID;
627 if ((info->multi == 0) &&
628 ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
629 (parse.funcid.func == CISTPL_FUNCID_MULTI) ||
630 (parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
631 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
632 if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
633 if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
634 info->multi = cf->io.win[0].len >> 3;
635 if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
636 (cf->io.win[1].len == 8))
637 info->multi = 2;
638 }
639 }
640
641 if (info->multi > 1)
642 multi_config(link);
643 else
644 simple_config(link);
645
646 if (info->ndev == 0)
647 goto failed;
648
649 if (info->manfid == MANFID_IBM) {
650 conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
651 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
652 if (last_ret) {
653 last_fn = AccessConfigurationRegister;
654 goto cs_failed;
655 }
656 reg.Action = CS_WRITE;
657 reg.Value = reg.Value | 1;
658 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
659 if (last_ret) {
660 last_fn = AccessConfigurationRegister;
661 goto cs_failed;
662 }
663 }
664
665 link->dev = &info->node[0];
666 link->state &= ~DEV_CONFIG_PENDING;
667 return;
668
669 cs_failed:
670 cs_error(link->handle, last_fn, last_ret);
671 failed:
672 serial_remove(link);
673 link->state &= ~DEV_CONFIG_PENDING;
674}
675
676/*======================================================================
677
678 The card status event handler. Mostly, this schedules other
679 stuff to run after an event is received. A CARD_REMOVAL event
680 also sets some flags to discourage the serial drivers from
681 talking to the ports.
682
683======================================================================*/
684
685static int
686serial_event(event_t event, int priority, event_callback_args_t * args)
687{
688 dev_link_t *link = args->client_data;
689 struct serial_info *info = link->priv;
690
691 DEBUG(1, "serial_event(0x%06x)\n", event);
692
693 switch (event) {
694 case CS_EVENT_CARD_REMOVAL:
695 serial_remove(link);
696 break;
697
698 case CS_EVENT_CARD_INSERTION:
699 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
700 serial_config(link);
701 break;
702
703 case CS_EVENT_PM_SUSPEND:
704 serial_suspend(link);
705 break;
706
707 case CS_EVENT_RESET_PHYSICAL:
708 if ((link->state & DEV_CONFIG) && !info->slave)
709 pcmcia_release_configuration(link->handle);
710 break;
711
712 case CS_EVENT_PM_RESUME:
713 serial_resume(link);
714 break;
715
716 case CS_EVENT_CARD_RESET:
717 if (DEV_OK(link) && !info->slave)
718 pcmcia_request_configuration(link->handle, &link->conf);
719 break;
720 }
721 return 0;
722}
723
724static struct pcmcia_driver serial_cs_driver = {
725 .owner = THIS_MODULE,
726 .drv = {
727 .name = "serial_cs",
728 },
729 .attach = serial_attach,
730 .detach = serial_detach,
731};
732
733static int __init init_serial_cs(void)
734{
735 return pcmcia_register_driver(&serial_cs_driver);
736}
737
738static void __exit exit_serial_cs(void)
739{
740 pcmcia_unregister_driver(&serial_cs_driver);
741 BUG_ON(dev_list != NULL);
742}
743
744module_init(init_serial_cs);
745module_exit(exit_serial_cs);
746
747MODULE_LICENSE("GPL");