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