1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 #ifdef __powerpc__ 36 #include "opt_ofwfb.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/fbio.h> 43 #include <sys/consio.h> 44 45 #include <machine/bus.h> 46 47 #include <dev/fb/fbreg.h> 48 #include <dev/syscons/syscons.h> 49 50 #ifndef SC_RENDER_DEBUG 51 #define SC_RENDER_DEBUG 0 52 #endif 53 54 static vr_clear_t gfb_clear; 55 static vr_draw_border_t gfb_border; 56 static vr_draw_t gfb_draw; 57 static vr_set_cursor_t gfb_cursor_shape; 58 static vr_draw_cursor_t gfb_cursor; 59 static vr_blink_cursor_t gfb_blink; 60 #ifndef SC_NO_CUTPASTE 61 static vr_draw_mouse_t gfb_mouse; 62 #else 63 #define gfb_mouse (vr_draw_mouse_t *)gfb_nop 64 #endif 65 66 static void gfb_nop(scr_stat *scp); 67 68 sc_rndr_sw_t txtrndrsw = { 69 (vr_init_t *)gfb_nop, 70 gfb_clear, 71 gfb_border, 72 gfb_draw, 73 gfb_cursor_shape, 74 gfb_cursor, 75 gfb_blink, 76 (vr_set_mouse_t *)gfb_nop, 77 gfb_mouse, 78 }; 79 80 #ifdef SC_PIXEL_MODE 81 sc_rndr_sw_t gfbrndrsw = { 82 (vr_init_t *)gfb_nop, 83 gfb_clear, 84 gfb_border, 85 gfb_draw, 86 gfb_cursor_shape, 87 gfb_cursor, 88 gfb_blink, 89 (vr_set_mouse_t *)gfb_nop, 90 gfb_mouse, 91 }; 92 #endif /* SC_PIXEL_MODE */ 93 94 #ifndef SC_NO_MODE_CHANGE 95 sc_rndr_sw_t grrndrsw = { 96 (vr_init_t *)gfb_nop, 97 (vr_clear_t *)gfb_nop, 98 gfb_border, 99 (vr_draw_t *)gfb_nop, 100 (vr_set_cursor_t *)gfb_nop, 101 (vr_draw_cursor_t *)gfb_nop, 102 (vr_blink_cursor_t *)gfb_nop, 103 (vr_set_mouse_t *)gfb_nop, 104 (vr_draw_mouse_t *)gfb_nop, 105 }; 106 #endif /* SC_NO_MODE_CHANGE */ 107 108 #ifndef SC_NO_CUTPASTE 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 vidd_clear(scp->sc->adp); 126 } 127 128 static void 129 gfb_border(scr_stat *scp, int color) 130 { 131 vidd_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 Calculate the number of characters past the end of the 151 visible screen... 152 */ 153 count = (from + count) - 154 (adp->va_info.vi_width * adp->va_info.vi_height); 155 156 /* 157 Calculate the number of rows past the end of the visible 158 screen... 159 */ 160 n = (count / adp->va_info.vi_width) + 1; 161 162 /* Scroll to make room for new text rows... */ 163 vidd_copy(adp, n, 0, n); 164 #if 0 165 vidd_clear(adp, n); 166 #endif 167 168 /* Display new text rows... */ 169 vidd_puts(adp, from, 170 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), count); 171 } 172 173 /* 174 We don't need to scroll, so we can just put the characters 175 all-at-once... 176 */ 177 else { 178 /* 179 Determine the method by which we are to display characters 180 (are we going to print forwards or backwards? 181 do we need to do a character-by-character copy, then?)... 182 */ 183 if (flip) 184 for (i = count; i-- > 0; ++from) { 185 c = sc_vtb_getc(&scp->vtb, from); 186 a = sc_vtb_geta(&scp->vtb, from) >> 8; 187 vidd_putc(adp, from, c, 188 (a >> 4) | ((a & 0xf) << 4)); 189 } 190 else { 191 vidd_puts(adp, from, 192 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), 193 count); 194 } 195 } 196 } 197 198 static void 199 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink) 200 { 201 if (base < 0 || base >= scp->font_size) 202 return; 203 /* the caller may set height <= 0 in order to disable the cursor */ 204 #if 0 205 scp->cursor_base = base; 206 scp->cursor_height = height; 207 #endif 208 vidd_set_hw_cursor_shape(scp->sc->adp, base, height, scp->font_size, 209 blink); 210 } 211 212 static int pxlblinkrate = 0; 213 214 #if defined(SC_OFWFB) 215 static void 216 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 217 { 218 video_adapter_t *adp; 219 int a, c; 220 221 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 222 return; 223 224 adp = scp->sc->adp; 225 if(blink) { 226 scp->status |= VR_CURSOR_BLINK; 227 if (on) { 228 scp->status |= VR_CURSOR_ON; 229 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 230 } else { 231 if (scp->status & VR_CURSOR_ON) 232 vidd_set_hw_cursor(adp, -1, -1); 233 scp->status &= ~VR_CURSOR_ON; 234 } 235 } else { 236 scp->status &= ~VR_CURSOR_BLINK; 237 if(on) { 238 scp->status |= VR_CURSOR_ON; 239 vidd_putc(scp->sc->adp, scp->cursor_oldpos, 240 sc_vtb_getc(&scp->vtb, scp->cursor_oldpos), 241 sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8); 242 a = sc_vtb_geta(&scp->vtb, at) >> 8; 243 c = sc_vtb_getc(&scp->vtb, at); 244 vidd_putc(scp->sc->adp, at, c, 245 (a >> 4) | ((a & 0xf) << 4)); 246 } else { 247 if (scp->status & VR_CURSOR_ON) 248 vidd_putc(scp->sc->adp, at, 249 sc_vtb_getc(&scp->vtb, at), 250 sc_vtb_geta(&scp->vtb, at) >> 8); 251 scp->status &= ~VR_CURSOR_ON; 252 } 253 } 254 } 255 #else 256 static void 257 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 258 { 259 video_adapter_t *adp; 260 261 adp = scp->sc->adp; 262 if (scp->curs_attr.height <= 0) 263 /* the text cursor is disabled */ 264 return; 265 266 if (on) { 267 if (!blink) { 268 scp->status |= VR_CURSOR_ON; 269 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 270 } else if (++pxlblinkrate & 4) { 271 pxlblinkrate = 0; 272 scp->status ^= VR_CURSOR_ON; 273 if(scp->status & VR_CURSOR_ON) 274 vidd_set_hw_cursor(adp, at%scp->xsize, 275 at/scp->xsize); 276 else 277 vidd_set_hw_cursor(adp, -1, -1); 278 } 279 } else { 280 if (scp->status & VR_CURSOR_ON) 281 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 282 scp->status &= ~VR_CURSOR_ON; 283 } 284 if (blink) 285 scp->status |= VR_CURSOR_BLINK; 286 else 287 scp->status &= ~VR_CURSOR_BLINK; 288 } 289 #endif 290 291 static void 292 gfb_blink(scr_stat *scp, int at, int flip) 293 { 294 if (!(scp->status & VR_CURSOR_BLINK)) 295 return; 296 if (!(++pxlblinkrate & 4)) 297 return; 298 pxlblinkrate = 0; 299 scp->status ^= VR_CURSOR_ON; 300 gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK, 301 scp->status & VR_CURSOR_ON, flip); 302 } 303 304 #ifndef SC_NO_CUTPASTE 305 306 static void 307 gfb_mouse(scr_stat *scp, int x, int y, int on) 308 { 309 if (on) { 310 vidd_putm(scp->sc->adp, x, y, mouse_pointer, 311 0xffffffff, 16, 8); 312 } else { 313 /* XXX: removal is incomplete for h/w cursors and borders. */ 314 } 315 } 316 317 #endif /* SC_NO_CUTPASTE */ 318