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