1 /* $OpenBSD: siotty.c,v 1.25 2021/01/09 02:34:21 aoyama Exp $ */ 2 /* $NetBSD: siotty.c,v 1.9 2002/03/17 19:40:43 atatat Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Tohru Nishimura. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/conf.h> 37 #include <sys/ioctl.h> 38 #include <sys/malloc.h> 39 #include <sys/proc.h> 40 #include <sys/tty.h> 41 #include <sys/uio.h> 42 #include <sys/fcntl.h> 43 #include <dev/cons.h> 44 45 #include <machine/board.h> 46 #include <machine/cpu.h> 47 48 #include <luna88k/dev/sioreg.h> 49 #include <luna88k/dev/siovar.h> 50 51 #define TIOCM_BREAK 01000 /* non standard use */ 52 53 static const u_int8_t ch0_regs[6] = { 54 WR0_RSTINT, /* reset E/S interrupt */ 55 WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */ 56 0, /* */ 57 WR3_RX8BIT | WR3_RXENBL, /* Rx */ 58 WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */ 59 WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */ 60 }; 61 62 static const struct speedtab siospeedtab[] = { 63 { 2400, WR4_BAUD24, }, 64 { 4800, WR4_BAUD48, }, 65 { 9600, WR4_BAUD96, }, 66 { -1, 0, }, 67 }; 68 69 struct siotty_softc { 70 struct device sc_dev; 71 struct tty *sc_tty; 72 struct sioreg *sc_ctl; 73 u_int sc_flags; 74 u_int8_t sc_wr[6]; 75 void *sc_si; /* software interrupt handler */ 76 u_int sc_hwflags; 77 #define SIOTTY_HW_CONSOLE 0x0001 78 79 u_int8_t *sc_rbuf; 80 u_int8_t *sc_rbufend; 81 u_int8_t * volatile sc_rbget; 82 u_int8_t * volatile sc_rbput; 83 volatile u_int sc_rbavail; 84 85 u_int8_t *sc_tba; 86 u_int sc_tbc; 87 88 bool sc_rx_ready; 89 bool sc_tx_busy; 90 bool sc_tx_done; 91 }; 92 93 #define SIOTTY_RING_SIZE 2048 94 u_int siotty_rbuf_size = SIOTTY_RING_SIZE; 95 96 cdev_decl(sio); 97 void siostart(struct tty *); 98 int sioparam(struct tty *, struct termios *); 99 void siottyintr(void *); 100 void siottysoft(void *); 101 void siotty_rxsoft(struct siotty_softc *, struct tty *); 102 void siotty_txsoft(struct siotty_softc *, struct tty *); 103 int siomctl(struct siotty_softc *, int, int); 104 105 int siotty_match(struct device *, void *, void *); 106 void siotty_attach(struct device *, struct device *, void *); 107 108 const struct cfattach siotty_ca = { 109 sizeof(struct siotty_softc), siotty_match, siotty_attach 110 }; 111 112 struct cfdriver siotty_cd = { 113 NULL, "siotty", DV_TTY 114 }; 115 116 int 117 siotty_match(struct device *parent, void *cf, void *aux) 118 { 119 struct sio_attach_args *args = aux; 120 121 if (args->channel != 0) /* XXX allow tty on Ch.B XXX */ 122 return 0; 123 return 1; 124 } 125 126 void 127 siotty_attach(struct device *parent, struct device *self, void *aux) 128 { 129 struct sio_softc *siosc = (void *)parent; 130 struct siotty_softc *sc = (void *)self; 131 struct sio_attach_args *args = aux; 132 int channel; 133 struct tty *tp; 134 135 channel = args->channel; 136 sc->sc_ctl = &siosc->sc_ctl[channel]; 137 memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs)); 138 siosc->sc_intrhand[channel].ih_func = siottyintr; 139 siosc->sc_intrhand[channel].ih_arg = sc; 140 if (args->hwflags == 1) 141 sc->sc_hwflags |= SIOTTY_HW_CONSOLE; 142 143 if (sc->sc_hwflags & SIOTTY_HW_CONSOLE) { 144 printf(" (console)"); 145 sc->sc_flags = TIOCFLAG_SOFTCAR; 146 } else { 147 setsioreg(sc->sc_ctl, WR0, WR0_CHANRST); 148 setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1); 149 setsioreg(sc->sc_ctl, WR2B, 0); 150 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 151 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); 152 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); 153 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]); 154 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 155 } 156 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */ 157 158 printf("\n"); 159 160 sc->sc_rbuf = malloc(siotty_rbuf_size * 2, M_DEVBUF, M_NOWAIT); 161 if (sc->sc_rbuf == NULL) { 162 printf("%s: unable to allocate ring buffer\n", 163 (sc->sc_dev).dv_xname); 164 return; 165 } 166 sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2); 167 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 168 sc->sc_rbavail = siotty_rbuf_size; 169 170 tp = ttymalloc(0); 171 tp->t_oproc = siostart; 172 tp->t_param = sioparam; 173 tp->t_hwiflow = NULL /* XXX siohwiflow XXX */; 174 if (sc->sc_hwflags & SIOTTY_HW_CONSOLE) 175 tp->t_dev = cn_tab->cn_dev; 176 sc->sc_tty = tp; 177 178 sc->sc_si = softintr_establish(IPL_SOFTTTY, siottysoft, sc); 179 } 180 181 /*-------------------- low level routine --------------------*/ 182 183 void 184 siottyintr(void *arg) 185 { 186 struct siotty_softc *sc; 187 struct sioreg *sio; 188 u_int8_t *put, *end; 189 u_int8_t c; 190 u_int16_t rr; 191 int cc; 192 193 sc = arg; 194 end = sc->sc_rbufend; 195 put = sc->sc_rbput; 196 cc = sc->sc_rbavail; 197 198 sio = sc->sc_ctl; 199 rr = getsiocsr(sio); 200 if (rr & RR_RXRDY) { 201 do { 202 if (cc > 0) { 203 c = sio->sio_data; 204 put[0] = c; 205 put[1] = rr & 0xff; 206 put += 2; 207 if (put >= end) 208 put = sc->sc_rbuf; 209 cc--; 210 } 211 if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) 212 sio->sio_cmd = WR0_ERRRST; 213 214 sc->sc_rbput = put; 215 sc->sc_rbavail = cc; 216 sc->sc_rx_ready = true; 217 } while ((rr = getsiocsr(sio)) & RR_RXRDY); 218 } 219 if (rr & RR_TXRDY) { 220 sio->sio_cmd = WR0_RSTPEND; 221 if (sc->sc_tbc > 0) { 222 sio->sio_data = *sc->sc_tba; 223 sc->sc_tba++; 224 sc->sc_tbc--; 225 } else { 226 if (sc->sc_tx_busy) { 227 sc->sc_tx_busy = false; 228 sc->sc_tx_done = true; 229 } 230 } 231 } 232 softintr_schedule(sc->sc_si); 233 } 234 235 void 236 siottysoft(void *arg) 237 { 238 struct siotty_softc *sc; 239 struct tty *tp; 240 241 sc = arg; 242 tp = sc->sc_tty; 243 244 if (sc->sc_rx_ready) { 245 sc->sc_rx_ready = false; 246 siotty_rxsoft(sc, tp); 247 } 248 if (sc->sc_tx_done) { 249 sc->sc_tx_done = false; 250 siotty_txsoft(sc, tp); 251 } 252 } 253 254 void 255 siotty_rxsoft(struct siotty_softc *sc, struct tty *tp) 256 { 257 uint8_t *get, *end; 258 u_int cc, scc; 259 unsigned int code; 260 uint8_t stat; 261 int s; 262 263 end = sc->sc_rbufend; 264 get = sc->sc_rbget; 265 scc = cc = siotty_rbuf_size - sc->sc_rbavail; 266 267 if (cc == siotty_rbuf_size) { 268 printf("%s: rx buffer overflow\n", (sc->sc_dev).dv_xname); 269 } 270 271 while (cc > 0) { 272 code = get[0]; 273 stat = get[1]; 274 if ((stat & RR_FRAMING) != 0) 275 code |= TTY_FE; 276 else if ((stat & RR_PARITY) != 0) 277 code |= TTY_PE; 278 279 (*linesw[tp->t_line].l_rint)(code, tp); 280 get += 2; 281 if (get >= end) 282 get = sc->sc_rbuf; 283 cc--; 284 } 285 286 if (cc != scc) { 287 s = spltty(); 288 sc->sc_rbget = get; 289 sc->sc_rbavail += scc - cc; 290 splx(s); 291 } 292 } 293 294 void 295 siotty_txsoft(struct siotty_softc *sc, struct tty *tp) 296 { 297 298 tp->t_state &= ~TS_BUSY; 299 if ((tp->t_state & TS_FLUSH) != 0) 300 tp->t_state &= ~TS_FLUSH; 301 else 302 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); 303 (*linesw[tp->t_line].l_start)(tp); 304 } 305 306 void 307 siostart(struct tty *tp) 308 { 309 struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)]; 310 int s; 311 u_int8_t *tba; 312 int tbc; 313 314 s = spltty(); 315 if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP)) 316 goto out; 317 ttwakeupwr(tp); 318 if (tp->t_outq.c_cc == 0) 319 goto out; 320 321 tp->t_state |= TS_BUSY; 322 323 tba = tp->t_outq.c_cf; 324 tbc = ndqb(&tp->t_outq, 0); 325 326 sc->sc_tba = tba; 327 sc->sc_tbc = tbc; 328 sc->sc_tx_busy = true; 329 330 sc->sc_ctl->sio_data = *sc->sc_tba; 331 sc->sc_tba++; 332 sc->sc_tbc--; 333 out: 334 splx(s); 335 } 336 337 int 338 siostop(struct tty *tp, int flag) 339 { 340 int s; 341 342 s = spltty(); 343 if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) { 344 /* 345 * Device is transmitting; must stop it. 346 */ 347 tp->t_state |= TS_FLUSH; 348 } 349 splx(s); 350 return (0); 351 } 352 353 int 354 sioparam(struct tty *tp, struct termios *t) 355 { 356 struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)]; 357 int wr4, s; 358 359 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 360 return EINVAL; 361 wr4 = ttspeedtab(t->c_ospeed, siospeedtab); 362 if (wr4 < 0) 363 return EINVAL; 364 365 if (sc->sc_flags & TIOCFLAG_SOFTCAR) { 366 t->c_cflag |= CLOCAL; 367 t->c_cflag &= ~HUPCL; 368 } 369 if (sc->sc_flags & TIOCFLAG_CLOCAL) 370 t->c_cflag |= CLOCAL; 371 372 /* 373 * If there were no changes, don't do anything. This avoids dropping 374 * input and improves performance when all we did was frob things like 375 * VMIN and VTIME. 376 */ 377 if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag) 378 return 0; 379 380 tp->t_ispeed = t->c_ispeed; 381 tp->t_ospeed = t->c_ospeed; 382 tp->t_cflag = t->c_cflag; 383 384 sc->sc_wr[WR3] &= 0x3f; 385 sc->sc_wr[WR5] &= 0x9f; 386 switch (tp->t_cflag & CSIZE) { 387 case CS7: 388 sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT; 389 break; 390 case CS8: 391 sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT; 392 break; 393 } 394 if (tp->t_cflag & PARENB) { 395 wr4 |= WR4_PARENAB; 396 if ((tp->t_cflag & PARODD) == 0) 397 wr4 |= WR4_EPARITY; 398 } 399 wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1; 400 sc->sc_wr[WR4] = wr4; 401 402 s = spltty(); 403 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); 404 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); 405 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]); 406 splx(s); 407 408 return 0; 409 } 410 411 int 412 siomctl(struct siotty_softc *sc, int control, int op) 413 { 414 int val, s, wr5, rr; 415 416 val = 0; 417 if (control & TIOCM_BREAK) 418 val |= WR5_BREAK; 419 if (control & TIOCM_DTR) 420 val |= WR5_DTR; 421 if (control & TIOCM_RTS) 422 val |= WR5_RTS; 423 s = spltty(); 424 wr5 = sc->sc_wr[WR5]; 425 switch (op) { 426 case DMSET: 427 wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS); 428 /* FALLTHROUGH */ 429 case DMBIS: 430 wr5 |= val; 431 break; 432 case DMBIC: 433 wr5 &= ~val; 434 break; 435 case DMGET: 436 val = 0; 437 rr = getsiocsr(sc->sc_ctl); 438 if (wr5 & WR5_DTR) 439 val |= TIOCM_DTR; 440 if (wr5 & WR5_RTS) 441 val |= TIOCM_RTS; 442 if (rr & RR_CTS) 443 val |= TIOCM_CTS; 444 if (rr & RR_DCD) 445 val |= TIOCM_CD; 446 goto done; 447 } 448 sc->sc_wr[WR5] = wr5; 449 setsioreg(sc->sc_ctl, WR5, wr5); 450 val = 0; 451 done: 452 splx(s); 453 return val; 454 } 455 456 /*-------------------- cdevsw[] interface --------------------*/ 457 458 int 459 sioopen(dev_t dev, int flag, int mode, struct proc *p) 460 { 461 struct siotty_softc *sc; 462 struct tty *tp; 463 int s; 464 465 if ((sc = siotty_cd.cd_devs[minor(dev)]) == NULL) 466 return ENXIO; 467 468 tp = sc->sc_tty; 469 470 if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) 471 && suser(p) != 0) 472 return EBUSY; 473 474 if ((tp->t_state & TS_ISOPEN) == 0) { 475 struct termios t; 476 477 tp->t_dev = dev; 478 t.c_ispeed = t.c_ospeed = TTYDEF_SPEED; 479 t.c_cflag = TTYDEF_CFLAG; 480 tp->t_ospeed = 0; /* force register update */ 481 (void)sioparam(tp, &t); 482 tp->t_iflag = TTYDEF_IFLAG; 483 tp->t_oflag = TTYDEF_OFLAG; 484 tp->t_lflag = TTYDEF_LFLAG; 485 ttychars(tp); 486 ttsetwater(tp); 487 /* raise RTS and DTR here; but, DTR lead is not wired */ 488 /* then check DCD condition; but, DCD lead is not wired */ 489 #if 0 490 if ((sc->sc_flags & TIOCFLAG_SOFTCAR) 491 || (tp->t_cflag & MDMBUF) 492 || (getsiocsr(sc->sc_ctl) & RR_DCD)) 493 tp->t_state |= TS_CARR_ON; 494 else 495 tp->t_state &= ~TS_CARR_ON; 496 #else 497 tp->t_state |= TS_CARR_ON; /* assume detected all the time */ 498 #endif 499 s = spltty(); 500 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 501 sc->sc_rbavail = siotty_rbuf_size; 502 splx(s); 503 } 504 505 return (*linesw[tp->t_line].l_open)(dev, tp, p); 506 } 507 508 int 509 sioclose(dev_t dev, int flag, int mode, struct proc *p) 510 { 511 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)]; 512 struct tty *tp = sc->sc_tty; 513 int s; 514 515 (*linesw[tp->t_line].l_close)(tp, flag, p); 516 517 s = spltty(); 518 siomctl(sc, TIOCM_BREAK, DMBIC); 519 #if 0 /* because unable to feed DTR signal */ 520 if ((tp->t_cflag & HUPCL) 521 || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) { 522 siomctl(sc, TIOCM_DTR, DMBIC); 523 /* Yield CPU time to others for 1 second, then ... */ 524 siomctl(sc, TIOCM_DTR, DMBIS); 525 } 526 #endif 527 splx(s); 528 return ttyclose(tp); 529 } 530 531 int 532 sioread(dev_t dev, struct uio *uio, int flag) 533 { 534 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)]; 535 struct tty *tp = sc->sc_tty; 536 537 return (*linesw[tp->t_line].l_read)(tp, uio, flag); 538 } 539 540 int 541 siowrite(dev_t dev, struct uio *uio, int flag) 542 { 543 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)]; 544 struct tty *tp = sc->sc_tty; 545 546 return (*linesw[tp->t_line].l_write)(tp, uio, flag); 547 } 548 549 int 550 sioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 551 { 552 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)]; 553 struct tty *tp = sc->sc_tty; 554 int error; 555 556 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 557 if (error >= 0) 558 return error; 559 560 error = ttioctl(tp, cmd, data, flag, p); 561 if (error >= 0) 562 return error; 563 564 /* the last resort for TIOC ioctl traversing */ 565 switch (cmd) { 566 case TIOCSBRK: /* Set the hardware into BREAK condition */ 567 siomctl(sc, TIOCM_BREAK, DMBIS); 568 break; 569 case TIOCCBRK: /* Clear the hardware BREAK condition */ 570 siomctl(sc, TIOCM_BREAK, DMBIC); 571 break; 572 case TIOCSDTR: /* Assert DTR signal */ 573 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS); 574 break; 575 case TIOCCDTR: /* Clear DTR signal */ 576 siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC); 577 break; 578 case TIOCMSET: /* Set modem state replacing current one */ 579 siomctl(sc, *(int *)data, DMSET); 580 break; 581 case TIOCMGET: /* Return current modem state */ 582 *(int *)data = siomctl(sc, 0, DMGET); 583 break; 584 case TIOCMBIS: /* Set individual bits of modem state */ 585 siomctl(sc, *(int *)data, DMBIS); 586 break; 587 case TIOCMBIC: /* Clear individual bits of modem state */ 588 siomctl(sc, *(int *)data, DMBIC); 589 break; 590 case TIOCSFLAGS: /* Instruct how serial port behaves */ 591 error = suser(p); 592 if (error != 0) 593 return EPERM; 594 sc->sc_flags = *(int *)data; 595 break; 596 case TIOCGFLAGS: /* Return current serial port state */ 597 *(int *)data = sc->sc_flags; 598 break; 599 default: 600 return ENOTTY; 601 } 602 return 0; 603 } 604 605 /* ARSGUSED */ 606 struct tty * 607 siotty(dev_t dev) 608 { 609 struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)]; 610 611 return sc->sc_tty; 612 } 613 614 /*-------------------- miscellaneous routines --------------------*/ 615 616 /* EXPORT */ void 617 setsioreg(struct sioreg *sio, int regno, int val) 618 { 619 if (regno != 0) 620 sio->sio_cmd = regno; /* DELAY(); */ 621 sio->sio_cmd = val; /* DELAY(); */ 622 } 623 624 /* EXPORT */ int 625 getsiocsr(struct sioreg *sio) 626 { 627 int val; 628 629 val = sio->sio_stat << 8; /* DELAY(); */ 630 sio->sio_cmd = 1; /* DELAY(); */ 631 val |= sio->sio_stat; /* DELAY(); */ 632 return val; 633 } 634 635 /*--------------------- console interface ----------------------*/ 636 637 void syscnattach(int); 638 int syscngetc(dev_t); 639 void syscnputc(dev_t, int); 640 641 struct consdev syscons = { 642 NULL, 643 NULL, 644 syscngetc, 645 syscnputc, 646 nullcnpollc, 647 NULL, 648 NODEV, 649 CN_HIGHPRI, 650 }; 651 652 /* EXPORT */ void 653 syscnattach(int channel) 654 { 655 /* 656 * Channel A is immediately initialized with 9600N1 right after cold 657 * boot/reset/poweron. ROM monitor emits one line message on CH.A. 658 */ 659 struct sioreg *sio; 660 sio = (struct sioreg *)OBIO_SIO + channel; 661 662 syscons.cn_dev = makedev(12, channel); 663 cn_tab = &syscons; 664 665 setsioreg(sio, WR0, WR0_CHANRST); 666 setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1); 667 setsioreg(sio, WR2B, 0); 668 setsioreg(sio, WR0, ch0_regs[WR0]); 669 setsioreg(sio, WR4, ch0_regs[WR4]); 670 setsioreg(sio, WR3, ch0_regs[WR3]); 671 setsioreg(sio, WR5, ch0_regs[WR5]); 672 setsioreg(sio, WR0, ch0_regs[WR0]); 673 } 674 675 /* EXPORT */ int 676 syscngetc(dev_t dev) 677 { 678 struct sioreg *sio; 679 int s, c; 680 681 sio = (struct sioreg *)OBIO_SIO + ((int)dev & 0x1); 682 s = splhigh(); 683 while ((getsiocsr(sio) & RR_RXRDY) == 0) 684 ; 685 c = sio->sio_data; 686 splx(s); 687 688 return c; 689 } 690 691 /* EXPORT */ void 692 syscnputc(dev_t dev, int c) 693 { 694 struct sioreg *sio; 695 int s; 696 697 sio = (struct sioreg *)OBIO_SIO + ((int)dev & 0x1); 698 s = splhigh(); 699 while ((getsiocsr(sio) & RR_TXRDY) == 0) 700 ; 701 sio->sio_cmd = WR0_RSTPEND; 702 sio->sio_data = c; 703 splx(s); 704 } 705