1 /* $NetBSD: gftty.c,v 1.4 2025/10/04 04:48:12 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2023, 2024 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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 * Support for the Goldfish virtual TTY. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: gftty.c,v 1.4 2025/10/04 04:48:12 thorpej Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/conf.h> 41 #include <sys/fcntl.h> 42 #include <sys/systm.h> 43 #include <sys/bus.h> 44 #include <sys/device.h> 45 #include <sys/kauth.h> 46 #include <sys/kmem.h> 47 #include <sys/tty.h> 48 49 #include <uvm/uvm_extern.h> 50 51 #include <dev/cons.h> 52 53 #include <dev/goldfish/gfttyvar.h> 54 55 #include "ioconf.h" 56 57 /* 58 * Goldfish TTY registers. 59 */ 60 #define GFTTY_PUT_CHAR 0x00 /* 8 bit output value */ 61 #define GFTTY_BYTES_READY 0x04 /* number of input bytes available */ 62 #define GFTTY_CMD 0x08 /* command */ 63 #define GFTTY_DATA_PTR 0x10 /* DMA pointer */ 64 #define GFTTY_DATA_LEN 0x14 /* DMA length */ 65 #define GFTTY_DATA_PTR_HIGH 0x18 /* DMA pointer (64-bit) */ 66 #define GFTTY_VERSION 0x20 /* TTY version */ 67 68 #define CMD_INT_DISABLE 0x00 69 #define CMD_INT_ENABLE 0x01 70 #define CMD_WRITE_BUFFER 0x02 71 #define CMD_READ_BUFFER 0x03 72 73 #define REG_READ0(c, r) \ 74 bus_space_read_4((c)->c_bst, (c)->c_bsh, (r)) 75 #define REG_WRITE0(c, r, v) \ 76 bus_space_write_4((c)->c_bst, (c)->c_bsh, (r), (v)) 77 78 #define REG_READ(sc, r) REG_READ0((sc)->sc_config, (r)) 79 #define REG_WRITE(sc, r, v) REG_WRITE0((sc)->sc_config, (r), (v)) 80 81 static int gftty_cngetc(dev_t); 82 static void gftty_cnputc(dev_t, int); 83 static void gftty_cnpollc(dev_t, int); 84 85 static struct gftty_config gftty_cnconfig; 86 static struct cnm_state gftty_cnmagic_state; 87 static struct consdev gftty_consdev = { 88 .cn_getc = gftty_cngetc, 89 .cn_putc = gftty_cnputc, 90 .cn_pollc = gftty_cnpollc, 91 .cn_dev = NODEV, 92 .cn_pri = CN_NORMAL, 93 }; 94 95 static dev_type_open(gftty_open); 96 static dev_type_close(gftty_close); 97 static dev_type_read(gftty_read); 98 static dev_type_write(gftty_write); 99 static dev_type_ioctl(gftty_ioctl); 100 static dev_type_stop(gftty_stop); 101 static dev_type_tty(gftty_tty); 102 static dev_type_poll(gftty_poll); 103 104 const struct cdevsw gftty_cdevsw = { 105 .d_open = gftty_open, 106 .d_close = gftty_close, 107 .d_read = gftty_read, 108 .d_write = gftty_write, 109 .d_ioctl = gftty_ioctl, 110 .d_stop = gftty_stop, 111 .d_tty = gftty_tty, 112 .d_poll = gftty_poll, 113 .d_mmap = nommap, 114 .d_kqfilter = ttykqfilter, 115 .d_discard = nodiscard, 116 .d_flag = D_TTY, 117 }; 118 119 static void gftty_start(struct tty *); 120 static int gftty_param_locked(struct tty *, struct termios *); 121 static int gftty_param(struct tty *, struct termios *); 122 123 static void gftty_softrx(void *); 124 125 #define GFTTY_UNIT(x) minor(x) 126 #define GFTTY_DMASIZE (64 * 1024) /* XXX TTY_MAXQSIZE */ 127 #define GFTTY_MAXSEGS ((GFTTY_DMASIZE / PAGE_SIZE) + 1) 128 #define GFTTY_RXBUFSIZE 128 129 #define GFTTY_RXBUFALLOC (128 << 1) 130 131 static void 132 gftty_reset_rxptrs(struct gftty_softc *sc) 133 { 134 sc->sc_rxpos = 0; 135 sc->sc_rxcur = 0; 136 sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur]; 137 sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur]; 138 } 139 140 /* 141 * gftty_attach -- 142 * Attach a Goldfish virual TTY. 143 */ 144 void 145 gftty_attach(struct gftty_softc *sc) 146 { 147 device_t self = sc->sc_dev; 148 int error; 149 bool is_console; 150 151 aprint_naive("\n"); 152 aprint_normal(": Google Goldfish TTY\n"); 153 154 /* If we got here without a config, we're the console. */ 155 if ((is_console = (sc->sc_config == NULL))) { 156 KASSERT(gftty_is_console(sc)); 157 sc->sc_config = &gftty_cnconfig; 158 aprint_normal_dev(sc->sc_dev, "console\n"); 159 } 160 161 if (sc->sc_config->c_version == 0) { 162 aprint_normal_dev(self, 163 "WARNING: version 0 device -- uncharted territory!\n"); 164 } 165 166 /* Register our Rx soft interrupt. */ 167 sc->sc_rx_si = softint_establish(SOFTINT_SERIAL, gftty_softrx, sc); 168 if (sc->sc_rx_si == NULL) { 169 aprint_error_dev(self, 170 "Unable to register software interrupt.\n"); 171 return; 172 } 173 174 error = bus_dmamap_create(sc->sc_dmat, GFTTY_DMASIZE, 175 GFTTY_MAXSEGS, GFTTY_DMASIZE, 0, BUS_DMA_WAITOK, 176 &sc->sc_tx_dma); 177 if (error != 0) { 178 aprint_error_dev(self, 179 "unable to create Tx DMA map, error %d.\n", error); 180 return; 181 } 182 error = bus_dmamap_create(sc->sc_dmat, GFTTY_RXBUFALLOC, 183 1, GFTTY_RXBUFALLOC, 0, BUS_DMA_WAITOK, 184 &sc->sc_rx_dma); 185 if (error != 0) { 186 aprint_error_dev(self, 187 "unable to create Rx DMA map, error %d.\n", error); 188 bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dma); 189 sc->sc_tx_dma = NULL; 190 return; 191 } 192 193 sc->sc_rxbuf = kmem_zalloc(GFTTY_RXBUFALLOC, KM_SLEEP); 194 error = bus_dmamap_load(sc->sc_dmat, sc->sc_rx_dma, 195 sc->sc_rxbuf, GFTTY_RXBUFALLOC, NULL, BUS_DMA_WAITOK); 196 if (error != 0) { 197 aprint_error_dev(self, 198 "unable to load Rx DMA map, error %d.\n", error); 199 kmem_free(sc->sc_rxbuf, GFTTY_RXBUFALLOC); 200 bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_dma); 201 sc->sc_rx_dma = NULL; 202 bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dma); 203 sc->sc_tx_dma = NULL; 204 return; 205 } 206 sc->sc_rxbufs[0] = sc->sc_rxbuf; 207 sc->sc_rxbufs[1] = sc->sc_rxbufs[0] + GFTTY_RXBUFSIZE; 208 if (sc->sc_config->c_version == 0) { 209 sc->sc_rxaddrs[0] = (bus_addr_t)sc->sc_rxbufs[0]; 210 } else { 211 sc->sc_rxaddrs[0] = sc->sc_rx_dma->dm_segs[0].ds_addr; 212 } 213 sc->sc_rxaddrs[1] = sc->sc_rxaddrs[0] + GFTTY_RXBUFSIZE; 214 gftty_reset_rxptrs(sc); 215 216 struct tty *tp = tty_alloc(); 217 tp->t_oproc = gftty_start; 218 tp->t_param = gftty_param; 219 tp->t_softc = sc; 220 221 mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_TTY); 222 223 if (is_console) { 224 /* Locate the major number. */ 225 int maj = cdevsw_lookup_major(&gftty_cdevsw); 226 tp->t_dev = cn_tab->cn_dev = makedev(maj, device_unit(self)); 227 } 228 229 mutex_spin_enter(&tty_lock); 230 sc->sc_tty = tp; 231 mutex_spin_exit(&tty_lock); 232 233 tty_attach(tp); 234 } 235 236 /* 237 * gftty_is_console -- 238 * Returns true if the specified gftty instance is currently 239 * the console. 240 */ 241 bool 242 gftty_is_console(struct gftty_softc *sc) 243 { 244 if (cn_tab == &gftty_consdev) { 245 return device_getprop_bool(sc->sc_dev, "is-console"); 246 } 247 return false; 248 } 249 250 /* 251 * gftty_init_config -- 252 * Initialize a config structure. 253 */ 254 static void 255 gftty_init_config(struct gftty_config *c, bus_space_tag_t bst, 256 bus_space_handle_t bsh) 257 { 258 c->c_bst = bst; 259 c->c_bsh = bsh; 260 c->c_version = REG_READ0(c, GFTTY_VERSION); 261 } 262 263 /* 264 * gftty_alloc_config -- 265 * Allocate a config structure, initialize it, and assign 266 * it to this device. 267 */ 268 void 269 gftty_alloc_config(struct gftty_softc *sc, bus_space_tag_t bst, 270 bus_space_handle_t bsh) 271 { 272 struct gftty_config *c = kmem_zalloc(sizeof(*c), KM_SLEEP); 273 274 gftty_init_config(c, bst, bsh); 275 sc->sc_config = c; 276 } 277 278 /* 279 * gftty_set_buffer -- 280 * Set the buffer address / length for an I/O operation. 281 */ 282 static void 283 gftty_set_buffer(struct gftty_config *c, bus_addr_t addr, bus_size_t size) 284 { 285 REG_WRITE0(c, GFTTY_DATA_PTR, BUS_ADDR_LO32(addr)); 286 if (sizeof(bus_addr_t) == 8) { 287 REG_WRITE0(c, GFTTY_DATA_PTR_HIGH, BUS_ADDR_HI32(addr)); 288 } 289 REG_WRITE0(c, GFTTY_DATA_LEN, (uint32_t)size); 290 } 291 292 /* 293 * gftty_flush -- 294 * Flush input bytes. 295 */ 296 static bool 297 gftty_flush(struct gftty_softc *sc) 298 { 299 uint32_t count; 300 bool claimed = false; 301 302 KASSERT(ttylocked(sc->sc_tty)); 303 304 mutex_spin_enter(&sc->sc_hwlock); 305 306 while ((count = REG_READ(sc, GFTTY_BYTES_READY)) != 0) { 307 claimed = true; 308 if (count > GFTTY_RXBUFALLOC) { 309 count = GFTTY_RXBUFALLOC; 310 } 311 gftty_set_buffer(sc->sc_config, 312 sc->sc_rx_dma->dm_segs[0].ds_addr, count); 313 REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER); 314 } 315 316 mutex_spin_exit(&sc->sc_hwlock); 317 318 gftty_reset_rxptrs(sc); 319 320 return claimed; 321 } 322 323 /* 324 * gftty_rx -- 325 * Receive from the virtual TTY. 326 */ 327 static bool 328 gftty_rx(struct gftty_softc *sc) 329 { 330 uint32_t count, avail; 331 bool claimed = false; 332 333 KASSERT(ttylocked(sc->sc_tty)); 334 335 mutex_spin_enter(&sc->sc_hwlock); 336 337 count = REG_READ(sc, GFTTY_BYTES_READY); 338 if (count != 0) { 339 claimed = true; 340 avail = GFTTY_RXBUFSIZE - sc->sc_rxpos; 341 if (count > avail) { 342 /* 343 * Receive what we can, but disable the interrupt 344 * until the buffer can be drained. 345 */ 346 REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE); 347 count = avail; 348 } 349 if (count != 0) { 350 bus_addr_t syncoff = 351 (sc->sc_rxaddr - sc->sc_rxaddrs[0]) + sc->sc_rxpos; 352 353 bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma, 354 syncoff, count, BUS_DMASYNC_PREREAD); 355 gftty_set_buffer(sc->sc_config, 356 sc->sc_rxaddr + sc->sc_rxpos, count); 357 REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER); 358 sc->sc_rxpos += count; 359 bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma, 360 syncoff, count, BUS_DMASYNC_POSTREAD); 361 } 362 softint_schedule(sc->sc_rx_si); 363 } 364 365 mutex_spin_exit(&sc->sc_hwlock); 366 367 return claimed; 368 } 369 370 /* 371 * gftty_softrx -- 372 * Software interrupt to comple Rx processing. 373 */ 374 static void 375 gftty_softrx(void *v) 376 { 377 struct gftty_softc *sc = v; 378 struct tty *tp = sc->sc_tty; 379 int i, len; 380 char *cp; 381 382 ttylock(tp); 383 cp = sc->sc_rxbuf; 384 len = sc->sc_rxpos; 385 sc->sc_rxcur ^= 1; 386 sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur]; 387 sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur]; 388 sc->sc_rxpos = 0; 389 if (ISSET(tp->t_state, TS_ISOPEN)) { 390 REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE); 391 } 392 ttyunlock(tp); 393 394 for (i = 0; i < len; i++) { 395 (*tp->t_linesw->l_rint)(*cp++, tp); 396 } 397 } 398 399 /* 400 * gftty_intr -- 401 * Interrupt service routine. 402 */ 403 int 404 gftty_intr(void *v) 405 { 406 struct gftty_softc *sc = v; 407 struct tty *tp = sc->sc_tty; 408 bool claimed; 409 410 ttylock(tp); 411 if (ISSET(tp->t_state, TS_ISOPEN)) { 412 claimed = gftty_rx(sc); 413 } else { 414 claimed = gftty_flush(sc); 415 } 416 ttyunlock(tp); 417 418 return claimed; 419 } 420 421 /* 422 * gftty_open -- 423 * cdevsw open routine. 424 */ 425 static int 426 gftty_open(dev_t dev, int flag, int mode, struct lwp *l) 427 { 428 struct gftty_softc *sc = 429 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 430 struct tty *tp; 431 432 if (sc == NULL) { 433 return ENXIO; 434 } 435 436 mutex_spin_enter(&tty_lock); 437 tp = sc->sc_tty; 438 mutex_spin_exit(&tty_lock); 439 if (tp == NULL) { 440 return ENXIO; 441 } 442 443 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) { 444 return EBUSY; 445 } 446 447 ttylock(tp); 448 449 if (ISSET(tp->t_state, TS_KERN_ONLY)) { 450 ttyunlock(tp); 451 return EBUSY; 452 } 453 454 tp->t_oproc = gftty_start; 455 tp->t_param = gftty_param; 456 tp->t_dev = dev; 457 458 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 459 struct termios t; 460 461 ttychars(tp); 462 tp->t_iflag = TTYDEF_IFLAG; 463 tp->t_oflag = TTYDEF_OFLAG; 464 tp->t_lflag = TTYDEF_LFLAG; 465 t.c_cflag = TTYDEF_CFLAG; 466 t.c_ispeed = t.c_ospeed = TTYDEF_SPEED; 467 (void) gftty_param_locked(tp, &t); 468 ttsetwater(tp); 469 470 gftty_flush(sc); 471 REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE); 472 } 473 SET(tp->t_state, TS_CARR_ON); 474 475 ttyunlock(tp); 476 477 int error = ttyopen(tp, 0, ISSET(flag, O_NONBLOCK)); 478 if (error == 0) { 479 error = (*tp->t_linesw->l_open)(dev, tp); 480 if (error != 0) { 481 ttyclose(tp); 482 } 483 } 484 485 if (error != 0 && 486 !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 487 REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE); 488 } 489 490 return error; 491 } 492 493 /* 494 * gftty_close -- 495 * cdevsw close routine. 496 */ 497 static int 498 gftty_close(dev_t dev, int flag, int mode, struct lwp *l) 499 { 500 struct gftty_softc *sc = 501 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 502 503 KASSERT(sc != NULL); 504 505 struct tty *tp = sc->sc_tty; 506 507 ttylock(tp); 508 509 /* XXX This is for cons.c. */ 510 if (!ISSET(tp->t_state, TS_ISOPEN)) { 511 ttyunlock(tp); 512 return 0; 513 } 514 515 if (ISSET(tp->t_state, TS_KERN_ONLY)) { 516 ttyunlock(tp); 517 return 0; 518 } 519 520 ttyunlock(tp); 521 522 (*tp->t_linesw->l_close)(tp, flag); 523 ttyclose(tp); 524 525 ttylock(tp); 526 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 527 REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE); 528 } 529 ttyunlock(tp); 530 531 return 0; 532 } 533 534 /* 535 * gftty_read -- 536 * cdevsw read routine. 537 */ 538 static int 539 gftty_read(dev_t dev, struct uio *uio, int flag) 540 { 541 struct gftty_softc *sc = 542 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 543 544 KASSERT(sc != NULL); 545 546 struct tty *tp = sc->sc_tty; 547 return (*tp->t_linesw->l_read)(tp, uio, flag); 548 } 549 550 /* 551 * gftty_write -- 552 * cdevsw write routine. 553 */ 554 static int 555 gftty_write(dev_t dev, struct uio *uio, int flag) 556 { 557 struct gftty_softc *sc = 558 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 559 560 KASSERT(sc != NULL); 561 562 struct tty *tp = sc->sc_tty; 563 return (*tp->t_linesw->l_write)(tp, uio, flag); 564 } 565 566 /* 567 * gftty_poll -- 568 * cdevsw poll routine. 569 */ 570 static int 571 gftty_poll(dev_t dev, int events, struct lwp *l) 572 { 573 struct gftty_softc *sc = 574 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 575 576 KASSERT(sc != NULL); 577 578 struct tty *tp = sc->sc_tty; 579 return (*tp->t_linesw->l_poll)(tp, events, l); 580 } 581 582 /* 583 * gftty_tty -- 584 * cdevsw tty routine. 585 */ 586 static struct tty * 587 gftty_tty(dev_t dev) 588 { 589 struct gftty_softc *sc = 590 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 591 592 KASSERT(sc != NULL); 593 594 return sc->sc_tty; 595 } 596 597 /* 598 * gftty_ioctl -- 599 * cdevsw ioctl routine. 600 */ 601 static int 602 gftty_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 603 { 604 struct gftty_softc *sc = 605 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 606 607 KASSERT(sc != NULL); 608 609 struct tty *tp = sc->sc_tty; 610 int error; 611 612 /* Do the line discipline ioctls first. */ 613 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 614 if (error != EPASSTHROUGH) { 615 return error; 616 } 617 618 /* Next, the TTY ioctls. */ 619 error = ttioctl(tp, cmd, data, flag, l); 620 if (error != EPASSTHROUGH) { 621 return error; 622 } 623 624 /* None at this layer. */ 625 return EPASSTHROUGH; 626 } 627 628 /* 629 * gftty_tx -- 630 * Transmit a buffer on the virtual TTY using DMA. 631 */ 632 static void 633 gftty_tx(struct gftty_softc *sc, void *buf, size_t len) 634 { 635 int error, i; 636 637 KASSERT(len <= GFTTY_DMASIZE); 638 639 error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dma, buf, len, 640 NULL, BUS_DMA_NOWAIT); 641 if (error) { 642 /* XXX report error */ 643 return; 644 } 645 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len, 646 BUS_DMASYNC_PREWRITE); 647 648 mutex_spin_enter(&sc->sc_hwlock); 649 for (i = 0; i < sc->sc_tx_dma->dm_nsegs; i++) { 650 gftty_set_buffer(sc->sc_config, 651 sc->sc_tx_dma->dm_segs[i].ds_addr, 652 sc->sc_tx_dma->dm_segs[i].ds_len); 653 REG_WRITE(sc, GFTTY_CMD, CMD_WRITE_BUFFER); 654 } 655 mutex_spin_exit(&sc->sc_hwlock); 656 657 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len, 658 BUS_DMASYNC_POSTWRITE); 659 bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dma); 660 } 661 662 /* 663 * gftty_start -- 664 * TTY oproc routine. 665 */ 666 static void 667 gftty_start(struct tty *tp) 668 { 669 struct gftty_softc *sc = tp->t_softc; 670 u_char *tbuf; 671 int n; 672 673 KASSERT(ttylocked(tp)); 674 675 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP) || 676 ttypull(tp) == 0) { 677 return; 678 } 679 SET(tp->t_state, TS_BUSY); 680 681 /* 682 * Drain the output from the ring buffer. This will normally 683 * be one contiguous chunk, but we have to do it in two pieces 684 * when the ring wraps. 685 */ 686 687 n = ndqb(&tp->t_outq, 0); 688 tbuf = tp->t_outq.c_cf; 689 gftty_tx(sc, tbuf, n); 690 ndflush(&tp->t_outq, n); 691 692 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 693 tbuf = tp->t_outq.c_cf; 694 gftty_tx(sc, tbuf, n); 695 ndflush(&tp->t_outq, n); 696 } 697 698 CLR(tp->t_state, TS_BUSY); 699 /* Come back if there's more to do. */ 700 if (ttypull(tp)) { 701 SET(tp->t_state, TS_TIMEOUT); 702 callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1); 703 } 704 } 705 706 /* 707 * gftty_stop -- 708 * cdevsw stop routine. 709 */ 710 static void 711 gftty_stop(struct tty *tp, int flag) 712 { 713 KASSERT(ttylocked(tp)); 714 715 if (ISSET(tp->t_state, TS_BUSY)) { 716 if (!ISSET(tp->t_state, TS_TTSTOP)) { 717 SET(tp->t_state, TS_FLUSH); 718 } 719 } 720 } 721 722 /* 723 * gftty_param_locked -- 724 * Set TTY parameters. TTY must be locked. 725 */ 726 static int 727 gftty_param_locked(struct tty *tp, struct termios *t) 728 { 729 730 KASSERT(ttylocked(tp)); 731 732 tp->t_ispeed = t->c_ispeed; 733 tp->t_ospeed = t->c_ospeed; 734 tp->t_cflag = t->c_cflag; 735 736 return 0; 737 } 738 739 /* 740 * gftty_param -- 741 * TTY param routine. 742 */ 743 static int 744 gftty_param(struct tty *tp, struct termios *t) 745 { 746 int rv; 747 748 ttylock(tp); 749 rv = gftty_param_locked(tp, t); 750 ttyunlock(tp); 751 752 return rv; 753 } 754 755 /* 756 * gftty console routines. 757 */ 758 static int 759 gftty_cngetc(dev_t dev) 760 { 761 struct gftty_config * const c = &gftty_cnconfig; 762 763 if (REG_READ0(c, GFTTY_BYTES_READY) == 0) { 764 return -1; 765 } 766 767 /* 768 * XXX This is all terrible and should burn to the ground. 769 * XXX This device desperately needs to be improved with 770 * XXX a GET_CHAR register. 771 */ 772 bus_addr_t addr; 773 uint8_t buf[1]; 774 775 if (c->c_version == 0) { 776 addr = (bus_addr_t)buf; 777 } else { 778 addr = vtophys((vaddr_t)buf); 779 } 780 781 gftty_set_buffer(c, addr, sizeof(buf)); 782 REG_WRITE0(c, GFTTY_CMD, CMD_READ_BUFFER); 783 784 return buf[0]; 785 } 786 787 static void 788 gftty_cnputc(dev_t dev, int ch) 789 { 790 REG_WRITE0(&gftty_cnconfig, GFTTY_PUT_CHAR, (unsigned char)ch); 791 } 792 793 static void 794 gftty_cnpollc(dev_t dev, int on) 795 { 796 /* XXX */ 797 } 798 799 /* 800 * gftty_cnattach -- 801 * Attach a Goldfish virtual TTY console. 802 */ 803 void 804 gftty_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh) 805 { 806 gftty_init_config(&gftty_cnconfig, bst, bsh); 807 808 cn_tab = &gftty_consdev; 809 cn_init_magic(&gftty_cnmagic_state); 810 cn_set_magic("+++++"); 811 } 812