1 /*- 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 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 * Copyright (c) 2000 Andrew Miklic 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_syscons.h" 33 #include "opt_gfb.h" 34 #ifdef __powerpc__ 35 #include "opt_ofwfb.h" 36 #endif 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/fbio.h> 42 #include <sys/consio.h> 43 44 #include <machine/bus.h> 45 46 #include <dev/fb/fbreg.h> 47 #include <dev/syscons/syscons.h> 48 49 #ifndef SC_RENDER_DEBUG 50 #define SC_RENDER_DEBUG 0 51 #endif 52 53 static vr_clear_t gfb_clear; 54 static vr_draw_border_t gfb_border; 55 static vr_draw_t gfb_draw; 56 static vr_set_cursor_t gfb_cursor_shape; 57 static vr_draw_cursor_t gfb_cursor; 58 static vr_blink_cursor_t gfb_blink; 59 #ifndef SC_NO_CUTPASTE 60 static vr_draw_mouse_t gfb_mouse; 61 #else 62 #define gfb_mouse (vr_draw_mouse_t *)gfb_nop 63 #endif 64 65 static void gfb_nop(scr_stat *scp); 66 67 sc_rndr_sw_t txtrndrsw = { 68 (vr_init_t *)gfb_nop, 69 gfb_clear, 70 gfb_border, 71 gfb_draw, 72 gfb_cursor_shape, 73 gfb_cursor, 74 gfb_blink, 75 (vr_set_mouse_t *)gfb_nop, 76 gfb_mouse, 77 }; 78 79 #ifdef SC_PIXEL_MODE 80 sc_rndr_sw_t gfbrndrsw = { 81 (vr_init_t *)gfb_nop, 82 gfb_clear, 83 gfb_border, 84 gfb_draw, 85 gfb_cursor_shape, 86 gfb_cursor, 87 gfb_blink, 88 (vr_set_mouse_t *)gfb_nop, 89 gfb_mouse, 90 }; 91 #endif /* SC_PIXEL_MODE */ 92 93 #ifndef SC_NO_MODE_CHANGE 94 sc_rndr_sw_t grrndrsw = { 95 (vr_init_t *)gfb_nop, 96 (vr_clear_t *)gfb_nop, 97 gfb_border, 98 (vr_draw_t *)gfb_nop, 99 (vr_set_cursor_t *)gfb_nop, 100 (vr_draw_cursor_t *)gfb_nop, 101 (vr_blink_cursor_t *)gfb_nop, 102 (vr_set_mouse_t *)gfb_nop, 103 (vr_draw_mouse_t *)gfb_nop, 104 }; 105 #endif /* SC_NO_MODE_CHANGE */ 106 107 #ifndef SC_NO_CUTPASTE 108 109 static u_char mouse_pointer[16] = { 110 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68, 111 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 112 }; 113 #endif 114 115 static void 116 gfb_nop(scr_stat *scp) 117 { 118 } 119 120 /* text mode renderer */ 121 122 static void 123 gfb_clear(scr_stat *scp, int c, int attr) 124 { 125 (*vidsw[scp->sc->adapter]->clear)(scp->sc->adp); 126 } 127 128 static void 129 gfb_border(scr_stat *scp, int color) 130 { 131 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 132 } 133 134 static void 135 gfb_draw(scr_stat *scp, int from, int count, int flip) 136 { 137 int c; 138 int a; 139 int i, n; 140 video_adapter_t *adp; 141 142 adp = scp->sc->adp; 143 144 /* 145 Determine if we need to scroll based on the offset 146 and the number of characters to be displayed... 147 */ 148 if (from + count > scp->xsize*scp->ysize) { 149 150 /* 151 Calculate the number of characters past the end of the 152 visible screen... 153 */ 154 count = (from + count) - 155 (adp->va_info.vi_width * adp->va_info.vi_height); 156 157 /* 158 Calculate the number of rows past the end of the visible 159 screen... 160 */ 161 n = (count / adp->va_info.vi_width) + 1; 162 163 /* Scroll to make room for new text rows... */ 164 (*vidsw[scp->sc->adapter]->copy)(adp, n, 0, n); 165 #if 0 166 (*vidsw[scp->sc->adapter]->clear)(adp, n); 167 #endif 168 169 /* Display new text rows... */ 170 (*vidsw[scp->sc->adapter]->puts)(adp, from, 171 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), count); 172 } 173 174 /* 175 We don't need to scroll, so we can just put the characters 176 all-at-once... 177 */ 178 else { 179 180 /* 181 Determine the method by which we are to display characters 182 (are we going to print forwards or backwards? 183 do we need to do a character-by-character copy, then?)... 184 */ 185 if (flip) 186 for (i = count; i-- > 0; ++from) { 187 c = sc_vtb_getc(&scp->vtb, from); 188 a = sc_vtb_geta(&scp->vtb, from) >> 8; 189 (*vidsw[scp->sc->adapter]->putc)(adp, from, c, 190 (a >> 4) | ((a & 0xf) << 4)); 191 } 192 else { 193 (*vidsw[scp->sc->adapter]->puts)(adp, from, 194 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), 195 count); 196 } 197 } 198 } 199 200 static void 201 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink) 202 { 203 if (base < 0 || base >= scp->font_size) 204 return; 205 /* the caller may set height <= 0 in order to disable the cursor */ 206 #if 0 207 scp->cursor_base = base; 208 scp->cursor_height = height; 209 #endif 210 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 211 base, height, scp->font_size, blink); 212 } 213 214 static int pxlblinkrate = 0; 215 216 #if defined(__sparc64__) || defined(SC_OFWFB) 217 static void 218 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 219 { 220 video_adapter_t *adp; 221 int a, c; 222 223 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 224 return; 225 226 adp = scp->sc->adp; 227 if(blink) { 228 scp->status |= VR_CURSOR_BLINK; 229 if (on) { 230 scp->status |= VR_CURSOR_ON; 231 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 232 at%scp->xsize, 233 at/scp->xsize); 234 } else { 235 if (scp->status & VR_CURSOR_ON) 236 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, 237 -1); 238 scp->status &= ~VR_CURSOR_ON; 239 } 240 } else { 241 scp->status &= ~VR_CURSOR_BLINK; 242 if(on) { 243 scp->status |= VR_CURSOR_ON; 244 (*vidsw[scp->sc->adapter]->putc)(scp->sc->adp, 245 scp->cursor_oldpos, 246 sc_vtb_getc(&scp->vtb, scp->cursor_oldpos), 247 sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8); 248 a = sc_vtb_geta(&scp->vtb, at) >> 8; 249 c = sc_vtb_getc(&scp->vtb, at); 250 (*vidsw[scp->sc->adapter]->putc)(scp->sc->adp, at, 251 c, (a >> 4) | ((a & 0xf) << 4)); 252 scp->cursor_saveunder_attr = a; 253 scp->cursor_saveunder_char = c; 254 } else { 255 if (scp->status & VR_CURSOR_ON) 256 (*vidsw[scp->sc->adapter]->putc)(scp->sc->adp, 257 at, scp->cursor_saveunder_char, 258 scp->cursor_saveunder_attr); 259 scp->status &= ~VR_CURSOR_ON; 260 } 261 } 262 } 263 #else 264 static void 265 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 266 { 267 video_adapter_t *adp; 268 269 adp = scp->sc->adp; 270 if (scp->curs_attr.height <= 0) 271 /* the text cursor is disabled */ 272 return; 273 274 if (on) { 275 if (!blink) { 276 scp->status |= VR_CURSOR_ON; 277 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 278 at%scp->xsize, at/scp->xsize); 279 } else if (++pxlblinkrate & 4) { 280 pxlblinkrate = 0; 281 scp->status ^= VR_CURSOR_ON; 282 if(scp->status & VR_CURSOR_ON) 283 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 284 at%scp->xsize, at/scp->xsize); 285 else 286 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, 287 -1); 288 } 289 } else { 290 if (scp->status & VR_CURSOR_ON) 291 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 292 at%scp->xsize, at/scp->xsize); 293 scp->status &= ~VR_CURSOR_ON; 294 } 295 if (blink) 296 scp->status |= VR_CURSOR_BLINK; 297 else 298 scp->status &= ~VR_CURSOR_BLINK; 299 } 300 #endif 301 302 static void 303 gfb_blink(scr_stat *scp, int at, int flip) 304 { 305 if (!(scp->status & VR_CURSOR_BLINK)) 306 return; 307 if (!(++pxlblinkrate & 4)) 308 return; 309 pxlblinkrate = 0; 310 scp->status ^= VR_CURSOR_ON; 311 gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK, 312 scp->status & VR_CURSOR_ON, flip); 313 } 314 315 #ifndef SC_NO_CUTPASTE 316 317 static void 318 gfb_mouse(scr_stat *scp, int x, int y, int on) 319 { 320 int i, pos; 321 322 if (on) { 323 324 /* Display the mouse pointer image... */ 325 (*vidsw[scp->sc->adapter]->putm)(scp->sc->adp, x, y, 326 mouse_pointer, 0xffffffff, 16, 8); 327 } else { 328 329 /* 330 Erase the mouse cursor image by redrawing the text 331 underneath it... 332 */ 333 return; 334 pos = x*scp->xsize + y; 335 i = (y < scp->xsize - 1) ? 2 : 1; 336 (*scp->rndr->draw)(scp, pos, i, FALSE); 337 if (x < scp->ysize - 1) 338 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 339 } 340 } 341 342 #endif /* SC_NO_CUTPASTE */ 343