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