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