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