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