blob: 83bfd11a1cc4af3803eda2f74a963c021477a59e [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
48#include <pcmcia/version.h>
49#include <pcmcia/cs_types.h>
50#include <pcmcia/cs.h>
51#include <pcmcia/cistpl.h>
52#include <pcmcia/ciscode.h>
53#include <pcmcia/ds.h>
54#include <pcmcia/cisreg.h>
55
56#include "8250.h"
57
58#ifdef PCMCIA_DEBUG
59static int pc_debug = PCMCIA_DEBUG;
60module_param(pc_debug, int, 0644);
61#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
62static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
63#else
64#define DEBUG(n, args...)
65#endif
66
67/*====================================================================*/
68
69/* Parameters that can be set with 'insmod' */
70
71/* Enable the speaker? */
72static int do_sound = 1;
73/* Skip strict UART tests? */
74static int buggy_uart;
75
76module_param(do_sound, int, 0444);
77module_param(buggy_uart, int, 0444);
78
79/*====================================================================*/
80
81/* Table of multi-port card ID's */
82
83struct multi_id {
84 u_short manfid;
85 u_short prodid;
86 int multi; /* 1 = multifunction, > 1 = # ports */
87};
88
89static struct multi_id multi_id[] = {
90 { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
91 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
92 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
93 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
94 { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
95 { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
96 { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
97};
98#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
99
100struct serial_info {
101 dev_link_t link;
102 int ndev;
103 int multi;
104 int slave;
105 int manfid;
106 dev_node_t node[4];
107 int line[4];
108};
109
Yum Rayan16f31112005-05-01 08:59:14 -0700110struct serial_cfg_mem {
111 tuple_t tuple;
112 cisparse_t parse;
113 u_char buf[256];
114};
115
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static void serial_config(dev_link_t * link);
118static int serial_event(event_t event, int priority,
119 event_callback_args_t * args);
120
121static dev_info_t dev_info = "serial_cs";
122
123static dev_link_t *serial_attach(void);
124static void serial_detach(dev_link_t *);
125
126static dev_link_t *dev_list = NULL;
127
128/*======================================================================
129
130 After a card is removed, serial_remove() will unregister
131 the serial device(s), and release the PCMCIA configuration.
132
133======================================================================*/
134
135static void serial_remove(dev_link_t *link)
136{
137 struct serial_info *info = link->priv;
138 int i;
139
140 link->state &= ~DEV_PRESENT;
141
142 DEBUG(0, "serial_release(0x%p)\n", link);
143
144 /*
145 * Recheck to see if the device is still configured.
146 */
147 if (info->link.state & DEV_CONFIG) {
148 for (i = 0; i < info->ndev; i++)
149 serial8250_unregister_port(info->line[i]);
150
151 info->link.dev = NULL;
152
153 if (!info->slave) {
154 pcmcia_release_configuration(info->link.handle);
155 pcmcia_release_io(info->link.handle, &info->link.io);
156 pcmcia_release_irq(info->link.handle, &info->link.irq);
157 }
158
159 info->link.state &= ~DEV_CONFIG;
160 }
161}
162
163static void serial_suspend(dev_link_t *link)
164{
165 link->state |= DEV_SUSPEND;
166
167 if (link->state & DEV_CONFIG) {
168 struct serial_info *info = link->priv;
169 int i;
170
171 for (i = 0; i < info->ndev; i++)
172 serial8250_suspend_port(info->line[i]);
173
174 if (!info->slave)
175 pcmcia_release_configuration(link->handle);
176 }
177}
178
179static void serial_resume(dev_link_t *link)
180{
181 link->state &= ~DEV_SUSPEND;
182
183 if (DEV_OK(link)) {
184 struct serial_info *info = link->priv;
185 int i;
186
187 if (!info->slave)
188 pcmcia_request_configuration(link->handle, &link->conf);
189
190 for (i = 0; i < info->ndev; i++)
191 serial8250_resume_port(info->line[i]);
192 }
193}
194
195/*======================================================================
196
197 serial_attach() creates an "instance" of the driver, allocating
198 local data structures for one device. The device is registered
199 with Card Services.
200
201======================================================================*/
202
203static dev_link_t *serial_attach(void)
204{
205 struct serial_info *info;
206 client_reg_t client_reg;
207 dev_link_t *link;
208 int ret;
209
210 DEBUG(0, "serial_attach()\n");
211
212 /* Create new serial device */
213 info = kmalloc(sizeof (*info), GFP_KERNEL);
214 if (!info)
215 return NULL;
216 memset(info, 0, sizeof (*info));
217 link = &info->link;
218 link->priv = info;
219
220 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
221 link->io.NumPorts1 = 8;
222 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
223 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
224 link->conf.Attributes = CONF_ENABLE_IRQ;
225 if (do_sound) {
226 link->conf.Attributes |= CONF_ENABLE_SPKR;
227 link->conf.Status = CCSR_AUDIO_ENA;
228 }
229 link->conf.IntType = INT_MEMORY_AND_IO;
230
231 /* Register with Card Services */
232 link->next = dev_list;
233 dev_list = link;
234 client_reg.dev_info = &dev_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 client_reg.Version = 0x0210;
236 client_reg.event_callback_args.client_data = link;
237 ret = pcmcia_register_client(&link->handle, &client_reg);
238 if (ret != CS_SUCCESS) {
239 cs_error(link->handle, RegisterClient, ret);
240 serial_detach(link);
241 return NULL;
242 }
243
244 return link;
245}
246
247/*======================================================================
248
249 This deletes a driver "instance". The device is de-registered
250 with Card Services. If it has been released, all local data
251 structures are freed. Otherwise, the structures will be freed
252 when the device is released.
253
254======================================================================*/
255
256static void serial_detach(dev_link_t * link)
257{
258 struct serial_info *info = link->priv;
259 dev_link_t **linkp;
260 int ret;
261
262 DEBUG(0, "serial_detach(0x%p)\n", link);
263
264 /* Locate device structure */
265 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
266 if (*linkp == link)
267 break;
268 if (*linkp == NULL)
269 return;
270
271 /*
272 * Ensure any outstanding scheduled tasks are completed.
273 */
274 flush_scheduled_work();
275
276 /*
277 * Ensure that the ports have been released.
278 */
279 serial_remove(link);
280
281 if (link->handle) {
282 ret = pcmcia_deregister_client(link->handle);
283 if (ret != CS_SUCCESS)
284 cs_error(link->handle, DeregisterClient, ret);
285 }
286
287 /* Unlink device structure, free bits */
288 *linkp = link->next;
289 kfree(info);
290}
291
292/*====================================================================*/
293
294static int setup_serial(client_handle_t handle, struct serial_info * info,
295 kio_addr_t iobase, int irq)
296{
297 struct uart_port port;
298 int line;
299
300 memset(&port, 0, sizeof (struct uart_port));
301 port.iobase = iobase;
302 port.irq = irq;
303 port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
304 port.uartclk = 1843200;
305 port.dev = &handle_to_dev(handle);
306 if (buggy_uart)
307 port.flags |= UPF_BUGGY_UART;
308 line = serial8250_register_port(&port);
309 if (line < 0) {
310 printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
311 "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
312 return -EINVAL;
313 }
314
315 info->line[info->ndev] = line;
316 sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
317 info->node[info->ndev].major = TTY_MAJOR;
318 info->node[info->ndev].minor = 0x40 + line;
319 if (info->ndev > 0)
320 info->node[info->ndev - 1].next = &info->node[info->ndev];
321 info->ndev++;
322
323 return 0;
324}
325
326/*====================================================================*/
327
328static int
329first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
330{
331 int i;
332 i = pcmcia_get_first_tuple(handle, tuple);
333 if (i != CS_SUCCESS)
334 return CS_NO_MORE_ITEMS;
335 i = pcmcia_get_tuple_data(handle, tuple);
336 if (i != CS_SUCCESS)
337 return i;
338 return pcmcia_parse_tuple(handle, tuple, parse);
339}
340
341static int
342next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
343{
344 int i;
345 i = pcmcia_get_next_tuple(handle, tuple);
346 if (i != CS_SUCCESS)
347 return CS_NO_MORE_ITEMS;
348 i = pcmcia_get_tuple_data(handle, tuple);
349 if (i != CS_SUCCESS)
350 return i;
351 return pcmcia_parse_tuple(handle, tuple, parse);
352}
353
354/*====================================================================*/
355
356static int simple_config(dev_link_t *link)
357{
358 static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
359 static int size_table[2] = { 8, 16 };
360 client_handle_t handle = link->handle;
361 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700362 struct serial_cfg_mem *cfg_mem;
363 tuple_t *tuple;
364 u_char *buf;
365 cisparse_t *parse;
366 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 config_info_t config;
368 int i, j, try;
369 int s;
370
Yum Rayan16f31112005-05-01 08:59:14 -0700371 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
372 if (!cfg_mem)
373 return -1;
374
375 tuple = &cfg_mem->tuple;
376 parse = &cfg_mem->parse;
377 cf = &parse->cftable_entry;
378 buf = cfg_mem->buf;
379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 /* If the card is already configured, look up the port and irq */
381 i = pcmcia_get_configuration_info(handle, &config);
382 if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
383 kio_addr_t port = 0;
384 if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
385 port = config.BasePort2;
386 info->slave = 1;
387 } else if ((info->manfid == MANFID_OSITECH) &&
388 (config.NumPorts1 == 0x40)) {
389 port = config.BasePort1 + 0x28;
390 info->slave = 1;
391 }
Yum Rayan16f31112005-05-01 08:59:14 -0700392 if (info->slave) {
393 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return setup_serial(handle, info, port, config.AssignedIRQ);
Yum Rayan16f31112005-05-01 08:59:14 -0700395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 }
397 link->conf.Vcc = config.Vcc;
398
399 /* First pass: look for a config entry that looks normal. */
Yum Rayan16f31112005-05-01 08:59:14 -0700400 tuple->TupleData = (cisdata_t *) buf;
401 tuple->TupleOffset = 0;
402 tuple->TupleDataMax = 255;
403 tuple->Attributes = 0;
404 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 /* Two tries: without IO aliases, then with aliases */
406 for (s = 0; s < 2; s++) {
407 for (try = 0; try < 2; try++) {
Yum Rayan16f31112005-05-01 08:59:14 -0700408 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 while (i != CS_NO_MORE_ITEMS) {
410 if (i != CS_SUCCESS)
411 goto next_entry;
412 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
413 link->conf.Vpp1 = link->conf.Vpp2 =
414 cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
415 if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
416 (cf->io.win[0].base != 0)) {
417 link->conf.ConfigIndex = cf->index;
418 link->io.BasePort1 = cf->io.win[0].base;
419 link->io.IOAddrLines = (try == 0) ?
420 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
421 i = pcmcia_request_io(link->handle, &link->io);
422 if (i == CS_SUCCESS)
423 goto found_port;
424 }
425next_entry:
Yum Rayan16f31112005-05-01 08:59:14 -0700426 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 }
428 }
429 }
430 /* Second pass: try to find an entry that isn't picky about
431 its base address, then try to grab any standard serial port
432 address, and finally try to get any free port. */
Yum Rayan16f31112005-05-01 08:59:14 -0700433 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 while (i != CS_NO_MORE_ITEMS) {
435 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
436 ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
437 link->conf.ConfigIndex = cf->index;
438 for (j = 0; j < 5; j++) {
439 link->io.BasePort1 = base[j];
440 link->io.IOAddrLines = base[j] ? 16 : 3;
441 i = pcmcia_request_io(link->handle, &link->io);
442 if (i == CS_SUCCESS)
443 goto found_port;
444 }
445 }
Yum Rayan16f31112005-05-01 08:59:14 -0700446 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
448
449 found_port:
450 if (i != CS_SUCCESS) {
451 printk(KERN_NOTICE
452 "serial_cs: no usable port range found, giving up\n");
453 cs_error(link->handle, RequestIO, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700454 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 return -1;
456 }
457
458 i = pcmcia_request_irq(link->handle, &link->irq);
459 if (i != CS_SUCCESS) {
460 cs_error(link->handle, RequestIRQ, i);
461 link->irq.AssignedIRQ = 0;
462 }
463 if (info->multi && (info->manfid == MANFID_3COM))
464 link->conf.ConfigIndex &= ~(0x08);
465 i = pcmcia_request_configuration(link->handle, &link->conf);
466 if (i != CS_SUCCESS) {
467 cs_error(link->handle, RequestConfiguration, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700468 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return -1;
470 }
Yum Rayan16f31112005-05-01 08:59:14 -0700471 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
473}
474
475static int multi_config(dev_link_t * link)
476{
477 client_handle_t handle = link->handle;
478 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700479 struct serial_cfg_mem *cfg_mem;
480 tuple_t *tuple;
481 u_char *buf;
482 cisparse_t *parse;
483 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 config_info_t config;
Yum Rayan16f31112005-05-01 08:59:14 -0700485 int i, rc, base2 = 0;
486
487 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
488 if (!cfg_mem)
489 return -1;
490 tuple = &cfg_mem->tuple;
491 parse = &cfg_mem->parse;
492 cf = &parse->cftable_entry;
493 buf = cfg_mem->buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 i = pcmcia_get_configuration_info(handle, &config);
496 if (i != CS_SUCCESS) {
497 cs_error(handle, GetConfigurationInfo, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700498 rc = -1;
499 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501 link->conf.Vcc = config.Vcc;
502
Yum Rayan16f31112005-05-01 08:59:14 -0700503 tuple->TupleData = (cisdata_t *) buf;
504 tuple->TupleOffset = 0;
505 tuple->TupleDataMax = 255;
506 tuple->Attributes = 0;
507 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 /* First, look for a generic full-sized window */
510 link->io.NumPorts1 = info->multi * 8;
Yum Rayan16f31112005-05-01 08:59:14 -0700511 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 while (i != CS_NO_MORE_ITEMS) {
513 /* The quad port cards have bad CIS's, so just look for a
514 window larger than 8 ports and assume it will be right */
515 if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
516 (cf->io.win[0].len > 8)) {
517 link->conf.ConfigIndex = cf->index;
518 link->io.BasePort1 = cf->io.win[0].base;
519 link->io.IOAddrLines =
520 cf->io.flags & CISTPL_IO_LINES_MASK;
521 i = pcmcia_request_io(link->handle, &link->io);
522 base2 = link->io.BasePort1 + 8;
523 if (i == CS_SUCCESS)
524 break;
525 }
Yum Rayan16f31112005-05-01 08:59:14 -0700526 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 }
528
529 /* If that didn't work, look for two windows */
530 if (i != CS_SUCCESS) {
531 link->io.NumPorts1 = link->io.NumPorts2 = 8;
532 info->multi = 2;
Yum Rayan16f31112005-05-01 08:59:14 -0700533 i = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 while (i != CS_NO_MORE_ITEMS) {
535 if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
536 link->conf.ConfigIndex = cf->index;
537 link->io.BasePort1 = cf->io.win[0].base;
538 link->io.BasePort2 = cf->io.win[1].base;
539 link->io.IOAddrLines =
540 cf->io.flags & CISTPL_IO_LINES_MASK;
541 i = pcmcia_request_io(link->handle, &link->io);
542 base2 = link->io.BasePort2;
543 if (i == CS_SUCCESS)
544 break;
545 }
Yum Rayan16f31112005-05-01 08:59:14 -0700546 i = next_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
548 }
549
550 if (i != CS_SUCCESS) {
551 cs_error(link->handle, RequestIO, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700552 rc = -1;
553 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 }
555
556 i = pcmcia_request_irq(link->handle, &link->irq);
557 if (i != CS_SUCCESS) {
558 printk(KERN_NOTICE
559 "serial_cs: no usable port range found, giving up\n");
560 cs_error(link->handle, RequestIRQ, i);
561 link->irq.AssignedIRQ = 0;
562 }
563 /* Socket Dual IO: this enables irq's for second port */
564 if (info->multi && (info->manfid == MANFID_SOCKET)) {
565 link->conf.Present |= PRESENT_EXT_STATUS;
566 link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
567 }
568 i = pcmcia_request_configuration(link->handle, &link->conf);
569 if (i != CS_SUCCESS) {
570 cs_error(link->handle, RequestConfiguration, i);
Yum Rayan16f31112005-05-01 08:59:14 -0700571 rc = -1;
572 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
574
575 /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
576 8 registers are for the UART, the others are extra registers */
577 if (info->manfid == MANFID_OXSEMI) {
578 if (cf->index == 1 || cf->index == 3) {
579 setup_serial(handle, info, base2, link->irq.AssignedIRQ);
580 outb(12, link->io.BasePort1 + 1);
581 } else {
582 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
583 outb(12, base2 + 1);
584 }
Yum Rayan16f31112005-05-01 08:59:14 -0700585 rc = 0;
586 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 }
588
589 setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
590 /* The Nokia cards are not really multiport cards */
Yum Rayan16f31112005-05-01 08:59:14 -0700591 if (info->manfid == MANFID_NOKIA) {
592 rc = 0;
593 goto free_cfg_mem;
594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 for (i = 0; i < info->multi - 1; i++)
Yum Rayan16f31112005-05-01 08:59:14 -0700596 setup_serial(handle, info, base2 + (8 * i),
597 link->irq.AssignedIRQ);
598 rc = 0;
599free_cfg_mem:
600 kfree(cfg_mem);
601 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
604/*======================================================================
605
606 serial_config() is scheduled to run after a CARD_INSERTION event
607 is received, to configure the PCMCIA socket, and to make the
608 serial device available to the system.
609
610======================================================================*/
611
612void serial_config(dev_link_t * link)
613{
614 client_handle_t handle = link->handle;
615 struct serial_info *info = link->priv;
Yum Rayan16f31112005-05-01 08:59:14 -0700616 struct serial_cfg_mem *cfg_mem;
617 tuple_t *tuple;
618 u_char *buf;
619 cisparse_t *parse;
620 cistpl_cftable_entry_t *cf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 int i, last_ret, last_fn;
622
623 DEBUG(0, "serial_config(0x%p)\n", link);
624
Yum Rayan16f31112005-05-01 08:59:14 -0700625 cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
626 if (!cfg_mem)
627 goto failed;
628
629 tuple = &cfg_mem->tuple;
630 parse = &cfg_mem->parse;
631 cf = &parse->cftable_entry;
632 buf = cfg_mem->buf;
633
634 tuple->TupleData = (cisdata_t *) buf;
635 tuple->TupleOffset = 0;
636 tuple->TupleDataMax = 255;
637 tuple->Attributes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* Get configuration register information */
Yum Rayan16f31112005-05-01 08:59:14 -0700639 tuple->DesiredTuple = CISTPL_CONFIG;
640 last_ret = first_tuple(handle, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (last_ret != CS_SUCCESS) {
642 last_fn = ParseTuple;
643 goto cs_failed;
644 }
Yum Rayan16f31112005-05-01 08:59:14 -0700645 link->conf.ConfigBase = parse->config.base;
646 link->conf.Present = parse->config.rmask[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 /* Configure card */
649 link->state |= DEV_CONFIG;
650
651 /* Is this a compliant multifunction card? */
Yum Rayan16f31112005-05-01 08:59:14 -0700652 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
653 tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
654 info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 /* Is this a multiport card? */
Yum Rayan16f31112005-05-01 08:59:14 -0700657 tuple->DesiredTuple = CISTPL_MANFID;
658 if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
Petr Vandrovecf1fc3992005-05-16 21:53:44 -0700659 info->manfid = parse->manfid.manf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 for (i = 0; i < MULTI_COUNT; i++)
661 if ((info->manfid == multi_id[i].manfid) &&
Petr Vandrovecf1fc3992005-05-16 21:53:44 -0700662 (parse->manfid.card == multi_id[i].prodid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 break;
664 if (i < MULTI_COUNT)
665 info->multi = multi_id[i].multi;
666 }
667
668 /* Another check for dual-serial cards: look for either serial or
669 multifunction cards that ask for appropriate IO port ranges */
Yum Rayan16f31112005-05-01 08:59:14 -0700670 tuple->DesiredTuple = CISTPL_FUNCID;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if ((info->multi == 0) &&
Yum Rayan16f31112005-05-01 08:59:14 -0700672 ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
673 (parse->funcid.func == CISTPL_FUNCID_MULTI) ||
674 (parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
675 tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
676 if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
678 info->multi = cf->io.win[0].len >> 3;
679 if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
680 (cf->io.win[1].len == 8))
681 info->multi = 2;
682 }
683 }
684
685 if (info->multi > 1)
686 multi_config(link);
687 else
688 simple_config(link);
689
690 if (info->ndev == 0)
691 goto failed;
692
693 if (info->manfid == MANFID_IBM) {
694 conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
695 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
696 if (last_ret) {
697 last_fn = AccessConfigurationRegister;
698 goto cs_failed;
699 }
700 reg.Action = CS_WRITE;
701 reg.Value = reg.Value | 1;
702 last_ret = pcmcia_access_configuration_register(link->handle, &reg);
703 if (last_ret) {
704 last_fn = AccessConfigurationRegister;
705 goto cs_failed;
706 }
707 }
708
709 link->dev = &info->node[0];
710 link->state &= ~DEV_CONFIG_PENDING;
Yum Rayan16f31112005-05-01 08:59:14 -0700711 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return;
713
714 cs_failed:
715 cs_error(link->handle, last_fn, last_ret);
716 failed:
717 serial_remove(link);
718 link->state &= ~DEV_CONFIG_PENDING;
Yum Rayan16f31112005-05-01 08:59:14 -0700719 kfree(cfg_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
722/*======================================================================
723
724 The card status event handler. Mostly, this schedules other
725 stuff to run after an event is received. A CARD_REMOVAL event
726 also sets some flags to discourage the serial drivers from
727 talking to the ports.
728
729======================================================================*/
730
731static int
732serial_event(event_t event, int priority, event_callback_args_t * args)
733{
734 dev_link_t *link = args->client_data;
735 struct serial_info *info = link->priv;
736
737 DEBUG(1, "serial_event(0x%06x)\n", event);
738
739 switch (event) {
740 case CS_EVENT_CARD_REMOVAL:
741 serial_remove(link);
742 break;
743
744 case CS_EVENT_CARD_INSERTION:
745 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
746 serial_config(link);
747 break;
748
749 case CS_EVENT_PM_SUSPEND:
750 serial_suspend(link);
751 break;
752
753 case CS_EVENT_RESET_PHYSICAL:
754 if ((link->state & DEV_CONFIG) && !info->slave)
755 pcmcia_release_configuration(link->handle);
756 break;
757
758 case CS_EVENT_PM_RESUME:
759 serial_resume(link);
760 break;
761
762 case CS_EVENT_CARD_RESET:
763 if (DEV_OK(link) && !info->slave)
764 pcmcia_request_configuration(link->handle, &link->conf);
765 break;
766 }
767 return 0;
768}
769
Dominik Brodowski325aa292005-06-27 16:28:18 -0700770static struct pcmcia_device_id serial_ids[] = {
771 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
772 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
773 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
774 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
775 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
776 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
777 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
778 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
779 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
780 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
781 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
782 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
Jun Komurof4d75102005-06-27 16:28:44 -0700783 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
784 PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
Dominik Brodowski325aa292005-06-27 16:28:18 -0700785 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
786 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
787 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
788 PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
789 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
790 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
791 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
792 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
793 PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
794 PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
795 PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
796 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
797 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
798 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
799 PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
800 PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
801 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
802 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
803 PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
804 PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
805 PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
806 PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
807 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
808 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
809 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
810 PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
811 PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
812 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
813 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
814 PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
815 PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
816 PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
817 PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
818 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
819 PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
820 PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
821 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
822 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
823 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
824 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
825 PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
826 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
827 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
828 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
829 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
830 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
831 PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
832 PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
833 PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
834 PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
835 PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
836 PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
837 PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
838 PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
839 PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
840 PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
841 PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
842 PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
843 PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
844 PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400", 0x816cc815, 0x23539b80),
845 PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
846 PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
847 PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
848 PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
849 PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
850 PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
851 PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
852 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
853 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
854 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
855 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
856 PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
857 PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
858 PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
859 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"),
860 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
861 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
862 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
863 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");