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