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