1/*	$NetBSD: vga_raster.c,v 1.34 2010/03/24 19:33:51 tnn Exp $	*/
2
3/*
4 * Copyright (c) 2001, 2002 Bang Jun-Young
5 * Copyright (c) 2004 Julio M. Merino Vidal
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
33 * All rights reserved.
34 *
35 * Author: Chris G. Demetriou
36 *
37 * Permission to use, copy, modify and distribute this software and
38 * its documentation is hereby granted, provided that both the copyright
39 * notice and this permission notice appear in all copies of the
40 * software, derivative works or modified versions, and any portions
41 * thereof, and that both notices appear in supporting documentation.
42 *
43 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
44 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
45 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 *
47 * Carnegie Mellon requests users of this software to return to
48 *
49 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
50 *  School of Computer Science
51 *  Carnegie Mellon University
52 *  Pittsburgh PA 15213-3890
53 *
54 * any improvements or extensions that they make and grant Carnegie the
55 * rights to redistribute these changes.
56 */
57
58#include <sys/cdefs.h>
59__KERNEL_RCSID(0, "$NetBSD: vga_raster.c,v 1.34 2010/03/24 19:33:51 tnn Exp $");
60
61#include "opt_wsmsgattrs.h" /* for WSDISPLAY_CUSTOM_OUTPUT */
62
63#include <sys/param.h>
64#include <sys/systm.h>
65#include <sys/callout.h>
66#include <sys/kernel.h>
67#include <sys/device.h>
68#include <sys/malloc.h>
69#include <sys/queue.h>
70#include <sys/bus.h>
71
72#include <dev/ic/mc6845reg.h>
73#include <dev/ic/pcdisplayvar.h>
74#include <dev/ic/vgareg.h>
75#include <dev/ic/vgavar.h>
76#include <dev/videomode/videomode.h>
77
78#include <dev/wscons/wsdisplayvar.h>
79#include <dev/wscons/wsconsio.h>
80#include <dev/wsfont/wsfont.h>
81
82#include <dev/ic/pcdisplay.h>
83
84int vga_no_builtinfont = 0;
85
86u_int8_t builtinfont_data[256 * 16];
87
88struct wsdisplay_font builtinfont = {
89	"builtin",			/* typeface name */
90	0,				/* firstchar */
91	256,				/* numchars */
92	WSDISPLAY_FONTENC_IBM,		/* encoding */
93	8,				/* width */
94	16,				/* height */
95	1,				/* stride */
96	WSDISPLAY_FONTORDER_L2R,	/* bit order */
97	WSDISPLAY_FONTORDER_L2R,	/* byte order */
98	builtinfont_data		/* data */
99};
100
101struct vga_scrmem {
102	u_int16_t ch;
103	u_int8_t attr;
104	u_int8_t second;	/* XXXBJY should be u_int8_t len; */
105	u_int8_t enc;
106};
107
108#ifdef VGA_CONSOLE_SCREENTYPE
109#define VGA_SCRMEM_SIZE		(80 * 30)
110#else
111#define VGA_SCRMEM_SIZE		(80 * 25)
112#endif
113
114struct vga_scrmem boot_scrmem[VGA_SCRMEM_SIZE];
115
116struct vga_raster_font {
117	LIST_ENTRY(vga_raster_font) next;
118	struct wsdisplay_font *font;
119};
120
121struct vgascreen {
122	LIST_ENTRY(vgascreen) next;
123	struct vga_config *cfg;
124	struct vga_handle *hdl;
125	const struct wsscreen_descr *type;
126
127	int active;
128	struct vga_scrmem *mem;
129	int encoding;
130
131	int dispoffset;
132	int mindispoffset;
133	int maxdispoffset;
134
135	int cursoron;			/* Is cursor displayed? */
136	int cursorcol;			/* Current cursor column */
137	int cursorrow;			/* Current cursor row */
138	struct vga_scrmem cursortmp;
139	int cursorstride;
140
141	LIST_HEAD(, vga_raster_font) fontset;
142};
143
144struct vga_moderegs {
145	u_int8_t miscout;		/* Misc. output */
146	u_int8_t crtc[MC6845_NREGS];	/* CRTC controller */
147	u_int8_t atc[VGA_ATC_NREGS];	/* Attribute controller */
148	u_int8_t ts[VGA_TS_NREGS];	/* Time sequencer */
149	u_int8_t gdc[VGA_GDC_NREGS];	/* Graphics display controller */
150};
151
152static int vgaconsole, vga_console_type, vga_console_attached;
153static struct vgascreen vga_console_screen;
154static struct vga_config vga_console_vc;
155static struct vga_raster_font vga_console_fontset_ascii;
156static struct videomode vga_console_modes[2] = {
157	/* 640x400 for 80x25, 80x40 and 80x50 modes */
158	{
159		25175, 640, 664, 760, 800, 400, 409, 411, 450, 0, NULL,
160	},
161	/* 640x480 for 80x30 mode */
162	{
163		25175, 640, 664, 760, 800, 480, 491, 493, 525, 0, NULL,
164	}
165};
166
167static void vga_raster_init(struct vga_config *, bus_space_tag_t,
168		bus_space_tag_t);
169static void vga_raster_init_screen(struct vga_config *, struct vgascreen *,
170		const struct wsscreen_descr *, int, long *);
171static void vga_raster_setup_font(struct vga_config *, struct vgascreen *);
172static void vga_setup_regs(struct videomode *, struct vga_moderegs *);
173static void vga_set_mode(struct vga_handle *, struct vga_moderegs *);
174static void vga_restore_screen(struct vgascreen *,
175		const struct wsscreen_descr *, struct vga_scrmem *);
176static void vga_raster_cursor_init(struct vgascreen *, int);
177static void _vga_raster_putchar(void *, int, int, u_int, long,
178		struct vga_raster_font *);
179
180static void vga_raster_cursor(void *, int, int, int);
181static int  vga_raster_mapchar(void *, int, u_int *);
182static void vga_raster_putchar(void *, int, int, u_int, long);
183static void vga_raster_copycols(void *, int, int, int, int);
184static void vga_raster_erasecols(void *, int, int, int, long);
185static void vga_raster_copyrows(void *, int, int, int);
186static void vga_raster_eraserows(void *, int, int, long);
187static int  vga_raster_allocattr(void *, int, int, int, long *);
188#ifdef WSDISPLAY_CUSTOM_OUTPUT
189static void vga_raster_replaceattr(void *, long, long);
190#endif /* WSDISPLAY_CUSTOM_OUTPUT */
191
192const struct wsdisplay_emulops vga_raster_emulops = {
193	vga_raster_cursor,
194	vga_raster_mapchar,
195	vga_raster_putchar,
196	vga_raster_copycols,
197	vga_raster_erasecols,
198	vga_raster_copyrows,
199	vga_raster_eraserows,
200	vga_raster_allocattr,
201#ifdef WSDISPLAY_CUSTOM_OUTPUT
202	vga_raster_replaceattr,
203#else /* WSDISPLAY_CUSTOM_OUTPUT */
204	NULL,
205#endif /* WSDISPLAY_CUSTOM_OUTPUT */
206};
207
208/*
209 * translate WS(=ANSI) color codes to standard pc ones
210 */
211static const unsigned char fgansitopc[] = {
212#ifdef __alpha__
213	/*
214	 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
215	 * XXX We should probably not bother with this
216	 * XXX (reinitialize the palette registers).
217	 */
218	FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED,
219	FG_MAGENTA, FG_BROWN, FG_LIGHTGREY
220#else
221	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
222	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
223#endif
224}, bgansitopc[] = {
225#ifdef __alpha__
226	BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED,
227	BG_MAGENTA, BG_BROWN, BG_LIGHTGREY
228#else
229	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
230	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
231#endif
232};
233
234const struct wsscreen_descr vga_25lscreen = {
235	"80x25", 80, 25,
236	&vga_raster_emulops,
237	8, 16,
238	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
239	&vga_console_modes[0]
240}, vga_25lscreen_mono = {
241	"80x25", 80, 25,
242	&vga_raster_emulops,
243	8, 16,
244	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
245	&vga_console_modes[0]
246}, vga_30lscreen = {
247	"80x30", 80, 30,
248	&vga_raster_emulops,
249	8, 16,
250	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
251	&vga_console_modes[1]
252}, vga_30lscreen_mono = {
253	"80x30", 80, 30,
254	&vga_raster_emulops,
255	8, 16,
256	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
257	&vga_console_modes[1]
258}, vga_40lscreen = {
259	"80x40", 80, 40,
260	&vga_raster_emulops,
261	8, 10,
262	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
263	&vga_console_modes[0]
264}, vga_40lscreen_mono = {
265	"80x40", 80, 40,
266	&vga_raster_emulops,
267	8, 10,
268	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
269	&vga_console_modes[0]
270}, vga_50lscreen = {
271	"80x50", 80, 50,
272	&vga_raster_emulops,
273	8, 8,
274	WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
275	&vga_console_modes[0]
276}, vga_50lscreen_mono = {
277	"80x50", 80, 50,
278	&vga_raster_emulops,
279	8, 8,
280	WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
281	&vga_console_modes[0]
282};
283
284const struct wsscreen_descr *_vga_scrlist[] = {
285	&vga_25lscreen,
286	&vga_30lscreen,
287	&vga_40lscreen,
288	&vga_50lscreen,
289}, *_vga_scrlist_mono[] = {
290	&vga_25lscreen_mono,
291	&vga_30lscreen_mono,
292	&vga_40lscreen_mono,
293	&vga_50lscreen_mono,
294};
295
296const struct wsscreen_list vga_screenlist = {
297	sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *),
298	_vga_scrlist
299}, vga_screenlist_mono = {
300	sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *),
301	_vga_scrlist_mono
302};
303
304static int	vga_raster_ioctl(void *, void *, u_long, void *, int,
305		    struct lwp *);
306static paddr_t	vga_raster_mmap(void *, void *, off_t, int);
307static int	vga_raster_alloc_screen(void *, const struct wsscreen_descr *,
308		    void **, int *, int *, long *);
309static void	vga_raster_free_screen(void *, void *);
310static int	vga_raster_show_screen(void *, void *, int,
311		    void (*)(void *, int, int), void *);
312static int	vga_raster_load_font(void *, void *, struct wsdisplay_font *);
313
314static void 	vga_switch_screen(struct vga_config *);
315static void 	vga_raster_setscreentype(struct vga_config *,
316		    const struct wsscreen_descr *);
317
318const struct wsdisplay_accessops vga_raster_accessops = {
319	vga_raster_ioctl,
320	vga_raster_mmap,
321	vga_raster_alloc_screen,
322	vga_raster_free_screen,
323	vga_raster_show_screen,
324	vga_raster_load_font,
325	NULL,	/* pollc */
326	NULL,	/* scroll */
327};
328
329int
330vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
331{
332	long defattr;
333	const struct wsscreen_descr *scr;
334#ifdef VGA_CONSOLE_SCREENTYPE
335	const char *typestr = NULL;
336#endif
337
338	if (check && !vga_common_probe(iot, memt))
339		return (ENXIO);
340
341	/* set up bus-independent VGA configuration */
342	vga_raster_init(&vga_console_vc, iot, memt);
343#ifdef VGA_CONSOLE_SCREENTYPE
344	scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
345	    &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
346	if (!scr)
347		/* Invalid screen type, continue with the default mode. */
348		typestr = "80x25";
349	else if (scr->nrows > 30)
350		/* Unsupported screen type, try 80x30. */
351		typestr = "80x30";
352	if (typestr)
353		scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
354		    &vga_screenlist_mono : &vga_screenlist, typestr);
355	if (scr != vga_console_vc.currenttype)
356		vga_console_vc.currenttype = scr;
357#else
358	scr = vga_console_vc.currenttype;
359#endif
360	vga_raster_init_screen(&vga_console_vc, &vga_console_screen, scr, 1,
361	    &defattr);
362
363	vga_console_screen.active = 1;
364	vga_console_vc.active = &vga_console_screen;
365
366	wsdisplay_cnattach(scr, &vga_console_screen,
367	    vga_console_screen.cursorcol, vga_console_screen.cursorrow,
368	    defattr);
369
370	vgaconsole = 1;
371	vga_console_type = type;
372	return (0);
373}
374
375void
376vga_raster_init(struct vga_config *vc, bus_space_tag_t iot,
377    bus_space_tag_t memt)
378{
379	struct vga_handle *vh = &vc->hdl;
380	u_int8_t mor;
381	struct vga_raster_font *vf;
382
383	vh->vh_iot = iot;
384	vh->vh_memt = memt;
385
386	if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
387		panic("vga_raster_init: couldn't map vga io");
388
389	/* read "misc output register" */
390	mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAR);
391	vh->vh_mono = !(mor & 1);
392
393	if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
394	    &vh->vh_ioh_6845))
395		panic("vga_raster_init: couldn't map 6845 io");
396
397	if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh))
398		panic("vga_raster_init: couldn't map memory");
399
400	if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 0, 0x10000,
401	    &vh->vh_memh))
402		panic("vga_raster_init: mem subrange failed");
403
404	/* should only reserve the space (no need to map - save KVM) */
405	vc->vc_biostag = memt;
406	if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0, &vc->vc_bioshdl))
407		vc->vc_biosmapped = 0;
408	else
409		vc->vc_biosmapped = 1;
410
411	vc->nscreens = 0;
412	LIST_INIT(&vc->screens);
413	vc->active = NULL;
414	vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen;
415	callout_init(&vc->vc_switch_callout, 0);
416
417	wsfont_init();
418	vc->nfonts = 1;
419	LIST_INIT(&vc->vc_fontlist);
420	vf = &vga_console_fontset_ascii;
421	if (vga_no_builtinfont) {
422		struct wsdisplay_font *wf;
423		int cookie;
424
425		/* prefer 8x16 pixel font */
426		cookie = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
427		    0, WSFONT_FIND_BITMAP);
428		if (cookie == -1)
429			cookie = wsfont_find(NULL, 0, 0, 0,
430			    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R,
431			    WSFONT_FIND_BITMAP);
432		if (cookie == -1 || wsfont_lock(cookie, &wf))
433			panic("vga_raster_init: can't load console font");
434		vf->font = wf;
435	} else {
436		vga_load_builtinfont(vh, builtinfont_data, 0, 256);
437		vf->font = &builtinfont;
438	}
439	LIST_INSERT_HEAD(&vc->vc_fontlist, vf, next);
440}
441
442void
443vga_raster_init_screen(struct vga_config *vc, struct vgascreen *scr,
444    const struct wsscreen_descr *type, int existing, long *attrp)
445{
446	int cpos;
447	int res;
448	struct vga_handle *vh;
449
450	scr->cfg = vc;
451	scr->hdl = &vc->hdl;
452	scr->type = type;
453	scr->mindispoffset = 0;
454	scr->maxdispoffset = scr->dispoffset +
455	    type->nrows * type->ncols * type->fontheight;
456	vh = &vc->hdl;
457
458	LIST_INIT(&scr->fontset);
459	vga_raster_setup_font(vc, scr);
460
461	if (existing) {
462		int i;
463
464		cpos = vga_6845_read(vh, cursorh) << 8;
465		cpos |= vga_6845_read(vh, cursorl);
466
467		/* make sure we have a valid cursor position */
468		if (cpos < 0 || cpos >= type->nrows * type->ncols)
469			cpos = 0;
470
471		scr->dispoffset = vga_6845_read(vh, startadrh) << 9;
472		scr->dispoffset |= vga_6845_read(vh, startadrl) << 1;
473
474		/* make sure we have a valid memory offset */
475		if (scr->dispoffset < scr->mindispoffset ||
476		    scr->dispoffset > scr->maxdispoffset)
477			scr->dispoffset = scr->mindispoffset;
478
479		scr->mem = boot_scrmem;
480		scr->active = 1;
481
482		/* Save the current screen to memory. XXXBJY assume 80x25 */
483		for (i = 0; i < 80 * 25; i++) {
484			scr->mem[i].ch = bus_space_read_1(vh->vh_memt,
485			    vh->vh_allmemh, 0x18000 + i * 2);
486			scr->mem[i].attr = bus_space_read_1(vh->vh_memt,
487			    vh->vh_allmemh, 0x18000 + i * 2 + 1);
488			scr->mem[i].enc = scr->encoding;
489		}
490
491		vga_raster_setscreentype(vc, type);
492
493		/* Clear the entire screen. */
494		vga_gdc_write(vh, mode, 0x02);
495		bus_space_set_region_4(vh->vh_memt, vh->vh_allmemh, 0, 0,
496		    0x4000);
497
498		vga_restore_screen(scr, type, scr->mem);
499	} else {
500		cpos = 0;
501		scr->dispoffset = scr->mindispoffset;
502		scr->mem = NULL;
503		scr->active = 0;
504	}
505
506	scr->cursorrow = cpos / type->ncols;
507	scr->cursorcol = cpos % type->ncols;
508	vga_raster_cursor_init(scr, existing);
509
510#ifdef __alpha__
511	if (!vc->hdl.vh_mono)
512		/*
513		 * DEC firmware uses a blue background.
514		 */
515		res = vga_raster_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE,
516		    WSATTR_WSCOLORS, attrp);
517	else
518#endif
519	res = vga_raster_allocattr(scr, 0, 0, 0, attrp);
520#ifdef DIAGNOSTIC
521	if (res)
522		panic("vga_raster_init_screen: attribute botch");
523#endif
524
525	vc->nscreens++;
526	LIST_INSERT_HEAD(&vc->screens, scr, next);
527}
528
529void
530vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot,
531    bus_space_tag_t memt, int type, int quirks,
532    const struct vga_funcs *vf)
533{
534	int console;
535	struct vga_config *vc;
536	struct wsemuldisplaydev_attach_args aa;
537
538	console = vga_is_console(iot, type);
539
540	if (console) {
541		vc = &vga_console_vc;
542		vga_console_attached = 1;
543	} else {
544		vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK);
545		vga_raster_init(vc, iot, memt);
546	}
547
548	vc->vc_type = type;
549	vc->vc_funcs = vf;
550
551	sc->sc_vc = vc;
552	vc->softc = sc;
553
554	aa.console = console;
555	aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
556	aa.accessops = &vga_raster_accessops;
557	aa.accesscookie = vc;
558
559	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
560}
561
562int
563vga_cndetach(void)
564{
565	struct vga_config *vc;
566	struct vga_handle *vh;
567
568	vc = &vga_console_vc;
569	vh = &vc->hdl;
570
571	if (vgaconsole) {
572		bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
573		bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
574
575		return 1;
576	}
577
578	return 0;
579}
580
581int
582vga_is_console(bus_space_tag_t iot, int type)
583{
584	if (vgaconsole &&
585	    !vga_console_attached &&
586	    iot == vga_console_vc.hdl.vh_iot &&
587	    (vga_console_type == -1 || (type == vga_console_type)))
588		return (1);
589	return (0);
590}
591
592static int
593vga_get_video(struct vga_config *vc)
594{
595
596	return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0;
597}
598
599static void
600vga_set_video(struct vga_config *vc, int state)
601{
602	int val;
603
604	vga_ts_write(&vc->hdl, syncreset, 0x01);
605	if (state) {					/* unblank screen */
606		val = vga_ts_read(&vc->hdl, mode);
607		vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK);
608#ifndef VGA_NO_VBLANK
609		val = vga_6845_read(&vc->hdl, mode);
610		vga_6845_write(&vc->hdl, mode, val | 0x80);
611#endif
612	} else {					/* blank screen */
613		val = vga_ts_read(&vc->hdl, mode);
614		vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK);
615#ifndef VGA_NO_VBLANK
616		val = vga_6845_read(&vc->hdl, mode);
617		vga_6845_write(&vc->hdl, mode, val & ~0x80);
618#endif
619	}
620	vga_ts_write(&vc->hdl, syncreset, 0x03);
621}
622
623int
624vga_raster_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
625	struct lwp *l)
626{
627	struct vga_config *vc = v;
628	const struct vga_funcs *vf = vc->vc_funcs;
629
630	switch (cmd) {
631	case WSDISPLAYIO_GTYPE:
632		*(int *)data = vc->vc_type;
633		return 0;
634
635	case WSDISPLAYIO_GINFO:
636		/* XXX should get detailed hardware information here */
637		return EPASSTHROUGH;
638
639	case WSDISPLAYIO_GVIDEO:
640#if 1
641		*(int *)data = (vga_get_video(vc) ?
642		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF);
643		return 0;
644#endif
645
646	case WSDISPLAYIO_SVIDEO:
647#if 1
648		vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
649		return 0;
650#endif
651
652	case WSDISPLAYIO_GETCMAP:
653	case WSDISPLAYIO_PUTCMAP:
654	case WSDISPLAYIO_GCURPOS:
655	case WSDISPLAYIO_SCURPOS:
656	case WSDISPLAYIO_GCURMAX:
657	case WSDISPLAYIO_GCURSOR:
658	case WSDISPLAYIO_SCURSOR:
659		/* NONE of these operations are by the generic VGA driver. */
660		return EPASSTHROUGH;
661	}
662
663	if (vc->vc_funcs == NULL)
664		return (EPASSTHROUGH);
665
666	if (vf->vf_ioctl == NULL)
667		return (EPASSTHROUGH);
668
669	return ((*vf->vf_ioctl)(v, cmd, data, flag, l));
670}
671
672static paddr_t
673vga_raster_mmap(void *v, void *vs, off_t offset, int prot)
674{
675	struct vga_config *vc = v;
676	const struct vga_funcs *vf = vc->vc_funcs;
677
678	if (vc->vc_funcs == NULL)
679		return (-1);
680
681	if (vf->vf_mmap == NULL)
682		return (-1);
683
684	return ((*vf->vf_mmap)(v, offset, prot));
685}
686
687int
688vga_raster_alloc_screen(void *v, const struct wsscreen_descr *type,
689    void **cookiep, int *curxp, int *curyp, long *defattrp)
690{
691	struct vga_config *vc = v;
692	struct vgascreen *scr;
693
694	if (vc->nscreens == 1) {
695		vc->screens.lh_first->mem = boot_scrmem;
696	}
697
698	scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
699	vga_raster_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
700
701	if (vc->nscreens == 1) {
702		scr->active = 1;
703		vc->active = scr;
704		vc->currenttype = type;
705	} else {
706		scr->mem = malloc(sizeof(struct vga_scrmem) *
707		    type->ncols * type->nrows, M_DEVBUF, M_WAITOK);
708		vga_raster_eraserows(scr, 0, type->nrows, *defattrp);
709	}
710
711	*cookiep = scr;
712	*curxp = scr->cursorcol;
713	*curyp = scr->cursorrow;
714
715	return (0);
716}
717
718void
719vga_raster_free_screen(void *v, void *cookie)
720{
721	struct vgascreen *vs = cookie;
722	struct vga_config *vc = vs->cfg;
723
724	LIST_REMOVE(vs, next);
725	vc->nscreens--;
726	if (vs != &vga_console_screen)
727		free(vs, M_DEVBUF);
728	else
729		panic("vga_raster_free_screen: console");
730
731	if (vc->active == vs)
732		vc->active = 0;
733}
734
735int
736vga_raster_show_screen(void *v, void *cookie, int waitok,
737    void (*cb)(void *, int, int), void *cbarg)
738{
739	struct vgascreen *scr = cookie, *oldscr;
740	struct vga_config *vc = scr->cfg;
741
742	oldscr = vc->active; /* can be NULL! */
743	if (scr == oldscr) {
744		return (0);
745	}
746
747	vc->wantedscreen = cookie;
748	vc->switchcb = cb;
749	vc->switchcbarg = cbarg;
750	if (cb) {
751		callout_reset(&vc->vc_switch_callout, 0,
752		    (void(*)(void *))vga_switch_screen, vc);
753		return (EAGAIN);
754	}
755
756	vga_switch_screen(vc);
757	return (0);
758}
759
760void
761vga_switch_screen(struct vga_config *vc)
762{
763	struct vgascreen *scr, *oldscr;
764	struct vga_handle *vh = &vc->hdl;
765	const struct wsscreen_descr *type;
766
767	scr = vc->wantedscreen;
768	if (!scr) {
769		printf("vga_switch_screen: disappeared\n");
770		(*vc->switchcb)(vc->switchcbarg, EIO, 0);
771		return;
772	}
773	type = scr->type;
774	oldscr = vc->active; /* can be NULL! */
775#ifdef DIAGNOSTIC
776	if (oldscr) {
777		if (!oldscr->active)
778			panic("vga_raster_show_screen: not active");
779		if (oldscr->type != vc->currenttype)
780			panic("vga_raster_show_screen: bad type");
781	}
782#endif
783	if (scr == oldscr) {
784		return;
785	}
786#ifdef DIAGNOSTIC
787	if (scr->active)
788		panic("vga_raster_show_screen: active");
789#endif
790
791	if (oldscr)
792		oldscr->active = 0;
793
794	if (vc->currenttype != type) {
795		vga_raster_setscreentype(vc, type);
796		vc->currenttype = type;
797	}
798
799	scr->dispoffset = scr->mindispoffset;
800
801	if (!oldscr || (scr->dispoffset != oldscr->dispoffset)) {
802		vga_6845_write(vh, startadrh, scr->dispoffset >> 8);
803		vga_6845_write(vh, startadrl, scr->dispoffset);
804	}
805
806	/* Clear the entire screen. */
807	vga_gdc_write(vh, mode, 0x02);
808	bus_space_set_region_4(vh->vh_memt, vh->vh_allmemh, 0, 0, 0x2000);
809
810	scr->active = 1;
811	vga_restore_screen(scr, type, scr->mem);
812
813	vc->active = scr;
814
815	vga_raster_cursor(scr, scr->cursoron, scr->cursorrow, scr->cursorcol);
816
817	vc->wantedscreen = 0;
818	if (vc->switchcb)
819		(*vc->switchcb)(vc->switchcbarg, 0, 0);
820}
821
822static int
823vga_raster_load_font(void *v, void *id,
824    struct wsdisplay_font *data)
825{
826	/* XXX */
827	printf("vga_raster_load_font: called\n");
828
829	return (0);
830}
831
832void
833vga_raster_setup_font(struct vga_config *vc, struct vgascreen *scr)
834{
835	struct vga_raster_font *vf;
836	struct wsdisplay_font *wf;
837	int cookie;
838
839	LIST_FOREACH(vf, &vc->vc_fontlist, next) {
840		if (wsfont_matches(vf->font, 0, 0, scr->type->fontheight, 0,
841		    WSFONT_FIND_BITMAP)) {
842			scr->encoding = vf->font->encoding;
843			LIST_INSERT_HEAD(&scr->fontset, vf, next);
844			return;
845		}
846	}
847
848	cookie = wsfont_find(NULL, 0, scr->type->fontheight, 0,
849	    WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP);
850	if (cookie == -1)
851		return;
852
853	if (wsfont_lock(cookie, &wf))
854		return;
855
856	vf = malloc(sizeof(struct vga_raster_font), M_DEVBUF, M_NOWAIT);
857	if (!vf) {
858		wsfont_unlock(cookie);
859		return;
860	}
861
862	vf->font = wf;
863	scr->encoding = vf->font->encoding;
864	LIST_INSERT_HEAD(&scr->fontset, vf, next);
865}
866
867void
868vga_setup_regs(struct videomode *mode, struct vga_moderegs *regs)
869{
870	int i;
871	int depth = 4;			/* XXXBJY hardcoded for now */
872	const u_int8_t palette[] = {
873		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
874		0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
875	};
876
877	/*
878	 * Compute hsync and vsync polarity.
879	 */
880	if ((mode->flags & (VID_PHSYNC | VID_NHSYNC))
881	    && (mode->flags & (VID_PVSYNC | VID_NVSYNC))) {
882	    	regs->miscout = 0x23;
883		if (mode->flags & VID_NHSYNC)
884			regs->miscout |= 0x40;
885		if (mode->flags & VID_NVSYNC)
886			regs->miscout |= 0x80;
887	} else {
888		if (mode->flags & VID_DBLSCAN)
889			mode->vdisplay *= 2;
890		if (mode->vdisplay < 400)
891			regs->miscout = 0xa3;
892		else if (mode->vdisplay < 480)
893			regs->miscout = 0x63;
894		else if (mode->vdisplay < 768)
895			regs->miscout = 0xe3;
896		else
897			regs->miscout = 0x23;
898	}
899
900	/*
901	 * Time sequencer
902	 */
903	if (depth == 4)
904		regs->ts[0] = 0x02;
905	else
906		regs->ts[0] = 0x00;
907	if (mode->flags & VID_CLKDIV2)
908		regs->ts[1] = 0x09;
909	else
910		regs->ts[1] = 0x01;
911	regs->ts[2] = 0x0f;
912	regs->ts[3] = 0x00;
913	if (depth < 8)
914		regs->ts[4] = 0x06;
915	else
916		regs->ts[4] = 0x0e;
917
918	/*
919	 * CRTC controller
920	 */
921	regs->crtc[0] = (mode->htotal >> 3) - 5;
922	regs->crtc[1] = (mode->hdisplay >> 3) - 1;
923	regs->crtc[2] = (mode->hsync_start >> 3) - 1;
924	regs->crtc[3] = (((mode->hsync_end >> 3) - 1) & 0x1f) | 0x80;
925	regs->crtc[4] = mode->hsync_start >> 3;
926	regs->crtc[5] = ((((mode->hsync_end >> 3) - 1) & 0x20) << 2)
927	    | (((mode->hsync_end >> 3)) & 0x1f);
928	regs->crtc[6] = (mode->vtotal - 2) & 0xff;
929	regs->crtc[7] = (((mode->vtotal - 2) & 0x100) >> 8)
930	    | (((mode->vdisplay - 1) & 0x100) >> 7)
931	    | ((mode->vsync_start & 0x100) >> 6)
932	    | (((mode->vsync_start - 1) & 0x100) >> 5)
933	    | 0x10
934	    | (((mode->vtotal - 2) & 0x200) >> 4)
935	    | (((mode->vdisplay - 1) & 0x200) >> 3)
936	    | ((mode->vsync_start & 0x200) >> 2);
937	regs->crtc[8] = 0x00;
938	regs->crtc[9] = (((mode->vsync_start - 1) & 0x200) >> 4) | 0x40;
939	if (mode->flags & VID_DBLSCAN)
940		regs->crtc[9] |= 0x80;
941	regs->crtc[10] = 0x00;
942	regs->crtc[11] = 0x00;
943	regs->crtc[12] = 0x00;
944	regs->crtc[13] = 0x00;
945	regs->crtc[14] = 0x00;
946	regs->crtc[15] = 0x00;
947	regs->crtc[16] = mode->vsync_start & 0xff;
948	regs->crtc[17] = (mode->vsync_end & 0x0f) | 0x20;
949	regs->crtc[18] = (mode->vdisplay - 1) & 0xff;
950	regs->crtc[19] = mode->hdisplay >> 4;	/* XXXBJY */
951	regs->crtc[20] = 0x00;
952	regs->crtc[21] = (mode->vsync_start - 1) & 0xff;
953	regs->crtc[22] = (mode->vsync_end - 1) & 0xff;
954	if (depth < 8)
955		regs->crtc[23] = 0xe3;
956	else
957		regs->crtc[23] = 0xc3;
958	regs->crtc[24] = 0xff;
959
960	/*
961	 * Graphics display controller
962	 */
963	regs->gdc[0] = 0x00;
964	regs->gdc[1] = 0x00;
965	regs->gdc[2] = 0x00;
966	regs->gdc[3] = 0x00;
967	regs->gdc[4] = 0x00;
968	if (depth == 4)
969		regs->gdc[5] = 0x02;
970	else
971		regs->gdc[5] = 0x40;
972	regs->gdc[6] = 0x01;
973	regs->gdc[7] = 0x0f;
974	regs->gdc[8] = 0xff;
975
976	/*
977	 * Attribute controller
978	 */
979	/* Set palette registers. */
980	for (i = 0; i < 16; i++)
981		regs->atc[i] = palette[i];
982	if (depth == 4)
983		regs->atc[16] = 0x01;	/* XXXBJY was 0x81 in XFree86 */
984	else
985		regs->atc[16] = 0x41;
986	regs->atc[17] = 0x00;		/* XXXBJY just a guess */
987	regs->atc[18] = 0x0f;
988	regs->atc[19] = 0x00;
989	regs->atc[20] = 0x00;
990}
991
992void
993vga_set_mode(struct vga_handle *vh, struct vga_moderegs *regs)
994{
995	int i;
996
997	/* Disable display. */
998	vga_ts_write(vh, mode, vga_ts_read(vh, mode) | VGA_TS_MODE_BLANK);
999
1000	/* Write misc output register. */
1001	bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAW,
1002	    regs->miscout);
1003
1004	/* Set synchronous reset. */
1005	vga_ts_write(vh, syncreset, 0x01);
1006	vga_ts_write(vh, mode, regs->ts[1] | VGA_TS_MODE_BLANK);
1007	for (i = 2; i < VGA_TS_NREGS; i++)
1008		_vga_ts_write(vh, i, regs->ts[i]);
1009	/* Clear synchronous reset. */
1010	vga_ts_write(vh, syncreset, 0x03);
1011
1012	/* Unprotect CRTC registers 0-7. */
1013	vga_6845_write(vh, vsynce, vga_6845_read(vh, vsynce) & ~0x80);
1014	/* Write CRTC registers. */
1015	for (i = 0; i < MC6845_NREGS; i++)
1016		_vga_6845_write(vh, i, regs->crtc[i]);
1017
1018	/* Write graphics display registers. */
1019	for (i = 0; i < VGA_GDC_NREGS; i++)
1020		_vga_gdc_write(vh, i, regs->gdc[i]);
1021
1022	/* Write attribute controller registers. */
1023	for (i = 0; i < VGA_ATC_NREGS; i++)
1024		_vga_attr_write(vh, i, regs->atc[i]);
1025
1026	/* Enable display. */
1027	vga_ts_write(vh, mode, vga_ts_read(vh, mode) & ~VGA_TS_MODE_BLANK);
1028}
1029
1030void
1031vga_raster_cursor_init(struct vgascreen *scr, int existing)
1032{
1033	struct vga_handle *vh = scr->hdl;
1034	bus_space_tag_t memt;
1035	bus_space_handle_t memh;
1036	int off;
1037
1038	if (existing) {
1039		/*
1040		 * This is the first screen. At this point, scr->active is
1041		 * false, so we can't use vga_raster_cursor() to do this.
1042		 */
1043		memt = vh->vh_memt;
1044		memh = vh->vh_memh;
1045		off = (scr->cursorrow * scr->type->ncols + scr->cursorcol) +
1046		    scr->dispoffset / 8;
1047
1048		scr->cursortmp = scr->mem[off];
1049		vga_raster_putchar(scr, scr->cursorrow, scr->cursorcol,
1050		    scr->cursortmp.ch, scr->cursortmp.attr ^ 0x77);
1051	} else {
1052		scr->cursortmp.ch = 0;
1053		scr->cursortmp.attr = 0;
1054		scr->cursortmp.second = 0;
1055		scr->cursortmp.enc = scr->encoding;
1056	}
1057
1058	scr->cursoron = 1;
1059}
1060
1061void
1062vga_raster_cursor(void *id, int on, int row, int col)
1063{
1064	struct vgascreen *scr = id;
1065	int off, tmp;
1066
1067	/* Remove old cursor image */
1068	if (scr->cursoron) {
1069		off = scr->cursorrow * scr->type->ncols + scr->cursorcol;
1070		if (scr->active) {
1071			tmp = scr->encoding;
1072			scr->encoding = scr->cursortmp.enc;
1073			if (scr->cursortmp.second)
1074				vga_raster_putchar(id, scr->cursorrow,
1075				    scr->cursorcol - 1, scr->cursortmp.ch,
1076				    scr->cursortmp.attr);
1077			else
1078				vga_raster_putchar(id, scr->cursorrow,
1079				    scr->cursorcol, scr->cursortmp.ch,
1080				    scr->cursortmp.attr);
1081			scr->encoding = tmp;
1082		}
1083	}
1084
1085	scr->cursorrow = row;
1086	scr->cursorcol = col;
1087
1088	if ((scr->cursoron = on) == 0)
1089		return;
1090
1091	off = scr->cursorrow * scr->type->ncols + scr->cursorcol;
1092	scr->cursortmp = scr->mem[off];
1093	if (scr->active) {
1094		tmp = scr->encoding;
1095		scr->encoding = scr->cursortmp.enc;
1096		if (scr->cursortmp.second)
1097			vga_raster_putchar(id, scr->cursorrow,
1098			    scr->cursorcol - 1, scr->cursortmp.ch,
1099			    scr->cursortmp.attr ^ 0x77);
1100		else
1101			vga_raster_putchar(id, scr->cursorrow,
1102			    scr->cursorcol, scr->cursortmp.ch,
1103			    scr->cursortmp.attr ^ 0x77);
1104		scr->encoding = tmp;
1105	}
1106}
1107
1108static int
1109vga_raster_mapchar(void *id, int uni, u_int *index)
1110{
1111	struct vgascreen *scr = id;
1112
1113	if (scr->encoding == WSDISPLAY_FONTENC_IBM)
1114		return pcdisplay_mapchar(id, uni, index);
1115	else {
1116		*index = uni;
1117		return 5;
1118	}
1119}
1120
1121void
1122vga_raster_putchar(void *id, int row, int col, u_int c, long attr)
1123{
1124	struct vgascreen *scr = id;
1125	size_t off;
1126	struct vga_raster_font *fs;
1127	u_int tmp_ch;
1128
1129	off = row * scr->type->ncols + col;
1130
1131	if (__predict_false(off >= (scr->type->ncols * scr->type->nrows)))
1132		return;
1133
1134	LIST_FOREACH(fs, &scr->fontset, next) {
1135		if ((scr->encoding == fs->font->encoding) &&
1136		    (c >= fs->font->firstchar) &&
1137		    (c < fs->font->firstchar + fs->font->numchars) &&
1138		    (scr->type->fontheight == fs->font->fontheight)) {
1139			if (scr->active) {
1140				tmp_ch = c - fs->font->firstchar;
1141				_vga_raster_putchar(scr, row, col, tmp_ch,
1142				    attr, fs);
1143			}
1144
1145			scr->mem[off].ch = c;
1146			scr->mem[off].attr = attr;
1147			scr->mem[off].second = 0;
1148			scr->mem[off].enc = fs->font->encoding;
1149
1150			if (fs->font->stride == 2) {
1151				scr->mem[off + 1].ch = c;
1152				scr->mem[off + 1].attr = attr;
1153				scr->mem[off + 1].second = 1;
1154				scr->mem[off + 1].enc = fs->font->encoding;
1155			}
1156
1157			return;
1158		}
1159	}
1160
1161	/*
1162	 * No match found.
1163	 */
1164	if (scr->active)
1165		/*
1166		 * Put a single width space character no matter what the
1167		 * actual width of the character is.
1168		 */
1169		_vga_raster_putchar(scr, row, col, ' ', attr,
1170		    &vga_console_fontset_ascii);
1171	scr->mem[off].ch = c;
1172	scr->mem[off].attr = attr;
1173	scr->mem[off].second = 0;
1174	scr->mem[off].enc = scr->encoding;
1175}
1176
1177static void
1178_vga_raster_putchar(void *id, int row, int col, u_int c, long attr,
1179    struct vga_raster_font *fs)
1180{
1181	struct vgascreen *scr = id;
1182	struct vga_handle *vh = scr->hdl;
1183	bus_space_tag_t memt = vh->vh_memt;
1184	bus_space_handle_t memh = vh->vh_memh;
1185	int i;
1186	int rasoff, rasoff2;
1187	int fheight = scr->type->fontheight;
1188	volatile u_int8_t dummy, pattern;
1189	u_int8_t fgcolor, bgcolor;
1190
1191	rasoff = scr->dispoffset + row * scr->type->ncols * fheight + col;
1192	rasoff2 = rasoff;
1193
1194#if 0
1195	bgcolor = bgansitopc[attr >> 4];
1196	fgcolor = fgansitopc[attr & 0x0f];
1197#else
1198	bgcolor = ((attr >> 4) & 0x0f);
1199	fgcolor = attr & 0x0f;
1200#endif
1201
1202	if (fs->font->stride == 1) {
1203		/* Paint background. */
1204		vga_gdc_write(vh, mode, 0x02);
1205		for (i = 0; i < fheight; i++) {
1206			bus_space_write_1(memt, memh, rasoff, bgcolor);
1207			rasoff += scr->type->ncols;
1208		}
1209
1210		/* Draw a single width character. */
1211		vga_gdc_write(vh, mode, 0x03);
1212		vga_gdc_write(vh, setres, fgcolor);
1213		for (i = 0; i < fheight; i++) {
1214			pattern = ((u_int8_t *)fs->font->data)[c * fheight + i];
1215			/* When pattern is 0, skip output for speed-up. */
1216			if (pattern != 0) {
1217				dummy = bus_space_read_1(memt, memh, rasoff2);
1218				bus_space_write_1(memt, memh, rasoff2, pattern);
1219			}
1220			rasoff2 += scr->type->ncols;
1221		}
1222	} else if (fs->font->stride == 2) {
1223		/* Paint background. */
1224		vga_gdc_write(vh, mode, 0x02);
1225		for (i = 0; i < fheight; i++) {
1226			bus_space_write_1(memt, memh, rasoff, bgcolor);
1227			bus_space_write_1(memt, memh, rasoff + 1, bgcolor);
1228			rasoff += scr->type->ncols;
1229		}
1230
1231		/* Draw a double width character. */
1232		vga_gdc_write(vh, mode, 0x03);
1233		vga_gdc_write(vh, setres, fgcolor);
1234		for (i = 0; i < fheight; i++) {
1235			pattern = ((u_int8_t *)fs->font->data)
1236			    [(c * fheight + i) * 2];
1237			if (pattern != 0) {
1238				dummy = bus_space_read_1(memt, memh, rasoff2);
1239				bus_space_write_1(memt, memh, rasoff2, pattern);
1240			}
1241			pattern = ((u_int8_t *)fs->font->data)
1242			    [(c * fheight + i) * 2 + 1];
1243			if (pattern != 0) {
1244				rasoff2++;
1245				dummy = bus_space_read_1(memt, memh, rasoff2);
1246				bus_space_write_1(memt, memh, rasoff2, pattern);
1247				rasoff2--;
1248			}
1249			rasoff2 += scr->type->ncols;
1250		}
1251	}
1252}
1253
1254void
1255vga_raster_copycols(void *id, int row, int srccol, int dstcol, int ncols)
1256{
1257	struct vgascreen *scr = id;
1258	struct vga_handle *vh = scr->hdl;
1259	bus_space_tag_t memt = vh->vh_memt;
1260	bus_space_handle_t memh = vh->vh_memh;
1261	bus_size_t srcoff, dstoff;
1262	bus_size_t rassrcoff, rasdstoff;
1263	int i;
1264	int fheight = scr->type->fontheight;
1265
1266	srcoff = row * scr->type->ncols + srccol;
1267	dstoff = row * scr->type->ncols + dstcol;
1268	rassrcoff = scr->dispoffset + row * scr->type->ncols * fheight + srccol;
1269	rasdstoff = scr->dispoffset + row * scr->type->ncols * fheight + dstcol;
1270
1271	memcpy(&scr->mem[dstoff], &scr->mem[srcoff],
1272	    ncols * sizeof(struct vga_scrmem));
1273
1274	vga_gdc_write(vh, mode, 0x01);
1275	if (scr->active) {
1276		for (i = 0; i < fheight; i++) {
1277			bus_space_copy_region_1(memt, memh,
1278			    rassrcoff + i * scr->type->ncols, memh,
1279			    rasdstoff + i * scr->type->ncols, ncols);
1280		}
1281	}
1282}
1283
1284void
1285vga_raster_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
1286{
1287	struct vgascreen *scr = id;
1288	int i;
1289
1290	if (scr->active == 0)
1291		return;
1292
1293	for (i = startcol; i < startcol + ncols; i++)
1294		vga_raster_putchar(id, row, i, ' ', fillattr);
1295}
1296
1297void
1298vga_raster_copyrows(void *id, int srcrow, int dstrow, int nrows)
1299{
1300	struct vgascreen *scr = id;
1301	struct vga_handle *vh = scr->hdl;
1302	bus_space_tag_t memt = vh->vh_memt;
1303	bus_space_handle_t memh = vh->vh_memh;
1304	int ncols;
1305	bus_size_t srcoff, dstoff;
1306	bus_size_t rassrcoff, rasdstoff;
1307	int fheight;
1308
1309	ncols = scr->type->ncols;
1310	fheight = scr->type->fontheight;
1311
1312	srcoff = srcrow * ncols;
1313	dstoff = dstrow * ncols;
1314	rassrcoff = srcoff * fheight;
1315	rasdstoff = dstoff * fheight;
1316
1317	if (scr->active) {
1318		vga_gdc_write(vh, mode, 0x01);
1319		if (dstrow == 0 && (srcrow + nrows == scr->type->nrows)) {
1320			int cursoron = scr->cursoron;
1321
1322			if (cursoron)
1323				/* Disable cursor. */
1324				vga_raster_cursor(scr, 0,
1325				    scr->cursorrow, scr->cursorcol);
1326
1327			/* scroll up whole screen */
1328			if ((scr->dispoffset + srcrow * ncols * fheight)
1329			    <= scr->maxdispoffset)
1330				scr->dispoffset += srcrow * ncols * fheight;
1331			else {
1332				bus_space_copy_region_1(memt, memh,
1333				    scr->dispoffset + rassrcoff,
1334				    memh, scr->mindispoffset,
1335				    nrows * ncols * fheight);
1336				scr->dispoffset = scr->mindispoffset;
1337			}
1338			vga_6845_write(vh, startadrh, scr->dispoffset >> 8);
1339			vga_6845_write(vh, startadrl, scr->dispoffset);
1340
1341			if (cursoron)
1342				/* Enable cursor. */
1343				vga_raster_cursor(scr, 1, scr->cursorrow,
1344				    scr->cursorcol);
1345		} else
1346			bus_space_copy_region_1(memt, memh,
1347			    scr->dispoffset + rassrcoff, memh,
1348			    scr->dispoffset + rasdstoff,
1349			    nrows * ncols * fheight);
1350	}
1351	memcpy(&scr->mem[dstoff], &scr->mem[srcoff],
1352	    nrows * ncols * sizeof(struct vga_scrmem));
1353}
1354
1355void
1356vga_raster_eraserows(void *id, int startrow, int nrows, long fillattr)
1357{
1358	struct vgascreen *scr = id;
1359	struct vga_handle *vh = scr->hdl;
1360	bus_space_tag_t memt = vh->vh_memt;
1361	bus_space_handle_t memh = vh->vh_memh;
1362	bus_size_t off, count;
1363	bus_size_t rasoff, rascount;
1364	int i;
1365
1366	off = startrow * scr->type->ncols;
1367	count = nrows * scr->type->ncols;
1368	rasoff = off * scr->type->fontheight;
1369	rascount = count * scr->type->fontheight;
1370
1371	if (scr->active) {
1372		u_int8_t bgcolor = (fillattr >> 4) & 0x0F;
1373
1374		/* Paint background. */
1375		vga_gdc_write(vh, mode, 0x02);
1376		if (scr->type->ncols % 4 == 0) {
1377			u_int32_t fill = bgcolor | (bgcolor << 8) |
1378			    (bgcolor << 16) | (bgcolor << 24);
1379			/* We can speed up I/O */
1380			for (i = rasoff; i < rasoff + rascount; i += 4)
1381				bus_space_write_4(memt, memh,
1382				    scr->dispoffset + i, fill);
1383		} else {
1384			u_int16_t fill = bgcolor | (bgcolor << 8);
1385			for (i = rasoff; i < rasoff + rascount; i += 2)
1386				bus_space_write_2(memt, memh,
1387				    scr->dispoffset + i, fill);
1388		}
1389	}
1390	for (i = 0; i < count; i++) {
1391		scr->mem[off + i].ch = ' ';
1392		scr->mem[off + i].attr = fillattr;
1393		scr->mem[off + i].second = 0;
1394		scr->mem[off + i].enc = scr->encoding;
1395	}
1396}
1397
1398static int
1399vga_raster_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1400{
1401	struct vgascreen *scr = id;
1402	struct vga_config *vc = scr->cfg;
1403
1404	if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) ||
1405	    (unsigned int)bg >= sizeof(bgansitopc)))
1406	    	return (EINVAL);
1407
1408	if (vc->hdl.vh_mono) {
1409		if (flags & WSATTR_WSCOLORS)
1410			return (EINVAL);
1411		if (flags & WSATTR_REVERSE)
1412			*attrp = 0x70;
1413		else
1414			*attrp = 0x07;
1415		if (flags & WSATTR_UNDERLINE)
1416			*attrp |= FG_UNDERLINE;
1417		if (flags & WSATTR_HILIT)
1418			*attrp |= FG_INTENSE;
1419	} else {
1420		if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
1421			return (EINVAL);
1422		if (flags & WSATTR_WSCOLORS)
1423			*attrp = fgansitopc[fg] | bgansitopc[bg];
1424		else
1425			*attrp = 7;
1426		if (flags & WSATTR_HILIT)
1427			*attrp += 8;
1428	}
1429	if (flags & WSATTR_BLINK)
1430		*attrp |= FG_BLINK;
1431	return (0);
1432}
1433
1434void
1435vga_restore_screen(struct vgascreen *scr,
1436    const struct wsscreen_descr *type, struct vga_scrmem *mem)
1437{
1438	int i, j, off, tmp;
1439
1440	tmp = scr->encoding;
1441	for (i = 0; i < type->nrows; i++) {
1442		for (j = 0; j < type->ncols; j++) {
1443			off = i * type->ncols + j;
1444			if (mem[off].second != 1) {
1445				scr->encoding = mem[off].enc;
1446				vga_raster_putchar(scr, i, j, mem[off].ch,
1447				    mem[off].attr);
1448			}
1449		}
1450	}
1451	scr->encoding = tmp;
1452}
1453
1454void
1455vga_raster_setscreentype(struct vga_config *vc,
1456    const struct wsscreen_descr *type)
1457{
1458	struct vga_handle *vh = &vc->hdl;
1459	struct vga_moderegs moderegs;
1460
1461	vga_setup_regs((struct videomode *)type->modecookie, &moderegs);
1462	vga_set_mode(vh, &moderegs);
1463}
1464
1465#ifdef WSDISPLAY_CUSTOM_OUTPUT
1466void
1467vga_raster_replaceattr(void *id, long oldattr, long newattr)
1468{
1469	struct vgascreen *scr = id;
1470	const struct wsscreen_descr *type = scr->type;
1471	int off;
1472
1473	for (off = 0; off < type->nrows * type->ncols; off++) {
1474		if (scr->mem[off].attr == oldattr)
1475			scr->mem[off].attr = newattr;
1476	}
1477
1478	/* Repaint the whole screen, if needed */
1479	if (scr->active)
1480		vga_restore_screen(scr, type, scr->mem);
1481}
1482#endif /* WSDISPLAY_CUSTOM_OUTPUT */
1483
1484void
1485vga_resume(struct vga_softc *sc)
1486{
1487#ifdef VGA_RESET_ON_RESUME
1488	vga_initregs(&sc->sc_vc->hdl);
1489#endif
1490}
1491