Home | History | Annotate | Line # | Download | only in ic
      1 /* $NetBSD: vga.c,v 1.120 2021/08/07 16:19:12 thorpej Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
      5  * All rights reserved.
      6  *
      7  * Author: Chris G. Demetriou
      8  *
      9  * Permission to use, copy, modify and distribute this software and
     10  * its documentation is hereby granted, provided that both the copyright
     11  * notice and this permission notice appear in all copies of the
     12  * software, derivative works or modified versions, and any portions
     13  * thereof, and that both notices appear in supporting documentation.
     14  *
     15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     17  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     18  *
     19  * Carnegie Mellon requests users of this software to return to
     20  *
     21  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     22  *  School of Computer Science
     23  *  Carnegie Mellon University
     24  *  Pittsburgh PA 15213-3890
     25  *
     26  * any improvements or extensions that they make and grant Carnegie the
     27  * rights to redistribute these changes.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: vga.c,v 1.120 2021/08/07 16:19:12 thorpej Exp $");
     32 
     33 #include "opt_vga.h"
     34 /* for WSCONS_SUPPORT_PCVTFONTS */
     35 #include "opt_wsdisplay_compat.h"
     36 /* for WSDISPLAY_CUSTOM_BORDER */
     37 #include "opt_wsdisplay_border.h"
     38 /* for WSDISPLAY_CUSTOM_OUTPUT */
     39 #include "opt_wsmsgattrs.h"
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/callout.h>
     44 #include <sys/kernel.h>
     45 #include <sys/device.h>
     46 #include <sys/malloc.h>
     47 #include <sys/queue.h>
     48 #include <sys/bus.h>
     49 
     50 #include <dev/ic/mc6845reg.h>
     51 #include <dev/ic/pcdisplayvar.h>
     52 #include <dev/ic/vgareg.h>
     53 #include <dev/ic/vgavar.h>
     54 
     55 #include <dev/wscons/wsdisplayvar.h>
     56 #include <dev/wscons/wsconsio.h>
     57 #include <dev/wscons/unicode.h>
     58 #include <dev/wsfont/wsfont.h>
     59 
     60 #include <dev/ic/pcdisplay.h>
     61 
     62 int vga_no_builtinfont = 0;
     63 
     64 static struct wsdisplay_font _vga_builtinfont = {
     65 	"builtin",			/* typeface name */
     66 	0,				/* firstchar */
     67 	256,				/* numbers */
     68 	WSDISPLAY_FONTENC_IBM,		/* encoding */
     69 	8,				/* width */
     70 	16,				/* height */
     71 	1,				/* stride */
     72 	WSDISPLAY_FONTORDER_L2R,	/* bit order */
     73 	0,				/* byte order */
     74 	NULL				/* data */
     75 };
     76 
     77 struct egavga_font {
     78 	struct wsdisplay_font *wsfont;
     79 	int cookie; /* wsfont handle, -1 invalid */
     80 	int slot; /* in adapter RAM */
     81 	int usecount;
     82 	TAILQ_ENTRY(egavga_font) next; /* LRU queue */
     83 };
     84 
     85 static struct egavga_font vga_builtinfont = {
     86 	.wsfont = &_vga_builtinfont,
     87 	.cookie = -1,
     88 	.slot = 0,
     89 };
     90 
     91 #ifdef VGA_CONSOLE_SCREENTYPE
     92 static struct egavga_font vga_consolefont;
     93 #endif
     94 
     95 struct vgascreen {
     96 	struct pcdisplayscreen pcs;
     97 
     98 	LIST_ENTRY(vgascreen) next;
     99 
    100 	struct vga_config *cfg;
    101 
    102 	/* videostate */
    103 	struct egavga_font *fontset1, *fontset2;
    104 	/* font data */
    105 
    106 	int mindispoffset, maxdispoffset;
    107 	int vga_rollover;
    108 	int visibleoffset;
    109 };
    110 
    111 static int vgaconsole, vga_console_type, vga_console_attached;
    112 static struct vgascreen vga_console_screen;
    113 static struct vga_config vga_console_vc;
    114 
    115 static struct egavga_font *egavga_getfont(struct vga_config *, struct vgascreen *,
    116 				   const char *, int);
    117 static void egavga_unreffont(struct vga_config *, struct egavga_font *);
    118 
    119 static int vga_selectfont(struct vga_config *, struct vgascreen *, const char *,
    120 				   const char *);
    121 static void vga_init_screen(struct vga_config *, struct vgascreen *,
    122 		     const struct wsscreen_descr *, int, long *);
    123 static void vga_init(struct vga_config *, bus_space_tag_t, bus_space_tag_t);
    124 static void vga_setfont(struct vga_config *, struct vgascreen *);
    125 
    126 static int vga_mapchar(void *, int, unsigned int *);
    127 static void vga_putchar(void *, int, int, u_int, long);
    128 static int vga_allocattr(void *, int, int, int, long *);
    129 static void vga_copyrows(void *, int, int, int);
    130 #ifdef WSDISPLAY_SCROLLSUPPORT
    131 static void vga_scroll (void *, void *, int);
    132 #endif
    133 
    134 const struct wsdisplay_emulops vga_emulops = {
    135 	pcdisplay_cursor,
    136 	vga_mapchar,
    137 	vga_putchar,
    138 	pcdisplay_copycols,
    139 	pcdisplay_erasecols,
    140 	vga_copyrows,
    141 	pcdisplay_eraserows,
    142 	vga_allocattr,
    143 #ifdef WSDISPLAY_CUSTOM_OUTPUT
    144 	pcdisplay_replaceattr,
    145 #else
    146 	NULL,
    147 #endif
    148 };
    149 
    150 /*
    151  * translate WS(=ANSI) color codes to standard pc ones
    152  */
    153 static const unsigned char fgansitopc[] = {
    154 #ifdef __alpha__
    155 	/*
    156 	 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
    157 	 * XXX We should probably not bother with this
    158 	 * XXX (reinitialize the palette registers).
    159 	 */
    160 	FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED,
    161 	FG_MAGENTA, FG_BROWN, FG_LIGHTGREY
    162 #else
    163 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
    164 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
    165 #endif
    166 }, bgansitopc[] = {
    167 #ifdef __alpha__
    168 	BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED,
    169 	BG_MAGENTA, BG_BROWN, BG_LIGHTGREY
    170 #else
    171 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
    172 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
    173 #endif
    174 };
    175 
    176 const struct wsscreen_descr vga_25lscreen = {
    177 	"80x25", 80, 25,
    178 	&vga_emulops,
    179 	8, 16,
    180 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
    181 	NULL,
    182 }, vga_25lscreen_mono = {
    183 	"80x25", 80, 25,
    184 	&vga_emulops,
    185 	8, 16,
    186 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
    187 	NULL,
    188 }, vga_25lscreen_bf = {
    189 	"80x25bf", 80, 25,
    190 	&vga_emulops,
    191 	8, 16,
    192 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
    193 	NULL,
    194 }, vga_40lscreen = {
    195 	"80x40", 80, 40,
    196 	&vga_emulops,
    197 	8, 10,
    198 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
    199 	NULL,
    200 }, vga_40lscreen_mono = {
    201 	"80x40", 80, 40,
    202 	&vga_emulops,
    203 	8, 10,
    204 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
    205 	NULL,
    206 }, vga_40lscreen_bf = {
    207 	"80x40bf", 80, 40,
    208 	&vga_emulops,
    209 	8, 10,
    210 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
    211 	NULL,
    212 }, vga_50lscreen = {
    213 	"80x50", 80, 50,
    214 	&vga_emulops,
    215 	8, 8,
    216 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
    217 	NULL,
    218 }, vga_50lscreen_mono = {
    219 	"80x50", 80, 50,
    220 	&vga_emulops,
    221 	8, 8,
    222 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
    223 	NULL,
    224 }, vga_50lscreen_bf = {
    225 	"80x50bf", 80, 50,
    226 	&vga_emulops,
    227 	8, 8,
    228 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
    229 	NULL,
    230 }, vga_24lscreen = {
    231 	"80x24", 80, 24,
    232 	&vga_emulops,
    233 	8, 16,
    234 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
    235 	NULL,
    236 }, vga_24lscreen_mono = {
    237 	"80x24", 80, 24,
    238 	&vga_emulops,
    239 	8, 16,
    240 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
    241 	NULL,
    242 }, vga_24lscreen_bf = {
    243 	"80x24bf", 80, 24,
    244 	&vga_emulops,
    245 	8, 16,
    246 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
    247 	NULL,
    248 };
    249 
    250 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT))
    251 
    252 const struct wsscreen_descr *_vga_scrlist[] = {
    253 	&vga_25lscreen,
    254 	&vga_25lscreen_bf,
    255 	&vga_40lscreen,
    256 	&vga_40lscreen_bf,
    257 	&vga_50lscreen,
    258 	&vga_50lscreen_bf,
    259 	&vga_24lscreen,
    260 	&vga_24lscreen_bf,
    261 	/* XXX other formats, graphics screen? */
    262 }, *_vga_scrlist_mono[] = {
    263 	&vga_25lscreen_mono,
    264 	&vga_40lscreen_mono,
    265 	&vga_50lscreen_mono,
    266 	&vga_24lscreen_mono,
    267 	/* XXX other formats, graphics screen? */
    268 };
    269 
    270 const struct wsscreen_list vga_screenlist = {
    271 	sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *),
    272 	_vga_scrlist
    273 }, vga_screenlist_mono = {
    274 	sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *),
    275 	_vga_scrlist_mono
    276 };
    277 
    278 static int	vga_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    279 static paddr_t	vga_mmap(void *, void *, off_t, int);
    280 static int	vga_alloc_screen(void *, const struct wsscreen_descr *,
    281 				 void **, int *, int *, long *);
    282 static void	vga_free_screen(void *, void *);
    283 static int	vga_show_screen(void *, void *, int,
    284 				void (*)(void *, int, int), void *);
    285 static int	vga_load_font(void *, void *, struct wsdisplay_font *);
    286 #ifdef WSDISPLAY_CUSTOM_BORDER
    287 static int	vga_getborder(struct vga_config *, u_int *);
    288 static int	vga_setborder(struct vga_config *, u_int);
    289 #endif /* WSDISPLAY_CUSTOM_BORDER */
    290 
    291 static void vga_doswitch(struct vga_config *);
    292 static void    vga_save_palette(struct vga_config *);
    293 static void    vga_restore_palette(struct vga_config *);
    294 
    295 
    296 const struct wsdisplay_accessops vga_accessops = {
    297 	vga_ioctl,
    298 	vga_mmap,
    299 	vga_alloc_screen,
    300 	vga_free_screen,
    301 	vga_show_screen,
    302 	vga_load_font,
    303 	NULL,
    304 #ifdef WSDISPLAY_SCROLLSUPPORT
    305 	vga_scroll,
    306 #else
    307 	NULL,
    308 #endif
    309 };
    310 
    311 /*
    312  * We want at least ASCII 32..127 be present in the
    313  * first font slot.
    314  */
    315 #define vga_valid_primary_font(f) \
    316 	(f->wsfont->encoding == WSDISPLAY_FONTENC_IBM || \
    317 	f->wsfont->encoding == WSDISPLAY_FONTENC_ISO || \
    318 	f->wsfont->encoding == WSDISPLAY_FONTENC_ISO2 || \
    319 	f->wsfont->encoding == WSDISPLAY_FONTENC_ISO7 || \
    320 	f->wsfont->encoding == WSDISPLAY_FONTENC_KOI8_R)
    321 
    322 static struct egavga_font *
    323 egavga_getfont(struct vga_config *vc, struct vgascreen *scr, const char *name,
    324 	       int primary)
    325 {
    326 	struct egavga_font *f;
    327 	int cookie;
    328 	struct wsdisplay_font *wf;
    329 
    330 	TAILQ_FOREACH(f, &vc->vc_fontlist, next) {
    331 		if (wsfont_matches(f->wsfont, name,
    332 		    8, scr->pcs.type->fontheight, 0, WSFONT_FIND_BITMAP) &&
    333 		    (!primary || vga_valid_primary_font(f))) {
    334 #ifdef VGAFONTDEBUG
    335 			if (scr != &vga_console_screen || vga_console_attached)
    336 				printf("vga_getfont: %s already present\n",
    337 				    name ? name : "<default>");
    338 #endif
    339 			goto found;
    340 		}
    341 	}
    342 
    343 	cookie = wsfont_find(name, 8, scr->pcs.type->fontheight, 0,
    344 	    WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP);
    345 	/* XXX obey "primary" */
    346 	if (cookie == -1) {
    347 #ifdef VGAFONTDEBUG
    348 		if (scr != &vga_console_screen || vga_console_attached)
    349 			printf("vga_getfont: %s not found\n",
    350 			    name ? name : "<default>");
    351 #endif
    352 		return (0);
    353 	}
    354 
    355 	if (wsfont_lock(cookie, &wf))
    356 		return (0);
    357 
    358 #ifdef VGA_CONSOLE_SCREENTYPE
    359 	if (scr == &vga_console_screen)
    360 		f = &vga_consolefont;
    361 	else
    362 #endif
    363 	f = malloc(sizeof(struct egavga_font), M_DEVBUF, M_WAITOK);
    364 	f->wsfont = wf;
    365 	f->cookie = cookie;
    366 	f->slot = -1; /* not yet loaded */
    367 	f->usecount = 0; /* incremented below */
    368 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
    369 
    370 found:
    371 	f->usecount++;
    372 #ifdef VGAFONTDEBUG
    373 	if (scr != &vga_console_screen || vga_console_attached)
    374 		printf("vga_getfont: usecount=%d\n", f->usecount);
    375 #endif
    376 	return (f);
    377 }
    378 
    379 static void
    380 egavga_unreffont(struct vga_config *vc, struct egavga_font *f)
    381 {
    382 
    383 	f->usecount--;
    384 #ifdef VGAFONTDEBUG
    385 	printf("vga_unreffont: usecount=%d\n", f->usecount);
    386 #endif
    387 	if (f->usecount == 0 && f->cookie != -1) {
    388 		TAILQ_REMOVE(&vc->vc_fontlist, f, next);
    389 		if (f->slot != -1) {
    390 			KASSERT(vc->vc_fonts[f->slot] == f);
    391 			vc->vc_fonts[f->slot] = 0;
    392 		}
    393 		wsfont_unlock(f->cookie);
    394 #ifdef VGA_CONSOLE_SCREENTYPE
    395 		if (f != &vga_consolefont)
    396 #endif
    397 		free(f, M_DEVBUF);
    398 	}
    399 }
    400 
    401 static int
    402 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1,
    403 	       const char *name2)
    404 {
    405 	const struct wsscreen_descr *type = scr->pcs.type;
    406 	struct egavga_font *f1, *f2;
    407 
    408 	f1 = egavga_getfont(vc, scr, name1, 1);
    409 	if (!f1)
    410 		return (ENXIO);
    411 
    412 	if (VGA_SCREEN_CANTWOFONTS(type) && name2) {
    413 		f2 = egavga_getfont(vc, scr, name2, 0);
    414 		if (!f2) {
    415 			egavga_unreffont(vc, f1);
    416 			return (ENXIO);
    417 		}
    418 	} else
    419 		f2 = 0;
    420 
    421 #ifdef VGAFONTDEBUG
    422 	if (scr != &vga_console_screen || vga_console_attached) {
    423 		printf("vga (%s): font1=%s (slot %d)", type->name,
    424 		    f1->wsfont->name, f1->slot);
    425 		if (f2)
    426 			printf(", font2=%s (slot %d)",
    427 			    f2->wsfont->name, f2->slot);
    428 		printf("\n");
    429 	}
    430 #endif
    431 	if (scr->fontset1)
    432 		egavga_unreffont(vc, scr->fontset1);
    433 	scr->fontset1 = f1;
    434 	if (scr->fontset2)
    435 		egavga_unreffont(vc, scr->fontset2);
    436 	scr->fontset2 = f2;
    437 	return (0);
    438 }
    439 
    440 static void
    441 vga_init_screen(struct vga_config *vc, struct vgascreen *scr,
    442 		const struct wsscreen_descr *type, int existing, long *attrp)
    443 {
    444 	int cpos;
    445 	int res __diagused;
    446 
    447 	scr->cfg = vc;
    448 	scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl;
    449 	scr->pcs.type = type;
    450 	scr->pcs.active = existing;
    451 	scr->mindispoffset = 0;
    452 	if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL)
    453 		scr->maxdispoffset = 0;
    454 	else
    455 		scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2;
    456 
    457 	if (existing) {
    458 		vc->active = scr;
    459 
    460 		cpos = vga_6845_read(&vc->hdl, cursorh) << 8;
    461 		cpos |= vga_6845_read(&vc->hdl, cursorl);
    462 
    463 		/* make sure we have a valid cursor position */
    464 		if (cpos < 0 || cpos >= type->nrows * type->ncols)
    465 			cpos = 0;
    466 
    467 		scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9;
    468 		scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1;
    469 
    470 		/* make sure we have a valid memory offset */
    471 		if (scr->pcs.dispoffset < scr->mindispoffset ||
    472 		    scr->pcs.dispoffset > scr->maxdispoffset)
    473 			scr->pcs.dispoffset = scr->mindispoffset;
    474 
    475 		if (type != vc->currenttype) {
    476 			vga_setscreentype(&vc->hdl, type);
    477 			vc->currenttype = type;
    478 		}
    479 	} else {
    480 		cpos = 0;
    481 		scr->pcs.dispoffset = scr->mindispoffset;
    482 	}
    483 
    484 	scr->pcs.visibleoffset = scr->pcs.dispoffset;
    485 	scr->vga_rollover = 0;
    486 
    487 	scr->pcs.cursorrow = cpos / type->ncols;
    488 	scr->pcs.cursorcol = cpos % type->ncols;
    489 	pcdisplay_cursor_init(&scr->pcs, existing);
    490 
    491 #ifdef __alpha__
    492 	if (!vc->hdl.vh_mono)
    493 		/*
    494 		 * DEC firmware uses a blue background.
    495 		 * XXX These should be specified as kernel options for
    496 		 * XXX alpha only, not hardcoded here (which is wrong
    497 		 * XXX anyway because the emulation layer will assume
    498 		 * XXX the default attribute is white on black).
    499 		 */
    500 		res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE,
    501 		    WSATTR_WSCOLORS, attrp);
    502 	else
    503 #endif
    504 	res = vga_allocattr(scr, 0, 0, 0, attrp);
    505 #ifdef DIAGNOSTIC
    506 	if (res)
    507 		panic("vga_init_screen: attribute botch");
    508 #endif
    509 
    510 	scr->pcs.mem = NULL;
    511 
    512 	scr->fontset1 = scr->fontset2 = 0;
    513 	if (vga_selectfont(vc, scr, 0, 0)) {
    514 		if (scr == &vga_console_screen)
    515 			panic("vga_init_screen: no font");
    516 		else
    517 			printf("vga_init_screen: no font\n");
    518 	}
    519 	if (existing)
    520 		vga_setfont(vc, scr);
    521 
    522 	vc->nscreens++;
    523 	LIST_INSERT_HEAD(&vc->screens, scr, next);
    524 }
    525 
    526 static void
    527 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt)
    528 {
    529 	struct vga_handle *vh = &vc->hdl;
    530 	uint8_t mor;
    531 	int i;
    532 
    533 	vh->vh_iot = iot;
    534 	vh->vh_memt = memt;
    535 
    536 	if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
    537 		panic("vga_init: couldn't map vga io");
    538 
    539 	/* read "misc output register" */
    540 	mor = vga_raw_read(vh, VGA_MISC_DATAR);
    541 	vh->vh_mono = !(mor & 1);
    542 
    543 	if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
    544 	    &vh->vh_ioh_6845))
    545 		panic("vga_init: couldn't map 6845 io");
    546 
    547 	if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000,
    548 	    BUS_SPACE_MAP_CACHEABLE, &vh->vh_allmemh))
    549 		panic("vga_init: couldn't map memory");
    550 
    551 	if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh,
    552 	    (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh))
    553 		panic("vga_init: mem subrange failed");
    554 
    555 	vc->nscreens = 0;
    556 	LIST_INIT(&vc->screens);
    557 	vc->active = NULL;
    558 	vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen;
    559 	callout_init(&vc->vc_switch_callout, 0);
    560 
    561 	wsfont_init();
    562 	if (vga_no_builtinfont) {
    563 		struct wsdisplay_font *wf;
    564 		int cookie;
    565 
    566 		cookie = wsfont_find(NULL, 8, 16, 0,
    567 		     WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP);
    568 		if (cookie == -1 || wsfont_lock(cookie, &wf))
    569 			panic("vga_init: can't load console font");
    570 		vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars,
    571 		    wf->fontheight, wf->data);
    572 		vga_builtinfont.wsfont = wf;
    573 		vga_builtinfont.cookie = cookie;
    574 		vga_builtinfont.slot = 0;
    575 	}
    576 	vc->vc_fonts[0] = &vga_builtinfont;
    577 	for (i = 1; i < 8; i++)
    578 		vc->vc_fonts[i] = 0;
    579 	TAILQ_INIT(&vc->vc_fontlist);
    580 	TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next);
    581 
    582 	vc->currentfontset1 = vc->currentfontset2 = 0;
    583 
    584 	if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc))
    585 		_vga_attr_write(vh, VGA_ATC_OVERSCAN,
    586 		                fgansitopc[WSDISPLAY_BORDER_COLOR]);
    587 	vga_save_palette(vc);
    588 }
    589 
    590 void
    591 vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot,
    592 		  bus_space_tag_t memt, int type, int quirks,
    593 		  const struct vga_funcs *vf)
    594 {
    595 	int console;
    596 	struct vga_config *vc;
    597 	struct wsemuldisplaydev_attach_args aa;
    598 
    599 	console = vga_is_console(iot, type);
    600 
    601 	if (console) {
    602 		vc = &vga_console_vc;
    603 		vga_console_attached = 1;
    604 	} else {
    605 		vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK);
    606 		vga_init(vc, iot, memt);
    607 	}
    608 
    609 	if (quirks & VGA_QUIRK_ONEFONT) {
    610 		vc->vc_nfontslots = 1;
    611 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL
    612 		/*
    613 		 * XXX maybe invalidate font in slot > 0, but this can
    614 		 * only be happen with VGA_CONSOLE_SCREENTYPE, and then
    615 		 * we require VGA_CONSOLE_ATI_BROKEN_FONTSEL anyway.
    616 		 */
    617 #endif
    618 	} else {
    619 		vc->vc_nfontslots = 8;
    620 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL
    621 		/*
    622 		 * XXX maybe validate builtin font shifted to slot 1 if
    623 		 * slot 0 got overwritten because of VGA_CONSOLE_SCREENTYPE,
    624 		 * but it will be reloaded anyway if needed.
    625 		 */
    626 #endif
    627 	}
    628 
    629 	/*
    630 	 * Save the builtin font to memory. In case it got overwritten
    631 	 * in console initialization, use the copy in slot 1.
    632 	 */
    633 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
    634 #define BUILTINFONTLOC (vga_builtinfont.slot == -1 ? 1 : 0)
    635 #else
    636 	KASSERT(vga_builtinfont.slot == 0);
    637 #define BUILTINFONTLOC (0)
    638 #endif
    639 	if (!vga_no_builtinfont) {
    640 		char *data =
    641 		    malloc(256 * vga_builtinfont.wsfont->fontheight,
    642 		    M_DEVBUF, M_WAITOK);
    643 		vga_readoutchars(&vc->hdl, BUILTINFONTLOC, 0, 256,
    644 		    vga_builtinfont.wsfont->fontheight, data);
    645 		vga_builtinfont.wsfont->data = data;
    646 	}
    647 
    648 	vc->vc_type = type;
    649 	vc->vc_funcs = vf;
    650 	vc->vc_quirks = quirks;
    651 
    652 	sc->sc_vc = vc;
    653 	vc->softc = sc;
    654 
    655 	aa.console = console;
    656 	aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
    657 	aa.accessops = &vga_accessops;
    658 	aa.accesscookie = vc;
    659 
    660 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint,
    661 	    CFARGS(.iattr = "wsemuldisplaydev"));
    662 }
    663 
    664 int
    665 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
    666 {
    667 	long defattr;
    668 	const struct wsscreen_descr *scr;
    669 
    670 	if (check && !vga_common_probe(iot, memt))
    671 		return (ENXIO);
    672 
    673 	/* set up bus-independent VGA configuration */
    674 	vga_init(&vga_console_vc, iot, memt);
    675 #ifdef VGA_CONSOLE_SCREENTYPE
    676 	scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
    677 	    &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
    678 	if (!scr)
    679 		panic("vga_cnattach: invalid screen type");
    680 #else
    681 	scr = vga_console_vc.currenttype;
    682 #endif
    683 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
    684 	/*
    685 	 * On some (most/all?) ATI cards, only font slot 0 is usable.
    686 	 * vga_init_screen() might need font slot 0 for a non-default
    687 	 * console font, so save the builtin VGA font to another font slot.
    688 	 * The attach() code will take care later.
    689 	 */
    690 	vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */
    691 	vga_copyfont01(&vga_console_vc.hdl);
    692 	vga_console_vc.vc_nfontslots = 1;
    693 #else
    694 	vga_console_vc.vc_nfontslots = 8;
    695 #endif
    696 #ifdef notdef
    697 	/* until we know better, assume "fast scrolling" does not work */
    698 	vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL;
    699 #endif
    700 
    701 	vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr);
    702 
    703 	wsdisplay_cnattach(scr, &vga_console_screen,
    704 	    vga_console_screen.pcs.cursorcol,
    705 	    vga_console_screen.pcs.cursorrow, defattr);
    706 
    707 	vgaconsole = 1;
    708 	vga_console_type = type;
    709 	return (0);
    710 }
    711 
    712 int
    713 vga_cndetach(void)
    714 {
    715 	struct vga_config *vc;
    716 	struct vga_handle *vh;
    717 
    718 	vc = &vga_console_vc;
    719 	vh = &vc->hdl;
    720 
    721 	if (vgaconsole) {
    722 		wsdisplay_cndetach();
    723 
    724 		bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
    725 		bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
    726 		bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000);
    727 
    728 		vga_console_attached = 0;
    729 		vgaconsole = 0;
    730 
    731 		return 1;
    732 	}
    733 
    734 	return 0;
    735 }
    736 
    737 int
    738 vga_is_console(bus_space_tag_t iot, int type)
    739 {
    740 	if (vgaconsole &&
    741 	    !vga_console_attached &&
    742 	    bus_space_is_equal(iot, vga_console_vc.hdl.vh_iot) &&
    743 	    (vga_console_type == -1 || (type == vga_console_type)))
    744 		return (1);
    745 	return (0);
    746 }
    747 
    748 static int
    749 vga_get_video(struct vga_config *vc)
    750 {
    751 
    752 	return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0;
    753 }
    754 
    755 static void
    756 vga_set_video(struct vga_config *vc, int state)
    757 {
    758 	int val;
    759 
    760 	vga_ts_write(&vc->hdl, syncreset, 0x01);
    761 	if (state) {					/* unblank screen */
    762 		val = vga_ts_read(&vc->hdl, mode);
    763 		vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK);
    764 #ifndef VGA_NO_VBLANK
    765 		val = vga_6845_read(&vc->hdl, mode);
    766 		vga_6845_write(&vc->hdl, mode, val | 0x80);
    767 #endif
    768 	} else {					/* blank screen */
    769 		val = vga_ts_read(&vc->hdl, mode);
    770 		vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK);
    771 #ifndef VGA_NO_VBLANK
    772 		val = vga_6845_read(&vc->hdl, mode);
    773 		vga_6845_write(&vc->hdl, mode, val & ~0x80);
    774 #endif
    775 	}
    776 	vga_ts_write(&vc->hdl, syncreset, 0x03);
    777 }
    778 
    779 static int
    780 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    781 {
    782 	struct vga_config *vc = v;
    783 	struct vgascreen *scr = vs;
    784 	const struct vga_funcs *vf = vc->vc_funcs;
    785 
    786 	switch (cmd) {
    787 	case WSDISPLAYIO_SMODE:
    788 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
    789 			vga_restore_palette(vc);
    790 		return 0;
    791 
    792 	case WSDISPLAYIO_GTYPE:
    793 		*(int *)data = vc->vc_type;
    794 		return 0;
    795 
    796 	case WSDISPLAYIO_GINFO:
    797 		/* XXX should get detailed hardware information here */
    798 		return EPASSTHROUGH;
    799 
    800 	case WSDISPLAYIO_GVIDEO:
    801 		*(int *)data = (vga_get_video(vc) ?
    802 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF);
    803 		return 0;
    804 
    805 	case WSDISPLAYIO_SVIDEO:
    806 		vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
    807 		return 0;
    808 
    809 	case WSDISPLAYIO_GETWSCHAR:
    810 		KASSERT(scr != NULL);
    811 		return pcdisplay_getwschar(&scr->pcs,
    812 		    (struct wsdisplay_char *)data);
    813 
    814 	case WSDISPLAYIO_PUTWSCHAR:
    815 		KASSERT(scr != NULL);
    816 		return pcdisplay_putwschar(&scr->pcs,
    817 		    (struct wsdisplay_char *)data);
    818 
    819 #ifdef WSDISPLAY_CUSTOM_BORDER
    820 	case WSDISPLAYIO_GBORDER:
    821 		return (vga_getborder(vc, (u_int *)data));
    822 
    823 	case WSDISPLAYIO_SBORDER:
    824 		return (vga_setborder(vc, *(u_int *)data));
    825 #endif
    826 
    827 	case WSDISPLAYIO_GETCMAP:
    828 	case WSDISPLAYIO_PUTCMAP:
    829 	case WSDISPLAYIO_GCURPOS:
    830 	case WSDISPLAYIO_SCURPOS:
    831 	case WSDISPLAYIO_GCURMAX:
    832 	case WSDISPLAYIO_GCURSOR:
    833 	case WSDISPLAYIO_SCURSOR:
    834 		/* NONE of these operations are by the generic VGA driver. */
    835 		return EPASSTHROUGH;
    836 	}
    837 
    838 	if (vc->vc_funcs == NULL)
    839 		return (EPASSTHROUGH);
    840 
    841 	if (vf->vf_ioctl == NULL)
    842 		return (EPASSTHROUGH);
    843 
    844 	return ((*vf->vf_ioctl)(v, cmd, data, flag, l));
    845 }
    846 
    847 static paddr_t
    848 vga_mmap(void *v, void *vs, off_t offset, int prot)
    849 {
    850 	struct vga_config *vc = v;
    851 	const struct vga_funcs *vf = vc->vc_funcs;
    852 
    853 	if (vc->vc_funcs == NULL)
    854 		return (-1);
    855 
    856 	if (vf->vf_mmap == NULL)
    857 		return (-1);
    858 
    859 	return ((*vf->vf_mmap)(v, offset, prot));
    860 }
    861 
    862 static int
    863 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    864 		 int *curxp, int *curyp, long *defattrp)
    865 {
    866 	struct vga_config *vc = v;
    867 	struct vgascreen *scr;
    868 
    869 	if (vc->nscreens == 1) {
    870 		struct vgascreen *scr1 = vc->screens.lh_first;
    871 		/*
    872 		 * When allocating the second screen, get backing store
    873 		 * for the first one too.
    874 		 * XXX We could be more clever and use video RAM.
    875 		 */
    876 		scr1->pcs.mem =
    877 		    malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2,
    878 		    M_DEVBUF, M_WAITOK);
    879 	}
    880 
    881 	scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
    882 	vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
    883 
    884 	if (vc->nscreens > 1) {
    885 		scr->pcs.mem = malloc(type->ncols * type->nrows * 2,
    886 		    M_DEVBUF, M_WAITOK);
    887 		pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp);
    888 	}
    889 
    890 	*cookiep = scr;
    891 	*curxp = scr->pcs.cursorcol;
    892 	*curyp = scr->pcs.cursorrow;
    893 
    894 	return (0);
    895 }
    896 
    897 static void
    898 vga_free_screen(void *v, void *cookie)
    899 {
    900 	struct vgascreen *vs = cookie;
    901 	struct vga_config *vc = vs->cfg;
    902 
    903 	LIST_REMOVE(vs, next);
    904 	vc->nscreens--;
    905 	if (vs->fontset1)
    906 		egavga_unreffont(vc, vs->fontset1);
    907 	if (vs->fontset2)
    908 		egavga_unreffont(vc, vs->fontset2);
    909 
    910 	if (vs != &vga_console_screen)
    911 		free(vs, M_DEVBUF);
    912 	else
    913 		panic("vga_free_screen: console");
    914 
    915 	if (vc->active == vs)
    916 		vc->active = 0;
    917 }
    918 
    919 static void vga_usefont(struct vga_config *, struct egavga_font *);
    920 
    921 static void
    922 vga_usefont(struct vga_config *vc, struct egavga_font *f)
    923 {
    924 	int slot;
    925 	struct egavga_font *of;
    926 
    927 	if (f->slot != -1)
    928 		goto toend;
    929 
    930 	for (slot = 0; slot < vc->vc_nfontslots; slot++) {
    931 		if (!vc->vc_fonts[slot])
    932 			goto loadit;
    933 	}
    934 
    935 	/* have to kick out another one */
    936 	TAILQ_FOREACH(of, &vc->vc_fontlist, next) {
    937 		if (of->slot != -1) {
    938 			KASSERT(vc->vc_fonts[of->slot] == of);
    939 			slot = of->slot;
    940 			of->slot = -1;
    941 			goto loadit;
    942 		}
    943 	}
    944 	panic("vga_usefont");
    945 
    946 loadit:
    947 	vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar,
    948 	    f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data);
    949 	f->slot = slot;
    950 	vc->vc_fonts[slot] = f;
    951 
    952 toend:
    953 	TAILQ_REMOVE(&vc->vc_fontlist, f, next);
    954 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
    955 }
    956 
    957 static void
    958 vga_setfont(struct vga_config *vc, struct vgascreen *scr)
    959 {
    960 	int fontslot1, fontslot2;
    961 
    962 	if (scr->fontset1)
    963 		vga_usefont(vc, scr->fontset1);
    964 	if (scr->fontset2)
    965 		vga_usefont(vc, scr->fontset2);
    966 
    967 	fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0);
    968 	fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1);
    969 	if (vc->currentfontset1 != fontslot1 ||
    970 	    vc->currentfontset2 != fontslot2) {
    971 		vga_setfontset(&vc->hdl, fontslot1, fontslot2);
    972 		vc->currentfontset1 = fontslot1;
    973 		vc->currentfontset2 = fontslot2;
    974 	}
    975 }
    976 
    977 static int
    978 vga_show_screen(void *v, void *cookie, int waitok,
    979 		void (*cb)(void *, int, int), void *cbarg)
    980 {
    981 	struct vgascreen *scr = cookie, *oldscr;
    982 	struct vga_config *vc = scr->cfg;
    983 
    984 	oldscr = vc->active; /* can be NULL! */
    985 	if (scr == oldscr) {
    986 		return (0);
    987 	}
    988 
    989 	vc->wantedscreen = cookie;
    990 	vc->switchcb = cb;
    991 	vc->switchcbarg = cbarg;
    992 	if (cb) {
    993 		callout_reset(&vc->vc_switch_callout, 0,
    994 		    (void(*)(void *))vga_doswitch, vc);
    995 		return (EAGAIN);
    996 	}
    997 
    998 	vga_doswitch(vc);
    999 	return (0);
   1000 }
   1001 
   1002 static void
   1003 vga_doswitch(struct vga_config *vc)
   1004 {
   1005 	struct vgascreen *scr, *oldscr;
   1006 	struct vga_handle *vh = &vc->hdl;
   1007 	const struct wsscreen_descr *type;
   1008 
   1009 	scr = vc->wantedscreen;
   1010 	if (!scr) {
   1011 		printf("vga_doswitch: disappeared\n");
   1012 		(*vc->switchcb)(vc->switchcbarg, EIO, 0);
   1013 		return;
   1014 	}
   1015 	type = scr->pcs.type;
   1016 	oldscr = vc->active; /* can be NULL! */
   1017 #ifdef DIAGNOSTIC
   1018 	if (oldscr) {
   1019 		if (!oldscr->pcs.active)
   1020 			panic("vga_show_screen: not active");
   1021 		if (oldscr->pcs.type != vc->currenttype)
   1022 			panic("vga_show_screen: bad type");
   1023 	}
   1024 #endif
   1025 	if (scr == oldscr) {
   1026 		return;
   1027 	}
   1028 #ifdef DIAGNOSTIC
   1029 	if (scr->pcs.active)
   1030 		panic("vga_show_screen: active");
   1031 #endif
   1032 
   1033 	if (oldscr) {
   1034 		const struct wsscreen_descr *oldtype = oldscr->pcs.type;
   1035 
   1036 		oldscr->pcs.active = 0;
   1037 		bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
   1038 		    oldscr->pcs.dispoffset, oldscr->pcs.mem,
   1039 		    oldtype->ncols * oldtype->nrows);
   1040 	}
   1041 
   1042 	if (vc->currenttype != type) {
   1043 		vga_setscreentype(vh, type);
   1044 		vc->currenttype = type;
   1045 	}
   1046 
   1047 	vga_setfont(vc, scr);
   1048 	vga_restore_palette(vc);
   1049 
   1050 	scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset;
   1051 	if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
   1052 		vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9);
   1053 		vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1);
   1054 	}
   1055 
   1056 	bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
   1057 	    scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows);
   1058 	scr->pcs.active = 1;
   1059 
   1060 	vc->active = scr;
   1061 
   1062 	pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron,
   1063 	    scr->pcs.cursorrow, scr->pcs.cursorcol);
   1064 
   1065 	vc->wantedscreen = 0;
   1066 	if (vc->switchcb)
   1067 		(*vc->switchcb)(vc->switchcbarg, 0, 0);
   1068 }
   1069 
   1070 static int
   1071 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data)
   1072 {
   1073 	struct vga_config *vc = v;
   1074 	struct vgascreen *scr = cookie;
   1075 	char *name2;
   1076 	int res;
   1077 
   1078 	if (scr) {
   1079 		name2 = NULL;
   1080 		if (data->name) {
   1081 			name2 = strchr(data->name, ',');
   1082 			if (name2)
   1083 				*name2++ = '\0';
   1084 		}
   1085 		res = vga_selectfont(vc, scr, data->name, name2);
   1086 		if (!res && scr->pcs.active)
   1087 			vga_setfont(vc, scr);
   1088 		return (res);
   1089 	}
   1090 
   1091 	return (0);
   1092 }
   1093 
   1094 static int
   1095 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp)
   1096 {
   1097 	struct vgascreen *scr = id;
   1098 	struct vga_config *vc = scr->cfg;
   1099 
   1100 	if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) ||
   1101 	    (unsigned int)bg >= sizeof(bgansitopc)))
   1102 		return (EINVAL);
   1103 
   1104 	if (vc->hdl.vh_mono) {
   1105 		if (flags & WSATTR_WSCOLORS)
   1106 			return (EINVAL);
   1107 		if (flags & WSATTR_REVERSE)
   1108 			*attrp = 0x70;
   1109 		else
   1110 			*attrp = 0x07;
   1111 		if (flags & WSATTR_UNDERLINE)
   1112 			*attrp |= FG_UNDERLINE;
   1113 		if (flags & WSATTR_HILIT)
   1114 			*attrp |= FG_INTENSE;
   1115 	} else {
   1116 		if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
   1117 			return (EINVAL);
   1118 		if (flags & WSATTR_WSCOLORS)
   1119 			*attrp = fgansitopc[fg] | bgansitopc[bg];
   1120 		else
   1121 			*attrp = 7;
   1122 		if (flags & WSATTR_HILIT)
   1123 			*attrp += 8;
   1124 	}
   1125 	if (flags & WSATTR_BLINK)
   1126 		*attrp |= FG_BLINK;
   1127 	return (0);
   1128 }
   1129 
   1130 static void
   1131 vga_copyrows(void *id, int srcrow, int dstrow, int nrows)
   1132 {
   1133 	struct vgascreen *scr = id;
   1134 	bus_space_tag_t memt = scr->pcs.hdl->ph_memt;
   1135 	bus_space_handle_t memh = scr->pcs.hdl->ph_memh;
   1136 	int ncols = scr->pcs.type->ncols;
   1137 	bus_size_t srcoff, dstoff;
   1138 
   1139 	srcoff = srcrow * ncols + 0;
   1140 	dstoff = dstrow * ncols + 0;
   1141 
   1142 	if (scr->pcs.active) {
   1143 		if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) {
   1144 #ifdef PCDISPLAY_SOFTCURSOR
   1145 			int cursoron = scr->pcs.cursoron;
   1146 
   1147 			if (cursoron)
   1148 				pcdisplay_cursor(&scr->pcs, 0,
   1149 				    scr->pcs.cursorrow, scr->pcs.cursorcol);
   1150 #endif
   1151 			/* scroll up whole screen */
   1152 			if ((scr->pcs.dispoffset + srcrow * ncols * 2)
   1153 			    <= scr->maxdispoffset) {
   1154 				scr->pcs.dispoffset += srcrow * ncols * 2;
   1155 			} else {
   1156 				bus_space_copy_region_2(memt, memh,
   1157 				    scr->pcs.dispoffset + srcoff * 2,
   1158 				    memh, scr->mindispoffset, nrows * ncols);
   1159 				scr->pcs.dispoffset = scr->mindispoffset;
   1160 			}
   1161 			vga_6845_write(&scr->cfg->hdl, startadrh,
   1162 			    scr->pcs.dispoffset >> 9);
   1163 			vga_6845_write(&scr->cfg->hdl, startadrl,
   1164 			    scr->pcs.dispoffset >> 1);
   1165 #ifdef PCDISPLAY_SOFTCURSOR
   1166 			if (cursoron)
   1167 				pcdisplay_cursor(&scr->pcs, 1,
   1168 				    scr->pcs.cursorrow, scr->pcs.cursorcol);
   1169 #endif
   1170 		} else {
   1171 			bus_space_copy_region_2(memt, memh,
   1172 			    scr->pcs.dispoffset + srcoff * 2,
   1173 			    memh, scr->pcs.dispoffset + dstoff * 2,
   1174 			    nrows * ncols);
   1175 		}
   1176 	} else
   1177 		memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff],
   1178 		    nrows * ncols * 2);
   1179 }
   1180 
   1181 #ifdef WSCONS_SUPPORT_PCVTFONTS
   1182 
   1183 #define NOTYET 0xffff
   1184 static const uint16_t pcvt_unichars[0xa0] = {
   1185 /* 0 */	_e006U, /* N/L control */
   1186 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1187 	NOTYET,
   1188 	0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */
   1189 	0x240a, /* SYMBOL FOR LINE FEED */
   1190 	0x240b, /* SYMBOL FOR VERTICAL TABULATION */
   1191 	0x240c, /* SYMBOL FOR FORM FEED */
   1192 	0x240d, /* SYMBOL FOR CARRIAGE RETURN */
   1193 	NOTYET, NOTYET,
   1194 /* 1 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1195 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1196 /* 2 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1197 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1198 /* 3 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1199 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
   1200 /* 4 */	0x03c1, /* GREEK SMALL LETTER RHO */
   1201 	0x03c8, /* GREEK SMALL LETTER PSI */
   1202 	0x2202, /* PARTIAL DIFFERENTIAL */
   1203 	0x03bb, /* GREEK SMALL LETTER LAMDA */
   1204 	0x03b9, /* GREEK SMALL LETTER IOTA */
   1205 	0x03b7, /* GREEK SMALL LETTER ETA */
   1206 	0x03b5, /* GREEK SMALL LETTER EPSILON */
   1207 	0x03c7, /* GREEK SMALL LETTER CHI */
   1208 	0x2228, /* LOGICAL OR */
   1209 	0x2227, /* LOGICAL AND */
   1210 	0x222a, /* UNION */
   1211 	0x2283, /* SUPERSET OF */
   1212 	0x2282, /* SUBSET OF */
   1213 	0x03a5, /* GREEK CAPITAL LETTER UPSILON */
   1214 	0x039e, /* GREEK CAPITAL LETTER XI */
   1215 	0x03a8, /* GREEK CAPITAL LETTER PSI */
   1216 /* 5 */	0x03a0, /* GREEK CAPITAL LETTER PI */
   1217 	0x21d2, /* RIGHTWARDS DOUBLE ARROW */
   1218 	0x21d4, /* LEFT RIGHT DOUBLE ARROW */
   1219 	0x039b, /* GREEK CAPITAL LETTER LAMDA */
   1220 	0x0398, /* GREEK CAPITAL LETTER THETA */
   1221 	0x2243, /* ASYMPTOTICALLY EQUAL TO */
   1222 	0x2207, /* NABLA */
   1223 	0x2206, /* INCREMENT */
   1224 	0x221d, /* PROPORTIONAL TO */
   1225 	0x2234, /* THEREFORE */
   1226 	0x222b, /* INTEGRAL */
   1227 	0x2215, /* DIVISION SLASH */
   1228 	0x2216, /* SET MINUS */
   1229 	_e00eU, /* angle? */
   1230 	_e00dU, /* inverted angle? */
   1231 	_e00bU, /* braceleftmid */
   1232 /* 6 */	_e00cU, /* bracerightmid */
   1233 	_e007U, /* bracelefttp */
   1234 	_e008U, /* braceleftbt */
   1235 	_e009U, /* bracerighttp */
   1236 	_e00aU, /* bracerightbt */
   1237 	0x221a, /* SQUARE ROOT */
   1238 	0x03c9, /* GREEK SMALL LETTER OMEGA */
   1239 	0x00a5, /* YEN SIGN */
   1240 	0x03be, /* GREEK SMALL LETTER XI */
   1241 	0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */
   1242 	0x00fe, /* LATIN SMALL LETTER THORN */
   1243 	0x00f0, /* LATIN SMALL LETTER ETH */
   1244 	0x00de, /* LATIN CAPITAL LETTER THORN */
   1245 	0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
   1246 	0x00d7, /* MULTIPLICATION SIGN */
   1247 	0x00d0, /* LATIN CAPITAL LETTER ETH */
   1248 /* 7 */	0x00be, /* VULGAR FRACTION THREE QUARTERS */
   1249 	0x00b8, /* CEDILLA */
   1250 	0x00b4, /* ACUTE ACCENT */
   1251 	0x00af, /* MACRON */
   1252 	0x00ae, /* REGISTERED SIGN */
   1253 	0x00ad, /* SOFT HYPHEN */
   1254 	0x00ac, /* NOT SIGN */
   1255 	0x00a8, /* DIAERESIS */
   1256 	0x2260, /* NOT EQUAL TO */
   1257 	0x23bd, /* scan 9 */
   1258 	0x23bc, /* scan 7 */
   1259 	0x2500, /* scan 5 */
   1260 	0x23bb, /* scan 3 */
   1261 	0x23ba, /* scan 1 */
   1262 	0x03c5, /* GREEK SMALL LETTER UPSILON */
   1263 	0x00f8, /* LATIN SMALL LETTER O WITH STROKE */
   1264 /* 8 */	0x0153, /* LATIN SMALL LIGATURE OE */
   1265 	0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */
   1266 	0x00e3, /* LATIN SMALL LETTER A WITH TILDE */
   1267 	0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
   1268 	0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
   1269 	0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
   1270 	0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
   1271 	0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
   1272 	0x0152, /* LATIN CAPITAL LIGATURE OE */
   1273 	0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
   1274 	0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
   1275 	0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
   1276 	0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
   1277 	0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
   1278 	0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
   1279 	0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
   1280 /* 9 */	0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
   1281 	0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
   1282 	0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
   1283 	0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
   1284 	0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
   1285 	0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
   1286 	0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
   1287 	0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
   1288 	0x00b9, /* SUPERSCRIPT ONE */
   1289 	0x00b7, /* MIDDLE DOT */
   1290 	0x03b6, /* GREEK SMALL LETTER ZETA */
   1291 	0x00b3, /* SUPERSCRIPT THREE */
   1292 	0x00a9, /* COPYRIGHT SIGN */
   1293 	0x00a4, /* CURRENCY SIGN */
   1294 	0x03ba, /* GREEK SMALL LETTER KAPPA */
   1295 	_e000U  /* mirrored question mark? */
   1296 };
   1297 
   1298 static int vga_pcvt_mapchar(int, u_int *);
   1299 
   1300 static int
   1301 vga_pcvt_mapchar(int uni, u_int *index)
   1302 {
   1303 	int i;
   1304 
   1305 	for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */
   1306 		if (uni == pcvt_unichars[i]) {
   1307 			*index = i;
   1308 			return (5);
   1309 		}
   1310 	*index = 0x99; /* middle dot */
   1311 	return (0);
   1312 }
   1313 
   1314 #endif /* WSCONS_SUPPORT_PCVTFONTS */
   1315 
   1316 #ifdef WSCONS_SUPPORT_ISO7FONTS
   1317 
   1318 static int
   1319 vga_iso7_mapchar(int uni, u_int *index)
   1320 {
   1321 
   1322 	/*
   1323 	 * U+0384 (GREEK TONOS) to
   1324 	 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS)
   1325 	 * map directly to the iso-9 font
   1326 	 */
   1327 	if (uni >= 0x0384 && uni <= 0x03ce) {
   1328 		/* U+0384 is at offset 0xb4 in the font */
   1329 		*index = uni - 0x0384 + 0xb4;
   1330 		return (5);
   1331 	}
   1332 
   1333 	/* XXX more chars in the iso-9 font */
   1334 
   1335 	*index = 0xa4; /* shaded rectangle */
   1336 	return (0);
   1337 }
   1338 
   1339 #endif /* WSCONS_SUPPORT_ISO7FONTS */
   1340 
   1341 static const uint16_t iso2_unichars[0x60] = {
   1342 	0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
   1343 	0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
   1344 	0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
   1345 	0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
   1346 	0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
   1347 	0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
   1348 	0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
   1349 	0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
   1350 	0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
   1351 	0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
   1352 	0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
   1353 	0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
   1354 };
   1355 
   1356 static const uint16_t koi8_unichars[0x40] = {
   1357 	0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
   1358 	0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
   1359 	0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
   1360 	0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
   1361 	0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
   1362 	0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
   1363 	0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
   1364 	0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
   1365 };
   1366 
   1367 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *);
   1368 
   1369 static int
   1370 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index)
   1371 {
   1372 
   1373 	switch (font->wsfont->encoding) {
   1374 	case WSDISPLAY_FONTENC_ISO:
   1375 		if (uni < 256) {
   1376 			*index = uni;
   1377 			return (5);
   1378 		} else {
   1379 			*index = ' ';
   1380 			return (0);
   1381 		}
   1382 	case WSDISPLAY_FONTENC_ISO2:
   1383 		if (uni < 0xa0) {
   1384 			*index = uni;
   1385 			return (5);
   1386 		} else {
   1387 			int i;
   1388 			for (i = 0; i < 0x60; i++) {
   1389 				if (uni == iso2_unichars[i]) {
   1390 					*index = i + 0xa0;
   1391 					return (5);
   1392 				}
   1393 			}
   1394 			*index = 0xa4; /* currency sign */
   1395 			return (0);
   1396 		}
   1397 	case WSDISPLAY_FONTENC_KOI8_R:
   1398 		if (uni < 0x80) {
   1399 			*index = uni;
   1400 			return (5);
   1401 		} else {
   1402 			int i;
   1403 			for (i = 0; i < 0x40; i++) {
   1404 				if (uni == koi8_unichars[i]) {
   1405 					*index = i + 0xc0;
   1406 					return (5);
   1407 				}
   1408 			}
   1409 			*index = 0x94; /* box */
   1410 			return (0);
   1411 		}
   1412 	case WSDISPLAY_FONTENC_IBM:
   1413 		return (pcdisplay_mapchar(id, uni, index));
   1414 #ifdef WSCONS_SUPPORT_PCVTFONTS
   1415 	case WSDISPLAY_FONTENC_PCVT:
   1416 		return (vga_pcvt_mapchar(uni, index));
   1417 #endif
   1418 #ifdef WSCONS_SUPPORT_ISO7FONTS
   1419 	case WSDISPLAY_FONTENC_ISO7:
   1420 		return (vga_iso7_mapchar(uni, index));
   1421 #endif
   1422 	default:
   1423 #ifdef VGAFONTDEBUG
   1424 		printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding);
   1425 #endif
   1426 		*index = ' ';
   1427 		return (0);
   1428 	}
   1429 }
   1430 
   1431 static int
   1432 vga_mapchar(void *id, int uni, u_int *index)
   1433 {
   1434 	struct vgascreen *scr = id;
   1435 	u_int idx1, idx2;
   1436 	int res1, res2;
   1437 
   1438 	res1 = 0;
   1439 	idx1 = ' '; /* space */
   1440 	if (scr->fontset1)
   1441 		res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1);
   1442 	res2 = -1;
   1443 	if (scr->fontset2) {
   1444 		KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type));
   1445 		res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2);
   1446 	}
   1447 	if (res2 > res1) {
   1448 		*index = idx2 | 0x0800; /* attribute bit 3 */
   1449 		return (res2);
   1450 	}
   1451 	*index = idx1;
   1452 	return (res1);
   1453 }
   1454 
   1455 #ifdef WSDISPLAY_SCROLLSUPPORT
   1456 static void
   1457 vga_scroll(void *v, void *cookie, int lines)
   1458 {
   1459 	struct vga_config *vc = v;
   1460 	struct vgascreen *scr = cookie;
   1461 	struct vga_handle *vh = &vc->hdl;
   1462 
   1463 	if (lines == 0) {
   1464 		if (scr->pcs.visibleoffset == scr->pcs.dispoffset)
   1465 			return;
   1466 
   1467 		scr->pcs.visibleoffset = scr->pcs.dispoffset;
   1468 	}
   1469 	else {
   1470 		int vga_scr_end;
   1471 		int margin = scr->pcs.type->ncols * 2;
   1472 		int ul, we, p, st;
   1473 
   1474 		vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols *
   1475 		    scr->pcs.type->nrows * 2);
   1476 		if (scr->vga_rollover > vga_scr_end + margin) {
   1477 			ul = vga_scr_end;
   1478 			we = scr->vga_rollover + scr->pcs.type->ncols * 2;
   1479 		} else {
   1480 			ul = 0;
   1481 			we = 0x8000;
   1482 		}
   1483 		p = (scr->pcs.visibleoffset - ul + we) % we + lines *
   1484 		    (scr->pcs.type->ncols * 2);
   1485 		st = (scr->pcs.dispoffset - ul + we) % we;
   1486 		if (p < margin)
   1487 			p = 0;
   1488 		if (p > st - margin)
   1489 			p = st;
   1490 		scr->pcs.visibleoffset = (p + ul) % we;
   1491 	}
   1492 
   1493 	vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9);
   1494 	vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1);
   1495 }
   1496 #endif
   1497 
   1498 static void
   1499 vga_putchar(void *c, int row, int col, u_int uc, long attr)
   1500 {
   1501 
   1502 	pcdisplay_putchar(c, row, col, uc, attr);
   1503 }
   1504 
   1505 #ifdef WSDISPLAY_CUSTOM_BORDER
   1506 static int
   1507 vga_getborder(struct vga_config *vc, u_int *valuep)
   1508 {
   1509 	struct vga_handle *vh = &vc->hdl;
   1510 	u_int idx;
   1511 	uint8_t value;
   1512 
   1513 	if (vh->vh_mono)
   1514 		return ENODEV;
   1515 
   1516 	value = _vga_attr_read(vh, VGA_ATC_OVERSCAN);
   1517 	for (idx = 0; idx < sizeof(fgansitopc); idx++) {
   1518 		if (fgansitopc[idx] == value) {
   1519 			*valuep = idx;
   1520 			return (0);
   1521 		}
   1522 	}
   1523 	return (EIO);
   1524 }
   1525 
   1526 static int
   1527 vga_setborder(struct vga_config *vc, u_int value)
   1528 {
   1529 	struct vga_handle *vh = &vc->hdl;
   1530 
   1531 	if (vh->vh_mono)
   1532 		return ENODEV;
   1533 	if (value >= sizeof(fgansitopc))
   1534 		return EINVAL;
   1535 
   1536 	_vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]);
   1537 	return (0);
   1538 }
   1539 #endif /* WSDISPLAY_CUSTOM_BORDER */
   1540 
   1541 void
   1542 vga_resume(struct vga_softc *sc)
   1543 {
   1544 #ifdef VGA_RESET_ON_RESUME
   1545 	vga_initregs(&sc->sc_vc->hdl);
   1546 #endif
   1547 #ifdef PCDISPLAY_SOFTCURSOR
   1548 	/* Disable the hardware cursor */
   1549 	vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20);
   1550 	vga_6845_write(&sc->sc_vc->hdl, curend, 0x00);
   1551 #endif
   1552 }
   1553 
   1554 static void
   1555 vga_save_palette(struct vga_config *vc)
   1556 {
   1557 	struct vga_handle *vh = &vc->hdl;
   1558 	size_t i;
   1559 	uint8_t *palette = vc->palette;
   1560 
   1561 	if (vh->vh_mono)
   1562 		return;
   1563 
   1564 	vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
   1565 	vga_raw_write(vh, VGA_DAC_ADDRR, 0x00);
   1566 	for (i = 0; i < sizeof(vc->palette); i++)
   1567 		*palette++ = vga_raw_read(vh, VGA_DAC_PALETTE);
   1568 
   1569 	vga_reset_state(vh);			/* reset flip/flop */
   1570 }
   1571 
   1572 static void
   1573 vga_restore_palette(struct vga_config *vc)
   1574 {
   1575 	struct vga_handle *vh = &vc->hdl;
   1576 	size_t i;
   1577 	uint8_t *palette = vc->palette;
   1578 
   1579 	if (vh->vh_mono)
   1580 		return;
   1581 
   1582 	vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
   1583 	vga_raw_write(vh, VGA_DAC_ADDRW, 0x00);
   1584 	for (i = 0; i < sizeof(vc->palette); i++)
   1585 		vga_raw_write(vh, VGA_DAC_PALETTE, *palette++);
   1586 
   1587 	vga_reset_state(vh);			/* reset flip/flop */
   1588 	vga_enable(vh);
   1589 }
   1590