Module Name:    src
Committed By:   thorpej
Date:           Sat Jan  6 17:52:43 UTC 2024

Modified Files:
        src/sys/arch/virt68k/dev: gftty_mainbus.c
        src/sys/dev/goldfish: gftty.c gfttyvar.h

Log Message:
Put some meat on the bones of the Goldfish TTY driver.  Works well enough
for sysinst.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/virt68k/dev/gftty_mainbus.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/goldfish/gftty.c
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/goldfish/gfttyvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/virt68k/dev/gftty_mainbus.c
diff -u src/sys/arch/virt68k/dev/gftty_mainbus.c:1.1 src/sys/arch/virt68k/dev/gftty_mainbus.c:1.2
--- src/sys/arch/virt68k/dev/gftty_mainbus.c:1.1	Tue Jan  2 07:40:59 2024
+++ src/sys/arch/virt68k/dev/gftty_mainbus.c	Sat Jan  6 17:52:43 2024
@@ -1,7 +1,7 @@
-/*	$NetBSD: gftty_mainbus.c,v 1.1 2024/01/02 07:40:59 thorpej Exp $	*/
+/*	$NetBSD: gftty_mainbus.c,v 1.2 2024/01/06 17:52:43 thorpej Exp $	*/
 
 /*-
- * Copyright (c) 2023 The NetBSD Foundation, Inc.
+ * Copyright (c) 2023, 2024 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gftty_mainbus.c,v 1.1 2024/01/02 07:40:59 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gftty_mainbus.c,v 1.2 2024/01/06 17:52:43 thorpej Exp $");
 
 #include <sys/types.h>
 #include <sys/bus.h>
@@ -61,6 +61,7 @@ gftty_mainbus_attach(device_t parent, de
 {
 	struct gftty_softc * const sc = device_private(self);
 	struct mainbus_attach_args * const ma = aux;
+	char strbuf[INTR_STRING_BUFSIZE];
 
 	sc->sc_dev = self;
 
@@ -75,7 +76,21 @@ gftty_mainbus_attach(device_t parent, de
 		gftty_alloc_config(sc, ma->ma_st, bsh);
 	}
 
+	sc->sc_dmat = ma->ma_dmat;
+
 	gftty_attach(sc);
+	if (sc->sc_tty != NULL) {
+		/* Attach was successful. Set up interrupt. */
+		sc->sc_ih = intr_establish(gftty_intr, sc,
+		    ma->ma_irq, IPL_TTY, 0);
+		if (sc->sc_ih == NULL) {
+			aprint_error_dev(self,
+			    "couldn't install interrupt handler\n");
+			return;
+		}
+		aprint_normal_dev(self, "interrupting at %s\n",
+		    intr_string(sc->sc_ih, strbuf, sizeof(strbuf)));
+	}
 }
 
 CFATTACH_DECL_NEW(gftty_mainbus, sizeof(struct gftty_softc),

Index: src/sys/dev/goldfish/gftty.c
diff -u src/sys/dev/goldfish/gftty.c:1.2 src/sys/dev/goldfish/gftty.c:1.3
--- src/sys/dev/goldfish/gftty.c:1.2	Tue Jan  2 07:30:29 2024
+++ src/sys/dev/goldfish/gftty.c	Sat Jan  6 17:52:43 2024
@@ -1,7 +1,7 @@
-/*	$NetBSD: gftty.c,v 1.2 2024/01/02 07:30:29 thorpej Exp $	*/
+/*	$NetBSD: gftty.c,v 1.3 2024/01/06 17:52:43 thorpej Exp $	*/
 
 /*-     
- * Copyright (c) 2023 The NetBSD Foundation, Inc.
+ * Copyright (c) 2023, 2024 The NetBSD Foundation, Inc.
  * All rights reserved.
  *              
  * This code is derived from software contributed to The NetBSD Foundation
@@ -34,13 +34,17 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gftty.c,v 1.2 2024/01/02 07:30:29 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gftty.c,v 1.3 2024/01/06 17:52:43 thorpej Exp $");
 
 #include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/device.h>
+#include <sys/kauth.h>
 #include <sys/kmem.h>
+#include <sys/tty.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -48,6 +52,8 @@ __KERNEL_RCSID(0, "$NetBSD: gftty.c,v 1.
 
 #include <dev/goldfish/gfttyvar.h>
 
+#include "ioconf.h"
+
 /*
  * Goldfish TTY registers.
  */
@@ -79,13 +85,58 @@ static void	gftty_cnpollc(dev_t, int);
 static struct gftty_config gftty_cnconfig;
 static struct cnm_state gftty_cnmagic_state;
 static struct consdev gftty_consdev = {
-	.cn_getc	=	gftty_cngetc,
-	.cn_putc	=	gftty_cnputc,
-	.cn_pollc	=	gftty_cnpollc,
-	.cn_dev		=	NODEV,
-	.cn_pri		=	CN_NORMAL,
+	.cn_getc  = gftty_cngetc,
+	.cn_putc  = gftty_cnputc,
+	.cn_pollc = gftty_cnpollc,
+	.cn_dev   = NODEV,
+	.cn_pri   = CN_NORMAL,
+};
+
+static dev_type_open(gftty_open);
+static dev_type_close(gftty_close);
+static dev_type_read(gftty_read);
+static dev_type_write(gftty_write);
+static dev_type_ioctl(gftty_ioctl);
+static dev_type_stop(gftty_stop);
+static dev_type_tty(gftty_tty);
+static dev_type_poll(gftty_poll);
+
+const struct cdevsw gftty_cdevsw = {
+	.d_open     = gftty_open,
+	.d_close    = gftty_close,
+	.d_read     = gftty_read,
+	.d_write    = gftty_write,
+	.d_ioctl    = gftty_ioctl,
+	.d_stop     = gftty_stop,
+	.d_tty      = gftty_tty,
+	.d_poll     = gftty_poll,
+	.d_mmap     = nommap,
+	.d_kqfilter = ttykqfilter,
+	.d_discard  = nodiscard,
+	.d_flag     = D_TTY,
 };
 
+static void	gftty_start(struct tty *);
+static int	gftty_param_locked(struct tty *, struct termios *);
+static int	gftty_param(struct tty *, struct termios *);
+
+static void	gftty_softrx(void *);
+
+#define	GFTTY_UNIT(x)		minor(x)
+#define	GFTTY_DMASIZE		(64 * 1024)	/* XXX TTY_MAXQSIZE */
+#define	GFTTY_MAXSEGS		((GFTTY_DMASIZE / PAGE_SIZE) + 1)
+#define	GFTTY_RXBUFSIZE		128
+#define	GFTTY_RXBUFALLOC	(128 << 1)
+
+static void
+gftty_reset_rxptrs(struct gftty_softc *sc)
+{
+	sc->sc_rxpos = 0;
+	sc->sc_rxcur = 0;
+	sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur];
+	sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur];
+}
+
 /*
  * gftty_attach --
  *	Attach a Goldfish virual TTY.
@@ -93,16 +144,93 @@ static struct consdev gftty_consdev = {
 void
 gftty_attach(struct gftty_softc *sc)
 {
+	device_t self = sc->sc_dev;
+	int error;
+	bool is_console;
 
 	aprint_naive("\n");
 	aprint_normal(": Google Goldfish TTY\n");
 
 	/* If we got here without a config, we're the console. */
