Annotation of sys/dev/ic/com.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: com.c,v 1.117 2007/07/15 19:25:49 kettenis Exp $ */
! 2: /* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg 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: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
! 17: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
! 20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! 23: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 26: * SUCH DAMAGE.
! 27: */
! 28: /*-
! 29: * Copyright (c) 1993, 1994, 1995, 1996
! 30: * Charles M. Hannum. All rights reserved.
! 31: * Copyright (c) 1991 The Regents of the University of California.
! 32: * All rights reserved.
! 33: *
! 34: * Redistribution and use in source and binary forms, with or without
! 35: * modification, are permitted provided that the following conditions
! 36: * are met:
! 37: * 1. Redistributions of source code must retain the above copyright
! 38: * notice, this list of conditions and the following disclaimer.
! 39: * 2. Redistributions in binary form must reproduce the above copyright
! 40: * notice, this list of conditions and the following disclaimer in the
! 41: * documentation and/or other materials provided with the distribution.
! 42: * 3. Neither the name of the University nor the names of its contributors
! 43: * may be used to endorse or promote products derived from this software
! 44: * without specific prior written permission.
! 45: *
! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 56: * SUCH DAMAGE.
! 57: *
! 58: * @(#)com.c 7.5 (Berkeley) 5/16/91
! 59: */
! 60:
! 61: /*
! 62: * COM driver, based on HP dca driver
! 63: * uses National Semiconductor NS16450/NS16550AF UART
! 64: */
! 65: #include <sys/param.h>
! 66: #include <sys/systm.h>
! 67: #include <sys/ioctl.h>
! 68: #include <sys/selinfo.h>
! 69: #include <sys/tty.h>
! 70: #include <sys/proc.h>
! 71: #include <sys/user.h>
! 72: #include <sys/conf.h>
! 73: #include <sys/file.h>
! 74: #include <sys/uio.h>
! 75: #include <sys/kernel.h>
! 76: #include <sys/syslog.h>
! 77: #include <sys/device.h>
! 78: #include <sys/vnode.h>
! 79: #ifdef DDB
! 80: #include <ddb/db_var.h>
! 81: #endif
! 82:
! 83: #include <machine/bus.h>
! 84: #if defined(__sparc64__) || !defined(__sparc__)
! 85: #include <machine/intr.h>
! 86: #endif
! 87:
! 88: #if !defined(__sparc__) || defined(__sparc64__)
! 89: #define COM_CONSOLE
! 90: #include <dev/cons.h>
! 91: #endif
! 92:
! 93: #include <dev/ic/comreg.h>
! 94: #include <dev/ic/comvar.h>
! 95: #include <dev/ic/ns16550reg.h>
! 96: #define com_lcr com_cfcr
! 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 __zaurus__
! 105: #include <arch/zaurus/dev/zaurus_scoopvar.h>
! 106: #endif
! 107:
! 108: /* XXX: These belong elsewhere */
! 109: cdev_decl(com);
! 110:
! 111: static u_char tiocm_xxx2mcr(int);
! 112:
! 113: void compwroff(struct com_softc *);
! 114: void cominit(bus_space_tag_t, bus_space_handle_t, int, int);
! 115: int com_is_console(bus_space_tag_t, bus_addr_t);
! 116:
! 117: struct cfdriver com_cd = {
! 118: NULL, "com", DV_TTY
! 119: };
! 120:
! 121: int comdefaultrate = TTYDEF_SPEED;
! 122: #ifdef COM_PXA2X0
! 123: bus_addr_t comsiraddr;
! 124: #endif
! 125: #ifdef COM_CONSOLE
! 126: int comconsfreq;
! 127: int comconsinit;
! 128: bus_addr_t comconsaddr;
! 129: int comconsattached;
! 130: bus_space_tag_t comconsiot;
! 131: bus_space_handle_t comconsioh;
! 132: tcflag_t comconscflag = TTYDEF_CFLAG;
! 133: #endif
! 134:
! 135: int commajor;
! 136:
! 137: #ifdef KGDB
! 138: #include <sys/kgdb.h>
! 139:
! 140: bus_addr_t com_kgdb_addr;
! 141: bus_space_tag_t com_kgdb_iot;
! 142: bus_space_handle_t com_kgdb_ioh;
! 143:
! 144: int com_kgdb_getc(void *);
! 145: void com_kgdb_putc(void *, int);
! 146: #endif /* KGDB */
! 147:
! 148: #define DEVUNIT(x) (minor(x) & 0x7f)
! 149: #define DEVCUA(x) (minor(x) & 0x80)
! 150:
! 151: int
! 152: comspeed(long freq, long speed)
! 153: {
! 154: #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
! 155:
! 156: int x, err;
! 157:
! 158: if (speed == 0)
! 159: return 0;
! 160: if (speed < 0)
! 161: return -1;
! 162: x = divrnd((freq / 16), speed);
! 163: if (x <= 0)
! 164: return -1;
! 165: err = divrnd((quad_t)freq * 1000 / 16, speed * x) - 1000;
! 166: if (err < 0)
! 167: err = -err;
! 168: if (err > COM_TOLERANCE)
! 169: return -1;
! 170: return x;
! 171:
! 172: #undef divrnd
! 173: }
! 174:
! 175: #ifdef COM_CONSOLE
! 176: int
! 177: comprobe1(bus_space_tag_t iot, bus_space_handle_t ioh)
! 178: {
! 179: int i, k;
! 180:
! 181: /* force access to id reg */
! 182: bus_space_write_1(iot, ioh, com_lcr, 0);
! 183: bus_space_write_1(iot, ioh, com_iir, 0);
! 184: for (i = 0; i < 32; i++) {
! 185: k = bus_space_read_1(iot, ioh, com_iir);
! 186: if (k & 0x38) {
! 187: bus_space_read_1(iot, ioh, com_data); /* cleanup */
! 188: } else
! 189: break;
! 190: }
! 191: if (i >= 32)
! 192: return 0;
! 193:
! 194: return 1;
! 195: }
! 196: #endif
! 197:
! 198: int
! 199: com_detach(struct device *self, int flags)
! 200: {
! 201: struct com_softc *sc = (struct com_softc *)self;
! 202: int maj, mn;
! 203:
! 204: sc->sc_swflags |= COM_SW_DEAD;
! 205:
! 206: /* locate the major number */
! 207: for (maj = 0; maj < nchrdev; maj++)
! 208: if (cdevsw[maj].d_open == comopen)
! 209: break;
! 210:
! 211: /* Nuke the vnodes for any open instances. */
! 212: mn = self->dv_unit;
! 213: vdevgone(maj, mn, mn, VCHR);
! 214:
! 215: /* XXX a symbolic constant for the cua bit would be nicer. */
! 216: mn |= 0x80;
! 217: vdevgone(maj, mn, mn, VCHR);
! 218:
! 219: /* Detach and free the tty. */
! 220: if (sc->sc_tty) {
! 221: ttyfree(sc->sc_tty);
! 222: }
! 223:
! 224: timeout_del(&sc->sc_dtr_tmo);
! 225: timeout_del(&sc->sc_diag_tmo);
! 226: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 227: softintr_disestablish(sc->sc_si);
! 228: #else
! 229: timeout_del(&sc->sc_comsoft_tmo);
! 230: #endif
! 231:
! 232: return (0);
! 233: }
! 234:
! 235: int
! 236: com_activate(struct device *self, enum devact act)
! 237: {
! 238: struct com_softc *sc = (struct com_softc *)self;
! 239: int s, rv = 0;
! 240:
! 241: s = spltty();
! 242: switch (act) {
! 243: case DVACT_ACTIVATE:
! 244: break;
! 245:
! 246: case DVACT_DEACTIVATE:
! 247: #ifdef KGDB
! 248: if (sc->sc_hwflags & (COM_HW_CONSOLE|COM_HW_KGDB)) {
! 249: #else
! 250: if (sc->sc_hwflags & COM_HW_CONSOLE) {
! 251: #endif /* KGDB */
! 252: rv = EBUSY;
! 253: break;
! 254: }
! 255:
! 256: if (sc->disable != NULL && sc->enabled != 0) {
! 257: (*sc->disable)(sc);
! 258: sc->enabled = 0;
! 259: }
! 260: break;
! 261: }
! 262: splx(s);
! 263: return (rv);
! 264: }
! 265:
! 266: int
! 267: comopen(dev_t dev, int flag, int mode, struct proc *p)
! 268: {
! 269: int unit = DEVUNIT(dev);
! 270: struct com_softc *sc;
! 271: bus_space_tag_t iot;
! 272: bus_space_handle_t ioh;
! 273: struct tty *tp;
! 274: int s;
! 275: int error = 0;
! 276:
! 277: if (unit >= com_cd.cd_ndevs)
! 278: return ENXIO;
! 279: sc = com_cd.cd_devs[unit];
! 280: if (!sc)
! 281: return ENXIO;
! 282:
! 283: #ifdef KGDB
! 284: /*
! 285: * If this is the kgdb port, no other use is permitted.
! 286: */
! 287: if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
! 288: return (EBUSY);
! 289: #endif /* KGDB */
! 290:
! 291: s = spltty();
! 292: if (!sc->sc_tty) {
! 293: tp = sc->sc_tty = ttymalloc();
! 294: } else
! 295: tp = sc->sc_tty;
! 296: splx(s);
! 297:
! 298: tp->t_oproc = comstart;
! 299: tp->t_param = comparam;
! 300: tp->t_dev = dev;
! 301: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 302: SET(tp->t_state, TS_WOPEN);
! 303: ttychars(tp);
! 304: tp->t_iflag = TTYDEF_IFLAG;
! 305: tp->t_oflag = TTYDEF_OFLAG;
! 306: #ifdef COM_CONSOLE
! 307: if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
! 308: tp->t_cflag = comconscflag;
! 309: else
! 310: #endif
! 311: tp->t_cflag = TTYDEF_CFLAG;
! 312: if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
! 313: SET(tp->t_cflag, CLOCAL);
! 314: if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
! 315: SET(tp->t_cflag, CRTSCTS);
! 316: if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
! 317: SET(tp->t_cflag, MDMBUF);
! 318: tp->t_lflag = TTYDEF_LFLAG;
! 319: tp->t_ispeed = tp->t_ospeed = comdefaultrate;
! 320:
! 321: s = spltty();
! 322:
! 323: sc->sc_initialize = 1;
! 324: comparam(tp, &tp->t_termios);
! 325: ttsetwater(tp);
! 326:
! 327: #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
! 328: timeout_add(&sc->sc_comsoft_tmo, 1);
! 329: #endif
! 330:
! 331: sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
! 332: sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
! 333: sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
! 334:
! 335: iot = sc->sc_iot;
! 336: ioh = sc->sc_ioh;
! 337:
! 338: /*
! 339: * Wake up the sleepy heads.
! 340: */
! 341: switch (sc->sc_uarttype) {
! 342: case COM_UART_ST16650:
! 343: case COM_UART_ST16650V2:
! 344: bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
! 345: bus_space_write_1(iot, ioh, com_efr, EFR_ECB);
! 346: bus_space_write_1(iot, ioh, com_ier, 0);
! 347: bus_space_write_1(iot, ioh, com_efr, 0);
! 348: bus_space_write_1(iot, ioh, com_lcr, 0);
! 349: break;
! 350: case COM_UART_TI16750:
! 351: bus_space_write_1(iot, ioh, com_ier, 0);
! 352: break;
! 353: case COM_UART_PXA2X0:
! 354: bus_space_write_1(iot, ioh, com_ier, IER_EUART);
! 355: break;
! 356: }
! 357:
! 358: if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
! 359: u_int8_t fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST;
! 360: u_int8_t lcr;
! 361:
! 362: if (tp->t_ispeed <= 1200)
! 363: fifo |= FIFO_TRIGGER_1;
! 364: else
! 365: fifo |= FIFO_TRIGGER_8;
! 366: if (sc->sc_uarttype == COM_UART_TI16750) {
! 367: fifo |= FIFO_ENABLE_64BYTE;
! 368: lcr = bus_space_read_1(iot, ioh, com_lcr);
! 369: bus_space_write_1(iot, ioh, com_lcr,
! 370: lcr | LCR_DLAB);
! 371: }
! 372:
! 373: /*
! 374: * (Re)enable and drain FIFOs.
! 375: *
! 376: * Certain SMC chips cause problems if the FIFOs are
! 377: * enabled while input is ready. Turn off the FIFO
! 378: * if necessary to clear the input. Test the input
! 379: * ready bit after enabling the FIFOs to handle races
! 380: * between enabling and fresh input.
! 381: *
! 382: * Set the FIFO threshold based on the receive speed.
! 383: */
! 384: for (;;) {
! 385: bus_space_write_1(iot, ioh, com_fifo, 0);
! 386: delay(100);
! 387: (void) bus_space_read_1(iot, ioh, com_data);
! 388: bus_space_write_1(iot, ioh, com_fifo, fifo |
! 389: FIFO_RCV_RST | FIFO_XMT_RST);
! 390: delay(100);
! 391: if(!ISSET(bus_space_read_1(iot, ioh,
! 392: com_lsr), LSR_RXRDY))
! 393: break;
! 394: }
! 395: if (sc->sc_uarttype == COM_UART_TI16750)
! 396: bus_space_write_1(iot, ioh, com_lcr, lcr);
! 397: }
! 398:
! 399: /* flush any pending I/O */
! 400: while (ISSET(bus_space_read_1(iot, ioh, com_lsr), LSR_RXRDY))
! 401: (void) bus_space_read_1(iot, ioh, com_data);
! 402: /* you turn me on, baby */
! 403: sc->sc_mcr = MCR_DTR | MCR_RTS;
! 404: if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN))
! 405: SET(sc->sc_mcr, MCR_IENABLE);
! 406: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 407: sc->sc_ier = IER_ERXRDY | IER_ERLS | IER_EMSC;
! 408: #ifdef COM_PXA2X0
! 409: if (sc->sc_uarttype == COM_UART_PXA2X0)
! 410: sc->sc_ier |= IER_EUART | IER_ERXTOUT;
! 411: #endif
! 412: bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
! 413:
! 414: sc->sc_msr = bus_space_read_1(iot, ioh, com_msr);
! 415: if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) || DEVCUA(dev) ||
! 416: ISSET(sc->sc_msr, MSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
! 417: SET(tp->t_state, TS_CARR_ON);
! 418: else
! 419: CLR(tp->t_state, TS_CARR_ON);
! 420: #ifdef COM_PXA2X0
! 421: if (sc->sc_uarttype == COM_UART_PXA2X0 &&
! 422: ISSET(sc->sc_hwflags, COM_HW_SIR)) {
! 423: bus_space_write_1(iot, ioh, com_isr, ISR_RECV);
! 424: #ifdef __zaurus__
! 425: scoop_set_irled(1);
! 426: #endif
! 427: }
! 428: #endif
! 429: } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
! 430: return EBUSY;
! 431: else
! 432: s = spltty();
! 433:
! 434: if (DEVCUA(dev)) {
! 435: if (ISSET(tp->t_state, TS_ISOPEN)) {
! 436: /* Ah, but someone already is dialed in... */
! 437: splx(s);
! 438: return EBUSY;
! 439: }
! 440: sc->sc_cua = 1; /* We go into CUA mode */
! 441: } else {
! 442: /* tty (not cua) device; wait for carrier if necessary */
! 443: if (ISSET(flag, O_NONBLOCK)) {
! 444: if (sc->sc_cua) {
! 445: /* Opening TTY non-blocking... but the CUA is busy */
! 446: splx(s);
! 447: return EBUSY;
! 448: }
! 449: } else {
! 450: while (sc->sc_cua ||
! 451: (!ISSET(tp->t_cflag, CLOCAL) &&
! 452: !ISSET(tp->t_state, TS_CARR_ON))) {
! 453: SET(tp->t_state, TS_WOPEN);
! 454: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, ttopen, 0);
! 455: /*
! 456: * If TS_WOPEN has been reset, that means the cua device
! 457: * has been closed. We don't want to fail in that case,
! 458: * so just go around again.
! 459: */
! 460: if (error && ISSET(tp->t_state, TS_WOPEN)) {
! 461: CLR(tp->t_state, TS_WOPEN);
! 462: if (!sc->sc_cua && !ISSET(tp->t_state, TS_ISOPEN))
! 463: compwroff(sc);
! 464: splx(s);
! 465: return error;
! 466: }
! 467: }
! 468: }
! 469: }
! 470: splx(s);
! 471:
! 472: return (*linesw[tp->t_line].l_open)(dev, tp);
! 473: }
! 474:
! 475: int
! 476: comclose(dev_t dev, int flag, int mode, struct proc *p)
! 477: {
! 478: int unit = DEVUNIT(dev);
! 479: struct com_softc *sc = com_cd.cd_devs[unit];
! 480: bus_space_tag_t iot = sc->sc_iot;
! 481: bus_space_handle_t ioh = sc->sc_ioh;
! 482: struct tty *tp = sc->sc_tty;
! 483: int s;
! 484:
! 485: #ifdef COM_CONSOLE
! 486: /* XXX This is for cons.c. */
! 487: if (!ISSET(tp->t_state, TS_ISOPEN))
! 488: return 0;
! 489: #endif
! 490:
! 491: if(sc->sc_swflags & COM_SW_DEAD)
! 492: return 0;
! 493:
! 494: (*linesw[tp->t_line].l_close)(tp, flag);
! 495: s = spltty();
! 496: if (ISSET(tp->t_state, TS_WOPEN)) {
! 497: /* tty device is waiting for carrier; drop dtr then re-raise */
! 498: CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
! 499: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 500: timeout_add(&sc->sc_dtr_tmo, hz * 2);
! 501: } else {
! 502: /* no one else waiting; turn off the uart */
! 503: compwroff(sc);
! 504: }
! 505: CLR(tp->t_state, TS_BUSY | TS_FLUSH);
! 506: #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
! 507: timeout_del(&sc->sc_comsoft_tmo);
! 508: #endif
! 509: sc->sc_cua = 0;
! 510: splx(s);
! 511: ttyclose(tp);
! 512:
! 513: #ifdef COM_CONSOLE
! 514: #ifdef notyet /* XXXX */
! 515: if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
! 516: ttyfree(tp);
! 517: sc->sc_tty = 0;
! 518: }
! 519: #endif
! 520: #endif
! 521: return 0;
! 522: }
! 523:
! 524: void
! 525: compwroff(struct com_softc *sc)
! 526: {
! 527: bus_space_tag_t iot = sc->sc_iot;
! 528: bus_space_handle_t ioh = sc->sc_ioh;
! 529: struct tty *tp = sc->sc_tty;
! 530:
! 531: CLR(sc->sc_lcr, LCR_SBREAK);
! 532: bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr);
! 533: bus_space_write_1(iot, ioh, com_ier, 0);
! 534: if (ISSET(tp->t_cflag, HUPCL) &&
! 535: !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
! 536: /* XXX perhaps only clear DTR */
! 537: sc->sc_mcr = 0;
! 538: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 539: }
! 540:
! 541: /*
! 542: * Turn FIFO off; enter sleep mode if possible.
! 543: */
! 544: bus_space_write_1(iot, ioh, com_fifo, 0);
! 545: delay(100);
! 546: (void) bus_space_read_1(iot, ioh, com_data);
! 547: delay(100);
! 548: bus_space_write_1(iot, ioh, com_fifo,
! 549: FIFO_RCV_RST | FIFO_XMT_RST);
! 550:
! 551: switch (sc->sc_uarttype) {
! 552: case COM_UART_ST16650:
! 553: case COM_UART_ST16650V2:
! 554: bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
! 555: bus_space_write_1(iot, ioh, com_efr, EFR_ECB);
! 556: bus_space_write_1(iot, ioh, com_ier, IER_SLEEP);
! 557: bus_space_write_1(iot, ioh, com_lcr, 0);
! 558: break;
! 559: case COM_UART_TI16750:
! 560: bus_space_write_1(iot, ioh, com_ier, IER_SLEEP);
! 561: break;
! 562: #ifdef COM_PXA2X0
! 563: case COM_UART_PXA2X0:
! 564: bus_space_write_1(iot, ioh, com_ier, 0);
! 565: #ifdef __zaurus__
! 566: if (ISSET(sc->sc_hwflags, COM_HW_SIR))
! 567: scoop_set_irled(0);
! 568: #endif
! 569: break;
! 570: #endif
! 571: }
! 572: }
! 573:
! 574: void
! 575: com_raisedtr(void *arg)
! 576: {
! 577: struct com_softc *sc = arg;
! 578:
! 579: SET(sc->sc_mcr, MCR_DTR | MCR_RTS);
! 580: bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr, sc->sc_mcr);
! 581: }
! 582:
! 583: int
! 584: comread(dev_t dev, struct uio *uio, int flag)
! 585: {
! 586: struct com_softc *sc = com_cd.cd_devs[DEVUNIT(dev)];
! 587: struct tty *tp = sc->sc_tty;
! 588:
! 589: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 590: }
! 591:
! 592: int
! 593: comwrite(dev_t dev, struct uio *uio, int flag)
! 594: {
! 595: struct com_softc *sc = com_cd.cd_devs[DEVUNIT(dev)];
! 596: struct tty *tp = sc->sc_tty;
! 597:
! 598: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 599: }
! 600:
! 601: struct tty *
! 602: comtty(dev_t dev)
! 603: {
! 604: struct com_softc *sc = com_cd.cd_devs[DEVUNIT(dev)];
! 605: struct tty *tp = sc->sc_tty;
! 606:
! 607: return (tp);
! 608: }
! 609:
! 610: static u_char
! 611: tiocm_xxx2mcr(int data)
! 612: {
! 613: u_char m = 0;
! 614:
! 615: if (ISSET(data, TIOCM_DTR))
! 616: SET(m, MCR_DTR);
! 617: if (ISSET(data, TIOCM_RTS))
! 618: SET(m, MCR_RTS);
! 619: return m;
! 620: }
! 621:
! 622: int
! 623: comioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 624: {
! 625: int unit = DEVUNIT(dev);
! 626: struct com_softc *sc = com_cd.cd_devs[unit];
! 627: struct tty *tp = sc->sc_tty;
! 628: bus_space_tag_t iot = sc->sc_iot;
! 629: bus_space_handle_t ioh = sc->sc_ioh;
! 630: int error;
! 631:
! 632: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 633: if (error >= 0)
! 634: return error;
! 635: error = ttioctl(tp, cmd, data, flag, p);
! 636: if (error >= 0)
! 637: return error;
! 638:
! 639: switch (cmd) {
! 640: case TIOCSBRK:
! 641: SET(sc->sc_lcr, LCR_SBREAK);
! 642: bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr);
! 643: break;
! 644: case TIOCCBRK:
! 645: CLR(sc->sc_lcr, LCR_SBREAK);
! 646: bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr);
! 647: break;
! 648: case TIOCSDTR:
! 649: SET(sc->sc_mcr, sc->sc_dtr);
! 650: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 651: break;
! 652: case TIOCCDTR:
! 653: CLR(sc->sc_mcr, sc->sc_dtr);
! 654: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 655: break;
! 656: case TIOCMSET:
! 657: CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
! 658: case TIOCMBIS:
! 659: SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
! 660: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 661: break;
! 662: case TIOCMBIC:
! 663: CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
! 664: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 665: break;
! 666: case TIOCMGET: {
! 667: u_char m;
! 668: int bits = 0;
! 669:
! 670: m = sc->sc_mcr;
! 671: if (ISSET(m, MCR_DTR))
! 672: SET(bits, TIOCM_DTR);
! 673: if (ISSET(m, MCR_RTS))
! 674: SET(bits, TIOCM_RTS);
! 675: m = sc->sc_msr;
! 676: if (ISSET(m, MSR_DCD))
! 677: SET(bits, TIOCM_CD);
! 678: if (ISSET(m, MSR_CTS))
! 679: SET(bits, TIOCM_CTS);
! 680: if (ISSET(m, MSR_DSR))
! 681: SET(bits, TIOCM_DSR);
! 682: if (ISSET(m, MSR_RI | MSR_TERI))
! 683: SET(bits, TIOCM_RI);
! 684: if (bus_space_read_1(iot, ioh, com_ier))
! 685: SET(bits, TIOCM_LE);
! 686: *(int *)data = bits;
! 687: break;
! 688: }
! 689: case TIOCGFLAGS: {
! 690: int driverbits, userbits = 0;
! 691:
! 692: driverbits = sc->sc_swflags;
! 693: if (ISSET(driverbits, COM_SW_SOFTCAR))
! 694: SET(userbits, TIOCFLAG_SOFTCAR);
! 695: if (ISSET(driverbits, COM_SW_CLOCAL))
! 696: SET(userbits, TIOCFLAG_CLOCAL);
! 697: if (ISSET(driverbits, COM_SW_CRTSCTS))
! 698: SET(userbits, TIOCFLAG_CRTSCTS);
! 699: if (ISSET(driverbits, COM_SW_MDMBUF))
! 700: SET(userbits, TIOCFLAG_MDMBUF);
! 701: if (ISSET(driverbits, COM_SW_PPS))
! 702: SET(userbits, TIOCFLAG_PPS);
! 703:
! 704: *(int *)data = userbits;
! 705: break;
! 706: }
! 707: case TIOCSFLAGS: {
! 708: int userbits, driverbits = 0;
! 709:
! 710: error = suser(p, 0);
! 711: if (error != 0)
! 712: return(EPERM);
! 713:
! 714: userbits = *(int *)data;
! 715: if (ISSET(userbits, TIOCFLAG_SOFTCAR) ||
! 716: ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
! 717: SET(driverbits, COM_SW_SOFTCAR);
! 718: if (ISSET(userbits, TIOCFLAG_CLOCAL))
! 719: SET(driverbits, COM_SW_CLOCAL);
! 720: if (ISSET(userbits, TIOCFLAG_CRTSCTS))
! 721: SET(driverbits, COM_SW_CRTSCTS);
! 722: if (ISSET(userbits, TIOCFLAG_MDMBUF))
! 723: SET(driverbits, COM_SW_MDMBUF);
! 724: if (ISSET(userbits, TIOCFLAG_PPS))
! 725: SET(driverbits, COM_SW_PPS);
! 726:
! 727: sc->sc_swflags = driverbits;
! 728: break;
! 729: }
! 730: default:
! 731: return ENOTTY;
! 732: }
! 733:
! 734: return 0;
! 735: }
! 736:
! 737: /* already called at spltty */
! 738: int
! 739: comparam(struct tty *tp, struct termios *t)
! 740: {
! 741: struct com_softc *sc = com_cd.cd_devs[DEVUNIT(tp->t_dev)];
! 742: bus_space_tag_t iot = sc->sc_iot;
! 743: bus_space_handle_t ioh = sc->sc_ioh;
! 744: int ospeed = comspeed(sc->sc_frequency, t->c_ospeed);
! 745: u_char lcr;
! 746: tcflag_t oldcflag;
! 747:
! 748: /* check requested parameters */
! 749: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
! 750: return EINVAL;
! 751:
! 752: lcr = ISSET(sc->sc_lcr, LCR_SBREAK);
! 753:
! 754: switch (ISSET(t->c_cflag, CSIZE)) {
! 755: case CS5:
! 756: SET(lcr, LCR_5BITS);
! 757: break;
! 758: case CS6:
! 759: SET(lcr, LCR_6BITS);
! 760: break;
! 761: case CS7:
! 762: SET(lcr, LCR_7BITS);
! 763: break;
! 764: case CS8:
! 765: SET(lcr, LCR_8BITS);
! 766: break;
! 767: }
! 768: if (ISSET(t->c_cflag, PARENB)) {
! 769: SET(lcr, LCR_PENAB);
! 770: if (!ISSET(t->c_cflag, PARODD))
! 771: SET(lcr, LCR_PEVEN);
! 772: }
! 773: if (ISSET(t->c_cflag, CSTOPB))
! 774: SET(lcr, LCR_STOPB);
! 775:
! 776: sc->sc_lcr = lcr;
! 777:
! 778: if (ospeed == 0) {
! 779: CLR(sc->sc_mcr, MCR_DTR);
! 780: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 781: }
! 782:
! 783: /*
! 784: * Set the FIFO threshold based on the receive speed, if we are
! 785: * changing it.
! 786: */
! 787: if (sc->sc_initialize || (tp->t_ispeed != t->c_ispeed)) {
! 788: sc->sc_initialize = 0;
! 789:
! 790: if (ospeed != 0) {
! 791: /*
! 792: * Make sure the transmit FIFO is empty before
! 793: * proceeding. If we don't do this, some revisions
! 794: * of the UART will hang. Interestingly enough,
! 795: * even if we do this while the last character is
! 796: * still being pushed out, they don't hang. This
! 797: * seems good enough.
! 798: */
! 799: while (ISSET(tp->t_state, TS_BUSY)) {
! 800: int error;
! 801:
! 802: ++sc->sc_halt;
! 803: error = ttysleep(tp, &tp->t_outq,
! 804: TTOPRI | PCATCH, "comprm", 0);
! 805: --sc->sc_halt;
! 806: if (error) {
! 807: comstart(tp);
! 808: return (error);
! 809: }
! 810: }
! 811:
! 812: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
! 813: bus_space_write_1(iot, ioh, com_dlbl, ospeed);
! 814: bus_space_write_1(iot, ioh, com_dlbh, ospeed >> 8);
! 815: bus_space_write_1(iot, ioh, com_lcr, lcr);
! 816: SET(sc->sc_mcr, MCR_DTR);
! 817: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 818: } else
! 819: bus_space_write_1(iot, ioh, com_lcr, lcr);
! 820:
! 821: if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
! 822: if (sc->sc_uarttype == COM_UART_TI16750) {
! 823: bus_space_write_1(iot, ioh, com_lcr,
! 824: lcr | LCR_DLAB);
! 825: bus_space_write_1(iot, ioh, com_fifo,
! 826: FIFO_ENABLE | FIFO_ENABLE_64BYTE |
! 827: (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
! 828: bus_space_write_1(iot, ioh, com_lcr, lcr);
! 829: } else
! 830: bus_space_write_1(iot, ioh, com_fifo,
! 831: FIFO_ENABLE |
! 832: (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
! 833: }
! 834: } else
! 835: bus_space_write_1(iot, ioh, com_lcr, lcr);
! 836:
! 837: /* When not using CRTSCTS, RTS follows DTR. */
! 838: if (!ISSET(t->c_cflag, CRTSCTS)) {
! 839: if (ISSET(sc->sc_mcr, MCR_DTR)) {
! 840: if (!ISSET(sc->sc_mcr, MCR_RTS)) {
! 841: SET(sc->sc_mcr, MCR_RTS);
! 842: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 843: }
! 844: } else {
! 845: if (ISSET(sc->sc_mcr, MCR_RTS)) {
! 846: CLR(sc->sc_mcr, MCR_RTS);
! 847: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 848: }
! 849: }
! 850: sc->sc_dtr = MCR_DTR | MCR_RTS;
! 851: } else
! 852: sc->sc_dtr = MCR_DTR;
! 853:
! 854: /* and copy to tty */
! 855: tp->t_ispeed = t->c_ispeed;
! 856: tp->t_ospeed = t->c_ospeed;
! 857: oldcflag = tp->t_cflag;
! 858: tp->t_cflag = t->c_cflag;
! 859:
! 860: /*
! 861: * If DCD is off and MDMBUF is changed, ask the tty layer if we should
! 862: * stop the device.
! 863: */
! 864: if (!ISSET(sc->sc_msr, MSR_DCD) &&
! 865: !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
! 866: ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) &&
! 867: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
! 868: CLR(sc->sc_mcr, sc->sc_dtr);
! 869: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 870: }
! 871:
! 872: /* Just to be sure... */
! 873: comstart(tp);
! 874: return 0;
! 875: }
! 876:
! 877: void
! 878: comstart(struct tty *tp)
! 879: {
! 880: struct com_softc *sc = com_cd.cd_devs[DEVUNIT(tp->t_dev)];
! 881: bus_space_tag_t iot = sc->sc_iot;
! 882: bus_space_handle_t ioh = sc->sc_ioh;
! 883: int s;
! 884:
! 885: s = spltty();
! 886: if (ISSET(tp->t_state, TS_BUSY))
! 887: goto out;
! 888: if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
! 889: goto stopped;
! 890: if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS))
! 891: goto stopped;
! 892: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 893: if (ISSET(tp->t_state, TS_ASLEEP)) {
! 894: CLR(tp->t_state, TS_ASLEEP);
! 895: wakeup(&tp->t_outq);
! 896: }
! 897: if (tp->t_outq.c_cc == 0)
! 898: goto stopped;
! 899: selwakeup(&tp->t_wsel);
! 900: }
! 901: SET(tp->t_state, TS_BUSY);
! 902:
! 903: #ifdef COM_PXA2X0
! 904: /* Enable transmitter slow infrared mode. */
! 905: if (sc->sc_uarttype == COM_UART_PXA2X0 &&
! 906: ISSET(sc->sc_hwflags, COM_HW_SIR))
! 907: bus_space_write_1(iot, ioh, com_isr, ISR_SEND);
! 908: #endif
! 909:
! 910: /* Enable transmit completion interrupts. */
! 911: if (!ISSET(sc->sc_ier, IER_ETXRDY)) {
! 912: SET(sc->sc_ier, IER_ETXRDY);
! 913: bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
! 914: }
! 915:
! 916: if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
! 917: u_char buffer[64]; /* XXX: largest fifo */
! 918:
! 919: int n = q_to_b(&tp->t_outq, buffer, sc->sc_fifolen);
! 920: int i;
! 921:
! 922: for (i = 0; i < n; i++) {
! 923: bus_space_write_1(iot, ioh, com_data, buffer[i]);
! 924: }
! 925: } else if (tp->t_outq.c_cc != 0)
! 926: bus_space_write_1(iot, ioh, com_data, getc(&tp->t_outq));
! 927: out:
! 928: splx(s);
! 929: return;
! 930: stopped:
! 931: if (ISSET(sc->sc_ier, IER_ETXRDY)) {
! 932: CLR(sc->sc_ier, IER_ETXRDY);
! 933: bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
! 934: #ifdef COM_PXA2X0
! 935: if (sc->sc_uarttype == COM_UART_PXA2X0 &&
! 936: ISSET(sc->sc_hwflags, COM_HW_SIR)) {
! 937: int timo;
! 938:
! 939: /* Wait for empty transmit shift register. */
! 940: timo = 20000;
! 941: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
! 942: LSR_TSRE) && --timo)
! 943: delay(1);
! 944:
! 945: /* Enable receiver slow infrared mode. */
! 946: bus_space_write_1(iot, ioh, com_isr, ISR_RECV);
! 947: }
! 948: #endif
! 949: }
! 950: splx(s);
! 951: }
! 952:
! 953: /*
! 954: * Stop output on a line.
! 955: */
! 956: int
! 957: comstop(struct tty *tp, int flag)
! 958: {
! 959: int s;
! 960:
! 961: s = spltty();
! 962: if (ISSET(tp->t_state, TS_BUSY))
! 963: if (!ISSET(tp->t_state, TS_TTSTOP))
! 964: SET(tp->t_state, TS_FLUSH);
! 965: splx(s);
! 966: return 0;
! 967: }
! 968:
! 969: void
! 970: comdiag(void *arg)
! 971: {
! 972: struct com_softc *sc = arg;
! 973: int overflows, floods;
! 974: int s;
! 975:
! 976: s = spltty();
! 977: sc->sc_errors = 0;
! 978: overflows = sc->sc_overflows;
! 979: sc->sc_overflows = 0;
! 980: floods = sc->sc_floods;
! 981: sc->sc_floods = 0;
! 982: splx(s);
! 983: log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
! 984: sc->sc_dev.dv_xname,
! 985: overflows, overflows == 1 ? "" : "s",
! 986: floods, floods == 1 ? "" : "s");
! 987: }
! 988:
! 989: void
! 990: comsoft(void *arg)
! 991: {
! 992: struct com_softc *sc = (struct com_softc *)arg;
! 993: struct tty *tp;
! 994: u_char *ibufp;
! 995: u_char *ibufend;
! 996: int c;
! 997: int s;
! 998: static int lsrmap[8] = {
! 999: 0, TTY_PE,
! 1000: TTY_FE, TTY_PE|TTY_FE,
! 1001: TTY_FE, TTY_PE|TTY_FE,
! 1002: TTY_FE, TTY_PE|TTY_FE
! 1003: };
! 1004:
! 1005: if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
! 1006: goto out;
! 1007:
! 1008: tp = sc->sc_tty;
! 1009:
! 1010: s = spltty();
! 1011:
! 1012: ibufp = sc->sc_ibuf;
! 1013: ibufend = sc->sc_ibufp;
! 1014:
! 1015: if (ibufp == ibufend) {
! 1016: splx(s);
! 1017: goto out;
! 1018: }
! 1019:
! 1020: sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
! 1021: sc->sc_ibufs[1] : sc->sc_ibufs[0];
! 1022: sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
! 1023: sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
! 1024:
! 1025: if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
! 1026: splx(s);
! 1027: goto out;
! 1028: }
! 1029:
! 1030: if (ISSET(tp->t_cflag, CRTSCTS) &&
! 1031: !ISSET(sc->sc_mcr, MCR_RTS)) {
! 1032: /* XXX */
! 1033: SET(sc->sc_mcr, MCR_RTS);
! 1034: bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr,
! 1035: sc->sc_mcr);
! 1036: }
! 1037:
! 1038: splx(s);
! 1039:
! 1040: while (ibufp < ibufend) {
! 1041: c = *ibufp++;
! 1042: if (ISSET(*ibufp, LSR_OE)) {
! 1043: sc->sc_overflows++;
! 1044: if (sc->sc_errors++ == 0)
! 1045: timeout_add(&sc->sc_diag_tmo, 60 * hz);
! 1046: }
! 1047: /* This is ugly, but fast. */
! 1048: c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
! 1049: (*linesw[tp->t_line].l_rint)(c, tp);
! 1050: }
! 1051:
! 1052: out:
! 1053: #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1054: timeout_add(&sc->sc_comsoft_tmo, 1);
! 1055: #else
! 1056: ;
! 1057: #endif
! 1058: }
! 1059:
! 1060: #ifdef KGDB
! 1061:
! 1062: /*
! 1063: * If a line break is set, or data matches one of the characters
! 1064: * gdb uses to signal a connection, then start up kgdb. Just gobble
! 1065: * any other data. Done in a stand alone function because comintr
! 1066: * does tty stuff and we don't have one.
! 1067: */
! 1068:
! 1069: int
! 1070: kgdbintr(void *arg)
! 1071: {
! 1072: struct com_softc *sc = arg;
! 1073: bus_space_tag_t iot = sc->sc_iot;
! 1074: bus_space_handle_t ioh = sc->sc_ioh;
! 1075: u_char lsr, data, msr, delta;
! 1076:
! 1077: if (!ISSET(sc->sc_hwflags, COM_HW_KGDB))
! 1078: return(0);
! 1079:
! 1080: for (;;) {
! 1081: lsr = bus_space_read_1(iot, ioh, com_lsr);
! 1082: if (ISSET(lsr, LSR_RXRDY)) {
! 1083: do {
! 1084: data = bus_space_read_1(iot, ioh, com_data);
! 1085: if (data == 3 || data == '$' || data == '+' ||
! 1086: ISSET(lsr, LSR_BI)) {
! 1087: kgdb_connect(1);
! 1088: data = 0;
! 1089: }
! 1090: lsr = bus_space_read_1(iot, ioh, com_lsr);
! 1091: } while (ISSET(lsr, LSR_RXRDY));
! 1092:
! 1093: }
! 1094: if (ISSET(lsr, LSR_BI|LSR_FE|LSR_PE|LSR_OE))
! 1095: printf("weird lsr %02x\n", lsr);
! 1096:
! 1097: msr = bus_space_read_1(iot, ioh, com_msr);
! 1098:
! 1099: if (msr != sc->sc_msr) {
! 1100: delta = msr ^ sc->sc_msr;
! 1101: sc->sc_msr = msr;
! 1102: if (ISSET(delta, MSR_DCD)) {
! 1103: if (!ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
! 1104: CLR(sc->sc_mcr, sc->sc_dtr);
! 1105: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 1106: }
! 1107: }
! 1108: }
! 1109: if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_NOPEND))
! 1110: return (1);
! 1111: }
! 1112: }
! 1113: #endif /* KGDB */
! 1114:
! 1115: int
! 1116: comintr(void *arg)
! 1117: {
! 1118: struct com_softc *sc = arg;
! 1119: bus_space_tag_t iot = sc->sc_iot;
! 1120: bus_space_handle_t ioh = sc->sc_ioh;
! 1121: struct tty *tp;
! 1122: u_char lsr, data, msr, delta;
! 1123:
! 1124: if (!sc->sc_tty)
! 1125: return (0); /* can't do squat. */
! 1126:
! 1127: if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_NOPEND))
! 1128: return (0);
! 1129:
! 1130: tp = sc->sc_tty;
! 1131:
! 1132: for (;;) {
! 1133: lsr = bus_space_read_1(iot, ioh, com_lsr);
! 1134:
! 1135: if (ISSET(lsr, LSR_RXRDY)) {
! 1136: u_char *p = sc->sc_ibufp;
! 1137:
! 1138: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1139: softintr_schedule(sc->sc_si);
! 1140: #endif
! 1141: do {
! 1142: data = bus_space_read_1(iot, ioh, com_data);
! 1143: if (ISSET(lsr, LSR_BI)) {
! 1144: #if defined(COM_CONSOLE) && defined(DDB)
! 1145: if (ISSET(sc->sc_hwflags,
! 1146: COM_HW_CONSOLE)) {
! 1147: if (db_console)
! 1148: Debugger();
! 1149: goto next;
! 1150: }
! 1151: #endif
! 1152: data = 0;
! 1153: }
! 1154: if (p >= sc->sc_ibufend) {
! 1155: sc->sc_floods++;
! 1156: if (sc->sc_errors++ == 0)
! 1157: timeout_add(&sc->sc_diag_tmo, 60 * hz);
! 1158: } else {
! 1159: *p++ = data;
! 1160: *p++ = lsr;
! 1161: if (p == sc->sc_ibufhigh &&
! 1162: ISSET(tp->t_cflag, CRTSCTS)) {
! 1163: /* XXX */
! 1164: CLR(sc->sc_mcr, MCR_RTS);
! 1165: bus_space_write_1(iot, ioh, com_mcr,
! 1166: sc->sc_mcr);
! 1167: }
! 1168: }
! 1169: #if defined(COM_CONSOLE) && defined(DDB)
! 1170: next:
! 1171: #endif
! 1172: lsr = bus_space_read_1(iot, ioh, com_lsr);
! 1173: } while (ISSET(lsr, LSR_RXRDY));
! 1174:
! 1175: sc->sc_ibufp = p;
! 1176: }
! 1177: msr = bus_space_read_1(iot, ioh, com_msr);
! 1178:
! 1179: if (msr != sc->sc_msr) {
! 1180: delta = msr ^ sc->sc_msr;
! 1181:
! 1182: ttytstamp(tp, sc->sc_msr & MSR_CTS, msr & MSR_CTS,
! 1183: sc->sc_msr & MSR_DCD, msr & MSR_DCD);
! 1184:
! 1185: sc->sc_msr = msr;
! 1186: if (ISSET(delta, MSR_DCD)) {
! 1187: if (!ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
! 1188: (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD)) == 0) {
! 1189: CLR(sc->sc_mcr, sc->sc_dtr);
! 1190: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
! 1191: }
! 1192: }
! 1193: if (ISSET(delta & msr, MSR_CTS) &&
! 1194: ISSET(tp->t_cflag, CRTSCTS)) {
! 1195: /* the line is up and we want to do rts/cts flow control */
! 1196: (*linesw[tp->t_line].l_start)(tp);
! 1197: }
! 1198: }
! 1199:
! 1200: if (ISSET(lsr, LSR_TXRDY) && ISSET(tp->t_state, TS_BUSY)) {
! 1201: CLR(tp->t_state, TS_BUSY | TS_FLUSH);
! 1202: if (sc->sc_halt > 0)
! 1203: wakeup(&tp->t_outq);
! 1204: (*linesw[tp->t_line].l_start)(tp);
! 1205: }
! 1206:
! 1207: #ifdef COM_PXA2X0
! 1208: if (sc->sc_uarttype == COM_UART_PXA2X0 &&
! 1209: ISSET(sc->sc_hwflags, COM_HW_SIR) &&
! 1210: ISSET(lsr, LSR_TXRDY) && ISSET(lsr, LSR_TSRE))
! 1211: bus_space_write_1(iot, ioh, com_isr, ISR_RECV);
! 1212: #endif
! 1213:
! 1214: if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_NOPEND))
! 1215: return (1);
! 1216: }
! 1217: }
! 1218:
! 1219: /*
! 1220: * Following are all routines needed for COM to act as console
! 1221: */
! 1222:
! 1223: #if defined(__sgi__)
! 1224: #undef CONADDR
! 1225: #undef COM_FREQ
! 1226: #include <machine/autoconf.h>
! 1227: #endif
! 1228:
! 1229: /*
! 1230: * The following functions are polled getc and putc routines, shared
! 1231: * by the console and kgdb glue.
! 1232: */
! 1233:
! 1234: int
! 1235: com_common_getc(bus_space_tag_t iot, bus_space_handle_t ioh)
! 1236: {
! 1237: int s = splhigh();
! 1238: u_char stat, c;
! 1239:
! 1240: #ifdef COM_PXA2X0
! 1241: if (com_is_console(iot, comsiraddr))
! 1242: bus_space_write_1(iot, ioh, com_isr, ISR_RECV);
! 1243: #endif
! 1244:
! 1245: /* block until a character becomes available */
! 1246: while (!ISSET(stat = bus_space_read_1(iot, ioh, com_lsr), LSR_RXRDY))
! 1247: continue;
! 1248:
! 1249: c = bus_space_read_1(iot, ioh, com_data);
! 1250: /* clear any interrupts generated by this transmission */
! 1251: stat = bus_space_read_1(iot, ioh, com_iir);
! 1252: splx(s);
! 1253: return (c);
! 1254: }
! 1255:
! 1256: void
! 1257: com_common_putc(bus_space_tag_t iot, bus_space_handle_t ioh, int c)
! 1258: {
! 1259: int s = spltty();
! 1260: int timo;
! 1261:
! 1262: printf("com_common_putc: enter\n");
! 1263:
! 1264: /* wait for any pending transmission to finish */
! 1265: timo = 2000;
! 1266: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr), LSR_TXRDY) && --timo)
! 1267: delay(1);
! 1268:
! 1269: #ifdef COM_PXA2X0
! 1270: if (com_is_console(iot, comsiraddr))
! 1271: bus_space_write_1(iot, ioh, com_isr, ISR_SEND);
! 1272: #endif
! 1273: bus_space_write_1(iot, ioh, com_data, (u_int8_t)(c & 0xff));
! 1274: bus_space_barrier(iot, ioh, 0, COM_NPORTS,
! 1275: (BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE));
! 1276:
! 1277: printf("com_common_putc: wait for TXRDY\n");
! 1278: /* wait for this transmission to complete */
! 1279: timo = 2000;
! 1280: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr), LSR_TXRDY) && --timo)
! 1281: delay(1);
! 1282:
! 1283: #ifdef COM_PXA2X0
! 1284: if (com_is_console(iot, comsiraddr)) {
! 1285: /* wait for transmit shift register to become empty */
! 1286: timo = 20000;
! 1287: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr), LSR_TSRE)
! 1288: && --timo)
! 1289: delay(1);
! 1290:
! 1291: bus_space_write_1(iot, ioh, com_isr, ISR_RECV);
! 1292: }
! 1293: #endif
! 1294:
! 1295: splx(s);
! 1296: }
! 1297:
! 1298: void
! 1299: cominit(bus_space_tag_t iot, bus_space_handle_t ioh, int rate, int frequency)
! 1300: {
! 1301: int s = splhigh();
! 1302: u_char stat;
! 1303:
! 1304: bus_space_write_1(iot, ioh, com_lcr, LCR_DLAB);
! 1305: rate = comspeed(frequency, rate); /* XXX not comdefaultrate? */
! 1306: bus_space_write_1(iot, ioh, com_dlbl, rate);
! 1307: bus_space_write_1(iot, ioh, com_dlbh, rate >> 8);
! 1308: bus_space_write_1(iot, ioh, com_lcr, LCR_8BITS);
! 1309: bus_space_write_1(iot, ioh, com_mcr, MCR_DTR | MCR_RTS);
! 1310: #ifdef COM_PXA2X0
! 1311: /* XXX */
! 1312: bus_space_write_1(iot, ioh, com_ier, IER_EUART); /* Make sure they are off */
! 1313: #else
! 1314: bus_space_write_1(iot, ioh, com_ier, 0); /* Make sure they are off */
! 1315: #endif
! 1316: bus_space_write_1(iot, ioh, com_fifo,
! 1317: FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1);
! 1318: stat = bus_space_read_1(iot, ioh, com_iir);
! 1319: splx(s);
! 1320: }
! 1321:
! 1322: #ifdef COM_CONSOLE
! 1323: void
! 1324: comcnprobe(struct consdev *cp)
! 1325: {
! 1326: /* XXX NEEDS TO BE FIXED XXX */
! 1327: #ifdef MD_ISA_IOT
! 1328: bus_space_tag_t iot = MD_ISA_IOT;
! 1329: #elif defined(__sgi__)
! 1330: bus_space_tag_t iot = sys_config.cons_iot;
! 1331: #else
! 1332: bus_space_tag_t iot = 0;
! 1333: #endif
! 1334: bus_space_handle_t ioh;
! 1335: int found;
! 1336:
! 1337: if (CONADDR == 0)
! 1338: return;
! 1339:
! 1340: comconsiot = iot;
! 1341: if (bus_space_map(iot, CONADDR, COM_NPORTS, 0, &ioh))
! 1342: return;
! 1343: found = comprobe1(iot, ioh);
! 1344: bus_space_unmap(iot, ioh, COM_NPORTS);
! 1345: if (!found)
! 1346: return;
! 1347:
! 1348: /* locate the major number */
! 1349: for (commajor = 0; commajor < nchrdev; commajor++)
! 1350: if (cdevsw[commajor].d_open == comopen)
! 1351: break;
! 1352:
! 1353: /* initialize required fields */
! 1354: cp->cn_dev = makedev(commajor, CONUNIT);
! 1355: #if defined(COMCONSOLE) || defined(PCCOMCONSOLE) || !defined(__amd64__)
! 1356: cp->cn_pri = CN_REMOTE;
! 1357: #else
! 1358: cp->cn_pri = CN_NORMAL;
! 1359: #endif
! 1360: }
! 1361:
! 1362: void
! 1363: comcninit(struct consdev *cp)
! 1364: {
! 1365: comconsaddr = CONADDR;
! 1366:
! 1367: if (bus_space_map(comconsiot, comconsaddr, COM_NPORTS, 0, &comconsioh))
! 1368: panic("comcninit: mapping failed");
! 1369:
! 1370: if (comconsfreq == 0)
! 1371: comconsfreq = COM_FREQ;
! 1372:
! 1373: cominit(comconsiot, comconsioh, comdefaultrate, comconsfreq);
! 1374: comconsinit = 0;
! 1375: }
! 1376:
! 1377:
! 1378: int
! 1379: comcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, int frequency, tcflag_t cflag)
! 1380: {
! 1381: static struct consdev comcons = {
! 1382: NULL, NULL, comcngetc, comcnputc, comcnpollc, NULL,
! 1383: NODEV, CN_NORMAL
! 1384: };
! 1385:
! 1386: #ifndef __sparc64__
! 1387: if (bus_space_map(iot, iobase, COM_NPORTS, 0, &comconsioh))
! 1388: return ENOMEM;
! 1389: #endif
! 1390:
! 1391: cominit(iot, comconsioh, rate, frequency);
! 1392:
! 1393: cn_tab = &comcons;
! 1394:
! 1395: comconsiot = iot;
! 1396: comconsaddr = iobase;
! 1397: comconscflag = cflag;
! 1398: comconsfreq = frequency;
! 1399:
! 1400: return (0);
! 1401: }
! 1402:
! 1403: int
! 1404: comcngetc(dev_t dev)
! 1405: {
! 1406: return (com_common_getc(comconsiot, comconsioh));
! 1407: }
! 1408:
! 1409: /*
! 1410: * Console kernel output character routine.
! 1411: */
! 1412: void
! 1413: comcnputc(dev_t dev, int c)
! 1414: {
! 1415: com_common_putc(comconsiot, comconsioh, c);
! 1416: }
! 1417:
! 1418: void
! 1419: comcnpollc(dev_t dev, int on)
! 1420: {
! 1421:
! 1422: }
! 1423: #endif /* COM_CONSOLE */
! 1424:
! 1425: #ifdef KGDB
! 1426: int
! 1427: com_kgdb_attach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
! 1428: int frequency,tcflag_t cflag)
! 1429: bus_space_tag_t iot;
! 1430: bus_addr_t iobase;
! 1431: int rate, frequency;
! 1432: tcflag_t cflag;
! 1433: {
! 1434: #ifdef COM_CONSOLE
! 1435: if (iot == comconsiot && iobase == comconsaddr) {
! 1436: return (EBUSY); /* cannot share with console */
! 1437: }
! 1438: #endif
! 1439:
! 1440: com_kgdb_iot = iot;
! 1441: com_kgdb_addr = iobase;
! 1442:
! 1443: if (bus_space_map(com_kgdb_iot, com_kgdb_addr, COM_NPORTS, 0,
! 1444: &com_kgdb_ioh))
! 1445: panic("com_kgdb_attach: mapping failed");
! 1446:
! 1447: /* XXX We currently don't respect KGDBMODE? */
! 1448: cominit(com_kgdb_iot, com_kgdb_ioh, rate, frequency);
! 1449:
! 1450: kgdb_attach(com_kgdb_getc, com_kgdb_putc, NULL);
! 1451: kgdb_dev = 123; /* unneeded, only to satisfy some tests */
! 1452:
! 1453: return (0);
! 1454: }
! 1455:
! 1456: /* ARGSUSED */
! 1457: int
! 1458: com_kgdb_getc(void *arg)
! 1459: {
! 1460:
! 1461: return (com_common_getc(com_kgdb_iot, com_kgdb_ioh));
! 1462: }
! 1463:
! 1464: /* ARGSUSED */
! 1465: void
! 1466: com_kgdb_putc(void *arg, int c)
! 1467: {
! 1468:
! 1469: return (com_common_putc(com_kgdb_iot, com_kgdb_ioh, c));
! 1470: }
! 1471: #endif /* KGDB */
! 1472:
! 1473: #ifdef COM_PXA2X0
! 1474: int
! 1475: com_is_console(bus_space_tag_t iot, bus_addr_t iobase)
! 1476: {
! 1477:
! 1478: if (comconsiot == iot && comconsaddr == iobase)
! 1479: return (1);
! 1480: #ifdef KGDB
! 1481: else if (com_kgdb_iot == iot && com_kgdb_addr == iobase)
! 1482: return (1);
! 1483: #endif
! 1484: return (0);
! 1485: }
! 1486: #endif
CVSweb