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