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 55static vr_clear_t gfb_clear; 56static vr_draw_border_t gfb_border; 57static vr_draw_t gfb_draw; 58static vr_set_cursor_t gfb_cursor_shape; 59static vr_draw_cursor_t gfb_cursor; 60static vr_blink_cursor_t gfb_blink; 61#ifndef SC_NO_CUTPASTE 62static vr_draw_mouse_t gfb_mouse; 63#else 64#define gfb_mouse (vr_draw_mouse_t *)gfb_nop 65#endif 66 67static void gfb_nop(scr_stat *scp); 68 69sc_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 82sc_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 96sc_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#ifdef __sparc64__ 111static u_char mouse_pointer[22 * 2] = { 112 0x00, 0x00, /* ............ */ 113 0x80, 0x00, /* *........... */ 114 0xc0, 0x00, /* **.......... */ 115 0xe0, 0x00, /* ***......... */ 116 0xf0, 0x00, /* ****........ */ 117 0xf8, 0x00, /* *****....... */ 118 0xfc, 0x00, /* ******...... */ 119 0xfe, 0x00, /* *******..... */ 120 0xff, 0x00, /* ********.... */ 121 0xff, 0x80, /* *********... */ 122 0xfc, 0xc0, /* ******..**.. */ 123 0xdc, 0x00, /* **.***...... */ 124 0x8e, 0x00, /* *...***..... */ 125 0x0e, 0x00, /* ....***..... */ 126 0x07, 0x00, /* .....***.... */ 127 0x04, 0x00, /* .....*...... */ 128 0x00, 0x00, /* ............ */ 129 0x00, 0x00, /* ............ */ 130 0x00, 0x00, /* ............ */ 131 0x00, 0x00, /* ............ */ 132 0x00, 0x00, /* ............ */ 133 0x00, 0x00 /* ............ */ 134}; 135#else 136static u_char mouse_pointer[16] = { 137 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68, 138 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 139}; 140#endif 141#endif 142 143static void 144gfb_nop(scr_stat *scp) 145{ 146} 147 148/* text mode renderer */ 149 150static void 151gfb_clear(scr_stat *scp, int c, int attr) 152{ 153 vidd_clear(scp->sc->adp); 154} 155 156static void 157gfb_border(scr_stat *scp, int color) 158{ 159 vidd_set_border(scp->sc->adp, color); 160} 161 162static void 163gfb_draw(scr_stat *scp, int from, int count, int flip) 164{ 165 int c; 166 int a; 167 int i, n; 168 video_adapter_t *adp; 169 170 adp = scp->sc->adp; 171 172 /* 173 Determine if we need to scroll based on the offset 174 and the number of characters to be displayed... 175 */ 176 if (from + count > scp->xsize*scp->ysize) { 177 178 /* 179 Calculate the number of characters past the end of the 180 visible screen... 181 */ 182 count = (from + count) - 183 (adp->va_info.vi_width * adp->va_info.vi_height); 184 185 /* 186 Calculate the number of rows past the end of the visible 187 screen... 188 */ 189 n = (count / adp->va_info.vi_width) + 1; 190 191 /* Scroll to make room for new text rows... */ 192 vidd_copy(adp, n, 0, n); 193#if 0 194 vidd_clear(adp, n); 195#endif 196 197 /* Display new text rows... */ 198 vidd_puts(adp, from, 199 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), count); 200 } 201 202 /* 203 We don't need to scroll, so we can just put the characters 204 all-at-once... 205 */ 206 else { 207 208 /* 209 Determine the method by which we are to display characters 210 (are we going to print forwards or backwards? 211 do we need to do a character-by-character copy, then?)... 212 */ 213 if (flip) 214 for (i = count; i-- > 0; ++from) { 215 c = sc_vtb_getc(&scp->vtb, from); 216 a = sc_vtb_geta(&scp->vtb, from) >> 8; 217 vidd_putc(adp, from, c, 218 (a >> 4) | ((a & 0xf) << 4)); 219 } 220 else { 221 vidd_puts(adp, from, 222 (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), 223 count); 224 } 225 } 226} 227 228static void 229gfb_cursor_shape(scr_stat *scp, int base, int height, int blink) 230{ 231 if (base < 0 || base >= scp->font_size) 232 return; 233 /* the caller may set height <= 0 in order to disable the cursor */ 234#if 0 235 scp->cursor_base = base; 236 scp->cursor_height = height; 237#endif 238 vidd_set_hw_cursor_shape(scp->sc->adp, base, height, scp->font_size, 239 blink); 240} 241 242static int pxlblinkrate = 0; 243 244#if defined(__sparc64__) || defined(SC_OFWFB) 245static void 246gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 247{ 248 video_adapter_t *adp; 249 int a, c; 250 251 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 252 return; 253 254 adp = scp->sc->adp; 255 if(blink) { 256 scp->status |= VR_CURSOR_BLINK; 257 if (on) { 258 scp->status |= VR_CURSOR_ON; 259 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 260 } else { 261 if (scp->status & VR_CURSOR_ON) 262 vidd_set_hw_cursor(adp, -1, -1); 263 scp->status &= ~VR_CURSOR_ON; 264 } 265 } else { 266 scp->status &= ~VR_CURSOR_BLINK; 267 if(on) { 268 scp->status |= VR_CURSOR_ON; 269 vidd_putc(scp->sc->adp, scp->cursor_oldpos, 270 sc_vtb_getc(&scp->vtb, scp->cursor_oldpos), 271 sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8); 272 a = sc_vtb_geta(&scp->vtb, at) >> 8; 273 c = sc_vtb_getc(&scp->vtb, at); 274 vidd_putc(scp->sc->adp, at, c, 275 (a >> 4) | ((a & 0xf) << 4)); 276 } else { 277 if (scp->status & VR_CURSOR_ON) 278 vidd_putc(scp->sc->adp, at, 279 sc_vtb_getc(&scp->vtb, at), 280 sc_vtb_geta(&scp->vtb, at) >> 8); 281 scp->status &= ~VR_CURSOR_ON; 282 } 283 } 284} 285#else 286static void 287gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip) 288{ 289 video_adapter_t *adp; 290 291 adp = scp->sc->adp; 292 if (scp->curs_attr.height <= 0) 293 /* the text cursor is disabled */ 294 return; 295 296 if (on) { 297 if (!blink) { 298 scp->status |= VR_CURSOR_ON; 299 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 300 } else if (++pxlblinkrate & 4) { 301 pxlblinkrate = 0; 302 scp->status ^= VR_CURSOR_ON; 303 if(scp->status & VR_CURSOR_ON) 304 vidd_set_hw_cursor(adp, at%scp->xsize, 305 at/scp->xsize); 306 else 307 vidd_set_hw_cursor(adp, -1, -1); 308 } 309 } else { 310 if (scp->status & VR_CURSOR_ON) 311 vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize); 312 scp->status &= ~VR_CURSOR_ON; 313 } 314 if (blink) 315 scp->status |= VR_CURSOR_BLINK; 316 else 317 scp->status &= ~VR_CURSOR_BLINK; 318} 319#endif 320 321static void 322gfb_blink(scr_stat *scp, int at, int flip) 323{ 324 if (!(scp->status & VR_CURSOR_BLINK)) 325 return; 326 if (!(++pxlblinkrate & 4)) 327 return; 328 pxlblinkrate = 0; 329 scp->status ^= VR_CURSOR_ON; 330 gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK, 331 scp->status & VR_CURSOR_ON, flip); 332} 333 334#ifndef SC_NO_CUTPASTE 335 336static void 337gfb_mouse(scr_stat *scp, int x, int y, int on) 338{ 339#ifdef __sparc64__ 340 vidd_putm(scp->sc->adp, x, y, mouse_pointer, 341 on ? 0xffffffff : 0x0, 22, 12); 342#else 343 if (on) { 344 vidd_putm(scp->sc->adp, x, y, mouse_pointer, 345 0xffffffff, 16, 8); 346 } else { 347 /* XXX: removal is incomplete for h/w cursors and borders. */ 348 } 349#endif 350} 351 352#endif /* SC_NO_CUTPASTE */ 353