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