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