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[0], 170 .vb_rows = &vt_constextbufrows[0], 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) == 0) 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 (vd->vd_flags & VDF_TEXTMODE) { 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 if (vw->vw_font != vf) { 1173 /* 1174 * In case vt_change_font called to update size we don't need 1175 * to update font link. 1176 */ 1177 vtfont_unref(vw->vw_font); 1178 vw->vw_font = vtfont_ref(vf); 1179 } 1180 1181 /* Force a full redraw the next timer tick. */ 1182 if (vd->vd_curwindow == vw) 1183 vd->vd_flags |= VDF_INVALID; 1184 vw->vw_flags &= ~VWF_BUSY; 1185 VT_UNLOCK(vd); 1186 return (0); 1187 } 1188 1189 static int 1190 vt_set_border(struct vt_window *vw, struct vt_font *vf, term_color_t c) 1191 { 1192 struct vt_device *vd = vw->vw_device; 1193 int x, y, off_x, off_y; 1194 1195 if (vd->vd_driver->vd_drawrect == NULL) 1196 return (ENOTSUP); 1197 1198 x = vd->vd_width - 1; 1199 y = vd->vd_height - 1; 1200 off_x = vd->vd_offset.tp_col; 1201 off_y = vd->vd_offset.tp_row; 1202 1203 /* Top bar. */ 1204 if (off_y > 0) 1205 vd->vd_driver->vd_drawrect(vd, 0, 0, x, off_y - 1, 1, c); 1206 /* Left bar. */ 1207 if (off_x > 0) 1208 vd->vd_driver->vd_drawrect(vd, 0, off_y, off_x - 1, y - off_y, 1209 1, c); 1210 /* Right bar. May be 1 pixel wider than necessary due to rounding. */ 1211 vd->vd_driver->vd_drawrect(vd, x - off_x, off_y, x, y - off_y, 1, c); 1212 /* Bottom bar. May be 1 mixel taller than necessary due to rounding. */ 1213 vd->vd_driver->vd_drawrect(vd, 0, y - off_y, x, y, 1, c); 1214 1215 return (0); 1216 } 1217 1218 static int 1219 vt_proc_alive(struct vt_window *vw) 1220 { 1221 struct proc *p; 1222 1223 if (vw->vw_smode.mode != VT_PROCESS) 1224 return (FALSE); 1225 1226 if (vw->vw_proc) { 1227 if ((p = pfind(vw->vw_pid)) != NULL) 1228 PROC_UNLOCK(p); 1229 if (vw->vw_proc == p) 1230 return (TRUE); 1231 vw->vw_proc = NULL; 1232 vw->vw_smode.mode = VT_AUTO; 1233 DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 1234 vw->vw_pid = 0; 1235 } 1236 return (FALSE); 1237 } 1238 1239 static int 1240 signal_vt_rel(struct vt_window *vw) 1241 { 1242 1243 if (vw->vw_smode.mode != VT_PROCESS) 1244 return (FALSE); 1245 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1246 vw->vw_proc = NULL; 1247 vw->vw_pid = 0; 1248 return (TRUE); 1249 } 1250 vw->vw_flags |= VWF_SWWAIT_REL; 1251 PROC_LOCK(vw->vw_proc); 1252 kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 1253 PROC_UNLOCK(vw->vw_proc); 1254 DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 1255 return (TRUE); 1256 } 1257 1258 static int 1259 signal_vt_acq(struct vt_window *vw) 1260 { 1261 1262 if (vw->vw_smode.mode != VT_PROCESS) 1263 return (FALSE); 1264 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1265 cnavailable(vw->vw_terminal->consdev, FALSE); 1266 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1267 vw->vw_proc = NULL; 1268 vw->vw_pid = 0; 1269 return (TRUE); 1270 } 1271 vw->vw_flags |= VWF_SWWAIT_ACQ; 1272 PROC_LOCK(vw->vw_proc); 1273 kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 1274 PROC_UNLOCK(vw->vw_proc); 1275 DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 1276 return (TRUE); 1277 } 1278 1279 static int 1280 finish_vt_rel(struct vt_window *vw, int release, int *s) 1281 { 1282 1283 if (vw->vw_flags & VWF_SWWAIT_REL) { 1284 vw->vw_flags &= ~VWF_SWWAIT_REL; 1285 if (release) { 1286 callout_drain(&vw->vw_proc_dead_timer); 1287 vt_late_window_switch(vw->vw_switch_to); 1288 } 1289 return (0); 1290 } 1291 return (EINVAL); 1292 } 1293 1294 static int 1295 finish_vt_acq(struct vt_window *vw) 1296 { 1297 1298 if (vw->vw_flags & VWF_SWWAIT_ACQ) { 1299 vw->vw_flags &= ~VWF_SWWAIT_ACQ; 1300 return (0); 1301 } 1302 return (EINVAL); 1303 } 1304 1305 #ifndef SC_NO_CUTPASTE 1306 static void 1307 vt_mouse_terminput_button(struct vt_device *vd, int button) 1308 { 1309 struct vt_window *vw; 1310 struct vt_font *vf; 1311 char mouseb[6] = "\x1B[M"; 1312 int i, x, y; 1313 1314 vw = vd->vd_curwindow; 1315 vf = vw->vw_font; 1316 1317 /* Translate to char position. */ 1318 x = vd->vd_mx / vf->vf_width; 1319 y = vd->vd_my / vf->vf_height; 1320 /* Avoid overflow. */ 1321 x = MIN(x, 255 - '!'); 1322 y = MIN(y, 255 - '!'); 1323 1324 mouseb[3] = ' ' + button; 1325 mouseb[4] = '!' + x; 1326 mouseb[5] = '!' + y; 1327 1328 for (i = 0; i < sizeof(mouseb); i++ ) 1329 terminal_input_char(vw->vw_terminal, mouseb[i]); 1330 } 1331 1332 static void 1333 vt_mouse_terminput(struct vt_device *vd, int type, int x, int y, int event, 1334 int cnt) 1335 { 1336 1337 switch (type) { 1338 case MOUSE_BUTTON_EVENT: 1339 if (cnt > 0) { 1340 /* Mouse button pressed. */ 1341 if (event & MOUSE_BUTTON1DOWN) 1342 vt_mouse_terminput_button(vd, 0); 1343 if (event & MOUSE_BUTTON2DOWN) 1344 vt_mouse_terminput_button(vd, 1); 1345 if (event & MOUSE_BUTTON3DOWN) 1346 vt_mouse_terminput_button(vd, 2); 1347 } else { 1348 /* Mouse button released. */ 1349 vt_mouse_terminput_button(vd, 3); 1350 } 1351 break; 1352 #ifdef notyet 1353 case MOUSE_MOTION_EVENT: 1354 if (mouse->u.data.z < 0) { 1355 /* Scroll up. */ 1356 sc_mouse_input_button(vd, 64); 1357 } else if (mouse->u.data.z > 0) { 1358 /* Scroll down. */ 1359 sc_mouse_input_button(vd, 65); 1360 } 1361 break; 1362 #endif 1363 } 1364 } 1365 1366 void 1367 vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel) 1368 { 1369 struct vt_device *vd; 1370 struct vt_window *vw; 1371 struct vt_font *vf; 1372 term_pos_t size; 1373 term_char_t *buf; 1374 int i, len, mark; 1375 1376 vd = main_vd; 1377 vw = vd->vd_curwindow; 1378 vf = vw->vw_font; 1379 mark = 0; 1380 1381 if (vw->vw_flags & VWF_MOUSE_HIDE) 1382 return; /* Mouse disabled. */ 1383 1384 if (vf == NULL) /* Text mode. */ 1385 return; 1386 1387 /* 1388 * TODO: add flag about pointer position changed, to not redraw chars 1389 * under mouse pointer when nothing changed. 1390 */ 1391 1392 if (vw->vw_mouse_level > 0) 1393 vt_mouse_terminput(vd, type, x, y, event, cnt); 1394 1395 switch (type) { 1396 case MOUSE_ACTION: 1397 case MOUSE_MOTION_EVENT: 1398 /* Movement */ 1399 x += vd->vd_mx; 1400 y += vd->vd_my; 1401 1402 vt_termsize(vd, vf, &size); 1403 1404 /* Apply limits. */ 1405 x = MAX(x, 0); 1406 y = MAX(y, 0); 1407 x = MIN(x, (size.tp_col * vf->vf_width) - 1); 1408 y = MIN(y, (size.tp_row * vf->vf_height) - 1); 1409 1410 vd->vd_mx = x; 1411 vd->vd_my = y; 1412 if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) && 1413 (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE, 1414 vd->vd_mx / vf->vf_width, 1415 vd->vd_my / vf->vf_height) == 1)) { 1416 1417 /* 1418 * We have something marked to copy, so update pointer 1419 * to window with selection. 1420 */ 1421 vd->vd_markedwin = vw; 1422 } 1423 return; /* Done */ 1424 case MOUSE_BUTTON_EVENT: 1425 /* Buttons */ 1426 break; 1427 default: 1428 return; /* Done */ 1429 } 1430 1431 switch (event) { 1432 case MOUSE_BUTTON1DOWN: 1433 switch (cnt % 4) { 1434 case 0: /* up */ 1435 mark = VTB_MARK_END; 1436 break; 1437 case 1: /* single click: start cut operation */ 1438 mark = VTB_MARK_START; 1439 break; 1440 case 2: /* double click: cut a word */ 1441 mark = VTB_MARK_WORD; 1442 break; 1443 case 3: /* triple click: cut a line */ 1444 mark = VTB_MARK_ROW; 1445 break; 1446 } 1447 break; 1448 case VT_MOUSE_PASTEBUTTON: 1449 switch (cnt) { 1450 case 0: /* up */ 1451 break; 1452 default: 1453 if (vd->vd_markedwin == NULL) 1454 return; 1455 /* Get current selecton size in bytes. */ 1456 len = vtbuf_get_marked_len(&vd->vd_markedwin->vw_buf); 1457 if (len <= 0) 1458 return; 1459 1460 buf = malloc(len, M_VT, M_WAITOK | M_ZERO); 1461 /* Request cupy/paste buffer data, no more than `len' */ 1462 vtbuf_extract_marked(&vd->vd_markedwin->vw_buf, buf, 1463 len); 1464 1465 len /= sizeof(term_char_t); 1466 for (i = 0; i < len; i++ ) { 1467 if (buf[i] == '\0') 1468 continue; 1469 terminal_input_char(vw->vw_terminal, buf[i]); 1470 } 1471 1472 /* Done, so cleanup. */ 1473 free(buf, M_VT); 1474 break; 1475 } 1476 return; /* Done */ 1477 case VT_MOUSE_EXTENDBUTTON: 1478 switch (cnt) { 1479 case 0: /* up */ 1480 if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN)) 1481 mark = VTB_MARK_EXTEND; 1482 else 1483 mark = 0; 1484 break; 1485 default: 1486 mark = VTB_MARK_EXTEND; 1487 break; 1488 } 1489 break; 1490 default: 1491 return; /* Done */ 1492 } 1493 1494 /* Save buttons state. */ 1495 if (cnt > 0) 1496 vd->vd_mstate |= event; 1497 else 1498 vd->vd_mstate &= ~event; 1499 1500 if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, 1501 vd->vd_my / vf->vf_height) == 1) { 1502 /* 1503 * We have something marked to copy, so update pointer to 1504 * window with selection. 1505 */ 1506 vd->vd_markedwin = vw; 1507 } 1508 } 1509 1510 void 1511 vt_mouse_state(int show) 1512 { 1513 struct vt_device *vd; 1514 struct vt_window *vw; 1515 1516 vd = main_vd; 1517 vw = vd->vd_curwindow; 1518 1519 switch (show) { 1520 case VT_MOUSE_HIDE: 1521 vw->vw_flags |= VWF_MOUSE_HIDE; 1522 break; 1523 case VT_MOUSE_SHOW: 1524 vw->vw_flags &= ~VWF_MOUSE_HIDE; 1525 break; 1526 } 1527 } 1528 #endif 1529 1530 static int 1531 vtterm_mmap(struct terminal *tm, vm_ooffset_t offset, vm_paddr_t * paddr, 1532 int nprot, vm_memattr_t *memattr) 1533 { 1534 struct vt_window *vw = tm->tm_softc; 1535 struct vt_device *vd = vw->vw_device; 1536 1537 if (vd->vd_driver->vd_fb_mmap) 1538 return (vd->vd_driver->vd_fb_mmap(vd, offset, paddr, nprot, 1539 memattr)); 1540 1541 return (ENXIO); 1542 } 1543 1544 static int 1545 vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 1546 struct thread *td) 1547 { 1548 struct vt_window *vw = tm->tm_softc; 1549 struct vt_device *vd = vw->vw_device; 1550 keyboard_t *kbd; 1551 int error, i, s; 1552 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1553 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1554 int ival; 1555 1556 switch (cmd) { 1557 case _IO('v', 4): 1558 cmd = VT_RELDISP; 1559 break; 1560 case _IO('v', 5): 1561 cmd = VT_ACTIVATE; 1562 break; 1563 case _IO('v', 6): 1564 cmd = VT_WAITACTIVE; 1565 break; 1566 case _IO('K', 20): 1567 cmd = KDSKBSTATE; 1568 break; 1569 case _IO('K', 67): 1570 cmd = KDSETRAD; 1571 break; 1572 case _IO('K', 7): 1573 cmd = KDSKBMODE; 1574 break; 1575 case _IO('K', 8): 1576 cmd = KDMKTONE; 1577 break; 1578 case _IO('K', 63): 1579 cmd = KIOCSOUND; 1580 break; 1581 case _IO('K', 66): 1582 cmd = KDSETLED; 1583 break; 1584 case _IO('c', 110): 1585 cmd = CONS_SETKBD; 1586 break; 1587 default: 1588 goto skip_thunk; 1589 } 1590 ival = IOCPARM_IVAL(data); 1591 data = (caddr_t)&ival; 1592 skip_thunk: 1593 #endif 1594 1595 switch (cmd) { 1596 case KDSETRAD: /* set keyboard repeat & delay rates (old) */ 1597 if (*(int *)data & ~0x7f) 1598 return (EINVAL); 1599 case GIO_KEYMAP: 1600 case PIO_KEYMAP: 1601 case GIO_DEADKEYMAP: 1602 case PIO_DEADKEYMAP: 1603 case GETFKEY: 1604 case SETFKEY: 1605 case KDGKBINFO: 1606 case KDGKBTYPE: 1607 case KDSKBSTATE: /* set keyboard state (locks) */ 1608 case KDGKBSTATE: /* get keyboard state (locks) */ 1609 case KDGETREPEAT: /* get keyboard repeat & delay rates */ 1610 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */ 1611 case KDSETLED: /* set keyboard LED status */ 1612 case KDGETLED: /* get keyboard LED status */ 1613 case KBADDKBD: /* add/remove keyboard to/from mux */ 1614 case KBRELKBD: { 1615 error = 0; 1616 1617 mtx_lock(&Giant); 1618 kbd = kbd_get_keyboard(vd->vd_keyboard); 1619 if (kbd != NULL) 1620 error = kbdd_ioctl(kbd, cmd, data); 1621 mtx_unlock(&Giant); 1622 if (error == ENOIOCTL) { 1623 if (cmd == KDGKBTYPE) { 1624 /* always return something? XXX */ 1625 *(int *)data = 0; 1626 } else { 1627 return (ENODEV); 1628 } 1629 } 1630 return (error); 1631 } 1632 case KDGKBMODE: { 1633 int mode = -1; 1634 1635 mtx_lock(&Giant); 1636 kbd = kbd_get_keyboard(vd->vd_keyboard); 1637 if (kbd != NULL) { 1638 kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode); 1639 } 1640 mtx_unlock(&Giant); 1641 DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode); 1642 *(int *)data = mode; 1643 return (0); 1644 } 1645 case KDSKBMODE: { 1646 int mode; 1647 1648 mode = *(int *)data; 1649 switch (mode) { 1650 case K_XLATE: 1651 case K_RAW: 1652 case K_CODE: 1653 vw->vw_kbdmode = mode; 1654 if (vw == vd->vd_curwindow) { 1655 keyboard_t *kbd; 1656 error = 0; 1657 1658 mtx_lock(&Giant); 1659 kbd = kbd_get_keyboard(vd->vd_keyboard); 1660 if (kbd != NULL) { 1661 error = kbdd_ioctl(kbd, KDSKBMODE, 1662 (void *)&mode); 1663 } 1664 mtx_unlock(&Giant); 1665 } 1666 return (0); 1667 default: 1668 return (EINVAL); 1669 } 1670 } 1671 case FBIOGTYPE: 1672 case FBIO_GETWINORG: /* get frame buffer window origin */ 1673 case FBIO_GETDISPSTART: /* get display start address */ 1674 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 1675 case FBIO_BLANK: /* blank display */ 1676 if (vd->vd_driver->vd_fb_ioctl) 1677 return (vd->vd_driver->vd_fb_ioctl(vd, cmd, data, td)); 1678 break; 1679 case CONS_BLANKTIME: 1680 /* XXX */ 1681 return (0); 1682 case CONS_GET: 1683 /* XXX */ 1684 *(int *)data = M_CG640x480; 1685 return (0); 1686 case CONS_BELLTYPE: /* set bell type sound */ 1687 if ((*(int *)data) & CONS_QUIET_BELL) 1688 vd->vd_flags |= VDF_QUIET_BELL; 1689 else 1690 vd->vd_flags &= ~VDF_QUIET_BELL; 1691 return (0); 1692 case CONS_GETINFO: { 1693 vid_info_t *vi = (vid_info_t *)data; 1694 1695 vi->m_num = vd->vd_curwindow->vw_number + 1; 1696 /* XXX: other fields! */ 1697 return (0); 1698 } 1699 case CONS_GETVERS: 1700 *(int *)data = 0x200; 1701 return (0); 1702 case CONS_MODEINFO: 1703 /* XXX */ 1704 return (0); 1705 case CONS_MOUSECTL: { 1706 mouse_info_t *mouse = (mouse_info_t*)data; 1707 1708 /* 1709 * This has no effect on vt(4). We don't draw any mouse 1710 * cursor. Just ignore MOUSE_HIDE and MOUSE_SHOW to 1711 * prevent excessive errors. All the other commands 1712 * should not be applied to individual TTYs, but only to 1713 * consolectl. 1714 */ 1715 switch (mouse->operation) { 1716 case MOUSE_HIDE: 1717 vd->vd_flags &= ~VDF_MOUSECURSOR; 1718 return (0); 1719 case MOUSE_SHOW: 1720 vd->vd_mx = vd->vd_width / 2; 1721 vd->vd_my = vd->vd_height / 2; 1722 vd->vd_flags |= VDF_MOUSECURSOR; 1723 return (0); 1724 default: 1725 return (EINVAL); 1726 } 1727 } 1728 case PIO_VFONT: { 1729 struct vt_font *vf; 1730 1731 error = vtfont_load((void *)data, &vf); 1732 if (error != 0) 1733 return (error); 1734 1735 error = vt_change_font(vw, vf); 1736 if (error == 0) { 1737 /* XXX: replace 0 with current bg color. */ 1738 vt_set_border(vw, vf, 0); 1739 } 1740 vtfont_unref(vf); 1741 return (error); 1742 } 1743 case GIO_SCRNMAP: { 1744 scrmap_t *sm = (scrmap_t *)data; 1745 int i; 1746 1747 /* We don't have screen maps, so return a handcrafted one. */ 1748 for (i = 0; i < 256; i++) 1749 sm->scrmap[i] = i; 1750 return (0); 1751 } 1752 case KDSETMODE: 1753 /* XXX */ 1754 return (0); 1755 case KDENABIO: /* allow io operations */ 1756 error = priv_check(td, PRIV_IO); 1757 if (error != 0) 1758 return (error); 1759 error = securelevel_gt(td->td_ucred, 0); 1760 if (error != 0) 1761 return (error); 1762 #if defined(__i386__) 1763 td->td_frame->tf_eflags |= PSL_IOPL; 1764 #elif defined(__amd64__) 1765 td->td_frame->tf_rflags |= PSL_IOPL; 1766 #endif 1767 return (0); 1768 case KDDISABIO: /* disallow io operations (default) */ 1769 #if defined(__i386__) 1770 td->td_frame->tf_eflags &= ~PSL_IOPL; 1771 #elif defined(__amd64__) 1772 td->td_frame->tf_rflags &= ~PSL_IOPL; 1773 #endif 1774 return (0); 1775 case KDMKTONE: /* sound the bell */ 1776 vtterm_beep(tm, *(u_int *)data); 1777 return (0); 1778 case KIOCSOUND: /* make tone (*data) hz */ 1779 /* TODO */ 1780 return (0); 1781 case CONS_SETKBD: /* set the new keyboard */ 1782 mtx_lock(&Giant); 1783 error = 0; 1784 if (vd->vd_keyboard != *(int *)data) { 1785 kbd = kbd_get_keyboard(*(int *)data); 1786 if (kbd == NULL) { 1787 mtx_unlock(&Giant); 1788 return (EINVAL); 1789 } 1790 i = kbd_allocate(kbd->kb_name, kbd->kb_unit, 1791 (void *)vd, vt_kbdevent, vd); 1792 if (i >= 0) { 1793 if (vd->vd_keyboard != -1) { 1794 kbd_release(kbd, (void *)vd); 1795 } 1796 kbd = kbd_get_keyboard(i); 1797 vd->vd_keyboard = i; 1798 1799 (void)kbdd_ioctl(kbd, KDSKBMODE, 1800 (caddr_t)&vd->vd_curwindow->vw_kbdmode); 1801 } else { 1802 error = EPERM; /* XXX */ 1803 } 1804 } 1805 mtx_unlock(&Giant); 1806 return (error); 1807 case CONS_RELKBD: /* release the current keyboard */ 1808 mtx_lock(&Giant); 1809 error = 0; 1810 if (vd->vd_keyboard != -1) { 1811 kbd = kbd_get_keyboard(vd->vd_keyboard); 1812 if (kbd == NULL) { 1813 mtx_unlock(&Giant); 1814 return (EINVAL); 1815 } 1816 error = kbd_release(kbd, (void *)vd); 1817 if (error == 0) { 1818 vd->vd_keyboard = -1; 1819 } 1820 } 1821 mtx_unlock(&Giant); 1822 return (error); 1823 case VT_ACTIVATE: { 1824 int win; 1825 win = *(int *)data - 1; 1826 DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, 1827 VT_UNIT(vw), win); 1828 if ((win > VT_MAXWINDOWS) || (win < 0)) 1829 return (EINVAL); 1830 return (vt_proc_window_switch(vd->vd_windows[win])); 1831 } 1832 case VT_GETACTIVE: 1833 *(int *)data = vd->vd_curwindow->vw_number + 1; 1834 return (0); 1835 case VT_GETINDEX: 1836 *(int *)data = vw->vw_number + 1; 1837 return (0); 1838 case VT_LOCKSWITCH: 1839 /* TODO: Check current state, switching can be in progress. */ 1840 if ((*(int *)data) == 0x01) 1841 vw->vw_flags |= VWF_VTYLOCK; 1842 else if ((*(int *)data) == 0x02) 1843 vw->vw_flags &= ~VWF_VTYLOCK; 1844 else 1845 return (EINVAL); 1846 return (0); 1847 case VT_OPENQRY: 1848 VT_LOCK(vd); 1849 for (i = 0; i < VT_MAXWINDOWS; i++) { 1850 vw = vd->vd_windows[i]; 1851 if (vw == NULL) 1852 continue; 1853 if (!(vw->vw_flags & VWF_OPENED)) { 1854 *(int *)data = vw->vw_number + 1; 1855 VT_UNLOCK(vd); 1856 return (0); 1857 } 1858 } 1859 VT_UNLOCK(vd); 1860 return (EINVAL); 1861 case VT_WAITACTIVE: 1862 error = 0; 1863 1864 i = *(unsigned int *)data; 1865 if (i > VT_MAXWINDOWS) 1866 return (EINVAL); 1867 if (i != 0) 1868 vw = vd->vd_windows[i - 1]; 1869 1870 VT_LOCK(vd); 1871 while (vd->vd_curwindow != vw && error == 0) 1872 error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 1873 VT_UNLOCK(vd); 1874 return (error); 1875 case VT_SETMODE: { /* set screen switcher mode */ 1876 struct vt_mode *mode; 1877 struct proc *p1; 1878 1879 mode = (struct vt_mode *)data; 1880 DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 1881 if (vw->vw_smode.mode == VT_PROCESS) { 1882 p1 = pfind(vw->vw_pid); 1883 if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 1884 if (p1) 1885 PROC_UNLOCK(p1); 1886 DPRINTF(5, "error EPERM\n"); 1887 return (EPERM); 1888 } 1889 if (p1) 1890 PROC_UNLOCK(p1); 1891 } 1892 if (mode->mode == VT_AUTO) { 1893 vw->vw_smode.mode = VT_AUTO; 1894 vw->vw_proc = NULL; 1895 vw->vw_pid = 0; 1896 DPRINTF(5, "VT_AUTO, "); 1897 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1898 cnavailable(vw->vw_terminal->consdev, TRUE); 1899 /* were we in the middle of the vty switching process? */ 1900 if (finish_vt_rel(vw, TRUE, &s) == 0) 1901 DPRINTF(5, "reset WAIT_REL, "); 1902 if (finish_vt_acq(vw) == 0) 1903 DPRINTF(5, "reset WAIT_ACQ, "); 1904 return (0); 1905 } else if (mode->mode == VT_PROCESS) { 1906 if (!ISSIGVALID(mode->relsig) || 1907 !ISSIGVALID(mode->acqsig) || 1908 !ISSIGVALID(mode->frsig)) { 1909 DPRINTF(5, "error EINVAL\n"); 1910 return (EINVAL); 1911 } 1912 DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 1913 bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 1914 vw->vw_proc = td->td_proc; 1915 vw->vw_pid = vw->vw_proc->p_pid; 1916 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1917 cnavailable(vw->vw_terminal->consdev, FALSE); 1918 } else { 1919 DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 1920 mode->mode); 1921 return (EINVAL); 1922 } 1923 DPRINTF(5, "\n"); 1924 return (0); 1925 } 1926 case VT_GETMODE: /* get screen switcher mode */ 1927 bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 1928 return (0); 1929 1930 case VT_RELDISP: /* screen switcher ioctl */ 1931 /* 1932 * This must be the current vty which is in the VT_PROCESS 1933 * switching mode... 1934 */ 1935 if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 1936 VT_PROCESS)) { 1937 return (EINVAL); 1938 } 1939 /* ...and this process is controlling it. */ 1940 if (vw->vw_proc != td->td_proc) { 1941 return (EPERM); 1942 } 1943 error = EINVAL; 1944 switch(*(int *)data) { 1945 case VT_FALSE: /* user refuses to release screen, abort */ 1946 if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 1947 DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", 1948 SC_DRIVER_NAME, VT_UNIT(vw)); 1949 break; 1950 case VT_TRUE: /* user has released screen, go on */ 1951 /* finish_vt_rel(..., TRUE, ...) should not be locked */ 1952 if (vw->vw_flags & VWF_SWWAIT_REL) { 1953 if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 1954 DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 1955 SC_DRIVER_NAME, VT_UNIT(vw)); 1956 } else { 1957 error = EINVAL; 1958 } 1959 return (error); 1960 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1961 if ((error = finish_vt_acq(vw)) == 0) 1962 DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", 1963 SC_DRIVER_NAME, VT_UNIT(vw)); 1964 break; 1965 default: 1966 break; 1967 } 1968 return (error); 1969 } 1970 1971 return (ENOIOCTL); 1972 } 1973 1974 static struct vt_window * 1975 vt_allocate_window(struct vt_device *vd, unsigned int window) 1976 { 1977 struct vt_window *vw; 1978 struct terminal *tm; 1979 term_pos_t size; 1980 struct winsize wsz; 1981 1982 vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 1983 vw->vw_device = vd; 1984 vw->vw_number = window; 1985 vw->vw_kbdmode = K_XLATE; 1986 1987 if ((vd->vd_flags & VDF_TEXTMODE) == 0) 1988 vw->vw_font = vtfont_ref(&vt_font_default); 1989 1990 vt_termsize(vd, vw->vw_font, &size); 1991 vt_winsize(vd, vw->vw_font, &wsz); 1992 vtbuf_init(&vw->vw_buf, &size); 1993 1994 tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 1995 terminal_set_winsize(tm, &wsz); 1996 vd->vd_windows[window] = vw; 1997 callout_init(&vw->vw_proc_dead_timer, 0); 1998 1999 return (vw); 2000 } 2001 2002 void 2003 vt_upgrade(struct vt_device *vd) 2004 { 2005 struct vt_window *vw; 2006 unsigned int i; 2007 2008 if (!vty_enabled(VTY_VT)) 2009 return; 2010 2011 for (i = 0; i < VT_MAXWINDOWS; i++) { 2012 vw = vd->vd_windows[i]; 2013 if (vw == NULL) { 2014 /* New window. */ 2015 vw = vt_allocate_window(vd, i); 2016 } 2017 if (!(vw->vw_flags & VWF_READY)) { 2018 callout_init(&vw->vw_proc_dead_timer, 0); 2019 terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 2020 vw->vw_flags |= VWF_READY; 2021 if (vw->vw_flags & VWF_CONSOLE) { 2022 /* For existing console window. */ 2023 EVENTHANDLER_REGISTER(shutdown_pre_sync, 2024 vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 2025 } 2026 } 2027 2028 } 2029 VT_LOCK(vd); 2030 if (vd->vd_curwindow == NULL) 2031 vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 2032 2033 if (!(vd->vd_flags & VDF_ASYNC)) { 2034 /* Attach keyboard. */ 2035 vt_allocate_keyboard(vd); 2036 2037 /* Init 25 Hz timer. */ 2038 callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 2039 2040 /* Start timer when everything ready. */ 2041 vd->vd_flags |= VDF_ASYNC; 2042 callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 2043 } 2044 2045 VT_UNLOCK(vd); 2046 2047 /* Refill settings with new sizes. */ 2048 vt_resize(vd); 2049 } 2050 2051 static void 2052 vt_resize(struct vt_device *vd) 2053 { 2054 struct vt_window *vw; 2055 int i; 2056 2057 for (i = 0; i < VT_MAXWINDOWS; i++) { 2058 vw = vd->vd_windows[i]; 2059 VT_LOCK(vd); 2060 /* Assign default font to window, if not textmode. */ 2061 if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) 2062 vw->vw_font = vtfont_ref(&vt_font_default); 2063 VT_UNLOCK(vd); 2064 /* Resize terminal windows */ 2065 while (vt_change_font(vw, vw->vw_font) == EBUSY) { 2066 DPRINTF(100, "%s: vt_change_font() is busy, " 2067 "window %d\n", __func__, i); 2068 } 2069 } 2070 } 2071 2072 void 2073 vt_allocate(struct vt_driver *drv, void *softc) 2074 { 2075 struct vt_device *vd; 2076 2077 if (!vty_enabled(VTY_VT)) 2078 return; 2079 2080 if (main_vd->vd_driver == NULL) { 2081 main_vd->vd_driver = drv; 2082 printf("VT: initialize with new VT driver \"%s\".\n", 2083 drv->vd_name); 2084 } else { 2085 /* 2086 * Check if have rights to replace current driver. For example: 2087 * it is bad idea to replace KMS driver with generic VGA one. 2088 */ 2089 if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 2090 printf("VT: Driver priority %d too low. Current %d\n ", 2091 drv->vd_priority, main_vd->vd_driver->vd_priority); 2092 return; 2093 } 2094 printf("VT: Replacing driver \"%s\" with new \"%s\".\n", 2095 main_vd->vd_driver->vd_name, drv->vd_name); 2096 } 2097 vd = main_vd; 2098 VT_LOCK(vd); 2099 if (drv->vd_maskbitbltchr == NULL) 2100 drv->vd_maskbitbltchr = drv->vd_bitbltchr; 2101 2102 if (vd->vd_flags & VDF_ASYNC) { 2103 /* Stop vt_flush periodic task. */ 2104 callout_drain(&vd->vd_timer); 2105 /* 2106 * Mute current terminal until we done. vt_change_font (called 2107 * from vt_resize) will unmute it. 2108 */ 2109 terminal_mute(vd->vd_curwindow->vw_terminal, 1); 2110 } 2111 2112 /* 2113 * Reset VDF_TEXTMODE flag, driver who require that flag (vt_vga) will 2114 * set it. 2115 */ 2116 vd->vd_flags &= ~VDF_TEXTMODE; 2117 2118 vd->vd_driver = drv; 2119 vd->vd_softc = softc; 2120 vd->vd_driver->vd_init(vd); 2121 VT_UNLOCK(vd); 2122 2123 /* Update windows sizes and initialize last items. */ 2124 vt_upgrade(vd); 2125 2126 #ifdef DEV_SPLASH 2127 if (vd->vd_flags & VDF_SPLASH) 2128 vtterm_splash(vd); 2129 #endif 2130 2131 if (vd->vd_flags & VDF_ASYNC) { 2132 /* Allow to put chars now. */ 2133 terminal_mute(vd->vd_curwindow->vw_terminal, 0); 2134 /* Rerun timer for screen updates. */ 2135 callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 2136 } 2137 2138 /* 2139 * Register as console. If it already registered, cnadd() will ignore 2140 * it. 2141 */ 2142 termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 2143 } 2144 2145 void 2146 vt_suspend() 2147 { 2148 2149 if (vt_suspendswitch == 0) 2150 return; 2151 /* Save current window. */ 2152 main_vd->vd_savedwindow = main_vd->vd_curwindow; 2153 /* Ask holding process to free window and switch to console window */ 2154 vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]); 2155 } 2156 2157 void 2158 vt_resume() 2159 { 2160 2161 if (vt_suspendswitch == 0) 2162 return; 2163 /* Switch back to saved window */ 2164 if (main_vd->vd_savedwindow != NULL) 2165 vt_proc_window_switch(main_vd->vd_savedwindow); 2166 main_vd->vd_savedwindow = NULL; 2167 } 2168