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: stable/11/sys/dev/syscons/scgfbrndr.c 331722 2018-03-29 02:50:57Z eadler $");
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#ifdef __sparc64__
109static u_char mouse_pointer[22 * 2] = {
110	0x00, 0x00,	/* ............ */
111	0x80, 0x00,	/* *........... */
112	0xc0, 0x00,	/* **.......... */
113	0xe0, 0x00,	/* ***......... */
114	0xf0, 0x00,	/* ****........ */
115	0xf8, 0x00,	/* *****....... */
116	0xfc, 0x00,	/* ******...... */
117	0xfe, 0x00,	/* *******..... */
118	0xff, 0x00,	/* ********.... */
119	0xff, 0x80,	/* *********... */
120	0xfc, 0xc0,	/* ******..**.. */
121	0xdc, 0x00,	/* **.***...... */
122	0x8e, 0x00,	/* *...***..... */
123	0x0e, 0x00,	/* ....***..... */
124	0x07, 0x00,	/* .....***.... */
125	0x04, 0x00,	/* .....*...... */
126	0x00, 0x00,	/* ............ */
127	0x00, 0x00,	/* ............ */
128	0x00, 0x00,	/* ............ */
129	0x00, 0x00,	/* ............ */
130	0x00, 0x00,	/* ............ */
131	0x00, 0x00	/* ............ */
132};
133#else
134static u_char mouse_pointer[16] = {
135	0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
136	0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
137};
138#endif
139#endif
140
141static void
142gfb_nop(scr_stat *scp)
143{
144}
145
146/* text mode renderer */
147
148static void
149gfb_clear(scr_stat *scp, int c, int attr)
150{
151	vidd_clear(scp->sc->adp);
152}
153
154static void
155gfb_border(scr_stat *scp, int color)
156{
157	vidd_set_border(scp->sc->adp, color);
158}
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		} else {
275			if (scp->status & VR_CURSOR_ON)
276				vidd_putc(scp->sc->adp, at,
277				    sc_vtb_getc(&scp->vtb, at),
278				    sc_vtb_geta(&scp->vtb, at) >> 8);
279			scp->status &= ~VR_CURSOR_ON;
280		}
281	}
282}
283#else
284static void
285gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
286{
287	video_adapter_t *adp;
288
289	adp = scp->sc->adp;
290	if (scp->curs_attr.height <= 0)
291		/* the text cursor is disabled */
292		return;
293
294	if (on) {
295		if (!blink) {
296			scp->status |= VR_CURSOR_ON;
297			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
298		} else if (++pxlblinkrate & 4) {
299			pxlblinkrate = 0;
300			scp->status ^= VR_CURSOR_ON;
301			if(scp->status & VR_CURSOR_ON)
302				vidd_set_hw_cursor(adp, at%scp->xsize,
303				    at/scp->xsize);
304			else
305				vidd_set_hw_cursor(adp, -1, -1);
306		}
307	} else {
308		if (scp->status & VR_CURSOR_ON)
309			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
310		scp->status &= ~VR_CURSOR_ON;
311	}
312	if (blink)
313		scp->status |= VR_CURSOR_BLINK;
314	else
315		scp->status &= ~VR_CURSOR_BLINK;
316}
317#endif
318
319static void
320gfb_blink(scr_stat *scp, int at, int flip)
321{
322	if (!(scp->status & VR_CURSOR_BLINK))
323		return;
324	if (!(++pxlblinkrate & 4))
325		return;
326	pxlblinkrate = 0;
327	scp->status ^= VR_CURSOR_ON;
328	gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK,
329	    scp->status & VR_CURSOR_ON, flip);
330}
331
332#ifndef SC_NO_CUTPASTE
333
334static void
335gfb_mouse(scr_stat *scp, int x, int y, int on)
336{
337#ifdef __sparc64__
338	vidd_putm(scp->sc->adp, x, y, mouse_pointer,
339	    on ? 0xffffffff : 0x0, 22, 12);
340#else
341	if (on) {
342		vidd_putm(scp->sc->adp, x, y, mouse_pointer,
343		    0xffffffff, 16, 8);
344	} else {
345		/* XXX: removal is incomplete for h/w cursors and borders. */
346	}
347#endif
348}
349
350#endif /* SC_NO_CUTPASTE */
351