xref: /netbsd-src/sys/dev/ic/vga.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /* $NetBSD: vga.c,v 1.118 2020/04/24 22:31:35 ad 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.118 2020/04/24 22:31:35 ad 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_ia(sc->sc_dev, "wsemuldisplaydev", &aa, wsemuldisplaydevprint);
661 }
662 
663 int
664 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
665 {
666 	long defattr;
667 	const struct wsscreen_descr *scr;
668 
669 	if (check && !vga_common_probe(iot, memt))
670 		return (ENXIO);
671 
672 	/* set up bus-independent VGA configuration */
673 	vga_init(&vga_console_vc, iot, memt);
674 #ifdef VGA_CONSOLE_SCREENTYPE
675 	scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
676 	    &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
677 	if (!scr)
678 		panic("vga_cnattach: invalid screen type");
679 #else
680 	scr = vga_console_vc.currenttype;
681 #endif
682 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
683 	/*
684 	 * On some (most/all?) ATI cards, only font slot 0 is usable.
685 	 * vga_init_screen() might need font slot 0 for a non-default
686 	 * console font, so save the builtin VGA font to another font slot.
687 	 * The attach() code will take care later.
688 	 */
689 	vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */
690 	vga_copyfont01(&vga_console_vc.hdl);
691 	vga_console_vc.vc_nfontslots = 1;
692 #else
693 	vga_console_vc.vc_nfontslots = 8;
694 #endif
695 #ifdef notdef
696 	/* until we know better, assume "fast scrolling" does not work */
697 	vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL;
698 #endif
699 
700 	vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr);
701 
702 	wsdisplay_cnattach(scr, &vga_console_screen,
703 	    vga_console_screen.pcs.cursorcol,
704 	    vga_console_screen.pcs.cursorrow, defattr);
705 
706 	vgaconsole = 1;
707 	vga_console_type = type;
708 	return (0);
709 }
710 
711 int
712 vga_cndetach(void)
713 {
714 	struct vga_config *vc;
715 	struct vga_handle *vh;
716 
717 	vc = &vga_console_vc;
718 	vh = &vc->hdl;
719 
720 	if (vgaconsole) {
721 		wsdisplay_cndetach();
722 
723 		bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
724 		bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
725 		bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000);
726 
727 		vga_console_attached = 0;
728 		vgaconsole = 0;
729 
730 		return 1;
731 	}
732 
733 	return 0;
734 }
735 
736 int
737 vga_is_console(bus_space_tag_t iot, int type)
738 {
739 	if (vgaconsole &&
740 	    !vga_console_attached &&
741 	    bus_space_is_equal(iot, vga_console_vc.hdl.vh_iot) &&
742 	    (vga_console_type == -1 || (type == vga_console_type)))
743 		return (1);
744 	return (0);
745 }
746 
747 static int
748 vga_get_video(struct vga_config *vc)
749 {
750 
751 	return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0;
752 }
753 
754 static void
755 vga_set_video(struct vga_config *vc, int state)
756 {
757 	int val;
758 
759 	vga_ts_write(&vc->hdl, syncreset, 0x01);
760 	if (state) {					/* unblank screen */
761 		val = vga_ts_read(&vc->hdl, mode);
762 		vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK);
763 #ifndef VGA_NO_VBLANK
764 		val = vga_6845_read(&vc->hdl, mode);
765 		vga_6845_write(&vc->hdl, mode, val | 0x80);
766 #endif
767 	} else {					/* blank screen */
768 		val = vga_ts_read(&vc->hdl, mode);
769 		vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK);
770 #ifndef VGA_NO_VBLANK
771 		val = vga_6845_read(&vc->hdl, mode);
772 		vga_6845_write(&vc->hdl, mode, val & ~0x80);
773 #endif
774 	}
775 	vga_ts_write(&vc->hdl, syncreset, 0x03);
776 }
777 
778 static int
779 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
780 {
781 	struct vga_config *vc = v;
782 	struct vgascreen *scr = vs;
783 	const struct vga_funcs *vf = vc->vc_funcs;
784 
785 	switch (cmd) {
786 	case WSDISPLAYIO_SMODE:
787 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
788 			vga_restore_palette(vc);
789 		return 0;
790 
791 	case WSDISPLAYIO_GTYPE:
792 		*(int *)data = vc->vc_type;
793 		return 0;
794 
795 	case WSDISPLAYIO_GINFO:
796 		/* XXX should get detailed hardware information here */
797 		return EPASSTHROUGH;
798 
799 	case WSDISPLAYIO_GVIDEO:
800 		*(int *)data = (vga_get_video(vc) ?
801 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF);
802 		return 0;
803 
804 	case WSDISPLAYIO_SVIDEO:
805 		vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
806 		return 0;
807 
808 	case WSDISPLAYIO_GETWSCHAR:
809 		KASSERT(scr != NULL);
810 		return pcdisplay_getwschar(&scr->pcs,
811 		    (struct wsdisplay_char *)data);
812 
813 	case WSDISPLAYIO_PUTWSCHAR:
814 		KASSERT(scr != NULL);
815 		return pcdisplay_putwschar(&scr->pcs,
816 		    (struct wsdisplay_char *)data);
817 
818 #ifdef WSDISPLAY_CUSTOM_BORDER
819 	case WSDISPLAYIO_GBORDER:
820 		return (vga_getborder(vc, (u_int *)data));
821 
822 	case WSDISPLAYIO_SBORDER:
823 		return (vga_setborder(vc, *(u_int *)data));
824 #endif
825 
826 	case WSDISPLAYIO_GETCMAP:
827 	case WSDISPLAYIO_PUTCMAP:
828 	case WSDISPLAYIO_GCURPOS:
829 	case WSDISPLAYIO_SCURPOS:
830 	case WSDISPLAYIO_GCURMAX:
831 	case WSDISPLAYIO_GCURSOR:
832 	case WSDISPLAYIO_SCURSOR:
833 		/* NONE of these operations are by the generic VGA driver. */
834 		return EPASSTHROUGH;
835 	}
836 
837 	if (vc->vc_funcs == NULL)
838 		return (EPASSTHROUGH);
839 
840 	if (vf->vf_ioctl == NULL)
841 		return (EPASSTHROUGH);
842 
843 	return ((*vf->vf_ioctl)(v, cmd, data, flag, l));
844 }
845 
846 static paddr_t
847 vga_mmap(void *v, void *vs, off_t offset, int prot)
848 {
849 	struct vga_config *vc = v;
850 	const struct vga_funcs *vf = vc->vc_funcs;
851 
852 	if (vc->vc_funcs == NULL)
853 		return (-1);
854 
855 	if (vf->vf_mmap == NULL)
856 		return (-1);
857 
858 	return ((*vf->vf_mmap)(v, offset, prot));
859 }
860 
861 static int
862 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
863 		 int *curxp, int *curyp, long *defattrp)
864 {
865 	struct vga_config *vc = v;
866 	struct vgascreen *scr;
867 
868 	if (vc->nscreens == 1) {
869 		struct vgascreen *scr1 = vc->screens.lh_first;
870 		/*
871 		 * When allocating the second screen, get backing store
872 		 * for the first one too.
873 		 * XXX We could be more clever and use video RAM.
874 		 */
875 		scr1->pcs.mem =
876 		    malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2,
877 		    M_DEVBUF, M_WAITOK);
878 	}
879 
880 	scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
881 	vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
882 
883 	if (vc->nscreens > 1) {
884 		scr->pcs.mem = malloc(type->ncols * type->nrows * 2,
885 		    M_DEVBUF, M_WAITOK);
886 		pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp);
887 	}
888 
889 	*cookiep = scr;
890 	*curxp = scr->pcs.cursorcol;
891 	*curyp = scr->pcs.cursorrow;
892 
893 	return (0);
894 }
895 
896 static void
897 vga_free_screen(void *v, void *cookie)
898 {
899 	struct vgascreen *vs = cookie;
900 	struct vga_config *vc = vs->cfg;
901 
902 	LIST_REMOVE(vs, next);
903 	vc->nscreens--;
904 	if (vs->fontset1)
905 		egavga_unreffont(vc, vs->fontset1);
906 	if (vs->fontset2)
907 		egavga_unreffont(vc, vs->fontset2);
908 
909 	if (vs != &vga_console_screen)
910 		free(vs, M_DEVBUF);
911 	else
912 		panic("vga_free_screen: console");
913 
914 	if (vc->active == vs)
915 		vc->active = 0;
916 }
917 
918 static void vga_usefont(struct vga_config *, struct egavga_font *);
919 
920 static void
921 vga_usefont(struct vga_config *vc, struct egavga_font *f)
922 {
923 	int slot;
924 	struct egavga_font *of;
925 
926 	if (f->slot != -1)
927 		goto toend;
928 
929 	for (slot = 0; slot < vc->vc_nfontslots; slot++) {
930 		if (!vc->vc_fonts[slot])
931 			goto loadit;
932 	}
933 
934 	/* have to kick out another one */
935 	TAILQ_FOREACH(of, &vc->vc_fontlist, next) {
936 		if (of->slot != -1) {
937 			KASSERT(vc->vc_fonts[of->slot] == of);
938 			slot = of->slot;
939 			of->slot = -1;
940 			goto loadit;
941 		}
942 	}
943 	panic("vga_usefont");
944 
945 loadit:
946 	vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar,
947 	    f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data);
948 	f->slot = slot;
949 	vc->vc_fonts[slot] = f;
950 
951 toend:
952 	TAILQ_REMOVE(&vc->vc_fontlist, f, next);
953 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
954 }
955 
956 static void
957 vga_setfont(struct vga_config *vc, struct vgascreen *scr)
958 {
959 	int fontslot1, fontslot2;
960 
961 	if (scr->fontset1)
962 		vga_usefont(vc, scr->fontset1);
963 	if (scr->fontset2)
964 		vga_usefont(vc, scr->fontset2);
965 
966 	fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0);
967 	fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1);
968 	if (vc->currentfontset1 != fontslot1 ||
969 	    vc->currentfontset2 != fontslot2) {
970 		vga_setfontset(&vc->hdl, fontslot1, fontslot2);
971 		vc->currentfontset1 = fontslot1;
972 		vc->currentfontset2 = fontslot2;
973 	}
974 }
975 
976 static int
977 vga_show_screen(void *v, void *cookie, int waitok,
978 		void (*cb)(void *, int, int), void *cbarg)
979 {
980 	struct vgascreen *scr = cookie, *oldscr;
981 	struct vga_config *vc = scr->cfg;
982 
983 	oldscr = vc->active; /* can be NULL! */
984 	if (scr == oldscr) {
985 		return (0);
986 	}
987 
988 	vc->wantedscreen = cookie;
989 	vc->switchcb = cb;
990 	vc->switchcbarg = cbarg;
991 	if (cb) {
992 		callout_reset(&vc->vc_switch_callout, 0,
993 		    (void(*)(void *))vga_doswitch, vc);
994 		return (EAGAIN);
995 	}
996 
997 	vga_doswitch(vc);
998 	return (0);
999 }
1000 
1001 static void
1002 vga_doswitch(struct vga_config *vc)
1003 {
1004 	struct vgascreen *scr, *oldscr;
1005 	struct vga_handle *vh = &vc->hdl;
1006 	const struct wsscreen_descr *type;
1007 
1008 	scr = vc->wantedscreen;
1009 	if (!scr) {
1010 		printf("vga_doswitch: disappeared\n");
1011 		(*vc->switchcb)(vc->switchcbarg, EIO, 0);
1012 		return;
1013 	}
1014 	type = scr->pcs.type;
1015 	oldscr = vc->active; /* can be NULL! */
1016 #ifdef DIAGNOSTIC
1017 	if (oldscr) {
1018 		if (!oldscr->pcs.active)
1019 			panic("vga_show_screen: not active");
1020 		if (oldscr->pcs.type != vc->currenttype)
1021 			panic("vga_show_screen: bad type");
1022 	}
1023 #endif
1024 	if (scr == oldscr) {
1025 		return;
1026 	}
1027 #ifdef DIAGNOSTIC
1028 	if (scr->pcs.active)
1029 		panic("vga_show_screen: active");
1030 #endif
1031 
1032 	if (oldscr) {
1033 		const struct wsscreen_descr *oldtype = oldscr->pcs.type;
1034 
1035 		oldscr->pcs.active = 0;
1036 		bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
1037 		    oldscr->pcs.dispoffset, oldscr->pcs.mem,
1038 		    oldtype->ncols * oldtype->nrows);
1039 	}
1040 
1041 	if (vc->currenttype != type) {
1042 		vga_setscreentype(vh, type);
1043 		vc->currenttype = type;
1044 	}
1045 
1046 	vga_setfont(vc, scr);
1047 	vga_restore_palette(vc);
1048 
1049 	scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset;
1050 	if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
1051 		vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9);
1052 		vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1);
1053 	}
1054 
1055 	bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
1056 	    scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows);
1057 	scr->pcs.active = 1;
1058 
1059 	vc->active = scr;
1060 
1061 	pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron,
1062 	    scr->pcs.cursorrow, scr->pcs.cursorcol);
1063 
1064 	vc->wantedscreen = 0;
1065 	if (vc->switchcb)
1066 		(*vc->switchcb)(vc->switchcbarg, 0, 0);
1067 }
1068 
1069 static int
1070 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data)
1071 {
1072 	struct vga_config *vc = v;
1073 	struct vgascreen *scr = cookie;
1074 	char *name2;
1075 	int res;
1076 
1077 	if (scr) {
1078 		name2 = NULL;
1079 		if (data->name) {
1080 			name2 = strchr(data->name, ',');
1081 			if (name2)
1082 				*name2++ = '\0';
1083 		}
1084 		res = vga_selectfont(vc, scr, data->name, name2);
1085 		if (!res && scr->pcs.active)
1086 			vga_setfont(vc, scr);
1087 		return (res);
1088 	}
1089 
1090 	return (0);
1091 }
1092 
1093 static int
1094 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1095 {
1096 	struct vgascreen *scr = id;
1097 	struct vga_config *vc = scr->cfg;
1098 
1099 	if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) ||
1100 	    (unsigned int)bg >= sizeof(bgansitopc)))
1101 		return (EINVAL);
1102 
1103 	if (vc->hdl.vh_mono) {
1104 		if (flags & WSATTR_WSCOLORS)
1105 			return (EINVAL);
1106 		if (flags & WSATTR_REVERSE)
1107 			*attrp = 0x70;
1108 		else
1109 			*attrp = 0x07;
1110 		if (flags & WSATTR_UNDERLINE)
1111 			*attrp |= FG_UNDERLINE;
1112 		if (flags & WSATTR_HILIT)
1113 			*attrp |= FG_INTENSE;
1114 	} else {
1115 		if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
1116 			return (EINVAL);
1117 		if (flags & WSATTR_WSCOLORS)
1118 			*attrp = fgansitopc[fg] | bgansitopc[bg];
1119 		else
1120 			*attrp = 7;
1121 		if (flags & WSATTR_HILIT)
1122 			*attrp += 8;
1123 	}
1124 	if (flags & WSATTR_BLINK)
1125 		*attrp |= FG_BLINK;
1126 	return (0);
1127 }
1128 
1129 static void
1130 vga_copyrows(void *id, int srcrow, int dstrow, int nrows)
1131 {
1132 	struct vgascreen *scr = id;
1133 	bus_space_tag_t memt = scr->pcs.hdl->ph_memt;
1134 	bus_space_handle_t memh = scr->pcs.hdl->ph_memh;
1135 	int ncols = scr->pcs.type->ncols;
1136 	bus_size_t srcoff, dstoff;
1137 
1138 	srcoff = srcrow * ncols + 0;
1139 	dstoff = dstrow * ncols + 0;
1140 
1141 	if (scr->pcs.active) {
1142 		if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) {
1143 #ifdef PCDISPLAY_SOFTCURSOR
1144 			int cursoron = scr->pcs.cursoron;
1145 
1146 			if (cursoron)
1147 				pcdisplay_cursor(&scr->pcs, 0,
1148 				    scr->pcs.cursorrow, scr->pcs.cursorcol);
1149 #endif
1150 			/* scroll up whole screen */
1151 			if ((scr->pcs.dispoffset + srcrow * ncols * 2)
1152 			    <= scr->maxdispoffset) {
1153 				scr->pcs.dispoffset += srcrow * ncols * 2;
1154 			} else {
1155 				bus_space_copy_region_2(memt, memh,
1156 				    scr->pcs.dispoffset + srcoff * 2,
1157 				    memh, scr->mindispoffset, nrows * ncols);
1158 				scr->pcs.dispoffset = scr->mindispoffset;
1159 			}
1160 			vga_6845_write(&scr->cfg->hdl, startadrh,
1161 			    scr->pcs.dispoffset >> 9);
1162 			vga_6845_write(&scr->cfg->hdl, startadrl,
1163 			    scr->pcs.dispoffset >> 1);
1164 #ifdef PCDISPLAY_SOFTCURSOR
1165 			if (cursoron)
1166 				pcdisplay_cursor(&scr->pcs, 1,
1167 				    scr->pcs.cursorrow, scr->pcs.cursorcol);
1168 #endif
1169 		} else {
1170 			bus_space_copy_region_2(memt, memh,
1171 			    scr->pcs.dispoffset + srcoff * 2,
1172 			    memh, scr->pcs.dispoffset + dstoff * 2,
1173 			    nrows * ncols);
1174 		}
1175 	} else
1176 		memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff],
1177 		    nrows * ncols * 2);
1178 }
1179 
1180 #ifdef WSCONS_SUPPORT_PCVTFONTS
1181 
1182 #define NOTYET 0xffff
1183 static const uint16_t pcvt_unichars[0xa0] = {
1184 /* 0 */	_e006U, /* N/L control */
1185 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1186 	NOTYET,
1187 	0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */
1188 	0x240a, /* SYMBOL FOR LINE FEED */
1189 	0x240b, /* SYMBOL FOR VERTICAL TABULATION */
1190 	0x240c, /* SYMBOL FOR FORM FEED */
1191 	0x240d, /* SYMBOL FOR CARRIAGE RETURN */
1192 	NOTYET, NOTYET,
1193 /* 1 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1194 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1195 /* 2 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1196 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1197 /* 3 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1198 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1199 /* 4 */	0x03c1, /* GREEK SMALL LETTER RHO */
1200 	0x03c8, /* GREEK SMALL LETTER PSI */
1201 	0x2202, /* PARTIAL DIFFERENTIAL */
1202 	0x03bb, /* GREEK SMALL LETTER LAMDA */
1203 	0x03b9, /* GREEK SMALL LETTER IOTA */
1204 	0x03b7, /* GREEK SMALL LETTER ETA */
1205 	0x03b5, /* GREEK SMALL LETTER EPSILON */
1206 	0x03c7, /* GREEK SMALL LETTER CHI */
1207 	0x2228, /* LOGICAL OR */
1208 	0x2227, /* LOGICAL AND */
1209 	0x222a, /* UNION */
1210 	0x2283, /* SUPERSET OF */
1211 	0x2282, /* SUBSET OF */
1212 	0x03a5, /* GREEK CAPITAL LETTER UPSILON */
1213 	0x039e, /* GREEK CAPITAL LETTER XI */
1214 	0x03a8, /* GREEK CAPITAL LETTER PSI */
1215 /* 5 */	0x03a0, /* GREEK CAPITAL LETTER PI */
1216 	0x21d2, /* RIGHTWARDS DOUBLE ARROW */
1217 	0x21d4, /* LEFT RIGHT DOUBLE ARROW */
1218 	0x039b, /* GREEK CAPITAL LETTER LAMDA */
1219 	0x0398, /* GREEK CAPITAL LETTER THETA */
1220 	0x2243, /* ASYMPTOTICALLY EQUAL TO */
1221 	0x2207, /* NABLA */
1222 	0x2206, /* INCREMENT */
1223 	0x221d, /* PROPORTIONAL TO */
1224 	0x2234, /* THEREFORE */
1225 	0x222b, /* INTEGRAL */
1226 	0x2215, /* DIVISION SLASH */
1227 	0x2216, /* SET MINUS */
1228 	_e00eU, /* angle? */
1229 	_e00dU, /* inverted angle? */
1230 	_e00bU, /* braceleftmid */
1231 /* 6 */	_e00cU, /* bracerightmid */
1232 	_e007U, /* bracelefttp */
1233 	_e008U, /* braceleftbt */
1234 	_e009U, /* bracerighttp */
1235 	_e00aU, /* bracerightbt */
1236 	0x221a, /* SQUARE ROOT */
1237 	0x03c9, /* GREEK SMALL LETTER OMEGA */
1238 	0x00a5, /* YEN SIGN */
1239 	0x03be, /* GREEK SMALL LETTER XI */
1240 	0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */
1241 	0x00fe, /* LATIN SMALL LETTER THORN */
1242 	0x00f0, /* LATIN SMALL LETTER ETH */
1243 	0x00de, /* LATIN CAPITAL LETTER THORN */
1244 	0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
1245 	0x00d7, /* MULTIPLICATION SIGN */
1246 	0x00d0, /* LATIN CAPITAL LETTER ETH */
1247 /* 7 */	0x00be, /* VULGAR FRACTION THREE QUARTERS */
1248 	0x00b8, /* CEDILLA */
1249 	0x00b4, /* ACUTE ACCENT */
1250 	0x00af, /* MACRON */
1251 	0x00ae, /* REGISTERED SIGN */
1252 	0x00ad, /* SOFT HYPHEN */
1253 	0x00ac, /* NOT SIGN */
1254 	0x00a8, /* DIAERESIS */
1255 	0x2260, /* NOT EQUAL TO */
1256 	0x23bd, /* scan 9 */
1257 	0x23bc, /* scan 7 */
1258 	0x2500, /* scan 5 */
1259 	0x23bb, /* scan 3 */
1260 	0x23ba, /* scan 1 */
1261 	0x03c5, /* GREEK SMALL LETTER UPSILON */
1262 	0x00f8, /* LATIN SMALL LETTER O WITH STROKE */
1263 /* 8 */	0x0153, /* LATIN SMALL LIGATURE OE */
1264 	0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */
1265 	0x00e3, /* LATIN SMALL LETTER A WITH TILDE */
1266 	0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1267 	0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1268 	0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
1269 	0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
1270 	0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
1271 	0x0152, /* LATIN CAPITAL LIGATURE OE */
1272 	0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
1273 	0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1274 	0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
1275 	0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
1276 	0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1277 	0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1278 	0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
1279 /* 9 */	0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
1280 	0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1281 	0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1282 	0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
1283 	0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
1284 	0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1285 	0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
1286 	0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
1287 	0x00b9, /* SUPERSCRIPT ONE */
1288 	0x00b7, /* MIDDLE DOT */
1289 	0x03b6, /* GREEK SMALL LETTER ZETA */
1290 	0x00b3, /* SUPERSCRIPT THREE */
1291 	0x00a9, /* COPYRIGHT SIGN */
1292 	0x00a4, /* CURRENCY SIGN */
1293 	0x03ba, /* GREEK SMALL LETTER KAPPA */
1294 	_e000U  /* mirrored question mark? */
1295 };
1296 
1297 static int vga_pcvt_mapchar(int, u_int *);
1298 
1299 static int
1300 vga_pcvt_mapchar(int uni, u_int *index)
1301 {
1302 	int i;
1303 
1304 	for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */
1305 		if (uni == pcvt_unichars[i]) {
1306 			*index = i;
1307 			return (5);
1308 		}
1309 	*index = 0x99; /* middle dot */
1310 	return (0);
1311 }
1312 
1313 #endif /* WSCONS_SUPPORT_PCVTFONTS */
1314 
1315 #ifdef WSCONS_SUPPORT_ISO7FONTS
1316 
1317 static int
1318 vga_iso7_mapchar(int uni, u_int *index)
1319 {
1320 
1321 	/*
1322 	 * U+0384 (GREEK TONOS) to
1323 	 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS)
1324 	 * map directly to the iso-9 font
1325 	 */
1326 	if (uni >= 0x0384 && uni <= 0x03ce) {
1327 		/* U+0384 is at offset 0xb4 in the font */
1328 		*index = uni - 0x0384 + 0xb4;
1329 		return (5);
1330 	}
1331 
1332 	/* XXX more chars in the iso-9 font */
1333 
1334 	*index = 0xa4; /* shaded rectangle */
1335 	return (0);
1336 }
1337 
1338 #endif /* WSCONS_SUPPORT_ISO7FONTS */
1339 
1340 static const uint16_t iso2_unichars[0x60] = {
1341 	0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
1342 	0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
1343 	0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
1344 	0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
1345 	0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
1346 	0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
1347 	0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
1348 	0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
1349 	0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
1350 	0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
1351 	0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
1352 	0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
1353 };
1354 
1355 static const uint16_t koi8_unichars[0x40] = {
1356 	0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
1357 	0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
1358 	0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
1359 	0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
1360 	0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
1361 	0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
1362 	0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
1363 	0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
1364 };
1365 
1366 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *);
1367 
1368 static int
1369 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index)
1370 {
1371 
1372 	switch (font->wsfont->encoding) {
1373 	case WSDISPLAY_FONTENC_ISO:
1374 		if (uni < 256) {
1375 			*index = uni;
1376 			return (5);
1377 		} else {
1378 			*index = ' ';
1379 			return (0);
1380 		}
1381 	case WSDISPLAY_FONTENC_ISO2:
1382 		if (uni < 0xa0) {
1383 			*index = uni;
1384 			return (5);
1385 		} else {
1386 			int i;
1387 			for (i = 0; i < 0x60; i++) {
1388 				if (uni == iso2_unichars[i]) {
1389 					*index = i + 0xa0;
1390 					return (5);
1391 				}
1392 			}
1393 			*index = 0xa4; /* currency sign */
1394 			return (0);
1395 		}
1396 	case WSDISPLAY_FONTENC_KOI8_R:
1397 		if (uni < 0x80) {
1398 			*index = uni;
1399 			return (5);
1400 		} else {
1401 			int i;
1402 			for (i = 0; i < 0x40; i++) {
1403 				if (uni == koi8_unichars[i]) {
1404 					*index = i + 0xc0;
1405 					return (5);
1406 				}
1407 			}
1408 			*index = 0x94; /* box */
1409 			return (0);
1410 		}
1411 	case WSDISPLAY_FONTENC_IBM:
1412 		return (pcdisplay_mapchar(id, uni, index));
1413 #ifdef WSCONS_SUPPORT_PCVTFONTS
1414 	case WSDISPLAY_FONTENC_PCVT:
1415 		return (vga_pcvt_mapchar(uni, index));
1416 #endif
1417 #ifdef WSCONS_SUPPORT_ISO7FONTS
1418 	case WSDISPLAY_FONTENC_ISO7:
1419 		return (vga_iso7_mapchar(uni, index));
1420 #endif
1421 	default:
1422 #ifdef VGAFONTDEBUG
1423 		printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding);
1424 #endif
1425 		*index = ' ';
1426 		return (0);
1427 	}
1428 }
1429 
1430 static int
1431 vga_mapchar(void *id, int uni, u_int *index)
1432 {
1433 	struct vgascreen *scr = id;
1434 	u_int idx1, idx2;
1435 	int res1, res2;
1436 
1437 	res1 = 0;
1438 	idx1 = ' '; /* space */
1439 	if (scr->fontset1)
1440 		res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1);
1441 	res2 = -1;
1442 	if (scr->fontset2) {
1443 		KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type));
1444 		res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2);
1445 	}
1446 	if (res2 > res1) {
1447 		*index = idx2 | 0x0800; /* attribute bit 3 */
1448 		return (res2);
1449 	}
1450 	*index = idx1;
1451 	return (res1);
1452 }
1453 
1454 #ifdef WSDISPLAY_SCROLLSUPPORT
1455 static void
1456 vga_scroll(void *v, void *cookie, int lines)
1457 {
1458 	struct vga_config *vc = v;
1459 	struct vgascreen *scr = cookie;
1460 	struct vga_handle *vh = &vc->hdl;
1461 
1462 	if (lines == 0) {
1463 		if (scr->pcs.visibleoffset == scr->pcs.dispoffset)
1464 			return;
1465 
1466 		scr->pcs.visibleoffset = scr->pcs.dispoffset;
1467 	}
1468 	else {
1469 		int vga_scr_end;
1470 		int margin = scr->pcs.type->ncols * 2;
1471 		int ul, we, p, st;
1472 
1473 		vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols *
1474 		    scr->pcs.type->nrows * 2);
1475 		if (scr->vga_rollover > vga_scr_end + margin) {
1476 			ul = vga_scr_end;
1477 			we = scr->vga_rollover + scr->pcs.type->ncols * 2;
1478 		} else {
1479 			ul = 0;
1480 			we = 0x8000;
1481 		}
1482 		p = (scr->pcs.visibleoffset - ul + we) % we + lines *
1483 		    (scr->pcs.type->ncols * 2);
1484 		st = (scr->pcs.dispoffset - ul + we) % we;
1485 		if (p < margin)
1486 			p = 0;
1487 		if (p > st - margin)
1488 			p = st;
1489 		scr->pcs.visibleoffset = (p + ul) % we;
1490 	}
1491 
1492 	vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9);
1493 	vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1);
1494 }
1495 #endif
1496 
1497 static void
1498 vga_putchar(void *c, int row, int col, u_int uc, long attr)
1499 {
1500 
1501 	pcdisplay_putchar(c, row, col, uc, attr);
1502 }
1503 
1504 #ifdef WSDISPLAY_CUSTOM_BORDER
1505 static int
1506 vga_getborder(struct vga_config *vc, u_int *valuep)
1507 {
1508 	struct vga_handle *vh = &vc->hdl;
1509 	u_int idx;
1510 	uint8_t value;
1511 
1512 	if (vh->vh_mono)
1513 		return ENODEV;
1514 
1515 	value = _vga_attr_read(vh, VGA_ATC_OVERSCAN);
1516 	for (idx = 0; idx < sizeof(fgansitopc); idx++) {
1517 		if (fgansitopc[idx] == value) {
1518 			*valuep = idx;
1519 			return (0);
1520 		}
1521 	}
1522 	return (EIO);
1523 }
1524 
1525 static int
1526 vga_setborder(struct vga_config *vc, u_int value)
1527 {
1528 	struct vga_handle *vh = &vc->hdl;
1529 
1530 	if (vh->vh_mono)
1531 		return ENODEV;
1532 	if (value >= sizeof(fgansitopc))
1533 		return EINVAL;
1534 
1535 	_vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]);
1536 	return (0);
1537 }
1538 #endif /* WSDISPLAY_CUSTOM_BORDER */
1539 
1540 void
1541 vga_resume(struct vga_softc *sc)
1542 {
1543 #ifdef VGA_RESET_ON_RESUME
1544 	vga_initregs(&sc->sc_vc->hdl);
1545 #endif
1546 #ifdef PCDISPLAY_SOFTCURSOR
1547 	/* Disable the hardware cursor */
1548 	vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20);
1549 	vga_6845_write(&sc->sc_vc->hdl, curend, 0x00);
1550 #endif
1551 }
1552 
1553 static void
1554 vga_save_palette(struct vga_config *vc)
1555 {
1556 	struct vga_handle *vh = &vc->hdl;
1557 	size_t i;
1558 	uint8_t *palette = vc->palette;
1559 
1560 	if (vh->vh_mono)
1561 		return;
1562 
1563 	vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
1564 	vga_raw_write(vh, VGA_DAC_ADDRR, 0x00);
1565 	for (i = 0; i < sizeof(vc->palette); i++)
1566 		*palette++ = vga_raw_read(vh, VGA_DAC_PALETTE);
1567 
1568 	vga_reset_state(vh);			/* reset flip/flop */
1569 }
1570 
1571 static void
1572 vga_restore_palette(struct vga_config *vc)
1573 {
1574 	struct vga_handle *vh = &vc->hdl;
1575 	size_t i;
1576 	uint8_t *palette = vc->palette;
1577 
1578 	if (vh->vh_mono)
1579 		return;
1580 
1581 	vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
1582 	vga_raw_write(vh, VGA_DAC_ADDRW, 0x00);
1583 	for (i = 0; i < sizeof(vc->palette); i++)
1584 		vga_raw_write(vh, VGA_DAC_PALETTE, *palette++);
1585 
1586 	vga_reset_state(vh);			/* reset flip/flop */
1587 	vga_enable(vh);
1588 }
1589