xref: /netbsd-src/sys/dev/ic/vga.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /* $NetBSD: vga.c,v 1.44 2001/12/02 12:46:32 bjh21 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.44 2001/12/02 12:46:32 bjh21 Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/callout.h>
36 #include <sys/kernel.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/queue.h>
40 #include <machine/bus.h>
41 
42 #include <dev/ic/mc6845reg.h>
43 #include <dev/ic/pcdisplayvar.h>
44 #include <dev/ic/vgareg.h>
45 #include <dev/ic/vgavar.h>
46 
47 #include <dev/wscons/wsdisplayvar.h>
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/unicode.h>
50 #include <dev/wsfont/wsfont.h>
51 
52 #include <dev/ic/pcdisplay.h>
53 
54 #include "opt_wsdisplay_compat.h" /* for WSCONS_SUPPORT_PCVTFONTS */
55 
56 static struct wsdisplay_font _vga_builtinfont = {
57 	"builtin",
58 	0, 256,
59 	WSDISPLAY_FONTENC_IBM,
60 	8, 16, 1,
61 	WSDISPLAY_FONTORDER_L2R, 0,
62 	0
63 };
64 
65 struct egavga_font {
66 	struct wsdisplay_font *wsfont;
67 	int cookie; /* wsfont handle */
68 	int slot; /* in adapter RAM */
69 	int usecount;
70 	TAILQ_ENTRY(egavga_font) next; /* LRU queue */
71 };
72 
73 static struct egavga_font vga_builtinfont = {
74 	&_vga_builtinfont,
75 	0, 0
76 };
77 
78 #ifdef VGA_CONSOLE_SCREENTYPE
79 static struct egavga_font vga_consolefont;
80 #endif
81 
82 struct vgascreen {
83 	struct pcdisplayscreen pcs;
84 
85 	LIST_ENTRY(vgascreen) next;
86 
87 	struct vga_config *cfg;
88 
89 	/* videostate */
90 	struct egavga_font *fontset1, *fontset2;
91 	/* font data */
92 	/* palette */
93 
94 	int mindispoffset, maxdispoffset;
95 };
96 
97 static int vgaconsole, vga_console_type, vga_console_attached;
98 static struct vgascreen vga_console_screen;
99 static struct vga_config vga_console_vc;
100 
101 struct egavga_font *egavga_getfont(struct vga_config *, struct vgascreen *,
102 				   char *, int);
103 void egavga_unreffont(struct vga_config *, struct egavga_font *);
104 
105 int vga_selectfont __P((struct vga_config *, struct vgascreen *,
106 			char *, char *));
107 void vga_init_screen __P((struct vga_config *, struct vgascreen *,
108 			  const struct wsscreen_descr *,
109 			  int, long *));
110 void vga_init __P((struct vga_config *, bus_space_tag_t,
111 		   bus_space_tag_t));
112 static void vga_setfont __P((struct vga_config *, struct vgascreen *));
113 
114 static int vga_mapchar __P((void *, int, unsigned int *));
115 static int	vga_alloc_attr __P((void *, int, int, int, long *));
116 void	vga_copyrows __P((void *, int, int, int));
117 
118 const struct wsdisplay_emulops vga_emulops = {
119 	pcdisplay_cursor,
120 	vga_mapchar,
121 	pcdisplay_putchar,
122 	pcdisplay_copycols,
123 	pcdisplay_erasecols,
124 	vga_copyrows,
125 	pcdisplay_eraserows,
126 	vga_alloc_attr
127 };
128 
129 /*
130  * translate WS(=ANSI) color codes to standard pc ones
131  */
132 static const unsigned char fgansitopc[] = {
133 #ifdef __alpha__
134 	/*
135 	 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
136 	 * XXX We should probably not bother with this
137 	 * XXX (reinitialize the palette registers).
138 	 */
139 	FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED,
140 	FG_MAGENTA, FG_BROWN, FG_LIGHTGREY
141 #else
142 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
143 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
144 #endif
145 }, bgansitopc[] = {
146 #ifdef __alpha__
147 	BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED,
148 	BG_MAGENTA, BG_BROWN, BG_LIGHTGREY
149 #else
150 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
151 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
152 #endif
153 };
154 
155 const struct wsscreen_descr vga_25lscreen = {
156 	"80x25", 80, 25,
157 	&vga_emulops,
158 	8, 16,
159 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
160 }, vga_25lscreen_mono = {
161 	"80x25", 80, 25,
162 	&vga_emulops,
163 	8, 16,
164 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
165 }, vga_25lscreen_bf = {
166 	"80x25bf", 80, 25,
167 	&vga_emulops,
168 	8, 16,
169 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
170 }, vga_40lscreen = {
171 	"80x40", 80, 40,
172 	&vga_emulops,
173 	8, 10,
174 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
175 }, vga_40lscreen_mono = {
176 	"80x40", 80, 40,
177 	&vga_emulops,
178 	8, 10,
179 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
180 }, vga_40lscreen_bf = {
181 	"80x40bf", 80, 40,
182 	&vga_emulops,
183 	8, 10,
184 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
185 }, vga_50lscreen = {
186 	"80x50", 80, 50,
187 	&vga_emulops,
188 	8, 8,
189 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
190 }, vga_50lscreen_mono = {
191 	"80x50", 80, 50,
192 	&vga_emulops,
193 	8, 8,
194 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
195 }, vga_50lscreen_bf = {
196 	"80x50bf", 80, 50,
197 	&vga_emulops,
198 	8, 8,
199 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
200 }, vga_24lscreen = {
201 	"80x24", 80, 24,
202 	&vga_emulops,
203 	8, 16,
204 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
205 }, vga_24lscreen_mono = {
206 	"80x24", 80, 24,
207 	&vga_emulops,
208 	8, 16,
209 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
210 }, vga_24lscreen_bf = {
211 	"80x24bf", 80, 24,
212 	&vga_emulops,
213 	8, 16,
214 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
215 };
216 
217 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT))
218 
219 const struct wsscreen_descr *_vga_scrlist[] = {
220 	&vga_25lscreen,
221 	&vga_25lscreen_bf,
222 	&vga_40lscreen,
223 	&vga_40lscreen_bf,
224 	&vga_50lscreen,
225 	&vga_50lscreen_bf,
226 	&vga_24lscreen,
227 	&vga_24lscreen_bf,
228 	/* XXX other formats, graphics screen? */
229 }, *_vga_scrlist_mono[] = {
230 	&vga_25lscreen_mono,
231 	&vga_40lscreen_mono,
232 	&vga_50lscreen_mono,
233 	&vga_24lscreen_mono,
234 	/* XXX other formats, graphics screen? */
235 };
236 
237 const struct wsscreen_list vga_screenlist = {
238 	sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *),
239 	_vga_scrlist
240 }, vga_screenlist_mono = {
241 	sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *),
242 	_vga_scrlist_mono
243 };
244 
245 static int	vga_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
246 static paddr_t	vga_mmap __P((void *, off_t, int));
247 static int	vga_alloc_screen __P((void *, const struct wsscreen_descr *,
248 				      void **, int *, int *, long *));
249 static void	vga_free_screen __P((void *, void *));
250 static int	vga_show_screen __P((void *, void *, int,
251 				     void (*) (void *, int, int), void *));
252 static int	vga_load_font __P((void *, void *, struct wsdisplay_font *));
253 
254 void vga_doswitch __P((struct vga_config *));
255 
256 const struct wsdisplay_accessops vga_accessops = {
257 	vga_ioctl,
258 	vga_mmap,
259 	vga_alloc_screen,
260 	vga_free_screen,
261 	vga_show_screen,
262 	vga_load_font
263 };
264 
265 /*
266  * The following functions implement back-end configuration grabbing
267  * and attachment.
268  */
269 int
270 vga_common_probe(iot, memt)
271 	bus_space_tag_t iot, memt;
272 {
273 	bus_space_handle_t ioh_vga, ioh_6845, memh;
274 	u_int8_t regval;
275 	u_int16_t vgadata;
276 	int gotio_vga, gotio_6845, gotmem, mono, rv;
277 	int dispoffset;
278 
279 	gotio_vga = gotio_6845 = gotmem = rv = 0;
280 
281 	if (bus_space_map(iot, 0x3c0, 0x10, 0, &ioh_vga))
282 		goto bad;
283 	gotio_vga = 1;
284 
285 	/* read "misc output register" */
286 	regval = bus_space_read_1(iot, ioh_vga, 0xc);
287 	mono = !(regval & 1);
288 
289 	if (bus_space_map(iot, (mono ? 0x3b0 : 0x3d0), 0x10, 0, &ioh_6845))
290 		goto bad;
291 	gotio_6845 = 1;
292 
293 	if (bus_space_map(memt, 0xa0000, 0x20000, 0, &memh))
294 		goto bad;
295 	gotmem = 1;
296 
297 	dispoffset = (mono ? 0x10000 : 0x18000);
298 
299 	vgadata = bus_space_read_2(memt, memh, dispoffset);
300 	bus_space_write_2(memt, memh, dispoffset, 0xa55a);
301 	if (bus_space_read_2(memt, memh, dispoffset) != 0xa55a)
302 		goto bad;
303 	bus_space_write_2(memt, memh, dispoffset, vgadata);
304 
305 	/*
306 	 * check if this is really a VGA
307 	 * (try to write "Color Select" register as XFree86 does)
308 	 * XXX check before if at least EGA?
309 	 */
310 	/* reset state */
311 	(void) bus_space_read_1(iot, ioh_6845, 10);
312 	bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX,
313 			  20 | 0x20); /* colselect | enable */
314 	regval = bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR);
315 	/* toggle the implemented bits */
316 	bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval ^ 0x0f);
317 	bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX,
318 			  20 | 0x20);
319 	/* read back */
320 	if (bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR) != (regval ^ 0x0f))
321 		goto bad;
322 	/* restore contents */
323 	bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval);
324 
325 	rv = 1;
326 bad:
327 	if (gotio_vga)
328 		bus_space_unmap(iot, ioh_vga, 0x10);
329 	if (gotio_6845)
330 		bus_space_unmap(iot, ioh_6845, 0x10);
331 	if (gotmem)
332 		bus_space_unmap(memt, memh, 0x20000);
333 
334 	return (rv);
335 }
336 
337 /*
338  * We want at least ASCII 32..127 be present in the
339  * first font slot.
340  */
341 #define vga_valid_primary_font(f) \
342 	(f->wsfont->encoding == WSDISPLAY_FONTENC_IBM || \
343 	f->wsfont->encoding == WSDISPLAY_FONTENC_ISO || \
344 	f->wsfont->encoding == WSDISPLAY_FONTENC_ISO7)
345 
346 struct egavga_font *
347 egavga_getfont(vc, scr, name, primary)
348 	struct vga_config *vc;
349 	struct vgascreen *scr;
350 	char *name;
351 	int primary;
352 {
353 	struct egavga_font *f;
354 	int cookie;
355 	struct wsdisplay_font *wf;
356 
357 	TAILQ_FOREACH(f, &vc->vc_fontlist, next) {
358 		if (wsfont_matches(f->wsfont, name,
359 				   8, scr->pcs.type->fontheight, 0) &&
360 		    (!primary || vga_valid_primary_font(f))) {
361 #ifdef VGAFONTDEBUG
362 			if (scr != &vga_console_screen || vga_console_attached)
363 				printf("vga_getfont: %s already present\n",
364 				       name ? name : "<default>");
365 #endif
366 			goto found;
367 		}
368 	}
369 
370 	cookie = wsfont_find(name, 8, scr->pcs.type->fontheight, 0);
371 	/* XXX obey "primary" */
372 	if (cookie == -1) {
373 #ifdef VGAFONTDEBUG
374 		if (scr != &vga_console_screen || vga_console_attached)
375 			printf("vga_getfont: %s not found\n", name);
376 #endif
377 		return (0);
378 	}
379 
380 	if (wsfont_lock(cookie, &wf, WSDISPLAY_FONTORDER_L2R, 0) < 0)
381 		return (0);
382 
383 #ifdef VGA_CONSOLE_SCREENTYPE
384 	if (scr == &vga_console_screen)
385 		f = &vga_consolefont;
386 	else
387 #endif
388 	f = malloc(sizeof(struct egavga_font), M_DEVBUF, M_NOWAIT);
389 	if (!f) {
390 		wsfont_unlock(cookie);
391 		return (0);
392 	}
393 	f->wsfont = wf;
394 	f->cookie = cookie;
395 	f->slot = -1; /* not yet loaded */
396 	f->usecount = 0; /* incremented below */
397 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
398 
399 found:
400 	f->usecount++;
401 #ifdef VGAFONTDEBUG
402 	if (scr != &vga_console_screen || vga_console_attached)
403 		printf("vga_getfont: usecount=%d\n", f->usecount);
404 #endif
405 	return (f);
406 }
407 
408 void
409 egavga_unreffont(vc, f)
410 	struct vga_config *vc;
411 	struct egavga_font *f;
412 {
413 
414 	f->usecount--;
415 #ifdef VGAFONTDEBUG
416 	printf("vga_unreffont: usecount=%d\n", f->usecount);
417 #endif
418 	if (f->usecount == 0 && f != &vga_builtinfont) {
419 		TAILQ_REMOVE(&vc->vc_fontlist, f, next);
420 		if (f->slot != -1) {
421 			KASSERT(vc->vc_fonts[f->slot] == f);
422 			vc->vc_fonts[f->slot] = 0;
423 		}
424 		wsfont_unlock(f->cookie);
425 #ifdef VGA_CONSOLE_SCREENTYPE
426 		if (f != &vga_consolefont)
427 #endif
428 		free(f, M_DEVBUF);
429 	}
430 }
431 
432 int
433 vga_selectfont(vc, scr, name1, name2)
434 	struct vga_config *vc;
435 	struct vgascreen *scr;
436 	char *name1, *name2; /* NULL: take first found */
437 {
438 	const struct wsscreen_descr *type = scr->pcs.type;
439 	struct egavga_font *f1, *f2;
440 
441 	f1 = egavga_getfont(vc, scr, name1, 1);
442 	if (!f1)
443 		return (ENXIO);
444 
445 	if (VGA_SCREEN_CANTWOFONTS(type) && name2) {
446 		f2 = egavga_getfont(vc, scr, name2, 0);
447 		if (!f2) {
448 			egavga_unreffont(vc, f1);
449 			return (ENXIO);
450 		}
451 	} else
452 		f2 = 0;
453 
454 #ifdef VGAFONTDEBUG
455 	if (scr != &vga_console_screen || vga_console_attached) {
456 		printf("vga (%s): font1=%s (slot %d)", type->name,
457 		       f1->wsfont->name, f1->slot);
458 		if (f2)
459 			printf(", font2=%s (slot %d)",
460 			       f2->wsfont->name, f2->slot);
461 		printf("\n");
462 	}
463 #endif
464 	if (scr->fontset1)
465 		egavga_unreffont(vc, scr->fontset1);
466 	scr->fontset1 = f1;
467 	if (scr->fontset2)
468 		egavga_unreffont(vc, scr->fontset2);
469 	scr->fontset2 = f2;
470 	return (0);
471 }
472 
473 void
474 vga_init_screen(vc, scr, type, existing, attrp)
475 	struct vga_config *vc;
476 	struct vgascreen *scr;
477 	const struct wsscreen_descr *type;
478 	int existing;
479 	long *attrp;
480 {
481 	int cpos;
482 	int res;
483 
484 	scr->cfg = vc;
485 	scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl;
486 	scr->pcs.type = type;
487 	scr->pcs.active = existing;
488 	scr->mindispoffset = 0;
489 	scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2;
490 
491 	if (existing) {
492 		vc->active = scr;
493 
494 		cpos = vga_6845_read(&vc->hdl, cursorh) << 8;
495 		cpos |= vga_6845_read(&vc->hdl, cursorl);
496 
497 		/* make sure we have a valid cursor position */
498 		if (cpos < 0 || cpos >= type->nrows * type->ncols)
499 			cpos = 0;
500 
501 		scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9;
502 		scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1;
503 
504 		/* make sure we have a valid memory offset */
505 		if (scr->pcs.dispoffset < scr->mindispoffset ||
506 		    scr->pcs.dispoffset > scr->maxdispoffset)
507 			scr->pcs.dispoffset = scr->mindispoffset;
508 
509 		if (type != vc->currenttype) {
510 			vga_setscreentype(&vc->hdl, type);
511 			vc->currenttype = type;
512 		}
513 	} else {
514 		cpos = 0;
515 		scr->pcs.dispoffset = scr->mindispoffset;
516 	}
517 
518 	scr->pcs.vc_crow = cpos / type->ncols;
519 	scr->pcs.vc_ccol = cpos % type->ncols;
520 	pcdisplay_cursor_init(&scr->pcs, existing);
521 
522 #ifdef __alpha__
523 	if (!vc->hdl.vh_mono)
524 		/*
525 		 * DEC firmware uses a blue background.
526 		 */
527 		res = vga_alloc_attr(scr, WSCOL_WHITE, WSCOL_BLUE,
528 				     WSATTR_WSCOLORS, attrp);
529 	else
530 #endif
531 	res = vga_alloc_attr(scr, 0, 0, 0, attrp);
532 #ifdef DIAGNOSTIC
533 	if (res)
534 		panic("vga_init_screen: attribute botch");
535 #endif
536 
537 	scr->pcs.mem = NULL;
538 
539 	wsfont_init();
540 	scr->fontset1 = scr->fontset2 = 0;
541 	if (vga_selectfont(vc, scr, 0, 0)) {
542 		if (scr == &vga_console_screen)
543 			panic("vga_init_screen: no font");
544 		else
545 			printf("vga_init_screen: no font\n");
546 	}
547 	if (existing)
548 		vga_setfont(vc, scr);
549 
550 	vc->nscreens++;
551 	LIST_INSERT_HEAD(&vc->screens, scr, next);
552 }
553 
554 void
555 vga_init(vc, iot, memt)
556 	struct vga_config *vc;
557 	bus_space_tag_t iot, memt;
558 {
559 	struct vga_handle *vh = &vc->hdl;
560 	u_int8_t mor;
561 	int i;
562 
563         vh->vh_iot = iot;
564         vh->vh_memt = memt;
565 
566         if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
567                 panic("vga_common_setup: couldn't map vga io");
568 
569 	/* read "misc output register" */
570 	mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, 0xc);
571 	vh->vh_mono = !(mor & 1);
572 
573 	if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
574 			  &vh->vh_ioh_6845))
575                 panic("vga_common_setup: couldn't map 6845 io");
576 
577         if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh))
578                 panic("vga_common_setup: couldn't map memory");
579 
580         if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh,
581 				(vh->vh_mono ? 0x10000 : 0x18000), 0x8000,
582 				&vh->vh_memh))
583                 panic("vga_common_setup: mem subrange failed");
584 
585 	/* should only reserve the space (no need to map - save KVM) */
586 	vc->vc_biostag = memt;
587 	if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0,
588 			  &vc->vc_bioshdl))
589 		vc->vc_biosmapped = 0;
590 	else
591 		vc->vc_biosmapped = 1;
592 
593 	vc->nscreens = 0;
594 	LIST_INIT(&vc->screens);
595 	vc->active = NULL;
596 	vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen;
597 	callout_init(&vc->vc_switch_callout);
598 
599 	vc->vc_fonts[0] = &vga_builtinfont;
600 	for (i = 1; i < 8; i++)
601 		vc->vc_fonts[i] = 0;
602 	TAILQ_INIT(&vc->vc_fontlist);
603 	TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next);
604 
605 	vc->currentfontset1 = vc->currentfontset2 = 0;
606 }
607 
608 void
609 vga_common_attach(sc, iot, memt, type, vf)
610 	struct vga_softc *sc;
611 	bus_space_tag_t iot, memt;
612 	int type;
613 	const struct vga_funcs *vf;
614 {
615 	int console;
616 	struct vga_config *vc;
617 	struct wsemuldisplaydev_attach_args aa;
618 
619 	console = vga_is_console(iot, type);
620 
621 	if (console) {
622 		vc = &vga_console_vc;
623 		vga_console_attached = 1;
624 	} else {
625 		vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK);
626 		vga_init(vc, iot, memt);
627 	}
628 
629 	vc->vc_type = type;
630 	vc->vc_funcs = vf;
631 
632 	sc->sc_vc = vc;
633 	vc->softc = sc;
634 
635 	aa.console = console;
636 	aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
637 	aa.accessops = &vga_accessops;
638 	aa.accesscookie = vc;
639 
640         config_found(&sc->sc_dev, &aa, wsemuldisplaydevprint);
641 }
642 
643 int
644 vga_cnattach(iot, memt, type, check)
645 	bus_space_tag_t iot, memt;
646 	int type, check;
647 {
648 	long defattr;
649 	const struct wsscreen_descr *scr;
650 
651 	if (check && !vga_common_probe(iot, memt))
652 		return (ENXIO);
653 
654 	/* set up bus-independent VGA configuration */
655 	vga_init(&vga_console_vc, iot, memt);
656 #ifdef VGA_CONSOLE_SCREENTYPE
657 	scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
658 	       &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
659 	if (!scr)
660 		panic("vga_cnattach: invalid screen type");
661 #else
662 	scr = vga_console_vc.currenttype;
663 #endif
664 	vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr);
665 
666 	wsdisplay_cnattach(scr, &vga_console_screen,
667 			   vga_console_screen.pcs.vc_ccol,
668 			   vga_console_screen.pcs.vc_crow,
669 			   defattr);
670 
671 	vgaconsole = 1;
672 	vga_console_type = type;
673 	return (0);
674 }
675 
676 int
677 vga_is_console(iot, type)
678 	bus_space_tag_t iot;
679 	int type;
680 {
681 	if (vgaconsole &&
682 	    !vga_console_attached &&
683 	    iot == vga_console_vc.hdl.vh_iot &&
684 	    (vga_console_type == -1 || (type == vga_console_type)))
685 		return (1);
686 	return (0);
687 }
688 
689 int
690 vga_ioctl(v, cmd, data, flag, p)
691 	void *v;
692 	u_long cmd;
693 	caddr_t data;
694 	int flag;
695 	struct proc *p;
696 {
697 	struct vga_config *vc = v;
698 	const struct vga_funcs *vf = vc->vc_funcs;
699 
700 	switch (cmd) {
701 	case WSDISPLAYIO_GTYPE:
702 		*(int *)data = vc->vc_type;
703 		return 0;
704 
705 	case WSDISPLAYIO_GINFO:
706 		/* XXX should get detailed hardware information here */
707 		return ENOTTY;
708 
709 	case WSDISPLAYIO_GETCMAP:
710 	case WSDISPLAYIO_PUTCMAP:
711 	case WSDISPLAYIO_GVIDEO:
712 	case WSDISPLAYIO_SVIDEO:
713 	case WSDISPLAYIO_GCURPOS:
714 	case WSDISPLAYIO_SCURPOS:
715 	case WSDISPLAYIO_GCURMAX:
716 	case WSDISPLAYIO_GCURSOR:
717 	case WSDISPLAYIO_SCURSOR:
718 		/* NONE of these operations are by the generic VGA driver. */
719 		return ENOTTY;
720 	}
721 
722 	if (vc->vc_funcs == NULL)
723 		return (-1);
724 
725 	if (vf->vf_ioctl == NULL)
726 		return (-1);
727 
728 	return ((*vf->vf_ioctl)(v, cmd, data, flag, p));
729 }
730 
731 static paddr_t
732 vga_mmap(v, offset, prot)
733 	void *v;
734 	off_t offset;
735 	int prot;
736 {
737 	struct vga_config *vc = v;
738 	const struct vga_funcs *vf = vc->vc_funcs;
739 
740 	if (vc->vc_funcs == NULL)
741 		return (-1);
742 
743 	if (vf->vf_mmap == NULL)
744 		return (-1);
745 
746 	return ((*vf->vf_mmap)(v, offset, prot));
747 }
748 
749 int
750 vga_alloc_screen(v, type, cookiep, curxp, curyp, defattrp)
751 	void *v;
752 	const struct wsscreen_descr *type;
753 	void **cookiep;
754 	int *curxp, *curyp;
755 	long *defattrp;
756 {
757 	struct vga_config *vc = v;
758 	struct vgascreen *scr;
759 
760 	if (vc->nscreens == 1) {
761 		struct vgascreen *scr1 = vc->screens.lh_first;
762 		/*
763 		 * When allocating the second screen, get backing store
764 		 * for the first one too.
765 		 * XXX We could be more clever and use video RAM.
766 		 */
767 		scr1->pcs.mem =
768 		  malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2,
769 			 M_DEVBUF, M_WAITOK);
770 	}
771 
772 	scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
773 	vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
774 
775 	if (vc->nscreens > 1) {
776 		scr->pcs.mem = malloc(type->ncols * type->nrows * 2,
777 				      M_DEVBUF, M_WAITOK);
778 		pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp);
779 	}
780 
781 	*cookiep = scr;
782 	*curxp = scr->pcs.vc_ccol;
783 	*curyp = scr->pcs.vc_crow;
784 
785 	return (0);
786 }
787 
788 void
789 vga_free_screen(v, cookie)
790 	void *v;
791 	void *cookie;
792 {
793 	struct vgascreen *vs = cookie;
794 	struct vga_config *vc = vs->cfg;
795 
796 	LIST_REMOVE(vs, next);
797 	if (vs->fontset1)
798 		egavga_unreffont(vc, vs->fontset1);
799 	if (vs->fontset2)
800 		egavga_unreffont(vc, vs->fontset2);
801 
802 	if (vs != &vga_console_screen)
803 		free(vs, M_DEVBUF);
804 	else
805 		panic("vga_free_screen: console");
806 
807 	if (vc->active == vs)
808 		vc->active = 0;
809 }
810 
811 static void vga_usefont(struct vga_config *, struct egavga_font *);
812 
813 static void
814 vga_usefont(vc, f)
815 	struct vga_config *vc;
816 	struct egavga_font *f;
817 {
818 	int slot;
819 	struct egavga_font *of;
820 
821 	if (f->slot != -1)
822 		goto toend;
823 
824 	for (slot = 0; slot < 8; slot++) {
825 		if (!vc->vc_fonts[slot])
826 			goto loadit;
827 	}
828 
829 	/* have to kick out another one */
830 	TAILQ_FOREACH(of, &vc->vc_fontlist, next) {
831 		if (of->slot != -1) {
832 			if (of == &vga_builtinfont)
833 				continue; /* XXX for now */
834 			KASSERT(vc->vc_fonts[of->slot] == of);
835 			slot = of->slot;
836 			of->slot = -1;
837 			goto loadit;
838 		}
839 	}
840 	panic("vga_usefont");
841 
842 loadit:
843 	vga_loadchars(&vc->hdl, slot, 0, 256,
844 		      f->wsfont->fontheight, f->wsfont->data);
845 	f->slot = slot;
846 	vc->vc_fonts[slot] = f;
847 
848 toend:
849 	TAILQ_REMOVE(&vc->vc_fontlist, f, next);
850 	TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
851 }
852 
853 static void
854 vga_setfont(vc, scr)
855 	struct vga_config *vc;
856 	struct vgascreen *scr;
857 {
858 	int fontslot1, fontslot2;
859 
860 	if (scr->fontset1)
861 		vga_usefont(vc, scr->fontset1);
862 	if (scr->fontset2)
863 		vga_usefont(vc, scr->fontset2);
864 
865 	fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0);
866 	fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1);
867 	if (vc->currentfontset1 != fontslot1 ||
868 	    vc->currentfontset2 != fontslot2) {
869 		vga_setfontset(&vc->hdl, fontslot1, fontslot2);
870 		vc->currentfontset1 = fontslot1;
871 		vc->currentfontset2 = fontslot2;
872 	}
873 }
874 
875 int
876 vga_show_screen(v, cookie, waitok, cb, cbarg)
877 	void *v;
878 	void *cookie;
879 	int waitok;
880 	void (*cb) __P((void *, int, int));
881 	void *cbarg;
882 {
883 	struct vgascreen *scr = cookie, *oldscr;
884 	struct vga_config *vc = scr->cfg;
885 
886 	oldscr = vc->active; /* can be NULL! */
887 	if (scr == oldscr) {
888 		return (0);
889 	}
890 
891 	vc->wantedscreen = cookie;
892 	vc->switchcb = cb;
893 	vc->switchcbarg = cbarg;
894 	if (cb) {
895 		callout_reset(&vc->vc_switch_callout, 0,
896 		    (void(*)(void *))vga_doswitch, vc);
897 		return (EAGAIN);
898 	}
899 
900 	vga_doswitch(vc);
901 	return (0);
902 }
903 
904 void
905 vga_doswitch(vc)
906 	struct vga_config *vc;
907 {
908 	struct vgascreen *scr, *oldscr;
909 	struct vga_handle *vh = &vc->hdl;
910 	const struct wsscreen_descr *type;
911 
912 	scr = vc->wantedscreen;
913 	if (!scr) {
914 		printf("vga_doswitch: disappeared\n");
915 		(*vc->switchcb)(vc->switchcbarg, EIO, 0);
916 		return;
917 	}
918 	type = scr->pcs.type;
919 	oldscr = vc->active; /* can be NULL! */
920 #ifdef DIAGNOSTIC
921 	if (oldscr) {
922 		if (!oldscr->pcs.active)
923 			panic("vga_show_screen: not active");
924 		if (oldscr->pcs.type != vc->currenttype)
925 			panic("vga_show_screen: bad type");
926 	}
927 #endif
928 	if (scr == oldscr) {
929 		return;
930 	}
931 #ifdef DIAGNOSTIC
932 	if (scr->pcs.active)
933 		panic("vga_show_screen: active");
934 #endif
935 
936 	if (oldscr) {
937 		const struct wsscreen_descr *oldtype = oldscr->pcs.type;
938 
939 		oldscr->pcs.active = 0;
940 		bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
941 					oldscr->pcs.dispoffset, oldscr->pcs.mem,
942 					oldtype->ncols * oldtype->nrows);
943 	}
944 
945 	if (vc->currenttype != type) {
946 		vga_setscreentype(vh, type);
947 		vc->currenttype = type;
948 	}
949 
950 	vga_setfont(vc, scr);
951 	/* XXX swich colours! */
952 
953 	scr->pcs.dispoffset = scr->mindispoffset;
954 	if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
955 		vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9);
956 		vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1);
957 	}
958 
959 	bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
960 				scr->pcs.dispoffset, scr->pcs.mem,
961 				type->ncols * type->nrows);
962 	scr->pcs.active = 1;
963 
964 	vc->active = scr;
965 
966 	pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron,
967 			 scr->pcs.vc_crow, scr->pcs.vc_ccol);
968 
969 	vc->wantedscreen = 0;
970 	if (vc->switchcb)
971 		(*vc->switchcb)(vc->switchcbarg, 0, 0);
972 }
973 
974 static int
975 vga_load_font(v, cookie, data)
976 	void *v;
977 	void *cookie;
978 	struct wsdisplay_font *data;
979 {
980 	struct vga_config *vc = v;
981 	struct vgascreen *scr = cookie;
982 	char *name2;
983 	int res;
984 
985 	if (scr) {
986 		name2 = strchr(data->name, ',');
987 		if (name2)
988 			*name2++ = '\0';
989 		res = vga_selectfont(vc, scr, data->name, name2);
990 		if (!res)
991 			vga_setfont(vc, scr);
992 		return (res);
993 	}
994 
995 	return (0);
996 }
997 
998 static int
999 vga_alloc_attr(id, fg, bg, flags, attrp)
1000 	void *id;
1001 	int fg, bg;
1002 	int flags;
1003 	long *attrp;
1004 {
1005 	struct vgascreen *scr = id;
1006 	struct vga_config *vc = scr->cfg;
1007 
1008 	if (vc->hdl.vh_mono) {
1009 		if (flags & WSATTR_WSCOLORS)
1010 			return (EINVAL);
1011 		if (flags & WSATTR_REVERSE)
1012 			*attrp = 0x70;
1013 		else
1014 			*attrp = 0x07;
1015 		if (flags & WSATTR_UNDERLINE)
1016 			*attrp |= FG_UNDERLINE;
1017 		if (flags & WSATTR_HILIT)
1018 			*attrp |= FG_INTENSE;
1019 	} else {
1020 		if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
1021 			return (EINVAL);
1022 		if (flags & WSATTR_WSCOLORS)
1023 			*attrp = fgansitopc[fg] | bgansitopc[bg];
1024 		else
1025 			*attrp = 7;
1026 		if (flags & WSATTR_HILIT)
1027 			*attrp += 8;
1028 	}
1029 	if (flags & WSATTR_BLINK)
1030 		*attrp |= FG_BLINK;
1031 	return (0);
1032 }
1033 
1034 void
1035 vga_copyrows(id, srcrow, dstrow, nrows)
1036 	void *id;
1037 	int srcrow, dstrow, nrows;
1038 {
1039 	struct vgascreen *scr = id;
1040 	bus_space_tag_t memt = scr->pcs.hdl->ph_memt;
1041 	bus_space_handle_t memh = scr->pcs.hdl->ph_memh;
1042 	int ncols = scr->pcs.type->ncols;
1043 	bus_size_t srcoff, dstoff;
1044 
1045 	srcoff = srcrow * ncols + 0;
1046 	dstoff = dstrow * ncols + 0;
1047 
1048 	if (scr->pcs.active) {
1049 		if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) {
1050 #ifdef PCDISPLAY_SOFTCURSOR
1051 			int cursoron = scr->pcs.cursoron;
1052 
1053 			if (cursoron)
1054 				pcdisplay_cursor(&scr->pcs, 0,
1055 				    scr->pcs.vc_crow, scr->pcs.vc_ccol);
1056 #endif
1057 			/* scroll up whole screen */
1058 			if ((scr->pcs.dispoffset + srcrow * ncols * 2)
1059 			    <= scr->maxdispoffset) {
1060 				scr->pcs.dispoffset += srcrow * ncols * 2;
1061 			} else {
1062 				bus_space_copy_region_2(memt, memh,
1063 					scr->pcs.dispoffset + srcoff * 2,
1064 					memh, scr->mindispoffset,
1065 					nrows * ncols);
1066 				scr->pcs.dispoffset = scr->mindispoffset;
1067 			}
1068 			vga_6845_write(&scr->cfg->hdl, startadrh,
1069 				       scr->pcs.dispoffset >> 9);
1070 			vga_6845_write(&scr->cfg->hdl, startadrl,
1071 				       scr->pcs.dispoffset >> 1);
1072 #ifdef PCDISPLAY_SOFTCURSOR
1073 			if (cursoron)
1074 				pcdisplay_cursor(&scr->pcs, 1,
1075 				    scr->pcs.vc_crow, scr->pcs.vc_ccol);
1076 #endif
1077 		} else {
1078 			bus_space_copy_region_2(memt, memh,
1079 					scr->pcs.dispoffset + srcoff * 2,
1080 					memh, scr->pcs.dispoffset + dstoff * 2,
1081 					nrows * ncols);
1082 		}
1083 	} else
1084 		memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff],
1085 		      nrows * ncols * 2);
1086 }
1087 
1088 #ifdef WSCONS_SUPPORT_PCVTFONTS
1089 
1090 #define NOTYET 0xffff
1091 static const u_int16_t pcvt_unichars[0xa0] = {
1092 /* 0 */	_e006U, /* N/L control */
1093 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1094 	NOTYET,
1095 	0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */
1096 	0x240a, /* SYMBOL FOR LINE FEED */
1097 	0x240b, /* SYMBOL FOR VERTICAL TABULATION */
1098 	0x240c, /* SYMBOL FOR FORM FEED */
1099 	0x240d, /* SYMBOL FOR CARRIAGE RETURN */
1100 	NOTYET, NOTYET,
1101 /* 1 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1102 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1103 /* 2 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1104 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1105 /* 3 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1106 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1107 /* 4 */	0x03c1, /* GREEK SMALL LETTER RHO */
1108 	0x03c8, /* GREEK SMALL LETTER PSI */
1109 	0x2202, /* PARTIAL DIFFERENTIAL */
1110 	0x03bb, /* GREEK SMALL LETTER LAMDA */
1111 	0x03b9, /* GREEK SMALL LETTER IOTA */
1112 	0x03b7, /* GREEK SMALL LETTER ETA */
1113 	0x03b5, /* GREEK SMALL LETTER EPSILON */
1114 	0x03c7, /* GREEK SMALL LETTER CHI */
1115 	0x2228, /* LOGICAL OR */
1116 	0x2227, /* LOGICAL AND */
1117 	0x222a, /* UNION */
1118 	0x2283, /* SUPERSET OF */
1119 	0x2282, /* SUBSET OF */
1120 	0x03a5, /* GREEK CAPITAL LETTER UPSILON */
1121 	0x039e, /* GREEK CAPITAL LETTER XI */
1122 	0x03a8, /* GREEK CAPITAL LETTER PSI */
1123 /* 5 */	0x03a0, /* GREEK CAPITAL LETTER PI */
1124 	0x21d2, /* RIGHTWARDS DOUBLE ARROW */
1125 	0x21d4, /* LEFT RIGHT DOUBLE ARROW */
1126 	0x039b, /* GREEK CAPITAL LETTER LAMDA */
1127 	0x0398, /* GREEK CAPITAL LETTER THETA */
1128 	0x2243, /* ASYMPTOTICALLY EQUAL TO */
1129 	0x2207, /* NABLA */
1130 	0x2206, /* INCREMENT */
1131 	0x221d, /* PROPORTIONAL TO */
1132 	0x2234, /* THEREFORE */
1133 	0x222b, /* INTEGRAL */
1134 	0x2215, /* DIVISION SLASH */
1135 	0x2216, /* SET MINUS */
1136 	_e00eU, /* angle? */
1137 	_e00dU, /* inverted angle? */
1138 	_e00bU, /* braceleftmid */
1139 /* 6 */	_e00cU, /* bracerightmid */
1140 	_e007U, /* bracelefttp */
1141 	_e008U, /* braceleftbt */
1142 	_e009U, /* bracerighttp */
1143 	_e00aU, /* bracerightbt */
1144 	0x221a, /* SQUARE ROOT */
1145 	0x03c9, /* GREEK SMALL LETTER OMEGA */
1146 	0x00a5, /* YEN SIGN */
1147 	0x03be, /* GREEK SMALL LETTER XI */
1148 	0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */
1149 	0x00fe, /* LATIN SMALL LETTER THORN */
1150 	0x00f0, /* LATIN SMALL LETTER ETH */
1151 	0x00de, /* LATIN CAPITAL LETTER THORN */
1152 	0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
1153 	0x00d7, /* MULTIPLICATION SIGN */
1154 	0x00d0, /* LATIN CAPITAL LETTER ETH */
1155 /* 7 */	0x00be, /* VULGAR FRACTION THREE QUARTERS */
1156 	0x00b8, /* CEDILLA */
1157 	0x00b4, /* ACUTE ACCENT */
1158 	0x00af, /* MACRON */
1159 	0x00ae, /* REGISTERED SIGN */
1160 	0x00ad, /* SOFT HYPHEN */
1161 	0x00ac, /* NOT SIGN */
1162 	0x00a8, /* DIAERESIS */
1163 	0x2260, /* NOT EQUAL TO */
1164 	_e005U, /* scan 9 */
1165 	_e004U, /* scan 7 */
1166 	_e003U, /* scan 5 */
1167 	_e002U, /* scan 3 */
1168 	_e001U, /* scan 1 */
1169 	0x03c5, /* GREEK SMALL LETTER UPSILON */
1170 	0x00f8, /* LATIN SMALL LETTER O WITH STROKE */
1171 /* 8 */	0x0153, /* LATIN SMALL LIGATURE OE */
1172 	0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */
1173 	0x00e3, /* LATIN SMALL LETTER A WITH TILDE */
1174 	0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1175 	0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1176 	0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
1177 	0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
1178 	0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
1179 	0x0152, /* LATIN CAPITAL LIGATURE OE */
1180 	0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
1181 	0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1182 	0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
1183 	0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
1184 	0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1185 	0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1186 	0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
1187 /* 9 */	0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
1188 	0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1189 	0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1190 	0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
1191 	0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
1192 	0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1193 	0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
1194 	0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
1195 	0x00b9, /* SUPERSCRIPT ONE */
1196 	0x00b7, /* MIDDLE DOT */
1197 	0x03b6, /* GREEK SMALL LETTER ZETA */
1198 	0x00b3, /* SUPERSCRIPT THREE */
1199 	0x00a9, /* COPYRIGHT SIGN */
1200 	0x00a4, /* CURRENCY SIGN */
1201 	0x03ba, /* GREEK SMALL LETTER KAPPA */
1202 	_e000U  /* mirrored question mark? */
1203 };
1204 
1205 static int vga_pcvt_mapchar __P((int, unsigned int *));
1206 
1207 static int
1208 vga_pcvt_mapchar(uni, index)
1209 	int uni;
1210 	unsigned int *index;
1211 {
1212 	int i;
1213 
1214 	for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */
1215 		if (uni == pcvt_unichars[i]) {
1216 			*index = i;
1217 			return (5);
1218 		}
1219 	*index = 0x99; /* middle dot */
1220 	return (0);
1221 }
1222 
1223 #endif /* WSCONS_SUPPORT_PCVTFONTS */
1224 
1225 #ifdef WSCONS_SUPPORT_ISO7FONTS
1226 
1227 static int
1228 vga_iso7_mapchar(int uni, unsigned int *index)
1229 {
1230 
1231 	/*
1232 	 * U+0384 (GREEK TONOS) to
1233 	 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS)
1234 	 * map directly to the iso-9 font
1235 	 */
1236 	if (uni >= 0x0384 && uni <= 0x03ce) {
1237 		/* U+0384 is at offset 0xb4 in the font */
1238 		*index = uni - 0x0384 + 0xb4;
1239 		return (5);
1240 	}
1241 
1242 	/* XXX more chars in the iso-9 font */
1243 
1244 	*index = 0xa4; /* shaded rectangle */
1245 	return (0);
1246 }
1247 
1248 #endif /* WSCONS_SUPPORT_ISO7FONTS */
1249 
1250 static int _vga_mapchar __P((void *, const struct egavga_font *, int, unsigned int *));
1251 
1252 static int
1253 _vga_mapchar(id, font, uni, index)
1254 	void *id;
1255 	const struct egavga_font *font;
1256 	int uni;
1257 	unsigned int *index;
1258 {
1259 
1260 	switch (font->wsfont->encoding) {
1261 	case WSDISPLAY_FONTENC_ISO:
1262 		if (uni < 256) {
1263 			*index = uni;
1264 			return (5);
1265 		} else {
1266 			*index = ' ';
1267 			return (0);
1268 		}
1269 		break;
1270 	case WSDISPLAY_FONTENC_IBM:
1271 		return (pcdisplay_mapchar(id, uni, index));
1272 #ifdef WSCONS_SUPPORT_PCVTFONTS
1273 	case WSDISPLAY_FONTENC_PCVT:
1274 		return (vga_pcvt_mapchar(uni, index));
1275 #endif
1276 #ifdef WSCONS_SUPPORT_ISO7FONTS
1277 	case WSDISPLAY_FONTENC_ISO7:
1278 		return (vga_iso7_mapchar(uni, index));
1279 #endif
1280 	default:
1281 #ifdef VGAFONTDEBUG
1282 		printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding);
1283 #endif
1284 		*index = ' ';
1285 		return (0);
1286 	}
1287 }
1288 
1289 static int
1290 vga_mapchar(id, uni, index)
1291 	void *id;
1292 	int uni;
1293 	unsigned int *index;
1294 {
1295 	struct vgascreen *scr = id;
1296 	unsigned int idx1, idx2;
1297 	int res1, res2;
1298 
1299 	res1 = 0;
1300 	idx1 = ' '; /* space */
1301 	if (scr->fontset1)
1302 		res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1);
1303 	res2 = -1;
1304 	if (scr->fontset2) {
1305 		KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type));
1306 		res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2);
1307 	}
1308 	if (res2 > res1) {
1309 		*index = idx2 | 0x0800; /* attribute bit 3 */
1310 		return (res2);
1311 	}
1312 	*index = idx1;
1313 	return (res1);
1314 }
1315