scgfbrndr.c revision 94617
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: head/sys/dev/syscons/scgfbrndr.c 94617 2002-04-13 22:34:16Z obrien $");
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
50static vr_clear_t		gfb_clear;
51static vr_draw_border_t		gfb_border;
52static vr_draw_t		gfb_draw;
53static vr_set_cursor_t		gfb_cursor_shape;
54static vr_draw_cursor_t		gfb_cursor;
55static vr_blink_cursor_t	gfb_blink;
56#ifndef SC_NO_CUTPASTE
57static vr_draw_mouse_t		gfb_mouse;
58#else
59#define gfb_mouse		(vr_draw_mouse_t *)gfb_nop
60#endif
61
62static void			gfb_nop(scr_stat *scp, ...);
63
64sc_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
76sc_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
89sc_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
103static 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
109static void
110gfb_nop(scr_stat *scp, ...)
111{
112}
113
114/* text mode renderer */
115
116static void
117gfb_clear(scr_stat *scp, int c, int attr)
118{
119	(*vidsw[scp->sc->adapter]->clear)(scp->sc->adp);
120}
121
122static void
123gfb_border(scr_stat *scp, int color)
124{
125	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
126}
127
128static void
129gfb_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
194static void
195gfb_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
208static int pxlblinkrate = 0;
209
210#if 0
211static void
212gfb_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
253static void
254gfb_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
290static void
291gfb_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
305static void
306gfb_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