Annotation of sys/arch/vax/vxt/qsc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: qsc.c,v 1.1 2006/08/27 16:55:41 miod Exp $ */
! 2: /*
! 3: * Copyright (c) 2006 Miodrag Vallat.
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice, this permission notice, and the disclaimer below
! 8: * appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18: /*
! 19: * Mach Operating System
! 20: * Copyright (c) 1993-1991 Carnegie Mellon University
! 21: * All Rights Reserved.
! 22: *
! 23: * Permission to use, copy, modify and distribute this software and its
! 24: * documentation is hereby granted, provided that both the copyright
! 25: * notice and this permission notice appear in all copies of the
! 26: * software, derivative works or modified versions, and any portions
! 27: * thereof, and that both notices appear in supporting documentation.
! 28: *
! 29: * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
! 30: * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
! 31: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
! 32: *
! 33: * Carnegie Mellon requests users of this software to return to
! 34: *
! 35: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
! 36: * School of Computer Science
! 37: * Carnegie Mellon University
! 38: * Pittsburgh PA 15213-3890
! 39: *
! 40: * any improvements or extensions that they make and grant Carnegie the
! 41: * rights to redistribute these changes.
! 42: */
! 43:
! 44: #include <sys/param.h>
! 45: #include <sys/ioctl.h>
! 46: #include <sys/proc.h>
! 47: #include <sys/tty.h>
! 48: #include <sys/systm.h>
! 49: #include <sys/device.h>
! 50: #include <sys/syslog.h>
! 51: #include <sys/conf.h>
! 52:
! 53: #include <machine/bus.h>
! 54: #include <machine/nexus.h>
! 55: #include <machine/sid.h>
! 56:
! 57: #include <dev/cons.h>
! 58:
! 59: #include <vax/vxt/vxtbusvar.h>
! 60:
! 61: #include <vax/vxt/qscreg.h>
! 62: #include <vax/vxt/qscvar.h>
! 63:
! 64: #ifdef DDB
! 65: #include <machine/cpu.h>
! 66: #include <ddb/db_var.h>
! 67: #endif
! 68:
! 69: #include "qsckbd.h"
! 70: #include "qscms.h"
! 71:
! 72: struct cfdriver qsc_cd = {
! 73: NULL, "qsc", DV_TTY
! 74: };
! 75:
! 76: /* console storage */
! 77: struct qsc_sv_reg qsccn_sv;
! 78:
! 79: /* prototypes */
! 80: cdev_decl(qsc);
! 81: cons_decl(qsc);
! 82: int qscintr(void *);
! 83: int qscparam(struct tty *, struct termios *);
! 84: void qscrint(struct qscsoftc *, u_int);
! 85: int qscspeed(int);
! 86: void qscstart(struct tty *);
! 87: struct tty *qsctty(dev_t);
! 88: void qscxint(struct qscsoftc *, u_int);
! 89:
! 90: /*
! 91: * Registers are mapped as the least-significant byte of 32-bit
! 92: * addresses. The following macros hide this.
! 93: */
! 94:
! 95: #define qsc_readp(sc, reg) \
! 96: bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, 4 * (reg))
! 97: #define qsc_read(sc, line, reg) \
! 98: bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, \
! 99: (sc)->sc_regaddr[line][reg])
! 100: #define qsc_writep(sc, reg, val) \
! 101: bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, 4 * (reg), (val))
! 102: #define qsc_write(sc, line, reg, val) \
! 103: bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, \
! 104: (sc)->sc_regaddr[line][reg], (val))
! 105:
! 106: #define SC_LINE(dev) (minor(dev))
! 107:
! 108: /*
! 109: * Attachment glue.
! 110: */
! 111:
! 112: int qsc_match(struct device *parent, void *self, void *aux);
! 113: void qsc_attach(struct device *parent, struct device *self, void *aux);
! 114: int qsc_print(void *, const char *);
! 115:
! 116: struct cfattach qsc_ca = {
! 117: sizeof(struct qscsoftc), qsc_match, qsc_attach
! 118: };
! 119:
! 120: int
! 121: qsc_match(struct device *parent, void *cf, void *aux)
! 122: {
! 123: struct bp_conf *bp = aux;
! 124:
! 125: if (strcmp(bp->type, qsc_cd.cd_name) == 0)
! 126: return (1);
! 127: return (0);
! 128: }
! 129:
! 130: void
! 131: qsc_attach(struct device *parent, struct device *self, void *aux)
! 132: {
! 133: extern struct vax_bus_space vax_mem_bus_space;
! 134: struct qscsoftc *sc = (struct qscsoftc *)self;
! 135: bus_space_handle_t ioh;
! 136: u_int line, pair, reg;
! 137: #if NQSCKBD > 0 || NQSCMS > 0
! 138: struct qsc_attach_args qa;
! 139: #endif
! 140:
! 141: sc->sc_iot = &vax_mem_bus_space;
! 142: if (bus_space_map(sc->sc_iot, QSCADDR, VAX_NBPG, 0, &ioh) != 0) {
! 143: printf(": can't map registers!\n");
! 144: return;
! 145: }
! 146: sc->sc_ioh = ioh;
! 147:
! 148: if (cn_tab->cn_putc == qsccnputc) {
! 149: sc->sc_console = 1;
! 150: printf(": console");
! 151: }
! 152:
! 153: /*
! 154: * Initialize line-specific data (register addresses)
! 155: */
! 156:
! 157: for (line = 0; line < SC_NLINES; line++) {
! 158: sc->sc_regaddr[line][SC_MR] = line * 8 + SC_MRA;
! 159: sc->sc_regaddr[line][SC_CSR] = line * 8 + SC_CSRA;
! 160: sc->sc_regaddr[line][SC_CR] = line * 8 + SC_CRA;
! 161: sc->sc_regaddr[line][SC_TXFIFO] = line * 8 + SC_TXFIFOA;
! 162:
! 163: sc->sc_regaddr[line][SC_IOPCR] = (line < 2 ? 0 : 0x10) +
! 164: (line & 1) + SC_IOPCRA;
! 165:
! 166: sc->sc_regaddr[line][SC_ACR] = (line < 2 ? 0 : 0x10) + SC_ACRAB;
! 167: sc->sc_regaddr[line][SC_IMR] = (line < 2 ? 0 : 0x10) + SC_IMRAB;
! 168: sc->sc_regaddr[line][SC_OPR] = (line < 2 ? 0 : 0x10) + SC_OPRAB;
! 169: }
! 170: for (line = 0; line < SC_NLINES; line++)
! 171: for (reg = 0; reg < SC_LOGICAL; reg++)
! 172: sc->sc_regaddr[line][reg] =
! 173: 0 + 4 * sc->sc_regaddr[line][reg];
! 174:
! 175: /*
! 176: * Initialize all lines.
! 177: */
! 178: sc->sc_sv_reg = sc->sc_console ? &qsccn_sv : &sc->sc_sv_reg_storage;
! 179: for (line = 0; line < SC_NLINES; line++) {
! 180: /* do not reinitialize the console line... */
! 181: if (sc->sc_console && line == QSC_LINE_SERIAL)
! 182: continue;
! 183:
! 184: sc->sc_sv_reg->sv_mr1[line] =
! 185: (line == 3 ? ODDPAR | PAREN : PARDIS) | RXRTS | CL8;
! 186: sc->sc_sv_reg->sv_mr2[line] = /* TXCTS | */ SB1;
! 187: sc->sc_sv_reg->sv_csr[line] = line < 2 ? BD9600 : BD4800;
! 188: sc->sc_sv_reg->sv_cr[line] = TXEN | RXEN;
! 189:
! 190: pair = line >> 1;
! 191:
! 192: if (sc->sc_console && pair == (QSC_LINE_SERIAL >> 1))
! 193: continue;
! 194:
! 195: /* Start out with Tx and RX interrupts disabled */
! 196: sc->sc_sv_reg->sv_imr[pair] = 0;
! 197: }
! 198:
! 199: for (line = 0; line < SC_NLINES; line++) {
! 200: /* do not reset the console line... */
! 201: if (sc->sc_console && line == QSC_LINE_SERIAL)
! 202: continue;
! 203:
! 204: qsc_write(sc, line, SC_CR, RXRESET | TXDIS | RXDIS);
! 205: DELAY(1);
! 206: qsc_write(sc, line, SC_CR, TXRESET | TXDIS | RXDIS);
! 207: DELAY(1);
! 208: qsc_write(sc, line, SC_CR, ERRRESET | TXDIS | RXDIS);
! 209: DELAY(1);
! 210: qsc_write(sc, line, SC_CR, BRKINTRESET | TXDIS | RXDIS);
! 211: DELAY(1);
! 212: qsc_write(sc, line, SC_CR, MRZERO | TXDIS | RXDIS);
! 213: DELAY(1);
! 214:
! 215: qsc_write(sc, line, SC_MR, 0);
! 216: qsc_write(sc, line, SC_MR, sc->sc_sv_reg->sv_mr1[line]);
! 217: qsc_write(sc, line, SC_MR, sc->sc_sv_reg->sv_mr2[line]);
! 218: qsc_write(sc, line, SC_CSR, sc->sc_sv_reg->sv_csr[line]);
! 219: qsc_write(sc, line, SC_CR, sc->sc_sv_reg->sv_cr[line]);
! 220: DELAY(1);
! 221: }
! 222:
! 223: for (pair = 0; pair < SC_NLINES / 2; pair++)
! 224: qsc_write(sc, pair << 1, SC_IMR,
! 225: sc->sc_sv_reg->sv_imr[pair]);
! 226:
! 227: for (line = 0; line < SC_NLINES; line++) {
! 228: sc->sc_tty[line] = NULL;
! 229: sc->sc_swflags[line] = 0;
! 230: }
! 231: if (sc->sc_console)
! 232: sc->sc_swflags[QSC_LINE_SERIAL] |= TIOCFLAG_SOFTCAR;
! 233:
! 234: printf("\n");
! 235:
! 236: /*
! 237: * Configure interrupts. We are bidding in 2681 mode for now.
! 238: */
! 239:
! 240: qsc_writep(sc, SC_ICR, 0x00);
! 241: for (line = SC_BIDCRA; line <= SC_BIDCRD; line++)
! 242: qsc_writep(sc, line, 0x00);
! 243: qsc_writep(sc, SC_IVR, VXT_INTRVEC >> 2);
! 244:
! 245: vxtbus_intr_establish(self->dv_xname, IPL_TTY, qscintr, sc);
! 246:
! 247: /*
! 248: * Attach subdevices, and enable RX and TX interrupts on their lines
! 249: * if successful.
! 250: */
! 251: #if NQSCKBD > 0
! 252: /* keyboard */
! 253: qa.qa_line = QSC_LINE_KEYBOARD;
! 254: qa.qa_console = !sc->sc_console;
! 255: qa.qa_hook = &sc->sc_hook[QSC_LINE_KEYBOARD];
! 256: if (config_found(self, &qa, qsc_print) != NULL)
! 257: sc->sc_sv_reg->sv_imr[QSC_LINE_KEYBOARD >> 1] |= IRXRDYA;
! 258: #endif
! 259: #if NQSCMS > 0
! 260: /* mouse */
! 261: qa.qa_line = QSC_LINE_MOUSE;
! 262: qa.qa_console = 0;
! 263: qa.qa_hook = &sc->sc_hook[QSC_LINE_MOUSE];
! 264: if (config_found(self, &qa, qsc_print) != NULL)
! 265: sc->sc_sv_reg->sv_imr[QSC_LINE_MOUSE >> 1] |= IRXRDYB;
! 266: #endif
! 267:
! 268: for (pair = 0; pair < SC_NLINES / 2; pair++)
! 269: qsc_write(sc, pair << 1, SC_IMR,
! 270: sc->sc_sv_reg->sv_imr[pair]);
! 271:
! 272: sc->sc_rdy = 1;
! 273: }
! 274:
! 275: /* speed tables */
! 276: const struct qsc_s {
! 277: int kspeed;
! 278: int dspeed;
! 279: } qsc_speeds[] = {
! 280: { B0, 0 }, /* 0 baud, special HUP condition */
! 281: { B50, NOBAUD }, /* 50 baud, not implemented */
! 282: { B75, BD75 }, /* 75 baud */
! 283: { B110, BD110 }, /* 110 baud */
! 284: { B134, BD134 }, /* 134.5 baud */
! 285: { B150, BD150 }, /* 150 baud */
! 286: { B200, NOBAUD }, /* 200 baud, not implemented */
! 287: { B300, BD300 }, /* 300 baud */
! 288: { B600, BD600 }, /* 600 baud */
! 289: { B1200, BD1200 }, /* 1200 baud */
! 290: { B1800, BD1800 }, /* 1800 baud */
! 291: { B2400, BD2400 }, /* 2400 baud */
! 292: { B4800, BD4800 }, /* 4800 baud */
! 293: { B9600, BD9600 }, /* 9600 baud */
! 294: { B19200, BD19200 }, /* 19200 baud */
! 295: { -1, NOBAUD }, /* anything more is uncivilized */
! 296: };
! 297:
! 298: int
! 299: qscspeed(int speed)
! 300: {
! 301: const struct qsc_s *ds;
! 302:
! 303: for (ds = qsc_speeds; ds->kspeed != -1; ds++)
! 304: if (ds->kspeed == speed)
! 305: return ds->dspeed;
! 306:
! 307: return NOBAUD;
! 308: }
! 309:
! 310: struct tty *
! 311: qsctty(dev_t dev)
! 312: {
! 313: u_int line;
! 314: struct qscsoftc *sc;
! 315:
! 316: line = SC_LINE(dev);
! 317: if (qsc_cd.cd_ndevs == 0 || line >= SC_NLINES)
! 318: return (NULL);
! 319:
! 320: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 321: if (sc == NULL)
! 322: return (NULL);
! 323:
! 324: return sc->sc_tty[line];
! 325: }
! 326:
! 327: void
! 328: qscstart(struct tty *tp)
! 329: {
! 330: struct qscsoftc *sc;
! 331: dev_t dev;
! 332: int s;
! 333: u_int line;
! 334: int c, tries;
! 335:
! 336: if ((tp->t_state & TS_ISOPEN) == 0)
! 337: return;
! 338:
! 339: dev = tp->t_dev;
! 340: line = SC_LINE(dev);
! 341: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 342:
! 343: s = spltty();
! 344:
! 345: if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
! 346: goto bail;
! 347:
! 348: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 349: if (tp->t_state & TS_ASLEEP) {
! 350: tp->t_state &= ~TS_ASLEEP;
! 351: wakeup((caddr_t)&tp->t_outq);
! 352: }
! 353: selwakeup(&tp->t_wsel);
! 354: if (tp->t_outq.c_cc == 0)
! 355: goto bail;
! 356: }
! 357:
! 358: tp->t_state |= TS_BUSY;
! 359: while (tp->t_outq.c_cc != 0) {
! 360:
! 361: /* load transmitter until it is full */
! 362: for (tries = 10000; tries != 0; tries --)
! 363: if (qsc_read(sc, line, SC_SR) & TXRDY)
! 364: break;
! 365:
! 366: if (tries == 0) {
! 367: timeout_add(&tp->t_rstrt_to, 1);
! 368: tp->t_state |= TS_TIMEOUT;
! 369: break;
! 370: } else {
! 371: c = getc(&tp->t_outq);
! 372:
! 373: qsc_write(sc, line, SC_TXFIFO, c & 0xff);
! 374:
! 375: sc->sc_sv_reg->sv_imr[line >> 1] |=
! 376: line & 1 ? ITXRDYB : ITXRDYA;
! 377: qsc_write(sc, line, SC_IMR,
! 378: sc->sc_sv_reg->sv_imr[line >> 1]);
! 379: }
! 380: }
! 381: tp->t_state &= ~TS_BUSY;
! 382:
! 383: bail:
! 384: splx(s);
! 385: }
! 386:
! 387: int
! 388: qscstop(struct tty *tp, int flag)
! 389: {
! 390: int s;
! 391:
! 392: s = spltty();
! 393: if (tp->t_state & TS_BUSY) {
! 394: if ((tp->t_state & TS_TTSTOP) == 0)
! 395: tp->t_state |= TS_FLUSH;
! 396: }
! 397: splx(s);
! 398:
! 399: return 0;
! 400: }
! 401:
! 402: int
! 403: qscioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 404: {
! 405: int error;
! 406: u_int line;
! 407: struct tty *tp;
! 408: struct qscsoftc *sc;
! 409:
! 410: line = SC_LINE(dev);
! 411: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 412:
! 413: tp = sc->sc_tty[line];
! 414: if (tp == NULL)
! 415: return (ENXIO);
! 416:
! 417: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 418: if (error >= 0)
! 419: return(error);
! 420:
! 421: error = ttioctl(tp, cmd, data, flag, p);
! 422: if (error >= 0)
! 423: return(error);
! 424:
! 425: switch (cmd) {
! 426: case TIOCGFLAGS:
! 427: *(int *)data = sc->sc_swflags[line];
! 428: break;
! 429: case TIOCSFLAGS:
! 430: error = suser(p, 0);
! 431: if (error != 0)
! 432: return (EPERM);
! 433:
! 434: sc->sc_swflags[line] = *(int *)data &
! 435: /* only allow valid flags */
! 436: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
! 437: break;
! 438: default:
! 439: return (ENOTTY);
! 440: }
! 441:
! 442: return (0);
! 443: }
! 444:
! 445: int
! 446: qscparam(struct tty *tp, struct termios *t)
! 447: {
! 448: int flags;
! 449: u_int line, pair;
! 450: int speeds;
! 451: u_int8_t mr1, mr2;
! 452: struct qscsoftc *sc;
! 453: dev_t dev;
! 454:
! 455: dev = tp->t_dev;
! 456: line = SC_LINE(dev);
! 457: pair = line >> 1;
! 458: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 459:
! 460: tp->t_ispeed = t->c_ispeed;
! 461: tp->t_ospeed = t->c_ospeed;
! 462: tp->t_cflag = t->c_cflag;
! 463:
! 464: flags = tp->t_flags;
! 465:
! 466: /* disable Tx and Rx */
! 467: if (sc->sc_console == 0 || line != QSC_LINE_SERIAL) {
! 468: if (line & 1)
! 469: sc->sc_sv_reg->sv_imr[pair] &= ~(ITXRDYB | IRXRDYB);
! 470: else
! 471: sc->sc_sv_reg->sv_imr[pair] &= ~(ITXRDYA | IRXRDYA);
! 472: qsc_write(sc, line, SC_IMR, sc->sc_sv_reg->sv_imr[pair]);
! 473:
! 474: /* set baudrate */
! 475: speeds = qscspeed(tp->t_ispeed);
! 476: if (speeds == NOBAUD)
! 477: speeds = DEFBAUD;
! 478: qsc_write(sc, line, SC_CSR, speeds);
! 479: sc->sc_sv_reg->sv_csr[line] = speeds;
! 480:
! 481: /* get saved mode registers and clear set up parameters */
! 482: mr1 = sc->sc_sv_reg->sv_mr1[line];
! 483: mr1 &= ~(CLMASK | PARTYPEMASK | PARMODEMASK);
! 484:
! 485: mr2 = sc->sc_sv_reg->sv_mr2[line];
! 486: mr2 &= ~SBMASK;
! 487:
! 488: /* set up character size */
! 489: switch (t->c_cflag & CSIZE) {
! 490: case CL8:
! 491: mr1 |= CL8;
! 492: break;
! 493: case CL7:
! 494: mr1 |= CL7;
! 495: break;
! 496: case CL6:
! 497: mr1 |= CL6;
! 498: break;
! 499: case CL5:
! 500: mr1 |= CL5;
! 501: break;
! 502: }
! 503:
! 504: /* set up stop bits */
! 505: if (tp->t_ospeed == B110)
! 506: mr2 |= SB2;
! 507: else
! 508: mr2 |= SB1;
! 509:
! 510: /* set up parity */
! 511: if (t->c_cflag & PARENB) {
! 512: mr1 |= PAREN;
! 513: if (t->c_cflag & PARODD)
! 514: mr1 |= ODDPAR;
! 515: else
! 516: mr1 |= EVENPAR;
! 517: } else
! 518: mr1 |= PARDIS;
! 519:
! 520: if (sc->sc_sv_reg->sv_mr1[line] != mr1 ||
! 521: sc->sc_sv_reg->sv_mr2[line] != mr2) {
! 522: /* write mode registers to duart */
! 523: qsc_write(sc, line, SC_CR, MRONE);
! 524: DELAY(1);
! 525: qsc_write(sc, line, SC_MR, mr1);
! 526: qsc_write(sc, line, SC_MR, mr2);
! 527:
! 528: /* save changed mode registers */
! 529: sc->sc_sv_reg->sv_mr1[line] = mr1;
! 530: sc->sc_sv_reg->sv_mr2[line] = mr2;
! 531: }
! 532: }
! 533:
! 534: /* enable transmitter? */
! 535: if (tp->t_state & TS_BUSY) {
! 536: sc->sc_sv_reg->sv_imr[pair] |= line & 1 ? ITXRDYB : ITXRDYA;
! 537: }
! 538:
! 539: /* re-enable the receiver */
! 540: sc->sc_sv_reg->sv_imr[pair] |= line & 1 ? IRXRDYB : IRXRDYA;
! 541: qsc_write(sc, line, SC_IMR, sc->sc_sv_reg->sv_imr[pair]);
! 542:
! 543: return (0);
! 544: }
! 545:
! 546: int
! 547: qscopen(dev_t dev, int flag, int mode, struct proc *p)
! 548: {
! 549: int s;
! 550: u_int line;
! 551: struct qscsoftc *sc;
! 552: struct tty *tp;
! 553:
! 554: line = SC_LINE(dev);
! 555: if (qsc_cd.cd_ndevs == 0 || line >= SC_NLINES)
! 556: return (ENXIO);
! 557: /* Line B is not wired... */
! 558: if (line == QSC_LINE_DEAD)
! 559: return (ENXIO);
! 560: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 561: if (sc == NULL)
! 562: return (ENXIO);
! 563:
! 564: /* if some other device is using the line, it's not available */
! 565: if (sc->sc_hook[line].fn != NULL)
! 566: return (ENXIO);
! 567:
! 568: s = spltty();
! 569: if (sc->sc_tty[line] != NULL)
! 570: tp = sc->sc_tty[line];
! 571: else
! 572: tp = sc->sc_tty[line] = ttymalloc();
! 573:
! 574: tp->t_oproc = qscstart;
! 575: tp->t_param = qscparam;
! 576: tp->t_dev = dev;
! 577:
! 578: if ((tp->t_state & TS_ISOPEN) == 0) {
! 579: ttychars(tp);
! 580:
! 581: if (tp->t_ispeed == 0) {
! 582: tp->t_iflag = TTYDEF_IFLAG;
! 583: tp->t_oflag = TTYDEF_OFLAG;
! 584: tp->t_lflag = TTYDEF_LFLAG;
! 585: tp->t_ispeed = tp->t_ospeed = B9600;
! 586: if (sc->sc_console && line == QSC_LINE_SERIAL) {
! 587: /* console is 8N1 */
! 588: tp->t_cflag = (CREAD | CS8 | HUPCL);
! 589: } else {
! 590: tp->t_cflag = TTYDEF_CFLAG;
! 591: }
! 592: }
! 593:
! 594: if (sc->sc_swflags[line] & TIOCFLAG_CLOCAL)
! 595: tp->t_cflag |= CLOCAL;
! 596: if (sc->sc_swflags[line] & TIOCFLAG_CRTSCTS)
! 597: tp->t_cflag |= CRTSCTS;
! 598: if (sc->sc_swflags[line] & TIOCFLAG_MDMBUF)
! 599: tp->t_cflag |= MDMBUF;
! 600:
! 601: qscparam(tp, &tp->t_termios);
! 602: ttsetwater(tp);
! 603:
! 604: tp->t_state |= TS_CARR_ON;
! 605: } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
! 606: splx(s);
! 607: return (EBUSY);
! 608: }
! 609:
! 610: /*
! 611: * Reset the tty pointer, as there could have been a dialout
! 612: * use of the tty with a dialin open waiting.
! 613: */
! 614: tp->t_dev = dev;
! 615: splx(s);
! 616: return ((*linesw[tp->t_line].l_open)(dev, tp));
! 617: }
! 618:
! 619: int
! 620: qscclose(dev_t dev, int flag, int mode, struct proc *p)
! 621: {
! 622: struct tty *tp;
! 623: struct qscsoftc *sc;
! 624: u_int line;
! 625:
! 626: line = SC_LINE(dev);
! 627: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 628:
! 629: tp = sc->sc_tty[line];
! 630: (*linesw[tp->t_line].l_close)(tp, flag);
! 631: ttyclose(tp);
! 632:
! 633: return (0);
! 634: }
! 635:
! 636: int
! 637: qscread(dev_t dev, struct uio *uio, int flag)
! 638: {
! 639: u_int line;
! 640: struct tty *tp;
! 641: struct qscsoftc *sc;
! 642:
! 643: line = SC_LINE(dev);
! 644: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 645:
! 646: tp = sc->sc_tty[line];
! 647: if (tp == NULL)
! 648: return (ENXIO);
! 649: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 650: }
! 651:
! 652: int
! 653: qscwrite(dev_t dev, struct uio *uio, int flag)
! 654: {
! 655: u_int line;
! 656: struct tty *tp;
! 657: struct qscsoftc *sc;
! 658:
! 659: line = SC_LINE(dev);
! 660: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
! 661:
! 662: tp = sc->sc_tty[line];
! 663: if (tp == NULL)
! 664: return (ENXIO);
! 665: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 666: }
! 667:
! 668: void
! 669: qscrint(struct qscsoftc *sc, u_int line)
! 670: {
! 671: struct tty *tp;
! 672: int data;
! 673: unsigned char sr;
! 674: int overrun = 0;
! 675:
! 676: tp = sc->sc_tty[line];
! 677:
! 678: /* read status reg */
! 679: while ((sr = qsc_read(sc, line, SC_SR)) & RXRDY) {
! 680: /* read data and reset receiver */
! 681: data = qsc_read(sc, line, SC_RXFIFO);
! 682:
! 683: if (sr & RBRK) {
! 684: /* clear break state */
! 685: qsc_write(sc, line, SC_CR, BRKINTRESET);
! 686: DELAY(1);
! 687: qsc_write(sc, line, SC_CR, ERRRESET);
! 688: DELAY(1);
! 689: continue;
! 690: }
! 691:
! 692: if ((sr & ROVRN) && cold == 0 && overrun == 0) {
! 693: log(LOG_WARNING, "%s line %d: receiver overrun\n",
! 694: sc->sc_dev.dv_xname, line);
! 695: overrun = 1;
! 696: }
! 697:
! 698: if (sr & FRERR)
! 699: data |= TTY_FE;
! 700: if (sr & PERR)
! 701: data |= TTY_PE;
! 702:
! 703: /* clear error state */
! 704: if (sr & (ROVRN | FRERR | PERR)) {
! 705: qsc_write(sc, line, SC_CR, ERRRESET);
! 706: DELAY(1);
! 707: }
! 708:
! 709: if (sc->sc_hook[line].fn != NULL) {
! 710: if ((data & TTY_ERRORMASK) != 0 ||
! 711: (*sc->sc_hook[line].fn)(sc->sc_hook[line].arg, data))
! 712: continue;
! 713: }
! 714:
! 715: if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0 &&
! 716: (sc->sc_console == 0 || line != QSC_LINE_SERIAL)) {
! 717: continue;
! 718: }
! 719:
! 720: /* no errors */
! 721: #if defined(DDB)
! 722: if (tp->t_dev == cn_tab->cn_dev) {
! 723: int j = kdbrint(data);
! 724:
! 725: if (j == 1)
! 726: continue;
! 727:
! 728: if (j == 2)
! 729: (*linesw[tp->t_line].l_rint)(27, tp);
! 730: }
! 731: #endif
! 732: (*linesw[tp->t_line].l_rint)(data, tp);
! 733: }
! 734: }
! 735:
! 736: void
! 737: qscxint(struct qscsoftc *sc, u_int line)
! 738: {
! 739: struct tty *tp;
! 740: u_int pair;
! 741:
! 742: tp = sc->sc_tty[line];
! 743:
! 744: if ((tp->t_state & (TS_ISOPEN|TS_WOPEN))==0)
! 745: goto out;
! 746:
! 747: if (tp->t_state & TS_BUSY) {
! 748: tp->t_state &= ~(TS_BUSY | TS_FLUSH);
! 749: qscstart(tp);
! 750: if (tp->t_state & TS_BUSY) {
! 751: /* do not disable transmitter, yet */
! 752: return;
! 753: }
! 754: }
! 755: out:
! 756:
! 757: /* disable transmitter */
! 758: pair = line >> 1;
! 759: sc->sc_sv_reg->sv_imr[pair] &= line & 1 ? ~ITXRDYB : ~ITXRDYA;
! 760: qsc_write(sc, line, SC_IMR, sc->sc_sv_reg->sv_imr[pair]);
! 761: }
! 762:
! 763: int
! 764: qscintr(void *arg)
! 765: {
! 766: struct qscsoftc *sc = arg;
! 767: u_int8_t isr[SC_NLINES >> 1], curisr;
! 768: u_int pair, line;
! 769: int rc = 0;
! 770:
! 771: for (pair = 0; pair < SC_NLINES >> 1; pair++) {
! 772: line = pair << 1;
! 773:
! 774: /* read interrupt status register and mask with imr */
! 775: isr[pair] = curisr = qsc_read(sc, line, SC_ISR);
! 776: curisr &= sc->sc_sv_reg->sv_imr[pair];
! 777: if (curisr == 0)
! 778: continue;
! 779:
! 780: rc = 1;
! 781:
! 782: if (curisr & IRXRDYA)
! 783: qscrint(sc, line);
! 784: if (curisr & ITXRDYA)
! 785: qscxint(sc, line);
! 786: if (curisr & IBRKA) {
! 787: qsc_write(sc, line, SC_CR, BRKINTRESET);
! 788: DELAY(1);
! 789: }
! 790:
! 791: if (curisr & IRXRDYB)
! 792: qscrint(sc, line + 1);
! 793: if (curisr & ITXRDYB)
! 794: qscxint(sc, line + 1);
! 795: if (curisr & IBRKB) {
! 796: qsc_write(sc, line + 1, SC_CR, BRKINTRESET);
! 797: DELAY(1);
! 798: }
! 799: }
! 800:
! 801: return (rc);
! 802: }
! 803:
! 804: /*
! 805: * Console interface routines.
! 806: */
! 807:
! 808: vaddr_t qsc_cnregs;
! 809: #define qsc_cnread(reg) \
! 810: *(volatile u_int8_t *)(qsc_cnregs + 4 * (reg))
! 811: #define qsc_cnwrite(reg, val) \
! 812: *(volatile u_int8_t *)(qsc_cnregs + 4 * (reg)) = (val)
! 813:
! 814: void
! 815: qsccnprobe(struct consdev *cp)
! 816: {
! 817: int maj;
! 818: extern int getmajor(void *);
! 819: extern vaddr_t iospace;
! 820:
! 821: if (vax_boardtype != VAX_BTYP_VXT)
! 822: return;
! 823:
! 824: /* locate the major number */
! 825: if ((maj = getmajor(qscopen)) < 0)
! 826: return;
! 827:
! 828: qsc_cnregs = iospace;
! 829: ioaccess(iospace, QSCADDR, 1);
! 830:
! 831: cp->cn_dev = makedev(maj, QSC_LINE_SERIAL);
! 832: cp->cn_pri = vax_confdata & 2 ? CN_NORMAL : CN_REMOTE;
! 833: }
! 834:
! 835: void
! 836: qsccninit(cp)
! 837: struct consdev *cp;
! 838: {
! 839: qsccn_sv.sv_mr1[QSC_LINE_SERIAL] = PARDIS | RXRTS | CL8;
! 840: qsccn_sv.sv_mr2[QSC_LINE_SERIAL] = /* TXCTS | */ SB1;
! 841: qsccn_sv.sv_csr[QSC_LINE_SERIAL] = BD9600;
! 842: qsccn_sv.sv_cr[QSC_LINE_SERIAL] = TXEN | RXEN;
! 843: qsccn_sv.sv_imr[QSC_LINE_SERIAL] = 0;
! 844:
! 845: qsc_cnwrite(SC_CRA, RXRESET | TXDIS | RXDIS);
! 846: DELAY(1);
! 847: qsc_cnwrite(SC_CRA, TXRESET | TXDIS | RXDIS);
! 848: DELAY(1);
! 849: qsc_cnwrite(SC_CRA, ERRRESET | TXDIS | RXDIS);
! 850: DELAY(1);
! 851: qsc_cnwrite(SC_CRA, BRKINTRESET | TXDIS | RXDIS);
! 852: DELAY(1);
! 853: qsc_cnwrite(SC_CRA, MRZERO | TXDIS | RXDIS);
! 854: DELAY(1);
! 855:
! 856: qsc_cnwrite(SC_MRA, 0);
! 857: qsc_cnwrite(SC_MRA, qsccn_sv.sv_mr1[QSC_LINE_SERIAL]);
! 858: qsc_cnwrite(SC_MRA, qsccn_sv.sv_mr2[QSC_LINE_SERIAL]);
! 859: qsc_cnwrite(SC_CSRA, qsccn_sv.sv_csr[QSC_LINE_SERIAL]);
! 860: qsc_cnwrite(SC_CRA, qsccn_sv.sv_cr[QSC_LINE_SERIAL]);
! 861: DELAY(1);
! 862:
! 863: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL]);
! 864: qsc_cnwrite(SC_IMRCD, 0);
! 865: }
! 866:
! 867: int
! 868: qsccngetc(dev_t dev)
! 869: {
! 870: unsigned char sr; /* status reg of line a/b */
! 871: u_char c; /* received character */
! 872: int s;
! 873:
! 874: s = spltty();
! 875:
! 876: /* disable interrupts for this line and enable receiver */
! 877: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL] & ~ITXRDYA);
! 878: qsc_cnwrite(SC_CRA, RXEN);
! 879: DELAY(1);
! 880:
! 881: for (;;) {
! 882: /* read status reg */
! 883: sr = qsc_cnread(SC_SRA);
! 884:
! 885: /* receiver interrupt handler*/
! 886: if (sr & RXRDY) {
! 887: /* read character from line */
! 888: c = qsc_cnread(SC_RXFIFOA);
! 889:
! 890: /* check break condition */
! 891: if (sr & RBRK) {
! 892: /* clear break state */
! 893: qsc_cnwrite(SC_CRA, BRKINTRESET);
! 894: DELAY(1);
! 895: qsc_cnwrite(SC_CRA, ERRRESET);
! 896: DELAY(1);
! 897: break;
! 898: }
! 899:
! 900: if (sr & (FRERR | PERR | ROVRN)) {
! 901: /* clear error state */
! 902: qsc_cnwrite(SC_CRA, ERRRESET);
! 903: DELAY(1);
! 904: } else {
! 905: break;
! 906: }
! 907: }
! 908: }
! 909:
! 910: /* restore the previous state */
! 911: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL]);
! 912: qsc_cnwrite(SC_CRA, qsccn_sv.sv_cr[QSC_LINE_SERIAL]);
! 913:
! 914: splx(s);
! 915:
! 916: return ((int)c);
! 917: }
! 918:
! 919: void
! 920: qsccnputc(dev_t dev, int c)
! 921: {
! 922: int s;
! 923:
! 924: if (mfpr(PR_MAPEN) == 0)
! 925: return;
! 926:
! 927: s = spltty();
! 928:
! 929: /* disable interrupts for this line and enable transmitter */
! 930: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL] & ~ITXRDYA);
! 931: qsc_cnwrite(SC_CRA, TXEN);
! 932: DELAY(1);
! 933:
! 934: while ((qsc_cnread(SC_SRA) & TXRDY) == 0)
! 935: ;
! 936: qsc_cnwrite(SC_TXFIFOA, c);
! 937:
! 938: /* wait for transmitter to empty */
! 939: while ((qsc_cnread(SC_SRA) & TXEMT) == 0)
! 940: ;
! 941:
! 942: /* restore the previous state */
! 943: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL]);
! 944: qsc_cnwrite(SC_CRA, qsccn_sv.sv_cr[QSC_LINE_SERIAL]);
! 945: DELAY(1);
! 946:
! 947: splx(s);
! 948: }
! 949:
! 950: void
! 951: qsccnpollc(dev, pollflag)
! 952: dev_t dev;
! 953: int pollflag;
! 954: {
! 955: }
! 956:
! 957: /*
! 958: * Keyboard and mouse helper routines
! 959: */
! 960:
! 961: #if NQSCKBD > 0 || NQSCMS > 0
! 962: int
! 963: qsc_print(void *aux, const char *name)
! 964: {
! 965: struct qsc_attach_args *qa = aux;
! 966:
! 967: if (name != NULL)
! 968: printf(qa->qa_line == QSC_LINE_KEYBOARD ?
! 969: "lkkbd at %s" : "lkms at %s", name);
! 970: else
! 971: printf(" line %d", qa->qa_line);
! 972:
! 973: return (UNCONF);
! 974: }
! 975:
! 976: int
! 977: qscgetc(u_int line)
! 978: {
! 979: bus_addr_t craddr;
! 980: struct qscsoftc *sc = NULL;
! 981: int s;
! 982: u_int8_t sr, imr, imrmask, cr, c;
! 983:
! 984: s = spltty();
! 985:
! 986: craddr = line == QSC_LINE_KEYBOARD ? SC_CRC : SC_CRD;
! 987: imrmask = line & 1 ? ~IRXRDYB : ~IRXRDYA;
! 988: imr = sc != NULL ? sc->sc_sv_reg->sv_imr[line / 2] : 0;
! 989: cr = sc != NULL ? sc->sc_sv_reg->sv_cr[line] : 0;
! 990:
! 991: /* disable interrupts for this line and enable receiver */
! 992: qsc_cnwrite(SC_IMRCD, imr & imrmask);
! 993: qsc_cnwrite(craddr, RXEN);
! 994: DELAY(1);
! 995:
! 996: for (;;) {
! 997: /* read status reg */
! 998: sr = qsc_cnread(line == QSC_LINE_KEYBOARD ? SC_SRC : SC_SRD);
! 999:
! 1000: /* receiver interrupt handler*/
! 1001: if (sr & RXRDY) {
! 1002: /* read character from line */
! 1003: c = qsc_cnread(line == QSC_LINE_KEYBOARD ?
! 1004: SC_RXFIFOC : SC_RXFIFOD);
! 1005:
! 1006: /* check break condition */
! 1007: if (sr & RBRK) {
! 1008: /* clear break state */
! 1009: qsc_cnwrite(craddr, BRKINTRESET);
! 1010: DELAY(1);
! 1011: qsc_cnwrite(craddr, ERRRESET);
! 1012: DELAY(1);
! 1013: break;
! 1014: }
! 1015:
! 1016: if (sr & (FRERR | PERR | ROVRN)) {
! 1017: /* clear error state */
! 1018: qsc_cnwrite(craddr, ERRRESET);
! 1019: DELAY(1);
! 1020: } else {
! 1021: break;
! 1022: }
! 1023: }
! 1024: }
! 1025:
! 1026: /* restore the previous state */
! 1027: qsc_cnwrite(SC_IMRCD, imr);
! 1028: qsc_cnwrite(craddr, cr);
! 1029: DELAY(1);
! 1030:
! 1031: splx(s);
! 1032:
! 1033: return ((int)c);
! 1034: }
! 1035:
! 1036: void
! 1037: qscputc(u_int line, int c)
! 1038: {
! 1039: bus_addr_t craddr;
! 1040: struct qscsoftc *sc = NULL;
! 1041: int s;
! 1042: u_int8_t imr, imrmask, cr;
! 1043:
! 1044: s = spltty();
! 1045:
! 1046: if (qsc_cd.cd_ndevs != 0 &&
! 1047: (sc = (struct qscsoftc *)qsc_cd.cd_devs[0]) != NULL)
! 1048: if (sc->sc_rdy == 0)
! 1049: sc = NULL;
! 1050:
! 1051: craddr = line == QSC_LINE_KEYBOARD ? SC_CRC : SC_CRD;
! 1052: imrmask = line & 1 ? ~ITXRDYB : ~ITXRDYA;
! 1053: imr = sc != NULL ? sc->sc_sv_reg->sv_imr[line / 2] : 0;
! 1054: cr = sc != NULL ? sc->sc_sv_reg->sv_cr[line] : 0;
! 1055:
! 1056: /* disable interrupts for this line and enable transmitter */
! 1057: qsc_cnwrite(SC_IMRCD, imr & imrmask);
! 1058: qsc_cnwrite(craddr, TXEN);
! 1059: DELAY(1);
! 1060:
! 1061: while ((qsc_cnread(line == QSC_LINE_KEYBOARD ? SC_SRC : SC_SRD) &
! 1062: TXRDY) == 0)
! 1063: ;
! 1064: qsc_cnwrite(line == QSC_LINE_KEYBOARD ? SC_TXFIFOC : SC_TXFIFOD, c);
! 1065:
! 1066: /* wait for transmitter to empty */
! 1067: while ((qsc_cnread(line == QSC_LINE_KEYBOARD ? SC_SRC : SC_SRD) &
! 1068: TXEMT) == 0)
! 1069: ;
! 1070:
! 1071: /* restore the previous state */
! 1072: qsc_cnwrite(SC_IMRCD, imr);
! 1073: qsc_cnwrite(craddr, cr);
! 1074: DELAY(1);
! 1075:
! 1076: splx(s);
! 1077: }
! 1078: #endif
CVSweb