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 42 #include <dev/drm/include/linux/fb.h> 43 44 #include "syscons.h" 45 46 #include <bus/isa/isareg.h> 47 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 (vr_draw_border_t *)kms_nop, 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 /* KMS renderer */ 208 209 static void 210 kms_draw(scr_stat *scp, int from, int count, int flip) 211 { 212 sc_softc_t *sc = scp->sc; 213 u_char *char_data; 214 int a, i; 215 uint32_t fg, bg; 216 vm_offset_t draw_pos, p; 217 int line_width, pixel_size; 218 219 line_width = sc->fbi->stride; 220 pixel_size = 4; 221 222 draw_pos = sc->fbi->vaddr + 223 scp->blk_width * pixel_size * (from % scp->xsize) + 224 scp->blk_height * line_width * (from / scp->xsize); 225 226 if (from + count > scp->xsize * scp->ysize) 227 count = scp->xsize * scp->ysize - from; 228 229 for (i = from; count-- > 0; i++) { 230 p = draw_pos; 231 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 232 scp->font_height]); 233 234 a = sc_vtb_geta(&scp->vtb, i); 235 if (flip) { 236 fg = colormap[((a & 0xf000) >> 4) >> 8]; 237 bg = colormap[(a & 0x0f00) >> 8]; 238 } else { 239 fg = colormap[(a & 0x0f00) >> 8]; 240 bg = colormap[((a & 0xf000) >> 4) >> 8]; 241 } 242 blit_blk(scp, char_data, scp->font_width, scp->font_height, 243 p, pixel_size, scp->blk_width, scp->blk_height, 244 line_width, fg, bg, BLIT_SET); 245 draw_pos += scp->blk_width * pixel_size; 246 if ((i % scp->xsize) == scp->xsize - 1) { 247 draw_pos += 248 (scp->blk_height - 1) * line_width + 249 scp->xpad * pixel_size; 250 } 251 } 252 } 253 254 static void 255 draw_kmscursor(scr_stat *scp, int at, int on, int flip) 256 { 257 sc_softc_t *sc = scp->sc; 258 int line_width, pixel_size; 259 int cursor_base; 260 int blk_base; 261 int a; 262 uint32_t fg, bg; 263 unsigned char *char_data; 264 vm_offset_t draw_pos; 265 266 line_width = sc->fbi->stride; 267 pixel_size = 4; 268 cursor_base = /* scp->font_height - */ scp->cursor_base; 269 blk_base = scp->blk_height * cursor_base / scp->font_height; 270 271 draw_pos = sc->fbi->vaddr + 272 scp->blk_width * pixel_size * (at % scp->xsize) + 273 scp->blk_height * line_width * (at / scp->xsize) + 274 blk_base * line_width; 275 276 a = sc_vtb_geta(&scp->vtb, at); 277 if (flip) { 278 fg = colormap[((on) ? (a & 0x0f00) : 279 ((a & 0xf000) >> 4)) >> 8]; 280 bg = colormap[((on) ? ((a & 0xf000) >> 4) : 281 (a & 0x0f00)) >> 8]; 282 } else { 283 fg = colormap[((on) ? ((a & 0xf000) >> 4) : 284 (a & 0x0f00)) >> 8]; 285 bg = colormap[((on) ? (a & 0x0f00) : 286 ((a & 0xf000) >> 4)) >> 8]; 287 } 288 289 char_data = &scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_height]; 290 char_data += cursor_base; 291 292 blit_blk(scp, char_data, 293 scp->font_width, scp->font_height - cursor_base, 294 draw_pos, pixel_size, 295 scp->blk_width, scp->blk_height - blk_base, 296 line_width, fg, bg, BLIT_SET); 297 } 298 299 static int pxlblinkrate = 0; 300 301 static void 302 kms_cursor(scr_stat *scp, int at, int blink, int on, int flip) 303 { 304 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 305 return; 306 307 if (on) { 308 if (!blink) { 309 scp->status |= VR_CURSOR_ON; 310 draw_kmscursor(scp, at, on, flip); 311 } else if (++pxlblinkrate & 4) { 312 pxlblinkrate = 0; 313 scp->status ^= VR_CURSOR_ON; 314 draw_kmscursor(scp, at, 315 scp->status & VR_CURSOR_ON, flip); 316 } 317 } else { 318 if (scp->status & VR_CURSOR_ON) 319 draw_kmscursor(scp, at, on, flip); 320 scp->status &= ~VR_CURSOR_ON; 321 } 322 if (blink) 323 scp->status |= VR_CURSOR_BLINK; 324 else 325 scp->status &= ~VR_CURSOR_BLINK; 326 } 327 328 static void 329 kms_blink(scr_stat *scp, int at, int flip) 330 { 331 if (!(scp->status & VR_CURSOR_BLINK)) 332 return; 333 if (!(++pxlblinkrate & 4)) 334 return; 335 pxlblinkrate = 0; 336 scp->status ^= VR_CURSOR_ON; 337 draw_kmscursor(scp, at, scp->status & VR_CURSOR_ON, flip); 338 } 339 340 #ifndef SC_NO_CUTPASTE 341 342 static void 343 draw_kmsmouse(scr_stat *scp, int x, int y) 344 { 345 sc_softc_t *sc = scp->sc; 346 int line_width, pixel_size; 347 int blk_width, blk_height; 348 vm_offset_t draw_pos; 349 350 line_width = sc->fbi->stride; 351 pixel_size = 4; 352 353 if (x + scp->font_width < scp->font_width * scp->xsize) 354 blk_width = scp->blk_width; 355 else 356 blk_width = scp->font_width * scp->xsize - x; 357 358 if (y + scp->font_height < scp->font_height * scp->ysize) 359 blk_height = scp->blk_height; 360 else 361 blk_height = scp->font_height * scp->ysize - y; 362 363 draw_pos = sc->fbi->vaddr + y * scp->blk_height / scp->font_height * 364 line_width + 365 x * scp->blk_width / scp->font_width * pixel_size; 366 blit_blk(scp, (unsigned char *)mouse_and_mask, 16, 16, 367 draw_pos, pixel_size, blk_width, blk_height, 368 line_width, colormap[0], 0, BLIT_MASK); 369 blit_blk(scp, (unsigned char *)mouse_or_mask, 16, 16, 370 draw_pos, pixel_size, blk_width, blk_height, 371 line_width, colormap[15], 0, BLIT_MASK); 372 } 373 374 static void 375 remove_kmsmouse(scr_stat *scp, int x, int y) 376 { 377 int col, row; 378 int pos; 379 int i; 380 381 /* erase the mouse cursor image */ 382 col = x / scp->font_width - scp->xoff; 383 row = y / scp->font_height - scp->yoff; 384 pos = row * scp->xsize + col; 385 i = (col < scp->xsize - 1) ? 2 : 1; 386 (*scp->rndr->draw)(scp, pos, i, FALSE); 387 if (row < scp->ysize - 1) 388 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 389 } 390 391 static void 392 kms_mouse(scr_stat *scp, int x, int y, int on) 393 { 394 if (on) 395 draw_kmsmouse(scp, x, y); 396 else 397 remove_kmsmouse(scp, x, y); 398 } 399 400 #endif /* SC_NO_CUTPASTE */ 401