1 /*- 2 * (MPSAFE) 3 * 4 * Copyright (c) 1998 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The DragonFly Project 8 * by Sascha Wildner <saw@online.de>. 9 * 10 * Simple font scaling code by Sascha Wildner and Matthew Dillon 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer as 17 * the first lines of this file unmodified. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD: src/sys/dev/syscons/scvidctl.c,v 1.19.2.2 2000/05/05 09:16:08 nyan Exp $ 34 */ 35 36 #include "opt_syscons.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/conf.h> 41 #include <sys/signalvar.h> 42 #include <sys/tty.h> 43 #include <sys/kernel.h> 44 #include <sys/thread2.h> 45 46 #include <machine/console.h> 47 #include <machine/framebuffer.h> 48 49 #include <dev/video/fb/fbreg.h> 50 #include "syscons.h" 51 52 SET_DECLARE(scrndr_set, const sc_renderer_t); 53 54 int 55 sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, 56 int fontsize) 57 { 58 video_info_t info; 59 u_char *font; 60 int prev_ysize; 61 int new_ysize; 62 int error; 63 64 lwkt_gettoken(&tty_token); 65 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info)) { 66 lwkt_reltoken(&tty_token); 67 return ENODEV; 68 } 69 lwkt_reltoken(&tty_token); 70 71 /* adjust argument values */ 72 if (fontsize <= 0) 73 fontsize = info.vi_cheight; 74 if (fontsize < 14) { 75 fontsize = 8; 76 #ifndef SC_NO_FONT_LOADING 77 if (!(scp->sc->fonts_loaded & FONT_8)) 78 return EINVAL; 79 font = scp->sc->font_8; 80 #else 81 font = NULL; 82 #endif 83 } else if (fontsize >= 16) { 84 fontsize = 16; 85 #ifndef SC_NO_FONT_LOADING 86 if (!(scp->sc->fonts_loaded & FONT_16)) 87 return EINVAL; 88 font = scp->sc->font_16; 89 #else 90 font = NULL; 91 #endif 92 } else { 93 fontsize = 14; 94 #ifndef SC_NO_FONT_LOADING 95 if (!(scp->sc->fonts_loaded & FONT_14)) 96 return EINVAL; 97 font = scp->sc->font_14; 98 #else 99 font = NULL; 100 #endif 101 } 102 if ((xsize <= 0) || (xsize > info.vi_width)) 103 xsize = info.vi_width; 104 if ((ysize <= 0) || (ysize > info.vi_height)) 105 ysize = info.vi_height; 106 107 /* stop screen saver, etc */ 108 crit_enter(); 109 if ((error = sc_clean_up(scp, FALSE))) { 110 crit_exit(); 111 return error; 112 } 113 114 if (scp->sc->fbi != NULL && 115 sc_render_match(scp, "kms", V_INFO_MM_TEXT) == NULL) { 116 crit_exit(); 117 return ENODEV; 118 } 119 if (scp->sc->fbi == NULL && 120 sc_render_match(scp, scp->sc->adp->va_name, V_INFO_MM_TEXT) == NULL) { 121 crit_exit(); 122 return ENODEV; 123 } 124 125 /* set up scp */ 126 new_ysize = 0; 127 #ifndef SC_NO_HISTORY 128 if (scp->history != NULL) { 129 sc_hist_save(scp); 130 new_ysize = sc_vtb_rows(scp->history); 131 } 132 #endif 133 prev_ysize = scp->ysize; 134 /* 135 * This is a kludge to fend off scrn_update() while we 136 * muck around with scp. XXX 137 */ 138 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 139 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE); 140 scp->mode = mode; 141 scp->model = V_INFO_MM_TEXT; 142 scp->xsize = xsize; 143 scp->ysize = ysize; 144 scp->xoff = 0; 145 scp->yoff = 0; 146 scp->xpixel = scp->xsize*8; 147 scp->ypixel = scp->ysize*fontsize; 148 scp->font = font; 149 scp->font_height = fontsize; 150 scp->font_width = 8; 151 152 /* allocate buffers */ 153 sc_alloc_scr_buffer(scp, TRUE, TRUE); 154 sc_init_emulator(scp, NULL); 155 #ifndef SC_NO_CUTPASTE 156 sc_alloc_cut_buffer(scp, FALSE); 157 #endif 158 #ifndef SC_NO_HISTORY 159 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 160 #endif 161 crit_exit(); 162 163 if (scp == scp->sc->cur_scp) 164 set_mode(scp); 165 scp->status &= ~UNKNOWN_MODE; 166 167 if (tp == NULL) 168 return 0; 169 DPRINTF(5, ("ws_*size (%d,%d), size (%d,%d)\n", 170 tp->t_winsize.ws_col, tp->t_winsize.ws_row, scp->xsize, scp->ysize)); 171 if (tp->t_winsize.ws_col != scp->xsize 172 || tp->t_winsize.ws_row != scp->ysize) { 173 tp->t_winsize.ws_col = scp->xsize; 174 tp->t_winsize.ws_row = scp->ysize; 175 pgsignal(tp->t_pgrp, SIGWINCH, 1); 176 } 177 178 return 0; 179 } 180 181 int 182 sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode) 183 { 184 #ifdef SC_NO_MODE_CHANGE 185 return ENODEV; 186 #else 187 video_info_t info; 188 int error; 189 190 lwkt_gettoken(&tty_token); 191 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info)) { 192 lwkt_reltoken(&tty_token); 193 return ENODEV; 194 } 195 lwkt_reltoken(&tty_token); 196 197 /* stop screen saver, etc */ 198 crit_enter(); 199 if ((error = sc_clean_up(scp, FALSE))) { 200 crit_exit(); 201 return error; 202 } 203 204 if (scp->sc->fbi != NULL && 205 sc_render_match(scp, "kms", V_INFO_MM_OTHER) == NULL) { 206 crit_exit(); 207 return ENODEV; 208 } 209 if (scp->sc->fbi == NULL && 210 sc_render_match(scp, scp->sc->adp->va_name, V_INFO_MM_OTHER) == NULL) { 211 crit_exit(); 212 return ENODEV; 213 } 214 215 /* set up scp */ 216 scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE | MOUSE_HIDDEN); 217 scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE); 218 scp->mode = mode; 219 scp->model = V_INFO_MM_OTHER; 220 /* 221 * Don't change xsize and ysize; preserve the previous vty 222 * and history buffers. 223 */ 224 scp->xoff = 0; 225 scp->yoff = 0; 226 scp->xpixel = info.vi_width; 227 scp->ypixel = info.vi_height; 228 scp->font = NULL; 229 scp->font_height = 0; 230 scp->font_width = 0; 231 #ifndef SC_NO_SYSMOUSE 232 /* move the mouse cursor at the center of the screen */ 233 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2); 234 #endif 235 sc_init_emulator(scp, NULL); 236 crit_exit(); 237 238 if (scp == scp->sc->cur_scp) 239 set_mode(scp); 240 /* clear_graphics();*/ 241 refresh_ega_palette(scp); 242 scp->status &= ~UNKNOWN_MODE; 243 244 if (tp == NULL) 245 return 0; 246 if (tp->t_winsize.ws_xpixel != scp->xpixel 247 || tp->t_winsize.ws_ypixel != scp->ypixel) { 248 tp->t_winsize.ws_xpixel = scp->xpixel; 249 tp->t_winsize.ws_ypixel = scp->ypixel; 250 pgsignal(tp->t_pgrp, SIGWINCH, 1); 251 } 252 253 return 0; 254 #endif /* SC_NO_MODE_CHANGE */ 255 } 256 257 int 258 sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, 259 int fontsize) 260 { 261 #ifndef SC_PIXEL_MODE 262 return ENODEV; 263 #else 264 video_info_t info; 265 u_char *font; 266 int prev_ysize; 267 int new_ysize; 268 int error; 269 270 lwkt_gettoken(&tty_token); 271 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info)) { 272 lwkt_reltoken(&tty_token); 273 return ENODEV; /* this shouldn't happen */ 274 } 275 lwkt_reltoken(&tty_token); 276 277 /* adjust argument values */ 278 if (fontsize <= 0) 279 fontsize = info.vi_cheight; 280 if (fontsize < 14) { 281 fontsize = 8; 282 #ifndef SC_NO_FONT_LOADING 283 if (!(scp->sc->fonts_loaded & FONT_8)) 284 return EINVAL; 285 font = scp->sc->font_8; 286 #else 287 font = NULL; 288 #endif 289 } else if (fontsize >= 16) { 290 fontsize = 16; 291 #ifndef SC_NO_FONT_LOADING 292 if (!(scp->sc->fonts_loaded & FONT_16)) 293 return EINVAL; 294 font = scp->sc->font_16; 295 #else 296 font = NULL; 297 #endif 298 } else { 299 fontsize = 14; 300 #ifndef SC_NO_FONT_LOADING 301 if (!(scp->sc->fonts_loaded & FONT_14)) 302 return EINVAL; 303 font = scp->sc->font_14; 304 #else 305 font = NULL; 306 #endif 307 } 308 if (xsize <= 0) 309 xsize = info.vi_width/8; 310 if (ysize <= 0) 311 ysize = info.vi_height/fontsize; 312 313 if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize)) 314 return EINVAL; 315 316 /* 317 * We currently support the following graphic modes: 318 * 319 * - 4 bpp planar modes whose memory size does not exceed 64K 320 * - 8 bbp packed pixel modes 321 * - 15, 16, 24 and 32 bpp direct modes with linear frame buffer 322 */ 323 324 if (info.vi_mem_model == V_INFO_MM_PLANAR) { 325 if (info.vi_planes != 4) 326 return ENODEV; 327 328 /* 329 * A memory size >64K requires bank switching to access the entire 330 * screen. XXX 331 */ 332 333 if (info.vi_width * info.vi_height / 8 > info.vi_window_size) 334 return ENODEV; 335 } else if (info.vi_mem_model == V_INFO_MM_PACKED) { 336 if (info.vi_depth != 8) 337 return ENODEV; 338 } else if (info.vi_mem_model == V_INFO_MM_DIRECT) { 339 if (!(info.vi_flags & V_INFO_LINEAR) && 340 (info.vi_depth != 15) && (info.vi_depth != 16) && 341 (info.vi_depth != 24) && (info.vi_depth != 32)) 342 return ENODEV; 343 } else 344 return ENODEV; 345 346 /* stop screen saver, etc */ 347 crit_enter(); 348 if ((error = sc_clean_up(scp, FALSE))) { 349 crit_exit(); 350 return error; 351 } 352 353 if (sc_render_match(scp, scp->sc->adp->va_name, info.vi_mem_model) == NULL) { 354 crit_exit(); 355 return ENODEV; 356 } 357 358 #if 0 359 if (scp->tsw) 360 (*scp->tsw->te_term)(scp, scp->ts); 361 scp->tsw = NULL; 362 scp->ts = NULL; 363 #endif 364 365 /* set up scp */ 366 new_ysize = 0; 367 #ifndef SC_NO_HISTORY 368 if (scp->history != NULL) { 369 sc_hist_save(scp); 370 new_ysize = sc_vtb_rows(scp->history); 371 } 372 #endif 373 prev_ysize = scp->ysize; 374 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 375 scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE); 376 scp->model = info.vi_mem_model; 377 scp->xsize = xsize; 378 scp->ysize = ysize; 379 scp->xoff = (scp->xpixel/8 - xsize)/2; 380 scp->yoff = (scp->ypixel/fontsize - ysize)/2; 381 scp->font = font; 382 scp->font_height = fontsize; 383 scp->font_width = 8; 384 385 /* allocate buffers */ 386 sc_alloc_scr_buffer(scp, TRUE, TRUE); 387 sc_init_emulator(scp, NULL); 388 #ifndef SC_NO_CUTPASTE 389 sc_alloc_cut_buffer(scp, FALSE); 390 #endif 391 #ifndef SC_NO_HISTORY 392 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 393 #endif 394 crit_exit(); 395 396 if (scp == scp->sc->cur_scp) { 397 sc_set_border(scp, scp->border); 398 sc_set_cursor_image(scp); 399 } 400 401 scp->status &= ~UNKNOWN_MODE; 402 403 if (tp == NULL) 404 return 0; 405 if (tp->t_winsize.ws_col != scp->xsize 406 || tp->t_winsize.ws_row != scp->ysize) { 407 tp->t_winsize.ws_col = scp->xsize; 408 tp->t_winsize.ws_row = scp->ysize; 409 pgsignal(tp->t_pgrp, SIGWINCH, 1); 410 } 411 412 return 0; 413 #endif /* SC_PIXEL_MODE */ 414 } 415 416 #define fb_ioctl(a, c, d) \ 417 (((a) == NULL) ? ENODEV : \ 418 (*vidsw[(a)->va_index]->ioctl)((a), (c), (caddr_t)(d))) 419 420 int 421 sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) 422 { 423 scr_stat *scp; 424 video_adapter_t *adp; 425 #ifndef SC_NO_MODE_CHANGE 426 video_info_t info; 427 #endif 428 int error, ret; 429 430 KKASSERT(tp->t_dev); 431 432 scp = SC_STAT(tp->t_dev); 433 if (scp == NULL) /* tp == SC_MOUSE */ 434 return ENOIOCTL; 435 adp = scp->sc->adp; 436 if (adp == NULL && scp->sc->fbi == NULL) /* shouldn't happen??? */ 437 return ENODEV; 438 439 lwkt_gettoken(&tty_token); 440 switch (cmd) { 441 442 case CONS_CURRENTADP: /* get current adapter index */ 443 case FBIO_ADAPTER: 444 if (scp->sc->fbi != NULL) { 445 ret = ENODEV; 446 } else { 447 ret = fb_ioctl(adp, FBIO_ADAPTER, data); 448 } 449 lwkt_reltoken(&tty_token); 450 return ret; 451 452 case CONS_CURRENT: /* get current adapter type */ 453 case FBIO_ADPTYPE: 454 if (scp->sc->fbi != NULL) { 455 ret = ENODEV; 456 } else { 457 ret = fb_ioctl(adp, FBIO_ADPTYPE, data); 458 } 459 lwkt_reltoken(&tty_token); 460 return ret; 461 462 case CONS_ADPINFO: /* adapter information */ 463 case FBIO_ADPINFO: 464 if (scp->sc->fbi != NULL) { 465 lwkt_reltoken(&tty_token); 466 return ENODEV; 467 } 468 if (((video_adapter_info_t *)data)->va_index >= 0) { 469 adp = vid_get_adapter(((video_adapter_info_t *)data)->va_index); 470 if (adp == NULL) { 471 lwkt_reltoken(&tty_token); 472 return ENODEV; 473 } 474 } 475 ret = fb_ioctl(adp, FBIO_ADPINFO, data); 476 lwkt_reltoken(&tty_token); 477 return ret; 478 479 case CONS_GET: /* get current video mode */ 480 case FBIO_GETMODE: 481 *(int *)data = scp->mode; 482 lwkt_reltoken(&tty_token); 483 return 0; 484 485 #ifndef SC_NO_MODE_CHANGE 486 case CONS_SET: 487 case FBIO_SETMODE: /* set video mode */ 488 if (scp->sc->fbi != NULL) { 489 lwkt_reltoken(&tty_token); 490 if (*(int *)data != 0) 491 return ENODEV; 492 else 493 return 0; 494 } 495 if (!(adp->va_flags & V_ADP_MODECHANGE)) { 496 lwkt_reltoken(&tty_token); 497 return ENODEV; 498 } 499 info.vi_mode = *(int *)data; 500 error = fb_ioctl(adp, FBIO_MODEINFO, &info); 501 if (error) { 502 lwkt_reltoken(&tty_token); 503 return error; 504 } 505 if (info.vi_flags & V_INFO_GRAPHICS) { 506 lwkt_reltoken(&tty_token); 507 return sc_set_graphics_mode(scp, tp, *(int *)data); 508 } else { 509 lwkt_reltoken(&tty_token); 510 return sc_set_text_mode(scp, tp, *(int *)data, 0, 0, 0); 511 } 512 #endif /* SC_NO_MODE_CHANGE */ 513 514 case CONS_MODEINFO: /* get mode information */ 515 case FBIO_MODEINFO: 516 if (scp->sc->fbi != NULL) { 517 /* Fabricate some mode information for KMS framebuffer */ 518 video_info_t *vinfo = (video_info_t *)data; 519 vinfo->vi_mode = 0; 520 vinfo->vi_flags = V_INFO_COLOR; 521 vinfo->vi_width = scp->xsize; 522 vinfo->vi_height = scp->ysize; 523 vinfo->vi_cwidth = scp->font_width; 524 vinfo->vi_cheight = scp->font_height; 525 vinfo->vi_window = 0; 526 vinfo->vi_window_size = 0; 527 vinfo->vi_buffer = 0; 528 vinfo->vi_buffer_size = 0; 529 vinfo->vi_mem_model = V_INFO_MM_TEXT; 530 ret = 0; 531 } else { 532 ret = fb_ioctl(adp, FBIO_MODEINFO, data); 533 } 534 lwkt_reltoken(&tty_token); 535 return ret; 536 537 case CONS_FINDMODE: /* find a matching video mode */ 538 case FBIO_FINDMODE: 539 if (scp->sc->fbi != NULL) { 540 ret = ENODEV; 541 } else { 542 ret = fb_ioctl(adp, FBIO_FINDMODE, data); 543 } 544 lwkt_reltoken(&tty_token); 545 return ret; 546 547 case CONS_SETWINORG: /* set frame buffer window origin */ 548 case FBIO_SETWINORG: 549 if (scp != scp->sc->cur_scp) { 550 lwkt_reltoken(&tty_token); 551 return ENODEV; /* XXX */ 552 } 553 if (scp->sc->fbi != NULL) { 554 lwkt_reltoken(&tty_token); 555 return ENODEV; 556 } 557 ret = fb_ioctl(adp, FBIO_SETWINORG, data); 558 lwkt_reltoken(&tty_token); 559 return ret; 560 561 case FBIO_GETWINORG: /* get frame buffer window origin */ 562 if (scp != scp->sc->cur_scp) { 563 lwkt_reltoken(&tty_token); 564 return ENODEV; /* XXX */ 565 } 566 if (scp->sc->fbi != NULL) { 567 ret = ENODEV; 568 } else { 569 ret = fb_ioctl(adp, FBIO_GETWINORG, data); 570 } 571 lwkt_reltoken(&tty_token); 572 return ret; 573 574 case FBIO_GETDISPSTART: 575 case FBIO_SETDISPSTART: 576 case FBIO_GETLINEWIDTH: 577 case FBIO_SETLINEWIDTH: 578 if (scp != scp->sc->cur_scp) { 579 lwkt_reltoken(&tty_token); 580 return ENODEV; /* XXX */ 581 } 582 if (scp->sc->fbi != NULL) { 583 if (cmd == FBIO_GETLINEWIDTH) { 584 *(u_int *)data = scp->sc->fbi->stride; 585 ret = 0; 586 } else { 587 ret = ENODEV; 588 } 589 } else { 590 ret = fb_ioctl(adp, cmd, data); 591 } 592 lwkt_reltoken(&tty_token); 593 return ret; 594 595 case FBIO_GETPALETTE: 596 case FBIO_SETPALETTE: 597 case FBIOPUTCMAP: 598 case FBIOGETCMAP: 599 case FBIOGTYPE: 600 case FBIOGATTR: 601 case FBIOSVIDEO: 602 case FBIOGVIDEO: 603 case FBIOSCURSOR: 604 case FBIOGCURSOR: 605 case FBIOSCURPOS: 606 case FBIOGCURPOS: 607 case FBIOGCURMAX: 608 if (scp != scp->sc->cur_scp) { 609 lwkt_reltoken(&tty_token); 610 return ENODEV; /* XXX */ 611 } 612 if (scp->sc->fbi != NULL) { 613 if (cmd == FBIOGTYPE) { 614 ((struct fbtype *)data)->fb_type = FBTYPE_DUMBFB; 615 ((struct fbtype *)data)->fb_height = scp->sc->fbi->height; 616 ((struct fbtype *)data)->fb_width = scp->sc->fbi->width; 617 ((struct fbtype *)data)->fb_depth = scp->sc->fbi->depth; 618 ((struct fbtype *)data)->fb_cmsize = 0; 619 ((struct fbtype *)data)->fb_size = 620 scp->sc->fbi->height * scp->sc->fbi->stride; 621 ret = 0; 622 } else { 623 ret = ENODEV; 624 } 625 } else { 626 ret = fb_ioctl(adp, cmd, data); 627 } 628 lwkt_reltoken(&tty_token); 629 return ret; 630 631 case KDSETMODE: /* set current mode of this (virtual) console */ 632 switch (*(int *)data) { 633 case KD_TEXT: /* switch to TEXT (known) mode */ 634 /* 635 * If scp->mode is of graphics modes, we don't know which 636 * text mode to switch back to... 637 */ 638 if (scp->status & GRAPHICS_MODE) { 639 lwkt_reltoken(&tty_token); 640 return EINVAL; 641 } 642 /* restore fonts & palette ! */ 643 #if 0 644 #ifndef SC_NO_FONT_LOADING 645 if (scp->sc->fbi == NULL && ISFONTAVAIL(adp->va_flags) 646 && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) { 647 /* 648 * FONT KLUDGE 649 * Don't load fonts for now... XXX 650 */ 651 if (scp->sc->fonts_loaded & FONT_8) 652 sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256); 653 if (scp->sc->fonts_loaded & FONT_14) 654 sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256); 655 if (scp->sc->fonts_loaded & FONT_16) 656 sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256); 657 } 658 #endif /* SC_NO_FONT_LOADING */ 659 #endif 660 661 #ifndef SC_NO_PALETTE_LOADING 662 if (scp->sc->fbi == NULL) 663 load_palette(adp, scp->sc->palette); 664 #endif 665 666 /* move hardware cursor out of the way */ 667 if (scp->sc->fbi == NULL) 668 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 669 /* FALL THROUGH */ 670 671 case KD_TEXT1: /* switch to TEXT (known) mode */ 672 /* 673 * If scp->mode is of graphics modes, we don't know which 674 * text/pixel mode to switch back to... 675 */ 676 if (scp->status & GRAPHICS_MODE) { 677 lwkt_reltoken(&tty_token); 678 return EINVAL; 679 } 680 crit_enter(); 681 if ((error = sc_clean_up(scp, FALSE))) { 682 crit_exit(); 683 lwkt_reltoken(&tty_token); 684 return error; 685 } 686 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 687 crit_exit(); 688 /* no restore fonts & palette */ 689 if (scp == scp->sc->cur_scp) 690 set_mode(scp); 691 sc_clear_screen(scp); 692 scp->status &= ~UNKNOWN_MODE; 693 lwkt_reltoken(&tty_token); 694 return 0; 695 696 #ifdef SC_PIXEL_MODE 697 case KD_PIXEL: /* pixel (raster) display */ 698 if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) { 699 lwkt_reltoken(&tty_token); 700 return EINVAL; 701 } 702 if (scp->sc->fbi != NULL) { 703 lwkt_reltoken(&tty_token); 704 return ENODEV; 705 } 706 if (scp->status & GRAPHICS_MODE) { 707 lwkt_reltoken(&tty_token); 708 return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, 709 scp->font_height); 710 } 711 crit_enter(); 712 if ((error = sc_clean_up(scp, FALSE))) { 713 crit_exit(); 714 lwkt_reltoken(&tty_token); 715 return error; 716 } 717 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 718 crit_exit(); 719 if (scp == scp->sc->cur_scp) { 720 set_mode(scp); 721 #ifndef SC_NO_PALETTE_LOADING 722 load_palette(adp, scp->sc->palette); 723 #endif 724 } 725 sc_clear_screen(scp); 726 scp->status &= ~UNKNOWN_MODE; 727 lwkt_reltoken(&tty_token); 728 return 0; 729 #endif /* SC_PIXEL_MODE */ 730 731 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 732 crit_enter(); 733 if ((error = sc_clean_up(scp, FALSE))) { 734 crit_exit(); 735 lwkt_reltoken(&tty_token); 736 return error; 737 } 738 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 739 crit_exit(); 740 lwkt_reltoken(&tty_token); 741 return 0; 742 743 default: 744 lwkt_reltoken(&tty_token); 745 return EINVAL; 746 } 747 /* NOT REACHED */ 748 749 #ifdef SC_PIXEL_MODE 750 case KDRASTER: /* set pixel (raster) display mode */ 751 if (scp->sc->fbi != NULL || ISUNKNOWNSC(scp) || ISTEXTSC(scp)) { 752 lwkt_reltoken(&tty_token); 753 return ENODEV; 754 } 755 lwkt_reltoken(&tty_token); 756 return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], 757 ((int *)data)[2]); 758 #endif /* SC_PIXEL_MODE */ 759 760 case KDGETMODE: /* get current mode of this (virtual) console */ 761 /* 762 * From the user program's point of view, KD_PIXEL is the same 763 * as KD_TEXT... 764 */ 765 *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT; 766 lwkt_reltoken(&tty_token); 767 return 0; 768 769 case KDSBORDER: /* set border color of this (virtual) console */ 770 /* Only values in the range [0..15] allowed */ 771 if (*(int *)data < 0 || *(int *)data > 15) { 772 lwkt_reltoken(&tty_token); 773 return EINVAL; 774 } 775 scp->border = *(int *)data; 776 if (scp == scp->sc->cur_scp) 777 sc_set_border(scp, scp->border); 778 lwkt_reltoken(&tty_token); 779 return 0; 780 } 781 782 lwkt_reltoken(&tty_token); 783 return ENOIOCTL; 784 } 785 786 static LIST_HEAD(, sc_renderer) sc_rndr_list = 787 LIST_HEAD_INITIALIZER(sc_rndr_list); 788 789 int 790 sc_render_add(sc_renderer_t *rndr) 791 { 792 LIST_INSERT_HEAD(&sc_rndr_list, rndr, link); 793 return 0; 794 } 795 796 int 797 sc_render_remove(sc_renderer_t *rndr) 798 { 799 /* 800 LIST_REMOVE(rndr, link); 801 */ 802 return EBUSY; /* XXX */ 803 } 804 805 sc_rndr_sw_t * 806 sc_render_match(scr_stat *scp, char *name, int model) 807 { 808 const sc_renderer_t **list; 809 const sc_renderer_t *p; 810 811 if (!LIST_EMPTY(&sc_rndr_list)) { 812 LIST_FOREACH(p, &sc_rndr_list, link) { 813 if ((strcmp(p->name, name) == 0) && 814 (model == p->model)) { 815 scp->status &= 816 ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 817 return p->rndrsw; 818 } 819 } 820 } else { 821 SET_FOREACH(list, scrndr_set) { 822 p = *list; 823 if ((strcmp(p->name, name) == 0) && 824 (model == p->model)) { 825 scp->status &= 826 ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 827 return p->rndrsw; 828 } 829 } 830 } 831 832 return NULL; 833 } 834 835 #define VIRTUAL_TTY(sc, x) ((SC_DEV((sc),(x)) != NULL) ? \ 836 (SC_DEV((sc),(x))->si_tty) : NULL) 837 838 void 839 sc_update_render(scr_stat *scp) 840 { 841 sc_rndr_sw_t *rndr; 842 sc_term_sw_t *sw; 843 struct tty *tp; 844 int prev_ysize, new_ysize; 845 #ifndef SC_NO_HISTORY 846 int old_xpos, old_ypos; 847 #endif 848 int error; 849 850 sw = scp->tsw; 851 if (sw == NULL) { 852 return; 853 } 854 855 if (scp->rndr == NULL) 856 return; 857 858 if (scp->fbi_generation == scp->sc->fbi_generation) 859 return; 860 861 crit_enter(); 862 scp->fbi_generation = scp->sc->fbi_generation; 863 /* Needed in case we are implicitly leaving PIXEL_MODE here */ 864 if (scp->model != V_INFO_MM_OTHER) 865 scp->model = V_INFO_MM_TEXT; 866 rndr = NULL; 867 if (strcmp(sw->te_renderer, "*") != 0) { 868 rndr = sc_render_match(scp, sw->te_renderer, scp->model); 869 } 870 if (rndr == NULL && scp->sc->fbi != NULL) { 871 rndr = sc_render_match(scp, "kms", scp->model); 872 } 873 if (rndr == NULL) { /* this shouldn't happen */ 874 rndr = sc_render_match(scp, scp->sc->adp->va_name, scp->model); 875 if (rndr != NULL) 876 scp->rndr = rndr; 877 crit_exit(); 878 return; 879 } 880 881 scp->rndr = rndr; 882 /* Mostly copied from sc_set_text_mode */ 883 if ((error = sc_clean_up(scp, FALSE))) { 884 crit_exit(); 885 return; 886 } 887 new_ysize = 0; 888 #ifndef SC_NO_HISTORY 889 old_xpos = old_ypos = 0; 890 if (scp->history != NULL) { 891 if (scp->xsize > 0) { 892 old_xpos = scp->xpos; 893 old_ypos = scp->ypos; 894 } 895 sc_hist_save(scp); 896 new_ysize = sc_vtb_rows(scp->history); 897 } 898 #endif 899 prev_ysize = scp->ysize; 900 scp->status |= MOUSE_HIDDEN; 901 if (scp->status & GRAPHICS_MODE) { 902 /* 903 * We don't handle GRAPHICS_MODE at all when using a KMS 904 * framebuffer, so silently switch to UNKNOWN_MODE then. 905 */ 906 scp->status |= UNKNOWN_MODE; 907 scp->status &= ~GRAPHICS_MODE; 908 } 909 /* Implicitly leave PIXEL_MODE, but stay in UNKNOWN mode */ 910 scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE); 911 scp->xpixel = scp->sc->fbi->width; 912 scp->ypixel = scp->sc->fbi->height; 913 914 /* 915 * Assume square pixels for now 916 */ 917 sc_font_scale(scp, 0, 0); 918 919 DPRINTF(1, ("kms console: scale-to %dx%d cols=%d rows=%d\n", 920 scp->blk_width, scp->blk_height, scp->xsize, scp->ysize)); 921 922 /* allocate buffers */ 923 sc_alloc_scr_buffer(scp, TRUE, TRUE); 924 sc_init_emulator(scp, NULL); 925 #ifndef SC_NO_CUTPASTE 926 sc_alloc_cut_buffer(scp, FALSE); 927 #endif 928 #ifndef SC_NO_HISTORY 929 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 930 if (scp->history != NULL) { 931 sc_hist_getback(scp, prev_ysize); 932 sc_move_cursor(scp, old_xpos, old_ypos); 933 } 934 #endif 935 crit_exit(); 936 tp = VIRTUAL_TTY(scp->sc, scp->index); 937 if (tp == NULL) 938 return; 939 if (tp->t_winsize.ws_col != scp->xsize || 940 tp->t_winsize.ws_row != scp->ysize) { 941 tp->t_winsize.ws_col = scp->xsize; 942 tp->t_winsize.ws_row = scp->ysize; 943 pgsignal(tp->t_pgrp, SIGWINCH, 1); 944 } 945 } 946