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_ */