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