1 /* $OpenBSD: com_pcmcia.c,v 1.29 2001/08/17 21:52:16 deraadt Exp $ */ 2 /* $NetBSD: com_pcmcia.c,v 1.15 1998/08/22 17:47:58 msaitoh Exp $ */ 3 4 /* 5 * Copyright (c) 1997 - 1999, Jason Downs. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name(s) of the author(s) nor the name OpenBSD 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 /*- 32 * Copyright (c) 1998 The NetBSD Foundation, Inc. 33 * All rights reserved. 34 * 35 * This code is derived from software contributed to The NetBSD Foundation 36 * by Charles M. Hannum. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the NetBSD 49 * Foundation, Inc. and its contributors. 50 * 4. Neither the name of The NetBSD Foundation nor the names of its 51 * contributors may be used to endorse or promote products derived 52 * from this software without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 55 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 * POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 /*- 68 * Copyright (c) 1991 The Regents of the University of California. 69 * All rights reserved. 70 * 71 * Redistribution and use in source and binary forms, with or without 72 * modification, are permitted provided that the following conditions 73 * are met: 74 * 1. Redistributions of source code must retain the above copyright 75 * notice, this list of conditions and the following disclaimer. 76 * 2. Redistributions in binary form must reproduce the above copyright 77 * notice, this list of conditions and the following disclaimer in the 78 * documentation and/or other materials provided with the distribution. 79 * 3. All advertising materials mentioning features or use of this software 80 * must display the following acknowledgement: 81 * This product includes software developed by the University of 82 * California, Berkeley and its contributors. 83 * 4. Neither the name of the University nor the names of its contributors 84 * may be used to endorse or promote products derived from this software 85 * without specific prior written permission. 86 * 87 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 88 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 89 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 90 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 91 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 92 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 93 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 94 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 95 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 96 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 97 * SUCH DAMAGE. 98 * 99 * @(#)com.c 7.5 (Berkeley) 5/16/91 100 */ 101 102 #include <sys/param.h> 103 #include <sys/systm.h> 104 #include <sys/ioctl.h> 105 #include <sys/select.h> 106 #include <sys/tty.h> 107 #include <sys/proc.h> 108 #include <sys/user.h> 109 #include <sys/conf.h> 110 #include <sys/file.h> 111 #include <sys/uio.h> 112 #include <sys/kernel.h> 113 #include <sys/syslog.h> 114 #include <sys/types.h> 115 #include <sys/device.h> 116 117 #include <machine/intr.h> 118 #include <machine/bus.h> 119 120 #include <dev/pcmcia/pcmciavar.h> 121 #include <dev/pcmcia/pcmciareg.h> 122 #include <dev/pcmcia/pcmciadevs.h> 123 124 #include <dev/isa/isavar.h> 125 126 #include "com.h" 127 #ifdef i386 128 #include "pccom.h" 129 #endif 130 131 #include <dev/ic/comreg.h> 132 #if NPCCOM > 0 133 #include <i386/isa/pccomvar.h> 134 #endif 135 #if NCOM > 0 136 #include <dev/ic/comvar.h> 137 #endif 138 #include <dev/ic/ns16550reg.h> 139 140 #include <dev/isa/isareg.h> 141 142 #define com_lcr com_cfcr 143 #define SET(t, f) (t) |= (f) 144 145 /* Devices that we need to match by CIS strings */ 146 struct com_pcmcia_product { 147 char *cis1_info[4]; 148 } com_pcmcia_prod[] = { 149 { PCMCIA_CIS_MEGAHERTZ_XJ2288 }, 150 }; 151 152 int com_pcmcia_match __P((struct device *, void *, void *)); 153 void com_pcmcia_attach __P((struct device *, struct device *, void *)); 154 int com_pcmcia_detach __P((struct device *, int)); 155 void com_pcmcia_cleanup __P((void *)); 156 int com_pcmcia_activate __P((struct device *, enum devact)); 157 158 int com_pcmcia_enable __P((struct com_softc *)); 159 void com_pcmcia_disable __P((struct com_softc *)); 160 int com_pcmcia_enable1 __P((struct com_softc *)); 161 void com_pcmcia_disable1 __P((struct com_softc *)); 162 163 void com_pcmcia_attach2 __P((struct com_softc *)); 164 165 struct com_pcmcia_softc { 166 struct com_softc sc_com; /* real "com" softc */ 167 168 /* PCMCIA-specific goo */ 169 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 170 int sc_io_window; /* our i/o window */ 171 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 172 void *sc_ih; /* interrupt handler */ 173 }; 174 175 #if NCOM_PCMCIA 176 struct cfattach com_pcmcia_ca = { 177 sizeof(struct com_pcmcia_softc), com_pcmcia_match, com_pcmcia_attach, 178 com_pcmcia_detach, com_pcmcia_activate 179 }; 180 #elif NPCCOM_PCMCIA 181 struct cfattach pccom_pcmcia_ca = { 182 sizeof(struct com_pcmcia_softc), com_pcmcia_match, com_pcmcia_attach, 183 com_pcmcia_detach, com_pcmcia_activate 184 }; 185 #endif 186 187 int 188 com_pcmcia_match(parent, match, aux) 189 struct device *parent; 190 void *match, *aux; 191 { 192 struct pcmcia_attach_args *pa = aux; 193 struct pcmcia_config_entry *cfe; 194 int i, j, comportmask; 195 196 /* 1. Does it claim to be a serial device? */ 197 if (pa->pf->function == PCMCIA_FUNCTION_SERIAL) 198 return 1; 199 200 /* 2. Does it have all four 'standard' port ranges? */ 201 comportmask = 0; 202 for (cfe = pa->pf->cfe_head.sqh_first; cfe; 203 cfe = cfe->cfe_list.sqe_next) { 204 switch (cfe->iospace[0].start) { 205 case IO_COM1: 206 comportmask |= 1; 207 break; 208 case IO_COM2: 209 comportmask |= 2; 210 break; 211 case IO_COM3: 212 comportmask |= 4; 213 break; 214 case IO_COM4: 215 comportmask |= 8; 216 break; 217 } 218 } 219 220 if (comportmask == 15) 221 return 1; 222 223 /* 3. Is this a card we know about? */ 224 for (i = 0; i < sizeof(com_pcmcia_prod)/sizeof(com_pcmcia_prod[0]); 225 i++) { 226 for (j = 0; j < 4; j++) 227 if (com_pcmcia_prod[i].cis1_info[j] && 228 pa->card->cis1_info[j] && 229 strcmp(pa->card->cis1_info[j], 230 com_pcmcia_prod[i].cis1_info[j])) 231 break; 232 if (j == 4) 233 return 1; 234 } 235 236 return 0; 237 } 238 239 int 240 com_pcmcia_activate(dev, act) 241 struct device *dev; 242 enum devact act; 243 { 244 struct com_pcmcia_softc *sc = (void *) dev; 245 int s; 246 247 s = spltty(); 248 switch (act) { 249 case DVACT_ACTIVATE: 250 pcmcia_function_enable(sc->sc_pf); 251 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY, 252 comintr, sc, sc->sc_com.sc_dev.dv_xname); 253 break; 254 255 case DVACT_DEACTIVATE: 256 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 257 pcmcia_function_disable(sc->sc_pf); 258 break; 259 } 260 splx(s); 261 return (0); 262 } 263 264 void 265 com_pcmcia_attach(parent, self, aux) 266 struct device *parent, *self; 267 void *aux; 268 { 269 struct com_pcmcia_softc *psc = (void *) self; 270 struct com_softc *sc = &psc->sc_com; 271 struct pcmcia_attach_args *pa = aux; 272 struct pcmcia_config_entry *cfe; 273 int autoalloc = 0; 274 275 psc->sc_pf = pa->pf; 276 277 retry: 278 /* find a cfe we can use */ 279 280 for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe; 281 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) { 282 #if 0 283 /* 284 * Some modem cards (e.g. Xircom CM33) also have 285 * mem space. Don't bother with this check. 286 */ 287 if (cfe->num_memspace != 0) 288 continue; 289 #endif 290 291 if (cfe->num_iospace != 1) 292 continue; 293 294 if (!pcmcia_io_alloc(pa->pf, 295 autoalloc ? 0 : cfe->iospace[0].start, 296 cfe->iospace[0].length, COM_NPORTS, &psc->sc_pcioh)) { 297 goto found; 298 } 299 } 300 if (autoalloc == 0) { 301 autoalloc = 1; 302 goto retry; 303 } else if (!cfe) { 304 printf(": can't allocate i/o space\n"); 305 return; 306 } 307 308 found: 309 sc->sc_iot = psc->sc_pcioh.iot; 310 sc->sc_ioh = psc->sc_pcioh.ioh; 311 312 /* Enable the card. */ 313 pcmcia_function_init(pa->pf, cfe); 314 if (com_pcmcia_enable1(sc)) 315 printf(": function enable failed\n"); 316 317 sc->enabled = 1; 318 319 /* map in the io space */ 320 321 if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? 322 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, psc->sc_pcioh.size, 323 &psc->sc_pcioh, &psc->sc_io_window)) { 324 printf(": can't map i/o space\n"); 325 return; 326 } 327 328 printf(" port 0x%lx/%d", psc->sc_pcioh.addr, psc->sc_pcioh.size); 329 330 sc->sc_iobase = -1; 331 sc->enable = com_pcmcia_enable; 332 sc->disable = com_pcmcia_disable; 333 sc->sc_frequency = COM_FREQ; 334 335 #ifdef notyet 336 com_attach_subr(sc); 337 #endif 338 /* establish the interrupt. */ 339 psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_TTY, 340 comintr, sc, ""); 341 if (psc->sc_ih == NULL) 342 printf(", couldn't establish interrupt"); 343 344 com_pcmcia_attach2(sc); 345 346 #ifdef notyet 347 sc->enabled = 0; 348 349 com_pcmcia_disable1(sc); 350 #endif 351 } 352 353 int 354 com_pcmcia_detach(dev, flags) 355 struct device *dev; 356 int flags; 357 { 358 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *)dev; 359 int error; 360 361 /* Release all resources. */ 362 error = com_detach(dev, flags); 363 if (error) 364 return (error); 365 366 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 367 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 368 369 return (0); 370 } 371 372 int 373 com_pcmcia_enable(sc) 374 struct com_softc *sc; 375 { 376 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 377 struct pcmcia_function *pf = psc->sc_pf; 378 379 /* establish the interrupt. */ 380 psc->sc_ih = pcmcia_intr_establish(pf, IPL_TTY, comintr, sc, 381 sc->sc_dev.dv_xname); 382 if (psc->sc_ih == NULL) { 383 printf("%s: couldn't establish interrupt\n", 384 sc->sc_dev.dv_xname); 385 return (1); 386 } 387 return com_pcmcia_enable1(sc); 388 } 389 390 int 391 com_pcmcia_enable1(sc) 392 struct com_softc *sc; 393 { 394 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 395 struct pcmcia_function *pf = psc->sc_pf; 396 int ret; 397 398 if ((ret = pcmcia_function_enable(pf))) 399 return(ret); 400 401 if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) || 402 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) || 403 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556B)) { 404 int reg; 405 406 /* turn off the ethernet-disable bit */ 407 408 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); 409 if (reg & 0x08) { 410 reg &= ~0x08; 411 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); 412 } 413 } 414 415 return(ret); 416 } 417 418 void 419 com_pcmcia_disable(sc) 420 struct com_softc *sc; 421 { 422 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 423 424 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 425 com_pcmcia_disable1(sc); 426 } 427 428 void 429 com_pcmcia_disable1(sc) 430 struct com_softc *sc; 431 { 432 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 433 434 pcmcia_function_disable(psc->sc_pf); 435 } 436 437 /* 438 * XXX This should be handled by a generic attach 439 */ 440 void 441 com_pcmcia_attach2(sc) 442 struct com_softc *sc; 443 { 444 bus_space_tag_t iot = sc->sc_iot; 445 bus_space_handle_t ioh = sc->sc_ioh; 446 u_int8_t lcr; 447 448 sc->sc_hwflags = 0; 449 sc->sc_swflags = 0; 450 451 /* 452 * Probe for all known forms of UART. 453 */ 454 lcr = bus_space_read_1(iot, ioh, com_lcr); 455 456 bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); 457 bus_space_write_1(iot, ioh, com_efr, 0); 458 bus_space_write_1(iot, ioh, com_lcr, 0); 459 460 bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE); 461 delay(100); 462 463 switch(bus_space_read_1(iot, ioh, com_iir) >> 6) { 464 case 0: 465 sc->sc_uarttype = COM_UART_16450; 466 break; 467 case 2: 468 sc->sc_uarttype = COM_UART_16550; 469 break; 470 case 3: 471 sc->sc_uarttype = COM_UART_16550A; 472 break; 473 default: 474 sc->sc_uarttype = COM_UART_UNKNOWN; 475 break; 476 } 477 478 if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */ 479 bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); 480 if (bus_space_read_1(iot, ioh, com_efr) == 0) { 481 sc->sc_uarttype = COM_UART_ST16650; 482 } else { 483 bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); 484 if (bus_space_read_1(iot, ioh, com_efr) == 0) 485 sc->sc_uarttype = COM_UART_ST16650V2; 486 } 487 } 488 489 #if NPCCOM > 0 490 #ifdef i386 491 if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */ 492 u_int8_t dlbl, dlbh; 493 494 /* Enable latch access and get the current values. */ 495 bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); 496 dlbl = bus_space_read_1(iot, ioh, com_dlbl); 497 dlbh = bus_space_read_1(iot, ioh, com_dlbh); 498 499 /* Zero out the latch divisors */ 500 bus_space_write_1(iot, ioh, com_dlbl, 0); 501 bus_space_write_1(iot, ioh, com_dlbh, 0); 502 503 if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) { 504 sc->sc_uarttype = COM_UART_XR16850; 505 sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl); 506 } 507 508 /* Reset to original. */ 509 bus_space_write_1(iot, ioh, com_dlbl, dlbl); 510 bus_space_write_1(iot, ioh, com_dlbh, dlbh); 511 } 512 #endif 513 #endif 514 515 /* Reset the LCR (latch access is probably enabled). */ 516 bus_space_write_1(iot, ioh, com_lcr, lcr); 517 if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */ 518 u_int8_t scr0, scr1, scr2; 519 520 scr0 = bus_space_read_1(iot, ioh, com_scratch); 521 bus_space_write_1(iot, ioh, com_scratch, 0xa5); 522 scr1 = bus_space_read_1(iot, ioh, com_scratch); 523 bus_space_write_1(iot, ioh, com_scratch, 0x5a); 524 scr2 = bus_space_read_1(iot, ioh, com_scratch); 525 bus_space_write_1(iot, ioh, com_scratch, scr0); 526 527 if ((scr1 != 0xa5) || (scr2 != 0x5a)) 528 sc->sc_uarttype = COM_UART_8250; 529 } 530 531 /* 532 * Print UART type and initialize ourself. 533 */ 534 sc->sc_fifolen = 1; /* default */ 535 switch (sc->sc_uarttype) { 536 case COM_UART_UNKNOWN: 537 printf(": unknown uart\n"); 538 break; 539 case COM_UART_8250: 540 printf(": ns8250, no fifo\n"); 541 break; 542 case COM_UART_16450: 543 printf(": ns16450, no fifo\n"); 544 break; 545 case COM_UART_16550: 546 printf(": ns16550, no working fifo\n"); 547 break; 548 case COM_UART_16550A: 549 printf(": ns16550a, 16 byte fifo\n"); 550 SET(sc->sc_hwflags, COM_HW_FIFO); 551 sc->sc_fifolen = 16; 552 break; 553 case COM_UART_ST16650: 554 printf(": st16650, no working fifo\n"); 555 break; 556 case COM_UART_ST16650V2: 557 printf(": st16650, 32 byte fifo\n"); 558 SET(sc->sc_hwflags, COM_HW_FIFO); 559 sc->sc_fifolen = 32; 560 break; 561 #if NPCCOM > 0 562 #ifdef i386 563 case COM_UART_XR16850: 564 printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev); 565 SET(sc->sc_hwflags, COM_HW_FIFO); 566 sc->sc_fifolen = 128; 567 break; 568 #endif 569 #endif 570 default: 571 panic("comattach: bad fifo type"); 572 } 573 574 /* clear and disable fifo */ 575 bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST); 576 (void)bus_space_read_1(iot, ioh, com_data); 577 bus_space_write_1(iot, ioh, com_fifo, 0); 578 } 579