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