1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009, 2013 The FreeBSD Foundation 5 * 6 * This software was developed by Ed Schouten under sponsorship from the 7 * FreeBSD Foundation. 8 * 9 * Portions of this software were developed by Oleksandr Rybalko 10 * under sponsorship from the FreeBSD Foundation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/consio.h> 36 #include <sys/devctl.h> 37 #include <sys/eventhandler.h> 38 #include <sys/fbio.h> 39 #include <sys/font.h> 40 #include <sys/kbio.h> 41 #include <sys/kdb.h> 42 #include <sys/kernel.h> 43 #include <sys/limits.h> 44 #include <sys/linker.h> 45 #include <sys/lock.h> 46 #include <sys/malloc.h> 47 #include <sys/mutex.h> 48 #include <sys/splash.h> 49 #include <sys/power.h> 50 #include <sys/priv.h> 51 #include <sys/proc.h> 52 #include <sys/random.h> 53 #include <sys/reboot.h> 54 #include <sys/sbuf.h> 55 #include <sys/systm.h> 56 #include <sys/terminal.h> 57 58 #include <dev/kbd/kbdreg.h> 59 #include <dev/vt/vt.h> 60 61 #if defined(__i386__) || defined(__amd64__) 62 #include <machine/psl.h> 63 #include <machine/frame.h> 64 #endif 65 66 static int vtterm_cngrab_noswitch(struct vt_device *, struct vt_window *); 67 static int vtterm_cnungrab_noswitch(struct vt_device *, struct vt_window *); 68 69 static tc_bell_t vtterm_bell; 70 static tc_cursor_t vtterm_cursor; 71 static tc_putchar_t vtterm_putchar; 72 static tc_fill_t vtterm_fill; 73 static tc_copy_t vtterm_copy; 74 static tc_pre_input_t vtterm_pre_input; 75 static tc_post_input_t vtterm_post_input; 76 static tc_param_t vtterm_param; 77 static tc_done_t vtterm_done; 78 79 static tc_cnprobe_t vtterm_cnprobe; 80 static tc_cngetc_t vtterm_cngetc; 81 82 static tc_cngrab_t vtterm_cngrab; 83 static tc_cnungrab_t vtterm_cnungrab; 84 85 static tc_opened_t vtterm_opened; 86 static tc_ioctl_t vtterm_ioctl; 87 static tc_mmap_t vtterm_mmap; 88 89 static const struct terminal_class vt_termclass = { 90 .tc_bell = vtterm_bell, 91 .tc_cursor = vtterm_cursor, 92 .tc_putchar = vtterm_putchar, 93 .tc_fill = vtterm_fill, 94 .tc_copy = vtterm_copy, 95 .tc_pre_input = vtterm_pre_input, 96 .tc_post_input = vtterm_post_input, 97 .tc_param = vtterm_param, 98 .tc_done = vtterm_done, 99 100 .tc_cnprobe = vtterm_cnprobe, 101 .tc_cngetc = vtterm_cngetc, 102 103 .tc_cngrab = vtterm_cngrab, 104 .tc_cnungrab = vtterm_cnungrab, 105 106 .tc_opened = vtterm_opened, 107 .tc_ioctl = vtterm_ioctl, 108 .tc_mmap = vtterm_mmap, 109 }; 110 111 /* 112 * Use a constant timer of 25 Hz to redraw the screen. 113 * 114 * XXX: In theory we should only fire up the timer when there is really 115 * activity. Unfortunately we cannot always start timers. We really 116 * don't want to process kernel messages synchronously, because it 117 * really slows down the system. 118 */ 119 #define VT_TIMERFREQ 25 120 121 /* Bell pitch/duration. */ 122 #define VT_BELLDURATION (SBT_1S / 20) 123 #define VT_BELLPITCH 800 124 125 #define VT_UNIT(vw) ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \ 126 (vw)->vw_number) 127 128 static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 129 "vt(4) parameters"); 130 static VT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)"); 131 static VT_SYSCTL_INT(enable_bell, 0, "Enable bell"); 132 static VT_SYSCTL_INT(debug, 0, "vt(4) debug level"); 133 static VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode"); 134 static VT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend"); 135 136 /* Slow down and dont rely on timers and interrupts */ 137 static VT_SYSCTL_INT(slow_down, 0, "Non-zero make console slower and synchronous."); 138 139 /* Allow to disable some keyboard combinations. */ 140 static VT_SYSCTL_INT(kbd_halt, 1, "Enable halt keyboard combination. " 141 "See kbdmap(5) to configure."); 142 static VT_SYSCTL_INT(kbd_poweroff, 1, "Enable Power Off keyboard combination. " 143 "See kbdmap(5) to configure."); 144 static VT_SYSCTL_INT(kbd_reboot, 1, "Enable reboot keyboard combination. " 145 "See kbdmap(5) to configure (typically Ctrl-Alt-Delete)."); 146 static VT_SYSCTL_INT(kbd_debug, 1, "Enable key combination to enter debugger. " 147 "See kbdmap(5) to configure (typically Ctrl-Alt-Esc)."); 148 static VT_SYSCTL_INT(kbd_panic, 0, "Enable request to panic. " 149 "See kbdmap(5) to configure."); 150 151 /* Used internally, not a tunable. */ 152 int vt_draw_logo_cpus; 153 VT_SYSCTL_INT(splash_cpu, 0, "Show logo CPUs during boot"); 154 VT_SYSCTL_INT(splash_ncpu, 0, "Override number of logos displayed " 155 "(0 = do not override)"); 156 VT_SYSCTL_INT(splash_cpu_style, 2, "Draw logo style " 157 "(0 = Alternate beastie, 1 = Beastie, 2 = Orb)"); 158 VT_SYSCTL_INT(splash_cpu_duration, 10, "Hide logos after (seconds)"); 159 160 static unsigned int vt_unit = 0; 161 static MALLOC_DEFINE(M_VT, "vt", "vt device"); 162 struct vt_device *main_vd = &vt_consdev; 163 164 /* Boot logo. */ 165 extern unsigned int vt_logo_width; 166 extern unsigned int vt_logo_height; 167 extern unsigned int vt_logo_depth; 168 extern unsigned char vt_logo_image[]; 169 #ifndef DEV_SPLASH 170 #define vtterm_draw_cpu_logos(...) do {} while (0) 171 const unsigned int vt_logo_sprite_height; 172 #endif 173 174 /* 175 * Console font. vt_font_loader will be filled with font data passed 176 * by loader. If there is no font passed by boot loader, we use built in 177 * default. 178 */ 179 extern struct vt_font vt_font_default; 180 static struct vt_font vt_font_loader; 181 static struct vt_font *vt_font_assigned = &vt_font_default; 182 183 #ifndef SC_NO_CUTPASTE 184 extern struct vt_mouse_cursor vt_default_mouse_pointer; 185 #endif 186 187 static int signal_vt_rel(struct vt_window *); 188 static int signal_vt_acq(struct vt_window *); 189 static int finish_vt_rel(struct vt_window *, int, int *); 190 static int finish_vt_acq(struct vt_window *); 191 static int vt_window_switch(struct vt_window *); 192 static int vt_late_window_switch(struct vt_window *); 193 static int vt_proc_alive(struct vt_window *); 194 static void vt_resize(struct vt_device *); 195 static void vt_update_static(void *); 196 #ifndef SC_NO_CUTPASTE 197 static void vt_mouse_paste(void); 198 #endif 199 static void vt_suspend_handler(void *priv, enum power_stype stype); 200 static void vt_resume_handler(void *priv, enum power_stype stype); 201 202 SET_DECLARE(vt_drv_set, struct vt_driver); 203 204 #define _VTDEFH MAX(100, PIXEL_HEIGHT(VT_FB_MAX_HEIGHT)) 205 #define _VTDEFW MAX(200, PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 206 207 static struct terminal vt_consterm; 208 static struct vt_window vt_conswindow; 209 static term_char_t vt_consdrawn[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; 210 static term_color_t vt_consdrawnfg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; 211 static term_color_t vt_consdrawnbg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; 212 static bool vt_cons_pos_to_flush[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; 213 struct vt_device vt_consdev = { 214 .vd_driver = NULL, 215 .vd_softc = NULL, 216 .vd_prev_driver = NULL, 217 .vd_prev_softc = NULL, 218 .vd_flags = VDF_INVALID, 219 .vd_windows = { [VT_CONSWINDOW] = &vt_conswindow, }, 220 .vd_curwindow = &vt_conswindow, 221 .vd_kbstate = 0, 222 223 #ifndef SC_NO_CUTPASTE 224 .vd_pastebuf = { 225 .vpb_buf = NULL, 226 .vpb_bufsz = 0, 227 .vpb_len = 0 228 }, 229 .vd_mcursor = &vt_default_mouse_pointer, 230 .vd_mcursor_fg = TC_WHITE, 231 .vd_mcursor_bg = TC_BLACK, 232 #endif 233 234 .vd_drawn = vt_consdrawn, 235 .vd_drawnfg = vt_consdrawnfg, 236 .vd_drawnbg = vt_consdrawnbg, 237 238 .vd_pos_to_flush = vt_cons_pos_to_flush, 239 }; 240 static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)]; 241 static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE]; 242 static struct vt_window vt_conswindow = { 243 .vw_number = VT_CONSWINDOW, 244 .vw_flags = VWF_CONSOLE, 245 .vw_buf = { 246 .vb_buffer = &vt_constextbuf[0], 247 .vb_rows = &vt_constextbufrows[0], 248 .vb_history_size = VBF_DEFAULT_HISTORY_SIZE, 249 .vb_curroffset = 0, 250 .vb_roffset = 0, 251 .vb_flags = VBF_STATIC, 252 .vb_mark_start = {.tp_row = 0, .tp_col = 0,}, 253 .vb_mark_end = {.tp_row = 0, .tp_col = 0,}, 254 .vb_scr_size = { 255 .tp_row = _VTDEFH, 256 .tp_col = _VTDEFW, 257 }, 258 }, 259 .vw_device = &vt_consdev, 260 .vw_terminal = &vt_consterm, 261 .vw_kbdmode = K_XLATE, 262 .vw_grabbed = 0, 263 .vw_bell_pitch = VT_BELLPITCH, 264 .vw_bell_duration = VT_BELLDURATION, 265 }; 266 267 /* Add to set of consoles. */ 268 TERMINAL_DECLARE_EARLY(vt_consterm, vt_termclass, &vt_conswindow); 269 270 /* 271 * Right after kmem is done to allow early drivers to use locking and allocate 272 * memory. 273 */ 274 SYSINIT(vt_update_static, SI_SUB_KMEM, SI_ORDER_ANY, vt_update_static, 275 &vt_consdev); 276 /* Delay until all devices attached, to not waste time. */ 277 SYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, vt_upgrade, 278 &vt_consdev); 279 280 static bool inside_vt_flush = false; 281 static bool inside_vt_window_switch = false; 282 283 /* Initialize locks/mem depended members. */ 284 static void 285 vt_update_static(void *dummy) 286 { 287 288 if (!vty_enabled(VTY_VT)) 289 return; 290 if (main_vd->vd_driver != NULL) 291 printf("VT(%s): %s %ux%u\n", main_vd->vd_driver->vd_name, 292 (main_vd->vd_flags & VDF_TEXTMODE) ? "text" : "resolution", 293 main_vd->vd_width, main_vd->vd_height); 294 else 295 printf("VT: init without driver.\n"); 296 297 mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF); 298 mtx_init(&main_vd->vd_flush_lock, "vtdev flush", NULL, MTX_DEF); 299 cv_init(&main_vd->vd_winswitch, "vtwswt"); 300 } 301 302 static void 303 vt_schedule_flush(struct vt_device *vd, int ms) 304 { 305 306 if (ms <= 0) 307 /* Default to initial value. */ 308 ms = 1000 / VT_TIMERFREQ; 309 310 callout_schedule(&vd->vd_timer, hz / (1000 / ms)); 311 } 312 313 void 314 vt_resume_flush_timer(struct vt_window *vw, int ms) 315 { 316 struct vt_device *vd = vw->vw_device; 317 318 if (vd->vd_curwindow != vw) 319 return; 320 321 if (!(vd->vd_flags & VDF_ASYNC) || 322 !atomic_cmpset_int(&vd->vd_timer_armed, 0, 1)) 323 return; 324 325 vt_schedule_flush(vd, ms); 326 } 327 328 static void 329 vt_suspend_flush_timer(struct vt_device *vd) 330 { 331 /* 332 * As long as this function is called locked, callout_stop() 333 * has the same effect like callout_drain() with regard to 334 * preventing the callback function from executing. 335 */ 336 VT_LOCK_ASSERT(vd, MA_OWNED); 337 338 if (!(vd->vd_flags & VDF_ASYNC) || 339 !atomic_cmpset_int(&vd->vd_timer_armed, 1, 0)) 340 return; 341 342 callout_stop(&vd->vd_timer); 343 } 344 345 static void 346 vt_switch_timer(void *arg, int pending) 347 { 348 349 (void)vt_late_window_switch((struct vt_window *)arg); 350 } 351 352 static int 353 vt_save_kbd_mode(struct vt_window *vw, keyboard_t *kbd) 354 { 355 int mode, ret; 356 357 mode = 0; 358 ret = kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode); 359 if (ret == ENOIOCTL) 360 ret = ENODEV; 361 if (ret != 0) 362 return (ret); 363 364 vw->vw_kbdmode = mode; 365 366 return (0); 367 } 368 369 static int 370 vt_update_kbd_mode(struct vt_window *vw, keyboard_t *kbd) 371 { 372 int ret; 373 374 ret = kbdd_ioctl(kbd, KDSKBMODE, (caddr_t)&vw->vw_kbdmode); 375 if (ret == ENOIOCTL) 376 ret = ENODEV; 377 378 return (ret); 379 } 380 381 static int 382 vt_save_kbd_state(struct vt_window *vw, keyboard_t *kbd) 383 { 384 int state, ret; 385 386 state = 0; 387 ret = kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 388 if (ret == ENOIOCTL) 389 ret = ENODEV; 390 if (ret != 0) 391 return (ret); 392 393 vw->vw_kbdstate &= ~LOCK_MASK; 394 vw->vw_kbdstate |= state & LOCK_MASK; 395 396 return (0); 397 } 398 399 static int 400 vt_update_kbd_state(struct vt_window *vw, keyboard_t *kbd) 401 { 402 int state, ret; 403 404 state = vw->vw_kbdstate & LOCK_MASK; 405 ret = kbdd_ioctl(kbd, KDSKBSTATE, (caddr_t)&state); 406 if (ret == ENOIOCTL) 407 ret = ENODEV; 408 409 return (ret); 410 } 411 412 static int 413 vt_save_kbd_leds(struct vt_window *vw, keyboard_t *kbd) 414 { 415 int leds, ret; 416 417 leds = 0; 418 ret = kbdd_ioctl(kbd, KDGETLED, (caddr_t)&leds); 419 if (ret == ENOIOCTL) 420 ret = ENODEV; 421 if (ret != 0) 422 return (ret); 423 424 vw->vw_kbdstate &= ~LED_MASK; 425 vw->vw_kbdstate |= leds & LED_MASK; 426 427 return (0); 428 } 429 430 static int 431 vt_update_kbd_leds(struct vt_window *vw, keyboard_t *kbd) 432 { 433 int leds, ret; 434 435 leds = vw->vw_kbdstate & LED_MASK; 436 ret = kbdd_ioctl(kbd, KDSETLED, (caddr_t)&leds); 437 if (ret == ENOIOCTL) 438 ret = ENODEV; 439 440 return (ret); 441 } 442 443 static int 444 vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw) 445 { 446 447 DPRINTF(40, "%s\n", __func__); 448 curvw->vw_switch_to = vw; 449 /* Set timer to allow switch in case when process hang. */ 450 taskqueue_enqueue_timeout(taskqueue_thread, &vw->vw_timeout_task_dead, hz * vt_deadtimer); 451 /* Notify process about vt switch attempt. */ 452 DPRINTF(30, "%s: Notify process.\n", __func__); 453 signal_vt_rel(curvw); 454 455 return (0); 456 } 457 458 static int 459 vt_window_postswitch(struct vt_window *vw) 460 { 461 462 signal_vt_acq(vw); 463 return (0); 464 } 465 466 /* vt_late_window_switch will do VT switching for regular case. */ 467 static int 468 vt_late_window_switch(struct vt_window *vw) 469 { 470 struct vt_window *curvw; 471 int ret; 472 473 taskqueue_cancel_timeout(taskqueue_thread, &vw->vw_timeout_task_dead, NULL); 474 475 ret = vt_window_switch(vw); 476 if (ret != 0) { 477 /* 478 * If the switch hasn't happened, then return the VT 479 * to the current owner, if any. 480 */ 481 curvw = vw->vw_device->vd_curwindow; 482 if (curvw->vw_smode.mode == VT_PROCESS) 483 (void)vt_window_postswitch(curvw); 484 return (ret); 485 } 486 487 /* Notify owner process about terminal availability. */ 488 if (vw->vw_smode.mode == VT_PROCESS) { 489 ret = vt_window_postswitch(vw); 490 } 491 return (ret); 492 } 493 494 /* Switch window. */ 495 static int 496 vt_proc_window_switch(struct vt_window *vw) 497 { 498 struct vt_window *curvw; 499 struct vt_device *vd; 500 int ret; 501 502 /* Prevent switching to NULL */ 503 if (vw == NULL) { 504 DPRINTF(30, "%s: Cannot switch: vw is NULL.", __func__); 505 return (EINVAL); 506 } 507 vd = vw->vw_device; 508 curvw = vd->vd_curwindow; 509 510 /* Check if virtual terminal is locked */ 511 if (curvw->vw_flags & VWF_VTYLOCK) 512 return (EBUSY); 513 514 /* Check if switch already in progress */ 515 if (curvw->vw_flags & VWF_SWWAIT_REL) { 516 /* Check if switching to same window */ 517 if (curvw->vw_switch_to == vw) { 518 DPRINTF(30, "%s: Switch in progress to same vw.", __func__); 519 return (0); /* success */ 520 } 521 DPRINTF(30, "%s: Switch in progress to different vw.", __func__); 522 return (EBUSY); 523 } 524 525 /* Avoid switching to already selected window */ 526 if (vw == curvw) { 527 DPRINTF(30, "%s: Cannot switch: vw == curvw.", __func__); 528 return (0); /* success */ 529 } 530 531 /* 532 * Early check for an attempt to switch to a non-functional VT. 533 * The same check is done in vt_window_switch(), but it's better 534 * to fail as early as possible to avoid needless pre-switch 535 * actions. 536 */ 537 VT_LOCK(vd); 538 if ((vw->vw_flags & (VWF_OPENED|VWF_CONSOLE)) == 0) { 539 VT_UNLOCK(vd); 540 return (EINVAL); 541 } 542 VT_UNLOCK(vd); 543 544 /* Ask current process permission to switch away. */ 545 if (curvw->vw_smode.mode == VT_PROCESS) { 546 DPRINTF(30, "%s: VT_PROCESS ", __func__); 547 if (vt_proc_alive(curvw) == FALSE) { 548 DPRINTF(30, "Dead. Cleaning."); 549 /* Dead */ 550 } else { 551 DPRINTF(30, "%s: Signaling process.\n", __func__); 552 /* Alive, try to ask him. */ 553 ret = vt_window_preswitch(vw, curvw); 554 /* Wait for process answer or timeout. */ 555 return (ret); 556 } 557 DPRINTF(30, "\n"); 558 } 559 560 ret = vt_late_window_switch(vw); 561 return (ret); 562 } 563 564 /* Switch window ignoring process locking. */ 565 static int 566 vt_window_switch(struct vt_window *vw) 567 { 568 struct vt_device *vd = vw->vw_device; 569 struct vt_window *curvw = vd->vd_curwindow; 570 keyboard_t *kbd; 571 572 if (inside_vt_window_switch && KERNEL_PANICKED()) 573 return (0); 574 575 inside_vt_window_switch = true; 576 577 if (kdb_active) { 578 /* 579 * When grabbing the console for the debugger, avoid 580 * locks as that can result in deadlock. While this 581 * could use try locks, that wouldn't really make a 582 * difference as there are sufficient barriers in 583 * debugger entry/exit to be equivalent to 584 * successfully try-locking here. 585 */ 586 if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) { 587 inside_vt_window_switch = false; 588 return (EINVAL); 589 } 590 591 vd->vd_curwindow = vw; 592 vd->vd_flags |= VDF_INVALID; 593 if (vd->vd_driver->vd_postswitch) 594 vd->vd_driver->vd_postswitch(vd); 595 inside_vt_window_switch = false; 596 return (0); 597 } 598 599 VT_LOCK(vd); 600 if (curvw == vw) { 601 /* 602 * Nothing to do, except ensure the driver has the opportunity to 603 * switch to console mode when panicking, making sure the panic 604 * is readable (even when a GUI was using ttyv0). 605 */ 606 if ((kdb_active || KERNEL_PANICKED()) && 607 vd->vd_driver->vd_postswitch) 608 vd->vd_driver->vd_postswitch(vd); 609 inside_vt_window_switch = false; 610 VT_UNLOCK(vd); 611 return (0); 612 } 613 if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) { 614 inside_vt_window_switch = false; 615 VT_UNLOCK(vd); 616 return (EINVAL); 617 } 618 619 vt_suspend_flush_timer(vd); 620 621 vd->vd_curwindow = vw; 622 vd->vd_flags |= VDF_INVALID; 623 cv_broadcast(&vd->vd_winswitch); 624 VT_UNLOCK(vd); 625 626 if (vd->vd_driver->vd_postswitch) 627 vd->vd_driver->vd_postswitch(vd); 628 629 vt_resume_flush_timer(vw, 0); 630 631 /* Restore per-window keyboard mode. */ 632 mtx_lock(&Giant); 633 if ((kbd = vd->vd_keyboard) != NULL) { 634 if (curvw->vw_kbdmode == K_XLATE) 635 vt_save_kbd_state(curvw, kbd); 636 637 vt_update_kbd_mode(vw, kbd); 638 vt_update_kbd_state(vw, kbd); 639 } 640 mtx_unlock(&Giant); 641 DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number); 642 643 inside_vt_window_switch = false; 644 return (0); 645 } 646 647 void 648 vt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size) 649 { 650 651 size->tp_row = vd->vd_height; 652 if (vt_draw_logo_cpus) 653 size->tp_row -= vt_logo_sprite_height; 654 size->tp_col = vd->vd_width; 655 if (vf != NULL) { 656 size->tp_row = MIN(size->tp_row / vf->vf_height, 657 PIXEL_HEIGHT(VT_FB_MAX_HEIGHT)); 658 size->tp_col = MIN(size->tp_col / vf->vf_width, 659 PIXEL_WIDTH(VT_FB_MAX_WIDTH)); 660 } 661 } 662 663 static inline void 664 vt_termrect(struct vt_device *vd, struct vt_font *vf, term_rect_t *rect) 665 { 666 667 rect->tr_begin.tp_row = rect->tr_begin.tp_col = 0; 668 if (vt_draw_logo_cpus) 669 rect->tr_begin.tp_row = vt_logo_sprite_height; 670 671 rect->tr_end.tp_row = vd->vd_height; 672 rect->tr_end.tp_col = vd->vd_width; 673 674 if (vf != NULL) { 675 rect->tr_begin.tp_row = 676 howmany(rect->tr_begin.tp_row, vf->vf_height); 677 678 rect->tr_end.tp_row = MIN(rect->tr_end.tp_row / vf->vf_height, 679 PIXEL_HEIGHT(VT_FB_MAX_HEIGHT)); 680 rect->tr_end.tp_col = MIN(rect->tr_end.tp_col / vf->vf_width, 681 PIXEL_WIDTH(VT_FB_MAX_WIDTH)); 682 } 683 } 684 685 void 686 vt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size) 687 { 688 689 size->ws_ypixel = vd->vd_height; 690 if (vt_draw_logo_cpus) 691 size->ws_ypixel -= vt_logo_sprite_height; 692 size->ws_row = size->ws_ypixel; 693 size->ws_col = size->ws_xpixel = vd->vd_width; 694 if (vf != NULL) { 695 size->ws_row = MIN(size->ws_row / vf->vf_height, 696 PIXEL_HEIGHT(VT_FB_MAX_HEIGHT)); 697 size->ws_col = MIN(size->ws_col / vf->vf_width, 698 PIXEL_WIDTH(VT_FB_MAX_WIDTH)); 699 } 700 } 701 702 void 703 vt_compute_drawable_area(struct vt_window *vw) 704 { 705 struct vt_device *vd; 706 struct vt_font *vf; 707 vt_axis_t height; 708 709 vd = vw->vw_device; 710 711 if (vw->vw_font == NULL) { 712 vw->vw_draw_area.tr_begin.tp_col = 0; 713 vw->vw_draw_area.tr_begin.tp_row = 0; 714 if (vt_draw_logo_cpus) 715 vw->vw_draw_area.tr_begin.tp_row = vt_logo_sprite_height; 716 vw->vw_draw_area.tr_end.tp_col = vd->vd_width; 717 vw->vw_draw_area.tr_end.tp_row = vd->vd_height; 718 return; 719 } 720 721 vf = vw->vw_font; 722 723 /* 724 * Compute the drawable area, so that the text is centered on 725 * the screen. 726 */ 727 728 height = vd->vd_height; 729 if (vt_draw_logo_cpus) 730 height -= vt_logo_sprite_height; 731 vw->vw_draw_area.tr_begin.tp_col = (vd->vd_width % vf->vf_width) / 2; 732 vw->vw_draw_area.tr_begin.tp_row = (height % vf->vf_height) / 2; 733 if (vt_draw_logo_cpus) 734 vw->vw_draw_area.tr_begin.tp_row += vt_logo_sprite_height; 735 vw->vw_draw_area.tr_end.tp_col = vw->vw_draw_area.tr_begin.tp_col + 736 rounddown(vd->vd_width, vf->vf_width); 737 vw->vw_draw_area.tr_end.tp_row = vw->vw_draw_area.tr_begin.tp_row + 738 rounddown(height, vf->vf_height); 739 } 740 741 static void 742 vt_scroll(struct vt_window *vw, int offset, int whence) 743 { 744 int diff; 745 term_pos_t size; 746 747 if ((vw->vw_flags & VWF_SCROLL) == 0) 748 return; 749 750 vt_termsize(vw->vw_device, vw->vw_font, &size); 751 752 diff = vthistory_seek(&vw->vw_buf, offset, whence); 753 if (diff) 754 vw->vw_device->vd_flags |= VDF_INVALID; 755 vt_resume_flush_timer(vw, 0); 756 } 757 758 static int 759 vt_machine_kbdevent(struct vt_device *vd, int c) 760 { 761 762 switch (c) { 763 case SPCLKEY | DBG: /* kbdmap(5) keyword `debug`. */ 764 if (vt_kbd_debug) { 765 kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); 766 #if VT_ALT_TO_ESC_HACK 767 /* 768 * There's an unfortunate conflict between SPCLKEY|DBG 769 * and VT_ALT_TO_ESC_HACK. Just assume they didn't mean 770 * it if we got to here. 771 */ 772 vd->vd_kbstate &= ~ALKED; 773 #endif 774 } 775 return (1); 776 case SPCLKEY | HALT: /* kbdmap(5) keyword `halt`. */ 777 if (vt_kbd_halt) 778 shutdown_nice(RB_HALT); 779 return (1); 780 case SPCLKEY | PASTE: /* kbdmap(5) keyword `paste`. */ 781 #ifndef SC_NO_CUTPASTE 782 /* Insert text from cut-paste buffer. */ 783 vt_mouse_paste(); 784 #endif 785 break; 786 case SPCLKEY | PDWN: /* kbdmap(5) keyword `pdwn`. */ 787 if (vt_kbd_poweroff) 788 shutdown_nice(RB_HALT|RB_POWEROFF); 789 return (1); 790 case SPCLKEY | PNC: /* kbdmap(5) keyword `panic`. */ 791 /* 792 * Request to immediate panic if sysctl 793 * kern.vt.enable_panic_key allow it. 794 */ 795 if (vt_kbd_panic) 796 panic("Forced by the panic key"); 797 return (1); 798 case SPCLKEY | RBT: /* kbdmap(5) keyword `boot`. */ 799 if (vt_kbd_reboot) 800 shutdown_nice(RB_AUTOBOOT); 801 return (1); 802 case SPCLKEY | SPSC: /* kbdmap(5) keyword `spsc`. */ 803 /* Force activatation/deactivation of the screen saver. */ 804 /* TODO */ 805 return (1); 806 case SPCLKEY | STBY: /* XXX Not present in kbdcontrol parser. */ 807 /* Put machine into Stand-By mode. */ 808 (void)power_pm_suspend(POWER_TRANSITION_STANDBY); 809 return (1); 810 case SPCLKEY | SUSP: /* kbdmap(5) keyword `susp`. */ 811 /* Suspend machine. */ 812 (void)power_pm_suspend(POWER_TRANSITION_SUSPEND); 813 return (1); 814 } 815 816 return (0); 817 } 818 819 static void 820 vt_scrollmode_kbdevent(struct vt_window *vw, int c, int console) 821 { 822 struct vt_device *vd; 823 term_pos_t size; 824 825 vd = vw->vw_device; 826 /* Only special keys handled in ScrollLock mode */ 827 if ((c & SPCLKEY) == 0) 828 return; 829 830 c &= ~SPCLKEY; 831 832 if (console == 0) { 833 if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 834 vw = vd->vd_windows[c - F_SCR]; 835 vt_proc_window_switch(vw); 836 return; 837 } 838 VT_LOCK(vd); 839 } 840 841 switch (c) { 842 case SLK: { 843 /* Turn scrolling off. */ 844 vt_scroll(vw, 0, VHS_END); 845 VTBUF_SLCK_DISABLE(&vw->vw_buf); 846 vw->vw_flags &= ~VWF_SCROLL; 847 break; 848 } 849 case FKEY | F(49): /* Home key. */ 850 vt_scroll(vw, 0, VHS_SET); 851 break; 852 case FKEY | F(50): /* Arrow up. */ 853 vt_scroll(vw, -1, VHS_CUR); 854 break; 855 case FKEY | F(51): /* Page up. */ 856 vt_termsize(vd, vw->vw_font, &size); 857 vt_scroll(vw, -size.tp_row, VHS_CUR); 858 break; 859 case FKEY | F(57): /* End key. */ 860 vt_scroll(vw, 0, VHS_END); 861 break; 862 case FKEY | F(58): /* Arrow down. */ 863 vt_scroll(vw, 1, VHS_CUR); 864 break; 865 case FKEY | F(59): /* Page down. */ 866 vt_termsize(vd, vw->vw_font, &size); 867 vt_scroll(vw, size.tp_row, VHS_CUR); 868 break; 869 } 870 871 if (console == 0) 872 VT_UNLOCK(vd); 873 } 874 875 static int 876 vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c) 877 { 878 struct vt_window *vw = vd->vd_curwindow; 879 880 #ifdef RANDOM_ENABLE_KBD 881 random_harvest_queue(&c, sizeof(c), RANDOM_KEYBOARD); 882 #endif 883 #if VT_ALT_TO_ESC_HACK 884 if (c & RELKEY) { 885 switch (c & ~RELKEY) { 886 case (SPCLKEY | RALT): 887 if (vt_enable_altgr != 0) 888 break; 889 case (SPCLKEY | LALT): 890 vd->vd_kbstate &= ~ALKED; 891 } 892 /* Other keys ignored for RELKEY event. */ 893 return (0); 894 } else { 895 switch (c & ~RELKEY) { 896 case (SPCLKEY | RALT): 897 if (vt_enable_altgr != 0) 898 break; 899 case (SPCLKEY | LALT): 900 vd->vd_kbstate |= ALKED; 901 } 902 } 903 #else 904 if (c & RELKEY) 905 /* Other keys ignored for RELKEY event. */ 906 return (0); 907 #endif 908 909 if (vt_machine_kbdevent(vd, c)) 910 return (0); 911 912 if (vw->vw_flags & VWF_SCROLL) { 913 vt_scrollmode_kbdevent(vw, c, 0/* Not a console */); 914 /* Scroll mode keys handled, nothing to do more. */ 915 return (0); 916 } 917 918 if (c & SPCLKEY) { 919 c &= ~SPCLKEY; 920 921 if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 922 vw = vd->vd_windows[c - F_SCR]; 923 vt_proc_window_switch(vw); 924 return (0); 925 } 926 927 switch (c) { 928 case NEXT: 929 /* Switch to next VT. */ 930 c = (vw->vw_number + 1) % VT_MAXWINDOWS; 931 vw = vd->vd_windows[c]; 932 vt_proc_window_switch(vw); 933 return (0); 934 case PREV: 935 /* Switch to previous VT. */ 936 c = (vw->vw_number + VT_MAXWINDOWS - 1) % VT_MAXWINDOWS; 937 vw = vd->vd_windows[c]; 938 vt_proc_window_switch(vw); 939 return (0); 940 case SLK: { 941 vt_save_kbd_state(vw, kbd); 942 VT_LOCK(vd); 943 if (vw->vw_kbdstate & SLKED) { 944 /* Turn scrolling on. */ 945 vw->vw_flags |= VWF_SCROLL; 946 VTBUF_SLCK_ENABLE(&vw->vw_buf); 947 } else { 948 /* Turn scrolling off. */ 949 vw->vw_flags &= ~VWF_SCROLL; 950 VTBUF_SLCK_DISABLE(&vw->vw_buf); 951 vt_scroll(vw, 0, VHS_END); 952 } 953 VT_UNLOCK(vd); 954 break; 955 } 956 case BKEY | BTAB: /* Back tab (usually, shift+tab). */ 957 terminal_input_special(vw->vw_terminal, TKEY_BTAB); 958 break; 959 case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 960 case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 961 case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 962 case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 963 /* F1 through F12 keys. */ 964 terminal_input_special(vw->vw_terminal, 965 TKEY_F1 + c - (FKEY | F(1))); 966 break; 967 case FKEY | F(49): /* Home key. */ 968 terminal_input_special(vw->vw_terminal, TKEY_HOME); 969 break; 970 case FKEY | F(50): /* Arrow up. */ 971 terminal_input_special(vw->vw_terminal, TKEY_UP); 972 break; 973 case FKEY | F(51): /* Page up. */ 974 terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP); 975 break; 976 case FKEY | F(53): /* Arrow left. */ 977 terminal_input_special(vw->vw_terminal, TKEY_LEFT); 978 break; 979 case FKEY | F(55): /* Arrow right. */ 980 terminal_input_special(vw->vw_terminal, TKEY_RIGHT); 981 break; 982 case FKEY | F(57): /* End key. */ 983 terminal_input_special(vw->vw_terminal, TKEY_END); 984 break; 985 case FKEY | F(58): /* Arrow down. */ 986 terminal_input_special(vw->vw_terminal, TKEY_DOWN); 987 break; 988 case FKEY | F(59): /* Page down. */ 989 terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN); 990 break; 991 case FKEY | F(60): /* Insert key. */ 992 terminal_input_special(vw->vw_terminal, TKEY_INSERT); 993 break; 994 case FKEY | F(61): /* Delete key. */ 995 terminal_input_special(vw->vw_terminal, TKEY_DELETE); 996 break; 997 } 998 } else if (KEYFLAGS(c) == 0) { 999 /* Don't do UTF-8 conversion when doing raw mode. */ 1000 if (vw->vw_kbdmode == K_XLATE) { 1001 #if VT_ALT_TO_ESC_HACK 1002 if (vd->vd_kbstate & ALKED) { 1003 /* 1004 * Prepend ESC sequence if one of ALT keys down. 1005 */ 1006 terminal_input_char(vw->vw_terminal, 0x1b); 1007 } 1008 #endif 1009 #if defined(KDB) 1010 kdb_alt_break(c, &vd->vd_altbrk); 1011 #endif 1012 terminal_input_char(vw->vw_terminal, KEYCHAR(c)); 1013 } else 1014 terminal_input_raw(vw->vw_terminal, c); 1015 } 1016 return (0); 1017 } 1018 1019 static int 1020 vt_kbdevent(keyboard_t *kbd, int event, void *arg) 1021 { 1022 struct vt_device *vd = arg; 1023 int c; 1024 1025 switch (event) { 1026 case KBDIO_KEYINPUT: 1027 break; 1028 case KBDIO_UNLOADING: 1029 mtx_lock(&Giant); 1030 vd->vd_keyboard = NULL; 1031 kbd_release(kbd, (void *)vd); 1032 mtx_unlock(&Giant); 1033 return (0); 1034 default: 1035 return (EINVAL); 1036 } 1037 1038 while ((c = kbdd_read_char(kbd, 0)) != NOKEY) 1039 vt_processkey(kbd, vd, c); 1040 1041 return (0); 1042 } 1043 1044 static int 1045 vt_allocate_keyboard(struct vt_device *vd) 1046 { 1047 int grabbed, i, idx0, idx; 1048 keyboard_t *k0, *k; 1049 keyboard_info_t ki; 1050 1051 /* 1052 * If vt_upgrade() happens while the console is grabbed, we are 1053 * potentially going to switch keyboard devices while the keyboard is in 1054 * use. Unwind the grabbing of the current keyboard first, then we will 1055 * re-grab the new keyboard below, before we return. 1056 */ 1057 if (vd->vd_curwindow == &vt_conswindow) { 1058 grabbed = vd->vd_curwindow->vw_grabbed; 1059 for (i = 0; i < grabbed; ++i) 1060 vtterm_cnungrab_noswitch(vd, vd->vd_curwindow); 1061 } 1062 1063 idx0 = kbd_allocate("kbdmux", -1, vd, vt_kbdevent, vd); 1064 if (idx0 >= 0) { 1065 DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); 1066 k0 = kbd_get_keyboard(idx0); 1067 1068 for (idx = kbd_find_keyboard2("*", -1, 0); 1069 idx != -1; 1070 idx = kbd_find_keyboard2("*", -1, idx + 1)) { 1071 k = kbd_get_keyboard(idx); 1072 1073 if (idx == idx0 || KBD_IS_BUSY(k)) 1074 continue; 1075 1076 bzero(&ki, sizeof(ki)); 1077 strncpy(ki.kb_name, k->kb_name, sizeof(ki.kb_name)); 1078 ki.kb_name[sizeof(ki.kb_name) - 1] = '\0'; 1079 ki.kb_unit = k->kb_unit; 1080 1081 kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 1082 } 1083 } else { 1084 DPRINTF(20, "%s: no kbdmux allocated\n", __func__); 1085 idx0 = kbd_allocate("*", -1, vd, vt_kbdevent, vd); 1086 if (idx0 < 0) { 1087 DPRINTF(10, "%s: No keyboard found.\n", __func__); 1088 return (-1); 1089 } 1090 k0 = kbd_get_keyboard(idx0); 1091 } 1092 vd->vd_keyboard = k0; 1093 DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, 1094 vd->vd_keyboard->kb_index); 1095 1096 if (vd->vd_curwindow == &vt_conswindow) { 1097 for (i = 0; i < grabbed; ++i) 1098 vtterm_cngrab_noswitch(vd, vd->vd_curwindow); 1099 } 1100 1101 return (idx0); 1102 } 1103 1104 #define DEVCTL_LEN 64 1105 static void 1106 vtterm_devctl(bool enabled, bool hushed, int hz, sbintime_t duration) 1107 { 1108 struct sbuf sb; 1109 char *buf; 1110 1111 buf = malloc(DEVCTL_LEN, M_VT, M_NOWAIT); 1112 if (buf == NULL) 1113 return; 1114 sbuf_new(&sb, buf, DEVCTL_LEN, SBUF_FIXEDLEN); 1115 sbuf_printf(&sb, "enabled=%s hushed=%s hz=%d duration_ms=%d", 1116 enabled ? "true" : "false", hushed ? "true" : "false", 1117 hz, (int)(duration / SBT_1MS)); 1118 sbuf_finish(&sb); 1119 if (sbuf_error(&sb) == 0) 1120 devctl_notify("VT", "BELL", "RING", sbuf_data(&sb)); 1121 sbuf_delete(&sb); 1122 free(buf, M_VT); 1123 } 1124 1125 static void 1126 vtterm_bell(struct terminal *tm) 1127 { 1128 struct vt_window *vw = tm->tm_softc; 1129 struct vt_device *vd = vw->vw_device; 1130 1131 vtterm_devctl(vt_enable_bell, vd->vd_flags & VDF_QUIET_BELL, 1132 vw->vw_bell_pitch, vw->vw_bell_duration); 1133 1134 if (!vt_enable_bell) 1135 return; 1136 1137 if (vd->vd_flags & VDF_QUIET_BELL) 1138 return; 1139 1140 if (vw->vw_bell_pitch == 0 || 1141 vw->vw_bell_duration == 0) 1142 return; 1143 1144 sysbeep(vw->vw_bell_pitch, vw->vw_bell_duration); 1145 } 1146 1147 /* 1148 * Beep with user-provided frequency and duration as specified by a KDMKTONE 1149 * ioctl (compatible with Linux). The frequency is specified as a 8254 PIT 1150 * divisor for a 1.19MHz clock. 1151 * 1152 * See https://tldp.org/LDP/lpg/node83.html. 1153 */ 1154 static void 1155 vtterm_beep(struct terminal *tm, u_int param) 1156 { 1157 u_int freq; 1158 sbintime_t period; 1159 struct vt_window *vw = tm->tm_softc; 1160 struct vt_device *vd = vw->vw_device; 1161 1162 if ((param == 0) || ((param & 0xffff) == 0)) { 1163 vtterm_bell(tm); 1164 return; 1165 } 1166 1167 /* XXX period unit is supposed to be "timer ticks." */ 1168 period = ((param >> 16) & 0xffff) * SBT_1MS; 1169 freq = 1193182 / (param & 0xffff); 1170 1171 vtterm_devctl(vt_enable_bell, vd->vd_flags & VDF_QUIET_BELL, 1172 freq, period); 1173 1174 if (!vt_enable_bell) 1175 return; 1176 1177 sysbeep(freq, period); 1178 } 1179 1180 static void 1181 vtterm_cursor(struct terminal *tm, const term_pos_t *p) 1182 { 1183 struct vt_window *vw = tm->tm_softc; 1184 1185 vtbuf_cursor_position(&vw->vw_buf, p); 1186 } 1187 1188 static void 1189 vtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c) 1190 { 1191 struct vt_window *vw = tm->tm_softc; 1192 1193 vtbuf_putchar(&vw->vw_buf, p, c); 1194 } 1195 1196 static void 1197 vtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c) 1198 { 1199 struct vt_window *vw = tm->tm_softc; 1200 1201 #ifndef SC_NO_CUTPASTE 1202 vtbuf_unmark_on_cross(&vw->vw_buf, r->tr_begin.tp_row, 1203 r->tr_end.tp_row); 1204 #endif 1205 vtbuf_fill(&vw->vw_buf, r, c); 1206 } 1207 1208 static void 1209 vtterm_copy(struct terminal *tm, const term_rect_t *r, 1210 const term_pos_t *p) 1211 { 1212 struct vt_window *vw = tm->tm_softc; 1213 1214 vtbuf_copy(&vw->vw_buf, r, p); 1215 } 1216 1217 static void 1218 vtterm_param(struct terminal *tm, int cmd, unsigned int arg) 1219 { 1220 struct vt_window *vw = tm->tm_softc; 1221 1222 switch (cmd) { 1223 case TP_SETLOCALCURSOR: 1224 /* 1225 * 0 means normal (usually block), 1 means hidden, and 1226 * 2 means blinking (always block) for compatibility with 1227 * syscons. We don't support any changes except hiding, 1228 * so must map 2 to 0. 1229 */ 1230 arg = (arg == 1) ? 0 : 1; 1231 /* FALLTHROUGH */ 1232 case TP_SHOWCURSOR: 1233 vtbuf_cursor_visibility(&vw->vw_buf, arg); 1234 vt_resume_flush_timer(vw, 0); 1235 break; 1236 case TP_MOUSE: 1237 vw->vw_mouse_level = arg; 1238 break; 1239 case TP_SETBELLPD: 1240 vw->vw_bell_pitch = TP_SETBELLPD_PITCH(arg); 1241 vw->vw_bell_duration = 1242 TICKS_2_MSEC(TP_SETBELLPD_DURATION(arg)) * SBT_1MS; 1243 break; 1244 } 1245 } 1246 1247 void 1248 vt_determine_colors(term_char_t c, int cursor, 1249 term_color_t *fg, term_color_t *bg) 1250 { 1251 term_color_t tmp; 1252 int invert; 1253 1254 invert = 0; 1255 1256 *fg = TCHAR_FGCOLOR(c); 1257 if (TCHAR_FORMAT(c) & TF_BOLD) 1258 *fg = TCOLOR_LIGHT(*fg); 1259 *bg = TCHAR_BGCOLOR(c); 1260 if (TCHAR_FORMAT(c) & TF_BLINK) 1261 *bg = TCOLOR_LIGHT(*bg); 1262 1263 if (TCHAR_FORMAT(c) & TF_REVERSE) 1264 invert ^= 1; 1265 if (cursor) 1266 invert ^= 1; 1267 1268 if (invert) { 1269 tmp = *fg; 1270 *fg = *bg; 1271 *bg = tmp; 1272 } 1273 } 1274 1275 #ifndef SC_NO_CUTPASTE 1276 int 1277 vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area) 1278 { 1279 unsigned int mx, my; 1280 1281 /* 1282 * We use the cursor position saved during the current refresh, 1283 * in case the cursor moved since. 1284 */ 1285 mx = vd->vd_mx_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_col; 1286 my = vd->vd_my_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_row; 1287 1288 if (mx >= area->tr_end.tp_col || 1289 mx + vd->vd_mcursor->width <= area->tr_begin.tp_col || 1290 my >= area->tr_end.tp_row || 1291 my + vd->vd_mcursor->height <= area->tr_begin.tp_row) 1292 return (0); 1293 return (1); 1294 } 1295 1296 static void 1297 vt_mark_mouse_position_as_dirty(struct vt_device *vd, int locked) 1298 { 1299 term_rect_t area; 1300 struct vt_window *vw; 1301 struct vt_font *vf; 1302 int x, y; 1303 1304 vw = vd->vd_curwindow; 1305 vf = vw->vw_font; 1306 1307 x = vd->vd_mx_drawn; 1308 y = vd->vd_my_drawn; 1309 1310 if (vf != NULL) { 1311 area.tr_begin.tp_col = x / vf->vf_width; 1312 area.tr_begin.tp_row = y / vf->vf_height; 1313 area.tr_end.tp_col = 1314 ((x + vd->vd_mcursor->width) / vf->vf_width) + 1; 1315 area.tr_end.tp_row = 1316 ((y + vd->vd_mcursor->height) / vf->vf_height) + 1; 1317 } else { 1318 /* 1319 * No font loaded (ie. vt_vga operating in textmode). 1320 * 1321 * FIXME: This fake area needs to be revisited once the 1322 * mouse cursor is supported in vt_vga's textmode. 1323 */ 1324 area.tr_begin.tp_col = x; 1325 area.tr_begin.tp_row = y; 1326 area.tr_end.tp_col = x + 2; 1327 area.tr_end.tp_row = y + 2; 1328 } 1329 1330 if (!locked) 1331 vtbuf_lock(&vw->vw_buf); 1332 if (vd->vd_driver->vd_invalidate_text) 1333 vd->vd_driver->vd_invalidate_text(vd, &area); 1334 vtbuf_dirty(&vw->vw_buf, &area); 1335 if (!locked) 1336 vtbuf_unlock(&vw->vw_buf); 1337 } 1338 #endif 1339 1340 static void 1341 vt_set_border(struct vt_device *vd, const term_rect_t *area, 1342 term_color_t c) 1343 { 1344 vd_drawrect_t *drawrect = vd->vd_driver->vd_drawrect; 1345 1346 if (drawrect == NULL) 1347 return; 1348 1349 /* Top bar */ 1350 if (area->tr_begin.tp_row > 0) 1351 drawrect(vd, 0, 0, vd->vd_width - 1, 1352 area->tr_begin.tp_row - 1, 1, c); 1353 1354 /* Left bar */ 1355 if (area->tr_begin.tp_col > 0) 1356 drawrect(vd, 0, area->tr_begin.tp_row, 1357 area->tr_begin.tp_col - 1, area->tr_end.tp_row - 1, 1, c); 1358 1359 /* Right bar */ 1360 if (area->tr_end.tp_col < vd->vd_width) 1361 drawrect(vd, area->tr_end.tp_col, area->tr_begin.tp_row, 1362 vd->vd_width - 1, area->tr_end.tp_row - 1, 1, c); 1363 1364 /* Bottom bar */ 1365 if (area->tr_end.tp_row < vd->vd_height) 1366 drawrect(vd, 0, area->tr_end.tp_row, vd->vd_width - 1, 1367 vd->vd_height - 1, 1, c); 1368 } 1369 1370 static void 1371 vt_flush_to_buffer(struct vt_device *vd, 1372 const struct vt_window *vw, const term_rect_t *area) 1373 { 1374 unsigned int col, row; 1375 term_char_t c; 1376 term_color_t fg, bg; 1377 size_t z; 1378 1379 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 1380 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 1381 ++col) { 1382 z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 1383 if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * 1384 PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 1385 continue; 1386 1387 c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 1388 vt_determine_colors(c, 1389 VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 1390 1391 if (vd->vd_drawn && (vd->vd_drawn[z] == c) && 1392 vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && 1393 vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) { 1394 vd->vd_pos_to_flush[z] = false; 1395 continue; 1396 } 1397 1398 vd->vd_pos_to_flush[z] = true; 1399 1400 if (vd->vd_drawn) 1401 vd->vd_drawn[z] = c; 1402 if (vd->vd_drawnfg) 1403 vd->vd_drawnfg[z] = fg; 1404 if (vd->vd_drawnbg) 1405 vd->vd_drawnbg[z] = bg; 1406 } 1407 } 1408 } 1409 1410 static void 1411 vt_bitblt_buffer(struct vt_device *vd, const struct vt_window *vw, 1412 const term_rect_t *area) 1413 { 1414 unsigned int col, row, x, y; 1415 struct vt_font *vf; 1416 term_char_t c; 1417 term_color_t fg, bg; 1418 const uint8_t *pattern; 1419 size_t z; 1420 1421 vf = vw->vw_font; 1422 1423 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 1424 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 1425 ++col) { 1426 x = col * vf->vf_width + 1427 vw->vw_draw_area.tr_begin.tp_col; 1428 y = row * vf->vf_height + 1429 vw->vw_draw_area.tr_begin.tp_row; 1430 1431 z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 1432 if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * 1433 PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 1434 continue; 1435 if (!vd->vd_pos_to_flush[z]) 1436 continue; 1437 1438 c = vd->vd_drawn[z]; 1439 fg = vd->vd_drawnfg[z]; 1440 bg = vd->vd_drawnbg[z]; 1441 1442 pattern = vtfont_lookup(vf, c); 1443 vd->vd_driver->vd_bitblt_bmp(vd, vw, 1444 pattern, NULL, vf->vf_width, vf->vf_height, 1445 x, y, fg, bg); 1446 } 1447 } 1448 1449 #ifndef SC_NO_CUTPASTE 1450 if (!vd->vd_mshown) 1451 return; 1452 1453 term_rect_t drawn_area; 1454 1455 drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 1456 drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 1457 drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 1458 drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 1459 1460 if (vt_is_cursor_in_area(vd, &drawn_area)) { 1461 vd->vd_driver->vd_bitblt_bmp(vd, vw, 1462 vd->vd_mcursor->map, vd->vd_mcursor->mask, 1463 vd->vd_mcursor->width, vd->vd_mcursor->height, 1464 vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 1465 vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 1466 vd->vd_mcursor_fg, vd->vd_mcursor_bg); 1467 } 1468 #endif 1469 } 1470 1471 static void 1472 vt_draw_decorations(struct vt_device *vd) 1473 { 1474 struct vt_window *vw; 1475 const teken_attr_t *a; 1476 1477 vw = vd->vd_curwindow; 1478 1479 a = teken_get_curattr(&vw->vw_terminal->tm_emulator); 1480 vt_set_border(vd, &vw->vw_draw_area, a->ta_bgcolor); 1481 1482 if (vt_draw_logo_cpus) 1483 vtterm_draw_cpu_logos(vd); 1484 } 1485 1486 static int 1487 vt_flush(struct vt_device *vd) 1488 { 1489 struct vt_window *vw; 1490 struct vt_font *vf; 1491 term_rect_t tarea; 1492 #ifndef SC_NO_CUTPASTE 1493 int cursor_was_shown, cursor_moved; 1494 #endif 1495 bool needs_refresh; 1496 1497 if (inside_vt_flush && KERNEL_PANICKED()) 1498 return (0); 1499 1500 vw = vd->vd_curwindow; 1501 if (vw == NULL) 1502 return (0); 1503 1504 if (vw->vw_flags & VWF_BUSY) 1505 return (0); 1506 1507 vf = vw->vw_font; 1508 if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL)) 1509 return (0); 1510 1511 VT_FLUSH_LOCK(vd); 1512 1513 vtbuf_lock(&vw->vw_buf); 1514 1515 if (vd->vd_flags & VDF_SPLASH) { 1516 vtbuf_unlock(&vw->vw_buf); 1517 VT_FLUSH_UNLOCK(vd); 1518 return (0); 1519 } 1520 1521 inside_vt_flush = true; 1522 1523 #ifndef SC_NO_CUTPASTE 1524 cursor_was_shown = vd->vd_mshown; 1525 cursor_moved = (vd->vd_mx != vd->vd_mx_drawn || 1526 vd->vd_my != vd->vd_my_drawn); 1527 1528 /* Check if the cursor should be displayed or not. */ 1529 if ((vd->vd_flags & VDF_MOUSECURSOR) && /* Mouse support enabled. */ 1530 !(vw->vw_flags & VWF_MOUSE_HIDE) && /* Cursor displayed. */ 1531 !kdb_active && !KERNEL_PANICKED()) { /* DDB inactive. */ 1532 vd->vd_mshown = 1; 1533 } else { 1534 vd->vd_mshown = 0; 1535 } 1536 1537 /* 1538 * If the cursor changed display state or moved, we must mark 1539 * the old position as dirty, so that it's erased. 1540 */ 1541 if (cursor_was_shown != vd->vd_mshown || 1542 (vd->vd_mshown && cursor_moved)) 1543 vt_mark_mouse_position_as_dirty(vd, true); 1544 1545 /* 1546 * Save position of the mouse cursor. It's used by backends to 1547 * know where to draw the cursor and during the next refresh to 1548 * erase the previous position. 1549 */ 1550 vd->vd_mx_drawn = vd->vd_mx; 1551 vd->vd_my_drawn = vd->vd_my; 1552 1553 /* 1554 * If the cursor is displayed and has moved since last refresh, 1555 * mark the new position as dirty. 1556 */ 1557 if (vd->vd_mshown && cursor_moved) 1558 vt_mark_mouse_position_as_dirty(vd, true); 1559 #endif 1560 1561 vtbuf_undirty(&vw->vw_buf, &tarea); 1562 1563 /* Force a full redraw when the screen contents might be invalid. */ 1564 needs_refresh = false; 1565 if (vd->vd_flags & (VDF_INVALID | VDF_SUSPENDED)) { 1566 needs_refresh = true; 1567 vd->vd_flags &= ~VDF_INVALID; 1568 1569 vt_termrect(vd, vf, &tarea); 1570 if (vd->vd_driver->vd_invalidate_text) 1571 vd->vd_driver->vd_invalidate_text(vd, &tarea); 1572 } 1573 1574 if (tarea.tr_begin.tp_col < tarea.tr_end.tp_col) { 1575 if (vd->vd_driver->vd_bitblt_after_vtbuf_unlock) { 1576 /* 1577 * When `vd_bitblt_after_vtbuf_unlock` is set to true, 1578 * we first remember the characters to redraw. They are 1579 * already copied to the `vd_drawn` arrays. 1580 * 1581 * We then unlock vt_buf and proceed with the actual 1582 * drawing using the backend driver. 1583 */ 1584 vt_flush_to_buffer(vd, vw, &tarea); 1585 vtbuf_unlock(&vw->vw_buf); 1586 vt_bitblt_buffer(vd, vw, &tarea); 1587 1588 if (needs_refresh) 1589 vt_draw_decorations(vd); 1590 1591 /* 1592 * We can reset `inside_vt_flush` after unlocking vtbuf 1593 * here because we also hold vt_flush_lock in this code 1594 * path. 1595 */ 1596 inside_vt_flush = false; 1597 } else { 1598 /* 1599 * When `vd_bitblt_after_vtbuf_unlock` is false, we use 1600 * the backend's `vd_bitblt_text` callback directly. 1601 */ 1602 vd->vd_driver->vd_bitblt_text(vd, vw, &tarea); 1603 1604 if (needs_refresh) 1605 vt_draw_decorations(vd); 1606 1607 inside_vt_flush = false; 1608 vtbuf_unlock(&vw->vw_buf); 1609 } 1610 1611 VT_FLUSH_UNLOCK(vd); 1612 1613 return (1); 1614 } 1615 1616 inside_vt_flush = false; 1617 vtbuf_unlock(&vw->vw_buf); 1618 1619 VT_FLUSH_UNLOCK(vd); 1620 1621 return (0); 1622 } 1623 1624 static void 1625 vt_timer(void *arg) 1626 { 1627 struct vt_device *vd; 1628 int changed; 1629 1630 vd = arg; 1631 /* Update screen if required. */ 1632 changed = vt_flush(vd); 1633 1634 /* Schedule for next update. */ 1635 if (changed) 1636 vt_schedule_flush(vd, 0); 1637 else 1638 vd->vd_timer_armed = 0; 1639 } 1640 1641 static void 1642 vtterm_pre_input(struct terminal *tm) 1643 { 1644 struct vt_window *vw = tm->tm_softc; 1645 1646 if (inside_vt_flush && KERNEL_PANICKED()) 1647 return; 1648 1649 vtbuf_lock(&vw->vw_buf); 1650 } 1651 1652 static void 1653 vtterm_post_input(struct terminal *tm) 1654 { 1655 struct vt_window *vw = tm->tm_softc; 1656 1657 if (inside_vt_flush && KERNEL_PANICKED()) 1658 return; 1659 1660 vtbuf_unlock(&vw->vw_buf); 1661 vt_resume_flush_timer(vw, 0); 1662 } 1663 1664 static void 1665 vtterm_done(struct terminal *tm) 1666 { 1667 struct vt_window *vw = tm->tm_softc; 1668 struct vt_device *vd = vw->vw_device; 1669 1670 if (kdb_active || KERNEL_PANICKED()) { 1671 /* Switch to the debugger. */ 1672 if (vd->vd_curwindow != vw) { 1673 vd->vd_curwindow = vw; 1674 vd->vd_flags |= VDF_INVALID; 1675 if (vd->vd_driver->vd_postswitch) 1676 vd->vd_driver->vd_postswitch(vd); 1677 } 1678 vd->vd_flags &= ~VDF_SPLASH; 1679 vt_flush(vd); 1680 } else if (vt_slow_down > 0) { 1681 int i, j; 1682 for (i = 0; i < vt_slow_down; i++) { 1683 for (j = 0; j < 1000; j++) 1684 vt_flush(vd); 1685 } 1686 } else if (!(vd->vd_flags & VDF_ASYNC)) { 1687 vt_flush(vd); 1688 } 1689 } 1690 1691 #ifdef DEV_SPLASH 1692 static void 1693 vtterm_splash(struct vt_device *vd) 1694 { 1695 struct splash_info *si; 1696 uintptr_t image; 1697 vt_axis_t top, left; 1698 1699 if (KERNEL_PANICKED()) 1700 return; 1701 1702 if ((vd->vd_flags & VDF_TEXTMODE) != 0 || (boothowto & RB_MUTE) == 0) 1703 return; 1704 1705 si = MD_FETCH(preload_kmdp, rebooting == 1 ? MODINFOMD_SHTDWNSPLASH : 1706 MODINFOMD_SPLASH, struct splash_info *); 1707 /* Quit before taking the lock if the backend lacks something. */ 1708 if (si == NULL) { 1709 if (vd->vd_driver->vd_bitblt_bmp == NULL) 1710 return; 1711 } else if (vd->vd_driver->vd_bitblt_argb == NULL || si->si_depth != 4) 1712 return; 1713 if (rebooting == 1 && vd->vd_driver->vd_blank == NULL) 1714 return; 1715 1716 vtbuf_lock(&vd->vd_curwindow->vw_buf); 1717 vd->vd_flags |= VDF_SPLASH; 1718 vtbuf_unlock(&vd->vd_curwindow->vw_buf); 1719 1720 if (rebooting == 1) 1721 vd->vd_driver->vd_blank(vd, TC_BLACK); 1722 1723 if (si == NULL) { 1724 top = (vd->vd_height - vt_logo_height) / 2; 1725 left = (vd->vd_width - vt_logo_width) / 2; 1726 vd->vd_driver->vd_bitblt_bmp(vd, 1727 vd->vd_curwindow, vt_logo_image, NULL, vt_logo_width, 1728 vt_logo_height, left, top, TC_WHITE, TC_BLACK); 1729 } else { 1730 image = (uintptr_t)si + sizeof(struct splash_info); 1731 image = roundup2(image, 8); 1732 top = (vd->vd_height - si->si_height) / 2; 1733 left = (vd->vd_width - si->si_width) / 2; 1734 vd->vd_driver->vd_bitblt_argb(vd, vd->vd_curwindow, 1735 (unsigned char *)image, si->si_width, si->si_height, 1736 left, top); 1737 } 1738 } 1739 #endif 1740 1741 static struct vt_font * 1742 parse_font_info_static(struct font_info *fi) 1743 { 1744 struct vt_font *vfp; 1745 uintptr_t ptr; 1746 uint32_t checksum; 1747 1748 if (fi == NULL) 1749 return (NULL); 1750 1751 ptr = (uintptr_t)fi; 1752 /* 1753 * Compute and verify checksum. The total sum of all the fields 1754 * must be 0. 1755 */ 1756 checksum = fi->fi_width; 1757 checksum += fi->fi_height; 1758 checksum += fi->fi_bitmap_size; 1759 for (unsigned i = 0; i < VFNT_MAPS; i++) 1760 checksum += fi->fi_map_count[i]; 1761 1762 if (checksum + fi->fi_checksum != 0) 1763 return (NULL); 1764 1765 ptr += sizeof(struct font_info); 1766 ptr = roundup2(ptr, 8); 1767 1768 vfp = &vt_font_loader; 1769 vfp->vf_height = fi->fi_height; 1770 vfp->vf_width = fi->fi_width; 1771 /* This is default font, set refcount 1 to disable removal. */ 1772 vfp->vf_refcount = 1; 1773 for (unsigned i = 0; i < VFNT_MAPS; i++) { 1774 if (fi->fi_map_count[i] == 0) 1775 continue; 1776 vfp->vf_map_count[i] = fi->fi_map_count[i]; 1777 vfp->vf_map[i] = (vfnt_map_t *)ptr; 1778 ptr += (fi->fi_map_count[i] * sizeof(vfnt_map_t)); 1779 ptr = roundup2(ptr, 8); 1780 } 1781 vfp->vf_bytes = (uint8_t *)ptr; 1782 return (vfp); 1783 } 1784 1785 /* 1786 * Set up default font with allocated data structures. 1787 * However, we can not set refcount here, because it is already set and 1788 * incremented in vtterm_cnprobe() to avoid being released by font load from 1789 * userland. 1790 */ 1791 static struct vt_font * 1792 parse_font_info(struct font_info *fi) 1793 { 1794 struct vt_font *vfp; 1795 uintptr_t ptr; 1796 uint32_t checksum; 1797 size_t size; 1798 1799 if (fi == NULL) 1800 return (NULL); 1801 1802 ptr = (uintptr_t)fi; 1803 /* 1804 * Compute and verify checksum. The total sum of all the fields 1805 * must be 0. 1806 */ 1807 checksum = fi->fi_width; 1808 checksum += fi->fi_height; 1809 checksum += fi->fi_bitmap_size; 1810 for (unsigned i = 0; i < VFNT_MAPS; i++) 1811 checksum += fi->fi_map_count[i]; 1812 1813 if (checksum + fi->fi_checksum != 0) 1814 return (NULL); 1815 1816 ptr += sizeof(struct font_info); 1817 ptr = roundup2(ptr, 8); 1818 1819 vfp = &vt_font_loader; 1820 vfp->vf_height = fi->fi_height; 1821 vfp->vf_width = fi->fi_width; 1822 for (unsigned i = 0; i < VFNT_MAPS; i++) { 1823 if (fi->fi_map_count[i] == 0) 1824 continue; 1825 vfp->vf_map_count[i] = fi->fi_map_count[i]; 1826 size = fi->fi_map_count[i] * sizeof(vfnt_map_t); 1827 vfp->vf_map[i] = malloc(size, M_VT, M_WAITOK | M_ZERO); 1828 bcopy((vfnt_map_t *)ptr, vfp->vf_map[i], size); 1829 ptr += size; 1830 ptr = roundup2(ptr, 8); 1831 } 1832 vfp->vf_bytes = malloc(fi->fi_bitmap_size, M_VT, M_WAITOK | M_ZERO); 1833 bcopy((uint8_t *)ptr, vfp->vf_bytes, fi->fi_bitmap_size); 1834 return (vfp); 1835 } 1836 1837 static void 1838 vt_init_font(void *arg) 1839 { 1840 struct font_info *fi; 1841 struct vt_font *font; 1842 1843 fi = MD_FETCH(preload_kmdp, MODINFOMD_FONT, struct font_info *); 1844 1845 font = parse_font_info(fi); 1846 if (font != NULL) 1847 vt_font_assigned = font; 1848 } 1849 1850 SYSINIT(vt_init_font, SI_SUB_KMEM, SI_ORDER_ANY, vt_init_font, &vt_consdev); 1851 1852 static void 1853 vt_init_font_static(void) 1854 { 1855 struct font_info *fi; 1856 struct vt_font *font; 1857 1858 fi = MD_FETCH(preload_kmdp, MODINFOMD_FONT, struct font_info *); 1859 1860 font = parse_font_info_static(fi); 1861 if (font != NULL) 1862 vt_font_assigned = font; 1863 } 1864 1865 #ifdef DEV_SPLASH 1866 static int 1867 vt_shutdown_splash(struct vt_window *vw) 1868 { 1869 vtterm_splash(vw->vw_device); 1870 return (0); 1871 } 1872 #endif 1873 1874 static void 1875 vtterm_cnprobe(struct terminal *tm, struct consdev *cp) 1876 { 1877 struct vt_driver *vtd, **vtdlist, *vtdbest = NULL; 1878 struct vt_window *vw = tm->tm_softc; 1879 struct vt_device *vd = vw->vw_device; 1880 struct winsize wsz; 1881 const term_attr_t *a; 1882 1883 if (!vty_enabled(VTY_VT)) 1884 return; 1885 1886 if (vd->vd_flags & VDF_INITIALIZED) 1887 /* Initialization already done. */ 1888 return; 1889 1890 SET_FOREACH(vtdlist, vt_drv_set) { 1891 vtd = *vtdlist; 1892 if (vtd->vd_probe == NULL) 1893 continue; 1894 if (vtd->vd_probe(vd) == CN_DEAD) 1895 continue; 1896 if ((vtdbest == NULL) || 1897 (vtd->vd_priority > vtdbest->vd_priority)) 1898 vtdbest = vtd; 1899 } 1900 if (vtdbest == NULL) { 1901 cp->cn_pri = CN_DEAD; 1902 vd->vd_flags |= VDF_DEAD; 1903 } else { 1904 vd->vd_driver = vtdbest; 1905 cp->cn_pri = vd->vd_driver->vd_init(vd); 1906 } 1907 1908 /* Check if driver's vt_init return CN_DEAD. */ 1909 if (cp->cn_pri == CN_DEAD) { 1910 vd->vd_flags |= VDF_DEAD; 1911 } 1912 1913 /* Initialize any early-boot keyboard drivers */ 1914 kbd_configure(KB_CONF_PROBE_ONLY); 1915 1916 vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1); 1917 vd->vd_windows[VT_CONSWINDOW] = vw; 1918 sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); 1919 1920 vt_init_font_static(); 1921 1922 /* Attach default font if not in TEXTMODE. */ 1923 if ((vd->vd_flags & VDF_TEXTMODE) == 0) { 1924 vw->vw_font = vtfont_ref(vt_font_assigned); 1925 vt_compute_drawable_area(vw); 1926 } 1927 1928 /* 1929 * The original screen size was faked (_VTDEFW x _VTDEFH). Now 1930 * that we have the real viewable size, fix it in the static 1931 * buffer. 1932 */ 1933 if (vd->vd_width != 0 && vd->vd_height != 0) 1934 vt_termsize(vd, vw->vw_font, &vw->vw_buf.vb_scr_size); 1935 1936 /* We need to access terminal attributes from vtbuf */ 1937 vw->vw_buf.vb_terminal = tm; 1938 vtbuf_init_early(&vw->vw_buf); 1939 vt_winsize(vd, vw->vw_font, &wsz); 1940 a = teken_get_curattr(&tm->tm_emulator); 1941 terminal_set_winsize_blank(tm, &wsz, 1, a); 1942 1943 if (vtdbest != NULL) { 1944 #ifdef DEV_SPLASH 1945 if (!vt_splash_cpu) 1946 vtterm_splash(vd); 1947 #endif 1948 vd->vd_flags |= VDF_INITIALIZED; 1949 } 1950 } 1951 1952 static int 1953 vtterm_cngetc(struct terminal *tm) 1954 { 1955 struct vt_window *vw = tm->tm_softc; 1956 struct vt_device *vd = vw->vw_device; 1957 keyboard_t *kbd; 1958 u_int c; 1959 1960 if (vw->vw_kbdsq && *vw->vw_kbdsq) 1961 return (*vw->vw_kbdsq++); 1962 1963 /* Make sure the splash screen is not there. */ 1964 if (vd->vd_flags & VDF_SPLASH) { 1965 /* Remove splash */ 1966 vd->vd_flags &= ~VDF_SPLASH; 1967 /* Mark screen as invalid to force update */ 1968 vd->vd_flags |= VDF_INVALID; 1969 vt_flush(vd); 1970 } 1971 1972 /* Stripped down keyboard handler. */ 1973 if ((kbd = vd->vd_keyboard) == NULL) 1974 return (-1); 1975 1976 /* Force keyboard input mode to K_XLATE */ 1977 vw->vw_kbdmode = K_XLATE; 1978 vt_update_kbd_mode(vw, kbd); 1979 1980 /* Switch the keyboard to polling to make it work here. */ 1981 kbdd_poll(kbd, TRUE); 1982 c = kbdd_read_char(kbd, 0); 1983 kbdd_poll(kbd, FALSE); 1984 if (c & RELKEY) 1985 return (-1); 1986 1987 if (vw->vw_flags & VWF_SCROLL) { 1988 vt_scrollmode_kbdevent(vw, c, 1/* Console mode */); 1989 vt_flush(vd); 1990 return (-1); 1991 } 1992 1993 /* Stripped down handling of vt_kbdevent(), without locking, etc. */ 1994 if (c & SPCLKEY) { 1995 switch (c) { 1996 case SPCLKEY | SLK: 1997 vt_save_kbd_state(vw, kbd); 1998 if (vw->vw_kbdstate & SLKED) { 1999 /* Turn scrolling on. */ 2000 vw->vw_flags |= VWF_SCROLL; 2001 VTBUF_SLCK_ENABLE(&vw->vw_buf); 2002 } else { 2003 /* Turn scrolling off. */ 2004 vt_scroll(vw, 0, VHS_END); 2005 vw->vw_flags &= ~VWF_SCROLL; 2006 VTBUF_SLCK_DISABLE(&vw->vw_buf); 2007 } 2008 break; 2009 case SPCLKEY | BTAB: /* Back tab (usually, shift+tab). */ 2010 vw->vw_kbdsq = "\x1b[Z"; 2011 break; 2012 /* XXX: KDB can handle history. */ 2013 case SPCLKEY | FKEY | F(50): /* Arrow up. */ 2014 vw->vw_kbdsq = "\x1b[A"; 2015 break; 2016 case SPCLKEY | FKEY | F(58): /* Arrow down. */ 2017 vw->vw_kbdsq = "\x1b[B"; 2018 break; 2019 case SPCLKEY | FKEY | F(55): /* Arrow right. */ 2020 vw->vw_kbdsq = "\x1b[C"; 2021 break; 2022 case SPCLKEY | FKEY | F(53): /* Arrow left. */ 2023 vw->vw_kbdsq = "\x1b[D"; 2024 break; 2025 } 2026 2027 /* Force refresh to make scrollback work. */ 2028 vt_flush(vd); 2029 } else if (KEYFLAGS(c) == 0) { 2030 return (KEYCHAR(c)); 2031 } 2032 2033 if (vw->vw_kbdsq && *vw->vw_kbdsq) 2034 return (*vw->vw_kbdsq++); 2035 2036 return (-1); 2037 } 2038 2039 /* 2040 * These two do most of what we want to do in vtterm_cnungrab, but without 2041 * actually switching windows. This is necessary for, e.g., 2042 * vt_allocate_keyboard() to get the current keyboard into the state it needs to 2043 * be in without damaging the device's window state. 2044 * 2045 * Both return the current grab count, though it's only used in vtterm_cnungrab. 2046 */ 2047 static int 2048 vtterm_cngrab_noswitch(struct vt_device *vd, struct vt_window *vw) 2049 { 2050 keyboard_t *kbd; 2051 2052 if (vw->vw_grabbed++ > 0) 2053 return (vw->vw_grabbed); 2054 2055 if ((kbd = vd->vd_keyboard) == NULL) 2056 return (1); 2057 2058 /* 2059 * Make sure the keyboard is accessible even when the kbd device 2060 * driver is disabled. 2061 */ 2062 kbdd_enable(kbd); 2063 2064 /* We shall always use the keyboard in the XLATE mode here. */ 2065 vw->vw_prev_kbdmode = vw->vw_kbdmode; 2066 vw->vw_kbdmode = K_XLATE; 2067 vt_update_kbd_mode(vw, kbd); 2068 2069 kbdd_poll(kbd, TRUE); 2070 return (1); 2071 } 2072 2073 static int 2074 vtterm_cnungrab_noswitch(struct vt_device *vd, struct vt_window *vw) 2075 { 2076 keyboard_t *kbd; 2077 2078 if (--vw->vw_grabbed > 0) 2079 return (vw->vw_grabbed); 2080 2081 if ((kbd = vd->vd_keyboard) == NULL) 2082 return (0); 2083 2084 kbdd_poll(kbd, FALSE); 2085 2086 vw->vw_kbdmode = vw->vw_prev_kbdmode; 2087 vt_update_kbd_mode(vw, kbd); 2088 kbdd_disable(kbd); 2089 return (0); 2090 } 2091 2092 static void 2093 vtterm_cngrab(struct terminal *tm) 2094 { 2095 struct vt_device *vd; 2096 struct vt_window *vw; 2097 2098 vw = tm->tm_softc; 2099 vd = vw->vw_device; 2100 2101 /* To be restored after we ungrab. */ 2102 if (vd->vd_grabwindow == NULL) 2103 vd->vd_grabwindow = vd->vd_curwindow; 2104 2105 if (!cold) 2106 vt_window_switch(vw); 2107 2108 vtterm_cngrab_noswitch(vd, vw); 2109 } 2110 2111 static void 2112 vtterm_cnungrab(struct terminal *tm) 2113 { 2114 struct vt_device *vd; 2115 struct vt_window *vw, *grabwindow; 2116 2117 vw = tm->tm_softc; 2118 vd = vw->vw_device; 2119 2120 MPASS(vd->vd_grabwindow != NULL); 2121 if (vtterm_cnungrab_noswitch(vd, vw) != 0) 2122 return; 2123 2124 /* 2125 * We set `vd_grabwindow` to NULL before calling vt_window_switch() 2126 * because it allows the underlying vt(4) backend to distinguish a 2127 * "grab" from an "ungrab" of the console. 2128 * 2129 * This is used by `vt_drmfb` in drm-kmod to call either 2130 * fb_debug_enter() or fb_debug_leave() appropriately. 2131 */ 2132 grabwindow = vd->vd_grabwindow; 2133 vd->vd_grabwindow = NULL; 2134 2135 if (!cold) 2136 vt_window_switch(grabwindow); 2137 } 2138 2139 static void 2140 vtterm_opened(struct terminal *tm, int opened) 2141 { 2142 struct vt_window *vw = tm->tm_softc; 2143 struct vt_device *vd = vw->vw_device; 2144 2145 VT_LOCK(vd); 2146 vd->vd_flags &= ~VDF_SPLASH; 2147 if (opened) 2148 vw->vw_flags |= VWF_OPENED; 2149 else { 2150 vw->vw_flags &= ~VWF_OPENED; 2151 /* TODO: finish ACQ/REL */ 2152 } 2153 VT_UNLOCK(vd); 2154 } 2155 2156 static int 2157 vt_change_font(struct vt_window *vw, struct vt_font *vf) 2158 { 2159 struct vt_device *vd = vw->vw_device; 2160 struct terminal *tm = vw->vw_terminal; 2161 term_pos_t size; 2162 struct winsize wsz; 2163 2164 /* 2165 * Changing fonts. 2166 * 2167 * Changing fonts is a little tricky. We must prevent 2168 * simultaneous access to the device, so we must stop 2169 * the display timer and the terminal from accessing. 2170 * We need to switch fonts and grow our screen buffer. 2171 * 2172 * XXX: Right now the code uses terminal_mute() to 2173 * prevent data from reaching the console driver while 2174 * resizing the screen buffer. This isn't elegant... 2175 */ 2176 2177 VT_LOCK(vd); 2178 if (vw->vw_flags & VWF_BUSY) { 2179 /* Another process is changing the font. */ 2180 VT_UNLOCK(vd); 2181 return (EBUSY); 2182 } 2183 vw->vw_flags |= VWF_BUSY; 2184 VT_UNLOCK(vd); 2185 2186 vt_termsize(vd, vf, &size); 2187 vt_winsize(vd, vf, &wsz); 2188 2189 /* Grow the screen buffer and terminal. */ 2190 terminal_mute(tm, 1); 2191 vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 2192 terminal_set_winsize_blank(tm, &wsz, 0, NULL); 2193 terminal_set_cursor(tm, &vw->vw_buf.vb_cursor); 2194 terminal_mute(tm, 0); 2195 2196 /* Actually apply the font to the current window. */ 2197 VT_LOCK(vd); 2198 if (vw->vw_font != vf && vw->vw_font != NULL && vf != NULL) { 2199 /* 2200 * In case vt_change_font called to update size we don't need 2201 * to update font link. 2202 */ 2203 vtfont_unref(vw->vw_font); 2204 vw->vw_font = vtfont_ref(vf); 2205 } 2206 2207 /* 2208 * Compute the drawable area and move the mouse cursor inside 2209 * it, in case the new area is smaller than the previous one. 2210 */ 2211 vt_compute_drawable_area(vw); 2212 vd->vd_mx = min(vd->vd_mx, 2213 vw->vw_draw_area.tr_end.tp_col - 2214 vw->vw_draw_area.tr_begin.tp_col - 1); 2215 vd->vd_my = min(vd->vd_my, 2216 vw->vw_draw_area.tr_end.tp_row - 2217 vw->vw_draw_area.tr_begin.tp_row - 1); 2218 2219 /* Force a full redraw the next timer tick. */ 2220 if (vd->vd_curwindow == vw) { 2221 vd->vd_flags |= VDF_INVALID; 2222 vt_resume_flush_timer(vw, 0); 2223 } 2224 vw->vw_flags &= ~VWF_BUSY; 2225 VT_UNLOCK(vd); 2226 return (0); 2227 } 2228 2229 static int 2230 vt_proc_alive(struct vt_window *vw) 2231 { 2232 struct proc *p; 2233 2234 if (vw->vw_smode.mode != VT_PROCESS) 2235 return (FALSE); 2236 2237 if (vw->vw_proc) { 2238 if ((p = pfind(vw->vw_pid)) != NULL) 2239 PROC_UNLOCK(p); 2240 if (vw->vw_proc == p) 2241 return (TRUE); 2242 vw->vw_proc = NULL; 2243 vw->vw_smode.mode = VT_AUTO; 2244 DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 2245 vw->vw_pid = 0; 2246 } 2247 return (FALSE); 2248 } 2249 2250 static int 2251 signal_vt_rel(struct vt_window *vw) 2252 { 2253 2254 if (vw->vw_smode.mode != VT_PROCESS) 2255 return (FALSE); 2256 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 2257 vw->vw_proc = NULL; 2258 vw->vw_pid = 0; 2259 return (TRUE); 2260 } 2261 vw->vw_flags |= VWF_SWWAIT_REL; 2262 PROC_LOCK(vw->vw_proc); 2263 kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 2264 PROC_UNLOCK(vw->vw_proc); 2265 DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 2266 return (TRUE); 2267 } 2268 2269 static int 2270 signal_vt_acq(struct vt_window *vw) 2271 { 2272 2273 if (vw->vw_smode.mode != VT_PROCESS) 2274 return (FALSE); 2275 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 2276 cnavailable(vw->vw_terminal->consdev, FALSE); 2277 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 2278 vw->vw_proc = NULL; 2279 vw->vw_pid = 0; 2280 return (TRUE); 2281 } 2282 vw->vw_flags |= VWF_SWWAIT_ACQ; 2283 PROC_LOCK(vw->vw_proc); 2284 kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 2285 PROC_UNLOCK(vw->vw_proc); 2286 DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 2287 return (TRUE); 2288 } 2289 2290 static int 2291 finish_vt_rel(struct vt_window *vw, int release, int *s) 2292 { 2293 2294 if (vw->vw_flags & VWF_SWWAIT_REL) { 2295 vw->vw_flags &= ~VWF_SWWAIT_REL; 2296 if (release) { 2297 taskqueue_drain_timeout(taskqueue_thread, &vw->vw_timeout_task_dead); 2298 (void)vt_late_window_switch(vw->vw_switch_to); 2299 } 2300 return (0); 2301 } 2302 return (EINVAL); 2303 } 2304 2305 static int 2306 finish_vt_acq(struct vt_window *vw) 2307 { 2308 2309 if (vw->vw_flags & VWF_SWWAIT_ACQ) { 2310 vw->vw_flags &= ~VWF_SWWAIT_ACQ; 2311 return (0); 2312 } 2313 return (EINVAL); 2314 } 2315 2316 #ifndef SC_NO_CUTPASTE 2317 static void 2318 vt_mouse_terminput_button(struct vt_device *vd, int button) 2319 { 2320 struct vt_window *vw; 2321 struct vt_font *vf; 2322 char mouseb[6] = "\x1B[M"; 2323 int i, x, y; 2324 2325 vw = vd->vd_curwindow; 2326 vf = vw->vw_font; 2327 2328 /* Translate to char position. */ 2329 x = vd->vd_mx / vf->vf_width; 2330 y = vd->vd_my / vf->vf_height; 2331 /* Avoid overflow. */ 2332 x = MIN(x, 255 - '!'); 2333 y = MIN(y, 255 - '!'); 2334 2335 mouseb[3] = ' ' + button; 2336 mouseb[4] = '!' + x; 2337 mouseb[5] = '!' + y; 2338 2339 for (i = 0; i < sizeof(mouseb); i++) 2340 terminal_input_char(vw->vw_terminal, mouseb[i]); 2341 } 2342 2343 static void 2344 vt_mouse_terminput(struct vt_device *vd, int type, int x, int y, int event, 2345 int cnt) 2346 { 2347 2348 switch (type) { 2349 case MOUSE_BUTTON_EVENT: 2350 if (cnt > 0) { 2351 /* Mouse button pressed. */ 2352 if (event & MOUSE_BUTTON1DOWN) 2353 vt_mouse_terminput_button(vd, 0); 2354 if (event & MOUSE_BUTTON2DOWN) 2355 vt_mouse_terminput_button(vd, 1); 2356 if (event & MOUSE_BUTTON3DOWN) 2357 vt_mouse_terminput_button(vd, 2); 2358 } else { 2359 /* Mouse button released. */ 2360 vt_mouse_terminput_button(vd, 3); 2361 } 2362 break; 2363 #ifdef notyet 2364 case MOUSE_MOTION_EVENT: 2365 if (mouse->u.data.z < 0) { 2366 /* Scroll up. */ 2367 sc_mouse_input_button(vd, 64); 2368 } else if (mouse->u.data.z > 0) { 2369 /* Scroll down. */ 2370 sc_mouse_input_button(vd, 65); 2371 } 2372 break; 2373 #endif 2374 } 2375 } 2376 2377 static void 2378 vt_mouse_paste(void) 2379 { 2380 term_char_t *buf; 2381 int i, len; 2382 2383 len = VD_PASTEBUFLEN(main_vd); 2384 buf = VD_PASTEBUF(main_vd); 2385 len /= sizeof(term_char_t); 2386 for (i = 0; i < len; i++) { 2387 if (TCHAR_CHARACTER(buf[i]) == '\0') 2388 continue; 2389 terminal_input_char(main_vd->vd_curwindow->vw_terminal, 2390 buf[i]); 2391 } 2392 } 2393 2394 void 2395 vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel) 2396 { 2397 struct vt_device *vd; 2398 struct vt_window *vw; 2399 struct vt_font *vf; 2400 term_pos_t size; 2401 int len, mark; 2402 2403 vd = main_vd; 2404 vw = vd->vd_curwindow; 2405 vf = vw->vw_font; 2406 2407 if (vw->vw_flags & (VWF_MOUSE_HIDE | VWF_GRAPHICS)) 2408 /* 2409 * Either the mouse is disabled, or the window is in 2410 * "graphics mode". The graphics mode is usually set by 2411 * an X server, using the KDSETMODE ioctl. 2412 */ 2413 return; 2414 2415 if (vf == NULL) /* Text mode. */ 2416 return; 2417 2418 /* 2419 * TODO: add flag about pointer position changed, to not redraw chars 2420 * under mouse pointer when nothing changed. 2421 */ 2422 2423 if (vw->vw_mouse_level > 0) 2424 vt_mouse_terminput(vd, type, x, y, event, cnt); 2425 2426 switch (type) { 2427 case MOUSE_ACTION: 2428 case MOUSE_MOTION_EVENT: 2429 /* Movement */ 2430 x += vd->vd_mx; 2431 y += vd->vd_my; 2432 2433 vt_termsize(vd, vf, &size); 2434 2435 /* Apply limits. */ 2436 x = MAX(x, 0); 2437 y = MAX(y, 0); 2438 x = MIN(x, (size.tp_col * vf->vf_width) - 1); 2439 y = MIN(y, (size.tp_row * vf->vf_height) - 1); 2440 2441 vd->vd_mx = x; 2442 vd->vd_my = y; 2443 if (vd->vd_mstate & (MOUSE_BUTTON1DOWN | VT_MOUSE_EXTENDBUTTON)) 2444 vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE, 2445 vd->vd_mx / vf->vf_width, 2446 vd->vd_my / vf->vf_height); 2447 2448 vt_resume_flush_timer(vw, 0); 2449 return; /* Done */ 2450 case MOUSE_BUTTON_EVENT: 2451 /* Buttons */ 2452 break; 2453 default: 2454 return; /* Done */ 2455 } 2456 2457 switch (event) { 2458 case MOUSE_BUTTON1DOWN: 2459 switch (cnt % 4) { 2460 case 0: /* up */ 2461 mark = VTB_MARK_END; 2462 break; 2463 case 1: /* single click: start cut operation */ 2464 mark = VTB_MARK_START; 2465 break; 2466 case 2: /* double click: cut a word */ 2467 mark = VTB_MARK_WORD; 2468 break; 2469 default: /* triple click: cut a line */ 2470 mark = VTB_MARK_ROW; 2471 break; 2472 } 2473 break; 2474 case VT_MOUSE_PASTEBUTTON: 2475 switch (cnt) { 2476 case 0: /* up */ 2477 break; 2478 default: 2479 vt_mouse_paste(); 2480 /* clear paste buffer selection after paste */ 2481 vtbuf_unmark(&vw->vw_buf); 2482 break; 2483 } 2484 return; /* Done */ 2485 case VT_MOUSE_EXTENDBUTTON: 2486 switch (cnt) { 2487 case 0: /* up */ 2488 if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN)) 2489 mark = VTB_MARK_EXTEND; 2490 else 2491 mark = VTB_MARK_NONE; 2492 break; 2493 default: 2494 mark = VTB_MARK_EXTEND; 2495 break; 2496 } 2497 break; 2498 default: 2499 return; /* Done */ 2500 } 2501 2502 /* Save buttons state. */ 2503 if (cnt > 0) 2504 vd->vd_mstate |= event; 2505 else 2506 vd->vd_mstate &= ~event; 2507 2508 if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, 2509 vd->vd_my / vf->vf_height) == 1) { 2510 /* 2511 * We have something marked to copy, so update pointer to 2512 * window with selection. 2513 */ 2514 vt_resume_flush_timer(vw, 0); 2515 2516 switch (mark) { 2517 case VTB_MARK_END: 2518 case VTB_MARK_WORD: 2519 case VTB_MARK_ROW: 2520 case VTB_MARK_EXTEND: 2521 break; 2522 default: 2523 /* Other types of mark do not require to copy data. */ 2524 return; 2525 } 2526 2527 /* Get current selection size in bytes. */ 2528 len = vtbuf_get_marked_len(&vw->vw_buf); 2529 if (len <= 0) 2530 return; 2531 2532 /* Reallocate buffer only if old one is too small. */ 2533 if (len > VD_PASTEBUFSZ(vd)) { 2534 VD_PASTEBUF(vd) = realloc(VD_PASTEBUF(vd), len, M_VT, 2535 M_WAITOK | M_ZERO); 2536 /* Update buffer size. */ 2537 VD_PASTEBUFSZ(vd) = len; 2538 } 2539 /* Request copy/paste buffer data, no more than `len' */ 2540 vtbuf_extract_marked(&vw->vw_buf, VD_PASTEBUF(vd), len, mark); 2541 2542 VD_PASTEBUFLEN(vd) = len; 2543 2544 /* XXX VD_PASTEBUF(vd) have to be freed on shutdown/unload. */ 2545 } 2546 } 2547 2548 void 2549 vt_mouse_state(int show) 2550 { 2551 struct vt_device *vd; 2552 struct vt_window *vw; 2553 2554 vd = main_vd; 2555 vw = vd->vd_curwindow; 2556 2557 switch (show) { 2558 case VT_MOUSE_HIDE: 2559 vw->vw_flags |= VWF_MOUSE_HIDE; 2560 break; 2561 case VT_MOUSE_SHOW: 2562 vw->vw_flags &= ~VWF_MOUSE_HIDE; 2563 break; 2564 } 2565 2566 /* Mark mouse position as dirty. */ 2567 vt_mark_mouse_position_as_dirty(vd, false); 2568 vt_resume_flush_timer(vw, 0); 2569 } 2570 #endif 2571 2572 static int 2573 vtterm_mmap(struct terminal *tm, vm_ooffset_t offset, vm_paddr_t * paddr, 2574 int nprot, vm_memattr_t *memattr) 2575 { 2576 struct vt_window *vw = tm->tm_softc; 2577 struct vt_device *vd = vw->vw_device; 2578 2579 if (vd->vd_driver->vd_fb_mmap) 2580 return (vd->vd_driver->vd_fb_mmap(vd, offset, paddr, nprot, 2581 memattr)); 2582 2583 return (ENXIO); 2584 } 2585 2586 static int 2587 vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 2588 struct thread *td) 2589 { 2590 struct vt_window *vw = tm->tm_softc; 2591 struct vt_device *vd = vw->vw_device; 2592 keyboard_t *kbd; 2593 int error, i, s; 2594 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 2595 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 2596 int ival; 2597 2598 switch (cmd) { 2599 case _IO('v', 4): 2600 cmd = VT_RELDISP; 2601 break; 2602 case _IO('v', 5): 2603 cmd = VT_ACTIVATE; 2604 break; 2605 case _IO('v', 6): 2606 cmd = VT_WAITACTIVE; 2607 break; 2608 case _IO('K', 20): 2609 cmd = KDSKBSTATE; 2610 break; 2611 case _IO('K', 67): 2612 cmd = KDSETRAD; 2613 break; 2614 case _IO('K', 7): 2615 cmd = KDSKBMODE; 2616 break; 2617 case _IO('K', 8): 2618 cmd = KDMKTONE; 2619 break; 2620 case _IO('K', 10): 2621 cmd = KDSETMODE; 2622 break; 2623 case _IO('K', 13): 2624 cmd = KDSBORDER; 2625 break; 2626 case _IO('K', 63): 2627 cmd = KIOCSOUND; 2628 break; 2629 case _IO('K', 66): 2630 cmd = KDSETLED; 2631 break; 2632 case _IO('c', 104): 2633 cmd = CONS_SETWINORG; 2634 break; 2635 case _IO('c', 110): 2636 cmd = CONS_SETKBD; 2637 break; 2638 default: 2639 goto skip_thunk; 2640 } 2641 ival = IOCPARM_IVAL(data); 2642 data = (caddr_t)&ival; 2643 skip_thunk: 2644 #endif 2645 2646 switch (cmd) { 2647 case KDSETRAD: /* set keyboard repeat & delay rates (old) */ 2648 if (*(int *)data & ~0x7f) 2649 return (EINVAL); 2650 /* FALLTHROUGH */ 2651 case GIO_KEYMAP: 2652 case PIO_KEYMAP: 2653 case GIO_DEADKEYMAP: 2654 case PIO_DEADKEYMAP: 2655 #ifdef COMPAT_FREEBSD13 2656 case OGIO_DEADKEYMAP: 2657 case OPIO_DEADKEYMAP: 2658 #endif /* COMPAT_FREEBSD13 */ 2659 case GETFKEY: 2660 case SETFKEY: 2661 case KDGKBINFO: 2662 case KDGKBTYPE: 2663 case KDGETREPEAT: /* get keyboard repeat & delay rates */ 2664 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */ 2665 case KBADDKBD: /* add keyboard to mux */ 2666 case KBRELKBD: { /* release keyboard from mux */ 2667 error = 0; 2668 2669 mtx_lock(&Giant); 2670 if ((kbd = vd->vd_keyboard) != NULL) 2671 error = kbdd_ioctl(kbd, cmd, data); 2672 mtx_unlock(&Giant); 2673 if (error == ENOIOCTL) { 2674 if (cmd == KDGKBTYPE) { 2675 /* always return something? XXX */ 2676 *(int *)data = 0; 2677 } else { 2678 return (ENODEV); 2679 } 2680 } 2681 return (error); 2682 } 2683 case KDGKBSTATE: { /* get keyboard state (locks) */ 2684 error = 0; 2685 2686 if (vw == vd->vd_curwindow) { 2687 mtx_lock(&Giant); 2688 if ((kbd = vd->vd_keyboard) != NULL) 2689 error = vt_save_kbd_state(vw, kbd); 2690 mtx_unlock(&Giant); 2691 2692 if (error != 0) 2693 return (error); 2694 } 2695 2696 *(int *)data = vw->vw_kbdstate & LOCK_MASK; 2697 2698 return (error); 2699 } 2700 case KDSKBSTATE: { /* set keyboard state (locks) */ 2701 int state; 2702 2703 state = *(int *)data; 2704 if (state & ~LOCK_MASK) 2705 return (EINVAL); 2706 2707 vw->vw_kbdstate &= ~LOCK_MASK; 2708 vw->vw_kbdstate |= state; 2709 2710 error = 0; 2711 if (vw == vd->vd_curwindow) { 2712 mtx_lock(&Giant); 2713 if ((kbd = vd->vd_keyboard) != NULL) 2714 error = vt_update_kbd_state(vw, kbd); 2715 mtx_unlock(&Giant); 2716 } 2717 2718 return (error); 2719 } 2720 case KDGETLED: { /* get keyboard LED status */ 2721 error = 0; 2722 2723 if (vw == vd->vd_curwindow) { 2724 mtx_lock(&Giant); 2725 if ((kbd = vd->vd_keyboard) != NULL) 2726 error = vt_save_kbd_leds(vw, kbd); 2727 mtx_unlock(&Giant); 2728 2729 if (error != 0) 2730 return (error); 2731 } 2732 2733 *(int *)data = vw->vw_kbdstate & LED_MASK; 2734 2735 return (error); 2736 } 2737 case KDSETLED: { /* set keyboard LED status */ 2738 int leds; 2739 2740 leds = *(int *)data; 2741 if (leds & ~LED_MASK) 2742 return (EINVAL); 2743 2744 vw->vw_kbdstate &= ~LED_MASK; 2745 vw->vw_kbdstate |= leds; 2746 2747 error = 0; 2748 if (vw == vd->vd_curwindow) { 2749 mtx_lock(&Giant); 2750 if ((kbd = vd->vd_keyboard) != NULL) 2751 error = vt_update_kbd_leds(vw, kbd); 2752 mtx_unlock(&Giant); 2753 } 2754 2755 return (error); 2756 } 2757 case KDGETMODE: 2758 *(int *)data = (vw->vw_flags & VWF_GRAPHICS) ? 2759 KD_GRAPHICS : KD_TEXT; 2760 return (0); 2761 case KDGKBMODE: { 2762 error = 0; 2763 2764 if (vw == vd->vd_curwindow) { 2765 mtx_lock(&Giant); 2766 if ((kbd = vd->vd_keyboard) != NULL) 2767 error = vt_save_kbd_mode(vw, kbd); 2768 mtx_unlock(&Giant); 2769 2770 if (error != 0) 2771 return (error); 2772 } 2773 2774 *(int *)data = vw->vw_kbdmode; 2775 2776 return (error); 2777 } 2778 case KDSKBMODE: { 2779 int mode; 2780 2781 mode = *(int *)data; 2782 switch (mode) { 2783 case K_XLATE: 2784 case K_RAW: 2785 case K_CODE: 2786 vw->vw_kbdmode = mode; 2787 2788 error = 0; 2789 if (vw == vd->vd_curwindow) { 2790 mtx_lock(&Giant); 2791 if ((kbd = vd->vd_keyboard) != NULL) 2792 error = vt_update_kbd_mode(vw, kbd); 2793 mtx_unlock(&Giant); 2794 } 2795 2796 return (error); 2797 default: 2798 return (EINVAL); 2799 } 2800 } 2801 case FBIOGTYPE: 2802 case FBIO_GETWINORG: /* get frame buffer window origin */ 2803 case FBIO_GETDISPSTART: /* get display start address */ 2804 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 2805 case FBIO_BLANK: /* blank display */ 2806 case FBIO_GETRGBOFFS: /* get RGB offsets */ 2807 if (vd->vd_driver->vd_fb_ioctl) 2808 return (vd->vd_driver->vd_fb_ioctl(vd, cmd, data, td)); 2809 break; 2810 case CONS_BLANKTIME: 2811 /* XXX */ 2812 return (0); 2813 case CONS_HISTORY: 2814 if (*(int *)data < 0 || 2815 *(int *)data > UINT_MAX / USHRT_MAX / sizeof(term_char_t)) 2816 return (EINVAL); 2817 if (*(int *)data != vw->vw_buf.vb_history_size) 2818 vtbuf_sethistory_size(&vw->vw_buf, *(int *)data); 2819 return (0); 2820 case CONS_CLRHIST: 2821 vtbuf_clearhistory(&vw->vw_buf); 2822 /* 2823 * Invalidate the entire visible window; it is not guaranteed 2824 * that this operation will be immediately followed by a scroll 2825 * event, so it would otherwise be possible for prior artifacts 2826 * to remain visible. 2827 */ 2828 VT_LOCK(vd); 2829 if (vw == vd->vd_curwindow) { 2830 vd->vd_flags |= VDF_INVALID; 2831 vt_resume_flush_timer(vw, 0); 2832 } 2833 VT_UNLOCK(vd); 2834 return (0); 2835 case CONS_GET: 2836 /* XXX */ 2837 *(int *)data = M_CG640x480; 2838 return (0); 2839 case CONS_BELLTYPE: /* set bell type sound */ 2840 if ((*(int *)data) & CONS_QUIET_BELL) 2841 vd->vd_flags |= VDF_QUIET_BELL; 2842 else 2843 vd->vd_flags &= ~VDF_QUIET_BELL; 2844 return (0); 2845 case CONS_GETINFO: { 2846 vid_info_t *vi = (vid_info_t *)data; 2847 if (vi->size != sizeof(struct vid_info)) 2848 return (EINVAL); 2849 2850 if (vw == vd->vd_curwindow) { 2851 mtx_lock(&Giant); 2852 if ((kbd = vd->vd_keyboard) != NULL) 2853 vt_save_kbd_state(vw, kbd); 2854 mtx_unlock(&Giant); 2855 } 2856 2857 vi->m_num = vd->vd_curwindow->vw_number + 1; 2858 vi->mk_keylock = vw->vw_kbdstate & LOCK_MASK; 2859 /* XXX: other fields! */ 2860 return (0); 2861 } 2862 case CONS_GETVERS: 2863 *(int *)data = 0x200; 2864 return (0); 2865 case CONS_MODEINFO: 2866 /* XXX */ 2867 return (0); 2868 case CONS_MOUSECTL: { 2869 mouse_info_t *mouse = (mouse_info_t*)data; 2870 2871 /* 2872 * All the commands except MOUSE_SHOW nd MOUSE_HIDE 2873 * should not be applied to individual TTYs, but only to 2874 * consolectl. 2875 */ 2876 switch (mouse->operation) { 2877 case MOUSE_HIDE: 2878 if (vd->vd_flags & VDF_MOUSECURSOR) { 2879 vd->vd_flags &= ~VDF_MOUSECURSOR; 2880 #ifndef SC_NO_CUTPASTE 2881 vt_mouse_state(VT_MOUSE_HIDE); 2882 #endif 2883 } 2884 return (0); 2885 case MOUSE_SHOW: 2886 if (!(vd->vd_flags & VDF_MOUSECURSOR)) { 2887 vd->vd_flags |= VDF_MOUSECURSOR; 2888 vd->vd_mx = vd->vd_width / 2; 2889 vd->vd_my = vd->vd_height / 2; 2890 #ifndef SC_NO_CUTPASTE 2891 vt_mouse_state(VT_MOUSE_SHOW); 2892 #endif 2893 } 2894 return (0); 2895 default: 2896 return (EINVAL); 2897 } 2898 } 2899 case PIO_VFONT: { 2900 struct vt_font *vf; 2901 2902 if (vd->vd_flags & VDF_TEXTMODE) 2903 return (ENOTSUP); 2904 2905 error = vtfont_load((void *)data, &vf); 2906 if (error != 0) 2907 return (error); 2908 2909 error = vt_change_font(vw, vf); 2910 vtfont_unref(vf); 2911 return (error); 2912 } 2913 case PIO_VFONT_DEFAULT: { 2914 /* Reset to default font. */ 2915 error = vt_change_font(vw, vt_font_assigned); 2916 return (error); 2917 } 2918 case GIO_SCRNMAP: { 2919 scrmap_t *sm = (scrmap_t *)data; 2920 2921 /* We don't have screen maps, so return a handcrafted one. */ 2922 for (i = 0; i < 256; i++) 2923 sm->scrmap[i] = i; 2924 return (0); 2925 } 2926 case KDSETMODE: 2927 /* 2928 * FIXME: This implementation is incomplete compared to 2929 * syscons. 2930 */ 2931 switch (*(int *)data) { 2932 case KD_TEXT: 2933 case KD_TEXT1: 2934 case KD_PIXEL: { 2935 bool restore = false; 2936 VT_LOCK(vd); 2937 if ((vw->vw_flags & VWF_GRAPHICS) && 2938 vw == vd->vd_curwindow) { 2939 /* 2940 * When leaving graphics mode on the currently 2941 * active window, reprogram the display 2942 * controller back to text mode immediately. 2943 * Without this, the CRTC retains the graphical 2944 * state and the console stays invisible until 2945 * the next VT switch. 2946 */ 2947 restore = true; 2948 vd->vd_flags |= VDF_INVALID; 2949 } 2950 vw->vw_flags &= ~VWF_GRAPHICS; 2951 VT_UNLOCK(vd); 2952 if (restore) { 2953 if (vd->vd_driver->vd_postswitch) 2954 vd->vd_driver->vd_postswitch(vd); 2955 vt_resume_flush_timer(vw, 0); 2956 } 2957 break; 2958 } 2959 case KD_GRAPHICS: 2960 vw->vw_flags |= VWF_GRAPHICS; 2961 break; 2962 } 2963 return (0); 2964 case KDENABIO: /* allow io operations */ 2965 error = priv_check(td, PRIV_IO); 2966 if (error != 0) 2967 return (error); 2968 error = securelevel_gt(td->td_ucred, 0); 2969 if (error != 0) 2970 return (error); 2971 #if defined(__i386__) 2972 td->td_frame->tf_eflags |= PSL_IOPL; 2973 #elif defined(__amd64__) 2974 td->td_frame->tf_rflags |= PSL_IOPL; 2975 #endif 2976 return (0); 2977 case KDDISABIO: /* disallow io operations (default) */ 2978 #if defined(__i386__) 2979 td->td_frame->tf_eflags &= ~PSL_IOPL; 2980 #elif defined(__amd64__) 2981 td->td_frame->tf_rflags &= ~PSL_IOPL; 2982 #endif 2983 return (0); 2984 case KDMKTONE: /* sound the bell */ 2985 vtterm_beep(tm, *(u_int *)data); 2986 return (0); 2987 case KIOCSOUND: /* make tone (*data) hz */ 2988 /* TODO */ 2989 return (0); 2990 case CONS_SETKBD: /* set the new keyboard */ 2991 mtx_lock(&Giant); 2992 error = 0; 2993 if (vd->vd_keyboard == NULL || 2994 vd->vd_keyboard->kb_index != *(int *)data) { 2995 kbd = kbd_get_keyboard(*(int *)data); 2996 if (kbd == NULL) { 2997 mtx_unlock(&Giant); 2998 return (EINVAL); 2999 } 3000 i = kbd_allocate(kbd->kb_name, kbd->kb_unit, 3001 (void *)vd, vt_kbdevent, vd); 3002 if (i >= 0) { 3003 if ((kbd = vd->vd_keyboard) != NULL) { 3004 vt_save_kbd_state(vd->vd_curwindow, kbd); 3005 kbd_release(kbd, (void *)vd); 3006 } 3007 kbd = vd->vd_keyboard = kbd_get_keyboard(i); 3008 3009 vt_update_kbd_mode(vd->vd_curwindow, kbd); 3010 vt_update_kbd_state(vd->vd_curwindow, kbd); 3011 } else { 3012 error = EPERM; /* XXX */ 3013 } 3014 } 3015 mtx_unlock(&Giant); 3016 return (error); 3017 case CONS_RELKBD: /* release the current keyboard */ 3018 mtx_lock(&Giant); 3019 error = 0; 3020 if ((kbd = vd->vd_keyboard) != NULL) { 3021 vt_save_kbd_state(vd->vd_curwindow, kbd); 3022 error = kbd_release(kbd, (void *)vd); 3023 if (error == 0) { 3024 vd->vd_keyboard = NULL; 3025 } 3026 } 3027 mtx_unlock(&Giant); 3028 return (error); 3029 case VT_ACTIVATE: { 3030 int win; 3031 win = *(int *)data - 1; 3032 DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, 3033 VT_UNIT(vw), win); 3034 if ((win >= VT_MAXWINDOWS) || (win < 0)) 3035 return (EINVAL); 3036 return (vt_proc_window_switch(vd->vd_windows[win])); 3037 } 3038 case VT_GETACTIVE: 3039 *(int *)data = vd->vd_curwindow->vw_number + 1; 3040 return (0); 3041 case VT_GETINDEX: 3042 *(int *)data = vw->vw_number + 1; 3043 return (0); 3044 case VT_LOCKSWITCH: 3045 /* TODO: Check current state, switching can be in progress. */ 3046 if ((*(int *)data) == 0x01) 3047 vw->vw_flags |= VWF_VTYLOCK; 3048 else if ((*(int *)data) == 0x02) 3049 vw->vw_flags &= ~VWF_VTYLOCK; 3050 else 3051 return (EINVAL); 3052 return (0); 3053 case VT_OPENQRY: 3054 VT_LOCK(vd); 3055 for (i = 0; i < VT_MAXWINDOWS; i++) { 3056 vw = vd->vd_windows[i]; 3057 if (vw == NULL) 3058 continue; 3059 if (!(vw->vw_flags & VWF_OPENED)) { 3060 *(int *)data = vw->vw_number + 1; 3061 VT_UNLOCK(vd); 3062 return (0); 3063 } 3064 } 3065 VT_UNLOCK(vd); 3066 return (EINVAL); 3067 case VT_WAITACTIVE: { 3068 unsigned int idx; 3069 3070 error = 0; 3071 3072 idx = *(unsigned int *)data; 3073 if (idx > VT_MAXWINDOWS) 3074 return (EINVAL); 3075 if (idx > 0) 3076 vw = vd->vd_windows[idx - 1]; 3077 3078 VT_LOCK(vd); 3079 while (vd->vd_curwindow != vw && error == 0) 3080 error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 3081 VT_UNLOCK(vd); 3082 return (error); 3083 } 3084 case VT_SETMODE: { /* set screen switcher mode */ 3085 struct vt_mode *mode; 3086 struct proc *p1; 3087 3088 mode = (struct vt_mode *)data; 3089 DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 3090 if (vw->vw_smode.mode == VT_PROCESS) { 3091 p1 = pfind(vw->vw_pid); 3092 if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 3093 if (p1) 3094 PROC_UNLOCK(p1); 3095 DPRINTF(5, "error EPERM\n"); 3096 return (EPERM); 3097 } 3098 if (p1) 3099 PROC_UNLOCK(p1); 3100 } 3101 if (mode->mode == VT_AUTO) { 3102 vw->vw_smode.mode = VT_AUTO; 3103 vw->vw_proc = NULL; 3104 vw->vw_pid = 0; 3105 DPRINTF(5, "VT_AUTO, "); 3106 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 3107 cnavailable(vw->vw_terminal->consdev, TRUE); 3108 /* were we in the middle of the vty switching process? */ 3109 if (finish_vt_rel(vw, TRUE, &s) == 0) 3110 DPRINTF(5, "reset WAIT_REL, "); 3111 if (finish_vt_acq(vw) == 0) 3112 DPRINTF(5, "reset WAIT_ACQ, "); 3113 return (0); 3114 } else if (mode->mode == VT_PROCESS) { 3115 if (!(_SIG_VALID(mode->relsig) && 3116 _SIG_VALID(mode->acqsig) && 3117 (mode->frsig == 0 || _SIG_VALID(mode->frsig)))) { 3118 DPRINTF(5, "error EINVAL\n"); 3119 return (EINVAL); 3120 } 3121 DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 3122 bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 3123 vw->vw_proc = td->td_proc; 3124 vw->vw_pid = vw->vw_proc->p_pid; 3125 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 3126 cnavailable(vw->vw_terminal->consdev, FALSE); 3127 } else { 3128 DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 3129 mode->mode); 3130 return (EINVAL); 3131 } 3132 DPRINTF(5, "\n"); 3133 return (0); 3134 } 3135 case VT_GETMODE: /* get screen switcher mode */ 3136 bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 3137 return (0); 3138 3139 case VT_RELDISP: /* screen switcher ioctl */ 3140 /* 3141 * This must be the current vty which is in the VT_PROCESS 3142 * switching mode... 3143 */ 3144 if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 3145 VT_PROCESS)) { 3146 return (EINVAL); 3147 } 3148 /* ...and this process is controlling it. */ 3149 if (vw->vw_proc != td->td_proc) { 3150 return (EPERM); 3151 } 3152 error = EINVAL; 3153 switch(*(int *)data) { 3154 case VT_FALSE: /* user refuses to release screen, abort */ 3155 if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 3156 DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", 3157 SC_DRIVER_NAME, VT_UNIT(vw)); 3158 break; 3159 case VT_TRUE: /* user has released screen, go on */ 3160 /* finish_vt_rel(..., TRUE, ...) should not be locked */ 3161 if (vw->vw_flags & VWF_SWWAIT_REL) { 3162 if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 3163 DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 3164 SC_DRIVER_NAME, VT_UNIT(vw)); 3165 } else { 3166 error = EINVAL; 3167 } 3168 return (error); 3169 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 3170 if ((error = finish_vt_acq(vw)) == 0) 3171 DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", 3172 SC_DRIVER_NAME, VT_UNIT(vw)); 3173 break; 3174 default: 3175 break; 3176 } 3177 return (error); 3178 } 3179 3180 return (ENOIOCTL); 3181 } 3182 3183 static struct vt_window * 3184 vt_allocate_window(struct vt_device *vd, unsigned int window) 3185 { 3186 struct vt_window *vw; 3187 struct terminal *tm; 3188 term_pos_t size; 3189 struct winsize wsz; 3190 3191 vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 3192 vw->vw_device = vd; 3193 vw->vw_number = window; 3194 vw->vw_kbdmode = K_XLATE; 3195 3196 if ((vd->vd_flags & VDF_TEXTMODE) == 0) { 3197 vw->vw_font = vtfont_ref(vt_font_assigned); 3198 vt_compute_drawable_area(vw); 3199 } 3200 3201 vt_termsize(vd, vw->vw_font, &size); 3202 vt_winsize(vd, vw->vw_font, &wsz); 3203 tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 3204 vw->vw_buf.vb_terminal = tm; /* must be set before vtbuf_init() */ 3205 vtbuf_init(&vw->vw_buf, &size); 3206 3207 terminal_set_winsize(tm, &wsz); 3208 vd->vd_windows[window] = vw; 3209 TIMEOUT_TASK_INIT(taskqueue_thread, &vw->vw_timeout_task_dead, 0, &vt_switch_timer, vw); 3210 3211 return (vw); 3212 } 3213 3214 void 3215 vt_upgrade(struct vt_device *vd) 3216 { 3217 struct vt_window *vw; 3218 unsigned int i; 3219 int register_handlers; 3220 3221 if (!vty_enabled(VTY_VT)) 3222 return; 3223 if (main_vd->vd_driver == NULL) 3224 return; 3225 3226 for (i = 0; i < VT_MAXWINDOWS; i++) { 3227 vw = vd->vd_windows[i]; 3228 if (vw == NULL) { 3229 /* New window. */ 3230 vw = vt_allocate_window(vd, i); 3231 } 3232 if (!(vw->vw_flags & VWF_READY)) { 3233 TIMEOUT_TASK_INIT(taskqueue_thread, &vw->vw_timeout_task_dead, 0, &vt_switch_timer, vw); 3234 terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 3235 vw->vw_flags |= VWF_READY; 3236 if (vw->vw_flags & VWF_CONSOLE) { 3237 /* For existing console window. */ 3238 EVENTHANDLER_REGISTER(shutdown_pre_sync, 3239 vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 3240 #ifdef DEV_SPLASH 3241 EVENTHANDLER_REGISTER(shutdown_pre_sync, 3242 vt_shutdown_splash, vw, SHUTDOWN_PRI_DEFAULT + 1); 3243 #endif 3244 } 3245 } 3246 } 3247 VT_LOCK(vd); 3248 if (vd->vd_curwindow == NULL) 3249 vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 3250 3251 register_handlers = 0; 3252 if (!(vd->vd_flags & VDF_ASYNC)) { 3253 /* Attach keyboard. */ 3254 vt_allocate_keyboard(vd); 3255 3256 /* Init 25 Hz timer. */ 3257 callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 3258 3259 /* 3260 * Start timer when everything ready. 3261 * Note that the operations here are purposefully ordered. 3262 * We need to ensure vd_timer_armed is non-zero before we set 3263 * the VDF_ASYNC flag. That prevents this function from 3264 * racing with vt_resume_flush_timer() to update the 3265 * callout structure. 3266 */ 3267 atomic_add_acq_int(&vd->vd_timer_armed, 1); 3268 vd->vd_flags |= VDF_ASYNC; 3269 callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 3270 register_handlers = 1; 3271 } 3272 3273 VT_UNLOCK(vd); 3274 3275 /* Refill settings with new sizes. */ 3276 vt_resize(vd); 3277 3278 if (register_handlers) { 3279 /* Register suspend/resume handlers. */ 3280 EVENTHANDLER_REGISTER(power_suspend_early, vt_suspend_handler, 3281 vd, EVENTHANDLER_PRI_ANY); 3282 EVENTHANDLER_REGISTER(power_resume, vt_resume_handler, vd, 3283 EVENTHANDLER_PRI_ANY); 3284 } 3285 } 3286 3287 static void 3288 vt_resize(struct vt_device *vd) 3289 { 3290 struct vt_window *vw; 3291 int i; 3292 3293 for (i = 0; i < VT_MAXWINDOWS; i++) { 3294 vw = vd->vd_windows[i]; 3295 VT_LOCK(vd); 3296 /* Assign default font to window, if not textmode. */ 3297 if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) 3298 vw->vw_font = vtfont_ref(vt_font_assigned); 3299 VT_UNLOCK(vd); 3300 3301 /* Resize terminal windows */ 3302 while (vt_change_font(vw, vw->vw_font) == EBUSY) { 3303 DPRINTF(100, "%s: vt_change_font() is busy, " 3304 "window %d\n", __func__, i); 3305 } 3306 } 3307 } 3308 3309 static void 3310 vt_replace_backend(const struct vt_driver *drv, void *softc) 3311 { 3312 struct vt_device *vd; 3313 3314 vd = main_vd; 3315 3316 if (vd->vd_flags & VDF_ASYNC) { 3317 /* Stop vt_flush periodic task. */ 3318 VT_LOCK(vd); 3319 vt_suspend_flush_timer(vd); 3320 VT_UNLOCK(vd); 3321 /* 3322 * Mute current terminal until we done. vt_change_font (called 3323 * from vt_resize) will unmute it. 3324 */ 3325 terminal_mute(vd->vd_curwindow->vw_terminal, 1); 3326 } 3327 3328 /* 3329 * Reset VDF_TEXTMODE flag, driver who require that flag (vt_vga) will 3330 * set it. 3331 */ 3332 VT_LOCK(vd); 3333 vd->vd_flags &= ~VDF_TEXTMODE; 3334 3335 if (drv != NULL) { 3336 /* 3337 * We want to upgrade from the current driver to the 3338 * given driver. 3339 */ 3340 3341 vd->vd_prev_driver = vd->vd_driver; 3342 vd->vd_prev_softc = vd->vd_softc; 3343 vd->vd_driver = drv; 3344 vd->vd_softc = softc; 3345 3346 vd->vd_driver->vd_init(vd); 3347 } else if (vd->vd_prev_driver != NULL && vd->vd_prev_softc != NULL) { 3348 /* 3349 * No driver given: we want to downgrade to the previous 3350 * driver. 3351 */ 3352 const struct vt_driver *old_drv; 3353 void *old_softc; 3354 3355 old_drv = vd->vd_driver; 3356 old_softc = vd->vd_softc; 3357 3358 vd->vd_driver = vd->vd_prev_driver; 3359 vd->vd_softc = vd->vd_prev_softc; 3360 vd->vd_prev_driver = NULL; 3361 vd->vd_prev_softc = NULL; 3362 3363 vd->vd_flags |= VDF_DOWNGRADE; 3364 3365 vd->vd_driver->vd_init(vd); 3366 3367 if (old_drv->vd_fini) 3368 old_drv->vd_fini(vd, old_softc); 3369 3370 vd->vd_flags &= ~VDF_DOWNGRADE; 3371 } 3372 3373 VT_UNLOCK(vd); 3374 3375 /* Update windows sizes and initialize last items. */ 3376 vt_upgrade(vd); 3377 3378 /* 3379 * Give a chance to the new backend to run the post-switch code, for 3380 * instance to refresh the screen. 3381 */ 3382 if (vd->vd_driver->vd_postswitch) 3383 vd->vd_driver->vd_postswitch(vd); 3384 3385 #ifdef DEV_SPLASH 3386 if (vd->vd_flags & VDF_SPLASH) 3387 vtterm_splash(vd); 3388 #endif 3389 3390 if (vd->vd_flags & VDF_ASYNC) { 3391 /* Allow to put chars now. */ 3392 terminal_mute(vd->vd_curwindow->vw_terminal, 0); 3393 /* Rerun timer for screen updates. */ 3394 vt_resume_flush_timer(vd->vd_curwindow, 0); 3395 } 3396 3397 /* 3398 * Register as console. If it already registered, cnadd() will ignore 3399 * it. 3400 */ 3401 termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 3402 } 3403 3404 static void 3405 vt_suspend_handler(void *priv, enum power_stype stype) 3406 { 3407 struct vt_device *vd; 3408 3409 vd = priv; 3410 vd->vd_flags |= VDF_SUSPENDED; 3411 if (vd->vd_driver != NULL && vd->vd_driver->vd_suspend != NULL) 3412 vd->vd_driver->vd_suspend(vd); 3413 } 3414 3415 static void 3416 vt_resume_handler(void *priv, enum power_stype stype) 3417 { 3418 struct vt_device *vd; 3419 3420 vd = priv; 3421 if (vd->vd_driver != NULL && vd->vd_driver->vd_resume != NULL) 3422 vd->vd_driver->vd_resume(vd); 3423 vd->vd_flags &= ~VDF_SUSPENDED; 3424 } 3425 3426 int 3427 vt_allocate(const struct vt_driver *drv, void *softc) 3428 { 3429 3430 if (!vty_enabled(VTY_VT)) 3431 return (EINVAL); 3432 3433 if (main_vd->vd_driver == NULL) { 3434 main_vd->vd_driver = drv; 3435 printf("VT: initialize with new VT driver \"%s\".\n", 3436 drv->vd_name); 3437 } else { 3438 /* 3439 * Check if have rights to replace current driver. For example: 3440 * it is bad idea to replace KMS driver with generic VGA one. 3441 */ 3442 if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 3443 printf("VT: Driver priority %d too low. Current %d\n ", 3444 drv->vd_priority, main_vd->vd_driver->vd_priority); 3445 return (EEXIST); 3446 } 3447 printf("VT: Replacing driver \"%s\" with new \"%s\".\n", 3448 main_vd->vd_driver->vd_name, drv->vd_name); 3449 } 3450 3451 vt_replace_backend(drv, softc); 3452 3453 return (0); 3454 } 3455 3456 int 3457 vt_deallocate(const struct vt_driver *drv, void *softc) 3458 { 3459 3460 if (!vty_enabled(VTY_VT)) 3461 return (EINVAL); 3462 3463 if (main_vd->vd_prev_driver == NULL || 3464 main_vd->vd_driver != drv || 3465 main_vd->vd_softc != softc) 3466 return (EPERM); 3467 3468 printf("VT: Switching back from \"%s\" to \"%s\".\n", 3469 main_vd->vd_driver->vd_name, main_vd->vd_prev_driver->vd_name); 3470 3471 vt_replace_backend(NULL, NULL); 3472 3473 return (0); 3474 } 3475 3476 void 3477 vt_suspend(struct vt_device *vd) 3478 { 3479 int error; 3480 3481 if (vt_suspendswitch == 0) 3482 return; 3483 /* Save current window. */ 3484 vd->vd_savedwindow = vd->vd_curwindow; 3485 /* Ask holding process to free window and switch to console window */ 3486 vt_proc_window_switch(vd->vd_windows[VT_CONSWINDOW]); 3487 3488 /* Wait for the window switch to complete. */ 3489 error = 0; 3490 VT_LOCK(vd); 3491 while (vd->vd_curwindow != vd->vd_windows[VT_CONSWINDOW] && error == 0) 3492 error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 3493 VT_UNLOCK(vd); 3494 } 3495 3496 void 3497 vt_resume(struct vt_device *vd) 3498 { 3499 3500 if (vt_suspendswitch == 0) 3501 return; 3502 /* Switch back to saved window, if any */ 3503 vt_proc_window_switch(vd->vd_savedwindow); 3504 vd->vd_savedwindow = NULL; 3505 } 3506