NetBSD/sys/dev/ic/vga_raster.c
jmcneill 48100f10e4 Calculate maxdispoffset rather than hard-coding it. Fixes scrolling in
80x25 mode.

XXX This doesn't handle odd modes like 80x30 on 640x480, but the driver
didn't allow that selection previously so at least it's an improvement
over the previous behaviour.
2008-10-19 17:47:38 +00:00

1489 lines
38 KiB
C

/* $NetBSD: vga_raster.c,v 1.33 2008/10/19 17:47:38 jmcneill Exp $ */
/*
* Copyright (c) 2001, 2002 Bang Jun-Young
* Copyright (c) 2004 Julio M. Merino Vidal
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1995, 1996 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vga_raster.c,v 1.33 2008/10/19 17:47:38 jmcneill Exp $");
#include "opt_wsmsgattrs.h" /* for WSDISPLAY_CUSTOM_OUTPUT */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/callout.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/bus.h>
#include <dev/ic/mc6845reg.h>
#include <dev/ic/pcdisplayvar.h>
#include <dev/ic/vgareg.h>
#include <dev/ic/vgavar.h>
#include <dev/ic/videomode.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wsfont/wsfont.h>
#include <dev/ic/pcdisplay.h>
int vga_no_builtinfont = 0;
u_int8_t builtinfont_data[256 * 16];
struct wsdisplay_font builtinfont = {
"builtin", /* typeface name */
0, /* firstchar */
256, /* numchars */
WSDISPLAY_FONTENC_IBM, /* encoding */
8, /* width */
16, /* height */
1, /* stride */
WSDISPLAY_FONTORDER_L2R, /* bit order */
WSDISPLAY_FONTORDER_L2R, /* byte order */
builtinfont_data /* data */
};
struct vga_scrmem {
u_int16_t ch;
u_int8_t attr;
u_int8_t second; /* XXXBJY should be u_int8_t len; */
u_int8_t enc;
};
#ifdef VGA_CONSOLE_SCREENTYPE
#define VGA_SCRMEM_SIZE (80 * 30)
#else
#define VGA_SCRMEM_SIZE (80 * 25)
#endif
struct vga_scrmem boot_scrmem[VGA_SCRMEM_SIZE];
struct vga_raster_font {
LIST_ENTRY(vga_raster_font) next;
struct wsdisplay_font *font;
};
struct vgascreen {
LIST_ENTRY(vgascreen) next;
struct vga_config *cfg;
struct vga_handle *hdl;
const struct wsscreen_descr *type;
int active;
struct vga_scrmem *mem;
int encoding;
int dispoffset;
int mindispoffset;
int maxdispoffset;
int cursoron; /* Is cursor displayed? */
int cursorcol; /* Current cursor column */
int cursorrow; /* Current cursor row */
struct vga_scrmem cursortmp;
int cursorstride;
LIST_HEAD(, vga_raster_font) fontset;
};
struct vga_moderegs {
u_int8_t miscout; /* Misc. output */
u_int8_t crtc[MC6845_NREGS]; /* CRTC controller */
u_int8_t atc[VGA_ATC_NREGS]; /* Attribute controller */
u_int8_t ts[VGA_TS_NREGS]; /* Time sequencer */
u_int8_t gdc[VGA_GDC_NREGS]; /* Graphics display controller */
};
static int vgaconsole, vga_console_type, vga_console_attached;
static struct vgascreen vga_console_screen;
static struct vga_config vga_console_vc;
static struct vga_raster_font vga_console_fontset_ascii;
static struct videomode vga_console_modes[2] = {
/* 640x400 for 80x25, 80x40 and 80x50 modes */
{
25175, 640, 664, 760, 800, 400, 409, 411, 450, 0, NULL,
},
/* 640x480 for 80x30 mode */
{
25175, 640, 664, 760, 800, 480, 491, 493, 525, 0, NULL,
}
};
static void vga_raster_init(struct vga_config *, bus_space_tag_t,
bus_space_tag_t);
static void vga_raster_init_screen(struct vga_config *, struct vgascreen *,
const struct wsscreen_descr *, int, long *);
static void vga_raster_setup_font(struct vga_config *, struct vgascreen *);
static void vga_setup_regs(struct videomode *, struct vga_moderegs *);
static void vga_set_mode(struct vga_handle *, struct vga_moderegs *);
static void vga_restore_screen(struct vgascreen *,
const struct wsscreen_descr *, struct vga_scrmem *);
static void vga_raster_cursor_init(struct vgascreen *, int);
static void _vga_raster_putchar(void *, int, int, u_int, long,
struct vga_raster_font *);
static void vga_raster_cursor(void *, int, int, int);
static int vga_raster_mapchar(void *, int, u_int *);
static void vga_raster_putchar(void *, int, int, u_int, long);
static void vga_raster_copycols(void *, int, int, int, int);
static void vga_raster_erasecols(void *, int, int, int, long);
static void vga_raster_copyrows(void *, int, int, int);
static void vga_raster_eraserows(void *, int, int, long);
static int vga_raster_allocattr(void *, int, int, int, long *);
#ifdef WSDISPLAY_CUSTOM_OUTPUT
static void vga_raster_replaceattr(void *, long, long);
#endif /* WSDISPLAY_CUSTOM_OUTPUT */
const struct wsdisplay_emulops vga_raster_emulops = {
vga_raster_cursor,
vga_raster_mapchar,
vga_raster_putchar,
vga_raster_copycols,
vga_raster_erasecols,
vga_raster_copyrows,
vga_raster_eraserows,
vga_raster_allocattr,
#ifdef WSDISPLAY_CUSTOM_OUTPUT
vga_raster_replaceattr,
#else /* WSDISPLAY_CUSTOM_OUTPUT */
NULL,
#endif /* WSDISPLAY_CUSTOM_OUTPUT */
};
/*
* translate WS(=ANSI) color codes to standard pc ones
*/
static const unsigned char fgansitopc[] = {
#ifdef __alpha__
/*
* XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
* XXX We should probably not bother with this
* XXX (reinitialize the palette registers).
*/
FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED,
FG_MAGENTA, FG_BROWN, FG_LIGHTGREY
#else
FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
#endif
}, bgansitopc[] = {
#ifdef __alpha__
BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED,
BG_MAGENTA, BG_BROWN, BG_LIGHTGREY
#else
BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
#endif
};
const struct wsscreen_descr vga_25lscreen = {
"80x25", 80, 25,
&vga_raster_emulops,
8, 16,
WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
&vga_console_modes[0]
}, vga_25lscreen_mono = {
"80x25", 80, 25,
&vga_raster_emulops,
8, 16,
WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
&vga_console_modes[0]
}, vga_30lscreen = {
"80x30", 80, 30,
&vga_raster_emulops,
8, 16,
WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
&vga_console_modes[1]
}, vga_30lscreen_mono = {
"80x30", 80, 30,
&vga_raster_emulops,
8, 16,
WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
&vga_console_modes[1]
}, vga_40lscreen = {
"80x40", 80, 40,
&vga_raster_emulops,
8, 10,
WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
&vga_console_modes[0]
}, vga_40lscreen_mono = {
"80x40", 80, 40,
&vga_raster_emulops,
8, 10,
WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
&vga_console_modes[0]
}, vga_50lscreen = {
"80x50", 80, 50,
&vga_raster_emulops,
8, 8,
WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
&vga_console_modes[0]
}, vga_50lscreen_mono = {
"80x50", 80, 50,
&vga_raster_emulops,
8, 8,
WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
&vga_console_modes[0]
};
const struct wsscreen_descr *_vga_scrlist[] = {
&vga_25lscreen,
&vga_30lscreen,
&vga_40lscreen,
&vga_50lscreen,
}, *_vga_scrlist_mono[] = {
&vga_25lscreen_mono,
&vga_30lscreen_mono,
&vga_40lscreen_mono,
&vga_50lscreen_mono,
};
const struct wsscreen_list vga_screenlist = {
sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *),
_vga_scrlist
}, vga_screenlist_mono = {
sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *),
_vga_scrlist_mono
};
static int vga_raster_ioctl(void *, void *, u_long, void *, int,
struct lwp *);
static paddr_t vga_raster_mmap(void *, void *, off_t, int);
static int vga_raster_alloc_screen(void *, const struct wsscreen_descr *,
void **, int *, int *, long *);
static void vga_raster_free_screen(void *, void *);
static int vga_raster_show_screen(void *, void *, int,
void (*)(void *, int, int), void *);
static int vga_raster_load_font(void *, void *, struct wsdisplay_font *);
static void vga_switch_screen(struct vga_config *);
static void vga_raster_setscreentype(struct vga_config *,
const struct wsscreen_descr *);
const struct wsdisplay_accessops vga_raster_accessops = {
vga_raster_ioctl,
vga_raster_mmap,
vga_raster_alloc_screen,
vga_raster_free_screen,
vga_raster_show_screen,
vga_raster_load_font,
NULL, /* pollc */
NULL, /* scroll */
};
int
vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
{
long defattr;
const struct wsscreen_descr *scr;
#ifdef VGA_CONSOLE_SCREENTYPE
const char *typestr = NULL;
#endif
if (check && !vga_common_probe(iot, memt))
return (ENXIO);
/* set up bus-independent VGA configuration */
vga_raster_init(&vga_console_vc, iot, memt);
#ifdef VGA_CONSOLE_SCREENTYPE
scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
&vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
if (!scr)
/* Invalid screen type, continue with the default mode. */
typestr = "80x25";
else if (scr->nrows > 30)
/* Unsupported screen type, try 80x30. */
typestr = "80x30";
if (typestr)
scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
&vga_screenlist_mono : &vga_screenlist, typestr);
if (scr != vga_console_vc.currenttype)
vga_console_vc.currenttype = scr;
#else
scr = vga_console_vc.currenttype;
#endif
vga_raster_init_screen(&vga_console_vc, &vga_console_screen, scr, 1,
&defattr);
vga_console_screen.active = 1;
vga_console_vc.active = &vga_console_screen;
wsdisplay_cnattach(scr, &vga_console_screen,
vga_console_screen.cursorcol, vga_console_screen.cursorrow,
defattr);
vgaconsole = 1;
vga_console_type = type;
return (0);
}
void
vga_raster_init(struct vga_config *vc, bus_space_tag_t iot,
bus_space_tag_t memt)
{
struct vga_handle *vh = &vc->hdl;
u_int8_t mor;
struct vga_raster_font *vf;
vh->vh_iot = iot;
vh->vh_memt = memt;
if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
panic("vga_raster_init: couldn't map vga io");
/* read "misc output register" */
mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAR);
vh->vh_mono = !(mor & 1);
if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
&vh->vh_ioh_6845))
panic("vga_raster_init: couldn't map 6845 io");
if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh))
panic("vga_raster_init: couldn't map memory");
if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 0, 0x10000,
&vh->vh_memh))
panic("vga_raster_init: mem subrange failed");
/* should only reserve the space (no need to map - save KVM) */
vc->vc_biostag = memt;
if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0, &vc->vc_bioshdl))
vc->vc_biosmapped = 0;
else
vc->vc_biosmapped = 1;
vc->nscreens = 0;
LIST_INIT(&vc->screens);
vc->active = NULL;
vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen;
callout_init(&vc->vc_switch_callout, 0);
wsfont_init();
vc->nfonts = 1;
LIST_INIT(&vc->vc_fontlist);
vf = &vga_console_fontset_ascii;
if (vga_no_builtinfont) {
struct wsdisplay_font *wf;
int cookie;
/* prefer 8x16 pixel font */
cookie = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
0);
if (cookie == -1)
cookie = wsfont_find(NULL, 0, 0, 0,
WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R);
if (cookie == -1 || wsfont_lock(cookie, &wf))
panic("vga_raster_init: can't load console font");
vf->font = wf;
} else {
vga_load_builtinfont(vh, builtinfont_data, 0, 256);
vf->font = &builtinfont;
}
LIST_INSERT_HEAD(&vc->vc_fontlist, vf, next);
}
void
vga_raster_init_screen(struct vga_config *vc, struct vgascreen *scr,
const struct wsscreen_descr *type, int existing, long *attrp)
{
int cpos;
int res;
struct vga_handle *vh;
scr->cfg = vc;
scr->hdl = &vc->hdl;
scr->type = type;
scr->mindispoffset = 0;
scr->maxdispoffset = scr->dispoffset +
type->nrows * type->ncols * type->fontheight;
vh = &vc->hdl;
LIST_INIT(&scr->fontset);
vga_raster_setup_font(vc, scr);
if (existing) {
int i;
cpos = vga_6845_read(vh, cursorh) << 8;
cpos |= vga_6845_read(vh, cursorl);
/* make sure we have a valid cursor position */
if (cpos < 0 || cpos >= type->nrows * type->ncols)
cpos = 0;
scr->dispoffset = vga_6845_read(vh, startadrh) << 9;
scr->dispoffset |= vga_6845_read(vh, startadrl) << 1;
/* make sure we have a valid memory offset */
if (scr->dispoffset < scr->mindispoffset ||
scr->dispoffset > scr->maxdispoffset)
scr->dispoffset = scr->mindispoffset;
scr->mem = boot_scrmem;
scr->active = 1;
/* Save the current screen to memory. XXXBJY assume 80x25 */
for (i = 0; i < 80 * 25; i++) {
scr->mem[i].ch = bus_space_read_1(vh->vh_memt,
vh->vh_allmemh, 0x18000 + i * 2);
scr->mem[i].attr = bus_space_read_1(vh->vh_memt,
vh->vh_allmemh, 0x18000 + i * 2 + 1);
scr->mem[i].enc = scr->encoding;
}
vga_raster_setscreentype(vc, type);
/* Clear the entire screen. */
vga_gdc_write(vh, mode, 0x02);
bus_space_set_region_4(vh->vh_memt, vh->vh_allmemh, 0, 0,
0x4000);
vga_restore_screen(scr, type, scr->mem);
} else {
cpos = 0;
scr->dispoffset = scr->mindispoffset;
scr->mem = NULL;
scr->active = 0;
}
scr->cursorrow = cpos / type->ncols;
scr->cursorcol = cpos % type->ncols;
vga_raster_cursor_init(scr, existing);
#ifdef __alpha__
if (!vc->hdl.vh_mono)
/*
* DEC firmware uses a blue background.
*/
res = vga_raster_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE,
WSATTR_WSCOLORS, attrp);
else
#endif
res = vga_raster_allocattr(scr, 0, 0, 0, attrp);
#ifdef DIAGNOSTIC
if (res)
panic("vga_raster_init_screen: attribute botch");
#endif
vc->nscreens++;
LIST_INSERT_HEAD(&vc->screens, scr, next);
}
void
vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot,
bus_space_tag_t memt, int type, int quirks,
const struct vga_funcs *vf)
{
int console;
struct vga_config *vc;
struct wsemuldisplaydev_attach_args aa;
console = vga_is_console(iot, type);
if (console) {
vc = &vga_console_vc;
vga_console_attached = 1;
} else {
vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK);
vga_raster_init(vc, iot, memt);
}
vc->vc_type = type;
vc->vc_funcs = vf;
sc->sc_vc = vc;
vc->softc = sc;
aa.console = console;
aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
aa.accessops = &vga_raster_accessops;
aa.accesscookie = vc;
config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
}
int
vga_cndetach(void)
{
struct vga_config *vc;
struct vga_handle *vh;
vc = &vga_console_vc;
vh = &vc->hdl;
if (vgaconsole) {
bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
return 1;
}
return 0;
}
int
vga_is_console(bus_space_tag_t iot, int type)
{
if (vgaconsole &&
!vga_console_attached &&
iot == vga_console_vc.hdl.vh_iot &&
(vga_console_type == -1 || (type == vga_console_type)))
return (1);
return (0);
}
static int
vga_get_video(struct vga_config *vc)
{
return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0;
}
static void
vga_set_video(struct vga_config *vc, int state)
{
int val;
vga_ts_write(&vc->hdl, syncreset, 0x01);
if (state) { /* unblank screen */
val = vga_ts_read(&vc->hdl, mode);
vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK);
#ifndef VGA_NO_VBLANK
val = vga_6845_read(&vc->hdl, mode);
vga_6845_write(&vc->hdl, mode, val | 0x80);
#endif
} else { /* blank screen */
val = vga_ts_read(&vc->hdl, mode);
vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK);
#ifndef VGA_NO_VBLANK
val = vga_6845_read(&vc->hdl, mode);
vga_6845_write(&vc->hdl, mode, val & ~0x80);
#endif
}
vga_ts_write(&vc->hdl, syncreset, 0x03);
}
int
vga_raster_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
struct lwp *l)
{
struct vga_config *vc = v;
const struct vga_funcs *vf = vc->vc_funcs;
switch (cmd) {
case WSDISPLAYIO_GTYPE:
*(int *)data = vc->vc_type;
return 0;
case WSDISPLAYIO_GINFO:
/* XXX should get detailed hardware information here */
return EPASSTHROUGH;
case WSDISPLAYIO_GVIDEO:
#if 1
*(int *)data = (vga_get_video(vc) ?
WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF);
return 0;
#endif
case WSDISPLAYIO_SVIDEO:
#if 1
vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
return 0;
#endif
case WSDISPLAYIO_GETCMAP:
case WSDISPLAYIO_PUTCMAP:
case WSDISPLAYIO_GCURPOS:
case WSDISPLAYIO_SCURPOS:
case WSDISPLAYIO_GCURMAX:
case WSDISPLAYIO_GCURSOR:
case WSDISPLAYIO_SCURSOR:
/* NONE of these operations are by the generic VGA driver. */
return EPASSTHROUGH;
}
if (vc->vc_funcs == NULL)
return (EPASSTHROUGH);
if (vf->vf_ioctl == NULL)
return (EPASSTHROUGH);
return ((*vf->vf_ioctl)(v, cmd, data, flag, l));
}
static paddr_t
vga_raster_mmap(void *v, void *vs, off_t offset, int prot)
{
struct vga_config *vc = v;
const struct vga_funcs *vf = vc->vc_funcs;
if (vc->vc_funcs == NULL)
return (-1);
if (vf->vf_mmap == NULL)
return (-1);
return ((*vf->vf_mmap)(v, offset, prot));
}
int
vga_raster_alloc_screen(void *v, const struct wsscreen_descr *type,
void **cookiep, int *curxp, int *curyp, long *defattrp)
{
struct vga_config *vc = v;
struct vgascreen *scr;
if (vc->nscreens == 1) {
vc->screens.lh_first->mem = boot_scrmem;
}
scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
vga_raster_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
if (vc->nscreens == 1) {
scr->active = 1;
vc->active = scr;
vc->currenttype = type;
} else {
scr->mem = malloc(sizeof(struct vga_scrmem) *
type->ncols * type->nrows, M_DEVBUF, M_WAITOK);
vga_raster_eraserows(scr, 0, type->nrows, *defattrp);
}
*cookiep = scr;
*curxp = scr->cursorcol;
*curyp = scr->cursorrow;
return (0);
}
void
vga_raster_free_screen(void *v, void *cookie)
{
struct vgascreen *vs = cookie;
struct vga_config *vc = vs->cfg;
LIST_REMOVE(vs, next);
vc->nscreens--;
if (vs != &vga_console_screen)
free(vs, M_DEVBUF);
else
panic("vga_raster_free_screen: console");
if (vc->active == vs)
vc->active = 0;
}
int
vga_raster_show_screen(void *v, void *cookie, int waitok,
void (*cb)(void *, int, int), void *cbarg)
{
struct vgascreen *scr = cookie, *oldscr;
struct vga_config *vc = scr->cfg;
oldscr = vc->active; /* can be NULL! */
if (scr == oldscr) {
return (0);
}
vc->wantedscreen = cookie;
vc->switchcb = cb;
vc->switchcbarg = cbarg;
if (cb) {
callout_reset(&vc->vc_switch_callout, 0,
(void(*)(void *))vga_switch_screen, vc);
return (EAGAIN);
}
vga_switch_screen(vc);
return (0);
}
void
vga_switch_screen(struct vga_config *vc)
{
struct vgascreen *scr, *oldscr;
struct vga_handle *vh = &vc->hdl;
const struct wsscreen_descr *type;
scr = vc->wantedscreen;
if (!scr) {
printf("vga_switch_screen: disappeared\n");
(*vc->switchcb)(vc->switchcbarg, EIO, 0);
return;
}
type = scr->type;
oldscr = vc->active; /* can be NULL! */
#ifdef DIAGNOSTIC
if (oldscr) {
if (!oldscr->active)
panic("vga_raster_show_screen: not active");
if (oldscr->type != vc->currenttype)
panic("vga_raster_show_screen: bad type");
}
#endif
if (scr == oldscr) {
return;
}
#ifdef DIAGNOSTIC
if (scr->active)
panic("vga_raster_show_screen: active");
#endif
if (oldscr)
oldscr->active = 0;
if (vc->currenttype != type) {
vga_raster_setscreentype(vc, type);
vc->currenttype = type;
}
scr->dispoffset = scr->mindispoffset;
if (!oldscr || (scr->dispoffset != oldscr->dispoffset)) {
vga_6845_write(vh, startadrh, scr->dispoffset >> 8);
vga_6845_write(vh, startadrl, scr->dispoffset);
}
/* Clear the entire screen. */
vga_gdc_write(vh, mode, 0x02);
bus_space_set_region_4(vh->vh_memt, vh->vh_allmemh, 0, 0, 0x2000);
scr->active = 1;
vga_restore_screen(scr, type, scr->mem);
vc->active = scr;
vga_raster_cursor(scr, scr->cursoron, scr->cursorrow, scr->cursorcol);
vc->wantedscreen = 0;
if (vc->switchcb)
(*vc->switchcb)(vc->switchcbarg, 0, 0);
}
static int
vga_raster_load_font(void *v, void *id,
struct wsdisplay_font *data)
{
/* XXX */
printf("vga_raster_load_font: called\n");
return (0);
}
void
vga_raster_setup_font(struct vga_config *vc, struct vgascreen *scr)
{
struct vga_raster_font *vf;
struct wsdisplay_font *wf;
int cookie;
LIST_FOREACH(vf, &vc->vc_fontlist, next) {
if (wsfont_matches(vf->font, 0, 0, scr->type->fontheight, 0)) {
scr->encoding = vf->font->encoding;
LIST_INSERT_HEAD(&scr->fontset, vf, next);
return;
}
}
cookie = wsfont_find(NULL, 0, scr->type->fontheight, 0,
WSDISPLAY_FONTORDER_L2R, 0);
if (cookie == -1)
return;
if (wsfont_lock(cookie, &wf))
return;
vf = malloc(sizeof(struct vga_raster_font), M_DEVBUF, M_NOWAIT);
if (!vf) {
wsfont_unlock(cookie);
return;
}
vf->font = wf;
scr->encoding = vf->font->encoding;
LIST_INSERT_HEAD(&scr->fontset, vf, next);
}
void
vga_setup_regs(struct videomode *mode, struct vga_moderegs *regs)
{
int i;
int depth = 4; /* XXXBJY hardcoded for now */
const u_int8_t palette[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
};
/*
* Compute hsync and vsync polarity.
*/
if ((mode->flags & (VID_PHSYNC | VID_NHSYNC))
&& (mode->flags & (VID_PVSYNC | VID_NVSYNC))) {
regs->miscout = 0x23;
if (mode->flags & VID_NHSYNC)
regs->miscout |= 0x40;
if (mode->flags & VID_NVSYNC)
regs->miscout |= 0x80;
} else {
if (mode->flags & VID_DBLSCAN)
mode->vdisplay *= 2;
if (mode->vdisplay < 400)
regs->miscout = 0xa3;
else if (mode->vdisplay < 480)
regs->miscout = 0x63;
else if (mode->vdisplay < 768)
regs->miscout = 0xe3;
else
regs->miscout = 0x23;
}
/*
* Time sequencer
*/
if (depth == 4)
regs->ts[0] = 0x02;
else
regs->ts[0] = 0x00;
if (mode->flags & VID_CLKDIV2)
regs->ts[1] = 0x09;
else
regs->ts[1] = 0x01;
regs->ts[2] = 0x0f;
regs->ts[3] = 0x00;
if (depth < 8)
regs->ts[4] = 0x06;
else
regs->ts[4] = 0x0e;
/*
* CRTC controller
*/
regs->crtc[0] = (mode->htotal >> 3) - 5;
regs->crtc[1] = (mode->hdisplay >> 3) - 1;
regs->crtc[2] = (mode->hsync_start >> 3) - 1;
regs->crtc[3] = (((mode->hsync_end >> 3) - 1) & 0x1f) | 0x80;
regs->crtc[4] = mode->hsync_start >> 3;
regs->crtc[5] = ((((mode->hsync_end >> 3) - 1) & 0x20) << 2)
| (((mode->hsync_end >> 3)) & 0x1f);
regs->crtc[6] = (mode->vtotal - 2) & 0xff;
regs->crtc[7] = (((mode->vtotal - 2) & 0x100) >> 8)
| (((mode->vdisplay - 1) & 0x100) >> 7)
| ((mode->vsync_start & 0x100) >> 6)
| (((mode->vsync_start - 1) & 0x100) >> 5)
| 0x10
| (((mode->vtotal - 2) & 0x200) >> 4)
| (((mode->vdisplay - 1) & 0x200) >> 3)
| ((mode->vsync_start & 0x200) >> 2);
regs->crtc[8] = 0x00;
regs->crtc[9] = (((mode->vsync_start - 1) & 0x200) >> 4) | 0x40;
if (mode->flags & VID_DBLSCAN)
regs->crtc[9] |= 0x80;
regs->crtc[10] = 0x00;
regs->crtc[11] = 0x00;
regs->crtc[12] = 0x00;
regs->crtc[13] = 0x00;
regs->crtc[14] = 0x00;
regs->crtc[15] = 0x00;
regs->crtc[16] = mode->vsync_start & 0xff;
regs->crtc[17] = (mode->vsync_end & 0x0f) | 0x20;
regs->crtc[18] = (mode->vdisplay - 1) & 0xff;
regs->crtc[19] = mode->hdisplay >> 4; /* XXXBJY */
regs->crtc[20] = 0x00;
regs->crtc[21] = (mode->vsync_start - 1) & 0xff;
regs->crtc[22] = (mode->vsync_end - 1) & 0xff;
if (depth < 8)
regs->crtc[23] = 0xe3;
else
regs->crtc[23] = 0xc3;
regs->crtc[24] = 0xff;
/*
* Graphics display controller
*/
regs->gdc[0] = 0x00;
regs->gdc[1] = 0x00;
regs->gdc[2] = 0x00;
regs->gdc[3] = 0x00;
regs->gdc[4] = 0x00;
if (depth == 4)
regs->gdc[5] = 0x02;
else
regs->gdc[5] = 0x40;
regs->gdc[6] = 0x01;
regs->gdc[7] = 0x0f;
regs->gdc[8] = 0xff;
/*
* Attribute controller
*/
/* Set palette registers. */
for (i = 0; i < 16; i++)
regs->atc[i] = palette[i];
if (depth == 4)
regs->atc[16] = 0x01; /* XXXBJY was 0x81 in XFree86 */
else
regs->atc[16] = 0x41;
regs->atc[17] = 0x00; /* XXXBJY just a guess */
regs->atc[18] = 0x0f;
regs->atc[19] = 0x00;
regs->atc[20] = 0x00;
}
void
vga_set_mode(struct vga_handle *vh, struct vga_moderegs *regs)
{
int i;
/* Disable display. */
vga_ts_write(vh, mode, vga_ts_read(vh, mode) | VGA_TS_MODE_BLANK);
/* Write misc output register. */
bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAW,
regs->miscout);
/* Set synchronous reset. */
vga_ts_write(vh, syncreset, 0x01);
vga_ts_write(vh, mode, regs->ts[1] | VGA_TS_MODE_BLANK);
for (i = 2; i < VGA_TS_NREGS; i++)
_vga_ts_write(vh, i, regs->ts[i]);
/* Clear synchronous reset. */
vga_ts_write(vh, syncreset, 0x03);
/* Unprotect CRTC registers 0-7. */
vga_6845_write(vh, vsynce, vga_6845_read(vh, vsynce) & ~0x80);
/* Write CRTC registers. */
for (i = 0; i < MC6845_NREGS; i++)
_vga_6845_write(vh, i, regs->crtc[i]);
/* Write graphics display registers. */
for (i = 0; i < VGA_GDC_NREGS; i++)
_vga_gdc_write(vh, i, regs->gdc[i]);
/* Write attribute controller registers. */
for (i = 0; i < VGA_ATC_NREGS; i++)
_vga_attr_write(vh, i, regs->atc[i]);
/* Enable display. */
vga_ts_write(vh, mode, vga_ts_read(vh, mode) & ~VGA_TS_MODE_BLANK);
}
void
vga_raster_cursor_init(struct vgascreen *scr, int existing)
{
struct vga_handle *vh = scr->hdl;
bus_space_tag_t memt;
bus_space_handle_t memh;
int off;
if (existing) {
/*
* This is the first screen. At this point, scr->active is
* false, so we can't use vga_raster_cursor() to do this.
*/
memt = vh->vh_memt;
memh = vh->vh_memh;
off = (scr->cursorrow * scr->type->ncols + scr->cursorcol) +
scr->dispoffset / 8;
scr->cursortmp = scr->mem[off];
vga_raster_putchar(scr, scr->cursorrow, scr->cursorcol,
scr->cursortmp.ch, scr->cursortmp.attr ^ 0x77);
} else {
scr->cursortmp.ch = 0;
scr->cursortmp.attr = 0;
scr->cursortmp.second = 0;
scr->cursortmp.enc = scr->encoding;
}
scr->cursoron = 1;
}
void
vga_raster_cursor(void *id, int on, int row, int col)
{
struct vgascreen *scr = id;
int off, tmp;
/* Remove old cursor image */
if (scr->cursoron) {
off = scr->cursorrow * scr->type->ncols + scr->cursorcol;
if (scr->active) {
tmp = scr->encoding;
scr->encoding = scr->cursortmp.enc;
if (scr->cursortmp.second)
vga_raster_putchar(id, scr->cursorrow,
scr->cursorcol - 1, scr->cursortmp.ch,
scr->cursortmp.attr);
else
vga_raster_putchar(id, scr->cursorrow,
scr->cursorcol, scr->cursortmp.ch,
scr->cursortmp.attr);
scr->encoding = tmp;
}
}
scr->cursorrow = row;
scr->cursorcol = col;
if ((scr->cursoron = on) == 0)
return;
off = scr->cursorrow * scr->type->ncols + scr->cursorcol;
scr->cursortmp = scr->mem[off];
if (scr->active) {
tmp = scr->encoding;
scr->encoding = scr->cursortmp.enc;
if (scr->cursortmp.second)
vga_raster_putchar(id, scr->cursorrow,
scr->cursorcol - 1, scr->cursortmp.ch,
scr->cursortmp.attr ^ 0x77);
else
vga_raster_putchar(id, scr->cursorrow,
scr->cursorcol, scr->cursortmp.ch,
scr->cursortmp.attr ^ 0x77);
scr->encoding = tmp;
}
}
static int
vga_raster_mapchar(void *id, int uni, u_int *index)
{
struct vgascreen *scr = id;
if (scr->encoding == WSDISPLAY_FONTENC_IBM)
return pcdisplay_mapchar(id, uni, index);
else {
*index = uni;
return 5;
}
}
void
vga_raster_putchar(void *id, int row, int col, u_int c, long attr)
{
struct vgascreen *scr = id;
size_t off;
struct vga_raster_font *fs;
u_int tmp_ch;
off = row * scr->type->ncols + col;
if (__predict_false(off >= (scr->type->ncols * scr->type->nrows)))
return;
LIST_FOREACH(fs, &scr->fontset, next) {
if ((scr->encoding == fs->font->encoding) &&
(c >= fs->font->firstchar) &&
(c < fs->font->firstchar + fs->font->numchars) &&
(scr->type->fontheight == fs->font->fontheight)) {
if (scr->active) {
tmp_ch = c - fs->font->firstchar;
_vga_raster_putchar(scr, row, col, tmp_ch,
attr, fs);
}
scr->mem[off].ch = c;
scr->mem[off].attr = attr;
scr->mem[off].second = 0;
scr->mem[off].enc = fs->font->encoding;
if (fs->font->stride == 2) {
scr->mem[off + 1].ch = c;
scr->mem[off + 1].attr = attr;
scr->mem[off + 1].second = 1;
scr->mem[off + 1].enc = fs->font->encoding;
}
return;
}
}
/*
* No match found.
*/
if (scr->active)
/*
* Put a single width space character no matter what the
* actual width of the character is.
*/
_vga_raster_putchar(scr, row, col, ' ', attr,
&vga_console_fontset_ascii);
scr->mem[off].ch = c;
scr->mem[off].attr = attr;
scr->mem[off].second = 0;
scr->mem[off].enc = scr->encoding;
}
static void
_vga_raster_putchar(void *id, int row, int col, u_int c, long attr,
struct vga_raster_font *fs)
{
struct vgascreen *scr = id;
struct vga_handle *vh = scr->hdl;
bus_space_tag_t memt = vh->vh_memt;
bus_space_handle_t memh = vh->vh_memh;
int i;
int rasoff, rasoff2;
int fheight = scr->type->fontheight;
volatile u_int8_t dummy, pattern;
u_int8_t fgcolor, bgcolor;
rasoff = scr->dispoffset + row * scr->type->ncols * fheight + col;
rasoff2 = rasoff;
#if 0
bgcolor = bgansitopc[attr >> 4];
fgcolor = fgansitopc[attr & 0x0f];
#else
bgcolor = ((attr >> 4) & 0x0f);
fgcolor = attr & 0x0f;
#endif
if (fs->font->stride == 1) {
/* Paint background. */
vga_gdc_write(vh, mode, 0x02);
for (i = 0; i < fheight; i++) {
bus_space_write_1(memt, memh, rasoff, bgcolor);
rasoff += scr->type->ncols;
}
/* Draw a single width character. */
vga_gdc_write(vh, mode, 0x03);
vga_gdc_write(vh, setres, fgcolor);
for (i = 0; i < fheight; i++) {
pattern = ((u_int8_t *)fs->font->data)[c * fheight + i];
/* When pattern is 0, skip output for speed-up. */
if (pattern != 0) {
dummy = bus_space_read_1(memt, memh, rasoff2);
bus_space_write_1(memt, memh, rasoff2, pattern);
}
rasoff2 += scr->type->ncols;
}
} else if (fs->font->stride == 2) {
/* Paint background. */
vga_gdc_write(vh, mode, 0x02);
for (i = 0; i < fheight; i++) {
bus_space_write_1(memt, memh, rasoff, bgcolor);
bus_space_write_1(memt, memh, rasoff + 1, bgcolor);
rasoff += scr->type->ncols;
}
/* Draw a double width character. */
vga_gdc_write(vh, mode, 0x03);
vga_gdc_write(vh, setres, fgcolor);
for (i = 0; i < fheight; i++) {
pattern = ((u_int8_t *)fs->font->data)
[(c * fheight + i) * 2];
if (pattern != 0) {
dummy = bus_space_read_1(memt, memh, rasoff2);
bus_space_write_1(memt, memh, rasoff2, pattern);
}
pattern = ((u_int8_t *)fs->font->data)
[(c * fheight + i) * 2 + 1];
if (pattern != 0) {
rasoff2++;
dummy = bus_space_read_1(memt, memh, rasoff2);
bus_space_write_1(memt, memh, rasoff2, pattern);
rasoff2--;
}
rasoff2 += scr->type->ncols;
}
}
}
void
vga_raster_copycols(void *id, int row, int srccol, int dstcol, int ncols)
{
struct vgascreen *scr = id;
struct vga_handle *vh = scr->hdl;
bus_space_tag_t memt = vh->vh_memt;
bus_space_handle_t memh = vh->vh_memh;
bus_size_t srcoff, dstoff;
bus_size_t rassrcoff, rasdstoff;
int i;
int fheight = scr->type->fontheight;
srcoff = row * scr->type->ncols + srccol;
dstoff = row * scr->type->ncols + dstcol;
rassrcoff = scr->dispoffset + row * scr->type->ncols * fheight + srccol;
rasdstoff = scr->dispoffset + row * scr->type->ncols * fheight + dstcol;
memcpy(&scr->mem[dstoff], &scr->mem[srcoff],
ncols * sizeof(struct vga_scrmem));
vga_gdc_write(vh, mode, 0x01);
if (scr->active) {
for (i = 0; i < fheight; i++) {
bus_space_copy_region_1(memt, memh,
rassrcoff + i * scr->type->ncols, memh,
rasdstoff + i * scr->type->ncols, ncols);
}
}
}
void
vga_raster_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
{
struct vgascreen *scr = id;
int i;
if (scr->active == 0)
return;
for (i = startcol; i < startcol + ncols; i++)
vga_raster_putchar(id, row, i, ' ', fillattr);
}
void
vga_raster_copyrows(void *id, int srcrow, int dstrow, int nrows)
{
struct vgascreen *scr = id;
struct vga_handle *vh = scr->hdl;
bus_space_tag_t memt = vh->vh_memt;
bus_space_handle_t memh = vh->vh_memh;
int ncols;
bus_size_t srcoff, dstoff;
bus_size_t rassrcoff, rasdstoff;
int fheight;
ncols = scr->type->ncols;
fheight = scr->type->fontheight;
srcoff = srcrow * ncols;
dstoff = dstrow * ncols;
rassrcoff = srcoff * fheight;
rasdstoff = dstoff * fheight;
if (scr->active) {
vga_gdc_write(vh, mode, 0x01);
if (dstrow == 0 && (srcrow + nrows == scr->type->nrows)) {
int cursoron = scr->cursoron;
if (cursoron)
/* Disable cursor. */
vga_raster_cursor(scr, 0,
scr->cursorrow, scr->cursorcol);
/* scroll up whole screen */
if ((scr->dispoffset + srcrow * ncols * fheight)
<= scr->maxdispoffset)
scr->dispoffset += srcrow * ncols * fheight;
else {
bus_space_copy_region_1(memt, memh,
scr->dispoffset + rassrcoff,
memh, scr->mindispoffset,
nrows * ncols * fheight);
scr->dispoffset = scr->mindispoffset;
}
vga_6845_write(vh, startadrh, scr->dispoffset >> 8);
vga_6845_write(vh, startadrl, scr->dispoffset);
if (cursoron)
/* Enable cursor. */
vga_raster_cursor(scr, 1, scr->cursorrow,
scr->cursorcol);
} else
bus_space_copy_region_1(memt, memh,
scr->dispoffset + rassrcoff, memh,
scr->dispoffset + rasdstoff,
nrows * ncols * fheight);
}
memcpy(&scr->mem[dstoff], &scr->mem[srcoff],
nrows * ncols * sizeof(struct vga_scrmem));
}
void
vga_raster_eraserows(void *id, int startrow, int nrows, long fillattr)
{
struct vgascreen *scr = id;
struct vga_handle *vh = scr->hdl;
bus_space_tag_t memt = vh->vh_memt;
bus_space_handle_t memh = vh->vh_memh;
bus_size_t off, count;
bus_size_t rasoff, rascount;
int i;
off = startrow * scr->type->ncols;
count = nrows * scr->type->ncols;
rasoff = off * scr->type->fontheight;
rascount = count * scr->type->fontheight;
if (scr->active) {
u_int8_t bgcolor = (fillattr >> 4) & 0x0F;
/* Paint background. */
vga_gdc_write(vh, mode, 0x02);
if (scr->type->ncols % 4 == 0) {
u_int32_t fill = bgcolor | (bgcolor << 8) |
(bgcolor << 16) | (bgcolor << 24);
/* We can speed up I/O */
for (i = rasoff; i < rasoff + rascount; i += 4)
bus_space_write_4(memt, memh,
scr->dispoffset + i, fill);
} else {
u_int16_t fill = bgcolor | (bgcolor << 8);
for (i = rasoff; i < rasoff + rascount; i += 2)
bus_space_write_2(memt, memh,
scr->dispoffset + i, fill);
}
}
for (i = 0; i < count; i++) {
scr->mem[off + i].ch = ' ';
scr->mem[off + i].attr = fillattr;
scr->mem[off + i].second = 0;
scr->mem[off + i].enc = scr->encoding;
}
}
static int
vga_raster_allocattr(void *id, int fg, int bg, int flags, long *attrp)
{
struct vgascreen *scr = id;
struct vga_config *vc = scr->cfg;
if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) ||
(unsigned int)bg >= sizeof(bgansitopc)))
return (EINVAL);
if (vc->hdl.vh_mono) {
if (flags & WSATTR_WSCOLORS)
return (EINVAL);
if (flags & WSATTR_REVERSE)
*attrp = 0x70;
else
*attrp = 0x07;
if (flags & WSATTR_UNDERLINE)
*attrp |= FG_UNDERLINE;
if (flags & WSATTR_HILIT)
*attrp |= FG_INTENSE;
} else {
if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
return (EINVAL);
if (flags & WSATTR_WSCOLORS)
*attrp = fgansitopc[fg] | bgansitopc[bg];
else
*attrp = 7;
if (flags & WSATTR_HILIT)
*attrp += 8;
}
if (flags & WSATTR_BLINK)
*attrp |= FG_BLINK;
return (0);
}
void
vga_restore_screen(struct vgascreen *scr,
const struct wsscreen_descr *type, struct vga_scrmem *mem)
{
int i, j, off, tmp;
tmp = scr->encoding;
for (i = 0; i < type->nrows; i++) {
for (j = 0; j < type->ncols; j++) {
off = i * type->ncols + j;
if (mem[off].second != 1) {
scr->encoding = mem[off].enc;
vga_raster_putchar(scr, i, j, mem[off].ch,
mem[off].attr);
}
}
}
scr->encoding = tmp;
}
void
vga_raster_setscreentype(struct vga_config *vc,
const struct wsscreen_descr *type)
{
struct vga_handle *vh = &vc->hdl;
struct vga_moderegs moderegs;
vga_setup_regs((struct videomode *)type->modecookie, &moderegs);
vga_set_mode(vh, &moderegs);
}
#ifdef WSDISPLAY_CUSTOM_OUTPUT
void
vga_raster_replaceattr(void *id, long oldattr, long newattr)
{
struct vgascreen *scr = id;
const struct wsscreen_descr *type = scr->type;
int off;
for (off = 0; off < type->nrows * type->ncols; off++) {
if (scr->mem[off].attr == oldattr)
scr->mem[off].attr = newattr;
}
/* Repaint the whole screen, if needed */
if (scr->active)
vga_restore_screen(scr, type, scr->mem);
}
#endif /* WSDISPLAY_CUSTOM_OUTPUT */
void
vga_resume(struct vga_softc *sc)
{
#ifdef VGA_RESET_ON_RESUME
vga_initregs(&sc->sc_vc->hdl);
#endif
}