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