vga_isa.c revision 46743
1138323Swollman/*-
22742Swollman * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
32742Swollman * Copyright (c) 1992-1998 S�ren Schmidt
42742Swollman * All rights reserved.
52742Swollman *
62742Swollman * Redistribution and use in source and binary forms, with or without
72742Swollman * modification, are permitted provided that the following conditions
858787Sru * are met:
92742Swollman * 1. Redistributions of source code must retain the above copyright
1058787Sru *    notice, this list of conditions and the following disclaimer as
112742Swollman *    the first lines of this file unmodified.
122742Swollman * 2. Redistributions in binary form must reproduce the above copyright
132742Swollman *    notice, this list of conditions and the following disclaimer in the
142742Swollman *    documentation and/or other materials provided with the distribution.
152742Swollman * 3. The name of the author may not be used to endorse or promote products
1658787Sru *    derived from this software without specific prior written permission.
1758787Sru *
1858787Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1958787Sru * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2058787Sru * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2158787Sru * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2258787Sru * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2358787Sru * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2458787Sru * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2558787Sru * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2658787Sru * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2714343Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2814343Swollman *
2914343Swollman * $Id: vga_isa.c,v 1.6 1999/05/08 20:20:18 peter Exp $
3014343Swollman */
3114343Swollman
3214343Swollman#include "vga.h"
3314343Swollman#include "opt_vga.h"
3475267Swollman#include "opt_fb.h"
3517200Swollman#include "opt_syscons.h"	/* should be removed in the future, XXX */
3675267Swollman
3775267Swollman#if NVGA > 0
3817200Swollman
3917200Swollman#include <sys/param.h>
4017200Swollman#include <sys/systm.h>
4117200Swollman#include <sys/kernel.h>
4217200Swollman#include <sys/bus.h>
4317200Swollman#include <sys/malloc.h>
4417200Swollman
4517200Swollman#include <vm/vm.h>
4617200Swollman#include <vm/pmap.h>
4717200Swollman
4817200Swollman#include <machine/console.h>
4917200Swollman#include <machine/md_var.h>
5017200Swollman#include <machine/pc/bios.h>
5117200Swollman
5275267Swollman#include <dev/fb/fbreg.h>
5375267Swollman#include <dev/fb/vgareg.h>
5475267Swollman
5575267Swollman#if 1
5675267Swollman#include <isa/isareg.h>
5775267Swollman#include <isa/isavar.h>
5875267Swollman#else
5975267Swollman#include <i386/isa/isa.h>
6075267Swollman#include <i386/isa/isa_device.h>
6175267Swollman#endif
6217200Swollman
632742Swollman#define DRIVER_NAME		"vga"
642742Swollman
6519878Swollman/* cdev driver declaration */
6619878Swollman
672742Swollman#define ISAVGA_UNIT(dev)	minor(dev)
682742Swollman#define ISAVGA_MKMINOR(unit)	(unit)
692742Swollman
702742Swollmantypedef struct isavga_softc {
712742Swollman	video_adapter_t	*adp;
7267578Swollman} isavga_softc_t;
7367578Swollman
7467578Swollman#if 1
7567578Swollman
7667578Swollman#define ISAVGA_SOFTC(unit)		\
7767578Swollman	((isavga_softc_t *)devclass_get_softc(isavga_devclass, unit))
7867578Swollman
7967578Swollmandevclass_t		isavga_devclass;
8067578Swollman
8167578Swollmanstatic int		isavga_probe(device_t dev);
8267578Swollmanstatic int		isavga_attach(device_t dev);
8367578Swollman
8486222Swollmanstatic device_method_t isavga_methods[] = {
8567578Swollman	DEVMETHOD(device_probe,		isavga_probe),
8667578Swollman	DEVMETHOD(device_attach,	isavga_attach),
8767578Swollman	{ 0, 0 }
8867578Swollman};
8986222Swollman
9067578Swollmanstatic driver_t isavga_driver = {
91114173Swollman	DRIVER_NAME,
92114173Swollman	isavga_methods,
93114173Swollman	sizeof(isavga_softc_t),
94114173Swollman};
95114173Swollman
96114173SwollmanDRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0);
97114173Swollman
98114173Swollman#else /* __i386__ */
99114173Swollman
100114173Swollman#define ISAVGA_SOFTC(unit)	(isavga_softc[unit])
101114173Swollman
102114173Swollmanstatic isavga_softc_t	*isavga_softc[NVGA];
103114173Swollman
104114173Swollmanstatic int		isavga_probe(struct isa_device *dev);
105114173Swollmanstatic int		isavga_attach(struct isa_device *dev);
106114173Swollman
107114173Swollmanstruct isa_driver vgadriver = {
1082742Swollman	isavga_probe,
10975267Swollman	isavga_attach,
1102742Swollman	DRIVER_NAME,
1112742Swollman	0,
11267578Swollman};
1132742Swollman
1142742Swollman#endif /* __i386__ */
1152742Swollman
1162742Swollmanstatic int		isavga_probe_unit(int unit, isavga_softc_t *sc,
1172742Swollman					  int flags);
1182742Swollmanstatic int		isavga_attach_unit(int unit, isavga_softc_t *sc,
1192742Swollman					   int flags);
12043543Swollman
12143543Swollman#ifdef FB_INSTALL_CDEV
12243543Swollman
1232742Swollmanstatic d_open_t		isavgaopen;
12419878Swollmanstatic d_close_t	isavgaclose;
1252742Swollmanstatic d_read_t		isavgaread;
1262742Swollmanstatic d_ioctl_t	isavgaioctl;
1272742Swollman
1282742Swollmanstatic struct  cdevsw vga_cdevsw = {
1292742Swollman	isavgaopen,	isavgaclose,	noread,		nowrite,	/* ?? */
1302742Swollman	isavgaioctl,	nostop,		nullreset,	nodevtotty,
1312742Swollman	seltrue,	nommap,		NULL,		DRIVER_NAME,
1322742Swollman	NULL,		-1,		nodump,		nopsize,
1332742Swollman};
1342742Swollman
1352742Swollman#endif /* FB_INSTALL_CDEV */
13614343Swollman
13714343Swollman#if 1
13814343Swollman
13914343Swollmanstatic int
14019878Swollmanisavga_probe(device_t dev)
1412742Swollman{
1422742Swollman	isavga_softc_t *sc;
1432742Swollman
1442742Swollman	device_set_desc(dev, "Generic ISA VGA");
1452742Swollman	sc = device_get_softc(dev);
1462742Swollman	return isavga_probe_unit(device_get_unit(dev), sc, isa_get_flags(dev));
1472742Swollman}
1482742Swollman
1492742Swollmanstatic int
1502742Swollmanisavga_attach(device_t dev)
1512742Swollman{
1522742Swollman	isavga_softc_t *sc;
1532742Swollman
1542742Swollman	sc = device_get_softc(dev);
1552742Swollman	return isavga_attach_unit(device_get_unit(dev), sc, isa_get_flags(dev));
15619878Swollman}
1572742Swollman
1582742Swollman#else /* __i386__ */
1592742Swollman
1602742Swollmanstatic int
1612742Swollmanisavga_probe(struct isa_device *dev)
16219878Swollman{
1632742Swollman	isavga_softc_t *sc;
1642742Swollman	int error;
16519878Swollman
1662742Swollman	if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0]))
1672742Swollman		return 0;
1682742Swollman	sc = isavga_softc[dev->id_unit]
1692742Swollman	   = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
1702742Swollman	if (sc == NULL)
1712742Swollman		return 0;
1722742Swollman
1732742Swollman	error = isavga_probe_unit(dev->id_unit, sc, dev->id_flags);
1742742Swollman	if (error) {
17519878Swollman		isavga_softc[dev->id_unit] = NULL;
1762742Swollman		free(sc, M_DEVBUF);
1772742Swollman		return 0;
1782742Swollman	}
1792742Swollman
1802742Swollman	dev->id_iobase = sc->adp->va_io_base;
1812742Swollman	dev->id_maddr = (caddr_t)BIOS_PADDRTOVADDR(sc->adp->va_mem_base);
1822742Swollman	dev->id_msize = sc->adp->va_mem_size;
1832742Swollman
1842742Swollman	return sc->adp->va_io_size;
18519878Swollman}
1862742Swollman
1872742Swollmanstatic int
1882742Swollmanisavga_attach(struct isa_device *dev)
1892742Swollman{
1902742Swollman	isavga_softc_t *sc;
1912742Swollman
1922742Swollman	if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0]))
1932742Swollman		return 0;
1942742Swollman	sc = isavga_softc[dev->id_unit];
19514343Swollman	if (sc == NULL)
19675267Swollman		return 0;
19775267Swollman
19875267Swollman	return ((isavga_attach_unit(dev->id_unit, sc, dev->id_flags)) ? 0 : 1);
19975267Swollman}
2002742Swollman
20186464Swollman#endif /* __i386__ */
20286222Swollman
20375267Swollmanstatic int
20467578Swollmanisavga_probe_unit(int unit, isavga_softc_t *sc, int flags)
205114173Swollman{
206114173Swollman	video_switch_t *sw;
207114173Swollman
208114173Swollman	bzero(sc, sizeof(*sc));
209114173Swollman	sw = vid_get_switch(DRIVER_NAME);
21067578Swollman	if (sw == NULL)
21114343Swollman		return 0;
21214343Swollman	return (*sw->probe)(unit, &sc->adp, NULL, flags);
21314343Swollman}
21414343Swollman
21514343Swollmanstatic int
21614343Swollmanisavga_attach_unit(int unit, isavga_softc_t *sc, int flags)
21714343Swollman{
21814343Swollman	video_switch_t *sw;
21914343Swollman	int error;
22014343Swollman
22114343Swollman	sw = vid_get_switch(DRIVER_NAME);
22214343Swollman	if (sw == NULL)
22314343Swollman		return ENXIO;
2242742Swollman
22586222Swollman	error = (*sw->init)(unit, sc->adp, flags);
22667578Swollman	if (error)
227136638Swollman		return ENXIO;
228136638Swollman
229136638Swollman#ifdef FB_INSTALL_CDEV
230114173Swollman	/* attach a virtual frame buffer device */
231114173Swollman	error = fb_attach(makedev(0, ISAVGA_MKMINOR(unit)), scp->adp,
232114173Swollman			  &vga_cdevsw);
233114173Swollman	if (error)
234114173Swollman		return error;
23567578Swollman#endif /* FB_INSTALL_CDEV */
23614343Swollman
23714343Swollman	if (bootverbose)
23814343Swollman		(*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose);
23914343Swollman
24014343Swollman	return 0;
24114343Swollman}
24214343Swollman
24314343Swollman/* LOW-LEVEL */
24414343Swollman
24514343Swollman#include <machine/clock.h>
24614343Swollman#include <machine/pc/vesa.h>
24714343Swollman
24814343Swollman#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
24914343Swollman#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
25014343Swollman#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
25114343Swollman
25286222Swollman/* for compatibility with old kernel options */
25386222Swollman#ifdef SC_ALT_SEQACCESS
25486222Swollman#undef SC_ALT_SEQACCESS
25586222Swollman#undef VGA_ALT_SEQACCESS
2562742Swollman#define VGA_ALT_SEQACCESS	1
25786222Swollman#endif
25867578Swollman
259136638Swollman#ifdef SLOW_VGA
26086222Swollman#undef SLOW_VGA
26186222Swollman#undef VGA_SLOW_IOACCESS
26275267Swollman#define VGA_SLOW_IOACCESS	1
26375267Swollman#endif
26467578Swollman
26514343Swollman/* architecture dependent option */
26614343Swollman#ifdef __alpha__
26714343Swollman#define VGA_NO_BIOS		1
26814343Swollman#endif
26914343Swollman
27014343Swollman/* this should really be in `rtc.h' */
2712742Swollman#define RTC_EQUIPMENT           0x14
27214343Swollman
27315309Swollman/* various sizes */
27415309Swollman#define V_MODE_MAP_SIZE		(M_VGA_CG320 + 1)
27515309Swollman#define V_MODE_PARAM_SIZE	64
27615309Swollman
27715309Swollman/* video adapter state buffer */
2782742Swollmanstruct adp_state {
27914343Swollman    int			sig;
28067578Swollman#define V_STATE_SIG	0x736f6962
281136638Swollman    u_char		regs[V_MODE_PARAM_SIZE];
282136638Swollman};
283136638Swollmantypedef struct adp_state adp_state_t;
28467578Swollman
28514343Swollman/* video adapter information */
28614343Swollman#define DCC_MONO	0
28714343Swollman#define DCC_CGA40	1
28814343Swollman#define DCC_CGA80	2
28914343Swollman#define DCC_EGAMONO	3
29014343Swollman#define DCC_EGA40	4
29114343Swollman#define DCC_EGA80	5
29214343Swollman
29314343Swollman/*
29414343Swollman * NOTE: `va_window' should have a virtual address, but is initialized
29514343Swollman * with a physical address in the following table, as verify_adapter()
2968029Swollman * will perform address conversion at run-time.
29714343Swollman */
29814343Swollmanstatic video_adapter_t adapter_init_value[] = {
29914343Swollman    /* DCC_MONO */
30086222Swollman    { 0, KD_MONO, "mda", 0, 0, 0, 	    IO_MDA, IO_MDASIZE, MONO_CRTC,
30114343Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
30219878Swollman      0, 0, 0, 7, 0, },
30375267Swollman    /* DCC_CGA40 */
30475267Swollman    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
30575267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
30675267Swollman      0, 0, 0, 3, 0, },
30714343Swollman    /* DCC_CGA80 */
30886222Swollman    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
30986222Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
31086222Swollman      0, 0, 0, 3, 0, },
31186222Swollman    /* DCC_EGAMONO */
31286222Swollman    { 0, KD_EGA,  "ega", 0, 0, 0,	    IO_MDA, 48,	  MONO_CRTC,
31386222Swollman      EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
31486222Swollman      0, 0, 0, 7, 0, },
31514343Swollman    /* DCC_EGA40 */
31675267Swollman    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
31775267Swollman      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
31814343Swollman      0, 0, 0, 3, 0, },
31914343Swollman    /* DCC_EGA80 */
32014343Swollman    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
32114343Swollman      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
322136638Swollman      0, 0, 0, 3, 0, },
32314343Swollman};
32475267Swollman
32575267Swollmanstatic video_adapter_t	biosadapter[2];
32614343Swollmanstatic int		biosadapters = 0;
32714343Swollman
32814343Swollman/* video driver declarations */
329136638Swollmanstatic int			vga_configure(int flags);
33014343Swollman       int			(*vga_sub_configure)(int flags);
33175267Swollmanstatic int			vga_nop(void);
33275267Swollmanstatic vi_probe_t		vga_probe;
33314343Swollmanstatic vi_init_t		vga_init;
33414343Swollmanstatic vi_get_info_t		vga_get_info;
33514343Swollmanstatic vi_query_mode_t		vga_query_mode;
33614343Swollmanstatic vi_set_mode_t		vga_set_mode;
33714343Swollmanstatic vi_save_font_t		vga_save_font;
338136638Swollmanstatic vi_load_font_t		vga_load_font;
33914343Swollmanstatic vi_show_font_t		vga_show_font;
34075267Swollmanstatic vi_save_palette_t	vga_save_palette;
34175267Swollmanstatic vi_load_palette_t	vga_load_palette;
34214343Swollmanstatic vi_set_border_t		vga_set_border;
34314343Swollmanstatic vi_save_state_t		vga_save_state;
34414343Swollmanstatic vi_load_state_t		vga_load_state;
34514343Swollmanstatic vi_set_win_org_t		vga_set_origin;
34614343Swollmanstatic vi_read_hw_cursor_t	vga_read_hw_cursor;
347136638Swollmanstatic vi_set_hw_cursor_t	vga_set_hw_cursor;
34814343Swollmanstatic vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
34975267Swollmanstatic vi_mmap_t		vga_mmap;
35075267Swollmanstatic vi_diag_t		vga_diag;
35114343Swollman
35214343Swollmanstatic video_switch_t vgavidsw = {
35314343Swollman	vga_probe,
35414343Swollman	vga_init,
35514343Swollman	vga_get_info,
356136638Swollman	vga_query_mode,
35714343Swollman	vga_set_mode,
35814343Swollman	vga_save_font,
35914343Swollman	vga_load_font,
36014343Swollman	vga_show_font,
36114343Swollman	vga_save_palette,
3622742Swollman	vga_load_palette,
36314343Swollman	vga_set_border,
36414343Swollman	vga_save_state,
36514343Swollman	vga_load_state,
36614343Swollman	vga_set_origin,
36714343Swollman	vga_read_hw_cursor,
36814343Swollman	vga_set_hw_cursor,
36914343Swollman	vga_set_hw_cursor_shape,
37014343Swollman	(vi_blank_display_t *)vga_nop,
37114343Swollman	vga_mmap,
37214343Swollman	vga_diag,
37314343Swollman};
37414343Swollman
37514343SwollmanVIDEO_DRIVER(mda, vgavidsw, NULL);
37614343SwollmanVIDEO_DRIVER(cga, vgavidsw, NULL);
37714343SwollmanVIDEO_DRIVER(ega, vgavidsw, NULL);
37814343SwollmanVIDEO_DRIVER(vga, vgavidsw, vga_configure);
3792742Swollman
38014343Swollman/* VGA BIOS standard video modes */
38114343Swollman#define EOT		(-1)
38214343Swollman#define NA		(-2)
383114173Swollman
384114173Swollmanstatic video_info_t bios_vmode[] = {
385114173Swollman    /* CGA */
386114173Swollman    { M_B40x25,     V_INFO_COLOR, 40, 25, 8,  8, 2, 1,
387114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
388114173Swollman    { M_C40x25,     V_INFO_COLOR, 40, 25, 8,  8, 4, 1,
389114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
390114173Swollman    { M_B80x25,     V_INFO_COLOR, 80, 25, 8,  8, 2, 1,
391114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
392114173Swollman    { M_C80x25,     V_INFO_COLOR, 80, 25, 8,  8, 4, 1,
393114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
394114173Swollman    /* EGA */
395114173Swollman    { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1,
396114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
397114173Swollman    { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1,
398114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
399114173Swollman    { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1,
400114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
401114173Swollman    { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1,
402114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40314343Swollman    /* VGA */
40414343Swollman    { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1,
405114173Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40614343Swollman    { M_VGA_M80x25, 0,            80, 25, 8, 16, 2, 1,
40714343Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
408114173Swollman    { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
40914343Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
41019878Swollman    /* MDA */
41114343Swollman    { M_EGAMONO80x25, 0,          80, 25, 8, 14, 2, 1,
412136638Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
4132742Swollman    /* EGA */
4142742Swollman    { M_ENH_B80x43, V_INFO_COLOR, 80, 43, 8,  8, 2, 1,
4152742Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
4162742Swollman    { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8,  8, 4, 1,
41714343Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
4182742Swollman    /* VGA */
419136638Swollman    { M_VGA_M80x30, 0,            80, 30, 8, 16, 2, 1,
420136638Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
421136638Swollman    { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
422136638Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
423136638Swollman    { M_VGA_M80x50, 0,            80, 50, 8,  8, 2, 1,
424136638Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
425136638Swollman    { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8,  8, 4, 1,
42614343Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
42714343Swollman    { M_VGA_M80x60, 0,            80, 60, 8,  8, 2, 1,
42814343Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
42914343Swollman    { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8,  8, 4, 1,
43014343Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43114343Swollman#ifndef VGA_NO_MODE_CHANGE
4322742Swollman    /* CGA */
43314343Swollman    { M_BG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
43414343Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43558787Sru    { M_CG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
43658787Sru      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43758787Sru    { M_BG640,      V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 1, 1,
43858787Sru      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43958787Sru    /* EGA */
44014343Swollman    { M_CG320_D,    V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 4, 4,
44114343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44214343Swollman    { M_CG640_E,    V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 4, 4,
44314343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44414343Swollman    { M_EGAMONOAPA, V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
44514343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 },
44614343Swollman    { M_ENHMONOAPA2,V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
44714343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44814343Swollman    { M_CG640x350,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2,
44914343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45014343Swollman    { M_ENH_CG640,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4,
45114343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45214343Swollman    /* VGA */
45314343Swollman    { M_BG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
45414343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45514343Swollman    { M_CG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
45614343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45714343Swollman    { M_VGA_CG320,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 8, 1,
45814343Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45975267Swollman    { M_VGA_MODEX,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8,  8, 8, 1,
46075267Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
46175267Swollman#endif /* VGA_NO_MODE_CHANGE */
46275267Swollman
46375267Swollman    { EOT },
46486222Swollman};
46575267Swollman
46614343Swollmanstatic int		init_done = FALSE;
46714343Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
46814343Swollmanstatic u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
46914343Swollmanstatic u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
47014343Swollman#endif
47114343Swollmanstatic u_char		*mode_map[V_MODE_MAP_SIZE];
47214343Swollmanstatic adp_state_t	adpstate;
47314343Swollmanstatic adp_state_t	adpstate2;
47414343Swollmanstatic int		rows_offset = 1;
47514343Swollman
47614343Swollman/* local macros and functions */
47714343Swollman#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
47814343Swollman
47914343Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
48014343Swollmanstatic void map_mode_table(u_char *map[], u_char *table, int max);
48114343Swollman#endif
4822742Swollmanstatic void clear_mode_map(video_adapter_t *adp, u_char *map[], int max,
48314343Swollman			   int color);
48414343Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
48514343Swollmanstatic int map_mode_num(int mode);
48614343Swollman#endif
48714343Swollmanstatic int map_gen_mode_num(int type, int color, int mode);
48814343Swollmanstatic int map_bios_mode_num(int type, int color, int bios_mode);
48914343Swollmanstatic u_char *get_mode_param(int mode);
49014343Swollman#ifndef VGA_NO_BIOS
49114343Swollmanstatic void fill_adapter_param(int code, video_adapter_t *adp);
49214343Swollman#endif
49314343Swollmanstatic int verify_adapter(video_adapter_t *adp);
49414343Swollmanstatic void update_adapter_info(video_adapter_t *adp, video_info_t *info);
49514343Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
49614343Swollman#define COMP_IDENTICAL	0
49714343Swollman#define COMP_SIMILAR	1
49814343Swollman#define COMP_DIFFERENT	2
49914343Swollmanstatic int comp_adpregs(u_char *buf1, u_char *buf2);
50014343Swollman#endif
50119878Swollmanstatic int probe_adapters(void);
50219878Swollman
50314343Swollman#ifndef VGA_NO_FONT_LOADING
50419878Swollman#define PARAM_BUFSIZE	6
50514343Swollmanstatic void set_font_mode(video_adapter_t *adp, u_char *buf);
50614343Swollmanstatic void set_normal_mode(video_adapter_t *adp, u_char *buf);
50714343Swollman#endif
50814343Swollman
50914343Swollmanstatic void dump_buffer(u_char *buf, size_t len);
51014343Swollman
51114343Swollman#define	ISMAPPED(pa, width)				\
51214343Swollman	(((pa) <= (u_long)0x1000 - (width)) 		\
51314343Swollman	 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
51414343Swollman
51514343Swollman#define	prologue(adp, flag, err)			\
51614343Swollman	if (!init_done || !((adp)->va_flags & (flag)))	\
51714343Swollman	    return (err)
51814343Swollman
51914343Swollman/* a backdoor for the console driver */
52014343Swollmanstatic int
52114343Swollmanvga_configure(int flags)
52214343Swollman{
52314343Swollman    int i;
52414343Swollman
52514343Swollman    probe_adapters();
5262742Swollman    for (i = 0; i < biosadapters; ++i) {
52714343Swollman	if (!probe_done(&biosadapter[i]))
52867578Swollman	    continue;
52914343Swollman	biosadapter[i].va_flags |= V_ADP_INITIALIZED;
53014343Swollman	if (!config_done(&biosadapter[i])) {
53114343Swollman	    if (vid_register(&biosadapter[i]) < 0)
53214343Swollman		continue;
53314343Swollman	    biosadapter[i].va_flags |= V_ADP_REGISTERED;
53414343Swollman	}
53514343Swollman    }
53614343Swollman    if (vga_sub_configure != NULL)
53714343Swollman	(*vga_sub_configure)(flags);
53814343Swollman
53914343Swollman    return biosadapters;
54014343Swollman}
54114343Swollman
54214343Swollman/* local subroutines */
54314343Swollman
54414343Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
54514343Swollman/* construct the mode parameter map */
54614343Swollmanstatic void
54767578Swollmanmap_mode_table(u_char *map[], u_char *table, int max)
54867578Swollman{
54958787Sru    int i;
55058787Sru
55158787Sru    for(i = 0; i < max; ++i)
55258787Sru	map[i] = table + i*V_MODE_PARAM_SIZE;
55358787Sru    for(; i < V_MODE_MAP_SIZE; ++i)
55458787Sru	map[i] = NULL;
55558787Sru}
55658787Sru#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
55758787Sru
55858787Srustatic void
55958787Sruclear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color)
56058787Sru{
56158787Sru    video_info_t info;
56267578Swollman    int i;
56367578Swollman
56467578Swollman    /*
56567578Swollman     * NOTE: we don't touch `bios_vmode[]' because it is shared
56675267Swollman     * by all adapters.
56775267Swollman     */
56886222Swollman    for(i = 0; i < max; ++i) {
56986222Swollman	if (vga_get_info(adp, i, &info))
57086222Swollman	    continue;
57186222Swollman	if ((info.vi_flags & V_INFO_COLOR) != color)
57286222Swollman	    map[i] = NULL;
57386222Swollman    }
574114173Swollman}
57567578Swollman
57667578Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
57767578Swollman/* map the non-standard video mode to a known mode number */
57867578Swollmanstatic int
57967578Swollmanmap_mode_num(int mode)
5802742Swollman{
58167578Swollman    static struct {
58267578Swollman        int from;
58367578Swollman        int to;
58467578Swollman    } mode_map[] = {
58567578Swollman        { M_ENH_B80x43, M_ENH_B80x25 },
58667578Swollman        { M_ENH_C80x43, M_ENH_C80x25 },
58767578Swollman        { M_VGA_M80x30, M_VGA_M80x25 },
58867578Swollman        { M_VGA_C80x30, M_VGA_C80x25 },
58967578Swollman        { M_VGA_M80x50, M_VGA_M80x25 },
59067578Swollman        { M_VGA_C80x50, M_VGA_C80x25 },
59186222Swollman        { M_VGA_M80x60, M_VGA_M80x25 },
59286222Swollman        { M_VGA_C80x60, M_VGA_C80x25 },
59386222Swollman        { M_VGA_MODEX,  M_VGA_CG320 },
59486222Swollman    };
59586222Swollman    int i;
59686222Swollman
59786222Swollman    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
59886222Swollman        if (mode_map[i].from == mode)
59986222Swollman            return mode_map[i].to;
60086222Swollman    }
60186222Swollman    return mode;
60286222Swollman}
60386222Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
60467578Swollman
60514343Swollman/* map a generic video mode to a known mode number */
60614343Swollmanstatic int
60719878Swollmanmap_gen_mode_num(int type, int color, int mode)
60814343Swollman{
60914343Swollman    static struct {
61058787Sru	int from;
61158787Sru	int to_color;
61258787Sru	int to_mono;
61358787Sru    } mode_map[] = {
61414343Swollman	{ M_TEXT_80x30,	M_VGA_C80x30, M_VGA_M80x30, },
61514343Swollman	{ M_TEXT_80x43,	M_ENH_C80x43, M_ENH_B80x43, },
61614343Swollman	{ M_TEXT_80x50,	M_VGA_C80x50, M_VGA_M80x50, },
61714343Swollman	{ M_TEXT_80x60,	M_VGA_C80x60, M_VGA_M80x60, },
61814343Swollman    };
61914343Swollman    int i;
62014343Swollman
62114343Swollman    if (mode == M_TEXT_80x25) {
62214343Swollman	switch (type) {
62314343Swollman
62414343Swollman	case KD_VGA:
62575267Swollman	    if (color)
62675267Swollman		return M_VGA_C80x25;
62775267Swollman	    else
62875267Swollman		return M_VGA_M80x25;
62975267Swollman	    break;
63014343Swollman
63114343Swollman	case KD_EGA:
63214343Swollman	    if (color)
63314343Swollman		return M_ENH_C80x25;
63414343Swollman	    else
63514343Swollman		return M_EGAMONO80x25;
63614343Swollman	    break;
63714343Swollman
63814343Swollman	case KD_CGA:
63914343Swollman	    return M_C80x25;
64014343Swollman
64114343Swollman	case KD_MONO:
64214343Swollman	case KD_HERCULES:
64314343Swollman	    return M_EGAMONO80x25;	/* XXX: this name is confusing */
64414343Swollman
64514343Swollman 	default:
64614343Swollman	    return -1;
64714343Swollman	}
64814343Swollman    }
64914343Swollman
65014343Swollman    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
65114343Swollman        if (mode_map[i].from == mode)
65214343Swollman            return ((color) ? mode_map[i].to_color : mode_map[i].to_mono);
65314343Swollman    }
65414343Swollman    return mode;
65514343Swollman}
65614343Swollman
65714343Swollman/* turn the BIOS video number into our video mode number */
65814343Swollmanstatic int
6592742Swollmanmap_bios_mode_num(int type, int color, int bios_mode)
66086222Swollman{
66143543Swollman    static int cga_modes[7] = {
66243543Swollman	M_B40x25, M_C40x25,		/* 0, 1 */
66343543Swollman	M_B80x25, M_C80x25,		/* 2, 3 */
66486222Swollman	M_BG320, M_CG320,
66543543Swollman	M_BG640,
66643543Swollman    };
66743543Swollman    static int ega_modes[17] = {
66843543Swollman	M_ENH_B40x25, M_ENH_C40x25,	/* 0, 1 */
66914343Swollman	M_ENH_B80x25, M_ENH_C80x25,	/* 2, 3 */
67019878Swollman	M_BG320, M_CG320,
67119878Swollman	M_BG640,
67219878Swollman	M_EGAMONO80x25,			/* 7 */
67319878Swollman	8, 9, 10, 11, 12,
67419878Swollman	M_CG320_D,
67519878Swollman	M_CG640_E,
67619878Swollman	M_ENHMONOAPA2,			/* XXX: video momery > 64K */
67719878Swollman	M_ENH_CG640,			/* XXX: video momery > 64K */
67819878Swollman    };
67919878Swollman    static int vga_modes[20] = {
68019878Swollman	M_VGA_C40x25, M_VGA_C40x25,	/* 0, 1 */
6812742Swollman	M_VGA_C80x25, M_VGA_C80x25,	/* 2, 3 */
6822742Swollman	M_BG320, M_CG320,
6832742Swollman	M_BG640,
68458787Sru	M_VGA_M80x25,			/* 7 */
68514343Swollman	8, 9, 10, 11, 12,
68658787Sru	M_CG320_D,
68758787Sru	M_CG640_E,
6882742Swollman	M_ENHMONOAPA2,
68986222Swollman	M_ENH_CG640,
69020094Swollman	M_BG640x480, M_CG640x480,
69120094Swollman	M_VGA_CG320,
69220094Swollman    };
69320094Swollman
69420094Swollman    switch (type) {
69520094Swollman
69620094Swollman    case KD_VGA:
69720094Swollman	if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0]))
698121098Swollman	    return vga_modes[bios_mode];
6992742Swollman	else if (color)
700121098Swollman	    return M_VGA_C80x25;
701121098Swollman	else
702121098Swollman	    return M_VGA_M80x25;
703121098Swollman	break;
704121098Swollman
705121098Swollman    case KD_EGA:
706121098Swollman	if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0]))
707121098Swollman	    return ega_modes[bios_mode];
7089908Swollman	else if (color)
7092742Swollman	    return M_ENH_C80x25;
7102742Swollman	else
7112742Swollman	    return M_EGAMONO80x25;
7129908Swollman	break;
7139908Swollman
7149908Swollman    case KD_CGA:
7159908Swollman	if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0]))
7169908Swollman	    return cga_modes[bios_mode];
7179908Swollman	else
7189908Swollman	    return M_C80x25;
7199908Swollman	break;
7209908Swollman
7219908Swollman    case KD_MONO:
7229908Swollman    case KD_HERCULES:
7239908Swollman	return M_EGAMONO80x25;		/* XXX: this name is confusing */
7249908Swollman
7259908Swollman    default:
7269908Swollman	break;
7279908Swollman    }
7289908Swollman    return -1;
7299908Swollman}
7309908Swollman
7319908Swollman/* look up a parameter table entry */
7329908Swollmanstatic u_char
7339908Swollman*get_mode_param(int mode)
7349908Swollman{
7359908Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
7369908Swollman    if (mode >= V_MODE_MAP_SIZE)
7379908Swollman	mode = map_mode_num(mode);
7389908Swollman#endif
7399908Swollman    if ((mode >= 0) && (mode < V_MODE_MAP_SIZE))
7409908Swollman	return mode_map[mode];
7419908Swollman    else
7429908Swollman	return NULL;
7432742Swollman}
74467578Swollman
7459908Swollman#ifndef VGA_NO_BIOS
74667578Swollmanstatic void
74767578Swollmanfill_adapter_param(int code, video_adapter_t *adp)
74867578Swollman{
74967578Swollman    static struct {
75067578Swollman	int primary;
75167578Swollman	int secondary;
75267578Swollman    } dcc[] = {
75367578Swollman	{ DCC_MONO, 			DCC_EGA40 /* CGA monitor */ },
75467578Swollman	{ DCC_MONO, 			DCC_EGA80 /* CGA monitor */ },
75567578Swollman	{ DCC_MONO, 			DCC_EGA80 /* CGA emulation */ },
75667578Swollman	{ DCC_MONO, 			DCC_EGA80 },
75767578Swollman	{ DCC_CGA40, 			DCC_EGAMONO },
7589908Swollman	{ DCC_CGA80, 			DCC_EGAMONO },
7592742Swollman	{ DCC_EGA40 /* CGA monitor */, 	DCC_MONO},
76017200Swollman	{ DCC_EGA80 /* CGA monitor */, 	DCC_MONO},
76117200Swollman	{ DCC_EGA80 /* CGA emulation */,DCC_MONO },
762121098Swollman	{ DCC_EGA80, 			DCC_MONO },
763121098Swollman	{ DCC_EGAMONO, 			DCC_CGA40 },
76417200Swollman	{ DCC_EGAMONO, 			DCC_CGA40 },
76517200Swollman    };
76617200Swollman
76717200Swollman    if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) {
76817200Swollman	adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
76917200Swollman	adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
77067578Swollman    } else {
77117200Swollman	adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary];
77267578Swollman	adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary];
77367578Swollman    }
77467578Swollman}
77567578Swollman#endif /* VGA_NO_BIOS */
77667578Swollman
77767578Swollmanstatic int
77817200Swollmanverify_adapter(video_adapter_t *adp)
779121098Swollman{
7802742Swollman    vm_offset_t buf;
7812742Swollman    u_int16_t v;
7822742Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
7832742Swollman    u_int32_t p;
7842742Swollman#endif
7852742Swollman
7862742Swollman    buf = BIOS_PADDRTOVADDR(adp->va_window);
787121098Swollman    v = readw(buf);
788121098Swollman    writew(buf, 0xA55A);
789121098Swollman    if (readw(buf) != 0xA55A)
790121098Swollman	return 1;
791121098Swollman    writew(buf, v);
792121098Swollman
7932742Swollman    switch (adp->va_type) {
7942742Swollman
7952742Swollman    case KD_EGA:
7962742Swollman	outb(adp->va_crtc_addr, 7);
7972742Swollman	if (inb(adp->va_crtc_addr) == 7) {
7982742Swollman	    adp->va_type = KD_VGA;
79967578Swollman	    adp->va_name = "vga";
80067578Swollman	    adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE;
80167578Swollman	}
80267578Swollman	adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER;
80367578Swollman	/* the color adapter may be in the 40x25 mode... XXX */
80467578Swollman
80567578Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
80667578Swollman	/* get the BIOS video mode pointer */
8072742Swollman	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8);
8082742Swollman	p = BIOS_SADDRTOLADDR(p);
8092742Swollman	if (ISMAPPED(p, sizeof(u_int32_t))) {
810121098Swollman	    p = *(u_int32_t *)BIOS_PADDRTOVADDR(p);
811121098Swollman	    p = BIOS_SADDRTOLADDR(p);
81220094Swollman	    if (ISMAPPED(p, V_MODE_PARAM_SIZE))
813121098Swollman		video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p);
814121098Swollman	}
8152742Swollman#endif
8162742Swollman	break;
81767578Swollman
81817200Swollman    case KD_CGA:
81920094Swollman	adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER;
82020094Swollman	/* may be in the 40x25 mode... XXX */
82120094Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
822121098Swollman	/* get the BIOS video mode pointer */
823121098Swollman	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
82420094Swollman	p = BIOS_SADDRTOLADDR(p);
82520094Swollman	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
826121098Swollman#endif
827121098Swollman	break;
82820094Swollman
82920094Swollman    case KD_MONO:
83020094Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
83120094Swollman	/* get the BIOS video mode pointer */
83220094Swollman	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
83320094Swollman	p = BIOS_SADDRTOLADDR(p);
83417200Swollman	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
83517200Swollman#endif
83617200Swollman	break;
83717200Swollman    }
83817200Swollman
83917200Swollman    return 0;
84017200Swollman}
84167578Swollman
84267578Swollmanstatic void
84367578Swollmanupdate_adapter_info(video_adapter_t *adp, video_info_t *info)
84467578Swollman{
84567578Swollman    adp->va_flags &= ~V_ADP_COLOR;
8462742Swollman    adp->va_flags |=
8472742Swollman	(info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
8482742Swollman    adp->va_crtc_addr =
8492742Swollman	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
8502742Swollman    adp->va_window = BIOS_PADDRTOVADDR(info->vi_window);
8512742Swollman    adp->va_window_size = info->vi_window_size;
8522742Swollman    adp->va_window_gran = info->vi_window_gran;
8532742Swollman    if (info->vi_buffer_size == 0) {
8542742Swollman    	adp->va_buffer = 0;
8552742Swollman    	adp->va_buffer_size = 0;
8562742Swollman    } else {
8572742Swollman    	adp->va_buffer = BIOS_PADDRTOVADDR(info->vi_buffer);
8582742Swollman    	adp->va_buffer_size = info->vi_buffer_size;
8592742Swollman    }
8602742Swollman    if (info->vi_flags & V_INFO_GRAPHICS) {
8612742Swollman	switch (info->vi_depth/info->vi_planes) {
8622742Swollman	case 1:
8632742Swollman	    adp->va_line_width = info->vi_width/8;
8642742Swollman	    break;
8652742Swollman	case 2:
8662742Swollman	    adp->va_line_width = info->vi_width/4;
867121098Swollman	    break;
8682742Swollman	case 4:
8692742Swollman	    adp->va_line_width = info->vi_width/2;
8702742Swollman	    break;
8712742Swollman	case 8:
8722742Swollman	default: /* shouldn't happen */
8732742Swollman	    adp->va_line_width = info->vi_width;
8742742Swollman	    break;
8752742Swollman	}
8762742Swollman    } else {
8772742Swollman	adp->va_line_width = info->vi_width;
8782742Swollman    }
8792742Swollman    bcopy(info, &adp->va_info, sizeof(adp->va_info));
880121098Swollman}
881121098Swollman
882121098Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
883121098Swollman/* compare two parameter table entries */
884121098Swollmanstatic int
885121098Swollmancomp_adpregs(u_char *buf1, u_char *buf2)
886121098Swollman{
887121098Swollman    static struct {
8882742Swollman        u_char mask;
8892742Swollman    } params[V_MODE_PARAM_SIZE] = {
890121098Swollman	{0xff}, {0x00}, {0xff}, 		/* COLS, ROWS, POINTS */
891121098Swollman	{0x00}, {0x00}, 			/* page length */
892121098Swollman	{0xfe}, {0xff}, {0xff}, {0xff},		/* sequencer registers */
893121098Swollman	{0xf3},					/* misc register */
894121098Swollman	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},	/* CRTC */
895121098Swollman	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},
89617200Swollman	{0x00}, {0x00}, {0x00}, {0x00}, {0x00},
89717200Swollman	{0x00}, {0xff}, {0x7f}, {0xff}, {0xff},
89817200Swollman	{0x7f}, {0xff}, {0xff}, {0xef}, {0xff},
89917200Swollman	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* attribute controller regs */
900121098Swollman	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
901121098Swollman	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
9022742Swollman	{0xff}, {0xff}, {0xff}, {0xff}, {0xf0},
9038029Swollman	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* GDC register */
90417200Swollman	{0xff}, {0xff}, {0xff}, {0xff},
90517200Swollman    };
90617200Swollman    int identical = TRUE;
907121098Swollman    int i;
908121098Swollman
90917200Swollman    if ((buf1 == NULL) || (buf2 == NULL))
91017200Swollman	return COMP_DIFFERENT;
91117200Swollman
91217200Swollman    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
91317200Swollman	if (params[i].mask == 0)	/* don't care */
914121098Swollman	    continue;
915121098Swollman	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
916121098Swollman	    return COMP_DIFFERENT;
917121098Swollman	if (buf1[i] != buf2[i])
918121098Swollman	    identical = FALSE;
919121098Swollman    }
920121098Swollman    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
921121098Swollman}
922121098Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
923121098Swollman
924121098Swollman/* probe video adapters and return the number of detected adapters */
925121098Swollmanstatic int
926121098Swollmanprobe_adapters(void)
92743014Swollman{
928121098Swollman    video_adapter_t *adp;
92943014Swollman    video_info_t info;
93043014Swollman    int i;
93143014Swollman
93243014Swollman    /* do this test only once */
93343014Swollman    if (init_done)
93443014Swollman	return biosadapters;
93543014Swollman    init_done = TRUE;
93643014Swollman
93743014Swollman    /*
93858787Sru     * Locate display adapters.
93943014Swollman     * The AT architecture supports upto two adapters. `syscons' allows
94043014Swollman     * the following combinations of adapters:
94167578Swollman     *     1) MDA + CGA
94267578Swollman     *     2) MDA + EGA/VGA color
94367578Swollman     *     3) CGA + EGA/VGA mono
94467578Swollman     * Note that `syscons' doesn't bother with MCGA as it is only
94567578Swollman     * avaiable for low end PS/2 models which has 80286 or earlier CPUs,
94667578Swollman     * thus, they are not running FreeBSD!
94767578Swollman     * When there are two adapaters in the system, one becomes `primary'
94867578Swollman     * and the other `secondary'. The EGA adapter has a set of DIP
94967578Swollman     * switches on board for this information and the EGA BIOS copies
95067578Swollman     * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88).
95167578Swollman     * The VGA BIOS has more sophisticated mechanism and has this
9522742Swollman     * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains
9532742Swollman     * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH.
9542742Swollman     */
9552742Swollman
9562742Swollman    /*
9572742Swollman     * Check rtc and BIOS data area.
958121098Swollman     * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead
9592742Swollman     * copy of RTC_EQUIPMENT.  Bits 4 and 5 of ETC_EQUIPMENT are
9602742Swollman     * zeros for EGA and VGA.  However, the EGA/VGA BIOS sets
9612742Swollman     * these bits in BIOSDATA_EQUIPMENT according to the monitor
9622742Swollman     * type detected.
9632742Swollman     */
964136638Swollman#ifndef VGA_NO_BIOS
965136638Swollman    switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
966136638Swollman    case 0:
967136638Swollman	/* EGA/VGA */
968136638Swollman	fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
969136638Swollman			   biosadapter);
970136638Swollman	break;
971136638Swollman    case 1:
972136638Swollman	/* CGA 40x25 */
973136638Swollman	/* FIXME: switch to the 80x25 mode? XXX */
974136638Swollman	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40];
975136638Swollman	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
976121098Swollman	break;
9772742Swollman    case 2:
9782742Swollman	/* CGA 80x25 */
9792742Swollman	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80];
980121098Swollman	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
981121098Swollman	break;
982121098Swollman    case 3:
983121098Swollman	/* MDA */
984121098Swollman	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
985121098Swollman	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
986121098Swollman	break;
987121098Swollman    }
988121098Swollman#else
989121098Swollman    /* assume EGA/VGA? XXX */
990121098Swollman    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80];
991121098Swollman    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
992136638Swollman#endif /* VGA_NO_BIOS */
993136638Swollman
994136638Swollman    biosadapters = 0;
995136638Swollman    if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) {
996136638Swollman	++biosadapters;
997136638Swollman	biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED;
998136638Swollman	biosadapter[V_ADP_SECONDARY].va_mode =
999136638Swollman	    biosadapter[V_ADP_SECONDARY].va_initial_mode =
1000136638Swollman	    map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type,
1001136638Swollman			      biosadapter[V_ADP_SECONDARY].va_flags
1002136638Swollman				  & V_ADP_COLOR,
1003136638Swollman			      biosadapter[V_ADP_SECONDARY].va_initial_bios_mode);
1004136638Swollman    } else {
1005121098Swollman	biosadapter[V_ADP_SECONDARY].va_type = -1;
1006121098Swollman    }
1007121098Swollman    if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) {
1008121098Swollman	++biosadapters;
1009121098Swollman	biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED;
1010121098Swollman#ifndef VGA_NO_BIOS
1011121098Swollman	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode =
1012121098Swollman	    readb(BIOS_PADDRTOVADDR(0x449));
1013121098Swollman#else
1014121098Swollman	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3;	/* XXX */
1015121098Swollman#endif
1016121098Swollman	biosadapter[V_ADP_PRIMARY].va_mode =
1017121098Swollman	    biosadapter[V_ADP_PRIMARY].va_initial_mode =
1018121098Swollman	    map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type,
1019121098Swollman			      biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR,
1020121098Swollman			      biosadapter[V_ADP_PRIMARY].va_initial_bios_mode);
1021121098Swollman    } else {
1022136638Swollman	biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY];
1023121098Swollman	biosadapter[V_ADP_SECONDARY].va_type = -1;
1024136638Swollman    }
1025136638Swollman    if (biosadapters == 0)
1026136638Swollman	return biosadapters;
1027136638Swollman    biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY;
1028136638Swollman    biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY;
1029136638Swollman
1030136638Swollman#if 0 /* we don't need these... */
1031136638Swollman    fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...);
1032136638Swollman    fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...);
1033136638Swollman#endif
1034136638Swollman
1035136638Swollman#if 0
10362742Swollman    /*
10372742Swollman     * We cannot have two video adapter of the same type; there must be
1038121098Swollman     * only one of color or mono adapter, or one each of them.
1039121098Swollman     */
1040121098Swollman    if (biosadapters > 1) {
1041121098Swollman	if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags)
1042121098Swollman	      & V_ADP_COLOR))
1043121098Swollman	    /* we have two mono or color adapters!! */
1044121098Swollman	    return (biosadapters = 0);
1045121098Swollman    }
1046121098Swollman#endif
1047121098Swollman
1048121098Swollman    /*
1049121098Swollman     * Ensure a zero start address.  This is mainly to recover after
105017200Swollman     * switching from pcvt using userconfig().  The registers are w/o
1051136638Swollman     * for old hardware so it's too hard to relocate the active screen
1052136638Swollman     * memory.
105317200Swollman     * This must be done before vga_save_state() for VGA.
105417200Swollman     */
105517200Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12);
105617200Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
105717200Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13);
1058121098Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
1059121098Swollman
106017200Swollman    /* the video mode parameter table in EGA/VGA BIOS */
106117200Swollman    /* NOTE: there can be only one EGA/VGA, wheather color or mono,
1062121098Swollman     * recognized by the video BIOS.
1063121098Swollman     */
106417200Swollman    if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) ||
10652742Swollman	(biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) {
10668029Swollman	adp = &biosadapter[V_ADP_PRIMARY];
106717200Swollman    } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) ||
106819878Swollman	       (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) {
10692742Swollman	adp = &biosadapter[V_ADP_SECONDARY];
10702742Swollman    } else {
10712742Swollman	adp = NULL;
10722742Swollman    }
10732742Swollman    bzero(mode_map, sizeof(mode_map));
10742742Swollman    if (adp != NULL) {
107514343Swollman	if (adp->va_type == KD_VGA) {
1076121098Swollman	    vga_save_state(adp, &adpstate, sizeof(adpstate));
1077121098Swollman#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
10782742Swollman	    mode_map[adp->va_initial_mode] = adpstate.regs;
10792742Swollman	    rows_offset = 1;
10802742Swollman#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
10812742Swollman	    if (video_mode_ptr == NULL) {
108214343Swollman		mode_map[adp->va_initial_mode] = adpstate.regs;
108314343Swollman		rows_offset = 1;
108414343Swollman	    } else {
108514343Swollman		/* discard the table if we are not familiar with it... */
108614343Swollman		u_char *mp;
10872742Swollman		map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
10882742Swollman		mp = get_mode_param(adp->va_initial_mode);
10892742Swollman		if (mp != NULL)
109014343Swollman		    bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs));
10912742Swollman		switch (comp_adpregs(adpstate.regs, mp)) {
109267578Swollman		case COMP_IDENTICAL:
10932742Swollman		    /*
109467578Swollman		     * OK, this parameter table looks reasonably familiar
109567578Swollman		     * to us...
109667578Swollman		     */
109767578Swollman		    /*
10982742Swollman		     * This is a kludge for Toshiba DynaBook SS433
10992742Swollman		     * whose BIOS video mode table entry has the actual #
11002742Swollman		     * of rows at the offset 1; BIOSes from other
11012742Swollman		     * manufacturers store the # of rows - 1 there. XXX
11028029Swollman		     */
110317200Swollman		    rows_offset = adpstate.regs[1] + 1 - mp[1];
110417200Swollman		    break;
1105121098Swollman
1106121098Swollman		case COMP_SIMILAR:
1107121098Swollman		    /*
1108121098Swollman		     * Not exactly the same, but similar enough to be
1109121098Swollman		     * trusted. However, use the saved register values
1110121098Swollman		     * for the initial mode and other modes which are
1111121098Swollman		     * based on the initial mode.
1112121098Swollman		     */
1113121098Swollman		    mode_map[adp->va_initial_mode] = adpstate.regs;
1114121098Swollman		    rows_offset = adpstate.regs[1] + 1 - mp[1];
1115121098Swollman		    adpstate.regs[1] -= rows_offset - 1;
1116121098Swollman		    break;
1117121098Swollman
1118121098Swollman		case COMP_DIFFERENT:
111967578Swollman		default:
112017200Swollman		    /*
112117200Swollman		     * Don't use the paramter table in BIOS. It doesn't
112217200Swollman		     * look familiar to us. Video mode switching is allowed
112367578Swollman		     * only if the new mode is the same as or based on
112467578Swollman		     * the initial mode.
112517200Swollman		     */
112619878Swollman		    video_mode_ptr = NULL;
112717200Swollman		    bzero(mode_map, sizeof(mode_map));
112817200Swollman		    mode_map[adp->va_initial_mode] = adpstate.regs;
112917200Swollman		    rows_offset = 1;
113017200Swollman		    break;
113117200Swollman		}
113217200Swollman	    }
113317200Swollman#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
113417200Swollman
113517200Swollman#ifndef VGA_NO_MODE_CHANGE
113617200Swollman	    adp->va_flags |= V_ADP_MODECHANGE;
113717200Swollman#endif
113817200Swollman#ifndef VGA_NO_FONT_LOADING
113917200Swollman	    adp->va_flags |= V_ADP_FONT;
114017200Swollman#endif
114117200Swollman	} else if (adp->va_type == KD_EGA) {
114217200Swollman#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
114317200Swollman	    rows_offset = 1;
114417200Swollman#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
114517200Swollman	    if (video_mode_ptr == NULL) {
114617200Swollman		rows_offset = 1;
114717200Swollman	    } else {
114817200Swollman		u_char *mp;
114917200Swollman		map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1);
115017200Swollman		/* XXX how can one validate the EGA table... */
115117200Swollman		mp = get_mode_param(adp->va_initial_mode);
11522742Swollman		if (mp != NULL) {
11532742Swollman		    adp->va_flags |= V_ADP_MODECHANGE;
11542742Swollman#ifndef VGA_NO_FONT_LOADING
11552742Swollman		    adp->va_flags |= V_ADP_FONT;
11562742Swollman#endif
11572742Swollman		    rows_offset = 1;
11582742Swollman		} else {
11592742Swollman		    /*
11602742Swollman		     * This is serious. We will not be able to switch video
1161121098Swollman		     * modes at all...
1162121098Swollman		     */
11632742Swollman		    video_mode_ptr = NULL;
116417200Swollman		    bzero(mode_map, sizeof(mode_map));
116517200Swollman		    rows_offset = 1;
1166121098Swollman                }
1167121098Swollman	    }
1168121098Swollman#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
116917200Swollman	}
117017200Swollman    }
117117200Swollman
117217200Swollman    /* remove conflicting modes if we have more than one adapter */
117317200Swollman    if (biosadapters > 1) {
117417200Swollman	for (i = 0; i < biosadapters; ++i) {
117517200Swollman	    if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE))
11762742Swollman		continue;
117717200Swollman	    clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1,
117817200Swollman			   (biosadapter[i].va_flags & V_ADP_COLOR) ?
11792742Swollman			       V_INFO_COLOR : 0);
118017200Swollman	    if ((biosadapter[i].va_type == KD_VGA)
118117200Swollman		|| (biosadapter[i].va_type == KD_EGA)) {
118217200Swollman		biosadapter[i].va_io_base =
118317200Swollman		    (biosadapter[i].va_flags & V_ADP_COLOR) ?
118417200Swollman			IO_VGA : IO_MDA;
11852742Swollman		biosadapter[i].va_io_size = 32;
11868029Swollman	    }
118717200Swollman	}
118817200Swollman    }
11892742Swollman
11902742Swollman    /* buffer address */
11912742Swollman    vga_get_info(&biosadapter[V_ADP_PRIMARY],
11922742Swollman		 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info);
11932742Swollman    update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info);
11942742Swollman
11952742Swollman    if (biosadapters > 1) {
1196121098Swollman	vga_get_info(&biosadapter[V_ADP_SECONDARY],
1197121098Swollman		     biosadapter[V_ADP_SECONDARY].va_initial_mode, &info);
11982742Swollman	update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info);
11992742Swollman    }
12002742Swollman
12012742Swollman    /*
12022742Swollman     * XXX: we should verify the following values for the primary adapter...
12032742Swollman     * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
12042742Swollman     * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
12052742Swollman     *                     ? 0 : V_ADP_COLOR;
12062742Swollman     * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
12072742Swollman     * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
12082742Swollman     * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
12092742Swollman     * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
12102742Swollman     */
12112742Swollman
12128029Swollman    return biosadapters;
121317200Swollman}
121417200Swollman
121567578Swollman/* entry points */
121617200Swollman
121758787Srustatic int
121867578Swollmanvga_nop(void)
121917200Swollman{
12202742Swollman    return 0;
12212742Swollman}
12222742Swollman
1223121098Swollmanstatic int
1224121098Swollmanvga_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
12252742Swollman{
12262742Swollman    probe_adapters();
12272742Swollman    if (unit >= biosadapters)
12282742Swollman	return ENXIO;
12292742Swollman
12302742Swollman    *adpp = &biosadapter[unit];
12312742Swollman
12322742Swollman    return 0;
12332742Swollman}
123417200Swollman
123517200Swollmanstatic int
123617200Swollmanvga_init(int unit, video_adapter_t *adp, int flags)
123717200Swollman{
12382742Swollman    if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp))
12398029Swollman	return ENXIO;
124058787Sru
124117200Swollman    if (!init_done(adp)) {
124258787Sru	/* nothing to do really... */
124317200Swollman	adp->va_flags |= V_ADP_INITIALIZED;
124420094Swollman    }
124520094Swollman
124620094Swollman    if (!config_done(adp)) {
124720094Swollman	if (vid_register(adp) < 0)
124820094Swollman		return ENXIO;
124920094Swollman	adp->va_flags |= V_ADP_REGISTERED;
125020094Swollman    }
125120094Swollman    if (vga_sub_configure != NULL)
125217200Swollman	(*vga_sub_configure)(0);
125358787Sru
125458787Sru    return 0;
125558787Sru}
125658787Sru
125758787Sru/*
125858787Sru * get_info():
125958787Sru * Return the video_info structure of the requested video mode.
126058787Sru *
126158787Sru * all adapters
126258787Sru */
126358787Srustatic int
126458787Sruvga_get_info(video_adapter_t *adp, int mode, video_info_t *info)
126558787Sru{
126686222Swollman    int i;
126758787Sru
126886222Swollman    if (!init_done)
126958787Sru	return 1;
127058787Sru
127158787Sru    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
127258787Sru#ifndef VGA_NO_MODE_CHANGE
127358787Sru    if (adp->va_flags & V_ADP_MODECHANGE) {
127458787Sru	/*
127558787Sru	 * If the parameter table entry for this mode is not found,
127658787Sru	 * the mode is not supported...
127758787Sru	 */
127858787Sru	if (get_mode_param(mode) == NULL)
127958787Sru	    return 1;
128058787Sru    } else
128158787Sru#endif /* VGA_NO_MODE_CHANGE */
128258787Sru    {
128358787Sru	/*
128458787Sru	 * Even if we don't support video mode switching on this adapter,
128558787Sru	 * the information on the initial (thus current) video mode
128658787Sru	 * should be made available.
128758787Sru	 */
128858787Sru	if (mode != adp->va_initial_mode)
128958787Sru	    return 1;
129058787Sru    }
129158787Sru
129258787Sru    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
129358787Sru	if (bios_vmode[i].vi_mode == NA)
129458787Sru	    continue;
129558787Sru	if (mode == bios_vmode[i].vi_mode) {
129658787Sru	    *info = bios_vmode[i];
129758787Sru	    return 0;
129858787Sru	}
129958787Sru    }
130058787Sru    return 1;
130158787Sru}
130258787Sru
130367578Swollman/*
130467578Swollman * query_mode():
130567578Swollman * Find a video mode matching the requested parameters.
130675267Swollman * Fields filled with 0 are considered "don't care" fields and
130767578Swollman * match any modes.
130867578Swollman *
130967578Swollman * all adapters
131067578Swollman */
131167578Swollmanstatic int
131267578Swollmanvga_query_mode(video_adapter_t *adp, video_info_t *info)
131367578Swollman{
131467578Swollman    video_info_t buf;
131575267Swollman    int i;
131675267Swollman
131775267Swollman    if (!init_done)
131875267Swollman	return -1;
131975267Swollman
132075267Swollman    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
132175267Swollman	if (bios_vmode[i].vi_mode == NA)
132275267Swollman	    continue;
132375267Swollman
132475267Swollman	if ((info->vi_width != 0)
132575267Swollman	    && (info->vi_width != bios_vmode[i].vi_width))
132675267Swollman		continue;
132775267Swollman	if ((info->vi_height != 0)
132875267Swollman	    && (info->vi_height != bios_vmode[i].vi_height))
132975267Swollman		continue;
133075267Swollman	if ((info->vi_cwidth != 0)
133175267Swollman	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
133275267Swollman		continue;
133375267Swollman	if ((info->vi_cheight != 0)
133475267Swollman	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
133575267Swollman		continue;
133675267Swollman	if ((info->vi_depth != 0)
133775267Swollman	    && (info->vi_depth != bios_vmode[i].vi_depth))
133875267Swollman		continue;
133975267Swollman	if ((info->vi_planes != 0)
134075267Swollman	    && (info->vi_planes != bios_vmode[i].vi_planes))
134175267Swollman		continue;
134275267Swollman	/* XXX: should check pixel format, memory model */
134375267Swollman	if ((info->vi_flags != 0)
134475267Swollman	    && (info->vi_flags != bios_vmode[i].vi_flags))
13452742Swollman		continue;
134617200Swollman
134717200Swollman	/* verify if this mode is supported on this adapter */
134817200Swollman	if (vga_get_info(adp, bios_vmode[i].vi_mode, &buf))
134917200Swollman		continue;
1350121098Swollman	return bios_vmode[i].vi_mode;
1351121098Swollman    }
135217200Swollman    return -1;
135317200Swollman}
135417200Swollman
135517200Swollman/*
135617200Swollman * set_mode():
135717200Swollman * Change the video mode.
13582742Swollman *
135917200Swollman * EGA/VGA
136058787Sru */
136158787Srustatic int
136275267Swollmanvga_set_mode(video_adapter_t *adp, int mode)
136375267Swollman{
136458787Sru#ifndef VGA_NO_MODE_CHANGE
136558787Sru    video_info_t info;
136675267Swollman    adp_state_t params;
136775267Swollman
136875267Swollman    prologue(adp, V_ADP_MODECHANGE, 1);
136975267Swollman
137075267Swollman    mode = map_gen_mode_num(adp->va_type,
137158787Sru			    adp->va_flags & V_ADP_COLOR, mode);
137258787Sru    if (vga_get_info(adp, mode, &info))
137358787Sru	return 1;
137475267Swollman    params.sig = V_STATE_SIG;
137575267Swollman    bcopy(get_mode_param(mode), params.regs, sizeof(params.regs));
137675267Swollman
137775267Swollman    switch (mode) {
137817200Swollman    case M_VGA_C80x60: case M_VGA_M80x60:
137917200Swollman	params.regs[2]  = 0x08;
138017200Swollman	params.regs[19] = 0x47;
138117200Swollman	goto special_480l;
138217200Swollman
13832742Swollman    case M_VGA_C80x30: case M_VGA_M80x30:
138417200Swollman	params.regs[19] = 0x4f;
138517200Swollmanspecial_480l:
138617200Swollman	params.regs[9] |= 0xc0;
138720094Swollman	params.regs[16] = 0x08;
138817200Swollman	params.regs[17] = 0x3e;
13892742Swollman	params.regs[26] = 0xea;
13908029Swollman	params.regs[28] = 0xdf;
13912742Swollman	params.regs[31] = 0xe7;
13922742Swollman	params.regs[32] = 0x04;
13932742Swollman	goto setup_mode;
13942742Swollman
139575267Swollman    case M_ENH_C80x43: case M_ENH_B80x43:
139675267Swollman	params.regs[28] = 87;
139775267Swollman	goto special_80x50;
139875267Swollman
139975267Swollman    case M_VGA_C80x50: case M_VGA_M80x50:
140075267Swollmanspecial_80x50:
14012742Swollman	params.regs[2] = 8;
140275267Swollman	params.regs[19] = 7;
140375267Swollman	goto setup_mode;
140475267Swollman
140575267Swollman    case M_VGA_C40x25: case M_VGA_C80x25:
140675267Swollman    case M_VGA_M80x25:
140775267Swollman    case M_B40x25:     case M_C40x25:
140875267Swollman    case M_B80x25:     case M_C80x25:
140975267Swollman    case M_ENH_B40x25: case M_ENH_C40x25:
141075267Swollman    case M_ENH_B80x25: case M_ENH_C80x25:
141175267Swollman    case M_EGAMONO80x25:
14122742Swollman
141375267Swollmansetup_mode:
141475267Swollman	vga_load_state(adp, &params);
141575267Swollman	break;
141675267Swollman
141775267Swollman    case M_VGA_MODEX:
141875267Swollman	/* "unchain" the VGA mode */
141964499Swollman	params.regs[5-1+0x04] &= 0xf7;
142064499Swollman	params.regs[5-1+0x04] |= 0x04;
142164499Swollman	/* turn off doubleword mode */
14222742Swollman	params.regs[10+0x14] &= 0xbf;
142317200Swollman	/* turn off word adressing */
142417200Swollman	params.regs[10+0x17] |= 0x40;
142517200Swollman	/* set logical screen width */
142658787Sru	params.regs[10+0x13] = 80;
142717200Swollman	/* set 240 lines */
142858787Sru	params.regs[10+0x11] = 0x2c;
142917200Swollman	params.regs[10+0x06] = 0x0d;
143017200Swollman	params.regs[10+0x07] = 0x3e;
143158787Sru	params.regs[10+0x10] = 0xea;
143217200Swollman	params.regs[10+0x11] = 0xac;
143317200Swollman	params.regs[10+0x12] = 0xdf;
143417200Swollman	params.regs[10+0x15] = 0xe7;
143517200Swollman	params.regs[10+0x16] = 0x06;
143658787Sru	/* set vertical sync polarity to reflect aspect ratio */
143717200Swollman	params.regs[9] = 0xe3;
143817200Swollman	goto setup_grmode;
143917200Swollman
144017200Swollman    case M_BG320:     case M_CG320:     case M_BG640:
144117200Swollman    case M_CG320_D:   case M_CG640_E:
144258787Sru    case M_CG640x350: case M_ENH_CG640:
144317200Swollman    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
144417200Swollman
144517200Swollmansetup_grmode:
144617200Swollman	vga_load_state(adp, &params);
144758787Sru	break;
144817200Swollman
144958787Sru    default:
145017200Swollman	return 1;
145117200Swollman    }
145243014Swollman
145343014Swollman    adp->va_mode = mode;
145443014Swollman    update_adapter_info(adp, &info);
145543014Swollman
145614343Swollman    /* move hardware cursor out of the way */
145743543Swollman    (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
145843543Swollman
145943543Swollman    return 0;
146043543Swollman#else /* VGA_NO_MODE_CHANGE */
146158787Sru    return 1;
146258787Sru#endif /* VGA_NO_MODE_CHANGE */
146358787Sru}
146458787Sru
146558787Sru#ifndef VGA_NO_FONT_LOADING
146658787Sru
146775267Swollmanstatic void
146875267Swollmanset_font_mode(video_adapter_t *adp, u_char *buf)
146975267Swollman{
147075267Swollman    u_char *mp;
147175267Swollman    int s;
147275267Swollman
147375267Swollman    s = splhigh();
147475267Swollman
147575267Swollman    /* save register values */
147675267Swollman    if (adp->va_type == KD_VGA) {
147775267Swollman	outb(TSIDX, 0x02); buf[0] = inb(TSREG);
147875267Swollman	outb(TSIDX, 0x04); buf[1] = inb(TSREG);
147975267Swollman	outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
148075267Swollman	outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
148175267Swollman	outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
148275267Swollman	inb(adp->va_crtc_addr + 6);
148375267Swollman	outb(ATC, 0x10); buf[5] = inb(ATC + 1);
148475267Swollman    } else /* if (adp->va_type == KD_EGA) */ {
148575267Swollman	/*
148675267Swollman	 * EGA cannot be read; copy parameters from the mode parameter
148775267Swollman	 * table.
148875267Swollman	 */
148975267Swollman	mp = get_mode_param(adp->va_mode);
149075267Swollman	buf[0] = mp[5 + 0x02 - 1];
149175267Swollman	buf[1] = mp[5 + 0x04 - 1];
149275267Swollman	buf[2] = mp[55 + 0x04];
149375267Swollman	buf[3] = mp[55 + 0x05];
149475267Swollman	buf[4] = mp[55 + 0x06];
149575267Swollman	buf[5] = mp[35 + 0x10];
149675267Swollman    }
149775267Swollman
149875267Swollman    /* setup vga for loading fonts */
149975267Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
150075267Swollman    outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
150175267Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
150275267Swollman    outb(ATC, 0x20);				/* enable palette */
150375267Swollman
150475267Swollman#if VGA_SLOW_IOACCESS
150575267Swollman#ifdef VGA_ALT_SEQACCESS
150675267Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x01);
150775267Swollman#endif
150875267Swollman    outb(TSIDX, 0x02); outb(TSREG, 0x04);
150975267Swollman    outb(TSIDX, 0x04); outb(TSREG, 0x07);
151075267Swollman#ifdef VGA_ALT_SEQACCESS
151175267Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x03);
151275267Swollman#endif
151375267Swollman    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
151475267Swollman    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
151575267Swollman    outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
151675267Swollman#else /* VGA_SLOW_IOACCESS */
151775267Swollman#ifdef VGA_ALT_SEQACCESS
151875267Swollman    outw(TSIDX, 0x0100);
151975267Swollman#endif
152075267Swollman    outw(TSIDX, 0x0402);
152175267Swollman    outw(TSIDX, 0x0704);
152275267Swollman#ifdef VGA_ALT_SEQACCESS
152375267Swollman    outw(TSIDX, 0x0300);
152486222Swollman#endif
152586222Swollman    outw(GDCIDX, 0x0204);
152686222Swollman    outw(GDCIDX, 0x0005);
152786222Swollman    outw(GDCIDX, 0x0406);               /* addr = a0000, 64kb */
152886222Swollman#endif /* VGA_SLOW_IOACCESS */
152986222Swollman
153086222Swollman    splx(s);
153186222Swollman}
153286222Swollman
153393799Swollmanstatic void
153493799Swollmanset_normal_mode(video_adapter_t *adp, u_char *buf)
153593799Swollman{
153693799Swollman    int s;
153793799Swollman
153893799Swollman    s = splhigh();
15392742Swollman
15402742Swollman    /* setup vga for normal operation mode again */
15412742Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
15422742Swollman    outb(ATC, 0x10); outb(ATC, buf[5]);
15432742Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1544121098Swollman    outb(ATC, 0x20);				/* enable palette */
15452742Swollman
15462742Swollman#if VGA_SLOW_IOACCESS
15472742Swollman#ifdef VGA_ALT_SEQACCESS
154875267Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x01);
154975267Swollman#endif
155093799Swollman    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
155193799Swollman    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
155293799Swollman#ifdef VGA_ALT_SEQACCESS
155393799Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x03);
15542742Swollman#endif
155543014Swollman    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
155658787Sru    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
155775267Swollman    if (adp->va_crtc_addr == MONO_CRTC) {
155843543Swollman	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
155943543Swollman    } else {
156064499Swollman	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
156164499Swollman    }
156275267Swollman#else /* VGA_SLOW_IOACCESS */
156364499Swollman#ifdef VGA_ALT_SEQACCESS
156464499Swollman    outw(TSIDX, 0x0100);
156564499Swollman#endif
156675267Swollman    outw(TSIDX, 0x0002 | (buf[0] << 8));
156764499Swollman    outw(TSIDX, 0x0004 | (buf[1] << 8));
156864499Swollman#ifdef VGA_ALT_SEQACCESS
156964499Swollman    outw(TSIDX, 0x0300);
157043014Swollman#endif
15712742Swollman    outw(GDCIDX, 0x0004 | (buf[2] << 8));
15722742Swollman    outw(GDCIDX, 0x0005 | (buf[3] << 8));
15732742Swollman    if (adp->va_crtc_addr == MONO_CRTC)
15742742Swollman        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
15752742Swollman    else
157675267Swollman        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
157786222Swollman#endif /* VGA_SLOW_IOACCESS */
157893799Swollman
157993799Swollman    splx(s);
158043014Swollman}
158158787Sru
158243014Swollman#endif /* VGA_NO_FONT_LOADING */
158343014Swollman
158443014Swollman/*
158543014Swollman * save_font():
158675267Swollman * Read the font data in the requested font page from the video adapter.
158743014Swollman *
158843014Swollman * EGA/VGA
158943014Swollman */
159043014Swollmanstatic int
159158787Sruvga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
159258787Sru	      int ch, int count)
159358787Sru{
159458787Sru#ifndef VGA_NO_FONT_LOADING
159558787Sru    u_char buf[PARAM_BUFSIZE];
159658787Sru    u_int32_t segment;
159775267Swollman    int c;
159864499Swollman#ifdef VGA_ALT_SEQACCESS
159958787Sru    int s;
160058787Sru    u_char val = 0;
160158787Sru#endif
160258787Sru
160364499Swollman    prologue(adp, V_ADP_FONT, 1);
16042742Swollman
16052742Swollman    if (fontsize < 14) {
16062742Swollman	/* FONT_8 */
16072742Swollman	fontsize = 8;
16082742Swollman    } else if (fontsize >= 32) {
160975267Swollman	fontsize = 32;
161064499Swollman    } else if (fontsize >= 16) {
16112742Swollman	/* FONT_16 */
16122742Swollman	fontsize = 16;
161314343Swollman    } else {
161458787Sru	/* FONT_14 */
16152742Swollman	fontsize = 14;
161675267Swollman    }
16172742Swollman
161875267Swollman    if (page < 0 || page >= 8)
161975267Swollman	return 1;
162075267Swollman    segment = FONT_BUF + 0x4000*page;
162164499Swollman    if (page > 3)
162275267Swollman	segment -= 0xe000;
162375267Swollman
162475267Swollman#ifdef VGA_ALT_SEQACCESS
162575267Swollman    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
162675267Swollman	s = splhigh();
162775267Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x01);
162814343Swollman	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
162975267Swollman	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
163093799Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x03);
163193799Swollman	splx(s);
163275267Swollman    }
163375267Swollman#endif
163475267Swollman
163575267Swollman    set_font_mode(adp, buf);
163675267Swollman    if (fontsize == 32) {
163775267Swollman	bcopy_fromio(segment + ch*32, data, fontsize*count);
163875267Swollman    } else {
163975267Swollman	for (c = ch; count > 0; ++c, --count) {
164075267Swollman	    bcopy_fromio(segment + c*32, data, fontsize);
164175267Swollman	    data += fontsize;
16422742Swollman	}
16432742Swollman    }
16442742Swollman    set_normal_mode(adp, buf);
16452742Swollman
16462742Swollman#ifdef VGA_ALT_SEQACCESS
16472742Swollman    if (adp->va_type == KD_VGA) {
16482742Swollman	s = splhigh();
16492742Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x01);
16502742Swollman	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
16512742Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x03);
16522742Swollman	splx(s);
16532742Swollman    }
16542742Swollman#endif
16552742Swollman
16562742Swollman    return 0;
16572742Swollman#else /* VGA_NO_FONT_LOADING */
16582742Swollman    return 1;
16592742Swollman#endif /* VGA_NO_FONT_LOADING */
16602742Swollman}
16612742Swollman
16622742Swollman/*
16632742Swollman * load_font():
16642742Swollman * Set the font data in the requested font page.
16652742Swollman * NOTE: it appears that some recent video adapters do not support
16662742Swollman * the font page other than 0... XXX
16672742Swollman *
16682742Swollman * EGA/VGA
16692742Swollman */
16702742Swollmanstatic int
16712742Swollmanvga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
16722742Swollman	      int ch, int count)
16732742Swollman{
16742742Swollman#ifndef VGA_NO_FONT_LOADING
16752742Swollman    u_char buf[PARAM_BUFSIZE];
16762742Swollman    u_int32_t segment;
167743014Swollman    int c;
16782742Swollman#ifdef VGA_ALT_SEQACCESS
16792742Swollman    int s;
16802742Swollman    u_char val = 0;
16812742Swollman#endif
16822742Swollman
16832742Swollman    prologue(adp, V_ADP_FONT, 1);
16842742Swollman
16852742Swollman    if (fontsize < 14) {
16862742Swollman	/* FONT_8 */
16872742Swollman	fontsize = 8;
16882742Swollman    } else if (fontsize >= 32) {
16892742Swollman	fontsize = 32;
16902742Swollman    } else if (fontsize >= 16) {
16912742Swollman	/* FONT_16 */
16922742Swollman	fontsize = 16;
16932742Swollman    } else {
16942742Swollman	/* FONT_14 */
16952742Swollman	fontsize = 14;
16962742Swollman    }
16972742Swollman
16982742Swollman    if (page < 0 || page >= 8)
16992742Swollman	return 1;
17002742Swollman    segment = FONT_BUF + 0x4000*page;
17012742Swollman    if (page > 3)
170243014Swollman	segment -= 0xe000;
17032742Swollman
17042742Swollman#ifdef VGA_ALT_SEQACCESS
17052742Swollman    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
17062742Swollman	s = splhigh();
17072742Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x01);
17082742Swollman	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
170920094Swollman	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
171020094Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x03);
171120094Swollman	splx(s);
171220094Swollman    }
17132742Swollman#endif
17142742Swollman
17152742Swollman    set_font_mode(adp, buf);
171658787Sru    if (fontsize == 32) {
17172742Swollman	bcopy_toio(data, segment + ch*32, fontsize*count);
17182742Swollman    } else {
17192742Swollman	for (c = ch; count > 0; ++c, --count) {
17202742Swollman	    bcopy_toio(data, segment + c*32, fontsize);
17212742Swollman	    data += fontsize;
17222742Swollman	}
172358787Sru    }
172458787Sru    set_normal_mode(adp, buf);
172558787Sru
172658787Sru#ifdef VGA_ALT_SEQACCESS
172758787Sru    if (adp->va_type == KD_VGA) {
172858787Sru	s = splhigh();
172958787Sru	outb(TSIDX, 0x00); outb(TSREG, 0x01);
173058787Sru	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
173158787Sru	outb(TSIDX, 0x00); outb(TSREG, 0x03);
173258787Sru	splx(s);
17332742Swollman    }
1734138323Swollman#endif
1735138323Swollman
1736138323Swollman    return 0;
1737138323Swollman#else /* VGA_NO_FONT_LOADING */
1738138323Swollman    return 1;
1739138323Swollman#endif /* VGA_NO_FONT_LOADING */
1740138323Swollman}
1741138323Swollman
1742138323Swollman/*
17432742Swollman * show_font():
17442742Swollman * Activate the requested font page.
17452742Swollman * NOTE: it appears that some recent video adapters do not support
17462742Swollman * the font page other than 0... XXX
17472742Swollman *
17482742Swollman * EGA/VGA
17492742Swollman */
17502742Swollmanstatic int
17512742Swollmanvga_show_font(video_adapter_t *adp, int page)
17522742Swollman{
17532742Swollman#ifndef VGA_NO_FONT_LOADING
17542742Swollman    static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
17552742Swollman    int s;
17562742Swollman
17572742Swollman    prologue(adp, V_ADP_FONT, 1);
17582742Swollman    if (page < 0 || page >= 8)
17592742Swollman	return 1;
17602742Swollman
17612742Swollman    s = splhigh();
176230711Swollman    outb(TSIDX, 0x03); outb(TSREG, cg[page]);
17632742Swollman    splx(s);
17642742Swollman
17652742Swollman    return 0;
176643014Swollman#else /* VGA_NO_FONT_LOADING */
176720094Swollman    return 1;
176843014Swollman#endif /* VGA_NO_FONT_LOADING */
176943014Swollman}
177058787Sru
1771138323Swollman/*
177258787Sru * save_palette():
1773138323Swollman * Read DAC values. The values have expressed in 8 bits.
17742742Swollman *
17752742Swollman * VGA
17762742Swollman */
177758787Srustatic int
17782742Swollmanvga_save_palette(video_adapter_t *adp, u_char *palette)
17792742Swollman{
17802742Swollman    int i;
17812742Swollman
17822742Swollman    prologue(adp, V_ADP_PALETTE, 1);
17832742Swollman
17842742Swollman    /*
17852742Swollman     * We store 8 bit values in the palette buffer, while the standard
178675267Swollman     * VGA has 6 bit DAC .
178775267Swollman     */
178875267Swollman    outb(PALRADR, 0x00);
178975267Swollman    for (i = 0; i < 256*3; ++i)
179075267Swollman	palette[i] = inb(PALDATA) << 2;
179175267Swollman    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
179275267Swollman    return 0;
179375267Swollman}
179475267Swollman
179575267Swollman/*
179675267Swollman * load_palette():
179775267Swollman * Set DAC values.
179875267Swollman *
179975267Swollman * VGA
180075267Swollman */
180175267Swollmanstatic int
180275267Swollmanvga_load_palette(video_adapter_t *adp, u_char *palette)
180375267Swollman{
180475267Swollman    int i;
18052742Swollman
18062742Swollman    prologue(adp, V_ADP_PALETTE, 1);
18072742Swollman
18082742Swollman    outb(PIXMASK, 0xff);		/* no pixelmask */
18092742Swollman    outb(PALWADR, 0x00);
18102742Swollman    for (i = 0; i < 256*3; ++i)
18112742Swollman	outb(PALDATA, palette[i] >> 2);
18122742Swollman    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
18132742Swollman    outb(ATC, 0x20);			/* enable palette */
18142742Swollman    return 0;
18152742Swollman}
181675267Swollman
181775267Swollman/*
18182742Swollman * set_border():
18192742Swollman * Change the border color.
18202742Swollman *
18212742Swollman * CGA/EGA/VGA
18222742Swollman */
18232742Swollmanstatic int
1824121098Swollmanvga_set_border(video_adapter_t *adp, int color)
1825121098Swollman{
18262742Swollman    prologue(adp, V_ADP_BORDER, 1);
18272742Swollman
18282742Swollman    switch (adp->va_type) {
18292742Swollman    case KD_EGA:
18302742Swollman    case KD_VGA:
18312742Swollman	inb(adp->va_crtc_addr + 6);	/* reset flip-flop */
183219878Swollman	outb(ATC, 0x31); outb(ATC, color & 0xff);
18332742Swollman	break;
18342742Swollman    case KD_CGA:
18352742Swollman	outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */
18362742Swollman	break;
18372742Swollman    case KD_MONO:
18382742Swollman    case KD_HERCULES:
18392742Swollman    default:
18402742Swollman	break;
18412742Swollman    }
18422742Swollman    return 0;
18432742Swollman}
18442742Swollman
18452742Swollman/*
184620094Swollman * save_state():
184720094Swollman * Read video register values.
18482742Swollman * NOTE: this function only reads the standard EGA/VGA registers.
18492742Swollman * any extra/extended registers of SVGA adapters are not saved.
18502742Swollman *
18512742Swollman * VGA
18522742Swollman */
18532742Swollmanstatic int
18542742Swollmanvga_save_state(video_adapter_t *adp, void *p, size_t size)
18552742Swollman{
18562742Swollman    video_info_t info;
185758787Sru    u_char *buf;
185843014Swollman    int crtc_addr;
185943014Swollman    int i, j;
18602742Swollman    int s;
18612742Swollman
18622742Swollman    if (size == 0) {
18632742Swollman	/* return the required buffer size */
18642742Swollman	prologue(adp, V_ADP_STATESAVE, 0);
18652742Swollman	return sizeof(adp_state_t);
18662742Swollman    } else {
18672742Swollman	prologue(adp, V_ADP_STATESAVE, 1);
18682742Swollman	if (size < sizeof(adp_state_t))
18692742Swollman	    return 1;
187043543Swollman    }
187143543Swollman
18722742Swollman    ((adp_state_t *)p)->sig = V_STATE_SIG;
18732742Swollman    buf = ((adp_state_t *)p)->regs;
18742742Swollman    bzero(buf, V_MODE_PARAM_SIZE);
187519878Swollman    crtc_addr = adp->va_crtc_addr;
18762742Swollman
18772742Swollman    s = splhigh();
187819878Swollman
18792742Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
18802742Swollman    for (i = 0, j = 5; i < 4; i++) {
188158787Sru	outb(TSIDX, i + 1);
18822742Swollman	buf[j++]  =  inb(TSREG);
18832742Swollman    }
188443014Swollman    buf[9]  =  inb(MISC + 10);			/* dot-clock */
188558787Sru    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
188620094Swollman
188720094Swollman    for (i = 0, j = 10; i < 25; i++) {		/* crtc */
18882742Swollman	outb(crtc_addr, i);
18892742Swollman	buf[j++]  =  inb(crtc_addr + 1);
18902742Swollman    }
18912742Swollman    for (i = 0, j = 35; i < 20; i++) {		/* attribute ctrl */
189286222Swollman        inb(crtc_addr + 6);			/* reset flip-flop */
18932742Swollman	outb(ATC, i);
18942742Swollman	buf[j++]  =  inb(ATC + 1);
18952742Swollman    }
18962742Swollman    for (i = 0, j = 55; i < 9; i++) {		/* graph data ctrl */
18972742Swollman	outb(GDCIDX, i);
189830711Swollman	buf[j++]  =  inb(GDCREG);
189930711Swollman    }
190030711Swollman    inb(crtc_addr + 6);				/* reset flip-flop */
19012742Swollman    outb(ATC, 0x20);				/* enable palette */
190230711Swollman
19032742Swollman    splx(s);
19042742Swollman
19052742Swollman#if 1
190643543Swollman    if (vga_get_info(adp, adp->va_mode, &info) == 0) {
190743543Swollman	if (info.vi_flags & V_INFO_GRAPHICS) {
190843543Swollman	    buf[0] = info.vi_width/info.vi_cwidth; /* COLS */
190943543Swollman	    buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */
191043543Swollman	} else {
19112742Swollman	    buf[0] = info.vi_width;		/* COLS */
19122742Swollman	    buf[1] = info.vi_height - 1;	/* ROWS */
19132742Swollman	}
191420094Swollman	buf[2] = info.vi_cheight;		/* POINTS */
191520094Swollman    } else {
19162742Swollman	/* XXX: shouldn't be happening... */
19172742Swollman	printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
191886222Swollman	       adp->va_unit, adp->va_name);
19192742Swollman    }
19202742Swollman#else
192120094Swollman    buf[0] = readb(BIOS_PADDRTOVADDR(0x44a));	/* COLS */
192243543Swollman    buf[1] = readb(BIOS_PADDRTOVADDR(0x484));	/* ROWS */
192343543Swollman    buf[2] = readb(BIOS_PADDRTOVADDR(0x485));	/* POINTS */
19242742Swollman    buf[3] = readb(BIOS_PADDRTOVADDR(0x44c));
19252742Swollman    buf[4] = readb(BIOS_PADDRTOVADDR(0x44d));
19262742Swollman#endif
19272742Swollman
192886222Swollman    return 0;
19292742Swollman}
19302742Swollman
19312742Swollman/*
19322742Swollman * load_state():
19332742Swollman * Set video registers at once.
193414343Swollman * NOTE: this function only updates the standard EGA/VGA registers.
19352742Swollman * any extra/extended registers of SVGA adapters are not changed.
193614343Swollman *
19372742Swollman * EGA/VGA
19382742Swollman */
19392742Swollmanstatic int
19402742Swollmanvga_load_state(video_adapter_t *adp, void *p)
19412742Swollman{
19422742Swollman    u_char *buf;
19432742Swollman    int crtc_addr;
19442742Swollman    int s;
19452742Swollman    int i;
19462742Swollman
194786222Swollman    prologue(adp, V_ADP_STATELOAD, 1);
19482742Swollman    if (((adp_state_t *)p)->sig != V_STATE_SIG)
19492742Swollman	return 1;
19502742Swollman
19512742Swollman    buf = ((adp_state_t *)p)->regs;
19522742Swollman    crtc_addr = adp->va_crtc_addr;
19532742Swollman
19542742Swollman    s = splhigh();
1955121098Swollman
1956121098Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
19572742Swollman    for (i = 0; i < 4; ++i) {			/* program sequencer */
19582742Swollman	outb(TSIDX, i + 1);
19592742Swollman	outb(TSREG, buf[i + 5]);
19602742Swollman    }
196143014Swollman    outb(MISC, buf[9]);				/* set dot-clock */
19622742Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
19632742Swollman    outb(crtc_addr, 0x11);
19642742Swollman    outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F);
196543014Swollman    for (i = 0; i < 25; ++i) {			/* program crtc */
196643014Swollman	outb(crtc_addr, i);
196720094Swollman	outb(crtc_addr + 1, buf[i + 10]);
196820094Swollman    }
196920094Swollman    inb(crtc_addr+6);				/* reset flip-flop */
197020094Swollman    for (i = 0; i < 20; ++i) {			/* program attribute ctrl */
197120094Swollman	outb(ATC, i);
19722742Swollman	outb(ATC, buf[i + 35]);
19732742Swollman    }
197443014Swollman    for (i = 0; i < 9; ++i) {			/* program graph data ctrl */
197520094Swollman	outb(GDCIDX, i);
19768029Swollman	outb(GDCREG, buf[i + 55]);
197714343Swollman    }
19782742Swollman    inb(crtc_addr + 6);				/* reset flip-flop */
197914343Swollman    outb(ATC, 0x20);				/* enable palette */
19802742Swollman
19818029Swollman#if notyet /* a temporary workaround for kernel panic, XXX */
198214343Swollman#ifndef VGA_NO_BIOS
198314343Swollman    if (adp->va_unit == V_ADP_PRIMARY) {
198414343Swollman	writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]);	/* COLS */
198514343Swollman	writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */
1986	writeb(BIOS_PADDRTOVADDR(0x485), buf[2]);	/* POINTS */
1987#if 0
1988	writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]);
1989	writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]);
1990#endif
1991    }
1992#endif /* VGA_NO_BIOS */
1993#endif /* notyet */
1994
1995    splx(s);
1996    return 0;
1997}
1998
1999/*
2000 * set_origin():
2001 * Change the origin (window mapping) of the banked frame buffer.
2002 */
2003static int
2004vga_set_origin(video_adapter_t *adp, off_t offset)
2005{
2006    /*
2007     * The standard video modes do not require window mapping;
2008     * always return error.
2009     */
2010    return 1;
2011}
2012
2013/*
2014 * read_hw_cursor():
2015 * Read the position of the hardware text cursor.
2016 *
2017 * all adapters
2018 */
2019static int
2020vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
2021{
2022    u_int16_t off;
2023    int s;
2024
2025    if (!init_done)
2026	return 1;
2027
2028    if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
2029	return 1;
2030
2031    s = spltty();
2032    outb(adp->va_crtc_addr, 14);
2033    off = inb(adp->va_crtc_addr + 1);
2034    outb(adp->va_crtc_addr, 15);
2035    off = (off << 8) | inb(adp->va_crtc_addr + 1);
2036    splx(s);
2037
2038    *row = off / adp->va_info.vi_width;
2039    *col = off % adp->va_info.vi_width;
2040
2041    return 0;
2042}
2043
2044/*
2045 * set_hw_cursor():
2046 * Move the hardware text cursor.  If col and row are both -1,
2047 * the cursor won't be shown.
2048 *
2049 * all adapters
2050 */
2051static int
2052vga_set_hw_cursor(video_adapter_t *adp, int col, int row)
2053{
2054    u_int16_t off;
2055    int s;
2056
2057    if (!init_done)
2058	return 1;
2059
2060    if ((col == -1) && (row == -1)) {
2061	off = -1;
2062    } else {
2063	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
2064	    return 1;
2065	off = row*adp->va_info.vi_width + col;
2066    }
2067
2068    s = spltty();
2069    outb(adp->va_crtc_addr, 14);
2070    outb(adp->va_crtc_addr + 1, off >> 8);
2071    outb(adp->va_crtc_addr, 15);
2072    outb(adp->va_crtc_addr + 1, off & 0x00ff);
2073    splx(s);
2074
2075    return 0;
2076}
2077
2078/*
2079 * set_hw_cursor_shape():
2080 * Change the shape of the hardware text cursor. If the height is
2081 * zero or negative, the cursor won't be shown.
2082 *
2083 * all adapters
2084 */
2085static int
2086vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
2087			int celsize, int blink)
2088{
2089    int s;
2090
2091    if (!init_done)
2092	return 1;
2093
2094    s = spltty();
2095    switch (adp->va_type) {
2096    case KD_VGA:
2097    case KD_CGA:
2098    case KD_MONO:
2099    case KD_HERCULES:
2100    default:
2101	if (height <= 0) {
2102	    /* make the cursor invisible */
2103	    outb(adp->va_crtc_addr, 10);
2104	    outb(adp->va_crtc_addr + 1, 32);
2105	    outb(adp->va_crtc_addr, 11);
2106	    outb(adp->va_crtc_addr + 1, 0);
2107	} else {
2108	    outb(adp->va_crtc_addr, 10);
2109	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2110	    outb(adp->va_crtc_addr, 11);
2111	    outb(adp->va_crtc_addr + 1, celsize - base - 1);
2112	}
2113	break;
2114    case KD_EGA:
2115	if (height <= 0) {
2116	    /* make the cursor invisible */
2117	    outb(adp->va_crtc_addr, 10);
2118	    outb(adp->va_crtc_addr + 1, celsize);
2119	    outb(adp->va_crtc_addr, 11);
2120	    outb(adp->va_crtc_addr + 1, 0);
2121	} else {
2122	    outb(adp->va_crtc_addr, 10);
2123	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2124	    outb(adp->va_crtc_addr, 11);
2125	    outb(adp->va_crtc_addr + 1, celsize - base);
2126	}
2127	break;
2128    }
2129    splx(s);
2130
2131    return 0;
2132}
2133
2134/*
2135 * mmap():
2136 * Mmap frame buffer.
2137 *
2138 * all adapters
2139 */
2140static int
2141vga_mmap(video_adapter_t *adp, vm_offset_t offset)
2142{
2143    if (offset > 0x20000 - PAGE_SIZE)
2144	return -1;
2145#ifdef __i386__
2146    return i386_btop((VIDEO_BUF_BASE + offset));
2147#endif
2148#ifdef __alpha__
2149    return alpha_btop((VIDEO_BUF_BASE + offset));
2150#endif
2151}
2152
2153static void
2154dump_buffer(u_char *buf, size_t len)
2155{
2156    int i;
2157
2158    for(i = 0; i < len;) {
2159	printf("%02x ", buf[i]);
2160	if ((++i % 16) == 0)
2161	    printf("\n");
2162    }
2163}
2164
2165/*
2166 * diag():
2167 * Print some information about the video adapter and video modes,
2168 * with requested level of details.
2169 *
2170 * all adapters
2171 */
2172static int
2173vga_diag(video_adapter_t *adp, int level)
2174{
2175#if FB_DEBUG > 1
2176    video_info_t info;
2177#endif
2178    u_char *mp;
2179
2180    if (!init_done)
2181	return 1;
2182
2183#if FB_DEBUG > 1
2184#ifndef VGA_NO_BIOS
2185    printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n",
2186	   rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488)));
2187    printf("vga: CRTC:0x%x, video option:0x%02x, ",
2188	   readw(BIOS_PADDRTOVADDR(0x463)),
2189	   readb(BIOS_PADDRTOVADDR(0x487)));
2190    printf("rows:%d, cols:%d, font height:%d\n",
2191	   readb(BIOS_PADDRTOVADDR(0x44a)),
2192	   readb(BIOS_PADDRTOVADDR(0x484)) + 1,
2193	   readb(BIOS_PADDRTOVADDR(0x485)));
2194#endif /* VGA_NO_BIOS */
2195#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
2196    printf("vga: param table EGA/VGA:%p", video_mode_ptr);
2197    printf(", CGA/MDA:%p\n", video_mode_ptr2);
2198#endif
2199    printf("vga: rows_offset:%d\n", rows_offset);
2200#endif /* FB_DEBUG > 1 */
2201
2202    fb_dump_adp_info(DRIVER_NAME, adp, level);
2203
2204#if FB_DEBUG > 1
2205    if (adp->va_flags & V_ADP_MODECHANGE) {
2206	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
2207	    if (bios_vmode[i].vi_mode == NA)
2208		continue;
2209	    if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
2210		continue;
2211	    fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
2212	}
2213    } else {
2214	vga_get_info(adp, adp->va_initial_mode, &info);	/* shouldn't fail */
2215	fb_dump_mode_info(DRIVER_NAME, adp, &info, level);
2216    }
2217#endif /* FB_DEBUG > 1 */
2218
2219    if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA))
2220	return 0;
2221#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
2222    if (video_mode_ptr == NULL)
2223	printf("vga%d: %s: WARNING: video mode switching is not "
2224	       "fully supported on this adapter\n",
2225	       adp->va_unit, adp->va_name);
2226#endif
2227    if (level <= 0)
2228	return 0;
2229
2230    if (adp->va_type == KD_VGA) {
2231	printf("VGA parameters upon power-up\n");
2232	dump_buffer(adpstate.regs, sizeof(adpstate.regs));
2233	printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode);
2234	dump_buffer(adpstate2.regs, sizeof(adpstate2.regs));
2235    }
2236
2237    mp = get_mode_param(adp->va_initial_mode);
2238    if (mp == NULL)	/* this shouldn't be happening */
2239	return 0;
2240    printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode);
2241    dump_buffer(mp, V_MODE_PARAM_SIZE);
2242
2243    return 0;
2244}
2245
2246#endif /* NVGA > 0 */
2247