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 void 136 blit_blk(scr_stat *scp, u_char *char_data, int sw, int sh, 137 vm_offset_t draw_pos, int pixel_size, 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, (c & (1 << pos) ? fg : bg)); 182 p += pixel_size; 183 sx += sx_inc; 184 } 185 break; 186 case BLIT_MASK: 187 for (x = 0; x < dw; ++x) { 188 if ((sx & 0x00070000) == 0) 189 c = char_data[sx >> 19]; 190 pos = ~(sx >> 16) & 7; 191 if (c & (1 << pos)) 192 writel(p, fg); 193 p += pixel_size; 194 sx += sx_inc; 195 } 196 break; 197 } 198 draw_pos += line_width; 199 sy += sy_inc; 200 if (sy >= 0x10000) { 201 char_data += (sy >> 16) * (sw >> 3); 202 sy &= 0x0FFFF; 203 } 204 } 205 } 206 207 static void 208 fill_rect(scr_stat *scp, vm_offset_t draw_pos, int pixel_size, 209 int width, int height, int line_width, uint32_t fg) 210 { 211 int i, j; 212 213 for (i = 0; i < height; i++) { 214 for (j = 0; j < width; j++) 215 writel(draw_pos + j * pixel_size, fg); 216 draw_pos += line_width; 217 } 218 } 219 220 /* KMS renderer */ 221 222 static void 223 kms_draw_border(scr_stat *scp, int color) 224 { 225 sc_softc_t *sc = scp->sc; 226 int line_width, pixel_size; 227 int rightpixel, bottompixel; 228 uint32_t fg; 229 vm_offset_t draw_pos; 230 231 fg = colormap[color]; 232 line_width = sc->fbi->stride; 233 pixel_size = 4; 234 rightpixel = sc->fbi->width - scp->xsize * scp->blk_width; 235 bottompixel = sc->fbi->height - scp->ysize * scp->blk_height; 236 237 if (sc->fbi->vaddr == 0) 238 return; 239 240 draw_pos = sc->fbi->vaddr + scp->blk_width * pixel_size * scp->xsize; 241 fill_rect(scp, draw_pos, pixel_size, rightpixel, 242 scp->blk_height * scp->ysize, line_width, fg); 243 244 draw_pos = sc->fbi->vaddr + scp->blk_height * scp->ysize * line_width; 245 fill_rect(scp, draw_pos, pixel_size, sc->fbi->width, 246 sc->fbi->height - scp->blk_height * scp->ysize, line_width, fg); 247 } 248 249 static void 250 kms_draw(scr_stat *scp, int from, int count, int flip) 251 { 252 sc_softc_t *sc = scp->sc; 253 u_char *char_data; 254 int a, i; 255 uint32_t fg, bg; 256 vm_offset_t draw_pos, p; 257 int line_width, pixel_size; 258 259 line_width = sc->fbi->stride; 260 pixel_size = 4; 261 262 if (sc->fbi->vaddr == 0) 263 return; 264 265 draw_pos = sc->fbi->vaddr + 266 scp->blk_height * line_width * (from / scp->xsize); 267 268 if (from + count > scp->xsize * scp->ysize) 269 count = scp->xsize * scp->ysize - from; 270 271 p = draw_pos + scp->blk_width * pixel_size * (from % scp->xsize); 272 for (i = from; count-- > 0; i++) { 273 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 274 scp->font_height]); 275 276 a = sc_vtb_geta(&scp->vtb, i); 277 if (flip) { 278 fg = colormap[((a & 0xf000) >> 4) >> 8]; 279 bg = colormap[(a & 0x0f00) >> 8]; 280 } else { 281 fg = colormap[(a & 0x0f00) >> 8]; 282 bg = colormap[((a & 0xf000) >> 4) >> 8]; 283 } 284 blit_blk(scp, char_data, scp->font_width, scp->font_height, 285 p, pixel_size, scp->blk_width, scp->blk_height, 286 line_width, fg, bg, BLIT_SET); 287 p += scp->blk_width * pixel_size; 288 if ((i % scp->xsize) == scp->xsize - 1) { 289 draw_pos += scp->blk_height * line_width; 290 p = draw_pos; 291 } 292 } 293 } 294 295 static void 296 draw_kmscursor(scr_stat *scp, int at, int on, int flip) 297 { 298 sc_softc_t *sc = scp->sc; 299 int line_width, pixel_size; 300 int cursor_base; 301 int blk_base; 302 int a; 303 uint32_t fg, bg; 304 unsigned char *char_data; 305 vm_offset_t draw_pos; 306 307 line_width = sc->fbi->stride; 308 pixel_size = 4; 309 cursor_base = /* scp->font_height - */ scp->cursor_base; 310 blk_base = scp->blk_height * cursor_base / scp->font_height; 311 312 if (sc->fbi->vaddr == 0) 313 return; 314 315 draw_pos = sc->fbi->vaddr + 316 scp->blk_width * pixel_size * (at % scp->xsize) + 317 scp->blk_height * line_width * (at / scp->xsize) + 318 blk_base * line_width; 319 320 a = sc_vtb_geta(&scp->vtb, at); 321 if (flip) { 322 fg = colormap[((on) ? (a & 0x0f00) : 323 ((a & 0xf000) >> 4)) >> 8]; 324 bg = colormap[((on) ? ((a & 0xf000) >> 4) : 325 (a & 0x0f00)) >> 8]; 326 } else { 327 fg = colormap[((on) ? ((a & 0xf000) >> 4) : 328 (a & 0x0f00)) >> 8]; 329 bg = colormap[((on) ? (a & 0x0f00) : 330 ((a & 0xf000) >> 4)) >> 8]; 331 } 332 333 char_data = &scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_height]; 334 char_data += cursor_base; 335 336 blit_blk(scp, char_data, 337 scp->font_width, scp->font_height - cursor_base, 338 draw_pos, pixel_size, 339 scp->blk_width, scp->blk_height - blk_base, 340 line_width, fg, bg, BLIT_SET); 341 } 342 343 static int pxlblinkrate = 0; 344 345 static void 346 kms_cursor(scr_stat *scp, int at, int blink, int on, int flip) 347 { 348 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 349 return; 350 351 if (on) { 352 if (!blink) { 353 scp->status |= VR_CURSOR_ON; 354 draw_kmscursor(scp, at, on, flip); 355 } else if (++pxlblinkrate & 4) { 356 pxlblinkrate = 0; 357 scp->status ^= VR_CURSOR_ON; 358 draw_kmscursor(scp, at, 359 scp->status & VR_CURSOR_ON, flip); 360 } 361 } else { 362 if (scp->status & VR_CURSOR_ON) 363 draw_kmscursor(scp, at, on, flip); 364 scp->status &= ~VR_CURSOR_ON; 365 } 366 if (blink) 367 scp->status |= VR_CURSOR_BLINK; 368 else 369 scp->status &= ~VR_CURSOR_BLINK; 370 } 371 372 static void 373 kms_blink(scr_stat *scp, int at, int flip) 374 { 375 if (!(scp->status & VR_CURSOR_BLINK)) 376 return; 377 if (!(++pxlblinkrate & 4)) 378 return; 379 pxlblinkrate = 0; 380 scp->status ^= VR_CURSOR_ON; 381 draw_kmscursor(scp, at, scp->status & VR_CURSOR_ON, flip); 382 } 383 384 #ifndef SC_NO_CUTPASTE 385 386 static void 387 draw_kmsmouse(scr_stat *scp, int x, int y) 388 { 389 sc_softc_t *sc = scp->sc; 390 int line_width, pixel_size; 391 int blk_width, blk_height; 392 vm_offset_t draw_pos; 393 394 line_width = sc->fbi->stride; 395 pixel_size = 4; 396 397 if (sc->fbi->vaddr == 0) 398 return; 399 400 if (x + scp->font_width < scp->font_width * scp->xsize) 401 blk_width = scp->blk_width; 402 else 403 blk_width = scp->font_width * scp->xsize - x; 404 405 if (y + scp->font_height < scp->font_height * scp->ysize) 406 blk_height = scp->blk_height; 407 else 408 blk_height = scp->font_height * scp->ysize - y; 409 410 draw_pos = sc->fbi->vaddr + y * scp->blk_height / scp->font_height * 411 line_width + 412 x * scp->blk_width / scp->font_width * pixel_size; 413 blit_blk(scp, (unsigned char *)mouse_and_mask, 16, 16, 414 draw_pos, pixel_size, blk_width, blk_height, 415 line_width, colormap[0], 0, BLIT_MASK); 416 blit_blk(scp, (unsigned char *)mouse_or_mask, 16, 16, 417 draw_pos, pixel_size, blk_width, blk_height, 418 line_width, colormap[15], 0, BLIT_MASK); 419 } 420 421 static void 422 remove_kmsmouse(scr_stat *scp, int x, int y) 423 { 424 int col, row; 425 int pos; 426 int i; 427 428 /* erase the mouse cursor image */ 429 col = x / scp->font_width - scp->xoff; 430 row = y / scp->font_height - scp->yoff; 431 pos = row * scp->xsize + col; 432 i = (col < scp->xsize - 1) ? 2 : 1; 433 (*scp->rndr->draw)(scp, pos, i, FALSE); 434 if (row < scp->ysize - 1) 435 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 436 } 437 438 static void 439 kms_mouse(scr_stat *scp, int x, int y, int on) 440 { 441 if (on) 442 draw_kmsmouse(scp, x, y); 443 else 444 remove_kmsmouse(scp, x, y); 445 } 446 447 #endif /* SC_NO_CUTPASTE */ 448