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