1 1.10 riastrad /* $NetBSD: viocon.c,v 1.10 2024/08/05 19:13:34 riastradh Exp $ */ 2 1.1 riastrad /* $OpenBSD: viocon.c,v 1.8 2021/11/05 11:38:29 mpi Exp $ */ 3 1.1 riastrad 4 1.1 riastrad /* 5 1.1 riastrad * Copyright (c) 2013-2015 Stefan Fritsch <sf (at) sfritsch.de> 6 1.1 riastrad * 7 1.1 riastrad * Permission to use, copy, modify, and distribute this software for any 8 1.1 riastrad * purpose with or without fee is hereby granted, provided that the above 9 1.1 riastrad * copyright notice and this permission notice appear in all copies. 10 1.1 riastrad * 11 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 1.1 riastrad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 riastrad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 1.1 riastrad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 riastrad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 riastrad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 1.1 riastrad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 riastrad */ 19 1.1 riastrad 20 1.1 riastrad #include <sys/cdefs.h> 21 1.10 riastrad __KERNEL_RCSID(0, "$NetBSD: viocon.c,v 1.10 2024/08/05 19:13:34 riastradh Exp $"); 22 1.1 riastrad 23 1.1 riastrad #include <sys/param.h> 24 1.1 riastrad #include <sys/types.h> 25 1.1 riastrad 26 1.1 riastrad #include <sys/bus.h> 27 1.1 riastrad #include <sys/conf.h> 28 1.1 riastrad #include <sys/device.h> 29 1.1 riastrad #include <sys/kauth.h> 30 1.1 riastrad #include <sys/kernel.h> 31 1.1 riastrad #include <sys/kmem.h> 32 1.1 riastrad #include <sys/lwp.h> 33 1.1 riastrad #include <sys/systm.h> 34 1.1 riastrad #include <sys/tty.h> 35 1.1 riastrad 36 1.1 riastrad #include <dev/pci/virtioreg.h> 37 1.1 riastrad #include <dev/pci/virtiovar.h> 38 1.1 riastrad 39 1.1 riastrad #include "ioconf.h" 40 1.1 riastrad 41 1.1 riastrad /* OpenBSD compat shims */ 42 1.1 riastrad #define ttymalloc(speed) tty_alloc() 43 1.1 riastrad #define splassert(ipl) __nothing 44 1.1 riastrad #define virtio_notify(vsc, vq) virtio_enqueue_commit(vsc, vq, -1, true) 45 1.1 riastrad #define ttwakeupwr(tp) __nothing 46 1.1 riastrad 47 1.1 riastrad /* features */ 48 1.1 riastrad #define VIRTIO_CONSOLE_F_SIZE (1ULL<<0) 49 1.1 riastrad #define VIRTIO_CONSOLE_F_MULTIPORT (1ULL<<1) 50 1.1 riastrad #define VIRTIO_CONSOLE_F_EMERG_WRITE (1ULL<<2) 51 1.1 riastrad 52 1.1 riastrad /* config space */ 53 1.1 riastrad #define VIRTIO_CONSOLE_COLS 0 /* 16 bits */ 54 1.1 riastrad #define VIRTIO_CONSOLE_ROWS 2 /* 16 bits */ 55 1.1 riastrad #define VIRTIO_CONSOLE_MAX_NR_PORTS 4 /* 32 bits */ 56 1.1 riastrad #define VIRTIO_CONSOLE_EMERG_WR 8 /* 32 bits */ 57 1.1 riastrad 58 1.1 riastrad #define VIOCON_DEBUG 0 59 1.1 riastrad 60 1.1 riastrad #if VIOCON_DEBUG 61 1.1 riastrad #define DPRINTF(x...) printf(x) 62 1.1 riastrad #else 63 1.1 riastrad #define DPRINTF(x...) 64 1.1 riastrad #endif 65 1.1 riastrad 66 1.1 riastrad #define VIRTIO_CONSOLE_FLAG_BITS \ 67 1.1 riastrad VIRTIO_COMMON_FLAG_BITS \ 68 1.1 riastrad "b\x00" "SIZE\0" \ 69 1.1 riastrad "b\x01" "MULTIPORT\0" \ 70 1.1 riastrad "b\x02" "EMERG_WRITE\0" 71 1.1 riastrad 72 1.1 riastrad struct virtio_console_control { 73 1.1 riastrad uint32_t id; /* Port number */ 74 1.1 riastrad 75 1.1 riastrad #define VIRTIO_CONSOLE_DEVICE_READY 0 76 1.1 riastrad #define VIRTIO_CONSOLE_PORT_ADD 1 77 1.1 riastrad #define VIRTIO_CONSOLE_PORT_REMOVE 2 78 1.1 riastrad #define VIRTIO_CONSOLE_PORT_READY 3 79 1.1 riastrad #define VIRTIO_CONSOLE_CONSOLE_PORT 4 80 1.1 riastrad #define VIRTIO_CONSOLE_RESIZE 5 81 1.1 riastrad #define VIRTIO_CONSOLE_PORT_OPEN 6 82 1.1 riastrad #define VIRTIO_CONSOLE_PORT_NAME 7 83 1.1 riastrad uint16_t event; 84 1.1 riastrad 85 1.1 riastrad uint16_t value; 86 1.1 riastrad }; 87 1.1 riastrad 88 1.1 riastrad struct virtio_console_control_resize { 89 1.1 riastrad /* yes, the order is different than in config space */ 90 1.1 riastrad uint16_t rows; 91 1.1 riastrad uint16_t cols; 92 1.1 riastrad }; 93 1.1 riastrad 94 1.1 riastrad #define BUFSIZE 128 95 1.1 riastrad 96 1.2 riastrad #define VIOCONDEV(u,p) makedev(cdevsw_lookup_major(&viocon_cdevsw), \ 97 1.2 riastrad ((u) << 4) | (p)) 98 1.1 riastrad #define VIOCONUNIT(x) (minor(x) >> 4) 99 1.1 riastrad #define VIOCONPORT(x) (minor(x) & 0x0f) 100 1.1 riastrad 101 1.1 riastrad struct viocon_port { 102 1.1 riastrad struct viocon_softc *vp_sc; 103 1.1 riastrad struct virtqueue *vp_rx; 104 1.1 riastrad struct virtqueue *vp_tx; 105 1.1 riastrad void *vp_si; 106 1.1 riastrad struct tty *vp_tty; 107 1.1 riastrad const char *vp_name; 108 1.1 riastrad bus_dma_segment_t vp_dmaseg; 109 1.1 riastrad bus_dmamap_t vp_dmamap; 110 1.1 riastrad #ifdef NOTYET 111 1.1 riastrad unsigned int vp_host_open:1; /* XXX needs F_MULTIPORT */ 112 1.1 riastrad unsigned int vp_guest_open:1; /* XXX needs F_MULTIPORT */ 113 1.1 riastrad unsigned int vp_is_console:1; /* XXX needs F_MULTIPORT */ 114 1.1 riastrad #endif 115 1.1 riastrad unsigned int vp_iflow:1; /* rx flow control */ 116 1.1 riastrad uint16_t vp_rows; 117 1.1 riastrad uint16_t vp_cols; 118 1.1 riastrad u_char *vp_rx_buf; 119 1.1 riastrad u_char *vp_tx_buf; 120 1.1 riastrad }; 121 1.1 riastrad 122 1.1 riastrad struct viocon_softc { 123 1.1 riastrad struct device *sc_dev; 124 1.1 riastrad struct virtio_softc *sc_virtio; 125 1.1 riastrad struct virtqueue *sc_vqs; 126 1.7 yamaguch #define VIOCON_PORT_RX 0 127 1.7 yamaguch #define VIOCON_PORT_TX 1 128 1.7 yamaguch #define VIOCON_PORT_NQS 2 129 1.1 riastrad 130 1.1 riastrad struct virtqueue *sc_c_vq_rx; 131 1.1 riastrad struct virtqueue *sc_c_vq_tx; 132 1.1 riastrad 133 1.1 riastrad unsigned int sc_max_ports; 134 1.1 riastrad struct viocon_port **sc_ports; 135 1.1 riastrad }; 136 1.1 riastrad 137 1.1 riastrad int viocon_match(struct device *, struct cfdata *, void *); 138 1.1 riastrad void viocon_attach(struct device *, struct device *, void *); 139 1.1 riastrad int viocon_tx_intr(struct virtqueue *); 140 1.1 riastrad int viocon_tx_drain(struct viocon_port *, struct virtqueue *vq); 141 1.1 riastrad int viocon_rx_intr(struct virtqueue *); 142 1.1 riastrad void viocon_rx_soft(void *); 143 1.1 riastrad void viocon_rx_fill(struct viocon_port *); 144 1.1 riastrad int viocon_port_create(struct viocon_softc *, int); 145 1.1 riastrad void vioconstart(struct tty *); 146 1.1 riastrad int vioconhwiflow(struct tty *, int); 147 1.1 riastrad int vioconparam(struct tty *, struct termios *); 148 1.1 riastrad int vioconopen(dev_t, int, int, struct lwp *); 149 1.1 riastrad int vioconclose(dev_t, int, int, struct lwp *); 150 1.1 riastrad int vioconread(dev_t, struct uio *, int); 151 1.1 riastrad int vioconwrite(dev_t, struct uio *, int); 152 1.1 riastrad void vioconstop(struct tty *, int); 153 1.1 riastrad int vioconioctl(dev_t, u_long, void *, int, struct lwp *); 154 1.1 riastrad struct tty *viocontty(dev_t dev); 155 1.1 riastrad 156 1.1 riastrad CFATTACH_DECL_NEW(viocon, sizeof(struct viocon_softc), 157 1.1 riastrad viocon_match, viocon_attach, /*detach*/NULL, /*activate*/NULL); 158 1.1 riastrad 159 1.1 riastrad const struct cdevsw viocon_cdevsw = { 160 1.1 riastrad .d_open = vioconopen, 161 1.1 riastrad .d_close = vioconclose, 162 1.1 riastrad .d_read = vioconread, 163 1.1 riastrad .d_write = vioconwrite, 164 1.1 riastrad .d_ioctl = vioconioctl, 165 1.1 riastrad .d_stop = vioconstop, 166 1.1 riastrad .d_tty = viocontty, 167 1.1 riastrad .d_poll = nopoll, /* XXX */ 168 1.1 riastrad .d_mmap = nommap, 169 1.1 riastrad .d_kqfilter = ttykqfilter, 170 1.1 riastrad .d_discard = nodiscard, 171 1.1 riastrad .d_flag = D_TTY, 172 1.1 riastrad }; 173 1.1 riastrad 174 1.1 riastrad static inline struct viocon_softc * 175 1.1 riastrad dev2sc(dev_t dev) 176 1.1 riastrad { 177 1.1 riastrad return device_lookup_private(&viocon_cd, VIOCONUNIT(dev)); 178 1.1 riastrad } 179 1.1 riastrad 180 1.1 riastrad static inline struct viocon_port * 181 1.1 riastrad dev2port(dev_t dev) 182 1.1 riastrad { 183 1.1 riastrad return dev2sc(dev)->sc_ports[VIOCONPORT(dev)]; 184 1.1 riastrad } 185 1.1 riastrad 186 1.1 riastrad int viocon_match(struct device *parent, struct cfdata *match, void *aux) 187 1.1 riastrad { 188 1.1 riastrad struct virtio_attach_args *va = aux; 189 1.1 riastrad if (va->sc_childdevid == VIRTIO_DEVICE_ID_CONSOLE) 190 1.1 riastrad return 1; 191 1.1 riastrad return 0; 192 1.1 riastrad } 193 1.1 riastrad 194 1.1 riastrad void 195 1.1 riastrad viocon_attach(struct device *parent, struct device *self, void *aux) 196 1.1 riastrad { 197 1.1 riastrad struct viocon_softc *sc = device_private(self); 198 1.1 riastrad struct virtio_softc *vsc = device_private(parent); 199 1.1 riastrad int maxports = 1; 200 1.7 yamaguch size_t nvqs; 201 1.1 riastrad 202 1.1 riastrad sc->sc_dev = self; 203 1.1 riastrad if (virtio_child(vsc) != NULL) { 204 1.1 riastrad aprint_error(": parent %s already has a child\n", 205 1.1 riastrad device_xname(parent)); 206 1.1 riastrad return; 207 1.1 riastrad } 208 1.1 riastrad sc->sc_virtio = vsc; 209 1.1 riastrad sc->sc_max_ports = maxports; 210 1.7 yamaguch nvqs = VIOCON_PORT_NQS * maxports; 211 1.1 riastrad 212 1.7 yamaguch sc->sc_vqs = kmem_zalloc(nvqs * sizeof(sc->sc_vqs[0]), 213 1.1 riastrad KM_SLEEP); 214 1.1 riastrad sc->sc_ports = kmem_zalloc(maxports * sizeof(sc->sc_ports[0]), 215 1.1 riastrad KM_SLEEP); 216 1.1 riastrad 217 1.6 yamaguch virtio_child_attach_start(vsc, self, IPL_TTY, 218 1.6 yamaguch /*req_features*/VIRTIO_CONSOLE_F_SIZE, VIRTIO_CONSOLE_FLAG_BITS); 219 1.1 riastrad 220 1.1 riastrad DPRINTF("%s: softc: %p\n", __func__, sc); 221 1.1 riastrad if (viocon_port_create(sc, 0) != 0) { 222 1.1 riastrad printf("\n%s: viocon_port_create failed\n", __func__); 223 1.1 riastrad goto err; 224 1.1 riastrad } 225 1.1 riastrad 226 1.7 yamaguch if (virtio_child_attach_finish(vsc, sc->sc_vqs, nvqs, 227 1.8 yamaguch /*config_change*/NULL, /*req_flags*/0) != 0) 228 1.1 riastrad goto err; 229 1.1 riastrad 230 1.10 riastrad viocon_rx_fill(sc->sc_ports[0]); 231 1.10 riastrad 232 1.1 riastrad return; 233 1.1 riastrad err: 234 1.7 yamaguch kmem_free(sc->sc_vqs, nvqs * sizeof(sc->sc_vqs[0])); 235 1.1 riastrad kmem_free(sc->sc_ports, maxports * sizeof(sc->sc_ports[0])); 236 1.1 riastrad virtio_child_attach_failed(vsc); 237 1.1 riastrad } 238 1.1 riastrad 239 1.1 riastrad int 240 1.1 riastrad viocon_port_create(struct viocon_softc *sc, int portidx) 241 1.1 riastrad { 242 1.1 riastrad struct virtio_softc *vsc = sc->sc_virtio; 243 1.1 riastrad int rxidx, txidx, allocsize, nsegs; 244 1.1 riastrad char name[6]; 245 1.1 riastrad struct viocon_port *vp; 246 1.1 riastrad void *kva; 247 1.1 riastrad struct tty *tp; 248 1.1 riastrad 249 1.1 riastrad vp = kmem_zalloc(sizeof(*vp), KM_SLEEP); 250 1.1 riastrad if (vp == NULL) 251 1.1 riastrad return ENOMEM; 252 1.1 riastrad sc->sc_ports[portidx] = vp; 253 1.1 riastrad vp->vp_sc = sc; 254 1.1 riastrad DPRINTF("%s: vp: %p\n", __func__, vp); 255 1.1 riastrad 256 1.7 yamaguch rxidx = (portidx * VIOCON_PORT_NQS) + VIOCON_PORT_RX; 257 1.7 yamaguch txidx = (portidx * VIOCON_PORT_NQS) + VIOCON_PORT_TX; 258 1.1 riastrad 259 1.1 riastrad snprintf(name, sizeof(name), "p%drx", portidx); 260 1.8 yamaguch virtio_init_vq_vqdone(vsc, &sc->sc_vqs[rxidx], rxidx, 261 1.8 yamaguch viocon_rx_intr); 262 1.8 yamaguch if (virtio_alloc_vq(vsc, &sc->sc_vqs[rxidx], BUFSIZE, 1, 263 1.1 riastrad name) != 0) { 264 1.1 riastrad printf("\nCan't alloc %s virtqueue\n", name); 265 1.1 riastrad goto err; 266 1.1 riastrad } 267 1.1 riastrad vp->vp_rx = &sc->sc_vqs[rxidx]; 268 1.1 riastrad vp->vp_si = softint_establish(SOFTINT_SERIAL, viocon_rx_soft, vp); 269 1.1 riastrad DPRINTF("%s: rx: %p\n", __func__, vp->vp_rx); 270 1.1 riastrad 271 1.1 riastrad snprintf(name, sizeof(name), "p%dtx", portidx); 272 1.8 yamaguch virtio_init_vq_vqdone(vsc, &sc->sc_vqs[txidx], txidx, 273 1.8 yamaguch viocon_tx_intr); 274 1.8 yamaguch if (virtio_alloc_vq(vsc, &sc->sc_vqs[txidx], BUFSIZE, 1, 275 1.1 riastrad name) != 0) { 276 1.1 riastrad printf("\nCan't alloc %s virtqueue\n", name); 277 1.1 riastrad goto err; 278 1.1 riastrad } 279 1.1 riastrad vp->vp_tx = &sc->sc_vqs[txidx]; 280 1.1 riastrad DPRINTF("%s: tx: %p\n", __func__, vp->vp_tx); 281 1.1 riastrad 282 1.1 riastrad allocsize = (vp->vp_rx->vq_num + vp->vp_tx->vq_num) * BUFSIZE; 283 1.1 riastrad 284 1.1 riastrad if (bus_dmamap_create(virtio_dmat(vsc), allocsize, 1, allocsize, 0, 285 1.1 riastrad BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &vp->vp_dmamap) != 0) 286 1.1 riastrad goto err; 287 1.1 riastrad if (bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 8, 0, &vp->vp_dmaseg, 288 1.1 riastrad 1, &nsegs, BUS_DMA_NOWAIT) != 0) 289 1.1 riastrad goto err; 290 1.1 riastrad if (bus_dmamem_map(virtio_dmat(vsc), &vp->vp_dmaseg, nsegs, 291 1.1 riastrad allocsize, &kva, BUS_DMA_NOWAIT) != 0) 292 1.1 riastrad goto err; 293 1.1 riastrad memset(kva, 0, allocsize); 294 1.1 riastrad if (bus_dmamap_load(virtio_dmat(vsc), vp->vp_dmamap, kva, 295 1.1 riastrad allocsize, NULL, BUS_DMA_NOWAIT) != 0) 296 1.1 riastrad goto err; 297 1.1 riastrad vp->vp_rx_buf = (unsigned char *)kva; 298 1.1 riastrad /* 299 1.1 riastrad * XXX use only a small circular tx buffer instead of many BUFSIZE buffers? 300 1.1 riastrad */ 301 1.1 riastrad vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE; 302 1.1 riastrad 303 1.1 riastrad if (virtio_features(vsc) & VIRTIO_CONSOLE_F_SIZE) { 304 1.1 riastrad vp->vp_cols = virtio_read_device_config_2(vsc, 305 1.1 riastrad VIRTIO_CONSOLE_COLS); 306 1.1 riastrad vp->vp_rows = virtio_read_device_config_2(vsc, 307 1.1 riastrad VIRTIO_CONSOLE_ROWS); 308 1.1 riastrad } 309 1.1 riastrad 310 1.1 riastrad tp = ttymalloc(1000000); 311 1.1 riastrad tp->t_oproc = vioconstart; 312 1.1 riastrad tp->t_param = vioconparam; 313 1.1 riastrad tp->t_hwiflow = vioconhwiflow; 314 1.2 riastrad tp->t_dev = VIOCONDEV(device_unit(sc->sc_dev), portidx); 315 1.1 riastrad vp->vp_tty = tp; 316 1.1 riastrad DPRINTF("%s: tty: %p\n", __func__, tp); 317 1.1 riastrad 318 1.1 riastrad virtio_start_vq_intr(vsc, vp->vp_rx); 319 1.1 riastrad virtio_start_vq_intr(vsc, vp->vp_tx); 320 1.1 riastrad 321 1.1 riastrad return 0; 322 1.1 riastrad err: 323 1.1 riastrad panic("%s failed", __func__); 324 1.1 riastrad return -1; 325 1.1 riastrad } 326 1.1 riastrad 327 1.1 riastrad int 328 1.1 riastrad viocon_tx_drain(struct viocon_port *vp, struct virtqueue *vq) 329 1.1 riastrad { 330 1.1 riastrad struct virtio_softc *vsc = vq->vq_owner; 331 1.1 riastrad int ndone = 0, len, slot; 332 1.1 riastrad 333 1.1 riastrad splassert(IPL_TTY); 334 1.1 riastrad while (virtio_dequeue(vsc, vq, &slot, &len) == 0) { 335 1.1 riastrad bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, 336 1.1 riastrad vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, BUFSIZE, 337 1.4 riastrad BUS_DMASYNC_POSTWRITE); 338 1.1 riastrad virtio_dequeue_commit(vsc, vq, slot); 339 1.1 riastrad ndone++; 340 1.1 riastrad } 341 1.1 riastrad return ndone; 342 1.1 riastrad } 343 1.1 riastrad 344 1.1 riastrad int 345 1.1 riastrad viocon_tx_intr(struct virtqueue *vq) 346 1.1 riastrad { 347 1.1 riastrad struct virtio_softc *vsc = vq->vq_owner; 348 1.1 riastrad struct viocon_softc *sc = device_private(virtio_child(vsc)); 349 1.1 riastrad int ndone = 0; 350 1.1 riastrad int portidx = (vq->vq_index - 1) / 2; 351 1.1 riastrad struct viocon_port *vp = sc->sc_ports[portidx]; 352 1.1 riastrad struct tty *tp = vp->vp_tty; 353 1.1 riastrad 354 1.1 riastrad splassert(IPL_TTY); 355 1.1 riastrad ndone = viocon_tx_drain(vp, vq); 356 1.1 riastrad if (ndone && ISSET(tp->t_state, TS_BUSY)) { 357 1.1 riastrad CLR(tp->t_state, TS_BUSY); 358 1.1 riastrad (*tp->t_linesw->l_start)(tp); 359 1.1 riastrad } 360 1.1 riastrad 361 1.1 riastrad return 1; 362 1.1 riastrad } 363 1.1 riastrad 364 1.1 riastrad void 365 1.1 riastrad viocon_rx_fill(struct viocon_port *vp) 366 1.1 riastrad { 367 1.1 riastrad struct virtqueue *vq = vp->vp_rx; 368 1.1 riastrad struct virtio_softc *vsc = vp->vp_sc->sc_virtio; 369 1.1 riastrad int r, slot, ndone = 0; 370 1.1 riastrad 371 1.1 riastrad while ((r = virtio_enqueue_prep(vsc, vq, &slot)) == 0) { 372 1.1 riastrad if (virtio_enqueue_reserve(vsc, vq, slot, 1) != 0) 373 1.1 riastrad break; 374 1.1 riastrad bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, slot * BUFSIZE, 375 1.1 riastrad BUFSIZE, BUS_DMASYNC_PREREAD); 376 1.1 riastrad virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap, slot * BUFSIZE, 377 1.1 riastrad BUFSIZE, 0); 378 1.1 riastrad virtio_enqueue_commit(vsc, vq, slot, 0); 379 1.1 riastrad ndone++; 380 1.1 riastrad } 381 1.9 riastrad KASSERTMSG(r == 0 || r == EAGAIN, "r=%d", r); 382 1.1 riastrad if (ndone > 0) 383 1.1 riastrad virtio_notify(vsc, vq); 384 1.1 riastrad } 385 1.1 riastrad 386 1.1 riastrad int 387 1.1 riastrad viocon_rx_intr(struct virtqueue *vq) 388 1.1 riastrad { 389 1.1 riastrad struct virtio_softc *vsc = vq->vq_owner; 390 1.1 riastrad struct viocon_softc *sc = device_private(virtio_child(vsc)); 391 1.1 riastrad int portidx = (vq->vq_index - 1) / 2; 392 1.1 riastrad struct viocon_port *vp = sc->sc_ports[portidx]; 393 1.1 riastrad 394 1.1 riastrad softint_schedule(vp->vp_si); 395 1.1 riastrad return 1; 396 1.1 riastrad } 397 1.1 riastrad 398 1.1 riastrad void 399 1.1 riastrad viocon_rx_soft(void *arg) 400 1.1 riastrad { 401 1.1 riastrad struct viocon_port *vp = arg; 402 1.1 riastrad struct virtqueue *vq = vp->vp_rx; 403 1.1 riastrad struct virtio_softc *vsc = vq->vq_owner; 404 1.1 riastrad struct tty *tp = vp->vp_tty; 405 1.1 riastrad int slot, len, i; 406 1.1 riastrad u_char *p; 407 1.1 riastrad 408 1.1 riastrad while (!vp->vp_iflow && virtio_dequeue(vsc, vq, &slot, &len) == 0) { 409 1.1 riastrad bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, 410 1.1 riastrad slot * BUFSIZE, BUFSIZE, BUS_DMASYNC_POSTREAD); 411 1.1 riastrad p = vp->vp_rx_buf + slot * BUFSIZE; 412 1.1 riastrad for (i = 0; i < len; i++) 413 1.1 riastrad (*tp->t_linesw->l_rint)(*p++, tp); 414 1.1 riastrad virtio_dequeue_commit(vsc, vq, slot); 415 1.1 riastrad } 416 1.1 riastrad 417 1.1 riastrad viocon_rx_fill(vp); 418 1.1 riastrad 419 1.1 riastrad return; 420 1.1 riastrad } 421 1.1 riastrad 422 1.1 riastrad void 423 1.1 riastrad vioconstart(struct tty *tp) 424 1.1 riastrad { 425 1.1 riastrad struct viocon_softc *sc = dev2sc(tp->t_dev); 426 1.1 riastrad struct virtio_softc *vsc; 427 1.1 riastrad struct viocon_port *vp = dev2port(tp->t_dev); 428 1.1 riastrad struct virtqueue *vq; 429 1.1 riastrad u_char *buf; 430 1.1 riastrad int s, cnt, slot, ret, ndone; 431 1.1 riastrad 432 1.1 riastrad vsc = sc->sc_virtio; 433 1.1 riastrad vq = vp->vp_tx; 434 1.1 riastrad 435 1.1 riastrad s = spltty(); 436 1.1 riastrad 437 1.1 riastrad ndone = viocon_tx_drain(vp, vq); 438 1.1 riastrad if (ISSET(tp->t_state, TS_BUSY)) { 439 1.1 riastrad if (ndone > 0) 440 1.1 riastrad CLR(tp->t_state, TS_BUSY); 441 1.1 riastrad else 442 1.1 riastrad goto out; 443 1.1 riastrad } 444 1.1 riastrad if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP)) 445 1.1 riastrad goto out; 446 1.1 riastrad 447 1.1 riastrad if (tp->t_outq.c_cc == 0) 448 1.1 riastrad goto out; 449 1.1 riastrad ndone = 0; 450 1.1 riastrad 451 1.1 riastrad while (tp->t_outq.c_cc > 0) { 452 1.1 riastrad ret = virtio_enqueue_prep(vsc, vq, &slot); 453 1.1 riastrad if (ret == EAGAIN) { 454 1.1 riastrad SET(tp->t_state, TS_BUSY); 455 1.1 riastrad break; 456 1.1 riastrad } 457 1.9 riastrad KASSERTMSG(ret == 0, "ret=%d", ret); 458 1.1 riastrad ret = virtio_enqueue_reserve(vsc, vq, slot, 1); 459 1.9 riastrad KASSERTMSG(ret == 0, "ret=%d", ret); 460 1.1 riastrad buf = vp->vp_tx_buf + slot * BUFSIZE; 461 1.1 riastrad cnt = q_to_b(&tp->t_outq, buf, BUFSIZE); 462 1.1 riastrad bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, 463 1.1 riastrad vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt, 464 1.1 riastrad BUS_DMASYNC_PREWRITE); 465 1.1 riastrad virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap, 466 1.1 riastrad vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt, 1); 467 1.1 riastrad virtio_enqueue_commit(vsc, vq, slot, 0); 468 1.1 riastrad ndone++; 469 1.1 riastrad } 470 1.1 riastrad if (ndone > 0) 471 1.1 riastrad virtio_notify(vsc, vq); 472 1.1 riastrad ttwakeupwr(tp); 473 1.1 riastrad out: 474 1.1 riastrad splx(s); 475 1.1 riastrad } 476 1.1 riastrad 477 1.1 riastrad int 478 1.1 riastrad vioconhwiflow(struct tty *tp, int stop) 479 1.1 riastrad { 480 1.1 riastrad struct viocon_port *vp = dev2port(tp->t_dev); 481 1.1 riastrad int s; 482 1.1 riastrad 483 1.1 riastrad s = spltty(); 484 1.1 riastrad vp->vp_iflow = stop; 485 1.1 riastrad if (stop) { 486 1.1 riastrad virtio_stop_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx); 487 1.1 riastrad } else { 488 1.1 riastrad virtio_start_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx); 489 1.1 riastrad softint_schedule(vp->vp_si); 490 1.1 riastrad } 491 1.1 riastrad splx(s); 492 1.1 riastrad return 1; 493 1.1 riastrad } 494 1.1 riastrad 495 1.1 riastrad int 496 1.1 riastrad vioconparam(struct tty *tp, struct termios *t) 497 1.1 riastrad { 498 1.1 riastrad tp->t_ispeed = t->c_ispeed; 499 1.1 riastrad tp->t_ospeed = t->c_ospeed; 500 1.1 riastrad tp->t_cflag = t->c_cflag; 501 1.1 riastrad 502 1.1 riastrad vioconstart(tp); 503 1.1 riastrad return 0; 504 1.1 riastrad } 505 1.1 riastrad 506 1.1 riastrad int 507 1.1 riastrad vioconopen(dev_t dev, int flag, int mode, struct lwp *l) 508 1.1 riastrad { 509 1.1 riastrad int unit = VIOCONUNIT(dev); 510 1.1 riastrad int port = VIOCONPORT(dev); 511 1.1 riastrad struct viocon_softc *sc; 512 1.1 riastrad struct viocon_port *vp; 513 1.1 riastrad struct tty *tp; 514 1.1 riastrad int s, error; 515 1.1 riastrad 516 1.1 riastrad sc = device_lookup_private(&viocon_cd, unit); 517 1.1 riastrad if (sc == NULL) 518 1.1 riastrad return (ENXIO); 519 1.1 riastrad if (!device_is_active(sc->sc_dev)) 520 1.1 riastrad return (ENXIO); 521 1.1 riastrad 522 1.1 riastrad s = spltty(); 523 1.1 riastrad if (port >= sc->sc_max_ports) { 524 1.1 riastrad splx(s); 525 1.1 riastrad return (ENXIO); 526 1.1 riastrad } 527 1.1 riastrad vp = sc->sc_ports[port]; 528 1.1 riastrad tp = vp->vp_tty; 529 1.1 riastrad #ifdef NOTYET 530 1.1 riastrad vp->vp_guest_open = 1; 531 1.1 riastrad #endif 532 1.1 riastrad splx(s); 533 1.1 riastrad 534 1.1 riastrad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 535 1.1 riastrad return (EBUSY); 536 1.1 riastrad 537 1.1 riastrad s = spltty(); 538 1.1 riastrad if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 539 1.1 riastrad ttychars(tp); 540 1.1 riastrad tp->t_ispeed = 1000000; 541 1.1 riastrad tp->t_ospeed = 1000000; 542 1.1 riastrad tp->t_cflag = TTYDEF_CFLAG|CLOCAL|CRTSCTS; 543 1.1 riastrad tp->t_iflag = TTYDEF_IFLAG; 544 1.1 riastrad tp->t_oflag = TTYDEF_OFLAG; 545 1.1 riastrad tp->t_lflag = TTYDEF_LFLAG; 546 1.1 riastrad if (vp->vp_cols != 0) { 547 1.1 riastrad tp->t_winsize.ws_col = vp->vp_cols; 548 1.1 riastrad tp->t_winsize.ws_row = vp->vp_rows; 549 1.1 riastrad } 550 1.1 riastrad 551 1.1 riastrad vioconparam(tp, &tp->t_termios); 552 1.1 riastrad ttsetwater(tp); 553 1.1 riastrad } 554 1.1 riastrad splx(s); 555 1.1 riastrad 556 1.1 riastrad error = (*tp->t_linesw->l_open)(dev, tp); 557 1.1 riastrad return error; 558 1.1 riastrad } 559 1.1 riastrad 560 1.1 riastrad int 561 1.1 riastrad vioconclose(dev_t dev, int flag, int mode, struct lwp *l) 562 1.1 riastrad { 563 1.1 riastrad struct viocon_port *vp = dev2port(dev); 564 1.1 riastrad struct tty *tp = vp->vp_tty; 565 1.1 riastrad int s; 566 1.1 riastrad 567 1.1 riastrad if (!ISSET(tp->t_state, TS_ISOPEN)) 568 1.1 riastrad return 0; 569 1.1 riastrad 570 1.1 riastrad (*tp->t_linesw->l_close)(tp, flag); 571 1.1 riastrad s = spltty(); 572 1.1 riastrad #ifdef NOTYET 573 1.1 riastrad vp->vp_guest_open = 0; 574 1.1 riastrad #endif 575 1.1 riastrad CLR(tp->t_state, TS_BUSY | TS_FLUSH); 576 1.1 riastrad ttyclose(tp); 577 1.1 riastrad splx(s); 578 1.1 riastrad 579 1.1 riastrad return 0; 580 1.1 riastrad } 581 1.1 riastrad 582 1.1 riastrad int 583 1.1 riastrad vioconread(dev_t dev, struct uio *uio, int flag) 584 1.1 riastrad { 585 1.1 riastrad struct viocon_port *vp = dev2port(dev); 586 1.1 riastrad struct tty *tp = vp->vp_tty; 587 1.1 riastrad 588 1.1 riastrad return (*tp->t_linesw->l_read)(tp, uio, flag); 589 1.1 riastrad } 590 1.1 riastrad 591 1.1 riastrad int 592 1.1 riastrad vioconwrite(dev_t dev, struct uio *uio, int flag) 593 1.1 riastrad { 594 1.1 riastrad struct viocon_port *vp = dev2port(dev); 595 1.1 riastrad struct tty *tp = vp->vp_tty; 596 1.1 riastrad 597 1.1 riastrad return (*tp->t_linesw->l_write)(tp, uio, flag); 598 1.1 riastrad } 599 1.1 riastrad 600 1.1 riastrad struct tty * 601 1.1 riastrad viocontty(dev_t dev) 602 1.1 riastrad { 603 1.1 riastrad struct viocon_port *vp = dev2port(dev); 604 1.1 riastrad 605 1.1 riastrad return vp->vp_tty; 606 1.1 riastrad } 607 1.1 riastrad 608 1.1 riastrad void 609 1.1 riastrad vioconstop(struct tty *tp, int flag) 610 1.1 riastrad { 611 1.1 riastrad int s; 612 1.1 riastrad 613 1.1 riastrad s = spltty(); 614 1.1 riastrad if (ISSET(tp->t_state, TS_BUSY)) 615 1.1 riastrad if (!ISSET(tp->t_state, TS_TTSTOP)) 616 1.1 riastrad SET(tp->t_state, TS_FLUSH); 617 1.1 riastrad splx(s); 618 1.1 riastrad } 619 1.1 riastrad 620 1.1 riastrad int 621 1.1 riastrad vioconioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 622 1.1 riastrad { 623 1.1 riastrad struct viocon_port *vp = dev2port(dev); 624 1.1 riastrad struct tty *tp; 625 1.1 riastrad int error1, error2; 626 1.1 riastrad 627 1.1 riastrad tp = vp->vp_tty; 628 1.1 riastrad 629 1.1 riastrad error1 = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 630 1.1 riastrad if (error1 >= 0) 631 1.1 riastrad return error1; 632 1.1 riastrad error2 = ttioctl(tp, cmd, data, flag, l); 633 1.1 riastrad if (error2 >= 0) 634 1.1 riastrad return error2; 635 1.1 riastrad return ENOTTY; 636 1.1 riastrad } 637