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