xref: /openbsd-src/sys/dev/ic/vga.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: vga.c,v 1.50 2009/03/29 21:53:52 sthen Exp $ */
2 /* $NetBSD: vga.c,v 1.28.2.1 2000/06/30 16:27:47 simonb Exp $ */
3 
4 /*-
5   * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
6   * Copyright (c) 1992-1998 S�ren Schmidt
7   * All rights reserved.
8   *
9   * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer as
14   *    the first lines of this file unmodified.
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in the
17   *    documentation and/or other materials provided with the distribution.
18   * 3. The name of the author may not be used to endorse or promote products
19   *    derived from this software without specific prior written permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
22   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31   *
32   */
33 /*
34  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
35  * All rights reserved.
36  *
37  * Author: Chris G. Demetriou
38  *
39  * Permission to use, copy, modify and distribute this software and
40  * its documentation is hereby granted, provided that both the copyright
41  * notice and this permission notice appear in all copies of the
42  * software, derivative works or modified versions, and any portions
43  * thereof, and that both notices appear in supporting documentation.
44  *
45  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48  *
49  * Carnegie Mellon requests users of this software to return to
50  *
51  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
52  *  School of Computer Science
53  *  Carnegie Mellon University
54  *  Pittsburgh PA 15213-3890
55  *
56  * any improvements or extensions that they make and grant Carnegie the
57  * rights to redistribute these changes.
58  */
59 
60 #include "vga.h"
61 
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/device.h>
66 #include <sys/malloc.h>
67 #include <sys/queue.h>
68 #include <machine/bus.h>
69 
70 #include <dev/ic/mc6845reg.h>
71 #include <dev/ic/pcdisplayvar.h>
72 #include <dev/ic/vgareg.h>
73 #include <dev/ic/vgavar.h>
74 
75 #include <dev/wscons/wsdisplayvar.h>
76 #include <dev/wscons/wsconsio.h>
77 #include <dev/wscons/unicode.h>
78 
79 #include <dev/ic/pcdisplay.h>
80 
81 static struct vgafont {
82 	char name[WSFONT_NAME_SIZE];
83 	int height;
84 	int encoding;
85 #ifdef notyet
86 	int firstchar, numchars;
87 #endif
88 	int slot;
89 } vga_builtinfont = {
90 	"builtin",
91 	16,
92 	WSDISPLAY_FONTENC_IBM,
93 #ifdef notyet
94 	0, 256,
95 #endif
96 	0
97 };
98 
99 struct vgascreen {
100 	struct pcdisplayscreen pcs;
101 
102 	LIST_ENTRY(vgascreen) next;
103 
104 	struct vga_config *cfg;
105 
106 	/* videostate */
107 	struct vgafont *fontset1, *fontset2;
108 	/* font data */
109 
110 	int mindispoffset, maxdispoffset;
111 	int vga_rollover;
112 };
113 
114 int vgaconsole, vga_console_type, vga_console_attached;
115 struct vgascreen vga_console_screen;
116 struct vga_config vga_console_vc;
117 
118 int	vga_selectfont(struct vga_config *, struct vgascreen *,
119     const char *, const char *);
120 void	vga_init_screen(struct vga_config *, struct vgascreen *,
121     const struct wsscreen_descr *, int, long *);
122 void	vga_init(struct vga_config *, bus_space_tag_t, bus_space_tag_t);
123 void	vga_setfont(struct vga_config *, struct vgascreen *);
124 
125 int	vga_mapchar(void *, int, unsigned int *);
126 void	vga_putchar(void *, int, int, u_int, long);
127 int	vga_alloc_attr(void *, int, int, int, long *);
128 void	vga_copyrows(void *, int, int, int);
129 void	vga_unpack_attr(void *, long, int *, int *, int *);
130 
131 int	displaysubmatch(struct device *, void *, void *);
132 
133 static const struct wsdisplay_emulops vga_emulops = {
134 	pcdisplay_cursor,
135 	vga_mapchar,
136 	vga_putchar,
137 	pcdisplay_copycols,
138 	pcdisplay_erasecols,
139 	vga_copyrows,
140 	pcdisplay_eraserows,
141 	vga_alloc_attr,
142 	vga_unpack_attr
143 };
144 
145 /*
146  * translate WS(=ANSI) color codes to standard pc ones
147  */
148 static const unsigned char fgansitopc[] = {
149 #ifdef __alpha__
150 	/*
151 	 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
152 	 * XXX We should probably not bother with this
153 	 * XXX (reinitialize the palette registers).
154 	 */
155 	FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED,
156 	FG_MAGENTA, FG_BROWN, FG_LIGHTGREY
157 #else
158 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
159 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
160 #endif
161 }, bgansitopc[] = {
162 #ifdef __alpha__
163 	BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED,
164 	BG_MAGENTA, BG_BROWN, BG_LIGHTGREY
165 #else
166 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
167 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
168 #endif
169 };
170 
171 /*
172  * translate standard pc color codes to WS(=ANSI) ones
173  */
174 static const u_int8_t pctoansi[] = {
175 #ifdef __alpha__
176 	WSCOL_BLACK, WSCOL_RED, WSCOL_GREEN, WSCOL_BROWN,
177 	WSCOL_BLUE, WSCOL_MAGENTA, WSCOL_CYAN, WSCOL_WHITE
178 #else
179 	WSCOL_BLACK, WSCOL_BLUE, WSCOL_GREEN, WSCOL_CYAN,
180 	WSCOL_RED, WSCOL_MAGENTA, WSCOL_BROWN, WSCOL_WHITE
181 #endif
182 };
183 
184 
185 const struct wsscreen_descr vga_stdscreen = {
186 	"80x25", 80, 25,
187 	&vga_emulops,
188 	8, 16,
189 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
190 }, vga_stdscreen_mono = {
191 	"80x25", 80, 25,
192 	&vga_emulops,
193 	8, 16,
194 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
195 }, vga_stdscreen_bf = {
196 	"80x25bf", 80, 25,
197 	&vga_emulops,
198 	8, 16,
199 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
200 }, vga_40lscreen = {
201 	"80x40", 80, 40,
202 	&vga_emulops,
203 	8, 10,
204 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
205 }, vga_40lscreen_mono = {
206 	"80x40", 80, 40,
207 	&vga_emulops,
208 	8, 10,
209 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
210 }, vga_40lscreen_bf = {
211 	"80x40bf", 80, 40,
212 	&vga_emulops,
213 	8, 10,
214 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
215 }, vga_50lscreen = {
216 	"80x50", 80, 50,
217 	&vga_emulops,
218 	8, 8,
219 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK
220 }, vga_50lscreen_mono = {
221 	"80x50", 80, 50,
222 	&vga_emulops,
223 	8, 8,
224 	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
225 }, vga_50lscreen_bf = {
226 	"80x50bf", 80, 50,
227 	&vga_emulops,
228 	8, 8,
229 	WSSCREEN_WSCOLORS | WSSCREEN_BLINK
230 };
231 
232 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT))
233 
234 const struct wsscreen_descr *_vga_scrlist[] = {
235 	&vga_stdscreen,
236 	&vga_stdscreen_bf,
237 	&vga_40lscreen,
238 	&vga_40lscreen_bf,
239 	&vga_50lscreen,
240 	&vga_50lscreen_bf,
241 	/* XXX other formats, graphics screen? */
242 }, *_vga_scrlist_mono[] = {
243 	&vga_stdscreen_mono,
244 	&vga_40lscreen_mono,
245 	&vga_50lscreen_mono,
246 	/* XXX other formats, graphics screen? */
247 };
248 
249 const struct wsscreen_list vga_screenlist = {
250 	sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *),
251 	_vga_scrlist
252 }, vga_screenlist_mono = {
253 	sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *),
254 	_vga_scrlist_mono
255 };
256 
257 int	vga_ioctl(void *, u_long, caddr_t, int, struct proc *);
258 paddr_t	vga_mmap(void *, off_t, int);
259 int	vga_alloc_screen(void *, const struct wsscreen_descr *,
260 			 void **, int *, int *, long *);
261 void	vga_free_screen(void *, void *);
262 int	vga_show_screen(void *, void *, int,
263 			void (*) (void *, int, int), void *);
264 int	vga_load_font(void *, void *, struct wsdisplay_font *);
265 void	vga_scrollback(void *, void *, int);
266 void	vga_burner(void *v, u_int on, u_int flags);
267 int	vga_getchar(void *, int, int, struct wsdisplay_charcell *);
268 
269 void vga_doswitch(struct vga_config *);
270 
271 const struct wsdisplay_accessops vga_accessops = {
272 	vga_ioctl,
273 	vga_mmap,
274 	vga_alloc_screen,
275 	vga_free_screen,
276 	vga_show_screen,
277 	vga_load_font,
278 	vga_scrollback,
279 	vga_getchar,
280 	vga_burner
281 };
282 
283 /*
284  * The following functions implement back-end configuration grabbing
285  * and attachment.
286  */
287 int
288 vga_common_probe(iot, memt)
289 	bus_space_tag_t iot, memt;
290 {
291 	bus_space_handle_t ioh_vga, ioh_6845, memh;
292 	u_int8_t regval;
293 	u_int16_t vgadata;
294 	int gotio_vga, gotio_6845, gotmem, mono, rv;
295 	int dispoffset;
296 
297 	gotio_vga = gotio_6845 = gotmem = rv = 0;
298 
299 	if (bus_space_map(iot, 0x3c0, 0x10, 0, &ioh_vga))
300 		goto bad;
301 	gotio_vga = 1;
302 
303 	/* read "misc output register" */
304 	regval = bus_space_read_1(iot, ioh_vga, 0xc);
305 	mono = !(regval & 1);
306 
307 	if (bus_space_map(iot, (mono ? 0x3b0 : 0x3d0), 0x10, 0, &ioh_6845))
308 		goto bad;
309 	gotio_6845 = 1;
310 
311 	if (bus_space_map(memt, 0xa0000, 0x20000, 0, &memh))
312 		goto bad;
313 	gotmem = 1;
314 
315 	dispoffset = (mono ? 0x10000 : 0x18000);
316 
317 	vgadata = bus_space_read_2(memt, memh, dispoffset);
318 	bus_space_write_2(memt, memh, dispoffset, 0xa55a);
319 	if (bus_space_read_2(memt, memh, dispoffset) != 0xa55a)
320 		goto bad;
321 	bus_space_write_2(memt, memh, dispoffset, vgadata);
322 
323 	/*
324 	 * check if this is really a VGA
325 	 * (try to write "Color Select" register as XFree86 does)
326 	 * XXX check before if at least EGA?
327 	 */
328 	/* reset state */
329 	(void) bus_space_read_1(iot, ioh_6845, 10);
330 	bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX,
331 			  20 | 0x20); /* colselect | enable */
332 	regval = bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR);
333 	/* toggle the implemented bits */
334 	bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval ^ 0x0f);
335 	bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX,
336 			  20 | 0x20);
337 	/* read back */
338 	if (bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR) != (regval ^ 0x0f))
339 		goto bad;
340 	/* restore contents */
341 	bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval);
342 
343 	rv = 1;
344 bad:
345 	if (gotio_vga)
346 		bus_space_unmap(iot, ioh_vga, 0x10);
347 	if (gotio_6845)
348 		bus_space_unmap(iot, ioh_6845, 0x10);
349 	if (gotmem)
350 		bus_space_unmap(memt, memh, 0x20000);
351 
352 	return (rv);
353 }
354 
355 /*
356  * We want at least ASCII 32..127 be present in the
357  * first font slot.
358  */
359 #define vga_valid_primary_font(f) \
360 	(f->encoding == WSDISPLAY_FONTENC_IBM || \
361 	f->encoding == WSDISPLAY_FONTENC_ISO)
362 
363 int
364 vga_selectfont(vc, scr, name1, name2)
365 	struct vga_config *vc;
366 	struct vgascreen *scr;
367 	const char *name1, *name2; /* NULL: take first found */
368 {
369 	const struct wsscreen_descr *type = scr->pcs.type;
370 	struct vgafont *f1, *f2;
371 	int i;
372 
373 	f1 = f2 = 0;
374 
375 	for (i = 0; i < 8; i++) {
376 		struct vgafont *f = vc->vc_fonts[i];
377 		if (!f || f->height != type->fontheight)
378 			continue;
379 		if (!f1 &&
380 		    vga_valid_primary_font(f) &&
381 		    (!name1 || !*name1 ||
382 		     !strncmp(name1, f->name, WSFONT_NAME_SIZE))) {
383 			f1 = f;
384 			continue;
385 		}
386 		if (!f2 &&
387 		    VGA_SCREEN_CANTWOFONTS(type) &&
388 		    (!name2 || !*name2 ||
389 		     !strncmp(name2, f->name, WSFONT_NAME_SIZE))) {
390 			f2 = f;
391 			continue;
392 		}
393 	}
394 
395 	/*
396 	 * The request fails if no primary font was found,
397 	 * or if a second font was requested but not found.
398 	 */
399 	if (f1 && (!name2 || !*name2 || f2)) {
400 #ifdef VGAFONTDEBUG
401 		if (scr != &vga_console_screen || vga_console_attached) {
402 			printf("vga (%s): font1=%s (slot %d)", type->name,
403 			       f1->name, f1->slot);
404 			if (f2)
405 				printf(", font2=%s (slot %d)",
406 				       f2->name, f2->slot);
407 			printf("\n");
408 		}
409 #endif
410 		scr->fontset1 = f1;
411 		scr->fontset2 = f2;
412 		return (0);
413 	}
414 	return (ENXIO);
415 }
416 
417 void
418 vga_init_screen(vc, scr, type, existing, attrp)
419 	struct vga_config *vc;
420 	struct vgascreen *scr;
421 	const struct wsscreen_descr *type;
422 	int existing;
423 	long *attrp;
424 {
425 	int cpos;
426 	int res;
427 
428 	scr->cfg = vc;
429 	scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl;
430 	scr->pcs.type = type;
431 	scr->pcs.active = 0;
432 	scr->mindispoffset = 0;
433 	scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2;
434 
435 	if (existing) {
436 		cpos = vga_6845_read(&vc->hdl, cursorh) << 8;
437 		cpos |= vga_6845_read(&vc->hdl, cursorl);
438 
439 		/* make sure we have a valid cursor position */
440 		if (cpos < 0 || cpos >= type->nrows * type->ncols)
441 			cpos = 0;
442 
443 		scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9;
444 		scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1;
445 
446 		/* make sure we have a valid memory offset */
447 		if (scr->pcs.dispoffset < scr->mindispoffset ||
448 		    scr->pcs.dispoffset > scr->maxdispoffset)
449 			scr->pcs.dispoffset = scr->mindispoffset;
450 	} else {
451 		cpos = 0;
452 		scr->pcs.dispoffset = scr->mindispoffset;
453 	}
454 	scr->pcs.visibleoffset = scr->pcs.dispoffset;
455 	scr->vga_rollover = 0;
456 
457 	scr->pcs.vc_crow = cpos / type->ncols;
458 	scr->pcs.vc_ccol = cpos % type->ncols;
459 	pcdisplay_cursor_init(&scr->pcs, existing);
460 
461 #ifdef __alpha__
462 	if (!vc->hdl.vh_mono)
463 		/*
464 		 * DEC firmware uses a blue background.
465 		 */
466 		res = vga_alloc_attr(scr, WSCOL_WHITE, WSCOL_BLUE,
467 				     WSATTR_WSCOLORS, attrp);
468 	else
469 #endif
470 	res = vga_alloc_attr(scr, 0, 0, 0, attrp);
471 #ifdef DIAGNOSTIC
472 	if (res)
473 		panic("vga_init_screen: attribute botch");
474 #endif
475 
476 	scr->pcs.mem = NULL;
477 
478 	scr->fontset1 = scr->fontset2 = 0;
479 	if (vga_selectfont(vc, scr, 0, 0)) {
480 		if (scr == &vga_console_screen)
481 			panic("vga_init_screen: no font");
482 		else
483 			printf("vga_init_screen: no font\n");
484 	}
485 
486 	vc->nscreens++;
487 	LIST_INSERT_HEAD(&vc->screens, scr, next);
488 }
489 
490 void
491 vga_init(vc, iot, memt)
492 	struct vga_config *vc;
493 	bus_space_tag_t iot, memt;
494 {
495 	struct vga_handle *vh = &vc->hdl;
496 	u_int8_t mor;
497 	int i;
498 
499         vh->vh_iot = iot;
500         vh->vh_memt = memt;
501 
502         if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
503                 panic("vga_common_setup: can't map vga i/o");
504 
505 	/* read "misc output register" */
506 	mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, 0xc);
507 	vh->vh_mono = !(mor & 1);
508 
509 	if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
510 			  &vh->vh_ioh_6845))
511                 panic("vga_common_setup: can't map 6845 i/o");
512 
513         if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh))
514                 panic("vga_common_setup: can't map mem space");
515 
516         if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh,
517 				(vh->vh_mono ? 0x10000 : 0x18000), 0x8000,
518 				&vh->vh_memh))
519                 panic("vga_common_setup: mem subrange failed");
520 
521 	vc->nscreens = 0;
522 	LIST_INIT(&vc->screens);
523 	vc->active = NULL;
524 	vc->currenttype = vh->vh_mono ? &vga_stdscreen_mono : &vga_stdscreen;
525 #if 0
526 	callout_init(&vc->vc_switch_callout);
527 #endif
528 
529 	vc->vc_fonts[0] = &vga_builtinfont;
530 	for (i = 1; i < 8; i++)
531 		vc->vc_fonts[i] = 0;
532 
533 	vc->currentfontset1 = vc->currentfontset2 = 0;
534 
535 	vga_save_palette(vc);
536 }
537 
538 void
539 vga_common_attach(self, iot, memt, type)
540 	struct device *self;
541 	bus_space_tag_t iot, memt;
542 	int type;
543 {
544 	vga_extended_attach(self, iot, memt, type, NULL);
545 }
546 
547 void
548 vga_extended_attach(self, iot, memt, type, map)
549 	struct device *self;
550 	bus_space_tag_t iot, memt;
551 	int type;
552 	paddr_t (*map)(void *, off_t, int);
553 {
554 	int console;
555 	struct vga_config *vc;
556 	struct wsemuldisplaydev_attach_args aa;
557 
558 	console = vga_is_console(iot, type);
559 
560 	if (console) {
561 		vc = &vga_console_vc;
562 		vga_console_attached = 1;
563 	} else {
564 		vc = malloc(sizeof(*vc), M_DEVBUF, M_NOWAIT | M_ZERO);
565 		if (vc == NULL)
566 			return;
567 		vga_init(vc, iot, memt);
568 	}
569 
570 	vc->vc_softc = self;
571 	vc->vc_type = type;
572 	vc->vc_mmap = map;
573 
574 	aa.console = console;
575 	aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
576 	aa.accessops = &vga_accessops;
577 	aa.accesscookie = vc;
578 	aa.defaultscreens = 0;
579 
580         config_found_sm(self, &aa, wsemuldisplaydevprint, displaysubmatch);
581 }
582 
583 int
584 displaysubmatch(struct device *parent, void *match, void *aux)
585 {
586 	extern struct cfdriver wsdisplay_cd;
587 	struct cfdata *cf = match;
588 
589 	/* only allow wsdisplay to attach */
590 	if (cf->cf_driver == &wsdisplay_cd)
591 		return ((*cf->cf_attach->ca_match)(parent, match, aux));
592 	return (0);
593 }
594 
595 int
596 vga_cnattach(iot, memt, type, check)
597 	bus_space_tag_t iot, memt;
598 	int type, check;
599 {
600 	long defattr;
601 	const struct wsscreen_descr *scr;
602 
603 	if (check && !vga_common_probe(iot, memt))
604 		return (ENXIO);
605 
606 	/* set up bus-independent VGA configuration */
607 	vga_init(&vga_console_vc, iot, memt);
608 	scr = vga_console_vc.currenttype;
609 	vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr);
610 
611 	vga_console_screen.pcs.active = 1;
612 	vga_console_vc.active = &vga_console_screen;
613 
614 	wsdisplay_cnattach(scr, &vga_console_screen,
615 			   vga_console_screen.pcs.vc_ccol,
616 			   vga_console_screen.pcs.vc_crow,
617 			   defattr);
618 
619 	vgaconsole = 1;
620 	vga_console_type = type;
621 	return (0);
622 }
623 
624 int
625 vga_is_console(iot, type)
626 	bus_space_tag_t iot;
627 	int type;
628 {
629 	if (vgaconsole &&
630 	    !vga_console_attached &&
631 	    iot == vga_console_vc.hdl.vh_iot &&
632 	    (vga_console_type == -1 || (type == vga_console_type)))
633 		return (1);
634 	return (0);
635 }
636 
637 int
638 vga_ioctl(v, cmd, data, flag, p)
639 	void *v;
640 	u_long cmd;
641 	caddr_t data;
642 	int flag;
643 	struct proc *p;
644 {
645 	struct vga_config *vc = v;
646 	int mode;
647 #if NVGA_PCI > 0
648 	int error;
649 
650 	if (vc->vc_type == WSDISPLAY_TYPE_PCIVGA &&
651 	    (error = vga_pci_ioctl(v, cmd, data, flag, p)) != ENOTTY)
652 		return (error);
653 #endif
654 
655 	switch (cmd) {
656 	case WSDISPLAYIO_GTYPE:
657 		*(int *)data = vc->vc_type;
658 		/* XXX should get detailed hardware information here */
659 		break;
660 
661 	case WSDISPLAYIO_SMODE:
662 		mode = *(u_int *)data;
663 		if (mode == WSDISPLAYIO_MODE_EMUL)
664 			vga_restore_palette(vc);
665 		break;
666 
667 	case WSDISPLAYIO_GVIDEO:
668 	case WSDISPLAYIO_SVIDEO:
669 		break;
670 
671 	case WSDISPLAYIO_GINFO:
672 	case WSDISPLAYIO_GETCMAP:
673 	case WSDISPLAYIO_PUTCMAP:
674 	case WSDISPLAYIO_GCURPOS:
675 	case WSDISPLAYIO_SCURPOS:
676 	case WSDISPLAYIO_GCURMAX:
677 	case WSDISPLAYIO_GCURSOR:
678 	case WSDISPLAYIO_SCURSOR:
679 	default:
680 		/* NONE of these operations are by the generic VGA driver. */
681 		return ENOTTY;
682 	}
683 
684 	return (0);
685 }
686 
687 paddr_t
688 vga_mmap(v, offset, prot)
689 	void *v;
690 	off_t offset;
691 	int prot;
692 {
693 	struct vga_config *vc = v;
694 
695 	if (vc->vc_mmap != NULL)
696 		return (*vc->vc_mmap)(v, offset, prot);
697 
698 	return -1;
699 }
700 
701 int
702 vga_alloc_screen(v, type, cookiep, curxp, curyp, defattrp)
703 	void *v;
704 	const struct wsscreen_descr *type;
705 	void **cookiep;
706 	int *curxp, *curyp;
707 	long *defattrp;
708 {
709 	struct vga_config *vc = v;
710 	struct vgascreen *scr;
711 
712 	if (vc->nscreens == 1) {
713 		/*
714 		 * When allocating the second screen, get backing store
715 		 * for the first one too.
716 		 * XXX We could be more clever and use video RAM.
717 		 */
718 		LIST_FIRST(&vc->screens)->pcs.mem =
719 		  malloc(type->ncols * type->nrows * 2, M_DEVBUF, M_WAITOK);
720 	}
721 
722 	scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
723 	vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
724 
725 	if (vc->nscreens == 1) {
726 		scr->pcs.active = 1;
727 		vc->active = scr;
728 		vc->currenttype = type;
729 	} else {
730 		scr->pcs.mem = malloc(type->ncols * type->nrows * 2,
731 				      M_DEVBUF, M_WAITOK);
732 		pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp);
733 	}
734 
735 	*cookiep = scr;
736 	*curxp = scr->pcs.vc_ccol;
737 	*curyp = scr->pcs.vc_crow;
738 
739 	return (0);
740 }
741 
742 void
743 vga_free_screen(v, cookie)
744 	void *v;
745 	void *cookie;
746 {
747 	struct vgascreen *vs = cookie;
748 	struct vga_config *vc = vs->cfg;
749 
750 	LIST_REMOVE(vs, next);
751 	vc->nscreens--;
752 	if (vs != &vga_console_screen) {
753 		/*
754 		 * deallocating the one but last screen
755 		 * removes backing store for the last one
756 		 */
757 		if (vc->nscreens == 1)
758 			free(LIST_FIRST(&vc->screens)->pcs.mem, M_DEVBUF);
759 
760 		/* Last screen has no backing store */
761 		if (vc->nscreens != 0)
762 			free(vs->pcs.mem, M_DEVBUF);
763 
764 		free(vs, M_DEVBUF);
765 	} else
766 		panic("vga_free_screen: console");
767 
768 	if (vc->active == vs)
769 		vc->active = NULL;
770 }
771 
772 void
773 vga_setfont(vc, scr)
774 	struct vga_config *vc;
775 	struct vgascreen *scr;
776 {
777 	int fontslot1, fontslot2;
778 
779 	fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0);
780 	fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1);
781 	if (vc->currentfontset1 != fontslot1 ||
782 	    vc->currentfontset2 != fontslot2) {
783 		vga_setfontset(&vc->hdl, fontslot1, fontslot2);
784 		vc->currentfontset1 = fontslot1;
785 		vc->currentfontset2 = fontslot2;
786 	}
787 }
788 
789 int
790 vga_show_screen(v, cookie, waitok, cb, cbarg)
791 	void *v;
792 	void *cookie;
793 	int waitok;
794 	void (*cb)(void *, int, int);
795 	void *cbarg;
796 {
797 	struct vgascreen *scr = cookie, *oldscr;
798 	struct vga_config *vc = scr->cfg;
799 
800 	oldscr = vc->active; /* can be NULL! */
801 	if (scr == oldscr) {
802 		return (0);
803 	}
804 
805 	vc->wantedscreen = cookie;
806 	vc->switchcb = cb;
807 	vc->switchcbarg = cbarg;
808 	if (cb) {
809 		timeout_set(&vc->vc_switch_timeout,
810 		    (void(*)(void *))vga_doswitch, vc);
811 		timeout_add(&vc->vc_switch_timeout, 0);
812 		return (EAGAIN);
813 	}
814 
815 	vga_doswitch(vc);
816 	return (0);
817 }
818 
819 void
820 vga_doswitch(vc)
821 	struct vga_config *vc;
822 {
823 	struct vgascreen *scr, *oldscr;
824 	struct vga_handle *vh = &vc->hdl;
825 	const struct wsscreen_descr *type;
826 
827 	scr = vc->wantedscreen;
828 	if (!scr) {
829 		printf("vga_doswitch: disappeared\n");
830 		(*vc->switchcb)(vc->switchcbarg, EIO, 0);
831 		return;
832 	}
833 	type = scr->pcs.type;
834 	oldscr = vc->active; /* can be NULL! */
835 #ifdef DIAGNOSTIC
836 	if (oldscr) {
837 		if (!oldscr->pcs.active)
838 			panic("vga_show_screen: not active");
839 		if (oldscr->pcs.type != vc->currenttype)
840 			panic("vga_show_screen: bad type");
841 	}
842 #endif
843 	if (scr == oldscr) {
844 		return;
845 	}
846 #ifdef DIAGNOSTIC
847 	if (scr->pcs.active)
848 		panic("vga_show_screen: active");
849 #endif
850 
851 	scr->vga_rollover = 0;
852 
853 	if (oldscr) {
854 		const struct wsscreen_descr *oldtype = oldscr->pcs.type;
855 
856 		oldscr->pcs.active = 0;
857 		bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
858 					oldscr->pcs.dispoffset, oldscr->pcs.mem,
859 					oldtype->ncols * oldtype->nrows);
860 	}
861 
862 	if (vc->currenttype != type) {
863 		vga_setscreentype(vh, type);
864 		vc->currenttype = type;
865 	}
866 
867 	vga_setfont(vc, scr);
868 	vga_restore_palette(vc);
869 
870 	scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset;
871 	if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
872 		vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9);
873 		vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1);
874 	}
875 
876 	bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
877 				scr->pcs.dispoffset, scr->pcs.mem,
878 				type->ncols * type->nrows);
879 	scr->pcs.active = 1;
880 
881 	vc->active = scr;
882 
883 	pcdisplay_cursor_reset(&scr->pcs);
884 	pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron,
885 			 scr->pcs.vc_crow, scr->pcs.vc_ccol);
886 
887 	vc->wantedscreen = 0;
888 	if (vc->switchcb)
889 		(*vc->switchcb)(vc->switchcbarg, 0, 0);
890 }
891 
892 int
893 vga_load_font(v, cookie, data)
894 	void *v;
895 	void *cookie;
896 	struct wsdisplay_font *data;
897 {
898 	struct vga_config *vc = v;
899 	struct vgascreen *scr = cookie;
900 	char *name2;
901 	int res, slot;
902 	struct vgafont *f;
903 
904 	if (scr) {
905 		if ((name2 = data->name) != NULL) {
906 			while (*name2 && *name2 != ',')
907 				name2++;
908 			if (*name2)
909 				*name2++ = '\0';
910 		}
911 		res = vga_selectfont(vc, scr, data->name, name2);
912 		if (!res)
913 			vga_setfont(vc, scr);
914 		return (res);
915 	}
916 
917 	if (data->fontwidth != 8 || data->stride != 1)
918 		return (EINVAL); /* XXX 1 byte per line */
919 	if (data->firstchar != 0 || data->numchars != 256)
920 		return (EINVAL);
921 #ifndef WSCONS_SUPPORT_PCVTFONTS
922 	if (data->encoding == WSDISPLAY_FONTENC_PCVT) {
923 		printf("vga: pcvt font support not built in, see vga(4)\n");
924 		return (EINVAL);
925 	}
926 #endif
927 
928 	if (data->index < 0) {
929 		for (slot = 0; slot < 8; slot++)
930 			if (!vc->vc_fonts[slot])
931 				break;
932 	} else
933 		slot = data->index;
934 
935 	if (slot >= 8)
936 		return (ENOSPC);
937 
938 	if (vc->vc_fonts[slot] != NULL)
939 		return (EEXIST);
940 	f = malloc(sizeof(struct vgafont), M_DEVBUF, M_WAITOK | M_CANFAIL);
941 	if (f == NULL)
942 		return (ENOMEM);
943 	strlcpy(f->name, data->name, sizeof(f->name));
944 	f->height = data->fontheight;
945 	f->encoding = data->encoding;
946 #ifdef notyet
947 	f->firstchar = data->firstchar;
948 	f->numchars = data->numchars;
949 #endif
950 #ifdef VGAFONTDEBUG
951 	printf("vga: load %s (8x%d, enc %d) font to slot %d\n", f->name,
952 	       f->height, f->encoding, slot);
953 #endif
954 	vga_loadchars(&vc->hdl, slot, 0, 256, f->height, data->data);
955 	f->slot = slot;
956 	vc->vc_fonts[slot] = f;
957 	data->cookie = f;
958 	data->index = slot;
959 
960 	return (0);
961 }
962 
963 void
964 vga_scrollback(v, cookie, lines)
965 	void *v;
966 	void *cookie;
967 	int lines;
968 {
969 	struct vga_config *vc = v;
970 	struct vgascreen *scr = cookie;
971 	struct vga_handle *vh = &vc->hdl;
972 
973 	if (lines == 0) {
974 		if (scr->pcs.visibleoffset == scr->pcs.dispoffset)
975 			return;
976 
977 		scr->pcs.visibleoffset = scr->pcs.dispoffset;	/* reset */
978 	}
979 	else {
980 		int vga_scr_end;
981 		int margin = scr->pcs.type->ncols * 2;
982 		int ul, we, p, st;
983 
984 		vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols *
985 		    scr->pcs.type->nrows * 2);
986 		if (scr->vga_rollover > vga_scr_end + margin) {
987 			ul = vga_scr_end;
988 			we = scr->vga_rollover + scr->pcs.type->ncols * 2;
989 		} else {
990 			ul = 0;
991 			we = 0x8000;
992 		}
993 		p = (scr->pcs.visibleoffset - ul + we) % we + lines *
994 		    (scr->pcs.type->ncols * 2);
995 		st = (scr->pcs.dispoffset - ul + we) % we;
996 		if (p < margin)
997 			p = 0;
998 		if (p > st - margin)
999 			p = st;
1000 		scr->pcs.visibleoffset = (p + ul) % we;
1001 	}
1002 
1003 	/* update visible position */
1004 	vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9);
1005 	vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1);
1006 }
1007 
1008 int
1009 vga_alloc_attr(id, fg, bg, flags, attrp)
1010 	void *id;
1011 	int fg, bg;
1012 	int flags;
1013 	long *attrp;
1014 {
1015 	struct vgascreen *scr = id;
1016 	struct vga_config *vc = scr->cfg;
1017 
1018 	if (vc->hdl.vh_mono) {
1019 		if (flags & WSATTR_WSCOLORS)
1020 			return (EINVAL);
1021 		if (flags & WSATTR_REVERSE)
1022 			*attrp = 0x70;
1023 		else
1024 			*attrp = 0x07;
1025 		if (flags & WSATTR_UNDERLINE)
1026 			*attrp |= FG_UNDERLINE;
1027 		if (flags & WSATTR_HILIT)
1028 			*attrp |= FG_INTENSE;
1029 	} else {
1030 		if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
1031 			return (EINVAL);
1032 		if (flags & WSATTR_WSCOLORS)
1033 			*attrp = fgansitopc[fg & 7] | bgansitopc[bg & 7];
1034 		else
1035 			*attrp = 7;
1036 		if ((flags & WSATTR_HILIT) || (fg & 8) || (bg & 8))
1037 			*attrp += 8;
1038 	}
1039 	if (flags & WSATTR_BLINK)
1040 		*attrp |= FG_BLINK;
1041 	return (0);
1042 }
1043 
1044 void
1045 vga_unpack_attr(id, attr, fg, bg, ul)
1046 	void *id;
1047 	long attr;
1048 	int *fg, *bg, *ul;
1049 {
1050 	struct vgascreen *scr = id;
1051 	struct vga_config *vc = scr->cfg;
1052 
1053 	if (vc->hdl.vh_mono) {
1054 		*fg = (attr & 0x07) == 0x07 ? WSCOL_WHITE : WSCOL_BLACK;
1055 		*bg = attr & 0x70 ? WSCOL_WHITE : WSCOL_BLACK;
1056 		if (ul != NULL)
1057 			*ul = *fg != WSCOL_WHITE && (attr & 0x01) ? 1 : 0;
1058 	} else {
1059 		*fg = pctoansi[attr & 0x07];
1060 		*bg = pctoansi[(attr & 0x70) >> 4];
1061 		if (ul != NULL)
1062 			*ul = 0;
1063 	}
1064 	if (attr & FG_INTENSE)
1065 		*fg += 8;
1066 }
1067 
1068 void
1069 vga_copyrows(id, srcrow, dstrow, nrows)
1070 	void *id;
1071 	int srcrow, dstrow, nrows;
1072 {
1073 	struct vgascreen *scr = id;
1074 	bus_space_tag_t memt = scr->pcs.hdl->ph_memt;
1075 	bus_space_handle_t memh = scr->pcs.hdl->ph_memh;
1076 	int ncols = scr->pcs.type->ncols;
1077 	bus_size_t srcoff, dstoff;
1078 
1079 	srcoff = srcrow * ncols + 0;
1080 	dstoff = dstrow * ncols + 0;
1081 
1082 	if (scr->pcs.active) {
1083 		if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) {
1084 #ifdef PCDISPLAY_SOFTCURSOR
1085 			int cursoron = scr->pcs.cursoron;
1086 
1087 			if (cursoron)
1088 				pcdisplay_cursor(&scr->pcs, 0,
1089 				    scr->pcs.vc_crow, scr->pcs.vc_ccol);
1090 #endif
1091 			/* scroll up whole screen */
1092 			if ((scr->pcs.dispoffset + srcrow * ncols * 2)
1093 			    <= scr->maxdispoffset) {
1094 				scr->pcs.dispoffset += srcrow * ncols * 2;
1095 			} else {
1096 				bus_space_copy_2(memt, memh,
1097 					scr->pcs.dispoffset + srcoff * 2,
1098 					memh, scr->mindispoffset,
1099 					nrows * ncols);
1100 				scr->vga_rollover = scr->pcs.dispoffset;
1101 				scr->pcs.dispoffset = scr->mindispoffset;
1102 			}
1103 			scr->pcs.visibleoffset = scr->pcs.dispoffset;
1104 			vga_6845_write(&scr->cfg->hdl, startadrh,
1105 				       scr->pcs.dispoffset >> 9);
1106 			vga_6845_write(&scr->cfg->hdl, startadrl,
1107 				       scr->pcs.dispoffset >> 1);
1108 #ifdef PCDISPLAY_SOFTCURSOR
1109 			if (cursoron)
1110 				pcdisplay_cursor(&scr->pcs, 1,
1111 				    scr->pcs.vc_crow, scr->pcs.vc_ccol);
1112 #endif
1113 		} else {
1114 			bus_space_copy_2(memt, memh,
1115 					scr->pcs.dispoffset + srcoff * 2,
1116 					memh, scr->pcs.dispoffset + dstoff * 2,
1117 					nrows * ncols);
1118 		}
1119 	} else
1120 		bcopy(&scr->pcs.mem[srcoff], &scr->pcs.mem[dstoff],
1121 		      nrows * ncols * 2);
1122 }
1123 
1124 #ifdef WSCONS_SUPPORT_PCVTFONTS
1125 
1126 #define NOTYET 0xffff
1127 static u_int16_t pcvt_unichars[0xa0] = {
1128 /* 0 */	_e006U,
1129 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1130 	NOTYET,
1131 	0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */
1132 	0x240a, /* SYMBOL FOR LINE FEED */
1133 	0x240b, /* SYMBOL FOR VERTICAL TABULATION */
1134 	0x240c, /* SYMBOL FOR FORM FEED */
1135 	0x240d, /* SYMBOL FOR CARRIAGE RETURN */
1136 	NOTYET, NOTYET,
1137 /* 1 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1138 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1139 /* 2 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1140 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1141 /* 3 */	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1142 	NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1143 /* 4 */	0x03c1, /* GREEK SMALL LETTER RHO */
1144 	0x03c8, /* GREEK SMALL LETTER PSI */
1145 	0x2202, /* PARTIAL DIFFERENTIAL */
1146 	0x03bb, /* GREEK SMALL LETTER LAMDA */
1147 	0x03b9, /* GREEK SMALL LETTER IOTA */
1148 	0x03b7, /* GREEK SMALL LETTER ETA */
1149 	0x03b5, /* GREEK SMALL LETTER EPSILON */
1150 	0x03c7, /* GREEK SMALL LETTER CHI */
1151 	0x2228, /* LOGICAL OR */
1152 	0x2227, /* LOGICAL AND */
1153 	0x222a, /* UNION */
1154 	0x2283, /* SUPERSET OF */
1155 	0x2282, /* SUBSET OF */
1156 	0x03a5, /* GREEK CAPITAL LETTER UPSILON */
1157 	0x039e, /* GREEK CAPITAL LETTER XI */
1158 	0x03a8, /* GREEK CAPITAL LETTER PSI */
1159 /* 5 */	0x03a0, /* GREEK CAPITAL LETTER PI */
1160 	0x21d2, /* RIGHTWARDS DOUBLE ARROW */
1161 	0x21d4, /* LEFT RIGHT DOUBLE ARROW */
1162 	0x039b, /* GREEK CAPITAL LETTER LAMDA */
1163 	0x0398, /* GREEK CAPITAL LETTER THETA */
1164 	0x2243, /* ASYMPTOTICALLY EQUAL TO */
1165 	0x2207, /* NABLA */
1166 	0x2206, /* INCREMENT */
1167 	0x221d, /* PROPORTIONAL TO */
1168 	0x2234, /* THEREFORE */
1169 	0x222b, /* INTEGRAL */
1170 	0x2215, /* DIVISION SLASH */
1171 	0x2216, /* SET MINUS */
1172 	_e00eU,
1173 	_e00dU,
1174 	_e00bU,
1175 /* 6 */	_e00cU,
1176 	_e007U,
1177 	_e008U,
1178 	_e009U,
1179 	_e00aU,
1180 	0x221a, /* SQUARE ROOT */
1181 	0x03c9, /* GREEK SMALL LETTER OMEGA */
1182 	0x00a5, /* YEN SIGN */
1183 	0x03be, /* GREEK SMALL LETTER XI */
1184 	0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */
1185 	0x00fe, /* LATIN SMALL LETTER THORN */
1186 	0x00f0, /* LATIN SMALL LETTER ETH */
1187 	0x00de, /* LATIN CAPITAL LETTER THORN */
1188 	0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
1189 	0x00d7, /* MULTIPLICATION SIGN */
1190 	0x00d0, /* LATIN CAPITAL LETTER ETH */
1191 /* 7 */	0x00be, /* VULGAR FRACTION THREE QUARTERS */
1192 	0x00b8, /* CEDILLA */
1193 	0x00b4, /* ACUTE ACCENT */
1194 	0x00af, /* MACRON */
1195 	0x00ae, /* REGISTERED SIGN */
1196 	0x00ad, /* SOFT HYPHEN */
1197 	0x00ac, /* NOT SIGN */
1198 	0x00a8, /* DIAERESIS */
1199 	0x2260, /* NOT EQUAL TO */
1200 	_e005U,
1201 	_e004U,
1202 	_e003U,
1203 	_e002U,
1204 	_e001U,
1205 	0x03c5, /* GREEK SMALL LETTER UPSILON */
1206 	0x00f8, /* LATIN SMALL LETTER O WITH STROKE */
1207 /* 8 */	0x0153, /* LATIN SMALL LIGATURE OE */
1208 	0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */
1209 	0x00e3, /* LATIN SMALL LETTER A WITH TILDE */
1210 	0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1211 	0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1212 	0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
1213 	0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
1214 	0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
1215 	0x0152, /* LATIN CAPITAL LIGATURE OE */
1216 	0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
1217 	0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1218 	0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
1219 	0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
1220 	0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1221 	0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1222 	0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
1223 /* 9 */	0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
1224 	0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1225 	0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1226 	0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
1227 	0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
1228 	0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1229 	0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
1230 	0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
1231 	0x00b9, /* SUPERSCRIPT ONE */
1232 	0x00b7, /* MIDDLE DOT */
1233 	0x03b6, /* GREEK SMALL LETTER ZETA */
1234 	0x00b3, /* SUPERSCRIPT THREE */
1235 	0x00a9, /* COPYRIGHT SIGN */
1236 	0x00a4, /* CURRENCY SIGN */
1237 	0x03ba, /* GREEK SMALL LETTER KAPPA */
1238 	_e000U
1239 };
1240 
1241 int vga_pcvt_mapchar(int, unsigned int *);
1242 
1243 int
1244 vga_pcvt_mapchar(uni, index)
1245 	int uni;
1246 	unsigned int *index;
1247 {
1248 	int i;
1249 
1250 	for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */
1251 		if (uni == pcvt_unichars[i]) {
1252 			*index = i;
1253 			return (5);
1254 		}
1255 	*index = 0x99; /* middle dot */
1256 	return (0);
1257 }
1258 
1259 #endif /* WSCONS_SUPPORT_PCVTFONTS */
1260 
1261 int _vga_mapchar(void *, struct vgafont *, int, unsigned int *);
1262 
1263 int
1264 _vga_mapchar(id, font, uni, index)
1265 	void *id;
1266 	struct vgafont *font;
1267 	int uni;
1268 	unsigned int *index;
1269 {
1270 
1271 	switch (font->encoding) {
1272 	case WSDISPLAY_FONTENC_ISO:
1273 		if (uni < 256) {
1274 			*index = uni;
1275 			return (5);
1276 		} else {
1277 			*index = ' ';
1278 			return (0);
1279 		}
1280 		break;
1281 	case WSDISPLAY_FONTENC_IBM:
1282 		return (pcdisplay_mapchar(id, uni, index));
1283 #ifdef WSCONS_SUPPORT_PCVTFONTS
1284 	case WSDISPLAY_FONTENC_PCVT:
1285 		return (vga_pcvt_mapchar(uni, index));
1286 #endif
1287 	default:
1288 #ifdef VGAFONTDEBUG
1289 		printf("_vga_mapchar: encoding=%d\n", font->encoding);
1290 #endif
1291 		*index = ' ';
1292 		return (0);
1293 	}
1294 }
1295 
1296 int
1297 vga_mapchar(id, uni, index)
1298 	void *id;
1299 	int uni;
1300 	unsigned int *index;
1301 {
1302 	struct vgascreen *scr = id;
1303 	unsigned int idx1, idx2;
1304 	int res1, res2;
1305 
1306 	res1 = 0;
1307 	idx1 = ' '; /* space */
1308 	if (scr->fontset1)
1309 		res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1);
1310 	res2 = -1;
1311 	if (scr->fontset2) {
1312 		KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type));
1313 		res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2);
1314 	}
1315 	if (res2 >= res1) {
1316 		*index = idx2 | 0x0800; /* attribute bit 3 */
1317 		return (res2);
1318 	}
1319 	*index = idx1;
1320 	return (res1);
1321 }
1322 
1323 void
1324 vga_putchar(c, row, col, uc, attr)
1325 	void *c;
1326 	int row;
1327 	int col;
1328 	u_int uc;
1329 	long attr;
1330 {
1331 	struct vgascreen *scr = c;
1332 
1333 	if (scr->pcs.visibleoffset != scr->pcs.dispoffset)
1334 		vga_scrollback(scr->cfg, scr, 0);
1335 
1336 	pcdisplay_putchar(c, row, col, uc, attr);
1337 }
1338 
1339 void
1340 vga_burner(v, on, flags)
1341 	void *v;
1342 	u_int on, flags;
1343 {
1344 	struct vga_config *vc = v;
1345 	struct vga_handle *vh = &vc->hdl;
1346 	u_int8_t r;
1347 	int s;
1348 
1349 	s = splhigh();
1350 	vga_ts_write(vh, syncreset, 0x01);
1351 	if (on) {
1352 		vga_ts_write(vh, mode, (vga_ts_read(vh, mode) & ~0x20));
1353 		r = vga_6845_read(vh, mode) | 0x80;
1354 		DELAY(10000);
1355 		vga_6845_write(vh, mode, r);
1356 	} else {
1357 		vga_ts_write(vh, mode, (vga_ts_read(vh, mode) | 0x20));
1358 		if (flags & WSDISPLAY_BURN_VBLANK) {
1359 			r = vga_6845_read(vh, mode) & ~0x80;
1360 			DELAY(10000);
1361 			vga_6845_write(vh, mode, r);
1362 		}
1363 	}
1364 	vga_ts_write(vh, syncreset, 0x03);
1365 	splx(s);
1366 }
1367 
1368 int
1369 vga_getchar(c, row, col, cell)
1370 	void *c;
1371 	int row, col;
1372 	struct wsdisplay_charcell *cell;
1373 {
1374 	struct vga_config *vc = c;
1375 
1376 	return (pcdisplay_getchar(vc->active, row, col, cell));
1377 }
1378 
1379 void
1380 vga_save_palette(struct vga_config *vc)
1381 {
1382 	struct vga_handle *vh = &vc->hdl;
1383 	uint i;
1384 	uint8_t *palette = vc->vc_palette;
1385 
1386 	if (vh->vh_mono)
1387 		return;
1388 
1389 	vga_raw_write(vh, VGA_DAC_MASK, 0xff);
1390 	vga_raw_write(vh, VGA_DAC_READ, 0x00);
1391 	for (i = 0; i < 3 * 256; i++)
1392 		*palette++ = vga_raw_read(vh, VGA_DAC_DATA);
1393 
1394 	vga_raw_read(vh, 0x0a);			/* reset flip/flop */
1395 }
1396 
1397 void
1398 vga_restore_palette(struct vga_config *vc)
1399 {
1400 	struct vga_handle *vh = &vc->hdl;
1401 	uint i;
1402 	uint8_t *palette = vc->vc_palette;
1403 
1404 	if (vh->vh_mono)
1405 		return;
1406 
1407 	vga_raw_write(vh, VGA_DAC_MASK, 0xff);
1408 	vga_raw_write(vh, VGA_DAC_WRITE, 0x00);
1409 	for (i = 0; i < 3 * 256; i++)
1410 		vga_raw_write(vh, VGA_DAC_DATA, *palette++);
1411 
1412 	vga_raw_read(vh, 0x0a);			/* reset flip/flop */
1413 
1414 	vga_enable(vh);
1415 }
1416 
1417 struct cfdriver vga_cd = {
1418 	NULL, "vga", DV_DULL
1419 };
1420