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