1 /*- 2 * Copyright (c) 2014 Imre Vadász <imre@vdsz.com> 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The DragonFly Project 6 * by Sascha Wildner <saw@online.de>. 7 * 8 * Simple font scaling code by Sascha Wildner and Matthew Dillon 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer as 15 * the first lines of this file unmodified. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "opt_syscons.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/thread.h> 38 #include <sys/thread2.h> 39 40 #include <machine/console.h> 41 #include <machine/framebuffer.h> 42 43 #include "syscons.h" 44 45 #include <bus/isa/isareg.h> 46 47 static vr_draw_border_t kms_draw_border; 48 static vr_draw_t kms_draw; 49 static vr_draw_cursor_t kms_cursor; 50 static vr_blink_cursor_t kms_blink; 51 #ifndef SC_NO_CUTPASTE 52 static vr_draw_mouse_t kms_mouse; 53 #endif 54 55 static void kms_nop(scr_stat *scp, ...); 56 57 static sc_rndr_sw_t kmsrndrsw = { 58 kms_draw_border, 59 kms_draw, 60 (vr_set_cursor_t *)kms_nop, 61 kms_cursor, 62 kms_blink, 63 #ifndef SC_NO_CUTPASTE 64 kms_mouse, 65 #else 66 (vr_draw_mouse_t *)kms_nop, 67 #endif 68 }; 69 RENDERER(kms, V_INFO_MM_TEXT, kmsrndrsw, kms_set); 70 71 #ifndef SC_NO_MODE_CHANGE 72 static sc_rndr_sw_t grrndrsw = { 73 (vr_draw_border_t *)kms_nop, 74 (vr_draw_t *)kms_nop, 75 (vr_set_cursor_t *)kms_nop, 76 (vr_draw_cursor_t *)kms_nop, 77 (vr_blink_cursor_t *)kms_nop, 78 (vr_draw_mouse_t *)kms_nop, 79 }; 80 RENDERER(kms, V_INFO_MM_OTHER, grrndrsw, kms_set); 81 #endif /* SC_NO_MODE_CHANGE */ 82 83 RENDERER_MODULE(kms, kms_set); 84 85 static uint32_t colormap[16] = { 86 0x00000000, /* BLACK */ 87 0x000000aa, /* BLUE */ 88 0x0000aa00, /* GREEN */ 89 0x0000aaaa, /* CYAN */ 90 0x00aa0000, /* RED */ 91 0x00aa00aa, /* MAGENTA */ 92 0x00aa5500, /* BROWN */ 93 0x00aaaaaa, /* WHITE */ 94 0x00555555, /* HIGHLIGHT BLACK */ 95 0x005555ff, /* HIGHLIGHT BLUE */ 96 0x0055ff55, /* HIGHLIGHT GREEN */ 97 0x0055ffff, /* HIGHLIGHT CYAN */ 98 0x00ff5555, /* HIGHLIGHT RED */ 99 0x00ff55ff, /* HIGHLIGHT MAGENTA */ 100 0x00ffff55, /* HIGHLIGHT BROWN */ 101 0x00ffffff, /* HIGHLIGHT WHITE */ 102 }; 103 104 #ifndef SC_NO_CUTPASTE 105 static u_short mouse_and_mask[16] = { 106 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 107 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 108 }; 109 static u_short mouse_or_mask[16] = { 110 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 111 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 112 }; 113 #endif 114 115 static void 116 kms_nop(scr_stat *scp, ...) 117 { 118 } 119 120 /* 121 * Scaled font rendering. Simple blit blitter copy operation with bitmap 122 * scaling. Scales the bitmap char_data(sw x sh) to the output bitmap 123 * draw_pos(dw x dh). 124 * 125 * This function does not do fractional scaling. 126 * 127 * SET - Sets both the fg and bg pen 128 * 129 * MASK - Sets only the fg pen based on the source mask and leaves 130 * the background untouched. 131 */ 132 #define BLIT_SET 0 133 #define BLIT_MASK 1 134 135 static inline void 136 blit_blk32(scr_stat *scp, u_char *char_data, int sw, int sh, 137 vm_offset_t draw_pos, int dw, int dh, 138 int line_width, uint32_t fg, uint32_t bg, int how) 139 { 140 vm_offset_t p; 141 int pos; 142 int x; /* destination iterator (whole pixels) */ 143 int y; 144 int sx, sx_inc; /* source iterator (fractional) */ 145 int sy, sy_inc; 146 uint8_t c; 147 148 /* 149 * Calculate fractional iterator for source 150 */ 151 if (dw) 152 sx_inc = (sw << 16) / dw; 153 else 154 sx_inc = 0; 155 156 if (dh) 157 sy_inc = (sh << 16) / dh; 158 else 159 sy_inc = 0; 160 161 sy = 0; 162 c = 0; 163 164 /* 165 * For each pixel row in the target 166 */ 167 for (y = 0; y < dh; ++y) { 168 sx = 0; 169 p = draw_pos; 170 171 /* 172 * Render all pixel columns in the target by calculating 173 * which bit in the source is applicable. 174 */ 175 switch(how) { 176 case BLIT_SET: 177 for (x = 0; x < dw; ++x) { 178 if ((sx & 0x00070000) == 0) 179 c = char_data[sx >> 19]; 180 pos = ~(sx >> 16) & 7; 181 writel(p + x * 4, (c & (1 << pos) ? fg : bg)); 182 sx += sx_inc; 183 } 184 break; 185 case BLIT_MASK: 186 for (x = 0; x < dw; ++x) { 187 if ((sx & 0x00070000) == 0) 188 c = char_data[sx >> 19]; 189 pos = ~(sx >> 16) & 7; 190 if (c & (1 << pos)) 191 writel(p + x * 4, fg); 192 sx += sx_inc; 193 } 194 break; 195 } 196 draw_pos += line_width; 197 sy += sy_inc; 198 if (sy >= 0x10000) { 199 char_data += (sy >> 16) * (sw >> 3); 200 sy &= 0x0FFFF; 201 } 202 } 203 } 204 205 static inline void 206 blit_blk24(scr_stat *scp, u_char *char_data, int sw, int sh, 207 vm_offset_t draw_pos, int dw, int dh, 208 int line_width, uint32_t fg, uint32_t bg, int how) 209 { 210 vm_offset_t p; 211 int pos; 212 int x; /* destination iterator (whole pixels) */ 213 int y; 214 int sx, sx_inc; /* source iterator (fractional) */ 215 int sy, sy_inc; 216 uint8_t c; 217 218 /* 219 * Calculate fractional iterator for source 220 */ 221 if (dw) 222 sx_inc = (sw << 16) / dw; 223 else 224 sx_inc = 0; 225 226 if (dh) 227 sy_inc = (sh << 16) / dh; 228 else 229 sy_inc = 0; 230 231 sy = 0; 232 c = 0; 233 234 /* 235 * For each pixel row in the target 236 */ 237 for (y = 0; y < dh; ++y) { 238 sx = 0; 239 p = draw_pos; 240 241 /* 242 * Render all pixel columns in the target by calculating 243 * which bit in the source is applicable. 244 */ 245 switch(how) { 246 case BLIT_SET: 247 for (x = 0; x < dw; ++x) { 248 if ((sx & 0x00070000) == 0) 249 c = char_data[sx >> 19]; 250 pos = ~(sx >> 16) & 7; 251 uint32_t col = c & (1 << pos) ? fg : bg; 252 writeb(p, col >> 16); 253 writeb(p + 1, col >> 8); 254 writeb(p + 2, col >> 0); 255 p += 3; 256 sx += sx_inc; 257 } 258 break; 259 case BLIT_MASK: 260 for (x = 0; x < dw; ++x) { 261 if ((sx & 0x00070000) == 0) 262 c = char_data[sx >> 19]; 263 pos = ~(sx >> 16) & 7; 264 if (c & (1 << pos)) { 265 writeb(p, fg >> 16); 266 writeb(p + 1, fg >> 8); 267 writeb(p + 2, fg >> 0); 268 } 269 p += 3; 270 sx += sx_inc; 271 } 272 break; 273 } 274 draw_pos += line_width; 275 sy += sy_inc; 276 if (sy >= 0x10000) { 277 char_data += (sy >> 16) * (sw >> 3); 278 sy &= 0x0FFFF; 279 } 280 } 281 } 282 283 static void 284 fill_rect32(scr_stat *scp, vm_offset_t draw_pos, int width, int height, 285 int line_width, uint32_t fg) 286 { 287 int i, j; 288 289 for (i = 0; i < height; i++) { 290 for (j = 0; j < width; j++) 291 writel(draw_pos + j * 4, fg); 292 draw_pos += line_width; 293 } 294 } 295 296 static void 297 fill_rect24(scr_stat *scp, vm_offset_t draw_pos, int width, int height, 298 int line_width, uint32_t fg) 299 { 300 int i, j, d; 301 302 d = line_width - width * 3; 303 KKASSERT(d >= 0); 304 305 if ((draw_pos & 0x3) == 0 && (line_width & 0x3) == 0 && 306 (width & 0x3) == 0) { 307 uint32_t fga = fg | (fg << 24); 308 uint32_t fgb = (fg << 16) | ((fg >> 8) & 0xffff); 309 uint32_t fgc = (fg << 8) | ((fg >> 16) & 0xff); 310 for (i = 0; i < height; i++) { 311 for (j = 0; j < width; j += 4) { 312 writel(draw_pos, fga); 313 writel(draw_pos + 4, fgb); 314 writel(draw_pos + 8, fgc); 315 draw_pos += 12; 316 } 317 draw_pos += d; 318 } 319 } else { 320 for (i = 0; i < height; i++) { 321 for (j = 0; j < width; j++) { 322 writeb(draw_pos, fg >> 16); 323 writeb(draw_pos + 1, fg >> 8); 324 writeb(draw_pos + 2, fg >> 0); 325 draw_pos += 3; 326 } 327 draw_pos += line_width; 328 } 329 } 330 } 331 332 /* KMS renderer */ 333 334 static void 335 kms_draw_border(scr_stat *scp, int color) 336 { 337 sc_softc_t *sc = scp->sc; 338 int line_width, pixel_size; 339 int rightpixel, bottompixel; 340 uint32_t fg; 341 vm_offset_t draw_pos; 342 343 if (sc->fbi->vaddr == 0) 344 return; 345 346 fg = colormap[color]; 347 line_width = sc->fbi->stride; 348 /* sc->fbi->depth may only be 24 or 32 */ 349 pixel_size = sc->fbi->depth == 24 ? 3 : 4; 350 rightpixel = sc->fbi->width - scp->xsize * scp->blk_width; 351 bottompixel = sc->fbi->height - scp->ysize * scp->blk_height; 352 353 draw_pos = sc->fbi->vaddr + scp->blk_width * pixel_size * scp->xsize; 354 if (pixel_size == 3) { 355 fill_rect24(scp, draw_pos, rightpixel, 356 scp->blk_height * scp->ysize, line_width, fg); 357 } else { 358 fill_rect32(scp, draw_pos, rightpixel, 359 scp->blk_height * scp->ysize, line_width, fg); 360 } 361 362 draw_pos = sc->fbi->vaddr + scp->blk_height * scp->ysize * line_width; 363 if (pixel_size == 3) { 364 fill_rect24(scp, draw_pos, sc->fbi->width, 365 sc->fbi->height - scp->blk_height * scp->ysize, line_width, 366 fg); 367 } else { 368 fill_rect32(scp, draw_pos, sc->fbi->width, 369 sc->fbi->height - scp->blk_height * scp->ysize, line_width, 370 fg); 371 } 372 } 373 374 static void 375 kms_draw(scr_stat *scp, int from, int count, int flip) 376 { 377 sc_softc_t *sc = scp->sc; 378 u_char *char_data; 379 int a, i; 380 uint32_t fg, bg; 381 vm_offset_t draw_pos, p; 382 int line_width, pixel_size; 383 384 if (sc->fbi->vaddr == 0) 385 return; 386 387 line_width = sc->fbi->stride; 388 /* sc->fbi->depth may only be 24 or 32 */ 389 pixel_size = sc->fbi->depth == 24 ? 3 : 4; 390 391 draw_pos = sc->fbi->vaddr + 392 scp->blk_height * line_width * (from / scp->xsize); 393 394 if (from + count > scp->xsize * scp->ysize) 395 count = scp->xsize * scp->ysize - from; 396 397 p = draw_pos + scp->blk_width * pixel_size * (from % scp->xsize); 398 for (i = from; count-- > 0; i++) { 399 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 400 scp->font_height]); 401 402 a = sc_vtb_geta(&scp->vtb, i); 403 if (flip) { 404 fg = colormap[((a & 0xf000) >> 4) >> 8]; 405 bg = colormap[(a & 0x0f00) >> 8]; 406 } else { 407 fg = colormap[(a & 0x0f00) >> 8]; 408 bg = colormap[((a & 0xf000) >> 4) >> 8]; 409 } 410 if (pixel_size == 3) { 411 blit_blk24(scp, char_data, scp->font_width, 412 scp->font_height, p, scp->blk_width, 413 scp->blk_height, line_width, fg, bg, 414 BLIT_SET); 415 } else { 416 blit_blk32(scp, char_data, scp->font_width, 417 scp->font_height, p, scp->blk_width, 418 scp->blk_height, line_width, fg, bg, 419 BLIT_SET); 420 } 421 p += scp->blk_width * pixel_size; 422 if ((i % scp->xsize) == scp->xsize - 1) { 423 draw_pos += scp->blk_height * line_width; 424 p = draw_pos; 425 } 426 } 427 } 428 429 static void 430 draw_kmscursor(scr_stat *scp, int at, int on, int flip) 431 { 432 sc_softc_t *sc = scp->sc; 433 int line_width, pixel_size; 434 int cursor_base; 435 int blk_base; 436 int a; 437 uint32_t fg, bg; 438 unsigned char *char_data; 439 vm_offset_t draw_pos; 440 441 if (sc->fbi->vaddr == 0) 442 return; 443 444 line_width = sc->fbi->stride; 445 /* sc->fbi->depth may only be 24 or 32 */ 446 pixel_size = sc->fbi->depth == 24 ? 3 : 4; 447 cursor_base = /* scp->font_height - */ scp->cursor_base; 448 blk_base = scp->blk_height * cursor_base / scp->font_height; 449 450 draw_pos = sc->fbi->vaddr + 451 scp->blk_width * pixel_size * (at % scp->xsize) + 452 scp->blk_height * line_width * (at / scp->xsize) + 453 blk_base * line_width; 454 455 a = sc_vtb_geta(&scp->vtb, at); 456 if (flip) { 457 fg = colormap[((on) ? (a & 0x0f00) : 458 ((a & 0xf000) >> 4)) >> 8]; 459 bg = colormap[((on) ? ((a & 0xf000) >> 4) : 460 (a & 0x0f00)) >> 8]; 461 } else { 462 fg = colormap[((on) ? ((a & 0xf000) >> 4) : 463 (a & 0x0f00)) >> 8]; 464 bg = colormap[((on) ? (a & 0x0f00) : 465 ((a & 0xf000) >> 4)) >> 8]; 466 } 467 468 char_data = &scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_height]; 469 char_data += cursor_base; 470 471 if (pixel_size == 3) { 472 blit_blk24(scp, char_data, 473 scp->font_width, scp->font_height - cursor_base, 474 draw_pos, scp->blk_width, scp->blk_height - blk_base, 475 line_width, fg, bg, BLIT_SET); 476 } else { 477 blit_blk32(scp, char_data, 478 scp->font_width, scp->font_height - cursor_base, 479 draw_pos, scp->blk_width, scp->blk_height - blk_base, 480 line_width, fg, bg, BLIT_SET); 481 } 482 } 483 484 static int pxlblinkrate = 0; 485 486 static void 487 kms_cursor(scr_stat *scp, int at, int blink, int on, int flip) 488 { 489 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 490 return; 491 492 if (on) { 493 if (!blink) { 494 scp->status |= VR_CURSOR_ON; 495 draw_kmscursor(scp, at, on, flip); 496 } else if (++pxlblinkrate & 4) { 497 pxlblinkrate = 0; 498 scp->status ^= VR_CURSOR_ON; 499 draw_kmscursor(scp, at, 500 scp->status & VR_CURSOR_ON, flip); 501 } 502 } else { 503 if (scp->status & VR_CURSOR_ON) 504 draw_kmscursor(scp, at, on, flip); 505 scp->status &= ~VR_CURSOR_ON; 506 } 507 if (blink) 508 scp->status |= VR_CURSOR_BLINK; 509 else 510 scp->status &= ~VR_CURSOR_BLINK; 511 } 512 513 static void 514 kms_blink(scr_stat *scp, int at, int flip) 515 { 516 if (!(scp->status & VR_CURSOR_BLINK)) 517 return; 518 if (!(++pxlblinkrate & 4)) 519 return; 520 pxlblinkrate = 0; 521 scp->status ^= VR_CURSOR_ON; 522 draw_kmscursor(scp, at, scp->status & VR_CURSOR_ON, flip); 523 } 524 525 #ifndef SC_NO_CUTPASTE 526 527 static void 528 draw_kmsmouse(scr_stat *scp, int x, int y) 529 { 530 sc_softc_t *sc = scp->sc; 531 int line_width, pixel_size; 532 int blk_width, blk_height; 533 vm_offset_t draw_pos; 534 535 if (sc->fbi->vaddr == 0) 536 return; 537 538 line_width = sc->fbi->stride; 539 /* sc->fbi->depth may only be 24 or 32 */ 540 pixel_size = sc->fbi->depth == 24 ? 3 : 4; 541 542 if (x + scp->font_width < scp->font_width * scp->xsize) 543 blk_width = scp->blk_width; 544 else 545 blk_width = scp->font_width * scp->xsize - x; 546 547 if (y + scp->font_height < scp->font_height * scp->ysize) 548 blk_height = scp->blk_height; 549 else 550 blk_height = scp->font_height * scp->ysize - y; 551 552 draw_pos = sc->fbi->vaddr + y * scp->blk_height / scp->font_height * 553 line_width + 554 x * scp->blk_width / scp->font_width * pixel_size; 555 if (pixel_size == 3) { 556 blit_blk24(scp, (unsigned char *)mouse_and_mask, 16, 16, 557 draw_pos, blk_width, blk_height, line_width, 558 colormap[0], 0, BLIT_MASK); 559 blit_blk24(scp, (unsigned char *)mouse_or_mask, 16, 16, 560 draw_pos, blk_width, blk_height, line_width, 561 colormap[15], 0, BLIT_MASK); 562 } else { 563 blit_blk32(scp, (unsigned char *)mouse_and_mask, 16, 16, 564 draw_pos, blk_width, blk_height, line_width, 565 colormap[0], 0, BLIT_MASK); 566 blit_blk32(scp, (unsigned char *)mouse_or_mask, 16, 16, 567 draw_pos, blk_width, blk_height, line_width, 568 colormap[15], 0, BLIT_MASK); 569 } 570 } 571 572 static void 573 remove_kmsmouse(scr_stat *scp, int x, int y) 574 { 575 int col, row; 576 int pos; 577 int i; 578 579 /* erase the mouse cursor image */ 580 col = x / scp->font_width - scp->xoff; 581 row = y / scp->font_height - scp->yoff; 582 pos = row * scp->xsize + col; 583 i = (col < scp->xsize - 1) ? 2 : 1; 584 (*scp->rndr->draw)(scp, pos, i, FALSE); 585 if (row < scp->ysize - 1) 586 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 587 } 588 589 static void 590 kms_mouse(scr_stat *scp, int x, int y, int on) 591 { 592 if (on) 593 draw_kmsmouse(scp, x, y); 594 else 595 remove_kmsmouse(scp, x, y); 596 } 597 598 #endif /* SC_NO_CUTPASTE */ 599