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