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 ret = ENODEV; 584 } else { 585 ret = fb_ioctl(adp, cmd, data); 586 } 587 lwkt_reltoken(&tty_token); 588 return ret; 589 590 case FBIO_GETPALETTE: 591 case FBIO_SETPALETTE: 592 case FBIOPUTCMAP: 593 case FBIOGETCMAP: 594 case FBIOGTYPE: 595 case FBIOGATTR: 596 case FBIOSVIDEO: 597 case FBIOGVIDEO: 598 case FBIOSCURSOR: 599 case FBIOGCURSOR: 600 case FBIOSCURPOS: 601 case FBIOGCURPOS: 602 case FBIOGCURMAX: 603 if (scp != scp->sc->cur_scp) { 604 lwkt_reltoken(&tty_token); 605 return ENODEV; /* XXX */ 606 } 607 if (scp->sc->fbi != NULL) { 608 ret = ENODEV; 609 } else { 610 ret = fb_ioctl(adp, cmd, data); 611 } 612 lwkt_reltoken(&tty_token); 613 return ret; 614 615 case KDSETMODE: /* set current mode of this (virtual) console */ 616 switch (*(int *)data) { 617 case KD_TEXT: /* switch to TEXT (known) mode */ 618 /* 619 * If scp->mode is of graphics modes, we don't know which 620 * text mode to switch back to... 621 */ 622 if (scp->status & GRAPHICS_MODE) { 623 lwkt_reltoken(&tty_token); 624 return EINVAL; 625 } 626 /* restore fonts & palette ! */ 627 #if 0 628 #ifndef SC_NO_FONT_LOADING 629 if (scp->sc->fbi == NULL && ISFONTAVAIL(adp->va_flags) 630 && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) { 631 /* 632 * FONT KLUDGE 633 * Don't load fonts for now... XXX 634 */ 635 if (scp->sc->fonts_loaded & FONT_8) 636 sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256); 637 if (scp->sc->fonts_loaded & FONT_14) 638 sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256); 639 if (scp->sc->fonts_loaded & FONT_16) 640 sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256); 641 } 642 #endif /* SC_NO_FONT_LOADING */ 643 #endif 644 645 #ifndef SC_NO_PALETTE_LOADING 646 if (scp->sc->fbi == NULL) 647 load_palette(adp, scp->sc->palette); 648 #endif 649 650 /* move hardware cursor out of the way */ 651 if (scp->sc->fbi == NULL) 652 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 653 /* FALL THROUGH */ 654 655 case KD_TEXT1: /* switch to TEXT (known) mode */ 656 /* 657 * If scp->mode is of graphics modes, we don't know which 658 * text/pixel mode to switch back to... 659 */ 660 if (scp->status & GRAPHICS_MODE) { 661 lwkt_reltoken(&tty_token); 662 return EINVAL; 663 } 664 crit_enter(); 665 if ((error = sc_clean_up(scp, FALSE))) { 666 crit_exit(); 667 lwkt_reltoken(&tty_token); 668 return error; 669 } 670 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 671 crit_exit(); 672 /* no restore fonts & palette */ 673 if (scp == scp->sc->cur_scp) 674 set_mode(scp); 675 sc_clear_screen(scp); 676 scp->status &= ~UNKNOWN_MODE; 677 lwkt_reltoken(&tty_token); 678 return 0; 679 680 #ifdef SC_PIXEL_MODE 681 case KD_PIXEL: /* pixel (raster) display */ 682 if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) { 683 lwkt_reltoken(&tty_token); 684 return EINVAL; 685 } 686 if (scp->sc->fbi != NULL) { 687 lwkt_reltoken(&tty_token); 688 return ENODEV; 689 } 690 if (scp->status & GRAPHICS_MODE) { 691 lwkt_reltoken(&tty_token); 692 return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, 693 scp->font_height); 694 } 695 crit_enter(); 696 if ((error = sc_clean_up(scp, FALSE))) { 697 crit_exit(); 698 lwkt_reltoken(&tty_token); 699 return error; 700 } 701 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 702 crit_exit(); 703 if (scp == scp->sc->cur_scp) { 704 set_mode(scp); 705 #ifndef SC_NO_PALETTE_LOADING 706 load_palette(adp, scp->sc->palette); 707 #endif 708 } 709 sc_clear_screen(scp); 710 scp->status &= ~UNKNOWN_MODE; 711 lwkt_reltoken(&tty_token); 712 return 0; 713 #endif /* SC_PIXEL_MODE */ 714 715 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 716 crit_enter(); 717 if ((error = sc_clean_up(scp, FALSE))) { 718 crit_exit(); 719 lwkt_reltoken(&tty_token); 720 return error; 721 } 722 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 723 crit_exit(); 724 lwkt_reltoken(&tty_token); 725 return 0; 726 727 default: 728 lwkt_reltoken(&tty_token); 729 return EINVAL; 730 } 731 /* NOT REACHED */ 732 733 #ifdef SC_PIXEL_MODE 734 case KDRASTER: /* set pixel (raster) display mode */ 735 if (scp->sc->fbi != NULL || ISUNKNOWNSC(scp) || ISTEXTSC(scp)) { 736 lwkt_reltoken(&tty_token); 737 return ENODEV; 738 } 739 lwkt_reltoken(&tty_token); 740 return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], 741 ((int *)data)[2]); 742 #endif /* SC_PIXEL_MODE */ 743 744 case KDGETMODE: /* get current mode of this (virtual) console */ 745 /* 746 * From the user program's point of view, KD_PIXEL is the same 747 * as KD_TEXT... 748 */ 749 *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT; 750 lwkt_reltoken(&tty_token); 751 return 0; 752 753 case KDSBORDER: /* set border color of this (virtual) console */ 754 /* Only values in the range [0..15] allowed */ 755 if (*(int *)data < 0 || *(int *)data > 15) { 756 lwkt_reltoken(&tty_token); 757 return EINVAL; 758 } 759 scp->border = *(int *)data; 760 if (scp == scp->sc->cur_scp) 761 sc_set_border(scp, scp->border); 762 lwkt_reltoken(&tty_token); 763 return 0; 764 } 765 766 lwkt_reltoken(&tty_token); 767 return ENOIOCTL; 768 } 769 770 static LIST_HEAD(, sc_renderer) sc_rndr_list = 771 LIST_HEAD_INITIALIZER(sc_rndr_list); 772 773 int 774 sc_render_add(sc_renderer_t *rndr) 775 { 776 LIST_INSERT_HEAD(&sc_rndr_list, rndr, link); 777 return 0; 778 } 779 780 int 781 sc_render_remove(sc_renderer_t *rndr) 782 { 783 /* 784 LIST_REMOVE(rndr, link); 785 */ 786 return EBUSY; /* XXX */ 787 } 788 789 sc_rndr_sw_t * 790 sc_render_match(scr_stat *scp, char *name, int model) 791 { 792 const sc_renderer_t **list; 793 const sc_renderer_t *p; 794 795 if (!LIST_EMPTY(&sc_rndr_list)) { 796 LIST_FOREACH(p, &sc_rndr_list, link) { 797 if ((strcmp(p->name, name) == 0) && 798 (model == p->model)) { 799 scp->status &= 800 ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 801 return p->rndrsw; 802 } 803 } 804 } else { 805 SET_FOREACH(list, scrndr_set) { 806 p = *list; 807 if ((strcmp(p->name, name) == 0) && 808 (model == p->model)) { 809 scp->status &= 810 ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 811 return p->rndrsw; 812 } 813 } 814 } 815 816 return NULL; 817 } 818 819 #define VIRTUAL_TTY(sc, x) ((SC_DEV((sc),(x)) != NULL) ? \ 820 (SC_DEV((sc),(x))->si_tty) : NULL) 821 822 void 823 sc_update_render(scr_stat *scp) 824 { 825 sc_rndr_sw_t *rndr; 826 sc_term_sw_t *sw; 827 struct tty *tp; 828 int prev_ysize, new_ysize; 829 #ifndef SC_NO_HISTORY 830 int old_xpos, old_ypos; 831 #endif 832 int error; 833 834 sw = scp->tsw; 835 if (sw == NULL) { 836 return; 837 } 838 839 if (scp->rndr == NULL) 840 return; 841 842 if (scp->fbi_generation == scp->sc->fbi_generation) 843 return; 844 845 crit_enter(); 846 scp->fbi_generation = scp->sc->fbi_generation; 847 /* Needed in case we are implicitly leaving PIXEL_MODE here */ 848 if (scp->model != V_INFO_MM_OTHER) 849 scp->model = V_INFO_MM_TEXT; 850 rndr = NULL; 851 if (strcmp(sw->te_renderer, "*") != 0) { 852 rndr = sc_render_match(scp, sw->te_renderer, scp->model); 853 } 854 if (rndr == NULL && scp->sc->fbi != NULL) { 855 rndr = sc_render_match(scp, "kms", scp->model); 856 } 857 if (rndr == NULL) { /* this shouldn't happen */ 858 rndr = sc_render_match(scp, scp->sc->adp->va_name, scp->model); 859 if (rndr != NULL) 860 scp->rndr = rndr; 861 crit_exit(); 862 return; 863 } 864 865 scp->rndr = rndr; 866 /* Mostly copied from sc_set_text_mode */ 867 if ((error = sc_clean_up(scp, FALSE))) { 868 crit_exit(); 869 return; 870 } 871 new_ysize = 0; 872 #ifndef SC_NO_HISTORY 873 old_xpos = old_ypos = 0; 874 if (scp->history != NULL) { 875 if (scp->xsize > 0) { 876 old_xpos = scp->xpos; 877 old_ypos = scp->ypos; 878 } 879 sc_hist_save(scp); 880 new_ysize = sc_vtb_rows(scp->history); 881 } 882 #endif 883 prev_ysize = scp->ysize; 884 scp->status |= MOUSE_HIDDEN; 885 if (scp->status & GRAPHICS_MODE) { 886 /* 887 * We don't handle GRAPHICS_MODE at all when using a KMS 888 * framebuffer, so silently switch to UNKNOWN_MODE then. 889 */ 890 scp->status |= UNKNOWN_MODE; 891 scp->status &= ~GRAPHICS_MODE; 892 } 893 /* Implicitly leave PIXEL_MODE, but stay in UNKNOWN mode */ 894 scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE); 895 scp->xpixel = scp->sc->fbi->width; 896 scp->ypixel = scp->sc->fbi->height; 897 898 /* 899 * Assume square pixels for now 900 */ 901 sc_font_scale(scp, 0, 0); 902 903 DPRINTF(1, ("kms console: scale-to %dx%d cols=%d rows=%d\n", 904 scp->blk_width, scp->blk_height, scp->xsize, scp->ysize)); 905 906 /* allocate buffers */ 907 sc_alloc_scr_buffer(scp, TRUE, TRUE); 908 sc_init_emulator(scp, NULL); 909 #ifndef SC_NO_CUTPASTE 910 sc_alloc_cut_buffer(scp, FALSE); 911 #endif 912 #ifndef SC_NO_HISTORY 913 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 914 if (scp->history != NULL) { 915 sc_hist_getback(scp, prev_ysize); 916 sc_move_cursor(scp, old_xpos, old_ypos); 917 } 918 #endif 919 crit_exit(); 920 tp = VIRTUAL_TTY(scp->sc, scp->index); 921 if (tp == NULL) 922 return; 923 if (tp->t_winsize.ws_col != scp->xsize || 924 tp->t_winsize.ws_row != scp->ysize) { 925 tp->t_winsize.ws_col = scp->xsize; 926 tp->t_winsize.ws_row = scp->ysize; 927 pgsignal(tp->t_pgrp, SIGWINCH, 1); 928 } 929 } 930