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