1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer as 12 * the first lines of this file unmodified. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Copyright (c) 2000 Andrew Miklic 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "opt_syscons.h" 35 #include "opt_gfb.h" 36 #ifdef __powerpc__ 37 #include "opt_ofwfb.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/fbio.h> 44 #include <sys/consio.h> 45 46 #include <machine/bus.h> 47 48 #include <dev/fb/fbreg.h> 49 #include <dev/syscons/syscons.h> 50 51 #ifndef SC_RENDER_DEBUG 52 #define SC_RENDER_DEBUG 0 53 #endif 54 55 static vr_clear_t gfb_clear; 56 static vr_draw_border_t gfb_border; 57 static vr_draw_t gfb_draw; 58 static vr_set_cursor_t gfb_cursor_shape; 59 static vr_draw_cursor_t gfb_cursor; 60 static vr_blink_cursor_t gfb_blink; 61 #ifndef SC_NO_CUTPASTE 62 static vr_draw_mouse_t gfb_mouse; 63 #else 64 #define gfb_mouse (vr_draw_mouse_t *)gfb_nop 65 #endif 66 67 static void gfb_nop(scr_stat *scp); 68 69 sc_rndr_sw_t txtrndrsw = { 70 (vr_init_t *)gfb_nop, 71 gfb_clear, 72 gfb_border, 73 gfb_draw, 74 gfb_cursor_shape, 75 gfb_cursor, 76 gfb_blink, 77 (vr_set_mouse_t *)gfb_nop, 78 gfb_mouse, 79 }; 80 81 #ifdef SC_PIXEL_MODE 82 sc_rndr_sw_t gfbrndrsw = { 83 (vr_init_t *)gfb_nop, 84 gfb_clear, 85 gfb_border, 86 gfb_draw, 87 gfb_cursor_shape, 88 gfb_cursor, 89 gfb_blink, 90 (vr_set_mouse_t *)gfb_nop, 91 gfb_mouse, 92 }; 93 #endif /* SC_PIXEL_MODE */ 94 95 #ifndef SC_NO_MODE_CHANGE 96 sc_rndr_sw_t grrndrsw = { 97 (vr_init_t *)gfb_nop, 98 (vr_clear_t *)gfb_nop, 99 gfb_border, 100 (vr_draw_t *)gfb_nop, 101 (vr_set_cursor_t *)gfb_nop, 102 (vr_draw_cursor_t *)gfb_nop, 103 (vr_blink_cursor_t *)gfb_nop, 104 (vr_set_mouse_t *)gfb_nop, 105 (vr_draw_mouse_t *)gfb_nop, 106 }; 107 #endif /* SC_NO_MODE_CHANGE */ 108 109 #ifndef SC_NO_CUTPASTE 110 static u_char mouse_pointer[16] = { 111 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68, 112 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 113 }; 114 #endif 115 116 static void 117 gfb_nop(scr_stat *scp) 118 { 119 } 120 121 /* text mode renderer */ 122 123 static void 124 gfb_clear(scr_stat *scp, int c, int attr) 125 { 126 vidd_clear(scp->sc->adp); 127 } 128 129 static void 130 gfb_border(scr_stat *scp, int color) 131 { 132 vidd_set_border(scp->sc->adp, color); 133 } 134 135 static void 136 gfb_draw(scr_stat *scp, int from, int count, int flip) 137 { 138 int c; 139 int a; 140 int i, n; 141 video_adapter_t *adp; 142 143 adp = scp->sc->adp; 144 145 /* 146 Determine if we need to scroll based on the offset 147 and the number of characters to be displayed... 148 */ 149 if (from + count > scp->xsize*scp->ysize) { 150 151 /* 152 Calculate the number of characters past the end of the 153 visible screen... 154 */ 155 count = (from + count) - 156 (adp->va_info.vi_width * adp->va_info.vi_height); 157 158 /* 159 Calculate the number of rows past the end of the visible 160 screen... 161 */ 162 n = (count / adp->va_info.vi_width) + 1; 163 164 /* Scroll to make room for new text rows... */ 165 vidd_copy(adp, n, 0, n); 166 #if 0 167 vidd_clear(adp, n); 168 #endif 169 170 /* Display new text rows... */ 171 vidd_puts(adp, from, 172 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), count); 173 } 174 175 /* 176 We don't need to scroll, so we can just put the characters 177 all-at-once... 178 */ 179 else { 180 181 /* 182 Determine the method by which we are to display characters 183 (are we going to print forwards or backwards? 184 do we need to do a character-by-character copy, then?)... 185 */ 186 if (flip) 187 for (i = count; i-- > 0; ++from) { 188 c = sc_vtb_getc(&scp->vtb, from); 189 a = sc_vtb_geta(&scp->vtb, from) >> 8; 190 vidd_putc(adp, from, c, 191 (a >> 4) | ((a & 0xf) << 4)); 192 } 193 else { 194 vidd_puts(adp, from, 195 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), 196 count); 197 } 198 } 199 } 200 201 static void 202 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink) 203 { 204 if (base < 0 || base >= scp->font_size) 205 return; 206 /* the caller may set height <= 0 in order to disable the cursor */ 207 #if 0 208 scp->cursor_base = base; 209 scp->cursor_height = height; 210 #endif 211 vidd_set_hw_cursor_shape(scp->sc->adp, base, height, scp->font_size, 212 blink); 213 } 214 215 static int pxlblinkrate = 0; 216 217 #if defined(SC_OFWFB) 218 static void 219 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 220 { 221 video_adapter_t *adp; 222 int a, c; 223 224 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 225 return; 226 227 adp = scp->sc->adp; 228 if(blink) { 229 scp->status |= VR_CURSOR_BLINK; 230 if (on) { 231 scp->status |= VR_CURSOR_ON; 232 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 233 } else { 234 if (scp->status & VR_CURSOR_ON) 235 vidd_set_hw_cursor(adp, -1, -1); 236 scp->status &= ~VR_CURSOR_ON; 237 } 238 } else { 239 scp->status &= ~VR_CURSOR_BLINK; 240 if(on) { 241 scp->status |= VR_CURSOR_ON; 242 vidd_putc(scp->sc->adp, scp->cursor_oldpos, 243 sc_vtb_getc(&scp->vtb, scp->cursor_oldpos), 244 sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8); 245 a = sc_vtb_geta(&scp->vtb, at) >> 8; 246 c = sc_vtb_getc(&scp->vtb, at); 247 vidd_putc(scp->sc->adp, at, c, 248 (a >> 4) | ((a & 0xf) << 4)); 249 } else { 250 if (scp->status & VR_CURSOR_ON) 251 vidd_putc(scp->sc->adp, at, 252 sc_vtb_getc(&scp->vtb, at), 253 sc_vtb_geta(&scp->vtb, at) >> 8); 254 scp->status &= ~VR_CURSOR_ON; 255 } 256 } 257 } 258 #else 259 static void 260 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 261 { 262 video_adapter_t *adp; 263 264 adp = scp->sc->adp; 265 if (scp->curs_attr.height <= 0) 266 /* the text cursor is disabled */ 267 return; 268 269 if (on) { 270 if (!blink) { 271 scp->status |= VR_CURSOR_ON; 272 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 273 } else if (++pxlblinkrate & 4) { 274 pxlblinkrate = 0; 275 scp->status ^= VR_CURSOR_ON; 276 if(scp->status & VR_CURSOR_ON) 277 vidd_set_hw_cursor(adp, at%scp->xsize, 278 at/scp->xsize); 279 else 280 vidd_set_hw_cursor(adp, -1, -1); 281 } 282 } else { 283 if (scp->status & VR_CURSOR_ON) 284 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 285 scp->status &= ~VR_CURSOR_ON; 286 } 287 if (blink) 288 scp->status |= VR_CURSOR_BLINK; 289 else 290 scp->status &= ~VR_CURSOR_BLINK; 291 } 292 #endif 293 294 static void 295 gfb_blink(scr_stat *scp, int at, int flip) 296 { 297 if (!(scp->status & VR_CURSOR_BLINK)) 298 return; 299 if (!(++pxlblinkrate & 4)) 300 return; 301 pxlblinkrate = 0; 302 scp->status ^= VR_CURSOR_ON; 303 gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK, 304 scp->status & VR_CURSOR_ON, flip); 305 } 306 307 #ifndef SC_NO_CUTPASTE 308 309 static void 310 gfb_mouse(scr_stat *scp, int x, int y, int on) 311 { 312 if (on) { 313 vidd_putm(scp->sc->adp, x, y, mouse_pointer, 314 0xffffffff, 16, 8); 315 } else { 316 /* XXX: removal is incomplete for h/w cursors and borders. */ 317 } 318 } 319 320 #endif /* SC_NO_CUTPASTE */ 321