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