xref: /freebsd/sys/dev/syscons/scgfbrndr.c (revision 06c3fb27)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer as
12  *    the first lines of this file unmodified.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Copyright (c) 2000 Andrew Miklic
29  */
30 
31 #include <sys/cdefs.h>
32 #include "opt_syscons.h"
33 #ifdef __powerpc__
34 #include "opt_ofwfb.h"
35 #endif
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/fbio.h>
41 #include <sys/consio.h>
42 
43 #include <machine/bus.h>
44 
45 #include <dev/fb/fbreg.h>
46 #include <dev/syscons/syscons.h>
47 
48 #ifndef SC_RENDER_DEBUG
49 #define SC_RENDER_DEBUG		0
50 #endif
51 
52 static vr_clear_t		gfb_clear;
53 static vr_draw_border_t		gfb_border;
54 static vr_draw_t		gfb_draw;
55 static vr_set_cursor_t		gfb_cursor_shape;
56 static vr_draw_cursor_t		gfb_cursor;
57 static vr_blink_cursor_t	gfb_blink;
58 #ifndef SC_NO_CUTPASTE
59 static vr_draw_mouse_t		gfb_mouse;
60 #else
61 #define gfb_mouse		(vr_draw_mouse_t *)gfb_nop
62 #endif
63 
64 static void			gfb_nop(scr_stat *scp);
65 
66 sc_rndr_sw_t txtrndrsw = {
67 	(vr_init_t *)gfb_nop,
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
79 sc_rndr_sw_t gfbrndrsw = {
80 	(vr_init_t *)gfb_nop,
81 	gfb_clear,
82 	gfb_border,
83 	gfb_draw,
84 	gfb_cursor_shape,
85 	gfb_cursor,
86 	gfb_blink,
87 	(vr_set_mouse_t *)gfb_nop,
88 	gfb_mouse,
89 };
90 #endif /* SC_PIXEL_MODE */
91 
92 #ifndef SC_NO_MODE_CHANGE
93 sc_rndr_sw_t grrndrsw = {
94 	(vr_init_t *)gfb_nop,
95 	(vr_clear_t *)gfb_nop,
96 	gfb_border,
97 	(vr_draw_t *)gfb_nop,
98 	(vr_set_cursor_t *)gfb_nop,
99 	(vr_draw_cursor_t *)gfb_nop,
100 	(vr_blink_cursor_t *)gfb_nop,
101 	(vr_set_mouse_t *)gfb_nop,
102 	(vr_draw_mouse_t *)gfb_nop,
103 };
104 #endif /* SC_NO_MODE_CHANGE */
105 
106 #ifndef SC_NO_CUTPASTE
107 static u_char mouse_pointer[16] = {
108 	0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
109 	0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
110 };
111 #endif
112 
113 static void
114 gfb_nop(scr_stat *scp)
115 {
116 }
117 
118 /* text mode renderer */
119 
120 static void
121 gfb_clear(scr_stat *scp, int c, int attr)
122 {
123 	vidd_clear(scp->sc->adp);
124 }
125 
126 static void
127 gfb_border(scr_stat *scp, int color)
128 {
129 	vidd_set_border(scp->sc->adp, color);
130 }
131 
132 static void
133 gfb_draw(scr_stat *scp, int from, int count, int flip)
134 {
135 	int c;
136 	int a;
137 	int i, n;
138 	video_adapter_t *adp;
139 
140 	adp = scp->sc->adp;
141 
142 	/*
143 	   Determine if we need to scroll based on the offset
144 	   and the number of characters to be displayed...
145 	 */
146 	if (from + count > scp->xsize*scp->ysize) {
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 		vidd_copy(adp, n, 0, n);
162 #if 0
163 		vidd_clear(adp, n);
164 #endif
165 
166 		/* Display new text rows... */
167 		vidd_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 		   Determine the method by which we are to display characters
178 		   (are we going to print forwards or backwards?
179 		   do we need to do a character-by-character copy, then?)...
180 		*/
181 		if (flip)
182 			for (i = count; i-- > 0; ++from) {
183 				c = sc_vtb_getc(&scp->vtb, from);
184 				a = sc_vtb_geta(&scp->vtb, from) >> 8;
185 				vidd_putc(adp, from, c,
186 				    (a >> 4) | ((a & 0xf) << 4));
187 			}
188 		else {
189 			vidd_puts(adp, from,
190 			    (u_int16_t *)sc_vtb_pointer(&scp->vtb, from),
191 			    count);
192 		}
193 	}
194 }
195 
196 static void
197 gfb_cursor_shape(scr_stat *scp, int base, int height, int blink)
198 {
199 	if (base < 0 || base >= scp->font_size)
200 		return;
201 	/* the caller may set height <= 0 in order to disable the cursor */
202 #if 0
203 	scp->cursor_base = base;
204 	scp->cursor_height = height;
205 #endif
206 	vidd_set_hw_cursor_shape(scp->sc->adp, base, height, scp->font_size,
207 	    blink);
208 }
209 
210 static int pxlblinkrate = 0;
211 
212 #if defined(SC_OFWFB)
213 static void
214 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
215 {
216 	video_adapter_t *adp;
217 	int a, c;
218 
219 	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
220 		return;
221 
222 	adp = scp->sc->adp;
223 	if(blink) {
224 		scp->status |= VR_CURSOR_BLINK;
225 		if (on) {
226 			scp->status |= VR_CURSOR_ON;
227 			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
228 		} else {
229 			if (scp->status & VR_CURSOR_ON)
230 				vidd_set_hw_cursor(adp, -1, -1);
231 			scp->status &= ~VR_CURSOR_ON;
232 		}
233 	} else {
234 		scp->status &= ~VR_CURSOR_BLINK;
235 		if(on) {
236 			scp->status |= VR_CURSOR_ON;
237 			vidd_putc(scp->sc->adp, scp->cursor_oldpos,
238 			    sc_vtb_getc(&scp->vtb, scp->cursor_oldpos),
239 			    sc_vtb_geta(&scp->vtb, scp->cursor_oldpos) >> 8);
240 			a = sc_vtb_geta(&scp->vtb, at) >> 8;
241 			c = sc_vtb_getc(&scp->vtb, at);
242 			vidd_putc(scp->sc->adp, at, c,
243 			    (a >> 4) | ((a & 0xf) << 4));
244 		} else {
245 			if (scp->status & VR_CURSOR_ON)
246 				vidd_putc(scp->sc->adp, at,
247 				    sc_vtb_getc(&scp->vtb, at),
248 				    sc_vtb_geta(&scp->vtb, at) >> 8);
249 			scp->status &= ~VR_CURSOR_ON;
250 		}
251 	}
252 }
253 #else
254 static void
255 gfb_cursor(scr_stat *scp, int at, int blink, int on, int flip)
256 {
257 	video_adapter_t *adp;
258 
259 	adp = scp->sc->adp;
260 	if (scp->curs_attr.height <= 0)
261 		/* the text cursor is disabled */
262 		return;
263 
264 	if (on) {
265 		if (!blink) {
266 			scp->status |= VR_CURSOR_ON;
267 			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
268 		} else if (++pxlblinkrate & 4) {
269 			pxlblinkrate = 0;
270 			scp->status ^= VR_CURSOR_ON;
271 			if(scp->status & VR_CURSOR_ON)
272 				vidd_set_hw_cursor(adp, at%scp->xsize,
273 				    at/scp->xsize);
274 			else
275 				vidd_set_hw_cursor(adp, -1, -1);
276 		}
277 	} else {
278 		if (scp->status & VR_CURSOR_ON)
279 			vidd_set_hw_cursor(adp, at%scp->xsize, at/scp->xsize);
280 		scp->status &= ~VR_CURSOR_ON;
281 	}
282 	if (blink)
283 		scp->status |= VR_CURSOR_BLINK;
284 	else
285 		scp->status &= ~VR_CURSOR_BLINK;
286 }
287 #endif
288 
289 static void
290 gfb_blink(scr_stat *scp, int at, int flip)
291 {
292 	if (!(scp->status & VR_CURSOR_BLINK))
293 		return;
294 	if (!(++pxlblinkrate & 4))
295 		return;
296 	pxlblinkrate = 0;
297 	scp->status ^= VR_CURSOR_ON;
298 	gfb_cursor(scp, at, scp->status & VR_CURSOR_BLINK,
299 	    scp->status & VR_CURSOR_ON, flip);
300 }
301 
302 #ifndef SC_NO_CUTPASTE
303 
304 static void
305 gfb_mouse(scr_stat *scp, int x, int y, int on)
306 {
307 	if (on) {
308 		vidd_putm(scp->sc->adp, x, y, mouse_pointer,
309 		    0xffffffff, 16, 8);
310 	} else {
311 		/* XXX: removal is incomplete for h/w cursors and borders. */
312 	}
313 }
314 
315 #endif /* SC_NO_CUTPASTE */
316