vga_isa.c revision 43664
1158421Swollman/*-
2153761Swollman * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
364499Swollman * 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
8158421Swollman * are met:
92742Swollman * 1. Redistributions of source code must retain the above copyright
102742Swollman *    notice, this list of conditions and the following disclaimer as
11158421Swollman *    the first lines of this file unmodified.
12158421Swollman * 2. Redistributions in binary form must reproduce the above copyright
132742Swollman *    notice, this list of conditions and the following disclaimer in the
1486222Swollman *    documentation and/or other materials provided with the distribution.
1520094Swollman * 3. The name of the author may not be used to endorse or promote products
1620094Swollman *    derived from this software without specific prior written permission.
1720094Swollman *
1820094Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1920094Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20158421Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21158421Swollman * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2220094Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
232742Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242742Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252742Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262742Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
272742Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2858787Sru *
292742Swollman * $Id: vga_isa.c,v 1.1 1999/01/23 16:53:30 dfr Exp $
302742Swollman */
312742Swollman
322742Swollman#include "vga.h"
33114173Swollman#include "opt_vga.h"
34114173Swollman#include "opt_fb.h"
35114173Swollman#include "opt_syscons.h"	/* should be removed in the future, XXX */
36114173Swollman
37114173Swollman#if NVGA > 0
38114173Swollman
39114173Swollman#include <sys/param.h>
40114173Swollman#include <sys/systm.h>
41114173Swollman#include <sys/kernel.h>
42114173Swollman#include <sys/bus.h>
43114173Swollman#include <sys/malloc.h>
44114173Swollman
45114173Swollman#include <vm/vm.h>
46114173Swollman#include <vm/pmap.h>
47149590Swollman
48149590Swollman#include <machine/console.h>
49114173Swollman#include <machine/md_var.h>
502742Swollman#include <machine/pc/bios.h>
519908Swollman
522742Swollman#include <dev/fb/fbreg.h>
532742Swollman#include <dev/fb/vgareg.h>
542742Swollman
552742Swollman#ifndef __i386__
562742Swollman#include <isa/isareg.h>
572742Swollman#include <isa/isavar.h>
582742Swollman#else
592742Swollman#include <i386/isa/isa.h>
602742Swollman#include <i386/isa/isa_device.h>
6120094Swollman#endif
622742Swollman
6320094Swollman#define DRIVER_NAME		"vga"
64158421Swollman
6520094Swollman/* cdev driver declaration */
6620094Swollman
6720094Swollman#define ISAVGA_UNIT(dev)	minor(dev)
6820094Swollman#define ISAVGA_MKMINOR(unit)	(unit)
6920094Swollman
7020094Swollmantypedef struct isavga_softc {
7120094Swollman	video_adapter_t	*adp;
7220094Swollman} isavga_softc_t;
7320094Swollman
7420094Swollman#ifndef __i386__
7520094Swollman
7620094Swollman#define ISAVGA_SOFTC(unit)		\
7720094Swollman	((isavga_softc_t *)devclass_get_softc(isavga_devclass, unit))
782742Swollman
792742Swollmandevclass_t		isavga_devclass;
802742Swollman
812742Swollmanstatic int		isavga_probe(device_t dev);
8219878Swollmanstatic int		isavga_attach(device_t dev);
832742Swollman
842742Swollmanstatic device_method_t isavga_methods[] = {
852742Swollman	DEVMETHOD(device_probe,		isavga_probe),
86158421Swollman	DEVMETHOD(device_attach,	isavga_attach),
87158421Swollman	{ 0, 0 }
88158421Swollman};
89158421Swollman
90158421Swollmanstatic driver_t isavga_driver = {
91153670Swollman	DRIVER_NAME,
9243014Swollman	isavga_methods,
9343014Swollman	DRIVER_TYPE_TTY,
9443014Swollman	sizeof(isavga_softc_t),
952742Swollman};
962742Swollman
9719878SwollmanDRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0);
9819878Swollman
9919878Swollman#else /* __i386__ */
10058787Sru
10143014Swollman#define ISAVGA_SOFTC(unit)	(isavga_softc[unit])
10275267Swollman
1032742Swollmanstatic isavga_softc_t	*isavga_softc[NVGA];
1042742Swollman
105153670Swollmanstatic int		isavga_probe(struct isa_device *dev);
106153670Swollmanstatic int		isavga_attach(struct isa_device *dev);
107153670Swollman
10843014Swollmanstruct isa_driver vgadriver = {
109153670Swollman	isavga_probe,
110153670Swollman	isavga_attach,
1112742Swollman	DRIVER_NAME,
1122742Swollman	0,
11319878Swollman};
11419878Swollman
11519878Swollman#endif /* __i386__ */
116149514Swollman
11720094Swollmanstatic int		isavga_probe_unit(int unit, isavga_softc_t *sc,
11843014Swollman					  int flags);
11943014Swollmanstatic int		isavga_attach_unit(int unit, isavga_softc_t *sc,
1202742Swollman					   int flags);
1212742Swollman
1222742Swollman#ifdef FB_INSTALL_CDEV
12367578Swollman
1242742Swollmanstatic d_open_t		isavgaopen;
1252742Swollmanstatic d_close_t	isavgaclose;
1262742Swollmanstatic d_read_t		isavgaread;
1272742Swollmanstatic d_ioctl_t	isavgaioctl;
1282742Swollman
12975267Swollmanstatic struct  cdevsw vga_cdevsw = {
13019878Swollman	isavgaopen,	isavgaclose,	noread,		nowrite,	/* ?? */
13119878Swollman	isavgaioctl,	nostop,		nullreset,	nodevtotty,
1322742Swollman	seltrue,	nommap,		NULL,		DRIVER_NAME,
13319878Swollman	NULL,		-1,		nodump,		nopsize,
13419878Swollman};
13519878Swollman
1362742Swollman#endif /* FB_INSTALL_CDEV */
1372742Swollman
1382742Swollman#ifndef __i386__
13967578Swollman
1402742Swollmanstatic int
14119878Swollmanisavga_probe(device_t dev)
1422742Swollman{
1432742Swollman	isavga_softc_t *sc;
14486222Swollman
14586222Swollman	device_set_desc(dev, "Generic ISA VGA");
146149514Swollman	sc = device_get_softc(dev);
147149514Swollman	return isavga_probe_unit(device_get_unit(dev), sc, isa_get_flags(dev));
148149514Swollman}
1492742Swollman
150149514Swollmanstatic int
151149514Swollmanisavga_attach(device_t dev)
15286222Swollman{
1532742Swollman	isavga_softc_t *sc;
1542742Swollman
1552742Swollman	sc = device_get_softc(dev);
1562742Swollman	return isavga_attach_unit(device_get_unit(dev), sc, isa_get_flags(dev));
1572742Swollman}
1582742Swollman
1592742Swollman#else /* __i386__ */
16014343Swollman
1612742Swollmanstatic int
16217200Swollmanisavga_probe(struct isa_device *dev)
16319878Swollman{
16419878Swollman	isavga_softc_t *sc;
1652742Swollman	int error;
16619878Swollman
1672742Swollman	if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0]))
1682742Swollman		return 0;
1692742Swollman	sc = isavga_softc[dev->id_unit]
1702742Swollman	   = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
17119878Swollman	if (sc == NULL)
1722742Swollman		return 0;
1732742Swollman
1742742Swollman	error = isavga_probe_unit(dev->id_unit, sc, dev->id_flags);
1752742Swollman	if (error) {
17643014Swollman		isavga_softc[dev->id_unit] = NULL;
1772742Swollman		free(sc, M_DEVBUF);
1782742Swollman		return 0;
1792742Swollman	}
1802742Swollman
18119878Swollman	dev->id_iobase = sc->adp->va_io_base;
18219878Swollman	dev->id_maddr = (caddr_t)BIOS_PADDRTOVADDR(sc->adp->va_mem_base);
1832742Swollman	dev->id_msize = sc->adp->va_mem_size;
1842742Swollman
1852742Swollman	return sc->adp->va_io_size;
18693799Swollman}
1872742Swollman
1882742Swollmanstatic int
1892742Swollmanisavga_attach(struct isa_device *dev)
1902742Swollman{
1912742Swollman	isavga_softc_t *sc;
1922742Swollman
1932742Swollman	if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0]))
1942742Swollman		return 0;
19519878Swollman	sc = isavga_softc[dev->id_unit];
1962742Swollman	if (sc == NULL)
1972742Swollman		return 0;
1982742Swollman
199158421Swollman	return ((isavga_attach_unit(dev->id_unit, sc, dev->id_flags)) ? 0 : 1);
200158421Swollman}
201158421Swollman
202158421Swollman#endif /* __i386__ */
2032742Swollman
204158421Swollmanstatic int
205158421Swollmanisavga_probe_unit(int unit, isavga_softc_t *sc, int flags)
2062742Swollman{
207158421Swollman	video_switch_t *sw;
2082742Swollman
2092742Swollman	bzero(sc, sizeof(*sc));
2102742Swollman	sw = vid_get_switch(DRIVER_NAME);
2112742Swollman	if (sw == NULL)
2122742Swollman		return 0;
21314343Swollman	return (*sw->probe)(unit, &sc->adp, NULL, flags);
21414343Swollman}
21593799Swollman
2162742Swollmanstatic int
21793799Swollmanisavga_attach_unit(int unit, isavga_softc_t *sc, int flags)
21893799Swollman{
21993799Swollman	video_switch_t *sw;
22093799Swollman	int error;
22193799Swollman
22293799Swollman	sw = vid_get_switch(DRIVER_NAME);
22367578Swollman	if (sw == NULL)
22493799Swollman		return ENXIO;
22514343Swollman
22693799Swollman	error = (*sw->init)(unit, sc->adp, flags);
22793799Swollman	if (error)
22814343Swollman		return ENXIO;
22993799Swollman
2302742Swollman#ifdef FB_INSTALL_CDEV
2312742Swollman	/* attach a virtual frame buffer device */
2322742Swollman	error = fb_attach(makedev(0, ISAVGA_MKMINOR(unit)), scp->adp,
23393799Swollman			  &vga_cdevsw);
23486222Swollman	if (error)
23593799Swollman		return error;
23614343Swollman#endif /* FB_INSTALL_CDEV */
23793799Swollman
23867578Swollman	if (bootverbose)
23919878Swollman		(*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose);
24014343Swollman
24193799Swollman	return 0;
24267578Swollman}
24319878Swollman
24419878Swollman/* LOW-LEVEL */
24514343Swollman
24693799Swollman#include <machine/clock.h>
24767578Swollman#include <machine/pc/vesa.h>
2482742Swollman
2492742Swollman#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
2502742Swollman#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
2512742Swollman#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
2522742Swollman
2532742Swollman/* for compatibility with old kernel options */
2542742Swollman#ifdef SC_ALT_SEQACCESS
2552742Swollman#undef SC_ALT_SEQACCESS
2562742Swollman#undef VGA_ALT_SEQACCESS
2572742Swollman#define VGA_ALT_SEQACCESS	1
2582742Swollman#endif
2592742Swollman
2602742Swollman#ifdef SLOW_VGA
2612742Swollman#undef SLOW_VGA
2622742Swollman#undef VGA_SLOW_IOACCESS
2632742Swollman#define VGA_SLOW_IOACCESS	1
2642742Swollman#endif
2652742Swollman
26658787Sru/* architecture dependent option */
2672742Swollman#ifdef __alpha__
26830711Swollman#define VGA_NO_BIOS		1
26930711Swollman#endif
27030711Swollman
27143014Swollman/* this should really be in `rtc.h' */
27230711Swollman#define RTC_EQUIPMENT           0x14
273158421Swollman
27443543Swollman/* various sizes */
27543543Swollman#define V_MODE_MAP_SIZE		(M_VGA_CG320 + 1)
27643543Swollman#define V_MODE_PARAM_SIZE	64
27730711Swollman
27830711Swollman/* video adapter state buffer */
27930711Swollmanstruct adp_state {
28030711Swollman    int			sig;
28130711Swollman#define V_STATE_SIG	0x736f6962
28230711Swollman    u_char		regs[V_MODE_PARAM_SIZE];
28330711Swollman};
28430711Swollmantypedef struct adp_state adp_state_t;
28530711Swollman
28630711Swollman/* video adapter information */
28730711Swollman#define DCC_MONO	0
28830711Swollman#define DCC_CGA40	1
28930711Swollman#define DCC_CGA80	2
29086222Swollman#define DCC_EGAMONO	3
29130711Swollman#define DCC_EGA40	4
29230711Swollman#define DCC_EGA80	5
29393799Swollman
2942742Swollman/*
29593799Swollman * NOTE: `va_window' should have a virtual address, but is initialized
29693799Swollman * with a physical address in the following table, as verify_adapter()
29793799Swollman * will perform address conversion at run-time.
29893799Swollman */
29993799Swollmanstatic video_adapter_t adapter_init_value[] = {
30093799Swollman    /* DCC_MONO */
30193799Swollman    { 0, KD_MONO, "mda", 0, 0, 0, 	    IO_MDA, IO_MDASIZE, MONO_CRTC,
30293799Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
30393799Swollman      0, 0, 0, 7, 0, },
30493799Swollman    /* DCC_CGA40 */
30593799Swollman    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
30693799Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
30793799Swollman      0, 0, 0, 3, 0, },
30893799Swollman    /* DCC_CGA80 */
3092742Swollman    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
31093799Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
31193799Swollman      0, 0, 0, 3, 0, },
31219878Swollman    /* DCC_EGAMONO */
3132742Swollman    { 0, KD_EGA,  "ega", 0, 0, 0,	    IO_MDA, 48,	  MONO_CRTC,
3142742Swollman      EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
3152742Swollman      0, 0, 0, 7, 0, },
3162742Swollman    /* DCC_EGA40 */
3172742Swollman    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
3182742Swollman      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
31919878Swollman      0, 0, 0, 3, 0, },
3202742Swollman    /* DCC_EGA80 */
32119878Swollman    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
3222742Swollman      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
32319878Swollman      0, 0, 0, 3, 0, },
3242742Swollman};
3252742Swollman
32643543Swollmanstatic video_adapter_t	biosadapter[2];
32743543Swollmanstatic int		biosadapters = 0;
3282742Swollman
3292742Swollman/* video driver declarations */
33043543Swollmanstatic int			vga_configure(int flags);
33158787Sru       int			(*vga_sub_configure)(int flags);
33243543Swollmanstatic int			vga_nop(void);
3332742Swollmanstatic vi_probe_t		vga_probe;
33467578Swollmanstatic vi_init_t		vga_init;
33567578Swollmanstatic vi_get_info_t		vga_get_info;
33667578Swollmanstatic vi_query_mode_t		vga_query_mode;
33767578Swollmanstatic vi_set_mode_t		vga_set_mode;
3382742Swollmanstatic vi_save_font_t		vga_save_font;
339149514Swollmanstatic vi_load_font_t		vga_load_font;
3409908Swollmanstatic vi_show_font_t		vga_show_font;
3419908Swollmanstatic vi_save_palette_t	vga_save_palette;
3429908Swollmanstatic vi_load_palette_t	vga_load_palette;
34314343Swollmanstatic vi_set_border_t		vga_set_border;
34414343Swollmanstatic vi_save_state_t		vga_save_state;
345149514Swollmanstatic vi_load_state_t		vga_load_state;
34620094Swollmanstatic vi_set_win_org_t		vga_set_origin;
34720094Swollmanstatic vi_read_hw_cursor_t	vga_read_hw_cursor;
34820094Swollmanstatic vi_set_hw_cursor_t	vga_set_hw_cursor;
349136638Swollmanstatic vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
350136638Swollmanstatic vi_mmap_t		vga_mmap;
351149514Swollmanstatic vi_diag_t		vga_diag;
352136638Swollman
353136638Swollmanstatic video_switch_t vgavidsw = {
354136638Swollman	vga_probe,
355136638Swollman	vga_init,
356136638Swollman	vga_get_info,
357136638Swollman	vga_query_mode,
358136638Swollman	vga_set_mode,
359153670Swollman	vga_save_font,
360153670Swollman	vga_load_font,
361153670Swollman	vga_show_font,
362153670Swollman	vga_save_palette,
363153670Swollman	vga_load_palette,
364153670Swollman	vga_set_border,
365153670Swollman	vga_save_state,
366153670Swollman	vga_load_state,
367153670Swollman	vga_set_origin,
368153670Swollman	vga_read_hw_cursor,
369153670Swollman	vga_set_hw_cursor,
3702742Swollman	vga_set_hw_cursor_shape,
3712742Swollman	(vi_blank_display_t *)vga_nop,
37219878Swollman	vga_mmap,
37319878Swollman	vga_diag,
37419878Swollman};
37519878Swollman
37620094SwollmanVIDEO_DRIVER(mda, vgavidsw, NULL);
37720094SwollmanVIDEO_DRIVER(cga, vgavidsw, NULL);
37820094SwollmanVIDEO_DRIVER(ega, vgavidsw, NULL);
37943543SwollmanVIDEO_DRIVER(vga, vgavidsw, vga_configure);
380136638Swollman
381153670Swollman/* VGA BIOS standard video modes */
382153670Swollman#define EOT		(-1)
3832742Swollman#define NA		(-2)
38458787Sru
38575267Swollmanstatic video_info_t bios_vmode[] = {
38675267Swollman    /* CGA */
38775267Swollman    { M_B40x25,     V_INFO_COLOR, 40, 25, 8,  8, 2, 1,
38875267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
38975267Swollman    { M_C40x25,     V_INFO_COLOR, 40, 25, 8,  8, 4, 1,
39075267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39175267Swollman    { M_B80x25,     V_INFO_COLOR, 80, 25, 8,  8, 2, 1,
39275267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39375267Swollman    { M_C80x25,     V_INFO_COLOR, 80, 25, 8,  8, 4, 1,
39475267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39575267Swollman    /* EGA */
39675267Swollman    { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1,
39775267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39875267Swollman    { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1,
39975267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40075267Swollman    { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1,
40175267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40275267Swollman    { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1,
40375267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40475267Swollman    /* VGA */
40575267Swollman    { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1,
40675267Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40758787Sru    { M_VGA_M80x25, 0,            80, 25, 8, 16, 2, 1,
40858787Sru      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
409149514Swollman    { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
41058787Sru      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
411149514Swollman    /* MDA */
41286222Swollman    { M_EGAMONO80x25, 0,          80, 25, 8, 14, 2, 1,
413149514Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
41458787Sru    /* EGA */
4152742Swollman    { M_ENH_B80x43, V_INFO_COLOR, 80, 43, 8,  8, 2, 1,
4162742Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
417136638Swollman    { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8,  8, 4, 1,
41819878Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
41919878Swollman    /* VGA */
4202742Swollman    { M_VGA_M80x30, 0,            80, 30, 8, 16, 2, 1,
4212742Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
4222742Swollman    { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
4232742Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
4242742Swollman    { M_VGA_M80x50, 0,            80, 50, 8,  8, 2, 1,
4252742Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
4262742Swollman    { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8,  8, 4, 1,
4272742Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
4282742Swollman    { M_VGA_M80x60, 0,            80, 60, 8,  8, 2, 1,
42986222Swollman      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
430158421Swollman    { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8,  8, 4, 1,
43186222Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43286222Swollman#ifndef VGA_NO_MODE_CHANGE
43386222Swollman    /* CGA */
43486222Swollman    { M_BG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
43586222Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
4362742Swollman    { M_CG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
4372742Swollman      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
438158421Swollman    { M_BG640,      V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 1, 1,
43958787Sru      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
44058787Sru    /* EGA */
44119878Swollman    { M_CG320_D,    V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 4, 4,
44286222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
4432742Swollman    { M_CG640_E,    V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 4, 4,
44486222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44586222Swollman    { M_EGAMONOAPA, V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
44686222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 },
44786222Swollman    { M_ENHMONOAPA2,V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
44886222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44986222Swollman    { M_CG640x350,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2,
45086222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45186222Swollman    { M_ENH_CG640,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4,
45286222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45386222Swollman    /* VGA */
45486222Swollman    { M_BG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
45586222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45686222Swollman    { M_CG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
45793799Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45819878Swollman    { M_VGA_CG320,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 8, 1,
45986222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
4602742Swollman    { M_VGA_MODEX,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8,  8, 8, 1,
46186222Swollman      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
4622742Swollman#endif /* VGA_NO_MODE_CHANGE */
46386222Swollman
4642742Swollman    { EOT },
46586222Swollman};
4662742Swollman
4672742Swollmanstatic int		init_done = FALSE;
468114173Swollmanstatic u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
469114173Swollmanstatic u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
470114173Swollmanstatic u_char		*mode_map[V_MODE_MAP_SIZE];
471114173Swollmanstatic adp_state_t	adpstate;
47221217Swollmanstatic adp_state_t	adpstate2;
473114173Swollmanstatic int		rows_offset = 1;
474114173Swollman
47521217Swollman/* local macros and functions */
476114173Swollman#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
477114173Swollman
478114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
479114173Swollmanstatic void map_mode_table(u_char *map[], u_char *table, int max);
480114173Swollman#endif
481114173Swollmanstatic void clear_mode_map(video_adapter_t *adp, u_char *map[], int max,
482114173Swollman			   int color);
483114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
484114173Swollmanstatic int map_mode_num(int mode);
485114173Swollman#endif
486114173Swollmanstatic int map_gen_mode_num(int type, int color, int mode);
487114173Swollmanstatic int map_bios_mode_num(int type, int color, int bios_mode);
488114173Swollmanstatic u_char *get_mode_param(int mode);
489114173Swollman#ifndef VGA_NO_BIOS
490114173Swollmanstatic void fill_adapter_param(int code, video_adapter_t *adp);
491114173Swollman#endif
492114173Swollmanstatic int verify_adapter(video_adapter_t *adp);
493114173Swollmanstatic void update_adapter_info(video_adapter_t *adp, video_info_t *info);
494114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
495114173Swollman#define COMP_IDENTICAL	0
496114173Swollman#define COMP_SIMILAR	1
497114173Swollman#define COMP_DIFFERENT	2
498149514Swollmanstatic int comp_adpregs(u_char *buf1, u_char *buf2);
499149514Swollman#endif
500149514Swollmanstatic int probe_adapters(void);
501149514Swollman
502149514Swollman#define PARAM_BUFSIZE	6
503149514Swollmanstatic void set_font_mode(video_adapter_t *adp, u_char *buf);
504149514Swollmanstatic void set_normal_mode(video_adapter_t *adp, u_char *buf);
505158421Swollman
506158421Swollmanstatic void dump_buffer(u_char *buf, size_t len);
507149514Swollman
508149514Swollman#define	ISMAPPED(pa, width)				\
509149514Swollman	(((pa) <= (u_long)0x1000 - (width)) 		\
510149514Swollman	 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
51121217Swollman
512149514Swollman#define	prologue(adp, flag, err)			\
513149514Swollman	if (!init_done || !((adp)->va_flags & (flag)))	\
514149514Swollman	    return (err)
515149514Swollman
516149514Swollman/* a backdoor for the console driver */
517149514Swollmanstatic int
518149514Swollmanvga_configure(int flags)
519149514Swollman{
520149514Swollman    int i;
521149514Swollman
522149514Swollman    probe_adapters();
523149514Swollman    for (i = 0; i < biosadapters; ++i) {
524149514Swollman	if (!probe_done(&biosadapter[i]))
525149514Swollman	    continue;
526158421Swollman	biosadapter[i].va_flags |= V_ADP_INITIALIZED;
527158421Swollman	if (!config_done(&biosadapter[i])) {
528158421Swollman	    if (vid_register(&biosadapter[i]) < 0)
529158421Swollman		continue;
530158421Swollman	    biosadapter[i].va_flags |= V_ADP_REGISTERED;
531158421Swollman	}
532158421Swollman    }
533158421Swollman    if (vga_sub_configure != NULL)
5342742Swollman	(*vga_sub_configure)(flags);
535114173Swollman
536114173Swollman    return biosadapters;
537114173Swollman}
538114173Swollman
539114173Swollman/* local subroutines */
540114173Swollman
541114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
542114173Swollman/* construct the mode parameter map */
543114173Swollmanstatic void
544114173Swollmanmap_mode_table(u_char *map[], u_char *table, int max)
545114173Swollman{
546114173Swollman    int i;
547114173Swollman
548114173Swollman    for(i = 0; i < max; ++i)
549114173Swollman	map[i] = table + i*V_MODE_PARAM_SIZE;
550114173Swollman    for(; i < V_MODE_MAP_SIZE; ++i)
551114173Swollman	map[i] = NULL;
552158421Swollman}
553158421Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
5542742Swollman
5552742Swollmanstatic void
55619878Swollmanclear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color)
557114173Swollman{
55819878Swollman    video_info_t info;
55919878Swollman    int i;
5602742Swollman
56164499Swollman    /*
5622742Swollman     * NOTE: we don't touch `bios_vmode[]' because it is shared
56364499Swollman     * by all adapters.
564149514Swollman     */
56564499Swollman    for(i = 0; i < max; ++i) {
56675267Swollman	if (vga_get_info(adp, i, &info))
56764499Swollman	    continue;
56864499Swollman	if ((info.vi_flags & V_INFO_COLOR) != color)
56964499Swollman	    map[i] = NULL;
57064499Swollman    }
57164499Swollman}
57264499Swollman
57364499Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
57464499Swollman/* map the non-standard video mode to a known mode number */
57564499Swollmanstatic int
57664499Swollmanmap_mode_num(int mode)
57764499Swollman{
5782742Swollman    static struct {
5792742Swollman        int from;
5802742Swollman        int to;
5812742Swollman    } mode_map[] = {
5822742Swollman        { M_ENH_B80x43, M_ENH_B80x25 },
58320094Swollman        { M_ENH_C80x43, M_ENH_C80x25 },
58420094Swollman        { M_VGA_M80x30, M_VGA_M80x25 },
58520094Swollman        { M_VGA_C80x30, M_VGA_C80x25 },
586158421Swollman        { M_VGA_M80x50, M_VGA_M80x25 },
587158421Swollman        { M_VGA_C80x50, M_VGA_C80x25 },
58820094Swollman        { M_VGA_M80x60, M_VGA_M80x25 },
58967578Swollman        { M_VGA_C80x60, M_VGA_C80x25 },
5902742Swollman        { M_VGA_MODEX,  M_VGA_CG320 },
5912742Swollman    };
59219878Swollman    int i;
5932742Swollman
5942742Swollman    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
5952742Swollman        if (mode_map[i].from == mode)
5962742Swollman            return mode_map[i].to;
5972742Swollman    }
5982742Swollman    return mode;
5992742Swollman}
6002742Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
60175267Swollman
60275267Swollman/* map a generic video mode to a known mode number */
60375267Swollmanstatic int
60475267Swollmanmap_gen_mode_num(int type, int color, int mode)
60575267Swollman{
60675267Swollman    static struct {
60775267Swollman	int from;
60875267Swollman	int to_color;
60975267Swollman	int to_mono;
61075267Swollman    } mode_map[] = {
61175267Swollman	{ M_TEXT_80x30,	M_VGA_C80x30, M_VGA_M80x30, },
61275267Swollman	{ M_TEXT_80x43,	M_ENH_C80x43, M_ENH_B80x43, },
61375267Swollman	{ M_TEXT_80x50,	M_VGA_C80x50, M_VGA_M80x50, },
61475267Swollman	{ M_TEXT_80x60,	M_VGA_C80x60, M_VGA_M80x60, },
61575267Swollman    };
61675267Swollman    int i;
61775267Swollman
61875267Swollman    if (mode == M_TEXT_80x25) {
61975267Swollman	switch (type) {
6202742Swollman
621158421Swollman	case KD_VGA:
6222742Swollman	    if (color)
6232742Swollman		return M_VGA_C80x25;
6242742Swollman	    else
6252742Swollman		return M_VGA_M80x25;
6262742Swollman	    break;
6272742Swollman
6282742Swollman	case KD_EGA:
6292742Swollman	    if (color)
6302742Swollman		return M_ENH_C80x25;
6312742Swollman	    else
6322742Swollman		return M_EGAMONO80x25;
6332742Swollman	    break;
6342742Swollman
6352742Swollman	case KD_CGA:
6362742Swollman	    return M_C80x25;
6372742Swollman
6382742Swollman	case KD_MONO:
6392742Swollman	case KD_HERCULES:
6402742Swollman	    return M_EGAMONO80x25;	/* XXX: this name is confusing */
6412742Swollman
6422742Swollman 	default:
6432742Swollman	    return -1;
6442742Swollman	}
6452742Swollman    }
6462742Swollman
6472742Swollman    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
6482742Swollman        if (mode_map[i].from == mode)
6492742Swollman            return ((color) ? mode_map[i].to_color : mode_map[i].to_mono);
6502742Swollman    }
6512742Swollman    return mode;
6522742Swollman}
6532742Swollman
6542742Swollman/* turn the BIOS video number into our video mode number */
6552742Swollmanstatic int
6562742Swollmanmap_bios_mode_num(int type, int color, int bios_mode)
6572742Swollman{
6582742Swollman    static int cga_modes[7] = {
6592742Swollman	M_B40x25, M_C40x25,		/* 0, 1 */
6602742Swollman	M_B80x25, M_C80x25,		/* 2, 3 */
6612742Swollman	M_BG320, M_CG320,
6622742Swollman	M_BG640,
6632742Swollman    };
664149514Swollman    static int ega_modes[17] = {
665149514Swollman	M_ENH_B40x25, M_ENH_C40x25,	/* 0, 1 */
666149514Swollman	M_ENH_B80x25, M_ENH_C80x25,	/* 2, 3 */
66730711Swollman	M_BG320, M_CG320,
6682742Swollman	M_BG640,
6692742Swollman	M_EGAMONO80x25,			/* 7 */
67043543Swollman	8, 9, 10, 11, 12,
67143543Swollman	M_CG320_D,
67243543Swollman	M_CG640_E,
67343543Swollman	M_ENHMONOAPA2,			/* XXX: video momery > 64K */
67443543Swollman	M_ENH_CG640,			/* XXX: video momery > 64K */
67543543Swollman    };
67643543Swollman    static int vga_modes[20] = {
67764499Swollman	M_VGA_C40x25, M_VGA_C40x25,	/* 0, 1 */
67864499Swollman	M_VGA_C80x25, M_VGA_C80x25,	/* 2, 3 */
67943543Swollman	M_BG320, M_CG320,
68064499Swollman	M_BG640,
68164499Swollman	M_VGA_M80x25,			/* 7 */
68264499Swollman	8, 9, 10, 11, 12,
68364499Swollman	M_CG320_D,
68464499Swollman	M_CG640_E,
68564499Swollman	M_ENHMONOAPA2,
68664499Swollman	M_ENH_CG640,
68764499Swollman	M_BG640x480, M_CG640x480,
68864499Swollman	M_VGA_CG320,
68964499Swollman    };
6902742Swollman
6912742Swollman    switch (type) {
6922742Swollman
69319878Swollman    case KD_VGA:
6942742Swollman	if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0]))
69519878Swollman	    return vga_modes[bios_mode];
6962742Swollman	else if (color)
69719878Swollman	    return M_VGA_C80x25;
6982742Swollman	else
69919878Swollman	    return M_VGA_M80x25;
7002742Swollman	break;
70119878Swollman
7022742Swollman    case KD_EGA:
70314343Swollman	if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0]))
70414343Swollman	    return ega_modes[bios_mode];
70530711Swollman	else if (color)
7062742Swollman	    return M_ENH_C80x25;
70775267Swollman	else
70819878Swollman	    return M_EGAMONO80x25;
70919878Swollman	break;
71019878Swollman
71119878Swollman    case KD_CGA:
7122742Swollman	if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0]))
71330711Swollman	    return cga_modes[bios_mode];
71430711Swollman	else
71543014Swollman	    return M_C80x25;
71614343Swollman	break;
717149514Swollman
71814343Swollman    case KD_MONO:
71943014Swollman    case KD_HERCULES:
72030711Swollman	return M_EGAMONO80x25;		/* XXX: this name is confusing */
72158787Sru
72243014Swollman    default:
723149514Swollman	break;
72443014Swollman    }
72558787Sru    return -1;
7269908Swollman}
72714343Swollman
72830711Swollman/* look up a parameter table entry */
72919878Swollmanstatic u_char
73030711Swollman*get_mode_param(int mode)
73130711Swollman{
73230711Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
73343014Swollman    if (mode >= V_MODE_MAP_SIZE)
73443543Swollman	mode = map_mode_num(mode);
73543543Swollman#endif
73614343Swollman    if ((mode >= 0) && (mode < V_MODE_MAP_SIZE))
73764499Swollman	return mode_map[mode];
73864499Swollman    else
73964499Swollman	return NULL;
74058787Sru}
74164499Swollman
74258787Sru#ifndef VGA_NO_BIOS
743149514Swollmanstatic void
74464499Swollmanfill_adapter_param(int code, video_adapter_t *adp)
74564499Swollman{
74664499Swollman    static struct {
74764499Swollman	int primary;
748149514Swollman	int secondary;
74943014Swollman    } dcc[] = {
75058787Sru	{ DCC_MONO, 			DCC_EGA40 /* CGA monitor */ },
75158787Sru	{ DCC_MONO, 			DCC_EGA80 /* CGA monitor */ },
75264499Swollman	{ DCC_MONO, 			DCC_EGA80 /* CGA emulation */ },
75364499Swollman	{ DCC_MONO, 			DCC_EGA80 },
75464499Swollman	{ DCC_CGA40, 			DCC_EGAMONO },
75564499Swollman	{ DCC_CGA80, 			DCC_EGAMONO },
75664499Swollman	{ DCC_EGA40 /* CGA monitor */, 	DCC_MONO},
75764499Swollman	{ DCC_EGA80 /* CGA monitor */, 	DCC_MONO},
75864499Swollman	{ DCC_EGA80 /* CGA emulation */,DCC_MONO },
75964499Swollman	{ DCC_EGA80, 			DCC_MONO },
76064499Swollman	{ DCC_EGAMONO, 			DCC_CGA40 },
76158787Sru	{ DCC_EGAMONO, 			DCC_CGA40 },
762149514Swollman    };
763149514Swollman
764149514Swollman    if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) {
765149514Swollman	adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
766149514Swollman	adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
767149514Swollman    } else {
768149514Swollman	adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary];
769149514Swollman	adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary];
770149514Swollman    }
77130711Swollman}
772149514Swollman#endif /* VGA_NO_BIOS */
773149514Swollman
774149514Swollmanstatic int
775149514Swollmanverify_adapter(video_adapter_t *adp)
776149514Swollman{
777149514Swollman    vm_offset_t buf;
778149514Swollman    u_int16_t v;
779149514Swollman
780149514Swollman    buf = BIOS_PADDRTOVADDR(adp->va_window);
781149514Swollman    v = readw(buf);
782149514Swollman    writew(buf, 0xA55A);
783149514Swollman    if (readw(buf) != 0xA55A)
784149514Swollman	return 1;
785149514Swollman    writew(buf, v);
786149514Swollman
787149514Swollman    switch (adp->va_type) {
788149514Swollman
789149514Swollman    case KD_EGA:
790149514Swollman	outb(adp->va_crtc_addr, 7);
791149514Swollman	if (inb(adp->va_crtc_addr) == 7) {
792149514Swollman	    adp->va_type = KD_VGA;
793149514Swollman	    adp->va_name = "vga";
794149514Swollman	    adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE;
795149514Swollman	}
796149514Swollman	adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER;
797149514Swollman	/* the color adapter may be in the 40x25 mode... XXX */
798149514Swollman
799149514Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
800149514Swollman	/* get the BIOS video mode pointer */
801149514Swollman	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8);
802149514Swollman	p = BIOS_SADDRTOLADDR(p);
803149514Swollman	if (ISMAPPED(p, sizeof(u_int32_t))) {
804149514Swollman	    p = *(u_int32_t *)BIOS_PADDRTOVADDR(p);
805149514Swollman	    p = BIOS_SADDRTOLADDR(p);
806149514Swollman	    if (ISMAPPED(p, V_MODE_PARAM_SIZE))
807149514Swollman		video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p);
808149514Swollman	}
809149514Swollman#endif
810149514Swollman	break;
811149514Swollman
812149514Swollman    case KD_CGA:
813149514Swollman	adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER;
814149514Swollman	/* may be in the 40x25 mode... XXX */
815149514Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
816149514Swollman	/* get the BIOS video mode pointer */
817149514Swollman	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
818149514Swollman	p = BIOS_SADDRTOLADDR(p);
819149514Swollman	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
820149514Swollman#endif
821149514Swollman	break;
822149514Swollman
823149514Swollman    case KD_MONO:
824149514Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
825149514Swollman	/* get the BIOS video mode pointer */
826149514Swollman	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
827149514Swollman	p = BIOS_SADDRTOLADDR(p);
828149514Swollman	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
829149514Swollman#endif
830149514Swollman	break;
8312742Swollman    }
83214343Swollman
83319878Swollman    return 0;
8342742Swollman}
8352742Swollman
8362742Swollmanstatic void
837105196Swollmanupdate_adapter_info(video_adapter_t *adp, video_info_t *info)
8382742Swollman{
8392742Swollman    adp->va_flags &= ~V_ADP_COLOR;
8402742Swollman    adp->va_flags |=
8412742Swollman	(info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
8422742Swollman    adp->va_crtc_addr =
8432742Swollman	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
844149514Swollman    adp->va_window = BIOS_PADDRTOVADDR(info->vi_window);
8459908Swollman    adp->va_window_size = info->vi_window_size;
8469908Swollman    adp->va_window_gran = info->vi_window_gran;
8479908Swollman    if (info->vi_buffer_size == 0) {
848149590Swollman    	adp->va_buffer = 0;
849149590Swollman    	adp->va_buffer_size = 0;
850149590Swollman    } else {
851149590Swollman    	adp->va_buffer = BIOS_PADDRTOVADDR(info->vi_buffer);
852149590Swollman    	adp->va_buffer_size = info->vi_buffer_size;
853149590Swollman    }
854149590Swollman    if (info->vi_flags & V_INFO_GRAPHICS)
855149590Swollman	adp->va_line_width = info->vi_width/8;
856149590Swollman    else
857149590Swollman	adp->va_line_width = info->vi_width;
858149590Swollman    bcopy(info, &adp->va_info, sizeof(adp->va_info));
859149590Swollman}
860158421Swollman
861158421Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
8629908Swollman/* compare two parameter table entries */
863149590Swollmanstatic int
864149590Swollmancomp_adpregs(u_char *buf1, u_char *buf2)
865149590Swollman{
866149590Swollman    static struct {
867149590Swollman        u_char mask;
868158421Swollman    } params[V_MODE_PARAM_SIZE] = {
869149590Swollman	0xff, 0x00, 0xff, 		/* COLS, ROWS, POINTS */
870149590Swollman	0x00, 0x00, 			/* page length */
8712742Swollman	0xfe, 0xff, 0xff, 0xff,		/* sequencer registers */
87243543Swollman	0xf3,				/* misc register */
87343543Swollman	0xff, 0xff, 0xff, 0x7f, 0xff,	/* CRTC */
87443543Swollman	0xff, 0xff, 0xff, 0x7f, 0xff,
87543543Swollman	0x00, 0x00, 0x00, 0x00, 0x00,
87643543Swollman	0x00, 0xff, 0x7f, 0xff, 0xff,
87743543Swollman	0x7f, 0xff, 0xff, 0xef, 0xff,
87843543Swollman	0xff, 0xff, 0xff, 0xff, 0xff,	/* attribute controller registers */
87943543Swollman	0xff, 0xff, 0xff, 0xff, 0xff,
88043543Swollman	0xff, 0xff, 0xff, 0xff, 0xff,
88143543Swollman	0xff, 0xff, 0xff, 0xff, 0xf0,
88243543Swollman	0xff, 0xff, 0xff, 0xff, 0xff,	/* GDC register */
88343543Swollman	0xff, 0xff, 0xff, 0xff,
88443543Swollman    };
88543543Swollman    int identical = TRUE;
88643543Swollman    int i;
88743543Swollman
88843543Swollman    if ((buf1 == NULL) || (buf2 == NULL))
88943543Swollman	return COMP_DIFFERENT;
89043543Swollman
89143543Swollman    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
89243543Swollman	if (params[i].mask == 0)	/* don't care */
893158421Swollman	    continue;
894158421Swollman	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
895158421Swollman	    return COMP_DIFFERENT;
89643543Swollman	if (buf1[i] != buf2[i])
8972742Swollman	    identical = FALSE;
89843543Swollman    }
89943543Swollman    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
90043543Swollman}
901149590Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
90243543Swollman
9032742Swollman/* probe video adapters and return the number of detected adapters */
9042742Swollmanstatic int
90558787Sruprobe_adapters(void)
90658787Sru{
90758787Sru    video_adapter_t *adp;
90858787Sru    video_info_t info;
90958787Sru    int i;
91058787Sru
91158787Sru    /* do this test only once */
91258787Sru    if (init_done)
91358787Sru	return biosadapters;
91458787Sru    init_done = TRUE;
91558787Sru
91658787Sru    /*
91758787Sru     * Locate display adapters.
91858787Sru     * The AT architecture supports upto two adapters. `syscons' allows
919153670Swollman     * the following combinations of adapters:
920153670Swollman     *     1) MDA + CGA
921153670Swollman     *     2) MDA + EGA/VGA color
922158421Swollman     *     3) CGA + EGA/VGA mono
923158421Swollman     * Note that `syscons' doesn't bother with MCGA as it is only
924158421Swollman     * avaiable for low end PS/2 models which has 80286 or earlier CPUs,
925158421Swollman     * thus, they are not running FreeBSD!
9262742Swollman     * When there are two adapaters in the system, one becomes `primary'
92775267Swollman     * and the other `secondary'. The EGA adapter has a set of DIP
92875267Swollman     * switches on board for this information and the EGA BIOS copies
92975267Swollman     * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88).
93075267Swollman     * The VGA BIOS has more sophisticated mechanism and has this
93175267Swollman     * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains
93275267Swollman     * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH.
93375267Swollman     */
93475267Swollman
93575267Swollman    /*
93675267Swollman     * Check rtc and BIOS data area.
93775267Swollman     * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead
93875267Swollman     * copy of RTC_EQUIPMENT.  Bits 4 and 5 of ETC_EQUIPMENT are
93975267Swollman     * zeros for EGA and VGA.  However, the EGA/VGA BIOS sets
94075267Swollman     * these bits in BIOSDATA_EQUIPMENT according to the monitor
94175267Swollman     * type detected.
94275267Swollman     */
94375267Swollman#ifndef VGA_NO_BIOS
94475267Swollman    switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
94575267Swollman    case 0:
94675267Swollman	/* EGA/VGA */
94758787Sru	fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
948153670Swollman			   biosadapter);
94958787Sru	break;
950153670Swollman    case 1:
951153670Swollman	/* CGA 40x25 */
952153670Swollman	/* FIXME: switch to the 80x25 mode? XXX */
9532742Swollman	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40];
9542742Swollman	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
95519878Swollman	break;
9562742Swollman    case 2:
957149514Swollman	/* CGA 80x25 */
9582742Swollman	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80];
959149514Swollman	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
96020094Swollman	break;
961149514Swollman    case 3:
96220094Swollman	/* MDA */
96320094Swollman	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
96420094Swollman	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
96520094Swollman	break;
966149514Swollman    }
967158421Swollman#else
96893799Swollman    /* assume EGA/VGA? XXX */
96993799Swollman    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80];
970158421Swollman    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
971158421Swollman#endif /* VGA_NO_BIOS */
97293799Swollman
97393799Swollman    biosadapters = 0;
97493799Swollman    if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) {
97593799Swollman	++biosadapters;
976149514Swollman	biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED;
977149514Swollman	biosadapter[V_ADP_SECONDARY].va_mode =
978149514Swollman	    biosadapter[V_ADP_SECONDARY].va_initial_mode =
979149514Swollman	    map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type,
980149514Swollman			      biosadapter[V_ADP_SECONDARY].va_flags
981149514Swollman				  & V_ADP_COLOR,
982149514Swollman			      biosadapter[V_ADP_SECONDARY].va_initial_bios_mode);
98393799Swollman    } else {
984149514Swollman	biosadapter[V_ADP_SECONDARY].va_type = -1;
985149514Swollman    }
986149514Swollman    if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) {
987149514Swollman	++biosadapters;
988149514Swollman	biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED;
989149514Swollman#ifndef VGA_NO_BIOS
990149514Swollman	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode =
991149514Swollman	    readb(BIOS_PADDRTOVADDR(0x449));
992149514Swollman#else
993149514Swollman	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3;	/* XXX */
994114173Swollman#endif
9952742Swollman	biosadapter[V_ADP_PRIMARY].va_mode =
99693799Swollman	    biosadapter[V_ADP_PRIMARY].va_initial_mode =
99793799Swollman	    map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type,
99843014Swollman			      biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR,
99993799Swollman			      biosadapter[V_ADP_PRIMARY].va_initial_bios_mode);
100093799Swollman    } else {
100193799Swollman	biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY];
1002149514Swollman	biosadapter[V_ADP_SECONDARY].va_type = -1;
1003149514Swollman    }
100493799Swollman    if (biosadapters == 0)
100593799Swollman	return biosadapters;
100693799Swollman    biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY;
100793799Swollman    biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY;
100893799Swollman
100993799Swollman#if 0 /* we don't need these... */
101093799Swollman    fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...);
101193799Swollman    fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...);
101293799Swollman#endif
1013149514Swollman
1014149514Swollman#if 0
101593799Swollman    /*
101620094Swollman     * We cannot have two video adapter of the same type; there must be
101793799Swollman     * only one of color or mono adapter, or one each of them.
101893799Swollman     */
101993799Swollman    if (biosadapters > 1) {
102093799Swollman	if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags)
102193799Swollman	      & V_ADP_COLOR))
102293799Swollman	    /* we have two mono or color adapters!! */
1023149514Swollman	    return (biosadapters = 0);
1024149514Swollman    }
102593799Swollman#endif
102693799Swollman
102793799Swollman    /*
102893799Swollman     * Ensure a zero start address.  This is mainly to recover after
102993799Swollman     * switching from pcvt using userconfig().  The registers are w/o
103093799Swollman     * for old hardware so it's too hard to relocate the active screen
103193799Swollman     * memory.
103293799Swollman     * This must be done before vga_save_state() for VGA.
103393799Swollman     */
103493799Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12);
1035121098Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
1036149514Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13);
1037149514Swollman    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
103893799Swollman
103993799Swollman    /* the video mode parameter table in EGA/VGA BIOS */
104093799Swollman    /* NOTE: there can be only one EGA/VGA, wheather color or mono,
104193799Swollman     * recognized by the video BIOS.
104293799Swollman     */
104393799Swollman    if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) ||
104493799Swollman	(biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) {
104593799Swollman	adp = &biosadapter[V_ADP_PRIMARY];
104693799Swollman    } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) ||
1047149514Swollman	       (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) {
1048149514Swollman	adp = &biosadapter[V_ADP_SECONDARY];
10492742Swollman    } else {
105067578Swollman	adp = NULL;
1051158421Swollman    }
1052149514Swollman    bzero(mode_map, sizeof(mode_map));
1053149514Swollman    if (adp != NULL) {
1054149514Swollman	if (adp->va_type == KD_VGA) {
1055149514Swollman	    vga_save_state(adp, &adpstate, sizeof(adpstate));
1056149514Swollman#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
1057149514Swollman	    mode_map[adp->va_initial_mode] = adpstate.regs;
1058153670Swollman	    rows_offset = 1;
1059153670Swollman#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1060153670Swollman	    if (video_mode_ptr == NULL) {
1061149514Swollman		mode_map[adp->va_initial_mode] = adpstate.regs;
106220094Swollman		rows_offset = 1;
1063153670Swollman	    } else {
1064153670Swollman		/* discard the table if we are not familiar with it... */
1065153670Swollman		map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
1066153670Swollman		mp = get_mode_param(adp->va_initial_mode);
10679908Swollman		if (mp != NULL)
10689908Swollman		    bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs));
106943014Swollman		switch (comp_adpregs(adpstate.regs, mp)) {
107019878Swollman		case COMP_IDENTICAL:
107158787Sru		    /*
1072153670Swollman		     * OK, this parameter table looks reasonably familiar
1073153670Swollman		     * to us...
10749908Swollman		     */
10752742Swollman		    /*
10762742Swollman		     * This is a kludge for Toshiba DynaBook SS433
107743014Swollman		     * whose BIOS video mode table entry has the actual #
10782742Swollman		     * of rows at the offset 1; BIOSes from other
10792742Swollman		     * manufacturers store the # of rows - 1 there. XXX
10802742Swollman		     */
10812742Swollman		    rows_offset = adpstate.regs[1] + 1 - mp[1];
10822742Swollman		    break;
10832742Swollman
1084158421Swollman		case COMP_SIMILAR:
10852742Swollman		    /*
10862742Swollman		     * Not exactly the same, but similar enough to be
10872742Swollman		     * trusted. However, use the saved register values
1088158421Swollman		     * for the initial mode and other modes which are
1089158421Swollman		     * based on the initial mode.
10902742Swollman		     */
10912742Swollman		    mode_map[adp->va_initial_mode] = adpstate.regs;
10922742Swollman		    rows_offset = adpstate.regs[1] + 1 - mp[1];
10932742Swollman		    adpstate.regs[1] -= rows_offset - 1;
10942742Swollman		    break;
10952742Swollman
10962742Swollman		case COMP_DIFFERENT:
10972742Swollman		default:
10982742Swollman		    /*
10992742Swollman		     * Don't use the paramter table in BIOS. It doesn't
11002742Swollman		     * look familiar to us. Video mode switching is allowed
11012742Swollman		     * only if the new mode is the same as or based on
11022742Swollman		     * the initial mode.
11032742Swollman		     */
11042742Swollman		    video_mode_ptr = NULL;
11052742Swollman		    bzero(mode_map, sizeof(mode_map));
11062742Swollman		    mode_map[adp->va_initial_mode] = adpstate.regs;
11072742Swollman		    rows_offset = 1;
11082742Swollman		    break;
11092742Swollman		}
11102742Swollman	    }
11112742Swollman#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
11122742Swollman
11132742Swollman#ifndef VGA_NO_MODE_CHANGE
11142742Swollman	    adp->va_flags |= V_ADP_MODECHANGE;
11152742Swollman#endif
11162742Swollman#ifndef VGA_NO_FONT_LOADING
111767578Swollman	    adp->va_flags |= V_ADP_FONT;
111819878Swollman#endif
11192742Swollman	} else if (adp->va_type == KD_EGA) {
11202742Swollman#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
11212742Swollman	    rows_offset = 1;
11222742Swollman#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
11232742Swollman	    if (video_mode_ptr == NULL) {
11242742Swollman		rows_offset = 1;
112519878Swollman	    } else {
11262742Swollman		map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1);
112719878Swollman		/* XXX how can one validate the EGA table... */
11282742Swollman		mp = get_mode_param(adp->va_initial_mode);
112919878Swollman		if (mp != NULL) {
11302742Swollman		    adp->va_flags |= V_ADP_MODECHANGE;
113119878Swollman#ifndef VGA_NO_FONT_LOADING
11322742Swollman		    adp->va_flags |= V_ADP_FONT;
113319878Swollman#endif
11342742Swollman		    rows_offset = 1;
113519878Swollman		} else {
11362742Swollman		    /*
113719878Swollman		     * This is serious. We will not be able to switch video
113819878Swollman		     * modes at all...
11392742Swollman		     */
114019878Swollman		    video_mode_ptr = NULL;
114120094Swollman		    bzero(mode_map, sizeof(mode_map));
114219878Swollman		    rows_offset = 1;
114319878Swollman                }
114420094Swollman	    }
114520094Swollman#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
114620094Swollman	}
114758787Sru    }
114858787Sru
11492742Swollman    /* remove conflicting modes if we have more than one adapter */
11502742Swollman    if (biosadapters > 1) {
115119878Swollman	for (i = 0; i < biosadapters; ++i) {
11522742Swollman	    if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE))
11532742Swollman		continue;
115419878Swollman	    clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1,
115586222Swollman			   (biosadapter[i].va_flags & V_ADP_COLOR) ?
115619878Swollman			       V_INFO_COLOR : 0);
115786222Swollman	    if ((biosadapter[i].va_type == KD_VGA)
1158136638Swollman		|| (biosadapter[i].va_type == KD_EGA)) {
1159136638Swollman		biosadapter[i].va_io_base =
1160136638Swollman		    (biosadapter[i].va_flags & V_ADP_COLOR) ?
11612742Swollman			IO_VGA : IO_MDA;
1162136638Swollman		biosadapter[i].va_io_size = 32;
1163136638Swollman	    }
1164136638Swollman	}
1165136638Swollman    }
1166136638Swollman
1167136638Swollman    /* buffer address */
1168136638Swollman    vga_get_info(&biosadapter[V_ADP_PRIMARY],
1169136638Swollman		 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info);
117019878Swollman    update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info);
117186222Swollman
1172158421Swollman    if (biosadapters > 1) {
1173158421Swollman	vga_get_info(&biosadapter[V_ADP_SECONDARY],
1174136638Swollman		     biosadapter[V_ADP_SECONDARY].va_initial_mode, &info);
1175136638Swollman	update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info);
117619878Swollman    }
117719878Swollman
1178136638Swollman    /*
1179136638Swollman     * XXX: we should verify the following values for the primary adapter...
1180136638Swollman     * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
118119878Swollman     * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
11822742Swollman     *                     ? 0 : V_ADP_COLOR;
11832742Swollman     * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
11842742Swollman     * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
118519878Swollman     * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
118619878Swollman     * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
118719878Swollman     */
11882742Swollman
11892742Swollman    return biosadapters;
119058787Sru}
1191158421Swollman
1192158421Swollman/* entry points */
119317200Swollman
119458787Srustatic int
119558787Sruvga_nop(void)
119658787Sru{
119758787Sru    return 0;
119858787Sru}
119958787Sru
120058787Srustatic int
120158787Sruvga_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
120258787Sru{
120358787Sru    probe_adapters();
120458787Sru    if (unit >= biosadapters)
120558787Sru	return ENXIO;
120658787Sru
120758787Sru    *adpp = &biosadapter[unit];
120858787Sru
120958787Sru    return 0;
121058787Sru}
121158787Sru
121258787Srustatic int
121358787Sruvga_init(int unit, video_adapter_t *adp, int flags)
121458787Sru{
121558787Sru    if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp))
121658787Sru	return ENXIO;
121758787Sru
121858787Sru    if (!init_done(adp)) {
121958787Sru	/* nothing to do really... */
122086222Swollman	adp->va_flags |= V_ADP_INITIALIZED;
122186222Swollman    }
122286222Swollman
122386222Swollman    if (!config_done(adp)) {
122486222Swollman	if (vid_register(adp) < 0)
122586222Swollman		return ENXIO;
122686222Swollman	adp->va_flags |= V_ADP_REGISTERED;
122786222Swollman    }
122886222Swollman    if (vga_sub_configure != NULL)
122986222Swollman	(*vga_sub_configure)(0);
123086222Swollman
123186222Swollman    return 0;
1232149514Swollman}
1233136638Swollman
1234136638Swollman/*
1235136638Swollman * get_info():
1236136638Swollman * Return the video_info structure of the requested video mode.
1237136638Swollman *
1238136638Swollman * all adapters
1239136638Swollman */
1240136638Swollmanstatic int
1241149514Swollmanvga_get_info(video_adapter_t *adp, int mode, video_info_t *info)
1242149514Swollman{
1243149514Swollman    int i;
1244149514Swollman
1245149514Swollman    if (!init_done)
1246149514Swollman	return 1;
1247149514Swollman
1248149514Swollman    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
1249149514Swollman#ifndef VGA_NO_MODE_CHANGE
1250149514Swollman    if (adp->va_flags & V_ADP_MODECHANGE) {
1251149514Swollman	/*
1252149514Swollman	 * If the parameter table entry for this mode is not found,
1253149514Swollman	 * the mode is not supported...
1254149514Swollman	 */
1255149514Swollman	if (get_mode_param(mode) == NULL)
1256149514Swollman	    return 1;
1257149514Swollman    } else
1258149514Swollman#endif /* VGA_NO_MODE_CHANGE */
12592742Swollman    {
126086222Swollman	/*
126186222Swollman	 * Even if we don't support video mode switching on this adapter,
1262158421Swollman	 * the information on the initial (thus current) video mode
1263158421Swollman	 * should be made available.
1264158421Swollman	 */
1265158421Swollman	if (mode != adp->va_initial_mode)
1266158421Swollman	    return 1;
1267158421Swollman    }
1268158421Swollman
1269158421Swollman    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1270158421Swollman	if (bios_vmode[i].vi_mode == NA)
1271158421Swollman	    continue;
1272158421Swollman	if (mode == bios_vmode[i].vi_mode) {
1273158421Swollman	    *info = bios_vmode[i];
1274158421Swollman	    return 0;
127558787Sru	}
1276136638Swollman    }
1277136638Swollman    return 1;
1278136638Swollman}
127958787Sru
12802742Swollman/*
128186222Swollman * query_mode():
128258787Sru * Find a video mode matching the requested parameters.
128358787Sru * Fields filled with 0 are considered "don't care" fields and
128458787Sru * match any modes.
128586222Swollman *
128658787Sru * all adapters
128758787Sru */
128819878Swollmanstatic int
128986222Swollmanvga_query_mode(video_adapter_t *adp, video_info_t *info)
129086222Swollman{
129186222Swollman    video_info_t buf;
129286222Swollman    int i;
129386222Swollman
129486222Swollman    if (!init_done)
12952742Swollman	return -1;
12962742Swollman
12972742Swollman    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
12982742Swollman	if (bios_vmode[i].vi_mode == NA)
12992742Swollman	    continue;
130019878Swollman
13012742Swollman	if ((info->vi_width != 0)
13022742Swollman	    && (info->vi_width != bios_vmode[i].vi_width))
13032742Swollman		continue;
13042742Swollman	if ((info->vi_height != 0)
13052742Swollman	    && (info->vi_height != bios_vmode[i].vi_height))
13062742Swollman		continue;
13072742Swollman	if ((info->vi_cwidth != 0)
130893799Swollman	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
130993799Swollman		continue;
131093799Swollman	if ((info->vi_cheight != 0)
131193799Swollman	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
131293799Swollman		continue;
131393799Swollman	if ((info->vi_depth != 0)
131493799Swollman	    && (info->vi_depth != bios_vmode[i].vi_depth))
131593799Swollman		continue;
131693799Swollman	if ((info->vi_planes != 0)
131793799Swollman	    && (info->vi_planes != bios_vmode[i].vi_planes))
131893799Swollman		continue;
131993799Swollman	/* XXX: should check pixel format, memory model */
132093799Swollman	if ((info->vi_flags != 0)
132193799Swollman	    && (info->vi_flags != bios_vmode[i].vi_flags))
132293799Swollman		continue;
132393799Swollman
132493799Swollman	/* verify if this mode is supported on this adapter */
132593799Swollman	if (vga_get_info(adp, bios_vmode[i].vi_mode, &buf))
132693799Swollman		continue;
132793799Swollman	return bios_vmode[i].vi_mode;
1328114173Swollman    }
1329114173Swollman    return -1;
1330114173Swollman}
1331114173Swollman
1332114173Swollman/*
1333114173Swollman * set_mode():
1334114173Swollman * Change the video mode.
1335114173Swollman *
1336114173Swollman * EGA/VGA
1337114173Swollman */
1338114173Swollmanstatic int
1339114173Swollmanvga_set_mode(video_adapter_t *adp, int mode)
1340114173Swollman{
1341114173Swollman#ifndef VGA_NO_MODE_CHANGE
1342114173Swollman    video_info_t info;
1343114173Swollman    adp_state_t params;
1344114173Swollman
134593799Swollman    prologue(adp, V_ADP_MODECHANGE, 1);
1346114173Swollman
1347114173Swollman    mode = map_gen_mode_num(adp->va_type,
13482742Swollman			    adp->va_flags & V_ADP_COLOR, mode);
13492742Swollman    if (vga_get_info(adp, mode, &info))
13502742Swollman	return 1;
13512742Swollman    params.sig = V_STATE_SIG;
13522742Swollman    bcopy(get_mode_param(mode), params.regs, sizeof(params.regs));
135319878Swollman
135493799Swollman    switch (mode) {
13552742Swollman    case M_VGA_C80x60: case M_VGA_M80x60:
13562742Swollman	params.regs[2]  = 0x08;
135743014Swollman	params.regs[19] = 0x47;
1358149514Swollman	goto special_480l;
135943014Swollman
136043014Swollman    case M_VGA_C80x30: case M_VGA_M80x30:
136143014Swollman	params.regs[19] = 0x4f;
136243014Swollmanspecial_480l:
136343014Swollman	params.regs[9] |= 0xc0;
136443014Swollman	params.regs[16] = 0x08;
136543014Swollman	params.regs[17] = 0x3e;
136643014Swollman	params.regs[26] = 0xea;
136743014Swollman	params.regs[28] = 0xdf;
136843014Swollman	params.regs[31] = 0xe7;
136943014Swollman	params.regs[32] = 0x04;
137043014Swollman	goto setup_mode;
137143014Swollman
137243014Swollman    case M_ENH_C80x43: case M_ENH_B80x43:
137343014Swollman	params.regs[28] = 87;
137443014Swollman	goto special_80x50;
137543014Swollman
137643014Swollman    case M_VGA_C80x50: case M_VGA_M80x50:
137743014Swollmanspecial_80x50:
137843014Swollman	params.regs[2] = 8;
137943014Swollman	params.regs[19] = 7;
138043014Swollman	goto setup_mode;
138143014Swollman
138243014Swollman    case M_VGA_C40x25: case M_VGA_C80x25:
138343014Swollman    case M_VGA_M80x25:
138443014Swollman    case M_B40x25:     case M_C40x25:
138543014Swollman    case M_B80x25:     case M_C80x25:
138643014Swollman    case M_ENH_B40x25: case M_ENH_C40x25:
138743014Swollman    case M_ENH_B80x25: case M_ENH_C80x25:
138843014Swollman    case M_EGAMONO80x25:
138943014Swollman
139043014Swollmansetup_mode:
139143014Swollman	vga_load_state(adp, &params);
139243014Swollman	break;
139343014Swollman
139443014Swollman    case M_VGA_MODEX:
139543014Swollman	/* "unchain" the VGA mode */
139643014Swollman	params.regs[5-1+0x04] &= 0xf7;
139743014Swollman	params.regs[5-1+0x04] |= 0x04;
139843014Swollman	/* turn off doubleword mode */
139943014Swollman	params.regs[10+0x14] &= 0xbf;
1400158421Swollman	/* turn off word adressing */
1401158421Swollman	params.regs[10+0x17] |= 0x40;
140243014Swollman	/* set logical screen width */
140343014Swollman	params.regs[10+0x13] = 80;
140443014Swollman	/* set 240 lines */
140543014Swollman	params.regs[10+0x11] = 0x2c;
140643014Swollman	params.regs[10+0x06] = 0x0d;
140743014Swollman	params.regs[10+0x07] = 0x3e;
140843014Swollman	params.regs[10+0x10] = 0xea;
140943014Swollman	params.regs[10+0x11] = 0xac;
141043014Swollman	params.regs[10+0x12] = 0xdf;
141143014Swollman	params.regs[10+0x15] = 0xe7;
141243014Swollman	params.regs[10+0x16] = 0x06;
141343014Swollman	/* set vertical sync polarity to reflect aspect ratio */
141443014Swollman	params.regs[9] = 0xe3;
141543014Swollman	goto setup_grmode;
141643014Swollman
141743014Swollman    case M_BG320:     case M_CG320:     case M_BG640:
141843014Swollman    case M_CG320_D:   case M_CG640_E:
141943014Swollman    case M_CG640x350: case M_ENH_CG640:
142058787Sru    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
142158787Sru
142258787Srusetup_grmode:
142358787Sru	vga_load_state(adp, &params);
142458787Sru	break;
142558787Sru
142658787Sru    default:
142758787Sru	return 1;
142858787Sru    }
142958787Sru
1430153670Swollman    adp->va_mode = mode;
1431153670Swollman    update_adapter_info(adp, &info);
1432153670Swollman
1433158421Swollman    /* move hardware cursor out of the way */
1434158421Swollman    (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
1435158421Swollman
1436158421Swollman    return 0;
1437158421Swollman#else /* VGA_NO_MODE_CHANGE */
1438158421Swollman    return 1;
143958787Sru#endif /* VGA_NO_MODE_CHANGE */
14402742Swollman}
144119878Swollman
144217200Swollman#ifndef VGA_NO_FONT_LOADING
144319878Swollman
144420094Swollmanstatic void
144517200Swollmanset_font_mode(video_adapter_t *adp, u_char *buf)
144620094Swollman{
144758787Sru    u_char *mp;
144858787Sru    int s;
1449153670Swollman
1450153670Swollman    s = splhigh();
1451158421Swollman
145258787Sru    /* save register values */
14532742Swollman    if (adp->va_type == KD_VGA) {
14542742Swollman	outb(TSIDX, 0x02); buf[0] = inb(TSREG);
145543014Swollman	outb(TSIDX, 0x04); buf[1] = inb(TSREG);
145643014Swollman	outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
145743014Swollman	outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
145858787Sru	outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
145958787Sru	inb(adp->va_crtc_addr + 6);
14602742Swollman	outb(ATC, 0x10); buf[5] = inb(ATC + 1);
146114343Swollman    } else /* if (adp->va_type == KD_EGA) */ {
146214343Swollman	/*
146314343Swollman	 * EGA cannot be read; copy parameters from the mode parameter
14642742Swollman	 * table.
146575267Swollman	 */
146675267Swollman	mp = get_mode_param(adp->va_mode);
146775267Swollman	buf[0] = mp[5 + 0x02 - 1];
146875267Swollman	buf[1] = mp[5 + 0x04 - 1];
1469158421Swollman	buf[2] = mp[55 + 0x04];
1470158421Swollman	buf[3] = mp[55 + 0x05];
1471158421Swollman	buf[4] = mp[55 + 0x06];
1472158421Swollman	buf[5] = mp[35 + 0x10];
1473158421Swollman    }
1474158421Swollman
1475158421Swollman    /* setup vga for loading fonts */
1476158421Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1477158421Swollman    outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
1478158421Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1479158421Swollman    outb(ATC, 0x20);				/* enable palette */
1480158421Swollman
1481158421Swollman#if VGA_SLOW_IOACCESS
1482158421Swollman#ifdef VGA_ALT_SEQACCESS
1483158421Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x01);
14842742Swollman#endif
148519878Swollman    outb(TSIDX, 0x02); outb(TSREG, 0x04);
148619878Swollman    outb(TSIDX, 0x04); outb(TSREG, 0x07);
148719878Swollman#ifdef VGA_ALT_SEQACCESS
148819878Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x03);
148919878Swollman#endif
149019878Swollman    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
14912742Swollman    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
149275267Swollman    outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
14932742Swollman#else /* VGA_SLOW_IOACCESS */
149419878Swollman#ifdef VGA_ALT_SEQACCESS
14952742Swollman    outw(TSIDX, 0x0100);
149619878Swollman#endif
14972742Swollman    outw(TSIDX, 0x0402);
14982742Swollman    outw(TSIDX, 0x0704);
14992742Swollman#ifdef VGA_ALT_SEQACCESS
150067578Swollman    outw(TSIDX, 0x0300);
15012742Swollman#endif
15022742Swollman    outw(GDCIDX, 0x0204);
15032742Swollman    outw(GDCIDX, 0x0005);
15042742Swollman    outw(GDCIDX, 0x0406);               /* addr = a0000, 64kb */
15052742Swollman#endif /* VGA_SLOW_IOACCESS */
15062742Swollman
15072742Swollman    splx(s);
15082742Swollman}
15092742Swollman
1510136638Swollmanstatic void
1511136638Swollmanset_normal_mode(video_adapter_t *adp, u_char *buf)
15122742Swollman{
1513136638Swollman    int s;
1514136638Swollman
1515136638Swollman    s = splhigh();
1516136638Swollman
1517136638Swollman    /* setup vga for normal operation mode again */
1518136638Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1519136638Swollman    outb(ATC, 0x10); outb(ATC, buf[5]);
152019878Swollman    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1521136638Swollman    outb(ATC, 0x20);				/* enable palette */
15222742Swollman
15232742Swollman#if VGA_SLOW_IOACCESS
152414343Swollman#ifdef VGA_ALT_SEQACCESS
152514343Swollman    outb(TSIDX, 0x00); outb(TSREG, 0x01);
152614343Swollman#endif
15272742Swollman    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
152819878Swollman    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
152958787Sru#ifdef VGA_ALT_SEQACCESS
153058787Sru    outb(TSIDX, 0x00); outb(TSREG, 0x03);
153158787Sru#endif
153219878Swollman    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
153319878Swollman    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
153430711Swollman    if (adp->va_crtc_addr == MONO_CRTC) {
153530711Swollman	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
153643014Swollman    } else {
153743014Swollman	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
153843014Swollman    }
153943014Swollman#else /* VGA_SLOW_IOACCESS */
154030711Swollman#ifdef VGA_ALT_SEQACCESS
154130711Swollman    outw(TSIDX, 0x0100);
154219878Swollman#endif
1543158421Swollman    outw(TSIDX, 0x0002 | (buf[0] << 8));
1544158421Swollman    outw(TSIDX, 0x0004 | (buf[1] << 8));
1545158421Swollman#ifdef VGA_ALT_SEQACCESS
1546158421Swollman    outw(TSIDX, 0x0300);
1547158421Swollman#endif
1548158421Swollman    outw(GDCIDX, 0x0004 | (buf[2] << 8));
1549158421Swollman    outw(GDCIDX, 0x0005 | (buf[3] << 8));
1550158421Swollman    if (adp->va_crtc_addr == MONO_CRTC)
1551158421Swollman        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
1552158421Swollman    else
1553158421Swollman        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
1554158421Swollman#endif /* VGA_SLOW_IOACCESS */
1555158421Swollman
1556158421Swollman    splx(s);
1557158421Swollman}
1558158421Swollman
1559158421Swollman#endif /* VGA_NO_FONT_LOADING */
1560158421Swollman
1561158421Swollman/*
1562158421Swollman * save_font():
1563158421Swollman * Read the font data in the requested font page from the video adapter.
1564158421Swollman *
1565158421Swollman * EGA/VGA
1566158421Swollman */
1567158421Swollmanstatic int
1568158421Swollmanvga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
1569158421Swollman	      int ch, int count)
1570158421Swollman{
1571158421Swollman#ifndef VGA_NO_FONT_LOADING
1572158421Swollman    u_char buf[PARAM_BUFSIZE];
1573158421Swollman    u_int32_t segment;
1574158421Swollman    int c;
1575158421Swollman#ifdef VGA_ALT_SEQACCESS
1576158421Swollman    int s;
1577158421Swollman    u_char val = 0;
1578158421Swollman#endif
1579158421Swollman
1580158421Swollman    prologue(adp, V_ADP_FONT, 1);
1581158421Swollman
1582158421Swollman    if (fontsize < 14) {
1583158421Swollman	/* FONT_8 */
1584158421Swollman	fontsize = 8;
1585158421Swollman    } else if (fontsize >= 32) {
15862742Swollman	fontsize = 32;
15872742Swollman    } else if (fontsize >= 16) {
158843014Swollman	/* FONT_16 */
15892742Swollman	fontsize = 16;
15902742Swollman    } else {
15912742Swollman	/* FONT_14 */
159219878Swollman	fontsize = 14;
159330711Swollman    }
1594158421Swollman
1595158421Swollman    if (page < 0 || page >= 8)
15962742Swollman	return 1;
15972742Swollman    segment = FONT_BUF + 0x4000*page;
15982742Swollman    if (page > 3)
159919878Swollman	segment -= 0xe000;
16002742Swollman
160119878Swollman#ifdef VGA_ALT_SEQACCESS
16022742Swollman    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
160319878Swollman	s = splhigh();
16042742Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x01);
16052742Swollman	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
16062742Swollman	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
160719878Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x03);
16082742Swollman	splx(s);
160919878Swollman    }
16102742Swollman#endif
161119878Swollman
16122742Swollman    set_font_mode(adp, buf);
161319878Swollman    if (fontsize == 32) {
16142742Swollman	bcopy_fromio(segment + ch*32, data, fontsize*count);
161519878Swollman    } else {
16162742Swollman	for (c = ch; count > 0; ++c, --count) {
161719878Swollman	    bcopy_fromio(segment + c*32, data, fontsize);
161819878Swollman	    data += fontsize;
16192742Swollman	}
162020094Swollman    }
162120094Swollman    set_normal_mode(adp, buf);
162220094Swollman
162320094Swollman#ifdef VGA_ALT_SEQACCESS
162420094Swollman    if (adp->va_type == KD_VGA) {
162520094Swollman	s = splhigh();
162620094Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x01);
162758787Sru	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
162858787Sru	outb(TSIDX, 0x00); outb(TSREG, 0x03);
162958787Sru	splx(s);
1630158421Swollman    }
163158787Sru#endif
163220094Swollman
163358787Sru    return 0;
163458787Sru#else /* VGA_NO_FONT_LOADING */
16352742Swollman    return 1;
163667578Swollman#endif /* VGA_NO_FONT_LOADING */
163719878Swollman}
16382742Swollman
16392742Swollman/*
1640158421Swollman * load_font():
16412742Swollman * Set the font data in the requested font page.
16422742Swollman * NOTE: it appears that some recent video adapters do not support
164343014Swollman * the font page other than 0... XXX
164419878Swollman *
164558787Sru * EGA/VGA
164619878Swollman */
16472742Swollmanstatic int
16482742Swollmanvga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
16492742Swollman	      int ch, int count)
16502742Swollman{
165119878Swollman#ifndef VGA_NO_FONT_LOADING
16522742Swollman    u_char buf[PARAM_BUFSIZE];
16532742Swollman    u_int32_t segment;
16542742Swollman    int c;
1655158421Swollman#ifdef VGA_ALT_SEQACCESS
16562742Swollman    int s;
165767578Swollman    u_char val = 0;
165843014Swollman#endif
165958787Sru
166058787Sru    prologue(adp, V_ADP_FONT, 1);
1661158421Swollman
166243014Swollman    if (fontsize < 14) {
16632742Swollman	/* FONT_8 */
16642742Swollman	fontsize = 8;
16652742Swollman    } else if (fontsize >= 32) {
16662742Swollman	fontsize = 32;
16672742Swollman    } else if (fontsize >= 16) {
16682742Swollman	/* FONT_16 */
16692742Swollman	fontsize = 16;
16702742Swollman    } else {
167143014Swollman	/* FONT_14 */
167243014Swollman	fontsize = 14;
167343014Swollman    }
167443014Swollman
1675158421Swollman    if (page < 0 || page >= 8)
1676158421Swollman	return 1;
167758787Sru    segment = FONT_BUF + 0x4000*page;
167843014Swollman    if (page > 3)
16792742Swollman	segment -= 0xe000;
168043014Swollman
1681158421Swollman#ifdef VGA_ALT_SEQACCESS
168258787Sru    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
168358787Sru	s = splhigh();
168443014Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x01);
16852742Swollman	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
16862742Swollman	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1687158421Swollman	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1688149514Swollman	splx(s);
16892742Swollman    }
16902742Swollman#endif
1691158421Swollman
1692158421Swollman    set_font_mode(adp, buf);
16932742Swollman    if (fontsize == 32) {
16942742Swollman	bcopy_toio(data, segment + ch*32, fontsize*count);
169519878Swollman    } else {
16962742Swollman	for (c = ch; count > 0; ++c, --count) {
16972742Swollman	    bcopy_toio(data, segment + c*32, fontsize);
16982742Swollman	    data += fontsize;
16992742Swollman	}
17002742Swollman    }
17012742Swollman    set_normal_mode(adp, buf);
17022742Swollman
17032742Swollman#ifdef VGA_ALT_SEQACCESS
1704    if (adp->va_type == KD_VGA) {
1705	s = splhigh();
1706	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1707	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
1708	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1709	splx(s);
1710    }
1711#endif
1712
1713    return 0;
1714#else /* VGA_NO_FONT_LOADING */
1715    return 1;
1716#endif /* VGA_NO_FONT_LOADING */
1717}
1718
1719/*
1720 * show_font():
1721 * Activate the requested font page.
1722 * NOTE: it appears that some recent video adapters do not support
1723 * the font page other than 0... XXX
1724 *
1725 * EGA/VGA
1726 */
1727static int
1728vga_show_font(video_adapter_t *adp, int page)
1729{
1730#ifndef VGA_NO_FONT_LOADING
1731    static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
1732    int s;
1733
1734    prologue(adp, V_ADP_FONT, 1);
1735    if (page < 0 || page >= 8)
1736	return 1;
1737
1738    s = splhigh();
1739    outb(TSIDX, 0x03); outb(TSREG, cg[page]);
1740    splx(s);
1741
1742    return 0;
1743#else /* VGA_NO_FONT_LOADING */
1744    return 1;
1745#endif /* VGA_NO_FONT_LOADING */
1746}
1747
1748/*
1749 * save_palette():
1750 * Read DAC values. The values have expressed in 8 bits.
1751 *
1752 * VGA
1753 */
1754static int
1755vga_save_palette(video_adapter_t *adp, u_char *palette)
1756{
1757    int i;
1758
1759    prologue(adp, V_ADP_PALETTE, 1);
1760
1761    /*
1762     * We store 8 bit values in the palette buffer, while the standard
1763     * VGA has 6 bit DAC .
1764     */
1765    outb(PALRADR, 0x00);
1766    for (i = 0; i < 256*3; ++i)
1767	palette[i] = inb(PALDATA) << 2;
1768    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
1769    return 0;
1770}
1771
1772/*
1773 * load_palette():
1774 * Set DAC values.
1775 *
1776 * VGA
1777 */
1778static int
1779vga_load_palette(video_adapter_t *adp, u_char *palette)
1780{
1781    int i;
1782
1783    prologue(adp, V_ADP_PALETTE, 1);
1784
1785    outb(PIXMASK, 0xff);		/* no pixelmask */
1786    outb(PALWADR, 0x00);
1787    for (i = 0; i < 256*3; ++i)
1788	outb(PALDATA, palette[i] >> 2);
1789    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
1790    outb(ATC, 0x20);			/* enable palette */
1791    return 0;
1792}
1793
1794/*
1795 * set_border():
1796 * Change the border color.
1797 *
1798 * CGA/EGA/VGA
1799 */
1800static int
1801vga_set_border(video_adapter_t *adp, int color)
1802{
1803    prologue(adp, V_ADP_BORDER, 1);
1804
1805    switch (adp->va_type) {
1806    case KD_EGA:
1807    case KD_VGA:
1808	inb(adp->va_crtc_addr + 6);	/* reset flip-flop */
1809	outb(ATC, 0x31); outb(ATC, color & 0xff);
1810	break;
1811    case KD_CGA:
1812	outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */
1813	break;
1814    case KD_MONO:
1815    case KD_HERCULES:
1816    default:
1817	break;
1818    }
1819    return 0;
1820}
1821
1822/*
1823 * save_state():
1824 * Read video register values.
1825 * NOTE: this function only reads the standard EGA/VGA registers.
1826 * any extra/extended registers of SVGA adapters are not saved.
1827 *
1828 * VGA
1829 */
1830static int
1831vga_save_state(video_adapter_t *adp, void *p, size_t size)
1832{
1833    video_info_t info;
1834    u_char *buf;
1835    int crtc_addr;
1836    int i, j;
1837    int s;
1838
1839    if (size == 0) {
1840	/* return the required buffer size */
1841	prologue(adp, V_ADP_STATESAVE, 0);
1842	return sizeof(adp_state_t);
1843    } else {
1844	prologue(adp, V_ADP_STATESAVE, 1);
1845	if (size < sizeof(adp_state_t))
1846	    return 1;
1847    }
1848
1849    ((adp_state_t *)p)->sig = V_STATE_SIG;
1850    buf = ((adp_state_t *)p)->regs;
1851    bzero(buf, V_MODE_PARAM_SIZE);
1852    crtc_addr = adp->va_crtc_addr;
1853
1854    s = splhigh();
1855
1856    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
1857    for (i = 0, j = 5; i < 4; i++) {
1858	outb(TSIDX, i + 1);
1859	buf[j++]  =  inb(TSREG);
1860    }
1861    buf[9]  =  inb(MISC + 10);			/* dot-clock */
1862    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
1863
1864    for (i = 0, j = 10; i < 25; i++) {		/* crtc */
1865	outb(crtc_addr, i);
1866	buf[j++]  =  inb(crtc_addr + 1);
1867    }
1868    for (i = 0, j = 35; i < 20; i++) {		/* attribute ctrl */
1869        inb(crtc_addr + 6);			/* reset flip-flop */
1870	outb(ATC, i);
1871	buf[j++]  =  inb(ATC + 1);
1872    }
1873    for (i = 0, j = 55; i < 9; i++) {		/* graph data ctrl */
1874	outb(GDCIDX, i);
1875	buf[j++]  =  inb(GDCREG);
1876    }
1877    inb(crtc_addr + 6);				/* reset flip-flop */
1878    outb(ATC, 0x20);				/* enable palette */
1879
1880    splx(s);
1881
1882#if 1
1883    if (vga_get_info(adp, adp->va_mode, &info) == 0) {
1884	if (info.vi_flags & V_INFO_GRAPHICS) {
1885	    buf[0] = info.vi_width/info.vi_cwidth; /* COLS */
1886	    buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */
1887	} else {
1888	    buf[0] = info.vi_width;		/* COLS */
1889	    buf[1] = info.vi_height - 1;	/* ROWS */
1890	}
1891	buf[2] = info.vi_cheight;		/* POINTS */
1892    } else {
1893	/* XXX: shouldn't be happening... */
1894	printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
1895	       adp->va_unit, adp->va_name);
1896    }
1897#else
1898    buf[0] = readb(BIOS_PADDRTOVADDR(0x44a));	/* COLS */
1899    buf[1] = readb(BIOS_PADDRTOVADDR(0x484));	/* ROWS */
1900    buf[2] = readb(BIOS_PADDRTOVADDR(0x485));	/* POINTS */
1901    buf[3] = readb(BIOS_PADDRTOVADDR(0x44c));
1902    buf[4] = readb(BIOS_PADDRTOVADDR(0x44d));
1903#endif
1904
1905    return 0;
1906}
1907
1908/*
1909 * load_state():
1910 * Set video registers at once.
1911 * NOTE: this function only updates the standard EGA/VGA registers.
1912 * any extra/extended registers of SVGA adapters are not changed.
1913 *
1914 * EGA/VGA
1915 */
1916static int
1917vga_load_state(video_adapter_t *adp, void *p)
1918{
1919    u_char *buf;
1920    int crtc_addr;
1921    int s;
1922    int i;
1923
1924    prologue(adp, V_ADP_STATELOAD, 1);
1925    if (((adp_state_t *)p)->sig != V_STATE_SIG)
1926	return 1;
1927
1928    buf = ((adp_state_t *)p)->regs;
1929    crtc_addr = adp->va_crtc_addr;
1930
1931    s = splhigh();
1932
1933    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
1934    for (i = 0; i < 4; ++i) {			/* program sequencer */
1935	outb(TSIDX, i + 1);
1936	outb(TSREG, buf[i + 5]);
1937    }
1938    outb(MISC, buf[9]);				/* set dot-clock */
1939    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
1940    outb(crtc_addr, 0x11);
1941    outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F);
1942    for (i = 0; i < 25; ++i) {			/* program crtc */
1943	outb(crtc_addr, i);
1944	outb(crtc_addr + 1, buf[i + 10]);
1945    }
1946    inb(crtc_addr+6);				/* reset flip-flop */
1947    for (i = 0; i < 20; ++i) {			/* program attribute ctrl */
1948	outb(ATC, i);
1949	outb(ATC, buf[i + 35]);
1950    }
1951    for (i = 0; i < 9; ++i) {			/* program graph data ctrl */
1952	outb(GDCIDX, i);
1953	outb(GDCREG, buf[i + 55]);
1954    }
1955    inb(crtc_addr + 6);				/* reset flip-flop */
1956    outb(ATC, 0x20);				/* enable palette */
1957
1958#ifndef VGA_NO_BIOS
1959    if (adp->va_unit == V_ADP_PRIMARY) {
1960	writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]);	/* COLS */
1961	writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */
1962	writeb(BIOS_PADDRTOVADDR(0x485), buf[2]);	/* POINTS */
1963#if 0
1964	writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]);
1965	writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]);
1966#endif
1967    }
1968#endif /* VGA_NO_BIOS */
1969
1970    splx(s);
1971    return 0;
1972}
1973
1974/*
1975 * set_origin():
1976 * Change the origin (window mapping) of the banked frame buffer.
1977 */
1978static int
1979vga_set_origin(video_adapter_t *adp, off_t offset)
1980{
1981    /*
1982     * The standard video modes do not require window mapping;
1983     * always return error.
1984     */
1985    return 1;
1986}
1987
1988/*
1989 * read_hw_cursor():
1990 * Read the position of the hardware text cursor.
1991 *
1992 * all adapters
1993 */
1994static int
1995vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
1996{
1997    u_int16_t off;
1998    int s;
1999
2000    if (!init_done)
2001	return 1;
2002
2003    if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
2004	return 1;
2005
2006    s = spltty();
2007    outb(adp->va_crtc_addr, 14);
2008    off = inb(adp->va_crtc_addr + 1);
2009    outb(adp->va_crtc_addr, 15);
2010    off = (off << 8) | inb(adp->va_crtc_addr + 1);
2011    splx(s);
2012
2013    *row = off / adp->va_info.vi_width;
2014    *col = off % adp->va_info.vi_width;
2015
2016    return 0;
2017}
2018
2019/*
2020 * set_hw_cursor():
2021 * Move the hardware text cursor.  If col and row are both -1,
2022 * the cursor won't be shown.
2023 *
2024 * all adapters
2025 */
2026static int
2027vga_set_hw_cursor(video_adapter_t *adp, int col, int row)
2028{
2029    u_int16_t off;
2030    int s;
2031
2032    if (!init_done)
2033	return 1;
2034
2035    if ((col == -1) && (row == -1)) {
2036	off = -1;
2037    } else {
2038	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
2039	    return 1;
2040	off = row*adp->va_info.vi_width + col;
2041    }
2042
2043    s = spltty();
2044    outb(adp->va_crtc_addr, 14);
2045    outb(adp->va_crtc_addr + 1, off >> 8);
2046    outb(adp->va_crtc_addr, 15);
2047    outb(adp->va_crtc_addr + 1, off & 0x00ff);
2048    splx(s);
2049
2050    return 0;
2051}
2052
2053/*
2054 * set_hw_cursor_shape():
2055 * Change the shape of the hardware text cursor. If the height is
2056 * zero or negative, the cursor won't be shown.
2057 *
2058 * all adapters
2059 */
2060static int
2061vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
2062			int celsize, int blink)
2063{
2064    int s;
2065
2066    if (!init_done)
2067	return 1;
2068
2069    s = spltty();
2070    switch (adp->va_type) {
2071    case KD_VGA:
2072    case KD_CGA:
2073    case KD_MONO:
2074    case KD_HERCULES:
2075    default:
2076	if (height <= 0) {
2077	    /* make the cursor invisible */
2078	    outb(adp->va_crtc_addr, 10);
2079	    outb(adp->va_crtc_addr + 1, 32);
2080	    outb(adp->va_crtc_addr, 11);
2081	    outb(adp->va_crtc_addr + 1, 0);
2082	} else {
2083	    outb(adp->va_crtc_addr, 10);
2084	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2085	    outb(adp->va_crtc_addr, 11);
2086	    outb(adp->va_crtc_addr + 1, celsize - base - 1);
2087	}
2088	break;
2089    case KD_EGA:
2090	if (height <= 0) {
2091	    /* make the cursor invisible */
2092	    outb(adp->va_crtc_addr, 10);
2093	    outb(adp->va_crtc_addr + 1, celsize);
2094	    outb(adp->va_crtc_addr, 11);
2095	    outb(adp->va_crtc_addr + 1, 0);
2096	} else {
2097	    outb(adp->va_crtc_addr, 10);
2098	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2099	    outb(adp->va_crtc_addr, 11);
2100	    outb(adp->va_crtc_addr + 1, celsize - base);
2101	}
2102	break;
2103    }
2104    splx(s);
2105
2106    return 0;
2107}
2108
2109/*
2110 * mmap():
2111 * Mmap frame buffer.
2112 *
2113 * all adapters
2114 */
2115static int
2116vga_mmap(video_adapter_t *adp, vm_offset_t offset)
2117{
2118    if (offset > 0x20000 - PAGE_SIZE)
2119	return -1;
2120#ifdef __i386__
2121    return i386_btop((VIDEO_BUF_BASE + offset));
2122#endif
2123#ifdef __alpha__
2124    return alpha_btop((VIDEO_BUF_BASE + offset));
2125#endif
2126}
2127
2128static void
2129dump_buffer(u_char *buf, size_t len)
2130{
2131    int i;
2132
2133    for(i = 0; i < len;) {
2134	printf("%02x ", buf[i]);
2135	if ((++i % 16) == 0)
2136	    printf("\n");
2137    }
2138}
2139
2140/*
2141 * diag():
2142 * Print some information about the video adapter and video modes,
2143 * with requested level of details.
2144 *
2145 * all adapters
2146 */
2147static int
2148vga_diag(video_adapter_t *adp, int level)
2149{
2150#if FB_DEBUG > 1
2151    video_info_t info;
2152#endif
2153    u_char *mp;
2154
2155    if (!init_done)
2156	return 1;
2157
2158#if FB_DEBUG > 1
2159#ifndef VGA_NO_BIOS
2160    printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n",
2161	   rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488)));
2162    printf("vga: CRTC:0x%x, video option:0x%02x, ",
2163	   readw(BIOS_PADDRTOVADDR(0x463)),
2164	   readb(BIOS_PADDRTOVADDR(0x487)));
2165    printf("rows:%d, cols:%d, font height:%d\n",
2166	   readb(BIOS_PADDRTOVADDR(0x44a)),
2167	   readb(BIOS_PADDRTOVADDR(0x484)) + 1,
2168	   readb(BIOS_PADDRTOVADDR(0x485)));
2169#endif /* VGA_NO_BIOS */
2170    printf("vga: param table EGA/VGA:%p", video_mode_ptr);
2171    printf(", CGA/MDA:%p\n", video_mode_ptr2);
2172    printf("vga: rows_offset:%d\n", rows_offset);
2173#endif /* FB_DEBUG > 1 */
2174
2175    fb_dump_adp_info(DRIVER_NAME, adp, level);
2176
2177#if FB_DEBUG > 1
2178    if (adp->va_flags & V_ADP_MODECHANGE) {
2179	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
2180	    if (bios_vmode[i].vi_mode == NA)
2181		continue;
2182	    if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
2183		continue;
2184	    fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
2185	}
2186    } else {
2187	vga_get_info(adp, adp->va_initial_mode, &info);	/* shouldn't fail */
2188	fb_dump_mode_info(DRIVER_NAME, adp, &info, level);
2189    }
2190#endif /* FB_DEBUG > 1 */
2191
2192    if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA))
2193	return 0;
2194#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
2195    if (video_mode_ptr == NULL)
2196	printf("vga%d: %s: WARNING: video mode switching is not "
2197	       "fully supported on this adapter\n",
2198	       adp->va_unit, adp->va_name);
2199#endif
2200    if (level <= 0)
2201	return 0;
2202
2203    if (adp->va_type == KD_VGA) {
2204	printf("VGA parameters upon power-up\n");
2205	dump_buffer(adpstate.regs, sizeof(adpstate.regs));
2206	printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode);
2207	dump_buffer(adpstate2.regs, sizeof(adpstate2.regs));
2208    }
2209
2210    mp = get_mode_param(adp->va_initial_mode);
2211    if (mp == NULL)	/* this shouldn't be happening */
2212	return 0;
2213    printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode);
2214    dump_buffer(mp, V_MODE_PARAM_SIZE);
2215
2216    return 0;
2217}
2218
2219#endif /* NVGA > 0 */
2220