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