1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999 Kazutaka YOKOTA <[email protected]>
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 #ifdef __sparc64__
111 static 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
136 static 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
143 static void
gfb_nop(scr_stat * scp)144 gfb_nop(scr_stat *scp)
145 {
146 }
147
148 /* text mode renderer */
149
150 static void
gfb_clear(scr_stat * scp,int c,int attr)151 gfb_clear(scr_stat *scp, int c, int attr)
152 {
153 vidd_clear(scp->sc->adp);
154 }
155
156 static void
gfb_border(scr_stat * scp,int color)157 gfb_border(scr_stat *scp, int color)
158 {
159 vidd_set_border(scp->sc->adp, color);
160 }
161
162 static void
gfb_draw(scr_stat * scp,int from,int count,int flip)163 gfb_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
228 static void
gfb_cursor_shape(scr_stat * scp,int base,int height,int blink)229 gfb_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
242 static int pxlblinkrate = 0;
243
244 #if defined(__sparc64__) || defined(SC_OFWFB)
245 static void
gfb_cursor(scr_stat * scp,int at,int blink,int on,int flip)246 gfb_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
286 static void
gfb_cursor(scr_stat * scp,int at,int blink,int on,int flip)287 gfb_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
321 static void
gfb_blink(scr_stat * scp,int at,int flip)322 gfb_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
336 static void
gfb_mouse(scr_stat * scp,int x,int y,int on)337 gfb_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