1 /*- 2 * Copyright (c) 2014 Imre Vadász <imre@vdsz.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "opt_syscons.h" 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/thread.h> 33 #include <sys/thread2.h> 34 35 #include <machine/console.h> 36 37 #include <dev/drm/include/linux/fb.h> 38 39 #include "syscons.h" 40 41 #include <bus/isa/isareg.h> 42 43 static vr_draw_t kms_draw; 44 static vr_draw_cursor_t kms_cursor; 45 static vr_blink_cursor_t kms_blink; 46 static vr_draw_mouse_t kms_mouse; 47 48 static void kms_nop(scr_stat *scp, ...); 49 50 static sc_rndr_sw_t kmsrndrsw = { 51 (vr_draw_border_t *)kms_nop, 52 kms_draw, 53 (vr_set_cursor_t *)kms_nop, 54 kms_cursor, 55 kms_blink, 56 #ifndef SC_NO_CUTPASTE 57 kms_mouse, 58 #else 59 (vr_draw_mouse_t *)kms_nop; 60 #endif 61 }; 62 RENDERER(kms, V_INFO_MM_TEXT, kmsrndrsw, kms_set); 63 64 #ifndef SC_NO_MODE_CHANGE 65 static sc_rndr_sw_t grrndrsw = { 66 (vr_draw_border_t *)kms_nop, 67 (vr_draw_t *)kms_nop, 68 (vr_set_cursor_t *)kms_nop, 69 (vr_draw_cursor_t *)kms_nop, 70 (vr_blink_cursor_t *)kms_nop, 71 (vr_draw_mouse_t *)kms_nop, 72 }; 73 RENDERER(kms, V_INFO_MM_OTHER, grrndrsw, kms_set); 74 #endif /* SC_NO_MODE_CHANGE */ 75 76 RENDERER_MODULE(kms, kms_set); 77 78 static uint32_t colormap[16] = { 79 0x00000000, /* BLACK */ 80 0x000000aa, /* BLUE */ 81 0x0000aa00, /* GREEN */ 82 0x0000aaaa, /* CYAN */ 83 0x00aa0000, /* RED */ 84 0x00aa00aa, /* MAGENTA */ 85 0x00aa5500, /* BROWN */ 86 0x00aaaaaa, /* WHITE */ 87 0x00555555, /* HIGHLIGHT BLACK */ 88 0x005555ff, /* HIGHLIGHT BLUE */ 89 0x0055ff55, /* HIGHLIGHT GREEN */ 90 0x0055ffff, /* HIGHLIGHT CYAN */ 91 0x00ff5555, /* HIGHLIGHT RED */ 92 0x00ff55ff, /* HIGHLIGHT MAGENTA */ 93 0x00ffff55, /* HIGHLIGHT BROWN */ 94 0x00ffffff, /* HIGHLIGHT WHITE */ 95 }; 96 97 #ifndef SC_NO_CUTPASTE 98 static u_short mouse_and_mask[16] = { 99 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 100 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 101 }; 102 static u_short mouse_or_mask[16] = { 103 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 104 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 105 }; 106 #endif 107 108 static void 109 kms_nop(scr_stat *scp, ...) 110 { 111 } 112 113 /* KMS renderer */ 114 115 static void 116 kms_draw(scr_stat *scp, int from, int count, int flip) 117 { 118 sc_softc_t *sc = scp->sc; 119 u_char *char_data; 120 int a, i, j; 121 uint32_t fg, bg; 122 vm_offset_t draw_pos, p; 123 int pos, line_width, pixel_size; 124 125 line_width = sc->fbi->stride; 126 pixel_size = 4; 127 128 draw_pos = sc->fbi->vaddr + 129 8 * pixel_size * (from % scp->xsize) + 130 scp->font_size * line_width * (from / scp->xsize); 131 132 if (from + count > scp->xsize * scp->ysize) 133 count = scp->xsize * scp->ysize - from; 134 135 for (i = from; count-- > 0; i++) { 136 p = draw_pos; 137 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 138 scp->font_size]); 139 140 a = sc_vtb_geta(&scp->vtb, i); 141 if (flip) { 142 fg = colormap[((a & 0xf000) >> 4) >> 8]; 143 bg = colormap[(a & 0x0f00) >> 8]; 144 } else { 145 fg = colormap[(a & 0x0f00) >> 8]; 146 bg = colormap[((a & 0xf000) >> 4) >> 8]; 147 } 148 149 for (j = 0; j < scp->font_size; j++, char_data++) { 150 for (pos = 7; pos >= 0; pos--, p += pixel_size) 151 writel(p, *char_data & (1 << pos) ? fg : bg); 152 p += line_width - 8 * pixel_size; 153 } 154 draw_pos += 8 * pixel_size; 155 if ((i % scp->xsize) == scp->xsize - 1) { 156 draw_pos += (scp->font_size - 1) * line_width + 157 scp->xpad * pixel_size; 158 } 159 } 160 } 161 162 static void 163 draw_kmscursor(scr_stat *scp, int at, int on, int flip) 164 { 165 sc_softc_t *sc = scp->sc; 166 int line_width, pixel_size, height; 167 int a, i, pos; 168 uint32_t fg, bg; 169 unsigned char *char_data; 170 vm_offset_t draw_pos; 171 172 line_width = sc->fbi->stride; 173 pixel_size = 4; 174 175 draw_pos = sc->fbi->vaddr + 176 8 * pixel_size * (at % scp->xsize) + 177 scp->font_size * line_width * (at / scp->xsize) + 178 (scp->font_size - scp->cursor_base - 1) * line_width; 179 180 a = sc_vtb_geta(&scp->vtb, at); 181 if (flip) { 182 fg = colormap[((on) ? (a & 0x0f00) : 183 ((a & 0xf000) >> 4)) >> 8]; 184 bg = colormap[((on) ? ((a & 0xf000) >> 4) : 185 (a & 0x0f00)) >> 8]; 186 } else { 187 fg = colormap[((on) ? ((a & 0xf000) >> 4) : 188 (a & 0x0f00)) >> 8]; 189 bg = colormap[((on) ? (a & 0x0f00) : 190 ((a & 0xf000) >> 4)) >> 8]; 191 } 192 193 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 194 scp->font_size - scp->cursor_base - 1]); 195 height = imin(scp->cursor_height, scp->font_size); 196 197 for (i = 0; i < height; i++, char_data--) { 198 for (pos = 7; pos >= 0; pos--, draw_pos += pixel_size) 199 writel(draw_pos, *char_data & (1 << pos) ? fg : bg); 200 draw_pos -= line_width + 8 * pixel_size; 201 } 202 } 203 204 static int pxlblinkrate = 0; 205 206 static void 207 kms_cursor(scr_stat *scp, int at, int blink, int on, int flip) 208 { 209 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 210 return; 211 212 if (on) { 213 if (!blink) { 214 scp->status |= VR_CURSOR_ON; 215 draw_kmscursor(scp, at, on, flip); 216 } else if (++pxlblinkrate & 4) { 217 pxlblinkrate = 0; 218 scp->status ^= VR_CURSOR_ON; 219 draw_kmscursor(scp, at, 220 scp->status & VR_CURSOR_ON, flip); 221 } 222 } else { 223 if (scp->status & VR_CURSOR_ON) 224 draw_kmscursor(scp, at, on, flip); 225 scp->status &= ~VR_CURSOR_ON; 226 } 227 if (blink) 228 scp->status |= VR_CURSOR_BLINK; 229 else 230 scp->status &= ~VR_CURSOR_BLINK; 231 } 232 233 static void 234 kms_blink(scr_stat *scp, int at, int flip) 235 { 236 if (!(scp->status & VR_CURSOR_BLINK)) 237 return; 238 if (!(++pxlblinkrate & 4)) 239 return; 240 pxlblinkrate = 0; 241 scp->status ^= VR_CURSOR_ON; 242 draw_kmscursor(scp, at, scp->status & VR_CURSOR_ON, flip); 243 } 244 245 #ifndef SC_NO_CUTPASTE 246 247 static void 248 draw_kmsmouse(scr_stat *scp, int x, int y) 249 { 250 sc_softc_t *sc = scp->sc; 251 int line_width, pixel_size; 252 int xend, yend; 253 int i, j; 254 vm_offset_t draw_pos; 255 256 line_width = sc->fbi->stride; 257 pixel_size = 4; 258 259 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 260 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 261 262 draw_pos = sc->fbi->vaddr + y * line_width + x * pixel_size; 263 264 for (i = 0; i < (yend - y); i++) { 265 for (j = (xend - x - 1); j >= 0; j--) { 266 if (mouse_or_mask[i] & 1 << (15 - j)) 267 writel(draw_pos + pixel_size * j, colormap[15]); 268 else if (mouse_and_mask[i] & 1 << (15 - j)) 269 writel(draw_pos + pixel_size * j, colormap[0]); 270 } 271 272 draw_pos += line_width; 273 } 274 } 275 276 static void 277 remove_kmsmouse(scr_stat *scp, int x, int y) 278 { 279 int col, row; 280 int pos; 281 int i; 282 283 /* erase the mouse cursor image */ 284 col = x/8 - scp->xoff; 285 row = y/scp->font_size - scp->yoff; 286 pos = row*scp->xsize + col; 287 i = (col < scp->xsize - 1) ? 2 : 1; 288 (*scp->rndr->draw)(scp, pos, i, FALSE); 289 if (row < scp->ysize - 1) 290 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 291 } 292 293 static void 294 kms_mouse(scr_stat *scp, int x, int y, int on) 295 { 296 if (on) 297 draw_kmsmouse(scp, x, y); 298 else 299 remove_kmsmouse(scp, x, y); 300 } 301 302 #endif /* SC_NO_CUTPASTE */ 303