vt_core.c revision 257626
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: user/ed/newcons/sys/dev/vt/vt_core.c 257626 2013-11-04 09:01:52Z ray $"); 35 36#include <sys/param.h> 37#include <sys/consio.h> 38#include <sys/eventhandler.h> 39#include <sys/fbio.h> 40#include <sys/kbio.h> 41#include <sys/kdb.h> 42#include <sys/kernel.h> 43#include <sys/lock.h> 44#include <sys/malloc.h> 45#include <sys/mutex.h> 46#include <sys/proc.h> 47#include <sys/reboot.h> 48#include <sys/systm.h> 49#include <sys/terminal.h> 50 51#include <dev/kbd/kbdreg.h> 52#include <dev/vt/vt.h> 53 54static tc_bell_t vtterm_bell; 55static tc_cursor_t vtterm_cursor; 56static tc_putchar_t vtterm_putchar; 57static tc_fill_t vtterm_fill; 58static tc_copy_t vtterm_copy; 59static tc_param_t vtterm_param; 60static tc_done_t vtterm_done; 61 62static tc_cnprobe_t vtterm_cnprobe; 63static tc_cngetc_t vtterm_cngetc; 64 65static tc_opened_t vtterm_opened; 66static tc_ioctl_t vtterm_ioctl; 67 68const struct terminal_class vt_termclass = { 69 .tc_bell = vtterm_bell, 70 .tc_cursor = vtterm_cursor, 71 .tc_putchar = vtterm_putchar, 72 .tc_fill = vtterm_fill, 73 .tc_copy = vtterm_copy, 74 .tc_param = vtterm_param, 75 .tc_done = vtterm_done, 76 77 .tc_cnprobe = vtterm_cnprobe, 78 .tc_cngetc = vtterm_cngetc, 79 80 .tc_opened = vtterm_opened, 81 .tc_ioctl = vtterm_ioctl, 82}; 83 84/* 85 * Use a constant timer of 25 Hz to redraw the screen. 86 * 87 * XXX: In theory we should only fire up the timer when there is really 88 * activity. Unfortunately we cannot always start timers. We really 89 * don't want to process kernel messages synchronously, because it 90 * really slows down the system. 91 */ 92#define VT_TIMERFREQ 25 93 94/* Bell pitch/duration. */ 95#define VT_BELLDURATION ((5 * hz + 99) / 100) 96#define VT_BELLPITCH 800 97 98#define VT_LOCK(vd) mtx_lock(&(vd)->vd_lock) 99#define VT_UNLOCK(vd) mtx_unlock(&(vd)->vd_lock) 100 101#define VT_UNIT(vw) ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \ 102 (vw)->vw_number) 103 104/* XXX while syscons is here. */ 105int sc_txtmouse_no_retrace_wait; 106 107static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "Newcons parameters"); 108VT_SYSCTL_INT(debug, 0, "Newcons debug level"); 109VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode"); 110 111static unsigned int vt_unit = 0; 112static MALLOC_DEFINE(M_VT, "vt", "vt device"); 113struct vt_device *main_vd = NULL; 114 115/* Boot logo. */ 116extern unsigned int vt_logo_width; 117extern unsigned int vt_logo_height; 118extern unsigned int vt_logo_depth; 119extern unsigned char vt_logo_image[]; 120 121/* Font. */ 122extern struct vt_font vt_font_default; 123 124static int signal_vt_rel(struct vt_window *); 125static int signal_vt_acq(struct vt_window *); 126static int finish_vt_rel(struct vt_window *, int, int *); 127static int finish_vt_acq(struct vt_window *); 128static int vt_window_switch(struct vt_window *); 129static int vt_late_window_switch(struct vt_window *); 130static int vt_proc_alive(struct vt_window *); 131static void vt_resize(struct vt_device *); 132 133static void 134vt_switch_timer(void *arg) 135{ 136 137 vt_late_window_switch((struct vt_window *)arg); 138} 139 140static int 141vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw) 142{ 143 144 DPRINTF(40, "%s\n", __func__); 145 curvw->vw_switch_to = vw; 146 /* Set timer to allow switch in case when process hang. */ 147 callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer, 148 vt_switch_timer, (void *)vw); 149 /* Notify process about vt switch attempt. */ 150 DPRINTF(30, "%s: Notify process.\n", __func__); 151 signal_vt_rel(curvw); 152 153 return (0); 154} 155 156static int 157vt_window_postswitch(struct vt_window *vw) 158{ 159 160 signal_vt_acq(vw); 161 return (0); 162} 163 164/* vt_late_window_switch will done VT switching for regular case. */ 165static int 166vt_late_window_switch(struct vt_window *vw) 167{ 168 int ret; 169 170 callout_stop(&vw->vw_proc_dead_timer); 171 172 ret = vt_window_switch(vw); 173 if (ret) 174 return (ret); 175 176 /* Notify owner process about terminal availability. */ 177 if (vw->vw_smode.mode == VT_PROCESS) { 178 ret = vt_window_postswitch(vw); 179 } 180 return (ret); 181} 182 183/* Switch window. */ 184static int 185vt_proc_window_switch(struct vt_window *vw) 186{ 187 struct vt_window *curvw; 188 struct vt_device *vd; 189 int ret; 190 191 if (vw->vw_flags & VWF_VTYLOCK) 192 return (EBUSY); 193 194 vd = vw->vw_device; 195 curvw = vd->vd_curwindow; 196 197 /* Ask current process permitions to switch away. */ 198 if (curvw->vw_smode.mode == VT_PROCESS) { 199 DPRINTF(30, "%s: VT_PROCESS ", __func__); 200 if (vt_proc_alive(curvw) == FALSE) { 201 DPRINTF(30, "Dead. Cleaning."); 202 /* Dead */ 203 } else { 204 DPRINTF(30, "%s: Signaling process.\n", __func__); 205 /* Alive, try to ask him. */ 206 ret = vt_window_preswitch(vw, curvw); 207 /* Wait for process answer or timeout. */ 208 return (ret); 209 } 210 DPRINTF(30, "\n"); 211 } 212 213 ret = vt_late_window_switch(vw); 214 return (ret); 215} 216 217/* Switch window ignoring process locking. */ 218static int 219vt_window_switch(struct vt_window *vw) 220{ 221 struct vt_device *vd = vw->vw_device; 222 struct vt_window *curvw = vd->vd_curwindow; 223 keyboard_t *kbd; 224 225 VT_LOCK(vd); 226 if (curvw == vw) { 227 /* Nothing to do. */ 228 VT_UNLOCK(vd); 229 return (0); 230 } 231 if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) { 232 VT_UNLOCK(vd); 233 return (EINVAL); 234 } 235 236 vd->vd_curwindow = vw; 237 vd->vd_flags |= VDF_INVALID; 238 cv_broadcast(&vd->vd_winswitch); 239 VT_UNLOCK(vd); 240 241 if (vd->vd_driver->vd_postswitch) 242 vd->vd_driver->vd_postswitch(vd); 243 244 /* Restore per-window keyboard mode. */ 245 mtx_lock(&Giant); 246 kbd = kbd_get_keyboard(vd->vd_keyboard); 247 if (kbd != NULL) { 248 kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode); 249 } 250 mtx_unlock(&Giant); 251 DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number); 252 253 return (0); 254} 255 256static inline void 257vt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size) 258{ 259 260 size->tp_row = vd->vd_height; 261 size->tp_col = vd->vd_width; 262 if (vf != NULL) { 263 size->tp_row /= vf->vf_height; 264 size->tp_col /= vf->vf_width; 265 } 266} 267 268static inline void 269vt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size) 270{ 271 272 size->ws_row = size->ws_ypixel = vd->vd_height; 273 size->ws_col = size->ws_xpixel = vd->vd_width; 274 if (vf != NULL) { 275 size->ws_row /= vf->vf_height; 276 size->ws_col /= vf->vf_width; 277 } 278} 279 280static void 281vt_scroll(struct vt_window *vw, int offset, int whence) 282{ 283 int diff; 284 term_pos_t size; 285 286 if ((vw->vw_flags & VWF_SCROLL) == 0) 287 return; 288 289 vt_termsize(vw->vw_device, vw->vw_font, &size); 290 291 diff = vthistory_seek(&vw->vw_buf, offset, whence); 292 /* 293 * Offset changed, please update Nth lines on sceen. 294 * +N - Nth lines at top; 295 * -N - Nth lines at bottom. 296 */ 297 298 if (diff < -size.tp_row || diff > size.tp_row) { 299 vw->vw_device->vd_flags |= VDF_INVALID; 300 return; 301 } 302 vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/ 303} 304 305static int 306vt_machine_kbdevent(int c) 307{ 308 309 switch (c) { 310 case SPCLKEY | DBG: 311 kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); 312 return (1); 313 case SPCLKEY | RBT: 314 /* XXX: Make this configurable! */ 315 shutdown_nice(0); 316 return (1); 317 case SPCLKEY | HALT: 318 shutdown_nice(RB_HALT); 319 return (1); 320 case SPCLKEY | PDWN: 321 shutdown_nice(RB_HALT|RB_POWEROFF); 322 return (1); 323 }; 324 325 return (0); 326} 327 328static void 329vt_scrollmode_kbdevent(struct vt_window *vw, int c, int console) 330{ 331 struct vt_device *vd; 332 term_pos_t size; 333 334 vd = vw->vw_device; 335 /* Only special keys handled in ScrollLock mode */ 336 if ((c & SPCLKEY) == 0) 337 return; 338 339 c &= ~SPCLKEY; 340 341 if (console == 0) { 342 if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 343 vw = vd->vd_windows[c - F_SCR]; 344 if (vw != NULL) 345 vt_proc_window_switch(vw); 346 return; 347 } 348 VT_LOCK(vd); 349 } 350 351 switch (c) { 352 case SLK: { 353 /* Turn scrolling off. */ 354 vt_scroll(vw, 0, VHS_END); 355 VTBUF_SLCK_DISABLE(&vw->vw_buf); 356 vw->vw_flags &= ~VWF_SCROLL; 357 break; 358 } 359 case FKEY | F(49): /* Home key. */ 360 vt_scroll(vw, 0, VHS_END); 361 break; 362 case FKEY | F(50): /* Arrow up. */ 363 vt_scroll(vw, -1, VHS_CUR); 364 break; 365 case FKEY | F(51): /* Page up. */ 366 vt_termsize(vd, vw->vw_font, &size); 367 vt_scroll(vw, -size.tp_row, VHS_CUR); 368 break; 369 case FKEY | F(57): /* End key. */ 370 vt_scroll(vw, 0, VHS_SET); 371 break; 372 case FKEY | F(58): /* Arrow down. */ 373 vt_scroll(vw, 1, VHS_CUR); 374 break; 375 case FKEY | F(59): /* Page down. */ 376 vt_termsize(vd, vw->vw_font, &size); 377 vt_scroll(vw, size.tp_row, VHS_CUR); 378 break; 379 } 380 381 if (console == 0) 382 VT_UNLOCK(vd); 383} 384 385static int 386vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c) 387{ 388 struct vt_window *vw = vd->vd_curwindow; 389 int state = 0; 390 391 if (c & RELKEY) 392 return (0); 393 394 if (vt_machine_kbdevent(c)) 395 return (0); 396 397 if (vw->vw_flags & VWF_SCROLL) { 398 vt_scrollmode_kbdevent(vw, c, 0/* Not a console */); 399 /* Scroll mode keys handled, nothing to do more. */ 400 return (0); 401 } 402 403 if (c & SPCLKEY) { 404 c &= ~SPCLKEY; 405 406 if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 407 vw = vd->vd_windows[c - F_SCR]; 408 if (vw != NULL) 409 vt_proc_window_switch(vw); 410 return (0); 411 } 412 413 switch (c) { 414 case SLK: { 415 416 kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 417 VT_LOCK(vd); 418 if (state & SLKED) { 419 /* Turn scrolling on. */ 420 vw->vw_flags |= VWF_SCROLL; 421 VTBUF_SLCK_ENABLE(&vw->vw_buf); 422 } else { 423 /* Turn scrolling off. */ 424 vw->vw_flags &= ~VWF_SCROLL; 425 VTBUF_SLCK_DISABLE(&vw->vw_buf); 426 vt_scroll(vw, 0, VHS_END); 427 } 428 VT_UNLOCK(vd); 429 break; 430 } 431 case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 432 case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 433 case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 434 case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 435 /* F1 through F12 keys. */ 436 terminal_input_special(vw->vw_terminal, 437 TKEY_F1 + c - (FKEY | F(1))); 438 break; 439 case FKEY | F(49): /* Home key. */ 440 terminal_input_special(vw->vw_terminal, TKEY_HOME); 441 break; 442 case FKEY | F(50): /* Arrow up. */ 443 terminal_input_special(vw->vw_terminal, TKEY_UP); 444 break; 445 case FKEY | F(51): /* Page up. */ 446 terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP); 447 break; 448 case FKEY | F(53): /* Arrow left. */ 449 terminal_input_special(vw->vw_terminal, TKEY_LEFT); 450 break; 451 case FKEY | F(55): /* Arrow right. */ 452 terminal_input_special(vw->vw_terminal, TKEY_RIGHT); 453 break; 454 case FKEY | F(57): /* End key. */ 455 terminal_input_special(vw->vw_terminal, TKEY_END); 456 break; 457 case FKEY | F(58): /* Arrow down. */ 458 terminal_input_special(vw->vw_terminal, TKEY_DOWN); 459 break; 460 case FKEY | F(59): /* Page down. */ 461 terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN); 462 break; 463 case FKEY | F(60): /* Insert key. */ 464 terminal_input_special(vw->vw_terminal, TKEY_INSERT); 465 break; 466 case FKEY | F(61): /* Delete key. */ 467 terminal_input_special(vw->vw_terminal, TKEY_DELETE); 468 break; 469 } 470 } else if (KEYFLAGS(c) == 0) { 471 /* Don't do UTF-8 conversion when doing raw mode. */ 472 if (vw->vw_kbdmode == K_XLATE) 473 terminal_input_char(vw->vw_terminal, KEYCHAR(c)); 474 else 475 terminal_input_raw(vw->vw_terminal, c); 476 } 477 return (0); 478} 479 480static int 481vt_kbdevent(keyboard_t *kbd, int event, void *arg) 482{ 483 struct vt_device *vd = arg; 484 int c; 485 486 switch (event) { 487 case KBDIO_KEYINPUT: 488 break; 489 case KBDIO_UNLOADING: 490 mtx_lock(&Giant); 491 vd->vd_keyboard = -1; 492 kbd_release(kbd, (void *)&vd->vd_keyboard); 493 mtx_unlock(&Giant); 494 return (0); 495 default: 496 return (EINVAL); 497 } 498 499 while ((c = kbdd_read_char(kbd, 0)) != NOKEY) 500 vt_processkey(kbd, vd, c); 501 502 return (0); 503} 504 505static int 506vt_allocate_keyboard(struct vt_device *vd) 507{ 508 int idx0, idx; 509 keyboard_t *k0, *k; 510 keyboard_info_t ki; 511 512 idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard, 513 vt_kbdevent, vd); 514 /* XXX: kb_token lost */ 515 vd->vd_keyboard = idx0; 516 if (idx0 != -1) { 517 DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); 518 k0 = kbd_get_keyboard(idx0); 519 520 for (idx = kbd_find_keyboard2("*", -1, 0); 521 idx != -1; 522 idx = kbd_find_keyboard2("*", -1, idx + 1)) { 523 k = kbd_get_keyboard(idx); 524 525 if (idx == idx0 || KBD_IS_BUSY(k)) 526 continue; 527 528 bzero(&ki, sizeof(ki)); 529 strcpy(ki.kb_name, k->kb_name); 530 ki.kb_unit = k->kb_unit; 531 532 kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 533 } 534 } else { 535 DPRINTF(20, "%s: no kbdmux allocated\n", __func__); 536 idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard, 537 vt_kbdevent, vd); 538 } 539 DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 540 541 return (idx0); 542} 543 544static void 545vtterm_bell(struct terminal *tm) 546{ 547 548 sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION); 549} 550 551static void 552vtterm_cursor(struct terminal *tm, const term_pos_t *p) 553{ 554 struct vt_window *vw = tm->tm_softc; 555 556 vtbuf_cursor_position(&vw->vw_buf, p); 557} 558 559static void 560vtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c) 561{ 562 struct vt_window *vw = tm->tm_softc; 563 564 vtbuf_putchar(&vw->vw_buf, p, c); 565} 566 567static void 568vtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c) 569{ 570 struct vt_window *vw = tm->tm_softc; 571 572 vtbuf_fill_locked(&vw->vw_buf, r, c); 573} 574 575static void 576vtterm_copy(struct terminal *tm, const term_rect_t *r, 577 const term_pos_t *p) 578{ 579 struct vt_window *vw = tm->tm_softc; 580 581 vtbuf_copy(&vw->vw_buf, r, p); 582} 583 584static void 585vtterm_param(struct terminal *tm, int cmd, unsigned int arg) 586{ 587 struct vt_window *vw = tm->tm_softc; 588 589 switch (cmd) { 590 case TP_SHOWCURSOR: 591 vtbuf_cursor_visibility(&vw->vw_buf, arg); 592 break; 593 } 594} 595 596static inline void 597vt_determine_colors(term_char_t c, int cursor, 598 term_color_t *fg, term_color_t *bg) 599{ 600 601 *fg = TCHAR_FGCOLOR(c); 602 if (TCHAR_FORMAT(c) & TF_BOLD) 603 *fg = TCOLOR_LIGHT(*fg); 604 *bg = TCHAR_BGCOLOR(c); 605 606 if (TCHAR_FORMAT(c) & TF_REVERSE) { 607 term_color_t tmp; 608 609 tmp = *fg; 610 *fg = *bg; 611 *bg = tmp; 612 } 613 614 if (cursor) { 615 *fg = *bg; 616 *bg = TC_WHITE; 617 } 618} 619 620static void 621vt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c, 622 int iscursor, unsigned int row, unsigned int col) 623{ 624 term_color_t fg, bg; 625 626 vt_determine_colors(c, iscursor, &fg, &bg); 627 628 if (vf != NULL) { 629 const uint8_t *src; 630 vt_axis_t top, left; 631 632 src = vtfont_lookup(vf, c); 633 634 /* 635 * Align the terminal to the centre of the screen. 636 * Fonts may not always be able to fill the entire 637 * screen. 638 */ 639 top = row * vf->vf_height + 640 (vd->vd_height % vf->vf_height) / 2; 641 left = col * vf->vf_width + 642 (vd->vd_width % vf->vf_width) / 2; 643 644 vd->vd_driver->vd_bitbltchr(vd, src, top, left, 645 vf->vf_width, vf->vf_height, fg, bg); 646 } else { 647 vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c), 648 row, col, fg, bg); 649 } 650} 651 652static void 653vt_flush(struct vt_device *vd) 654{ 655 struct vt_window *vw = vd->vd_curwindow; 656 struct vt_font *vf = vw->vw_font; 657 term_pos_t size; 658 term_rect_t tarea; 659 struct vt_bufmask tmask; 660 unsigned int row, col; 661 term_char_t *r; 662 663 if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY) 664 return; 665 666 vtbuf_undirty(&vw->vw_buf, &tarea, &tmask); 667 vt_termsize(vd, vf, &size); 668 669 /* Force a full redraw when the screen contents are invalid. */ 670 if (vd->vd_flags & VDF_INVALID) { 671 tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0; 672 tarea.tr_end = size; 673 tmask.vbm_row = tmask.vbm_col = VBM_DIRTY; 674 675 /* 676 * Blank to prevent borders with artifacts. This is 677 * only required when the font doesn't exactly fill the 678 * screen. 679 */ 680 if (vd->vd_flags & VDF_INVALID && vf != NULL && 681 (vd->vd_width % vf->vf_width != 0 || 682 vd->vd_height % vf->vf_height != 0)) 683 vd->vd_driver->vd_blank(vd, TC_BLACK); 684 685 vd->vd_flags &= ~VDF_INVALID; 686 } 687 688 689 for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) { 690 if (!VTBUF_DIRTYROW(&tmask, row)) 691 continue; 692 r = VTBUF_GET_ROW(&vw->vw_buf, row); 693 for (col = tarea.tr_begin.tp_col; 694 col < tarea.tr_end.tp_col; col++) { 695 if (!VTBUF_DIRTYCOL(&tmask, col)) 696 continue; 697 698 vt_bitblt_char(vd, vf, r[col], 699 VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col); 700 } 701 } 702} 703 704static void 705vt_timer(void *arg) 706{ 707 struct vt_device *vd; 708 709 vd = arg; 710 /* Update screen if required. */ 711 vt_flush(vd); 712 /* Schedule for next update. */ 713 callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 714} 715 716static void 717vtterm_done(struct terminal *tm) 718{ 719 struct vt_window *vw = tm->tm_softc; 720 struct vt_device *vd = vw->vw_device; 721 722 if (kdb_active || panicstr != NULL) { 723 /* Switch to the debugger. */ 724 if (vd->vd_curwindow != vw) { 725 vd->vd_curwindow = vw; 726 vd->vd_flags |= VDF_INVALID; 727 if (vd->vd_driver->vd_postswitch) 728 vd->vd_driver->vd_postswitch(vd); 729 } 730 vd->vd_flags &= ~VDF_SPLASH; 731 vt_flush(vd); 732 } else if (!(vd->vd_flags & VDF_ASYNC)) { 733 vt_flush(vd); 734 } 735} 736 737static void 738vtterm_splash(struct vt_device *vd) 739{ 740 vt_axis_t top, left; 741 742 /* Display a nice boot splash. */ 743 if (!(vd->vd_flags & VDF_TEXTMODE)) { 744 745 top = (vd->vd_height - vt_logo_height) / 2; 746 left = (vd->vd_width - vt_logo_width) / 2; 747 switch (vt_logo_depth) { 748 case 1: 749 /* XXX: Unhardcode colors! */ 750 vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, top, left, 751 vt_logo_width, vt_logo_height, 0xf, 0x0); 752 } 753 vd->vd_flags |= VDF_SPLASH; 754 } 755} 756 757static void 758vtterm_cnprobe(struct terminal *tm, struct consdev *cp) 759{ 760 struct vt_window *vw = tm->tm_softc; 761 struct vt_device *vd = vw->vw_device; 762 struct winsize wsz; 763 764 if (vd->vd_flags & VDF_INITIALIZED) 765 /* Initialization already done. */ 766 return; 767 768 cp->cn_pri = vd->vd_driver->vd_init(vd); 769 if (cp->cn_pri == CN_DEAD) { 770 vd->vd_flags |= VDF_DEAD; 771 return; 772 } 773 774 /* Initialize any early-boot keyboard drivers */ 775 kbd_configure(KB_CONF_PROBE_ONLY); 776 777 vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1); 778 vd->vd_windows[VT_CONSWINDOW] = vw; 779 sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); 780 781 if (!(vd->vd_flags & VDF_TEXTMODE)) 782 vw->vw_font = vtfont_ref(&vt_font_default); 783 784 vtbuf_init_early(&vw->vw_buf); 785 vt_winsize(vd, vw->vw_font, &wsz); 786 terminal_set_winsize(tm, &wsz); 787 788 vtterm_splash(vd); 789 790 vd->vd_flags |= VDF_INITIALIZED; 791 main_vd = vd; 792} 793 794static int 795vtterm_cngetc(struct terminal *tm) 796{ 797 struct vt_window *vw = tm->tm_softc; 798 struct vt_device *vd = vw->vw_device; 799 keyboard_t *kbd; 800 int state; 801 u_int c; 802 803 if (vw->vw_kbdsq && *vw->vw_kbdsq) 804 return (*vw->vw_kbdsq++); 805 806 state = 0; 807 /* Make sure the splash screen is not there. */ 808 if (vd->vd_flags & VDF_SPLASH) { 809 /* Remove splash */ 810 vd->vd_flags &= ~VDF_SPLASH; 811 /* Mark screen as invalid to force update */ 812 vd->vd_flags |= VDF_INVALID; 813 vt_flush(vd); 814 } 815 816 /* Stripped down keyboard handler. */ 817 kbd = kbd_get_keyboard(vd->vd_keyboard); 818 if (kbd == NULL) 819 return (-1); 820 821 /* Force keyboard input mode to K_XLATE */ 822 c = K_XLATE; 823 kbdd_ioctl(kbd, KDSKBMODE, (void *)&c); 824 825 /* Switch the keyboard to polling to make it work here. */ 826 kbdd_poll(kbd, TRUE); 827 c = kbdd_read_char(kbd, 0); 828 kbdd_poll(kbd, FALSE); 829 if (c & RELKEY) 830 return (-1); 831 832 if (vw->vw_flags & VWF_SCROLL) { 833 vt_scrollmode_kbdevent(vw, c, 1/* Console mode */); 834 vt_flush(vd); 835 return (-1); 836 } 837 838 /* Stripped down handling of vt_kbdevent(), without locking, etc. */ 839 if (c & SPCLKEY) { 840 switch (c) { 841 case SPCLKEY | SLK: 842 kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 843 if (state & SLKED) { 844 /* Turn scrolling on. */ 845 vw->vw_flags |= VWF_SCROLL; 846 VTBUF_SLCK_ENABLE(&vw->vw_buf); 847 } else { 848 /* Turn scrolling off. */ 849 vt_scroll(vw, 0, VHS_END); 850 vw->vw_flags &= ~VWF_SCROLL; 851 VTBUF_SLCK_DISABLE(&vw->vw_buf); 852 } 853 break; 854 /* XXX: KDB can handle history. */ 855 case SPCLKEY | FKEY | F(50): /* Arrow up. */ 856 vw->vw_kbdsq = "\x1b[A"; 857 break; 858 case SPCLKEY | FKEY | F(58): /* Arrow down. */ 859 vw->vw_kbdsq = "\x1b[B"; 860 break; 861 case SPCLKEY | FKEY | F(55): /* Arrow right. */ 862 vw->vw_kbdsq = "\x1b[C"; 863 break; 864 case SPCLKEY | FKEY | F(53): /* Arrow left. */ 865 vw->vw_kbdsq = "\x1b[D"; 866 break; 867 } 868 869 /* Force refresh to make scrollback work. */ 870 vt_flush(vd); 871 } else if (KEYFLAGS(c) == 0) { 872 return KEYCHAR(c); 873 } 874 875 if (vw->vw_kbdsq && *vw->vw_kbdsq) 876 return (* 877 vw->vw_kbdsq++); 878 879 return (-1); 880} 881 882static void 883vtterm_opened(struct terminal *tm, int opened) 884{ 885 struct vt_window *vw = tm->tm_softc; 886 struct vt_device *vd = vw->vw_device; 887 888 VT_LOCK(vd); 889 vd->vd_flags &= ~VDF_SPLASH; 890 if (opened) 891 vw->vw_flags |= VWF_OPENED; 892 else { 893 vw->vw_flags &= ~VWF_OPENED; 894 /* TODO: finish ACQ/REL */ 895 } 896 VT_UNLOCK(vd); 897} 898 899static int 900vt_change_font(struct vt_window *vw, struct vt_font *vf) 901{ 902 struct vt_device *vd = vw->vw_device; 903 struct terminal *tm = vw->vw_terminal; 904 term_pos_t size; 905 struct winsize wsz; 906 907 /* 908 * Changing fonts. 909 * 910 * Changing fonts is a little tricky. We must prevent 911 * simultaneous access to the device, so we must stop 912 * the display timer and the terminal from accessing. 913 * We need to switch fonts and grow our screen buffer. 914 * 915 * XXX: Right now the code uses terminal_mute() to 916 * prevent data from reaching the console driver while 917 * resizing the screen buffer. This isn't elegant... 918 */ 919 920 VT_LOCK(vd); 921 if (vw->vw_flags & VWF_BUSY) { 922 /* Another process is changing the font. */ 923 VT_UNLOCK(vd); 924 return (EBUSY); 925 } 926 if (vw->vw_font == NULL) { 927 /* Our device doesn't need fonts. */ 928 VT_UNLOCK(vd); 929 return (ENOTTY); 930 } 931 vw->vw_flags |= VWF_BUSY; 932 VT_UNLOCK(vd); 933 934 vt_termsize(vd, vf, &size); 935 vt_winsize(vd, vf, &wsz); 936 937 /* Grow the screen buffer and terminal. */ 938 terminal_mute(tm, 1); 939 vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 940 terminal_set_winsize_blank(tm, &wsz, 0); 941 terminal_mute(tm, 0); 942 943 /* Actually apply the font to the current window. */ 944 VT_LOCK(vd); 945 vtfont_unref(vw->vw_font); 946 vw->vw_font = vtfont_ref(vf); 947 948 /* Force a full redraw the next timer tick. */ 949 if (vd->vd_curwindow == vw) 950 vd->vd_flags |= VDF_INVALID; 951 vw->vw_flags &= ~VWF_BUSY; 952 VT_UNLOCK(vd); 953 return (0); 954} 955 956static int 957vt_proc_alive(struct vt_window *vw) 958{ 959 struct proc *p; 960 961 if (vw->vw_smode.mode != VT_PROCESS) 962 return FALSE; 963 964 if (vw->vw_proc) { 965 if ((p = pfind(vw->vw_pid)) != NULL) 966 PROC_UNLOCK(p); 967 if (vw->vw_proc == p) 968 return TRUE; 969 vw->vw_proc = NULL; 970 vw->vw_smode.mode = VT_AUTO; 971 DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 972 vw->vw_pid = 0; 973 } 974 return FALSE; 975} 976 977static int 978signal_vt_rel(struct vt_window *vw) 979{ 980 if (vw->vw_smode.mode != VT_PROCESS) 981 return FALSE; 982 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 983 vw->vw_proc = NULL; 984 vw->vw_pid = 0; 985 return TRUE; 986 } 987 vw->vw_flags |= VWF_SWWAIT_REL; 988 PROC_LOCK(vw->vw_proc); 989 kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 990 PROC_UNLOCK(vw->vw_proc); 991 DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 992 return TRUE; 993} 994 995static int 996signal_vt_acq(struct vt_window *vw) 997{ 998 if (vw->vw_smode.mode != VT_PROCESS) 999 return FALSE; 1000 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1001 cnavailable(vw->vw_terminal->consdev, FALSE); 1002 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1003 vw->vw_proc = NULL; 1004 vw->vw_pid = 0; 1005 return TRUE; 1006 } 1007 vw->vw_flags |= VWF_SWWAIT_ACQ; 1008 PROC_LOCK(vw->vw_proc); 1009 kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 1010 PROC_UNLOCK(vw->vw_proc); 1011 DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 1012 return TRUE; 1013} 1014 1015static int 1016finish_vt_rel(struct vt_window *vw, int release, int *s) 1017{ 1018 if (vw->vw_flags & VWF_SWWAIT_REL) { 1019 vw->vw_flags &= ~VWF_SWWAIT_REL; 1020 if (release) { 1021 callout_drain(&vw->vw_proc_dead_timer); 1022 vt_late_window_switch(vw->vw_switch_to); 1023 } 1024 return 0; 1025 } 1026 return EINVAL; 1027} 1028 1029static int 1030finish_vt_acq(struct vt_window *vw) 1031{ 1032 if (vw->vw_flags & VWF_SWWAIT_ACQ) { 1033 vw->vw_flags &= ~VWF_SWWAIT_ACQ; 1034 return 0; 1035 } 1036 return EINVAL; 1037} 1038 1039static int 1040vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 1041 struct thread *td) 1042{ 1043 struct vt_window *vw = tm->tm_softc; 1044 struct vt_device *vd = vw->vw_device; 1045 int error, s; 1046 1047 switch (cmd) { 1048 case GIO_KEYMAP: 1049 case PIO_KEYMAP: 1050 case GIO_DEADKEYMAP: 1051 case PIO_DEADKEYMAP: 1052 case GETFKEY: 1053 case SETFKEY: 1054 case KDGKBINFO: { 1055 keyboard_t *kbd; 1056 error = 0; 1057 1058 mtx_lock(&Giant); 1059 kbd = kbd_get_keyboard(vd->vd_keyboard); 1060 if (kbd != NULL) 1061 error = kbdd_ioctl(kbd, cmd, data); 1062 mtx_unlock(&Giant); 1063 if (error == ENOIOCTL) 1064 return (ENODEV); 1065 return (error); 1066 } 1067 case KDGKBMODE: { 1068 int mode = -1; 1069 keyboard_t *kbd; 1070 1071 mtx_lock(&Giant); 1072 kbd = kbd_get_keyboard(vd->vd_keyboard); 1073 if (kbd != NULL) { 1074 kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode); 1075 } 1076 mtx_unlock(&Giant); 1077 DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode); 1078 *(int *)data = mode; 1079 return (0); 1080 } 1081 case KDSKBMODE: { 1082 int mode; 1083 1084 mode = *(int *)data; 1085 switch (mode) { 1086 case K_XLATE: 1087 case K_RAW: 1088 case K_CODE: 1089 vw->vw_kbdmode = mode; 1090 if (vw == vd->vd_curwindow) { 1091 keyboard_t *kbd; 1092 error = 0; 1093 1094 DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 1095 mtx_lock(&Giant); 1096 kbd = kbd_get_keyboard(vd->vd_keyboard); 1097 if (kbd != NULL) { 1098 DPRINTF(20, "kbdd_ioctl(KDSKBMODE, %d)\n", mode); 1099 error = kbdd_ioctl(kbd, KDSKBMODE, 1100 (void *)&mode); 1101 } 1102 mtx_unlock(&Giant); 1103 if (error) 1104 DPRINTF(20, "kbdd_ioctl(KDSKBMODE) return %d\n", error); 1105 } 1106 return (0); 1107 default: 1108 return (EINVAL); 1109 } 1110 } 1111 case CONS_BLANKTIME: 1112 /* XXX */ 1113 return (0); 1114 case CONS_GET: 1115 /* XXX */ 1116 *(int *)data = M_CG640x480; 1117 return (0); 1118 case CONS_GETINFO: { 1119 vid_info_t *vi = (vid_info_t *)data; 1120 1121 vi->m_num = vd->vd_curwindow->vw_number + 1; 1122 /* XXX: other fields! */ 1123 return (0); 1124 } 1125 case CONS_GETVERS: 1126 *(int *)data = 0x200; 1127 return 0; 1128 case CONS_MODEINFO: 1129 /* XXX */ 1130 return (0); 1131 case CONS_MOUSECTL: { 1132 mouse_info_t *mouse = (mouse_info_t*)data; 1133 1134 /* 1135 * This has no effect on vt(4). We don't draw any mouse 1136 * cursor. Just ignore MOUSE_HIDE and MOUSE_SHOW to 1137 * prevent excessive errors. All the other commands 1138 * should not be applied to individual TTYs, but only to 1139 * consolectl. 1140 */ 1141 switch (mouse->operation) { 1142 case MOUSE_HIDE: 1143 case MOUSE_SHOW: 1144 return (0); 1145 default: 1146 return (EINVAL); 1147 } 1148 } 1149 case PIO_VFONT: { 1150 struct vt_font *vf; 1151 1152 error = vtfont_load((void *)data, &vf); 1153 if (error != 0) 1154 return (error); 1155 1156 error = vt_change_font(vw, vf); 1157 vtfont_unref(vf); 1158 return (error); 1159 } 1160 case GIO_SCRNMAP: { 1161 scrmap_t *sm = (scrmap_t *)data; 1162 int i; 1163 1164 /* We don't have screen maps, so return a handcrafted one. */ 1165 for (i = 0; i < 256; i++) 1166 sm->scrmap[i] = i; 1167 return (0); 1168 } 1169 case KDGETLED: 1170 /* XXX */ 1171 return (0); 1172 case KDSETLED: 1173 /* XXX */ 1174 return (0); 1175 case KDSETMODE: 1176 /* XXX */ 1177 return (0); 1178 case KDSETRAD: 1179 /* XXX */ 1180 return (0); 1181 case VT_ACTIVATE: { 1182 int win; 1183 win = *(int *)data - 1; 1184 DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, VT_UNIT(vw), win); 1185 if ((win > VT_MAXWINDOWS) || (win < 0)) 1186 return (EINVAL); 1187 return (vt_proc_window_switch(vd->vd_windows[win])); 1188 } 1189 case VT_GETACTIVE: 1190 *(int *)data = vd->vd_curwindow->vw_number + 1; 1191 return (0); 1192 case VT_GETINDEX: 1193 *(int *)data = vw->vw_number + 1; 1194 return (0); 1195 case VT_LOCKSWITCH: 1196 /* TODO: Check current state, switching can be in progress. */ 1197 if ((*(int *)data) & 0x01) 1198 vw->vw_flags |= VWF_VTYLOCK; 1199 else 1200 vw->vw_flags &= ~VWF_VTYLOCK; 1201 case VT_OPENQRY: { 1202 unsigned int i; 1203 1204 VT_LOCK(vd); 1205 for (i = 0; i < VT_MAXWINDOWS; i++) { 1206 vw = vd->vd_windows[i]; 1207 if (vw == NULL) 1208 continue; 1209 if (!(vw->vw_flags & VWF_OPENED)) { 1210 *(int *)data = vw->vw_number + 1; 1211 VT_UNLOCK(vd); 1212 return (0); 1213 } 1214 } 1215 VT_UNLOCK(vd); 1216 return (EINVAL); 1217 } 1218 case VT_WAITACTIVE: { 1219 unsigned int i; 1220 error = 0; 1221 1222 i = *(unsigned int *)data; 1223 if (i > VT_MAXWINDOWS) 1224 return (EINVAL); 1225 if (i != 0) 1226 vw = vd->vd_windows[i - 1]; 1227 1228 VT_LOCK(vd); 1229 while (vd->vd_curwindow != vw && error == 0) 1230 error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 1231 VT_UNLOCK(vd); 1232 return (error); 1233 } 1234 case VT_SETMODE: /* set screen switcher mode */ 1235 { 1236 struct vt_mode *mode; 1237 struct proc *p1; 1238 1239 mode = (struct vt_mode *)data; 1240 DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 1241 if (vw->vw_smode.mode == VT_PROCESS) { 1242 p1 = pfind(vw->vw_pid); 1243 if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 1244 if (p1) 1245 PROC_UNLOCK(p1); 1246 DPRINTF(5, "error EPERM\n"); 1247 return (EPERM); 1248 } 1249 if (p1) 1250 PROC_UNLOCK(p1); 1251 } 1252 if (mode->mode == VT_AUTO) { 1253 vw->vw_smode.mode = VT_AUTO; 1254 vw->vw_proc = NULL; 1255 vw->vw_pid = 0; 1256 DPRINTF(5, "VT_AUTO, "); 1257 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1258 cnavailable(vw->vw_terminal->consdev, TRUE); 1259 /* were we in the middle of the vty switching process? */ 1260 if (finish_vt_rel(vw, TRUE, &s) == 0) 1261 DPRINTF(5, "reset WAIT_REL, "); 1262 if (finish_vt_acq(vw) == 0) 1263 DPRINTF(5, "reset WAIT_ACQ, "); 1264 return (0); 1265 } else if (mode->mode == VT_PROCESS) { 1266 if (!ISSIGVALID(mode->relsig) || 1267 !ISSIGVALID(mode->acqsig) || 1268 !ISSIGVALID(mode->frsig)) { 1269 DPRINTF(5, "error EINVAL\n"); 1270 return (EINVAL); 1271 } 1272 DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 1273 bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 1274 vw->vw_proc = td->td_proc; 1275 vw->vw_pid = vw->vw_proc->p_pid; 1276 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1277 cnavailable(vw->vw_terminal->consdev, FALSE); 1278 } else { 1279 DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 1280 mode->mode); 1281 return (EINVAL); 1282 } 1283 DPRINTF(5, "\n"); 1284 return 0; 1285 } 1286 1287 case VT_GETMODE: /* get screen switcher mode */ 1288 bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 1289 return 0; 1290 1291 case VT_RELDISP: /* screen switcher ioctl */ 1292 /* 1293 * This must be the current vty which is in the VT_PROCESS 1294 * switching mode... 1295 */ 1296 if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 1297 VT_PROCESS)) { 1298 return EINVAL; 1299 } 1300 /* ...and this process is controlling it. */ 1301 if (vw->vw_proc != td->td_proc) { 1302 return EPERM; 1303 } 1304 error = EINVAL; 1305 switch(*(int *)data) { 1306 case VT_FALSE: /* user refuses to release screen, abort */ 1307 if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 1308 DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", SC_DRIVER_NAME, 1309 VT_UNIT(vw)); 1310 break; 1311 case VT_TRUE: /* user has released screen, go on */ 1312 /* finish_vt_rel(..., TRUE, ...) should not be locked */ 1313 if (vw->vw_flags & VWF_SWWAIT_REL) { 1314 if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 1315 DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 1316 SC_DRIVER_NAME, VT_UNIT(vw)); 1317 } else { 1318 error = EINVAL; 1319 } 1320 return (error); 1321 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1322 if ((error = finish_vt_acq(vw)) == 0) 1323 DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", SC_DRIVER_NAME, 1324 VT_UNIT(vw)); 1325 break; 1326 default: 1327 break; 1328 } 1329 return error; 1330 } 1331 1332 return (ENOIOCTL); 1333} 1334 1335static struct vt_window * 1336vt_allocate_window(struct vt_device *vd, unsigned int window) 1337{ 1338 struct vt_window *vw; 1339 struct terminal *tm; 1340 term_pos_t size; 1341 struct winsize wsz; 1342 1343 vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 1344 vw->vw_device = vd; 1345 vw->vw_number = window; 1346 vw->vw_kbdmode = K_XLATE; 1347 1348 if (!(vd->vd_flags & VDF_TEXTMODE)) 1349 vw->vw_font = vtfont_ref(&vt_font_default); 1350 1351 vt_termsize(vd, vw->vw_font, &size); 1352 vt_winsize(vd, vw->vw_font, &wsz); 1353 vtbuf_init(&vw->vw_buf, &size); 1354 1355 tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 1356 terminal_set_winsize(tm, &wsz); 1357 vd->vd_windows[window] = vw; 1358 callout_init(&vw->vw_proc_dead_timer, 0); 1359 1360 return (vw); 1361} 1362 1363void 1364vt_upgrade(struct vt_device *vd) 1365{ 1366 struct vt_window *vw; 1367 unsigned int i; 1368 1369 /* Device didn't pass vd_init() or already upgraded. */ 1370 if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD)) 1371 return; 1372 vd->vd_flags |= VDF_ASYNC; 1373 1374 mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF); 1375 cv_init(&vd->vd_winswitch, "vtwswt"); 1376 1377 /* Init 25 Hz timer. */ 1378 callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 1379 1380 for (i = 0; i < VT_MAXWINDOWS; i++) { 1381 vw = vd->vd_windows[i]; 1382 if (vw == NULL) { 1383 /* New window. */ 1384 vw = vt_allocate_window(vd, i); 1385 } 1386 if (i == VT_CONSWINDOW) { 1387 /* Console window. */ 1388 EVENTHANDLER_REGISTER(shutdown_pre_sync, 1389 vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 1390 } 1391 terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 1392 } 1393 if (vd->vd_curwindow == NULL) 1394 vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 1395 1396 /* Attach keyboard. */ 1397 vt_allocate_keyboard(vd); 1398 DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 1399 1400 /* Start timer when everything ready. */ 1401 callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 1402} 1403 1404static void 1405vt_resize(struct vt_device *vd) 1406{ 1407 struct vt_window *vw; 1408 int i; 1409 1410 for (i = 0; i < VT_MAXWINDOWS; i++) { 1411 vw = vd->vd_windows[i]; 1412 /* Resize terminal windows */ 1413 vt_change_font(vw, vw->vw_font); 1414 } 1415} 1416 1417void 1418vt_allocate(struct vt_driver *drv, void *softc) 1419{ 1420 struct vt_device *vd; 1421 struct winsize wsz; 1422 1423 if (main_vd == NULL) { 1424 main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO); 1425 printf("%s: VT initialize with new VT driver.\n", __func__); 1426 } else { 1427 /* 1428 * Check if have rights to replace current driver. For example: 1429 * it is bad idea to replace KMS driver with generic VGA one. 1430 */ 1431 if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 1432 printf("%s: Driver priority %d too low. Current %d\n ", 1433 __func__, drv->vd_priority, 1434 main_vd->vd_driver->vd_priority); 1435 return; 1436 } 1437 printf("%s: Replace existing VT driver.\n", __func__); 1438 } 1439 vd = main_vd; 1440 1441 /* Stop vt_flush periodic task. */ 1442 if (vd->vd_curwindow != NULL) 1443 callout_drain(&vd->vd_timer); 1444 1445 vd->vd_driver = drv; 1446 vd->vd_softc = softc; 1447 vd->vd_driver->vd_init(vd); 1448 1449 vt_upgrade(vd); 1450 1451 /* Refill settings with new sizes. */ 1452 vt_resize(vd); 1453 1454 if (vd->vd_flags & VDF_SPLASH) 1455 vtterm_splash(vd); 1456 1457 if (vd->vd_curwindow != NULL) 1458 callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 1459 1460 termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 1461 1462 /* Update console window sizes to actual. */ 1463 vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz); 1464 terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz); 1465} 1466