1 /* $NetBSD: siotty.c,v 1.44 2015/08/21 10:48:06 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 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 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34 __KERNEL_RCSID(0, "$NetBSD: siotty.c,v 1.44 2015/08/21 10:48:06 christos Exp $"); 35 36 #include "opt_ddb.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/conf.h> 42 #include <sys/ioctl.h> 43 #include <sys/proc.h> 44 #include <sys/tty.h> 45 #include <sys/uio.h> 46 #include <sys/callout.h> 47 #include <sys/fcntl.h> 48 #include <dev/cons.h> 49 #include <sys/kauth.h> 50 #include <sys/kmem.h> 51 52 #include <machine/cpu.h> 53 54 #include <luna68k/dev/sioreg.h> 55 #include <luna68k/dev/siovar.h> 56 #include <luna68k/dev/syscn.h> 57 58 #include "ioconf.h" 59 60 #define TIOCM_BREAK 01000 /* non standard use */ 61 62 static const uint8_t ch0_regs[6] = { 63 WR0_RSTINT, /* reset E/S interrupt */ 64 WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */ 65 0, /* */ 66 WR3_RX8BIT | WR3_RXENBL, /* Rx */ 67 WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */ 68 WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */ 69 }; 70 71 static const struct speedtab siospeedtab[] = { 72 { 2400, WR4_BAUD24, }, 73 { 4800, WR4_BAUD48, }, 74 { 9600, WR4_BAUD96, }, 75 { -1, 0, }, 76 }; 77 78 struct siotty_softc { 79 device_t sc_dev; 80 struct tty *sc_tty; 81 struct sioreg *sc_ctl; 82 u_int sc_flags; 83 uint8_t sc_wr[6]; 84 void *sc_si; /* software interrupt handler */ 85 u_int sc_hwflags; 86 #define SIOTTY_HW_CONSOLE 0x0001 87 88 uint8_t *sc_rbuf; 89 uint8_t *sc_rbufend; 90 uint8_t * volatile sc_rbget; 91 uint8_t * volatile sc_rbput; 92 volatile u_int sc_rbavail; 93 94 uint8_t *sc_tba; 95 u_int sc_tbc; 96 97 bool sc_rx_ready; 98 bool sc_tx_busy; 99 bool sc_tx_done; 100 }; 101 102 #define SIOTTY_RING_SIZE 2048 103 u_int siotty_rbuf_size = SIOTTY_RING_SIZE; 104 105 static struct cnm_state siotty_cnm_state; 106 107 #include "siotty.h" 108 static void siostart(struct tty *); 109 static int sioparam(struct tty *, struct termios *); 110 static void siottyintr(void *); 111 static void siottysoft(void *); 112 static void siotty_rxsoft(struct siotty_softc *, struct tty *); 113 static void siotty_txsoft(struct siotty_softc *, struct tty *); 114 static int siomctl(struct siotty_softc *, int, int); 115 116 static int siotty_match(device_t, cfdata_t, void *); 117 static void siotty_attach(device_t, device_t, void *); 118 119 CFATTACH_DECL_NEW(siotty, sizeof(struct siotty_softc), 120 siotty_match, siotty_attach, NULL, NULL); 121 122 dev_type_open(sioopen); 123 dev_type_close(sioclose); 124 dev_type_read(sioread); 125 dev_type_write(siowrite); 126 dev_type_ioctl(sioioctl); 127 dev_type_stop(siostop); 128 dev_type_tty(siotty); 129 dev_type_poll(siopoll); 130 131 const struct cdevsw siotty_cdevsw = { 132 .d_open = sioopen, 133 .d_close = sioclose, 134 .d_read = sioread, 135 .d_write = siowrite, 136 .d_ioctl = sioioctl, 137 .d_stop = siostop, 138 .d_tty = siotty, 139 .d_poll = siopoll, 140 .d_mmap = nommap, 141 .d_kqfilter = ttykqfilter, 142 .d_discard = nodiscard, 143 .d_flag = D_TTY 144 }; 145 146 static int 147 siotty_match(device_t parent, cfdata_t cf, void *aux) 148 { 149 struct sio_attach_args *args = aux; 150 151 if (args->channel != 0) /* XXX allow tty on Ch.B XXX */ 152 return 0; 153 return 1; 154 } 155 156 static void 157 siotty_attach(device_t parent, device_t self, void *aux) 158 { 159 struct sio_softc *siosc = device_private(parent); 160 struct siotty_softc *sc = device_private(self); 161 struct sio_attach_args *args = aux; 162 int channel; 163 struct tty *tp; 164 165 sc->sc_dev = self; 166 channel = args->channel; 167 sc->sc_ctl = &siosc->sc_ctl[channel]; 168 memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs)); 169 siosc->sc_intrhand[channel].ih_func = siottyintr; 170 siosc->sc_intrhand[channel].ih_arg = sc; 171 if (args->hwflags == 1) 172 sc->sc_hwflags |= SIOTTY_HW_CONSOLE; 173 174 if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0) { 175 aprint_normal(" (console)"); 176 sc->sc_flags = TIOCFLAG_SOFTCAR; 177 } else { 178 setsioreg(sc->sc_ctl, WR0, WR0_CHANRST); 179 setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1); 180 setsioreg(sc->sc_ctl, WR2B, 0); 181 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 182 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); 183 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); 184 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]); 185 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 186 } 187 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */ 188 189 aprint_normal("\n"); 190 191 sc->sc_rbuf = kmem_alloc(siotty_rbuf_size * 2, KM_NOSLEEP); 192 if (sc->sc_rbuf == NULL) { 193 aprint_error_dev(self, "unable to allocate ring buffer\n"); 194 return; 195 } 196 sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2); 197 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 198 sc->sc_rbavail = siotty_rbuf_size; 199 200 tp = tty_alloc(); 201 tp->t_oproc = siostart; 202 tp->t_param = sioparam; 203 tp->t_hwiflow = NULL /* XXX siohwiflow XXX */; 204 if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0) 205 tp->t_dev = cn_tab->cn_dev; 206 sc->sc_tty = tp; 207 208 tty_attach(tp); 209 210 sc->sc_si = softint_establish(SOFTINT_SERIAL, siottysoft, sc); 211 } 212 213 /*-------------------- low level routine --------------------*/ 214 215 static void 216 siottyintr(void *arg) 217 { 218 struct siotty_softc *sc; 219 struct sioreg *sio; 220 uint8_t *put, *end; 221 uint8_t c; 222 uint16_t rr; 223 int cc; 224 225 sc = arg; 226 end = sc->sc_rbufend; 227 put = sc->sc_rbput; 228 cc = sc->sc_rbavail; 229 230 sio = sc->sc_ctl; 231 rr = getsiocsr(sio); 232 if ((rr & RR_BREAK) != 0) { 233 sio->sio_cmd = WR0_RSTINT; 234 cn_check_magic(sc->sc_tty->t_dev, CNC_BREAK, siotty_cnm_state); 235 } 236 if ((rr & RR_RXRDY) != 0) { 237 do { 238 if (cc > 0) { 239 c = sio->sio_data; 240 cn_check_magic(sc->sc_tty->t_dev, c, 241 siotty_cnm_state); 242 put[0] = c; 243 put[1] = rr & 0xff; 244 put += 2; 245 if (put >= end) 246 put = sc->sc_rbuf; 247 cc--; 248 } 249 if ((rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) != 0) 250 sio->sio_cmd = WR0_ERRRST; 251 252 sc->sc_rbput = put; 253 sc->sc_rbavail = cc; 254 sc->sc_rx_ready = true; 255 } while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0); 256 } 257 if ((rr & RR_TXRDY) != 0) { 258 sio->sio_cmd = WR0_RSTPEND; 259 if (sc->sc_tbc > 0) { 260 sio->sio_data = *sc->sc_tba; 261 sc->sc_tba++; 262 sc->sc_tbc--; 263 } else { 264 if (sc->sc_tx_busy) { 265 sc->sc_tx_busy = false; 266 sc->sc_tx_done = true; 267 } 268 } 269 } 270 softint_schedule(sc->sc_si); 271 } 272 273 static void 274 siottysoft(void *arg) 275 { 276 struct siotty_softc *sc; 277 struct tty *tp; 278 279 sc = arg; 280 tp = sc->sc_tty; 281 282 if (sc->sc_rx_ready) { 283 sc->sc_rx_ready = false; 284 siotty_rxsoft(sc, tp); 285 } 286 if (sc->sc_tx_done) { 287 sc->sc_tx_done = false; 288 siotty_txsoft(sc, tp); 289 } 290 } 291 292 static void 293 siotty_rxsoft(struct siotty_softc *sc, struct tty *tp) 294 { 295 uint8_t *get, *end; 296 u_int cc, scc; 297 unsigned int code; 298 uint8_t stat; 299 int s; 300 301 end = sc->sc_rbufend; 302 get = sc->sc_rbget; 303 scc = cc = siotty_rbuf_size - sc->sc_rbavail; 304 305 if (cc == siotty_rbuf_size) { 306 printf("%s: rx buffer overflow\n", device_xname(sc->sc_dev)); 307 } 308 309 while (cc > 0) { 310 code = get[0]; 311 stat = get[1]; 312 if ((stat & RR_FRAMING) != 0) 313 code |= TTY_FE; 314 else if ((stat & RR_PARITY) != 0) 315 code |= TTY_PE; 316 317 (*tp->t_linesw->l_rint)(code, tp); 318 get += 2; 319 if (get >= end) 320 get = sc->sc_rbuf; 321 cc--; 322 } 323 324 if (cc != scc) { 325 s = splserial(); 326 sc->sc_rbget = get; 327 sc->sc_rbavail += scc - cc; 328 splx(s); 329 } 330 } 331 332 static void 333 siotty_txsoft(struct siotty_softc *sc, struct tty *tp) 334 { 335 336 tp->t_state &= ~TS_BUSY; 337 if ((tp->t_state & TS_FLUSH) != 0) 338 tp->t_state &= ~TS_FLUSH; 339 else 340 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); 341 (*tp->t_linesw->l_start)(tp); 342 } 343 344 static void 345 siostart(struct tty *tp) 346 { 347 struct siotty_softc *sc; 348 int s; 349 uint8_t *tba; 350 int tbc; 351 352 sc = device_lookup_private(&siotty_cd, minor(tp->t_dev)); 353 s = splserial(); 354 if ((tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP)) != 0) 355 goto out; 356 if (!ttypull(tp)) 357 goto out; 358 tp->t_state |= TS_BUSY; 359 360 tba = tp->t_outq.c_cf; 361 tbc = ndqb(&tp->t_outq, 0); 362 363 sc->sc_tba = tba; 364 sc->sc_tbc = tbc; 365 sc->sc_tx_busy = true; 366 367 sc->sc_ctl->sio_data = *sc->sc_tba; 368 sc->sc_tba++; 369 sc->sc_tbc--; 370 out: 371 splx(s); 372 } 373 374 void 375 siostop(struct tty *tp, int flag) 376 { 377 int s; 378 379 s = splserial(); 380 if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) { 381 /* 382 * Device is transmitting; must stop it. 383 */ 384 tp->t_state |= TS_FLUSH; 385 } 386 splx(s); 387 } 388 389 static int 390 sioparam(struct tty *tp, struct termios *t) 391 { 392 struct siotty_softc *sc; 393 int wr4, s; 394 395 sc = device_lookup_private(&siotty_cd, minor(tp->t_dev)); 396 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 397 return EINVAL; 398 wr4 = ttspeedtab(t->c_ospeed, siospeedtab); 399 if (wr4 < 0) 400 return EINVAL; 401 402 if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0) { 403 t->c_cflag |= CLOCAL; 404 t->c_cflag &= ~HUPCL; 405 } 406 if ((sc->sc_flags & TIOCFLAG_CLOCAL) != 0) 407 t->c_cflag |= CLOCAL; 408 409 /* 410 * If there were no changes, don't do anything. This avoids dropping 411 * input and improves performance when all we did was frob things like 412 * VMIN and VTIME. 413 */ 414 if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag) 415 return 0; 416 417 tp->t_ispeed = t->c_ispeed; 418 tp->t_ospeed = t->c_ospeed; 419 tp->t_cflag = t->c_cflag; 420 421 sc->sc_wr[WR3] &= 0x3f; 422 sc->sc_wr[WR5] &= 0x9f; 423 switch (tp->t_cflag & CSIZE) { 424 case CS7: 425 sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT; 426 break; 427 case CS8: 428 sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT; 429 break; 430 } 431 if ((tp->t_cflag & PARENB) != 0) { 432 wr4 |= WR4_PARENAB; 433 if ((tp->t_cflag & PARODD) == 0) 434 wr4 |= WR4_EPARITY; 435 } 436 wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1; 437 sc->sc_wr[WR4] = wr4; 438 439 s = splserial(); 440 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); 441 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); 442 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]); 443 splx(s); 444 445 return 0; 446 } 447 448 static int 449 siomctl(struct siotty_softc *sc, int control, int op) 450 { 451 int val, s; 452 uint8_t wr5; 453 uint16_t rr; 454 455 val = 0; 456 if ((control & TIOCM_BREAK) != 0) 457 val |= WR5_BREAK; 458 if ((control & TIOCM_DTR) != 0) 459 val |= WR5_DTR; 460 if ((control & TIOCM_RTS) != 0) 461 val |= WR5_RTS; 462 s = splserial(); 463 wr5 = sc->sc_wr[WR5]; 464 switch (op) { 465 case DMSET: 466 wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS); 467 /* FALLTHRU */ 468 case DMBIS: 469 wr5 |= val; 470 break; 471 case DMBIC: 472 wr5 &= ~val; 473 break; 474 case DMGET: 475 val = 0; 476 rr = getsiocsr(sc->sc_ctl); 477 if ((wr5 & WR5_DTR) != 0) 478 val |= TIOCM_DTR; 479 if ((wr5 & WR5_RTS) != 0) 480 val |= TIOCM_RTS; 481 if ((rr & RR_CTS) != 0) 482 val |= TIOCM_CTS; 483 if ((rr & RR_DCD) != 0) 484 val |= TIOCM_CD; 485 goto done; 486 } 487 sc->sc_wr[WR5] = wr5; 488 setsioreg(sc->sc_ctl, WR5, wr5); 489 val = 0; 490 done: 491 splx(s); 492 return val; 493 } 494 495 /*-------------------- cdevsw[] interface --------------------*/ 496 497 int 498 sioopen(dev_t dev, int flag, int mode, struct lwp *l) 499 { 500 struct siotty_softc *sc; 501 struct tty *tp; 502 int error; 503 int s; 504 505 sc = device_lookup_private(&siotty_cd, minor(dev)); 506 if (sc == NULL) 507 return ENXIO; 508 509 tp = sc->sc_tty; 510 511 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 512 return EBUSY; 513 514 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 515 struct termios t; 516 517 tp->t_dev = dev; 518 t.c_ispeed = t.c_ospeed = TTYDEF_SPEED; 519 t.c_cflag = TTYDEF_CFLAG; 520 tp->t_ospeed = 0; /* force register update */ 521 (void)sioparam(tp, &t); 522 tp->t_iflag = TTYDEF_IFLAG; 523 tp->t_oflag = TTYDEF_OFLAG; 524 tp->t_lflag = TTYDEF_LFLAG; 525 ttychars(tp); 526 ttsetwater(tp); 527 /* raise RTS and DTR here; but, DTR lead is not wired */ 528 /* then check DCD condition; but, DCD lead is not wired */ 529 #if 0 530 if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0 531 || (tp->t_cflag & MDMBUF) != 0 532 || (getsiocsr(sc->sc_ctl) & RR_DCD) != 0) 533 tp->t_state |= TS_CARR_ON; 534 else 535 tp->t_state &= ~TS_CARR_ON; 536 #else 537 tp->t_state |= TS_CARR_ON; /* assume detected all the time */ 538 #endif 539 540 s = splserial(); 541 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 542 sc->sc_rbavail = siotty_rbuf_size; 543 splx(s); 544 } 545 546 error = ttyopen(tp, 0, (flag & O_NONBLOCK)); 547 if (error > 0) 548 return error; 549 return (*tp->t_linesw->l_open)(dev, tp); 550 } 551 552 int 553 sioclose(dev_t dev, int flag, int mode, struct lwp *l) 554 { 555 struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev)); 556 struct tty *tp = sc->sc_tty; 557 int s; 558 559 (*tp->t_linesw->l_close)(tp, flag); 560 561 s = splserial(); 562 siomctl(sc, TIOCM_BREAK, DMBIC); 563 #if 0 /* because unable to feed DTR signal */ 564 if ((tp->t_cflag & HUPCL) != 0 565 || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) { 566 siomctl(sc, TIOCM_DTR, DMBIC); 567 /* Yield CPU time to others for 1 second, then ... */ 568 siomctl(sc, TIOCM_DTR, DMBIS); 569 } 570 #endif 571 splx(s); 572 return ttyclose(tp); 573 } 574 575 int 576 sioread(dev_t dev, struct uio *uio, int flag) 577 { 578 struct siotty_softc *sc; 579 struct tty *tp; 580 581 sc = device_lookup_private(&siotty_cd, minor(dev)); 582 tp = sc->sc_tty; 583 return (*tp->t_linesw->l_read)(tp, uio, flag); 584 } 585 586 int 587 siowrite(dev_t dev, struct uio *uio, int flag) 588 { 589 struct siotty_softc *sc; 590 struct tty *tp; 591 592 sc = device_lookup_private(&siotty_cd, minor(dev)); 593 tp = sc->sc_tty; 594 return (*tp->t_linesw->l_write)(tp, uio, flag); 595 } 596 597 int 598 siopoll(dev_t dev, int events, struct lwp *l) 599 { 600 struct siotty_softc *sc; 601 struct tty *tp; 602 603 sc = device_lookup_private(&siotty_cd, minor(dev)); 604 tp = sc->sc_tty; 605 return ((*tp->t_linesw->l_poll)(tp, events, l)); 606 } 607 608 int 609 sioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 610 { 611 struct siotty_softc *sc; 612 struct tty *tp; 613 int error; 614 615 sc = device_lookup_private(&siotty_cd, minor(dev)); 616 tp = sc->sc_tty; 617 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 618 if (error != EPASSTHROUGH) 619 return error; 620 621 error = ttioctl(tp, cmd, data, flag, l); 622 if (error != EPASSTHROUGH) 623 return error; 624 625 /* the last resort for TIOC ioctl tranversing */ 626 switch (cmd) { 627 case TIOCSBRK: /* Set the hardware into BREAK condition */ 628 siomctl(sc, TIOCM_BREAK, DMBIS); 629 break; 630 case TIOCCBRK: /* Clear the hardware BREAK condition */ 631 siomctl(sc, TIOCM_BREAK, DMBIC); 632 break; 633 case TIOCSDTR: /* Assert DTR signal */ 634 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS); 635 break; 636 case TIOCCDTR: /* Clear DTR signal */ 637 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC); 638 break; 639 case TIOCMSET: /* Set modem state replacing current one */ 640 siomctl(sc, *(int *)data, DMSET); 641 break; 642 case TIOCMGET: /* Return current modem state */ 643 *(int *)data = siomctl(sc, 0, DMGET); 644 break; 645 case TIOCMBIS: /* Set individual bits of modem state */ 646 siomctl(sc, *(int *)data, DMBIS); 647 break; 648 case TIOCMBIC: /* Clear individual bits of modem state */ 649 siomctl(sc, *(int *)data, DMBIC); 650 break; 651 case TIOCSFLAGS: /* Instruct how serial port behaves */ 652 sc->sc_flags = *(int *)data; 653 break; 654 case TIOCGFLAGS: /* Return current serial port state */ 655 *(int *)data = sc->sc_flags; 656 break; 657 default: 658 return EPASSTHROUGH; 659 } 660 return 0; 661 } 662 663 /* ARSGUSED */ 664 struct tty * 665 siotty(dev_t dev) 666 { 667 struct siotty_softc *sc; 668 669 sc = device_lookup_private(&siotty_cd, minor(dev)); 670 return sc->sc_tty; 671 } 672 673 /*-------------------- miscelleneous routine --------------------*/ 674 675 /* EXPORT */ void 676 setsioreg(struct sioreg *sio, int regno, int val) 677 { 678 679 if (regno != 0) 680 sio->sio_cmd = regno; /* DELAY(); */ 681 sio->sio_cmd = val; /* DELAY(); */ 682 } 683 684 /* EXPORT */ uint16_t 685 getsiocsr(struct sioreg *sio) 686 { 687 int val; 688 689 val = sio->sio_stat << 8; /* DELAY(); */ 690 sio->sio_cmd = 1; /* DELAY(); */ 691 val |= sio->sio_stat; /* DELAY(); */ 692 return val; 693 } 694 695 /*--------------------- console interface ----------------------*/ 696 697 struct consdev syscons = { 698 NULL, 699 NULL, 700 syscngetc, 701 syscnputc, 702 nullcnpollc, 703 NULL, 704 NULL, 705 NULL, 706 NODEV, 707 CN_REMOTE, 708 }; 709 710 /* EXPORT */ void 711 syscninit(int channel) 712 { 713 /* 714 * Channel A is immediately initialized with 9600N1 right after cold 715 * boot/reset/poweron. ROM monitor emits one line message on CH.A. 716 */ 717 struct sioreg *sio; 718 sio = (struct sioreg *)0x51000000 + channel; 719 720 syscons.cn_dev = makedev(cdevsw_lookup_major(&siotty_cdevsw), 721 channel); 722 cn_tab = &syscons; 723 cn_init_magic(&siotty_cnm_state); 724 cn_set_magic("\047\001"); 725 726 setsioreg(sio, WR0, WR0_CHANRST); 727 setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1); 728 setsioreg(sio, WR2B, 0); 729 setsioreg(sio, WR0, ch0_regs[WR0]); 730 setsioreg(sio, WR4, ch0_regs[WR4]); 731 setsioreg(sio, WR3, ch0_regs[WR3]); 732 setsioreg(sio, WR5, ch0_regs[WR5]); 733 setsioreg(sio, WR0, ch0_regs[WR0]); 734 } 735 736 /* EXPORT */ int 737 syscngetc(dev_t dev) 738 { 739 struct sioreg *sio; 740 int s, c; 741 742 sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1); 743 s = splhigh(); 744 while ((getsiocsr(sio) & RR_RXRDY) == 0) 745 continue; 746 c = sio->sio_data; 747 splx(s); 748 749 return c; 750 } 751 752 /* EXPORT */ void 753 syscnputc(dev_t dev, int c) 754 { 755 struct sioreg *sio; 756 int s; 757 758 sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1); 759 s = splhigh(); 760 while ((getsiocsr(sio) & RR_TXRDY) == 0) 761 continue; 762 sio->sio_cmd = WR0_RSTPEND; 763 sio->sio_data = c; 764 splx(s); 765 } 766