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