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 48 #include <dev/drm/include/linux/fb.h> 49 #include <dev/video/fb/fbreg.h> 50 #include "syscons.h" 51 52 SET_DECLARE(scrndr_set, const sc_renderer_t); 53 54 static int desired_cols = 0; 55 TUNABLE_INT("kern.kms_columns", &desired_cols); 56 57 int 58 sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, 59 int fontsize) 60 { 61 video_info_t info; 62 u_char *font; 63 int prev_ysize; 64 int new_ysize; 65 int error; 66 67 lwkt_gettoken(&tty_token); 68 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info)) { 69 lwkt_reltoken(&tty_token); 70 return ENODEV; 71 } 72 lwkt_reltoken(&tty_token); 73 74 /* adjust argument values */ 75 if (fontsize <= 0) 76 fontsize = info.vi_cheight; 77 if (fontsize < 14) { 78 fontsize = 8; 79 #ifndef SC_NO_FONT_LOADING 80 if (!(scp->sc->fonts_loaded & FONT_8)) 81 return EINVAL; 82 font = scp->sc->font_8; 83 #else 84 font = NULL; 85 #endif 86 } else if (fontsize >= 16) { 87 fontsize = 16; 88 #ifndef SC_NO_FONT_LOADING 89 if (!(scp->sc->fonts_loaded & FONT_16)) 90 return EINVAL; 91 font = scp->sc->font_16; 92 #else 93 font = NULL; 94 #endif 95 } else { 96 fontsize = 14; 97 #ifndef SC_NO_FONT_LOADING 98 if (!(scp->sc->fonts_loaded & FONT_14)) 99 return EINVAL; 100 font = scp->sc->font_14; 101 #else 102 font = NULL; 103 #endif 104 } 105 if ((xsize <= 0) || (xsize > info.vi_width)) 106 xsize = info.vi_width; 107 if ((ysize <= 0) || (ysize > info.vi_height)) 108 ysize = info.vi_height; 109 110 /* stop screen saver, etc */ 111 crit_enter(); 112 if ((error = sc_clean_up(scp))) { 113 crit_exit(); 114 return error; 115 } 116 117 if (scp->sc->fbi != NULL && 118 sc_render_match(scp, "kms", V_INFO_MM_TEXT) == NULL) { 119 crit_exit(); 120 return ENODEV; 121 } 122 if (scp->sc->fbi == NULL && 123 sc_render_match(scp, scp->sc->adp->va_name, V_INFO_MM_TEXT) == NULL) { 124 crit_exit(); 125 return ENODEV; 126 } 127 128 /* set up scp */ 129 new_ysize = 0; 130 #ifndef SC_NO_HISTORY 131 if (scp->history != NULL) { 132 sc_hist_save(scp); 133 new_ysize = sc_vtb_rows(scp->history); 134 } 135 #endif 136 prev_ysize = scp->ysize; 137 /* 138 * This is a kludge to fend off scrn_update() while we 139 * muck around with scp. XXX 140 */ 141 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 142 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE); 143 scp->mode = mode; 144 scp->model = V_INFO_MM_TEXT; 145 scp->xsize = xsize; 146 scp->ysize = ysize; 147 scp->xoff = 0; 148 scp->yoff = 0; 149 scp->xpixel = scp->xsize*8; 150 scp->ypixel = scp->ysize*fontsize; 151 scp->font = font; 152 scp->font_height = fontsize; 153 scp->font_width = 8; 154 155 /* allocate buffers */ 156 sc_alloc_scr_buffer(scp, TRUE, TRUE); 157 sc_init_emulator(scp, NULL); 158 #ifndef SC_NO_CUTPASTE 159 sc_alloc_cut_buffer(scp, FALSE); 160 #endif 161 #ifndef SC_NO_HISTORY 162 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 163 #endif 164 crit_exit(); 165 166 if (scp == scp->sc->cur_scp) 167 set_mode(scp); 168 scp->status &= ~UNKNOWN_MODE; 169 170 if (tp == NULL) 171 return 0; 172 DPRINTF(5, ("ws_*size (%d,%d), size (%d,%d)\n", 173 tp->t_winsize.ws_col, tp->t_winsize.ws_row, scp->xsize, scp->ysize)); 174 if (tp->t_winsize.ws_col != scp->xsize 175 || tp->t_winsize.ws_row != scp->ysize) { 176 tp->t_winsize.ws_col = scp->xsize; 177 tp->t_winsize.ws_row = scp->ysize; 178 pgsignal(tp->t_pgrp, SIGWINCH, 1); 179 } 180 181 return 0; 182 } 183 184 int 185 sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode) 186 { 187 #ifdef SC_NO_MODE_CHANGE 188 return ENODEV; 189 #else 190 video_info_t info; 191 int error; 192 193 lwkt_gettoken(&tty_token); 194 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info)) { 195 lwkt_reltoken(&tty_token); 196 return ENODEV; 197 } 198 lwkt_reltoken(&tty_token); 199 200 /* stop screen saver, etc */ 201 crit_enter(); 202 if ((error = sc_clean_up(scp))) { 203 crit_exit(); 204 return error; 205 } 206 207 if (scp->sc->fbi != NULL && 208 sc_render_match(scp, "kms", V_INFO_MM_OTHER) == NULL) { 209 crit_exit(); 210 return ENODEV; 211 } 212 if (scp->sc->fbi == NULL && 213 sc_render_match(scp, scp->sc->adp->va_name, V_INFO_MM_OTHER) == NULL) { 214 crit_exit(); 215 return ENODEV; 216 } 217 218 /* set up scp */ 219 scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE | MOUSE_HIDDEN); 220 scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE); 221 scp->mode = mode; 222 scp->model = V_INFO_MM_OTHER; 223 /* 224 * Don't change xsize and ysize; preserve the previous vty 225 * and history buffers. 226 */ 227 scp->xoff = 0; 228 scp->yoff = 0; 229 scp->xpixel = info.vi_width; 230 scp->ypixel = info.vi_height; 231 scp->font = NULL; 232 scp->font_height = 0; 233 scp->font_width = 0; 234 #ifndef SC_NO_SYSMOUSE 235 /* move the mouse cursor at the center of the screen */ 236 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2); 237 #endif 238 sc_init_emulator(scp, NULL); 239 crit_exit(); 240 241 if (scp == scp->sc->cur_scp) 242 set_mode(scp); 243 /* clear_graphics();*/ 244 refresh_ega_palette(scp); 245 scp->status &= ~UNKNOWN_MODE; 246 247 if (tp == NULL) 248 return 0; 249 if (tp->t_winsize.ws_xpixel != scp->xpixel 250 || tp->t_winsize.ws_ypixel != scp->ypixel) { 251 tp->t_winsize.ws_xpixel = scp->xpixel; 252 tp->t_winsize.ws_ypixel = scp->ypixel; 253 pgsignal(tp->t_pgrp, SIGWINCH, 1); 254 } 255 256 return 0; 257 #endif /* SC_NO_MODE_CHANGE */ 258 } 259 260 int 261 sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, 262 int fontsize) 263 { 264 #ifndef SC_PIXEL_MODE 265 return ENODEV; 266 #else 267 video_info_t info; 268 u_char *font; 269 int prev_ysize; 270 int new_ysize; 271 int error; 272 273 lwkt_gettoken(&tty_token); 274 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info)) { 275 lwkt_reltoken(&tty_token); 276 return ENODEV; /* this shouldn't happen */ 277 } 278 lwkt_reltoken(&tty_token); 279 280 /* adjust argument values */ 281 if (fontsize <= 0) 282 fontsize = info.vi_cheight; 283 if (fontsize < 14) { 284 fontsize = 8; 285 #ifndef SC_NO_FONT_LOADING 286 if (!(scp->sc->fonts_loaded & FONT_8)) 287 return EINVAL; 288 font = scp->sc->font_8; 289 #else 290 font = NULL; 291 #endif 292 } else if (fontsize >= 16) { 293 fontsize = 16; 294 #ifndef SC_NO_FONT_LOADING 295 if (!(scp->sc->fonts_loaded & FONT_16)) 296 return EINVAL; 297 font = scp->sc->font_16; 298 #else 299 font = NULL; 300 #endif 301 } else { 302 fontsize = 14; 303 #ifndef SC_NO_FONT_LOADING 304 if (!(scp->sc->fonts_loaded & FONT_14)) 305 return EINVAL; 306 font = scp->sc->font_14; 307 #else 308 font = NULL; 309 #endif 310 } 311 if (xsize <= 0) 312 xsize = info.vi_width/8; 313 if (ysize <= 0) 314 ysize = info.vi_height/fontsize; 315 316 if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize)) 317 return EINVAL; 318 319 /* 320 * We currently support the following graphic modes: 321 * 322 * - 4 bpp planar modes whose memory size does not exceed 64K 323 * - 8 bbp packed pixel modes 324 * - 15, 16, 24 and 32 bpp direct modes with linear frame buffer 325 */ 326 327 if (info.vi_mem_model == V_INFO_MM_PLANAR) { 328 if (info.vi_planes != 4) 329 return ENODEV; 330 331 /* 332 * A memory size >64K requires bank switching to access the entire 333 * screen. XXX 334 */ 335 336 if (info.vi_width * info.vi_height / 8 > info.vi_window_size) 337 return ENODEV; 338 } else if (info.vi_mem_model == V_INFO_MM_PACKED) { 339 if (info.vi_depth != 8) 340 return ENODEV; 341 } else if (info.vi_mem_model == V_INFO_MM_DIRECT) { 342 if (!(info.vi_flags & V_INFO_LINEAR) && 343 (info.vi_depth != 15) && (info.vi_depth != 16) && 344 (info.vi_depth != 24) && (info.vi_depth != 32)) 345 return ENODEV; 346 } else 347 return ENODEV; 348 349 /* stop screen saver, etc */ 350 crit_enter(); 351 if ((error = sc_clean_up(scp))) { 352 crit_exit(); 353 return error; 354 } 355 356 if (sc_render_match(scp, scp->sc->adp->va_name, info.vi_mem_model) == NULL) { 357 crit_exit(); 358 return ENODEV; 359 } 360 361 #if 0 362 if (scp->tsw) 363 (*scp->tsw->te_term)(scp, scp->ts); 364 scp->tsw = NULL; 365 scp->ts = NULL; 366 #endif 367 368 /* set up scp */ 369 new_ysize = 0; 370 #ifndef SC_NO_HISTORY 371 if (scp->history != NULL) { 372 sc_hist_save(scp); 373 new_ysize = sc_vtb_rows(scp->history); 374 } 375 #endif 376 prev_ysize = scp->ysize; 377 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 378 scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE); 379 scp->model = info.vi_mem_model; 380 scp->xsize = xsize; 381 scp->ysize = ysize; 382 scp->xoff = (scp->xpixel/8 - xsize)/2; 383 scp->yoff = (scp->ypixel/fontsize - ysize)/2; 384 scp->font = font; 385 scp->font_height = fontsize; 386 scp->font_width = 8; 387 388 /* allocate buffers */ 389 sc_alloc_scr_buffer(scp, TRUE, TRUE); 390 sc_init_emulator(scp, NULL); 391 #ifndef SC_NO_CUTPASTE 392 sc_alloc_cut_buffer(scp, FALSE); 393 #endif 394 #ifndef SC_NO_HISTORY 395 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 396 #endif 397 crit_exit(); 398 399 if (scp == scp->sc->cur_scp) { 400 sc_set_border(scp, scp->border); 401 sc_set_cursor_image(scp); 402 } 403 404 scp->status &= ~UNKNOWN_MODE; 405 406 if (tp == NULL) 407 return 0; 408 if (tp->t_winsize.ws_col != scp->xsize 409 || tp->t_winsize.ws_row != scp->ysize) { 410 tp->t_winsize.ws_col = scp->xsize; 411 tp->t_winsize.ws_row = scp->ysize; 412 pgsignal(tp->t_pgrp, SIGWINCH, 1); 413 } 414 415 return 0; 416 #endif /* SC_PIXEL_MODE */ 417 } 418 419 #define fb_ioctl(a, c, d) \ 420 (((a) == NULL) ? ENODEV : \ 421 (*vidsw[(a)->va_index]->ioctl)((a), (c), (caddr_t)(d))) 422 423 int 424 sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) 425 { 426 scr_stat *scp; 427 video_adapter_t *adp; 428 #ifndef SC_NO_MODE_CHANGE 429 video_info_t info; 430 #endif 431 int error, ret; 432 433 KKASSERT(tp->t_dev); 434 435 scp = SC_STAT(tp->t_dev); 436 if (scp == NULL) /* tp == SC_MOUSE */ 437 return ENOIOCTL; 438 adp = scp->sc->adp; 439 if (adp == NULL) /* shouldn't happen??? */ 440 return ENODEV; 441 442 lwkt_gettoken(&tty_token); 443 switch (cmd) { 444 445 case CONS_CURRENTADP: /* get current adapter index */ 446 case FBIO_ADAPTER: 447 ret = fb_ioctl(adp, FBIO_ADAPTER, data); 448 lwkt_reltoken(&tty_token); 449 return ret; 450 451 case CONS_CURRENT: /* get current adapter type */ 452 case FBIO_ADPTYPE: 453 ret = fb_ioctl(adp, FBIO_ADPTYPE, data); 454 lwkt_reltoken(&tty_token); 455 return ret; 456 457 case CONS_ADPINFO: /* adapter information */ 458 case FBIO_ADPINFO: 459 if (((video_adapter_info_t *)data)->va_index >= 0) { 460 adp = vid_get_adapter(((video_adapter_info_t *)data)->va_index); 461 if (adp == NULL) { 462 lwkt_reltoken(&tty_token); 463 return ENODEV; 464 } 465 } 466 ret = fb_ioctl(adp, FBIO_ADPINFO, data); 467 lwkt_reltoken(&tty_token); 468 return ret; 469 470 case CONS_GET: /* get current video mode */ 471 case FBIO_GETMODE: 472 *(int *)data = scp->mode; 473 lwkt_reltoken(&tty_token); 474 return 0; 475 476 #ifndef SC_NO_MODE_CHANGE 477 case CONS_SET: 478 case FBIO_SETMODE: /* set video mode */ 479 if (!(adp->va_flags & V_ADP_MODECHANGE)) { 480 lwkt_reltoken(&tty_token); 481 return ENODEV; 482 } 483 info.vi_mode = *(int *)data; 484 error = fb_ioctl(adp, FBIO_MODEINFO, &info); 485 if (error) { 486 lwkt_reltoken(&tty_token); 487 return error; 488 } 489 if (info.vi_flags & V_INFO_GRAPHICS) { 490 lwkt_reltoken(&tty_token); 491 return sc_set_graphics_mode(scp, tp, *(int *)data); 492 } else { 493 lwkt_reltoken(&tty_token); 494 return sc_set_text_mode(scp, tp, *(int *)data, 0, 0, 0); 495 } 496 #endif /* SC_NO_MODE_CHANGE */ 497 498 case CONS_MODEINFO: /* get mode information */ 499 case FBIO_MODEINFO: 500 ret = fb_ioctl(adp, FBIO_MODEINFO, data); 501 lwkt_reltoken(&tty_token); 502 return ret; 503 504 case CONS_FINDMODE: /* find a matching video mode */ 505 case FBIO_FINDMODE: 506 ret = fb_ioctl(adp, FBIO_FINDMODE, data); 507 lwkt_reltoken(&tty_token); 508 return ret; 509 510 case CONS_SETWINORG: /* set frame buffer window origin */ 511 case FBIO_SETWINORG: 512 if (scp != scp->sc->cur_scp) { 513 lwkt_reltoken(&tty_token); 514 return ENODEV; /* XXX */ 515 } 516 ret = fb_ioctl(adp, FBIO_SETWINORG, data); 517 lwkt_reltoken(&tty_token); 518 return ret; 519 520 case FBIO_GETWINORG: /* get frame buffer window origin */ 521 if (scp != scp->sc->cur_scp) { 522 lwkt_reltoken(&tty_token); 523 return ENODEV; /* XXX */ 524 } 525 ret = fb_ioctl(adp, FBIO_GETWINORG, data); 526 lwkt_reltoken(&tty_token); 527 return ret; 528 529 case FBIO_GETDISPSTART: 530 case FBIO_SETDISPSTART: 531 case FBIO_GETLINEWIDTH: 532 case FBIO_SETLINEWIDTH: 533 if (scp != scp->sc->cur_scp) { 534 lwkt_reltoken(&tty_token); 535 return ENODEV; /* XXX */ 536 } 537 ret = fb_ioctl(adp, cmd, data); 538 lwkt_reltoken(&tty_token); 539 return ret; 540 541 case FBIO_GETPALETTE: 542 case FBIO_SETPALETTE: 543 case FBIOPUTCMAP: 544 case FBIOGETCMAP: 545 case FBIOGTYPE: 546 case FBIOGATTR: 547 case FBIOSVIDEO: 548 case FBIOGVIDEO: 549 case FBIOSCURSOR: 550 case FBIOGCURSOR: 551 case FBIOSCURPOS: 552 case FBIOGCURPOS: 553 case FBIOGCURMAX: 554 if (scp != scp->sc->cur_scp) { 555 lwkt_reltoken(&tty_token); 556 return ENODEV; /* XXX */ 557 } 558 ret = fb_ioctl(adp, cmd, data); 559 lwkt_reltoken(&tty_token); 560 return ret; 561 562 case KDSETMODE: /* set current mode of this (virtual) console */ 563 switch (*(int *)data) { 564 case KD_TEXT: /* switch to TEXT (known) mode */ 565 /* 566 * If scp->mode is of graphics modes, we don't know which 567 * text mode to switch back to... 568 */ 569 if (scp->status & GRAPHICS_MODE) { 570 lwkt_reltoken(&tty_token); 571 return EINVAL; 572 } 573 /* restore fonts & palette ! */ 574 #if 0 575 #ifndef SC_NO_FONT_LOADING 576 if (ISFONTAVAIL(adp->va_flags) 577 && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) 578 /* 579 * FONT KLUDGE 580 * Don't load fonts for now... XXX 581 */ 582 if (scp->sc->fonts_loaded & FONT_8) 583 sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256); 584 if (scp->sc->fonts_loaded & FONT_14) 585 sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256); 586 if (scp->sc->fonts_loaded & FONT_16) 587 sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256); 588 } 589 #endif /* SC_NO_FONT_LOADING */ 590 #endif 591 592 #ifndef SC_NO_PALETTE_LOADING 593 load_palette(adp, scp->sc->palette); 594 #endif 595 596 /* move hardware cursor out of the way */ 597 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 598 /* FALL THROUGH */ 599 600 case KD_TEXT1: /* switch to TEXT (known) mode */ 601 /* 602 * If scp->mode is of graphics modes, we don't know which 603 * text/pixel mode to switch back to... 604 */ 605 if (scp->status & GRAPHICS_MODE) { 606 lwkt_reltoken(&tty_token); 607 return EINVAL; 608 } 609 crit_enter(); 610 if ((error = sc_clean_up(scp))) { 611 crit_exit(); 612 lwkt_reltoken(&tty_token); 613 return error; 614 } 615 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 616 crit_exit(); 617 /* no restore fonts & palette */ 618 if (scp == scp->sc->cur_scp) 619 set_mode(scp); 620 sc_clear_screen(scp); 621 scp->status &= ~UNKNOWN_MODE; 622 lwkt_reltoken(&tty_token); 623 return 0; 624 625 #ifdef SC_PIXEL_MODE 626 case KD_PIXEL: /* pixel (raster) display */ 627 if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) { 628 lwkt_reltoken(&tty_token); 629 return EINVAL; 630 } 631 if (scp->status & GRAPHICS_MODE) { 632 lwkt_reltoken(&tty_token); 633 return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, 634 scp->font_height); 635 } 636 crit_enter(); 637 if ((error = sc_clean_up(scp))) { 638 crit_exit(); 639 lwkt_reltoken(&tty_token); 640 return error; 641 } 642 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 643 crit_exit(); 644 if (scp == scp->sc->cur_scp) { 645 set_mode(scp); 646 #ifndef SC_NO_PALETTE_LOADING 647 load_palette(adp, scp->sc->palette); 648 #endif 649 } 650 sc_clear_screen(scp); 651 scp->status &= ~UNKNOWN_MODE; 652 lwkt_reltoken(&tty_token); 653 return 0; 654 #endif /* SC_PIXEL_MODE */ 655 656 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 657 crit_enter(); 658 if ((error = sc_clean_up(scp))) { 659 crit_exit(); 660 lwkt_reltoken(&tty_token); 661 return error; 662 } 663 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 664 crit_exit(); 665 lwkt_reltoken(&tty_token); 666 return 0; 667 668 default: 669 lwkt_reltoken(&tty_token); 670 return EINVAL; 671 } 672 /* NOT REACHED */ 673 674 #ifdef SC_PIXEL_MODE 675 case KDRASTER: /* set pixel (raster) display mode */ 676 if (ISUNKNOWNSC(scp) || ISTEXTSC(scp)) { 677 lwkt_reltoken(&tty_token); 678 return ENODEV; 679 } 680 lwkt_reltoken(&tty_token); 681 return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], 682 ((int *)data)[2]); 683 #endif /* SC_PIXEL_MODE */ 684 685 case KDGETMODE: /* get current mode of this (virtual) console */ 686 /* 687 * From the user program's point of view, KD_PIXEL is the same 688 * as KD_TEXT... 689 */ 690 *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT; 691 lwkt_reltoken(&tty_token); 692 return 0; 693 694 case KDSBORDER: /* set border color of this (virtual) console */ 695 scp->border = *data; 696 if (scp == scp->sc->cur_scp) 697 sc_set_border(scp, scp->border); 698 lwkt_reltoken(&tty_token); 699 return 0; 700 } 701 702 lwkt_reltoken(&tty_token); 703 return ENOIOCTL; 704 } 705 706 static LIST_HEAD(, sc_renderer) sc_rndr_list = 707 LIST_HEAD_INITIALIZER(sc_rndr_list); 708 709 int 710 sc_render_add(sc_renderer_t *rndr) 711 { 712 LIST_INSERT_HEAD(&sc_rndr_list, rndr, link); 713 return 0; 714 } 715 716 int 717 sc_render_remove(sc_renderer_t *rndr) 718 { 719 /* 720 LIST_REMOVE(rndr, link); 721 */ 722 return EBUSY; /* XXX */ 723 } 724 725 sc_rndr_sw_t * 726 sc_render_match(scr_stat *scp, char *name, int model) 727 { 728 const sc_renderer_t **list; 729 const sc_renderer_t *p; 730 731 if (!LIST_EMPTY(&sc_rndr_list)) { 732 LIST_FOREACH(p, &sc_rndr_list, link) { 733 if ((strcmp(p->name, name) == 0) && 734 (model == p->model)) { 735 scp->status &= 736 ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 737 return p->rndrsw; 738 } 739 } 740 } else { 741 SET_FOREACH(list, scrndr_set) { 742 p = *list; 743 if ((strcmp(p->name, name) == 0) && 744 (model == p->model)) { 745 scp->status &= 746 ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 747 return p->rndrsw; 748 } 749 } 750 } 751 752 return NULL; 753 } 754 755 #define VIRTUAL_TTY(sc, x) ((SC_DEV((sc),(x)) != NULL) ? \ 756 (SC_DEV((sc),(x))->si_tty) : NULL) 757 758 void 759 sc_update_render(scr_stat *scp) 760 { 761 sc_rndr_sw_t *rndr; 762 sc_term_sw_t *sw; 763 struct tty *tp; 764 int prev_ysize, new_ysize; 765 int error; 766 767 sw = scp->tsw; 768 if (sw == NULL) { 769 return; 770 } 771 772 if (scp->rndr == NULL) 773 return; 774 775 if (scp->fbi == scp->sc->fbi) 776 return; 777 778 crit_enter(); 779 scp->fbi = scp->sc->fbi; 780 rndr = NULL; 781 if (strcmp(sw->te_renderer, "*") != 0) { 782 rndr = sc_render_match(scp, sw->te_renderer, scp->model); 783 } 784 if (rndr == NULL && scp->sc->fbi != NULL) { 785 rndr = sc_render_match(scp, "kms", scp->model); 786 } 787 if (rndr != NULL) { 788 scp->rndr = rndr; 789 /* Mostly copied from sc_set_text_mode */ 790 if ((error = sc_clean_up(scp))) { 791 crit_exit(); 792 return; 793 } 794 new_ysize = 0; 795 #ifndef SC_NO_HISTORY 796 if (scp->history != NULL) { 797 sc_hist_save(scp); 798 new_ysize = sc_vtb_rows(scp->history); 799 } 800 #endif 801 prev_ysize = scp->ysize; 802 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 803 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE); 804 scp->model = V_INFO_MM_TEXT; 805 scp->xpixel = scp->fbi->width; 806 scp->ypixel = scp->fbi->height; 807 808 /* 809 * Assume square pixels for now 810 */ 811 kprintf("kms console: xpixels %d ypixels %d\n", 812 scp->xpixel, scp->ypixel); 813 814 /* 815 * If columns not specified in /boot/loader.conf then 816 * calculate a non-fractional scaling that yields a 817 * reasonable number of rows and columns. If it is <0, 818 * don't scale at all. 819 */ 820 if (desired_cols == 0) { 821 int nomag = 1; 822 while (scp->xpixel / (scp->font_width * nomag) >= 80 && 823 scp->ypixel / (scp->font_height * nomag) >= 25) { 824 ++nomag; 825 } 826 if (nomag > 1) 827 --nomag; 828 desired_cols = scp->xpixel / (scp->font_width * nomag); 829 } else if (desired_cols < 0) { 830 desired_cols = scp->xpixel / scp->font_width; 831 } 832 scp->blk_width = scp->xpixel / desired_cols; 833 scp->blk_height = scp->blk_width * scp->font_height / 834 scp->font_width; 835 836 /* scp->xsize = scp->xpixel / scp->blk_width; total possible */ 837 scp->xsize = desired_cols; 838 scp->ysize = scp->ypixel / scp->blk_height; 839 scp->xpad = scp->fbi->stride / 4 - scp->xsize * scp->blk_width; 840 841 kprintf("kms console: scale-to %dx%d cols=%d rows=%d\n", 842 scp->blk_width, scp->blk_height, 843 scp->xsize, scp->ysize); 844 845 /* allocate buffers */ 846 sc_alloc_scr_buffer(scp, TRUE, TRUE); 847 sc_init_emulator(scp, NULL); 848 #ifndef SC_NO_CUTPASTE 849 sc_alloc_cut_buffer(scp, FALSE); 850 #endif 851 #ifndef SC_NO_HISTORY 852 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE); 853 #endif 854 crit_exit(); 855 scp->status &= ~UNKNOWN_MODE; 856 tp = VIRTUAL_TTY(scp->sc, scp->index); 857 if (tp == NULL) 858 return; 859 if (tp->t_winsize.ws_col != scp->xsize || 860 tp->t_winsize.ws_row != scp->ysize) { 861 tp->t_winsize.ws_col = scp->xsize; 862 tp->t_winsize.ws_row = scp->ysize; 863 pgsignal(tp->t_pgrp, SIGWINCH, 1); 864 } 865 return; 866 } 867 if (rndr == NULL) { 868 rndr = sc_render_match(scp, scp->sc->adp->va_name, scp->model); 869 } 870 871 if (rndr != NULL) { 872 scp->rndr = rndr; 873 } 874 crit_exit(); 875 } 876