xref: /dragonfly/sys/dev/misc/syscons/scvgarndr.c (revision 19fe1c42)
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The DragonFly Project
6  * by Sascha Wildner <saw@online.de>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer as
13  *    the first lines of this file unmodified.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/dev/syscons/scvgarndr.c,v 1.5.2.3 2001/07/28 12:51:47 yokota Exp $
30  * $DragonFly: src/sys/dev/misc/syscons/scvgarndr.c,v 1.17 2008/08/10 19:45:01 swildner Exp $
31  */
32 
33 #include "opt_syscons.h"
34 #include "opt_vga.h"
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 
40 #include <machine/console.h>
41 
42 #include <dev/video/fb/fbreg.h>
43 #include <dev/video/fb/vgareg.h>
44 #include "syscons.h"
45 
46 #include <bus/isa/isareg.h>
47 
48 static vr_draw_border_t		vga_txtborder;
49 static vr_draw_t		vga_txtdraw;
50 static vr_set_cursor_t		vga_txtcursor_shape;
51 static vr_draw_cursor_t		vga_txtcursor;
52 static vr_blink_cursor_t	vga_txtblink;
53 #ifndef SC_NO_CUTPASTE
54 static vr_draw_mouse_t		vga_txtmouse;
55 #else
56 #define	vga_txtmouse		(vr_draw_mouse_t *)vga_nop
57 #endif
58 
59 #ifdef SC_PIXEL_MODE
60 static vr_init_t		vga_rndrinit;
61 static vr_draw_border_t		vga_pxlborder_direct;
62 static vr_draw_border_t		vga_pxlborder_planar;
63 static vr_draw_t		vga_vgadraw_direct;
64 static vr_draw_t		vga_vgadraw_planar;
65 static vr_set_cursor_t		vga_pxlcursor_shape;
66 static vr_draw_cursor_t		vga_pxlcursor_direct;
67 static vr_draw_cursor_t		vga_pxlcursor_planar;
68 static vr_blink_cursor_t	vga_pxlblink_direct;
69 static vr_blink_cursor_t	vga_pxlblink_planar;
70 #ifndef SC_NO_CUTPASTE
71 static vr_draw_mouse_t		vga_pxlmouse_direct;
72 static vr_draw_mouse_t		vga_pxlmouse_planar;
73 #else
74 #define	vga_pxlmouse_direct	(vr_draw_mouse_t *)vga_nop
75 #define	vga_pxlmouse_planar	(vr_draw_mouse_t *)vga_nop
76 #endif
77 #endif /* SC_PIXEL_MODE */
78 
79 #ifndef SC_NO_MODE_CHANGE
80 static vr_draw_border_t		vga_grborder;
81 #endif
82 
83 static void			vga_nop(scr_stat *scp, ...);
84 
85 static sc_rndr_sw_t txtrndrsw = {
86 	(vr_init_t *)vga_nop,
87 	vga_txtborder,
88 	vga_txtdraw,
89 	vga_txtcursor_shape,
90 	vga_txtcursor,
91 	vga_txtblink,
92 	(vr_set_mouse_t *)vga_nop,
93 	vga_txtmouse,
94 };
95 RENDERER(vga, 0, txtrndrsw, vga_set);
96 
97 #ifdef SC_PIXEL_MODE
98 static sc_rndr_sw_t vgarndrsw = {
99 	vga_rndrinit,
100 	(vr_draw_border_t *)vga_nop,
101 	(vr_draw_t *)vga_nop,
102 	vga_pxlcursor_shape,
103 	(vr_draw_cursor_t *)vga_nop,
104 	(vr_blink_cursor_t *)vga_nop,
105 	(vr_set_mouse_t *)vga_nop,
106 	(vr_draw_mouse_t *)vga_nop,
107 };
108 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
109 #endif /* SC_PIXEL_MODE */
110 
111 #ifndef SC_NO_MODE_CHANGE
112 static sc_rndr_sw_t grrndrsw = {
113 	(vr_init_t *)vga_nop,
114 	vga_grborder,
115 	(vr_draw_t *)vga_nop,
116 	(vr_set_cursor_t *)vga_nop,
117 	(vr_draw_cursor_t *)vga_nop,
118 	(vr_blink_cursor_t *)vga_nop,
119 	(vr_set_mouse_t *)vga_nop,
120 	(vr_draw_mouse_t *)vga_nop,
121 };
122 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
123 #endif /* SC_NO_MODE_CHANGE */
124 
125 RENDERER_MODULE(vga, vga_set);
126 
127 #ifndef SC_NO_CUTPASTE
128 static u_short mouse_and_mask[16] = {
129 	0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
130 	0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
131 };
132 static u_short mouse_or_mask[16] = {
133 	0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
134 	0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
135 };
136 #endif
137 
138 static void
139 vga_nop(scr_stat *scp, ...)
140 {
141 }
142 
143 /* text mode renderer */
144 
145 static void
146 vga_txtborder(scr_stat *scp, int color)
147 {
148 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
149 }
150 
151 static void
152 vga_txtdraw(scr_stat *scp, int from, int count, int flip)
153 {
154 	uint16_t *p;
155 	int c;
156 	int a;
157 
158 	if (from + count > scp->xsize*scp->ysize)
159 		count = scp->xsize*scp->ysize - from;
160 
161 	if (flip) {
162 		for (p = scp->scr.vtb_buffer + from; count-- > 0; ++from) {
163 			c = sc_vtb_getc(&scp->vtb, from);
164 			a = sc_vtb_geta(&scp->vtb, from);
165 			a = (a & 0x8800) | ((a & 0x7000) >> 4)
166 				| ((a & 0x0700) << 4);
167 			p = sc_vtb_putchar(&scp->scr, p, c, a);
168 		}
169 	} else {
170 		sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
171 	}
172 }
173 
174 static void
175 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
176 {
177 	if (base < 0 || base >= scp->font_size)
178 		return;
179 	/* the caller may set height <= 0 in order to disable the cursor */
180 #if 0
181 	scp->cursor_base = base;
182 	scp->cursor_height = height;
183 #endif
184 	(*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
185 							base, height,
186 							scp->font_size, blink);
187 }
188 
189 static void
190 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
191 {
192 	sc_softc_t *sc;
193 
194 	sc = scp->sc;
195 	scp->cursor_saveunder_char = c;
196 	scp->cursor_saveunder_attr = a;
197 
198 #ifndef SC_NO_FONT_LOADING
199 	if (sc->flags & SC_CHAR_CURSOR) {
200 		unsigned char *font;
201 		int h;
202 		int i;
203 
204 		if (scp->font_size < 14) {
205 			font = sc->font_8;
206 			h = 8;
207 		} else if (scp->font_size >= 16) {
208 			font = sc->font_16;
209 			h = 16;
210 		} else {
211 			font = sc->font_14;
212 			h = 14;
213 		}
214 		if (scp->cursor_base >= h)
215 			return;
216 		if (flip)
217 			a = (a & 0x8800)
218 				| ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
219 		bcopy(font + c*h, font + sc->cursor_char*h, h);
220 		font = font + sc->cursor_char*h;
221 		for (i = imax(h - scp->cursor_base - scp->cursor_height, 0);
222 			i < h - scp->cursor_base; ++i) {
223 			font[i] ^= 0xff;
224 		}
225 		sc->font_loading_in_progress = TRUE;
226 		/* XXX */
227 		(*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font,
228 						 sc->cursor_char, 1);
229 		sc->font_loading_in_progress = FALSE;
230 		sc_vtb_putc(&scp->scr, at, sc->cursor_char, a);
231 	} else
232 #endif /* SC_NO_FONT_LOADING */
233 	{
234 		if ((a & 0x7000) == 0x7000) {
235 			a &= 0x8f00;
236 			if ((a & 0x0700) == 0)
237 				a |= 0x0700;
238 		} else {
239 			a |= 0x7000;
240 			if ((a & 0x0700) == 0x0700)
241 				a &= 0xf000;
242 		}
243 		if (flip)
244 			a = (a & 0x8800)
245 				| ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
246 		sc_vtb_putc(&scp->scr, at, c, a);
247 	}
248 }
249 
250 static void
251 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
252 {
253 	video_adapter_t *adp;
254 	int cursor_attr;
255 
256 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
257 		return;
258 
259 	adp = scp->sc->adp;
260 	if (blink) {
261 		scp->status |= VR_CURSOR_BLINK;
262 		if (on) {
263 			scp->status |= VR_CURSOR_ON;
264 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
265 							       at%scp->xsize,
266 							       at/scp->xsize);
267 		} else {
268 			if (scp->status & VR_CURSOR_ON)
269 				(*vidsw[adp->va_index]->set_hw_cursor)(adp,
270 								       -1, -1);
271 			scp->status &= ~VR_CURSOR_ON;
272 		}
273 	} else {
274 		scp->status &= ~VR_CURSOR_BLINK;
275 		if (on) {
276 			scp->status |= VR_CURSOR_ON;
277 			draw_txtcharcursor(scp, at,
278 					   sc_vtb_getc(&scp->scr, at),
279 					   sc_vtb_geta(&scp->scr, at),
280 					   flip);
281 		} else {
282 			cursor_attr = scp->cursor_saveunder_attr;
283 			if (flip)
284 				cursor_attr = (cursor_attr & 0x8800)
285 					| ((cursor_attr & 0x7000) >> 4)
286 					| ((cursor_attr & 0x0700) << 4);
287 			if (scp->status & VR_CURSOR_ON)
288 				sc_vtb_putc(&scp->scr, at,
289 					    scp->cursor_saveunder_char,
290 					    cursor_attr);
291 			scp->status &= ~VR_CURSOR_ON;
292 		}
293 	}
294 }
295 
296 static void
297 vga_txtblink(scr_stat *scp, int at, int flip)
298 {
299 }
300 
301 #ifndef SC_NO_CUTPASTE
302 
303 static void
304 draw_txtmouse(scr_stat *scp, int x, int y)
305 {
306 #ifndef SC_ALT_MOUSE_IMAGE
307     if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) {
308 	u_char font_buf[128];
309 	u_short cursor[32];
310 	u_char c;
311 	int pos;
312 	int xoffset, yoffset;
313 	int i;
314 
315 	/* prepare mousepointer char's bitmaps */
316 	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
317 	bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
318 	      &font_buf[0], scp->font_size);
319 	bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
320 	      &font_buf[32], scp->font_size);
321 	bcopy(scp->font
322 		 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
323 	      &font_buf[64], scp->font_size);
324 	bcopy(scp->font
325 		 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
326 	      &font_buf[96], scp->font_size);
327 	for (i = 0; i < scp->font_size; ++i) {
328 		cursor[i] = font_buf[i]<<8 | font_buf[i+32];
329 		cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
330 	}
331 
332 	/* now and-or in the mousepointer image */
333 	xoffset = x%8;
334 	yoffset = y%scp->font_size;
335 	for (i = 0; i < 16; ++i) {
336 		cursor[i + yoffset] =
337 	    		(cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset))
338 	    		| (mouse_or_mask[i] >> xoffset);
339 	}
340 	for (i = 0; i < scp->font_size; ++i) {
341 		font_buf[i] = (cursor[i] & 0xff00) >> 8;
342 		font_buf[i + 32] = cursor[i] & 0xff;
343 		font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
344 		font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
345 	}
346 
347 #if 1
348 	/* wait for vertical retrace to avoid jitter on some videocards */
349 	while (!(inb(CRTC + 6) & 0x08)) /* idle */ ;
350 #endif
351 	c = scp->sc->mouse_char;
352 	(*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf,
353 					      c, 4);
354 
355 	sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
356 	/* FIXME: may be out of range! */
357 	sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
358 		    sc_vtb_geta(&scp->scr, pos + scp->xsize));
359 	if (x < (scp->xsize - 1)*8) {
360 		sc_vtb_putc(&scp->scr, pos + 1, c + 1,
361 			    sc_vtb_geta(&scp->scr, pos + 1));
362 		sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
363 			    sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
364 	}
365     } else
366 #endif /* SC_ALT_MOUSE_IMAGE */
367     {
368 	/* Red, magenta and brown are mapped to green to to keep it readable */
369 	static const int col_conv[16] = {
370 		6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
371 	};
372 	int pos;
373 	int color;
374 	int a;
375 
376 	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
377 	a = sc_vtb_geta(&scp->scr, pos);
378 	if (scp->sc->adp->va_flags & V_ADP_COLOR)
379 		color = (col_conv[(a & 0xf000) >> 12] << 12)
380 			| ((a & 0x0f00) | 0x0800);
381 	else
382 		color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
383 	sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
384     }
385 }
386 
387 static void
388 remove_txtmouse(scr_stat *scp, int x, int y)
389 {
390 }
391 
392 static void
393 vga_txtmouse(scr_stat *scp, int x, int y, int on)
394 {
395 	if (on)
396 		draw_txtmouse(scp, x, y);
397 	else
398 		remove_txtmouse(scp, x, y);
399 }
400 
401 #endif /* SC_NO_CUTPASTE */
402 
403 #ifdef SC_PIXEL_MODE
404 
405 /* pixel (raster text) mode renderer */
406 
407 static void
408 vga_rndrinit(scr_stat *scp)
409 {
410 	if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) {
411 		scp->rndr->draw_border = vga_pxlborder_planar;
412 		scp->rndr->draw = vga_vgadraw_planar;
413 		scp->rndr->draw_cursor = vga_pxlcursor_planar;
414 		scp->rndr->blink_cursor = vga_pxlblink_planar;
415 		scp->rndr->draw_mouse = vga_pxlmouse_planar;
416 	} else if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT) {
417 		scp->rndr->draw_border = vga_pxlborder_direct;
418 		scp->rndr->draw = vga_vgadraw_direct;
419 		scp->rndr->draw_cursor = vga_pxlcursor_direct;
420 		scp->rndr->blink_cursor = vga_pxlblink_direct;
421 		scp->rndr->draw_mouse = vga_pxlmouse_direct;
422 	}
423 }
424 
425 static void
426 vga_pxlborder_direct(scr_stat *scp, int color)
427 {
428 	int i, x, y;
429 	int line_width, pixel_size;
430 	uint32_t u32 = 0;
431 	vm_offset_t draw_pos, draw_end, p;
432 
433 	line_width = scp->sc->adp->va_line_width;
434 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
435 
436 	for (i = 0; i < 4 / pixel_size; ++i)
437 		u32 += scp->ega_palette[color] << (i * 8 * pixel_size);
438 
439 	if (scp->yoff > 0) {
440 		draw_pos = scp->sc->adp->va_window;
441 		draw_end = draw_pos +
442 		    line_width * scp->yoff * scp->font_size;
443 
444 		for (p = draw_pos; p < draw_end; p += 4)
445 			writel(p, u32);
446 	}
447 
448 	y = (scp->yoff + scp->ysize) * scp->font_size;
449 
450 	if (scp->ypixel > y) {
451 		draw_pos = scp->sc->adp->va_window + line_width * y;
452 		draw_end = draw_pos + line_width * (scp->ypixel - y);
453 
454 		for (p = draw_pos; p < draw_end; p += 4)
455 			writel(p, u32);
456 	}
457 
458 	y = scp->yoff * scp->font_size;
459 	x = scp->xpixel / 8 - scp->xoff - scp->xsize;
460 
461 	for (i = 0; i < scp->ysize * scp->font_size; ++i) {
462 		if (scp->xoff > 0) {
463 			draw_pos = scp->sc->adp->va_window +
464 			    line_width * (y + i);
465 			draw_end = draw_pos + scp->xoff * 8 * pixel_size;
466 
467 			for (p = draw_pos; p < draw_end; p += 4)
468 				writel(p, u32);
469 		}
470 
471 		if (x > 0) {
472 			draw_pos = scp->sc->adp->va_window +
473 			    line_width * (y + i) +
474 			    scp->xoff * 8 * pixel_size +
475 			    scp->xsize * 8 * pixel_size;
476 			draw_end = draw_pos + x * 8 * pixel_size;
477 
478 			for (p = draw_pos; p < draw_end; p += 4)
479 				writel(p, u32);
480 		}
481 	}
482 }
483 
484 static void
485 vga_pxlborder_planar(scr_stat *scp, int color)
486 {
487 	vm_offset_t p;
488 	int line_width;
489 	int x;
490 	int y;
491 	int i;
492 
493 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
494 
495 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
496 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
497 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
498 	outw(GDCIDX, 0xff08);		/* bit mask */
499 	outw(GDCIDX, (color << 8) | 0x00);	/* set/reset */
500 	line_width = scp->sc->adp->va_line_width;
501 	p = scp->sc->adp->va_window;
502 	if (scp->yoff > 0)
503 		bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
504 	y = (scp->yoff + scp->ysize)*scp->font_size;
505 	if (scp->ypixel > y)
506 		bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
507 	y = scp->yoff*scp->font_size;
508 	x = scp->xpixel/8 - scp->xoff - scp->xsize;
509 	for (i = 0; i < scp->ysize*scp->font_size; ++i) {
510 		if (scp->xoff > 0)
511 			bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
512 		if (x > 0)
513 			bzero_io((void *)(p + line_width*(y + i)
514 				     + scp->xoff + scp->xsize), x);
515 	}
516 	outw(GDCIDX, 0x0000);		/* set/reset */
517 	outw(GDCIDX, 0x0001);		/* set/reset enable */
518 }
519 
520 static void
521 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip)
522 {
523 	int line_width, pixel_size;
524 	int a, i, j, k, l, pos;
525 	uint32_t fg, bg, u32;
526 	unsigned char *char_data;
527 	vm_offset_t draw_pos, p;
528 
529 	line_width = scp->sc->adp->va_line_width;
530 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
531 
532 	draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size);
533 
534 	if (from + count > scp->xsize * scp->ysize)
535 		count = scp->xsize * scp->ysize - from;
536 
537 	for (i = from; count-- > 0; ++i) {
538 		a = sc_vtb_geta(&scp->vtb, i);
539 
540 		if (flip) {
541 			fg = scp->ega_palette[(((a & 0x7000) >> 4) |
542 			    (a & 0x0800)) >> 8];
543 			bg = scp->ega_palette[(((a & 0x8000) >> 4) |
544 			    (a & 0x0700)) >> 8];
545 		} else {
546 			fg = scp->ega_palette[(a & 0x0f00) >> 8];
547 			bg = scp->ega_palette[(a & 0xf000) >> 12];
548 		}
549 
550 		p = draw_pos;
551 		char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) *
552 		    scp->font_size]);
553 
554 		for (j = 0; j < scp->font_size; ++j, ++char_data) {
555 			pos = 7;
556 
557 			for (k = 0; k < 2 * pixel_size; ++k) {
558 				u32 = 0;
559 
560 				for (l = 0; l < 4 / pixel_size; ++l) {
561 					u32 += (*char_data & (1 << pos--) ?
562 					    fg : bg) << (l * 8 * pixel_size);
563 				}
564 
565 				writel(p, u32);
566 				p += 4;
567 			}
568 
569 			p += line_width - 8 * pixel_size;
570 		}
571 
572 		draw_pos += 8 * pixel_size;
573 
574 		if ((i % scp->xsize) == scp->xsize - 1)
575 			draw_pos += scp->xoff * 16 * pixel_size +
576 			     (scp->font_size - 1) * line_width;
577 	}
578 }
579 
580 static void
581 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip)
582 {
583 	vm_offset_t d;
584 	vm_offset_t e;
585 	u_char *f;
586 	u_short bg;
587 	u_short col1, col2;
588 	int line_width;
589 	int i, j;
590 	int a;
591 	u_char c;
592 
593 	d = VIDEO_MEMORY_POS(scp, from, 1);
594 
595 	line_width = scp->sc->adp->va_line_width;
596 
597 	outw(GDCIDX, 0x0305);		/* read mode 0, write mode 3 */
598 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
599 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
600 	outw(GDCIDX, 0xff08);		/* bit mask */
601 	bg = -1;
602 	if (from + count > scp->xsize*scp->ysize)
603 		count = scp->xsize*scp->ysize - from;
604 	for (i = from; count-- > 0; ++i) {
605 		a = sc_vtb_geta(&scp->vtb, i);
606 		if (flip) {
607 			col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
608 			col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
609 		} else {
610 			col1 = (a & 0x0f00);
611 			col2 = (a & 0xf000) >> 4;
612 		}
613 		/* set background color in EGA/VGA latch */
614 		if (bg != col2) {
615 			bg = col2;
616 			outw(GDCIDX, 0x0005);	/* read mode 0, write mode 0 */
617 			outw(GDCIDX, bg | 0x00); /* set/reset */
618 			writeb(d, 0);
619 			c = readb(d);		/* set bg color in the latch */
620 			outw(GDCIDX, 0x0305);	/* read mode 0, write mode 3 */
621 		}
622 		/* foreground color */
623 		outw(GDCIDX, col1 | 0x00);	/* set/reset */
624 		e = d;
625 		f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
626 		for (j = 0; j < scp->font_size; ++j, ++f) {
627 	        	writeb(e, *f);
628 			e += line_width;
629 		}
630 		++d;
631 		if ((i % scp->xsize) == scp->xsize - 1)
632 			d += scp->xoff*2
633 				 + (scp->font_size - 1)*line_width;
634 	}
635 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
636 	outw(GDCIDX, 0x0000);		/* set/reset */
637 	outw(GDCIDX, 0x0001);		/* set/reset enable */
638 }
639 
640 static void
641 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
642 {
643 	if (base < 0 || base >= scp->font_size)
644 		return;
645 	/* the caller may set height <= 0 in order to disable the cursor */
646 #if 0
647 	scp->cursor_base = base;
648 	scp->cursor_height = height;
649 #endif
650 }
651 
652 static void
653 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
654 {
655 	int line_width, pixel_size, height;
656 	int a, i, j, k, pos;
657 	uint32_t fg, bg, u32;
658 	unsigned char *char_data;
659 	vm_offset_t draw_pos;
660 
661 	line_width = scp->sc->adp->va_line_width;
662 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
663 
664 	draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) +
665 	    (scp->font_size - scp->cursor_base - 1) * line_width;
666 
667 	a = sc_vtb_geta(&scp->vtb, at);
668 
669 	if (flip) {
670 		fg = scp->ega_palette[((on) ? (a & 0x0f00) :
671 		    ((a & 0xf000) >> 4)) >> 8];
672 		bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) :
673 		    (a & 0x0f00)) >> 8];
674 	} else {
675 		fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) :
676 		    (a & 0x0f00)) >> 8];
677 		bg = scp->ega_palette[((on) ? (a & 0x0f00) :
678 		    ((a & 0xf000) >> 4)) >> 8];
679 	}
680 
681 	char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
682 	    scp->font_size - scp->cursor_base - 1]);
683 
684 	height = imin(scp->cursor_height, scp->font_size);
685 
686 	for (i = 0; i < height; ++i, --char_data) {
687 		pos = 7;
688 
689 		for (j = 0; j < 2 * pixel_size; ++j) {
690 			u32 = 0;
691 
692 			for (k = 0; k < 4 / pixel_size; ++k) {
693 				u32 += (*char_data & (1 << pos--) ?
694 				    fg : bg) << (k * 8 * pixel_size);
695 			}
696 
697 			writel(draw_pos, u32);
698 			draw_pos += 4;
699 		}
700 
701 		draw_pos -= line_width + 8 * pixel_size;
702 	}
703 }
704 
705 static void
706 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
707 {
708 	vm_offset_t d;
709 	u_char *f;
710 	int line_width;
711 	int height;
712 	int col;
713 	int a;
714 	int i;
715 	u_char c;
716 
717 	line_width = scp->sc->adp->va_line_width;
718 
719 	d = VIDEO_MEMORY_POS(scp, at, 1) +
720 	    (scp->font_size - scp->cursor_base - 1) * line_width;
721 
722 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
723 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
724 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
725 	/* set background color in EGA/VGA latch */
726 	a = sc_vtb_geta(&scp->vtb, at);
727 	if (flip)
728 		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
729 	else
730 		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
731 	outw(GDCIDX, col | 0x00);	/* set/reset */
732 	outw(GDCIDX, 0xff08);		/* bit mask */
733 	writeb(d, 0);
734 	c = readb(d);			/* set bg color in the latch */
735 	/* foreground color */
736 	if (flip)
737 		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
738 	else
739 		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
740 	outw(GDCIDX, col | 0x00);	/* set/reset */
741 	f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
742 		+ scp->font_size - scp->cursor_base - 1]);
743 	height = imin(scp->cursor_height, scp->font_size);
744 	for (i = 0; i < height; ++i, --f) {
745 		outw(GDCIDX, (*f << 8) | 0x08);	/* bit mask */
746 	       	writeb(d, 0);
747 		d -= line_width;
748 	}
749 	outw(GDCIDX, 0x0000);		/* set/reset */
750 	outw(GDCIDX, 0x0001);		/* set/reset enable */
751 	outw(GDCIDX, 0xff08);		/* bit mask */
752 }
753 
754 static int pxlblinkrate = 0;
755 
756 static void
757 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip)
758 {
759 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
760 		return;
761 
762 	if (on) {
763 		if (!blink) {
764 			scp->status |= VR_CURSOR_ON;
765 			draw_pxlcursor_direct(scp, at, on, flip);
766 		} else if (++pxlblinkrate & 4) {
767 			pxlblinkrate = 0;
768 			scp->status ^= VR_CURSOR_ON;
769 			draw_pxlcursor_direct(scp, at,
770 					      scp->status & VR_CURSOR_ON,
771 					      flip);
772 		}
773 	} else {
774 		if (scp->status & VR_CURSOR_ON)
775 			draw_pxlcursor_direct(scp, at, on, flip);
776 		scp->status &= ~VR_CURSOR_ON;
777 	}
778 	if (blink)
779 		scp->status |= VR_CURSOR_BLINK;
780 	else
781 		scp->status &= ~VR_CURSOR_BLINK;
782 }
783 
784 static void
785 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip)
786 {
787 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
788 		return;
789 
790 	if (on) {
791 		if (!blink) {
792 			scp->status |= VR_CURSOR_ON;
793 			draw_pxlcursor_planar(scp, at, on, flip);
794 		} else if (++pxlblinkrate & 4) {
795 			pxlblinkrate = 0;
796 			scp->status ^= VR_CURSOR_ON;
797 			draw_pxlcursor_planar(scp, at,
798 					      scp->status & VR_CURSOR_ON,
799 					      flip);
800 		}
801 	} else {
802 		if (scp->status & VR_CURSOR_ON)
803 			draw_pxlcursor_planar(scp, at, on, flip);
804 		scp->status &= ~VR_CURSOR_ON;
805 	}
806 	if (blink)
807 		scp->status |= VR_CURSOR_BLINK;
808 	else
809 		scp->status &= ~VR_CURSOR_BLINK;
810 }
811 
812 static void
813 vga_pxlblink_direct(scr_stat *scp, int at, int flip)
814 {
815 	if (!(scp->status & VR_CURSOR_BLINK))
816 		return;
817 	if (!(++pxlblinkrate & 4))
818 		return;
819 	pxlblinkrate = 0;
820 	scp->status ^= VR_CURSOR_ON;
821 	draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip);
822 }
823 
824 static void
825 vga_pxlblink_planar(scr_stat *scp, int at, int flip)
826 {
827 	if (!(scp->status & VR_CURSOR_BLINK))
828 		return;
829 	if (!(++pxlblinkrate & 4))
830 		return;
831 	pxlblinkrate = 0;
832 	scp->status ^= VR_CURSOR_ON;
833 	draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip);
834 }
835 
836 #ifndef SC_NO_CUTPASTE
837 
838 static void
839 draw_pxlmouse_direct(scr_stat *scp, int x, int y)
840 {
841 	int line_width, pixel_size;
842 	int xend, yend;
843 	int i, j;
844 	vm_offset_t draw_pos;
845 
846 	line_width = scp->sc->adp->va_line_width;
847 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
848 
849 	xend = imin(x + 8, 8 * (scp->xoff + scp->xsize));
850 	yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
851 
852 	draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size;
853 
854 	for (i = 0; i < (yend - y); i++) {
855 		for (j = (xend - x - 1); j >= 0; j--) {
856 			switch (scp->sc->adp->va_info.vi_depth) {
857 			case 32:
858 				if (mouse_or_mask[i] & 1 << (15 - j))
859 					writel(draw_pos + 4 * j,
860 					    scp->ega_palette[15]);
861 				else if (mouse_and_mask[i] & 1 << (15 - j))
862 					writel(draw_pos + 4 * j,
863 					    scp->ega_palette[0]);
864 				break;
865 			case 16:
866 				/* FALLTHROUGH */
867 			case 15:
868 				if (mouse_or_mask[i] & 1 << (15 - j))
869 					writew(draw_pos + 2 * j,
870 					    scp->ega_palette[15]);
871 				else if (mouse_and_mask[i] & 1 << (15 - j))
872 					writew(draw_pos + 2 * j,
873 					    scp->ega_palette[0]);
874 				break;
875 			}
876 		}
877 
878 		draw_pos += line_width;
879 	}
880 }
881 
882 static void
883 draw_pxlmouse_planar(scr_stat *scp, int x, int y)
884 {
885 	vm_offset_t p;
886 	int line_width;
887 	int xoff;
888 	int ymax;
889 	u_short m;
890 	int i, j;
891 
892 	line_width = scp->sc->adp->va_line_width;
893 	xoff = (x - scp->xoff*8)%8;
894 	ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
895 
896 	outw(GDCIDX, 0x0805);		/* read mode 1, write mode 0 */
897 	outw(GDCIDX, 0x0001);		/* set/reset enable */
898 	outw(GDCIDX, 0x0002);		/* color compare */
899 	outw(GDCIDX, 0x0007);		/* color don't care */
900 	outw(GDCIDX, 0xff08);		/* bit mask */
901 	outw(GDCIDX, 0x0803);		/* data rotate/function select (and) */
902 	p = scp->sc->adp->va_window + line_width*y + x/8;
903 	if (x < 8 * (scp->xoff + scp->xsize) - 8) {
904 		for (i = y, j = 0; i < ymax; ++i, ++j) {
905 			m = ~(mouse_and_mask[j] >> xoff);
906 			*(u_char *)p &= m >> 8;
907 			*(u_char *)(p + 1) &= m;
908 			p += line_width;
909 		}
910 	} else {
911 		xoff += 8;
912 		for (i = y, j = 0; i < ymax; ++i, ++j) {
913 			m = ~(mouse_and_mask[j] >> xoff);
914 			*(u_char *)p &= m;
915 			p += line_width;
916 		}
917 	}
918 	outw(GDCIDX, 0x1003);		/* data rotate/function select (or) */
919 	p = scp->sc->adp->va_window + line_width*y + x/8;
920 	if (x < 8 * (scp->xoff + scp->xsize) - 8) {
921 		for (i = y, j = 0; i < ymax; ++i, ++j) {
922 			m = mouse_or_mask[j] >> xoff;
923 			*(u_char *)p &= m >> 8;
924 			*(u_char *)(p + 1) &= m;
925 			p += line_width;
926 		}
927 	} else {
928 		for (i = y, j = 0; i < ymax; ++i, ++j) {
929 			m = mouse_or_mask[j] >> xoff;
930 			*(u_char *)p &= m;
931 			p += line_width;
932 		}
933 	}
934 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
935 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
936 }
937 
938 static void
939 remove_pxlmouse(scr_stat *scp, int x, int y)
940 {
941 	int col, row;
942 	int pos;
943 	int i;
944 
945 	/* erase the mouse cursor image */
946 	col = x/8 - scp->xoff;
947 	row = y/scp->font_size - scp->yoff;
948 	pos = row*scp->xsize + col;
949 	i = (col < scp->xsize - 1) ? 2 : 1;
950 	(*scp->rndr->draw)(scp, pos, i, FALSE);
951 	if (row < scp->ysize - 1)
952 		(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
953 }
954 
955 static void
956 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
957 {
958 	if (on)
959 		draw_pxlmouse_direct(scp, x, y);
960 	else
961 		remove_pxlmouse(scp, x, y);
962 }
963 
964 static void
965 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on)
966 {
967 	if (on)
968 		draw_pxlmouse_planar(scp, x, y);
969 	else
970 		remove_pxlmouse(scp, x, y);
971 }
972 
973 #endif /* SC_NO_CUTPASTE */
974 #endif /* SC_PIXEL_MODE */
975 
976 #ifndef SC_NO_MODE_CHANGE
977 
978 /* graphics mode renderer */
979 
980 static void
981 vga_grborder(scr_stat *scp, int color)
982 {
983 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
984 }
985 
986 #endif
987