xref: /freebsd/sys/dev/syscons/scgfbrndr.c (revision 2357939bc239bd5334a169b62313806178dd8f30)
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Copyright (c) 2000 Andrew Miklic
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include "opt_syscons.h"
33 #include "opt_gfb.h"
34 #ifdef __sparc64__
35 #include "opt_creator.h"
36 #endif
37 #ifdef __powerpc__
38 #include "opt_ofwfb.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/fbio.h>
45 #include <sys/consio.h>
46 
47 #include <machine/bus.h>
48 
49 #include <dev/fb/fbreg.h>
50 #include <dev/syscons/syscons.h>
51 
52 #ifndef SC_RENDER_DEBUG
53 #define SC_RENDER_DEBUG		0
54 #endif
55 
56 static vr_clear_t		gfb_clear;
57 static vr_draw_border_t		gfb_border;
58 static vr_draw_t		gfb_draw;
59 static vr_set_cursor_t		gfb_cursor_shape;
60 static vr_draw_cursor_t		gfb_cursor;
61 static vr_blink_cursor_t	gfb_blink;
62 #ifndef SC_NO_CUTPASTE
63 static vr_draw_mouse_t		gfb_mouse;
64 #else
65 #define gfb_mouse		(vr_draw_mouse_t *)gfb_nop
66 #endif
67 
68 static void			gfb_nop(scr_stat *scp, ...);
69 
70 sc_rndr_sw_t txtrndrsw = {
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 	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_clear_t *)gfb_nop,
97 	gfb_border,
98 	(vr_draw_t *)gfb_nop,
99 	(vr_set_cursor_t *)gfb_nop,
100 	(vr_draw_cursor_t *)gfb_nop,
101 	(vr_blink_cursor_t *)gfb_nop,
102 	(vr_set_mouse_t *)gfb_nop,
103 	(vr_draw_mouse_t *)gfb_nop,
104 };
105 #endif /* SC_NO_MODE_CHANGE */
106 
107 #ifndef SC_NO_CUTPASTE
108 
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 	(*vidsw[scp->sc->adapter]->clear)(scp->sc->adp);
126 }
127 
128 static void
129 gfb_border(scr_stat *scp, int color)
130 {
131 	(*vidsw[scp->sc->adapter]->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 		/*
151 		   Calculate the number of characters past the end of the
152 		   visible screen...
153 		*/
154 		count = (from + count) -
155 		    (adp->va_info.vi_width * adp->va_info.vi_height);
156 
157 		/*
158 		   Calculate the number of rows past the end of the visible
159 		   screen...
160 		*/
161 		n = (count / adp->va_info.vi_width) + 1;
162 
163 		/* Scroll to make room for new text rows... */
164 		(*vidsw[scp->sc->adapter]->copy)(adp, n, 0, n);
165 #if 0
166 		(*vidsw[scp->sc->adapter]->clear)(adp, n);
167 #endif
168 
169 		/* Display new text rows... */
170 		(*vidsw[scp->sc->adapter]->puts)(adp, from,
171 		    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), count);
172 	}
173 
174 	/*
175 	   We don't need to scroll, so we can just put the characters
176 	   all-at-once...
177 	*/
178 	else {
179 
180 		/*
181 		   Determine the method by which we are to display characters
182 		   (are we going to print forwards or backwards?
183 		   do we need to do a character-by-character copy, then?)...
184 		*/
185 		if (flip)
186 			for (i = count; i-- > 0; ++from) {
187 				c = sc_vtb_getc(&scp->vtb, from);
188 				a = sc_vtb_geta(&scp->vtb, from) >> 8;
189 				(*vidsw[scp->sc->adapter]->putc)(adp, from, c,
190 				    (a >> 4) | ((a & 0xf) << 4));
191 			}
192 		else {
193 			(*vidsw[scp->sc->adapter]->puts)(adp, from,
194 			    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from),
195 			    count);
196 		}
197 	}
198 }
199 
200 static void
201 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink)
202 {
203 	if (base < 0 || base >= scp->font_size)
204 		return;
205 	/* the caller may set height <= 0 in order to disable the cursor */
206 #if 0
207 	scp->cursor_base = base;
208 	scp->cursor_height = height;
209 #endif
210 	(*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
211 	    base, height, scp->font_size, blink);
212 }
213 
214 static int pxlblinkrate = 0;
215 
216 #if defined(DEV_CREATOR) || defined(SC_OFWFB)
217 static void
218 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
219 {
220 	video_adapter_t *adp;
221 	int a, c;
222 
223 	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
224 		return;
225 
226 	adp = scp->sc->adp;
227 	if(blink) {
228 		scp->status |= VR_CURSOR_BLINK;
229 		if (on) {
230 			scp->status |= VR_CURSOR_ON;
231 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
232 			    at%scp->xsize,
233 			    at/scp->xsize);
234 		} else {
235 			if (scp->status & VR_CURSOR_ON)
236 				(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1,
237 				    -1);
238 			scp->status &= ~VR_CURSOR_ON;
239 		}
240 	} else {
241 		scp->status &= ~VR_CURSOR_BLINK;
242 		if(on) {
243 			scp->status |= VR_CURSOR_ON;
244 			(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp,
245 			    scp->cursor_oldpos,
246 			    sc_vtb_getc(&scp->vtb, scp->cursor_oldpos),
247 			    sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8);
248 			a = sc_vtb_geta(&scp->vtb, at) >> 8;
249 			c = sc_vtb_getc(&scp->vtb, at);
250 			(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp, at,
251 			    c, (a >> 4) | ((a & 0xf) << 4));
252 			scp->cursor_saveunder_attr = a;
253 			scp->cursor_saveunder_char = c;
254 		} else {
255 			if (scp->status & VR_CURSOR_ON)
256 				(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp,
257 				    at, scp->cursor_saveunder_char,
258 				    scp->cursor_saveunder_attr);
259 			scp->status &= ~VR_CURSOR_ON;
260 		}
261 	}
262 }
263 #else
264 static void
265 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
266 {
267 	video_adapter_t *adp;
268 
269 	adp = scp->sc->adp;
270 	if (scp->curs_attr.height <= 0)
271 		/* the text cursor is disabled */
272 		return;
273 
274 	if (on) {
275 		if (!blink) {
276 			scp->status |= VR_CURSOR_ON;
277 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
278 			    at%scp->xsize, at/scp->xsize);
279 		} else if (++pxlblinkrate & 4) {
280 			pxlblinkrate = 0;
281 			scp->status ^= VR_CURSOR_ON;
282 			if(scp->status & VR_CURSOR_ON)
283 				(*vidsw[adp->va_index]->set_hw_cursor)(adp,
284 				    at%scp->xsize, at/scp->xsize);
285 			else
286 				(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1,
287 				    -1);
288 		}
289 	} else {
290 		if (scp->status & VR_CURSOR_ON)
291 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
292 			    at%scp->xsize, at/scp->xsize);
293 		scp->status &= ~VR_CURSOR_ON;
294 	}
295 	if (blink)
296 		scp->status |= VR_CURSOR_BLINK;
297 	else
298 		scp->status &= ~VR_CURSOR_BLINK;
299 }
300 #endif
301 
302 static void
303 gfb_blink(scr_stat *scp, int at, int flip)
304 {
305 	if (!(scp->status & VR_CURSOR_BLINK))
306 		return;
307 	if (!(++pxlblinkrate & 4))
308 		return;
309 	pxlblinkrate = 0;
310 	scp->status ^= VR_CURSOR_ON;
311 	gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK,
312 	    scp->status & VR_CURSOR_ON, flip);
313 }
314 
315 #ifndef SC_NO_CUTPASTE
316 
317 static void
318 gfb_mouse(scr_stat *scp, int x, int y, int on)
319 {
320 	int i, pos;
321 
322 	if (on) {
323 
324 		/* Display the mouse pointer image... */
325 		(*vidsw[scp->sc->adapter]->putm)(scp->sc->adp, x, y,
326 		    mouse_pointer, 0xffffffff, 16);
327 	} else {
328 
329 		/*
330 		   Erase the mouse cursor image by redrawing the text
331 		   underneath it...
332 		*/
333 		return;
334 		pos = x*scp->xsize + y;
335 		i = (y < scp->xsize - 1) ? 2 : 1;
336 		(*scp->rndr->draw)(scp, pos, i, FALSE);
337 		if (x < scp->ysize - 1)
338 			(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
339 	}
340 }
341 
342 #endif /* SC_NO_CUTPASTE */
343