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