1 /* $NetBSD: gftty.c,v 1.3 2024/01/06 17:52:43 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.3 2024/01/06 17:52:43 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 bool val; 246 247 if (prop_dictionary_get_bool(device_properties(sc->sc_dev), 248 "is-console", &val)) { 249 return val; 250 } 251 } 252 return false; 253 } 254 255 /* 256 * gftty_init_config -- 257 * Initialize a config structure. 258 */ 259 static void 260 gftty_init_config(struct gftty_config *c, bus_space_tag_t bst, 261 bus_space_handle_t bsh) 262 { 263 c->c_bst = bst; 264 c->c_bsh = bsh; 265 c->c_version = REG_READ0(c, GFTTY_VERSION); 266 } 267 268 /* 269 * gftty_alloc_config -- 270 * Allocate a config structure, initialize it, and assign 271 * it to this device. 272 */ 273 void 274 gftty_alloc_config(struct gftty_softc *sc, bus_space_tag_t bst, 275 bus_space_handle_t bsh) 276 { 277 struct gftty_config *c = kmem_zalloc(sizeof(*c), KM_SLEEP); 278 279 gftty_init_config(c, bst, bsh); 280 sc->sc_config = c; 281 } 282 283 /* 284 * gftty_set_buffer -- 285 * Set the buffer address / length for an I/O operation. 286 */ 287 static void 288 gftty_set_buffer(struct gftty_config *c, bus_addr_t addr, bus_size_t size) 289 { 290 REG_WRITE0(c, GFTTY_DATA_PTR, BUS_ADDR_LO32(addr)); 291 if (sizeof(bus_addr_t) == 8) { 292 REG_WRITE0(c, GFTTY_DATA_PTR_HIGH, BUS_ADDR_HI32(addr)); 293 } 294 REG_WRITE0(c, GFTTY_DATA_LEN, (uint32_t)size); 295 } 296 297 /* 298 * gftty_flush -- 299 * Flush input bytes. 300 */ 301 static bool 302 gftty_flush(struct gftty_softc *sc) 303 { 304 uint32_t count; 305 bool claimed = false; 306 307 KASSERT(ttylocked(sc->sc_tty)); 308 309 mutex_spin_enter(&sc->sc_hwlock); 310 311 while ((count = REG_READ(sc, GFTTY_BYTES_READY)) != 0) { 312 claimed = true; 313 if (count > GFTTY_RXBUFALLOC) { 314 count = GFTTY_RXBUFALLOC; 315 } 316 gftty_set_buffer(sc->sc_config, 317 sc->sc_rx_dma->dm_segs[0].ds_addr, count); 318 REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER); 319 } 320 321 mutex_spin_exit(&sc->sc_hwlock); 322 323 gftty_reset_rxptrs(sc); 324 325 return claimed; 326 } 327 328 /* 329 * gftty_rx -- 330 * Receive from the virtual TTY. 331 */ 332 static bool 333 gftty_rx(struct gftty_softc *sc) 334 { 335 uint32_t count, avail; 336 bool claimed = false; 337 338 KASSERT(ttylocked(sc->sc_tty)); 339 340 mutex_spin_enter(&sc->sc_hwlock); 341 342 count = REG_READ(sc, GFTTY_BYTES_READY); 343 if (count != 0) { 344 claimed = true; 345 avail = GFTTY_RXBUFSIZE - sc->sc_rxpos; 346 if (count > avail) { 347 /* 348 * Receive what we can, but disable the interrupt 349 * until the buffer can be drained. 350 */ 351 REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE); 352 count = avail; 353 } 354 if (count != 0) { 355 bus_addr_t syncoff = 356 (sc->sc_rxaddr - sc->sc_rxaddrs[0]) + sc->sc_rxpos; 357 358 bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma, 359 syncoff, count, BUS_DMASYNC_PREREAD); 360 gftty_set_buffer(sc->sc_config, 361 sc->sc_rxaddr + sc->sc_rxpos, count); 362 REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER); 363 sc->sc_rxpos += count; 364 bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma, 365 syncoff, count, BUS_DMASYNC_POSTREAD); 366 } 367 softint_schedule(sc->sc_rx_si); 368 } 369 370 mutex_spin_exit(&sc->sc_hwlock); 371 372 return claimed; 373 } 374 375 /* 376 * gftty_softrx -- 377 * Software interrupt to comple Rx processing. 378 */ 379 static void 380 gftty_softrx(void *v) 381 { 382 struct gftty_softc *sc = v; 383 struct tty *tp = sc->sc_tty; 384 int i, len; 385 char *cp; 386 387 ttylock(tp); 388 cp = sc->sc_rxbuf; 389 len = sc->sc_rxpos; 390 sc->sc_rxcur ^= 1; 391 sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur]; 392 sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur]; 393 sc->sc_rxpos = 0; 394 if (ISSET(tp->t_state, TS_ISOPEN)) { 395 REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE); 396 } 397 ttyunlock(tp); 398 399 for (i = 0; i < len; i++) { 400 (*tp->t_linesw->l_rint)(*cp++, tp); 401 } 402 } 403 404 /* 405 * gftty_intr -- 406 * Interrupt service routine. 407 */ 408 int 409 gftty_intr(void *v) 410 { 411 struct gftty_softc *sc = v; 412 struct tty *tp = sc->sc_tty; 413 bool claimed; 414 415 ttylock(tp); 416 if (ISSET(tp->t_state, TS_ISOPEN)) { 417 claimed = gftty_rx(sc); 418 } else { 419 claimed = gftty_flush(sc); 420 } 421 ttyunlock(tp); 422 423 return claimed; 424 } 425 426 /* 427 * gftty_open -- 428 * cdevsw open routine. 429 */ 430 static int 431 gftty_open(dev_t dev, int flag, int mode, struct lwp *l) 432 { 433 struct gftty_softc *sc = 434 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 435 struct tty *tp; 436 437 if (sc == NULL) { 438 return ENXIO; 439 } 440 441 mutex_spin_enter(&tty_lock); 442 tp = sc->sc_tty; 443 mutex_spin_exit(&tty_lock); 444 if (tp == NULL) { 445 return ENXIO; 446 } 447 448 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) { 449 return EBUSY; 450 } 451 452 ttylock(tp); 453 454 if (ISSET(tp->t_state, TS_KERN_ONLY)) { 455 ttyunlock(tp); 456 return EBUSY; 457 } 458 459 tp->t_oproc = gftty_start; 460 tp->t_param = gftty_param; 461 tp->t_dev = dev; 462 463 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 464 struct termios t; 465 466 ttychars(tp); 467 tp->t_iflag = TTYDEF_IFLAG; 468 tp->t_oflag = TTYDEF_OFLAG; 469 tp->t_lflag = TTYDEF_LFLAG; 470 t.c_cflag = TTYDEF_CFLAG; 471 t.c_ispeed = t.c_ospeed = TTYDEF_SPEED; 472 (void) gftty_param_locked(tp, &t); 473 ttsetwater(tp); 474 475 gftty_flush(sc); 476 REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE); 477 } 478 SET(tp->t_state, TS_CARR_ON); 479 480 ttyunlock(tp); 481 482 int error = ttyopen(tp, 0, ISSET(flag, O_NONBLOCK)); 483 if (error == 0) { 484 error = (*tp->t_linesw->l_open)(dev, tp); 485 if (error != 0) { 486 ttyclose(tp); 487 } 488 } 489 490 if (error != 0 && 491 !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 492 REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE); 493 } 494 495 return error; 496 } 497 498 /* 499 * gftty_close -- 500 * cdevsw close routine. 501 */ 502 static int 503 gftty_close(dev_t dev, int flag, int mode, struct lwp *l) 504 { 505 struct gftty_softc *sc = 506 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 507 508 KASSERT(sc != NULL); 509 510 struct tty *tp = sc->sc_tty; 511 512 ttylock(tp); 513 514 /* XXX This is for cons.c. */ 515 if (!ISSET(tp->t_state, TS_ISOPEN)) { 516 ttyunlock(tp); 517 return 0; 518 } 519 520 if (ISSET(tp->t_state, TS_KERN_ONLY)) { 521 ttyunlock(tp); 522 return 0; 523 } 524 525 ttyunlock(tp); 526 527 (*tp->t_linesw->l_close)(tp, flag); 528 ttyclose(tp); 529 530 ttylock(tp); 531 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 532 REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE); 533 } 534 ttyunlock(tp); 535 536 return 0; 537 } 538 539 /* 540 * gftty_read -- 541 * cdevsw read routine. 542 */ 543 static int 544 gftty_read(dev_t dev, struct uio *uio, int flag) 545 { 546 struct gftty_softc *sc = 547 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 548 549 KASSERT(sc != NULL); 550 551 struct tty *tp = sc->sc_tty; 552 return (*tp->t_linesw->l_read)(tp, uio, flag); 553 } 554 555 /* 556 * gftty_write -- 557 * cdevsw write routine. 558 */ 559 static int 560 gftty_write(dev_t dev, struct uio *uio, int flag) 561 { 562 struct gftty_softc *sc = 563 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 564 565 KASSERT(sc != NULL); 566 567 struct tty *tp = sc->sc_tty; 568 return (*tp->t_linesw->l_write)(tp, uio, flag); 569 } 570 571 /* 572 * gftty_poll -- 573 * cdevsw poll routine. 574 */ 575 static int 576 gftty_poll(dev_t dev, int events, struct lwp *l) 577 { 578 struct gftty_softc *sc = 579 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 580 581 KASSERT(sc != NULL); 582 583 struct tty *tp = sc->sc_tty; 584 return (*tp->t_linesw->l_poll)(tp, events, l); 585 } 586 587 /* 588 * gftty_tty -- 589 * cdevsw tty routine. 590 */ 591 static struct tty * 592 gftty_tty(dev_t dev) 593 { 594 struct gftty_softc *sc = 595 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 596 597 KASSERT(sc != NULL); 598 599 return sc->sc_tty; 600 } 601 602 /* 603 * gftty_ioctl -- 604 * cdevsw ioctl routine. 605 */ 606 static int 607 gftty_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 608 { 609 struct gftty_softc *sc = 610 device_lookup_private(&gftty_cd, GFTTY_UNIT(dev)); 611 612 KASSERT(sc != NULL); 613 614 struct tty *tp = sc->sc_tty; 615 int error; 616 617 /* Do the line discipline ioctls first. */ 618 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 619 if (error != EPASSTHROUGH) { 620 return error; 621 } 622 623 /* Next, the TTY ioctls. */ 624 error = ttioctl(tp, cmd, data, flag, l); 625 if (error != EPASSTHROUGH) { 626 return error; 627 } 628 629 /* None at this layer. */ 630 return EPASSTHROUGH; 631 } 632 633 /* 634 * gftty_tx -- 635 * Transmit a buffer on the virtual TTY using DMA. 636 */ 637 static void 638 gftty_tx(struct gftty_softc *sc, void *buf, size_t len) 639 { 640 int error, i; 641 642 KASSERT(len <= GFTTY_DMASIZE); 643 644 error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dma, buf, len, 645 NULL, BUS_DMA_NOWAIT); 646 if (error) { 647 /* XXX report error */ 648 return; 649 } 650 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len, 651 BUS_DMASYNC_PREWRITE); 652 653 mutex_spin_enter(&sc->sc_hwlock); 654 for (i = 0; i < sc->sc_tx_dma->dm_nsegs; i++) { 655 gftty_set_buffer(sc->sc_config, 656 sc->sc_tx_dma->dm_segs[i].ds_addr, 657 sc->sc_tx_dma->dm_segs[i].ds_len); 658 REG_WRITE(sc, GFTTY_CMD, CMD_WRITE_BUFFER); 659 } 660 mutex_spin_exit(&sc->sc_hwlock); 661 662 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len, 663 BUS_DMASYNC_POSTWRITE); 664 bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dma); 665 } 666 667 /* 668 * gftty_start -- 669 * TTY oproc routine. 670 */ 671 static void 672 gftty_start(struct tty *tp) 673 { 674 struct gftty_softc *sc = tp->t_softc; 675 u_char *tbuf; 676 int n; 677 678 KASSERT(ttylocked(tp)); 679 680 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP) || 681 ttypull(tp) == 0) { 682 return; 683 } 684 SET(tp->t_state, TS_BUSY); 685 686 /* 687 * Drain the output from the ring buffer. This will normally 688 * be one contiguous chunk, but we have to do it in two pieces 689 * when the ring wraps. 690 */ 691 692 n = ndqb(&tp->t_outq, 0); 693 tbuf = tp->t_outq.c_cf; 694 gftty_tx(sc, tbuf, n); 695 ndflush(&tp->t_outq, n); 696 697 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 698 tbuf = tp->t_outq.c_cf; 699 gftty_tx(sc, tbuf, n); 700 ndflush(&tp->t_outq, n); 701 } 702 703 CLR(tp->t_state, TS_BUSY); 704 /* Come back if there's more to do. */ 705 if (ttypull(tp)) { 706 SET(tp->t_state, TS_TIMEOUT); 707 callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1); 708 } 709 } 710 711 /* 712 * gftty_stop -- 713 * cdevsw stop routine. 714 */ 715 static void 716 gftty_stop(struct tty *tp, int flag) 717 { 718 KASSERT(ttylocked(tp)); 719 720 if (ISSET(tp->t_state, TS_BUSY)) { 721 if (!ISSET(tp->t_state, TS_TTSTOP)) { 722 SET(tp->t_state, TS_FLUSH); 723 } 724 } 725 } 726 727 /* 728 * gftty_param_locked -- 729 * Set TTY parameters. TTY must be locked. 730 */ 731 static int 732 gftty_param_locked(struct tty *tp, struct termios *t) 733 { 734 735 KASSERT(ttylocked(tp)); 736 737 tp->t_ispeed = t->c_ispeed; 738 tp->t_ospeed = t->c_ospeed; 739 tp->t_cflag = t->c_cflag; 740 741 return 0; 742 } 743 744 /* 745 * gftty_param -- 746 * TTY param routine. 747 */ 748 static int 749 gftty_param(struct tty *tp, struct termios *t) 750 { 751 int rv; 752 753 ttylock(tp); 754 rv = gftty_param_locked(tp, t); 755 ttyunlock(tp); 756 757 return rv; 758 } 759 760 /* 761 * gftty console routines. 762 */ 763 static int 764 gftty_cngetc(dev_t dev) 765 { 766 struct gftty_config * const c = &gftty_cnconfig; 767 768 if (REG_READ0(c, GFTTY_BYTES_READY) == 0) { 769 return -1; 770 } 771 772 /* 773 * XXX This is all terrible and should burn to the ground. 774 * XXX This device desperately needs to be improved with 775 * XXX a GET_CHAR register. 776 */ 777 bus_addr_t addr; 778 uint8_t buf[1]; 779 780 if (c->c_version == 0) { 781 addr = (bus_addr_t)buf; 782 } else { 783 addr = vtophys((vaddr_t)buf); 784 } 785 786 gftty_set_buffer(c, addr, sizeof(buf)); 787 REG_WRITE0(c, GFTTY_CMD, CMD_READ_BUFFER); 788 789 return buf[0]; 790 } 791 792 static void 793 gftty_cnputc(dev_t dev, int ch) 794 { 795 REG_WRITE0(&gftty_cnconfig, GFTTY_PUT_CHAR, (unsigned char)ch); 796 } 797 798 static void 799 gftty_cnpollc(dev_t dev, int on) 800 { 801 /* XXX */ 802 } 803 804 /* 805 * gftty_cnattach -- 806 * Attach a Goldfish virtual TTY console. 807 */ 808 void 809 gftty_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh) 810 { 811 gftty_init_config(&gftty_cnconfig, bst, bsh); 812 813 cn_tab = &gftty_consdev; 814 cn_init_magic(&gftty_cnmagic_state); 815 cn_set_magic("+++++"); 816 } 817