xref: /freebsd/sys/dev/syscons/scgfbrndr.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/fbio.h>
42 #include <sys/consio.h>
43 
44 #include <machine/bus.h>
45 
46 #include <dev/fb/fbreg.h>
47 #include <dev/syscons/syscons.h>
48 
49 #ifndef SC_RENDER_DEBUG
50 #define SC_RENDER_DEBUG		0
51 #endif
52 
53 static vr_clear_t		gfb_clear;
54 static vr_draw_border_t		gfb_border;
55 static vr_draw_t		gfb_draw;
56 static vr_set_cursor_t		gfb_cursor_shape;
57 static vr_draw_cursor_t		gfb_cursor;
58 static vr_blink_cursor_t	gfb_blink;
59 #ifndef SC_NO_CUTPASTE
60 static vr_draw_mouse_t		gfb_mouse;
61 #else
62 #define gfb_mouse		(vr_draw_mouse_t *)gfb_nop
63 #endif
64 
65 static void			gfb_nop(scr_stat *scp, ...);
66 
67 sc_rndr_sw_t txtrndrsw = {
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 	gfb_clear,
81 	gfb_border,
82 	gfb_draw,
83 	gfb_cursor_shape,
84 	gfb_cursor,
85 	gfb_blink,
86 	(vr_set_mouse_t *)gfb_nop,
87 	gfb_mouse,
88 };
89 #endif /* SC_PIXEL_MODE */
90 
91 #ifndef SC_NO_MODE_CHANGE
92 sc_rndr_sw_t grrndrsw = {
93 	(vr_clear_t *)gfb_nop,
94 	gfb_border,
95 	(vr_draw_t *)gfb_nop,
96 	(vr_set_cursor_t *)gfb_nop,
97 	(vr_draw_cursor_t *)gfb_nop,
98 	(vr_blink_cursor_t *)gfb_nop,
99 	(vr_set_mouse_t *)gfb_nop,
100 	(vr_draw_mouse_t *)gfb_nop,
101 };
102 #endif /* SC_NO_MODE_CHANGE */
103 
104 #ifndef SC_NO_CUTPASTE
105 
106 static u_char mouse_pointer[16] = {
107 	0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
108 	0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
109 };
110 #endif
111 
112 static void
113 gfb_nop(scr_stat *scp, ...)
114 {
115 }
116 
117 /* text mode renderer */
118 
119 static void
120 gfb_clear(scr_stat *scp, int c, int attr)
121 {
122 	(*vidsw[scp->sc->adapter]->clear)(scp->sc->adp);
123 }
124 
125 static void
126 gfb_border(scr_stat *scp, int color)
127 {
128 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
129 }
130 
131 static void
132 gfb_draw(scr_stat *scp, int from, int count, int flip)
133 {
134 	int c;
135 	int a;
136 	int i, n;
137 	video_adapter_t *adp;
138 
139 	adp = scp->sc->adp;
140 
141 	/*
142 	   Determine if we need to scroll based on the offset
143 	   and the number of characters to be displayed...
144 	 */
145 	if (from + count > scp->xsize*scp->ysize) {
146 
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 		(*vidsw[scp->sc->adapter]->copy)(adp, n, 0, n);
162 #if 0
163 		(*vidsw[scp->sc->adapter]->clear)(adp, n);
164 #endif
165 
166 		/* Display new text rows... */
167 		(*vidsw[scp->sc->adapter]->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 		/*
178 		   Determine the method by which we are to display characters
179 		   (are we going to print forwards or backwards?
180 		   do we need to do a character-by-character copy, then?)...
181 		*/
182 		if (flip)
183 			for (i = count; i-- > 0; ++from) {
184 				c = sc_vtb_getc(&scp->vtb, from);
185 				a = sc_vtb_geta(&scp->vtb, from) >> 8;
186 				(*vidsw[scp->sc->adapter]->putc)(adp, from, c,
187 				    (a >> 4) | ((a & 0xf) << 4));
188 			}
189 		else {
190 			(*vidsw[scp->sc->adapter]->puts)(adp, from,
191 			    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from),
192 			    count);
193 		}
194 	}
195 }
196 
197 static void
198 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink)
199 {
200 	if (base < 0 || base >= scp->font_size)
201 		return;
202 	/* the caller may set height <= 0 in order to disable the cursor */
203 #if 0
204 	scp->cursor_base = base;
205 	scp->cursor_height = height;
206 #endif
207 	(*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
208 	    base, height, scp->font_size, blink);
209 }
210 
211 static int pxlblinkrate = 0;
212 
213 #ifdef DEV_CREATOR
214 static void
215 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
216 {
217 	video_adapter_t *adp;
218 	int a, c;
219 
220 	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
221 		return;
222 
223 	adp = scp->sc->adp;
224 	if(blink) {
225 		scp->status |= VR_CURSOR_BLINK;
226 		if (on) {
227 			scp->status |= VR_CURSOR_ON;
228 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
229 			    at%scp->xsize,
230 			    at/scp->xsize);
231 		} else {
232 			if (scp->status & VR_CURSOR_ON)
233 				(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1,
234 				    -1);
235 			scp->status &= ~VR_CURSOR_ON;
236 		}
237 	} else {
238 		scp->status &= ~VR_CURSOR_BLINK;
239 		if(on) {
240 			scp->status |= VR_CURSOR_ON;
241 			(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp,
242 			    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 			(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp, at,
248 			    c, (a >> 4) | ((a & 0xf) << 4));
249 			scp->cursor_saveunder_attr = a;
250 			scp->cursor_saveunder_char = c;
251 		} else {
252 			if (scp->status & VR_CURSOR_ON)
253 				(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp,
254 				    at, scp->cursor_saveunder_char,
255 				    scp->cursor_saveunder_attr);
256 			scp->status &= ~VR_CURSOR_ON;
257 		}
258 	}
259 }
260 #else
261 static void
262 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
263 {
264 	video_adapter_t *adp;
265 
266 	adp = scp->sc->adp;
267 	if (scp->curs_attr.height <= 0)
268 		/* the text cursor is disabled */
269 		return;
270 
271 	if (on) {
272 		if (!blink) {
273 			scp->status |= VR_CURSOR_ON;
274 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
275 			    at%scp->xsize, at/scp->xsize);
276 		} else if (++pxlblinkrate & 4) {
277 			pxlblinkrate = 0;
278 			scp->status ^= VR_CURSOR_ON;
279 			if(scp->status & VR_CURSOR_ON)
280 				(*vidsw[adp->va_index]->set_hw_cursor)(adp,
281 				    at%scp->xsize, at/scp->xsize);
282 			else
283 				(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1,
284 				    -1);
285 		}
286 	} else {
287 		if (scp->status & VR_CURSOR_ON)
288 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
289 			    at%scp->xsize, at/scp->xsize);
290 		scp->status &= ~VR_CURSOR_ON;
291 	}
292 	if (blink)
293 		scp->status |= VR_CURSOR_BLINK;
294 	else
295 		scp->status &= ~VR_CURSOR_BLINK;
296 }
297 #endif
298 
299 static void
300 gfb_blink(scr_stat *scp, int at, int flip)
301 {
302 	if (!(scp->status & VR_CURSOR_BLINK))
303 		return;
304 	if (!(++pxlblinkrate & 4))
305 		return;
306 	pxlblinkrate = 0;
307 	scp->status ^= VR_CURSOR_ON;
308 	gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK,
309 	    scp->status & VR_CURSOR_ON, flip);
310 }
311 
312 #ifndef SC_NO_CUTPASTE
313 
314 static void
315 gfb_mouse(scr_stat *scp, int x, int y, int on)
316 {
317 	int i, pos;
318 
319 	if (on) {
320 
321 		/* Display the mouse pointer image... */
322 		(*vidsw[scp->sc->adapter]->putm)(scp->sc->adp, x, y,
323 		    mouse_pointer, 0xffffffff, 16);
324 	} else {
325 
326 		/*
327 		   Erase the mouse cursor image by redrawing the text
328 		   underneath it...
329 		*/
330 		return;
331 		pos = x*scp->xsize + y;
332 		i = (y < scp->xsize - 1) ? 2 : 1;
333 		(*scp->rndr->draw)(scp, pos, i, FALSE);
334 		if (x < scp->ysize - 1)
335 			(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
336 	}
337 }
338 
339 #endif /* SC_NO_CUTPASTE */
340