Annotation of sys/dev/ic/com_subr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: com_subr.c,v 1.10 2007/03/20 17:37:34 deraadt Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1997 - 1999, Jason Downs. All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
! 16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
! 19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! 22: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: */
! 27: /*-
! 28: * Copyright (c) 1993, 1994, 1995, 1996
! 29: * Charles M. Hannum. All rights reserved.
! 30: * Copyright (c) 1991 The Regents of the University of California.
! 31: * All rights reserved.
! 32: *
! 33: * Redistribution and use in source and binary forms, with or without
! 34: * modification, are permitted provided that the following conditions
! 35: * are met:
! 36: * 1. Redistributions of source code must retain the above copyright
! 37: * notice, this list of conditions and the following disclaimer.
! 38: * 2. Redistributions in binary form must reproduce the above copyright
! 39: * notice, this list of conditions and the following disclaimer in the
! 40: * documentation and/or other materials provided with the distribution.
! 41: * 3. Neither the name of the University nor the names of its contributors
! 42: * may be used to endorse or promote products derived from this software
! 43: * without specific prior written permission.
! 44: *
! 45: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 46: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 47: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 48: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 49: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 50: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 51: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 52: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 53: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 54: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 55: * SUCH DAMAGE.
! 56: *
! 57: * @(#)com.c 7.5 (Berkeley) 5/16/91
! 58: */
! 59:
! 60: /*
! 61: * COM driver, based on HP dca driver
! 62: * uses National Semiconductor NS16450/NS16550AF UART
! 63: */
! 64: #include <sys/param.h>
! 65: #include <sys/systm.h>
! 66: #include <sys/kernel.h>
! 67: #include <sys/device.h>
! 68: #include <sys/tty.h>
! 69:
! 70: #include "com.h"
! 71: #ifdef i386
! 72: #include "pccom.h"
! 73: #else
! 74: #define NPCCOM 0
! 75: #endif
! 76:
! 77: #include <machine/bus.h>
! 78: #if defined(__sparc64__) || !defined(__sparc__)
! 79: #include <machine/intr.h>
! 80: #endif
! 81:
! 82: #if !defined(__sparc__) || defined(__sparc64__)
! 83: #define COM_CONSOLE
! 84: #include <dev/cons.h>
! 85: #endif
! 86:
! 87: #include <dev/ic/comreg.h>
! 88: #include <dev/ic/ns16550reg.h>
! 89: #define com_lcr com_cfcr
! 90:
! 91: #if NCOM > 0
! 92: #include <dev/ic/comvar.h>
! 93: #endif
! 94: #if NPCCOM > 0
! 95: #include <i386/isa/pccomvar.h>
! 96: #endif
! 97:
! 98: #ifdef COM_PXA2X0
! 99: #define com_isr 8
! 100: #define ISR_SEND (ISR_RXPL | ISR_XMODE | ISR_XMITIR)
! 101: #define ISR_RECV (ISR_RXPL | ISR_XMODE | ISR_RCVEIR)
! 102: #endif
! 103:
! 104: #ifdef COM_CONSOLE
! 105: #include <sys/conf.h>
! 106: cdev_decl(com);
! 107: #endif
! 108:
! 109: void com_enable_debugport(struct com_softc *);
! 110: void com_fifo_probe(struct com_softc *);
! 111:
! 112: #if defined(COM_CONSOLE) || defined(KGDB)
! 113: void
! 114: com_enable_debugport(sc)
! 115: struct com_softc *sc;
! 116: {
! 117: int s;
! 118:
! 119: /* Turn on line break interrupt, set carrier. */
! 120: s = splhigh();
! 121: #ifdef KGDB
! 122: SET(sc->sc_ier, IER_ERXRDY);
! 123: #ifdef COM_PXA2X0
! 124: if (sc->sc_uarttype == COM_UART_PXA2X0)
! 125: sc->sc_ier |= IER_EUART | IER_ERXTOUT;
! 126: #endif
! 127: bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_ier, sc->sc_ier);
! 128: #endif
! 129: SET(sc->sc_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
! 130: bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr, sc->sc_mcr);
! 131:
! 132: splx(s);
! 133: }
! 134: #endif /* COM_CONSOLED || KGDB */
! 135:
! 136: void
! 137: com_attach_subr(sc)
! 138: struct com_softc *sc;
! 139: {
! 140: bus_space_tag_t iot = sc->sc_iot;
! 141: bus_space_handle_t ioh = sc->sc_ioh;
! 142: u_int8_t lcr;
! 143:
! 144: sc->sc_ier = 0;
! 145: #ifdef COM_PXA2X0
! 146: if (sc->sc_uarttype == COM_UART_PXA2X0)
! 147: sc->sc_ier |= IER_EUART;
! 148: #endif
! 149:
! 150: /* disable interrupts */
! 151: bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
! 152:
! 153: #ifdef COM_CONSOLE
! 154: if (sc->sc_iobase == comconsaddr) {
! 155: comconsattached = 1;
! 156: delay(10000); /* wait for output to finish */
! 157: SET(sc->sc_hwflags, COM_HW_CONSOLE);
! 158: SET(sc->sc_swflags, COM_SW_SOFTCAR);
! 159: }
! 160: #endif
! 161:
! 162: /*
! 163: * Probe for all known forms of UART.
! 164: */
! 165: lcr = bus_space_read_1(iot, ioh, com_lcr);
! 166: bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
! 167: bus_space_write_1(iot, ioh, com_efr, 0);
! 168: bus_space_write_1(iot, ioh, com_lcr, 0);
! 169:
! 170: bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
! 171: delay(100);
! 172:
! 173: /*
! 174: * Skip specific probes if attachment code knows it already.
! 175: */
! 176: if (sc->sc_uarttype == COM_UART_UNKNOWN)
! 177: switch (bus_space_read_1(iot, ioh, com_iir) >> 6) {
! 178: case 0:
! 179: sc->sc_uarttype = COM_UART_16450;
! 180: break;
! 181: case 2:
! 182: sc->sc_uarttype = COM_UART_16550;
! 183: break;
! 184: case 3:
! 185: sc->sc_uarttype = COM_UART_16550A;
! 186: break;
! 187: default:
! 188: sc->sc_uarttype = COM_UART_UNKNOWN;
! 189: break;
! 190: }
! 191:
! 192: if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */
! 193: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
! 194: if (bus_space_read_1(iot, ioh, com_efr) == 0) {
! 195: sc->sc_uarttype = COM_UART_ST16650;
! 196: } else {
! 197: bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
! 198: if (bus_space_read_1(iot, ioh, com_efr) == 0)
! 199: sc->sc_uarttype = COM_UART_ST16650V2;
! 200: }
! 201: }
! 202:
! 203: #if NPCCOM > 0 /* until com works with large FIFOs */
! 204: if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */
! 205: u_int8_t dlbl, dlbh;
! 206:
! 207: /* Enable latch access and get the current values. */
! 208: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
! 209: dlbl = bus_space_read_1(iot, ioh, com_dlbl);
! 210: dlbh = bus_space_read_1(iot, ioh, com_dlbh);
! 211:
! 212: /* Zero out the latch divisors */
! 213: bus_space_write_1(iot, ioh, com_dlbl, 0);
! 214: bus_space_write_1(iot, ioh, com_dlbh, 0);
! 215:
! 216: if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) {
! 217: sc->sc_uarttype = COM_UART_XR16850;
! 218: sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl);
! 219: }
! 220:
! 221: /* Reset to original. */
! 222: bus_space_write_1(iot, ioh, com_dlbl, dlbl);
! 223: bus_space_write_1(iot, ioh, com_dlbh, dlbh);
! 224: }
! 225: #endif
! 226:
! 227: if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for TI16750s */
! 228: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
! 229: bus_space_write_1(iot, ioh, com_fifo,
! 230: FIFO_ENABLE | FIFO_ENABLE_64BYTE);
! 231: if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 7) {
! 232: #if 0
! 233: bus_space_write_1(iot, ioh, com_lcr, 0);
! 234: if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 6)
! 235: #endif
! 236: sc->sc_uarttype = COM_UART_TI16750;
! 237: }
! 238: bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
! 239: }
! 240:
! 241: /* Reset the LCR (latch access is probably enabled). */
! 242: bus_space_write_1(iot, ioh, com_lcr, lcr);
! 243: if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */
! 244: u_int8_t scr0, scr1, scr2;
! 245:
! 246: scr0 = bus_space_read_1(iot, ioh, com_scratch);
! 247: bus_space_write_1(iot, ioh, com_scratch, 0xa5);
! 248: scr1 = bus_space_read_1(iot, ioh, com_scratch);
! 249: bus_space_write_1(iot, ioh, com_scratch, 0x5a);
! 250: scr2 = bus_space_read_1(iot, ioh, com_scratch);
! 251: bus_space_write_1(iot, ioh, com_scratch, scr0);
! 252:
! 253: if ((scr1 != 0xa5) || (scr2 != 0x5a))
! 254: sc->sc_uarttype = COM_UART_8250;
! 255: }
! 256:
! 257: /*
! 258: * Print UART type and initialize ourself.
! 259: */
! 260: switch (sc->sc_uarttype) {
! 261: case COM_UART_UNKNOWN:
! 262: printf(": unknown uart\n");
! 263: break;
! 264: case COM_UART_8250:
! 265: printf(": ns8250, no fifo\n");
! 266: break;
! 267: case COM_UART_16450:
! 268: printf(": ns16450, no fifo\n");
! 269: break;
! 270: case COM_UART_16550:
! 271: printf(": ns16550, no working fifo\n");
! 272: break;
! 273: case COM_UART_16550A:
! 274: if (sc->sc_fifolen == 0)
! 275: sc->sc_fifolen = 16;
! 276: printf(": ns16550a, %d byte fifo\n", sc->sc_fifolen);
! 277: SET(sc->sc_hwflags, COM_HW_FIFO);
! 278: break;
! 279: #ifdef COM_PXA2X0
! 280: case COM_UART_PXA2X0:
! 281: printf(": pxa2x0, 32 byte fifo");
! 282: SET(sc->sc_hwflags, COM_HW_FIFO);
! 283: sc->sc_fifolen = 32;
! 284: if (sc->sc_iobase == comsiraddr) {
! 285: SET(sc->sc_hwflags, COM_HW_SIR);
! 286: printf(" (SIR)");
! 287: }
! 288: printf("\n");
! 289: break;
! 290: #endif
! 291: case COM_UART_ST16650:
! 292: printf(": st16650, no working fifo\n");
! 293: break;
! 294: case COM_UART_ST16650V2:
! 295: if (sc->sc_fifolen == 0)
! 296: sc->sc_fifolen = 32;
! 297: printf(": st16650, %d byte fifo\n", sc->sc_fifolen);
! 298: SET(sc->sc_hwflags, COM_HW_FIFO);
! 299: break;
! 300: case COM_UART_ST16C654:
! 301: printf(": st16c654, 64 byte fifo\n");
! 302: SET(sc->sc_hwflags, COM_HW_FIFO);
! 303: sc->sc_fifolen = 64;
! 304: break;
! 305: case COM_UART_TI16750:
! 306: printf(": ti16750, 64 byte fifo\n");
! 307: SET(sc->sc_hwflags, COM_HW_FIFO);
! 308: sc->sc_fifolen = 64;
! 309: break;
! 310: #if NPCCOM > 0
! 311: case COM_UART_XR16850:
! 312: printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
! 313: SET(sc->sc_hwflags, COM_HW_FIFO);
! 314: sc->sc_fifolen = 128;
! 315: break;
! 316: #ifdef COM_UART_OX16C950
! 317: case COM_UART_OX16C950:
! 318: printf(": ox16c950 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
! 319: SET(sc->sc_hwflags, COM_HW_FIFO);
! 320: sc->sc_fifolen = 128;
! 321: break;
! 322: #endif
! 323: #endif
! 324: default:
! 325: panic("comattach: bad fifo type");
! 326: }
! 327:
! 328: #ifdef notyet
! 329: com_fifo_probe(sc);
! 330: #endif
! 331:
! 332: if (sc->sc_fifolen == 0) {
! 333: CLR(sc->sc_hwflags, COM_HW_FIFO);
! 334: sc->sc_fifolen = 1;
! 335: }
! 336:
! 337: /* clear and disable fifo */
! 338: bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST);
! 339: (void)bus_space_read_1(iot, ioh, com_data);
! 340: bus_space_write_1(iot, ioh, com_fifo, 0);
! 341:
! 342: sc->sc_mcr = 0;
! 343: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 344:
! 345: #ifdef KGDB
! 346: /*
! 347: * Allow kgdb to "take over" this port. If this is
! 348: * the kgdb device, it has exclusive use.
! 349: */
! 350:
! 351: if (iot == com_kgdb_iot && sc->sc_iobase == com_kgdb_addr &&
! 352: !ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
! 353: printf("%s: kgdb\n", sc->sc_dev.dv_xname);
! 354: SET(sc->sc_hwflags, COM_HW_KGDB);
! 355: }
! 356: #endif /* KGDB */
! 357:
! 358: #ifdef COM_CONSOLE
! 359: if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
! 360: int maj;
! 361:
! 362: /* locate the major number */
! 363: for (maj = 0; maj < nchrdev; maj++)
! 364: if (cdevsw[maj].d_open == comopen)
! 365: break;
! 366:
! 367: if (maj < nchrdev && cn_tab->cn_dev == NODEV)
! 368: cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
! 369:
! 370: printf("%s: console\n", sc->sc_dev.dv_xname);
! 371: }
! 372: #endif
! 373:
! 374: timeout_set(&sc->sc_diag_tmo, comdiag, sc);
! 375: timeout_set(&sc->sc_dtr_tmo, com_raisedtr, sc);
! 376: #if NCOM > 0
! 377: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 378: sc->sc_si = softintr_establish(IPL_TTY, comsoft, sc);
! 379: if (sc->sc_si == NULL)
! 380: panic("%s: can't establish soft interrupt",
! 381: sc->sc_dev.dv_xname);
! 382: #else
! 383: timeout_set(&sc->sc_comsoft_tmo, comsoft, sc);
! 384: #endif
! 385: #endif /* NCOM */
! 386:
! 387: /*
! 388: * If there are no enable/disable functions, assume the device
! 389: * is always enabled.
! 390: */
! 391: if (!sc->enable)
! 392: sc->enabled = 1;
! 393:
! 394: #if defined(COM_CONSOLE) || defined(KGDB)
! 395: if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE|COM_HW_KGDB))
! 396: com_enable_debugport(sc);
! 397: #endif
! 398: }
! 399:
! 400: void
! 401: com_fifo_probe(struct com_softc *sc)
! 402: {
! 403: bus_space_handle_t ioh = sc->sc_ioh;
! 404: bus_space_tag_t iot = sc->sc_iot;
! 405: u_int8_t fifo, ier;
! 406: int timo, len;
! 407:
! 408: if (!ISSET(sc->sc_hwflags, COM_HW_FIFO))
! 409: return;
! 410:
! 411: ier = 0;
! 412: #ifdef COM_PXA2X0
! 413: if (sc->sc_uarttype == COM_UART_PXA2X0)
! 414: ier |= IER_EUART;
! 415: #endif
! 416: bus_space_write_1(iot, ioh, com_ier, ier);
! 417: bus_space_write_1(iot, ioh, com_lcr, LCR_DLAB);
! 418: bus_space_write_1(iot, ioh, com_dlbl, 3);
! 419: bus_space_write_1(iot, ioh, com_dlbh, 0);
! 420: bus_space_write_1(iot, ioh, com_lcr, LCR_PNONE | LCR_8BITS);
! 421: bus_space_write_1(iot, ioh, com_mcr, MCR_LOOPBACK);
! 422:
! 423: fifo = FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST;
! 424: if (sc->sc_uarttype == COM_UART_TI16750)
! 425: fifo |= FIFO_ENABLE_64BYTE;
! 426:
! 427: bus_space_write_1(iot, ioh, com_fifo, fifo);
! 428:
! 429: for (len = 0; len < 256; len++) {
! 430: bus_space_write_1(iot, ioh, com_data, (len + 1));
! 431: timo = 2000;
! 432: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
! 433: LSR_TXRDY) && --timo)
! 434: delay(1);
! 435: if (!timo)
! 436: break;
! 437: }
! 438:
! 439: delay(100);
! 440:
! 441: for (len = 0; len < 256; len++) {
! 442: timo = 2000;
! 443: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
! 444: LSR_RXRDY) && --timo)
! 445: delay(1);
! 446: if (!timo || bus_space_read_1(iot, ioh, com_data) != (len + 1))
! 447: break;
! 448: }
! 449:
! 450: /* For safety, always use the smaller value. */
! 451: if (sc->sc_fifolen > len) {
! 452: printf("%s: probed fifo depth: %d bytes\n",
! 453: sc->sc_dev.dv_xname, len);
! 454: sc->sc_fifolen = len;
! 455: }
! 456: }
CVSweb