xref: /freebsd/sys/dev/syscons/scgfbrndr.c (revision 8eb2bee6c0f4957c6c1cea826e59cda4d18a2a64)
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 #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