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, &reg);
573 	reg.Action = CS_WRITE;
574 	reg.Value = reg.Value | 1;
575 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
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