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