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