xref: /dragonfly/sys/dev/misc/syscons/scvgarndr.c (revision 0ac6bf9d)
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.15 2006/02/19 09:16:26 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 crtc_addr;
314 	int i;
315 
316 	/* prepare mousepointer char's bitmaps */
317 	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
318 	bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
319 	      &font_buf[0], scp->font_size);
320 	bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
321 	      &font_buf[32], scp->font_size);
322 	bcopy(scp->font
323 		 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
324 	      &font_buf[64], scp->font_size);
325 	bcopy(scp->font
326 		 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
327 	      &font_buf[96], scp->font_size);
328 	for (i = 0; i < scp->font_size; ++i) {
329 		cursor[i] = font_buf[i]<<8 | font_buf[i+32];
330 		cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
331 	}
332 
333 	/* now and-or in the mousepointer image */
334 	xoffset = x%8;
335 	yoffset = y%scp->font_size;
336 	for (i = 0; i < 16; ++i) {
337 		cursor[i + yoffset] =
338 	    		(cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset))
339 	    		| (mouse_or_mask[i] >> xoffset);
340 	}
341 	for (i = 0; i < scp->font_size; ++i) {
342 		font_buf[i] = (cursor[i] & 0xff00) >> 8;
343 		font_buf[i + 32] = cursor[i] & 0xff;
344 		font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
345 		font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
346 	}
347 
348 #if 1
349 	/* wait for vertical retrace to avoid jitter on some videocards */
350 	crtc_addr = scp->sc->adp->va_crtc_addr;
351 	while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ;
352 #endif
353 	c = scp->sc->mouse_char;
354 	(*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf,
355 					      c, 4);
356 
357 	sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
358 	/* FIXME: may be out of range! */
359 	sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
360 		    sc_vtb_geta(&scp->scr, pos + scp->xsize));
361 	if (x < (scp->xsize - 1)*8) {
362 		sc_vtb_putc(&scp->scr, pos + 1, c + 1,
363 			    sc_vtb_geta(&scp->scr, pos + 1));
364 		sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
365 			    sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
366 	}
367     } else
368 #endif /* SC_ALT_MOUSE_IMAGE */
369     {
370 	/* Red, magenta and brown are mapped to green to to keep it readable */
371 	static const int col_conv[16] = {
372 		6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
373 	};
374 	int pos;
375 	int color;
376 	int a;
377 
378 	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
379 	a = sc_vtb_geta(&scp->scr, pos);
380 	if (scp->sc->adp->va_flags & V_ADP_COLOR)
381 		color = (col_conv[(a & 0xf000) >> 12] << 12)
382 			| ((a & 0x0f00) | 0x0800);
383 	else
384 		color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
385 	sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
386     }
387 }
388 
389 static void
390 remove_txtmouse(scr_stat *scp, int x, int y)
391 {
392 }
393 
394 static void
395 vga_txtmouse(scr_stat *scp, int x, int y, int on)
396 {
397 	if (on)
398 		draw_txtmouse(scp, x, y);
399 	else
400 		remove_txtmouse(scp, x, y);
401 }
402 
403 #endif /* SC_NO_CUTPASTE */
404 
405 #ifdef SC_PIXEL_MODE
406 
407 /* pixel (raster text) mode renderer */
408 
409 static void
410 vga_rndrinit(scr_stat *scp)
411 {
412 	if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) {
413 		scp->rndr->draw_border = vga_pxlborder_planar;
414 		scp->rndr->draw = vga_vgadraw_planar;
415 		scp->rndr->draw_cursor = vga_pxlcursor_planar;
416 		scp->rndr->blink_cursor = vga_pxlblink_planar;
417 		scp->rndr->draw_mouse = vga_pxlmouse_planar;
418 	} else if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT) {
419 		scp->rndr->draw_border = vga_pxlborder_direct;
420 		scp->rndr->draw = vga_vgadraw_direct;
421 		scp->rndr->draw_cursor = vga_pxlcursor_direct;
422 		scp->rndr->blink_cursor = vga_pxlblink_direct;
423 		scp->rndr->draw_mouse = vga_pxlmouse_direct;
424 	}
425 }
426 
427 static void
428 vga_pxlborder_direct(scr_stat *scp, int color)
429 {
430 	int i, x, y;
431 	int line_width, pixel_size;
432 	uint32_t u32 = 0;
433 	vm_offset_t draw_pos, draw_end, p;
434 
435 	line_width = scp->sc->adp->va_line_width;
436 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
437 
438 	for (i = 0; i < 4 / pixel_size; ++i)
439 		u32 += scp->ega_palette[color] << (i * 8 * pixel_size);
440 
441 	if (scp->yoff > 0) {
442 		draw_pos = scp->sc->adp->va_window;
443 		draw_end = draw_pos +
444 		    line_width * scp->yoff * scp->font_size;
445 
446 		for (p = draw_pos; p < draw_end; p += 4)
447 			writel(p, u32);
448 	}
449 
450 	y = (scp->yoff + scp->ysize) * scp->font_size;
451 
452 	if (scp->ypixel > y) {
453 		draw_pos = scp->sc->adp->va_window + line_width * y;
454 		draw_end = draw_pos + line_width * (scp->ypixel - y);
455 
456 		for (p = draw_pos; p < draw_end; p += 4)
457 			writel(p, u32);
458 	}
459 
460 	y = scp->yoff * scp->font_size;
461 	x = scp->xpixel / 8 - scp->xoff - scp->xsize;
462 
463 	for (i = 0; i < scp->ysize * scp->font_size; ++i) {
464 		if (scp->xoff > 0) {
465 			draw_pos = scp->sc->adp->va_window +
466 			    line_width * (y + i);
467 			draw_end = draw_pos + scp->xoff * 8 * pixel_size;
468 
469 			for (p = draw_pos; p < draw_end; p += 4)
470 				writel(p, u32);
471 		}
472 
473 		if (x > 0) {
474 			draw_pos = scp->sc->adp->va_window +
475 			    line_width * (y + i) +
476 			    scp->xoff * 8 * pixel_size +
477 			    scp->xsize * 8 * pixel_size;
478 			draw_end = draw_pos + x * 8 * pixel_size;
479 
480 			for (p = draw_pos; p < draw_end; p += 4)
481 				writel(p, u32);
482 		}
483 	}
484 }
485 
486 static void
487 vga_pxlborder_planar(scr_stat *scp, int color)
488 {
489 	vm_offset_t p;
490 	int line_width;
491 	int x;
492 	int y;
493 	int i;
494 
495 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
496 
497 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
498 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
499 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
500 	outw(GDCIDX, 0xff08);		/* bit mask */
501 	outw(GDCIDX, (color << 8) | 0x00);	/* set/reset */
502 	line_width = scp->sc->adp->va_line_width;
503 	p = scp->sc->adp->va_window;
504 	if (scp->yoff > 0)
505 		bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
506 	y = (scp->yoff + scp->ysize)*scp->font_size;
507 	if (scp->ypixel > y)
508 		bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
509 	y = scp->yoff*scp->font_size;
510 	x = scp->xpixel/8 - scp->xoff - scp->xsize;
511 	for (i = 0; i < scp->ysize*scp->font_size; ++i) {
512 		if (scp->xoff > 0)
513 			bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
514 		if (x > 0)
515 			bzero_io((void *)(p + line_width*(y + i)
516 				     + scp->xoff + scp->xsize), x);
517 	}
518 	outw(GDCIDX, 0x0000);		/* set/reset */
519 	outw(GDCIDX, 0x0001);		/* set/reset enable */
520 }
521 
522 static void
523 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip)
524 {
525 	int line_width, pixel_size;
526 	int a, i, j, k, l, pos;
527 	uint32_t fg, bg, u32;
528 	unsigned char *char_data;
529 	vm_offset_t draw_pos, p;
530 
531 	line_width = scp->sc->adp->va_line_width;
532 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
533 
534 	draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size);
535 
536 	if (from + count > scp->xsize * scp->ysize)
537 		count = scp->xsize * scp->ysize - from;
538 
539 	for (i = from; count-- > 0; ++i) {
540 		a = sc_vtb_geta(&scp->vtb, i);
541 
542 		if (flip) {
543 			fg = scp->ega_palette[(((a & 0x7000) >> 4) |
544 			    (a & 0x0800)) >> 8];
545 			bg = scp->ega_palette[(((a & 0x8000) >> 4) |
546 			    (a & 0x0700)) >> 8];
547 		} else {
548 			fg = scp->ega_palette[(a & 0x0f00) >> 8];
549 			bg = scp->ega_palette[(a & 0xf000) >> 12];
550 		}
551 
552 		p = draw_pos;
553 		char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) *
554 		    scp->font_size]);
555 
556 		for (j = 0; j < scp->font_size; ++j, ++char_data) {
557 			pos = 7;
558 
559 			for (k = 0; k < 2 * pixel_size; ++k) {
560 				u32 = 0;
561 
562 				for (l = 0; l < 4 / pixel_size; ++l) {
563 					u32 += (*char_data & (1 << pos--) ?
564 					    fg : bg) << (l * 8 * pixel_size);
565 				}
566 
567 				writel(p, u32);
568 				p += 4;
569 			}
570 
571 			p += line_width - 8 * pixel_size;
572 		}
573 
574 		draw_pos += 8 * pixel_size;
575 
576 		if ((i % scp->xsize) == scp->xsize - 1)
577 			draw_pos += scp->xoff * 16 * pixel_size +
578 			     (scp->font_size - 1) * line_width;
579 	}
580 }
581 
582 static void
583 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip)
584 {
585 	vm_offset_t d;
586 	vm_offset_t e;
587 	u_char *f;
588 	u_short bg;
589 	u_short col1, col2;
590 	int line_width;
591 	int i, j;
592 	int a;
593 	u_char c;
594 
595 	d = VIDEO_MEMORY_POS(scp, from, 1);
596 
597 	line_width = scp->sc->adp->va_line_width;
598 
599 	outw(GDCIDX, 0x0305);		/* read mode 0, write mode 3 */
600 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
601 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
602 	outw(GDCIDX, 0xff08);		/* bit mask */
603 	bg = -1;
604 	if (from + count > scp->xsize*scp->ysize)
605 		count = scp->xsize*scp->ysize - from;
606 	for (i = from; count-- > 0; ++i) {
607 		a = sc_vtb_geta(&scp->vtb, i);
608 		if (flip) {
609 			col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
610 			col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
611 		} else {
612 			col1 = (a & 0x0f00);
613 			col2 = (a & 0xf000) >> 4;
614 		}
615 		/* set background color in EGA/VGA latch */
616 		if (bg != col2) {
617 			bg = col2;
618 			outw(GDCIDX, 0x0005);	/* read mode 0, write mode 0 */
619 			outw(GDCIDX, bg | 0x00); /* set/reset */
620 			writeb(d, 0);
621 			c = readb(d);		/* set bg color in the latch */
622 			outw(GDCIDX, 0x0305);	/* read mode 0, write mode 3 */
623 		}
624 		/* foreground color */
625 		outw(GDCIDX, col1 | 0x00);	/* set/reset */
626 		e = d;
627 		f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
628 		for (j = 0; j < scp->font_size; ++j, ++f) {
629 	        	writeb(e, *f);
630 			e += line_width;
631 		}
632 		++d;
633 		if ((i % scp->xsize) == scp->xsize - 1)
634 			d += scp->xoff*2
635 				 + (scp->font_size - 1)*line_width;
636 	}
637 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
638 	outw(GDCIDX, 0x0000);		/* set/reset */
639 	outw(GDCIDX, 0x0001);		/* set/reset enable */
640 }
641 
642 static void
643 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
644 {
645 	if (base < 0 || base >= scp->font_size)
646 		return;
647 	/* the caller may set height <= 0 in order to disable the cursor */
648 #if 0
649 	scp->cursor_base = base;
650 	scp->cursor_height = height;
651 #endif
652 }
653 
654 static void
655 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
656 {
657 	int line_width, pixel_size, height;
658 	int a, i, j, k, pos;
659 	uint32_t fg, bg, u32;
660 	unsigned char *char_data;
661 	vm_offset_t draw_pos;
662 
663 	line_width = scp->sc->adp->va_line_width;
664 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
665 
666 	draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) +
667 	    (scp->font_size - scp->cursor_base - 1) * line_width;
668 
669 	a = sc_vtb_geta(&scp->vtb, at);
670 
671 	if (flip) {
672 		fg = scp->ega_palette[((on) ? (a & 0x0f00) :
673 		    ((a & 0xf000) >> 4)) >> 8];
674 		bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) :
675 		    (a & 0x0f00)) >> 8];
676 	} else {
677 		fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) :
678 		    (a & 0x0f00)) >> 8];
679 		bg = scp->ega_palette[((on) ? (a & 0x0f00) :
680 		    ((a & 0xf000) >> 4)) >> 8];
681 	}
682 
683 	char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
684 	    scp->font_size - scp->cursor_base - 1]);
685 
686 	height = imin(scp->cursor_height, scp->font_size);
687 
688 	for (i = 0; i < height; ++i, --char_data) {
689 		pos = 7;
690 
691 		for (j = 0; j < 2 * pixel_size; ++j) {
692 			u32 = 0;
693 
694 			for (k = 0; k < 4 / pixel_size; ++k) {
695 				u32 += (*char_data & (1 << pos--) ?
696 				    fg : bg) << (k * 8 * pixel_size);
697 			}
698 
699 			writel(draw_pos, u32);
700 			draw_pos += 4;
701 		}
702 
703 		draw_pos -= line_width + 8 * pixel_size;
704 	}
705 }
706 
707 static void
708 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
709 {
710 	vm_offset_t d;
711 	u_char *f;
712 	int line_width;
713 	int height;
714 	int col;
715 	int a;
716 	int i;
717 	u_char c;
718 
719 	line_width = scp->sc->adp->va_line_width;
720 
721 	d = VIDEO_MEMORY_POS(scp, at, 1) +
722 	    (scp->font_size - scp->cursor_base - 1) * line_width;
723 
724 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
725 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
726 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
727 	/* set background color in EGA/VGA latch */
728 	a = sc_vtb_geta(&scp->vtb, at);
729 	if (flip)
730 		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
731 	else
732 		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
733 	outw(GDCIDX, col | 0x00);	/* set/reset */
734 	outw(GDCIDX, 0xff08);		/* bit mask */
735 	writeb(d, 0);
736 	c = readb(d);			/* set bg color in the latch */
737 	/* foreground color */
738 	if (flip)
739 		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
740 	else
741 		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
742 	outw(GDCIDX, col | 0x00);	/* set/reset */
743 	f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
744 		+ scp->font_size - scp->cursor_base - 1]);
745 	height = imin(scp->cursor_height, scp->font_size);
746 	for (i = 0; i < height; ++i, --f) {
747 		outw(GDCIDX, (*f << 8) | 0x08);	/* bit mask */
748 	       	writeb(d, 0);
749 		d -= line_width;
750 	}
751 	outw(GDCIDX, 0x0000);		/* set/reset */
752 	outw(GDCIDX, 0x0001);		/* set/reset enable */
753 	outw(GDCIDX, 0xff08);		/* bit mask */
754 }
755 
756 static int pxlblinkrate = 0;
757 
758 static void
759 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip)
760 {
761 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
762 		return;
763 
764 	if (on) {
765 		if (!blink) {
766 			scp->status |= VR_CURSOR_ON;
767 			draw_pxlcursor_direct(scp, at, on, flip);
768 		} else if (++pxlblinkrate & 4) {
769 			pxlblinkrate = 0;
770 			scp->status ^= VR_CURSOR_ON;
771 			draw_pxlcursor_direct(scp, at,
772 					      scp->status & VR_CURSOR_ON,
773 					      flip);
774 		}
775 	} else {
776 		if (scp->status & VR_CURSOR_ON)
777 			draw_pxlcursor_direct(scp, at, on, flip);
778 		scp->status &= ~VR_CURSOR_ON;
779 	}
780 	if (blink)
781 		scp->status |= VR_CURSOR_BLINK;
782 	else
783 		scp->status &= ~VR_CURSOR_BLINK;
784 }
785 
786 static void
787 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip)
788 {
789 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
790 		return;
791 
792 	if (on) {
793 		if (!blink) {
794 			scp->status |= VR_CURSOR_ON;
795 			draw_pxlcursor_planar(scp, at, on, flip);
796 		} else if (++pxlblinkrate & 4) {
797 			pxlblinkrate = 0;
798 			scp->status ^= VR_CURSOR_ON;
799 			draw_pxlcursor_planar(scp, at,
800 					      scp->status & VR_CURSOR_ON,
801 					      flip);
802 		}
803 	} else {
804 		if (scp->status & VR_CURSOR_ON)
805 			draw_pxlcursor_planar(scp, at, on, flip);
806 		scp->status &= ~VR_CURSOR_ON;
807 	}
808 	if (blink)
809 		scp->status |= VR_CURSOR_BLINK;
810 	else
811 		scp->status &= ~VR_CURSOR_BLINK;
812 }
813 
814 static void
815 vga_pxlblink_direct(scr_stat *scp, int at, int flip)
816 {
817 	if (!(scp->status & VR_CURSOR_BLINK))
818 		return;
819 	if (!(++pxlblinkrate & 4))
820 		return;
821 	pxlblinkrate = 0;
822 	scp->status ^= VR_CURSOR_ON;
823 	draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip);
824 }
825 
826 static void
827 vga_pxlblink_planar(scr_stat *scp, int at, int flip)
828 {
829 	if (!(scp->status & VR_CURSOR_BLINK))
830 		return;
831 	if (!(++pxlblinkrate & 4))
832 		return;
833 	pxlblinkrate = 0;
834 	scp->status ^= VR_CURSOR_ON;
835 	draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip);
836 }
837 
838 #ifndef SC_NO_CUTPASTE
839 
840 static void
841 draw_pxlmouse_direct(scr_stat *scp, int x, int y)
842 {
843 	int line_width, pixel_size;
844 	int xend, yend;
845 	int i, j;
846 	vm_offset_t draw_pos;
847 
848 	line_width = scp->sc->adp->va_line_width;
849 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
850 
851 	xend = imin(x + 8, 8 * (scp->xoff + scp->xsize));
852 	yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
853 
854 	draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size;
855 
856 	for (i = 0; i < (yend - y); i++) {
857 		for (j = (xend - x - 1); j >= 0; j--) {
858 			switch (scp->sc->adp->va_info.vi_depth) {
859 			case 32:
860 				if (mouse_or_mask[i] & 1 << (15 - j))
861 					writel(draw_pos + 4 * j,
862 					    scp->ega_palette[15]);
863 				else if (mouse_and_mask[i] & 1 << (15 - j))
864 					writel(draw_pos + 4 * j,
865 					    scp->ega_palette[0]);
866 				break;
867 			case 16:
868 				/* FALLTHROUGH */
869 			case 15:
870 				if (mouse_or_mask[i] & 1 << (15 - j))
871 					writew(draw_pos + 2 * j,
872 					    scp->ega_palette[15]);
873 				else if (mouse_and_mask[i] & 1 << (15 - j))
874 					writew(draw_pos + 2 * j,
875 					    scp->ega_palette[0]);
876 				break;
877 			}
878 		}
879 
880 		draw_pos += line_width;
881 	}
882 }
883 
884 static void
885 draw_pxlmouse_planar(scr_stat *scp, int x, int y)
886 {
887 	vm_offset_t p;
888 	int line_width;
889 	int xoff, yoff;
890 	int ymax;
891 	u_short m;
892 	int i, j;
893 
894 	line_width = scp->sc->adp->va_line_width;
895 	xoff = (x - scp->xoff*8)%8;
896 	yoff = y - (y/line_width)*line_width;
897 	ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
898 
899 	outw(GDCIDX, 0x0805);		/* read mode 1, write mode 0 */
900 	outw(GDCIDX, 0x0001);		/* set/reset enable */
901 	outw(GDCIDX, 0x0002);		/* color compare */
902 	outw(GDCIDX, 0x0007);		/* color don't care */
903 	outw(GDCIDX, 0xff08);		/* bit mask */
904 	outw(GDCIDX, 0x0803);		/* data rotate/function select (and) */
905 	p = scp->sc->adp->va_window + line_width*y + x/8;
906 	if (x < 8 * (scp->xoff + scp->xsize) - 8) {
907 		for (i = y, j = 0; i < ymax; ++i, ++j) {
908 			m = ~(mouse_and_mask[j] >> xoff);
909 			*(u_char *)p &= m >> 8;
910 			*(u_char *)(p + 1) &= m;
911 			p += line_width;
912 		}
913 	} else {
914 		xoff += 8;
915 		for (i = y, j = 0; i < ymax; ++i, ++j) {
916 			m = ~(mouse_and_mask[j] >> xoff);
917 			*(u_char *)p &= m;
918 			p += line_width;
919 		}
920 	}
921 	outw(GDCIDX, 0x1003);		/* data rotate/function select (or) */
922 	p = scp->sc->adp->va_window + line_width*y + x/8;
923 	if (x < 8 * (scp->xoff + scp->xsize) - 8) {
924 		for (i = y, j = 0; i < ymax; ++i, ++j) {
925 			m = mouse_or_mask[j] >> xoff;
926 			*(u_char *)p &= m >> 8;
927 			*(u_char *)(p + 1) &= m;
928 			p += line_width;
929 		}
930 	} else {
931 		for (i = y, j = 0; i < ymax; ++i, ++j) {
932 			m = mouse_or_mask[j] >> xoff;
933 			*(u_char *)p &= m;
934 			p += line_width;
935 		}
936 	}
937 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
938 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
939 }
940 
941 static void
942 remove_pxlmouse(scr_stat *scp, int x, int y)
943 {
944 	int col, row;
945 	int pos;
946 	int i;
947 
948 	/* erase the mouse cursor image */
949 	col = x/8 - scp->xoff;
950 	row = y/scp->font_size - scp->yoff;
951 	pos = row*scp->xsize + col;
952 	i = (col < scp->xsize - 1) ? 2 : 1;
953 	(*scp->rndr->draw)(scp, pos, i, FALSE);
954 	if (row < scp->ysize - 1)
955 		(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
956 }
957 
958 static void
959 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
960 {
961 	if (on)
962 		draw_pxlmouse_direct(scp, x, y);
963 	else
964 		remove_pxlmouse(scp, x, y);
965 }
966 
967 static void
968 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on)
969 {
970 	if (on)
971 		draw_pxlmouse_planar(scp, x, y);
972 	else
973 		remove_pxlmouse(scp, x, y);
974 }
975 
976 #endif /* SC_NO_CUTPASTE */
977 #endif /* SC_PIXEL_MODE */
978 
979 #ifndef SC_NO_MODE_CHANGE
980 
981 /* graphics mode renderer */
982 
983 static void
984 vga_grborder(scr_stat *scp, int color)
985 {
986 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
987 }
988 
989 #endif
990