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