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