Home | History | Annotate | Line # | Download | only in goldfish
      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