xref: /freebsd/sys/dev/syscons/scgfbrndr.c (revision 2b944ee2b959e9b29fd72dcbf87aad8ad5537bc4)
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
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  * $FreeBSD$
27  */
28 
29 #include "sc.h"
30 #include "vga.h"
31 #include "opt_syscons.h"
32 #include "opt_vga.h"
33 
34 #if NSC > 0 && NVGA > 0
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/fb/fbreg.h>
43 #include <dev/fb/vgareg.h>
44 #include <dev/syscons/syscons.h>
45 
46 #include <isa/isareg.h>
47 
48 #ifndef SC_RENDER_DEBUG
49 #define SC_RENDER_DEBUG		0
50 #endif
51 
52 static vr_clear_t		vga_txtclear;
53 static vr_draw_border_t		vga_txtborder;
54 static vr_draw_t		vga_txtdraw;
55 static vr_set_cursor_t		vga_txtcursor_shape;
56 static vr_draw_cursor_t		vga_txtcursor;
57 static vr_blink_cursor_t	vga_txtblink;
58 #ifndef SC_NO_CUTPASTE
59 static vr_draw_mouse_t		vga_txtmouse;
60 #else
61 #define vga_txtmouse		(vr_draw_mouse_t *)vga_nop
62 #endif
63 
64 #ifdef SC_PIXEL_MODE
65 static vr_clear_t		vga_pxlclear;
66 static vr_draw_border_t		vga_pxlborder;
67 static vr_draw_t		vga_egadraw;
68 static vr_draw_t		vga_vgadraw;
69 static vr_set_cursor_t		vga_pxlcursor_shape;
70 static vr_draw_cursor_t		vga_pxlcursor;
71 static vr_blink_cursor_t	vga_pxlblink;
72 #ifndef SC_NO_CUTPASTE
73 static vr_draw_mouse_t		vga_pxlmouse;
74 #else
75 #define vga_pxlmouse		(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 struct linker_set	vga_set;
86 
87 static sc_rndr_sw_t txtrndrsw = {
88 	vga_txtclear,
89 	vga_txtborder,
90 	vga_txtdraw,
91 	vga_txtcursor_shape,
92 	vga_txtcursor,
93 	vga_txtblink,
94 	(vr_set_mouse_t *)vga_nop,
95 	vga_txtmouse,
96 };
97 RENDERER(mda, 0, txtrndrsw, vga_set);
98 RENDERER(cga, 0, txtrndrsw, vga_set);
99 RENDERER(ega, 0, txtrndrsw, vga_set);
100 RENDERER(vga, 0, txtrndrsw, vga_set);
101 
102 #ifdef SC_PIXEL_MODE
103 static sc_rndr_sw_t egarndrsw = {
104 	vga_pxlclear,
105 	vga_pxlborder,
106 	vga_egadraw,
107 	vga_pxlcursor_shape,
108 	vga_pxlcursor,
109 	vga_pxlblink,
110 	(vr_set_mouse_t *)vga_nop,
111 	vga_pxlmouse,
112 };
113 RENDERER(ega, PIXEL_MODE, egarndrsw, vga_set);
114 
115 static sc_rndr_sw_t vgarndrsw = {
116 	vga_pxlclear,
117 	vga_pxlborder,
118 	vga_vgadraw,
119 	vga_pxlcursor_shape,
120 	vga_pxlcursor,
121 	vga_pxlblink,
122 	(vr_set_mouse_t *)vga_nop,
123 	vga_pxlmouse,
124 };
125 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
126 #endif /* SC_PIXEL_MODE */
127 
128 #ifndef SC_NO_MODE_CHANGE
129 static sc_rndr_sw_t grrndrsw = {
130 	(vr_clear_t *)vga_nop,
131 	vga_grborder,
132 	(vr_draw_t *)vga_nop,
133 	(vr_set_cursor_t *)vga_nop,
134 	(vr_draw_cursor_t *)vga_nop,
135 	(vr_blink_cursor_t *)vga_nop,
136 	(vr_set_mouse_t *)vga_nop,
137 	(vr_draw_mouse_t *)vga_nop,
138 };
139 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set);
140 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set);
141 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
142 #endif /* SC_NO_MODE_CHANGE */
143 
144 RENDERER_MODULE(vga, vga_set);
145 
146 #ifndef SC_NO_CUTPASTE
147 static u_short mouse_and_mask[16] = {
148 	0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
149 	0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
150 };
151 static u_short mouse_or_mask[16] = {
152 	0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
153 	0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
154 };
155 #endif
156 
157 static void
158 vga_nop(scr_stat *scp, ...)
159 {
160 }
161 
162 /* text mode renderer */
163 
164 static void
165 vga_txtclear(scr_stat *scp, int c, int attr)
166 {
167 	sc_vtb_clear(&scp->scr, c, attr);
168 }
169 
170 static void
171 vga_txtborder(scr_stat *scp, int color)
172 {
173 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
174 }
175 
176 static void
177 vga_txtdraw(scr_stat *scp, int from, int count, int flip)
178 {
179 	vm_offset_t p;
180 	int c;
181 	int a;
182 
183 	if (from + count > scp->xsize*scp->ysize)
184 		count = scp->xsize*scp->ysize - from;
185 
186 	if (flip) {
187 		for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) {
188 			c = sc_vtb_getc(&scp->vtb, from);
189 			a = sc_vtb_geta(&scp->vtb, from);
190 			a = (a & 0x8800) | ((a & 0x7000) >> 4)
191 				| ((a & 0x0700) << 4);
192 			p = sc_vtb_putchar(&scp->scr, p, c, a);
193 		}
194 	} else {
195 		sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
196 	}
197 }
198 
199 static void
200 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
201 {
202 	if (base < 0 || base >= scp->font_size)
203 		return;
204 	/* the caller may set height <= 0 in order to disable the cursor */
205 #if 0
206 	scp->cursor_base = base;
207 	scp->cursor_height = height;
208 #endif
209 	(*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
210 							base, height,
211 							scp->font_size, blink);
212 }
213 
214 static void
215 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
216 {
217 	video_adapter_t *adp;
218 	int cursor_attr;
219 
220 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
221 		return;
222 
223 	adp = scp->sc->adp;
224 	if (blink) {
225 		scp->status |= VR_CURSOR_BLINK;
226 		if (on) {
227 			scp->status |= VR_CURSOR_ON;
228 			(*vidsw[adp->va_index]->set_hw_cursor)(adp,
229 							       at%scp->xsize,
230 							       at/scp->xsize);
231 		} else {
232 			if (scp->status & VR_CURSOR_ON)
233 				(*vidsw[adp->va_index]->set_hw_cursor)(adp,
234 								       -1, -1);
235 			scp->status &= ~VR_CURSOR_ON;
236 		}
237 	} else {
238 		scp->status &= ~VR_CURSOR_BLINK;
239 		if (on) {
240 			scp->status |= VR_CURSOR_ON;
241 			cursor_attr = sc_vtb_geta(&scp->vtb, at);
242 			scp->cursor_saveunder_char = sc_vtb_getc(&scp->scr, at);
243 			scp->cursor_saveunder_attr = cursor_attr;
244 			if ((cursor_attr & 0x7000) == 0x7000) {
245 				cursor_attr &= 0x8f00;
246 				if ((cursor_attr & 0x0700) == 0)
247 					cursor_attr |= 0x0700;
248 			} else {
249 				cursor_attr |= 0x7000;
250 				if ((cursor_attr & 0x0700) == 0x0700)
251 					cursor_attr &= 0xf000;
252 			}
253 			if (flip)
254 				cursor_attr = (cursor_attr & 0x8800)
255 					| ((cursor_attr & 0x7000) >> 4)
256 					| ((cursor_attr & 0x0700) << 4);
257 			sc_vtb_putc(&scp->scr, at,
258 				    sc_vtb_getc(&scp->scr, at),
259 				    cursor_attr);
260 		} else {
261 			cursor_attr = scp->cursor_saveunder_attr;
262 			if (flip)
263 				cursor_attr = (cursor_attr & 0x8800)
264 					| ((cursor_attr & 0x7000) >> 4)
265 					| ((cursor_attr & 0x0700) << 4);
266 			if (scp->status & VR_CURSOR_ON)
267 				sc_vtb_putc(&scp->scr, at,
268 					    scp->cursor_saveunder_char,
269 					    cursor_attr);
270 			scp->status &= ~VR_CURSOR_ON;
271 		}
272 	}
273 }
274 
275 static void
276 vga_txtblink(scr_stat *scp, int at, int flip)
277 {
278 }
279 
280 #ifndef SC_NO_CUTPASTE
281 
282 static void
283 draw_txtmouse(scr_stat *scp, int x, int y)
284 {
285 #ifndef SC_ALT_MOUSE_IMAGE
286 	u_char font_buf[128];
287 	u_short cursor[32];
288 	u_char c;
289 	int pos;
290 	int xoffset, yoffset;
291 	int crtc_addr;
292 	int i;
293 
294 	/* prepare mousepointer char's bitmaps */
295 	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
296 	bcopy(scp->font + sc_vtb_getc(&scp->vtb, pos)*scp->font_size,
297 	      &font_buf[0], scp->font_size);
298 	bcopy(scp->font + sc_vtb_getc(&scp->vtb, pos + 1)*scp->font_size,
299 	      &font_buf[32], scp->font_size);
300 	bcopy(scp->font
301 		 + sc_vtb_getc(&scp->vtb, pos + scp->xsize)*scp->font_size,
302 	      &font_buf[64], scp->font_size);
303 	bcopy(scp->font
304 		 + sc_vtb_getc(&scp->vtb, pos + scp->xsize + 1)*scp->font_size,
305 	      &font_buf[96], scp->font_size);
306 	for (i = 0; i < scp->font_size; ++i) {
307 		cursor[i] = font_buf[i]<<8 | font_buf[i+32];
308 		cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
309 	}
310 
311 	/* now and-or in the mousepointer image */
312 	xoffset = x%8;
313 	yoffset = y%scp->font_size;
314 	for (i = 0; i < 16; ++i) {
315 		cursor[i + yoffset] =
316 	    		(cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset))
317 	    		| (mouse_or_mask[i] >> xoffset);
318 	}
319 	for (i = 0; i < scp->font_size; ++i) {
320 		font_buf[i] = (cursor[i] & 0xff00) >> 8;
321 		font_buf[i + 32] = cursor[i] & 0xff;
322 		font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
323 		font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
324 	}
325 
326 #if 1
327 	/* wait for vertical retrace to avoid jitter on some videocards */
328 	crtc_addr = scp->sc->adp->va_crtc_addr;
329 	while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ;
330 #endif
331 	c = scp->sc->mouse_char;
332 	(*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf,
333 					      c, 4);
334 
335 	sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
336 	/* FIXME: may be out of range! */
337 	sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
338 		    sc_vtb_geta(&scp->scr, pos + scp->xsize));
339 	if (x < (scp->xsize - 1)*8) {
340 		sc_vtb_putc(&scp->scr, pos + 1, c + 1,
341 			    sc_vtb_geta(&scp->scr, pos + 1));
342 		sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
343 			    sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
344 	}
345 #else /* SC_ALT_MOUSE_IMAGE */
346 	/* Red, magenta and brown are mapped to green to to keep it readable */
347 	static const int col_conv[16] = {
348 		6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
349 	};
350 	int pos;
351 	int color;
352 	int a;
353 
354 	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
355 	a = sc_vtb_geta(&scp->scr, pos);
356 	if (scp->sc->adp->va_flags & V_ADP_COLOR)
357 		color = (col_conv[(a & 0xf000) >> 12] << 12)
358 			| ((a & 0x0f00) | 0x0800);
359 	else
360 		color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
361 	sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
362 #endif /* SC_ALT_MOUSE_IMAGE */
363 }
364 
365 static void
366 remove_txtmouse(scr_stat *scp, int x, int y)
367 {
368 }
369 
370 static void
371 vga_txtmouse(scr_stat *scp, int x, int y, int on)
372 {
373 	if (on)
374 		draw_txtmouse(scp, x, y);
375 	else
376 		remove_txtmouse(scp, x, y);
377 }
378 
379 #endif /* SC_NO_CUTPASTE */
380 
381 #ifdef SC_PIXEL_MODE
382 
383 /* pixel (raster text) mode renderer */
384 
385 static void
386 vga_pxlclear(scr_stat *scp, int c, int attr)
387 {
388 	vm_offset_t p;
389 	int line_width;
390 	int lines;
391 	int i;
392 
393 	/* XXX: we are just filling the screen with the background color... */
394 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
395 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
396 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
397 	outw(GDCIDX, 0xff08);		/* bit mask */
398 	outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */
399 	line_width = scp->sc->adp->va_line_width;
400 	lines = scp->ysize*scp->font_size;
401 	p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size
402 		+ scp->xoff;
403 	for (i = 0; i < lines; ++i) {
404 		bzero_io((void *)p, scp->xsize);
405 		p += line_width;
406 	}
407 	outw(GDCIDX, 0x0000);		/* set/reset */
408 	outw(GDCIDX, 0x0001);		/* set/reset enable */
409 }
410 
411 static void
412 vga_pxlborder(scr_stat *scp, int color)
413 {
414 	vm_offset_t p;
415 	int line_width;
416 	int i;
417 
418 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
419 
420 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
421 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
422 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
423 	outw(GDCIDX, 0xff08);		/* bit mask */
424 	outw(GDCIDX, (color << 8) | 0x00);	/* set/reset */
425 	line_width = scp->sc->adp->va_line_width;
426 	p = scp->sc->adp->va_window;
427 	if (scp->yoff > 0) {
428 		bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
429 		bzero_io((void *)(p + line_width*(scp->yoff + scp->ysize)
430 					  *scp->font_size),
431 			 line_width*(scp->ypixel
432 				     - (scp->yoff + scp->ysize)*scp->font_size));
433 	}
434 	if (scp->xoff > 0) {
435 		for (i = 0; i < scp->ysize*scp->font_size; ++i) {
436 			bzero_io((void *)(p + line_width
437 					          *(scp->yoff*scp->font_size + i)),
438 				 scp->xoff);
439 			bzero_io((void *)(p + line_width
440 						  *(scp->yoff*scp->font_size + i)
441 				     + scp->xoff + scp->xsize),
442 				 scp->xpixel/8 - scp->xoff - scp->xsize);
443 		}
444 	}
445 	outw(GDCIDX, 0x0000);		/* set/reset */
446 	outw(GDCIDX, 0x0001);		/* set/reset enable */
447 }
448 
449 static void
450 vga_egadraw(scr_stat *scp, int from, int count, int flip)
451 {
452 	vm_offset_t d;
453 	vm_offset_t e;
454 	u_char *f;
455 	u_short bg;
456 	u_short col1, col2;
457 	int line_width;
458 	int i, j;
459 	int a;
460 	u_char c;
461 
462 	line_width = scp->sc->adp->va_line_width;
463 	d = scp->sc->adp->va_window
464 		+ scp->xoff
465 		+ scp->yoff*scp->font_size*line_width
466 		+ (from%scp->xsize)
467 		+ scp->font_size*line_width*(from/scp->xsize);
468 
469 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
470 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
471 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
472 	bg = -1;
473 	if (from + count > scp->xsize*scp->ysize)
474 		count = scp->xsize*scp->ysize - from;
475 	for (i = from; count-- > 0; ++i) {
476 		a = sc_vtb_geta(&scp->vtb, i);
477 		if (flip) {
478 			col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
479 			col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
480 		} else {
481 			col1 = (a & 0x0f00);
482 			col2 = (a & 0xf000) >> 4;
483 		}
484 		/* set background color in EGA/VGA latch */
485 		if (bg != col2) {
486 			bg = col2;
487 			outw(GDCIDX, bg | 0x00);	/* set/reset */
488 			outw(GDCIDX, 0xff08);		/* bit mask */
489 			writeb(d, 0);
490 			c = readb(d);	/* set bg color in the latch */
491 		}
492 		/* foreground color */
493 		outw(GDCIDX, col1 | 0x00);		/* set/reset */
494 		e = d;
495 		f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
496 		for (j = 0; j < scp->font_size; ++j, ++f) {
497 			outw(GDCIDX, (*f << 8) | 0x08);	/* bit mask */
498 	        	writeb(e, 0);
499 			e += line_width;
500 		}
501 		++d;
502 		if ((i % scp->xsize) == scp->xsize - 1)
503 			d += scp->xoff*2
504 				 + (scp->font_size - 1)*line_width;
505 	}
506 	outw(GDCIDX, 0x0000);		/* set/reset */
507 	outw(GDCIDX, 0x0001);		/* set/reset enable */
508 	outw(GDCIDX, 0xff08);		/* bit mask */
509 }
510 
511 static void
512 vga_vgadraw(scr_stat *scp, int from, int count, int flip)
513 {
514 	vm_offset_t d;
515 	vm_offset_t e;
516 	u_char *f;
517 	u_short bg;
518 	u_short col1, col2;
519 	int line_width;
520 	int i, j;
521 	int a;
522 	u_char c;
523 
524 	line_width = scp->sc->adp->va_line_width;
525 	d = scp->sc->adp->va_window
526 		+ scp->xoff
527 		+ scp->yoff*scp->font_size*line_width
528 		+ (from%scp->xsize)
529 		+ scp->font_size*line_width*(from/scp->xsize);
530 
531 	outw(GDCIDX, 0x0305);		/* read mode 0, write mode 3 */
532 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
533 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
534 	outw(GDCIDX, 0xff08);		/* bit mask */
535 	bg = -1;
536 	if (from + count > scp->xsize*scp->ysize)
537 		count = scp->xsize*scp->ysize - from;
538 	for (i = from; count-- > 0; ++i) {
539 		a = sc_vtb_geta(&scp->vtb, i);
540 		if (flip) {
541 			col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
542 			col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
543 		} else {
544 			col1 = (a & 0x0f00);
545 			col2 = (a & 0xf000) >> 4;
546 		}
547 		/* set background color in EGA/VGA latch */
548 		if (bg != col2) {
549 			bg = col2;
550 			outw(GDCIDX, 0x0005);	/* read mode 0, write mode 0 */
551 			outw(GDCIDX, bg | 0x00); /* set/reset */
552 			writeb(d, 0);
553 			c = readb(d);		/* set bg color in the latch */
554 			outw(GDCIDX, 0x0305);	/* read mode 0, write mode 3 */
555 		}
556 		/* foreground color */
557 		outw(GDCIDX, col1 | 0x00);	/* set/reset */
558 		e = d;
559 		f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
560 		for (j = 0; j < scp->font_size; ++j, ++f) {
561 	        	writeb(e, *f);
562 			e += line_width;
563 		}
564 		++d;
565 		if ((i % scp->xsize) == scp->xsize - 1)
566 			d += scp->xoff*2
567 				 + (scp->font_size - 1)*line_width;
568 	}
569 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
570 	outw(GDCIDX, 0x0000);		/* set/reset */
571 	outw(GDCIDX, 0x0001);		/* set/reset enable */
572 }
573 
574 static void
575 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
576 {
577 	if (base < 0 || base >= scp->font_size)
578 		return;
579 	/* the caller may set height <= 0 in order to disable the cursor */
580 #if 0
581 	scp->cursor_base = base;
582 	scp->cursor_height = height;
583 #endif
584 }
585 
586 static void
587 draw_pxlcursor(scr_stat *scp, int at, int on, int flip)
588 {
589 	vm_offset_t d;
590 	u_char *f;
591 	int line_width;
592 	int height;
593 	int col;
594 	int a;
595 	int i;
596 	u_char c;
597 
598 	line_width = scp->sc->adp->va_line_width;
599 	d = scp->sc->adp->va_window
600 		+ scp->xoff
601 		+ scp->yoff*scp->font_size*line_width
602 		+ (at%scp->xsize)
603 		+ scp->font_size*line_width*(at/scp->xsize)
604 		+ (scp->font_size - scp->cursor_base - 1)*line_width;
605 
606 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
607 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
608 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
609 	/* set background color in EGA/VGA latch */
610 	a = sc_vtb_geta(&scp->vtb, at);
611 	if (flip)
612 		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
613 	else
614 		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
615 	outw(GDCIDX, col | 0x00);	/* set/reset */
616 	outw(GDCIDX, 0xff08);		/* bit mask */
617 	writeb(d, 0);
618 	c = readb(d);			/* set bg color in the latch */
619 	/* foreground color */
620 	if (flip)
621 		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
622 	else
623 		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
624 	outw(GDCIDX, col | 0x00);	/* set/reset */
625 	f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
626 		+ scp->font_size - scp->cursor_base - 1]);
627 	height = imin(scp->cursor_height, scp->font_size);
628 	for (i = 0; i < height; ++i, --f) {
629 		outw(GDCIDX, (*f << 8) | 0x08);	/* bit mask */
630 	       	writeb(d, 0);
631 		d -= line_width;
632 	}
633 	outw(GDCIDX, 0x0000);		/* set/reset */
634 	outw(GDCIDX, 0x0001);		/* set/reset enable */
635 	outw(GDCIDX, 0xff08);		/* bit mask */
636 }
637 
638 static void
639 vga_pxlcursor(scr_stat *scp, int at, int blink, int on, int flip)
640 {
641 	if (scp->cursor_height <= 0)	/* the text cursor is disabled */
642 		return;
643 
644 	if (on) {
645 		scp->status |= VR_CURSOR_ON;
646 		draw_pxlcursor(scp, at, on, flip);
647 	} else {
648 		if (scp->status & VR_CURSOR_ON)
649 			draw_pxlcursor(scp, at, on, flip);
650 		scp->status &= ~VR_CURSOR_ON;
651 	}
652 	if (blink)
653 		scp->status |= VR_CURSOR_BLINK;
654 	else
655 		scp->status &= ~VR_CURSOR_BLINK;
656 }
657 
658 static void
659 vga_pxlblink(scr_stat *scp, int at, int flip)
660 {
661 	static int blinkrate = 0;
662 
663 	if (!(scp->status & VR_CURSOR_BLINK))
664 		return;
665 	if (!(++blinkrate & 4))
666 		return;
667 	blinkrate = 0;
668 	scp->status ^= VR_CURSOR_ON;
669 	draw_pxlcursor(scp, at, scp->status & VR_CURSOR_ON, flip);
670 }
671 
672 #ifndef SC_NO_CUTPASTE
673 
674 static void
675 draw_pxlmouse(scr_stat *scp, int x, int y)
676 {
677 	vm_offset_t p;
678 	int line_width;
679 	int xoff, yoff;
680 	int ymax;
681 	u_short m;
682 	int i, j;
683 
684 	line_width = scp->sc->adp->va_line_width;
685 	xoff = (x - scp->xoff*8)%8;
686 	yoff = y - (y/line_width)*line_width;
687 	ymax = imin(y + 16, scp->ypixel);
688 
689 	outw(GDCIDX, 0x0805);		/* read mode 1, write mode 0 */
690 	outw(GDCIDX, 0x0001);		/* set/reset enable */
691 	outw(GDCIDX, 0x0002);		/* color compare */
692 	outw(GDCIDX, 0x0007);		/* color don't care */
693 	outw(GDCIDX, 0xff08);		/* bit mask */
694 	outw(GDCIDX, 0x0803);		/* data rotate/function select (and) */
695 	p = scp->sc->adp->va_window + line_width*y + x/8;
696 	if (x < scp->xpixel - 16) {
697 		for (i = y, j = 0; i < ymax; ++i, ++j) {
698 			m = ~(mouse_and_mask[j] >> xoff);
699 #ifdef __i386__
700 			*(u_char *)p &= m >> 8;
701 			*(u_char *)(p + 1) &= m;
702 #elif defined(__alpha__)
703 			writeb(p, readb(p) & (m >> 8));
704 			writeb(p + 1, readb(p + 1) & (m >> 8));
705 #endif
706 			p += line_width;
707 		}
708 	} else {
709 		xoff += 8;
710 		for (i = y, j = 0; i < ymax; ++i, ++j) {
711 			m = ~(mouse_and_mask[j] >> xoff);
712 #ifdef __i386__
713 			*(u_char *)p &= m;
714 #elif defined(__alpha__)
715 			writeb(p, readb(p) & (m >> 8));
716 #endif
717 			p += line_width;
718 		}
719 	}
720 	outw(GDCIDX, 0x1003);		/* data rotate/function select (or) */
721 	p = scp->sc->adp->va_window + line_width*y + x/8;
722 	if (x < scp->xpixel - 16) {
723 		for (i = y, j = 0; i < ymax; ++i, ++j) {
724 			m = mouse_or_mask[j] >> xoff;
725 #ifdef __i386__
726 			*(u_char *)p &= m >> 8;
727 			*(u_char *)(p + 1) &= m;
728 #elif defined(__alpha__)
729 			writeb(p, readb(p) & (m >> 8));
730 			writeb(p + 1, readb(p + 1) & (m >> 8));
731 #endif
732 			p += line_width;
733 		}
734 	} else {
735 		for (i = y, j = 0; i < ymax; ++i, ++j) {
736 			m = mouse_or_mask[j] >> xoff;
737 #ifdef __i386__
738 			*(u_char *)p &= m;
739 #elif defined(__alpha__)
740 			writeb(p, readb(p) & (m >> 8));
741 #endif
742 			p += line_width;
743 		}
744 	}
745 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
746 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
747 }
748 
749 static void
750 remove_pxlmouse(scr_stat *scp, int x, int y)
751 {
752 	vm_offset_t p;
753 	int col, row;
754 	int pos;
755 	int line_width;
756 	int ymax;
757 	int i;
758 
759 	/* erase the mouse cursor image */
760 	col = x/8 - scp->xoff;
761 	row = y/scp->font_size - scp->yoff;
762 	pos = row*scp->xsize + col;
763 	i = (col < scp->xsize - 1) ? 2 : 1;
764 	(*scp->rndr->draw)(scp, pos, i, FALSE);
765 	if (row < scp->ysize - 1)
766 		(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
767 
768 	/* paint border if necessary */
769 	line_width = scp->sc->adp->va_line_width;
770 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
771 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
772 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
773 	outw(GDCIDX, 0xff08);		/* bit mask */
774 	outw(GDCIDX, (scp->border << 8) | 0x00);	/* set/reset */
775 	if (row == scp->ysize - 1) {
776 		i = (scp->ysize + scp->yoff)*scp->font_size;
777 		ymax = imin(i + scp->font_size, scp->ypixel);
778 		p = scp->sc->adp->va_window + i*line_width + scp->xoff + col;
779 		if (col < scp->xsize - 1) {
780 			for (; i < ymax; ++i) {
781 				writeb(p, 0);
782 				writeb(p + 1, 0);
783 				p += line_width;
784 			}
785 		} else {
786 			for (; i < ymax; ++i) {
787 				writeb(p, 0);
788 				p += line_width;
789 			}
790 		}
791 	}
792 	if ((col == scp->xsize - 1) && (scp->xoff > 0)) {
793 		i = (row + scp->yoff)*scp->font_size;
794 		ymax = imin(i + scp->font_size*2, scp->ypixel);
795 		p = scp->sc->adp->va_window + i*line_width
796 			+ scp->xoff + scp->xsize;
797 		for (; i < ymax; ++i) {
798 			writeb(p, 0);
799 			p += line_width;
800 		}
801 	}
802 	outw(GDCIDX, 0x0000);		/* set/reset */
803 	outw(GDCIDX, 0x0001);		/* set/reset enable */
804 }
805 
806 static void
807 vga_pxlmouse(scr_stat *scp, int x, int y, int on)
808 {
809 	if (on)
810 		draw_pxlmouse(scp, x, y);
811 	else
812 		remove_pxlmouse(scp, x, y);
813 }
814 
815 #endif /* SC_NO_CUTPASTE */
816 #endif /* SC_PIXEL_MODE */
817 
818 #ifndef SC_NO_MODE_CHANGE
819 
820 /* graphics mode renderer */
821 
822 static void
823 vga_grborder(scr_stat *scp, int color)
824 {
825 	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
826 }
827 
828 #endif
829 
830 #endif /* NSC > 0 && NVGA > 0 */
831