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