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