Home | History | Annotate | Line # | Download | only in goldfish
      1 /*	$NetBSD: gftty.c,v 1.9 2026/11/10 03:05:01 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.9 2026/11/10 03:05:01 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 virtual 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 complete 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 	unsigned char *cp, ch;
    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 		ch = *cp++;
    396 		if (cn_check_magic(tp->t_dev, ch, &gftty_cnmagic_state)) {
    397 			continue;
    398 		}
    399 		(*tp->t_linesw->l_rint)(ch, tp);
    400 	}
    401 }
    402 
    403 /*
    404  * gftty_intr --
    405  *	Interrupt service routine.
    406  */
    407 int
    408 gftty_intr(void *v)
    409 {
    410 	struct gftty_softc *sc = v;
    411 	struct tty *tp = sc->sc_tty;
    412 	bool claimed;
    413 
    414 	ttylock(tp);
    415 	if (ISSET(tp->t_state, TS_ISOPEN)) {
    416 		claimed = gftty_rx(sc);
    417 	} else {
    418 		claimed = gftty_flush(sc);
    419 	}
    420 	ttyunlock(tp);
    421 
    422 	return claimed;
    423 }
    424 
    425 /*
    426  * gftty_open --
    427  *	cdevsw open routine.
    428  */
    429 static int
    430 gftty_open(dev_t dev, int flag, int mode, struct lwp *l)
    431 {
    432 	struct gftty_softc *sc =
    433 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    434 	struct tty *tp;
    435 
    436 	if (sc == NULL) {
    437 		return ENXIO;
    438 	}
    439 
    440 	mutex_spin_enter(&tty_lock);
    441 	tp = sc->sc_tty;
    442 	mutex_spin_exit(&tty_lock);
    443 	if (tp == NULL) {
    444 		return ENXIO;
    445 	}
    446 
    447 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
    448 		return EBUSY;
    449 	}
    450 
    451 	ttylock(tp);
    452 
    453 	if (ISSET(tp->t_state, TS_KERN_ONLY)) {
    454 		ttyunlock(tp);
    455 		return EBUSY;
    456 	}
    457 
    458 	tp->t_oproc = gftty_start;
    459 	tp->t_param = gftty_param;
    460 	tp->t_dev = dev;
    461 
    462 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    463 		struct termios t;
    464 
    465 		ttychars(tp);
    466 		tp->t_iflag = TTYDEF_IFLAG;
    467 		tp->t_oflag = TTYDEF_OFLAG;
    468 		tp->t_lflag = TTYDEF_LFLAG;
    469 		t.c_cflag = TTYDEF_CFLAG;
    470 		t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
    471 		(void) gftty_param_locked(tp, &t);
    472 		ttsetwater(tp);
    473 
    474 		gftty_flush(sc);
    475 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE);
    476 	}
    477 	SET(tp->t_state, TS_CARR_ON);
    478 
    479 	ttyunlock(tp);
    480 
    481 	int error = ttyopen(tp, 0, ISSET(flag, O_NONBLOCK));
    482 	if (error == 0) {
    483 		error = (*tp->t_linesw->l_open)(dev, tp);
    484 		if (error != 0) {
    485 			ttyclose(tp);
    486 		}
    487 	}
    488 
    489 	if (error != 0 &&
    490 	    !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    491 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
    492 	}
    493 
    494 	return error;
    495 }
    496 
    497 /*
    498  * gftty_close --
    499  *	cdevsw close routine.
    500  */
    501 static int
    502 gftty_close(dev_t dev, int flag, int mode, struct lwp *l)
    503 {
    504 	struct gftty_softc *sc =
    505 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    506 
    507 	KASSERT(sc != NULL);
    508 
    509 	struct tty *tp = sc->sc_tty;
    510 
    511 	ttylock(tp);
    512 
    513 	/* XXX This is for cons.c. */
    514 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
    515 		ttyunlock(tp);
    516 		return 0;
    517 	}
    518 
    519 	if (ISSET(tp->t_state, TS_KERN_ONLY)) {
    520 		ttyunlock(tp);
    521 		return 0;
    522 	}
    523 
    524 	ttyunlock(tp);
    525 
    526 	(*tp->t_linesw->l_close)(tp, flag);
    527 	ttyclose(tp);
    528 
    529 	ttylock(tp);
    530 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    531 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
    532 	}
    533 	ttyunlock(tp);
    534 
    535 	return 0;
    536 }
    537 
    538 /*
    539  * gftty_read --
    540  *	cdevsw read routine.
    541  */
    542 static int
    543 gftty_read(dev_t dev, struct uio *uio, int flag)
    544 {
    545 	struct gftty_softc *sc =
    546 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    547 
    548 	KASSERT(sc != NULL);
    549 
    550 	struct tty *tp = sc->sc_tty;
    551 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    552 }
    553 
    554 /*
    555  * gftty_write --
    556  *	cdevsw write routine.
    557  */
    558 static int
    559 gftty_write(dev_t dev, struct uio *uio, int flag)
    560 {
    561 	struct gftty_softc *sc =
    562 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    563 
    564 	KASSERT(sc != NULL);
    565 
    566 	struct tty *tp = sc->sc_tty;
    567 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    568 }
    569 
    570 /*
    571  * gftty_poll --
    572  *	cdevsw poll routine.
    573  */
    574 static int
    575 gftty_poll(dev_t dev, int events, struct lwp *l)
    576 {
    577 	struct gftty_softc *sc =
    578 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    579 
    580 	KASSERT(sc != NULL);
    581 
    582 	struct tty *tp = sc->sc_tty;
    583 	return (*tp->t_linesw->l_poll)(tp, events, l);
    584 }
    585 
    586 /*
    587  * gftty_tty --
    588  *	cdevsw tty routine.
    589  */
    590 static struct tty *
    591 gftty_tty(dev_t dev)
    592 {
    593 	struct gftty_softc *sc =
    594 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    595 
    596 	KASSERT(sc != NULL);
    597 
    598 	return sc->sc_tty;
    599 }
    600 
    601 /*
    602  * gftty_ioctl --
    603  *	cdevsw ioctl routine.
    604  */
    605 static int
    606 gftty_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    607 {
    608 	struct gftty_softc *sc =
    609 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
    610 
    611 	KASSERT(sc != NULL);
    612 
    613 	struct tty *tp = sc->sc_tty;
    614 	int error;
    615 
    616 	/* Do the line discipline ioctls first. */
    617 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    618 	if (error != EPASSTHROUGH) {
    619 		return error;
    620 	}
    621 
    622 	/* Next, the TTY ioctls. */
    623 	error = ttioctl(tp, cmd, data, flag, l);
    624 	if (error != EPASSTHROUGH) {
    625 		return error;
    626 	}
    627 
    628 	/* None at this layer. */
    629 	return EPASSTHROUGH;
    630 }
    631 
    632 /*
    633  * gftty_tx --
    634  *	Transmit a buffer on the virtual TTY using DMA.
    635  */
    636 static void
    637 gftty_tx(struct gftty_softc *sc, void *buf, size_t len)
    638 {
    639 	int error, i;
    640 
    641 	KASSERT(len <= GFTTY_DMASIZE);
    642 
    643 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dma, buf, len,
    644 	    NULL, BUS_DMA_NOWAIT);
    645 	if (error) {
    646 		/* XXX report error */
    647 		return;
    648 	}
    649 	bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len,
    650 	    BUS_DMASYNC_PREWRITE);
    651 
    652 	mutex_spin_enter(&sc->sc_hwlock);
    653 	for (i = 0; i < sc->sc_tx_dma->dm_nsegs; i++) {
    654 		gftty_set_buffer(sc->sc_config,
    655 		    sc->sc_tx_dma->dm_segs[i].ds_addr,
    656 		    sc->sc_tx_dma->dm_segs[i].ds_len);
    657 		REG_WRITE(sc, GFTTY_CMD, CMD_WRITE_BUFFER);
    658 	}
    659 	mutex_spin_exit(&sc->sc_hwlock);
    660 
    661 	bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len,
    662 	    BUS_DMASYNC_POSTWRITE);
    663 	bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dma);
    664 }
    665 
    666 /*
    667  * gftty_start --
    668  *	TTY oproc routine.
    669  */
    670 static void
    671 gftty_start(struct tty *tp)
    672 {
    673 	struct gftty_softc *sc = tp->t_softc;
    674 	u_char *tbuf;
    675 	int n;
    676 
    677 	KASSERT(ttylocked(tp));
    678 
    679 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP) ||
    680 	    ttypull(tp) == 0) {
    681 		return;
    682 	}
    683 	SET(tp->t_state, TS_BUSY);
    684 
    685 	/*
    686 	 * Drain the output from the ring buffer.  This will normally
    687 	 * be one contiguous chunk, but we have to do it in two pieces
    688 	 * when the ring wraps.
    689 	 */
    690 
    691 	n = ndqb(&tp->t_outq, 0);
    692 	tbuf = tp->t_outq.c_cf;
    693 	gftty_tx(sc, tbuf, n);
    694 	ndflush(&tp->t_outq, n);
    695 
    696 	if ((n = ndqb(&tp->t_outq, 0)) > 0) {
    697 		tbuf = tp->t_outq.c_cf;
    698 		gftty_tx(sc, tbuf, n);
    699 		ndflush(&tp->t_outq, n);
    700 	}
    701 
    702 	CLR(tp->t_state, TS_BUSY);
    703 	/* Come back if there's more to do. */
    704 	if (ttypull(tp)) {
    705 		SET(tp->t_state, TS_TIMEOUT);
    706 		callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1);
    707 	}
    708 }
    709 
    710 /*
    711  * gftty_stop --
    712  *	cdevsw stop routine.
    713  */
    714 static void
    715 gftty_stop(struct tty *tp, int flag)
    716 {
    717 	KASSERT(ttylocked(tp));
    718 
    719 	if (ISSET(tp->t_state, TS_BUSY)) {
    720 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
    721 			SET(tp->t_state, TS_FLUSH);
    722 		}
    723 	}
    724 }
    725 
    726 /*
    727  * gftty_param_locked --
    728  *	Set TTY parameters.  TTY must be locked.
    729  */
    730 static int
    731 gftty_param_locked(struct tty *tp, struct termios *t)
    732 {
    733 
    734 	KASSERT(ttylocked(tp));
    735 
    736 	tp->t_ispeed = t->c_ispeed;
    737 	tp->t_ospeed = t->c_ospeed;
    738 	tp->t_cflag = t->c_cflag;
    739 
    740 	return 0;
    741 }
    742 
    743 /*
    744  * gftty_param --
    745  *	TTY param routine.
    746  */
    747 static int
    748 gftty_param(struct tty *tp, struct termios *t)
    749 {
    750 	int rv;
    751 
    752 	ttylock(tp);
    753 	rv = gftty_param_locked(tp, t);
    754 	ttyunlock(tp);
    755 
    756 	return rv;
    757 }
    758 
    759 /*
    760  * gftty console routines.
    761  */
    762 static int
    763 gftty_cngetc(dev_t dev)
    764 {
    765 	struct gftty_config * const c = &gftty_cnconfig;
    766 
    767 	if (REG_READ0(c, GFTTY_BYTES_READY) == 0) {
    768 		return -1;
    769 	}
    770 
    771 	/*
    772 	 * XXX This is all terrible and should burn to the ground.
    773 	 * XXX This device desperately needs to be improved with
    774 	 * XXX a GET_CHAR register.
    775 	 */
    776 	bus_addr_t addr;
    777 	uint8_t buf[1];
    778 
    779 	if (c->c_version == 0) {
    780 		addr = (bus_addr_t)buf;
    781 	} else {
    782 		addr = vtophys((vaddr_t)buf);
    783 	}
    784 
    785 	gftty_set_buffer(c, addr, sizeof(buf));
    786 	REG_WRITE0(c, GFTTY_CMD, CMD_READ_BUFFER);
    787 
    788 	cn_check_magic(dev, buf[0], &gftty_cnmagic_state);
    789 
    790 	return buf[0];
    791 }
    792 
    793 static void
    794 gftty_cnputc(dev_t dev, int ch)
    795 {
    796 	REG_WRITE0(&gftty_cnconfig, GFTTY_PUT_CHAR, (unsigned char)ch);
    797 }
    798 
    799 static void
    800 gftty_cnpollc(dev_t dev, int on)
    801 {
    802 	/* XXX */
    803 }
    804 
    805 /*
    806  * gftty_cnattach --
    807  *	Attach a Goldfish virtual TTY console.
    808  */
    809 void
    810 gftty_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh)
    811 {
    812 	gftty_init_config(&gftty_cnconfig, bst, bsh);
    813 
    814 	cn_tab = &gftty_consdev;
    815 	cn_init_magic(&gftty_cnmagic_state);
    816 	cn_set_magic("+++++");
    817 }
    818