scgfbrndr.c revision 56043
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 56043 2000-01-15 15:25:43Z yokota $
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
52static vr_clear_t		vga_txtclear;
53static vr_draw_border_t		vga_txtborder;
54static vr_draw_t		vga_txtdraw;
55static vr_set_cursor_t		vga_txtcursor_shape;
56static vr_draw_cursor_t		vga_txtcursor;
57static vr_blink_cursor_t	vga_txtblink;
58#ifndef SC_NO_CUTPASTE
59static 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
65static vr_clear_t		vga_pxlclear;
66static vr_draw_border_t		vga_pxlborder;
67static vr_draw_t		vga_egadraw;
68static vr_draw_t		vga_vgadraw;
69static vr_set_cursor_t		vga_pxlcursor_shape;
70static vr_draw_cursor_t		vga_pxlcursor;
71static vr_blink_cursor_t	vga_pxlblink;
72#ifndef SC_NO_CUTPASTE
73static 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
80static vr_draw_border_t		vga_grborder;
81#endif
82
83static void			vga_nop(scr_stat *scp, ...);
84
85static struct linker_set	vga_set;
86
87static 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};
97RENDERER(mda, 0, txtrndrsw, vga_set);
98RENDERER(cga, 0, txtrndrsw, vga_set);
99RENDERER(ega, 0, txtrndrsw, vga_set);
100RENDERER(vga, 0, txtrndrsw, vga_set);
101
102#ifdef SC_PIXEL_MODE
103static 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};
113RENDERER(ega, PIXEL_MODE, egarndrsw, vga_set);
114
115static 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};
125RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
126#endif /* SC_PIXEL_MODE */
127
128#ifndef SC_NO_MODE_CHANGE
129static 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};
139RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set);
140RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set);
141RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
142#endif /* SC_NO_MODE_CHANGE */
143
144RENDERER_MODULE(vga, vga_set);
145
146#ifndef SC_NO_CUTPASTE
147static 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};
151static 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
157static void
158vga_nop(scr_stat *scp, ...)
159{
160}
161
162/* text mode renderer */
163
164static void
165vga_txtclear(scr_stat *scp, int c, int attr)
166{
167	sc_vtb_clear(&scp->scr, c, attr);
168}
169
170static void
171vga_txtborder(scr_stat *scp, int color)
172{
173	(*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
174}
175
176static void
177vga_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
199static void
200vga_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
214static void
215vga_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
275static void
276vga_txtblink(scr_stat *scp, int at, int flip)
277{
278}
279
280#ifndef SC_NO_CUTPASTE
281
282static void
283draw_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
365static void
366remove_txtmouse(scr_stat *scp, int x, int y)
367{
368}
369
370static void
371vga_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
385static void
386vga_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
411static void
412vga_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
449static void
450vga_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
511static void
512vga_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
574static void
575vga_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
586static void
587draw_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
638static void
639vga_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
658static void
659vga_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
674static void
675draw_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
749static void
750remove_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
806static void
807vga_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
822static void
823vga_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