xref: /freebsd/sys/dev/syscons/scgfbrndr.c (revision b28624fde638caadd4a89f50c9b7e7da0f98c4d2)
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 __powerpc__
35 #include "opt_ofwfb.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 	(vr_init_t *)gfb_nop,
69 	gfb_clear,
70 	gfb_border,
71 	gfb_draw,
72 	gfb_cursor_shape,
73 	gfb_cursor,
74 	gfb_blink,
75 	(vr_set_mouse_t *)gfb_nop,
76 	gfb_mouse,
77 };
78 
79 #ifdef SC_PIXEL_MODE
80 sc_rndr_sw_t gfbrndrsw = {
81 	(vr_init_t *)gfb_nop,
82 	gfb_clear,
83 	gfb_border,
84 	gfb_draw,
85 	gfb_cursor_shape,
86 	gfb_cursor,
87 	gfb_blink,
88 	(vr_set_mouse_t *)gfb_nop,
89 	gfb_mouse,
90 };
91 #endif /* SC_PIXEL_MODE */
92 
93 #ifndef SC_NO_MODE_CHANGE
94 sc_rndr_sw_t grrndrsw = {
95 	(vr_init_t *)gfb_nop,
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 #ifdef __sparc64__
109 static u_char mouse_pointer[22 * 2] = {
110 	0x00, 0x00,	/* ............ */
111 	0x80, 0x00,	/* *........... */
112 	0xc0, 0x00,	/* **.......... */
113 	0xe0, 0x00,	/* ***......... */
114 	0xf0, 0x00,	/* ****........ */
115 	0xf8, 0x00,	/* *****....... */
116 	0xfc, 0x00,	/* ******...... */
117 	0xfe, 0x00,	/* *******..... */
118 	0xff, 0x00,	/* ********.... */
119 	0xff, 0x80,	/* *********... */
120 	0xfc, 0xc0,	/* ******..**.. */
121 	0xdc, 0x00,	/* **.***...... */
122 	0x8e, 0x00,	/* *...***..... */
123 	0x0e, 0x00,	/* ....***..... */
124 	0x07, 0x00,	/* .....***.... */
125 	0x04, 0x00,	/* .....*...... */
126 	0x00, 0x00,	/* ............ */
127 	0x00, 0x00,	/* ............ */
128 	0x00, 0x00,	/* ............ */
129 	0x00, 0x00,	/* ............ */
130 	0x00, 0x00,	/* ............ */
131 	0x00, 0x00	/* ............ */
132 };
133 #else
134 static u_char mouse_pointer[16] = {
135 	0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
136 	0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
137 };
138 #endif
139 #endif
140 
141 static void
142 gfb_nop(scr_stat *scp)
143 {
144 }
145 
146 /* text mode renderer */
147 
148 static void
149 gfb_clear(scr_stat *scp, int c, int attr)
150 {
151 	(*vidsw[scp->sc->adapter]->clear)(scp->sc->adp);
152 }
153 
154 static void
155 gfb_border(scr_stat *scp, int color)
156 {
157 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
158 }
159 
160 static void
161 gfb_draw(scr_stat *scp, int from, int count, int flip)
162 {
163 	int c;
164 	int a;
165 	int i, n;
166 	video_adapter_t *adp;
167 
168 	adp = scp->sc->adp;
169 
170 	/*
171 	   Determine if we need to scroll based on the offset
172 	   and the number of characters to be displayed...
173 	 */
174 	if (from + count > scp->xsize*scp->ysize) {
175 
176 		/*
177 		   Calculate the number of characters past the end of the
178 		   visible screen...
179 		*/
180 		count = (from + count) -
181 		    (adp->va_info.vi_width * adp->va_info.vi_height);
182 
183 		/*
184 		   Calculate the number of rows past the end of the visible
185 		   screen...
186 		*/
187 		n = (count / adp->va_info.vi_width) + 1;
188 
189 		/* Scroll to make room for new text rows... */
190 		(*vidsw[scp->sc->adapter]->copy)(adp, n, 0, n);
191 #if 0
192 		(*vidsw[scp->sc->adapter]->clear)(adp, n);
193 #endif
194 
195 		/* Display new text rows... */
196 		(*vidsw[scp->sc->adapter]->puts)(adp, from,
197 		    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from), count);
198 	}
199 
200 	/*
201 	   We don't need to scroll, so we can just put the characters
202 	   all-at-once...
203 	*/
204 	else {
205 
206 		/*
207 		   Determine the method by which we are to display characters
208 		   (are we going to print forwards or backwards?
209 		   do we need to do a character-by-character copy, then?)...
210 		*/
211 		if (flip)
212 			for (i = count; i-- > 0; ++from) {
213 				c = sc_vtb_getc(&scp->vtb, from);
214 				a = sc_vtb_geta(&scp->vtb, from) >> 8;
215 				(*vidsw[scp->sc->adapter]->putc)(adp, from, c,
216 				    (a >> 4) | ((a & 0xf) << 4));
217 			}
218 		else {
219 			(*vidsw[scp->sc->adapter]->puts)(adp, from,
220 			    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from),
221 			    count);
222 		}
223 	}
224 }
225 
226 static void
227 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink)
228 {
229 	if (base < 0 || base >= scp->font_size)
230 		return;
231 	/* the caller may set height <= 0 in order to disable the cursor */
232 #if 0
233 	scp->cursor_base = base;
234 	scp->cursor_height = height;
235 #endif
236 	(*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
237 	    base, height, scp->font_size, blink);
238 }
239 
240 static int pxlblinkrate = 0;
241 
242 #if defined(__sparc64__) || defined(SC_OFWFB)
243 static void
244 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
245 {
246 	video_adapter_t *adp;
247 	int a, c;
248 
249 	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
250 		return;
251 
252 	adp = scp->sc->adp;
253 	if(blink) {
254 		scp->status |= VR_CURSOR_BLINK;
255 		if (on) {
256 			scp->status |= VR_CURSOR_ON;
257 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
258 			    at%scp->xsize,
259 			    at/scp->xsize);
260 		} else {
261 			if (scp->status & VR_CURSOR_ON)
262 				(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1,
263 				    -1);
264 			scp->status &= ~VR_CURSOR_ON;
265 		}
266 	} else {
267 		scp->status &= ~VR_CURSOR_BLINK;
268 		if(on) {
269 			scp->status |= VR_CURSOR_ON;
270 			(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp,
271 			    scp->cursor_oldpos,
272 			    sc_vtb_getc(&scp->vtb, scp->cursor_oldpos),
273 			    sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8);
274 			a = sc_vtb_geta(&scp->vtb, at) >> 8;
275 			c = sc_vtb_getc(&scp->vtb, at);
276 			(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp, at,
277 			    c, (a >> 4) | ((a & 0xf) << 4));
278 			scp->cursor_saveunder_attr = a;
279 			scp->cursor_saveunder_char = c;
280 		} else {
281 			if (scp->status & VR_CURSOR_ON)
282 				(*vidsw[scp->sc->adapter]->putc)(scp->sc->adp,
283 				    at, scp->cursor_saveunder_char,
284 				    scp->cursor_saveunder_attr);
285 			scp->status &= ~VR_CURSOR_ON;
286 		}
287 	}
288 }
289 #else
290 static void
291 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
292 {
293 	video_adapter_t *adp;
294 
295 	adp = scp->sc->adp;
296 	if (scp->curs_attr.height <= 0)
297 		/* the text cursor is disabled */
298 		return;
299 
300 	if (on) {
301 		if (!blink) {
302 			scp->status |= VR_CURSOR_ON;
303 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
304 			    at%scp->xsize, at/scp->xsize);
305 		} else if (++pxlblinkrate & 4) {
306 			pxlblinkrate = 0;
307 			scp->status ^= VR_CURSOR_ON;
308 			if(scp->status & VR_CURSOR_ON)
309 				(*vidsw[adp->va_index]->set_hw_cursor)(adp,
310 				    at%scp->xsize, at/scp->xsize);
311 			else
312 				(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1,
313 				    -1);
314 		}
315 	} else {
316 		if (scp->status & VR_CURSOR_ON)
317 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
318 			    at%scp->xsize, at/scp->xsize);
319 		scp->status &= ~VR_CURSOR_ON;
320 	}
321 	if (blink)
322 		scp->status |= VR_CURSOR_BLINK;
323 	else
324 		scp->status &= ~VR_CURSOR_BLINK;
325 }
326 #endif
327 
328 static void
329 gfb_blink(scr_stat *scp, int at, int flip)
330 {
331 	if (!(scp->status & VR_CURSOR_BLINK))
332 		return;
333 	if (!(++pxlblinkrate & 4))
334 		return;
335 	pxlblinkrate = 0;
336 	scp->status ^= VR_CURSOR_ON;
337 	gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK,
338 	    scp->status & VR_CURSOR_ON, flip);
339 }
340 
341 #ifndef SC_NO_CUTPASTE
342 
343 static void
344 gfb_mouse(scr_stat *scp, int x, int y, int on)
345 {
346 #ifdef __sparc64__
347 		(*vidsw[scp->sc->adapter]->putm)(scp->sc->adp, x, y,
348 		    mouse_pointer, on ? 0xffffffff : 0x0, 22, 12);
349 #else
350 	int i, pos;
351 
352 	if (on) {
353 
354 		/* Display the mouse pointer image... */
355 		(*vidsw[scp->sc->adapter]->putm)(scp->sc->adp, x, y,
356 		    mouse_pointer, 0xffffffff, 16, 8);
357 	} else {
358 
359 		/*
360 		   Erase the mouse cursor image by redrawing the text
361 		   underneath it...
362 		*/
363 		return;
364 		pos = x*scp->xsize + y;
365 		i = (y < scp->xsize - 1) ? 2 : 1;
366 		(*scp->rndr->draw)(scp, pos, i, FALSE);
367 		if (x < scp->ysize - 1)
368 			(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
369 	}
370 #endif
371 }
372 
373 #endif /* SC_NO_CUTPASTE */
374