xref: /netbsd-src/sys/dev/ic/vga.c (revision 80d9064ac03cbb6a4174695f0d5b237c8766d3d0)
1 /* $NetBSD: vga.c,v 1.113 2014/08/21 13:52:22 macallan 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@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.113 2014/08/21 13:52:22 macallan 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_NOWAIT);
364 	if (!f) {
365 		wsfont_unlock(cookie);
366 		return (0);
367 	}
368 	f->wsfont = wf;
369 	f->cookie = cookie;
370 	f->slot = -1; /* not yet loaded */
371 	f->usecount = 0; /* incremented below */
372 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
373 
374 found:
375 	f->usecount++;
376 #ifdef VGAFONTDEBUG
377 	if (scr != &vga_console_screen || vga_console_attached)
378 		printf("vga_getfont: usecount=%d\n", f->usecount);
379 #endif
380 	return (f);
381 }
382 
383 static void
384 egavga_unreffont(struct vga_config *vc, struct egavga_font *f)
385 {
386 
387 	f->usecount--;
388 #ifdef VGAFONTDEBUG
389 	printf("vga_unreffont: usecount=%d\n", f->usecount);
390 #endif
391 	if (f->usecount == 0 && f->cookie != -1) {
392 		TAILQ_REMOVE(&vc->vc_fontlist, f, next);
393 		if (f->slot != -1) {
394 			KASSERT(vc->vc_fonts[f->slot] == f);
395 			vc->vc_fonts[f->slot] = 0;
396 		}
397 		wsfont_unlock(f->cookie);
398 #ifdef VGA_CONSOLE_SCREENTYPE
399 		if (f != &vga_consolefont)
400 #endif
401 		free(f, M_DEVBUF);
402 	}
403 }
404 
405 static int
406 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1,
407 	       const char *name2)
408 {
409 	const struct wsscreen_descr *type = scr->pcs.type;
410 	struct egavga_font *f1, *f2;
411 
412 	f1 = egavga_getfont(vc, scr, name1, 1);
413 	if (!f1)
414 		return (ENXIO);
415 
416 	if (VGA_SCREEN_CANTWOFONTS(type) && name2) {
417 		f2 = egavga_getfont(vc, scr, name2, 0);
418 		if (!f2) {
419 			egavga_unreffont(vc, f1);
420 			return (ENXIO);
421 		}
422 	} else
423 		f2 = 0;
424 
425 #ifdef VGAFONTDEBUG
426 	if (scr != &vga_console_screen || vga_console_attached) {
427 		printf("vga (%s): font1=%s (slot %d)", type->name,
428 		    f1->wsfont->name, f1->slot);
429 		if (f2)
430 			printf(", font2=%s (slot %d)",
431 			    f2->wsfont->name, f2->slot);
432 		printf("\n");
433 	}
434 #endif
435 	if (scr->fontset1)
436 		egavga_unreffont(vc, scr->fontset1);
437 	scr->fontset1 = f1;
438 	if (scr->fontset2)
439 		egavga_unreffont(vc, scr->fontset2);
440 	scr->fontset2 = f2;
441 	return (0);
442 }
443 
444 static void
445 vga_init_screen(struct vga_config *vc, struct vgascreen *scr,
446 		const struct wsscreen_descr *type, int existing, long *attrp)
447 {
448 	int cpos;
449 	int res __diagused;
450 
451 	scr->cfg = vc;
452 	scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl;
453 	scr->pcs.type = type;
454 	scr->pcs.active = existing;
455 	scr->mindispoffset = 0;
456 	if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL)
457 		scr->maxdispoffset = 0;
458 	else
459 		scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2;
460 
461 	if (existing) {
462 		vc->active = scr;
463 
464 		cpos = vga_6845_read(&vc->hdl, cursorh) << 8;
465 		cpos |= vga_6845_read(&vc->hdl, cursorl);
466 
467 		/* make sure we have a valid cursor position */
468 		if (cpos < 0 || cpos >= type->nrows * type->ncols)
469 			cpos = 0;
470 
471 		scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9;
472 		scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1;
473 
474 		/* make sure we have a valid memory offset */
475 		if (scr->pcs.dispoffset < scr->mindispoffset ||
476 		    scr->pcs.dispoffset > scr->maxdispoffset)
477 			scr->pcs.dispoffset = scr->mindispoffset;
478 
479 		if (type != vc->currenttype) {
480 			vga_setscreentype(&vc->hdl, type);
481 			vc->currenttype = type;
482 		}
483 	} else {
484 		cpos = 0;
485 		scr->pcs.dispoffset = scr->mindispoffset;
486 	}
487 
488 	scr->pcs.visibleoffset = scr->pcs.dispoffset;
489 	scr->vga_rollover = 0;
490 
491 	scr->pcs.cursorrow = cpos / type->ncols;
492 	scr->pcs.cursorcol = cpos % type->ncols;
493 	pcdisplay_cursor_init(&scr->pcs, existing);
494 
495 #ifdef __alpha__
496 	if (!vc->hdl.vh_mono)
497 		/*
498 		 * DEC firmware uses a blue background.
499 		 * XXX These should be specified as kernel options for
500 		 * XXX alpha only, not hardcoded here (which is wrong
501 		 * XXX anyway because the emulation layer will assume
502 		 * XXX the default attribute is white on black).
503 		 */
504 		res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE,
505 		    WSATTR_WSCOLORS, attrp);
506 	else
507 #endif
508 	res = vga_allocattr(scr, 0, 0, 0, attrp);
509 #ifdef DIAGNOSTIC
510 	if (res)
511 		panic("vga_init_screen: attribute botch");
512 #endif
513 
514 	scr->pcs.mem = NULL;
515 
516 	scr->fontset1 = scr->fontset2 = 0;
517 	if (vga_selectfont(vc, scr, 0, 0)) {
518 		if (scr == &vga_console_screen)
519 			panic("vga_init_screen: no font");
520 		else
521 			printf("vga_init_screen: no font\n");
522 	}
523 	if (existing)
524 		vga_setfont(vc, scr);
525 
526 	vc->nscreens++;
527 	LIST_INSERT_HEAD(&vc->screens, scr, next);
528 }
529 
530 static void
531 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt)
532 {
533 	struct vga_handle *vh = &vc->hdl;
534 	uint8_t mor;
535 	int i;
536 
537 	vh->vh_iot = iot;
538 	vh->vh_memt = memt;
539 
540 	if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
541 		panic("vga_init: couldn't map vga io");
542 
543 	/* read "misc output register" */
544 	mor = vga_raw_read(vh, VGA_MISC_DATAR);
545 	vh->vh_mono = !(mor & 1);
546 
547 	if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
548 	    &vh->vh_ioh_6845))
549 		panic("vga_init: couldn't map 6845 io");
550 
551 	if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh))
552 		panic("vga_init: couldn't map memory");
553 
554 	if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh,
555 	    (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh))
556 		panic("vga_init: mem subrange failed");
557 
558 #if 0
559 	/* should only reserve the space (no need to map - save KVM) */
560 	vc->vc_biostag = memt;
561 	if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0, &vc->vc_bioshdl))
562 		vc->vc_biosmapped = 0;
563 	else
564 		vc->vc_biosmapped = 1;
565 #endif
566 	vc->nscreens = 0;
567 	LIST_INIT(&vc->screens);
568 	vc->active = NULL;
569 	vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen;
570 	callout_init(&vc->vc_switch_callout, 0);
571 
572 	wsfont_init();
573 	if (vga_no_builtinfont) {
574 		struct wsdisplay_font *wf;
575 		int cookie;
576 
577 		cookie = wsfont_find(NULL, 8, 16, 0,
578 		     WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP);
579 		if (cookie == -1 || wsfont_lock(cookie, &wf))
580 			panic("vga_init: can't load console font");
581 		vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars,
582 		    wf->fontheight, wf->data);
583 		vga_builtinfont.wsfont = wf;
584 		vga_builtinfont.cookie = cookie;
585 		vga_builtinfont.slot = 0;
586 	}
587 	vc->vc_fonts[0] = &vga_builtinfont;
588 	for (i = 1; i < 8; i++)
589 		vc->vc_fonts[i] = 0;
590 	TAILQ_INIT(&vc->vc_fontlist);
591 	TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next);
592 
593 	vc->currentfontset1 = vc->currentfontset2 = 0;
594 
595 	if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc))
596 		_vga_attr_write(vh, VGA_ATC_OVERSCAN,
597 		                fgansitopc[WSDISPLAY_BORDER_COLOR]);
598 	vga_save_palette(vc);
599 }
600 
601 void
602 vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot,
603 		  bus_space_tag_t memt, int type, int quirks,
604 		  const struct vga_funcs *vf)
605 {
606 	int console;
607 	struct vga_config *vc;
608 	struct wsemuldisplaydev_attach_args aa;
609 
610 	console = vga_is_console(iot, type);
611 
612 	if (console) {
613 		vc = &vga_console_vc;
614 		vga_console_attached = 1;
615 	} else {
616 		vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK);
617 		vga_init(vc, iot, memt);
618 	}
619 
620 	if (quirks & VGA_QUIRK_ONEFONT) {
621 		vc->vc_nfontslots = 1;
622 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL
623 		/*
624 		 * XXX maybe invalidate font in slot > 0, but this can
625 		 * only be happen with VGA_CONSOLE_SCREENTYPE, and then
626 		 * we require VGA_CONSOLE_ATI_BROKEN_FONTSEL anyway.
627 		 */
628 #endif
629 	} else {
630 		vc->vc_nfontslots = 8;
631 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL
632 		/*
633 		 * XXX maybe validate builtin font shifted to slot 1 if
634 		 * slot 0 got overwritten because of VGA_CONSOLE_SCREENTYPE,
635 		 * but it will be reloaded anyway if needed.
636 		 */
637 #endif
638 	}
639 
640 	/*
641 	 * Save the builtin font to memory. In case it got overwritten
642 	 * in console initialization, use the copy in slot 1.
643 	 */
644 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
645 #define BUILTINFONTLOC (vga_builtinfont.slot == -1 ? 1 : 0)
646 #else
647 	KASSERT(vga_builtinfont.slot == 0);
648 #define BUILTINFONTLOC (0)
649 #endif
650 	if (!vga_no_builtinfont) {
651 		char *data =
652 		    malloc(256 * vga_builtinfont.wsfont->fontheight,
653 		    M_DEVBUF, M_WAITOK);
654 		vga_readoutchars(&vc->hdl, BUILTINFONTLOC, 0, 256,
655 		    vga_builtinfont.wsfont->fontheight, data);
656 		vga_builtinfont.wsfont->data = data;
657 	}
658 
659 	vc->vc_type = type;
660 	vc->vc_funcs = vf;
661 	vc->vc_quirks = quirks;
662 
663 	sc->sc_vc = vc;
664 	vc->softc = sc;
665 
666 	aa.console = console;
667 	aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
668 	aa.accessops = &vga_accessops;
669 	aa.accesscookie = vc;
670 
671 	config_found_ia(sc->sc_dev, "wsemuldisplaydev", &aa, wsemuldisplaydevprint);
672 }
673 
674 int
675 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
676 {
677 	long defattr;
678 	const struct wsscreen_descr *scr;
679 
680 	if (check && !vga_common_probe(iot, memt))
681 		return (ENXIO);
682 
683 	/* set up bus-independent VGA configuration */
684 	vga_init(&vga_console_vc, iot, memt);
685 #ifdef VGA_CONSOLE_SCREENTYPE
686 	scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
687 	    &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
688 	if (!scr)
689 		panic("vga_cnattach: invalid screen type");
690 #else
691 	scr = vga_console_vc.currenttype;
692 #endif
693 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
694 	/*
695 	 * On some (most/all?) ATI cards, only font slot 0 is usable.
696 	 * vga_init_screen() might need font slot 0 for a non-default
697 	 * console font, so save the builtin VGA font to another font slot.
698 	 * The attach() code will take care later.
699 	 */
700 	vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */
701 	vga_copyfont01(&vga_console_vc.hdl);
702 	vga_console_vc.vc_nfontslots = 1;
703 #else
704 	vga_console_vc.vc_nfontslots = 8;
705 #endif
706 #ifdef notdef
707 	/* until we know better, assume "fast scrolling" does not work */
708 	vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL;
709 #endif
710 
711 	vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr);
712 
713 	wsdisplay_cnattach(scr, &vga_console_screen,
714 	    vga_console_screen.pcs.cursorcol,
715 	    vga_console_screen.pcs.cursorrow, defattr);
716 
717 	vgaconsole = 1;
718 	vga_console_type = type;
719 	return (0);
720 }
721 
722 int
723 vga_cndetach(void)
724 {
725 	struct vga_config *vc;
726 	struct vga_handle *vh;
727 
728 	vc = &vga_console_vc;
729 	vh = &vc->hdl;
730 
731 	if (vgaconsole) {
732 		wsdisplay_cndetach();
733 
734 		bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
735 		bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
736 
737 		vga_console_attached = 0;
738 		vgaconsole = 0;
739 
740 		return 1;
741 	}
742 
743 	return 0;
744 }
745 
746 int
747 vga_is_console(bus_space_tag_t iot, int type)
748 {
749 	if (vgaconsole &&
750 	    !vga_console_attached &&
751 	    bus_space_is_equal(iot, vga_console_vc.hdl.vh_iot) &&
752 	    (vga_console_type == -1 || (type == vga_console_type)))
753 		return (1);
754 	return (0);
755 }
756 
757 static int
758 vga_get_video(struct vga_config *vc)
759 {
760 
761 	return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0;
762 }
763 
764 static void
765 vga_set_video(struct vga_config *vc, int state)
766 {
767 	int val;
768 
769 	vga_ts_write(&vc->hdl, syncreset, 0x01);
770 	if (state) {					/* unblank screen */
771 		val = vga_ts_read(&vc->hdl, mode);
772 		vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK);
773 #ifndef VGA_NO_VBLANK
774 		val = vga_6845_read(&vc->hdl, mode);
775 		vga_6845_write(&vc->hdl, mode, val | 0x80);
776 #endif
777 	} else {					/* blank screen */
778 		val = vga_ts_read(&vc->hdl, mode);
779 		vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK);
780 #ifndef VGA_NO_VBLANK
781 		val = vga_6845_read(&vc->hdl, mode);
782 		vga_6845_write(&vc->hdl, mode, val & ~0x80);
783 #endif
784 	}
785 	vga_ts_write(&vc->hdl, syncreset, 0x03);
786 }
787 
788 static int
789 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
790 {
791 	struct vga_config *vc = v;
792 	struct vgascreen *scr = vs;
793 	const struct vga_funcs *vf = vc->vc_funcs;
794 
795 	switch (cmd) {
796 	case WSDISPLAYIO_SMODE:
797 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
798 			vga_restore_palette(vc);
799 		return 0;
800 
801 	case WSDISPLAYIO_GTYPE:
802 		*(int *)data = vc->vc_type;
803 		return 0;
804 
805 	case WSDISPLAYIO_GINFO:
806 		/* XXX should get detailed hardware information here */
807 		return EPASSTHROUGH;
808 
809 	case WSDISPLAYIO_GVIDEO:
810 		*(int *)data = (vga_get_video(vc) ?
811 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF);
812 		return 0;
813 
814 	case WSDISPLAYIO_SVIDEO:
815 		vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
816 		return 0;
817 
818 	case WSDISPLAYIO_GETWSCHAR:
819 		KASSERT(scr != NULL);
820 		return pcdisplay_getwschar(&scr->pcs,
821 		    (struct wsdisplay_char *)data);
822 
823 	case WSDISPLAYIO_PUTWSCHAR:
824 		KASSERT(scr != NULL);
825 		return pcdisplay_putwschar(&scr->pcs,
826 		    (struct wsdisplay_char *)data);
827 
828 #ifdef WSDISPLAY_CUSTOM_BORDER
829 	case WSDISPLAYIO_GBORDER:
830 		return (vga_getborder(vc, (u_int *)data));
831 
832 	case WSDISPLAYIO_SBORDER:
833 		return (vga_setborder(vc, *(u_int *)data));
834 #endif
835 
836 	case WSDISPLAYIO_GETCMAP:
837 	case WSDISPLAYIO_PUTCMAP:
838 	case WSDISPLAYIO_GCURPOS:
839 	case WSDISPLAYIO_SCURPOS:
840 	case WSDISPLAYIO_GCURMAX:
841 	case WSDISPLAYIO_GCURSOR:
842 	case WSDISPLAYIO_SCURSOR:
843 		/* NONE of these operations are by the generic VGA driver. */
844 		return EPASSTHROUGH;
845 	}
846 
847 	if (vc->vc_funcs == NULL)
848 		return (EPASSTHROUGH);
849 
850 	if (vf->vf_ioctl == NULL)
851 		return (EPASSTHROUGH);
852 
853 	return ((*vf->vf_ioctl)(v, cmd, data, flag, l));
854 }
855 
856 static paddr_t
857 vga_mmap(void *v, void *vs, off_t offset, int prot)
858 {
859 	struct vga_config *vc = v;
860 	const struct vga_funcs *vf = vc->vc_funcs;
861 
862 	if (vc->vc_funcs == NULL)
863 		return (-1);
864 
865 	if (vf->vf_mmap == NULL)
866 		return (-1);
867 
868 	return ((*vf->vf_mmap)(v, offset, prot));
869 }
870 
871 static int
872 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
873 		 int *curxp, int *curyp, long *defattrp)
874 {
875 	struct vga_config *vc = v;
876 	struct vgascreen *scr;
877 
878 	if (vc->nscreens == 1) {
879 		struct vgascreen *scr1 = vc->screens.lh_first;
880 		/*
881 		 * When allocating the second screen, get backing store
882 		 * for the first one too.
883 		 * XXX We could be more clever and use video RAM.
884 		 */
885 		scr1->pcs.mem =
886 		    malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2,
887 		    M_DEVBUF, M_WAITOK);
888 	}
889 
890 	scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
891 	vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
892 
893 	if (vc->nscreens > 1) {
894 		scr->pcs.mem = malloc(type->ncols * type->nrows * 2,
895 		    M_DEVBUF, M_WAITOK);
896 		pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp);
897 	}
898 
899 	*cookiep = scr;
900 	*curxp = scr->pcs.cursorcol;
901 	*curyp = scr->pcs.cursorrow;
902 
903 	return (0);
904 }
905 
906 static void
907 vga_free_screen(void *v, void *cookie)
908 {
909 	struct vgascreen *vs = cookie;
910 	struct vga_config *vc = vs->cfg;
911 
912 	LIST_REMOVE(vs, next);
913 	vc->nscreens--;
914 	if (vs->fontset1)
915 		egavga_unreffont(vc, vs->fontset1);
916 	if (vs->fontset2)
917 		egavga_unreffont(vc, vs->fontset2);
918 
919 	if (vs != &vga_console_screen)
920 		free(vs, M_DEVBUF);
921 	else
922 		panic("vga_free_screen: console");
923 
924 	if (vc->active == vs)
925 		vc->active = 0;
926 }
927 
928 static void vga_usefont(struct vga_config *, struct egavga_font *);
929 
930 static void
931 vga_usefont(struct vga_config *vc, struct egavga_font *f)
932 {
933 	int slot;
934 	struct egavga_font *of;
935 
936 	if (f->slot != -1)
937 		goto toend;
938 
939 	for (slot = 0; slot < vc->vc_nfontslots; slot++) {
940 		if (!vc->vc_fonts[slot])
941 			goto loadit;
942 	}
943 
944 	/* have to kick out another one */
945 	TAILQ_FOREACH(of, &vc->vc_fontlist, next) {
946 		if (of->slot != -1) {
947 			KASSERT(vc->vc_fonts[of->slot] == of);
948 			slot = of->slot;
949 			of->slot = -1;
950 			goto loadit;
951 		}
952 	}
953 	panic("vga_usefont");
954 
955 loadit:
956 	vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar,
957 	    f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data);
958 	f->slot = slot;
959 	vc->vc_fonts[slot] = f;
960 
961 toend:
962 	TAILQ_REMOVE(&vc->vc_fontlist, f, next);
963 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
964 }
965 
966 static void
967 vga_setfont(struct vga_config *vc, struct vgascreen *scr)
968 {
969 	int fontslot1, fontslot2;
970 
971 	if (scr->fontset1)
972 		vga_usefont(vc, scr->fontset1);
973 	if (scr->fontset2)
974 		vga_usefont(vc, scr->fontset2);
975 
976 	fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0);
977 	fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1);
978 	if (vc->currentfontset1 != fontslot1 ||
979 	    vc->currentfontset2 != fontslot2) {
980 		vga_setfontset(&vc->hdl, fontslot1, fontslot2);
981 		vc->currentfontset1 = fontslot1;
982 		vc->currentfontset2 = fontslot2;
983 	}
984 }
985 
986 static int
987 vga_show_screen(void *v, void *cookie, int waitok,
988 		void (*cb)(void *, int, int), void *cbarg)
989 {
990 	struct vgascreen *scr = cookie, *oldscr;
991 	struct vga_config *vc = scr->cfg;
992 
993 	oldscr = vc->active; /* can be NULL! */
994 	if (scr == oldscr) {
995 		return (0);
996 	}
997 
998 	vc->wantedscreen = cookie;
999 	vc->switchcb = cb;
1000 	vc->switchcbarg = cbarg;
1001 	if (cb) {
1002 		callout_reset(&vc->vc_switch_callout, 0,
1003 		    (void(*)(void *))vga_doswitch, vc);
1004 		return (EAGAIN);
1005 	}
1006 
1007 	vga_doswitch(vc);
1008 	return (0);
1009 }
1010 
1011 static void
1012 vga_doswitch(struct vga_config *vc)
1013 {
1014 	struct vgascreen *scr, *oldscr;
1015 	struct vga_handle *vh = &vc->hdl;
1016 	const struct wsscreen_descr *type;
1017 
1018 	scr = vc->wantedscreen;
1019 	if (!scr) {
1020 		printf("vga_doswitch: disappeared\n");
1021 		(*vc->switchcb)(vc->switchcbarg, EIO, 0);
1022 		return;
1023 	}
1024 	type = scr->pcs.type;
1025 	oldscr = vc->active; /* can be NULL! */
1026 #ifdef DIAGNOSTIC
1027 	if (oldscr) {
1028 		if (!oldscr->pcs.active)
1029 			panic("vga_show_screen: not active");
1030 		if (oldscr->pcs.type != vc->currenttype)
1031 			panic("vga_show_screen: bad type");
1032 	}
1033 #endif
1034 	if (scr == oldscr) {
1035 		return;
1036 	}
1037 #ifdef DIAGNOSTIC
1038 	if (scr->pcs.active)
1039 		panic("vga_show_screen: active");
1040 #endif
1041 
1042 	if (oldscr) {
1043 		const struct wsscreen_descr *oldtype = oldscr->pcs.type;
1044 
1045 		oldscr->pcs.active = 0;
1046 		bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
1047 		    oldscr->pcs.dispoffset, oldscr->pcs.mem,
1048 		    oldtype->ncols * oldtype->nrows);
1049 	}
1050 
1051 	if (vc->currenttype != type) {
1052 		vga_setscreentype(vh, type);
1053 		vc->currenttype = type;
1054 	}
1055 
1056 	vga_setfont(vc, scr);
1057 	vga_restore_palette(vc);
1058 
1059 	scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset;
1060 	if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
1061 		vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9);
1062 		vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1);
1063 	}
1064 
1065 	bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
1066 	    scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows);
1067 	scr->pcs.active = 1;
1068 
1069 	vc->active = scr;
1070 
1071 	pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron,
1072 	    scr->pcs.cursorrow, scr->pcs.cursorcol);
1073 
1074 	vc->wantedscreen = 0;
1075 	if (vc->switchcb)
1076 		(*vc->switchcb)(vc->switchcbarg, 0, 0);
1077 }
1078 
1079 static int
1080 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data)
1081 {
1082 	struct vga_config *vc = v;
1083 	struct vgascreen *scr = cookie;
1084 	char *name2;
1085 	int res;
1086 
1087 	if (scr) {
1088 		name2 = NULL;
1089 		if (data->name) {
1090 			name2 = strchr(data->name, ',');
1091 			if (name2)
1092 				*name2++ = '\0';
1093 		}
1094 		res = vga_selectfont(vc, scr, data->name, name2);
1095 		if (!res && scr->pcs.active)
1096 			vga_setfont(vc, scr);
1097 		return (res);
1098 	}
1099 
1100 	return (0);
1101 }
1102 
1103 static int
1104 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1105 {
1106 	struct vgascreen *scr = id;
1107 	struct vga_config *vc = scr->cfg;
1108 
1109 	if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) ||
1110 	    (unsigned int)bg >= sizeof(bgansitopc)))
1111 		return (EINVAL);
1112 
1113 	if (vc->hdl.vh_mono) {
1114 		if (flags & WSATTR_WSCOLORS)
1115 			return (EINVAL);
1116 		if (flags & WSATTR_REVERSE)
1117 			*attrp = 0x70;
1118 		else
1119 			*attrp = 0x07;
1120 		if (flags & WSATTR_UNDERLINE)
1121 			*attrp |= FG_UNDERLINE;
1122 		if (flags & WSATTR_HILIT)
1123 			*attrp |= FG_INTENSE;
1124 	} else {
1125 		if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
1126 			return (EINVAL);
1127 		if (flags & WSATTR_WSCOLORS)
1128 			*attrp = fgansitopc[fg] | bgansitopc[bg];
1129 		else
1130 			*attrp = 7;
1131 		if (flags & WSATTR_HILIT)
1132 			*attrp += 8;
1133 	}
1134 	if (flags & WSATTR_BLINK)
1135 		*attrp |= FG_BLINK;
1136 	return (0);
1137 }
1138 
1139 static void
1140 vga_copyrows(void *id, int srcrow, int dstrow, int nrows)
1141 {
1142 	struct vgascreen *scr = id;
1143 	bus_space_tag_t memt = scr->pcs.hdl->ph_memt;
1144 	bus_space_handle_t memh = scr->pcs.hdl->ph_memh;
1145 	int ncols = scr->pcs.type->ncols;
1146 	bus_size_t srcoff, dstoff;
1147 
1148 	srcoff = srcrow * ncols + 0;
1149 	dstoff = dstrow * ncols + 0;
1150 
1151 	if (scr->pcs.active) {
1152 		if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) {
1153 #ifdef PCDISPLAY_SOFTCURSOR
1154 			int cursoron = scr->pcs.cursoron;
1155 
1156 			if (cursoron)
1157 				pcdisplay_cursor(&scr->pcs, 0,
1158 				    scr->pcs.cursorrow, scr->pcs.cursorcol);
1159 #endif
1160 			/* scroll up whole screen */
1161 			if ((scr->pcs.dispoffset + srcrow * ncols * 2)
1162 			    <= scr->maxdispoffset) {
1163 				scr->pcs.dispoffset += srcrow * ncols * 2;
1164 			} else {
1165 				bus_space_copy_region_2(memt, memh,
1166 				    scr->pcs.dispoffset + srcoff * 2,
1167 				    memh, scr->mindispoffset, nrows * ncols);
1168 				scr->pcs.dispoffset = scr->mindispoffset;
1169 			}
1170 			vga_6845_write(&scr->cfg->hdl, startadrh,
1171 			    scr->pcs.dispoffset >> 9);
1172 			vga_6845_write(&scr->cfg->hdl, startadrl,
1173 			    scr->pcs.dispoffset >> 1);
1174 #ifdef PCDISPLAY_SOFTCURSOR
1175 			if (cursoron)
1176 				pcdisplay_cursor(&scr->pcs, 1,
1177 				    scr->pcs.cursorrow, scr->pcs.cursorcol);
1178 #endif
1179 		} else {
1180 			bus_space_copy_region_2(memt, memh,
1181 			    scr->pcs.dispoffset + srcoff * 2,
1182 			    memh, scr->pcs.dispoffset + dstoff * 2,
1183 			    nrows * ncols);
1184 		}
1185 	} else
1186 		memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff],
1187 		    nrows * ncols * 2);
1188 }
1189 
1190 #ifdef WSCONS_SUPPORT_PCVTFONTS
1191 
1192 #define NOTYET 0xffff
1193 static const uint16_t pcvt_unichars[0xa0] = {
1194 /* 0 */	_e006U, /* N/L control */
1195 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1196 	NOTYET,
1197 	0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */
1198 	0x240a, /* SYMBOL FOR LINE FEED */
1199 	0x240b, /* SYMBOL FOR VERTICAL TABULATION */
1200 	0x240c, /* SYMBOL FOR FORM FEED */
1201 	0x240d, /* SYMBOL FOR CARRIAGE RETURN */
1202 	NOTYET, NOTYET,
1203 /* 1 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1204 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1205 /* 2 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1206 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1207 /* 3 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1208 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1209 /* 4 */	0x03c1, /* GREEK SMALL LETTER RHO */
1210 	0x03c8, /* GREEK SMALL LETTER PSI */
1211 	0x2202, /* PARTIAL DIFFERENTIAL */
1212 	0x03bb, /* GREEK SMALL LETTER LAMDA */
1213 	0x03b9, /* GREEK SMALL LETTER IOTA */
1214 	0x03b7, /* GREEK SMALL LETTER ETA */
1215 	0x03b5, /* GREEK SMALL LETTER EPSILON */
1216 	0x03c7, /* GREEK SMALL LETTER CHI */
1217 	0x2228, /* LOGICAL OR */
1218 	0x2227, /* LOGICAL AND */
1219 	0x222a, /* UNION */
1220 	0x2283, /* SUPERSET OF */
1221 	0x2282, /* SUBSET OF */
1222 	0x03a5, /* GREEK CAPITAL LETTER UPSILON */
1223 	0x039e, /* GREEK CAPITAL LETTER XI */
1224 	0x03a8, /* GREEK CAPITAL LETTER PSI */
1225 /* 5 */	0x03a0, /* GREEK CAPITAL LETTER PI */
1226 	0x21d2, /* RIGHTWARDS DOUBLE ARROW */
1227 	0x21d4, /* LEFT RIGHT DOUBLE ARROW */
1228 	0x039b, /* GREEK CAPITAL LETTER LAMDA */
1229 	0x0398, /* GREEK CAPITAL LETTER THETA */
1230 	0x2243, /* ASYMPTOTICALLY EQUAL TO */
1231 	0x2207, /* NABLA */
1232 	0x2206, /* INCREMENT */
1233 	0x221d, /* PROPORTIONAL TO */
1234 	0x2234, /* THEREFORE */
1235 	0x222b, /* INTEGRAL */
1236 	0x2215, /* DIVISION SLASH */
1237 	0x2216, /* SET MINUS */
1238 	_e00eU, /* angle? */
1239 	_e00dU, /* inverted angle? */
1240 	_e00bU, /* braceleftmid */
1241 /* 6 */	_e00cU, /* bracerightmid */
1242 	_e007U, /* bracelefttp */
1243 	_e008U, /* braceleftbt */
1244 	_e009U, /* bracerighttp */
1245 	_e00aU, /* bracerightbt */
1246 	0x221a, /* SQUARE ROOT */
1247 	0x03c9, /* GREEK SMALL LETTER OMEGA */
1248 	0x00a5, /* YEN SIGN */
1249 	0x03be, /* GREEK SMALL LETTER XI */
1250 	0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */
1251 	0x00fe, /* LATIN SMALL LETTER THORN */
1252 	0x00f0, /* LATIN SMALL LETTER ETH */
1253 	0x00de, /* LATIN CAPITAL LETTER THORN */
1254 	0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
1255 	0x00d7, /* MULTIPLICATION SIGN */
1256 	0x00d0, /* LATIN CAPITAL LETTER ETH */
1257 /* 7 */	0x00be, /* VULGAR FRACTION THREE QUARTERS */
1258 	0x00b8, /* CEDILLA */
1259 	0x00b4, /* ACUTE ACCENT */
1260 	0x00af, /* MACRON */
1261 	0x00ae, /* REGISTERED SIGN */
1262 	0x00ad, /* SOFT HYPHEN */
1263 	0x00ac, /* NOT SIGN */
1264 	0x00a8, /* DIAERESIS */
1265 	0x2260, /* NOT EQUAL TO */
1266 	0x23bd, /* scan 9 */
1267 	0x23bc, /* scan 7 */
1268 	0x2500, /* scan 5 */
1269 	0x23bb, /* scan 3 */
1270 	0x23ba, /* scan 1 */
1271 	0x03c5, /* GREEK SMALL LETTER UPSILON */
1272 	0x00f8, /* LATIN SMALL LETTER O WITH STROKE */
1273 /* 8 */	0x0153, /* LATIN SMALL LIGATURE OE */
1274 	0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */
1275 	0x00e3, /* LATIN SMALL LETTER A WITH TILDE */
1276 	0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1277 	0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1278 	0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
1279 	0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
1280 	0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
1281 	0x0152, /* LATIN CAPITAL LIGATURE OE */
1282 	0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
1283 	0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1284 	0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
1285 	0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
1286 	0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1287 	0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1288 	0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
1289 /* 9 */	0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
1290 	0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1291 	0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1292 	0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
1293 	0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
1294 	0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1295 	0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
1296 	0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
1297 	0x00b9, /* SUPERSCRIPT ONE */
1298 	0x00b7, /* MIDDLE DOT */
1299 	0x03b6, /* GREEK SMALL LETTER ZETA */
1300 	0x00b3, /* SUPERSCRIPT THREE */
1301 	0x00a9, /* COPYRIGHT SIGN */
1302 	0x00a4, /* CURRENCY SIGN */
1303 	0x03ba, /* GREEK SMALL LETTER KAPPA */
1304 	_e000U  /* mirrored question mark? */
1305 };
1306 
1307 static int vga_pcvt_mapchar(int, u_int *);
1308 
1309 static int
1310 vga_pcvt_mapchar(int uni, u_int *index)
1311 {
1312 	int i;
1313 
1314 	for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */
1315 		if (uni == pcvt_unichars[i]) {
1316 			*index = i;
1317 			return (5);
1318 		}
1319 	*index = 0x99; /* middle dot */
1320 	return (0);
1321 }
1322 
1323 #endif /* WSCONS_SUPPORT_PCVTFONTS */
1324 
1325 #ifdef WSCONS_SUPPORT_ISO7FONTS
1326 
1327 static int
1328 vga_iso7_mapchar(int uni, u_int *index)
1329 {
1330 
1331 	/*
1332 	 * U+0384 (GREEK TONOS) to
1333 	 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS)
1334 	 * map directly to the iso-9 font
1335 	 */
1336 	if (uni >= 0x0384 && uni <= 0x03ce) {
1337 		/* U+0384 is at offset 0xb4 in the font */
1338 		*index = uni - 0x0384 + 0xb4;
1339 		return (5);
1340 	}
1341 
1342 	/* XXX more chars in the iso-9 font */
1343 
1344 	*index = 0xa4; /* shaded rectangle */
1345 	return (0);
1346 }
1347 
1348 #endif /* WSCONS_SUPPORT_ISO7FONTS */
1349 
1350 static const uint16_t iso2_unichars[0x60] = {
1351 	0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
1352 	0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
1353 	0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
1354 	0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
1355 	0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
1356 	0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
1357 	0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
1358 	0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
1359 	0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
1360 	0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
1361 	0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
1362 	0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
1363 };
1364 
1365 static const uint16_t koi8_unichars[0x40] = {
1366 	0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
1367 	0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
1368 	0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
1369 	0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
1370 	0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
1371 	0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
1372 	0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
1373 	0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
1374 };
1375 
1376 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *);
1377 
1378 static int
1379 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index)
1380 {
1381 
1382 	switch (font->wsfont->encoding) {
1383 	case WSDISPLAY_FONTENC_ISO:
1384 		if (uni < 256) {
1385 			*index = uni;
1386 			return (5);
1387 		} else {
1388 			*index = ' ';
1389 			return (0);
1390 		}
1391 	case WSDISPLAY_FONTENC_ISO2:
1392 		if (uni < 0xa0) {
1393 			*index = uni;
1394 			return (5);
1395 		} else {
1396 			int i;
1397 			for (i = 0; i < 0x60; i++) {
1398 				if (uni == iso2_unichars[i]) {
1399 					*index = i + 0xa0;
1400 					return (5);
1401 				}
1402 			}
1403 			*index = 0xa4; /* currency sign */
1404 			return (0);
1405 		}
1406 	case WSDISPLAY_FONTENC_KOI8_R:
1407 		if (uni < 0x80) {
1408 			*index = uni;
1409 			return (5);
1410 		} else {
1411 			int i;
1412 			for (i = 0; i < 0x40; i++) {
1413 				if (uni == koi8_unichars[i]) {
1414 					*index = i + 0xc0;
1415 					return (5);
1416 				}
1417 			}
1418 			*index = 0x94; /* box */
1419 			return (0);
1420 		}
1421 	case WSDISPLAY_FONTENC_IBM:
1422 		return (pcdisplay_mapchar(id, uni, index));
1423 #ifdef WSCONS_SUPPORT_PCVTFONTS
1424 	case WSDISPLAY_FONTENC_PCVT:
1425 		return (vga_pcvt_mapchar(uni, index));
1426 #endif
1427 #ifdef WSCONS_SUPPORT_ISO7FONTS
1428 	case WSDISPLAY_FONTENC_ISO7:
1429 		return (vga_iso7_mapchar(uni, index));
1430 #endif
1431 	default:
1432 #ifdef VGAFONTDEBUG
1433 		printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding);
1434 #endif
1435 		*index = ' ';
1436 		return (0);
1437 	}
1438 }
1439 
1440 static int
1441 vga_mapchar(void *id, int uni, u_int *index)
1442 {
1443 	struct vgascreen *scr = id;
1444 	u_int idx1, idx2;
1445 	int res1, res2;
1446 
1447 	res1 = 0;
1448 	idx1 = ' '; /* space */
1449 	if (scr->fontset1)
1450 		res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1);
1451 	res2 = -1;
1452 	if (scr->fontset2) {
1453 		KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type));
1454 		res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2);
1455 	}
1456 	if (res2 > res1) {
1457 		*index = idx2 | 0x0800; /* attribute bit 3 */
1458 		return (res2);
1459 	}
1460 	*index = idx1;
1461 	return (res1);
1462 }
1463 
1464 #ifdef WSDISPLAY_SCROLLSUPPORT
1465 static void
1466 vga_scroll(void *v, void *cookie, int lines)
1467 {
1468 	struct vga_config *vc = v;
1469 	struct vgascreen *scr = cookie;
1470 	struct vga_handle *vh = &vc->hdl;
1471 
1472 	if (lines == 0) {
1473 		if (scr->pcs.visibleoffset == scr->pcs.dispoffset)
1474 			return;
1475 
1476 		scr->pcs.visibleoffset = scr->pcs.dispoffset;
1477 	}
1478 	else {
1479 		int vga_scr_end;
1480 		int margin = scr->pcs.type->ncols * 2;
1481 		int ul, we, p, st;
1482 
1483 		vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols *
1484 		    scr->pcs.type->nrows * 2);
1485 		if (scr->vga_rollover > vga_scr_end + margin) {
1486 			ul = vga_scr_end;
1487 			we = scr->vga_rollover + scr->pcs.type->ncols * 2;
1488 		} else {
1489 			ul = 0;
1490 			we = 0x8000;
1491 		}
1492 		p = (scr->pcs.visibleoffset - ul + we) % we + lines *
1493 		    (scr->pcs.type->ncols * 2);
1494 		st = (scr->pcs.dispoffset - ul + we) % we;
1495 		if (p < margin)
1496 			p = 0;
1497 		if (p > st - margin)
1498 			p = st;
1499 		scr->pcs.visibleoffset = (p + ul) % we;
1500 	}
1501 
1502 	vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9);
1503 	vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1);
1504 }
1505 #endif
1506 
1507 static void
1508 vga_putchar(void *c, int row, int col, u_int uc, long attr)
1509 {
1510 
1511 	pcdisplay_putchar(c, row, col, uc, attr);
1512 }
1513 
1514 #ifdef WSDISPLAY_CUSTOM_BORDER
1515 static int
1516 vga_getborder(struct vga_config *vc, u_int *valuep)
1517 {
1518 	struct vga_handle *vh = &vc->hdl;
1519 	u_int idx;
1520 	uint8_t value;
1521 
1522 	if (vh->vh_mono)
1523 		return ENODEV;
1524 
1525 	value = _vga_attr_read(vh, VGA_ATC_OVERSCAN);
1526 	for (idx = 0; idx < sizeof(fgansitopc); idx++) {
1527 		if (fgansitopc[idx] == value) {
1528 			*valuep = idx;
1529 			return (0);
1530 		}
1531 	}
1532 	return (EIO);
1533 }
1534 
1535 static int
1536 vga_setborder(struct vga_config *vc, u_int value)
1537 {
1538 	struct vga_handle *vh = &vc->hdl;
1539 
1540 	if (vh->vh_mono)
1541 		return ENODEV;
1542 	if (value >= sizeof(fgansitopc))
1543 		return EINVAL;
1544 
1545 	_vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]);
1546 	return (0);
1547 }
1548 #endif /* WSDISPLAY_CUSTOM_BORDER */
1549 
1550 void
1551 vga_resume(struct vga_softc *sc)
1552 {
1553 #ifdef VGA_RESET_ON_RESUME
1554 	vga_initregs(&sc->sc_vc->hdl);
1555 #endif
1556 #ifdef PCDISPLAY_SOFTCURSOR
1557 	/* Disable the hardware cursor */
1558 	vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20);
1559 	vga_6845_write(&sc->sc_vc->hdl, curend, 0x00);
1560 #endif
1561 }
1562 
1563 static void
1564 vga_save_palette(struct vga_config *vc)
1565 {
1566 	struct vga_handle *vh = &vc->hdl;
1567 	size_t i;
1568 	uint8_t *palette = vc->palette;
1569 
1570 	if (vh->vh_mono)
1571 		return;
1572 
1573 	vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
1574 	vga_raw_write(vh, VGA_DAC_ADDRR, 0x00);
1575 	for (i = 0; i < sizeof(vc->palette); i++)
1576 		*palette++ = vga_raw_read(vh, VGA_DAC_PALETTE);
1577 
1578 	vga_reset_state(vh);			/* reset flip/flop */
1579 }
1580 
1581 static void
1582 vga_restore_palette(struct vga_config *vc)
1583 {
1584 	struct vga_handle *vh = &vc->hdl;
1585 	size_t i;
1586 	uint8_t *palette = vc->palette;
1587 
1588 	if (vh->vh_mono)
1589 		return;
1590 
1591 	vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
1592 	vga_raw_write(vh, VGA_DAC_ADDRW, 0x00);
1593 	for (i = 0; i < sizeof(vc->palette); i++)
1594 		vga_raw_write(vh, VGA_DAC_PALETTE, *palette++);
1595 
1596 	vga_reset_state(vh);			/* reset flip/flop */
1597 	vga_enable(vh);
1598 }
1599