vga_isa.c revision 43105
143105Sdfr/*-
243105Sdfr * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
343105Sdfr * Copyright (c) 1992-1998 S�ren Schmidt
443105Sdfr * All rights reserved.
543105Sdfr *
643105Sdfr * Redistribution and use in source and binary forms, with or without
743105Sdfr * modification, are permitted provided that the following conditions
843105Sdfr * are met:
943105Sdfr * 1. Redistributions of source code must retain the above copyright
1043105Sdfr *    notice, this list of conditions and the following disclaimer as
1143105Sdfr *    the first lines of this file unmodified.
1243105Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1343105Sdfr *    notice, this list of conditions and the following disclaimer in the
1443105Sdfr *    documentation and/or other materials provided with the distribution.
1543105Sdfr * 3. The name of the author may not be used to endorse or promote products
1643105Sdfr *    derived from this software without specific prior written permission.
1743105Sdfr *
1843105Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1943105Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2043105Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2143105Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2243105Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2343105Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2443105Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2543105Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2643105Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2743105Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2843105Sdfr *
2943105Sdfr * $Id: vga_isa.c,v 1.1 1999/01/09 02:44:41 yokota Exp $
3043105Sdfr */
3143105Sdfr
3243105Sdfr#include "vga.h"
3343105Sdfr#include "opt_vga.h"
3443105Sdfr#include "opt_fb.h"
3543105Sdfr#include "opt_syscons.h"	/* should be removed in the future, XXX */
3643105Sdfr
3743105Sdfr#if NVGA > 0
3843105Sdfr
3943105Sdfr#include <sys/param.h>
4043105Sdfr#include <sys/systm.h>
4143105Sdfr#include <sys/kernel.h>
4243105Sdfr#include <sys/bus.h>
4343105Sdfr#include <sys/malloc.h>
4443105Sdfr
4543105Sdfr#include <vm/vm.h>
4643105Sdfr#include <vm/pmap.h>
4743105Sdfr
4843105Sdfr#include <machine/console.h>
4943105Sdfr#include <machine/md_var.h>
5043105Sdfr#include <machine/pc/bios.h>
5143105Sdfr
5243105Sdfr#include <dev/fb/fbreg.h>
5343105Sdfr#include <dev/fb/vgareg.h>
5443105Sdfr
5543105Sdfr#ifndef __i386__
5643105Sdfr#include <isa/isareg.h>
5743105Sdfr#include <isa/isavar.h>
5843105Sdfr#else
5943105Sdfr#include <i386/isa/isa.h>
6043105Sdfr#include <i386/isa/isa_device.h>
6143105Sdfr#endif
6243105Sdfr
6343105Sdfr#define DRIVER_NAME		"vga"
6443105Sdfr
6543105Sdfr/* cdev driver declaration */
6643105Sdfr
6743105Sdfr#define ISAVGA_UNIT(dev)	minor(dev)
6843105Sdfr#define ISAVGA_MKMINOR(unit)	(unit)
6943105Sdfr
7043105Sdfrtypedef struct isavga_softc {
7143105Sdfr	video_adapter_t	*adp;
7243105Sdfr} isavga_softc_t;
7343105Sdfr
7443105Sdfr#ifndef __i386__
7543105Sdfr
7643105Sdfr#define ISAVGA_SOFTC(unit)		\
7743105Sdfr	((isavga_softc_t *)devclass_get_softc(isavga_devclass, unit))
7843105Sdfr
7943105Sdfrdevclass_t		isavga_devclass;
8043105Sdfr
8143105Sdfrstatic int		isavga_probe(device_t dev);
8243105Sdfrstatic int		isavga_attach(device_t dev);
8343105Sdfr
8443105Sdfrstatic device_method_t isavga_methods[] = {
8543105Sdfr	DEVMETHOD(device_probe,		isavga_probe),
8643105Sdfr	DEVMETHOD(device_attach,	isavga_attach),
8743105Sdfr	{ 0, 0 }
8843105Sdfr};
8943105Sdfr
9043105Sdfrstatic driver_t isavga_driver = {
9143105Sdfr	DRIVER_NAME,
9243105Sdfr	isavga_methods,
9343105Sdfr	DRIVER_TYPE_TTY,
9443105Sdfr	sizeof(isavga_softc_t),
9543105Sdfr};
9643105Sdfr
9743105SdfrDRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0);
9843105Sdfr
9943105Sdfr#else /* __i386__ */
10043105Sdfr
10143105Sdfr#define ISAVGA_SOFTC(unit)	(isavga_softc[unit])
10243105Sdfr
10343105Sdfrstatic isavga_softc_t	*isavga_softc[NVGA];
10443105Sdfr
10543105Sdfrstatic int		isavga_probe(struct isa_device *dev);
10643105Sdfrstatic int		isavga_attach(struct isa_device *dev);
10743105Sdfr
10843105Sdfrstruct isa_driver vgadriver = {
10943105Sdfr	isavga_probe,
11043105Sdfr	isavga_attach,
11143105Sdfr	DRIVER_NAME,
11243105Sdfr	0,
11343105Sdfr};
11443105Sdfr
11543105Sdfr#endif /* __i386__ */
11643105Sdfr
11743105Sdfrstatic int		isavga_probe_unit(int unit, isavga_softc_t *sc,
11843105Sdfr					  int flags);
11943105Sdfrstatic int		isavga_attach_unit(int unit, isavga_softc_t *sc,
12043105Sdfr					   int flags);
12143105Sdfr
12243105Sdfr#ifdef FB_INSTALL_CDEV
12343105Sdfr
12443105Sdfrstatic d_open_t		isavgaopen;
12543105Sdfrstatic d_close_t	isavgaclose;
12643105Sdfrstatic d_read_t		isavgaread;
12743105Sdfrstatic d_ioctl_t	isavgaioctl;
12843105Sdfr
12943105Sdfrstatic struct  cdevsw vga_cdevsw = {
13043105Sdfr	isavgaopen,	isavgaclose,	noread,		nowrite,	/* ?? */
13143105Sdfr	isavgaioctl,	nostop,		nullreset,	nodevtotty,
13243105Sdfr	seltrue,	nommap,		NULL,		DRIVER_NAME,
13343105Sdfr	NULL,		-1,		nodump,		nopsize,
13443105Sdfr};
13543105Sdfr
13643105Sdfr#endif /* FB_INSTALL_CDEV */
13743105Sdfr
13843105Sdfr#ifndef __i386__
13943105Sdfr
14043105Sdfrstatic int
14143105Sdfrisavga_probe(device_t dev)
14243105Sdfr{
14343105Sdfr	isavga_softc_t *sc;
14443105Sdfr
14543105Sdfr	device_set_desc(dev, "Generic ISA VGA");
14643105Sdfr	sc = device_get_softc(dev);
14743105Sdfr	return isavga_probe_unit(device_get_unit(dev), sc, isa_get_flags(dev));
14843105Sdfr}
14943105Sdfr
15043105Sdfrstatic int
15143105Sdfrisavga_attach(device_t dev)
15243105Sdfr{
15343105Sdfr	isavga_softc_t *sc;
15443105Sdfr
15543105Sdfr	sc = device_get_softc(dev);
15643105Sdfr	return isavga_attach_unit(device_get_unit(dev), sc, isa_get_flags(dev));
15743105Sdfr}
15843105Sdfr
15943105Sdfr#else /* __i386__ */
16043105Sdfr
16143105Sdfrstatic int
16243105Sdfrisavga_probe(struct isa_device *dev)
16343105Sdfr{
16443105Sdfr	isavga_softc_t *sc;
16543105Sdfr	int error;
16643105Sdfr
16743105Sdfr	if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0]))
16843105Sdfr		return 0;
16943105Sdfr	sc = isavga_softc[dev->id_unit]
17043105Sdfr	   = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
17143105Sdfr	if (sc == NULL)
17243105Sdfr		return 0;
17343105Sdfr
17443105Sdfr	error = isavga_probe_unit(dev->id_unit, sc, dev->id_flags);
17543105Sdfr	if (error) {
17643105Sdfr		isavga_softc[dev->id_unit] = NULL;
17743105Sdfr		free(sc, M_DEVBUF);
17843105Sdfr		return 0;
17943105Sdfr	}
18043105Sdfr
18143105Sdfr	dev->id_iobase = sc->adp->va_io_base;
18243105Sdfr	dev->id_maddr = (caddr_t)BIOS_PADDRTOVADDR(sc->adp->va_mem_base);
18343105Sdfr	dev->id_msize = sc->adp->va_mem_size;
18443105Sdfr
18543105Sdfr	return sc->adp->va_io_size;
18643105Sdfr}
18743105Sdfr
18843105Sdfrstatic int
18943105Sdfrisavga_attach(struct isa_device *dev)
19043105Sdfr{
19143105Sdfr	isavga_softc_t *sc;
19243105Sdfr
19343105Sdfr	if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0]))
19443105Sdfr		return 0;
19543105Sdfr	sc = isavga_softc[dev->id_unit];
19643105Sdfr	if (sc == NULL)
19743105Sdfr		return 0;
19843105Sdfr
19943105Sdfr	return ((isavga_attach_unit(dev->id_unit, sc, dev->id_flags)) ? 0 : 1);
20043105Sdfr}
20143105Sdfr
20243105Sdfr#endif /* __i386__ */
20343105Sdfr
20443105Sdfrstatic int
20543105Sdfrisavga_probe_unit(int unit, isavga_softc_t *sc, int flags)
20643105Sdfr{
20743105Sdfr	video_switch_t *sw;
20843105Sdfr
20943105Sdfr	bzero(sc, sizeof(*sc));
21043105Sdfr	sw = vid_get_switch(DRIVER_NAME);
21143105Sdfr	if (sw == NULL)
21243105Sdfr		return 0;
21343105Sdfr	return (*sw->probe)(unit, &sc->adp, NULL, flags);
21443105Sdfr}
21543105Sdfr
21643105Sdfrstatic int
21743105Sdfrisavga_attach_unit(int unit, isavga_softc_t *sc, int flags)
21843105Sdfr{
21943105Sdfr	video_switch_t *sw;
22043105Sdfr	int error;
22143105Sdfr
22243105Sdfr	sw = vid_get_switch(DRIVER_NAME);
22343105Sdfr	if (sw == NULL)
22443105Sdfr		return ENXIO;
22543105Sdfr
22643105Sdfr	error = (*sw->init)(unit, sc->adp, flags);
22743105Sdfr	if (error)
22843105Sdfr		return ENXIO;
22943105Sdfr
23043105Sdfr#ifdef FB_INSTALL_CDEV
23143105Sdfr	/* attach a virtual frame buffer device */
23243105Sdfr	error = fb_attach(makedev(0, ISAVGA_MKMINOR(unit)), scp->adp,
23343105Sdfr			  &vga_cdevsw);
23443105Sdfr	if (error)
23543105Sdfr		return error;
23643105Sdfr#endif /* FB_INSTALL_CDEV */
23743105Sdfr
23843105Sdfr	if (bootverbose)
23943105Sdfr		(*sw->diag)(sc->adp, bootverbose);
24043105Sdfr
24143105Sdfr	return 0;
24243105Sdfr}
24343105Sdfr
24443105Sdfr/* LOW-LEVEL */
24543105Sdfr
24643105Sdfr#include <machine/clock.h>
24743105Sdfr#include <machine/pc/vesa.h>
24843105Sdfr
24943105Sdfr#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
25043105Sdfr#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
25143105Sdfr#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
25243105Sdfr
25343105Sdfr/* for compatibility with old kernel options */
25443105Sdfr#ifdef SC_ALT_SEQACCESS
25543105Sdfr#undef SC_ALT_SEQACCESS
25643105Sdfr#undef VGA_ALT_SEQACCESS
25743105Sdfr#define VGA_ALT_SEQACCESS	1
25843105Sdfr#endif
25943105Sdfr
26043105Sdfr#ifdef SLOW_VGA
26143105Sdfr#undef SLOW_VGA
26243105Sdfr#undef VGA_SLOW_IOACCESS
26343105Sdfr#define VGA_SLOW_IOACCESS	1
26443105Sdfr#endif
26543105Sdfr
26643105Sdfr/* architecture dependent option */
26743105Sdfr#ifdef __alpha__
26843105Sdfr#define VGA_NO_BIOS		1
26943105Sdfr#endif
27043105Sdfr
27143105Sdfr/* this should really be in `rtc.h' */
27243105Sdfr#define RTC_EQUIPMENT           0x14
27343105Sdfr
27443105Sdfr/* various sizes */
27543105Sdfr#define V_MODE_MAP_SIZE		(M_VGA_CG320 + 1)
27643105Sdfr#define V_MODE_PARAM_SIZE	64
27743105Sdfr
27843105Sdfr/* video adapter state buffer */
27943105Sdfrstruct adp_state {
28043105Sdfr    int			sig;
28143105Sdfr#define V_STATE_SIG	0x736f6962
28243105Sdfr    u_char		regs[V_MODE_PARAM_SIZE];
28343105Sdfr};
28443105Sdfrtypedef struct adp_state adp_state_t;
28543105Sdfr
28643105Sdfr/* video adapter information */
28743105Sdfr#define DCC_MONO	0
28843105Sdfr#define DCC_CGA40	1
28943105Sdfr#define DCC_CGA80	2
29043105Sdfr#define DCC_EGAMONO	3
29143105Sdfr#define DCC_EGA40	4
29243105Sdfr#define DCC_EGA80	5
29343105Sdfr
29443105Sdfr/*
29543105Sdfr * NOTE: `va_window' should have a virtual address, but is initialized
29643105Sdfr * with a physical address in the following table, as verify_adapter()
29743105Sdfr * will perform address conversion at run-time.
29843105Sdfr */
29943105Sdfrstatic video_adapter_t adapter_init_value[] = {
30043105Sdfr    /* DCC_MONO */
30143105Sdfr    { 0, KD_MONO, "mda", 0, 0, 0, 	    IO_MDA, IO_MDASIZE, MONO_CRTC,
30243105Sdfr      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
30343105Sdfr      0, 0, 0, 7, 0, 0, NULL },
30443105Sdfr    /* DCC_CGA40 */
30543105Sdfr    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
30643105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
30743105Sdfr      0, 0, 0, 3, 0, 0, NULL },
30843105Sdfr    /* DCC_CGA80 */
30943105Sdfr    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
31043105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
31143105Sdfr      0, 0, 0, 3, 0, 0, NULL },
31243105Sdfr    /* DCC_EGAMONO */
31343105Sdfr    { 0, KD_EGA,  "ega", 0, 0, 0,	    IO_MDA, 48,	  MONO_CRTC,
31443105Sdfr      EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
31543105Sdfr      0, 0, 0, 7, 0, 0, NULL },
31643105Sdfr    /* DCC_EGA40 */
31743105Sdfr    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
31843105Sdfr      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
31943105Sdfr      0, 0, 0, 3, 0, 0, NULL },
32043105Sdfr    /* DCC_EGA80 */
32143105Sdfr    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
32243105Sdfr      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
32343105Sdfr      0, 0, 0, 3, 0, 0, NULL },
32443105Sdfr};
32543105Sdfr
32643105Sdfrstatic video_adapter_t	biosadapter[2];
32743105Sdfrstatic int		biosadapters = 0;
32843105Sdfr
32943105Sdfr/* video driver declarations */
33043105Sdfrstatic int			vga_configure(int flags);
33143105Sdfr       int			(*vga_sub_configure)(int flags);
33243105Sdfrstatic int			vga_nop(void);
33343105Sdfrstatic vi_probe_t		vga_probe;
33443105Sdfrstatic vi_init_t		vga_init;
33543105Sdfrstatic vi_get_info_t		vga_get_info;
33643105Sdfrstatic vi_query_mode_t		vga_query_mode;
33743105Sdfrstatic vi_set_mode_t		vga_set_mode;
33843105Sdfrstatic vi_save_font_t		vga_save_font;
33943105Sdfrstatic vi_load_font_t		vga_load_font;
34043105Sdfrstatic vi_show_font_t		vga_show_font;
34143105Sdfrstatic vi_save_palette_t	vga_save_palette;
34243105Sdfrstatic vi_load_palette_t	vga_load_palette;
34343105Sdfrstatic vi_set_border_t		vga_set_border;
34443105Sdfrstatic vi_save_state_t		vga_save_state;
34543105Sdfrstatic vi_load_state_t		vga_load_state;
34643105Sdfrstatic vi_set_win_org_t		vga_set_origin;
34743105Sdfrstatic vi_read_hw_cursor_t	vga_read_hw_cursor;
34843105Sdfrstatic vi_set_hw_cursor_t	vga_set_hw_cursor;
34943105Sdfrstatic vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
35043105Sdfrstatic vi_mmap_t		vga_mmap;
35143105Sdfrstatic vi_diag_t		vga_diag;
35243105Sdfr
35343105Sdfrstatic video_switch_t vgavidsw = {
35443105Sdfr	vga_probe,
35543105Sdfr	vga_init,
35643105Sdfr	vga_get_info,
35743105Sdfr	vga_query_mode,
35843105Sdfr	vga_set_mode,
35943105Sdfr	vga_save_font,
36043105Sdfr	vga_load_font,
36143105Sdfr	vga_show_font,
36243105Sdfr	vga_save_palette,
36343105Sdfr	vga_load_palette,
36443105Sdfr	vga_set_border,
36543105Sdfr	vga_save_state,
36643105Sdfr	vga_load_state,
36743105Sdfr	vga_set_origin,
36843105Sdfr	vga_read_hw_cursor,
36943105Sdfr	vga_set_hw_cursor,
37043105Sdfr	vga_set_hw_cursor_shape,
37143105Sdfr	(vi_blank_display_t *)vga_nop,
37243105Sdfr	vga_mmap,
37343105Sdfr	vga_diag,
37443105Sdfr};
37543105Sdfr
37643105SdfrVIDEO_DRIVER(mda, vgavidsw, NULL);
37743105SdfrVIDEO_DRIVER(cga, vgavidsw, NULL);
37843105SdfrVIDEO_DRIVER(ega, vgavidsw, NULL);
37943105SdfrVIDEO_DRIVER(vga, vgavidsw, vga_configure);
38043105Sdfr
38143105Sdfr/* VGA BIOS standard video modes */
38243105Sdfr#define EOT		(-1)
38343105Sdfr#define NA		(-2)
38443105Sdfr
38543105Sdfrstatic video_info_t bios_vmode[] = {
38643105Sdfr    /* CGA */
38743105Sdfr    { M_B40x25,     V_INFO_COLOR, 40, 25, 8,  8, 2, 1,
38843105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
38943105Sdfr    { M_C40x25,     V_INFO_COLOR, 40, 25, 8,  8, 4, 1,
39043105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39143105Sdfr    { M_B80x25,     V_INFO_COLOR, 80, 25, 8,  8, 2, 1,
39243105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39343105Sdfr    { M_C80x25,     V_INFO_COLOR, 80, 25, 8,  8, 4, 1,
39443105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39543105Sdfr    /* EGA */
39643105Sdfr    { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1,
39743105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
39843105Sdfr    { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1,
39943105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40043105Sdfr    { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1,
40143105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40243105Sdfr    { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1,
40343105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40443105Sdfr    /* VGA */
40543105Sdfr    { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1,
40643105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
40743105Sdfr    { M_VGA_M80x25, 0,            80, 25, 8, 16, 2, 1,
40843105Sdfr      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
40943105Sdfr    { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
41043105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
41143105Sdfr    /* MDA */
41243105Sdfr    { M_EGAMONO80x25, 0,          80, 25, 8, 14, 2, 1,
41343105Sdfr      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
41443105Sdfr    /* EGA */
41543105Sdfr    { M_ENH_B80x43, V_INFO_COLOR, 80, 43, 8,  8, 2, 1,
41643105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
41743105Sdfr    { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8,  8, 4, 1,
41843105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
41943105Sdfr    /* VGA */
42043105Sdfr    { M_VGA_M80x30, 0,            80, 30, 8, 16, 2, 1,
42143105Sdfr      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
42243105Sdfr    { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
42343105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
42443105Sdfr    { M_VGA_M80x50, 0,            80, 50, 8,  8, 2, 1,
42543105Sdfr      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
42643105Sdfr    { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8,  8, 4, 1,
42743105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
42843105Sdfr    { M_VGA_M80x60, 0,            80, 60, 8,  8, 2, 1,
42943105Sdfr      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
43043105Sdfr    { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8,  8, 4, 1,
43143105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43243105Sdfr#ifndef VGA_NO_MODE_CHANGE
43343105Sdfr    /* CGA */
43443105Sdfr    { M_BG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
43543105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43643105Sdfr    { M_CG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
43743105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
43843105Sdfr    { M_BG640,      V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 1, 1,
43943105Sdfr      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
44043105Sdfr    /* EGA */
44143105Sdfr    { M_CG320_D,    V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 4, 4,
44243105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44343105Sdfr    { M_CG640_E,    V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 4, 4,
44443105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44543105Sdfr    { M_EGAMONOAPA, V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
44643105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 },
44743105Sdfr    { M_ENHMONOAPA2,V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
44843105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
44943105Sdfr    { M_CG640x350,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2,
45043105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45143105Sdfr    { M_ENH_CG640,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4,
45243105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45343105Sdfr    /* VGA */
45443105Sdfr    { M_BG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
45543105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45643105Sdfr    { M_CG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
45743105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
45843105Sdfr    { M_VGA_CG320,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 8, 1,
45943105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
46043105Sdfr    { M_VGA_MODEX,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8,  8, 8, 1,
46143105Sdfr      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
46243105Sdfr#endif /* VGA_NO_MODE_CHANGE */
46343105Sdfr
46443105Sdfr    { EOT },
46543105Sdfr};
46643105Sdfr
46743105Sdfrstatic int		init_done = FALSE;
46843105Sdfrstatic u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
46943105Sdfrstatic u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
47043105Sdfrstatic u_char		*mode_map[V_MODE_MAP_SIZE];
47143105Sdfrstatic adp_state_t	adpstate;
47243105Sdfrstatic adp_state_t	adpstate2;
47343105Sdfrstatic int		rows_offset = 1;
47443105Sdfr
47543105Sdfr/* local macros and functions */
47643105Sdfr#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
47743105Sdfr
47843105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
47943105Sdfrstatic void map_mode_table(u_char *map[], u_char *table, int max);
48043105Sdfr#endif
48143105Sdfrstatic void clear_mode_map(video_adapter_t *adp, u_char *map[], int max,
48243105Sdfr			   int color);
48343105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
48443105Sdfrstatic int map_mode_num(int mode);
48543105Sdfr#endif
48643105Sdfrstatic int map_gen_mode_num(int type, int color, int mode);
48743105Sdfrstatic int map_bios_mode_num(int type, int color, int bios_mode);
48843105Sdfrstatic u_char *get_mode_param(int mode);
48943105Sdfr#ifndef VGA_NO_BIOS
49043105Sdfrstatic void fill_adapter_param(int code, video_adapter_t *adp);
49143105Sdfr#endif
49243105Sdfrstatic int verify_adapter(video_adapter_t *adp);
49343105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
49443105Sdfr#define COMP_IDENTICAL	0
49543105Sdfr#define COMP_SIMILAR	1
49643105Sdfr#define COMP_DIFFERENT	2
49743105Sdfrstatic int comp_adpregs(u_char *buf1, u_char *buf2);
49843105Sdfr#endif
49943105Sdfrstatic int probe_adapters(void);
50043105Sdfr
50143105Sdfr#define PARAM_BUFSIZE	6
50243105Sdfrstatic void set_font_mode(video_adapter_t *adp, u_char *buf);
50343105Sdfrstatic void set_normal_mode(video_adapter_t *adp, u_char *buf);
50443105Sdfr
50543105Sdfrstatic void dump_buffer(u_char *buf, size_t len);
50643105Sdfr
50743105Sdfr#define	ISMAPPED(pa, width)				\
50843105Sdfr	(((pa) <= (u_long)0x1000 - (width)) 		\
50943105Sdfr	 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
51043105Sdfr
51143105Sdfr#define	prologue(adp, flag, err)			\
51243105Sdfr	if (!init_done || !((adp)->va_flags & (flag)))	\
51343105Sdfr	    return (err)
51443105Sdfr
51543105Sdfr/* a backdoor for the console driver */
51643105Sdfrstatic int
51743105Sdfrvga_configure(int flags)
51843105Sdfr{
51943105Sdfr    int i;
52043105Sdfr
52143105Sdfr    probe_adapters();
52243105Sdfr    for (i = 0; i < biosadapters; ++i) {
52343105Sdfr	if (!probe_done(&biosadapter[i]))
52443105Sdfr	    continue;
52543105Sdfr	biosadapter[i].va_flags |= V_ADP_INITIALIZED;
52643105Sdfr	if (!config_done(&biosadapter[i])) {
52743105Sdfr	    if (vid_register(&biosadapter[i]) < 0)
52843105Sdfr		continue;
52943105Sdfr	    biosadapter[i].va_flags |= V_ADP_REGISTERED;
53043105Sdfr	}
53143105Sdfr    }
53243105Sdfr    if (vga_sub_configure != NULL)
53343105Sdfr	(*vga_sub_configure)(flags);
53443105Sdfr
53543105Sdfr    return biosadapters;
53643105Sdfr}
53743105Sdfr
53843105Sdfr/* local subroutines */
53943105Sdfr
54043105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
54143105Sdfr/* construct the mode parameter map */
54243105Sdfrstatic void
54343105Sdfrmap_mode_table(u_char *map[], u_char *table, int max)
54443105Sdfr{
54543105Sdfr    int i;
54643105Sdfr
54743105Sdfr    for(i = 0; i < max; ++i)
54843105Sdfr	map[i] = table + i*V_MODE_PARAM_SIZE;
54943105Sdfr    for(; i < V_MODE_MAP_SIZE; ++i)
55043105Sdfr	map[i] = NULL;
55143105Sdfr}
55243105Sdfr#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
55343105Sdfr
55443105Sdfrstatic void
55543105Sdfrclear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color)
55643105Sdfr{
55743105Sdfr    video_info_t info;
55843105Sdfr    int i;
55943105Sdfr
56043105Sdfr    /*
56143105Sdfr     * NOTE: we don't touch `bios_vmode[]' because it is shared
56243105Sdfr     * by all adapters.
56343105Sdfr     */
56443105Sdfr    for(i = 0; i < max; ++i) {
56543105Sdfr	if (vga_get_info(adp, i, &info))
56643105Sdfr	    continue;
56743105Sdfr	if ((info.vi_flags & V_INFO_COLOR) != color)
56843105Sdfr	    map[i] = NULL;
56943105Sdfr    }
57043105Sdfr}
57143105Sdfr
57243105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
57343105Sdfr/* map the non-standard video mode to a known mode number */
57443105Sdfrstatic int
57543105Sdfrmap_mode_num(int mode)
57643105Sdfr{
57743105Sdfr    static struct {
57843105Sdfr        int from;
57943105Sdfr        int to;
58043105Sdfr    } mode_map[] = {
58143105Sdfr        { M_ENH_B80x43, M_ENH_B80x25 },
58243105Sdfr        { M_ENH_C80x43, M_ENH_C80x25 },
58343105Sdfr        { M_VGA_M80x30, M_VGA_M80x25 },
58443105Sdfr        { M_VGA_C80x30, M_VGA_C80x25 },
58543105Sdfr        { M_VGA_M80x50, M_VGA_M80x25 },
58643105Sdfr        { M_VGA_C80x50, M_VGA_C80x25 },
58743105Sdfr        { M_VGA_M80x60, M_VGA_M80x25 },
58843105Sdfr        { M_VGA_C80x60, M_VGA_C80x25 },
58943105Sdfr        { M_VGA_MODEX,  M_VGA_CG320 },
59043105Sdfr    };
59143105Sdfr    int i;
59243105Sdfr
59343105Sdfr    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
59443105Sdfr        if (mode_map[i].from == mode)
59543105Sdfr            return mode_map[i].to;
59643105Sdfr    }
59743105Sdfr    return mode;
59843105Sdfr}
59943105Sdfr#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
60043105Sdfr
60143105Sdfr/* map a generic video mode to a known mode number */
60243105Sdfrstatic int
60343105Sdfrmap_gen_mode_num(int type, int color, int mode)
60443105Sdfr{
60543105Sdfr    static struct {
60643105Sdfr	int from;
60743105Sdfr	int to_color;
60843105Sdfr	int to_mono;
60943105Sdfr    } mode_map[] = {
61043105Sdfr	{ M_TEXT_80x30,	M_VGA_C80x30, M_VGA_M80x30, },
61143105Sdfr	{ M_TEXT_80x43,	M_ENH_C80x43, M_ENH_B80x43, },
61243105Sdfr	{ M_TEXT_80x50,	M_VGA_C80x50, M_VGA_M80x50, },
61343105Sdfr	{ M_TEXT_80x60,	M_VGA_C80x60, M_VGA_M80x60, },
61443105Sdfr    };
61543105Sdfr    int i;
61643105Sdfr
61743105Sdfr    if (mode == M_TEXT_80x25) {
61843105Sdfr	switch (type) {
61943105Sdfr
62043105Sdfr	case KD_VGA:
62143105Sdfr	    if (color)
62243105Sdfr		return M_VGA_C80x25;
62343105Sdfr	    else
62443105Sdfr		return M_VGA_M80x25;
62543105Sdfr	    break;
62643105Sdfr
62743105Sdfr	case KD_EGA:
62843105Sdfr	    if (color)
62943105Sdfr		return M_ENH_C80x25;
63043105Sdfr	    else
63143105Sdfr		return M_EGAMONO80x25;
63243105Sdfr	    break;
63343105Sdfr
63443105Sdfr	case KD_CGA:
63543105Sdfr	    return M_C80x25;
63643105Sdfr
63743105Sdfr	case KD_MONO:
63843105Sdfr	case KD_HERCULES:
63943105Sdfr	    return M_EGAMONO80x25;	/* XXX: this name is confusing */
64043105Sdfr
64143105Sdfr 	default:
64243105Sdfr	    return -1;
64343105Sdfr	}
64443105Sdfr    }
64543105Sdfr
64643105Sdfr    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
64743105Sdfr        if (mode_map[i].from == mode)
64843105Sdfr            return ((color) ? mode_map[i].to_color : mode_map[i].to_mono);
64943105Sdfr    }
65043105Sdfr    return mode;
65143105Sdfr}
65243105Sdfr
65343105Sdfr/* turn the BIOS video number into our video mode number */
65443105Sdfrstatic int
65543105Sdfrmap_bios_mode_num(int type, int color, int bios_mode)
65643105Sdfr{
65743105Sdfr    static int cga_modes[7] = {
65843105Sdfr	M_B40x25, M_C40x25,		/* 0, 1 */
65943105Sdfr	M_B80x25, M_C80x25,		/* 2, 3 */
66043105Sdfr	M_BG320, M_CG320,
66143105Sdfr	M_BG640,
66243105Sdfr    };
66343105Sdfr    static int ega_modes[17] = {
66443105Sdfr	M_ENH_B40x25, M_ENH_C40x25,	/* 0, 1 */
66543105Sdfr	M_ENH_B80x25, M_ENH_C80x25,	/* 2, 3 */
66643105Sdfr	M_BG320, M_CG320,
66743105Sdfr	M_BG640,
66843105Sdfr	M_EGAMONO80x25,			/* 7 */
66943105Sdfr	8, 9, 10, 11, 12,
67043105Sdfr	M_CG320_D,
67143105Sdfr	M_CG640_E,
67243105Sdfr	M_ENHMONOAPA2,			/* XXX: video momery > 64K */
67343105Sdfr	M_ENH_CG640,			/* XXX: video momery > 64K */
67443105Sdfr    };
67543105Sdfr    static int vga_modes[20] = {
67643105Sdfr	M_VGA_C40x25, M_VGA_C40x25,	/* 0, 1 */
67743105Sdfr	M_VGA_C80x25, M_VGA_C80x25,	/* 2, 3 */
67843105Sdfr	M_BG320, M_CG320,
67943105Sdfr	M_BG640,
68043105Sdfr	M_VGA_M80x25,			/* 7 */
68143105Sdfr	8, 9, 10, 11, 12,
68243105Sdfr	M_CG320_D,
68343105Sdfr	M_CG640_E,
68443105Sdfr	M_ENHMONOAPA2,
68543105Sdfr	M_ENH_CG640,
68643105Sdfr	M_BG640x480, M_CG640x480,
68743105Sdfr	M_VGA_CG320,
68843105Sdfr    };
68943105Sdfr
69043105Sdfr    switch (type) {
69143105Sdfr
69243105Sdfr    case KD_VGA:
69343105Sdfr	if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0]))
69443105Sdfr	    return vga_modes[bios_mode];
69543105Sdfr	else if (color)
69643105Sdfr	    return M_VGA_C80x25;
69743105Sdfr	else
69843105Sdfr	    return M_VGA_M80x25;
69943105Sdfr	break;
70043105Sdfr
70143105Sdfr    case KD_EGA:
70243105Sdfr	if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0]))
70343105Sdfr	    return ega_modes[bios_mode];
70443105Sdfr	else if (color)
70543105Sdfr	    return M_ENH_C80x25;
70643105Sdfr	else
70743105Sdfr	    return M_EGAMONO80x25;
70843105Sdfr	break;
70943105Sdfr
71043105Sdfr    case KD_CGA:
71143105Sdfr	if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0]))
71243105Sdfr	    return cga_modes[bios_mode];
71343105Sdfr	else
71443105Sdfr	    return M_C80x25;
71543105Sdfr	break;
71643105Sdfr
71743105Sdfr    case KD_MONO:
71843105Sdfr    case KD_HERCULES:
71943105Sdfr	return M_EGAMONO80x25;		/* XXX: this name is confusing */
72043105Sdfr
72143105Sdfr    default:
72243105Sdfr	break;
72343105Sdfr    }
72443105Sdfr    return -1;
72543105Sdfr}
72643105Sdfr
72743105Sdfr/* look up a parameter table entry */
72843105Sdfrstatic u_char
72943105Sdfr*get_mode_param(int mode)
73043105Sdfr{
73143105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
73243105Sdfr    if (mode >= V_MODE_MAP_SIZE)
73343105Sdfr	mode = map_mode_num(mode);
73443105Sdfr#endif
73543105Sdfr    if ((mode >= 0) && (mode < V_MODE_MAP_SIZE))
73643105Sdfr	return mode_map[mode];
73743105Sdfr    else
73843105Sdfr	return NULL;
73943105Sdfr}
74043105Sdfr
74143105Sdfr#ifndef VGA_NO_BIOS
74243105Sdfrstatic void
74343105Sdfrfill_adapter_param(int code, video_adapter_t *adp)
74443105Sdfr{
74543105Sdfr    static struct {
74643105Sdfr	int primary;
74743105Sdfr	int secondary;
74843105Sdfr    } dcc[] = {
74943105Sdfr	{ DCC_MONO, 			DCC_EGA40 /* CGA monitor */ },
75043105Sdfr	{ DCC_MONO, 			DCC_EGA80 /* CGA monitor */ },
75143105Sdfr	{ DCC_MONO, 			DCC_EGA80 /* CGA emulation */ },
75243105Sdfr	{ DCC_MONO, 			DCC_EGA80 },
75343105Sdfr	{ DCC_CGA40, 			DCC_EGAMONO },
75443105Sdfr	{ DCC_CGA80, 			DCC_EGAMONO },
75543105Sdfr	{ DCC_EGA40 /* CGA monitor */, 	DCC_MONO},
75643105Sdfr	{ DCC_EGA80 /* CGA monitor */, 	DCC_MONO},
75743105Sdfr	{ DCC_EGA80 /* CGA emulation */,DCC_MONO },
75843105Sdfr	{ DCC_EGA80, 			DCC_MONO },
75943105Sdfr	{ DCC_EGAMONO, 			DCC_CGA40 },
76043105Sdfr	{ DCC_EGAMONO, 			DCC_CGA40 },
76143105Sdfr    };
76243105Sdfr
76343105Sdfr    if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) {
76443105Sdfr	adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
76543105Sdfr	adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
76643105Sdfr    } else {
76743105Sdfr	adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary];
76843105Sdfr	adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary];
76943105Sdfr    }
77043105Sdfr}
77143105Sdfr#endif /* VGA_NO_BIOS */
77243105Sdfr
77343105Sdfrstatic int
77443105Sdfrverify_adapter(video_adapter_t *adp)
77543105Sdfr{
77643105Sdfr    vm_offset_t buf;
77743105Sdfr    u_int16_t v;
77843105Sdfr
77943105Sdfr    buf = BIOS_PADDRTOVADDR(adp->va_window);
78043105Sdfr    v = readw(buf);
78143105Sdfr    writew(buf, 0xA55A);
78243105Sdfr    if (readw(buf) != 0xA55A)
78343105Sdfr	return 1;
78443105Sdfr    writew(buf, v);
78543105Sdfr
78643105Sdfr    switch (adp->va_type) {
78743105Sdfr
78843105Sdfr    case KD_EGA:
78943105Sdfr	outb(adp->va_crtc_addr, 7);
79043105Sdfr	if (inb(adp->va_crtc_addr) == 7) {
79143105Sdfr	    adp->va_type = KD_VGA;
79243105Sdfr	    adp->va_name = "vga";
79343105Sdfr	    adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE;
79443105Sdfr	}
79543105Sdfr	adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER;
79643105Sdfr	/* the color adapter may be in the 40x25 mode... XXX */
79743105Sdfr
79843105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
79943105Sdfr	/* get the BIOS video mode pointer */
80043105Sdfr	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8);
80143105Sdfr	p = BIOS_SADDRTOLADDR(p);
80243105Sdfr	if (ISMAPPED(p, sizeof(u_int32_t))) {
80343105Sdfr	    p = *(u_int32_t *)BIOS_PADDRTOVADDR(p);
80443105Sdfr	    p = BIOS_SADDRTOLADDR(p);
80543105Sdfr	    if (ISMAPPED(p, V_MODE_PARAM_SIZE))
80643105Sdfr		video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p);
80743105Sdfr	}
80843105Sdfr#endif
80943105Sdfr	break;
81043105Sdfr
81143105Sdfr    case KD_CGA:
81243105Sdfr	adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER;
81343105Sdfr	/* may be in the 40x25 mode... XXX */
81443105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
81543105Sdfr	/* get the BIOS video mode pointer */
81643105Sdfr	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
81743105Sdfr	p = BIOS_SADDRTOLADDR(p);
81843105Sdfr	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
81943105Sdfr#endif
82043105Sdfr	break;
82143105Sdfr
82243105Sdfr    case KD_MONO:
82343105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
82443105Sdfr	/* get the BIOS video mode pointer */
82543105Sdfr	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
82643105Sdfr	p = BIOS_SADDRTOLADDR(p);
82743105Sdfr	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
82843105Sdfr#endif
82943105Sdfr	break;
83043105Sdfr    }
83143105Sdfr
83243105Sdfr    return 0;
83343105Sdfr}
83443105Sdfr
83543105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
83643105Sdfr/* compare two parameter table entries */
83743105Sdfrstatic int
83843105Sdfrcomp_adpregs(u_char *buf1, u_char *buf2)
83943105Sdfr{
84043105Sdfr    static struct {
84143105Sdfr        u_char mask;
84243105Sdfr    } params[V_MODE_PARAM_SIZE] = {
84343105Sdfr	0xff, 0x00, 0xff, 		/* COLS, ROWS, POINTS */
84443105Sdfr	0x00, 0x00, 			/* page length */
84543105Sdfr	0xfe, 0xff, 0xff, 0xff,		/* sequencer registers */
84643105Sdfr	0xf3,				/* misc register */
84743105Sdfr	0xff, 0xff, 0xff, 0x7f, 0xff,	/* CRTC */
84843105Sdfr	0xff, 0xff, 0xff, 0x7f, 0xff,
84943105Sdfr	0x00, 0x00, 0x00, 0x00, 0x00,
85043105Sdfr	0x00, 0xff, 0x7f, 0xff, 0xff,
85143105Sdfr	0x7f, 0xff, 0xff, 0xef, 0xff,
85243105Sdfr	0xff, 0xff, 0xff, 0xff, 0xff,	/* attribute controller registers */
85343105Sdfr	0xff, 0xff, 0xff, 0xff, 0xff,
85443105Sdfr	0xff, 0xff, 0xff, 0xff, 0xff,
85543105Sdfr	0xff, 0xff, 0xff, 0xff, 0xf0,
85643105Sdfr	0xff, 0xff, 0xff, 0xff, 0xff,	/* GDC register */
85743105Sdfr	0xff, 0xff, 0xff, 0xff,
85843105Sdfr    };
85943105Sdfr    int identical = TRUE;
86043105Sdfr    int i;
86143105Sdfr
86243105Sdfr    if ((buf1 == NULL) || (buf2 == NULL))
86343105Sdfr	return COMP_DIFFERENT;
86443105Sdfr
86543105Sdfr    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
86643105Sdfr	if (params[i].mask == 0)	/* don't care */
86743105Sdfr	    continue;
86843105Sdfr	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
86943105Sdfr	    return COMP_DIFFERENT;
87043105Sdfr	if (buf1[i] != buf2[i])
87143105Sdfr	    identical = FALSE;
87243105Sdfr    }
87343105Sdfr    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
87443105Sdfr}
87543105Sdfr#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
87643105Sdfr
87743105Sdfr/* probe video adapters and return the number of detected adapters */
87843105Sdfrstatic int
87943105Sdfrprobe_adapters(void)
88043105Sdfr{
88143105Sdfr    video_adapter_t *adp;
88243105Sdfr    video_info_t info;
88343105Sdfr    int i;
88443105Sdfr
88543105Sdfr    /* do this test only once */
88643105Sdfr    if (init_done)
88743105Sdfr	return biosadapters;
88843105Sdfr    init_done = TRUE;
88943105Sdfr
89043105Sdfr    /*
89143105Sdfr     * Locate display adapters.
89243105Sdfr     * The AT architecture supports upto two adapters. `syscons' allows
89343105Sdfr     * the following combinations of adapters:
89443105Sdfr     *     1) MDA + CGA
89543105Sdfr     *     2) MDA + EGA/VGA color
89643105Sdfr     *     3) CGA + EGA/VGA mono
89743105Sdfr     * Note that `syscons' doesn't bother with MCGA as it is only
89843105Sdfr     * avaiable for low end PS/2 models which has 80286 or earlier CPUs,
89943105Sdfr     * thus, they are not running FreeBSD!
90043105Sdfr     * When there are two adapaters in the system, one becomes `primary'
90143105Sdfr     * and the other `secondary'. The EGA adapter has a set of DIP
90243105Sdfr     * switches on board for this information and the EGA BIOS copies
90343105Sdfr     * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88).
90443105Sdfr     * The VGA BIOS has more sophisticated mechanism and has this
90543105Sdfr     * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains
90643105Sdfr     * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH.
90743105Sdfr     */
90843105Sdfr
90943105Sdfr    /*
91043105Sdfr     * Check rtc and BIOS data area.
91143105Sdfr     * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead
91243105Sdfr     * copy of RTC_EQUIPMENT.  Bits 4 and 5 of ETC_EQUIPMENT are
91343105Sdfr     * zeros for EGA and VGA.  However, the EGA/VGA BIOS sets
91443105Sdfr     * these bits in BIOSDATA_EQUIPMENT according to the monitor
91543105Sdfr     * type detected.
91643105Sdfr     */
91743105Sdfr#ifndef VGA_NO_BIOS
91843105Sdfr    switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
91943105Sdfr    case 0:
92043105Sdfr	/* EGA/VGA */
92143105Sdfr	fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
92243105Sdfr			   biosadapter);
92343105Sdfr	break;
92443105Sdfr    case 1:
92543105Sdfr	/* CGA 40x25 */
92643105Sdfr	/* FIXME: switch to the 80x25 mode? XXX */
92743105Sdfr	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40];
92843105Sdfr	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
92943105Sdfr	break;
93043105Sdfr    case 2:
93143105Sdfr	/* CGA 80x25 */
93243105Sdfr	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80];
93343105Sdfr	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
93443105Sdfr	break;
93543105Sdfr    case 3:
93643105Sdfr	/* MDA */
93743105Sdfr	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
93843105Sdfr	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
93943105Sdfr	break;
94043105Sdfr    }
94143105Sdfr#else
94243105Sdfr    /* assume EGA/VGA? XXX */
94343105Sdfr    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80];
94443105Sdfr    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
94543105Sdfr#endif /* VGA_NO_BIOS */
94643105Sdfr
94743105Sdfr    biosadapters = 0;
94843105Sdfr    if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) {
94943105Sdfr	++biosadapters;
95043105Sdfr	biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED;
95143105Sdfr	biosadapter[V_ADP_SECONDARY].va_mode =
95243105Sdfr	    biosadapter[V_ADP_SECONDARY].va_initial_mode =
95343105Sdfr	    map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type,
95443105Sdfr			      biosadapter[V_ADP_SECONDARY].va_flags
95543105Sdfr				  & V_ADP_COLOR,
95643105Sdfr			      biosadapter[V_ADP_SECONDARY].va_initial_bios_mode);
95743105Sdfr    } else {
95843105Sdfr	biosadapter[V_ADP_SECONDARY].va_type = -1;
95943105Sdfr    }
96043105Sdfr    if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) {
96143105Sdfr	++biosadapters;
96243105Sdfr	biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED;
96343105Sdfr#ifndef VGA_NO_BIOS
96443105Sdfr	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode =
96543105Sdfr	    readb(BIOS_PADDRTOVADDR(0x449));
96643105Sdfr#else
96743105Sdfr	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3;	/* XXX */
96843105Sdfr#endif
96943105Sdfr	biosadapter[V_ADP_PRIMARY].va_mode =
97043105Sdfr	    biosadapter[V_ADP_PRIMARY].va_initial_mode =
97143105Sdfr	    map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type,
97243105Sdfr			      biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR,
97343105Sdfr			      biosadapter[V_ADP_PRIMARY].va_initial_bios_mode);
97443105Sdfr    } else {
97543105Sdfr	biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY];
97643105Sdfr	biosadapter[V_ADP_SECONDARY].va_type = -1;
97743105Sdfr    }
97843105Sdfr    if (biosadapters == 0)
97943105Sdfr	return biosadapters;
98043105Sdfr#if 0
98143105Sdfr    biosadapter[V_ADP_PRIMARY].va_index = V_ADP_PRIMARY;
98243105Sdfr    biosadapter[V_ADP_SECONDARY].va_index = V_ADP_SECONDARY;
98343105Sdfr#endif
98443105Sdfr    biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY;
98543105Sdfr    biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY;
98643105Sdfr
98743105Sdfr#if 0 /* we don't need these... */
98843105Sdfr    fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...);
98943105Sdfr    fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...);
99043105Sdfr#endif
99143105Sdfr
99243105Sdfr#if 0
99343105Sdfr    /*
99443105Sdfr     * We cannot have two video adapter of the same type; there must be
99543105Sdfr     * only one of color or mono adapter, or one each of them.
99643105Sdfr     */
99743105Sdfr    if (biosadapters > 1) {
99843105Sdfr	if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags)
99943105Sdfr	      & V_ADP_COLOR))
100043105Sdfr	    /* we have two mono or color adapters!! */
100143105Sdfr	    return (biosadapters = 0);
100243105Sdfr    }
100343105Sdfr#endif
100443105Sdfr
100543105Sdfr    /*
100643105Sdfr     * Ensure a zero start address.  This is mainly to recover after
100743105Sdfr     * switching from pcvt using userconfig().  The registers are w/o
100843105Sdfr     * for old hardware so it's too hard to relocate the active screen
100943105Sdfr     * memory.
101043105Sdfr     * This must be done before vga_save_state() for VGA.
101143105Sdfr     */
101243105Sdfr    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12);
101343105Sdfr    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
101443105Sdfr    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13);
101543105Sdfr    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
101643105Sdfr
101743105Sdfr    /* the video mode parameter table in EGA/VGA BIOS */
101843105Sdfr    /* NOTE: there can be only one EGA/VGA, wheather color or mono,
101943105Sdfr     * recognized by the video BIOS.
102043105Sdfr     */
102143105Sdfr    if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) ||
102243105Sdfr	(biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) {
102343105Sdfr	adp = &biosadapter[V_ADP_PRIMARY];
102443105Sdfr    } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) ||
102543105Sdfr	       (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) {
102643105Sdfr	adp = &biosadapter[V_ADP_SECONDARY];
102743105Sdfr    } else {
102843105Sdfr	adp = NULL;
102943105Sdfr    }
103043105Sdfr    bzero(mode_map, sizeof(mode_map));
103143105Sdfr    if (adp != NULL) {
103243105Sdfr	if (adp->va_type == KD_VGA) {
103343105Sdfr	    vga_save_state(adp, &adpstate, sizeof(adpstate));
103443105Sdfr#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
103543105Sdfr	    mode_map[adp->va_initial_mode] = adpstate.regs;
103643105Sdfr	    rows_offset = 1;
103743105Sdfr#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
103843105Sdfr	    if (video_mode_ptr == NULL) {
103943105Sdfr		mode_map[adp->va_initial_mode] = adpstate.regs;
104043105Sdfr		rows_offset = 1;
104143105Sdfr	    } else {
104243105Sdfr		/* discard the table if we are not familiar with it... */
104343105Sdfr		map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
104443105Sdfr		mp = get_mode_param(adp->va_initial_mode);
104543105Sdfr		if (mp != NULL)
104643105Sdfr		    bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs));
104743105Sdfr		switch (comp_adpregs(adpstate.regs, mp)) {
104843105Sdfr		case COMP_IDENTICAL:
104943105Sdfr		    /*
105043105Sdfr		     * OK, this parameter table looks reasonably familiar
105143105Sdfr		     * to us...
105243105Sdfr		     */
105343105Sdfr		    /*
105443105Sdfr		     * This is a kludge for Toshiba DynaBook SS433
105543105Sdfr		     * whose BIOS video mode table entry has the actual #
105643105Sdfr		     * of rows at the offset 1; BIOSes from other
105743105Sdfr		     * manufacturers store the # of rows - 1 there. XXX
105843105Sdfr		     */
105943105Sdfr		    rows_offset = adpstate.regs[1] + 1 - mp[1];
106043105Sdfr		    break;
106143105Sdfr
106243105Sdfr		case COMP_SIMILAR:
106343105Sdfr		    /*
106443105Sdfr		     * Not exactly the same, but similar enough to be
106543105Sdfr		     * trusted. However, use the saved register values
106643105Sdfr		     * for the initial mode and other modes which are
106743105Sdfr		     * based on the initial mode.
106843105Sdfr		     */
106943105Sdfr		    mode_map[adp->va_initial_mode] = adpstate.regs;
107043105Sdfr		    rows_offset = adpstate.regs[1] + 1 - mp[1];
107143105Sdfr		    adpstate.regs[1] -= rows_offset - 1;
107243105Sdfr		    break;
107343105Sdfr
107443105Sdfr		case COMP_DIFFERENT:
107543105Sdfr		default:
107643105Sdfr		    /*
107743105Sdfr		     * Don't use the paramter table in BIOS. It doesn't
107843105Sdfr		     * look familiar to us. Video mode switching is allowed
107943105Sdfr		     * only if the new mode is the same as or based on
108043105Sdfr		     * the initial mode.
108143105Sdfr		     */
108243105Sdfr		    video_mode_ptr = NULL;
108343105Sdfr		    bzero(mode_map, sizeof(mode_map));
108443105Sdfr		    mode_map[adp->va_initial_mode] = adpstate.regs;
108543105Sdfr		    rows_offset = 1;
108643105Sdfr		    break;
108743105Sdfr		}
108843105Sdfr	    }
108943105Sdfr#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
109043105Sdfr
109143105Sdfr#ifndef VGA_NO_MODE_CHANGE
109243105Sdfr	    adp->va_flags |= V_ADP_MODECHANGE;
109343105Sdfr#endif
109443105Sdfr#ifndef VGA_NO_FONT_LOADING
109543105Sdfr	    adp->va_flags |= V_ADP_FONT;
109643105Sdfr#endif
109743105Sdfr	} else if (adp->va_type == KD_EGA) {
109843105Sdfr#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
109943105Sdfr	    rows_offset = 1;
110043105Sdfr#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
110143105Sdfr	    if (video_mode_ptr == NULL) {
110243105Sdfr		rows_offset = 1;
110343105Sdfr	    } else {
110443105Sdfr		map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1);
110543105Sdfr		/* XXX how can one validate the EGA table... */
110643105Sdfr		mp = get_mode_param(adp->va_initial_mode);
110743105Sdfr		if (mp != NULL) {
110843105Sdfr		    adp->va_flags |= V_ADP_MODECHANGE;
110943105Sdfr#ifndef VGA_NO_FONT_LOADING
111043105Sdfr		    adp->va_flags |= V_ADP_FONT;
111143105Sdfr#endif
111243105Sdfr		    rows_offset = 1;
111343105Sdfr		} else {
111443105Sdfr		    /*
111543105Sdfr		     * This is serious. We will not be able to switch video
111643105Sdfr		     * modes at all...
111743105Sdfr		     */
111843105Sdfr		    video_mode_ptr = NULL;
111943105Sdfr		    bzero(mode_map, sizeof(mode_map));
112043105Sdfr		    rows_offset = 1;
112143105Sdfr                }
112243105Sdfr	    }
112343105Sdfr#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
112443105Sdfr	}
112543105Sdfr    }
112643105Sdfr
112743105Sdfr    /* remove conflicting modes if we have more than one adapter */
112843105Sdfr    if (biosadapters > 1) {
112943105Sdfr	for (i = 0; i < biosadapters; ++i) {
113043105Sdfr	    if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE))
113143105Sdfr		continue;
113243105Sdfr	    clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1,
113343105Sdfr			   (biosadapter[i].va_flags & V_ADP_COLOR) ?
113443105Sdfr			       V_INFO_COLOR : 0);
113543105Sdfr	    if ((biosadapter[i].va_type == KD_VGA)
113643105Sdfr		|| (biosadapter[i].va_type == KD_EGA)) {
113743105Sdfr		biosadapter[i].va_io_base =
113843105Sdfr		    (biosadapter[i].va_flags & V_ADP_COLOR) ?
113943105Sdfr			IO_VGA : IO_MDA;
114043105Sdfr		biosadapter[i].va_io_size = 32;
114143105Sdfr	    }
114243105Sdfr	}
114343105Sdfr    }
114443105Sdfr
114543105Sdfr    /* buffer address */
114643105Sdfr    vga_get_info(&biosadapter[V_ADP_PRIMARY],
114743105Sdfr		 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info);
114843105Sdfr    biosadapter[V_ADP_PRIMARY].va_mode_flags = info.vi_flags;
114943105Sdfr    biosadapter[V_ADP_PRIMARY].va_window = BIOS_PADDRTOVADDR(info.vi_window);
115043105Sdfr    biosadapter[V_ADP_PRIMARY].va_window_size = info.vi_window_size;
115143105Sdfr    biosadapter[V_ADP_PRIMARY].va_window_gran = info.vi_window_gran;
115243105Sdfr    if (info.vi_buffer_size == 0) {
115343105Sdfr	biosadapter[V_ADP_PRIMARY].va_buffer = 0;
115443105Sdfr	biosadapter[V_ADP_PRIMARY].va_buffer_size = 0;
115543105Sdfr    } else {
115643105Sdfr	biosadapter[V_ADP_PRIMARY].va_buffer
115743105Sdfr	    = BIOS_PADDRTOVADDR(info.vi_buffer);
115843105Sdfr	biosadapter[V_ADP_PRIMARY].va_buffer_size = info.vi_buffer_size;
115943105Sdfr    }
116043105Sdfr
116143105Sdfr    if (biosadapters > 1) {
116243105Sdfr	vga_get_info(&biosadapter[V_ADP_SECONDARY],
116343105Sdfr		     biosadapter[V_ADP_SECONDARY].va_initial_mode, &info);
116443105Sdfr	biosadapter[V_ADP_SECONDARY].va_mode_flags = info.vi_flags;
116543105Sdfr	biosadapter[V_ADP_SECONDARY].va_window =
116643105Sdfr	    BIOS_PADDRTOVADDR(info.vi_window);
116743105Sdfr	biosadapter[V_ADP_SECONDARY].va_window_size = info.vi_window_size;
116843105Sdfr	biosadapter[V_ADP_SECONDARY].va_window_gran = info.vi_window_gran;
116943105Sdfr	if (info.vi_buffer_size == 0) {
117043105Sdfr	    biosadapter[V_ADP_SECONDARY].va_buffer = 0;
117143105Sdfr	    biosadapter[V_ADP_SECONDARY].va_buffer_size = 0;
117243105Sdfr	} else {
117343105Sdfr	    biosadapter[V_ADP_SECONDARY].va_buffer =
117443105Sdfr		BIOS_PADDRTOVADDR(info.vi_buffer);
117543105Sdfr	    biosadapter[V_ADP_SECONDARY].va_buffer_size = info.vi_buffer_size;
117643105Sdfr	}
117743105Sdfr    }
117843105Sdfr
117943105Sdfr    /*
118043105Sdfr     * XXX: we should verify the following values for the primary adapter...
118143105Sdfr     * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
118243105Sdfr     * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
118343105Sdfr     *                     ? 0 : V_ADP_COLOR;
118443105Sdfr     * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
118543105Sdfr     * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
118643105Sdfr     * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
118743105Sdfr     * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
118843105Sdfr     */
118943105Sdfr
119043105Sdfr    return biosadapters;
119143105Sdfr}
119243105Sdfr
119343105Sdfr/* entry points */
119443105Sdfr
119543105Sdfrstatic int
119643105Sdfrvga_nop(void)
119743105Sdfr{
119843105Sdfr    return 0;
119943105Sdfr}
120043105Sdfr
120143105Sdfrstatic int
120243105Sdfrvga_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
120343105Sdfr{
120443105Sdfr    probe_adapters();
120543105Sdfr    if (unit >= biosadapters)
120643105Sdfr	return ENXIO;
120743105Sdfr
120843105Sdfr    *adpp = &biosadapter[unit];
120943105Sdfr
121043105Sdfr    return 0;
121143105Sdfr}
121243105Sdfr
121343105Sdfrstatic int
121443105Sdfrvga_init(int unit, video_adapter_t *adp, int flags)
121543105Sdfr{
121643105Sdfr    if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp))
121743105Sdfr	return ENXIO;
121843105Sdfr
121943105Sdfr    if (!init_done(adp)) {
122043105Sdfr	/* nothing to do really... */
122143105Sdfr	adp->va_flags |= V_ADP_INITIALIZED;
122243105Sdfr    }
122343105Sdfr
122443105Sdfr    if (!config_done(adp)) {
122543105Sdfr	if (vid_register(adp) < 0)
122643105Sdfr		return ENXIO;
122743105Sdfr	adp->va_flags |= V_ADP_REGISTERED;
122843105Sdfr    }
122943105Sdfr    if (vga_sub_configure != NULL)
123043105Sdfr	(*vga_sub_configure)(0);
123143105Sdfr
123243105Sdfr    return 0;
123343105Sdfr}
123443105Sdfr
123543105Sdfr/*
123643105Sdfr * get_info():
123743105Sdfr * Return the video_info structure of the requested video mode.
123843105Sdfr *
123943105Sdfr * all adapters
124043105Sdfr */
124143105Sdfrstatic int
124243105Sdfrvga_get_info(video_adapter_t *adp, int mode, video_info_t *info)
124343105Sdfr{
124443105Sdfr    int i;
124543105Sdfr
124643105Sdfr    if (!init_done)
124743105Sdfr	return 1;
124843105Sdfr
124943105Sdfr    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
125043105Sdfr#ifndef VGA_NO_MODE_CHANGE
125143105Sdfr    if (adp->va_flags & V_ADP_MODECHANGE) {
125243105Sdfr	/*
125343105Sdfr	 * If the parameter table entry for this mode is not found,
125443105Sdfr	 * the mode is not supported...
125543105Sdfr	 */
125643105Sdfr	if (get_mode_param(mode) == NULL)
125743105Sdfr	    return 1;
125843105Sdfr    } else
125943105Sdfr#endif /* VGA_NO_MODE_CHANGE */
126043105Sdfr    {
126143105Sdfr	/*
126243105Sdfr	 * Even if we don't support video mode switching on this adapter,
126343105Sdfr	 * the information on the initial (thus current) video mode
126443105Sdfr	 * should be made available.
126543105Sdfr	 */
126643105Sdfr	if (mode != adp->va_initial_mode)
126743105Sdfr	    return 1;
126843105Sdfr    }
126943105Sdfr
127043105Sdfr    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
127143105Sdfr	if (bios_vmode[i].vi_mode == NA)
127243105Sdfr	    continue;
127343105Sdfr	if (mode == bios_vmode[i].vi_mode) {
127443105Sdfr	    *info = bios_vmode[i];
127543105Sdfr	    return 0;
127643105Sdfr	}
127743105Sdfr    }
127843105Sdfr    return 1;
127943105Sdfr}
128043105Sdfr
128143105Sdfr/*
128243105Sdfr * query_mode():
128343105Sdfr * Find a video mode matching the requested parameters.
128443105Sdfr * Fields filled with 0 are considered "don't care" fields and
128543105Sdfr * match any modes.
128643105Sdfr *
128743105Sdfr * all adapters
128843105Sdfr */
128943105Sdfrstatic int
129043105Sdfrvga_query_mode(video_adapter_t *adp, video_info_t *info)
129143105Sdfr{
129243105Sdfr    video_info_t buf;
129343105Sdfr    int i;
129443105Sdfr
129543105Sdfr    if (!init_done)
129643105Sdfr	return -1;
129743105Sdfr
129843105Sdfr    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
129943105Sdfr	if (bios_vmode[i].vi_mode == NA)
130043105Sdfr	    continue;
130143105Sdfr
130243105Sdfr	if ((info->vi_width != 0)
130343105Sdfr	    && (info->vi_width != bios_vmode[i].vi_width))
130443105Sdfr		continue;
130543105Sdfr	if ((info->vi_height != 0)
130643105Sdfr	    && (info->vi_height != bios_vmode[i].vi_height))
130743105Sdfr		continue;
130843105Sdfr	if ((info->vi_cwidth != 0)
130943105Sdfr	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
131043105Sdfr		continue;
131143105Sdfr	if ((info->vi_cheight != 0)
131243105Sdfr	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
131343105Sdfr		continue;
131443105Sdfr	if ((info->vi_depth != 0)
131543105Sdfr	    && (info->vi_depth != bios_vmode[i].vi_depth))
131643105Sdfr		continue;
131743105Sdfr	if ((info->vi_planes != 0)
131843105Sdfr	    && (info->vi_planes != bios_vmode[i].vi_planes))
131943105Sdfr		continue;
132043105Sdfr	/* XXX: should check pixel format, memory model */
132143105Sdfr	if ((info->vi_flags != 0)
132243105Sdfr	    && (info->vi_flags != bios_vmode[i].vi_flags))
132343105Sdfr		continue;
132443105Sdfr
132543105Sdfr	/* verify if this mode is supported on this adapter */
132643105Sdfr	if (vga_get_info(adp, bios_vmode[i].vi_mode, &buf))
132743105Sdfr		continue;
132843105Sdfr	return bios_vmode[i].vi_mode;
132943105Sdfr    }
133043105Sdfr    return -1;
133143105Sdfr}
133243105Sdfr
133343105Sdfr/*
133443105Sdfr * set_mode():
133543105Sdfr * Change the video mode.
133643105Sdfr *
133743105Sdfr * EGA/VGA
133843105Sdfr */
133943105Sdfrstatic int
134043105Sdfrvga_set_mode(video_adapter_t *adp, int mode)
134143105Sdfr{
134243105Sdfr#ifndef VGA_NO_MODE_CHANGE
134343105Sdfr    video_info_t info;
134443105Sdfr    adp_state_t params;
134543105Sdfr
134643105Sdfr    prologue(adp, V_ADP_MODECHANGE, 1);
134743105Sdfr
134843105Sdfr    mode = map_gen_mode_num(adp->va_type,
134943105Sdfr			    adp->va_flags & V_ADP_COLOR, mode);
135043105Sdfr    if (vga_get_info(adp, mode, &info))
135143105Sdfr	return 1;
135243105Sdfr    params.sig = V_STATE_SIG;
135343105Sdfr    bcopy(get_mode_param(mode), params.regs, sizeof(params.regs));
135443105Sdfr
135543105Sdfr    switch (mode) {
135643105Sdfr    case M_VGA_C80x60: case M_VGA_M80x60:
135743105Sdfr	params.regs[2]  = 0x08;
135843105Sdfr	params.regs[19] = 0x47;
135943105Sdfr	goto special_480l;
136043105Sdfr
136143105Sdfr    case M_VGA_C80x30: case M_VGA_M80x30:
136243105Sdfr	params.regs[19] = 0x4f;
136343105Sdfrspecial_480l:
136443105Sdfr	params.regs[9] |= 0xc0;
136543105Sdfr	params.regs[16] = 0x08;
136643105Sdfr	params.regs[17] = 0x3e;
136743105Sdfr	params.regs[26] = 0xea;
136843105Sdfr	params.regs[28] = 0xdf;
136943105Sdfr	params.regs[31] = 0xe7;
137043105Sdfr	params.regs[32] = 0x04;
137143105Sdfr	goto setup_mode;
137243105Sdfr
137343105Sdfr    case M_ENH_C80x43: case M_ENH_B80x43:
137443105Sdfr	params.regs[28] = 87;
137543105Sdfr	goto special_80x50;
137643105Sdfr
137743105Sdfr    case M_VGA_C80x50: case M_VGA_M80x50:
137843105Sdfrspecial_80x50:
137943105Sdfr	params.regs[2] = 8;
138043105Sdfr	params.regs[19] = 7;
138143105Sdfr	goto setup_mode;
138243105Sdfr
138343105Sdfr    case M_VGA_C40x25: case M_VGA_C80x25:
138443105Sdfr    case M_VGA_M80x25:
138543105Sdfr    case M_B40x25:     case M_C40x25:
138643105Sdfr    case M_B80x25:     case M_C80x25:
138743105Sdfr    case M_ENH_B40x25: case M_ENH_C40x25:
138843105Sdfr    case M_ENH_B80x25: case M_ENH_C80x25:
138943105Sdfr    case M_EGAMONO80x25:
139043105Sdfr
139143105Sdfrsetup_mode:
139243105Sdfr	vga_load_state(adp, &params);
139343105Sdfr	break;
139443105Sdfr
139543105Sdfr    case M_VGA_MODEX:
139643105Sdfr	/* "unchain" the VGA mode */
139743105Sdfr	params.regs[5-1+0x04] &= 0xf7;
139843105Sdfr	params.regs[5-1+0x04] |= 0x04;
139943105Sdfr	/* turn off doubleword mode */
140043105Sdfr	params.regs[10+0x14] &= 0xbf;
140143105Sdfr	/* turn off word adressing */
140243105Sdfr	params.regs[10+0x17] |= 0x40;
140343105Sdfr	/* set logical screen width */
140443105Sdfr	params.regs[10+0x13] = 80;
140543105Sdfr	/* set 240 lines */
140643105Sdfr	params.regs[10+0x11] = 0x2c;
140743105Sdfr	params.regs[10+0x06] = 0x0d;
140843105Sdfr	params.regs[10+0x07] = 0x3e;
140943105Sdfr	params.regs[10+0x10] = 0xea;
141043105Sdfr	params.regs[10+0x11] = 0xac;
141143105Sdfr	params.regs[10+0x12] = 0xdf;
141243105Sdfr	params.regs[10+0x15] = 0xe7;
141343105Sdfr	params.regs[10+0x16] = 0x06;
141443105Sdfr	/* set vertical sync polarity to reflect aspect ratio */
141543105Sdfr	params.regs[9] = 0xe3;
141643105Sdfr	goto setup_grmode;
141743105Sdfr
141843105Sdfr    case M_BG320:     case M_CG320:     case M_BG640:
141943105Sdfr    case M_CG320_D:   case M_CG640_E:
142043105Sdfr    case M_CG640x350: case M_ENH_CG640:
142143105Sdfr    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
142243105Sdfr
142343105Sdfrsetup_grmode:
142443105Sdfr	vga_load_state(adp, &params);
142543105Sdfr	break;
142643105Sdfr
142743105Sdfr    default:
142843105Sdfr	return 1;
142943105Sdfr    }
143043105Sdfr
143143105Sdfr    adp->va_mode = mode;
143243105Sdfr    adp->va_mode_flags = info.vi_flags;
143343105Sdfr    adp->va_flags &= ~V_ADP_COLOR;
143443105Sdfr    adp->va_flags |=
143543105Sdfr	(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
143643105Sdfr    adp->va_crtc_addr =
143743105Sdfr	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
143843105Sdfr    adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
143943105Sdfr    adp->va_window_size = info.vi_window_size;
144043105Sdfr    adp->va_window_gran = info.vi_window_gran;
144143105Sdfr    if (info.vi_buffer_size == 0) {
144243105Sdfr    	adp->va_buffer = 0;
144343105Sdfr    	adp->va_buffer_size = 0;
144443105Sdfr    } else {
144543105Sdfr    	adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
144643105Sdfr    	adp->va_buffer_size = info.vi_buffer_size;
144743105Sdfr    }
144843105Sdfr
144943105Sdfr    /* move hardware cursor out of the way */
145043105Sdfr    (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
145143105Sdfr
145243105Sdfr    return 0;
145343105Sdfr#else /* VGA_NO_MODE_CHANGE */
145443105Sdfr    return 1;
145543105Sdfr#endif /* VGA_NO_MODE_CHANGE */
145643105Sdfr}
145743105Sdfr
145843105Sdfr#ifndef VGA_NO_FONT_LOADING
145943105Sdfr
146043105Sdfrstatic void
146143105Sdfrset_font_mode(video_adapter_t *adp, u_char *buf)
146243105Sdfr{
146343105Sdfr    u_char *mp;
146443105Sdfr    int s;
146543105Sdfr
146643105Sdfr    s = splhigh();
146743105Sdfr
146843105Sdfr    /* save register values */
146943105Sdfr    if (adp->va_type == KD_VGA) {
147043105Sdfr	outb(TSIDX, 0x02); buf[0] = inb(TSREG);
147143105Sdfr	outb(TSIDX, 0x04); buf[1] = inb(TSREG);
147243105Sdfr	outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
147343105Sdfr	outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
147443105Sdfr	outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
147543105Sdfr	inb(adp->va_crtc_addr + 6);
147643105Sdfr	outb(ATC, 0x10); buf[5] = inb(ATC + 1);
147743105Sdfr    } else /* if (adp->va_type == KD_EGA) */ {
147843105Sdfr	/*
147943105Sdfr	 * EGA cannot be read; copy parameters from the mode parameter
148043105Sdfr	 * table.
148143105Sdfr	 */
148243105Sdfr	mp = get_mode_param(adp->va_mode);
148343105Sdfr	buf[0] = mp[5 + 0x02 - 1];
148443105Sdfr	buf[1] = mp[5 + 0x04 - 1];
148543105Sdfr	buf[2] = mp[55 + 0x04];
148643105Sdfr	buf[3] = mp[55 + 0x05];
148743105Sdfr	buf[4] = mp[55 + 0x06];
148843105Sdfr	buf[5] = mp[35 + 0x10];
148943105Sdfr    }
149043105Sdfr
149143105Sdfr    /* setup vga for loading fonts */
149243105Sdfr    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
149343105Sdfr    outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
149443105Sdfr    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
149543105Sdfr    outb(ATC, 0x20);				/* enable palette */
149643105Sdfr
149743105Sdfr#if VGA_SLOW_IOACCESS
149843105Sdfr#ifdef VGA_ALT_SEQACCESS
149943105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x01);
150043105Sdfr#endif
150143105Sdfr    outb(TSIDX, 0x02); outb(TSREG, 0x04);
150243105Sdfr    outb(TSIDX, 0x04); outb(TSREG, 0x07);
150343105Sdfr#ifdef VGA_ALT_SEQACCESS
150443105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x03);
150543105Sdfr#endif
150643105Sdfr    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
150743105Sdfr    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
150843105Sdfr    outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
150943105Sdfr#else /* VGA_SLOW_IOACCESS */
151043105Sdfr#ifdef VGA_ALT_SEQACCESS
151143105Sdfr    outw(TSIDX, 0x0100);
151243105Sdfr#endif
151343105Sdfr    outw(TSIDX, 0x0402);
151443105Sdfr    outw(TSIDX, 0x0704);
151543105Sdfr#ifdef VGA_ALT_SEQACCESS
151643105Sdfr    outw(TSIDX, 0x0300);
151743105Sdfr#endif
151843105Sdfr    outw(GDCIDX, 0x0204);
151943105Sdfr    outw(GDCIDX, 0x0005);
152043105Sdfr    outw(GDCIDX, 0x0406);               /* addr = a0000, 64kb */
152143105Sdfr#endif /* VGA_SLOW_IOACCESS */
152243105Sdfr
152343105Sdfr    splx(s);
152443105Sdfr}
152543105Sdfr
152643105Sdfrstatic void
152743105Sdfrset_normal_mode(video_adapter_t *adp, u_char *buf)
152843105Sdfr{
152943105Sdfr    int s;
153043105Sdfr
153143105Sdfr    s = splhigh();
153243105Sdfr
153343105Sdfr    /* setup vga for normal operation mode again */
153443105Sdfr    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
153543105Sdfr    outb(ATC, 0x10); outb(ATC, buf[5]);
153643105Sdfr    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
153743105Sdfr    outb(ATC, 0x20);				/* enable palette */
153843105Sdfr
153943105Sdfr#if VGA_SLOW_IOACCESS
154043105Sdfr#ifdef VGA_ALT_SEQACCESS
154143105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x01);
154243105Sdfr#endif
154343105Sdfr    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
154443105Sdfr    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
154543105Sdfr#ifdef VGA_ALT_SEQACCESS
154643105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x03);
154743105Sdfr#endif
154843105Sdfr    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
154943105Sdfr    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
155043105Sdfr    if (adp->va_crtc_addr == MONO_CRTC) {
155143105Sdfr	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
155243105Sdfr    } else {
155343105Sdfr	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
155443105Sdfr    }
155543105Sdfr#else /* VGA_SLOW_IOACCESS */
155643105Sdfr#ifdef VGA_ALT_SEQACCESS
155743105Sdfr    outw(TSIDX, 0x0100);
155843105Sdfr#endif
155943105Sdfr    outw(TSIDX, 0x0002 | (buf[0] << 8));
156043105Sdfr    outw(TSIDX, 0x0004 | (buf[1] << 8));
156143105Sdfr#ifdef VGA_ALT_SEQACCESS
156243105Sdfr    outw(TSIDX, 0x0300);
156343105Sdfr#endif
156443105Sdfr    outw(GDCIDX, 0x0004 | (buf[2] << 8));
156543105Sdfr    outw(GDCIDX, 0x0005 | (buf[3] << 8));
156643105Sdfr    if (adp->va_crtc_addr == MONO_CRTC)
156743105Sdfr        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
156843105Sdfr    else
156943105Sdfr        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
157043105Sdfr#endif /* VGA_SLOW_IOACCESS */
157143105Sdfr
157243105Sdfr    splx(s);
157343105Sdfr}
157443105Sdfr
157543105Sdfr#endif /* VGA_NO_FONT_LOADING */
157643105Sdfr
157743105Sdfr/*
157843105Sdfr * save_font():
157943105Sdfr * Read the font data in the requested font page from the video adapter.
158043105Sdfr *
158143105Sdfr * EGA/VGA
158243105Sdfr */
158343105Sdfrstatic int
158443105Sdfrvga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
158543105Sdfr	      int ch, int count)
158643105Sdfr{
158743105Sdfr#ifndef VGA_NO_FONT_LOADING
158843105Sdfr    u_char buf[PARAM_BUFSIZE];
158943105Sdfr    u_int32_t segment;
159043105Sdfr    int c;
159143105Sdfr#ifdef VGA_ALT_SEQACCESS
159243105Sdfr    int s;
159343105Sdfr    u_char val = 0;
159443105Sdfr#endif
159543105Sdfr
159643105Sdfr    prologue(adp, V_ADP_FONT, 1);
159743105Sdfr
159843105Sdfr    if (fontsize < 14) {
159943105Sdfr	/* FONT_8 */
160043105Sdfr	fontsize = 8;
160143105Sdfr    } else if (fontsize >= 32) {
160243105Sdfr	fontsize = 32;
160343105Sdfr    } else if (fontsize >= 16) {
160443105Sdfr	/* FONT_16 */
160543105Sdfr	fontsize = 16;
160643105Sdfr    } else {
160743105Sdfr	/* FONT_14 */
160843105Sdfr	fontsize = 14;
160943105Sdfr    }
161043105Sdfr
161143105Sdfr    if (page < 0 || page >= 8)
161243105Sdfr	return 1;
161343105Sdfr    segment = FONT_BUF + 0x4000*page;
161443105Sdfr    if (page > 3)
161543105Sdfr	segment -= 0xe000;
161643105Sdfr
161743105Sdfr#ifdef VGA_ALT_SEQACCESS
161843105Sdfr    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
161943105Sdfr	s = splhigh();
162043105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x01);
162143105Sdfr	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
162243105Sdfr	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
162343105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x03);
162443105Sdfr	splx(s);
162543105Sdfr    }
162643105Sdfr#endif
162743105Sdfr
162843105Sdfr    set_font_mode(adp, buf);
162943105Sdfr    if (fontsize == 32) {
163043105Sdfr	bcopy_fromio(segment + ch*32, data, fontsize*count);
163143105Sdfr    } else {
163243105Sdfr	for (c = ch; count > 0; ++c, --count) {
163343105Sdfr	    bcopy_fromio(segment + c*32, data, fontsize);
163443105Sdfr	    data += fontsize;
163543105Sdfr	}
163643105Sdfr    }
163743105Sdfr    set_normal_mode(adp, buf);
163843105Sdfr
163943105Sdfr#ifdef VGA_ALT_SEQACCESS
164043105Sdfr    if (adp->va_type == KD_VGA) {
164143105Sdfr	s = splhigh();
164243105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x01);
164343105Sdfr	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
164443105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x03);
164543105Sdfr	splx(s);
164643105Sdfr    }
164743105Sdfr#endif
164843105Sdfr
164943105Sdfr    return 0;
165043105Sdfr#else /* VGA_NO_FONT_LOADING */
165143105Sdfr    return 1;
165243105Sdfr#endif /* VGA_NO_FONT_LOADING */
165343105Sdfr}
165443105Sdfr
165543105Sdfr/*
165643105Sdfr * load_font():
165743105Sdfr * Set the font data in the requested font page.
165843105Sdfr * NOTE: it appears that some recent video adapters do not support
165943105Sdfr * the font page other than 0... XXX
166043105Sdfr *
166143105Sdfr * EGA/VGA
166243105Sdfr */
166343105Sdfrstatic int
166443105Sdfrvga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
166543105Sdfr	      int ch, int count)
166643105Sdfr{
166743105Sdfr#ifndef VGA_NO_FONT_LOADING
166843105Sdfr    u_char buf[PARAM_BUFSIZE];
166943105Sdfr    u_int32_t segment;
167043105Sdfr    int c;
167143105Sdfr#ifdef VGA_ALT_SEQACCESS
167243105Sdfr    int s;
167343105Sdfr    u_char val = 0;
167443105Sdfr#endif
167543105Sdfr
167643105Sdfr    prologue(adp, V_ADP_FONT, 1);
167743105Sdfr
167843105Sdfr    if (fontsize < 14) {
167943105Sdfr	/* FONT_8 */
168043105Sdfr	fontsize = 8;
168143105Sdfr    } else if (fontsize >= 32) {
168243105Sdfr	fontsize = 32;
168343105Sdfr    } else if (fontsize >= 16) {
168443105Sdfr	/* FONT_16 */
168543105Sdfr	fontsize = 16;
168643105Sdfr    } else {
168743105Sdfr	/* FONT_14 */
168843105Sdfr	fontsize = 14;
168943105Sdfr    }
169043105Sdfr
169143105Sdfr    if (page < 0 || page >= 8)
169243105Sdfr	return 1;
169343105Sdfr    segment = FONT_BUF + 0x4000*page;
169443105Sdfr    if (page > 3)
169543105Sdfr	segment -= 0xe000;
169643105Sdfr
169743105Sdfr#ifdef VGA_ALT_SEQACCESS
169843105Sdfr    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
169943105Sdfr	s = splhigh();
170043105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x01);
170143105Sdfr	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
170243105Sdfr	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
170343105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x03);
170443105Sdfr	splx(s);
170543105Sdfr    }
170643105Sdfr#endif
170743105Sdfr
170843105Sdfr    set_font_mode(adp, buf);
170943105Sdfr    if (fontsize == 32) {
171043105Sdfr	bcopy_toio(data, segment + ch*32, fontsize*count);
171143105Sdfr    } else {
171243105Sdfr	for (c = ch; count > 0; ++c, --count) {
171343105Sdfr	    bcopy_toio(data, segment + c*32, fontsize);
171443105Sdfr	    data += fontsize;
171543105Sdfr	}
171643105Sdfr    }
171743105Sdfr    set_normal_mode(adp, buf);
171843105Sdfr
171943105Sdfr#ifdef VGA_ALT_SEQACCESS
172043105Sdfr    if (adp->va_type == KD_VGA) {
172143105Sdfr	s = splhigh();
172243105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x01);
172343105Sdfr	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
172443105Sdfr	outb(TSIDX, 0x00); outb(TSREG, 0x03);
172543105Sdfr	splx(s);
172643105Sdfr    }
172743105Sdfr#endif
172843105Sdfr
172943105Sdfr    return 0;
173043105Sdfr#else /* VGA_NO_FONT_LOADING */
173143105Sdfr    return 1;
173243105Sdfr#endif /* VGA_NO_FONT_LOADING */
173343105Sdfr}
173443105Sdfr
173543105Sdfr/*
173643105Sdfr * show_font():
173743105Sdfr * Activate the requested font page.
173843105Sdfr * NOTE: it appears that some recent video adapters do not support
173943105Sdfr * the font page other than 0... XXX
174043105Sdfr *
174143105Sdfr * EGA/VGA
174243105Sdfr */
174343105Sdfrstatic int
174443105Sdfrvga_show_font(video_adapter_t *adp, int page)
174543105Sdfr{
174643105Sdfr#ifndef VGA_NO_FONT_LOADING
174743105Sdfr    static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
174843105Sdfr    int s;
174943105Sdfr
175043105Sdfr    prologue(adp, V_ADP_FONT, 1);
175143105Sdfr    if (page < 0 || page >= 8)
175243105Sdfr	return 1;
175343105Sdfr
175443105Sdfr    s = splhigh();
175543105Sdfr    outb(TSIDX, 0x03); outb(TSREG, cg[page]);
175643105Sdfr    splx(s);
175743105Sdfr
175843105Sdfr    return 0;
175943105Sdfr#else /* VGA_NO_FONT_LOADING */
176043105Sdfr    return 1;
176143105Sdfr#endif /* VGA_NO_FONT_LOADING */
176243105Sdfr}
176343105Sdfr
176443105Sdfr/*
176543105Sdfr * save_palette():
176643105Sdfr * Read DAC values. The values have expressed in 8 bits.
176743105Sdfr *
176843105Sdfr * VGA
176943105Sdfr */
177043105Sdfrstatic int
177143105Sdfrvga_save_palette(video_adapter_t *adp, u_char *palette)
177243105Sdfr{
177343105Sdfr    int i;
177443105Sdfr
177543105Sdfr    prologue(adp, V_ADP_PALETTE, 1);
177643105Sdfr
177743105Sdfr    /*
177843105Sdfr     * We store 8 bit values in the palette buffer, while the standard
177943105Sdfr     * VGA has 6 bit DAC .
178043105Sdfr     */
178143105Sdfr    outb(PALRADR, 0x00);
178243105Sdfr    for (i = 0; i < 256*3; ++i)
178343105Sdfr	palette[i] = inb(PALDATA) << 2;
178443105Sdfr    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
178543105Sdfr    return 0;
178643105Sdfr}
178743105Sdfr
178843105Sdfr/*
178943105Sdfr * load_palette():
179043105Sdfr * Set DAC values.
179143105Sdfr *
179243105Sdfr * VGA
179343105Sdfr */
179443105Sdfrstatic int
179543105Sdfrvga_load_palette(video_adapter_t *adp, u_char *palette)
179643105Sdfr{
179743105Sdfr    int i;
179843105Sdfr
179943105Sdfr    prologue(adp, V_ADP_PALETTE, 1);
180043105Sdfr
180143105Sdfr    outb(PIXMASK, 0xff);		/* no pixelmask */
180243105Sdfr    outb(PALWADR, 0x00);
180343105Sdfr    for (i = 0; i < 256*3; ++i)
180443105Sdfr	outb(PALDATA, palette[i] >> 2);
180543105Sdfr    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
180643105Sdfr    outb(ATC, 0x20);			/* enable palette */
180743105Sdfr    return 0;
180843105Sdfr}
180943105Sdfr
181043105Sdfr/*
181143105Sdfr * set_border():
181243105Sdfr * Change the border color.
181343105Sdfr *
181443105Sdfr * CGA/EGA/VGA
181543105Sdfr */
181643105Sdfrstatic int
181743105Sdfrvga_set_border(video_adapter_t *adp, int color)
181843105Sdfr{
181943105Sdfr    prologue(adp, V_ADP_BORDER, 1);
182043105Sdfr
182143105Sdfr    switch (adp->va_type) {
182243105Sdfr    case KD_EGA:
182343105Sdfr    case KD_VGA:
182443105Sdfr	inb(adp->va_crtc_addr + 6);	/* reset flip-flop */
182543105Sdfr	outb(ATC, 0x31); outb(ATC, color & 0xff);
182643105Sdfr	break;
182743105Sdfr    case KD_CGA:
182843105Sdfr	outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */
182943105Sdfr	break;
183043105Sdfr    case KD_MONO:
183143105Sdfr    case KD_HERCULES:
183243105Sdfr    default:
183343105Sdfr	break;
183443105Sdfr    }
183543105Sdfr    return 0;
183643105Sdfr}
183743105Sdfr
183843105Sdfr/*
183943105Sdfr * save_state():
184043105Sdfr * Read video register values.
184143105Sdfr * NOTE: this function only reads the standard EGA/VGA registers.
184243105Sdfr * any extra/extended registers of SVGA adapters are not saved.
184343105Sdfr *
184443105Sdfr * VGA
184543105Sdfr */
184643105Sdfrstatic int
184743105Sdfrvga_save_state(video_adapter_t *adp, void *p, size_t size)
184843105Sdfr{
184943105Sdfr    video_info_t info;
185043105Sdfr    u_char *buf;
185143105Sdfr    int crtc_addr;
185243105Sdfr    int i, j;
185343105Sdfr    int s;
185443105Sdfr
185543105Sdfr    if (size == 0) {
185643105Sdfr	/* return the required buffer size */
185743105Sdfr	prologue(adp, V_ADP_STATESAVE, 0);
185843105Sdfr	return sizeof(adp_state_t);
185943105Sdfr    } else {
186043105Sdfr	prologue(adp, V_ADP_STATESAVE, 1);
186143105Sdfr	if (size < sizeof(adp_state_t))
186243105Sdfr	    return 1;
186343105Sdfr    }
186443105Sdfr
186543105Sdfr    ((adp_state_t *)p)->sig = V_STATE_SIG;
186643105Sdfr    buf = ((adp_state_t *)p)->regs;
186743105Sdfr    bzero(buf, V_MODE_PARAM_SIZE);
186843105Sdfr    crtc_addr = adp->va_crtc_addr;
186943105Sdfr
187043105Sdfr    s = splhigh();
187143105Sdfr
187243105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
187343105Sdfr    for (i = 0, j = 5; i < 4; i++) {
187443105Sdfr	outb(TSIDX, i + 1);
187543105Sdfr	buf[j++]  =  inb(TSREG);
187643105Sdfr    }
187743105Sdfr    buf[9]  =  inb(MISC + 10);			/* dot-clock */
187843105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
187943105Sdfr
188043105Sdfr    for (i = 0, j = 10; i < 25; i++) {		/* crtc */
188143105Sdfr	outb(crtc_addr, i);
188243105Sdfr	buf[j++]  =  inb(crtc_addr + 1);
188343105Sdfr    }
188443105Sdfr    for (i = 0, j = 35; i < 20; i++) {		/* attribute ctrl */
188543105Sdfr        inb(crtc_addr + 6);			/* reset flip-flop */
188643105Sdfr	outb(ATC, i);
188743105Sdfr	buf[j++]  =  inb(ATC + 1);
188843105Sdfr    }
188943105Sdfr    for (i = 0, j = 55; i < 9; i++) {		/* graph data ctrl */
189043105Sdfr	outb(GDCIDX, i);
189143105Sdfr	buf[j++]  =  inb(GDCREG);
189243105Sdfr    }
189343105Sdfr    inb(crtc_addr + 6);				/* reset flip-flop */
189443105Sdfr    outb(ATC, 0x20);				/* enable palette */
189543105Sdfr
189643105Sdfr    splx(s);
189743105Sdfr
189843105Sdfr#if 1
189943105Sdfr    if (vga_get_info(adp, adp->va_mode, &info) == 0) {
190043105Sdfr	if (info.vi_flags & V_INFO_GRAPHICS) {
190143105Sdfr	    buf[0] = info.vi_width/info.vi_cwidth; /* COLS */
190243105Sdfr	    buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */
190343105Sdfr	} else {
190443105Sdfr	    buf[0] = info.vi_width;		/* COLS */
190543105Sdfr	    buf[1] = info.vi_height - 1;	/* ROWS */
190643105Sdfr	}
190743105Sdfr	buf[2] = info.vi_cheight;		/* POINTS */
190843105Sdfr    } else {
190943105Sdfr	/* XXX: shouldn't be happening... */
191043105Sdfr	printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
191143105Sdfr	       adp->va_unit, adp->va_name);
191243105Sdfr    }
191343105Sdfr#else
191443105Sdfr    buf[0] = readb(BIOS_PADDRTOVADDR(0x44a));	/* COLS */
191543105Sdfr    buf[1] = readb(BIOS_PADDRTOVADDR(0x484));	/* ROWS */
191643105Sdfr    buf[2] = readb(BIOS_PADDRTOVADDR(0x485));	/* POINTS */
191743105Sdfr    buf[3] = readb(BIOS_PADDRTOVADDR(0x44c));
191843105Sdfr    buf[4] = readb(BIOS_PADDRTOVADDR(0x44d));
191943105Sdfr#endif
192043105Sdfr
192143105Sdfr    return 0;
192243105Sdfr}
192343105Sdfr
192443105Sdfr/*
192543105Sdfr * load_state():
192643105Sdfr * Set video registers at once.
192743105Sdfr * NOTE: this function only updates the standard EGA/VGA registers.
192843105Sdfr * any extra/extended registers of SVGA adapters are not changed.
192943105Sdfr *
193043105Sdfr * EGA/VGA
193143105Sdfr */
193243105Sdfrstatic int
193343105Sdfrvga_load_state(video_adapter_t *adp, void *p)
193443105Sdfr{
193543105Sdfr    u_char *buf;
193643105Sdfr    int crtc_addr;
193743105Sdfr    int s;
193843105Sdfr    int i;
193943105Sdfr
194043105Sdfr    prologue(adp, V_ADP_STATELOAD, 1);
194143105Sdfr    if (((adp_state_t *)p)->sig != V_STATE_SIG)
194243105Sdfr	return 1;
194343105Sdfr
194443105Sdfr    buf = ((adp_state_t *)p)->regs;
194543105Sdfr    crtc_addr = adp->va_crtc_addr;
194643105Sdfr
194743105Sdfr    s = splhigh();
194843105Sdfr
194943105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
195043105Sdfr    for (i = 0; i < 4; ++i) {			/* program sequencer */
195143105Sdfr	outb(TSIDX, i + 1);
195243105Sdfr	outb(TSREG, buf[i + 5]);
195343105Sdfr    }
195443105Sdfr    outb(MISC, buf[9]);				/* set dot-clock */
195543105Sdfr    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
195643105Sdfr    outb(crtc_addr, 0x11);
195743105Sdfr    outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F);
195843105Sdfr    for (i = 0; i < 25; ++i) {			/* program crtc */
195943105Sdfr	outb(crtc_addr, i);
196043105Sdfr	outb(crtc_addr + 1, buf[i + 10]);
196143105Sdfr    }
196243105Sdfr    inb(crtc_addr+6);				/* reset flip-flop */
196343105Sdfr    for (i = 0; i < 20; ++i) {			/* program attribute ctrl */
196443105Sdfr	outb(ATC, i);
196543105Sdfr	outb(ATC, buf[i + 35]);
196643105Sdfr    }
196743105Sdfr    for (i = 0; i < 9; ++i) {			/* program graph data ctrl */
196843105Sdfr	outb(GDCIDX, i);
196943105Sdfr	outb(GDCREG, buf[i + 55]);
197043105Sdfr    }
197143105Sdfr    inb(crtc_addr + 6);				/* reset flip-flop */
197243105Sdfr    outb(ATC, 0x20);				/* enable palette */
197343105Sdfr
197443105Sdfr#ifndef VGA_NO_BIOS
197543105Sdfr    if (adp->va_unit == V_ADP_PRIMARY) {
197643105Sdfr	writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]);	/* COLS */
197743105Sdfr	writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */
197843105Sdfr	writeb(BIOS_PADDRTOVADDR(0x485), buf[2]);	/* POINTS */
197943105Sdfr#if 0
198043105Sdfr	writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]);
198143105Sdfr	writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]);
198243105Sdfr#endif
198343105Sdfr    }
198443105Sdfr#endif /* VGA_NO_BIOS */
198543105Sdfr
198643105Sdfr    splx(s);
198743105Sdfr    return 0;
198843105Sdfr}
198943105Sdfr
199043105Sdfr/*
199143105Sdfr * set_origin():
199243105Sdfr * Change the origin (window mapping) of the banked frame buffer.
199343105Sdfr */
199443105Sdfrstatic int
199543105Sdfrvga_set_origin(video_adapter_t *adp, off_t offset)
199643105Sdfr{
199743105Sdfr    /*
199843105Sdfr     * The standard video modes do not require window mapping;
199943105Sdfr     * always return error.
200043105Sdfr     */
200143105Sdfr    return 1;
200243105Sdfr}
200343105Sdfr
200443105Sdfr/*
200543105Sdfr * read_hw_cursor():
200643105Sdfr * Read the position of the hardware text cursor.
200743105Sdfr *
200843105Sdfr * all adapters
200943105Sdfr */
201043105Sdfrstatic int
201143105Sdfrvga_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
201243105Sdfr{
201343105Sdfr    video_info_t info;
201443105Sdfr    u_int16_t off;
201543105Sdfr    int s;
201643105Sdfr
201743105Sdfr    if (!init_done)
201843105Sdfr	return 1;
201943105Sdfr
202043105Sdfr    (*vidsw[adp->va_index]->get_info)(adp, adp->va_mode, &info);
202143105Sdfr    if (info.vi_flags & V_INFO_GRAPHICS)
202243105Sdfr	return 1;
202343105Sdfr
202443105Sdfr    s = spltty();
202543105Sdfr    outb(adp->va_crtc_addr, 14);
202643105Sdfr    off = inb(adp->va_crtc_addr + 1);
202743105Sdfr    outb(adp->va_crtc_addr, 15);
202843105Sdfr    off = (off << 8) | inb(adp->va_crtc_addr + 1);
202943105Sdfr    splx(s);
203043105Sdfr
203143105Sdfr    *row = off / info.vi_width;
203243105Sdfr    *col = off % info.vi_width;
203343105Sdfr
203443105Sdfr    return 0;
203543105Sdfr}
203643105Sdfr
203743105Sdfr/*
203843105Sdfr * set_hw_cursor():
203943105Sdfr * Move the hardware text cursor.  If col and row are both -1,
204043105Sdfr * the cursor won't be shown.
204143105Sdfr *
204243105Sdfr * all adapters
204343105Sdfr */
204443105Sdfrstatic int
204543105Sdfrvga_set_hw_cursor(video_adapter_t *adp, int col, int row)
204643105Sdfr{
204743105Sdfr    video_info_t info;
204843105Sdfr    u_int16_t off;
204943105Sdfr    int s;
205043105Sdfr
205143105Sdfr    if (!init_done)
205243105Sdfr	return 1;
205343105Sdfr
205443105Sdfr    if ((col == -1) && (row == -1)) {
205543105Sdfr	off = -1;
205643105Sdfr    } else {
205743105Sdfr	(*vidsw[adp->va_index]->get_info)(adp, adp->va_mode, &info);
205843105Sdfr	if (info.vi_flags & V_INFO_GRAPHICS)
205943105Sdfr	    return 1;
206043105Sdfr	off = row*info.vi_width + col;
206143105Sdfr    }
206243105Sdfr
206343105Sdfr    s = spltty();
206443105Sdfr    outb(adp->va_crtc_addr, 14);
206543105Sdfr    outb(adp->va_crtc_addr + 1, off >> 8);
206643105Sdfr    outb(adp->va_crtc_addr, 15);
206743105Sdfr    outb(adp->va_crtc_addr + 1, off & 0x00ff);
206843105Sdfr    splx(s);
206943105Sdfr
207043105Sdfr    return 0;
207143105Sdfr}
207243105Sdfr
207343105Sdfr/*
207443105Sdfr * set_hw_cursor_shape():
207543105Sdfr * Change the shape of the hardware text cursor. If the height is
207643105Sdfr * zero or negative, the cursor won't be shown.
207743105Sdfr *
207843105Sdfr * all adapters
207943105Sdfr */
208043105Sdfrstatic int
208143105Sdfrvga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
208243105Sdfr			int celsize, int blink)
208343105Sdfr{
208443105Sdfr    int s;
208543105Sdfr
208643105Sdfr    if (!init_done)
208743105Sdfr	return 1;
208843105Sdfr
208943105Sdfr    s = spltty();
209043105Sdfr    switch (adp->va_type) {
209143105Sdfr    case KD_VGA:
209243105Sdfr    case KD_CGA:
209343105Sdfr    case KD_MONO:
209443105Sdfr    case KD_HERCULES:
209543105Sdfr    default:
209643105Sdfr	if (height <= 0) {
209743105Sdfr	    /* make the cursor invisible */
209843105Sdfr	    outb(adp->va_crtc_addr, 10);
209943105Sdfr	    outb(adp->va_crtc_addr + 1, 32);
210043105Sdfr	    outb(adp->va_crtc_addr, 11);
210143105Sdfr	    outb(adp->va_crtc_addr + 1, 0);
210243105Sdfr	} else {
210343105Sdfr	    outb(adp->va_crtc_addr, 10);
210443105Sdfr	    outb(adp->va_crtc_addr + 1, celsize - base - height);
210543105Sdfr	    outb(adp->va_crtc_addr, 11);
210643105Sdfr	    outb(adp->va_crtc_addr + 1, celsize - base - 1);
210743105Sdfr	}
210843105Sdfr	break;
210943105Sdfr    case KD_EGA:
211043105Sdfr	if (height <= 0) {
211143105Sdfr	    /* make the cursor invisible */
211243105Sdfr	    outb(adp->va_crtc_addr, 10);
211343105Sdfr	    outb(adp->va_crtc_addr + 1, celsize);
211443105Sdfr	    outb(adp->va_crtc_addr, 11);
211543105Sdfr	    outb(adp->va_crtc_addr + 1, 0);
211643105Sdfr	} else {
211743105Sdfr	    outb(adp->va_crtc_addr, 10);
211843105Sdfr	    outb(adp->va_crtc_addr + 1, celsize - base - height);
211943105Sdfr	    outb(adp->va_crtc_addr, 11);
212043105Sdfr	    outb(adp->va_crtc_addr + 1, celsize - base);
212143105Sdfr	}
212243105Sdfr	break;
212343105Sdfr    }
212443105Sdfr    splx(s);
212543105Sdfr
212643105Sdfr    return 0;
212743105Sdfr}
212843105Sdfr
212943105Sdfr/*
213043105Sdfr * mmap():
213143105Sdfr * Mmap frame buffer.
213243105Sdfr *
213343105Sdfr * all adapters
213443105Sdfr */
213543105Sdfrstatic int
213643105Sdfrvga_mmap(video_adapter_t *adp, vm_offset_t offset)
213743105Sdfr{
213843105Sdfr    if (offset > 0x20000 - PAGE_SIZE)
213943105Sdfr	return -1;
214043105Sdfr#ifdef __i386__
214143105Sdfr    return i386_btop((VIDEO_BUF_BASE + offset));
214243105Sdfr#endif
214343105Sdfr#ifdef __alpha__
214443105Sdfr    return alpha_btop((VIDEO_BUF_BASE + offset));
214543105Sdfr#endif
214643105Sdfr}
214743105Sdfr
214843105Sdfrstatic void
214943105Sdfrdump_buffer(u_char *buf, size_t len)
215043105Sdfr{
215143105Sdfr    int i;
215243105Sdfr
215343105Sdfr    for(i = 0; i < len;) {
215443105Sdfr	printf("%02x ", buf[i]);
215543105Sdfr	if ((++i % 16) == 0)
215643105Sdfr	    printf("\n");
215743105Sdfr    }
215843105Sdfr}
215943105Sdfr
216043105Sdfr/*
216143105Sdfr * diag():
216243105Sdfr * Print some information about the video adapter and video modes,
216343105Sdfr * with requested level of details.
216443105Sdfr *
216543105Sdfr * all adapters
216643105Sdfr */
216743105Sdfrstatic int
216843105Sdfrvga_diag(video_adapter_t *adp, int level)
216943105Sdfr{
217043105Sdfr#if FB_DEBUG > 1
217143105Sdfr    video_info_t info;
217243105Sdfr#endif
217343105Sdfr    u_char *mp;
217443105Sdfr
217543105Sdfr    if (!init_done)
217643105Sdfr	return 1;
217743105Sdfr
217843105Sdfr#if FB_DEBUG > 1
217943105Sdfr#ifndef VGA_NO_BIOS
218043105Sdfr    printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n",
218143105Sdfr	   rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488)));
218243105Sdfr    printf("vga: CRTC:0x%x, video option:0x%02x, ",
218343105Sdfr	   readw(BIOS_PADDRTOVADDR(0x463)),
218443105Sdfr	   readb(BIOS_PADDRTOVADDR(0x487)));
218543105Sdfr    printf("rows:%d, cols:%d, font height:%d\n",
218643105Sdfr	   readb(BIOS_PADDRTOVADDR(0x44a)),
218743105Sdfr	   readb(BIOS_PADDRTOVADDR(0x484)) + 1,
218843105Sdfr	   readb(BIOS_PADDRTOVADDR(0x485)));
218943105Sdfr#endif /* VGA_NO_BIOS */
219043105Sdfr    printf("vga: param table EGA/VGA:%p", video_mode_ptr);
219143105Sdfr    printf(", CGA/MDA:%p\n", video_mode_ptr2);
219243105Sdfr    printf("vga: rows_offset:%d\n", rows_offset);
219343105Sdfr#endif /* FB_DEBUG > 1 */
219443105Sdfr
219543105Sdfr    fb_dump_adp_info(DRIVER_NAME, adp, level);
219643105Sdfr
219743105Sdfr#if FB_DEBUG > 1
219843105Sdfr    if (adp->va_flags & V_ADP_MODECHANGE) {
219943105Sdfr	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
220043105Sdfr	    if (bios_vmode[i].vi_mode == NA)
220143105Sdfr		continue;
220243105Sdfr	    if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
220343105Sdfr		continue;
220443105Sdfr	    fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
220543105Sdfr	}
220643105Sdfr    } else {
220743105Sdfr	vga_get_info(adp, adp->va_initial_mode, &info);	/* shouldn't fail */
220843105Sdfr	fb_dump_mode_info(DRIVER_NAME, adp, &info, level);
220943105Sdfr    }
221043105Sdfr#endif /* FB_DEBUG > 1 */
221143105Sdfr
221243105Sdfr    if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA))
221343105Sdfr	return 0;
221443105Sdfr#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
221543105Sdfr    if (video_mode_ptr == NULL)
221643105Sdfr	printf("vga%d: %s: WARNING: video mode switching is not "
221743105Sdfr	       "fully supported on this adapter\n",
221843105Sdfr	       adp->va_unit, adp->va_name);
221943105Sdfr#endif
222043105Sdfr    if (level <= 0)
222143105Sdfr	return 0;
222243105Sdfr
222343105Sdfr    if (adp->va_type == KD_VGA) {
222443105Sdfr	printf("VGA parameters upon power-up\n");
222543105Sdfr	dump_buffer(adpstate.regs, sizeof(adpstate.regs));
222643105Sdfr	printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode);
222743105Sdfr	dump_buffer(adpstate2.regs, sizeof(adpstate2.regs));
222843105Sdfr    }
222943105Sdfr
223043105Sdfr    mp = get_mode_param(adp->va_initial_mode);
223143105Sdfr    if (mp == NULL)	/* this shouldn't be happening */
223243105Sdfr	return 0;
223343105Sdfr    printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode);
223443105Sdfr    dump_buffer(mp, V_MODE_PARAM_SIZE);
223543105Sdfr
223643105Sdfr    return 0;
223743105Sdfr}
223843105Sdfr
223943105Sdfr#endif /* NVGA > 0 */
2240