xref: /dflybsd-src/sys/dev/misc/syscons/sckmsrndr.c (revision 02d0b1ce2a4f5e91f8a38d977e6239e4483d4d48)
1 /*-
2  * Copyright (c) 2014 Imre Vadász <imre@vdsz.com>
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 
27 #include "opt_syscons.h"
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/thread.h>
33 #include <sys/thread2.h>
34 
35 #include <machine/console.h>
36 
37 #include <dev/drm/include/linux/fb.h>
38 
39 #include "syscons.h"
40 
41 #include <bus/isa/isareg.h>
42 
43 static vr_draw_t		kms_draw;
44 static vr_draw_cursor_t		kms_cursor;
45 static vr_blink_cursor_t	kms_blink;
46 static vr_draw_mouse_t		kms_mouse;
47 
48 static void			kms_nop(scr_stat *scp, ...);
49 
50 static sc_rndr_sw_t kmsrndrsw = {
51 	(vr_draw_border_t *)kms_nop,
52 	kms_draw,
53 	(vr_set_cursor_t *)kms_nop,
54 	kms_cursor,
55 	kms_blink,
56 #ifndef SC_NO_CUTPASTE
57 	kms_mouse,
58 #else
59 	(vr_draw_mouse_t *)kms_nop;
60 #endif
61 };
62 RENDERER(kms, V_INFO_MM_TEXT, kmsrndrsw, kms_set);
63 
64 #ifndef SC_NO_MODE_CHANGE
65 static sc_rndr_sw_t grrndrsw = {
66 	(vr_draw_border_t *)kms_nop,
67 	(vr_draw_t *)kms_nop,
68 	(vr_set_cursor_t *)kms_nop,
69 	(vr_draw_cursor_t *)kms_nop,
70 	(vr_blink_cursor_t *)kms_nop,
71 	(vr_draw_mouse_t *)kms_nop,
72 };
73 RENDERER(kms, V_INFO_MM_OTHER, grrndrsw, kms_set);
74 #endif /* SC_NO_MODE_CHANGE */
75 
76 RENDERER_MODULE(kms, kms_set);
77 
78 static uint32_t colormap[16] = {
79 	0x00000000,	/* BLACK */
80 	0x000000aa,	/* BLUE */
81 	0x0000aa00,	/* GREEN */
82 	0x0000aaaa,	/* CYAN */
83 	0x00aa0000,	/* RED */
84 	0x00aa00aa,	/* MAGENTA */
85 	0x00aa5500,	/* BROWN */
86 	0x00aaaaaa,	/* WHITE */
87 	0x00555555,	/* HIGHLIGHT BLACK */
88 	0x005555ff,	/* HIGHLIGHT BLUE */
89 	0x0055ff55,	/* HIGHLIGHT GREEN */
90 	0x0055ffff,	/* HIGHLIGHT CYAN */
91 	0x00ff5555,	/* HIGHLIGHT RED */
92 	0x00ff55ff,	/* HIGHLIGHT MAGENTA */
93 	0x00ffff55,	/* HIGHLIGHT BROWN */
94 	0x00ffffff,	/* HIGHLIGHT WHITE */
95 };
96 
97 #ifndef SC_NO_CUTPASTE
98 static u_short mouse_and_mask[16] = {
99 	0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
100 	0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
101 };
102 static u_short mouse_or_mask[16] = {
103 	0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
104 	0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
105 };
106 #endif
107 
108 static void
109 kms_nop(scr_stat *scp, ...)
110 {
111 }
112 
113 /* KMS renderer */
114 
115 static void
116 kms_draw(scr_stat *scp, int from, int count, int flip)
117 {
118 	sc_softc_t *sc = scp->sc;
119 	u_char *char_data;
120 	int a, i, j;
121 	uint32_t fg, bg;
122 	vm_offset_t draw_pos, p;
123 	int pos, line_width, pixel_size;
124 
125 	line_width = sc->fbi->stride;
126 	pixel_size = 4;
127 
128 	draw_pos = sc->fbi->vaddr +
129 	    8 * pixel_size * (from % scp->xsize) +
130 	    scp->font_size * line_width * (from / scp->xsize);
131 
132 	if (from + count > scp->xsize * scp->ysize)
133 		count = scp->xsize * scp->ysize - from;
134 
135 	for (i = from; count-- > 0; i++) {
136 		p = draw_pos;
137 		char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) *
138 		    scp->font_size]);
139 
140 		a = sc_vtb_geta(&scp->vtb, i);
141 		if (flip) {
142 			fg = colormap[((a & 0xf000) >> 4) >> 8];
143 			bg = colormap[(a & 0x0f00) >> 8];
144 		} else {
145 			fg = colormap[(a & 0x0f00) >> 8];
146 			bg = colormap[((a & 0xf000) >> 4) >> 8];
147 		}
148 
149 		for (j = 0; j < scp->font_size; j++, char_data++) {
150 			for (pos = 7; pos >= 0; pos--, p += pixel_size)
151 				writel(p, *char_data & (1 << pos) ? fg : bg);
152 			p += line_width - 8 * pixel_size;
153 		}
154 		draw_pos += 8 * pixel_size;
155 		if ((i % scp->xsize) == scp->xsize - 1) {
156 			draw_pos += (scp->font_size - 1) * line_width +
157 			    scp->xpad * pixel_size;
158 		}
159 	}
160 }
161 
162 static void
163 draw_kmscursor(scr_stat *scp, int at, int on, int flip)
164 {
165 	sc_softc_t *sc = scp->sc;
166 	int line_width, pixel_size, height;
167 	int a, i, pos;
168 	uint32_t fg, bg;
169 	unsigned char *char_data;
170 	vm_offset_t draw_pos;
171 
172 	line_width = sc->fbi->stride;
173 	pixel_size = 4;
174 
175 	draw_pos = sc->fbi->vaddr +
176 	    8 * pixel_size * (at % scp->xsize) +
177 	    scp->font_size * line_width * (at / scp->xsize) +
178 	    (scp->font_size - scp->cursor_base - 1) * line_width;
179 
180 	a = sc_vtb_geta(&scp->vtb, at);
181 	if (flip) {
182 		fg = colormap[((on) ? (a & 0x0f00) :
183 		    ((a & 0xf000) >> 4)) >> 8];
184 		bg = colormap[((on) ? ((a & 0xf000) >> 4) :
185 		    (a & 0x0f00)) >> 8];
186 	} else {
187 		fg = colormap[((on) ? ((a & 0xf000) >> 4) :
188 		    (a & 0x0f00)) >> 8];
189 		bg = colormap[((on) ? (a & 0x0f00) :
190 		    ((a & 0xf000) >> 4)) >> 8];
191 	}
192 
193 	char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
194 	    scp->font_size - scp->cursor_base - 1]);
195 	height = imin(scp->cursor_height, scp->font_size);
196 
197 	for (i = 0; i < height; i++, char_data--) {
198 		for (pos = 7; pos >= 0; pos--, draw_pos += pixel_size)
199 			writel(draw_pos, *char_data & (1 << pos) ? fg : bg);
200 		draw_pos -= line_width + 8 * pixel_size;
201 	}
202 }
203 
204 static int pxlblinkrate = 0;
205 
206 static void
207 kms_cursor(scr_stat *scp, int at, int blink, int on, int flip)
208 {
209 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
210 		return;
211 
212 	if (on) {
213 		if (!blink) {
214 			scp->status |= VR_CURSOR_ON;
215 			draw_kmscursor(scp, at, on, flip);
216 		} else if (++pxlblinkrate & 4) {
217 			pxlblinkrate = 0;
218 			scp->status ^= VR_CURSOR_ON;
219 			draw_kmscursor(scp, at,
220 			    scp->status & VR_CURSOR_ON, flip);
221 		}
222 	} else {
223 		if (scp->status & VR_CURSOR_ON)
224 			draw_kmscursor(scp, at, on, flip);
225 		scp->status &= ~VR_CURSOR_ON;
226 	}
227 	if (blink)
228 		scp->status |= VR_CURSOR_BLINK;
229 	else
230 		scp->status &= ~VR_CURSOR_BLINK;
231 }
232 
233 static void
234 kms_blink(scr_stat *scp, int at, int flip)
235 {
236 	if (!(scp->status & VR_CURSOR_BLINK))
237 		return;
238 	if (!(++pxlblinkrate & 4))
239 		return;
240 	pxlblinkrate = 0;
241 	scp->status ^= VR_CURSOR_ON;
242 	draw_kmscursor(scp, at, scp->status & VR_CURSOR_ON, flip);
243 }
244 
245 #ifndef SC_NO_CUTPASTE
246 
247 static void
248 draw_kmsmouse(scr_stat *scp, int x, int y)
249 {
250 	sc_softc_t *sc = scp->sc;
251 	int line_width, pixel_size;
252 	int xend, yend;
253 	int i, j;
254 	vm_offset_t draw_pos;
255 
256 	line_width = sc->fbi->stride;
257 	pixel_size = 4;
258 
259 	xend = imin(x + 8, 8 * (scp->xoff + scp->xsize));
260 	yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
261 
262 	draw_pos = sc->fbi->vaddr + y * line_width + x * pixel_size;
263 
264 	for (i = 0; i < (yend - y); i++) {
265 		for (j = (xend - x - 1); j >= 0; j--) {
266 			if (mouse_or_mask[i] & 1 << (15 - j))
267 				writel(draw_pos + pixel_size * j, colormap[15]);
268 			else if (mouse_and_mask[i] & 1 << (15 - j))
269 				writel(draw_pos + pixel_size * j, colormap[0]);
270 		}
271 
272 		draw_pos += line_width;
273 	}
274 }
275 
276 static void
277 remove_kmsmouse(scr_stat *scp, int x, int y)
278 {
279 	int col, row;
280 	int pos;
281 	int i;
282 
283 	/* erase the mouse cursor image */
284 	col = x/8 - scp->xoff;
285 	row = y/scp->font_size - scp->yoff;
286 	pos = row*scp->xsize + col;
287 	i = (col < scp->xsize - 1) ? 2 : 1;
288 	(*scp->rndr->draw)(scp, pos, i, FALSE);
289 	if (row < scp->ysize - 1)
290 		(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
291 }
292 
293 static void
294 kms_mouse(scr_stat *scp, int x, int y, int on)
295 {
296 	if (on)
297 		draw_kmsmouse(scp, x, y);
298 	else
299 		remove_kmsmouse(scp, x, y);
300 }
301 
302 #endif /* SC_NO_CUTPASTE */
303