1 /* $NetBSD: qvaux.c,v 1.3 2021/04/24 23:36:50 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles H. Dickman 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1992, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Ralph Campbell and Rick Macklem. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 /* 65 * Copyright (c) 1996 Ken C. Wellsch. All rights reserved. 66 * 67 * This code is derived from software contributed to Berkeley by 68 * Ralph Campbell and Rick Macklem. 69 * 70 * Redistribution and use in source and binary forms, with or without 71 * modification, are permitted provided that the following conditions 72 * are met: 73 * 1. Redistributions of source code must retain the above copyright 74 * notice, this list of conditions and the following disclaimer. 75 * 2. Redistributions in binary form must reproduce the above copyright 76 * notice, this list of conditions and the following disclaimer in the 77 * documentation and/or other materials provided with the distribution. 78 * 3. All advertising materials mentioning features or use of this software 79 * must display the following acknowledgement: 80 * This product includes software developed by the University of 81 * California, Berkeley and its contributors. 82 * 4. Neither the name of the University nor the names of its contributors 83 * may be used to endorse or promote products derived from this software 84 * without specific prior written permission. 85 * 86 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 87 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 88 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 89 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 90 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 91 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 92 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 93 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 94 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 95 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 96 * SUCH DAMAGE. 97 */ 98 99 #include <sys/cdefs.h> 100 __KERNEL_RCSID(0, "$$"); 101 102 #include <sys/param.h> 103 #include <sys/systm.h> 104 #include <sys/callout.h> 105 #include <sys/ioctl.h> 106 #include <sys/tty.h> 107 #include <sys/proc.h> 108 #include <sys/buf.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/device.h> 115 #include <sys/kauth.h> 116 117 #include <sys/bus.h> 118 #include <dev/qbus/ubavar.h> 119 120 #include <vax/uba/qvareg.h> 121 #include <vax/uba/qvavar.h> 122 #include <vax/uba/qvkbdvar.h> 123 124 #include <dev/cons.h> 125 #include "qv.h" 126 #include "qvkbd.h" 127 #include "qvms.h" 128 #include "qv_ic.h" 129 130 #define QVAUX_DELAY(x) /* nothing */ 131 #define control inline 132 133 static control uint 134 qvaux_read1(struct qvaux_softc *sc, u_int off) 135 { 136 u_int rv; 137 138 rv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off); 139 QVAUX_DELAY(1); 140 return rv; 141 } 142 143 static control u_int 144 qvaux_read2(struct qvaux_softc *sc, u_int off) 145 { 146 u_int rv; 147 148 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, off); 149 QVAUX_DELAY(1); 150 return rv; 151 } 152 153 static control void 154 qvaux_write1(struct qvaux_softc *sc, u_int off, u_int val) 155 { 156 157 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, val); 158 bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_qr.qr_firstreg, 159 sc->sc_qr.qr_winsize, BUS_SPACE_BARRIER_WRITE | 160 BUS_SPACE_BARRIER_READ); 161 QVAUX_DELAY(10); 162 } 163 164 static control void 165 qvaux_write2(struct qvaux_softc *sc, u_int off, u_int val) 166 { 167 168 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, val); 169 bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_qr.qr_firstreg, 170 sc->sc_qr.qr_winsize, BUS_SPACE_BARRIER_WRITE | 171 BUS_SPACE_BARRIER_READ); 172 QVAUX_DELAY(10); 173 } 174 175 #include "ioconf.h" 176 177 /* Flags used to monitor modem bits, make them understood outside driver */ 178 179 #define DML_DTR TIOCM_DTR 180 #define DML_DCD TIOCM_CD 181 #define DML_RI TIOCM_RI 182 #define DML_BRK 0100000 /* no equivalent, we will mask */ 183 184 static const struct speedtab qvauxspeedtab[] = 185 { 186 { 0, 0 }, 187 { 75, CSR_B75 }, 188 { 110, CSR_B110 }, 189 { 134, CSR_B134 }, 190 { 150, CSR_B150 }, 191 { 300, CSR_B300 }, 192 { 600, CSR_B600 }, 193 { 1200, CSR_B1200 }, 194 { 2000, CSR_B2000 }, 195 { 2400, CSR_B2400 }, 196 { 4800, CSR_B4800 }, 197 { 7200, CSR_B7200 }, 198 { 9600, CSR_B9600 }, 199 { 19200, CSR_B19200 }, 200 { -1, -1 } 201 }; 202 203 int qvaux_match(device_t, cfdata_t, void *); 204 static void qvaux_attach(device_t , device_t , void *); 205 static void qvauxstart(struct tty *); 206 static int qvauxparam(struct tty *, struct termios *); 207 static unsigned qvauxmctl(struct qvaux_softc *, int, int, int); 208 //static void qvauxscan(void *); 209 int qvauxgetc(struct qvaux_linestate *); 210 void qvauxputc(struct qvaux_linestate *, int); 211 212 static dev_type_open(qvauxopen); 213 static dev_type_close(qvauxclose); 214 static dev_type_read(qvauxread); 215 static dev_type_write(qvauxwrite); 216 static dev_type_ioctl(qvauxioctl); 217 static dev_type_stop(qvauxstop); 218 static dev_type_tty(qvauxtty); 219 static dev_type_poll(qvauxpoll); 220 221 const struct cdevsw qvaux_cdevsw = { 222 qvauxopen, qvauxclose, qvauxread, qvauxwrite, qvauxioctl, 223 qvauxstop, qvauxtty, qvauxpoll, nommap, ttykqfilter, nodiscard, D_TTY 224 }; 225 226 int qvaux_timer; /* true if timer started */ 227 struct callout qvauxscan_ch; 228 static struct cnm_state qvaux_cnm_state; 229 230 CFATTACH_DECL_NEW(qvaux, sizeof(struct qvaux_softc), 231 qvaux_match, qvaux_attach, NULL, NULL); 232 233 #if NQVKBD > 0 || NQVMS > 0 234 static int 235 qvaux_print(void *aux, const char *name) 236 { 237 struct qvauxkm_attach_args *daa = aux; 238 if (name == NULL) { 239 aprint_normal(" line %d", daa->daa_line); 240 } 241 242 return QUIET; 243 } 244 #endif 245 246 int 247 qvaux_match(device_t parent, cfdata_t match, void *aux) 248 { 249 /* always match since we are physically part of parent */ 250 return 1; 251 } 252 253 /*ARGSUSED*/ 254 static void 255 qvaux_attach(device_t parent, device_t self, void *aux) 256 { 257 struct qvaux_softc *sc = device_private(self); 258 struct uba_attach_args *ua = aux; 259 #if NQVKBD > 0 || NQVMS > 0 260 struct qvauxkm_attach_args daa; 261 #endif 262 263 /* set floating DUART vector and enable interrupts */ 264 qv_ic_setvec(ua, QVA_QVIC, QV_DUART_VEC, ua->ua_cvec); 265 qv_ic_arm(ua, QVA_QVIC, QV_IC_ENA); 266 bus_space_write_2(ua->ua_iot, ua->ua_ioh, QVA_QVCSR, 267 bus_space_read_2(ua->ua_iot, ua->ua_ioh, QVA_QVCSR) | (1 << 6)); 268 269 sc->sc_dev = self; 270 sc->sc_iot = ua->ua_iot; 271 sc->sc_ioh = ua->ua_ioh; 272 273 /* device register access structure */ 274 sc->sc_qr.qr_ipcr = DU_IPCR; 275 sc->sc_qr.qr_acr = DU_ACR; 276 sc->sc_qr.qr_isr = DU_ISR; 277 sc->sc_qr. qr_imr = DU_IMR; 278 sc->sc_qr.qr_ctur = DU_CTUR; 279 sc->sc_qr.qr_ctlr = DU_CTLR; 280 sc->sc_qr.qr_ip = DU_IP; 281 sc->sc_qr.qr_opcr = DU_OPCR; 282 sc->sc_qr.qr_cstrt = DU_IMR; 283 sc->sc_qr.qr_opset = DU_OPSET; 284 sc->sc_qr.qr_cstop = DU_CSTOP; 285 sc->sc_qr.qr_opclr = DU_OPCLR; 286 sc->sc_qr.qr_ch_regs[0].qr_mr = CH_MR(0); 287 sc->sc_qr.qr_ch_regs[0].qr_sr = CH_SR(0); 288 sc->sc_qr.qr_ch_regs[0].qr_csr = CH_CSR(0); 289 sc->sc_qr.qr_ch_regs[0].qr_cr = CH_CR(0); 290 sc->sc_qr.qr_ch_regs[0].qr_dat = CH_DAT(0); 291 sc->sc_qr.qr_ch_regs[1].qr_mr = CH_MR(1); 292 sc->sc_qr.qr_ch_regs[1].qr_sr = CH_SR(1); 293 sc->sc_qr.qr_ch_regs[1].qr_csr = CH_CSR(1); 294 sc->sc_qr.qr_ch_regs[1].qr_cr = CH_CR(1); 295 sc->sc_qr.qr_ch_regs[1].qr_dat = CH_DAT(1); 296 297 sc->sc_qr.qr_firstreg = QVA_FIRSTREG; 298 sc->sc_qr.qr_winsize = QVA_WINSIZE; 299 300 /* register DUART interrupt handler */ 301 uba_intr_establish(ua->ua_icookie, ua->ua_cvec, 302 qvauxint, sc, &sc->sc_tintrcnt); 303 qv_ic_enable(ua, QVA_QVIC, QV_DUART_VEC, QV_IC_ENA); 304 305 qvauxattach(sc, ua->ua_evcnt, -1); 306 307 #if NQVKBD > 0 308 /* XXX set line parameters */ 309 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_csr, 310 (CSR_B4800 << 4) | CSR_B4800); 311 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_cr, CR_CMD_MR1 | CR_ENA_RX); 312 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_mr, MR1_CS8 | MR1_PNONE); 313 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_mr, MR2_STOP1); 314 315 daa.daa_line = 0; 316 daa.daa_flags = 0; 317 config_found(self, &daa, qvaux_print, CFARG_EOL); 318 #endif 319 #if NQVMS > 0 320 /* XXX set line parameters */ 321 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_csr, 322 (CSR_B4800 << 4) | CSR_B4800); 323 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_cr, CR_CMD_MR1 | CR_ENA_RX); 324 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_mr, MR1_CS8 | MR1_PODD); 325 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_mr, MR2_STOP1); 326 327 daa.daa_line = 1; 328 daa.daa_flags = 0; 329 config_found(self, &daa, qvaux_print, CFARG_EOL); 330 #endif 331 332 } 333 334 void 335 qvauxattach(struct qvaux_softc *sc, struct evcnt *parent_evcnt, int consline) 336 { 337 int n; 338 dev_t dev; 339 340 /* Initialize our softc structure. */ 341 for (n = 0; n < NQVAUXLINE; n++) { 342 sc->sc_qvaux[n].qvaux_sc = sc; 343 sc->sc_qvaux[n].qvaux_line = n; 344 sc->sc_qvaux[n].qvaux_tty = tty_alloc(); 345 dev = sc->sc_qvaux[n].qvaux_tty->t_dev; 346 sc->sc_qvaux[n].qvaux_tty->t_dev = makedev(major(dev),n); 347 } 348 349 evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, parent_evcnt, 350 device_xname(sc->sc_dev), "rintr"); 351 evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, parent_evcnt, 352 device_xname(sc->sc_dev), "tintr"); 353 354 /* Console magic keys */ 355 cn_init_magic(&qvaux_cnm_state); 356 cn_set_magic("\047\001"); /* default magic is BREAK */ 357 /* VAX will change it in MD code */ 358 359 sc->sc_rxint = sc->sc_brk = 0; 360 sc->sc_consline = consline; 361 362 sc->sc_imr = INT_RXA | INT_RXB; 363 qvaux_write2(sc, sc->sc_qr.qr_imr, sc->sc_imr); 364 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_cr, CR_ENA_TX | CR_ENA_RX); 365 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_cr, CR_ENA_TX | CR_ENA_RX); 366 367 DELAY(10000); 368 369 printf("\n"); 370 } 371 372 /* DUART Interrupt entry */ 373 374 void 375 qvauxint(void *arg) 376 { 377 struct qvaux_softc *sc = arg; 378 int isr; 379 380 isr = qvaux_read2(sc, sc->sc_qr.qr_isr); 381 382 if (isr & (INT_RXA | INT_RXB | INT_BRKA | INT_BRKB)) 383 qvauxrint(arg); 384 385 isr = qvaux_read2(sc, sc->sc_qr.qr_isr); 386 387 if (isr & (INT_TXA | INT_TXB) & sc->sc_imr) 388 qvauxxint(arg); 389 } 390 391 /* Receiver Interrupt */ 392 393 void 394 qvauxrint(void *arg) 395 { 396 struct qvaux_softc *sc = arg; 397 struct tty *tp; 398 int cc, mcc, line; 399 unsigned stat[2]; 400 int overrun = 0; 401 402 //printf(" qvauxrint "); 403 404 sc->sc_rxint++; 405 406 // determine source and loop until all are no longer active 407 for (;;) { 408 stat[0] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[0].qr_sr); 409 stat[1] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[1].qr_sr); 410 if ((stat[0] & SR_RX_RDY) == 0) { 411 if ((stat[1] & SR_RX_RDY) == 0) 412 break; 413 else 414 line = 1; 415 } 416 else 417 line = 0; 418 cc = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[line].qr_dat) & 0xFF; 419 tp = sc->sc_qvaux[line].qvaux_tty; 420 421 /* Must be caught early */ 422 if (sc->sc_qvaux[line].qvaux_catch && 423 (*sc->sc_qvaux[line].qvaux_catch)(sc->sc_qvaux[line] 424 .qvaux_private, cc)) { 425 continue; 426 } 427 428 if (stat[line] & SR_BREAK) // do SR error bits need to be 429 // cleared by an error reset? 430 mcc = CNC_BREAK; 431 else 432 mcc = cc; 433 434 cn_check_magic(tp->t_dev, mcc, qvaux_cnm_state); 435 436 if (!(tp->t_state & TS_ISOPEN)) { 437 cv_broadcast(&tp->t_rawcv); 438 continue; 439 } 440 441 if ((stat[line] & SR_OVERRUN) && overrun == 0) { // ? 442 log(LOG_WARNING, "%s: silo overflow, line %d\n", 443 device_xname(sc->sc_dev), line); 444 overrun = 1; 445 } 446 447 if (stat[line] & SR_FRAME) // ? 448 cc |= TTY_FE; 449 if (stat[line] & SR_PARITY) // ? 450 cc |= TTY_PE; 451 452 (*tp->t_linesw->l_rint)(cc, tp); 453 } 454 } 455 456 /* Transmitter Interrupt */ 457 458 void 459 qvauxxint(void *arg) 460 { 461 struct qvaux_softc *sc = arg; 462 struct tty *tp; 463 struct clist *cl; 464 int line, ch, stat[2]; 465 466 for (;;) { 467 stat[0] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[0].qr_sr); 468 stat[1] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[1].qr_sr); 469 if (((stat[0] & SR_TX_RDY) == 0) 470 || ((sc->sc_imr & INT_TXA) == 0)) { 471 if (((stat[1] & SR_TX_RDY) == 0) 472 || ((sc->sc_imr & INT_TXB) == 0)) 473 break; 474 else 475 line = 1; 476 } 477 else 478 line = 0; 479 tp = sc->sc_qvaux[line].qvaux_tty; 480 cl = &tp->t_outq; 481 tp->t_state &= ~TS_BUSY; 482 483 /* Just send out a char if we have one */ 484 /* As long as we can fill the chip buffer, we just loop here */ 485 // no fifo, just holding register 486 if (cl->c_cc) { 487 tp->t_state |= TS_BUSY; 488 ch = getc(cl); 489 qvaux_write1(sc, sc->sc_qr.qr_ch_regs[line].qr_dat, ch); 490 continue; 491 } 492 /* Nothing to send, clear the tx flags */ 493 sc->sc_imr &= ~((line) ? (INT_TXB) : (INT_TXA)); 494 qvaux_write2(sc, sc->sc_qr.qr_imr, sc->sc_imr); 495 496 if (sc->sc_qvaux[line].qvaux_catch) 497 continue; 498 499 if (tp->t_state & TS_FLUSH) 500 tp->t_state &= ~TS_FLUSH; 501 else 502 ndflush (&tp->t_outq, cl->c_cc); 503 504 (*tp->t_linesw->l_start)(tp); 505 } 506 } 507 508 int 509 qvauxopen(dev_t dev, int flag, int mode, struct lwp *l) 510 { 511 const int line = QVA_PORT(minor(dev)); 512 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 513 QVA_I2C(minor(dev))); // only one controller 514 struct tty *tp; 515 int error = 0; 516 517 if (sc == NULL || line >= NQVAUXLINE) 518 return ENXIO; 519 520 /* if some other device is using the line, it's busy */ 521 if (sc->sc_qvaux[line].qvaux_catch) 522 return EBUSY; 523 524 tp = sc->sc_qvaux[line].qvaux_tty; 525 if (tp == NULL) 526 return (ENODEV); 527 528 tp->t_oproc = qvauxstart; 529 tp->t_param = qvauxparam; 530 tp->t_dev = dev; 531 532 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 533 return (EBUSY); 534 535 if ((tp->t_state & TS_ISOPEN) == 0) { 536 ttychars(tp); 537 if (tp->t_ispeed == 0) { 538 tp->t_iflag = TTYDEF_IFLAG; 539 tp->t_oflag = TTYDEF_OFLAG; 540 tp->t_cflag = TTYDEF_CFLAG; 541 tp->t_lflag = TTYDEF_LFLAG; 542 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 543 } 544 (void) qvauxparam(tp, &tp->t_termios); 545 ttsetwater(tp); 546 } 547 548 /* Use DMBIS and *not* DMSET or else we clobber incoming bits */ 549 if (qvauxmctl(sc, line, DML_DTR, DMBIS) & DML_DCD) 550 tp->t_state |= TS_CARR_ON; 551 mutex_spin_enter(&tty_lock); 552 while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) && 553 !(tp->t_state & TS_CARR_ON)) { 554 tp->t_wopen++; 555 error = ttysleep(tp, &tp->t_rawcv, true, 0); 556 tp->t_wopen--; 557 if (error) 558 break; 559 } 560 mutex_spin_exit(&tty_lock); 561 if (error) 562 return (error); 563 return ((*tp->t_linesw->l_open)(dev, tp)); 564 } 565 566 /*ARGSUSED*/ 567 int 568 qvauxclose(dev_t dev, int flag, int mode, struct lwp *l) 569 { 570 const int line = QVA_PORT(minor(dev)); 571 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 572 QVA_I2C(minor(dev))); // only one controller 573 struct tty *tp = sc->sc_qvaux[line].qvaux_tty; 574 575 (*tp->t_linesw->l_close)(tp, flag); 576 577 /* Make sure a BREAK state is not left enabled. */ 578 (void) qvauxmctl(sc, line, DML_BRK, DMBIC); 579 580 /* Do a hangup if so required. */ 581 if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN)) 582 (void) qvauxmctl(sc, line, 0, DMSET); 583 584 return ttyclose(tp); 585 } 586 587 int 588 qvauxread(dev_t dev, struct uio *uio, int flag) 589 { 590 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 591 QVA_I2C(minor(dev))); // only one controller 592 struct tty *tp = sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty; 593 594 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 595 } 596 597 int 598 qvauxwrite(dev_t dev, struct uio *uio, int flag) 599 { 600 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 601 QVA_I2C(minor(dev))); // only one controller 602 struct tty *tp = sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty; 603 604 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 605 } 606 607 int 608 qvauxpoll(dev_t dev, int events, struct lwp *l) 609 { 610 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 611 QVA_I2C(minor(dev))); // only one controller 612 struct tty *tp = sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty; 613 614 return ((*tp->t_linesw->l_poll)(tp, events, l)); 615 } 616 617 /*ARGSUSED*/ 618 int 619 qvauxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 620 { 621 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 622 QVA_I2C(minor(dev))); // only one controller 623 const int line = QVA_PORT(minor(dev)); 624 struct tty *tp = sc->sc_qvaux[line].qvaux_tty; 625 int error; 626 627 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 628 if (error >= 0) 629 return (error); 630 631 error = ttioctl(tp, cmd, data, flag, l); 632 if (error >= 0) 633 return (error); 634 635 switch (cmd) { 636 case TIOCSBRK: 637 (void) qvauxmctl(sc, line, DML_BRK, DMBIS); 638 break; 639 640 case TIOCCBRK: 641 (void) qvauxmctl(sc, line, DML_BRK, DMBIC); 642 break; 643 644 case TIOCSDTR: 645 (void) qvauxmctl(sc, line, DML_DTR, DMBIS); 646 break; 647 648 case TIOCCDTR: 649 (void) qvauxmctl(sc, line, DML_DTR, DMBIC); 650 break; 651 652 case TIOCMSET: 653 (void) qvauxmctl(sc, line, *(int *)data, DMSET); 654 break; 655 656 case TIOCMBIS: 657 (void) qvauxmctl(sc, line, *(int *)data, DMBIS); 658 break; 659 660 case TIOCMBIC: 661 (void) qvauxmctl(sc, line, *(int *)data, DMBIC); 662 break; 663 664 case TIOCMGET: 665 *(int *)data = (qvauxmctl(sc, line, 0, DMGET) & ~DML_BRK); 666 break; 667 668 default: 669 return (EPASSTHROUGH); 670 } 671 return (0); 672 } 673 674 struct tty * 675 qvauxtty(dev_t dev) 676 { 677 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 678 QVA_I2C(minor(dev))); 679 680 return sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty; 681 } 682 683 /*ARGSUSED*/ 684 void 685 qvauxstop(struct tty *tp, int flag) 686 { 687 if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY) 688 tp->t_state |= TS_FLUSH; 689 } 690 691 void 692 qvauxstart(struct tty *tp) 693 { 694 struct qvaux_softc *sc; 695 int line; 696 int s; 697 698 s = spltty(); 699 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) { 700 splx(s); 701 return; 702 } 703 if (!ttypull(tp)) { 704 splx(s); 705 return; 706 } 707 708 line = QVA_PORT(minor(tp->t_dev)); 709 sc = device_lookup_private(&qvaux_cd, QVA_I2C(minor(tp->t_dev))); 710 711 tp->t_state |= TS_BUSY; 712 sc->sc_imr |= ((line) ? (INT_TXB) : (INT_TXA)); 713 qvaux_write2(sc, sc->sc_qr.qr_imr, sc->sc_imr); 714 qvauxxint(sc); 715 splx(s); 716 } 717 718 static int 719 qvauxparam(struct tty *tp, struct termios *t) 720 { 721 struct qvaux_softc *sc = device_lookup_private(&qvaux_cd, 722 QVA_I2C(minor(tp->t_dev))); 723 const int line = QVA_PORT(minor(tp->t_dev)); 724 int cflag = t->c_cflag; 725 int ispeed = ttspeedtab(t->c_ispeed, qvauxspeedtab); 726 int ospeed = ttspeedtab(t->c_ospeed, qvauxspeedtab); 727 unsigned mr1, mr2; 728 int s; 729 730 731 /* check requested parameters */ 732 if (ospeed < 0 || ispeed < 0) 733 return (EINVAL); 734 735 tp->t_ispeed = t->c_ispeed; 736 tp->t_ospeed = t->c_ospeed; 737 tp->t_cflag = cflag; 738 739 if (ospeed == 0) { 740 (void) qvauxmctl(sc, line, 0, DMSET); /* hang up line */ 741 return (0); 742 } 743 744 s = spltty(); 745 746 /* XXX This is wrong. Flush output or the chip gets very confused. */ 747 //ttywait(tp); 748 749 //lpr = DZ_LPR_RX_ENABLE | ((ispeed&0xF)<<8) | line; 750 751 qvaux_write2(sc, sc->sc_qr.qr_acr, ACR_BRG); 752 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_csr, 753 (ispeed << 4) | ospeed); 754 755 mr1 = mr2 = 0; 756 757 switch (cflag & CSIZE) 758 { 759 case CS5: 760 mr1 |= MR1_CS5; 761 break; 762 case CS6: 763 mr1 |= MR1_CS6; 764 break; 765 case CS7: 766 mr1 |= MR1_CS7; 767 break; 768 default: 769 mr1 |= MR1_CS8; 770 break; 771 } 772 if (cflag & PARENB) { 773 if (cflag & PARODD) 774 mr1 |= MR1_PODD; 775 else 776 mr1 |= MR1_PEVEN; 777 } 778 else 779 mr1 |= MR1_PNONE; 780 if (cflag & CSTOPB) 781 mr2 |= MR2_STOP2; 782 else 783 mr2 |= MR2_STOP1; 784 785 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_cr, 786 CR_CMD_MR1 | CR_ENA_RX); // reset to mr1 787 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_mr, mr1); 788 qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_mr, mr2); 789 qvaux_write2(sc, sc->sc_qr.qr_acr, ACR_BRG); 790 (void) splx(s); 791 DELAY(10000); 792 793 return (0); 794 } 795 796 // QVSS has no modem control signals 797 static unsigned 798 qvauxmctl(struct qvaux_softc *sc, int line, int bits, int how) 799 { 800 /* unsigned status; */ 801 unsigned mbits; 802 unsigned bit; 803 int s; 804 805 s = spltty(); 806 mbits = 0; 807 bit = (1 << line); 808 #if 0 809 810 /* external signals as seen from the port */ 811 status = qvaux_read1(sc, sc->sc_dr.dr_dcd) | sc->sc_dsr; 812 if (status & bit) 813 mbits |= DML_DCD; 814 status = qvaux_read1(sc, sc->sc_dr.dr_ring); 815 if (status & bit) 816 mbits |= DML_RI; 817 818 /* internal signals/state delivered to port */ 819 status = qvaux_read1(sc, sc->sc_dr.dr_dtr); 820 if (status & bit) 821 mbits |= DML_DTR; 822 #endif 823 if (sc->sc_brk & bit) 824 mbits |= DML_BRK; 825 826 switch (how) 827 { 828 case DMSET: 829 mbits = bits; 830 break; 831 832 case DMBIS: 833 mbits |= bits; 834 break; 835 836 case DMBIC: 837 mbits &= ~bits; 838 break; 839 840 case DMGET: 841 (void) splx(s); 842 return (mbits); 843 } 844 #if 0 845 if (mbits & DML_DTR) { 846 qvaux_write1(sc, sc->sc_dr.dr_dtr, 847 qvaux_read1(sc, sc->sc_dr.dr_dtr) | bit); 848 } else { 849 qvaux_write1(sc, sc->sc_dr.dr_dtr, 850 qvaux_read1(sc, sc->sc_dr.dr_dtr) & ~bit); 851 } 852 #endif 853 if (mbits & DML_BRK) { 854 sc->sc_brk |= bit; 855 qvaux_write1(sc, sc->sc_qr.qr_ch_regs[line].qr_cr, 856 CR_CMD_START_BRK); 857 } else { 858 sc->sc_brk &= ~bit; 859 qvaux_write1(sc, sc->sc_qr.qr_ch_regs[line].qr_cr, 860 CR_CMD_STOP_BRK); 861 } 862 863 (void) splx(s); 864 865 return (mbits); 866 } 867 868 /* 869 * Called after an ubareset. The QVSS card is reset, but the only thing 870 * that must be done is to start the receiver and transmitter again. 871 * No DMA setup to care about. 872 */ 873 void 874 qvauxreset(device_t dev) 875 { 876 struct qvaux_softc *sc = device_private(dev); 877 struct tty *tp; 878 int i; 879 880 for (i = 0; i < NQVAUXLINE; i++) { 881 tp = sc->sc_qvaux[i].qvaux_tty; 882 883 if (((tp->t_state & TS_ISOPEN) == 0) || (tp->t_wopen == 0)) 884 continue; 885 886 qvauxparam(tp, &tp->t_termios); 887 qvauxmctl(sc, i, DML_DTR, DMSET); 888 tp->t_state &= ~TS_BUSY; 889 qvauxstart(tp); /* Kick off transmitter again */ 890 } 891 } 892 893 #if NQVKBD > 0 || NQVMS > 0 894 int 895 qvauxgetc(struct qvaux_linestate *ls) 896 { 897 #if 0 898 int line = ls->qvaux_line; 899 int s; 900 u_short rbuf; 901 902 s = spltty(); 903 for (;;) { 904 for(; (dz->csr & DZ_CSR_RX_DONE) == 0;); 905 rbuf = dz->rbuf; 906 if (((rbuf >> 8) & 3) == line) { 907 splx(s); 908 return (rbuf & 0xff); 909 } 910 } 911 #endif 912 return 0; 913 } 914 915 void 916 qvauxputc(struct qvaux_linestate *ls, int ch) 917 { 918 //int line; 919 int s; 920 921 /* if the qvaux has already been attached, the MI 922 driver will do the transmitting: */ 923 if (ls && ls->qvaux_sc) { 924 s = spltty(); 925 // line = ls->qvaux_line; 926 putc(ch, &ls->qvaux_tty->t_outq); 927 qvauxstart(ls->qvaux_tty); 928 splx(s); 929 return; 930 } 931 932 /* use qvauxcnputc to do the transmitting: */ 933 //qvauxcnputc(makedev(cdevsw_lookup_major(&qvaux_cdevsw), 0), ch); 934 } 935 #endif /* NQVKBD > 0 || NQVMS > 0 */ 936