scgfbrndr.c revision 174985
1117395Skan/*-
2169689Skan * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3117395Skan * All rights reserved.
4117395Skan *
5117395Skan * Redistribution and use in source and binary forms, with or without
6117395Skan * modification, are permitted provided that the following conditions
7117395Skan * are met:
8117395Skan * 1. Redistributions of source code must retain the above copyright
9117395Skan *    notice, this list of conditions and the following disclaimer as
10117395Skan *    the first lines of this file unmodified.
11117395Skan * 2. Redistributions in binary form must reproduce the above copyright
12117395Skan *    notice, this list of conditions and the following disclaimer in the
13117395Skan *    documentation and/or other materials provided with the distribution.
14117395Skan *
15117395Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16117395Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17117395Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18117395Skan * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19117395Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20117395Skan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21117395Skan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22117395Skan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23117395Skan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24117395Skan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25117395Skan *
26117395Skan * Copyright (c) 2000 Andrew Miklic
27169689Skan */
28169689Skan
29117395Skan#include <sys/cdefs.h>
30117395Skan__FBSDID("$FreeBSD: head/sys/dev/syscons/scgfbrndr.c 174985 2007-12-29 23:26:59Z wkoszek $");
31117395Skan
32117395Skan#include "opt_syscons.h"
33117395Skan#include "opt_gfb.h"
34117395Skan#ifdef __powerpc__
35117395Skan#include "opt_ofwfb.h"
36117395Skan#endif
37169689Skan
38169689Skan#include <sys/param.h>
39169689Skan#include <sys/systm.h>
40169689Skan#include <sys/kernel.h>
41169689Skan#include <sys/fbio.h>
42117395Skan#include <sys/consio.h>
43117395Skan
44117395Skan#include <machine/bus.h>
45117395Skan
46117395Skan#include <dev/fb/fbreg.h>
47117395Skan#include <dev/syscons/syscons.h>
48117395Skan
49117395Skan#ifndef SC_RENDER_DEBUG
50117395Skan#define SC_RENDER_DEBUG		0
51117395Skan#endif
52117395Skan
53117395Skanstatic vr_clear_t		gfb_clear;
54117395Skanstatic vr_draw_border_t		gfb_border;
55117395Skanstatic vr_draw_t		gfb_draw;
56117395Skanstatic vr_set_cursor_t		gfb_cursor_shape;
57117395Skanstatic vr_draw_cursor_t		gfb_cursor;
58117395Skanstatic vr_blink_cursor_t	gfb_blink;
59117395Skan#ifndef SC_NO_CUTPASTE
60117395Skanstatic vr_draw_mouse_t		gfb_mouse;
61117395Skan#else
62117395Skan#define gfb_mouse		(vr_draw_mouse_t *)gfb_nop
63117395Skan#endif
64117395Skan
65117395Skanstatic void			gfb_nop(scr_stat *scp);
66117395Skan
67117395Skansc_rndr_sw_t txtrndrsw = {
68117395Skan	(vr_init_t *)gfb_nop,
69117395Skan	gfb_clear,
70117395Skan	gfb_border,
71117395Skan	gfb_draw,
72117395Skan	gfb_cursor_shape,
73117395Skan	gfb_cursor,
74117395Skan	gfb_blink,
75117395Skan	(vr_set_mouse_t *)gfb_nop,
76117395Skan	gfb_mouse,
77117395Skan};
78117395Skan
79117395Skan#ifdef SC_PIXEL_MODE
80117395Skansc_rndr_sw_t gfbrndrsw = {
81117395Skan	(vr_init_t *)gfb_nop,
82117395Skan	gfb_clear,
83117395Skan	gfb_border,
84117395Skan	gfb_draw,
85117395Skan	gfb_cursor_shape,
86117395Skan	gfb_cursor,
87117395Skan	gfb_blink,
88117395Skan	(vr_set_mouse_t *)gfb_nop,
89117395Skan	gfb_mouse,
90117395Skan};
91117395Skan#endif /* SC_PIXEL_MODE */
92117395Skan
93117395Skan#ifndef SC_NO_MODE_CHANGE
94117395Skansc_rndr_sw_t grrndrsw = {
95117395Skan	(vr_init_t *)gfb_nop,
96117395Skan	(vr_clear_t *)gfb_nop,
97117395Skan	gfb_border,
98117395Skan	(vr_draw_t *)gfb_nop,
99117395Skan	(vr_set_cursor_t *)gfb_nop,
100117395Skan	(vr_draw_cursor_t *)gfb_nop,
101117395Skan	(vr_blink_cursor_t *)gfb_nop,
102117395Skan	(vr_set_mouse_t *)gfb_nop,
103117395Skan	(vr_draw_mouse_t *)gfb_nop,
104117395Skan};
105117395Skan#endif /* SC_NO_MODE_CHANGE */
106117395Skan
107117395Skan#ifndef SC_NO_CUTPASTE
108117395Skan#ifdef __sparc64__
109117395Skanstatic u_char mouse_pointer[22 * 2] = {
110117395Skan	0x00, 0x00,	/* ............ */
111117395Skan	0x80, 0x00,	/* *........... */
112117395Skan	0xc0, 0x00,	/* **.......... */
113117395Skan	0xe0, 0x00,	/* ***......... */
114117395Skan	0xf0, 0x00,	/* ****........ */
115117395Skan	0xf8, 0x00,	/* *****....... */
116117395Skan	0xfc, 0x00,	/* ******...... */
117117395Skan	0xfe, 0x00,	/* *******..... */
118117395Skan	0xff, 0x00,	/* ********.... */
119117395Skan	0xff, 0x80,	/* *********... */
120117395Skan	0xfc, 0xc0,	/* ******..**.. */
121117395Skan	0xdc, 0x00,	/* **.***...... */
122117395Skan	0x8e, 0x00,	/* *...***..... */
123117395Skan	0x0e, 0x00,	/* ....***..... */
124117395Skan	0x07, 0x00,	/* .....***.... */
125117395Skan	0x04, 0x00,	/* .....*...... */
126117395Skan	0x00, 0x00,	/* ............ */
127117395Skan	0x00, 0x00,	/* ............ */
128117395Skan	0x00, 0x00,	/* ............ */
129117395Skan	0x00, 0x00,	/* ............ */
130117395Skan	0x00, 0x00,	/* ............ */
131117395Skan	0x00, 0x00	/* ............ */
132117395Skan};
133117395Skan#else
134117395Skanstatic u_char mouse_pointer[16] = {
135117395Skan	0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
136117395Skan	0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
137117395Skan};
138117395Skan#endif
139117395Skan#endif
140117395Skan
141117395Skanstatic void
142117395Skangfb_nop(scr_stat *scp)
143117395Skan{
144117395Skan}
145117395Skan
146117395Skan/* text mode renderer */
147117395Skan
148117395Skanstatic void
149117395Skangfb_clear(scr_stat *scp, int c, int attr)
150117395Skan{
151117395Skan	vidd_clear(scp->sc->adp);
152117395Skan}
153117395Skan
154117395Skanstatic void
155117395Skangfb_border(scr_stat *scp, int color)
156117395Skan{
157169689Skan	vidd_set_border(scp->sc->adp, color);
158169689Skan}
159
160static void
161gfb_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		vidd_copy(adp, n, 0, n);
191#if 0
192		vidd_clear(adp, n);
193#endif
194
195		/* Display new text rows... */
196		vidd_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				vidd_putc(adp, from, c,
216				    (a >> 4) | ((a & 0xf) << 4));
217			}
218		else {
219			vidd_puts(adp, from,
220			    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from),
221			    count);
222		}
223	}
224}
225
226static void
227gfb_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	vidd_set_hw_cursor_shape(scp->sc->adp, base, height, scp->font_size,
237	    blink);
238}
239
240static int pxlblinkrate = 0;
241
242#if defined(__sparc64__) || defined(SC_OFWFB)
243static void
244gfb_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			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
258		} else {
259			if (scp->status & VR_CURSOR_ON)
260				vidd_set_hw_cursor(adp, -1, -1);
261			scp->status &= ~VR_CURSOR_ON;
262		}
263	} else {
264		scp->status &= ~VR_CURSOR_BLINK;
265		if(on) {
266			scp->status |= VR_CURSOR_ON;
267			vidd_putc(scp->sc->adp, scp->cursor_oldpos,
268			    sc_vtb_getc(&scp->vtb, scp->cursor_oldpos),
269			    sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8);
270			a = sc_vtb_geta(&scp->vtb, at) >> 8;
271			c = sc_vtb_getc(&scp->vtb, at);
272			vidd_putc(scp->sc->adp, at, c,
273			    (a >> 4) | ((a & 0xf) << 4));
274			scp->cursor_saveunder_attr = a;
275			scp->cursor_saveunder_char = c;
276		} else {
277			if (scp->status & VR_CURSOR_ON)
278				vidd_putc(scp->sc->adp, at,
279				    scp->cursor_saveunder_char,
280				    scp->cursor_saveunder_attr);
281			scp->status &= ~VR_CURSOR_ON;
282		}
283	}
284}
285#else
286static void
287gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
288{
289	video_adapter_t *adp;
290
291	adp = scp->sc->adp;
292	if (scp->curs_attr.height <= 0)
293		/* the text cursor is disabled */
294		return;
295
296	if (on) {
297		if (!blink) {
298			scp->status |= VR_CURSOR_ON;
299			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
300		} else if (++pxlblinkrate & 4) {
301			pxlblinkrate = 0;
302			scp->status ^= VR_CURSOR_ON;
303			if(scp->status & VR_CURSOR_ON)
304				vidd_set_hw_cursor(adp, at%scp->xsize,
305				    at/scp->xsize);
306			else
307				vidd_set_hw_cursor(adp, -1, -1);
308		}
309	} else {
310		if (scp->status & VR_CURSOR_ON)
311			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
312		scp->status &= ~VR_CURSOR_ON;
313	}
314	if (blink)
315		scp->status |= VR_CURSOR_BLINK;
316	else
317		scp->status &= ~VR_CURSOR_BLINK;
318}
319#endif
320
321static void
322gfb_blink(scr_stat *scp, int at, int flip)
323{
324	if (!(scp->status & VR_CURSOR_BLINK))
325		return;
326	if (!(++pxlblinkrate & 4))
327		return;
328	pxlblinkrate = 0;
329	scp->status ^= VR_CURSOR_ON;
330	gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK,
331	    scp->status & VR_CURSOR_ON, flip);
332}
333
334#ifndef SC_NO_CUTPASTE
335
336static void
337gfb_mouse(scr_stat *scp, int x, int y, int on)
338{
339#ifdef __sparc64__
340		vidd_putm(scp->sc->adp, x, y, mouse_pointer,
341		    on ? 0xffffffff : 0x0, 22, 12);
342#else
343	int i, pos;
344
345	if (on) {
346
347		/* Display the mouse pointer image... */
348		vidd_putm(scp->sc->adp, x, y, mouse_pointer,
349		    0xffffffff, 16, 8);
350	} else {
351
352		/*
353		   Erase the mouse cursor image by redrawing the text
354		   underneath it...
355		*/
356		return;
357		pos = x*scp->xsize + y;
358		i = (y < scp->xsize - 1) ? 2 : 1;
359		(*scp->rndr->draw)(scp, pos, i, FALSE);
360		if (x < scp->ysize - 1)
361			(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
362	}
363#endif
364}
365
366#endif /* SC_NO_CUTPASTE */
367