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 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 vidd_copy(adp, n, 0, n); 165 #if 0 166 vidd_clear(adp, n); 167 #endif 168 169 /* Display new text rows... */ 170 vidd_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 Determine the method by which we are to display characters 181 (are we going to print forwards or backwards? 182 do we need to do a character-by-character copy, then?)... 183 */ 184 if (flip) 185 for (i = count; i-- > 0; ++from) { 186 c = sc_vtb_getc(&scp->vtb, from); 187 a = sc_vtb_geta(&scp->vtb, from) >> 8; 188 vidd_putc(adp, from, c, 189 (a >> 4) | ((a & 0xf) << 4)); 190 } 191 else { 192 vidd_puts(adp, from, 193 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), 194 count); 195 } 196 } 197 } 198 199 static void 200 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink) 201 { 202 if (base < 0 || base >= scp->font_size) 203 return; 204 /* the caller may set height <= 0 in order to disable the cursor */ 205 #if 0 206 scp->cursor_base = base; 207 scp->cursor_height = height; 208 #endif 209 vidd_set_hw_cursor_shape(scp->sc->adp, base, height, scp->font_size, 210 blink); 211 } 212 213 static int pxlblinkrate = 0; 214 215 #if defined(SC_OFWFB) 216 static void 217 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 218 { 219 video_adapter_t *adp; 220 int a, c; 221 222 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 223 return; 224 225 adp = scp->sc->adp; 226 if(blink) { 227 scp->status |= VR_CURSOR_BLINK; 228 if (on) { 229 scp->status |= VR_CURSOR_ON; 230 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 231 } else { 232 if (scp->status & VR_CURSOR_ON) 233 vidd_set_hw_cursor(adp, -1, -1); 234 scp->status &= ~VR_CURSOR_ON; 235 } 236 } else { 237 scp->status &= ~VR_CURSOR_BLINK; 238 if(on) { 239 scp->status |= VR_CURSOR_ON; 240 vidd_putc(scp->sc->adp, scp->cursor_oldpos, 241 sc_vtb_getc(&scp->vtb, scp->cursor_oldpos), 242 sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8); 243 a = sc_vtb_geta(&scp->vtb, at) >> 8; 244 c = sc_vtb_getc(&scp->vtb, at); 245 vidd_putc(scp->sc->adp, at, c, 246 (a >> 4) | ((a & 0xf) << 4)); 247 } else { 248 if (scp->status & VR_CURSOR_ON) 249 vidd_putc(scp->sc->adp, at, 250 sc_vtb_getc(&scp->vtb, at), 251 sc_vtb_geta(&scp->vtb, at) >> 8); 252 scp->status &= ~VR_CURSOR_ON; 253 } 254 } 255 } 256 #else 257 static void 258 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 259 { 260 video_adapter_t *adp; 261 262 adp = scp->sc->adp; 263 if (scp->curs_attr.height <= 0) 264 /* the text cursor is disabled */ 265 return; 266 267 if (on) { 268 if (!blink) { 269 scp->status |= VR_CURSOR_ON; 270 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 271 } else if (++pxlblinkrate & 4) { 272 pxlblinkrate = 0; 273 scp->status ^= VR_CURSOR_ON; 274 if(scp->status & VR_CURSOR_ON) 275 vidd_set_hw_cursor(adp, at%scp->xsize, 276 at/scp->xsize); 277 else 278 vidd_set_hw_cursor(adp, -1, -1); 279 } 280 } else { 281 if (scp->status & VR_CURSOR_ON) 282 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 283 scp->status &= ~VR_CURSOR_ON; 284 } 285 if (blink) 286 scp->status |= VR_CURSOR_BLINK; 287 else 288 scp->status &= ~VR_CURSOR_BLINK; 289 } 290 #endif 291 292 static void 293 gfb_blink(scr_stat *scp, int at, int flip) 294 { 295 if (!(scp->status & VR_CURSOR_BLINK)) 296 return; 297 if (!(++pxlblinkrate & 4)) 298 return; 299 pxlblinkrate = 0; 300 scp->status ^= VR_CURSOR_ON; 301 gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK, 302 scp->status & VR_CURSOR_ON, flip); 303 } 304 305 #ifndef SC_NO_CUTPASTE 306 307 static void 308 gfb_mouse(scr_stat *scp, int x, int y, int on) 309 { 310 if (on) { 311 vidd_putm(scp->sc->adp, x, y, mouse_pointer, 312 0xffffffff, 16, 8); 313 } else { 314 /* XXX: removal is incomplete for h/w cursors and borders. */ 315 } 316 } 317 318 #endif /* SC_NO_CUTPASTE */ 319