-	if (sc->sc_config == NULL) {
+	if ((is_console = (sc->sc_config == NULL))) {
 		KASSERT(gftty_is_console(sc));
 		sc->sc_config = &gftty_cnconfig;
 		aprint_normal_dev(sc->sc_dev, "console\n");
 	}
+
+	if (sc->sc_config->c_version == 0) {
+		aprint_normal_dev(self,
+		    "WARNING: version 0 device -- uncharted territory!\n");
+	}
+
+	/* Register our Rx soft interrupt. */
+	sc->sc_rx_si = softint_establish(SOFTINT_SERIAL, gftty_softrx, sc);
+	if (sc->sc_rx_si == NULL) {
+		aprint_error_dev(self,
+		    "Unable to register software interrupt.\n");
+		return;
+	}
+
+	error = bus_dmamap_create(sc->sc_dmat, GFTTY_DMASIZE,
+	    GFTTY_MAXSEGS, GFTTY_DMASIZE, 0, BUS_DMA_WAITOK,
+	    &sc->sc_tx_dma);
+	if (error != 0) {
+		aprint_error_dev(self,
+		    "unable to create Tx DMA map, error %d.\n", error);
+		return;
+	}
+	error = bus_dmamap_create(sc->sc_dmat, GFTTY_RXBUFALLOC,
+	    1, GFTTY_RXBUFALLOC, 0, BUS_DMA_WAITOK,
+	    &sc->sc_rx_dma);
+	if (error != 0) {
+		aprint_error_dev(self,
+		    "unable to create Rx DMA map, error %d.\n", error);
+		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dma);
+		sc->sc_tx_dma = NULL;
+		return;
+	}
+
+	sc->sc_rxbuf = kmem_zalloc(GFTTY_RXBUFALLOC, KM_SLEEP);
+	error = bus_dmamap_load(sc->sc_dmat, sc->sc_rx_dma,
+	    sc->sc_rxbuf, GFTTY_RXBUFALLOC, NULL, BUS_DMA_WAITOK);
+	if (error != 0) {
+		aprint_error_dev(self,
+		    "unable to load Rx DMA map, error %d.\n", error);
+		kmem_free(sc->sc_rxbuf, GFTTY_RXBUFALLOC);
+		bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_dma);
+		sc->sc_rx_dma = NULL;
+		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dma);
+		sc->sc_tx_dma = NULL;
+		return;
+	}
+	sc->sc_rxbufs[0] = sc->sc_rxbuf;
+	sc->sc_rxbufs[1] = sc->sc_rxbufs[0] + GFTTY_RXBUFSIZE;
+	if (sc->sc_config->c_version == 0) {
+		sc->sc_rxaddrs[0] = (bus_addr_t)sc->sc_rxbufs[0];
+	} else {
+		sc->sc_rxaddrs[0] = sc->sc_rx_dma->dm_segs[0].ds_addr;
+	}
+	sc->sc_rxaddrs[1] = sc->sc_rxaddrs[0] + GFTTY_RXBUFSIZE;
+	gftty_reset_rxptrs(sc);
+
+	struct tty *tp = tty_alloc();
+	tp->t_oproc = gftty_start;
+	tp->t_param = gftty_param;
+	tp->t_softc = sc;
+
+	mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_TTY);
+
+	if (is_console) {
+		/* Locate the major number. */
+		int maj = cdevsw_lookup_major(&gftty_cdevsw);
+		tp->t_dev = cn_tab->cn_dev = makedev(maj, device_unit(self));
+	}
+
+	mutex_spin_enter(&tty_lock);
+	sc->sc_tty = tp;
+	mutex_spin_exit(&tty_lock);
+
+	tty_attach(tp);
 }
 
 /*
@@ -167,6 +295,469 @@ gftty_set_buffer(struct gftty_config *c,
 }
 
 /*
+ * gftty_flush --
+ *	Flush input bytes.
+ */
+static bool
+gftty_flush(struct gftty_softc *sc)
+{
+	uint32_t count;
+	bool claimed = false;
+
+	KASSERT(ttylocked(sc->sc_tty));
+
+	mutex_spin_enter(&sc->sc_hwlock);
+
+	while ((count = REG_READ(sc, GFTTY_BYTES_READY)) != 0) {
+		claimed = true;
+		if (count > GFTTY_RXBUFALLOC) {
+			count = GFTTY_RXBUFALLOC;
+		}
+		gftty_set_buffer(sc->sc_config,
+		    sc->sc_rx_dma->dm_segs[0].ds_addr, count);
+		REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER);
+	}
+
+	mutex_spin_exit(&sc->sc_hwlock);
+
+	gftty_reset_rxptrs(sc);
+
+	return claimed;
+}
+
+/*
+ * gftty_rx --
+ *	Receive from the virtual TTY.
+ */
+static bool
+gftty_rx(struct gftty_softc *sc)
+{
+	uint32_t count, avail;
+	bool claimed = false;
+
+	KASSERT(ttylocked(sc->sc_tty));
+
+	mutex_spin_enter(&sc->sc_hwlock);
+
+	count = REG_READ(sc, GFTTY_BYTES_READY);
+	if (count != 0) {
+		claimed = true;
+		avail = GFTTY_RXBUFSIZE - sc->sc_rxpos;
+		if (count > avail) {
+			/*
+			 * Receive what we can, but disable the interrupt
+			 * until the buffer can be drained.
+			 */
+			REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
+			count = avail;
+		}
+		if (count != 0) {
+			bus_addr_t syncoff =
+			    (sc->sc_rxaddr - sc->sc_rxaddrs[0]) + sc->sc_rxpos;
+
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma,
+			    syncoff, count, BUS_DMASYNC_PREREAD);
+			gftty_set_buffer(sc->sc_config,
+			    sc->sc_rxaddr + sc->sc_rxpos, count);
+			REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER);
+			sc->sc_rxpos += count;
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma,
+			    syncoff, count, BUS_DMASYNC_POSTREAD);
+		}
+		softint_schedule(sc->sc_rx_si);
+	}
+
+	mutex_spin_exit(&sc->sc_hwlock);
+
+	return claimed;
+}
+
+/*
+ * gftty_softrx --
+ *	Software interrupt to comple Rx processing.
+ */
+static void
+gftty_softrx(void *v)
+{
+	struct gftty_softc *sc = v;
+	struct tty *tp = sc->sc_tty;
+	int i, len;
+	char *cp;
+
+	ttylock(tp);
+	cp = sc->sc_rxbuf;
+	len = sc->sc_rxpos;
+	sc->sc_rxcur ^= 1;
+	sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur];
+	sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur];
+	sc->sc_rxpos = 0;
+	if (ISSET(tp->t_state, TS_ISOPEN)) {
+		REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE);
+	}
+	ttyunlock(tp);
+
+	for (i = 0; i < len; i++) {
+		(*tp->t_linesw->l_rint)(*cp++, tp);
+	}
+}
+
+/*
+ * gftty_intr --
+ *	Interrupt service routine.
+ */
+int
+gftty_intr(void *v)
+{
+	struct gftty_softc *sc = v;
+	struct tty *tp = sc->sc_tty;
+	bool claimed;
+
+	ttylock(tp);
+	if (ISSET(tp->t_state, TS_ISOPEN)) {
+		claimed = gftty_rx(sc);
+	} else {
+		claimed = gftty_flush(sc);
+	}
+	ttyunlock(tp);
+
+	return claimed;
+}
+
+/*
+ * gftty_open --
+ *	cdevsw open routine.
+ */
+static int
+gftty_open(dev_t dev, int flag, int mode, struct lwp *l)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+	struct tty *tp;
+
+	if (sc == NULL) {
+		return ENXIO;
+	}
+
+	mutex_spin_enter(&tty_lock);
+	tp = sc->sc_tty;
+	mutex_spin_exit(&tty_lock);
+	if (tp == NULL) {
+		return ENXIO;
+	}
+
+	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
+		return EBUSY;
+	}
+
+	ttylock(tp);
+
+	if (ISSET(tp->t_state, TS_KERN_ONLY)) {
+		ttyunlock(tp);
+		return EBUSY;
+	}
+
+	tp->t_oproc = gftty_start;
+	tp->t_param = gftty_param;
+	tp->t_dev = dev;
+
+	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+		struct termios t;
+
+		ttychars(tp);
+		tp->t_iflag = TTYDEF_IFLAG;
+		tp->t_oflag = TTYDEF_OFLAG;
+		tp->t_lflag = TTYDEF_LFLAG;
+		t.c_cflag = TTYDEF_CFLAG;
+		t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
+		(void) gftty_param_locked(tp, &t);
+		ttsetwater(tp);
+
+		gftty_flush(sc);
+		REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE);
+	}
+	SET(tp->t_state, TS_CARR_ON);
+
+	ttyunlock(tp);
+
+	int error = ttyopen(tp, 0, ISSET(flag, O_NONBLOCK));
+	if (error == 0) {
+		error = (*tp->t_linesw->l_open)(dev, tp);
+		if (error != 0) {
+			ttyclose(tp);
+		}
+	}
+
+	if (error != 0 &&
+	    !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+		REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
+	}
+
+	return error;
+}
+
+/*
+ * gftty_close --
+ *	cdevsw close routine.
+ */
+static int
+gftty_close(dev_t dev, int flag, int mode, struct lwp *l)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+
+	KASSERT(sc != NULL);
+
+	struct tty *tp = sc->sc_tty;
+
+	ttylock(tp);
+
+	/* XXX This is for cons.c. */
+	if (!ISSET(tp->t_state, TS_ISOPEN)) {
+		ttyunlock(tp);
+		return 0;
+	}
+
+	if (ISSET(tp->t_state, TS_KERN_ONLY)) {
+		ttyunlock(tp);
+		return 0;
+	}
+
+	ttyunlock(tp);
+
+	(*tp->t_linesw->l_close)(tp, flag);
+	ttyclose(tp);
+
+	ttylock(tp);
+	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+		REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
+	}
+	ttyunlock(tp);
+
+	return 0;
+}
+
+/*
+ * gftty_read --
+ *	cdevsw read routine.
+ */
+static int
+gftty_read(dev_t dev, struct uio *uio, int flag)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+
+	KASSERT(sc != NULL);
+
+	struct tty *tp = sc->sc_tty;
+	return (*tp->t_linesw->l_read)(tp, uio, flag);
+}
+
+/*
+ * gftty_write --
+ *	cdevsw write routine.
+ */
+static int
+gftty_write(dev_t dev, struct uio *uio, int flag)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+
+	KASSERT(sc != NULL);
+
+	struct tty *tp = sc->sc_tty;
+	return (*tp->t_linesw->l_write)(tp, uio, flag);
+}
+
+/*
+ * gftty_poll --
+ *	cdevsw poll routine.
+ */
+static int
+gftty_poll(dev_t dev, int events, struct lwp *l)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+
+	KASSERT(sc != NULL);
+
+	struct tty *tp = sc->sc_tty;
+	return (*tp->t_linesw->l_poll)(tp, events, l);
+}
+
+/*
+ * gftty_tty --
+ *	cdevsw tty routine.
+ */
+static struct tty *
+gftty_tty(dev_t dev)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+	
+	KASSERT(sc != NULL);
+
+	return sc->sc_tty;
+}
+
+/*
+ * gftty_ioctl --
+ *	cdevsw ioctl routine.
+ */
+static int
+gftty_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
+{
+	struct gftty_softc *sc =
+	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
+
+	KASSERT(sc != NULL);
+
+	struct tty *tp = sc->sc_tty;
+	int error;
+
+	/* Do the line discipline ioctls first. */
+	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
+	if (error != EPASSTHROUGH) {
+		return error;
+	}
+
+	/* Next, the TTY ioctls. */
+	error = ttioctl(tp, cmd, data, flag, l);
+	if (error != EPASSTHROUGH) {
+		return error;
+	}
+
+	/* None at this layer. */
+	return EPASSTHROUGH;
+}
+
+/*
+ * gftty_tx --
+ *	Transmit a buffer on the virtual TTY using DMA.
+ */
+static void
+gftty_tx(struct gftty_softc *sc, void *buf, size_t len)
+{
+	int error, i;
+
+	KASSERT(len <= GFTTY_DMASIZE);
+
+	error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dma, buf, len,
+	    NULL, BUS_DMA_NOWAIT);
+	if (error) {
+		/* XXX report error */
+		return;
+	}
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len,
+	    BUS_DMASYNC_PREWRITE);
+
+	mutex_spin_enter(&sc->sc_hwlock);
+	for (i = 0; i < sc->sc_tx_dma->dm_nsegs; i++) {
+		gftty_set_buffer(sc->sc_config,
+		    sc->sc_tx_dma->dm_segs[i].ds_addr,
+		    sc->sc_tx_dma->dm_segs[i].ds_len);
+		REG_WRITE(sc, GFTTY_CMD, CMD_WRITE_BUFFER);
+	}
+	mutex_spin_exit(&sc->sc_hwlock);
+
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len,
+	    BUS_DMASYNC_POSTWRITE);
+	bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dma);
+}
+
+/*
+ * gftty_start --
+ *	TTY oproc routine.
+ */
+static void
+gftty_start(struct tty *tp)
+{
+	struct gftty_softc *sc = tp->t_softc;
+	u_char *tbuf;
+	int n;
+
+	KASSERT(ttylocked(tp));
+
+	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP) ||
+	    ttypull(tp) == 0) {
+		return;
+	}
+	SET(tp->t_state, TS_BUSY);
+
+	/*
+	 * Drain the output from the ring buffer.  This will normally
+	 * be one contiguous chunk, but we have to do it in two pieces
+	 * when the ring wraps.
+	 */
+
+	n = ndqb(&tp->t_outq, 0);
+	tbuf = tp->t_outq.c_cf;
+	gftty_tx(sc, tbuf, n);
+	ndflush(&tp->t_outq, n);
+
+	if ((n = ndqb(&tp->t_outq, 0)) > 0) {
+		tbuf = tp->t_outq.c_cf;
+		gftty_tx(sc, tbuf, n);
+		ndflush(&tp->t_outq, n);
+	}
+
+	CLR(tp->t_state, TS_BUSY);
+	/* Come back if there's more to do. */
+	if (ttypull(tp)) {
+		SET(tp->t_state, TS_TIMEOUT);
+		callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1);
+	}
+}
+
+/*
+ * gftty_stop --
+ *	cdevsw stop routine.
+ */
+static void
+gftty_stop(struct tty *tp, int flag)
+{
+	KASSERT(ttylocked(tp));
+
+	if (ISSET(tp->t_state, TS_BUSY)) {
+		if (!ISSET(tp->t_state, TS_TTSTOP)) {
+			SET(tp->t_state, TS_FLUSH);
+		}
+	}
+}
+
+/*
+ * gftty_param_locked --
+ *	Set TTY parameters.  TTY must be locked.
+ */
+static int
+gftty_param_locked(struct tty *tp, struct termios *t)
+{
+
+	KASSERT(ttylocked(tp));
+
+	tp->t_ispeed = t->c_ispeed;
+	tp->t_ospeed = t->c_ospeed;
+	tp->t_cflag = t->c_cflag;
+
+	return 0;
+}
+
+/*
+ * gftty_param --
+ *	TTY param routine.
+ */
+static int
+gftty_param(struct tty *tp, struct termios *t)
+{
+	int rv;
+
+	ttylock(tp);
+	rv = gftty_param_locked(tp, t);
+	ttyunlock(tp);
+
+	return rv;
+}
+
+/*
  * gftty console routines.
  */
 static int

