scgfbrndr.c revision 146746
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 146746 2005-05-29 12:47:39Z marius $");
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
53static vr_clear_t		gfb_clear;
54static vr_draw_border_t		gfb_border;
55static vr_draw_t		gfb_draw;
56static vr_set_cursor_t		gfb_cursor_shape;
57static vr_draw_cursor_t		gfb_cursor;
58static vr_blink_cursor_t	gfb_blink;
59#ifndef SC_NO_CUTPASTE
60static vr_draw_mouse_t		gfb_mouse;
61#else
62#define gfb_mouse		(vr_draw_mouse_t *)gfb_nop
63#endif
64
65static void			gfb_nop(scr_stat *scp, ...);
66
67sc_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
80sc_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
94sc_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
109static 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
115static void
116gfb_nop(scr_stat *scp, ...)
117{
118}
119
120/* text mode renderer */
121
122static void
123gfb_clear(scr_stat *scp, int c, int attr)
124{
125	(*vidsw[scp->sc->adapter]->clear)(scp->sc->adp);
126}
127
128static void
129gfb_border(scr_stat *scp, int color)
130{
131	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
132}
133
134static void
135gfb_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
200static void
201gfb_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
214static int pxlblinkrate = 0;
215
216#if defined(__sparc64__) || defined(SC_OFWFB)
217static void
218gfb_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
264static void
265gfb_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
302static void
303gfb_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
317static void
318gfb_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