xref: /netbsd-src/sys/dev/goldfish/gftty.c (revision f7864055e3b51cf3158479b411229225af637e26)
1*f7864055Sthorpej /*	$NetBSD: gftty.c,v 1.3 2024/01/06 17:52:43 thorpej Exp $	*/
2bcb5d394Sthorpej 
3bcb5d394Sthorpej /*-
4*f7864055Sthorpej  * Copyright (c) 2023, 2024 The NetBSD Foundation, Inc.
5bcb5d394Sthorpej  * All rights reserved.
6bcb5d394Sthorpej  *
7bcb5d394Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
8bcb5d394Sthorpej  * by Jason R. Thorpe.
9bcb5d394Sthorpej  *
10bcb5d394Sthorpej  * Redistribution and use in source and binary forms, with or without
11bcb5d394Sthorpej  * modification, are permitted provided that the following conditions
12bcb5d394Sthorpej  * are met:
13bcb5d394Sthorpej  * 1. Redistributions of source code must retain the above copyright
14bcb5d394Sthorpej  *    notice, this list of conditions and the following disclaimer.
15bcb5d394Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
16bcb5d394Sthorpej  *    notice, this list of conditions and the following disclaimer in the
17bcb5d394Sthorpej  *    documentation and/or other materials provided with the distribution.
18bcb5d394Sthorpej  *
19bcb5d394Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20bcb5d394Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21bcb5d394Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22bcb5d394Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23bcb5d394Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24bcb5d394Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25bcb5d394Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26bcb5d394Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27bcb5d394Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28bcb5d394Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29bcb5d394Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
30bcb5d394Sthorpej  */
31bcb5d394Sthorpej 
32bcb5d394Sthorpej /*
330f1e0402Sthorpej  * Support for the Goldfish virtual TTY.
34bcb5d394Sthorpej  */
35bcb5d394Sthorpej 
36bcb5d394Sthorpej #include <sys/cdefs.h>
37*f7864055Sthorpej __KERNEL_RCSID(0, "$NetBSD: gftty.c,v 1.3 2024/01/06 17:52:43 thorpej Exp $");
38bcb5d394Sthorpej 
39bcb5d394Sthorpej #include <sys/param.h>
40*f7864055Sthorpej #include <sys/conf.h>
41*f7864055Sthorpej #include <sys/fcntl.h>
42bcb5d394Sthorpej #include <sys/systm.h>
43bcb5d394Sthorpej #include <sys/bus.h>
44bcb5d394Sthorpej #include <sys/device.h>
45*f7864055Sthorpej #include <sys/kauth.h>
46bcb5d394Sthorpej #include <sys/kmem.h>
47*f7864055Sthorpej #include <sys/tty.h>
48bcb5d394Sthorpej 
49bcb5d394Sthorpej #include <uvm/uvm_extern.h>
50bcb5d394Sthorpej 
51bcb5d394Sthorpej #include <dev/cons.h>
52bcb5d394Sthorpej 
53bcb5d394Sthorpej #include <dev/goldfish/gfttyvar.h>
54bcb5d394Sthorpej 
55*f7864055Sthorpej #include "ioconf.h"
56*f7864055Sthorpej 
57bcb5d394Sthorpej /*
58bcb5d394Sthorpej  * Goldfish TTY registers.
59bcb5d394Sthorpej  */
60bcb5d394Sthorpej #define	GFTTY_PUT_CHAR		0x00	/* 8 bit output value */
61bcb5d394Sthorpej #define	GFTTY_BYTES_READY	0x04	/* number of input bytes available */
62bcb5d394Sthorpej #define	GFTTY_CMD		0x08	/* command */
63bcb5d394Sthorpej #define	GFTTY_DATA_PTR		0x10	/* DMA pointer */
64bcb5d394Sthorpej #define	GFTTY_DATA_LEN		0x14	/* DMA length */
65bcb5d394Sthorpej #define	GFTTY_DATA_PTR_HIGH	0x18	/* DMA pointer (64-bit) */
66bcb5d394Sthorpej #define	GFTTY_VERSION		0x20	/* TTY version */
67bcb5d394Sthorpej 
68bcb5d394Sthorpej #define	CMD_INT_DISABLE		0x00
69bcb5d394Sthorpej #define	CMD_INT_ENABLE		0x01
70bcb5d394Sthorpej #define	CMD_WRITE_BUFFER	0x02
71bcb5d394Sthorpej #define	CMD_READ_BUFFER		0x03
72bcb5d394Sthorpej 
73bcb5d394Sthorpej #define	REG_READ0(c, r)		\
74bcb5d394Sthorpej 	bus_space_read_4((c)->c_bst, (c)->c_bsh, (r))
75bcb5d394Sthorpej #define	REG_WRITE0(c, r, v)	\
76bcb5d394Sthorpej 	bus_space_write_4((c)->c_bst, (c)->c_bsh, (r), (v))
77bcb5d394Sthorpej 
78bcb5d394Sthorpej #define	REG_READ(sc, r)		REG_READ0((sc)->sc_config, (r))
79bcb5d394Sthorpej #define	REG_WRITE(sc, r, v)	REG_WRITE0((sc)->sc_config, (r), (v))
80bcb5d394Sthorpej 
81bcb5d394Sthorpej static int	gftty_cngetc(dev_t);
82bcb5d394Sthorpej static void	gftty_cnputc(dev_t, int);
83bcb5d394Sthorpej static void	gftty_cnpollc(dev_t, int);
84bcb5d394Sthorpej 
85bcb5d394Sthorpej static struct gftty_config gftty_cnconfig;
86bcb5d394Sthorpej static struct cnm_state gftty_cnmagic_state;
87bcb5d394Sthorpej static struct consdev gftty_consdev = {
88bcb5d394Sthorpej 	.cn_getc  = gftty_cngetc,
89bcb5d394Sthorpej 	.cn_putc  = gftty_cnputc,
90bcb5d394Sthorpej 	.cn_pollc = gftty_cnpollc,
91bcb5d394Sthorpej 	.cn_dev   = NODEV,
92bcb5d394Sthorpej 	.cn_pri   = CN_NORMAL,
93bcb5d394Sthorpej };
94bcb5d394Sthorpej 
95*f7864055Sthorpej static dev_type_open(gftty_open);
96*f7864055Sthorpej static dev_type_close(gftty_close);
97*f7864055Sthorpej static dev_type_read(gftty_read);
98*f7864055Sthorpej static dev_type_write(gftty_write);
99*f7864055Sthorpej static dev_type_ioctl(gftty_ioctl);
100*f7864055Sthorpej static dev_type_stop(gftty_stop);
101*f7864055Sthorpej static dev_type_tty(gftty_tty);
102*f7864055Sthorpej static dev_type_poll(gftty_poll);
103*f7864055Sthorpej 
104*f7864055Sthorpej const struct cdevsw gftty_cdevsw = {
105*f7864055Sthorpej 	.d_open     = gftty_open,
106*f7864055Sthorpej 	.d_close    = gftty_close,
107*f7864055Sthorpej 	.d_read     = gftty_read,
108*f7864055Sthorpej 	.d_write    = gftty_write,
109*f7864055Sthorpej 	.d_ioctl    = gftty_ioctl,
110*f7864055Sthorpej 	.d_stop     = gftty_stop,
111*f7864055Sthorpej 	.d_tty      = gftty_tty,
112*f7864055Sthorpej 	.d_poll     = gftty_poll,
113*f7864055Sthorpej 	.d_mmap     = nommap,
114*f7864055Sthorpej 	.d_kqfilter = ttykqfilter,
115*f7864055Sthorpej 	.d_discard  = nodiscard,
116*f7864055Sthorpej 	.d_flag     = D_TTY,
117*f7864055Sthorpej };
118*f7864055Sthorpej 
119*f7864055Sthorpej static void	gftty_start(struct tty *);
120*f7864055Sthorpej static int	gftty_param_locked(struct tty *, struct termios *);
121*f7864055Sthorpej static int	gftty_param(struct tty *, struct termios *);
122*f7864055Sthorpej 
123*f7864055Sthorpej static void	gftty_softrx(void *);
124*f7864055Sthorpej 
125*f7864055Sthorpej #define	GFTTY_UNIT(x)		minor(x)
126*f7864055Sthorpej #define	GFTTY_DMASIZE		(64 * 1024)	/* XXX TTY_MAXQSIZE */
127*f7864055Sthorpej #define	GFTTY_MAXSEGS		((GFTTY_DMASIZE / PAGE_SIZE) + 1)
128*f7864055Sthorpej #define	GFTTY_RXBUFSIZE		128
129*f7864055Sthorpej #define	GFTTY_RXBUFALLOC	(128 << 1)
130*f7864055Sthorpej 
131*f7864055Sthorpej static void
gftty_reset_rxptrs(struct gftty_softc * sc)132*f7864055Sthorpej gftty_reset_rxptrs(struct gftty_softc *sc)
133*f7864055Sthorpej {
134*f7864055Sthorpej 	sc->sc_rxpos = 0;
135*f7864055Sthorpej 	sc->sc_rxcur = 0;
136*f7864055Sthorpej 	sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur];
137*f7864055Sthorpej 	sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur];
138*f7864055Sthorpej }
139*f7864055Sthorpej 
140bcb5d394Sthorpej /*
141bcb5d394Sthorpej  * gftty_attach --
142bcb5d394Sthorpej  *	Attach a Goldfish virual TTY.
143bcb5d394Sthorpej  */
144bcb5d394Sthorpej void
gftty_attach(struct gftty_softc * sc)145bcb5d394Sthorpej gftty_attach(struct gftty_softc *sc)
146bcb5d394Sthorpej {
147*f7864055Sthorpej 	device_t self = sc->sc_dev;
148*f7864055Sthorpej 	int error;
149*f7864055Sthorpej 	bool is_console;
150bcb5d394Sthorpej 
151bcb5d394Sthorpej 	aprint_naive("\n");
152bcb5d394Sthorpej 	aprint_normal(": Google Goldfish TTY\n");
153bcb5d394Sthorpej 
154bcb5d394Sthorpej 	/* If we got here without a config, we're the console. */
155*f7864055Sthorpej 	if ((is_console = (sc->sc_config == NULL))) {
156bcb5d394Sthorpej 		KASSERT(gftty_is_console(sc));
157bcb5d394Sthorpej 		sc->sc_config = &gftty_cnconfig;
158bcb5d394Sthorpej 		aprint_normal_dev(sc->sc_dev, "console\n");
159bcb5d394Sthorpej 	}
160*f7864055Sthorpej 
161*f7864055Sthorpej 	if (sc->sc_config->c_version == 0) {
162*f7864055Sthorpej 		aprint_normal_dev(self,
163*f7864055Sthorpej 		    "WARNING: version 0 device -- uncharted territory!\n");
164*f7864055Sthorpej 	}
165*f7864055Sthorpej 
166*f7864055Sthorpej 	/* Register our Rx soft interrupt. */
167*f7864055Sthorpej 	sc->sc_rx_si = softint_establish(SOFTINT_SERIAL, gftty_softrx, sc);
168*f7864055Sthorpej 	if (sc->sc_rx_si == NULL) {
169*f7864055Sthorpej 		aprint_error_dev(self,
170*f7864055Sthorpej 		    "Unable to register software interrupt.\n");
171*f7864055Sthorpej 		return;
172*f7864055Sthorpej 	}
173*f7864055Sthorpej 
174*f7864055Sthorpej 	error = bus_dmamap_create(sc->sc_dmat, GFTTY_DMASIZE,
175*f7864055Sthorpej 	    GFTTY_MAXSEGS, GFTTY_DMASIZE, 0, BUS_DMA_WAITOK,
176*f7864055Sthorpej 	    &sc->sc_tx_dma);
177*f7864055Sthorpej 	if (error != 0) {
178*f7864055Sthorpej 		aprint_error_dev(self,
179*f7864055Sthorpej 		    "unable to create Tx DMA map, error %d.\n", error);
180*f7864055Sthorpej 		return;
181*f7864055Sthorpej 	}
182*f7864055Sthorpej 	error = bus_dmamap_create(sc->sc_dmat, GFTTY_RXBUFALLOC,
183*f7864055Sthorpej 	    1, GFTTY_RXBUFALLOC, 0, BUS_DMA_WAITOK,
184*f7864055Sthorpej 	    &sc->sc_rx_dma);
185*f7864055Sthorpej 	if (error != 0) {
186*f7864055Sthorpej 		aprint_error_dev(self,
187*f7864055Sthorpej 		    "unable to create Rx DMA map, error %d.\n", error);
188*f7864055Sthorpej 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dma);
189*f7864055Sthorpej 		sc->sc_tx_dma = NULL;
190*f7864055Sthorpej 		return;
191*f7864055Sthorpej 	}
192*f7864055Sthorpej 
193*f7864055Sthorpej 	sc->sc_rxbuf = kmem_zalloc(GFTTY_RXBUFALLOC, KM_SLEEP);
194*f7864055Sthorpej 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_rx_dma,
195*f7864055Sthorpej 	    sc->sc_rxbuf, GFTTY_RXBUFALLOC, NULL, BUS_DMA_WAITOK);
196*f7864055Sthorpej 	if (error != 0) {
197*f7864055Sthorpej 		aprint_error_dev(self,
198*f7864055Sthorpej 		    "unable to load Rx DMA map, error %d.\n", error);
199*f7864055Sthorpej 		kmem_free(sc->sc_rxbuf, GFTTY_RXBUFALLOC);
200*f7864055Sthorpej 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_dma);
201*f7864055Sthorpej 		sc->sc_rx_dma = NULL;
202*f7864055Sthorpej 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dma);
203*f7864055Sthorpej 		sc->sc_tx_dma = NULL;
204*f7864055Sthorpej 		return;
205*f7864055Sthorpej 	}
206*f7864055Sthorpej 	sc->sc_rxbufs[0] = sc->sc_rxbuf;
207*f7864055Sthorpej 	sc->sc_rxbufs[1] = sc->sc_rxbufs[0] + GFTTY_RXBUFSIZE;
208*f7864055Sthorpej 	if (sc->sc_config->c_version == 0) {
209*f7864055Sthorpej 		sc->sc_rxaddrs[0] = (bus_addr_t)sc->sc_rxbufs[0];
210*f7864055Sthorpej 	} else {
211*f7864055Sthorpej 		sc->sc_rxaddrs[0] = sc->sc_rx_dma->dm_segs[0].ds_addr;
212*f7864055Sthorpej 	}
213*f7864055Sthorpej 	sc->sc_rxaddrs[1] = sc->sc_rxaddrs[0] + GFTTY_RXBUFSIZE;
214*f7864055Sthorpej 	gftty_reset_rxptrs(sc);
215*f7864055Sthorpej 
216*f7864055Sthorpej 	struct tty *tp = tty_alloc();
217*f7864055Sthorpej 	tp->t_oproc = gftty_start;
218*f7864055Sthorpej 	tp->t_param = gftty_param;
219*f7864055Sthorpej 	tp->t_softc = sc;
220*f7864055Sthorpej 
221*f7864055Sthorpej 	mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_TTY);
222*f7864055Sthorpej 
223*f7864055Sthorpej 	if (is_console) {
224*f7864055Sthorpej 		/* Locate the major number. */
225*f7864055Sthorpej 		int maj = cdevsw_lookup_major(&gftty_cdevsw);
226*f7864055Sthorpej 		tp->t_dev = cn_tab->cn_dev = makedev(maj, device_unit(self));
227*f7864055Sthorpej 	}
228*f7864055Sthorpej 
229*f7864055Sthorpej 	mutex_spin_enter(&tty_lock);
230*f7864055Sthorpej 	sc->sc_tty = tp;
231*f7864055Sthorpej 	mutex_spin_exit(&tty_lock);
232*f7864055Sthorpej 
233*f7864055Sthorpej 	tty_attach(tp);
234bcb5d394Sthorpej }
235bcb5d394Sthorpej 
236bcb5d394Sthorpej /*
237bcb5d394Sthorpej  * gftty_is_console --
238bcb5d394Sthorpej  *	Returns true if the specified gftty instance is currently
239bcb5d394Sthorpej  *	the console.
240bcb5d394Sthorpej  */
241bcb5d394Sthorpej bool
gftty_is_console(struct gftty_softc * sc)242bcb5d394Sthorpej gftty_is_console(struct gftty_softc *sc)
243bcb5d394Sthorpej {
244bcb5d394Sthorpej 	if (cn_tab == &gftty_consdev) {
245bcb5d394Sthorpej 		bool val;
246bcb5d394Sthorpej 
247bcb5d394Sthorpej 		if (prop_dictionary_get_bool(device_properties(sc->sc_dev),
248bcb5d394Sthorpej 					     "is-console", &val)) {
249bcb5d394Sthorpej 			return val;
250bcb5d394Sthorpej 		}
251bcb5d394Sthorpej 	}
252bcb5d394Sthorpej 	return false;
253bcb5d394Sthorpej }
254bcb5d394Sthorpej 
255bcb5d394Sthorpej /*
256bcb5d394Sthorpej  * gftty_init_config --
257bcb5d394Sthorpej  *	Initialize a config structure.
258bcb5d394Sthorpej  */
259bcb5d394Sthorpej static void
gftty_init_config(struct gftty_config * c,bus_space_tag_t bst,bus_space_handle_t bsh)260bcb5d394Sthorpej gftty_init_config(struct gftty_config *c, bus_space_tag_t bst,
261bcb5d394Sthorpej     bus_space_handle_t bsh)
262bcb5d394Sthorpej {
263bcb5d394Sthorpej 	c->c_bst = bst;
264bcb5d394Sthorpej 	c->c_bsh = bsh;
265bcb5d394Sthorpej 	c->c_version = REG_READ0(c, GFTTY_VERSION);
266bcb5d394Sthorpej }
267bcb5d394Sthorpej 
268bcb5d394Sthorpej /*
269bcb5d394Sthorpej  * gftty_alloc_config --
270bcb5d394Sthorpej  *	Allocate a config structure, initialize it, and assign
271bcb5d394Sthorpej  *	it to this device.
272bcb5d394Sthorpej  */
273bcb5d394Sthorpej void
gftty_alloc_config(struct gftty_softc * sc,bus_space_tag_t bst,bus_space_handle_t bsh)274bcb5d394Sthorpej gftty_alloc_config(struct gftty_softc *sc, bus_space_tag_t bst,
275bcb5d394Sthorpej     bus_space_handle_t bsh)
276bcb5d394Sthorpej {
277bcb5d394Sthorpej 	struct gftty_config *c = kmem_zalloc(sizeof(*c), KM_SLEEP);
278bcb5d394Sthorpej 
279bcb5d394Sthorpej 	gftty_init_config(c, bst, bsh);
280bcb5d394Sthorpej 	sc->sc_config = c;
281bcb5d394Sthorpej }
282bcb5d394Sthorpej 
283bcb5d394Sthorpej /*
284bcb5d394Sthorpej  * gftty_set_buffer --
285bcb5d394Sthorpej  *	Set the buffer address / length for an I/O operation.
286bcb5d394Sthorpej  */
287bcb5d394Sthorpej static void
gftty_set_buffer(struct gftty_config * c,bus_addr_t addr,bus_size_t size)288bcb5d394Sthorpej gftty_set_buffer(struct gftty_config *c, bus_addr_t addr, bus_size_t size)
289bcb5d394Sthorpej {
290bcb5d394Sthorpej 	REG_WRITE0(c, GFTTY_DATA_PTR, BUS_ADDR_LO32(addr));
291bcb5d394Sthorpej 	if (sizeof(bus_addr_t) == 8) {
292bcb5d394Sthorpej 		REG_WRITE0(c, GFTTY_DATA_PTR_HIGH, BUS_ADDR_HI32(addr));
293bcb5d394Sthorpej 	}
294bcb5d394Sthorpej 	REG_WRITE0(c, GFTTY_DATA_LEN, (uint32_t)size);
295bcb5d394Sthorpej }
296bcb5d394Sthorpej 
297bcb5d394Sthorpej /*
298*f7864055Sthorpej  * gftty_flush --
299*f7864055Sthorpej  *	Flush input bytes.
300*f7864055Sthorpej  */
301*f7864055Sthorpej static bool
gftty_flush(struct gftty_softc * sc)302*f7864055Sthorpej gftty_flush(struct gftty_softc *sc)
303*f7864055Sthorpej {
304*f7864055Sthorpej 	uint32_t count;
305*f7864055Sthorpej 	bool claimed = false;
306*f7864055Sthorpej 
307*f7864055Sthorpej 	KASSERT(ttylocked(sc->sc_tty));
308*f7864055Sthorpej 
309*f7864055Sthorpej 	mutex_spin_enter(&sc->sc_hwlock);
310*f7864055Sthorpej 
311*f7864055Sthorpej 	while ((count = REG_READ(sc, GFTTY_BYTES_READY)) != 0) {
312*f7864055Sthorpej 		claimed = true;
313*f7864055Sthorpej 		if (count > GFTTY_RXBUFALLOC) {
314*f7864055Sthorpej 			count = GFTTY_RXBUFALLOC;
315*f7864055Sthorpej 		}
316*f7864055Sthorpej 		gftty_set_buffer(sc->sc_config,
317*f7864055Sthorpej 		    sc->sc_rx_dma->dm_segs[0].ds_addr, count);
318*f7864055Sthorpej 		REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER);
319*f7864055Sthorpej 	}
320*f7864055Sthorpej 
321*f7864055Sthorpej 	mutex_spin_exit(&sc->sc_hwlock);
322*f7864055Sthorpej 
323*f7864055Sthorpej 	gftty_reset_rxptrs(sc);
324*f7864055Sthorpej 
325*f7864055Sthorpej 	return claimed;
326*f7864055Sthorpej }
327*f7864055Sthorpej 
328*f7864055Sthorpej /*
329*f7864055Sthorpej  * gftty_rx --
330*f7864055Sthorpej  *	Receive from the virtual TTY.
331*f7864055Sthorpej  */
332*f7864055Sthorpej static bool
gftty_rx(struct gftty_softc * sc)333*f7864055Sthorpej gftty_rx(struct gftty_softc *sc)
334*f7864055Sthorpej {
335*f7864055Sthorpej 	uint32_t count, avail;
336*f7864055Sthorpej 	bool claimed = false;
337*f7864055Sthorpej 
338*f7864055Sthorpej 	KASSERT(ttylocked(sc->sc_tty));
339*f7864055Sthorpej 
340*f7864055Sthorpej 	mutex_spin_enter(&sc->sc_hwlock);
341*f7864055Sthorpej 
342*f7864055Sthorpej 	count = REG_READ(sc, GFTTY_BYTES_READY);
343*f7864055Sthorpej 	if (count != 0) {
344*f7864055Sthorpej 		claimed = true;
345*f7864055Sthorpej 		avail = GFTTY_RXBUFSIZE - sc->sc_rxpos;
346*f7864055Sthorpej 		if (count > avail) {
347*f7864055Sthorpej 			/*
348*f7864055Sthorpej 			 * Receive what we can, but disable the interrupt
349*f7864055Sthorpej 			 * until the buffer can be drained.
350*f7864055Sthorpej 			 */
351*f7864055Sthorpej 			REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
352*f7864055Sthorpej 			count = avail;
353*f7864055Sthorpej 		}
354*f7864055Sthorpej 		if (count != 0) {
355*f7864055Sthorpej 			bus_addr_t syncoff =
356*f7864055Sthorpej 			    (sc->sc_rxaddr - sc->sc_rxaddrs[0]) + sc->sc_rxpos;
357*f7864055Sthorpej 
358*f7864055Sthorpej 			bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma,
359*f7864055Sthorpej 			    syncoff, count, BUS_DMASYNC_PREREAD);
360*f7864055Sthorpej 			gftty_set_buffer(sc->sc_config,
361*f7864055Sthorpej 			    sc->sc_rxaddr + sc->sc_rxpos, count);
362*f7864055Sthorpej 			REG_WRITE(sc, GFTTY_CMD, CMD_READ_BUFFER);
363*f7864055Sthorpej 			sc->sc_rxpos += count;
364*f7864055Sthorpej 			bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dma,
365*f7864055Sthorpej 			    syncoff, count, BUS_DMASYNC_POSTREAD);
366*f7864055Sthorpej 		}
367*f7864055Sthorpej 		softint_schedule(sc->sc_rx_si);
368*f7864055Sthorpej 	}
369*f7864055Sthorpej 
370*f7864055Sthorpej 	mutex_spin_exit(&sc->sc_hwlock);
371*f7864055Sthorpej 
372*f7864055Sthorpej 	return claimed;
373*f7864055Sthorpej }
374*f7864055Sthorpej 
375*f7864055Sthorpej /*
376*f7864055Sthorpej  * gftty_softrx --
377*f7864055Sthorpej  *	Software interrupt to comple Rx processing.
378*f7864055Sthorpej  */
379*f7864055Sthorpej static void
gftty_softrx(void * v)380*f7864055Sthorpej gftty_softrx(void *v)
381*f7864055Sthorpej {
382*f7864055Sthorpej 	struct gftty_softc *sc = v;
383*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
384*f7864055Sthorpej 	int i, len;
385*f7864055Sthorpej 	char *cp;
386*f7864055Sthorpej 
387*f7864055Sthorpej 	ttylock(tp);
388*f7864055Sthorpej 	cp = sc->sc_rxbuf;
389*f7864055Sthorpej 	len = sc->sc_rxpos;
390*f7864055Sthorpej 	sc->sc_rxcur ^= 1;
391*f7864055Sthorpej 	sc->sc_rxbuf = sc->sc_rxbufs[sc->sc_rxcur];
392*f7864055Sthorpej 	sc->sc_rxaddr = sc->sc_rxaddrs[sc->sc_rxcur];
393*f7864055Sthorpej 	sc->sc_rxpos = 0;
394*f7864055Sthorpej 	if (ISSET(tp->t_state, TS_ISOPEN)) {
395*f7864055Sthorpej 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE);
396*f7864055Sthorpej 	}
397*f7864055Sthorpej 	ttyunlock(tp);
398*f7864055Sthorpej 
399*f7864055Sthorpej 	for (i = 0; i < len; i++) {
400*f7864055Sthorpej 		(*tp->t_linesw->l_rint)(*cp++, tp);
401*f7864055Sthorpej 	}
402*f7864055Sthorpej }
403*f7864055Sthorpej 
404*f7864055Sthorpej /*
405*f7864055Sthorpej  * gftty_intr --
406*f7864055Sthorpej  *	Interrupt service routine.
407*f7864055Sthorpej  */
408*f7864055Sthorpej int
gftty_intr(void * v)409*f7864055Sthorpej gftty_intr(void *v)
410*f7864055Sthorpej {
411*f7864055Sthorpej 	struct gftty_softc *sc = v;
412*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
413*f7864055Sthorpej 	bool claimed;
414*f7864055Sthorpej 
415*f7864055Sthorpej 	ttylock(tp);
416*f7864055Sthorpej 	if (ISSET(tp->t_state, TS_ISOPEN)) {
417*f7864055Sthorpej 		claimed = gftty_rx(sc);
418*f7864055Sthorpej 	} else {
419*f7864055Sthorpej 		claimed = gftty_flush(sc);
420*f7864055Sthorpej 	}
421*f7864055Sthorpej 	ttyunlock(tp);
422*f7864055Sthorpej 
423*f7864055Sthorpej 	return claimed;
424*f7864055Sthorpej }
425*f7864055Sthorpej 
426*f7864055Sthorpej /*
427*f7864055Sthorpej  * gftty_open --
428*f7864055Sthorpej  *	cdevsw open routine.
429*f7864055Sthorpej  */
430*f7864055Sthorpej static int
gftty_open(dev_t dev,int flag,int mode,struct lwp * l)431*f7864055Sthorpej gftty_open(dev_t dev, int flag, int mode, struct lwp *l)
432*f7864055Sthorpej {
433*f7864055Sthorpej 	struct gftty_softc *sc =
434*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
435*f7864055Sthorpej 	struct tty *tp;
436*f7864055Sthorpej 
437*f7864055Sthorpej 	if (sc == NULL) {
438*f7864055Sthorpej 		return ENXIO;
439*f7864055Sthorpej 	}
440*f7864055Sthorpej 
441*f7864055Sthorpej 	mutex_spin_enter(&tty_lock);
442*f7864055Sthorpej 	tp = sc->sc_tty;
443*f7864055Sthorpej 	mutex_spin_exit(&tty_lock);
444*f7864055Sthorpej 	if (tp == NULL) {
445*f7864055Sthorpej 		return ENXIO;
446*f7864055Sthorpej 	}
447*f7864055Sthorpej 
448*f7864055Sthorpej 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
449*f7864055Sthorpej 		return EBUSY;
450*f7864055Sthorpej 	}
451*f7864055Sthorpej 
452*f7864055Sthorpej 	ttylock(tp);
453*f7864055Sthorpej 
454*f7864055Sthorpej 	if (ISSET(tp->t_state, TS_KERN_ONLY)) {
455*f7864055Sthorpej 		ttyunlock(tp);
456*f7864055Sthorpej 		return EBUSY;
457*f7864055Sthorpej 	}
458*f7864055Sthorpej 
459*f7864055Sthorpej 	tp->t_oproc = gftty_start;
460*f7864055Sthorpej 	tp->t_param = gftty_param;
461*f7864055Sthorpej 	tp->t_dev = dev;
462*f7864055Sthorpej 
463*f7864055Sthorpej 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
464*f7864055Sthorpej 		struct termios t;
465*f7864055Sthorpej 
466*f7864055Sthorpej 		ttychars(tp);
467*f7864055Sthorpej 		tp->t_iflag = TTYDEF_IFLAG;
468*f7864055Sthorpej 		tp->t_oflag = TTYDEF_OFLAG;
469*f7864055Sthorpej 		tp->t_lflag = TTYDEF_LFLAG;
470*f7864055Sthorpej 		t.c_cflag = TTYDEF_CFLAG;
471*f7864055Sthorpej 		t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
472*f7864055Sthorpej 		(void) gftty_param_locked(tp, &t);
473*f7864055Sthorpej 		ttsetwater(tp);
474*f7864055Sthorpej 
475*f7864055Sthorpej 		gftty_flush(sc);
476*f7864055Sthorpej 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_ENABLE);
477*f7864055Sthorpej 	}
478*f7864055Sthorpej 	SET(tp->t_state, TS_CARR_ON);
479*f7864055Sthorpej 
480*f7864055Sthorpej 	ttyunlock(tp);
481*f7864055Sthorpej 
482*f7864055Sthorpej 	int error = ttyopen(tp, 0, ISSET(flag, O_NONBLOCK));
483*f7864055Sthorpej 	if (error == 0) {
484*f7864055Sthorpej 		error = (*tp->t_linesw->l_open)(dev, tp);
485*f7864055Sthorpej 		if (error != 0) {
486*f7864055Sthorpej 			ttyclose(tp);
487*f7864055Sthorpej 		}
488*f7864055Sthorpej 	}
489*f7864055Sthorpej 
490*f7864055Sthorpej 	if (error != 0 &&
491*f7864055Sthorpej 	    !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
492*f7864055Sthorpej 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
493*f7864055Sthorpej 	}
494*f7864055Sthorpej 
495*f7864055Sthorpej 	return error;
496*f7864055Sthorpej }
497*f7864055Sthorpej 
498*f7864055Sthorpej /*
499*f7864055Sthorpej  * gftty_close --
500*f7864055Sthorpej  *	cdevsw close routine.
501*f7864055Sthorpej  */
502*f7864055Sthorpej static int
gftty_close(dev_t dev,int flag,int mode,struct lwp * l)503*f7864055Sthorpej gftty_close(dev_t dev, int flag, int mode, struct lwp *l)
504*f7864055Sthorpej {
505*f7864055Sthorpej 	struct gftty_softc *sc =
506*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
507*f7864055Sthorpej 
508*f7864055Sthorpej 	KASSERT(sc != NULL);
509*f7864055Sthorpej 
510*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
511*f7864055Sthorpej 
512*f7864055Sthorpej 	ttylock(tp);
513*f7864055Sthorpej 
514*f7864055Sthorpej 	/* XXX This is for cons.c. */
515*f7864055Sthorpej 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
516*f7864055Sthorpej 		ttyunlock(tp);
517*f7864055Sthorpej 		return 0;
518*f7864055Sthorpej 	}
519*f7864055Sthorpej 
520*f7864055Sthorpej 	if (ISSET(tp->t_state, TS_KERN_ONLY)) {
521*f7864055Sthorpej 		ttyunlock(tp);
522*f7864055Sthorpej 		return 0;
523*f7864055Sthorpej 	}
524*f7864055Sthorpej 
525*f7864055Sthorpej 	ttyunlock(tp);
526*f7864055Sthorpej 
527*f7864055Sthorpej 	(*tp->t_linesw->l_close)(tp, flag);
528*f7864055Sthorpej 	ttyclose(tp);
529*f7864055Sthorpej 
530*f7864055Sthorpej 	ttylock(tp);
531*f7864055Sthorpej 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
532*f7864055Sthorpej 		REG_WRITE(sc, GFTTY_CMD, CMD_INT_DISABLE);
533*f7864055Sthorpej 	}
534*f7864055Sthorpej 	ttyunlock(tp);
535*f7864055Sthorpej 
536*f7864055Sthorpej 	return 0;
537*f7864055Sthorpej }
538*f7864055Sthorpej 
539*f7864055Sthorpej /*
540*f7864055Sthorpej  * gftty_read --
541*f7864055Sthorpej  *	cdevsw read routine.
542*f7864055Sthorpej  */
543*f7864055Sthorpej static int
gftty_read(dev_t dev,struct uio * uio,int flag)544*f7864055Sthorpej gftty_read(dev_t dev, struct uio *uio, int flag)
545*f7864055Sthorpej {
546*f7864055Sthorpej 	struct gftty_softc *sc =
547*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
548*f7864055Sthorpej 
549*f7864055Sthorpej 	KASSERT(sc != NULL);
550*f7864055Sthorpej 
551*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
552*f7864055Sthorpej 	return (*tp->t_linesw->l_read)(tp, uio, flag);
553*f7864055Sthorpej }
554*f7864055Sthorpej 
555*f7864055Sthorpej /*
556*f7864055Sthorpej  * gftty_write --
557*f7864055Sthorpej  *	cdevsw write routine.
558*f7864055Sthorpej  */
559*f7864055Sthorpej static int
gftty_write(dev_t dev,struct uio * uio,int flag)560*f7864055Sthorpej gftty_write(dev_t dev, struct uio *uio, int flag)
561*f7864055Sthorpej {
562*f7864055Sthorpej 	struct gftty_softc *sc =
563*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
564*f7864055Sthorpej 
565*f7864055Sthorpej 	KASSERT(sc != NULL);
566*f7864055Sthorpej 
567*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
568*f7864055Sthorpej 	return (*tp->t_linesw->l_write)(tp, uio, flag);
569*f7864055Sthorpej }
570*f7864055Sthorpej 
571*f7864055Sthorpej /*
572*f7864055Sthorpej  * gftty_poll --
573*f7864055Sthorpej  *	cdevsw poll routine.
574*f7864055Sthorpej  */
575*f7864055Sthorpej static int
gftty_poll(dev_t dev,int events,struct lwp * l)576*f7864055Sthorpej gftty_poll(dev_t dev, int events, struct lwp *l)
577*f7864055Sthorpej {
578*f7864055Sthorpej 	struct gftty_softc *sc =
579*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
580*f7864055Sthorpej 
581*f7864055Sthorpej 	KASSERT(sc != NULL);
582*f7864055Sthorpej 
583*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
584*f7864055Sthorpej 	return (*tp->t_linesw->l_poll)(tp, events, l);
585*f7864055Sthorpej }
586*f7864055Sthorpej 
587*f7864055Sthorpej /*
588*f7864055Sthorpej  * gftty_tty --
589*f7864055Sthorpej  *	cdevsw tty routine.
590*f7864055Sthorpej  */
591*f7864055Sthorpej static struct tty *
gftty_tty(dev_t dev)592*f7864055Sthorpej gftty_tty(dev_t dev)
593*f7864055Sthorpej {
594*f7864055Sthorpej 	struct gftty_softc *sc =
595*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
596*f7864055Sthorpej 
597*f7864055Sthorpej 	KASSERT(sc != NULL);
598*f7864055Sthorpej 
599*f7864055Sthorpej 	return sc->sc_tty;
600*f7864055Sthorpej }
601*f7864055Sthorpej 
602*f7864055Sthorpej /*
603*f7864055Sthorpej  * gftty_ioctl --
604*f7864055Sthorpej  *	cdevsw ioctl routine.
605*f7864055Sthorpej  */
606*f7864055Sthorpej static int
gftty_ioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)607*f7864055Sthorpej gftty_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
608*f7864055Sthorpej {
609*f7864055Sthorpej 	struct gftty_softc *sc =
610*f7864055Sthorpej 	    device_lookup_private(&gftty_cd, GFTTY_UNIT(dev));
611*f7864055Sthorpej 
612*f7864055Sthorpej 	KASSERT(sc != NULL);
613*f7864055Sthorpej 
614*f7864055Sthorpej 	struct tty *tp = sc->sc_tty;
615*f7864055Sthorpej 	int error;
616*f7864055Sthorpej 
617*f7864055Sthorpej 	/* Do the line discipline ioctls first. */
618*f7864055Sthorpej 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
619*f7864055Sthorpej 	if (error != EPASSTHROUGH) {
620*f7864055Sthorpej 		return error;
621*f7864055Sthorpej 	}
622*f7864055Sthorpej 
623*f7864055Sthorpej 	/* Next, the TTY ioctls. */
624*f7864055Sthorpej 	error = ttioctl(tp, cmd, data, flag, l);
625*f7864055Sthorpej 	if (error != EPASSTHROUGH) {
626*f7864055Sthorpej 		return error;
627*f7864055Sthorpej 	}
628*f7864055Sthorpej 
629*f7864055Sthorpej 	/* None at this layer. */
630*f7864055Sthorpej 	return EPASSTHROUGH;
631*f7864055Sthorpej }
632*f7864055Sthorpej 
633*f7864055Sthorpej /*
634*f7864055Sthorpej  * gftty_tx --
635*f7864055Sthorpej  *	Transmit a buffer on the virtual TTY using DMA.
636*f7864055Sthorpej  */
637*f7864055Sthorpej static void
gftty_tx(struct gftty_softc * sc,void * buf,size_t len)638*f7864055Sthorpej gftty_tx(struct gftty_softc *sc, void *buf, size_t len)
639*f7864055Sthorpej {
640*f7864055Sthorpej 	int error, i;
641*f7864055Sthorpej 
642*f7864055Sthorpej 	KASSERT(len <= GFTTY_DMASIZE);
643*f7864055Sthorpej 
644*f7864055Sthorpej 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dma, buf, len,
645*f7864055Sthorpej 	    NULL, BUS_DMA_NOWAIT);
646*f7864055Sthorpej 	if (error) {
647*f7864055Sthorpej 		/* XXX report error */
648*f7864055Sthorpej 		return;
649*f7864055Sthorpej 	}
650*f7864055Sthorpej 	bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len,
651*f7864055Sthorpej 	    BUS_DMASYNC_PREWRITE);
652*f7864055Sthorpej 
653*f7864055Sthorpej 	mutex_spin_enter(&sc->sc_hwlock);
654*f7864055Sthorpej 	for (i = 0; i < sc->sc_tx_dma->dm_nsegs; i++) {
655*f7864055Sthorpej 		gftty_set_buffer(sc->sc_config,
656*f7864055Sthorpej 		    sc->sc_tx_dma->dm_segs[i].ds_addr,
657*f7864055Sthorpej 		    sc->sc_tx_dma->dm_segs[i].ds_len);
658*f7864055Sthorpej 		REG_WRITE(sc, GFTTY_CMD, CMD_WRITE_BUFFER);
659*f7864055Sthorpej 	}
660*f7864055Sthorpej 	mutex_spin_exit(&sc->sc_hwlock);
661*f7864055Sthorpej 
662*f7864055Sthorpej 	bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dma, 0, len,
663*f7864055Sthorpej 	    BUS_DMASYNC_POSTWRITE);
664*f7864055Sthorpej 	bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dma);
665*f7864055Sthorpej }
666*f7864055Sthorpej 
667*f7864055Sthorpej /*
668*f7864055Sthorpej  * gftty_start --
669*f7864055Sthorpej  *	TTY oproc routine.
670*f7864055Sthorpej  */
671*f7864055Sthorpej static void
gftty_start(struct tty * tp)672*f7864055Sthorpej gftty_start(struct tty *tp)
673*f7864055Sthorpej {
674*f7864055Sthorpej 	struct gftty_softc *sc = tp->t_softc;
675*f7864055Sthorpej 	u_char *tbuf;
676*f7864055Sthorpej 	int n;
677*f7864055Sthorpej 
678*f7864055Sthorpej 	KASSERT(ttylocked(tp));
679*f7864055Sthorpej 
680*f7864055Sthorpej 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP) ||
681*f7864055Sthorpej 	    ttypull(tp) == 0) {
682*f7864055Sthorpej 		return;
683*f7864055Sthorpej 	}
684*f7864055Sthorpej 	SET(tp->t_state, TS_BUSY);
685*f7864055Sthorpej 
686*f7864055Sthorpej 	/*
687*f7864055Sthorpej 	 * Drain the output from the ring buffer.  This will normally
688*f7864055Sthorpej 	 * be one contiguous chunk, but we have to do it in two pieces
689*f7864055Sthorpej 	 * when the ring wraps.
690*f7864055Sthorpej 	 */
691*f7864055Sthorpej 
692*f7864055Sthorpej 	n = ndqb(&tp->t_outq, 0);
693*f7864055Sthorpej 	tbuf = tp->t_outq.c_cf;
694*f7864055Sthorpej 	gftty_tx(sc, tbuf, n);
695*f7864055Sthorpej 	ndflush(&tp->t_outq, n);
696*f7864055Sthorpej 
697*f7864055Sthorpej 	if ((n = ndqb(&tp->t_outq, 0)) > 0) {
698*f7864055Sthorpej 		tbuf = tp->t_outq.c_cf;
699*f7864055Sthorpej 		gftty_tx(sc, tbuf, n);
700*f7864055Sthorpej 		ndflush(&tp->t_outq, n);
701*f7864055Sthorpej 	}
702*f7864055Sthorpej 
703*f7864055Sthorpej 	CLR(tp->t_state, TS_BUSY);
704*f7864055Sthorpej 	/* Come back if there's more to do. */
705*f7864055Sthorpej 	if (ttypull(tp)) {
706*f7864055Sthorpej 		SET(tp->t_state, TS_TIMEOUT);
707*f7864055Sthorpej 		callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1);
708*f7864055Sthorpej 	}
709*f7864055Sthorpej }
710*f7864055Sthorpej 
711*f7864055Sthorpej /*
712*f7864055Sthorpej  * gftty_stop --
713*f7864055Sthorpej  *	cdevsw stop routine.
714*f7864055Sthorpej  */
715*f7864055Sthorpej static void
gftty_stop(struct tty * tp,int flag)716*f7864055Sthorpej gftty_stop(struct tty *tp, int flag)
717*f7864055Sthorpej {
718*f7864055Sthorpej 	KASSERT(ttylocked(tp));
719*f7864055Sthorpej 
720*f7864055Sthorpej 	if (ISSET(tp->t_state, TS_BUSY)) {
721*f7864055Sthorpej 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
722*f7864055Sthorpej 			SET(tp->t_state, TS_FLUSH);
723*f7864055Sthorpej 		}
724*f7864055Sthorpej 	}
725*f7864055Sthorpej }
726*f7864055Sthorpej 
727*f7864055Sthorpej /*
728*f7864055Sthorpej  * gftty_param_locked --
729*f7864055Sthorpej  *	Set TTY parameters.  TTY must be locked.
730*f7864055Sthorpej  */
731*f7864055Sthorpej static int
gftty_param_locked(struct tty * tp,struct termios * t)732*f7864055Sthorpej gftty_param_locked(struct tty *tp, struct termios *t)
733*f7864055Sthorpej {
734*f7864055Sthorpej 
735*f7864055Sthorpej 	KASSERT(ttylocked(tp));
736*f7864055Sthorpej 
737*f7864055Sthorpej 	tp->t_ispeed = t->c_ispeed;
738*f7864055Sthorpej 	tp->t_ospeed = t->c_ospeed;
739*f7864055Sthorpej 	tp->t_cflag = t->c_cflag;
740*f7864055Sthorpej 
741*f7864055Sthorpej 	return 0;
742*f7864055Sthorpej }
743*f7864055Sthorpej 
744*f7864055Sthorpej /*
745*f7864055Sthorpej  * gftty_param --
746*f7864055Sthorpej  *	TTY param routine.
747*f7864055Sthorpej  */
748*f7864055Sthorpej static int
gftty_param(struct tty * tp,struct termios * t)749*f7864055Sthorpej gftty_param(struct tty *tp, struct termios *t)
750*f7864055Sthorpej {
751*f7864055Sthorpej 	int rv;
752*f7864055Sthorpej 
753*f7864055Sthorpej 	ttylock(tp);
754*f7864055Sthorpej 	rv = gftty_param_locked(tp, t);
755*f7864055Sthorpej 	ttyunlock(tp);
756*f7864055Sthorpej 
757*f7864055Sthorpej 	return rv;
758*f7864055Sthorpej }
759*f7864055Sthorpej 
760*f7864055Sthorpej /*
761bcb5d394Sthorpej  * gftty console routines.
762bcb5d394Sthorpej  */
763bcb5d394Sthorpej static int
gftty_cngetc(dev_t dev)764bcb5d394Sthorpej gftty_cngetc(dev_t dev)
765bcb5d394Sthorpej {
766bcb5d394Sthorpej 	struct gftty_config * const c = &gftty_cnconfig;
767bcb5d394Sthorpej 
768bcb5d394Sthorpej 	if (REG_READ0(c, GFTTY_BYTES_READY) == 0) {
769bcb5d394Sthorpej 		return -1;
770bcb5d394Sthorpej 	}
771bcb5d394Sthorpej 
772bcb5d394Sthorpej 	/*
773bcb5d394Sthorpej 	 * XXX This is all terrible and should burn to the ground.
774bcb5d394Sthorpej 	 * XXX This device desperately needs to be improved with
775bcb5d394Sthorpej 	 * XXX a GET_CHAR register.
776bcb5d394Sthorpej 	 */
777bcb5d394Sthorpej 	bus_addr_t addr;
778bcb5d394Sthorpej 	uint8_t buf[1];
779bcb5d394Sthorpej 
780bcb5d394Sthorpej 	if (c->c_version == 0) {
781bcb5d394Sthorpej 		addr = (bus_addr_t)buf;
782bcb5d394Sthorpej 	} else {
783bcb5d394Sthorpej 		addr = vtophys((vaddr_t)buf);
784bcb5d394Sthorpej 	}
785bcb5d394Sthorpej 
786bcb5d394Sthorpej 	gftty_set_buffer(c, addr, sizeof(buf));
787bcb5d394Sthorpej 	REG_WRITE0(c, GFTTY_CMD, CMD_READ_BUFFER);
788bcb5d394Sthorpej 
789bcb5d394Sthorpej 	return buf[0];
790bcb5d394Sthorpej }
791bcb5d394Sthorpej 
792bcb5d394Sthorpej static void
gftty_cnputc(dev_t dev,int ch)793bcb5d394Sthorpej gftty_cnputc(dev_t dev, int ch)
794bcb5d394Sthorpej {
795bcb5d394Sthorpej 	REG_WRITE0(&gftty_cnconfig, GFTTY_PUT_CHAR, (unsigned char)ch);
796bcb5d394Sthorpej }
797bcb5d394Sthorpej 
798bcb5d394Sthorpej static void
gftty_cnpollc(dev_t dev,int on)799bcb5d394Sthorpej gftty_cnpollc(dev_t dev, int on)
800bcb5d394Sthorpej {
801bcb5d394Sthorpej 	/* XXX */
802bcb5d394Sthorpej }
803bcb5d394Sthorpej 
804bcb5d394Sthorpej /*
805bcb5d394Sthorpej  * gftty_cnattach --
806bcb5d394Sthorpej  *	Attach a Goldfish virtual TTY console.
807bcb5d394Sthorpej  */
808bcb5d394Sthorpej void
gftty_cnattach(bus_space_tag_t bst,bus_space_handle_t bsh)809bcb5d394Sthorpej gftty_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh)
810bcb5d394Sthorpej {
811bcb5d394Sthorpej 	gftty_init_config(&gftty_cnconfig, bst, bsh);
812bcb5d394Sthorpej 
813bcb5d394Sthorpej 	cn_tab = &gftty_consdev;
814bcb5d394Sthorpej 	cn_init_magic(&gftty_cnmagic_state);
815bcb5d394Sthorpej 	cn_set_magic("+++++");
816bcb5d394Sthorpej }
817