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