blob: 2c7d3ef76e8e8d627eca5c77f2c561b5d7bedc8c [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
88static struct multi_id multi_id[] = {
89 { 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);
117static int serial_event(event_t event, int priority,
118 event_callback_args_t * args);
119
120static dev_info_t dev_info = "serial_cs";
121
122static dev_link_t *serial_attach(void);
123static void serial_detach(dev_link_t *);
124
125static dev_link_t *dev_list = NULL;
126
127/*======================================================================
128
129 After a card is removed, serial_remove() will unregister
130 the serial device(s), and release the PCMCIA configuration.
131
132======================================================================*/
133
134static void serial_remove(dev_link_t *link)
135{
136 struct serial_info *info = link->priv;
137 int i;
138
139 link->state &= ~DEV_PRESENT;
140
141 DEBUG(0, "serial_release(0x%p)\n", link);
142
143 /*
144 * Recheck to see if the device is still configured.
145 */
146 if (info->link.state & DEV_CONFIG) {
147 for (i = 0; i < info->ndev; i++)
148 serial8250_unregister_port(info->line[i]);
149
150 info->link.dev = NULL;
151
152 if (!info->slave) {
153 pcmcia_release_configuration(info->link.handle);
154 pcmcia_release_io(info->link.handle, &info->link.io);
155 pcmcia_release_irq(info->link.handle, &info->link.irq);
156 }
157
158 info->link.state &= ~DEV_CONFIG;
159 }
160}
161
162static void serial_suspend(dev_link_t *link)
163{
164 link->state |= DEV_SUSPEND;
165
166 if (link->state & DEV_CONFIG) {
167 struct serial_info *info = link->priv;
168 int i;
169
170 for (i = 0; i < info->ndev; i++)
171 serial8250_suspend_port(info->line[i]);
172
173 if (!info->slave)
174 pcmcia_release_configuration(link->handle);
175 }
176}
177
178static void serial_resume(dev_link_t *link)
179{
180 link->state &= ~DEV_SUSPEND;
181
182 if (DEV_OK(link)) {
183 struct serial_info *info = link->priv;
184 int i;
185
186 if (!info->slave)
187 pcmcia_request_configuration(link->handle, &link->conf);
188
189 for (i = 0; i < info->ndev; i++)
190 serial8250_resume_port(info->line[i]);
191 }
192}
193
194/*======================================================================
195
196 serial_attach() creates an "instance" of the driver, allocating
197 local data structures for one device. The device is registered
198 with Card Services.
199
200======================================================================*/
201
202static dev_link_t *serial_attach(void)
203{
204 struct serial_info *info;
205 client_reg_t client_reg;
206 dev_link_t *link;
207 int ret;
208
209 DEBUG(0, "serial_attach()\n");
210
211 /* Create new serial device */
212 info = kmalloc(sizeof (*info), GFP_KERNEL);
213 if (!info)
214 return NULL;
215 memset(info, 0, sizeof (*info));
216 link = &info->link;
217 link->priv = info;
218
219 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
220 link->io.NumPorts1 = 8;
221 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
222 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
223 link->conf.Attributes = CONF_ENABLE_IRQ;
224 if (do_sound) {
225 link->conf.Attributes |= CONF_ENABLE_SPKR;
226 link->conf.Status = CCSR_AUDIO_ENA;
227 }
228 link->conf.IntType = INT_MEMORY_AND_IO;
229
230 /* Register with Card Services */
231 link->next = dev_list;
232 dev_list = link;
233 client_reg.dev_info = &dev_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 client_reg.Version = 0x0210;
235 client_reg.event_callback_args.client_data = link;
236 ret = pcmcia_register_client(&link->handle, &client_reg);
237 if (ret != CS_SUCCESS) {
238 cs_error(link->handle, RegisterClient, ret);
239 serial_detach(link);
240 return NULL;
241 }
242
243 return link;
244}
245
246/*======================================================================
247
248 This deletes a driver "instance". The device is de-registered
249 with Card Services. If it has been released, all local data
250 structures are freed. Otherwise, the structures will be freed
251 when the device is released.
252
253======================================================================*/
254
255static void serial_detach(dev_link_t * link)
256{
257 struct serial_info *info = link->priv;
258 dev_link_t **linkp;
259 int ret;
260
261 DEBUG(0, "serial_detach(0x%p)\n", link);
262
263 /* Locate device structure */
264 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
265 if (*linkp == link)
266 break;
267 if (*linkp == NULL)
268 return;
269
270 /*
271 * Ensure any outstanding scheduled tasks are completed.
272 */
273 flush_scheduled_work();
274
275 /*
276 * Ensure that the ports have been released.
277 */
278 serial_remove(link);
279
280 if (link->handle) {
281 ret = pcmcia_deregister_client(link->handle);
282 if (ret != CS_SUCCESS)
283 cs_error(link->handle, DeregisterClient, ret);
284 }
285
286 /* Unlink device structure, free bits */
287 *linkp = link->next;
288 kfree(info);
289}
290
291/*====================================================================*/
292
293static int setup_serial(client_handle_t handle, struct serial_info * info,
294 kio_addr_t iobase, int irq)
295{
296 struct uart_port port;
297 int line;
298
299 memset(&port, 0, sizeof (struct uart_port));
300 port.iobase = iobase;
301 port.irq = irq;
302 port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
303 port.uartclk = 1843200;
304 port.dev = &handle_to_dev(handle);
305 if (buggy_uart)
306 port.flags |= UPF_BUGGY_UART;
307 line = serial8250_register_port(&port);
308 if (line < 0) {
309 printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
310 "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
311 return -EINVAL;
312 }
313
314 info->line[info->ndev] = line;
315 sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
316 info->node[info->ndev].major = TTY_MAJOR;
317 info->node[info->ndev].minor = 0x40 + line;
318 if (info->ndev > 0)
319 info->node[info->ndev - 1].next = &info->node[info->ndev];
320 info->ndev++;
321
322 return 0;
323}
324
325/*====================================================================*/
326
327static int
328first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
329{
330 int i;
331 i = pcmcia_get_first_tuple(handle, tuple);
332 if (i != CS_SUCCESS)
333 return CS_NO_MORE_ITEMS;
334 i = pcmcia_get_tuple_data(handle, tuple);
335 if (i != CS_SUCCESS)
336 return i;
337 return pcmcia_parse_tuple(handle, tuple, parse);
338}
339
340static int
341next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
342{
343 int i;
344 i = pcmcia_get_next_tuple(handle, tuple);
345 if (i != CS_SUCCESS)
346 return CS_NO_MORE_ITEMS;
347 i = pcmcia_get_tuple_data(handle, tuple);
348 if (i != CS_SUCCESS)
349 return i;
350 return pcmcia_parse_tuple(handle, tuple, parse);
351}
352
353/*====================================================================*/
354
355static int simple_config(dev_link_t *link)
356{
357 static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
358 static int size_table[2] = { 8, 16 };
359 client_handle_t handle = link->handle;
360 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700361 struct serial_cfg_mem *cfg_mem;
362 tuple_t *tuple;
363 u_char *buf;
364 cisparse_t *parse;
365 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 config_info_t config;
367 int i, j, try;
368 int s;
369
Yum Rayan16f31112005-05-01 08:59:14 -0700370 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
371 if (!cfg_mem)
372 return -1;
373
374 tuple = &cfg_mem->tuple;
375 parse = &cfg_mem->parse;
376 cf = &parse->cftable_entry;
377 buf = cfg_mem->buf;
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 /* If the card is already configured, look up the port and irq */
380 i = pcmcia_get_configuration_info(handle, &config);
381 if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
382 kio_addr_t port = 0;
383 if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
384 port = config.BasePort2;
385 info->slave = 1;
386 } else if ((info->manfid == MANFID_OSITECH) &&
387 (config.NumPorts1 == 0x40)) {
388 port = config.BasePort1 + 0x28;
389 info->slave = 1;
390 }
Yum Rayan16f31112005-05-01 08:59:14 -0700391 if (info->slave) {
392 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 return setup_serial(handle, info, port, config.AssignedIRQ);
Yum Rayan16f31112005-05-01 08:59:14 -0700394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 }
396 link->conf.Vcc = config.Vcc;
397
398 /* First pass: look for a config entry that looks normal. */
Yum Rayan16f31112005-05-01 08:59:14 -0700399 tuple->TupleData = (cisdata_t *) buf;
400 tuple->TupleOffset = 0;
401 tuple->TupleDataMax = 255;
402 tuple->Attributes = 0;
403 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 /* Two tries: without IO aliases, then with aliases */
405 for (s = 0; s < 2; s++) {
406 for (try = 0; try < 2; try++) {
Yum Rayan16f31112005-05-01 08:59:14 -0700407 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 while (i != CS_NO_MORE_ITEMS) {
409 if (i != CS_SUCCESS)
410 goto next_entry;
411 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
412 link->conf.Vpp1 = link->conf.Vpp2 =
413 cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
414 if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
415 (cf->io.win[0].base != 0)) {
416 link->conf.ConfigIndex = cf->index;
417 link->io.BasePort1 = cf->io.win[0].base;
418 link->io.IOAddrLines = (try == 0) ?
419 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
420 i = pcmcia_request_io(link->handle, &link->io);
421 if (i == CS_SUCCESS)
422 goto found_port;
423 }
424next_entry:
Yum Rayan16f31112005-05-01 08:59:14 -0700425 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427 }
428 }
429 /* Second pass: try to find an entry that isn't picky about
430 its base address, then try to grab any standard serial port
431 address, and finally try to get any free port. */
Yum Rayan16f31112005-05-01 08:59:14 -0700432 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 while (i != CS_NO_MORE_ITEMS) {
434 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
435 ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
436 link->conf.ConfigIndex = cf->index;
437 for (j = 0; j < 5; j++) {
438 link->io.BasePort1 = base[j];
439 link->io.IOAddrLines = base[j] ? 16 : 3;
440 i = pcmcia_request_io(link->handle, &link->io);
441 if (i == CS_SUCCESS)
442 goto found_port;
443 }
444 }
Yum Rayan16f31112005-05-01 08:59:14 -0700445 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 }
447
448 found_port:
449 if (i != CS_SUCCESS) {
450 printk(KERN_NOTICE
451 "serial_cs: no usable port range found, giving up\n");
452 cs_error(link->handle, RequestIO, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700453 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return -1;
455 }
456
457 i = pcmcia_request_irq(link->handle, &link->irq);
458 if (i != CS_SUCCESS) {
459 cs_error(link->handle, RequestIRQ, i);
460 link->irq.AssignedIRQ = 0;
461 }
462 if (info->multi && (info->manfid == MANFID_3COM))
463 link->conf.ConfigIndex &= ~(0x08);
464 i = pcmcia_request_configuration(link->handle, &link->conf);
465 if (i != CS_SUCCESS) {
466 cs_error(link->handle, RequestConfiguration, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700467 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 return -1;
469 }
Yum Rayan16f31112005-05-01 08:59:14 -0700470 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
472}
473
474static int multi_config(dev_link_t * link)
475{
476 client_handle_t handle = link->handle;
477 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700478 struct serial_cfg_mem *cfg_mem;
479 tuple_t *tuple;
480 u_char *buf;
481 cisparse_t *parse;
482 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 config_info_t config;
Yum Rayan16f31112005-05-01 08:59:14 -0700484 int i, rc, base2 = 0;
485
486 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
487 if (!cfg_mem)
488 return -1;
489 tuple = &cfg_mem->tuple;
490 parse = &cfg_mem->parse;
491 cf = &parse->cftable_entry;
492 buf = cfg_mem->buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 i = pcmcia_get_configuration_info(handle, &config);
495 if (i != CS_SUCCESS) {
496 cs_error(handle, GetConfigurationInfo, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700497 rc = -1;
498 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
500 link->conf.Vcc = config.Vcc;
501
Yum Rayan16f31112005-05-01 08:59:14 -0700502 tuple->TupleData = (cisdata_t *) buf;
503 tuple->TupleOffset = 0;
504 tuple->TupleDataMax = 255;
505 tuple->Attributes = 0;
506 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 /* First, look for a generic full-sized window */
509 link->io.NumPorts1 = info->multi * 8;
Yum Rayan16f31112005-05-01 08:59:14 -0700510 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 while (i != CS_NO_MORE_ITEMS) {
512 /* The quad port cards have bad CIS's, so just look for a
513 window larger than 8 ports and assume it will be right */
514 if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
515 (cf->io.win[0].len > 8)) {
516 link->conf.ConfigIndex = cf->index;
517 link->io.BasePort1 = cf->io.win[0].base;
518 link->io.IOAddrLines =
519 cf->io.flags & CISTPL_IO_LINES_MASK;
520 i = pcmcia_request_io(link->handle, &link->io);
521 base2 = link->io.BasePort1 + 8;
522 if (i == CS_SUCCESS)
523 break;
524 }
Yum Rayan16f31112005-05-01 08:59:14 -0700525 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
527
528 /* If that didn't work, look for two windows */
529 if (i != CS_SUCCESS) {
530 link->io.NumPorts1 = link->io.NumPorts2 = 8;
531 info->multi = 2;
Yum Rayan16f31112005-05-01 08:59:14 -0700532 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 while (i != CS_NO_MORE_ITEMS) {
534 if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
535 link->conf.ConfigIndex = cf->index;
536 link->io.BasePort1 = cf->io.win[0].base;
537 link->io.BasePort2 = cf->io.win[1].base;
538 link->io.IOAddrLines =
539 cf->io.flags & CISTPL_IO_LINES_MASK;
540 i = pcmcia_request_io(link->handle, &link->io);
541 base2 = link->io.BasePort2;
542 if (i == CS_SUCCESS)
543 break;
544 }
Yum Rayan16f31112005-05-01 08:59:14 -0700545 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 }
547 }
548
549 if (i != CS_SUCCESS) {
550 cs_error(link->handle, RequestIO, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700551 rc = -1;
552 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
554
555 i = pcmcia_request_irq(link->handle, &link->irq);
556 if (i != CS_SUCCESS) {
557 printk(KERN_NOTICE
558 "serial_cs: no usable port range found, giving up\n");
559 cs_error(link->handle, RequestIRQ, i);
560 link->irq.AssignedIRQ = 0;
561 }
562 /* Socket Dual IO: this enables irq's for second port */
563 if (info->multi && (info->manfid == MANFID_SOCKET)) {
564 link->conf.Present |= PRESENT_EXT_STATUS;
565 link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
566 }
567 i = pcmcia_request_configuration(link->handle, &link->conf);
568 if (i != CS_SUCCESS) {
569 cs_error(link->handle, RequestConfiguration, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700570 rc = -1;
571 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 }
573
574 /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
575 8 registers are for the UART, the others are extra registers */
576 if (info->manfid == MANFID_OXSEMI) {
577 if (cf->index == 1 || cf->index == 3) {
578 setup_serial(handle, info, base2, link->irq.AssignedIRQ);
579 outb(12, link->io.BasePort1 + 1);
580 } else {
581 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
582 outb(12, base2 + 1);
583 }
Yum Rayan16f31112005-05-01 08:59:14 -0700584 rc = 0;
585 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 }
587
588 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
589 /* The Nokia cards are not really multiport cards */
Yum Rayan16f31112005-05-01 08:59:14 -0700590 if (info->manfid == MANFID_NOKIA) {
591 rc = 0;
592 goto free_cfg_mem;
593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 for (i = 0; i < info->multi - 1; i++)
Yum Rayan16f31112005-05-01 08:59:14 -0700595 setup_serial(handle, info, base2 + (8 * i),
596 link->irq.AssignedIRQ);
597 rc = 0;
598free_cfg_mem:
599 kfree(cfg_mem);
600 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603/*======================================================================
604
605 serial_config() is scheduled to run after a CARD_INSERTION event
606 is received, to configure the PCMCIA socket, and to make the
607 serial device available to the system.
608
609======================================================================*/
610
611void serial_config(dev_link_t * link)
612{
613 client_handle_t handle = link->handle;
614 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700615 struct serial_cfg_mem *cfg_mem;
616 tuple_t *tuple;
617 u_char *buf;
618 cisparse_t *parse;
619 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 int i, last_ret, last_fn;
621
622 DEBUG(0, "serial_config(0x%p)\n", link);
623
Yum Rayan16f31112005-05-01 08:59:14 -0700624 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
625 if (!cfg_mem)
626 goto failed;
627
628 tuple = &cfg_mem->tuple;
629 parse = &cfg_mem->parse;
630 cf = &parse->cftable_entry;
631 buf = cfg_mem->buf;
632
633 tuple->TupleData = (cisdata_t *) buf;
634 tuple->TupleOffset = 0;
635 tuple->TupleDataMax = 255;
636 tuple->Attributes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /* Get configuration register information */
Yum Rayan16f31112005-05-01 08:59:14 -0700638 tuple->DesiredTuple = CISTPL_CONFIG;
639 last_ret = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 if (last_ret != CS_SUCCESS) {
641 last_fn = ParseTuple;
642 goto cs_failed;
643 }
Yum Rayan16f31112005-05-01 08:59:14 -0700644 link->conf.ConfigBase = parse->config.base;
645 link->conf.Present = parse->config.rmask[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 /* Configure card */
648 link->state |= DEV_CONFIG;
649
650 /* Is this a compliant multifunction card? */
Yum Rayan16f31112005-05-01 08:59:14 -0700651 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
652 tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
653 info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 /* Is this a multiport card? */
Yum Rayan16f31112005-05-01 08:59:14 -0700656 tuple->DesiredTuple = CISTPL_MANFID;
657 if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
Petr Vandrovecf1fc3992005-05-16 21:53:44 -0700658 info->manfid = parse->manfid.manf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 for (i = 0; i < MULTI_COUNT; i++)
660 if ((info->manfid == multi_id[i].manfid) &&
Petr Vandrovecf1fc3992005-05-16 21:53:44 -0700661 (parse->manfid.card == multi_id[i].prodid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 if (i < MULTI_COUNT)
664 info->multi = multi_id[i].multi;
665 }
666
667 /* Another check for dual-serial cards: look for either serial or
668 multifunction cards that ask for appropriate IO port ranges */
Yum Rayan16f31112005-05-01 08:59:14 -0700669 tuple->DesiredTuple = CISTPL_FUNCID;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if ((info->multi == 0) &&
Yum Rayan16f31112005-05-01 08:59:14 -0700671 ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
672 (parse->funcid.func == CISTPL_FUNCID_MULTI) ||
673 (parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
674 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
675 if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
677 info->multi = cf->io.win[0].len >> 3;
678 if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
679 (cf->io.win[1].len == 8))
680 info->multi = 2;
681 }
682 }
683
684 if (info->multi > 1)
685 multi_config(link);
686 else
687 simple_config(link);
688
689 if (info->ndev == 0)
690 goto failed;
691
692 if (info->manfid == MANFID_IBM) {
693 conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
694 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
695 if (last_ret) {
696 last_fn = AccessConfigurationRegister;
697 goto cs_failed;
698 }
699 reg.Action = CS_WRITE;
700 reg.Value = reg.Value | 1;
701 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
702 if (last_ret) {
703 last_fn = AccessConfigurationRegister;
704 goto cs_failed;
705 }
706 }
707
708 link->dev = &info->node[0];
709 link->state &= ~DEV_CONFIG_PENDING;
Yum Rayan16f31112005-05-01 08:59:14 -0700710 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return;
712
713 cs_failed:
714 cs_error(link->handle, last_fn, last_ret);
715 failed:
716 serial_remove(link);
717 link->state &= ~DEV_CONFIG_PENDING;
Yum Rayan16f31112005-05-01 08:59:14 -0700718 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719}
720
721/*======================================================================
722
723 The card status event handler. Mostly, this schedules other
724 stuff to run after an event is received. A CARD_REMOVAL event
725 also sets some flags to discourage the serial drivers from
726 talking to the ports.
727
728======================================================================*/
729
730static int
731serial_event(event_t event, int priority, event_callback_args_t * args)
732{
733 dev_link_t *link = args->client_data;
734 struct serial_info *info = link->priv;
735
736 DEBUG(1, "serial_event(0x%06x)\n", event);
737
738 switch (event) {
739 case CS_EVENT_CARD_REMOVAL:
740 serial_remove(link);
741 break;
742
743 case CS_EVENT_CARD_INSERTION:
744 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
745 serial_config(link);
746 break;
747
748 case CS_EVENT_PM_SUSPEND:
749 serial_suspend(link);
750 break;
751
752 case CS_EVENT_RESET_PHYSICAL:
753 if ((link->state & DEV_CONFIG) && !info->slave)
754 pcmcia_release_configuration(link->handle);
755 break;
756
757 case CS_EVENT_PM_RESUME:
758 serial_resume(link);
759 break;
760
761 case CS_EVENT_CARD_RESET:
762 if (DEV_OK(link) && !info->slave)
763 pcmcia_request_configuration(link->handle, &link->conf);
764 break;
765 }
766 return 0;
767}
768
Dominik Brodowski325aa292005-06-27 16:28:18 -0700769static struct pcmcia_device_id serial_ids[] = {
770 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
771 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
772 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
773 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
774 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
775 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
776 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
777 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
778 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
779 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
780 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
781 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
Jun Komurof4d75102005-06-27 16:28:44 -0700782 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
783 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700784 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
785 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
786 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
787 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
788 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
789 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
790 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
791 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
792 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
Komurod277ad02005-07-28 01:07:24 -0700793 PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700794 PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
795 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
796 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
797 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
798 PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
799 PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
Komurod277ad02005-07-28 01:07:24 -0700800 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
801 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700802 PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
803 PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
804 PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
Komurod277ad02005-07-28 01:07:24 -0700805 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700806 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
807 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
808 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
809 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
810 PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
811 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
812 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
813 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
814 PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
815 PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
816 PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
817 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
818 PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
819 PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
820 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
821 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
822 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
823 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
824 PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
825 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
826 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
827 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
828 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
829 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
830 PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
831 PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
832 PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
833 PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
834 PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
835 PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
836 PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
837 PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
838 PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
839 PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
840 PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
841 PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
842 PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
Komurod277ad02005-07-28 01:07:24 -0700843 PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700844 PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
845 PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
846 PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
847 PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
848 PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
849 PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
850 PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
851 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
852 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
853 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
854 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
855 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
856 PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
857 PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
858 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"),
859 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
860 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
861 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
Dominik Brodowskia42f0dc2005-09-24 23:12:44 -0700862 PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
Dominik Brodowski325aa292005-06-27 16:28:18 -0700863 PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "MT5634ZLX.cis"),
864 PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
865 PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
866 PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
867 /* too generic */
868 /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
869 /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
870 PCMCIA_DEVICE_FUNC_ID(2),
871 PCMCIA_DEVICE_NULL,
872};
873MODULE_DEVICE_TABLE(pcmcia, serial_ids);
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875static struct pcmcia_driver serial_cs_driver = {
876 .owner = THIS_MODULE,
877 .drv = {
878 .name = "serial_cs",
879 },
880 .attach = serial_attach,
Dominik Brodowski1e212f32005-07-07 17:59:00 -0700881 .event = serial_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 .detach = serial_detach,
Dominik Brodowski325aa292005-06-27 16:28:18 -0700883 .id_table = serial_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884};
885
886static int __init init_serial_cs(void)
887{
888 return pcmcia_register_driver(&serial_cs_driver);
889}
890
891static void __exit exit_serial_cs(void)
892{
893 pcmcia_unregister_driver(&serial_cs_driver);
894 BUG_ON(dev_list != NULL);
895}
896
897module_init(init_serial_cs);
898module_exit(exit_serial_cs);
899
900MODULE_LICENSE("GPL");