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