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