1/*====================================================================== 2 3 A driver for PCMCIA serial devices 4 5 serial_cs.c 1.128 2001/10/18 12:18:35 6 7 The contents of this file are subject to the Mozilla Public 8 License Version 1.1 (the "License"); you may not use this file 9 except in compliance with the License. You may obtain a copy of 10 the License at http://www.mozilla.org/MPL/ 11 12 Software distributed under the License is distributed on an "AS 13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14 implied. See the License for the specific language governing 15 rights and limitations under the License. 16 17 The initial developer of the original code is David A. Hinds 18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 20 21 Alternatively, the contents of this file may be used under the 22 terms of the GNU General Public License version 2 (the "GPL"), in 23 which case the provisions of the GPL are applicable instead of the 24 above. If you wish to allow the use of your version of this file 25 only under the terms of the GPL and not to allow others to use 26 your version of this file under the MPL, indicate your decision 27 by deleting the provisions above and replace them with the notice 28 and other provisions required by the GPL. If you do not delete 29 the provisions above, a recipient may use your version of this 30 file under either the MPL or the GPL. 31 32======================================================================*/ 33 34#include <linux/module.h> 35#include <linux/kernel.h> 36#include <linux/init.h> 37#include <linux/sched.h> 38#include <linux/ptrace.h> 39#include <linux/slab.h> 40#include <linux/string.h> 41#include <linux/timer.h> 42#include <linux/tty.h> 43#include <linux/serial.h> 44#include <linux/major.h> 45#include <asm/io.h> 46#include <asm/system.h> 47#include <asm/byteorder.h> 48 49#include <pcmcia/version.h> 50#include <pcmcia/cs_types.h> 51#include <pcmcia/cs.h> 52#include <pcmcia/cistpl.h> 53#include <pcmcia/ciscode.h> 54#include <pcmcia/ds.h> 55#include <pcmcia/cisreg.h> 56 57/*====================================================================*/ 58 59/* Module parameters */ 60 61MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 62MODULE_DESCRIPTION("PCMCIA serial card driver"); 63MODULE_LICENSE("Dual MPL/GPL"); 64 65#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") 66 67/* Bit map of interrupts to choose from */ 68INT_MODULE_PARM(irq_mask, 0xdeb8); 69static int irq_list[4] = { -1 }; 70MODULE_PARM(irq_list, "1-4i"); 71 72/* Enable the speaker? */ 73INT_MODULE_PARM(do_sound, 1); 74 75#ifdef PCMCIA_DEBUG 76INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); 77#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) 78static char *version = 79"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; 80#else 81#define DEBUG(n, args...) 82#endif 83 84/*====================================================================*/ 85 86/* Table of multi-port card ID's */ 87 88typedef struct { 89 u_short manfid; 90 u_short prodid; 91 int multi; /* 1 = multifunction, > 1 = # ports */ 92} multi_id_t; 93 94static multi_id_t multi_id[] = { 95 { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 }, 96 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, 97 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, 98 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, 99 { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, 100 { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, 101 { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 }, 102 { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 }, 103 { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 } 104}; 105#define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t)) 106 107typedef struct serial_info_t { 108 dev_link_t link; 109 int ndev; 110 int multi; 111 int slave; 112 int manfid; 113 dev_node_t node[4]; 114 int line[4]; 115} serial_info_t; 116 117static void serial_config(dev_link_t *link); 118static void serial_release(u_long arg); 119static int serial_event(event_t event, int priority, 120 event_callback_args_t *args); 121 122static dev_info_t dev_info = "serial_cs"; 123 124static dev_link_t *serial_attach(void); 125static void serial_detach(dev_link_t *); 126 127static dev_link_t *dev_list = NULL; 128 129/*====================================================================*/ 130 131static void cs_error(client_handle_t handle, int func, int ret) 132{ 133 error_info_t err = { func, ret }; 134 CardServices(ReportError, handle, &err); 135} 136 137/*====================================================================== 138 139 serial_attach() creates an "instance" of the driver, allocating 140 local data structures for one device. The device is registered 141 with Card Services. 142 143======================================================================*/ 144 145static dev_link_t *serial_attach(void) 146{ 147 serial_info_t *info; 148 client_reg_t client_reg; 149 dev_link_t *link; 150 int i, ret; 151 152 DEBUG(0, "serial_attach()\n"); 153 154 /* Create new serial device */ 155 info = kmalloc(sizeof(*info), GFP_KERNEL); 156 if (!info) return NULL; 157 memset(info, 0, sizeof(*info)); 158 link = &info->link; link->priv = info; 159 160 link->release.function = &serial_release; 161 link->release.data = (u_long)link; 162 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 163 link->io.NumPorts1 = 8; 164 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 165 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; 166 if (irq_list[0] == -1) 167 link->irq.IRQInfo2 = irq_mask; 168 else 169 for (i = 0; i < 4; i++) 170 link->irq.IRQInfo2 |= 1 << irq_list[i]; 171 link->conf.Attributes = CONF_ENABLE_IRQ; 172 link->conf.Vcc = 50; 173 if (do_sound) { 174 link->conf.Attributes |= CONF_ENABLE_SPKR; 175 link->conf.Status = CCSR_AUDIO_ENA; 176 } 177 link->conf.IntType = INT_MEMORY_AND_IO; 178 179 /* Register with Card Services */ 180 link->next = dev_list; 181 dev_list = link; 182 client_reg.dev_info = &dev_info; 183 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; 184 client_reg.EventMask = 185 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 186 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | 187 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; 188 client_reg.event_handler = &serial_event; 189 client_reg.Version = 0x0210; 190 client_reg.event_callback_args.client_data = link; 191 ret = CardServices(RegisterClient, &link->handle, &client_reg); 192 if (ret != CS_SUCCESS) { 193 cs_error(link->handle, RegisterClient, ret); 194 serial_detach(link); 195 return NULL; 196 } 197 198 return link; 199} /* serial_attach */ 200 201/*====================================================================== 202 203 This deletes a driver "instance". The device is de-registered 204 with Card Services. If it has been released, all local data 205 structures are freed. Otherwise, the structures will be freed 206 when the device is released. 207 208======================================================================*/ 209 210static void serial_detach(dev_link_t *link) 211{ 212 serial_info_t *info = link->priv; 213 dev_link_t **linkp; 214 int ret; 215 216 DEBUG(0, "serial_detach(0x%p)\n", link); 217 218 /* Locate device structure */ 219 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) 220 if (*linkp == link) break; 221 if (*linkp == NULL) 222 return; 223 224 del_timer(&link->release); 225 if (link->state & DEV_CONFIG) 226 serial_release((u_long)link); 227 228 if (link->handle) { 229 ret = CardServices(DeregisterClient, link->handle); 230 if (ret != CS_SUCCESS) 231 cs_error(link->handle, DeregisterClient, ret); 232 } 233 234 /* Unlink device structure, free bits */ 235 *linkp = link->next; 236 kfree(info); 237 238} /* serial_detach */ 239 240/*====================================================================*/ 241 242static int setup_serial(serial_info_t *info, ioaddr_t port, int irq) 243{ 244 struct serial_struct serial; 245 int line; 246 247 memset(&serial, 0, sizeof(serial)); 248 serial.port = port; 249 serial.irq = irq; 250 serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; 251 line = register_serial(&serial); 252 if (line < 0) { 253 printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," 254 " irq %d failed\n", (u_long)serial.port, serial.irq); 255 return -1; 256 } 257 258 info->line[info->ndev] = line; 259 sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); 260 info->node[info->ndev].major = TTY_MAJOR; 261 info->node[info->ndev].minor = 0x40+line; 262 if (info->ndev > 0) 263 info->node[info->ndev-1].next = &info->node[info->ndev]; 264 info->ndev++; 265 266 return 0; 267} 268 269/*====================================================================*/ 270 271static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, 272 cisparse_t *parse) 273{ 274 int i; 275 i = CardServices(fn, handle, tuple); 276 if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS; 277 i = CardServices(GetTupleData, handle, tuple); 278 if (i != CS_SUCCESS) return i; 279 return CardServices(ParseTuple, handle, tuple, parse); 280} 281 282#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) 283#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) 284 285/*====================================================================*/ 286 287static int simple_config(dev_link_t *link) 288{ 289 static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; 290 client_handle_t handle = link->handle; 291 serial_info_t *info = link->priv; 292 tuple_t tuple; 293 u_char buf[256]; 294 cisparse_t parse; 295 cistpl_cftable_entry_t *cf = &parse.cftable_entry; 296 config_info_t config; 297 int i, j, try; 298 299 /* If the card is already configured, look up the port and irq */ 300 i = CardServices(GetConfigurationInfo, handle, &config); 301 if ((i == CS_SUCCESS) && 302 (config.Attributes & CONF_VALID_CLIENT)) { 303 ioaddr_t port = 0; 304 if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { 305 port = config.BasePort2; 306 info->slave = 1; 307 } else if ((info->manfid == MANFID_OSITECH) && 308 (config.NumPorts1 == 0x40)) { 309 port = config.BasePort1 + 0x28; 310 info->slave = 1; 311 } 312 if (info->slave) 313 return setup_serial(info, port, config.AssignedIRQ); 314 } 315 link->conf.Vcc = config.Vcc; 316 317 /* First pass: look for a config entry that looks normal. */ 318 tuple.TupleData = (cisdata_t *)buf; 319 tuple.TupleOffset = 0; tuple.TupleDataMax = 255; 320 tuple.Attributes = 0; 321 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 322 /* Two tries: without IO aliases, then with aliases */ 323 for (try = 0; try < 2; try++) { 324 i = first_tuple(handle, &tuple, &parse); 325 while (i != CS_NO_MORE_ITEMS) { 326 if (i != CS_SUCCESS) goto next_entry; 327 if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM)) 328 link->conf.Vpp1 = link->conf.Vpp2 = 329 cf->vpp1.param[CISTPL_POWER_VNOM]/10000; 330 if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && 331 (cf->io.win[0].base != 0)) { 332 link->conf.ConfigIndex = cf->index; 333 link->io.BasePort1 = cf->io.win[0].base; 334 link->io.IOAddrLines = (try == 0) ? 335 16 : cf->io.flags & CISTPL_IO_LINES_MASK; 336 i = CardServices(RequestIO, link->handle, &link->io); 337 if (i == CS_SUCCESS) goto found_port; 338 } 339 next_entry: 340 i = next_tuple(handle, &tuple, &parse); 341 } 342 } 343 344 /* Second pass: try to find an entry that isn't picky about 345 its base address, then try to grab any standard serial port 346 address, and finally try to get any free port. */ 347 i = first_tuple(handle, &tuple, &parse); 348 while (i != CS_NO_MORE_ITEMS) { 349 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && 350 ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { 351 link->conf.ConfigIndex = cf->index; 352 for (j = 0; j < 5; j++) { 353 link->io.BasePort1 = base[j]; 354 link->io.IOAddrLines = base[j] ? 16 : 3; 355 i = CardServices(RequestIO, link->handle, 356 &link->io); 357 if (i == CS_SUCCESS) goto found_port; 358 } 359 } 360 i = next_tuple(handle, &tuple, &parse); 361 } 362 363found_port: 364 if (i != CS_SUCCESS) { 365 cs_error(link->handle, RequestIO, i); 366 return -1; 367 } 368 369 i = CardServices(RequestIRQ, link->handle, &link->irq); 370 if (i != CS_SUCCESS) { 371 cs_error(link->handle, RequestIRQ, i); 372 link->irq.AssignedIRQ = 0; 373 } 374 if (info->multi && (info->manfid == MANFID_3COM)) 375 link->conf.ConfigIndex &= ~(0x08); 376 i = CardServices(RequestConfiguration, link->handle, &link->conf); 377 if (i != CS_SUCCESS) { 378 cs_error(link->handle, RequestConfiguration, i); 379 return -1; 380 } 381 382 return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); 383} 384 385static int multi_config(dev_link_t *link) 386{ 387 client_handle_t handle = link->handle; 388 serial_info_t *info = link->priv; 389 tuple_t tuple; 390 u_char buf[256]; 391 cisparse_t parse; 392 cistpl_cftable_entry_t *cf = &parse.cftable_entry; 393 int i, base2 = 0; 394 395 tuple.TupleData = (cisdata_t *)buf; 396 tuple.TupleOffset = 0; tuple.TupleDataMax = 255; 397 tuple.Attributes = 0; 398 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 399 400 /* First, look for a generic full-sized window */ 401 link->io.NumPorts1 = info->multi * 8; 402 i = first_tuple(handle, &tuple, &parse); 403 while (i != CS_NO_MORE_ITEMS) { 404 /* The quad port cards have bad CIS's, so just look for a 405 window larger than 8 ports and assume it will be right */ 406 if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && 407 (cf->io.win[0].len > 8)) { 408 link->conf.ConfigIndex = cf->index; 409 link->io.BasePort1 = cf->io.win[0].base; 410 link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; 411 i = CardServices(RequestIO, link->handle, &link->io); 412 base2 = link->io.BasePort1 + 8; 413 if (i == CS_SUCCESS) break; 414 } 415 i = next_tuple(handle, &tuple, &parse); 416 } 417 418 /* If that didn't work, look for two windows */ 419 if (i != CS_SUCCESS) { 420 link->io.NumPorts1 = link->io.NumPorts2 = 8; 421 info->multi = 2; 422 i = first_tuple(handle, &tuple, &parse); 423 while (i != CS_NO_MORE_ITEMS) { 424 if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { 425 link->conf.ConfigIndex = cf->index; 426 link->io.BasePort1 = cf->io.win[0].base; 427 link->io.BasePort2 = cf->io.win[1].base; 428 link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; 429 i = CardServices(RequestIO, link->handle, &link->io); 430 base2 = link->io.BasePort2; 431 if (i == CS_SUCCESS) break; 432 } 433 i = next_tuple(handle, &tuple, &parse); 434 } 435 } 436 437 if (i != CS_SUCCESS) { 438 cs_error(link->handle, RequestIO, i); 439 return -1; 440 } 441 442 i = CardServices(RequestIRQ, link->handle, &link->irq); 443 if (i != CS_SUCCESS) { 444 cs_error(link->handle, RequestIRQ, i); 445 link->irq.AssignedIRQ = 0; 446 } 447 /* Socket Dual IO: this enables irq's for second port */ 448 if (info->multi && (info->manfid == MANFID_SOCKET)) { 449 link->conf.Present |= PRESENT_EXT_STATUS; 450 link->conf.ExtStatus = ESR_REQ_ATTN_ENA; 451 } 452 i = CardServices(RequestConfiguration, link->handle, &link->conf); 453 if (i != CS_SUCCESS) { 454 cs_error(link->handle, RequestConfiguration, i); 455 return -1; 456 } 457 458 setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); 459 /* The Nokia cards are not really multiport cards */ 460 if (info->manfid == MANFID_NOKIA) 461 return 0; 462 for (i = 0; i < info->multi-1; i++) 463 setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); 464 465 return 0; 466} 467 468/*====================================================================== 469 470 serial_config() is scheduled to run after a CARD_INSERTION event 471 is received, to configure the PCMCIA socket, and to make the 472 serial device available to the system. 473 474======================================================================*/ 475 476#define CS_CHECK(fn, args...) \ 477while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed 478 479void serial_config(dev_link_t *link) 480{ 481 client_handle_t handle = link->handle; 482 serial_info_t *info = link->priv; 483 tuple_t tuple; 484 u_short buf[128]; 485 cisparse_t parse; 486 cistpl_cftable_entry_t *cf = &parse.cftable_entry; 487 int i, last_ret, last_fn; 488 489 DEBUG(0, "serial_config(0x%p)\n", link); 490 491 tuple.TupleData = (cisdata_t *)buf; 492 tuple.TupleOffset = 0; tuple.TupleDataMax = 255; 493 tuple.Attributes = 0; 494 /* Get configuration register information */ 495 tuple.DesiredTuple = CISTPL_CONFIG; 496 last_ret = first_tuple(handle, &tuple, &parse); 497 if (last_ret != CS_SUCCESS) { 498 last_fn = ParseTuple; 499 goto cs_failed; 500 } 501 link->conf.ConfigBase = parse.config.base; 502 link->conf.Present = parse.config.rmask[0]; 503 504 /* Configure card */ 505 link->state |= DEV_CONFIG; 506 507 /* Is this a compliant multifunction card? */ 508 tuple.DesiredTuple = CISTPL_LONGLINK_MFC; 509 tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; 510 info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); 511 512 /* Is this a multiport card? */ 513 tuple.DesiredTuple = CISTPL_MANFID; 514 if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { 515 info->manfid = le16_to_cpu(buf[0]); 516 for (i = 0; i < MULTI_COUNT; i++) 517 if ((info->manfid == multi_id[i].manfid) && 518 (le16_to_cpu(buf[1]) == multi_id[i].prodid)) 519 break; 520 if (i < MULTI_COUNT) 521 info->multi = multi_id[i].multi; 522 } 523 524 /* Another check for dual-serial cards: look for either serial or 525 multifunction cards that ask for appropriate IO port ranges */ 526 tuple.DesiredTuple = CISTPL_FUNCID; 527 if ((info->multi == 0) && 528 ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || 529 (parse.funcid.func == CISTPL_FUNCID_MULTI) || 530 (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { 531 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 532 if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { 533 if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) 534 info->multi = cf->io.win[0].len >> 3; 535 if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && 536 (cf->io.win[1].len == 8)) 537 info->multi = 2; 538 } 539 } 540 541 if (info->multi > 1) 542 multi_config(link); 543 else 544 simple_config(link); 545 546 if (info->ndev == 0) 547 goto failed; 548 549 if (info->manfid == MANFID_IBM) { 550 conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; 551 CS_CHECK(AccessConfigurationRegister, link->handle, ®); 552 reg.Action = CS_WRITE; 553 reg.Value = reg.Value | 1; 554 CS_CHECK(AccessConfigurationRegister, link->handle, ®); 555 } 556 557 link->dev = &info->node[0]; 558 link->state &= ~DEV_CONFIG_PENDING; 559 return; 560 561cs_failed: 562 cs_error(link->handle, last_fn, last_ret); 563failed: 564 serial_release((u_long)link); 565 566} /* serial_config */ 567 568/*====================================================================== 569 570 After a card is removed, serial_release() will unregister the net 571 device, and release the PCMCIA configuration. 572 573======================================================================*/ 574 575void serial_release(u_long arg) 576{ 577 dev_link_t *link = (dev_link_t *)arg; 578 serial_info_t *info = link->priv; 579 int i; 580 581 DEBUG(0, "serial_release(0x%p)\n", link); 582 583 for (i = 0; i < info->ndev; i++) { 584 unregister_serial(info->line[i]); 585 } 586 link->dev = NULL; 587 588 if (!info->slave) { 589 CardServices(ReleaseConfiguration, link->handle); 590 CardServices(ReleaseIO, link->handle, &link->io); 591 CardServices(ReleaseIRQ, link->handle, &link->irq); 592 } 593 594 link->state &= ~DEV_CONFIG; 595 596} /* serial_release */ 597 598/*====================================================================== 599 600 The card status event handler. Mostly, this schedules other 601 stuff to run after an event is received. A CARD_REMOVAL event 602 also sets some flags to discourage the serial drivers from 603 talking to the ports. 604 605======================================================================*/ 606 607static int serial_event(event_t event, int priority, 608 event_callback_args_t *args) 609{ 610 dev_link_t *link = args->client_data; 611 serial_info_t *info = link->priv; 612 613 DEBUG(1, "serial_event(0x%06x)\n", event); 614 615 switch (event) { 616 case CS_EVENT_CARD_REMOVAL: 617 link->state &= ~DEV_PRESENT; 618 if (link->state & DEV_CONFIG) 619 mod_timer(&link->release, jiffies + HZ/20); 620 break; 621 case CS_EVENT_CARD_INSERTION: 622 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; 623 serial_config(link); 624 break; 625 case CS_EVENT_PM_SUSPEND: 626 link->state |= DEV_SUSPEND; 627 /* Fall through... */ 628 case CS_EVENT_RESET_PHYSICAL: 629 if ((link->state & DEV_CONFIG) && !info->slave) 630 CardServices(ReleaseConfiguration, link->handle); 631 break; 632 case CS_EVENT_PM_RESUME: 633 link->state &= ~DEV_SUSPEND; 634 /* Fall through... */ 635 case CS_EVENT_CARD_RESET: 636 if (DEV_OK(link) && !info->slave) 637 CardServices(RequestConfiguration, link->handle, &link->conf); 638 break; 639 } 640 return 0; 641} /* serial_event */ 642 643/*====================================================================*/ 644 645static int __init init_serial_cs(void) 646{ 647 servinfo_t serv; 648 DEBUG(0, "%s\n", version); 649 CardServices(GetCardServicesInfo, &serv); 650 if (serv.Revision != CS_RELEASE_CODE) { 651 printk(KERN_NOTICE "serial_cs: Card Services release " 652 "does not match!\n"); 653 return -1; 654 } 655 register_pccard_driver(&dev_info, &serial_attach, &serial_detach); 656 return 0; 657} 658 659static void __exit exit_serial_cs(void) 660{ 661 DEBUG(0, "serial_cs: unloading\n"); 662 unregister_pccard_driver(&dev_info); 663 while (dev_list != NULL) 664 serial_detach(dev_list); 665} 666 667module_init(init_serial_cs); 668module_exit(exit_serial_cs); 669