1 /*- 2 * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* Driver for VirtIO console devices. */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/ctype.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/kdb.h> 39 #include <sys/lock.h> 40 #include <sys/mutex.h> 41 #include <sys/sglist.h> 42 #include <sys/sysctl.h> 43 #include <sys/taskqueue.h> 44 #include <sys/queue.h> 45 46 #include <sys/conf.h> 47 #include <sys/cons.h> 48 #include <sys/tty.h> 49 50 #include <machine/bus.h> 51 #include <machine/resource.h> 52 #include <sys/bus.h> 53 54 #include <dev/virtio/virtio.h> 55 #include <dev/virtio/virtqueue.h> 56 #include <dev/virtio/console/virtio_console.h> 57 58 #include "virtio_if.h" 59 60 #define VTCON_MAX_PORTS 32 61 #define VTCON_TTY_PREFIX "V" 62 #define VTCON_TTY_ALIAS_PREFIX "vtcon" 63 #define VTCON_BULK_BUFSZ 128 64 #define VTCON_CTRL_BUFSZ 128 65 66 /* 67 * The buffers cannot cross more than one page boundary due to the 68 * size of the sglist segment array used. 69 */ 70 CTASSERT(VTCON_BULK_BUFSZ <= PAGE_SIZE); 71 CTASSERT(VTCON_CTRL_BUFSZ <= PAGE_SIZE); 72 73 CTASSERT(sizeof(struct virtio_console_config) <= VTCON_CTRL_BUFSZ); 74 75 struct vtcon_softc; 76 struct vtcon_softc_port; 77 78 struct vtcon_port { 79 struct mtx vtcport_mtx; 80 struct vtcon_softc *vtcport_sc; 81 struct vtcon_softc_port *vtcport_scport; 82 struct tty *vtcport_tty; 83 struct virtqueue *vtcport_invq; 84 struct virtqueue *vtcport_outvq; 85 int vtcport_id; 86 int vtcport_flags; 87 #define VTCON_PORT_FLAG_GONE 0x01 88 #define VTCON_PORT_FLAG_CONSOLE 0x02 89 #define VTCON_PORT_FLAG_ALIAS 0x04 90 91 #if defined(KDB) 92 int vtcport_alt_break_state; 93 #endif 94 }; 95 96 #define VTCON_PORT_LOCK(_port) mtx_lock(&(_port)->vtcport_mtx) 97 #define VTCON_PORT_UNLOCK(_port) mtx_unlock(&(_port)->vtcport_mtx) 98 99 struct vtcon_softc_port { 100 struct vtcon_softc *vcsp_sc; 101 struct vtcon_port *vcsp_port; 102 struct virtqueue *vcsp_invq; 103 struct virtqueue *vcsp_outvq; 104 }; 105 106 struct vtcon_softc { 107 device_t vtcon_dev; 108 struct mtx vtcon_mtx; 109 uint64_t vtcon_features; 110 uint32_t vtcon_max_ports; 111 uint32_t vtcon_flags; 112 #define VTCON_FLAG_DETACHED 0x01 113 #define VTCON_FLAG_SIZE 0x02 114 #define VTCON_FLAG_MULTIPORT 0x04 115 116 /* 117 * Ports can be added and removed during runtime, but we have 118 * to allocate all the virtqueues during attach. This array is 119 * indexed by the port ID. 120 */ 121 struct vtcon_softc_port *vtcon_ports; 122 123 struct task vtcon_ctrl_task; 124 struct virtqueue *vtcon_ctrl_rxvq; 125 struct virtqueue *vtcon_ctrl_txvq; 126 struct mtx vtcon_ctrl_tx_mtx; 127 }; 128 129 #define VTCON_LOCK(_sc) mtx_lock(&(_sc)->vtcon_mtx) 130 #define VTCON_UNLOCK(_sc) mtx_unlock(&(_sc)->vtcon_mtx) 131 #define VTCON_LOCK_ASSERT(_sc) \ 132 mtx_assert(&(_sc)->vtcon_mtx, MA_OWNED) 133 #define VTCON_LOCK_ASSERT_NOTOWNED(_sc) \ 134 mtx_assert(&(_sc)->vtcon_mtx, MA_NOTOWNED) 135 136 #define VTCON_CTRL_TX_LOCK(_sc) mtx_lock(&(_sc)->vtcon_ctrl_tx_mtx) 137 #define VTCON_CTRL_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->vtcon_ctrl_tx_mtx) 138 139 #define VTCON_ASSERT_VALID_PORTID(_sc, _id) \ 140 KASSERT((_id) >= 0 && (_id) < (_sc)->vtcon_max_ports, \ 141 ("%s: port ID %d out of range", __func__, _id)) 142 143 #define VTCON_FEATURES VIRTIO_CONSOLE_F_MULTIPORT 144 145 static struct virtio_feature_desc vtcon_feature_desc[] = { 146 { VIRTIO_CONSOLE_F_SIZE, "ConsoleSize" }, 147 { VIRTIO_CONSOLE_F_MULTIPORT, "MultiplePorts" }, 148 { VIRTIO_CONSOLE_F_EMERG_WRITE, "EmergencyWrite" }, 149 { 0, NULL } 150 }; 151 152 static int vtcon_modevent(module_t, int, void *); 153 static void vtcon_drain_all(void); 154 155 static int vtcon_probe(device_t); 156 static int vtcon_attach(device_t); 157 static int vtcon_detach(device_t); 158 static int vtcon_config_change(device_t); 159 160 static int vtcon_setup_features(struct vtcon_softc *); 161 static int vtcon_negotiate_features(struct vtcon_softc *); 162 static int vtcon_alloc_scports(struct vtcon_softc *); 163 static int vtcon_alloc_virtqueues(struct vtcon_softc *); 164 static void vtcon_read_config(struct vtcon_softc *, 165 struct virtio_console_config *); 166 167 static void vtcon_determine_max_ports(struct vtcon_softc *, 168 struct virtio_console_config *); 169 static void vtcon_destroy_ports(struct vtcon_softc *); 170 static void vtcon_stop(struct vtcon_softc *); 171 172 static int vtcon_ctrl_event_enqueue(struct vtcon_softc *, 173 struct virtio_console_control *); 174 static int vtcon_ctrl_event_create(struct vtcon_softc *); 175 static void vtcon_ctrl_event_requeue(struct vtcon_softc *, 176 struct virtio_console_control *); 177 static int vtcon_ctrl_event_populate(struct vtcon_softc *); 178 static void vtcon_ctrl_event_drain(struct vtcon_softc *); 179 static int vtcon_ctrl_init(struct vtcon_softc *); 180 static void vtcon_ctrl_deinit(struct vtcon_softc *); 181 static void vtcon_ctrl_port_add_event(struct vtcon_softc *, int); 182 static void vtcon_ctrl_port_remove_event(struct vtcon_softc *, int); 183 static void vtcon_ctrl_port_console_event(struct vtcon_softc *, int); 184 static void vtcon_ctrl_port_open_event(struct vtcon_softc *, int); 185 static void vtcon_ctrl_port_name_event(struct vtcon_softc *, int, 186 const char *, size_t); 187 static void vtcon_ctrl_process_event(struct vtcon_softc *, 188 struct virtio_console_control *, void *, size_t); 189 static void vtcon_ctrl_task_cb(void *, int); 190 static void vtcon_ctrl_event_intr(void *); 191 static void vtcon_ctrl_poll(struct vtcon_softc *, 192 struct virtio_console_control *control); 193 static void vtcon_ctrl_send_control(struct vtcon_softc *, uint32_t, 194 uint16_t, uint16_t); 195 196 static int vtcon_port_enqueue_buf(struct vtcon_port *, void *, size_t); 197 static int vtcon_port_create_buf(struct vtcon_port *); 198 static void vtcon_port_requeue_buf(struct vtcon_port *, void *); 199 static int vtcon_port_populate(struct vtcon_port *); 200 static void vtcon_port_destroy(struct vtcon_port *); 201 static int vtcon_port_create(struct vtcon_softc *, int); 202 static void vtcon_port_dev_alias(struct vtcon_port *, const char *, 203 size_t); 204 static void vtcon_port_drain_bufs(struct virtqueue *); 205 static void vtcon_port_drain(struct vtcon_port *); 206 static void vtcon_port_teardown(struct vtcon_port *); 207 static void vtcon_port_change_size(struct vtcon_port *, uint16_t, 208 uint16_t); 209 static void vtcon_port_update_console_size(struct vtcon_softc *); 210 static void vtcon_port_enable_intr(struct vtcon_port *); 211 static void vtcon_port_disable_intr(struct vtcon_port *); 212 static void vtcon_port_in(struct vtcon_port *); 213 static void vtcon_port_intr(void *); 214 static void vtcon_port_out(struct vtcon_port *, void *, int); 215 static void vtcon_port_submit_event(struct vtcon_port *, uint16_t, 216 uint16_t); 217 218 static int vtcon_tty_open(struct tty *); 219 static void vtcon_tty_close(struct tty *); 220 static void vtcon_tty_outwakeup(struct tty *); 221 static void vtcon_tty_free(void *); 222 223 static void vtcon_get_console_size(struct vtcon_softc *, uint16_t *, 224 uint16_t *); 225 226 static void vtcon_enable_interrupts(struct vtcon_softc *); 227 static void vtcon_disable_interrupts(struct vtcon_softc *); 228 229 #define vtcon_modern(_sc) (((_sc)->vtcon_features & VIRTIO_F_VERSION_1) != 0) 230 #define vtcon_htog16(_sc, _val) virtio_htog16(vtcon_modern(_sc), _val) 231 #define vtcon_htog32(_sc, _val) virtio_htog32(vtcon_modern(_sc), _val) 232 #define vtcon_htog64(_sc, _val) virtio_htog64(vtcon_modern(_sc), _val) 233 #define vtcon_gtoh16(_sc, _val) virtio_gtoh16(vtcon_modern(_sc), _val) 234 #define vtcon_gtoh32(_sc, _val) virtio_gtoh32(vtcon_modern(_sc), _val) 235 #define vtcon_gtoh64(_sc, _val) virtio_gtoh64(vtcon_modern(_sc), _val) 236 237 static int vtcon_pending_free; 238 239 static struct ttydevsw vtcon_tty_class = { 240 .tsw_flags = 0, 241 .tsw_open = vtcon_tty_open, 242 .tsw_close = vtcon_tty_close, 243 .tsw_outwakeup = vtcon_tty_outwakeup, 244 .tsw_free = vtcon_tty_free, 245 }; 246 247 static device_method_t vtcon_methods[] = { 248 /* Device methods. */ 249 DEVMETHOD(device_probe, vtcon_probe), 250 DEVMETHOD(device_attach, vtcon_attach), 251 DEVMETHOD(device_detach, vtcon_detach), 252 253 /* VirtIO methods. */ 254 DEVMETHOD(virtio_config_change, vtcon_config_change), 255 256 DEVMETHOD_END 257 }; 258 259 static driver_t vtcon_driver = { 260 "vtcon", 261 vtcon_methods, 262 sizeof(struct vtcon_softc) 263 }; 264 static devclass_t vtcon_devclass; 265 266 DRIVER_MODULE(virtio_console, virtio_mmio, vtcon_driver, vtcon_devclass, 267 vtcon_modevent, 0); 268 DRIVER_MODULE(virtio_console, virtio_pci, vtcon_driver, vtcon_devclass, 269 vtcon_modevent, 0); 270 MODULE_VERSION(virtio_console, 1); 271 MODULE_DEPEND(virtio_console, virtio, 1, 1, 1); 272 273 VIRTIO_SIMPLE_PNPTABLE(virtio_console, VIRTIO_ID_CONSOLE, 274 "VirtIO Console Adapter"); 275 VIRTIO_SIMPLE_PNPINFO(virtio_mmio, virtio_console); 276 VIRTIO_SIMPLE_PNPINFO(virtio_pci, virtio_console); 277 278 static int 279 vtcon_modevent(module_t mod, int type, void *unused) 280 { 281 int error; 282 283 switch (type) { 284 case MOD_LOAD: 285 error = 0; 286 break; 287 case MOD_QUIESCE: 288 error = 0; 289 break; 290 case MOD_UNLOAD: 291 vtcon_drain_all(); 292 error = 0; 293 break; 294 case MOD_SHUTDOWN: 295 error = 0; 296 break; 297 default: 298 error = EOPNOTSUPP; 299 break; 300 } 301 302 return (error); 303 } 304 305 static void 306 vtcon_drain_all(void) 307 { 308 int first; 309 310 for (first = 1; vtcon_pending_free != 0; first = 0) { 311 if (first != 0) { 312 printf("virtio_console: Waiting for all detached TTY " 313 "devices to have open fds closed.\n"); 314 } 315 pause("vtcondra", hz); 316 } 317 } 318 319 static int 320 vtcon_probe(device_t dev) 321 { 322 return (VIRTIO_SIMPLE_PROBE(dev, virtio_console)); 323 } 324 325 static int 326 vtcon_attach(device_t dev) 327 { 328 struct vtcon_softc *sc; 329 struct virtio_console_config concfg; 330 int error; 331 332 sc = device_get_softc(dev); 333 sc->vtcon_dev = dev; 334 virtio_set_feature_desc(dev, vtcon_feature_desc); 335 336 mtx_init(&sc->vtcon_mtx, "vtconmtx", NULL, MTX_DEF); 337 mtx_init(&sc->vtcon_ctrl_tx_mtx, "vtconctrlmtx", NULL, MTX_DEF); 338 339 error = vtcon_setup_features(sc); 340 if (error) { 341 device_printf(dev, "cannot setup features\n"); 342 goto fail; 343 } 344 345 vtcon_read_config(sc, &concfg); 346 vtcon_determine_max_ports(sc, &concfg); 347 348 error = vtcon_alloc_scports(sc); 349 if (error) { 350 device_printf(dev, "cannot allocate softc port structures\n"); 351 goto fail; 352 } 353 354 error = vtcon_alloc_virtqueues(sc); 355 if (error) { 356 device_printf(dev, "cannot allocate virtqueues\n"); 357 goto fail; 358 } 359 360 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) { 361 TASK_INIT(&sc->vtcon_ctrl_task, 0, vtcon_ctrl_task_cb, sc); 362 error = vtcon_ctrl_init(sc); 363 if (error) 364 goto fail; 365 } else { 366 error = vtcon_port_create(sc, 0); 367 if (error) 368 goto fail; 369 if (sc->vtcon_flags & VTCON_FLAG_SIZE) 370 vtcon_port_update_console_size(sc); 371 } 372 373 error = virtio_setup_intr(dev, INTR_TYPE_TTY); 374 if (error) { 375 device_printf(dev, "cannot setup virtqueue interrupts\n"); 376 goto fail; 377 } 378 379 vtcon_enable_interrupts(sc); 380 381 vtcon_ctrl_send_control(sc, VIRTIO_CONSOLE_BAD_ID, 382 VIRTIO_CONSOLE_DEVICE_READY, 1); 383 384 fail: 385 if (error) 386 vtcon_detach(dev); 387 388 return (error); 389 } 390 391 static int 392 vtcon_detach(device_t dev) 393 { 394 struct vtcon_softc *sc; 395 396 sc = device_get_softc(dev); 397 398 VTCON_LOCK(sc); 399 sc->vtcon_flags |= VTCON_FLAG_DETACHED; 400 if (device_is_attached(dev)) 401 vtcon_stop(sc); 402 VTCON_UNLOCK(sc); 403 404 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) { 405 taskqueue_drain(taskqueue_thread, &sc->vtcon_ctrl_task); 406 vtcon_ctrl_deinit(sc); 407 } 408 409 vtcon_destroy_ports(sc); 410 mtx_destroy(&sc->vtcon_mtx); 411 mtx_destroy(&sc->vtcon_ctrl_tx_mtx); 412 413 return (0); 414 } 415 416 static int 417 vtcon_config_change(device_t dev) 418 { 419 struct vtcon_softc *sc; 420 421 sc = device_get_softc(dev); 422 423 /* 424 * When the multiport feature is negotiated, all configuration 425 * changes are done through control virtqueue events. 426 */ 427 if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0) { 428 if (sc->vtcon_flags & VTCON_FLAG_SIZE) 429 vtcon_port_update_console_size(sc); 430 } 431 432 return (0); 433 } 434 435 static int 436 vtcon_negotiate_features(struct vtcon_softc *sc) 437 { 438 device_t dev; 439 uint64_t features; 440 441 dev = sc->vtcon_dev; 442 features = VTCON_FEATURES; 443 444 sc->vtcon_features = virtio_negotiate_features(dev, features); 445 return (virtio_finalize_features(dev)); 446 } 447 448 static int 449 vtcon_setup_features(struct vtcon_softc *sc) 450 { 451 device_t dev; 452 int error; 453 454 dev = sc->vtcon_dev; 455 456 error = vtcon_negotiate_features(sc); 457 if (error) 458 return (error); 459 460 if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_SIZE)) 461 sc->vtcon_flags |= VTCON_FLAG_SIZE; 462 if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_MULTIPORT)) 463 sc->vtcon_flags |= VTCON_FLAG_MULTIPORT; 464 465 return (0); 466 } 467 468 #define VTCON_GET_CONFIG(_dev, _feature, _field, _cfg) \ 469 if (virtio_with_feature(_dev, _feature)) { \ 470 virtio_read_device_config(_dev, \ 471 offsetof(struct virtio_console_config, _field), \ 472 &(_cfg)->_field, sizeof((_cfg)->_field)); \ 473 } 474 475 static void 476 vtcon_read_config(struct vtcon_softc *sc, struct virtio_console_config *concfg) 477 { 478 device_t dev; 479 480 dev = sc->vtcon_dev; 481 482 bzero(concfg, sizeof(struct virtio_console_config)); 483 484 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, cols, concfg); 485 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, rows, concfg); 486 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_MULTIPORT, max_nr_ports, concfg); 487 } 488 489 #undef VTCON_GET_CONFIG 490 491 static int 492 vtcon_alloc_scports(struct vtcon_softc *sc) 493 { 494 struct vtcon_softc_port *scport; 495 int max, i; 496 497 max = sc->vtcon_max_ports; 498 499 sc->vtcon_ports = malloc(sizeof(struct vtcon_softc_port) * max, 500 M_DEVBUF, M_NOWAIT | M_ZERO); 501 if (sc->vtcon_ports == NULL) 502 return (ENOMEM); 503 504 for (i = 0; i < max; i++) { 505 scport = &sc->vtcon_ports[i]; 506 scport->vcsp_sc = sc; 507 } 508 509 return (0); 510 } 511 512 static int 513 vtcon_alloc_virtqueues(struct vtcon_softc *sc) 514 { 515 device_t dev; 516 struct vq_alloc_info *info; 517 struct vtcon_softc_port *scport; 518 int i, idx, portidx, nvqs, error; 519 520 dev = sc->vtcon_dev; 521 522 nvqs = sc->vtcon_max_ports * 2; 523 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) 524 nvqs += 2; 525 526 info = malloc(sizeof(struct vq_alloc_info) * nvqs, M_TEMP, M_NOWAIT); 527 if (info == NULL) 528 return (ENOMEM); 529 530 for (i = 0, idx = 0, portidx = 0; i < nvqs / 2; i++, idx += 2) { 531 if (i == 1) { 532 /* The control virtqueues are after the first port. */ 533 VQ_ALLOC_INFO_INIT(&info[idx], 0, 534 vtcon_ctrl_event_intr, sc, &sc->vtcon_ctrl_rxvq, 535 "%s-control rx", device_get_nameunit(dev)); 536 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, 537 NULL, sc, &sc->vtcon_ctrl_txvq, 538 "%s-control tx", device_get_nameunit(dev)); 539 continue; 540 } 541 542 scport = &sc->vtcon_ports[portidx]; 543 544 VQ_ALLOC_INFO_INIT(&info[idx], 0, vtcon_port_intr, 545 scport, &scport->vcsp_invq, "%s-port%d in", 546 device_get_nameunit(dev), i); 547 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, NULL, 548 NULL, &scport->vcsp_outvq, "%s-port%d out", 549 device_get_nameunit(dev), i); 550 551 portidx++; 552 } 553 554 error = virtio_alloc_virtqueues(dev, 0, nvqs, info); 555 free(info, M_TEMP); 556 557 return (error); 558 } 559 560 static void 561 vtcon_determine_max_ports(struct vtcon_softc *sc, 562 struct virtio_console_config *concfg) 563 { 564 565 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) { 566 sc->vtcon_max_ports = 567 min(concfg->max_nr_ports, VTCON_MAX_PORTS); 568 if (sc->vtcon_max_ports == 0) 569 sc->vtcon_max_ports = 1; 570 } else 571 sc->vtcon_max_ports = 1; 572 } 573 574 static void 575 vtcon_destroy_ports(struct vtcon_softc *sc) 576 { 577 struct vtcon_softc_port *scport; 578 struct vtcon_port *port; 579 struct virtqueue *vq; 580 int i; 581 582 if (sc->vtcon_ports == NULL) 583 return; 584 585 VTCON_LOCK(sc); 586 for (i = 0; i < sc->vtcon_max_ports; i++) { 587 scport = &sc->vtcon_ports[i]; 588 589 port = scport->vcsp_port; 590 if (port != NULL) { 591 scport->vcsp_port = NULL; 592 VTCON_PORT_LOCK(port); 593 VTCON_UNLOCK(sc); 594 vtcon_port_teardown(port); 595 VTCON_LOCK(sc); 596 } 597 598 vq = scport->vcsp_invq; 599 if (vq != NULL) 600 vtcon_port_drain_bufs(vq); 601 } 602 VTCON_UNLOCK(sc); 603 604 free(sc->vtcon_ports, M_DEVBUF); 605 sc->vtcon_ports = NULL; 606 } 607 608 static void 609 vtcon_stop(struct vtcon_softc *sc) 610 { 611 612 vtcon_disable_interrupts(sc); 613 virtio_stop(sc->vtcon_dev); 614 } 615 616 static int 617 vtcon_ctrl_event_enqueue(struct vtcon_softc *sc, 618 struct virtio_console_control *control) 619 { 620 struct sglist_seg segs[2]; 621 struct sglist sg; 622 struct virtqueue *vq; 623 int error; 624 625 vq = sc->vtcon_ctrl_rxvq; 626 627 sglist_init(&sg, 2, segs); 628 error = sglist_append(&sg, control, VTCON_CTRL_BUFSZ); 629 KASSERT(error == 0, ("%s: error %d adding control to sglist", 630 __func__, error)); 631 632 return (virtqueue_enqueue(vq, control, &sg, 0, sg.sg_nseg)); 633 } 634 635 static int 636 vtcon_ctrl_event_create(struct vtcon_softc *sc) 637 { 638 struct virtio_console_control *control; 639 int error; 640 641 control = malloc(VTCON_CTRL_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT); 642 if (control == NULL) 643 return (ENOMEM); 644 645 error = vtcon_ctrl_event_enqueue(sc, control); 646 if (error) 647 free(control, M_DEVBUF); 648 649 return (error); 650 } 651 652 static void 653 vtcon_ctrl_event_requeue(struct vtcon_softc *sc, 654 struct virtio_console_control *control) 655 { 656 int error; 657 658 bzero(control, VTCON_CTRL_BUFSZ); 659 660 error = vtcon_ctrl_event_enqueue(sc, control); 661 KASSERT(error == 0, 662 ("%s: cannot requeue control buffer %d", __func__, error)); 663 } 664 665 static int 666 vtcon_ctrl_event_populate(struct vtcon_softc *sc) 667 { 668 struct virtqueue *vq; 669 int nbufs, error; 670 671 vq = sc->vtcon_ctrl_rxvq; 672 error = ENOSPC; 673 674 for (nbufs = 0; !virtqueue_full(vq); nbufs++) { 675 error = vtcon_ctrl_event_create(sc); 676 if (error) 677 break; 678 } 679 680 if (nbufs > 0) { 681 virtqueue_notify(vq); 682 error = 0; 683 } 684 685 return (error); 686 } 687 688 static void 689 vtcon_ctrl_event_drain(struct vtcon_softc *sc) 690 { 691 struct virtio_console_control *control; 692 struct virtqueue *vq; 693 int last; 694 695 vq = sc->vtcon_ctrl_rxvq; 696 last = 0; 697 698 if (vq == NULL) 699 return; 700 701 VTCON_LOCK(sc); 702 while ((control = virtqueue_drain(vq, &last)) != NULL) 703 free(control, M_DEVBUF); 704 VTCON_UNLOCK(sc); 705 } 706 707 static int 708 vtcon_ctrl_init(struct vtcon_softc *sc) 709 { 710 int error; 711 712 error = vtcon_ctrl_event_populate(sc); 713 714 return (error); 715 } 716 717 static void 718 vtcon_ctrl_deinit(struct vtcon_softc *sc) 719 { 720 721 vtcon_ctrl_event_drain(sc); 722 } 723 724 static void 725 vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id) 726 { 727 device_t dev; 728 int error; 729 730 dev = sc->vtcon_dev; 731 732 /* This single thread only way for ports to be created. */ 733 if (sc->vtcon_ports[id].vcsp_port != NULL) { 734 device_printf(dev, "%s: adding port %d, but already exists\n", 735 __func__, id); 736 return; 737 } 738 739 error = vtcon_port_create(sc, id); 740 if (error) { 741 device_printf(dev, "%s: cannot create port %d: %d\n", 742 __func__, id, error); 743 vtcon_ctrl_send_control(sc, id, VIRTIO_CONSOLE_PORT_READY, 0); 744 return; 745 } 746 } 747 748 static void 749 vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id) 750 { 751 device_t dev; 752 struct vtcon_softc_port *scport; 753 struct vtcon_port *port; 754 755 dev = sc->vtcon_dev; 756 scport = &sc->vtcon_ports[id]; 757 758 VTCON_LOCK(sc); 759 port = scport->vcsp_port; 760 if (port == NULL) { 761 VTCON_UNLOCK(sc); 762 device_printf(dev, "%s: remove port %d, but does not exist\n", 763 __func__, id); 764 return; 765 } 766 767 scport->vcsp_port = NULL; 768 VTCON_PORT_LOCK(port); 769 VTCON_UNLOCK(sc); 770 vtcon_port_teardown(port); 771 } 772 773 static void 774 vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id) 775 { 776 device_t dev; 777 struct vtcon_softc_port *scport; 778 struct vtcon_port *port; 779 780 dev = sc->vtcon_dev; 781 scport = &sc->vtcon_ports[id]; 782 783 VTCON_LOCK(sc); 784 port = scport->vcsp_port; 785 if (port == NULL) { 786 VTCON_UNLOCK(sc); 787 device_printf(dev, "%s: console port %d, but does not exist\n", 788 __func__, id); 789 return; 790 } 791 792 VTCON_PORT_LOCK(port); 793 VTCON_UNLOCK(sc); 794 port->vtcport_flags |= VTCON_PORT_FLAG_CONSOLE; 795 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 796 VTCON_PORT_UNLOCK(port); 797 } 798 799 static void 800 vtcon_ctrl_port_open_event(struct vtcon_softc *sc, int id) 801 { 802 device_t dev; 803 struct vtcon_softc_port *scport; 804 struct vtcon_port *port; 805 806 dev = sc->vtcon_dev; 807 scport = &sc->vtcon_ports[id]; 808 809 VTCON_LOCK(sc); 810 port = scport->vcsp_port; 811 if (port == NULL) { 812 VTCON_UNLOCK(sc); 813 device_printf(dev, "%s: open port %d, but does not exist\n", 814 __func__, id); 815 return; 816 } 817 818 VTCON_PORT_LOCK(port); 819 VTCON_UNLOCK(sc); 820 vtcon_port_enable_intr(port); 821 VTCON_PORT_UNLOCK(port); 822 } 823 824 static void 825 vtcon_ctrl_port_name_event(struct vtcon_softc *sc, int id, const char *name, 826 size_t len) 827 { 828 device_t dev; 829 struct vtcon_softc_port *scport; 830 struct vtcon_port *port; 831 832 dev = sc->vtcon_dev; 833 scport = &sc->vtcon_ports[id]; 834 835 /* 836 * The VirtIO specification says the NUL terminator is not included in 837 * the length, but QEMU includes it. Adjust the length if needed. 838 */ 839 if (name == NULL || len == 0) 840 return; 841 if (name[len - 1] == '\0') { 842 len--; 843 if (len == 0) 844 return; 845 } 846 847 VTCON_LOCK(sc); 848 port = scport->vcsp_port; 849 if (port == NULL) { 850 VTCON_UNLOCK(sc); 851 device_printf(dev, "%s: name port %d, but does not exist\n", 852 __func__, id); 853 return; 854 } 855 856 VTCON_PORT_LOCK(port); 857 VTCON_UNLOCK(sc); 858 vtcon_port_dev_alias(port, name, len); 859 VTCON_PORT_UNLOCK(port); 860 } 861 862 static void 863 vtcon_ctrl_process_event(struct vtcon_softc *sc, 864 struct virtio_console_control *control, void *data, size_t data_len) 865 { 866 device_t dev; 867 uint32_t id; 868 uint16_t event; 869 870 dev = sc->vtcon_dev; 871 id = vtcon_htog32(sc, control->id); 872 event = vtcon_htog16(sc, control->event); 873 874 if (id >= sc->vtcon_max_ports) { 875 device_printf(dev, "%s: event %d invalid port ID %d\n", 876 __func__, event, id); 877 return; 878 } 879 880 switch (event) { 881 case VIRTIO_CONSOLE_PORT_ADD: 882 vtcon_ctrl_port_add_event(sc, id); 883 break; 884 885 case VIRTIO_CONSOLE_PORT_REMOVE: 886 vtcon_ctrl_port_remove_event(sc, id); 887 break; 888 889 case VIRTIO_CONSOLE_CONSOLE_PORT: 890 vtcon_ctrl_port_console_event(sc, id); 891 break; 892 893 case VIRTIO_CONSOLE_RESIZE: 894 break; 895 896 case VIRTIO_CONSOLE_PORT_OPEN: 897 vtcon_ctrl_port_open_event(sc, id); 898 break; 899 900 case VIRTIO_CONSOLE_PORT_NAME: 901 vtcon_ctrl_port_name_event(sc, id, (const char *)data, data_len); 902 break; 903 } 904 } 905 906 static void 907 vtcon_ctrl_task_cb(void *xsc, int pending) 908 { 909 struct vtcon_softc *sc; 910 struct virtqueue *vq; 911 struct virtio_console_control *control; 912 void *data; 913 size_t data_len; 914 int detached; 915 uint32_t len; 916 917 sc = xsc; 918 vq = sc->vtcon_ctrl_rxvq; 919 920 VTCON_LOCK(sc); 921 922 while ((detached = (sc->vtcon_flags & VTCON_FLAG_DETACHED)) == 0) { 923 control = virtqueue_dequeue(vq, &len); 924 if (control == NULL) 925 break; 926 927 if (len > sizeof(struct virtio_console_control)) { 928 data = (void *) &control[1]; 929 data_len = len - sizeof(struct virtio_console_control); 930 } else { 931 data = NULL; 932 data_len = 0; 933 } 934 935 VTCON_UNLOCK(sc); 936 vtcon_ctrl_process_event(sc, control, data, data_len); 937 VTCON_LOCK(sc); 938 vtcon_ctrl_event_requeue(sc, control); 939 } 940 941 if (!detached) { 942 virtqueue_notify(vq); 943 if (virtqueue_enable_intr(vq) != 0) 944 taskqueue_enqueue(taskqueue_thread, 945 &sc->vtcon_ctrl_task); 946 } 947 948 VTCON_UNLOCK(sc); 949 } 950 951 static void 952 vtcon_ctrl_event_intr(void *xsc) 953 { 954 struct vtcon_softc *sc; 955 956 sc = xsc; 957 958 /* 959 * Only some events require us to potentially block, but it 960 * easier to just defer all event handling to the taskqueue. 961 */ 962 taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task); 963 } 964 965 static void 966 vtcon_ctrl_poll(struct vtcon_softc *sc, 967 struct virtio_console_control *control) 968 { 969 struct sglist_seg segs[2]; 970 struct sglist sg; 971 struct virtqueue *vq; 972 int error; 973 974 vq = sc->vtcon_ctrl_txvq; 975 976 sglist_init(&sg, 2, segs); 977 error = sglist_append(&sg, control, 978 sizeof(struct virtio_console_control)); 979 KASSERT(error == 0, ("%s: error %d adding control to sglist", 980 __func__, error)); 981 982 /* 983 * We cannot use the softc lock to serialize access to this 984 * virtqueue since this is called from the tty layer with the 985 * port lock held. Acquiring the softc would violate our lock 986 * ordering. 987 */ 988 VTCON_CTRL_TX_LOCK(sc); 989 KASSERT(virtqueue_empty(vq), 990 ("%s: virtqueue is not emtpy", __func__)); 991 error = virtqueue_enqueue(vq, control, &sg, sg.sg_nseg, 0); 992 if (error == 0) { 993 virtqueue_notify(vq); 994 virtqueue_poll(vq, NULL); 995 } 996 VTCON_CTRL_TX_UNLOCK(sc); 997 } 998 999 static void 1000 vtcon_ctrl_send_control(struct vtcon_softc *sc, uint32_t portid, 1001 uint16_t event, uint16_t value) 1002 { 1003 struct virtio_console_control control; 1004 1005 if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0) 1006 return; 1007 1008 control.id = vtcon_gtoh32(sc, portid); 1009 control.event = vtcon_gtoh16(sc, event); 1010 control.value = vtcon_gtoh16(sc, value); 1011 1012 vtcon_ctrl_poll(sc, &control); 1013 } 1014 1015 static int 1016 vtcon_port_enqueue_buf(struct vtcon_port *port, void *buf, size_t len) 1017 { 1018 struct sglist_seg segs[2]; 1019 struct sglist sg; 1020 struct virtqueue *vq; 1021 int error; 1022 1023 vq = port->vtcport_invq; 1024 1025 sglist_init(&sg, 2, segs); 1026 error = sglist_append(&sg, buf, len); 1027 KASSERT(error == 0, 1028 ("%s: error %d adding buffer to sglist", __func__, error)); 1029 1030 error = virtqueue_enqueue(vq, buf, &sg, 0, sg.sg_nseg); 1031 1032 return (error); 1033 } 1034 1035 static int 1036 vtcon_port_create_buf(struct vtcon_port *port) 1037 { 1038 void *buf; 1039 int error; 1040 1041 buf = malloc(VTCON_BULK_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT); 1042 if (buf == NULL) 1043 return (ENOMEM); 1044 1045 error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ); 1046 if (error) 1047 free(buf, M_DEVBUF); 1048 1049 return (error); 1050 } 1051 1052 static void 1053 vtcon_port_requeue_buf(struct vtcon_port *port, void *buf) 1054 { 1055 int error; 1056 1057 error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ); 1058 KASSERT(error == 0, 1059 ("%s: cannot requeue input buffer %d", __func__, error)); 1060 } 1061 1062 static int 1063 vtcon_port_populate(struct vtcon_port *port) 1064 { 1065 struct virtqueue *vq; 1066 int nbufs, error; 1067 1068 vq = port->vtcport_invq; 1069 error = ENOSPC; 1070 1071 for (nbufs = 0; !virtqueue_full(vq); nbufs++) { 1072 error = vtcon_port_create_buf(port); 1073 if (error) 1074 break; 1075 } 1076 1077 if (nbufs > 0) { 1078 virtqueue_notify(vq); 1079 error = 0; 1080 } 1081 1082 return (error); 1083 } 1084 1085 static void 1086 vtcon_port_destroy(struct vtcon_port *port) 1087 { 1088 1089 port->vtcport_sc = NULL; 1090 port->vtcport_scport = NULL; 1091 port->vtcport_invq = NULL; 1092 port->vtcport_outvq = NULL; 1093 port->vtcport_id = -1; 1094 mtx_destroy(&port->vtcport_mtx); 1095 free(port, M_DEVBUF); 1096 } 1097 1098 static int 1099 vtcon_port_init_vqs(struct vtcon_port *port) 1100 { 1101 struct vtcon_softc_port *scport; 1102 int error; 1103 1104 scport = port->vtcport_scport; 1105 1106 port->vtcport_invq = scport->vcsp_invq; 1107 port->vtcport_outvq = scport->vcsp_outvq; 1108 1109 /* 1110 * Free any data left over from when this virtqueue was in use by a 1111 * prior port. We have not yet notified the host that the port is 1112 * ready, so assume nothing in the virtqueue can be for us. 1113 */ 1114 vtcon_port_drain(port); 1115 1116 KASSERT(virtqueue_empty(port->vtcport_invq), 1117 ("%s: in virtqueue is not empty", __func__)); 1118 KASSERT(virtqueue_empty(port->vtcport_outvq), 1119 ("%s: out virtqueue is not empty", __func__)); 1120 1121 error = vtcon_port_populate(port); 1122 if (error) 1123 return (error); 1124 1125 return (0); 1126 } 1127 1128 static int 1129 vtcon_port_create(struct vtcon_softc *sc, int id) 1130 { 1131 device_t dev; 1132 struct vtcon_softc_port *scport; 1133 struct vtcon_port *port; 1134 int error; 1135 1136 dev = sc->vtcon_dev; 1137 scport = &sc->vtcon_ports[id]; 1138 1139 VTCON_ASSERT_VALID_PORTID(sc, id); 1140 MPASS(scport->vcsp_port == NULL); 1141 1142 port = malloc(sizeof(struct vtcon_port), M_DEVBUF, M_NOWAIT | M_ZERO); 1143 if (port == NULL) 1144 return (ENOMEM); 1145 1146 port->vtcport_sc = sc; 1147 port->vtcport_scport = scport; 1148 port->vtcport_id = id; 1149 mtx_init(&port->vtcport_mtx, "vtcpmtx", NULL, MTX_DEF); 1150 port->vtcport_tty = tty_alloc_mutex(&vtcon_tty_class, port, 1151 &port->vtcport_mtx); 1152 1153 error = vtcon_port_init_vqs(port); 1154 if (error) { 1155 VTCON_PORT_LOCK(port); 1156 vtcon_port_teardown(port); 1157 return (error); 1158 } 1159 1160 VTCON_LOCK(sc); 1161 VTCON_PORT_LOCK(port); 1162 scport->vcsp_port = port; 1163 vtcon_port_enable_intr(port); 1164 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_READY, 1); 1165 VTCON_PORT_UNLOCK(port); 1166 VTCON_UNLOCK(sc); 1167 1168 tty_makedev(port->vtcport_tty, NULL, "%s%r.%r", VTCON_TTY_PREFIX, 1169 device_get_unit(dev), id); 1170 1171 return (0); 1172 } 1173 1174 static void 1175 vtcon_port_dev_alias(struct vtcon_port *port, const char *name, size_t len) 1176 { 1177 struct vtcon_softc *sc; 1178 struct cdev *pdev; 1179 struct tty *tp; 1180 int i, error; 1181 1182 sc = port->vtcport_sc; 1183 tp = port->vtcport_tty; 1184 1185 if (port->vtcport_flags & VTCON_PORT_FLAG_ALIAS) 1186 return; 1187 1188 /* Port name is UTF-8, but we can only handle ASCII. */ 1189 for (i = 0; i < len; i++) { 1190 if (!isascii(name[i])) 1191 return; 1192 } 1193 1194 /* 1195 * Port name may not conform to the devfs requirements so we cannot use 1196 * tty_makealias() because the MAKEDEV_CHECKNAME flag must be specified. 1197 */ 1198 error = make_dev_alias_p(MAKEDEV_NOWAIT | MAKEDEV_CHECKNAME, &pdev, 1199 tp->t_dev, "%s/%*s", VTCON_TTY_ALIAS_PREFIX, (int)len, name); 1200 if (error) { 1201 device_printf(sc->vtcon_dev, 1202 "%s: cannot make dev alias (%s/%*s) error %d\n", __func__, 1203 VTCON_TTY_ALIAS_PREFIX, (int)len, name, error); 1204 } else 1205 port->vtcport_flags |= VTCON_PORT_FLAG_ALIAS; 1206 } 1207 1208 static void 1209 vtcon_port_drain_bufs(struct virtqueue *vq) 1210 { 1211 void *buf; 1212 int last; 1213 1214 last = 0; 1215 1216 while ((buf = virtqueue_drain(vq, &last)) != NULL) 1217 free(buf, M_DEVBUF); 1218 } 1219 1220 static void 1221 vtcon_port_drain(struct vtcon_port *port) 1222 { 1223 1224 vtcon_port_drain_bufs(port->vtcport_invq); 1225 } 1226 1227 static void 1228 vtcon_port_teardown(struct vtcon_port *port) 1229 { 1230 struct tty *tp; 1231 1232 tp = port->vtcport_tty; 1233 1234 port->vtcport_flags |= VTCON_PORT_FLAG_GONE; 1235 1236 if (tp != NULL) { 1237 atomic_add_int(&vtcon_pending_free, 1); 1238 tty_rel_gone(tp); 1239 } else 1240 vtcon_port_destroy(port); 1241 } 1242 1243 static void 1244 vtcon_port_change_size(struct vtcon_port *port, uint16_t cols, uint16_t rows) 1245 { 1246 struct tty *tp; 1247 struct winsize sz; 1248 1249 tp = port->vtcport_tty; 1250 1251 if (tp == NULL) 1252 return; 1253 1254 bzero(&sz, sizeof(struct winsize)); 1255 sz.ws_col = cols; 1256 sz.ws_row = rows; 1257 1258 tty_set_winsize(tp, &sz); 1259 } 1260 1261 static void 1262 vtcon_port_update_console_size(struct vtcon_softc *sc) 1263 { 1264 struct vtcon_port *port; 1265 struct vtcon_softc_port *scport; 1266 uint16_t cols, rows; 1267 1268 vtcon_get_console_size(sc, &cols, &rows); 1269 1270 /* 1271 * For now, assume the first (only) port is the console. Note 1272 * QEMU does not implement this feature yet. 1273 */ 1274 scport = &sc->vtcon_ports[0]; 1275 1276 VTCON_LOCK(sc); 1277 port = scport->vcsp_port; 1278 1279 if (port != NULL) { 1280 VTCON_PORT_LOCK(port); 1281 VTCON_UNLOCK(sc); 1282 vtcon_port_change_size(port, cols, rows); 1283 VTCON_PORT_UNLOCK(port); 1284 } else 1285 VTCON_UNLOCK(sc); 1286 } 1287 1288 static void 1289 vtcon_port_enable_intr(struct vtcon_port *port) 1290 { 1291 1292 /* 1293 * NOTE: The out virtqueue is always polled, so its interrupt 1294 * kept disabled. 1295 */ 1296 virtqueue_enable_intr(port->vtcport_invq); 1297 } 1298 1299 static void 1300 vtcon_port_disable_intr(struct vtcon_port *port) 1301 { 1302 1303 if (port->vtcport_invq != NULL) 1304 virtqueue_disable_intr(port->vtcport_invq); 1305 if (port->vtcport_outvq != NULL) 1306 virtqueue_disable_intr(port->vtcport_outvq); 1307 } 1308 1309 static void 1310 vtcon_port_in(struct vtcon_port *port) 1311 { 1312 struct virtqueue *vq; 1313 struct tty *tp; 1314 char *buf; 1315 uint32_t len; 1316 int i, deq; 1317 1318 tp = port->vtcport_tty; 1319 vq = port->vtcport_invq; 1320 1321 again: 1322 deq = 0; 1323 1324 while ((buf = virtqueue_dequeue(vq, &len)) != NULL) { 1325 for (i = 0; i < len; i++) { 1326 #if defined(KDB) 1327 if (port->vtcport_flags & VTCON_PORT_FLAG_CONSOLE) 1328 kdb_alt_break(buf[i], 1329 &port->vtcport_alt_break_state); 1330 #endif 1331 ttydisc_rint(tp, buf[i], 0); 1332 } 1333 vtcon_port_requeue_buf(port, buf); 1334 deq++; 1335 } 1336 ttydisc_rint_done(tp); 1337 1338 if (deq > 0) 1339 virtqueue_notify(vq); 1340 1341 if (virtqueue_enable_intr(vq) != 0) 1342 goto again; 1343 } 1344 1345 static void 1346 vtcon_port_intr(void *scportx) 1347 { 1348 struct vtcon_softc_port *scport; 1349 struct vtcon_softc *sc; 1350 struct vtcon_port *port; 1351 1352 scport = scportx; 1353 sc = scport->vcsp_sc; 1354 1355 VTCON_LOCK(sc); 1356 port = scport->vcsp_port; 1357 if (port == NULL) { 1358 VTCON_UNLOCK(sc); 1359 return; 1360 } 1361 VTCON_PORT_LOCK(port); 1362 VTCON_UNLOCK(sc); 1363 if ((port->vtcport_flags & VTCON_PORT_FLAG_GONE) == 0) 1364 vtcon_port_in(port); 1365 VTCON_PORT_UNLOCK(port); 1366 } 1367 1368 static void 1369 vtcon_port_out(struct vtcon_port *port, void *buf, int bufsize) 1370 { 1371 struct sglist_seg segs[2]; 1372 struct sglist sg; 1373 struct virtqueue *vq; 1374 int error; 1375 1376 vq = port->vtcport_outvq; 1377 KASSERT(virtqueue_empty(vq), 1378 ("%s: port %p out virtqueue not emtpy", __func__, port)); 1379 1380 sglist_init(&sg, 2, segs); 1381 error = sglist_append(&sg, buf, bufsize); 1382 KASSERT(error == 0, ("%s: error %d adding buffer to sglist", 1383 __func__, error)); 1384 1385 error = virtqueue_enqueue(vq, buf, &sg, sg.sg_nseg, 0); 1386 if (error == 0) { 1387 virtqueue_notify(vq); 1388 virtqueue_poll(vq, NULL); 1389 } 1390 } 1391 1392 static void 1393 vtcon_port_submit_event(struct vtcon_port *port, uint16_t event, 1394 uint16_t value) 1395 { 1396 struct vtcon_softc *sc; 1397 1398 sc = port->vtcport_sc; 1399 1400 vtcon_ctrl_send_control(sc, port->vtcport_id, event, value); 1401 } 1402 1403 static int 1404 vtcon_tty_open(struct tty *tp) 1405 { 1406 struct vtcon_port *port; 1407 1408 port = tty_softc(tp); 1409 1410 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) 1411 return (ENXIO); 1412 1413 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 1414 1415 return (0); 1416 } 1417 1418 static void 1419 vtcon_tty_close(struct tty *tp) 1420 { 1421 struct vtcon_port *port; 1422 1423 port = tty_softc(tp); 1424 1425 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) 1426 return; 1427 1428 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0); 1429 } 1430 1431 static void 1432 vtcon_tty_outwakeup(struct tty *tp) 1433 { 1434 struct vtcon_port *port; 1435 char buf[VTCON_BULK_BUFSZ]; 1436 int len; 1437 1438 port = tty_softc(tp); 1439 1440 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) 1441 return; 1442 1443 while ((len = ttydisc_getc(tp, buf, sizeof(buf))) != 0) 1444 vtcon_port_out(port, buf, len); 1445 } 1446 1447 static void 1448 vtcon_tty_free(void *xport) 1449 { 1450 struct vtcon_port *port; 1451 1452 port = xport; 1453 1454 vtcon_port_destroy(port); 1455 atomic_subtract_int(&vtcon_pending_free, 1); 1456 } 1457 1458 static void 1459 vtcon_get_console_size(struct vtcon_softc *sc, uint16_t *cols, uint16_t *rows) 1460 { 1461 struct virtio_console_config concfg; 1462 1463 KASSERT(sc->vtcon_flags & VTCON_FLAG_SIZE, 1464 ("%s: size feature not negotiated", __func__)); 1465 1466 vtcon_read_config(sc, &concfg); 1467 1468 *cols = concfg.cols; 1469 *rows = concfg.rows; 1470 } 1471 1472 static void 1473 vtcon_enable_interrupts(struct vtcon_softc *sc) 1474 { 1475 struct vtcon_softc_port *scport; 1476 struct vtcon_port *port; 1477 int i; 1478 1479 VTCON_LOCK(sc); 1480 1481 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) 1482 virtqueue_enable_intr(sc->vtcon_ctrl_rxvq); 1483 1484 for (i = 0; i < sc->vtcon_max_ports; i++) { 1485 scport = &sc->vtcon_ports[i]; 1486 1487 port = scport->vcsp_port; 1488 if (port == NULL) 1489 continue; 1490 1491 VTCON_PORT_LOCK(port); 1492 vtcon_port_enable_intr(port); 1493 VTCON_PORT_UNLOCK(port); 1494 } 1495 1496 VTCON_UNLOCK(sc); 1497 } 1498 1499 static void 1500 vtcon_disable_interrupts(struct vtcon_softc *sc) 1501 { 1502 struct vtcon_softc_port *scport; 1503 struct vtcon_port *port; 1504 int i; 1505 1506 VTCON_LOCK_ASSERT(sc); 1507 1508 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) 1509 virtqueue_disable_intr(sc->vtcon_ctrl_rxvq); 1510 1511 for (i = 0; i < sc->vtcon_max_ports; i++) { 1512 scport = &sc->vtcon_ports[i]; 1513 1514 port = scport->vcsp_port; 1515 if (port == NULL) 1516 continue; 1517 1518 VTCON_PORT_LOCK(port); 1519 vtcon_port_disable_intr(port); 1520 VTCON_PORT_UNLOCK(port); 1521 } 1522 } 1523