blob: ff38820a03f549b603e6bd262b2ce353a7ce9a99 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 A driver for PCMCIA serial devices
4
5 serial_cs.c 1.134 2002/05/04 05:48:53
6
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
11
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
16
17 The initial developer of the original code is David A. Hinds
18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU General Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
31
32======================================================================*/
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/kernel.h>
37#include <linux/init.h>
38#include <linux/sched.h>
39#include <linux/ptrace.h>
40#include <linux/slab.h>
41#include <linux/string.h>
42#include <linux/timer.h>
43#include <linux/serial_core.h>
44#include <linux/major.h>
45#include <asm/io.h>
46#include <asm/system.h>
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <pcmcia/cs_types.h>
49#include <pcmcia/cs.h>
50#include <pcmcia/cistpl.h>
51#include <pcmcia/ciscode.h>
52#include <pcmcia/ds.h>
53#include <pcmcia/cisreg.h>
54
55#include "8250.h"
56
57#ifdef PCMCIA_DEBUG
58static int pc_debug = PCMCIA_DEBUG;
59module_param(pc_debug, int, 0644);
60#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
61static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
62#else
63#define DEBUG(n, args...)
64#endif
65
66/*====================================================================*/
67
68/* Parameters that can be set with 'insmod' */
69
70/* Enable the speaker? */
71static int do_sound = 1;
72/* Skip strict UART tests? */
73static int buggy_uart;
74
75module_param(do_sound, int, 0444);
76module_param(buggy_uart, int, 0444);
77
78/*====================================================================*/
79
80/* Table of multi-port card ID's */
81
82struct multi_id {
83 u_short manfid;
84 u_short prodid;
85 int multi; /* 1 = multifunction, > 1 = # ports */
86};
87
Arjan van de Vencb3592b2005-11-28 21:04:11 +000088static const struct multi_id multi_id[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
90 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
91 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
92 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
93 { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
94 { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
95 { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
96};
97#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
98
99struct serial_info {
100 dev_link_t link;
101 int ndev;
102 int multi;
103 int slave;
104 int manfid;
105 dev_node_t node[4];
106 int line[4];
107};
108
Yum Rayan16f31112005-05-01 08:59:14 -0700109struct serial_cfg_mem {
110 tuple_t tuple;
111 cisparse_t parse;
112 u_char buf[256];
113};
114
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116static void serial_config(dev_link_t * link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/*======================================================================
120
121 After a card is removed, serial_remove() will unregister
122 the serial device(s), and release the PCMCIA configuration.
123
124======================================================================*/
125
126static void serial_remove(dev_link_t *link)
127{
128 struct serial_info *info = link->priv;
129 int i;
130
131 link->state &= ~DEV_PRESENT;
132
133 DEBUG(0, "serial_release(0x%p)\n", link);
134
135 /*
136 * Recheck to see if the device is still configured.
137 */
138 if (info->link.state & DEV_CONFIG) {
139 for (i = 0; i < info->ndev; i++)
140 serial8250_unregister_port(info->line[i]);
141
142 info->link.dev = NULL;
143
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100144 if (!info->slave)
145 pcmcia_disable_device(link->handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147 info->link.state &= ~DEV_CONFIG;
148 }
149}
150
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100151static int serial_suspend(struct pcmcia_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100153 dev_link_t *link = dev_to_instance(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 link->state |= DEV_SUSPEND;
155
156 if (link->state & DEV_CONFIG) {
157 struct serial_info *info = link->priv;
158 int i;
159
160 for (i = 0; i < info->ndev; i++)
161 serial8250_suspend_port(info->line[i]);
162
163 if (!info->slave)
164 pcmcia_release_configuration(link->handle);
165 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100166
167 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100170static int serial_resume(struct pcmcia_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100172 dev_link_t *link = dev_to_instance(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 link->state &= ~DEV_SUSPEND;
174
175 if (DEV_OK(link)) {
176 struct serial_info *info = link->priv;
177 int i;
178
179 if (!info->slave)
180 pcmcia_request_configuration(link->handle, &link->conf);
181
182 for (i = 0; i < info->ndev; i++)
183 serial8250_resume_port(info->line[i]);
184 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100185
186 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188
189/*======================================================================
190
191 serial_attach() creates an "instance" of the driver, allocating
192 local data structures for one device. The device is registered
193 with Card Services.
194
195======================================================================*/
196
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100197static int serial_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
199 struct serial_info *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 dev_link_t *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 DEBUG(0, "serial_attach()\n");
203
204 /* Create new serial device */
205 info = kmalloc(sizeof (*info), GFP_KERNEL);
206 if (!info)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100207 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 memset(info, 0, sizeof (*info));
209 link = &info->link;
210 link->priv = info;
211
212 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
213 link->io.NumPorts1 = 8;
214 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
215 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
216 link->conf.Attributes = CONF_ENABLE_IRQ;
217 if (do_sound) {
218 link->conf.Attributes |= CONF_ENABLE_SPKR;
219 link->conf.Status = CCSR_AUDIO_ENA;
220 }
221 link->conf.IntType = INT_MEMORY_AND_IO;
222
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100223 link->handle = p_dev;
224 p_dev->instance = link;
225 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
226 serial_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100228 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
230
231/*======================================================================
232
233 This deletes a driver "instance". The device is de-registered
234 with Card Services. If it has been released, all local data
235 structures are freed. Otherwise, the structures will be freed
236 when the device is released.
237
238======================================================================*/
239
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100240static void serial_detach(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100242 dev_link_t *link = dev_to_instance(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 struct serial_info *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 DEBUG(0, "serial_detach(0x%p)\n", link);
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 /*
248 * Ensure any outstanding scheduled tasks are completed.
249 */
250 flush_scheduled_work();
251
252 /*
253 * Ensure that the ports have been released.
254 */
255 serial_remove(link);
256
Dominik Brodowskib4635812005-11-14 21:25:35 +0100257 /* free bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 kfree(info);
259}
260
261/*====================================================================*/
262
263static int setup_serial(client_handle_t handle, struct serial_info * info,
264 kio_addr_t iobase, int irq)
265{
266 struct uart_port port;
267 int line;
268
269 memset(&port, 0, sizeof (struct uart_port));
270 port.iobase = iobase;
271 port.irq = irq;
272 port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
273 port.uartclk = 1843200;
274 port.dev = &handle_to_dev(handle);
275 if (buggy_uart)
276 port.flags |= UPF_BUGGY_UART;
277 line = serial8250_register_port(&port);
278 if (line < 0) {
279 printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
280 "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
281 return -EINVAL;
282 }
283
284 info->line[info->ndev] = line;
285 sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
286 info->node[info->ndev].major = TTY_MAJOR;
287 info->node[info->ndev].minor = 0x40 + line;
288 if (info->ndev > 0)
289 info->node[info->ndev - 1].next = &info->node[info->ndev];
290 info->ndev++;
291
292 return 0;
293}
294
295/*====================================================================*/
296
297static int
298first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
299{
300 int i;
301 i = pcmcia_get_first_tuple(handle, tuple);
302 if (i != CS_SUCCESS)
303 return CS_NO_MORE_ITEMS;
304 i = pcmcia_get_tuple_data(handle, tuple);
305 if (i != CS_SUCCESS)
306 return i;
307 return pcmcia_parse_tuple(handle, tuple, parse);
308}
309
310static int
311next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
312{
313 int i;
314 i = pcmcia_get_next_tuple(handle, tuple);
315 if (i != CS_SUCCESS)
316 return CS_NO_MORE_ITEMS;
317 i = pcmcia_get_tuple_data(handle, tuple);
318 if (i != CS_SUCCESS)
319 return i;
320 return pcmcia_parse_tuple(handle, tuple, parse);
321}
322
323/*====================================================================*/
324
325static int simple_config(dev_link_t *link)
326{
Arjan van de Vencb3592b2005-11-28 21:04:11 +0000327 static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
328 static const int size_table[2] = { 8, 16 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 client_handle_t handle = link->handle;
330 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700331 struct serial_cfg_mem *cfg_mem;
332 tuple_t *tuple;
333 u_char *buf;
334 cisparse_t *parse;
335 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 config_info_t config;
337 int i, j, try;
338 int s;
339
Yum Rayan16f31112005-05-01 08:59:14 -0700340 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
341 if (!cfg_mem)
342 return -1;
343
344 tuple = &cfg_mem->tuple;
345 parse = &cfg_mem->parse;
346 cf = &parse->cftable_entry;
347 buf = cfg_mem->buf;
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 /* If the card is already configured, look up the port and irq */
350 i = pcmcia_get_configuration_info(handle, &config);
351 if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
352 kio_addr_t port = 0;
353 if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
354 port = config.BasePort2;
355 info->slave = 1;
356 } else if ((info->manfid == MANFID_OSITECH) &&
357 (config.NumPorts1 == 0x40)) {
358 port = config.BasePort1 + 0x28;
359 info->slave = 1;
360 }
Yum Rayan16f31112005-05-01 08:59:14 -0700361 if (info->slave) {
362 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return setup_serial(handle, info, port, config.AssignedIRQ);
Yum Rayan16f31112005-05-01 08:59:14 -0700364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 }
366 link->conf.Vcc = config.Vcc;
367
368 /* First pass: look for a config entry that looks normal. */
Yum Rayan16f31112005-05-01 08:59:14 -0700369 tuple->TupleData = (cisdata_t *) buf;
370 tuple->TupleOffset = 0;
371 tuple->TupleDataMax = 255;
372 tuple->Attributes = 0;
373 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 /* Two tries: without IO aliases, then with aliases */
375 for (s = 0; s < 2; s++) {
376 for (try = 0; try < 2; try++) {
Yum Rayan16f31112005-05-01 08:59:14 -0700377 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 while (i != CS_NO_MORE_ITEMS) {
379 if (i != CS_SUCCESS)
380 goto next_entry;
381 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
382 link->conf.Vpp1 = link->conf.Vpp2 =
383 cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
384 if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
385 (cf->io.win[0].base != 0)) {
386 link->conf.ConfigIndex = cf->index;
387 link->io.BasePort1 = cf->io.win[0].base;
388 link->io.IOAddrLines = (try == 0) ?
389 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
390 i = pcmcia_request_io(link->handle, &link->io);
391 if (i == CS_SUCCESS)
392 goto found_port;
393 }
394next_entry:
Yum Rayan16f31112005-05-01 08:59:14 -0700395 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 }
397 }
398 }
399 /* Second pass: try to find an entry that isn't picky about
400 its base address, then try to grab any standard serial port
401 address, and finally try to get any free port. */
Yum Rayan16f31112005-05-01 08:59:14 -0700402 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 while (i != CS_NO_MORE_ITEMS) {
404 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
405 ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
406 link->conf.ConfigIndex = cf->index;
407 for (j = 0; j < 5; j++) {
408 link->io.BasePort1 = base[j];
409 link->io.IOAddrLines = base[j] ? 16 : 3;
410 i = pcmcia_request_io(link->handle, &link->io);
411 if (i == CS_SUCCESS)
412 goto found_port;
413 }
414 }
Yum Rayan16f31112005-05-01 08:59:14 -0700415 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 }
417
418 found_port:
419 if (i != CS_SUCCESS) {
420 printk(KERN_NOTICE
421 "serial_cs: no usable port range found, giving up\n");
422 cs_error(link->handle, RequestIO, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700423 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return -1;
425 }
426
427 i = pcmcia_request_irq(link->handle, &link->irq);
428 if (i != CS_SUCCESS) {
429 cs_error(link->handle, RequestIRQ, i);
430 link->irq.AssignedIRQ = 0;
431 }
432 if (info->multi && (info->manfid == MANFID_3COM))
433 link->conf.ConfigIndex &= ~(0x08);
434 i = pcmcia_request_configuration(link->handle, &link->conf);
435 if (i != CS_SUCCESS) {
436 cs_error(link->handle, RequestConfiguration, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700437 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return -1;
439 }
Yum Rayan16f31112005-05-01 08:59:14 -0700440 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
442}
443
444static int multi_config(dev_link_t * link)
445{
446 client_handle_t handle = link->handle;
447 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700448 struct serial_cfg_mem *cfg_mem;
449 tuple_t *tuple;
450 u_char *buf;
451 cisparse_t *parse;
452 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 config_info_t config;
Yum Rayan16f31112005-05-01 08:59:14 -0700454 int i, rc, base2 = 0;
455
456 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
457 if (!cfg_mem)
458 return -1;
459 tuple = &cfg_mem->tuple;
460 parse = &cfg_mem->parse;
461 cf = &parse->cftable_entry;
462 buf = cfg_mem->buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 i = pcmcia_get_configuration_info(handle, &config);
465 if (i != CS_SUCCESS) {
466 cs_error(handle, GetConfigurationInfo, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700467 rc = -1;
468 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
470 link->conf.Vcc = config.Vcc;
471
Yum Rayan16f31112005-05-01 08:59:14 -0700472 tuple->TupleData = (cisdata_t *) buf;
473 tuple->TupleOffset = 0;
474 tuple->TupleDataMax = 255;
475 tuple->Attributes = 0;
476 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
478 /* First, look for a generic full-sized window */
479 link->io.NumPorts1 = info->multi * 8;
Yum Rayan16f31112005-05-01 08:59:14 -0700480 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 while (i != CS_NO_MORE_ITEMS) {
482 /* The quad port cards have bad CIS's, so just look for a
483 window larger than 8 ports and assume it will be right */
484 if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
485 (cf->io.win[0].len > 8)) {
486 link->conf.ConfigIndex = cf->index;
487 link->io.BasePort1 = cf->io.win[0].base;
488 link->io.IOAddrLines =
489 cf->io.flags & CISTPL_IO_LINES_MASK;
490 i = pcmcia_request_io(link->handle, &link->io);
491 base2 = link->io.BasePort1 + 8;
492 if (i == CS_SUCCESS)
493 break;
494 }
Yum Rayan16f31112005-05-01 08:59:14 -0700495 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 }
497
498 /* If that didn't work, look for two windows */
499 if (i != CS_SUCCESS) {
500 link->io.NumPorts1 = link->io.NumPorts2 = 8;
501 info->multi = 2;
Yum Rayan16f31112005-05-01 08:59:14 -0700502 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 while (i != CS_NO_MORE_ITEMS) {
504 if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
505 link->conf.ConfigIndex = cf->index;
506 link->io.BasePort1 = cf->io.win[0].base;
507 link->io.BasePort2 = cf->io.win[1].base;
508 link->io.IOAddrLines =
509 cf->io.flags & CISTPL_IO_LINES_MASK;
510 i = pcmcia_request_io(link->handle, &link->io);
511 base2 = link->io.BasePort2;
512 if (i == CS_SUCCESS)
513 break;
514 }
Yum Rayan16f31112005-05-01 08:59:14 -0700515 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 }
517 }
518
519 if (i != CS_SUCCESS) {
520 cs_error(link->handle, RequestIO, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700521 rc = -1;
522 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
524
525 i = pcmcia_request_irq(link->handle, &link->irq);
526 if (i != CS_SUCCESS) {
527 printk(KERN_NOTICE
528 "serial_cs: no usable port range found, giving up\n");
529 cs_error(link->handle, RequestIRQ, i);
530 link->irq.AssignedIRQ = 0;
531 }
532 /* Socket Dual IO: this enables irq's for second port */
533 if (info->multi && (info->manfid == MANFID_SOCKET)) {
534 link->conf.Present |= PRESENT_EXT_STATUS;
535 link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
536 }
537 i = pcmcia_request_configuration(link->handle, &link->conf);
538 if (i != CS_SUCCESS) {
539 cs_error(link->handle, RequestConfiguration, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700540 rc = -1;
541 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
543
544 /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
545 8 registers are for the UART, the others are extra registers */
546 if (info->manfid == MANFID_OXSEMI) {
547 if (cf->index == 1 || cf->index == 3) {
548 setup_serial(handle, info, base2, link->irq.AssignedIRQ);
549 outb(12, link->io.BasePort1 + 1);
550 } else {
551 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
552 outb(12, base2 + 1);
553 }
Yum Rayan16f31112005-05-01 08:59:14 -0700554 rc = 0;
555 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
557
558 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
559 /* The Nokia cards are not really multiport cards */
Yum Rayan16f31112005-05-01 08:59:14 -0700560 if (info->manfid == MANFID_NOKIA) {
561 rc = 0;
562 goto free_cfg_mem;
563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 for (i = 0; i < info->multi - 1; i++)
Yum Rayan16f31112005-05-01 08:59:14 -0700565 setup_serial(handle, info, base2 + (8 * i),
566 link->irq.AssignedIRQ);
567 rc = 0;
568free_cfg_mem:
569 kfree(cfg_mem);
570 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571}
572
573/*======================================================================
574
575 serial_config() is scheduled to run after a CARD_INSERTION event
576 is received, to configure the PCMCIA socket, and to make the
577 serial device available to the system.
578
579======================================================================*/
580
581void serial_config(dev_link_t * link)
582{
583 client_handle_t handle = link->handle;
584 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700585 struct serial_cfg_mem *cfg_mem;
586 tuple_t *tuple;
587 u_char *buf;
588 cisparse_t *parse;
589 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 int i, last_ret, last_fn;
591
592 DEBUG(0, "serial_config(0x%p)\n", link);
593
Yum Rayan16f31112005-05-01 08:59:14 -0700594 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
595 if (!cfg_mem)
596 goto failed;
597
598 tuple = &cfg_mem->tuple;
599 parse = &cfg_mem->parse;
600 cf = &parse->cftable_entry;
601 buf = cfg_mem->buf;
602
603 tuple->TupleData = (cisdata_t *) buf;
604 tuple->TupleOffset = 0;
605 tuple->TupleDataMax = 255;
606 tuple->Attributes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 /* Get configuration register information */
Yum Rayan16f31112005-05-01 08:59:14 -0700608 tuple->DesiredTuple = CISTPL_CONFIG;
609 last_ret = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (last_ret != CS_SUCCESS) {
611 last_fn = ParseTuple;
612 goto cs_failed;
613 }
Yum Rayan16f31112005-05-01 08:59:14 -0700614 link->conf.ConfigBase = parse->config.base;
615 link->conf.Present = parse->config.rmask[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 /* Configure card */
618 link->state |= DEV_CONFIG;
619
620 /* Is this a compliant multifunction card? */
Yum Rayan16f31112005-05-01 08:59:14 -0700621 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
622 tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
623 info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 /* Is this a multiport card? */
Yum Rayan16f31112005-05-01 08:59:14 -0700626 tuple->DesiredTuple = CISTPL_MANFID;
627 if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
Petr Vandrovecf1fc3992005-05-16 21:53:44 -0700628 info->manfid = parse->manfid.manf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 for (i = 0; i < MULTI_COUNT; i++)
630 if ((info->manfid == multi_id[i].manfid) &&
Petr Vandrovecf1fc3992005-05-16 21:53:44 -0700631 (parse->manfid.card == multi_id[i].prodid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 break;
633 if (i < MULTI_COUNT)
634 info->multi = multi_id[i].multi;
635 }
636
637 /* Another check for dual-serial cards: look for either serial or
638 multifunction cards that ask for appropriate IO port ranges */
Yum Rayan16f31112005-05-01 08:59:14 -0700639 tuple->DesiredTuple = CISTPL_FUNCID;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 if ((info->multi == 0) &&
Yum Rayan16f31112005-05-01 08:59:14 -0700641 ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
642 (parse->funcid.func == CISTPL_FUNCID_MULTI) ||
643 (parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
644 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
645 if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
647 info->multi = cf->io.win[0].len >> 3;
648 if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
649 (cf->io.win[1].len == 8))
650 info->multi = 2;
651 }
652 }
653
654 if (info->multi > 1)
655 multi_config(link);
656 else
657 simple_config(link);
658
659 if (info->ndev == 0)
660 goto failed;
661
662 if (info->manfid == MANFID_IBM) {
663 conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
664 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
665 if (last_ret) {
666 last_fn = AccessConfigurationRegister;
667 goto cs_failed;
668 }
669 reg.Action = CS_WRITE;
670 reg.Value = reg.Value | 1;
671 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
672 if (last_ret) {
673 last_fn = AccessConfigurationRegister;
674 goto cs_failed;
675 }
676 }
677
678 link->dev = &info->node[0];
679 link->state &= ~DEV_CONFIG_PENDING;
Yum Rayan16f31112005-05-01 08:59:14 -0700680 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return;
682
683 cs_failed:
684 cs_error(link->handle, last_fn, last_ret);
685 failed:
686 serial_remove(link);
687 link->state &= ~DEV_CONFIG_PENDING;
Yum Rayan16f31112005-05-01 08:59:14 -0700688 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
Dominik Brodowski325aa292005-06-27 16:28:18 -0700691static struct pcmcia_device_id serial_ids[] = {
692 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
693 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
694 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
695 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
696 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
697 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
698 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
699 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
700 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
701 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
702 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
703 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
Jun Komurof4d75102005-06-27 16:28:44 -0700704 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
705 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700706 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
707 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
708 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
709 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
710 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
711 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
712 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
713 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
714 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
Komurod277ad02005-07-28 01:07:24 -0700715 PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700716 PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
717 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
718 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
719 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
720 PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
721 PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
Komurod277ad02005-07-28 01:07:24 -0700722 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
723 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700724 PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
725 PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
726 PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
Komurod277ad02005-07-28 01:07:24 -0700727 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700728 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
729 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
730 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
731 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
732 PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
733 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
734 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
735 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
736 PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
737 PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
738 PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
Domen Puncer1de9ced2006-03-06 10:25:53 +0100739 PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700740 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
741 PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
742 PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
743 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
744 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
745 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
746 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
747 PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
748 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
749 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
750 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
751 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
752 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
753 PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
754 PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
755 PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
756 PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
757 PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
Domen Puncer1de9ced2006-03-06 10:25:53 +0100758 PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700759 PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
760 PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
761 PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
762 PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
763 PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
764 PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
765 PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
766 PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
Komurod277ad02005-07-28 01:07:24 -0700767 PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700768 PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
769 PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
770 PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
771 PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
772 PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
773 PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
774 PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
775 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
776 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
777 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
778 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
779 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
780 PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
781 PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
782 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"),
783 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
784 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
785 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
Dominik Brodowskia42f0dc2005-09-24 23:12:44 -0700786 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
Dominik Brodowskif542ff62006-01-10 19:06:33 +0100787 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
788 PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
Dominik Brodowski325aa292005-06-27 16:28:18 -0700789 PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "MT5634ZLX.cis"),
790 PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
791 PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
792 PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
793 /* too generic */
794 /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
795 /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
796 PCMCIA_DEVICE_FUNC_ID(2),
797 PCMCIA_DEVICE_NULL,
798};
799MODULE_DEVICE_TABLE(pcmcia, serial_ids);
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801static struct pcmcia_driver serial_cs_driver = {
802 .owner = THIS_MODULE,
803 .drv = {
804 .name = "serial_cs",
805 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100806 .probe = serial_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100807 .remove = serial_detach,
Dominik Brodowski325aa292005-06-27 16:28:18 -0700808 .id_table = serial_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100809 .suspend = serial_suspend,
810 .resume = serial_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811};
812
813static int __init init_serial_cs(void)
814{
815 return pcmcia_register_driver(&serial_cs_driver);
816}
817
818static void __exit exit_serial_cs(void)
819{
820 pcmcia_unregister_driver(&serial_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821}
822
823module_init(init_serial_cs);
824module_exit(exit_serial_cs);
825
826MODULE_LICENSE("GPL");