1 /*======================================================================
2
3 A driver for PCMCIA serial devices
4
5 serial_cs.c 1.138 2002/10/25 06:24:52
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
23 which 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/kernel.h>
36 #include <linux/init.h>
37 #include <linux/sched.h>
38 #include <linux/ptrace.h>
39 #include <linux/slab.h>
40 #include <linux/string.h>
41 #include <linux/timer.h>
42 #include <linux/tty.h>
43 #include <linux/serial.h>
44 #include <linux/major.h>
45 #include <asm/io.h>
46 #include <asm/system.h>
47 #include <asm/byteorder.h>
48
49 #include <pcmcia/version.h>
50 #include <pcmcia/cs_types.h>
51 #include <pcmcia/cs.h>
52 #include <pcmcia/cistpl.h>
53 #include <pcmcia/ciscode.h>
54 #include <pcmcia/ds.h>
55 #include <pcmcia/cisreg.h>
56
57 /*====================================================================*/
58
59 /* Module parameters */
60
61 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
62 MODULE_DESCRIPTION("PCMCIA serial card driver");
63 MODULE_LICENSE("Dual MPL/GPL");
64
65 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
66
67 /* Bit map of interrupts to choose from */
68 INT_MODULE_PARM(irq_mask, 0xdeb8);
69 static int irq_list[4] = { -1 };
70 MODULE_PARM(irq_list, "1-4i");
71
72 INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */
73 INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */
74
75 #ifdef PCMCIA_DEBUG
76 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
77 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
78 static char *version =
79 "serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
80 #else
81 #define DEBUG(n, args...)
82 #endif
83
84 /*====================================================================*/
85
86 /* Table of multi-port card ID's */
87
88 typedef struct {
89 u_short manfid;
90 u_short prodid;
91 int multi; /* 1 = multifunction, > 1 = # ports */
92 } multi_id_t;
93
94 static multi_id_t multi_id[] = {
95 { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
96 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
97 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
98 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
99 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
100 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
101 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
102 { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
103 { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
104 { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
105 };
106 #define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t))
107
108 typedef struct serial_info_t {
109 dev_link_t link;
110 int ndev;
111 int multi;
112 int slave;
113 int manfid;
114 dev_node_t node[4];
115 int line[4];
116 } serial_info_t;
117
118 static void serial_config(dev_link_t *link);
119 static void serial_release(u_long arg);
120 static int serial_event(event_t event, int priority,
121 event_callback_args_t *args);
122
123 static dev_info_t dev_info = "serial_cs";
124
125 static dev_link_t *serial_attach(void);
126 static void serial_detach(dev_link_t *);
127
128 static dev_link_t *dev_list = NULL;
129
130 /*====================================================================*/
131
cs_error(client_handle_t handle,int func,int ret)132 static void cs_error(client_handle_t handle, int func, int ret)
133 {
134 error_info_t err = { func, ret };
135 CardServices(ReportError, handle, &err);
136 }
137
138 /*======================================================================
139
140 serial_attach() creates an "instance" of the driver, allocating
141 local data structures for one device. The device is registered
142 with Card Services.
143
144 ======================================================================*/
145
serial_attach(void)146 static dev_link_t *serial_attach(void)
147 {
148 serial_info_t *info;
149 client_reg_t client_reg;
150 dev_link_t *link;
151 int i, ret;
152
153 DEBUG(0, "serial_attach()\n");
154
155 /* Create new serial device */
156 info = kmalloc(sizeof(*info), GFP_KERNEL);
157 if (!info) return NULL;
158 memset(info, 0, sizeof(*info));
159 link = &info->link; link->priv = info;
160
161 link->release.function = &serial_release;
162 link->release.data = (u_long)link;
163 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
164 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
165 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
166 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
167 if (irq_list[0] == -1)
168 link->irq.IRQInfo2 = irq_mask;
169 else
170 for (i = 0; i < 4; i++)
171 link->irq.IRQInfo2 |= 1 << irq_list[i];
172 link->conf.Attributes = CONF_ENABLE_IRQ;
173 if (do_sound) {
174 link->conf.Attributes |= CONF_ENABLE_SPKR;
175 link->conf.Status = CCSR_AUDIO_ENA;
176 }
177 link->conf.IntType = INT_MEMORY_AND_IO;
178
179 /* Register with Card Services */
180 link->next = dev_list;
181 dev_list = link;
182 client_reg.dev_info = &dev_info;
183 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
184 client_reg.EventMask =
185 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
186 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
187 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
188 client_reg.event_handler = &serial_event;
189 client_reg.Version = 0x0210;
190 client_reg.event_callback_args.client_data = link;
191 ret = CardServices(RegisterClient, &link->handle, &client_reg);
192 if (ret != CS_SUCCESS) {
193 cs_error(link->handle, RegisterClient, ret);
194 serial_detach(link);
195 return NULL;
196 }
197
198 return link;
199 } /* serial_attach */
200
201 /*======================================================================
202
203 This deletes a driver "instance". The device is de-registered
204 with Card Services. If it has been released, all local data
205 structures are freed. Otherwise, the structures will be freed
206 when the device is released.
207
208 ======================================================================*/
209
serial_detach(dev_link_t * link)210 static void serial_detach(dev_link_t *link)
211 {
212 serial_info_t *info = link->priv;
213 dev_link_t **linkp;
214 int ret;
215
216 DEBUG(0, "serial_detach(0x%p)\n", link);
217
218 /* Locate device structure */
219 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
220 if (*linkp == link) break;
221 if (*linkp == NULL)
222 return;
223
224 del_timer(&link->release);
225 if (link->state & DEV_CONFIG)
226 serial_release((u_long)link);
227
228 if (link->handle) {
229 ret = CardServices(DeregisterClient, link->handle);
230 if (ret != CS_SUCCESS)
231 cs_error(link->handle, DeregisterClient, ret);
232 }
233
234 /* Unlink device structure, free bits */
235 *linkp = link->next;
236 kfree(info);
237
238 } /* serial_detach */
239
240 /*====================================================================*/
241
setup_serial(serial_info_t * info,ioaddr_t port,int irq)242 static int setup_serial(serial_info_t *info, ioaddr_t port, int irq)
243 {
244 struct serial_struct serial;
245 int line;
246
247 memset(&serial, 0, sizeof(serial));
248 serial.port = port;
249 serial.irq = irq;
250 serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
251 if (buggy_uart)
252 serial.flags |= ASYNC_BUGGY_UART;
253 line = register_serial(&serial);
254 if (line < 0) {
255 printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
256 " irq %d failed\n", (u_long)serial.port, serial.irq);
257 return -1;
258 }
259
260 info->line[info->ndev] = line;
261 sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
262 info->node[info->ndev].major = TTY_MAJOR;
263 info->node[info->ndev].minor = 0x40+line;
264 if (info->ndev > 0)
265 info->node[info->ndev-1].next = &info->node[info->ndev];
266 info->ndev++;
267
268 return 0;
269 }
270
271 /*====================================================================*/
272
get_tuple(int fn,client_handle_t handle,tuple_t * tuple,cisparse_t * parse)273 static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
274 cisparse_t *parse)
275 {
276 int i;
277 i = CardServices(fn, handle, tuple);
278 if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS;
279 i = CardServices(GetTupleData, handle, tuple);
280 if (i != CS_SUCCESS) return i;
281 return CardServices(ParseTuple, handle, tuple, parse);
282 }
283
284 #define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
285 #define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
286
287 /*====================================================================*/
288
simple_config(dev_link_t * link)289 static int simple_config(dev_link_t *link)
290 {
291 static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
292 client_handle_t handle = link->handle;
293 serial_info_t *info = link->priv;
294 tuple_t tuple;
295 u_char buf[256];
296 cisparse_t parse;
297 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
298 config_info_t config;
299 int i, j, try;
300
301 /* If the card is already configured, look up the port and irq */
302 i = CardServices(GetConfigurationInfo, handle, &config);
303 if ((i == CS_SUCCESS) &&
304 (config.Attributes & CONF_VALID_CLIENT)) {
305 ioaddr_t port = 0;
306 if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
307 port = config.BasePort2;
308 info->slave = 1;
309 } else if ((info->manfid == MANFID_OSITECH) &&
310 (config.NumPorts1 == 0x40)) {
311 port = config.BasePort1 + 0x28;
312 info->slave = 1;
313 }
314 if (info->slave)
315 return setup_serial(info, port, config.AssignedIRQ);
316 }
317 link->conf.Vcc = config.Vcc;
318
319 link->io.NumPorts1 = 8;
320 link->io.NumPorts2 = 0;
321
322 /* First pass: look for a config entry that looks normal. */
323 tuple.TupleData = (cisdata_t *)buf;
324 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
325 tuple.Attributes = 0;
326 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
327 /* Two tries: without IO aliases, then with aliases */
328 for (try = 0; try < 2; try++) {
329 i = first_tuple(handle, &tuple, &parse);
330 while (i != CS_NO_MORE_ITEMS) {
331 if (i != CS_SUCCESS) goto next_entry;
332 if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM))
333 link->conf.Vpp1 = link->conf.Vpp2 =
334 cf->vpp1.param[CISTPL_POWER_VNOM]/10000;
335 if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
336 (cf->io.win[0].base != 0)) {
337 link->conf.ConfigIndex = cf->index;
338 link->io.BasePort1 = cf->io.win[0].base;
339 link->io.IOAddrLines = (try == 0) ?
340 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
341 i = CardServices(RequestIO, link->handle, &link->io);
342 if (i == CS_SUCCESS) goto found_port;
343 }
344 next_entry:
345 i = next_tuple(handle, &tuple, &parse);
346 }
347 }
348
349 /* Second pass: try to find an entry that isn't picky about
350 its base address, then try to grab any standard serial port
351 address, and finally try to get any free port. */
352 i = first_tuple(handle, &tuple, &parse);
353 while (i != CS_NO_MORE_ITEMS) {
354 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
355 ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
356 link->conf.ConfigIndex = cf->index;
357 for (j = 0; j < 5; j++) {
358 link->io.BasePort1 = base[j];
359 link->io.IOAddrLines = base[j] ? 16 : 3;
360 i = CardServices(RequestIO, link->handle, &link->io);
361 if (i == CS_SUCCESS) goto found_port;
362 }
363 }
364 i = next_tuple(handle, &tuple, &parse);
365 }
366
367 found_port:
368 if (i != CS_SUCCESS) {
369 cs_error(link->handle, RequestIO, i);
370 return -1;
371 }
372
373 i = CardServices(RequestIRQ, link->handle, &link->irq);
374 if (i != CS_SUCCESS) {
375 cs_error(link->handle, RequestIRQ, i);
376 link->irq.AssignedIRQ = 0;
377 }
378 if (info->multi && (info->manfid == MANFID_3COM))
379 link->conf.ConfigIndex &= ~(0x08);
380 i = CardServices(RequestConfiguration, link->handle, &link->conf);
381 if (i != CS_SUCCESS) {
382 cs_error(link->handle, RequestConfiguration, i);
383 return -1;
384 }
385
386 return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
387 }
388
multi_config(dev_link_t * link)389 static int multi_config(dev_link_t *link)
390 {
391 client_handle_t handle = link->handle;
392 serial_info_t *info = link->priv;
393 tuple_t tuple;
394 u_char buf[256];
395 cisparse_t parse;
396 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
397 config_info_t config;
398 int i, base2 = 0;
399
400 CardServices(GetConfigurationInfo, handle, &config);
401 link->conf.Vcc = config.Vcc;
402
403 tuple.TupleData = (cisdata_t *)buf;
404 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
405 tuple.Attributes = 0;
406 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
407
408 /* First, look for a generic full-sized window */
409 link->io.NumPorts1 = info->multi * 8;
410 i = first_tuple(handle, &tuple, &parse);
411 while (i != CS_NO_MORE_ITEMS) {
412 /* The quad port cards have bad CIS's, so just look for a
413 window larger than 8 ports and assume it will be right */
414 if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
415 (cf->io.win[0].len > 8)) {
416 link->conf.ConfigIndex = cf->index;
417 link->io.BasePort1 = cf->io.win[0].base;
418 link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
419 i = CardServices(RequestIO, link->handle, &link->io);
420 base2 = link->io.BasePort1 + 8;
421 if (i == CS_SUCCESS) break;
422 }
423 i = next_tuple(handle, &tuple, &parse);
424 }
425
426 /* If that didn't work, look for two windows */
427 if (i != CS_SUCCESS) {
428 link->io.NumPorts1 = link->io.NumPorts2 = 8;
429 info->multi = 2;
430 i = first_tuple(handle, &tuple, &parse);
431 while (i != CS_NO_MORE_ITEMS) {
432 if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
433 link->conf.ConfigIndex = cf->index;
434 link->io.BasePort1 = cf->io.win[0].base;
435 link->io.BasePort2 = cf->io.win[1].base;
436 link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
437 i = CardServices(RequestIO, link->handle, &link->io);
438 base2 = link->io.BasePort2;
439 if (i == CS_SUCCESS) break;
440 }
441 i = next_tuple(handle, &tuple, &parse);
442 }
443 }
444
445 if (i != CS_SUCCESS) {
446 /* At worst, try to configure as a single port */
447 return simple_config(link);
448 }
449
450 i = CardServices(RequestIRQ, link->handle, &link->irq);
451 if (i != CS_SUCCESS) {
452 cs_error(link->handle, RequestIRQ, i);
453 link->irq.AssignedIRQ = 0;
454 }
455 /* Socket Dual IO: this enables irq's for second port */
456 if (info->multi && (info->manfid == MANFID_SOCKET)) {
457 link->conf.Present |= PRESENT_EXT_STATUS;
458 link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
459 }
460 i = CardServices(RequestConfiguration, link->handle, &link->conf);
461 if (i != CS_SUCCESS) {
462 cs_error(link->handle, RequestConfiguration, i);
463 return -1;
464 }
465
466 /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
467 8 registers are for the UART, the others are extra registers */
468 if (info->manfid == MANFID_OXSEMI) {
469 if (cf->index == 1 || cf->index == 3) {
470 setup_serial(info, base2, link->irq.AssignedIRQ);
471 outb(12,link->io.BasePort1+1);
472 } else {
473 setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
474 outb(12,base2+1);
475 }
476 return 0;
477 }
478
479 setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
480 /* The Nokia cards are not really multiport cards */
481 if (info->manfid == MANFID_NOKIA)
482 return 0;
483 for (i = 0; i < info->multi-1; i++)
484 setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
485
486 return 0;
487 }
488
489 /*======================================================================
490
491 serial_config() is scheduled to run after a CARD_INSERTION event
492 is received, to configure the PCMCIA socket, and to make the
493 serial device available to the system.
494
495 ======================================================================*/
496
497 #define CS_CHECK(fn, args...) \
498 while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
499
serial_config(dev_link_t * link)500 void serial_config(dev_link_t *link)
501 {
502 client_handle_t handle = link->handle;
503 serial_info_t *info = link->priv;
504 tuple_t tuple;
505 u_short buf[128];
506 cisparse_t parse;
507 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
508 int i, last_ret, last_fn;
509
510 DEBUG(0, "serial_config(0x%p)\n", link);
511
512 tuple.TupleData = (cisdata_t *)buf;
513 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
514 tuple.Attributes = 0;
515 /* Get configuration register information */
516 tuple.DesiredTuple = CISTPL_CONFIG;
517 last_ret = first_tuple(handle, &tuple, &parse);
518 if (last_ret != CS_SUCCESS) {
519 last_fn = ParseTuple;
520 goto cs_failed;
521 }
522 link->conf.ConfigBase = parse.config.base;
523 link->conf.Present = parse.config.rmask[0];
524
525 /* Configure card */
526 link->state |= DEV_CONFIG;
527
528 /* Is this a compliant multifunction card? */
529 tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
530 tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
531 info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
532
533 /* Scan list of known multiport card ID's */
534 tuple.DesiredTuple = CISTPL_MANFID;
535 if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
536 info->manfid = le16_to_cpu(buf[0]);
537 for (i = 0; i < MULTI_COUNT; i++)
538 if ((info->manfid == multi_id[i].manfid) &&
539 (le16_to_cpu(buf[1]) == multi_id[i].prodid))
540 break;
541 if (i < MULTI_COUNT)
542 info->multi = multi_id[i].multi;
543 }
544
545 /* Another check for dual-serial cards: look for either serial or
546 multifunction cards that ask for appropriate IO port ranges */
547 tuple.DesiredTuple = CISTPL_FUNCID;
548 if ((info->multi == 0) &&
549 ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
550 (parse.funcid.func == CISTPL_FUNCID_MULTI) ||
551 (parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
552 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
553 if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
554 if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
555 info->multi = cf->io.win[0].len >> 3;
556 if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
557 (cf->io.win[1].len == 8))
558 info->multi = 2;
559 }
560 }
561
562 if (info->multi > 1)
563 multi_config(link);
564 else
565 simple_config(link);
566
567 if (info->ndev == 0)
568 goto failed;
569
570 if (info->manfid == MANFID_IBM) {
571 conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
572 CS_CHECK(AccessConfigurationRegister, link->handle, ®);
573 reg.Action = CS_WRITE;
574 reg.Value = reg.Value | 1;
575 CS_CHECK(AccessConfigurationRegister, link->handle, ®);
576 }
577
578 link->dev = &info->node[0];
579 link->state &= ~DEV_CONFIG_PENDING;
580 return;
581
582 cs_failed:
583 cs_error(link->handle, last_fn, last_ret);
584 failed:
585 serial_release((u_long)link);
586 link->state &= ~DEV_CONFIG_PENDING;
587
588 } /* serial_config */
589
590 /*======================================================================
591
592 After a card is removed, serial_release() will unregister the net
593 device, and release the PCMCIA configuration.
594
595 ======================================================================*/
596
serial_release(u_long arg)597 void serial_release(u_long arg)
598 {
599 dev_link_t *link = (dev_link_t *)arg;
600 serial_info_t *info = link->priv;
601 int i;
602
603 DEBUG(0, "serial_release(0x%p)\n", link);
604
605 for (i = 0; i < info->ndev; i++) {
606 unregister_serial(info->line[i]);
607 }
608 link->dev = NULL;
609
610 if (!info->slave) {
611 CardServices(ReleaseConfiguration, link->handle);
612 CardServices(ReleaseIO, link->handle, &link->io);
613 CardServices(ReleaseIRQ, link->handle, &link->irq);
614 }
615
616 link->state &= ~DEV_CONFIG;
617
618 } /* serial_release */
619
620 /*======================================================================
621
622 The card status event handler. Mostly, this schedules other
623 stuff to run after an event is received. A CARD_REMOVAL event
624 also sets some flags to discourage the serial drivers from
625 talking to the ports.
626
627 ======================================================================*/
628
serial_event(event_t event,int priority,event_callback_args_t * args)629 static int serial_event(event_t event, int priority,
630 event_callback_args_t *args)
631 {
632 dev_link_t *link = args->client_data;
633 serial_info_t *info = link->priv;
634
635 DEBUG(1, "serial_event(0x%06x)\n", event);
636
637 switch (event) {
638 case CS_EVENT_CARD_REMOVAL:
639 link->state &= ~DEV_PRESENT;
640 if (link->state & DEV_CONFIG)
641 mod_timer(&link->release, jiffies + HZ/20);
642 break;
643 case CS_EVENT_CARD_INSERTION:
644 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
645 serial_config(link);
646 break;
647 case CS_EVENT_PM_SUSPEND:
648 link->state |= DEV_SUSPEND;
649 /* Fall through... */
650 case CS_EVENT_RESET_PHYSICAL:
651 if ((link->state & DEV_CONFIG) && !info->slave)
652 CardServices(ReleaseConfiguration, link->handle);
653 break;
654 case CS_EVENT_PM_RESUME:
655 link->state &= ~DEV_SUSPEND;
656 /* Fall through... */
657 case CS_EVENT_CARD_RESET:
658 if (DEV_OK(link) && !info->slave)
659 CardServices(RequestConfiguration, link->handle, &link->conf);
660 break;
661 }
662 return 0;
663 } /* serial_event */
664
665 /*====================================================================*/
666
init_serial_cs(void)667 static int __init init_serial_cs(void)
668 {
669 servinfo_t serv;
670 DEBUG(0, "%s\n", version);
671 CardServices(GetCardServicesInfo, &serv);
672 if (serv.Revision != CS_RELEASE_CODE) {
673 printk(KERN_NOTICE "serial_cs: Card Services release "
674 "does not match!\n");
675 return -EINVAL;
676 }
677 register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
678 return 0;
679 }
680
exit_serial_cs(void)681 static void __exit exit_serial_cs(void)
682 {
683 DEBUG(0, "serial_cs: unloading\n");
684 unregister_pccard_driver(&dev_info);
685 while (dev_list != NULL)
686 serial_detach(dev_list);
687 }
688
689 module_init(init_serial_cs);
690 module_exit(exit_serial_cs);
691