Index: src/sys/dev/goldfish/gfttyvar.h
diff -u src/sys/dev/goldfish/gfttyvar.h:1.1 src/sys/dev/goldfish/gfttyvar.h:1.2
--- src/sys/dev/goldfish/gfttyvar.h:1.1	Tue Jan  2 07:29:39 2024
+++ src/sys/dev/goldfish/gfttyvar.h	Sat Jan  6 17:52:43 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: gfttyvar.h,v 1.1 2024/01/02 07:29:39 thorpej Exp $	*/
+/*	$NetBSD: gfttyvar.h,v 1.2 2024/01/06 17:52:43 thorpej Exp $	*/
 
 /*-     
  * Copyright (c) 2023 The NetBSD Foundation, Inc.
@@ -32,6 +32,10 @@
 #ifndef _DEV_GOLDFISH_GFTTYVAR_H_
 #define	_DEV_GOLDFISH_GFTTYVAR_H_
 
+#include <sys/bus.h>
+#include <sys/mutex.h>
+#include <sys/tty.h>
+
 struct gftty_config {
 	bus_space_tag_t		c_bst;
 	bus_space_handle_t	c_bsh;
@@ -41,12 +45,30 @@ struct gftty_config {
 struct gftty_softc {
 	device_t		sc_dev;
 	struct gftty_config	*sc_config;
+
+	void			*sc_ih;
+	void			*sc_rx_si;
+
+	bus_dma_tag_t		sc_dmat;
+	bus_dmamap_t		sc_tx_dma;
+	bus_dmamap_t		sc_rx_dma;
+
+	kmutex_t		sc_hwlock;	/* locks DMA pointer */
+
+	struct tty		*sc_tty;
+	char			*sc_rxbufs[2];
+	bus_addr_t		sc_rxaddrs[2];
+	char			*sc_rxbuf;	/* tty lock */
+	bus_addr_t		sc_rxaddr;	/* tty lock */
+	int			sc_rxpos;	/* tty lock */
+	int			sc_rxcur;	/* tty lock */
 };
 
 void	gftty_attach(struct gftty_softc *sc);
 bool	gftty_is_console(struct gftty_softc *sc);
 void	gftty_alloc_config(struct gftty_softc *sc, bus_space_tag_t,
 	    bus_space_handle_t);
+int	gftty_intr(void *);
 void	gftty_cnattach(bus_space_tag_t, bus_space_handle_t);
 
 #endif /* _DEV_GOLDFISH_GFTTYVAR_H_ */

Reply via email to