scvgarndr.c revision 205605
160484Sobrien/*-
260484Sobrien * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
360484Sobrien * All rights reserved.
460484Sobrien *
560484Sobrien * This code is derived from software contributed to The DragonFly Project
660484Sobrien * by Sascha Wildner <saw@online.de>
760484Sobrien *
860484Sobrien * Redistribution and use in source and binary forms, with or without
960484Sobrien * modification, are permitted provided that the following conditions
1060484Sobrien * are met:
1160484Sobrien * 1. Redistributions of source code must retain the above copyright
1260484Sobrien *    notice, this list of conditions and the following disclaimer as
1360484Sobrien *    the first lines of this file unmodified.
1460484Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1560484Sobrien *    notice, this list of conditions and the following disclaimer in the
1660484Sobrien *    documentation and/or other materials provided with the distribution.
1760484Sobrien *
1860484Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1960484Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2060484Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2160484Sobrien * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2260484Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2360484Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2460484Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2560484Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2660484Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2760484Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2860484Sobrien *
2960484Sobrien */
3060484Sobrien
3160484Sobrien#include <sys/cdefs.h>
3260484Sobrien__FBSDID("$FreeBSD: head/sys/dev/syscons/scvgarndr.c 205605 2010-03-24 15:40:18Z jkim $");
3360484Sobrien
3460484Sobrien#include "opt_syscons.h"
3560484Sobrien#include "opt_vga.h"
3660484Sobrien
3760484Sobrien#include <sys/param.h>
3860484Sobrien#include <sys/systm.h>
3960484Sobrien#include <sys/kernel.h>
4060484Sobrien#include <sys/module.h>
4160484Sobrien#include <sys/fbio.h>
4260484Sobrien#include <sys/consio.h>
4360484Sobrien
4460484Sobrien#include <machine/bus.h>
4560484Sobrien
4660484Sobrien#include <dev/fb/fbreg.h>
4760484Sobrien#include <dev/fb/vgareg.h>
4860484Sobrien#include <dev/syscons/syscons.h>
4960484Sobrien
5060484Sobrien#include <isa/isareg.h>
5160484Sobrien
5260484Sobrien#ifndef SC_RENDER_DEBUG
5360484Sobrien#define SC_RENDER_DEBUG		0
5460484Sobrien#endif
5560484Sobrien
5660484Sobrienstatic vr_clear_t		vga_txtclear;
5760484Sobrienstatic vr_draw_border_t		vga_txtborder;
5860484Sobrienstatic vr_draw_t		vga_txtdraw;
5960484Sobrienstatic vr_set_cursor_t		vga_txtcursor_shape;
6060484Sobrienstatic vr_draw_cursor_t		vga_txtcursor;
6160484Sobrienstatic vr_blink_cursor_t	vga_txtblink;
6260484Sobrien#ifndef SC_NO_CUTPASTE
6360484Sobrienstatic vr_draw_mouse_t		vga_txtmouse;
6460484Sobrien#else
6560484Sobrien#define vga_txtmouse		(vr_draw_mouse_t *)vga_nop
6660484Sobrien#endif
6760484Sobrien
6860484Sobrien#ifdef SC_PIXEL_MODE
6960484Sobrienstatic vr_init_t		vga_rndrinit;
7060484Sobrienstatic vr_clear_t		vga_pxlclear_direct;
7160484Sobrienstatic vr_clear_t		vga_pxlclear_planar;
7260484Sobrienstatic vr_draw_border_t		vga_pxlborder_direct;
7360484Sobrienstatic vr_draw_border_t		vga_pxlborder_planar;
7460484Sobrienstatic vr_draw_t		vga_egadraw;
7560484Sobrienstatic vr_draw_t		vga_vgadraw_direct;
7660484Sobrienstatic vr_draw_t		vga_vgadraw_planar;
7760484Sobrienstatic vr_set_cursor_t		vga_pxlcursor_shape;
7860484Sobrienstatic vr_draw_cursor_t		vga_pxlcursor_direct;
7960484Sobrienstatic vr_draw_cursor_t		vga_pxlcursor_planar;
8060484Sobrienstatic vr_blink_cursor_t	vga_pxlblink_direct;
8160484Sobrienstatic vr_blink_cursor_t	vga_pxlblink_planar;
8260484Sobrien#ifndef SC_NO_CUTPASTE
8360484Sobrienstatic vr_draw_mouse_t		vga_pxlmouse_direct;
8460484Sobrienstatic vr_draw_mouse_t		vga_pxlmouse_planar;
8560484Sobrien#else
8660484Sobrien#define vga_pxlmouse_direct	(vr_draw_mouse_t *)vga_nop
8760484Sobrien#define vga_pxlmouse_planar	(vr_draw_mouse_t *)vga_nop
8860484Sobrien#endif
8960484Sobrien#endif /* SC_PIXEL_MODE */
9060484Sobrien
9160484Sobrien#ifndef SC_NO_MODE_CHANGE
9260484Sobrienstatic vr_draw_border_t		vga_grborder;
9360484Sobrien#endif
9460484Sobrien
9560484Sobrienstatic void			vga_nop(scr_stat *scp);
9660484Sobrien
9760484Sobrienstatic sc_rndr_sw_t txtrndrsw = {
9860484Sobrien	(vr_init_t *)vga_nop,
9960484Sobrien	vga_txtclear,
10060484Sobrien	vga_txtborder,
10160484Sobrien	vga_txtdraw,
10260484Sobrien	vga_txtcursor_shape,
10360484Sobrien	vga_txtcursor,
10460484Sobrien	vga_txtblink,
10560484Sobrien	(vr_set_mouse_t *)vga_nop,
10660484Sobrien	vga_txtmouse,
10760484Sobrien};
10860484SobrienRENDERER(mda, 0, txtrndrsw, vga_set);
10960484SobrienRENDERER(cga, 0, txtrndrsw, vga_set);
11060484SobrienRENDERER(ega, 0, txtrndrsw, vga_set);
11160484SobrienRENDERER(vga, 0, txtrndrsw, vga_set);
11260484Sobrien
11360484Sobrien#ifdef SC_PIXEL_MODE
11460484Sobrienstatic sc_rndr_sw_t egarndrsw = {
11560484Sobrien	(vr_init_t *)vga_nop,
11660484Sobrien	vga_pxlclear_planar,
11760484Sobrien	vga_pxlborder_planar,
11860484Sobrien	vga_egadraw,
11960484Sobrien	vga_pxlcursor_shape,
12060484Sobrien	vga_pxlcursor_planar,
12160484Sobrien	vga_pxlblink_planar,
12260484Sobrien	(vr_set_mouse_t *)vga_nop,
12360484Sobrien	vga_pxlmouse_planar,
12460484Sobrien};
12560484SobrienRENDERER(ega, PIXEL_MODE, egarndrsw, vga_set);
12677298Sobrien
12777298Sobrienstatic sc_rndr_sw_t vgarndrsw = {
12877298Sobrien	vga_rndrinit,
12977298Sobrien	(vr_clear_t *)vga_nop,
13077298Sobrien	(vr_draw_border_t *)vga_nop,
13177298Sobrien	(vr_draw_t *)vga_nop,
13277298Sobrien	vga_pxlcursor_shape,
13377298Sobrien	(vr_draw_cursor_t *)vga_nop,
13477298Sobrien	(vr_blink_cursor_t *)vga_nop,
13577298Sobrien	(vr_set_mouse_t *)vga_nop,
13677298Sobrien	(vr_draw_mouse_t *)vga_nop,
13777298Sobrien};
13877298SobrienRENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
13977298Sobrien#endif /* SC_PIXEL_MODE */
14077298Sobrien
14177298Sobrien#ifndef SC_NO_MODE_CHANGE
14277298Sobrienstatic sc_rndr_sw_t grrndrsw = {
14360484Sobrien	(vr_init_t *)vga_nop,
14477298Sobrien	(vr_clear_t *)vga_nop,
14560484Sobrien	vga_grborder,
14677298Sobrien	(vr_draw_t *)vga_nop,
14760484Sobrien	(vr_set_cursor_t *)vga_nop,
14860484Sobrien	(vr_draw_cursor_t *)vga_nop,
14960484Sobrien	(vr_blink_cursor_t *)vga_nop,
15060484Sobrien	(vr_set_mouse_t *)vga_nop,
15160484Sobrien	(vr_draw_mouse_t *)vga_nop,
15260484Sobrien};
15360484SobrienRENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set);
15460484SobrienRENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set);
15560484SobrienRENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
15660484Sobrien#endif /* SC_NO_MODE_CHANGE */
15760484Sobrien
15860484SobrienRENDERER_MODULE(vga, vga_set);
15960484Sobrien
16060484Sobrien#ifndef SC_NO_CUTPASTE
16160484Sobrien#if !defined(SC_ALT_MOUSE_IMAGE) || defined(SC_PIXEL_MODE)
16260484Sobrienstatic u_short mouse_and_mask[16] = {
16360484Sobrien	0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
16460484Sobrien	0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
16560484Sobrien};
16660484Sobrienstatic u_short mouse_or_mask[16] = {
16760484Sobrien	0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
16860484Sobrien	0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
16960484Sobrien};
17060484Sobrien#endif
17160484Sobrien#endif
17260484Sobrien
17360484Sobrien#ifdef SC_PIXEL_MODE
17460484Sobrien#define	VIDEO_MEMORY_POS(scp, pos, x) 					\
17560484Sobrien	scp->sc->adp->va_window +					\
17660484Sobrien	x * scp->xoff +							\
17760484Sobrien	scp->yoff * scp->font_size * scp->sc->adp->va_line_width +	\
17860484Sobrien	x * (pos % scp->xsize) +					\
17960484Sobrien	scp->font_size * scp->sc->adp->va_line_width * (pos / scp->xsize)
18060484Sobrien
18160484Sobrien#define	vga_drawpxl(pos, color)						\
18260484Sobrien	switch (scp->sc->adp->va_info.vi_depth) {			\
18360484Sobrien		case 32:						\
18460484Sobrien			writel(pos, vga_palette32[color]);		\
18560484Sobrien			break;						\
18660484Sobrien		case 24:						\
18760484Sobrien			if (((pos) & 1) == 0) {				\
18860484Sobrien				writew(pos, vga_palette32[color]);	\
18960484Sobrien				writeb(pos + 2, vga_palette32[color] >> 16);\
19060484Sobrien			} else {					\
19160484Sobrien				writeb(pos, vga_palette32[color]);	\
19260484Sobrien				writew(pos + 1, vga_palette32[color] >> 8);\
19360484Sobrien			}						\
19460484Sobrien			break;						\
19560484Sobrien		case 16:						\
19660484Sobrien			if (scp->sc->adp->va_info.vi_pixel_fsizes[1] == 5)\
19760484Sobrien				writew(pos, vga_palette15[color]);	\
19860484Sobrien			else						\
19960484Sobrien				writew(pos, vga_palette16[color]);	\
20060484Sobrien			break;						\
20160484Sobrien		case 15:						\
20260484Sobrien			writew(pos, vga_palette15[color]);		\
20360484Sobrien			break;						\
20460484Sobrien		case 8:							\
20560484Sobrien			writeb(pos, (uint8_t)color);			\
20660484Sobrien		}
20760484Sobrien
20860484Sobrienstatic uint32_t vga_palette32[16] = {
20960484Sobrien	0x000000, 0x0000ad, 0x00ad00, 0x00adad,
21060484Sobrien	0xad0000, 0xad00ad, 0xad5200, 0xadadad,
21160484Sobrien	0x525252, 0x5252ff, 0x52ff52, 0x52ffff,
21260484Sobrien	0xff5252, 0xff52ff, 0xffff52, 0xffffff
21360484Sobrien};
21460484Sobrien
21560484Sobrienstatic uint16_t vga_palette16[16] = {
21660484Sobrien	0x0000, 0x0016, 0x0560, 0x0576, 0xb000, 0xb016, 0xb2a0, 0xb576,
21760484Sobrien	0x52aa, 0x52bf, 0x57ea, 0x57ff, 0xfaaa, 0xfabf, 0xffea, 0xffff
21860484Sobrien};
21960484Sobrien
22060484Sobrienstatic uint16_t vga_palette15[16] = {
22160484Sobrien	0x0000, 0x0016, 0x02c0, 0x02d6, 0x5800, 0x5816, 0x5940, 0x5ad6,
22260484Sobrien	0x294a, 0x295f, 0x2bea, 0x2bff, 0x7d4a, 0x7d5f, 0x7fea, 0x7fff
22360484Sobrien};
22460484Sobrien
22560484Sobrien#ifndef SC_NO_CUTPASTE
22660484Sobrienstatic uint32_t mouse_buf32[256];
22760484Sobrienstatic uint16_t mouse_buf16[256];
22860484Sobrienstatic uint8_t  mouse_buf8[256];
22960484Sobrien#endif
23060484Sobrien#endif
23160484Sobrien
23260484Sobrienstatic void
23360484Sobrienvga_nop(scr_stat *scp)
23460484Sobrien{
23560484Sobrien}
23660484Sobrien
23760484Sobrien/* text mode renderer */
23860484Sobrien
23977298Sobrienstatic void
24060484Sobrienvga_txtclear(scr_stat *scp, int c, int attr)
24160484Sobrien{
24260484Sobrien	sc_vtb_clear(&scp->scr, c, attr);
24360484Sobrien}
24460484Sobrien
24560484Sobrienstatic void
24660484Sobrienvga_txtborder(scr_stat *scp, int color)
24760484Sobrien{
24860484Sobrien	vidd_set_border(scp->sc->adp, color);
24960484Sobrien}
25060484Sobrien
25160484Sobrienstatic void
25260484Sobrienvga_txtdraw(scr_stat *scp, int from, int count, int flip)
25360484Sobrien{
25460484Sobrien	vm_offset_t p;
25560484Sobrien	int c;
25660484Sobrien	int a;
25760484Sobrien
25860484Sobrien	if (from + count > scp->xsize*scp->ysize)
25960484Sobrien		count = scp->xsize*scp->ysize - from;
26060484Sobrien
26160484Sobrien	if (flip) {
26260484Sobrien		for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) {
26360484Sobrien			c = sc_vtb_getc(&scp->vtb, from);
26460484Sobrien			a = sc_vtb_geta(&scp->vtb, from);
26560484Sobrien			a = (a & 0x8800) | ((a & 0x7000) >> 4)
26660484Sobrien				| ((a & 0x0700) << 4);
26760484Sobrien			p = sc_vtb_putchar(&scp->scr, p, c, a);
26860484Sobrien		}
26960484Sobrien	} else {
27060484Sobrien		sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
27160484Sobrien	}
27277298Sobrien}
27360484Sobrien
27460484Sobrienstatic void
27560484Sobrienvga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
27660484Sobrien{
27760484Sobrien	if (base < 0 || base >= scp->font_size)
27860484Sobrien		return;
27960484Sobrien	/* the caller may set height <= 0 in order to disable the cursor */
28060484Sobrien#if 0
28160484Sobrien	scp->curs_attr.base = base;
28260484Sobrien	scp->curs_attr.height = height;
28360484Sobrien#endif
28460484Sobrien	vidd_set_hw_cursor_shape(scp->sc->adp, base, height,
28560484Sobrien	    scp->font_size, blink);
28660484Sobrien}
28760484Sobrien
28860484Sobrienstatic void
28960484Sobriendraw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
29060484Sobrien{
29160484Sobrien	sc_softc_t *sc;
29260484Sobrien
29360484Sobrien	sc = scp->sc;
29460484Sobrien	scp->cursor_saveunder_char = c;
29560484Sobrien	scp->cursor_saveunder_attr = a;
29660484Sobrien
29760484Sobrien#ifndef SC_NO_FONT_LOADING
29860484Sobrien	if (scp->curs_attr.flags & CONS_CHAR_CURSOR) {
29960484Sobrien		unsigned char *font;
30060484Sobrien		int h;
30160484Sobrien		int i;
30260484Sobrien
30360484Sobrien		if (scp->font_size < 14) {
30477298Sobrien			font = sc->font_8;
30560484Sobrien			h = 8;
30660484Sobrien		} else if (scp->font_size >= 16) {
30760484Sobrien			font = sc->font_16;
30860484Sobrien			h = 16;
30960484Sobrien		} else {
31060484Sobrien			font = sc->font_14;
31160484Sobrien			h = 14;
31260484Sobrien		}
31360484Sobrien		if (scp->curs_attr.base >= h)
31460484Sobrien			return;
31560484Sobrien		if (flip)
31660484Sobrien			a = (a & 0x8800)
31760484Sobrien				| ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
31860484Sobrien		bcopy(font + c*h, font + sc->cursor_char*h, h);
31977298Sobrien		font = font + sc->cursor_char*h;
32060484Sobrien		for (i = imax(h - scp->curs_attr.base - scp->curs_attr.height, 0);
32160484Sobrien			i < h - scp->curs_attr.base; ++i) {
32260484Sobrien			font[i] ^= 0xff;
32360484Sobrien		}
32460484Sobrien		/* XXX */
32560484Sobrien		vidd_load_font(sc->adp, 0, h, 8, font, sc->cursor_char, 1);
32660484Sobrien		sc_vtb_putc(&scp->scr, at, sc->cursor_char, a);
32760484Sobrien	} else
32860484Sobrien#endif /* SC_NO_FONT_LOADING */
32960484Sobrien	{
33060484Sobrien		if ((a & 0x7000) == 0x7000) {
33160484Sobrien			a &= 0x8f00;
33260484Sobrien			if ((a & 0x0700) == 0)
33360484Sobrien				a |= 0x0700;
33477298Sobrien		} else {
33560484Sobrien			a |= 0x7000;
33660484Sobrien			if ((a & 0x0700) == 0x0700)
33760484Sobrien				a &= 0xf000;
33860484Sobrien		}
33960484Sobrien		if (flip)
34060484Sobrien			a = (a & 0x8800)
34160484Sobrien				| ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
34260484Sobrien		sc_vtb_putc(&scp->scr, at, c, a);
34360484Sobrien	}
34460484Sobrien}
34560484Sobrien
34660484Sobrienstatic void
34760484Sobrienvga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
34860484Sobrien{
34960484Sobrien	video_adapter_t *adp;
35060484Sobrien	int cursor_attr;
35177298Sobrien
35260484Sobrien	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
35360484Sobrien		return;
35460484Sobrien
35560484Sobrien	adp = scp->sc->adp;
35660484Sobrien	if (blink) {
35760484Sobrien		scp->status |= VR_CURSOR_BLINK;
35860484Sobrien		if (on) {
35960484Sobrien			scp->status |= VR_CURSOR_ON;
36060484Sobrien			vidd_set_hw_cursor(adp, at%scp->xsize,
36160484Sobrien			    at/scp->xsize);
36260484Sobrien		} else {
36360484Sobrien			if (scp->status & VR_CURSOR_ON)
36460484Sobrien				vidd_set_hw_cursor(adp, -1, -1);
36560484Sobrien			scp->status &= ~VR_CURSOR_ON;
36660484Sobrien		}
36760484Sobrien	} else {
36860484Sobrien		scp->status &= ~VR_CURSOR_BLINK;
36960484Sobrien		if (on) {
37060484Sobrien			scp->status |= VR_CURSOR_ON;
37160484Sobrien			draw_txtcharcursor(scp, at,
37260484Sobrien					   sc_vtb_getc(&scp->scr, at),
37360484Sobrien					   sc_vtb_geta(&scp->scr, at),
37460484Sobrien					   flip);
37560484Sobrien		} else {
37660484Sobrien			cursor_attr = scp->cursor_saveunder_attr;
37760484Sobrien			if (flip)
37860484Sobrien				cursor_attr = (cursor_attr & 0x8800)
37960484Sobrien					| ((cursor_attr & 0x7000) >> 4)
38060484Sobrien					| ((cursor_attr & 0x0700) << 4);
38160484Sobrien			if (scp->status & VR_CURSOR_ON)
38260484Sobrien				sc_vtb_putc(&scp->scr, at,
38360484Sobrien					    scp->cursor_saveunder_char,
38460484Sobrien					    cursor_attr);
38560484Sobrien			scp->status &= ~VR_CURSOR_ON;
38660484Sobrien		}
38760484Sobrien	}
38860484Sobrien}
38960484Sobrien
39060484Sobrienstatic void
39160484Sobrienvga_txtblink(scr_stat *scp, int at, int flip)
39260484Sobrien{
39360484Sobrien}
39460484Sobrien
39560484Sobrien#ifndef SC_NO_CUTPASTE
39660484Sobrien
39760484Sobrienstatic void
39860484Sobriendraw_txtmouse(scr_stat *scp, int x, int y)
39960484Sobrien{
40060484Sobrien#ifndef SC_ALT_MOUSE_IMAGE
40160484Sobrien    if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) {
40260484Sobrien	u_char font_buf[128];
40360484Sobrien	u_short cursor[32];
40460484Sobrien	u_char c;
40560484Sobrien	int pos;
40660484Sobrien	int xoffset, yoffset;
40760484Sobrien	int crtc_addr;
40860484Sobrien	int i;
40960484Sobrien
41060484Sobrien	/* prepare mousepointer char's bitmaps */
41160484Sobrien	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
41260484Sobrien	bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
41360484Sobrien	      &font_buf[0], scp->font_size);
41460484Sobrien	bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
41560484Sobrien	      &font_buf[32], scp->font_size);
41660484Sobrien	bcopy(scp->font
41760484Sobrien		 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
41860484Sobrien	      &font_buf[64], scp->font_size);
41960484Sobrien	bcopy(scp->font
42060484Sobrien		 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
42160484Sobrien	      &font_buf[96], scp->font_size);
42260484Sobrien	for (i = 0; i < scp->font_size; ++i) {
42360484Sobrien		cursor[i] = font_buf[i]<<8 | font_buf[i+32];
42460484Sobrien		cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
42560484Sobrien	}
42660484Sobrien
42760484Sobrien	/* now and-or in the mousepointer image */
42860484Sobrien	xoffset = x%8;
42960484Sobrien	yoffset = y%scp->font_size;
43060484Sobrien	for (i = 0; i < 16; ++i) {
43160484Sobrien		cursor[i + yoffset] =
43260484Sobrien	    		(cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset))
43360484Sobrien	    		| (mouse_or_mask[i] >> xoffset);
43460484Sobrien	}
43560484Sobrien	for (i = 0; i < scp->font_size; ++i) {
43660484Sobrien		font_buf[i] = (cursor[i] & 0xff00) >> 8;
43760484Sobrien		font_buf[i + 32] = cursor[i] & 0xff;
43860484Sobrien		font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
43960484Sobrien		font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
44060484Sobrien	}
44160484Sobrien
44260484Sobrien#if 1
44360484Sobrien	/* wait for vertical retrace to avoid jitter on some videocards */
44460484Sobrien	crtc_addr = scp->sc->adp->va_crtc_addr;
44560484Sobrien	while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ;
44660484Sobrien#endif
44760484Sobrien	c = scp->sc->mouse_char;
44860484Sobrien	vidd_load_font(scp->sc->adp, 0, 32, 8, font_buf, c, 4);
44960484Sobrien
45060484Sobrien	sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
45160484Sobrien	/* FIXME: may be out of range! */
45260484Sobrien	sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
45360484Sobrien		    sc_vtb_geta(&scp->scr, pos + scp->xsize));
45460484Sobrien	if (x < (scp->xsize - 1)*8) {
45560484Sobrien		sc_vtb_putc(&scp->scr, pos + 1, c + 1,
45660484Sobrien			    sc_vtb_geta(&scp->scr, pos + 1));
45760484Sobrien		sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
45860484Sobrien			    sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
45960484Sobrien	}
46060484Sobrien    } else
46160484Sobrien#endif /* SC_ALT_MOUSE_IMAGE */
46260484Sobrien    {
46360484Sobrien	/* Red, magenta and brown are mapped to green to to keep it readable */
46460484Sobrien	static const int col_conv[16] = {
46560484Sobrien		6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
46660484Sobrien	};
46760484Sobrien	int pos;
46860484Sobrien	int color;
46960484Sobrien	int a;
47060484Sobrien
47160484Sobrien	pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
47260484Sobrien	a = sc_vtb_geta(&scp->scr, pos);
47360484Sobrien	if (scp->sc->adp->va_flags & V_ADP_COLOR)
47460484Sobrien		color = (col_conv[(a & 0xf000) >> 12] << 12)
47560484Sobrien			| ((a & 0x0f00) | 0x0800);
47660484Sobrien	else
47760484Sobrien		color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
47860484Sobrien	sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
47960484Sobrien    }
48060484Sobrien}
48160484Sobrien
48260484Sobrienstatic void
48360484Sobrienremove_txtmouse(scr_stat *scp, int x, int y)
48460484Sobrien{
48560484Sobrien}
48660484Sobrien
48760484Sobrienstatic void
48860484Sobrienvga_txtmouse(scr_stat *scp, int x, int y, int on)
48960484Sobrien{
49060484Sobrien	if (on)
49160484Sobrien		draw_txtmouse(scp, x, y);
49260484Sobrien	else
49360484Sobrien		remove_txtmouse(scp, x, y);
49460484Sobrien}
49560484Sobrien
49660484Sobrien#endif /* SC_NO_CUTPASTE */
49760484Sobrien
49860484Sobrien#ifdef SC_PIXEL_MODE
49960484Sobrien
50060484Sobrien/* pixel (raster text) mode renderer */
50160484Sobrien
50260484Sobrienstatic void
50360484Sobrienvga_rndrinit(scr_stat *scp)
50460484Sobrien{
50560484Sobrien	if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) {
50660484Sobrien		scp->rndr->clear = vga_pxlclear_planar;
50760484Sobrien		scp->rndr->draw_border = vga_pxlborder_planar;
50860484Sobrien		scp->rndr->draw = vga_vgadraw_planar;
50960484Sobrien		scp->rndr->draw_cursor = vga_pxlcursor_planar;
51060484Sobrien		scp->rndr->blink_cursor = vga_pxlblink_planar;
51160484Sobrien		scp->rndr->draw_mouse = vga_pxlmouse_planar;
51260484Sobrien	} else
51360484Sobrien	if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT ||
51460484Sobrien	    scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PACKED) {
51560484Sobrien		scp->rndr->clear = vga_pxlclear_direct;
51660484Sobrien		scp->rndr->draw_border = vga_pxlborder_direct;
51760484Sobrien		scp->rndr->draw = vga_vgadraw_direct;
51860484Sobrien		scp->rndr->draw_cursor = vga_pxlcursor_direct;
51960484Sobrien		scp->rndr->blink_cursor = vga_pxlblink_direct;
52060484Sobrien		scp->rndr->draw_mouse = vga_pxlmouse_direct;
52160484Sobrien	}
52260484Sobrien}
52360484Sobrien
52460484Sobrienstatic void
52560484Sobrienvga_pxlclear_direct(scr_stat *scp, int c, int attr)
52660484Sobrien{
52760484Sobrien	vm_offset_t p;
52860484Sobrien	int line_width;
52960484Sobrien	int pixel_size;
53060484Sobrien	int lines;
53160484Sobrien	int i;
53260484Sobrien
53360484Sobrien	line_width = scp->sc->adp->va_line_width;
53460484Sobrien	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
53560484Sobrien	lines = scp->ysize * scp->font_size;
53660484Sobrien	p = scp->sc->adp->va_window +
53760484Sobrien	    line_width * scp->yoff * scp->font_size +
53860484Sobrien	    scp->xoff * 8 * pixel_size;
53960484Sobrien
54060484Sobrien	for (i = 0; i < lines; ++i) {
54160484Sobrien		bzero_io((void *)p, scp->xsize * 8 * pixel_size);
54260484Sobrien		p += line_width;
54360484Sobrien	}
54460484Sobrien}
54560484Sobrien
54660484Sobrienstatic void
54760484Sobrienvga_pxlclear_planar(scr_stat *scp, int c, int attr)
54860484Sobrien{
54960484Sobrien	vm_offset_t p;
55060484Sobrien	int line_width;
55160484Sobrien	int lines;
55260484Sobrien	int i;
55360484Sobrien
55460484Sobrien	/* XXX: we are just filling the screen with the background color... */
55560484Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
55660484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
55760484Sobrien	outw(GDCIDX, 0x0f01);		/* set/reset enable */
55860484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
55960484Sobrien	outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */
56060484Sobrien	line_width = scp->sc->adp->va_line_width;
56160484Sobrien	lines = scp->ysize*scp->font_size;
56260484Sobrien	p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size
56360484Sobrien		+ scp->xoff;
56460484Sobrien	for (i = 0; i < lines; ++i) {
56560484Sobrien		bzero_io((void *)p, scp->xsize);
56660484Sobrien		p += line_width;
56760484Sobrien	}
56860484Sobrien	outw(GDCIDX, 0x0000);		/* set/reset */
56960484Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
57060484Sobrien}
57160484Sobrien
57260484Sobrienstatic void
57360484Sobrienvga_pxlborder_direct(scr_stat *scp, int color)
57460484Sobrien{
57560484Sobrien	vm_offset_t s;
57660484Sobrien	vm_offset_t e;
57760484Sobrien	vm_offset_t f;
57877298Sobrien	int line_width;
57960484Sobrien	int pixel_size;
58060484Sobrien	int x;
58160484Sobrien	int y;
58260484Sobrien	int i;
58360484Sobrien
58460484Sobrien	line_width = scp->sc->adp->va_line_width;
58560484Sobrien	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
58660484Sobrien
58760484Sobrien	if (scp->yoff > 0) {
58860484Sobrien		s = scp->sc->adp->va_window;
58960484Sobrien		e = s + line_width * scp->yoff * scp->font_size;
59060484Sobrien
59160484Sobrien		for (f = s; f < e; f += pixel_size)
59260484Sobrien			vga_drawpxl(f, color);
59360484Sobrien	}
59477298Sobrien
59560484Sobrien	y = (scp->yoff + scp->ysize) * scp->font_size;
59660484Sobrien
59760484Sobrien	if (scp->ypixel > y) {
59860484Sobrien		s = scp->sc->adp->va_window + line_width * y;
59960484Sobrien		e = s + line_width * (scp->ypixel - y);
60060484Sobrien
60160484Sobrien		for (f = s; f < e; f += pixel_size)
60260484Sobrien			vga_drawpxl(f, color);
60360484Sobrien	}
60460484Sobrien
60560484Sobrien	y = scp->yoff * scp->font_size;
60660484Sobrien	x = scp->xpixel / 8 - scp->xoff - scp->xsize;
60760484Sobrien
60860484Sobrien	for (i = 0; i < scp->ysize * scp->font_size; ++i) {
60960484Sobrien		if (scp->xoff > 0) {
61060484Sobrien			s = scp->sc->adp->va_window + line_width * (y + i);
61160484Sobrien			e = s + scp->xoff * 8 * pixel_size;
61260484Sobrien
61360484Sobrien			for (f = s; f < e; f += pixel_size)
61460484Sobrien				vga_drawpxl(f, color);
61560484Sobrien		}
61660484Sobrien
61760484Sobrien		if (x > 0) {
61860484Sobrien			s = scp->sc->adp->va_window + line_width * (y + i) +
61960484Sobrien			    scp->xoff * 8 * pixel_size +
62060484Sobrien			    scp->xsize * 8 * pixel_size;
62160484Sobrien			e = s + x * 8 * pixel_size;
62260484Sobrien
62360484Sobrien			for (f = s; f < e; f += pixel_size)
62460484Sobrien				vga_drawpxl(f, color);
62560484Sobrien		}
62660484Sobrien	}
62760484Sobrien}
62860484Sobrien
62960484Sobrienstatic void
63060484Sobrienvga_pxlborder_planar(scr_stat *scp, int color)
63160484Sobrien{
63260484Sobrien	vm_offset_t p;
63360484Sobrien	int line_width;
63460484Sobrien	int x;
63560484Sobrien	int y;
63660484Sobrien	int i;
63760484Sobrien
63860484Sobrien	vidd_set_border(scp->sc->adp, color);
63960484Sobrien
64060484Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
64160484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
64260484Sobrien	outw(GDCIDX, 0x0f01);		/* set/reset enable */
64360484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
64460484Sobrien	outw(GDCIDX, (color << 8) | 0x00);	/* set/reset */
64560484Sobrien	line_width = scp->sc->adp->va_line_width;
64660484Sobrien	p = scp->sc->adp->va_window;
64760484Sobrien	if (scp->yoff > 0)
64860484Sobrien		bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
64960484Sobrien	y = (scp->yoff + scp->ysize)*scp->font_size;
65060484Sobrien	if (scp->ypixel > y)
65160484Sobrien		bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
65260484Sobrien	y = scp->yoff*scp->font_size;
65360484Sobrien	x = scp->xpixel/8 - scp->xoff - scp->xsize;
65460484Sobrien	for (i = 0; i < scp->ysize*scp->font_size; ++i) {
65560484Sobrien		if (scp->xoff > 0)
65660484Sobrien			bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
65760484Sobrien		if (x > 0)
65860484Sobrien			bzero_io((void *)(p + line_width*(y + i)
65960484Sobrien				     + scp->xoff + scp->xsize), x);
66060484Sobrien	}
66160484Sobrien	outw(GDCIDX, 0x0000);		/* set/reset */
66260484Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
66360484Sobrien}
66460484Sobrien
66560484Sobrienstatic void
66660484Sobrienvga_egadraw(scr_stat *scp, int from, int count, int flip)
66760484Sobrien{
66860484Sobrien	vm_offset_t d;
66960484Sobrien	vm_offset_t e;
67060484Sobrien	u_char *f;
67160484Sobrien	u_short bg;
67260484Sobrien	u_short col1, col2;
67377298Sobrien	int line_width;
67460484Sobrien	int i, j;
67560484Sobrien	int a;
67660484Sobrien	u_char c;
67760484Sobrien
67860484Sobrien	line_width = scp->sc->adp->va_line_width;
67960484Sobrien
68060484Sobrien	d = VIDEO_MEMORY_POS(scp, from, 1);
68160484Sobrien
68260484Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
68360484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
68460484Sobrien	outw(GDCIDX, 0x0f01);		/* set/reset enable */
68560484Sobrien	bg = -1;
68660484Sobrien	if (from + count > scp->xsize*scp->ysize)
68760484Sobrien		count = scp->xsize*scp->ysize - from;
68877298Sobrien	for (i = from; count-- > 0; ++i) {
68960484Sobrien		a = sc_vtb_geta(&scp->vtb, i);
69060484Sobrien		if (flip) {
69160484Sobrien			col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
69260484Sobrien			col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
69360484Sobrien		} else {
69460484Sobrien			col1 = (a & 0x0f00);
69560484Sobrien			col2 = (a & 0xf000) >> 4;
69660484Sobrien		}
69760484Sobrien		/* set background color in EGA/VGA latch */
69860484Sobrien		if (bg != col2) {
69960484Sobrien			bg = col2;
70060484Sobrien			outw(GDCIDX, bg | 0x00);	/* set/reset */
70160484Sobrien			outw(GDCIDX, 0xff08);		/* bit mask */
70260484Sobrien			writeb(d, 0);
70377298Sobrien			c = readb(d);	/* set bg color in the latch */
70460484Sobrien		}
70560484Sobrien		/* foreground color */
70660484Sobrien		outw(GDCIDX, col1 | 0x00);		/* set/reset */
70760484Sobrien		e = d;
70860484Sobrien		f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
70960484Sobrien		for (j = 0; j < scp->font_size; ++j, ++f) {
71060484Sobrien			outw(GDCIDX, (*f << 8) | 0x08);	/* bit mask */
71160484Sobrien	        	writeb(e, 0);
71260484Sobrien			e += line_width;
71360484Sobrien		}
71460484Sobrien		++d;
71560484Sobrien		if ((i % scp->xsize) == scp->xsize - 1)
71660484Sobrien			d += scp->xoff*2
71760484Sobrien				 + (scp->font_size - 1)*line_width;
71877298Sobrien	}
71960484Sobrien	outw(GDCIDX, 0x0000);		/* set/reset */
72060484Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
72160484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
72260484Sobrien}
72360484Sobrien
72460484Sobrienstatic void
72560484Sobrienvga_vgadraw_direct(scr_stat *scp, int from, int count, int flip)
72660484Sobrien{
72760484Sobrien	vm_offset_t d = 0;
72860484Sobrien	vm_offset_t e;
72960484Sobrien	u_char *f;
73060484Sobrien	u_short col1, col2, color;
73160484Sobrien	int line_width, pixel_size;
73260484Sobrien	int i, j, k;
73360484Sobrien	int a;
73460484Sobrien
73560484Sobrien	line_width = scp->sc->adp->va_line_width;
73660484Sobrien	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
73760484Sobrien
73860484Sobrien	d = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size);
73960484Sobrien
74060484Sobrien	if (from + count > scp->xsize * scp->ysize)
74160484Sobrien		count = scp->xsize * scp->ysize - from;
74260484Sobrien
74360484Sobrien	for (i = from; count-- > 0; ++i) {
74460484Sobrien		a = sc_vtb_geta(&scp->vtb, i);
74560484Sobrien
74660484Sobrien		if (flip) {
74760484Sobrien			col1 = (((a & 0x7000) >> 4) | (a & 0x0800)) >> 8;
74860484Sobrien			col2 = (((a & 0x8000) >> 4) | (a & 0x0700)) >> 8;
74960484Sobrien		} else {
75060484Sobrien			col1 = (a & 0x0f00) >> 8;
75160484Sobrien			col2 = (a & 0xf000) >> 12;
75260484Sobrien		}
75360484Sobrien
75460484Sobrien		e = d;
75560484Sobrien		f = &(scp->font[sc_vtb_getc(&scp->vtb, i) * scp->font_size]);
75660484Sobrien
75760484Sobrien		for (j = 0; j < scp->font_size; ++j, ++f) {
75860484Sobrien			for (k = 0; k < 8; ++k) {
75960484Sobrien				color = *f & (1 << (7 - k)) ? col1 : col2;
76060484Sobrien				vga_drawpxl(e + pixel_size * k, color);
76160484Sobrien			}
76260484Sobrien
76360484Sobrien			e += line_width;
76460484Sobrien		}
76560484Sobrien
76660484Sobrien		d += 8 * pixel_size;
76760484Sobrien
76860484Sobrien		if ((i % scp->xsize) == scp->xsize - 1)
76960484Sobrien			d += scp->xoff * 16 * pixel_size +
77060484Sobrien			     (scp->font_size - 1) * line_width;
77160484Sobrien	}
77260484Sobrien}
77360484Sobrien
77460484Sobrienstatic void
77560484Sobrienvga_vgadraw_planar(scr_stat *scp, int from, int count, int flip)
77660484Sobrien{
77760484Sobrien	vm_offset_t d;
77860484Sobrien	vm_offset_t e;
77960484Sobrien	u_char *f;
78060484Sobrien	u_short bg;
78160484Sobrien	u_short col1, col2;
78260484Sobrien	int line_width;
78360484Sobrien	int i, j;
78460484Sobrien	int a;
78560484Sobrien	u_char c;
78660484Sobrien
78760484Sobrien	d = VIDEO_MEMORY_POS(scp, from, 1);
78860484Sobrien
78960484Sobrien	line_width = scp->sc->adp->va_line_width;
79060484Sobrien
79160484Sobrien	outw(GDCIDX, 0x0305);		/* read mode 0, write mode 3 */
79260484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
79360484Sobrien	outw(GDCIDX, 0x0f01);		/* set/reset enable */
79460484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
79560484Sobrien	bg = -1;
79660484Sobrien	if (from + count > scp->xsize*scp->ysize)
79760484Sobrien		count = scp->xsize*scp->ysize - from;
79860484Sobrien	for (i = from; count-- > 0; ++i) {
79960484Sobrien		a = sc_vtb_geta(&scp->vtb, i);
80060484Sobrien		if (flip) {
80160484Sobrien			col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
80260484Sobrien			col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
80360484Sobrien		} else {
80460484Sobrien			col1 = (a & 0x0f00);
80560484Sobrien			col2 = (a & 0xf000) >> 4;
80660484Sobrien		}
80760484Sobrien		/* set background color in EGA/VGA latch */
80860484Sobrien		if (bg != col2) {
80960484Sobrien			bg = col2;
81060484Sobrien			outw(GDCIDX, 0x0005);	/* read mode 0, write mode 0 */
81160484Sobrien			outw(GDCIDX, bg | 0x00); /* set/reset */
81260484Sobrien			writeb(d, 0);
81360484Sobrien			c = readb(d);		/* set bg color in the latch */
81460484Sobrien			outw(GDCIDX, 0x0305);	/* read mode 0, write mode 3 */
81560484Sobrien		}
81660484Sobrien		/* foreground color */
81760484Sobrien		outw(GDCIDX, col1 | 0x00);	/* set/reset */
81860484Sobrien		e = d;
81960484Sobrien		f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
82060484Sobrien		for (j = 0; j < scp->font_size; ++j, ++f) {
82160484Sobrien	        	writeb(e, *f);
82260484Sobrien			e += line_width;
82360484Sobrien		}
82460484Sobrien		++d;
82560484Sobrien		if ((i % scp->xsize) == scp->xsize - 1)
82660484Sobrien			d += scp->xoff*2
82760484Sobrien				 + (scp->font_size - 1)*line_width;
82860484Sobrien	}
82960484Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
83060484Sobrien	outw(GDCIDX, 0x0000);		/* set/reset */
83160484Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
83260484Sobrien}
83360484Sobrien
83460484Sobrienstatic void
83560484Sobrienvga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
83660484Sobrien{
83760484Sobrien	if (base < 0 || base >= scp->font_size)
83860484Sobrien		return;
83960484Sobrien	/* the caller may set height <= 0 in order to disable the cursor */
84060484Sobrien#if 0
84160484Sobrien	scp->curs_attr.base = base;
84260484Sobrien	scp->curs_attr.height = height;
84360484Sobrien#endif
84460484Sobrien}
84560484Sobrien
84660484Sobrienstatic void
84760484Sobriendraw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
84860484Sobrien{
84960484Sobrien	vm_offset_t d = 0;
85060484Sobrien	u_char *f;
85160484Sobrien	int line_width, pixel_size;
85260484Sobrien	int height;
85360484Sobrien	int col1, col2, color;
85460484Sobrien	int a;
85560484Sobrien	int i, j;
85660484Sobrien
85760484Sobrien	line_width = scp->sc->adp->va_line_width;
85860484Sobrien	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
85960484Sobrien
86060484Sobrien	d = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) +
86160484Sobrien	    (scp->font_size - scp->curs_attr.base - 1) * line_width;
86260484Sobrien
86360484Sobrien	a = sc_vtb_geta(&scp->vtb, at);
86460484Sobrien
86560484Sobrien	if (flip) {
86660484Sobrien		col1 = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8;
86760484Sobrien		col2 = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8;
86860484Sobrien	} else {
86960484Sobrien		col1 = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8;
87060484Sobrien		col2 = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8;
87160484Sobrien	}
87260484Sobrien
87360484Sobrien	f = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
87460484Sobrien	      scp->font_size - scp->curs_attr.base - 1]);
87560484Sobrien
87660484Sobrien	height = imin(scp->curs_attr.height, scp->font_size);
87760484Sobrien
87860484Sobrien	for (i = 0; i < height; ++i, --f) {
87960484Sobrien		for (j = 0; j < 8; ++j) {
88060484Sobrien			color = *f & (1 << (7 - j)) ? col1 : col2;
88160484Sobrien			vga_drawpxl(d + pixel_size * j, color);
88260484Sobrien		}
88360484Sobrien
88460484Sobrien		d -= line_width;
88560484Sobrien	}
88660484Sobrien}
88760484Sobrien
88860484Sobrienstatic void
88960484Sobriendraw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
89060484Sobrien{
89160484Sobrien	vm_offset_t d;
89260484Sobrien	u_char *f;
89360484Sobrien	int line_width;
89460484Sobrien	int height;
89560484Sobrien	int col;
89660484Sobrien	int a;
89760484Sobrien	int i;
89860484Sobrien	u_char c;
89960484Sobrien
90060484Sobrien	line_width = scp->sc->adp->va_line_width;
90160484Sobrien
90260484Sobrien	d = VIDEO_MEMORY_POS(scp, at, 1) +
90360484Sobrien	    (scp->font_size - scp->curs_attr.base - 1) * line_width;
90460484Sobrien
90560484Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
90660484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
90760484Sobrien	outw(GDCIDX, 0x0f01);		/* set/reset enable */
90860484Sobrien	/* set background color in EGA/VGA latch */
90960484Sobrien	a = sc_vtb_geta(&scp->vtb, at);
91060484Sobrien	if (flip)
91160484Sobrien		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
91260484Sobrien	else
91360484Sobrien		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
91460484Sobrien	outw(GDCIDX, col | 0x00);	/* set/reset */
91560484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
91660484Sobrien	writeb(d, 0);
91760484Sobrien	c = readb(d);			/* set bg color in the latch */
91860484Sobrien	/* foreground color */
91960484Sobrien	if (flip)
92060484Sobrien		col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
92160484Sobrien	else
92260484Sobrien		col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
92360484Sobrien	outw(GDCIDX, col | 0x00);	/* set/reset */
92460484Sobrien	f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
92560484Sobrien		+ scp->font_size - scp->curs_attr.base - 1]);
92660484Sobrien	height = imin(scp->curs_attr.height, scp->font_size);
92760484Sobrien	for (i = 0; i < height; ++i, --f) {
92860484Sobrien		outw(GDCIDX, (*f << 8) | 0x08);	/* bit mask */
92960484Sobrien	       	writeb(d, 0);
93060484Sobrien		d -= line_width;
93160484Sobrien	}
93260484Sobrien	outw(GDCIDX, 0x0000);		/* set/reset */
93360484Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
93460484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
93560484Sobrien}
93660484Sobrien
93760484Sobrienstatic int pxlblinkrate = 0;
93860484Sobrien
93960484Sobrienstatic void
94060484Sobrienvga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip)
94160484Sobrien{
94260484Sobrien	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
94360484Sobrien		return;
94460484Sobrien
94560484Sobrien	if (on) {
94660484Sobrien		if (!blink) {
94760484Sobrien			scp->status |= VR_CURSOR_ON;
94860484Sobrien			draw_pxlcursor_direct(scp, at, on, flip);
94960484Sobrien		} else if (++pxlblinkrate & 4) {
95060484Sobrien			pxlblinkrate = 0;
95160484Sobrien			scp->status ^= VR_CURSOR_ON;
95260484Sobrien			draw_pxlcursor_direct(scp, at,
95360484Sobrien					      scp->status & VR_CURSOR_ON,
95460484Sobrien					      flip);
95560484Sobrien		}
95660484Sobrien	} else {
95760484Sobrien		if (scp->status & VR_CURSOR_ON)
95860484Sobrien			draw_pxlcursor_direct(scp, at, on, flip);
95960484Sobrien		scp->status &= ~VR_CURSOR_ON;
96077298Sobrien	}
96160484Sobrien	if (blink)
96260484Sobrien		scp->status |= VR_CURSOR_BLINK;
96360484Sobrien	else
96460484Sobrien		scp->status &= ~VR_CURSOR_BLINK;
96560484Sobrien}
96660484Sobrien
96760484Sobrienstatic void
96860484Sobrienvga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip)
96960484Sobrien{
97060484Sobrien	if (scp->curs_attr.height <= 0)	/* the text cursor is disabled */
97160484Sobrien		return;
97260484Sobrien
97360484Sobrien	if (on) {
97460484Sobrien		if (!blink) {
97577298Sobrien			scp->status |= VR_CURSOR_ON;
97660484Sobrien			draw_pxlcursor_planar(scp, at, on, flip);
97760484Sobrien		} else if (++pxlblinkrate & 4) {
97860484Sobrien			pxlblinkrate = 0;
97960484Sobrien			scp->status ^= VR_CURSOR_ON;
98060484Sobrien			draw_pxlcursor_planar(scp, at,
98160484Sobrien					      scp->status & VR_CURSOR_ON,
98260484Sobrien					      flip);
98360484Sobrien		}
98460484Sobrien	} else {
98560484Sobrien		if (scp->status & VR_CURSOR_ON)
98660484Sobrien			draw_pxlcursor_planar(scp, at, on, flip);
98760484Sobrien		scp->status &= ~VR_CURSOR_ON;
98860484Sobrien	}
98960484Sobrien	if (blink)
99060484Sobrien		scp->status |= VR_CURSOR_BLINK;
99177298Sobrien	else
99277298Sobrien		scp->status &= ~VR_CURSOR_BLINK;
99360484Sobrien}
99460484Sobrien
99560484Sobrienstatic void
99660484Sobrienvga_pxlblink_direct(scr_stat *scp, int at, int flip)
99777298Sobrien{
99860484Sobrien	if (!(scp->status & VR_CURSOR_BLINK))
99960484Sobrien		return;
100060484Sobrien	if (!(++pxlblinkrate & 4))
100160484Sobrien		return;
100260484Sobrien	pxlblinkrate = 0;
100377298Sobrien	scp->status ^= VR_CURSOR_ON;
100477298Sobrien	draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip);
100577298Sobrien}
100677298Sobrien
100760484Sobrienstatic void
100860484Sobrienvga_pxlblink_planar(scr_stat *scp, int at, int flip)
100960484Sobrien{
101060484Sobrien	if (!(scp->status & VR_CURSOR_BLINK))
101160484Sobrien		return;
101260484Sobrien	if (!(++pxlblinkrate & 4))
101360484Sobrien		return;
101460484Sobrien	pxlblinkrate = 0;
101560484Sobrien	scp->status ^= VR_CURSOR_ON;
101660484Sobrien	draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip);
101777298Sobrien}
101860484Sobrien
101960484Sobrien#ifndef SC_NO_CUTPASTE
102060484Sobrien
102160484Sobrienstatic void
102260484Sobriendraw_pxlmouse_planar(scr_stat *scp, int x, int y)
102360484Sobrien{
102460484Sobrien	vm_offset_t p;
102577298Sobrien	int line_width;
102660484Sobrien	int xoff, yoff;
102760484Sobrien	int ymax;
102860484Sobrien	u_short m;
102960484Sobrien	int i, j;
103060484Sobrien
103177298Sobrien	line_width = scp->sc->adp->va_line_width;
103260484Sobrien	xoff = (x - scp->xoff*8)%8;
103360484Sobrien	yoff = y - (y/line_width)*line_width;
103460484Sobrien	ymax = imin(y + 16, scp->ypixel);
103560484Sobrien
103660484Sobrien	outw(GDCIDX, 0x0805);		/* read mode 1, write mode 0 */
103760484Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
103860484Sobrien	outw(GDCIDX, 0x0002);		/* color compare */
103960484Sobrien	outw(GDCIDX, 0x0007);		/* color don't care */
104077298Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
104160484Sobrien	outw(GDCIDX, 0x0803);		/* data rotate/function select (and) */
104260484Sobrien	p = scp->sc->adp->va_window + line_width*y + x/8;
104360484Sobrien	if (x < scp->xpixel - 8) {
104460484Sobrien		for (i = y, j = 0; i < ymax; ++i, ++j) {
104577298Sobrien			m = ~(mouse_and_mask[j] >> xoff);
104660484Sobrien#if defined(__i386__) || defined(__amd64__)
104760484Sobrien			*(u_char *)p &= m >> 8;
104860484Sobrien			*(u_char *)(p + 1) &= m;
104960484Sobrien#else
105060484Sobrien			writeb(p, readb(p) & (m >> 8));
105177298Sobrien			writeb(p + 1, readb(p + 1) & (m >> 8));
105260484Sobrien#endif
105360484Sobrien			p += line_width;
105460484Sobrien		}
105560484Sobrien	} else {
105677298Sobrien		xoff += 8;
105760484Sobrien		for (i = y, j = 0; i < ymax; ++i, ++j) {
105860484Sobrien			m = ~(mouse_and_mask[j] >> xoff);
105960484Sobrien#if defined(__i386__) || defined(__amd64__)
106060484Sobrien			*(u_char *)p &= m;
106160484Sobrien#else
106277298Sobrien			writeb(p, readb(p) & (m >> 8));
106377298Sobrien#endif
106460484Sobrien			p += line_width;
106577298Sobrien		}
106660484Sobrien	}
106760484Sobrien	outw(GDCIDX, 0x1003);		/* data rotate/function select (or) */
106877298Sobrien	p = scp->sc->adp->va_window + line_width*y + x/8;
106960484Sobrien	if (x < scp->xpixel - 8) {
107060484Sobrien		for (i = y, j = 0; i < ymax; ++i, ++j) {
107177298Sobrien			m = mouse_or_mask[j] >> xoff;
107260484Sobrien#if defined(__i386__) || defined(__amd64__)
107377298Sobrien			*(u_char *)p &= m >> 8;
107460484Sobrien			*(u_char *)(p + 1) &= m;
107577298Sobrien#else
107660484Sobrien			writeb(p, readb(p) & (m >> 8));
107760484Sobrien			writeb(p + 1, readb(p + 1) & (m >> 8));
107860484Sobrien#endif
107960484Sobrien			p += line_width;
108060484Sobrien		}
108160484Sobrien	} else {
108260484Sobrien		for (i = y, j = 0; i < ymax; ++i, ++j) {
108377298Sobrien			m = mouse_or_mask[j] >> xoff;
108460484Sobrien#if defined(__i386__) || defined(__amd64__)
108560484Sobrien			*(u_char *)p &= m;
108660484Sobrien#else
108777298Sobrien			writeb(p, readb(p) & (m >> 8));
108860484Sobrien#endif
108977298Sobrien			p += line_width;
109060484Sobrien		}
109160484Sobrien	}
109277298Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
109360484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
109460484Sobrien}
109560484Sobrien
109660484Sobrienstatic void
109760484Sobrienremove_pxlmouse_planar(scr_stat *scp, int x, int y)
109877298Sobrien{
109977298Sobrien	vm_offset_t p;
110060484Sobrien	int col, row;
110177298Sobrien	int pos;
110260484Sobrien	int line_width;
110360484Sobrien	int ymax;
110460484Sobrien	int i;
110560484Sobrien
110660484Sobrien	/* erase the mouse cursor image */
110777298Sobrien	col = x/8 - scp->xoff;
110860484Sobrien	row = y/scp->font_size - scp->yoff;
110960484Sobrien	pos = row*scp->xsize + col;
111060484Sobrien	i = (col < scp->xsize - 1) ? 2 : 1;
111160484Sobrien	(*scp->rndr->draw)(scp, pos, i, FALSE);
111260484Sobrien	if (row < scp->ysize - 1)
111377298Sobrien		(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
111460484Sobrien
111560484Sobrien	/* paint border if necessary */
111660484Sobrien	line_width = scp->sc->adp->va_line_width;
111760484Sobrien	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
111860484Sobrien	outw(GDCIDX, 0x0003);		/* data rotate/function select */
111960484Sobrien	outw(GDCIDX, 0x0f01);		/* set/reset enable */
112060484Sobrien	outw(GDCIDX, 0xff08);		/* bit mask */
112177298Sobrien	outw(GDCIDX, (scp->border << 8) | 0x00);	/* set/reset */
112260484Sobrien	if (row == scp->ysize - 1) {
112360484Sobrien		i = (scp->ysize + scp->yoff)*scp->font_size;
112460484Sobrien		ymax = imin(i + scp->font_size, scp->ypixel);
112560484Sobrien		p = scp->sc->adp->va_window + i*line_width + scp->xoff + col;
112660484Sobrien		if (col < scp->xsize - 1) {
112760484Sobrien			for (; i < ymax; ++i) {
112860484Sobrien				writeb(p, 0);
112960484Sobrien				writeb(p + 1, 0);
113060484Sobrien				p += line_width;
113160484Sobrien			}
113260484Sobrien		} else {
113360484Sobrien			for (; i < ymax; ++i) {
113460484Sobrien				writeb(p, 0);
113560484Sobrien				p += line_width;
113660484Sobrien			}
113777298Sobrien		}
113860484Sobrien	}
113960484Sobrien	if ((col == scp->xsize - 1) && (scp->xoff > 0)) {
114060484Sobrien		i = (row + scp->yoff)*scp->font_size;
114160484Sobrien		ymax = imin(i + scp->font_size*2, scp->ypixel);
114260484Sobrien		p = scp->sc->adp->va_window + i*line_width
114360484Sobrien			+ scp->xoff + scp->xsize;
114460484Sobrien		for (; i < ymax; ++i) {
114560484Sobrien			writeb(p, 0);
114660484Sobrien			p += line_width;
114760484Sobrien		}
114860484Sobrien	}
114960484Sobrien	outw(GDCIDX, 0x0000);		/* set/reset */
115077298Sobrien	outw(GDCIDX, 0x0001);		/* set/reset enable */
115160484Sobrien}
115260484Sobrien
115360484Sobrienstatic void
115460484Sobrienvga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
115560484Sobrien{
115660484Sobrien	vm_offset_t p;
115760484Sobrien	int line_width, pixel_size;
115860484Sobrien	int xend, yend;
115960484Sobrien	static int x_old = 0, xend_old = 0;
116060484Sobrien	static int y_old = 0, yend_old = 0;
116160484Sobrien	int i, j;
116260484Sobrien	uint32_t *u32;
116360484Sobrien	uint16_t *u16;
116460484Sobrien	uint8_t  *u8;
116560484Sobrien	int bpp;
116660484Sobrien
116760484Sobrien	if (!on)
116860484Sobrien		return;
116960484Sobrien
117060484Sobrien	bpp = scp->sc->adp->va_info.vi_depth;
117177298Sobrien
117260484Sobrien	if ((bpp == 16) && (scp->sc->adp->va_info.vi_pixel_fsizes[1] == 5))
117360484Sobrien		bpp = 15;
117460484Sobrien
117560484Sobrien	line_width = scp->sc->adp->va_line_width;
117660484Sobrien	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
117760484Sobrien
117860484Sobrien	xend = imin(x + 16, scp->xpixel);
117960484Sobrien	yend = imin(y + 16, scp->ypixel);
118060484Sobrien
118160484Sobrien	p = scp->sc->adp->va_window + y_old * line_width + x_old * pixel_size;
118260484Sobrien
118360484Sobrien	for (i = 0; i < (yend_old - y_old); i++) {
118477298Sobrien		for (j = (xend_old - x_old - 1); j >= 0; j--) {
118560484Sobrien			switch (bpp) {
118660484Sobrien			case 32:
118760484Sobrien				u32 = (uint32_t*)(p + j * pixel_size);
118860484Sobrien				writel(u32, mouse_buf32[i * 16 + j]);
118960484Sobrien				break;
119060484Sobrien			case 16:
119160484Sobrien				/* FALLTHROUGH */
119260484Sobrien			case 15:
119360484Sobrien				u16 = (uint16_t*)(p + j * pixel_size);
119460484Sobrien				writew(u16, mouse_buf16[i * 16 + j]);
119560484Sobrien				break;
119660484Sobrien			case 8:
119760484Sobrien				u8 = (uint8_t*)(p + j * pixel_size);
119860484Sobrien				writeb(u8, mouse_buf8[i * 16 + j]);
119960484Sobrien				break;
120060484Sobrien			}
120160484Sobrien		}
120260484Sobrien
120360484Sobrien		p += line_width;
120460484Sobrien	}
120560484Sobrien
120660484Sobrien	p = scp->sc->adp->va_window + y * line_width + x * pixel_size;
120760484Sobrien
120860484Sobrien	for (i = 0; i < (yend - y); i++) {
120960484Sobrien		for (j = (xend - x - 1); j >= 0; j--) {
121060484Sobrien			switch (bpp) {
121160484Sobrien			case 32:
121260484Sobrien				u32 = (uint32_t*)(p + j * pixel_size);
121360484Sobrien				mouse_buf32[i * 16 + j] = *u32;
121460484Sobrien				if (mouse_or_mask[i] & (1 << (15 - j)))
121560484Sobrien					writel(u32, vga_palette32[15]);
121660484Sobrien				else if (mouse_and_mask[i] & (1 << (15 - j)))
121760484Sobrien					writel(u32, 0);
121860484Sobrien				break;
121960484Sobrien			case 16:
122060484Sobrien				u16 = (uint16_t*)(p + j * pixel_size);
122160484Sobrien				mouse_buf16[i * 16 + j] = *u16;
122260484Sobrien				if (mouse_or_mask[i] & (1 << (15 - j)))
122360484Sobrien					writew(u16, vga_palette16[15]);
122460484Sobrien				else if (mouse_and_mask[i] & (1 << (15 - j)))
122560484Sobrien					writew(u16, 0);
122660484Sobrien				break;
122760484Sobrien			case 15:
122860484Sobrien				u16 = (uint16_t*)(p  + j * pixel_size);
122960484Sobrien				mouse_buf16[i * 16 + j] = *u16;
123060484Sobrien				if (mouse_or_mask[i] & (1 << (15 - j)))
123160484Sobrien					writew(u16, vga_palette15[15]);
123260484Sobrien				else if (mouse_and_mask[i] & (1 << (15 - j)))
123360484Sobrien					writew(u16, 0);
123460484Sobrien				break;
123560484Sobrien			case 8:
123660484Sobrien				u8 = (uint8_t*)(p + j * pixel_size);
123760484Sobrien				mouse_buf8[i * 16 + j] = *u8;
123860484Sobrien				if (mouse_or_mask[i] & (1 << (15 - j)))
123960484Sobrien					writeb(u8, 15);
124060484Sobrien				else if (mouse_and_mask[i] & (1 << (15 - j)))
124160484Sobrien					writeb(u8, 0);
124260484Sobrien				break;
124360484Sobrien			}
124460484Sobrien		}
124560484Sobrien
124660484Sobrien		p += line_width;
124760484Sobrien	}
124860484Sobrien
124960484Sobrien	x_old = x;
125077298Sobrien	y_old = y;
125160484Sobrien	xend_old = xend;
125260484Sobrien	yend_old = yend;
125377298Sobrien}
125460484Sobrien
125560484Sobrienstatic void
125677298Sobrienvga_pxlmouse_planar(scr_stat *scp, int x, int y, int on)
125760484Sobrien{
125860484Sobrien	if (on)
125960484Sobrien		draw_pxlmouse_planar(scp, x, y);
126060484Sobrien	else
126160484Sobrien		remove_pxlmouse_planar(scp, x, y);
126260484Sobrien}
126360484Sobrien
126460484Sobrien#endif /* SC_NO_CUTPASTE */
126560484Sobrien#endif /* SC_PIXEL_MODE */
126660484Sobrien
126760484Sobrien#ifndef SC_NO_MODE_CHANGE
126860484Sobrien
126960484Sobrien/* graphics mode renderer */
127060484Sobrien
127160484Sobrienstatic void
127260484Sobrienvga_grborder(scr_stat *scp, int color)
127360484Sobrien{
127460484Sobrien	vidd_set_border(scp->sc->adp, color);
127560484Sobrien}
127660484Sobrien
127760484Sobrien#endif
127860484Sobrien