148104Syokota/*-
248104Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
348104Syokota * Copyright (c) 1992-1998 S�ren Schmidt
448104Syokota * All rights reserved.
548104Syokota *
648104Syokota * Redistribution and use in source and binary forms, with or without
748104Syokota * modification, are permitted provided that the following conditions
848104Syokota * are met:
948104Syokota * 1. Redistributions of source code must retain the above copyright
1048104Syokota *    notice, this list of conditions and the following disclaimer as
1148104Syokota *    the first lines of this file unmodified.
1248104Syokota * 2. Redistributions in binary form must reproduce the above copyright
1348104Syokota *    notice, this list of conditions and the following disclaimer in the
1448104Syokota *    documentation and/or other materials provided with the distribution.
1548104Syokota * 3. The name of the author may not be used to endorse or promote products
1648104Syokota *    derived from this software without specific prior written permission.
1748104Syokota *
1848104Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1948104Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2048104Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2148104Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2248104Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2348104Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2448104Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2548104Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2648104Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2748104Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2848104Syokota *
2948104Syokota */
3048104Syokota
31119418Sobrien#include <sys/cdefs.h>
32119418Sobrien__FBSDID("$FreeBSD$");
33119418Sobrien
3448104Syokota#include "opt_vga.h"
3548104Syokota#include "opt_fb.h"
36153072Sru#ifndef FB_DEBUG
37153072Sru#define	FB_DEBUG	0
38153072Sru#endif
3948104Syokota#include "opt_syscons.h"	/* should be removed in the future, XXX */
4048104Syokota
4148104Syokota#include <sys/param.h>
4248104Syokota#include <sys/systm.h>
4348104Syokota#include <sys/kernel.h>
4448104Syokota#include <sys/conf.h>
4548104Syokota#include <sys/fcntl.h>
4648104Syokota#include <sys/malloc.h>
4748104Syokota#include <sys/fbio.h>
4848104Syokota
4948104Syokota#include <vm/vm.h>
5048104Syokota#include <vm/vm_param.h>
5148104Syokota#include <vm/pmap.h>
5248104Syokota
5348104Syokota#include <machine/md_var.h>
54135690Speter#if defined(__i386__) || defined(__amd64__)
5548104Syokota#include <machine/pc/bios.h>
56114383Speter#endif
5765176Sdfr#include <machine/bus.h>
5848104Syokota
5948104Syokota#include <dev/fb/fbreg.h>
6048104Syokota#include <dev/fb/vgareg.h>
6148104Syokota
6248104Syokota#include <isa/isareg.h>
6348104Syokota
6448104Syokota#ifndef VGA_DEBUG
6548104Syokota#define VGA_DEBUG		0
6648104Syokota#endif
6748104Syokota
68114485Smarcel/* XXX machine/pc/bios.h has got too much i386-specific stuff in it */
69114383Speter#ifndef BIOS_PADDRTOVADDR
70114485Smarcel#define	BIOS_PADDRTOVADDR(x)	(x)
71114383Speter#endif
72114485Smarcel
7348104Syokotaint
7448104Syokotavga_probe_unit(int unit, video_adapter_t *buf, int flags)
7548104Syokota{
7648104Syokota	video_adapter_t *adp;
7748104Syokota	video_switch_t *sw;
7848104Syokota	int error;
7948104Syokota
8048104Syokota	sw = vid_get_switch(VGA_DRIVER_NAME);
8148104Syokota	if (sw == NULL)
8248104Syokota		return 0;
8348104Syokota	error = (*sw->probe)(unit, &adp, NULL, flags);
8448104Syokota	if (error)
8548104Syokota		return error;
8648104Syokota	bcopy(adp, buf, sizeof(*buf));
8748104Syokota	return 0;
8848104Syokota}
8948104Syokota
9048104Syokotaint
9148104Syokotavga_attach_unit(int unit, vga_softc_t *sc, int flags)
9248104Syokota{
9348104Syokota	video_switch_t *sw;
9448104Syokota	int error;
9548104Syokota
9648104Syokota	sw = vid_get_switch(VGA_DRIVER_NAME);
9748104Syokota	if (sw == NULL)
9848104Syokota		return ENXIO;
9948104Syokota
10048104Syokota	error = (*sw->probe)(unit, &sc->adp, NULL, flags);
10148104Syokota	if (error)
10248104Syokota		return error;
10348104Syokota	return (*sw->init)(unit, sc->adp, flags);
10448104Syokota}
10548104Syokota
10648104Syokota/* cdev driver functions */
10748104Syokota
10848104Syokota#ifdef FB_INSTALL_CDEV
10948104Syokota
11048104Syokotaint
111130585Sphkvga_open(struct cdev *dev, vga_softc_t *sc, int flag, int mode, struct thread *td)
11248104Syokota{
11348104Syokota	if (sc == NULL)
11448104Syokota		return ENXIO;
11548104Syokota	if (mode & (O_CREAT | O_APPEND | O_TRUNC))
11648104Syokota		return ENODEV;
11748104Syokota
11883366Sjulian	return genfbopen(&sc->gensc, sc->adp, flag, mode, td);
11948104Syokota}
12048104Syokota
12148104Syokotaint
122130585Sphkvga_close(struct cdev *dev, vga_softc_t *sc, int flag, int mode, struct thread *td)
12348104Syokota{
12483366Sjulian	return genfbclose(&sc->gensc, sc->adp, flag, mode, td);
12548104Syokota}
12648104Syokota
12748104Syokotaint
128130585Sphkvga_read(struct cdev *dev, vga_softc_t *sc, struct uio *uio, int flag)
12948104Syokota{
13048104Syokota	return genfbread(&sc->gensc, sc->adp, uio, flag);
13148104Syokota}
13248104Syokota
13348104Syokotaint
134130585Sphkvga_write(struct cdev *dev, vga_softc_t *sc, struct uio *uio, int flag)
13548104Syokota{
13648104Syokota	return genfbread(&sc->gensc, sc->adp, uio, flag);
13748104Syokota}
13848104Syokota
13948104Syokotaint
140130585Sphkvga_ioctl(struct cdev *dev, vga_softc_t *sc, u_long cmd, caddr_t arg, int flag,
14183366Sjulian	  struct thread *td)
14248104Syokota{
14383366Sjulian	return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td);
14448104Syokota}
14548104Syokota
14648104Syokotaint
147201223Srnolandvga_mmap(struct cdev *dev, vga_softc_t *sc, vm_ooffset_t offset,
148201223Srnoland    vm_offset_t *paddr, int prot, vm_memattr_t *memattr)
14948104Syokota{
150201223Srnoland	return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot, memattr);
15148104Syokota}
15248104Syokota
15348104Syokota#endif /* FB_INSTALL_CDEV */
15448104Syokota
15548104Syokota/* LOW-LEVEL */
15648104Syokota
157178193Sphk#include <isa/rtc.h>
158114383Speter#ifdef __i386__
159197025Sdelphij#include <dev/fb/vesa.h>
160114383Speter#endif
16148104Syokota
16248104Syokota#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
16348104Syokota#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
16448104Syokota#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
16548104Syokota
16648104Syokota/* for compatibility with old kernel options */
16748104Syokota#ifdef SC_ALT_SEQACCESS
16848104Syokota#undef SC_ALT_SEQACCESS
16948104Syokota#undef VGA_ALT_SEQACCESS
17048104Syokota#define VGA_ALT_SEQACCESS	1
17148104Syokota#endif
17248104Syokota
17348104Syokota#ifdef SLOW_VGA
17448104Syokota#undef SLOW_VGA
17548104Syokota#undef VGA_SLOW_IOACCESS
176153072Sru#define VGA_SLOW_IOACCESS
17748104Syokota#endif
17848104Syokota
17948104Syokota/* architecture dependent option */
180197185Sdelphij#if !defined(__i386__) && !defined(__amd64__)
18148104Syokota#define VGA_NO_BIOS		1
18248104Syokota#endif
18348104Syokota
18448104Syokota/* this should really be in `rtc.h' */
18548104Syokota#define RTC_EQUIPMENT           0x14
18648104Syokota
18748104Syokota/* various sizes */
18848104Syokota#define V_MODE_MAP_SIZE		(M_VGA_CG320 + 1)
18948104Syokota#define V_MODE_PARAM_SIZE	64
19048104Syokota
19148104Syokota/* video adapter state buffer */
19248104Syokotastruct adp_state {
19348104Syokota    int			sig;
19448104Syokota#define V_STATE_SIG	0x736f6962
19548104Syokota    u_char		regs[V_MODE_PARAM_SIZE];
19648104Syokota};
19748104Syokotatypedef struct adp_state adp_state_t;
19848104Syokota
19948104Syokota/* video adapter information */
20048104Syokota#define DCC_MONO	0
20148104Syokota#define DCC_CGA40	1
20248104Syokota#define DCC_CGA80	2
20348104Syokota#define DCC_EGAMONO	3
20448104Syokota#define DCC_EGA40	4
20548104Syokota#define DCC_EGA80	5
20648104Syokota
20748104Syokota/*
20848104Syokota * NOTE: `va_window' should have a virtual address, but is initialized
20948104Syokota * with a physical address in the following table, as verify_adapter()
21048104Syokota * will perform address conversion at run-time.
21148104Syokota */
21248104Syokotastatic video_adapter_t adapter_init_value[] = {
21348104Syokota    /* DCC_MONO */
21448104Syokota    { 0, KD_MONO, "mda", 0, 0, 0, 	    IO_MDA, IO_MDASIZE, MONO_CRTC,
21548104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
21648104Syokota      0, 0, 0, 0, 7, 0, },
21748104Syokota    /* DCC_CGA40 */
21848104Syokota    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
21948104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
22048104Syokota      0, 0, 0, 0, 3, 0, },
22148104Syokota    /* DCC_CGA80 */
22248104Syokota    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
22348104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
22448104Syokota      0, 0, 0, 0, 3, 0, },
22548104Syokota    /* DCC_EGAMONO */
22648104Syokota    { 0, KD_EGA,  "ega", 0, 0, 0,	    IO_MDA, 48,	  MONO_CRTC,
22748104Syokota      EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
22848104Syokota      0, 0, 0, 0, 7, 0, },
22948104Syokota    /* DCC_EGA40 */
23048104Syokota    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
23148104Syokota      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
23248104Syokota      0, 0, 0, 0, 3, 0, },
23348104Syokota    /* DCC_EGA80 */
23448104Syokota    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
23548104Syokota      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
23648104Syokota      0, 0, 0, 0, 3, 0, },
23748104Syokota};
23848104Syokota
23948104Syokotastatic video_adapter_t	biosadapter[2];
24048104Syokotastatic int		biosadapters = 0;
24148104Syokota
24248104Syokota/* video driver declarations */
24348104Syokotastatic int			vga_configure(int flags);
24448104Syokota       int			(*vga_sub_configure)(int flags);
24548238Speter#if 0
24648104Syokotastatic int			vga_nop(void);
24748238Speter#endif
24848104Syokotastatic int			vga_error(void);
24948104Syokotastatic vi_probe_t		vga_probe;
25048104Syokotastatic vi_init_t		vga_init;
25148104Syokotastatic vi_get_info_t		vga_get_info;
25248104Syokotastatic vi_query_mode_t		vga_query_mode;
25348104Syokotastatic vi_set_mode_t		vga_set_mode;
25448104Syokotastatic vi_save_font_t		vga_save_font;
25548104Syokotastatic vi_load_font_t		vga_load_font;
25648104Syokotastatic vi_show_font_t		vga_show_font;
25748104Syokotastatic vi_save_palette_t	vga_save_palette;
25848104Syokotastatic vi_load_palette_t	vga_load_palette;
25948104Syokotastatic vi_set_border_t		vga_set_border;
26048104Syokotastatic vi_save_state_t		vga_save_state;
26148104Syokotastatic vi_load_state_t		vga_load_state;
26248104Syokotastatic vi_set_win_org_t		vga_set_origin;
26348104Syokotastatic vi_read_hw_cursor_t	vga_read_hw_cursor;
26448104Syokotastatic vi_set_hw_cursor_t	vga_set_hw_cursor;
26548104Syokotastatic vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
26648104Syokotastatic vi_blank_display_t	vga_blank_display;
26748104Syokotastatic vi_mmap_t		vga_mmap_buf;
26848104Syokotastatic vi_ioctl_t		vga_dev_ioctl;
26948104Syokota#ifndef VGA_NO_MODE_CHANGE
27048104Syokotastatic vi_clear_t		vga_clear;
27148104Syokotastatic vi_fill_rect_t		vga_fill_rect;
27248104Syokotastatic vi_bitblt_t		vga_bitblt;
27348104Syokota#else /* VGA_NO_MODE_CHANGE */
27448104Syokota#define vga_clear		(vi_clear_t *)vga_error
27548104Syokota#define vga_fill_rect		(vi_fill_rect_t *)vga_error
27648104Syokota#define vga_bitblt		(vi_bitblt_t *)vga_error
27748104Syokota#endif
27848104Syokotastatic vi_diag_t		vga_diag;
27948104Syokota
28048104Syokotastatic video_switch_t vgavidsw = {
28148104Syokota	vga_probe,
28248104Syokota	vga_init,
28348104Syokota	vga_get_info,
28448104Syokota	vga_query_mode,
28548104Syokota	vga_set_mode,
28648104Syokota	vga_save_font,
28748104Syokota	vga_load_font,
28848104Syokota	vga_show_font,
28948104Syokota	vga_save_palette,
29048104Syokota	vga_load_palette,
29148104Syokota	vga_set_border,
29248104Syokota	vga_save_state,
29348104Syokota	vga_load_state,
29448104Syokota	vga_set_origin,
29548104Syokota	vga_read_hw_cursor,
29648104Syokota	vga_set_hw_cursor,
29748104Syokota	vga_set_hw_cursor_shape,
29848104Syokota	vga_blank_display,
29948104Syokota	vga_mmap_buf,
30048104Syokota	vga_dev_ioctl,
30148104Syokota	vga_clear,
30248104Syokota	vga_fill_rect,
30348104Syokota	vga_bitblt,
30448104Syokota	vga_error,
30548104Syokota	vga_error,
30648104Syokota	vga_diag,
30748104Syokota};
30848104Syokota
30948104SyokotaVIDEO_DRIVER(mda, vgavidsw, NULL);
31048104SyokotaVIDEO_DRIVER(cga, vgavidsw, NULL);
31148104SyokotaVIDEO_DRIVER(ega, vgavidsw, NULL);
31248104SyokotaVIDEO_DRIVER(vga, vgavidsw, vga_configure);
31348104Syokota
31448104Syokota/* VGA BIOS standard video modes */
31548104Syokota#define EOT		(-1)
31648104Syokota#define NA		(-2)
31748104Syokota
31848104Syokotastatic video_info_t bios_vmode[] = {
31948104Syokota    /* CGA */
32048104Syokota    { M_B40x25,     V_INFO_COLOR, 40, 25, 8,  8, 2, 1,
32148104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
32248104Syokota    { M_C40x25,     V_INFO_COLOR, 40, 25, 8,  8, 4, 1,
32348104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
32448104Syokota    { M_B80x25,     V_INFO_COLOR, 80, 25, 8,  8, 2, 1,
32548104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
32648104Syokota    { M_C80x25,     V_INFO_COLOR, 80, 25, 8,  8, 4, 1,
32748104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
32848104Syokota    /* EGA */
32948104Syokota    { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1,
33048104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
33148104Syokota    { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1,
33248104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
33348104Syokota    { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1,
33448104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
33548104Syokota    { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1,
33648104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
33748104Syokota    /* VGA */
33848104Syokota    { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1,
33948104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
34048104Syokota    { M_VGA_M80x25, 0,            80, 25, 8, 16, 2, 1,
34148104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
34248104Syokota    { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
34348104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
34448104Syokota    /* MDA */
34548104Syokota    { M_EGAMONO80x25, 0,          80, 25, 8, 14, 2, 1,
34648104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
34748104Syokota    /* EGA */
34848104Syokota    { M_ENH_B80x43, 0,            80, 43, 8,  8, 2, 1,
34948104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
35048104Syokota    { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8,  8, 4, 1,
35148104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
35248104Syokota    /* VGA */
35348104Syokota    { M_VGA_M80x30, 0,            80, 30, 8, 16, 2, 1,
35448104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
35548104Syokota    { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
35648104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
35748104Syokota    { M_VGA_M80x50, 0,            80, 50, 8,  8, 2, 1,
35848104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
35948104Syokota    { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8,  8, 4, 1,
36048104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
36148104Syokota    { M_VGA_M80x60, 0,            80, 60, 8,  8, 2, 1,
36248104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
36348104Syokota    { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8,  8, 4, 1,
36448104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
36548104Syokota
36648104Syokota#ifndef VGA_NO_MODE_CHANGE
36748104Syokota
36848104Syokota#ifdef VGA_WIDTH90
36948104Syokota    { M_VGA_M90x25, 0,            90, 25, 8, 16, 2, 1,
37048104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
37148104Syokota    { M_VGA_C90x25, V_INFO_COLOR, 90, 25, 8, 16, 4, 1,
37248104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
37348104Syokota    { M_VGA_M90x30, 0,            90, 30, 8, 16, 2, 1,
37448104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
37548104Syokota    { M_VGA_C90x30, V_INFO_COLOR, 90, 30, 8, 16, 4, 1,
37648104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
37748104Syokota    { M_VGA_M90x43, 0,            90, 43, 8,  8, 2, 1,
37848104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
37948104Syokota    { M_VGA_C90x43, V_INFO_COLOR, 90, 43, 8,  8, 4, 1,
38048104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
38148104Syokota    { M_VGA_M90x50, 0,            90, 50, 8,  8, 2, 1,
38248104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
38348104Syokota    { M_VGA_C90x50, V_INFO_COLOR, 90, 50, 8,  8, 4, 1,
38448104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
38548104Syokota    { M_VGA_M90x60, 0,            90, 60, 8,  8, 2, 1,
38648104Syokota      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
38748104Syokota    { M_VGA_C90x60, V_INFO_COLOR, 90, 60, 8,  8, 4, 1,
38848104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
38948104Syokota#endif /* VGA_WIDTH90 */
39048104Syokota
39148104Syokota    /* CGA */
39248104Syokota    { M_BG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
39348104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_CGA },
39448104Syokota    { M_CG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
39548104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_CGA },
39648104Syokota    { M_BG640,      V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 1, 1,
39748104Syokota      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_CGA },
39848104Syokota    /* EGA */
39948104Syokota    { M_CG320_D,    V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 4, 4,
40048104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
40148104Syokota      V_INFO_MM_PLANAR },
40248104Syokota    { M_CG640_E,    V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 4, 4,
40348104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
40448104Syokota      V_INFO_MM_PLANAR },
40548104Syokota    { M_EGAMONOAPA, V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
40648104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 ,
40748104Syokota      V_INFO_MM_PLANAR },
40848104Syokota    { M_ENHMONOAPA2,V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
40948104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
41048104Syokota      V_INFO_MM_PLANAR },
41148104Syokota    { M_CG640x350,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2,
41248104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
41348104Syokota      V_INFO_MM_PLANAR },
41448104Syokota    { M_ENH_CG640,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4,
41548104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
41648104Syokota      V_INFO_MM_PLANAR },
41748104Syokota    /* VGA */
41848104Syokota    { M_BG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
41948104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
42048104Syokota      V_INFO_MM_PLANAR },
42148104Syokota    { M_CG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
42248104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
42348104Syokota      V_INFO_MM_PLANAR },
42448104Syokota    { M_VGA_CG320,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 8, 1,
42548104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
42648104Syokota      V_INFO_MM_PACKED, 1 },
42750299Syokota    { M_VGA_MODEX,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8,  8, 8, 4,
42848104Syokota      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
42950299Syokota      V_INFO_MM_VGAX, 1 },
43048104Syokota#endif /* VGA_NO_MODE_CHANGE */
43148104Syokota
43248104Syokota    { EOT },
43348104Syokota};
43448104Syokota
43548104Syokotastatic int		vga_init_done = FALSE;
43648104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
43748104Syokotastatic u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
43848104Syokotastatic u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
43948104Syokota#endif
44048104Syokotastatic u_char		*mode_map[V_MODE_MAP_SIZE];
44148104Syokotastatic adp_state_t	adpstate;
44248104Syokotastatic adp_state_t	adpstate2;
44348104Syokotastatic int		rows_offset = 1;
44448104Syokota
44548104Syokota/* local macros and functions */
44648104Syokota#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
44748104Syokota
44848104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
44948104Syokotastatic void map_mode_table(u_char *map[], u_char *table, int max);
45048104Syokota#endif
45148104Syokotastatic void clear_mode_map(video_adapter_t *adp, u_char *map[], int max,
45248104Syokota			   int color);
45348104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
45448104Syokotastatic int map_mode_num(int mode);
45548104Syokota#endif
45648104Syokotastatic int map_gen_mode_num(int type, int color, int mode);
45748104Syokotastatic int map_bios_mode_num(int type, int color, int bios_mode);
45848104Syokotastatic u_char *get_mode_param(int mode);
45948104Syokota#ifndef VGA_NO_BIOS
46048104Syokotastatic void fill_adapter_param(int code, video_adapter_t *adp);
46148104Syokota#endif
46248104Syokotastatic int verify_adapter(video_adapter_t *adp);
46348104Syokotastatic void update_adapter_info(video_adapter_t *adp, video_info_t *info);
46448104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
46548104Syokota#define COMP_IDENTICAL	0
46648104Syokota#define COMP_SIMILAR	1
46748104Syokota#define COMP_DIFFERENT	2
46848104Syokotastatic int comp_adpregs(u_char *buf1, u_char *buf2);
46948104Syokota#endif
47048104Syokotastatic int probe_adapters(void);
47148104Syokotastatic int set_line_length(video_adapter_t *adp, int pixel);
47248104Syokotastatic int set_display_start(video_adapter_t *adp, int x, int y);
47348104Syokota
47448104Syokota#ifndef VGA_NO_MODE_CHANGE
47548104Syokota#ifdef VGA_WIDTH90
47648104Syokotastatic void set_width90(adp_state_t *params);
47748104Syokota#endif
47848104Syokota#endif /* !VGA_NO_MODE_CHANGE */
47948104Syokota
48048104Syokota#ifndef VGA_NO_FONT_LOADING
48148104Syokota#define PARAM_BUFSIZE	6
48248104Syokotastatic void set_font_mode(video_adapter_t *adp, u_char *buf);
48348104Syokotastatic void set_normal_mode(video_adapter_t *adp, u_char *buf);
48448104Syokota#endif
48548104Syokota
48648104Syokota#ifndef VGA_NO_MODE_CHANGE
487138891Srustatic void filll_io(int val, vm_offset_t d, size_t size);
48848104Syokotastatic void planar_fill(video_adapter_t *adp, int val);
48948104Syokotastatic void packed_fill(video_adapter_t *adp, int val);
49048104Syokotastatic void direct_fill(video_adapter_t *adp, int val);
49148104Syokota#ifdef notyet
49248104Syokotastatic void planar_fill_rect(video_adapter_t *adp, int val, int x, int y,
49348104Syokota			     int cx, int cy);
49448104Syokotastatic void packed_fill_rect(video_adapter_t *adp, int val, int x, int y,
49548104Syokota			     int cx, int cy);
49648104Syokotastatic void direct_fill_rect16(video_adapter_t *adp, int val, int x, int y,
49748104Syokota			       int cx, int cy);
49848104Syokotastatic void direct_fill_rect24(video_adapter_t *adp, int val, int x, int y,
49948104Syokota			       int cx, int cy);
50048104Syokotastatic void direct_fill_rect32(video_adapter_t *adp, int val, int x, int y,
50148104Syokota			       int cx, int cy);
50248104Syokota#endif /* notyet */
50348104Syokota#endif /* !VGA_NO_MODE_CHANGE */
50448104Syokota
50548104Syokotastatic void dump_buffer(u_char *buf, size_t len);
50648104Syokota
50748104Syokota#define	ISMAPPED(pa, width)				\
50848104Syokota	(((pa) <= (u_long)0x1000 - (width)) 		\
50948104Syokota	 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
51048104Syokota
51148104Syokota#define	prologue(adp, flag, err)			\
51248104Syokota	if (!vga_init_done || !((adp)->va_flags & (flag)))	\
51348104Syokota	    return (err)
51448104Syokota
51548104Syokota/* a backdoor for the console driver */
51648104Syokotastatic int
51748104Syokotavga_configure(int flags)
51848104Syokota{
51948104Syokota    int i;
52048104Syokota
52148104Syokota    probe_adapters();
52248104Syokota    for (i = 0; i < biosadapters; ++i) {
52348104Syokota	if (!probe_done(&biosadapter[i]))
52448104Syokota	    continue;
52548104Syokota	biosadapter[i].va_flags |= V_ADP_INITIALIZED;
52648104Syokota	if (!config_done(&biosadapter[i])) {
52748104Syokota	    if (vid_register(&biosadapter[i]) < 0)
52848104Syokota		continue;
52948104Syokota	    biosadapter[i].va_flags |= V_ADP_REGISTERED;
53048104Syokota	}
53148104Syokota    }
53248104Syokota    if (vga_sub_configure != NULL)
53348104Syokota	(*vga_sub_configure)(flags);
53448104Syokota
53548104Syokota    return biosadapters;
53648104Syokota}
53748104Syokota
53848104Syokota/* local subroutines */
53948104Syokota
54048104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
54148104Syokota/* construct the mode parameter map */
54248104Syokotastatic void
54348104Syokotamap_mode_table(u_char *map[], u_char *table, int max)
54448104Syokota{
54548104Syokota    int i;
54648104Syokota
54748104Syokota    for(i = 0; i < max; ++i)
54848104Syokota	map[i] = table + i*V_MODE_PARAM_SIZE;
54948104Syokota    for(; i < V_MODE_MAP_SIZE; ++i)
55048104Syokota	map[i] = NULL;
55148104Syokota}
55248104Syokota#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
55348104Syokota
55448104Syokotastatic void
55548104Syokotaclear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color)
55648104Syokota{
55748104Syokota    video_info_t info;
55848104Syokota    int i;
55948104Syokota
56048104Syokota    /*
56148104Syokota     * NOTE: we don't touch `bios_vmode[]' because it is shared
56248104Syokota     * by all adapters.
56348104Syokota     */
56448104Syokota    for(i = 0; i < max; ++i) {
56548104Syokota	if (vga_get_info(adp, i, &info))
56648104Syokota	    continue;
56748104Syokota	if ((info.vi_flags & V_INFO_COLOR) != color)
56848104Syokota	    map[i] = NULL;
56948104Syokota    }
57048104Syokota}
57148104Syokota
57248104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
57348104Syokota/* map the non-standard video mode to a known mode number */
57448104Syokotastatic int
57548104Syokotamap_mode_num(int mode)
57648104Syokota{
57748104Syokota    static struct {
57848104Syokota        int from;
57948104Syokota        int to;
58048104Syokota    } mode_map[] = {
58148104Syokota        { M_ENH_B80x43, M_ENH_B80x25 },
58248104Syokota        { M_ENH_C80x43, M_ENH_C80x25 },
58348104Syokota        { M_VGA_M80x30, M_VGA_M80x25 },
58448104Syokota        { M_VGA_C80x30, M_VGA_C80x25 },
58548104Syokota        { M_VGA_M80x50, M_VGA_M80x25 },
58648104Syokota        { M_VGA_C80x50, M_VGA_C80x25 },
58748104Syokota        { M_VGA_M80x60, M_VGA_M80x25 },
58848104Syokota        { M_VGA_C80x60, M_VGA_C80x25 },
58948104Syokota#ifdef VGA_WIDTH90
59048104Syokota        { M_VGA_M90x25, M_VGA_M80x25 },
59148104Syokota        { M_VGA_C90x25, M_VGA_C80x25 },
59248104Syokota        { M_VGA_M90x30, M_VGA_M80x25 },
59348104Syokota        { M_VGA_C90x30, M_VGA_C80x25 },
59448104Syokota        { M_VGA_M90x43, M_ENH_B80x25 },
59548104Syokota        { M_VGA_C90x43, M_ENH_C80x25 },
59648104Syokota        { M_VGA_M90x50, M_VGA_M80x25 },
59748104Syokota        { M_VGA_C90x50, M_VGA_C80x25 },
59848104Syokota        { M_VGA_M90x60, M_VGA_M80x25 },
59948104Syokota        { M_VGA_C90x60, M_VGA_C80x25 },
60048104Syokota#endif
60148104Syokota        { M_VGA_MODEX,  M_VGA_CG320 },
60248104Syokota    };
60348104Syokota    int i;
60448104Syokota
60548104Syokota    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
60648104Syokota        if (mode_map[i].from == mode)
60748104Syokota            return mode_map[i].to;
60848104Syokota    }
60948104Syokota    return mode;
61048104Syokota}
61148104Syokota#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
61248104Syokota
61348104Syokota/* map a generic video mode to a known mode number */
61448104Syokotastatic int
61548104Syokotamap_gen_mode_num(int type, int color, int mode)
61648104Syokota{
61748104Syokota    static struct {
61848104Syokota	int from;
61948104Syokota	int to_color;
62048104Syokota	int to_mono;
62148104Syokota    } mode_map[] = {
62248104Syokota	{ M_TEXT_80x30,	M_VGA_C80x30, M_VGA_M80x30, },
62348104Syokota	{ M_TEXT_80x43,	M_ENH_C80x43, M_ENH_B80x43, },
62448104Syokota	{ M_TEXT_80x50,	M_VGA_C80x50, M_VGA_M80x50, },
62548104Syokota	{ M_TEXT_80x60,	M_VGA_C80x60, M_VGA_M80x60, },
62648104Syokota    };
62748104Syokota    int i;
62848104Syokota
62948104Syokota    if (mode == M_TEXT_80x25) {
63048104Syokota	switch (type) {
63148104Syokota
63248104Syokota	case KD_VGA:
63348104Syokota	    if (color)
63448104Syokota		return M_VGA_C80x25;
63548104Syokota	    else
63648104Syokota		return M_VGA_M80x25;
63748104Syokota	    break;
63848104Syokota
63948104Syokota	case KD_EGA:
64048104Syokota	    if (color)
64148104Syokota		return M_ENH_C80x25;
64248104Syokota	    else
64348104Syokota		return M_EGAMONO80x25;
64448104Syokota	    break;
64548104Syokota
64648104Syokota	case KD_CGA:
64748104Syokota	    return M_C80x25;
64848104Syokota
64948104Syokota	case KD_MONO:
65048104Syokota	case KD_HERCULES:
65148104Syokota	    return M_EGAMONO80x25;	/* XXX: this name is confusing */
65248104Syokota
65348104Syokota 	default:
65448104Syokota	    return -1;
65548104Syokota	}
65648104Syokota    }
65748104Syokota
65848104Syokota    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
65948104Syokota        if (mode_map[i].from == mode)
66048104Syokota            return ((color) ? mode_map[i].to_color : mode_map[i].to_mono);
66148104Syokota    }
66248104Syokota    return mode;
66348104Syokota}
66448104Syokota
66548104Syokota/* turn the BIOS video number into our video mode number */
66648104Syokotastatic int
66748104Syokotamap_bios_mode_num(int type, int color, int bios_mode)
66848104Syokota{
66948104Syokota    static int cga_modes[7] = {
67048104Syokota	M_B40x25, M_C40x25,		/* 0, 1 */
67148104Syokota	M_B80x25, M_C80x25,		/* 2, 3 */
67248104Syokota	M_BG320, M_CG320,
67348104Syokota	M_BG640,
67448104Syokota    };
67548104Syokota    static int ega_modes[17] = {
67648104Syokota	M_ENH_B40x25, M_ENH_C40x25,	/* 0, 1 */
67748104Syokota	M_ENH_B80x25, M_ENH_C80x25,	/* 2, 3 */
67848104Syokota	M_BG320, M_CG320,
67948104Syokota	M_BG640,
68048104Syokota	M_EGAMONO80x25,			/* 7 */
68148104Syokota	8, 9, 10, 11, 12,
68248104Syokota	M_CG320_D,
68348104Syokota	M_CG640_E,
68448104Syokota	M_ENHMONOAPA2,			/* XXX: video momery > 64K */
68548104Syokota	M_ENH_CG640,			/* XXX: video momery > 64K */
68648104Syokota    };
68748104Syokota    static int vga_modes[20] = {
68848104Syokota	M_VGA_C40x25, M_VGA_C40x25,	/* 0, 1 */
68948104Syokota	M_VGA_C80x25, M_VGA_C80x25,	/* 2, 3 */
69048104Syokota	M_BG320, M_CG320,
69148104Syokota	M_BG640,
69248104Syokota	M_VGA_M80x25,			/* 7 */
69348104Syokota	8, 9, 10, 11, 12,
69448104Syokota	M_CG320_D,
69548104Syokota	M_CG640_E,
69648104Syokota	M_ENHMONOAPA2,
69748104Syokota	M_ENH_CG640,
69848104Syokota	M_BG640x480, M_CG640x480,
69948104Syokota	M_VGA_CG320,
70048104Syokota    };
70148104Syokota
70248104Syokota    switch (type) {
70348104Syokota
70448104Syokota    case KD_VGA:
70548104Syokota	if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0]))
70648104Syokota	    return vga_modes[bios_mode];
70748104Syokota	else if (color)
70848104Syokota	    return M_VGA_C80x25;
70948104Syokota	else
71048104Syokota	    return M_VGA_M80x25;
71148104Syokota	break;
71248104Syokota
71348104Syokota    case KD_EGA:
71448104Syokota	if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0]))
71548104Syokota	    return ega_modes[bios_mode];
71648104Syokota	else if (color)
71748104Syokota	    return M_ENH_C80x25;
71848104Syokota	else
71948104Syokota	    return M_EGAMONO80x25;
72048104Syokota	break;
72148104Syokota
72248104Syokota    case KD_CGA:
72348104Syokota	if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0]))
72448104Syokota	    return cga_modes[bios_mode];
72548104Syokota	else
72648104Syokota	    return M_C80x25;
72748104Syokota	break;
72848104Syokota
72948104Syokota    case KD_MONO:
73048104Syokota    case KD_HERCULES:
73148104Syokota	return M_EGAMONO80x25;		/* XXX: this name is confusing */
73248104Syokota
73348104Syokota    default:
73448104Syokota	break;
73548104Syokota    }
73648104Syokota    return -1;
73748104Syokota}
73848104Syokota
73948104Syokota/* look up a parameter table entry */
74048104Syokotastatic u_char
74148104Syokota*get_mode_param(int mode)
74248104Syokota{
74348104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
74448104Syokota    if (mode >= V_MODE_MAP_SIZE)
74548104Syokota	mode = map_mode_num(mode);
74648104Syokota#endif
74748104Syokota    if ((mode >= 0) && (mode < V_MODE_MAP_SIZE))
74848104Syokota	return mode_map[mode];
74948104Syokota    else
75048104Syokota	return NULL;
75148104Syokota}
75248104Syokota
75348104Syokota#ifndef VGA_NO_BIOS
75448104Syokotastatic void
75548104Syokotafill_adapter_param(int code, video_adapter_t *adp)
75648104Syokota{
75748104Syokota    static struct {
75848104Syokota	int primary;
75948104Syokota	int secondary;
76048104Syokota    } dcc[] = {
76148104Syokota	{ DCC_MONO, 			DCC_EGA40 /* CGA monitor */ },
76248104Syokota	{ DCC_MONO, 			DCC_EGA80 /* CGA monitor */ },
76348104Syokota	{ DCC_MONO, 			DCC_EGA80 },
76455727Syokota	{ DCC_MONO, 			DCC_EGA80 },
76548104Syokota	{ DCC_CGA40, 			DCC_EGAMONO },
76648104Syokota	{ DCC_CGA80, 			DCC_EGAMONO },
76748104Syokota	{ DCC_EGA40 /* CGA monitor */, 	DCC_MONO},
76848104Syokota	{ DCC_EGA80 /* CGA monitor */, 	DCC_MONO},
76955727Syokota	{ DCC_EGA80,			DCC_MONO },
77048104Syokota	{ DCC_EGA80, 			DCC_MONO },
77148104Syokota	{ DCC_EGAMONO, 			DCC_CGA40 },
77255727Syokota	{ DCC_EGAMONO, 			DCC_CGA80 },
77348104Syokota    };
77448104Syokota
77548104Syokota    if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) {
77648104Syokota	adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
77748104Syokota	adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
77848104Syokota    } else {
77948104Syokota	adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary];
78048104Syokota	adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary];
78148104Syokota    }
78248104Syokota}
78348104Syokota#endif /* VGA_NO_BIOS */
78448104Syokota
78548104Syokotastatic int
78648104Syokotaverify_adapter(video_adapter_t *adp)
78748104Syokota{
78848104Syokota    vm_offset_t buf;
78948104Syokota    u_int16_t v;
79048104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
79148104Syokota    u_int32_t p;
79248104Syokota#endif
79348104Syokota
79448104Syokota    buf = BIOS_PADDRTOVADDR(adp->va_window);
79548104Syokota    v = readw(buf);
79648104Syokota    writew(buf, 0xA55A);
79748104Syokota    if (readw(buf) != 0xA55A)
79848104Syokota	return ENXIO;
79948104Syokota    writew(buf, v);
80048104Syokota
80148104Syokota    switch (adp->va_type) {
80248104Syokota
80348104Syokota    case KD_EGA:
80448104Syokota	outb(adp->va_crtc_addr, 7);
80548104Syokota	if (inb(adp->va_crtc_addr) == 7) {
80648104Syokota	    adp->va_type = KD_VGA;
80748104Syokota	    adp->va_name = "vga";
80848104Syokota	    adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE;
80948104Syokota	}
81048104Syokota	adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER;
81148104Syokota	/* the color adapter may be in the 40x25 mode... XXX */
81248104Syokota
81348104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
81448104Syokota	/* get the BIOS video mode pointer */
81548104Syokota	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8);
81648104Syokota	p = BIOS_SADDRTOLADDR(p);
81748104Syokota	if (ISMAPPED(p, sizeof(u_int32_t))) {
81848104Syokota	    p = *(u_int32_t *)BIOS_PADDRTOVADDR(p);
81948104Syokota	    p = BIOS_SADDRTOLADDR(p);
82048104Syokota	    if (ISMAPPED(p, V_MODE_PARAM_SIZE))
82148104Syokota		video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p);
82248104Syokota	}
82348104Syokota#endif
82448104Syokota	break;
82548104Syokota
82648104Syokota    case KD_CGA:
82748104Syokota	adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER;
82848104Syokota	/* may be in the 40x25 mode... XXX */
82948104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
83048104Syokota	/* get the BIOS video mode pointer */
83148104Syokota	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
83248104Syokota	p = BIOS_SADDRTOLADDR(p);
83348104Syokota	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
83448104Syokota#endif
83548104Syokota	break;
83648104Syokota
83748104Syokota    case KD_MONO:
83848104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
83948104Syokota	/* get the BIOS video mode pointer */
84048104Syokota	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
84148104Syokota	p = BIOS_SADDRTOLADDR(p);
84248104Syokota	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
84348104Syokota#endif
84448104Syokota	break;
84548104Syokota    }
84648104Syokota
84748104Syokota    return 0;
84848104Syokota}
84948104Syokota
85048104Syokotastatic void
85148104Syokotaupdate_adapter_info(video_adapter_t *adp, video_info_t *info)
85248104Syokota{
85348104Syokota    adp->va_flags &= ~V_ADP_COLOR;
85448104Syokota    adp->va_flags |=
85548104Syokota	(info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
85648104Syokota    adp->va_crtc_addr =
85748104Syokota	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
85848104Syokota    adp->va_window = BIOS_PADDRTOVADDR(info->vi_window);
85948104Syokota    adp->va_window_size = info->vi_window_size;
86048104Syokota    adp->va_window_gran = info->vi_window_gran;
86148104Syokota    adp->va_window_orig = 0;
86248104Syokota    /* XXX */
86348104Syokota    adp->va_buffer = info->vi_buffer;
86448104Syokota    adp->va_buffer_size = info->vi_buffer_size;
86550299Syokota    if (info->vi_mem_model == V_INFO_MM_VGAX) {
86650299Syokota	adp->va_line_width = info->vi_width/2;
86750299Syokota    } else if (info->vi_flags & V_INFO_GRAPHICS) {
86848104Syokota	switch (info->vi_depth/info->vi_planes) {
86948104Syokota	case 1:
87048104Syokota	    adp->va_line_width = info->vi_width/8;
87148104Syokota	    break;
87248104Syokota	case 2:
87348104Syokota	    adp->va_line_width = info->vi_width/4;
87448104Syokota	    break;
87548104Syokota	case 4:
87648104Syokota	    adp->va_line_width = info->vi_width/2;
87748104Syokota	    break;
87848104Syokota	case 8:
87948104Syokota	default: /* shouldn't happen */
88048104Syokota	    adp->va_line_width = info->vi_width;
88148104Syokota	    break;
88248104Syokota	}
88348104Syokota    } else {
88448104Syokota	adp->va_line_width = info->vi_width;
88548104Syokota    }
88648104Syokota    adp->va_disp_start.x = 0;
88748104Syokota    adp->va_disp_start.y = 0;
88848104Syokota    bcopy(info, &adp->va_info, sizeof(adp->va_info));
88948104Syokota}
89048104Syokota
89148104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
89248104Syokota/* compare two parameter table entries */
89348104Syokotastatic int
89448104Syokotacomp_adpregs(u_char *buf1, u_char *buf2)
89548104Syokota{
89648104Syokota    static struct {
89748104Syokota        u_char mask;
89848104Syokota    } params[V_MODE_PARAM_SIZE] = {
89948104Syokota	{0xff}, {0x00}, {0xff}, 		/* COLS}, ROWS}, POINTS */
90048104Syokota	{0x00}, {0x00}, 			/* page length */
90148104Syokota	{0xfe}, {0xff}, {0xff}, {0xff},		/* sequencer registers */
90248104Syokota	{0xf3},					/* misc register */
90348104Syokota	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},	/* CRTC */
90448104Syokota	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},
90548104Syokota	{0x00}, {0x00}, {0x00}, {0x00}, {0x00},
90648104Syokota	{0x00}, {0xff}, {0x7f}, {0xff}, {0xff},
90748104Syokota	{0x7f}, {0xff}, {0xff}, {0xef}, {0xff},
90848104Syokota	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* attribute controller regs */
90948104Syokota	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
91048104Syokota	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
91148104Syokota	{0xff}, {0xff}, {0xff}, {0xff}, {0xf0},
91248104Syokota	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* GDC register */
91348104Syokota	{0xff}, {0xff}, {0xff}, {0xff},
91448104Syokota    };
91548104Syokota    int identical = TRUE;
91648104Syokota    int i;
91748104Syokota
91848104Syokota    if ((buf1 == NULL) || (buf2 == NULL))
91948104Syokota	return COMP_DIFFERENT;
92048104Syokota
92148104Syokota    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
92248104Syokota	if (params[i].mask == 0)	/* don't care */
92348104Syokota	    continue;
92448104Syokota	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
92548104Syokota	    return COMP_DIFFERENT;
92648104Syokota	if (buf1[i] != buf2[i])
92748104Syokota	    identical = FALSE;
92848104Syokota    }
92948104Syokota    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
93048104Syokota}
93148104Syokota#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
93248104Syokota
93348104Syokota/* probe video adapters and return the number of detected adapters */
93448104Syokotastatic int
93548104Syokotaprobe_adapters(void)
93648104Syokota{
93748104Syokota    video_adapter_t *adp;
93848104Syokota    video_info_t info;
93948104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
94048104Syokota    u_char *mp;
94148104Syokota#endif
94248104Syokota    int i;
94348104Syokota
94448104Syokota    /* do this test only once */
94548104Syokota    if (vga_init_done)
94648104Syokota	return biosadapters;
94748104Syokota    vga_init_done = TRUE;
94848104Syokota
94948104Syokota    /*
95048104Syokota     * Locate display adapters.
95148104Syokota     * The AT architecture supports upto two adapters. `syscons' allows
95248104Syokota     * the following combinations of adapters:
95348104Syokota     *     1) MDA + CGA
95448104Syokota     *     2) MDA + EGA/VGA color
95548104Syokota     *     3) CGA + EGA/VGA mono
95648104Syokota     * Note that `syscons' doesn't bother with MCGA as it is only
95748104Syokota     * avaiable for low end PS/2 models which has 80286 or earlier CPUs,
95848104Syokota     * thus, they are not running FreeBSD!
95948104Syokota     * When there are two adapaters in the system, one becomes `primary'
96048104Syokota     * and the other `secondary'. The EGA adapter has a set of DIP
96148104Syokota     * switches on board for this information and the EGA BIOS copies
96248104Syokota     * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88).
96348104Syokota     * The VGA BIOS has more sophisticated mechanism and has this
96448104Syokota     * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains
96548104Syokota     * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH.
96648104Syokota     */
96748104Syokota
96848104Syokota    /*
96948104Syokota     * Check rtc and BIOS data area.
97048104Syokota     * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead
97148104Syokota     * copy of RTC_EQUIPMENT.  Bits 4 and 5 of ETC_EQUIPMENT are
97248104Syokota     * zeros for EGA and VGA.  However, the EGA/VGA BIOS sets
97348104Syokota     * these bits in BIOSDATA_EQUIPMENT according to the monitor
97448104Syokota     * type detected.
97548104Syokota     */
97648104Syokota#ifndef VGA_NO_BIOS
97755729Syokota    if (*(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8)) {
97855729Syokota	/* EGA/VGA BIOS is present */
97948104Syokota	fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
98048104Syokota			   biosadapter);
98155729Syokota    } else {
98255729Syokota	switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
98355729Syokota	case 0:
98455729Syokota	    /* EGA/VGA: shouldn't be happening */
98555729Syokota	    fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
98655729Syokota			       biosadapter);
98755729Syokota	    break;
98855729Syokota	case 1:
98955729Syokota	    /* CGA 40x25 */
99055729Syokota	    /* FIXME: switch to the 80x25 mode? XXX */
99155729Syokota	    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40];
99255729Syokota	    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
99355729Syokota	    break;
99455729Syokota	case 2:
99555729Syokota	    /* CGA 80x25 */
99655729Syokota	    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80];
99755729Syokota	    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
99855729Syokota	    break;
99955729Syokota	case 3:
100055729Syokota	    /* MDA */
100155729Syokota	    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
100255729Syokota	    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
100355729Syokota	    break;
100455729Syokota	}
100548104Syokota    }
100648104Syokota#else
100748104Syokota    /* assume EGA/VGA? XXX */
100848104Syokota    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80];
100948104Syokota    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
101048104Syokota#endif /* VGA_NO_BIOS */
101148104Syokota
101248104Syokota    biosadapters = 0;
101348104Syokota    if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) {
101448104Syokota	++biosadapters;
101548104Syokota	biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED;
101648104Syokota	biosadapter[V_ADP_SECONDARY].va_mode =
101748104Syokota	    biosadapter[V_ADP_SECONDARY].va_initial_mode =
101848104Syokota	    map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type,
101948104Syokota			      biosadapter[V_ADP_SECONDARY].va_flags
102048104Syokota				  & V_ADP_COLOR,
102148104Syokota			      biosadapter[V_ADP_SECONDARY].va_initial_bios_mode);
102248104Syokota    } else {
102348104Syokota	biosadapter[V_ADP_SECONDARY].va_type = -1;
102448104Syokota    }
102548104Syokota    if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) {
102648104Syokota	++biosadapters;
102748104Syokota	biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED;
102848104Syokota#ifndef VGA_NO_BIOS
102948104Syokota	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode =
103048104Syokota	    readb(BIOS_PADDRTOVADDR(0x449));
103148104Syokota#else
103248104Syokota	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3;	/* XXX */
103348104Syokota#endif
103448104Syokota	biosadapter[V_ADP_PRIMARY].va_mode =
103548104Syokota	    biosadapter[V_ADP_PRIMARY].va_initial_mode =
103648104Syokota	    map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type,
103748104Syokota			      biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR,
103848104Syokota			      biosadapter[V_ADP_PRIMARY].va_initial_bios_mode);
103948104Syokota    } else {
104048104Syokota	biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY];
104148104Syokota	biosadapter[V_ADP_SECONDARY].va_type = -1;
104248104Syokota    }
104348104Syokota    if (biosadapters == 0)
104448104Syokota	return biosadapters;
104548104Syokota    biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY;
104648104Syokota    biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY;
104748104Syokota
104848104Syokota#if 0 /* we don't need these... */
104948104Syokota    fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...);
105048104Syokota    fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...);
105148104Syokota#endif
105248104Syokota
1053153072Sru#ifdef notyet
105448104Syokota    /*
105548104Syokota     * We cannot have two video adapter of the same type; there must be
105648104Syokota     * only one of color or mono adapter, or one each of them.
105748104Syokota     */
105848104Syokota    if (biosadapters > 1) {
105948104Syokota	if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags)
106048104Syokota	      & V_ADP_COLOR))
106148104Syokota	    /* we have two mono or color adapters!! */
106248104Syokota	    return (biosadapters = 0);
106348104Syokota    }
106448104Syokota#endif
106548104Syokota
106648104Syokota    /*
106794275Sphk     * Ensure a zero start address. The registers are w/o
106848104Syokota     * for old hardware so it's too hard to relocate the active screen
106948104Syokota     * memory.
107048104Syokota     * This must be done before vga_save_state() for VGA.
107148104Syokota     */
107248104Syokota    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12);
107348104Syokota    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
107448104Syokota    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13);
107548104Syokota    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
107648104Syokota
107748104Syokota    /* the video mode parameter table in EGA/VGA BIOS */
107848104Syokota    /* NOTE: there can be only one EGA/VGA, wheather color or mono,
107948104Syokota     * recognized by the video BIOS.
108048104Syokota     */
108148104Syokota    if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) ||
108248104Syokota	(biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) {
108348104Syokota	adp = &biosadapter[V_ADP_PRIMARY];
108448104Syokota    } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) ||
108548104Syokota	       (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) {
108648104Syokota	adp = &biosadapter[V_ADP_SECONDARY];
108748104Syokota    } else {
108848104Syokota	adp = NULL;
108948104Syokota    }
109048104Syokota    bzero(mode_map, sizeof(mode_map));
109148104Syokota    if (adp != NULL) {
109248104Syokota	if (adp->va_type == KD_VGA) {
109348104Syokota	    vga_save_state(adp, &adpstate, sizeof(adpstate));
109448104Syokota#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
109548104Syokota	    mode_map[adp->va_initial_mode] = adpstate.regs;
109648104Syokota	    rows_offset = 1;
109748104Syokota#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
109848104Syokota	    if (video_mode_ptr == NULL) {
109948104Syokota		mode_map[adp->va_initial_mode] = adpstate.regs;
110048104Syokota		rows_offset = 1;
110148104Syokota	    } else {
110248104Syokota		/* discard the table if we are not familiar with it... */
110348104Syokota		map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
110448104Syokota		mp = get_mode_param(adp->va_initial_mode);
110548104Syokota		if (mp != NULL)
110648104Syokota		    bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs));
110748104Syokota		switch (comp_adpregs(adpstate.regs, mp)) {
110848104Syokota		case COMP_IDENTICAL:
110948104Syokota		    /*
111048104Syokota		     * OK, this parameter table looks reasonably familiar
111148104Syokota		     * to us...
111248104Syokota		     */
111348104Syokota		    /*
111448104Syokota		     * This is a kludge for Toshiba DynaBook SS433
111548104Syokota		     * whose BIOS video mode table entry has the actual #
111648104Syokota		     * of rows at the offset 1; BIOSes from other
111748104Syokota		     * manufacturers store the # of rows - 1 there. XXX
111848104Syokota		     */
111948104Syokota		    rows_offset = adpstate.regs[1] + 1 - mp[1];
112048104Syokota		    break;
112148104Syokota
112248104Syokota		case COMP_SIMILAR:
112348104Syokota		    /*
112448104Syokota		     * Not exactly the same, but similar enough to be
112548104Syokota		     * trusted. However, use the saved register values
112648104Syokota		     * for the initial mode and other modes which are
112748104Syokota		     * based on the initial mode.
112848104Syokota		     */
112948104Syokota		    mode_map[adp->va_initial_mode] = adpstate.regs;
113048104Syokota		    rows_offset = adpstate.regs[1] + 1 - mp[1];
113148104Syokota		    adpstate.regs[1] -= rows_offset - 1;
113248104Syokota		    break;
113348104Syokota
113448104Syokota		case COMP_DIFFERENT:
113548104Syokota		default:
113648104Syokota		    /*
113748104Syokota		     * Don't use the paramter table in BIOS. It doesn't
113848104Syokota		     * look familiar to us. Video mode switching is allowed
113948104Syokota		     * only if the new mode is the same as or based on
114048104Syokota		     * the initial mode.
114148104Syokota		     */
114248104Syokota		    video_mode_ptr = NULL;
114348104Syokota		    bzero(mode_map, sizeof(mode_map));
114448104Syokota		    mode_map[adp->va_initial_mode] = adpstate.regs;
114548104Syokota		    rows_offset = 1;
114648104Syokota		    break;
114748104Syokota		}
114848104Syokota	    }
114948104Syokota#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
115048104Syokota
115148104Syokota#ifndef VGA_NO_MODE_CHANGE
115248104Syokota	    adp->va_flags |= V_ADP_MODECHANGE;
115348104Syokota#endif
115448104Syokota#ifndef VGA_NO_FONT_LOADING
115548104Syokota	    adp->va_flags |= V_ADP_FONT;
115648104Syokota#endif
115748104Syokota	} else if (adp->va_type == KD_EGA) {
115848104Syokota#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
115948104Syokota	    rows_offset = 1;
116048104Syokota#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
116148104Syokota	    if (video_mode_ptr == NULL) {
116248104Syokota		rows_offset = 1;
116348104Syokota	    } else {
116448104Syokota		map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1);
116548104Syokota		/* XXX how can one validate the EGA table... */
116648104Syokota		mp = get_mode_param(adp->va_initial_mode);
116748104Syokota		if (mp != NULL) {
116848104Syokota		    adp->va_flags |= V_ADP_MODECHANGE;
116948104Syokota#ifndef VGA_NO_FONT_LOADING
117048104Syokota		    adp->va_flags |= V_ADP_FONT;
117148104Syokota#endif
117248104Syokota		    rows_offset = 1;
117348104Syokota		} else {
117448104Syokota		    /*
117548104Syokota		     * This is serious. We will not be able to switch video
117648104Syokota		     * modes at all...
117748104Syokota		     */
117848104Syokota		    video_mode_ptr = NULL;
117948104Syokota		    bzero(mode_map, sizeof(mode_map));
118048104Syokota		    rows_offset = 1;
118148104Syokota                }
118248104Syokota	    }
118348104Syokota#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
118448104Syokota	}
118548104Syokota    }
118648104Syokota
118748104Syokota    /* remove conflicting modes if we have more than one adapter */
118856522Sdfr    if (biosadapters > 0) {
118948104Syokota	for (i = 0; i < biosadapters; ++i) {
119048104Syokota	    if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE))
119148104Syokota		continue;
119248104Syokota	    clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1,
119348104Syokota			   (biosadapter[i].va_flags & V_ADP_COLOR) ?
119448104Syokota			       V_INFO_COLOR : 0);
119548104Syokota	    if ((biosadapter[i].va_type == KD_VGA)
119648104Syokota		|| (biosadapter[i].va_type == KD_EGA)) {
119748104Syokota		biosadapter[i].va_io_base =
119848104Syokota		    (biosadapter[i].va_flags & V_ADP_COLOR) ?
119948104Syokota			IO_VGA : IO_MDA;
120048104Syokota		biosadapter[i].va_io_size = 32;
120148104Syokota	    }
120248104Syokota	}
120348104Syokota    }
120448104Syokota
120548104Syokota    /* buffer address */
120648104Syokota    vga_get_info(&biosadapter[V_ADP_PRIMARY],
120748104Syokota		 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info);
120848104Syokota    info.vi_flags &= ~V_INFO_LINEAR; /* XXX */
120948104Syokota    update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info);
121048104Syokota
121148104Syokota    if (biosadapters > 1) {
121248104Syokota	vga_get_info(&biosadapter[V_ADP_SECONDARY],
121348104Syokota		     biosadapter[V_ADP_SECONDARY].va_initial_mode, &info);
121448104Syokota	info.vi_flags &= ~V_INFO_LINEAR; /* XXX */
121548104Syokota	update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info);
121648104Syokota    }
121748104Syokota
121848104Syokota    /*
121948104Syokota     * XXX: we should verify the following values for the primary adapter...
122048104Syokota     * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
122148104Syokota     * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
122248104Syokota     *                     ? 0 : V_ADP_COLOR;
122348104Syokota     * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
122448104Syokota     * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
122548104Syokota     * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
122648104Syokota     * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
122748104Syokota     */
122848104Syokota
122948104Syokota    return biosadapters;
123048104Syokota}
123148104Syokota
123248104Syokota/* set the scan line length in pixel */
123348104Syokotastatic int
123448104Syokotaset_line_length(video_adapter_t *adp, int pixel)
123548104Syokota{
123648104Syokota    u_char *mp;
123748104Syokota    int ppw;	/* pixels per word */
123848104Syokota    int bpl;	/* bytes per line */
123948104Syokota    int count;
124048104Syokota
124148104Syokota    if ((adp->va_type != KD_VGA) && (adp->va_type != KD_EGA))
124248104Syokota	return ENODEV;
124348104Syokota    mp = get_mode_param(adp->va_mode);
124448104Syokota    if (mp == NULL)
124548104Syokota	return EINVAL;
124648104Syokota
124748104Syokota    switch (adp->va_info.vi_mem_model) {
124848104Syokota    case V_INFO_MM_PLANAR:
124948104Syokota	ppw = 16/(adp->va_info.vi_depth/adp->va_info.vi_planes);
125048104Syokota	count = (pixel + ppw - 1)/ppw/2;
125148104Syokota	bpl = ((pixel + ppw - 1)/ppw/2)*4;
125248104Syokota	break;
125348104Syokota    case V_INFO_MM_PACKED:
125448104Syokota	count = (pixel + 7)/8;
125548104Syokota	bpl = ((pixel + 7)/8)*8;
125648104Syokota	break;
125748104Syokota    case V_INFO_MM_TEXT:
125848104Syokota	count = (pixel + 7)/8;			/* columns */
125948104Syokota	bpl = (pixel + 7)/8;			/* columns */
126048104Syokota	break;
126148104Syokota    default:
126248104Syokota	return ENODEV;
126348104Syokota    }
126448104Syokota
126548104Syokota    if (mp[10 + 0x17] & 0x40)			/* CRTC mode control reg */
126648104Syokota	count *= 2;				/* byte mode */
126748104Syokota    outb(adp->va_crtc_addr, 0x13);
126848104Syokota    outb(adp->va_crtc_addr + 1, count);
126948104Syokota    adp->va_line_width = bpl;
127048104Syokota
127148104Syokota    return 0;
127248104Syokota}
127348104Syokota
127448104Syokotastatic int
127548104Syokotaset_display_start(video_adapter_t *adp, int x, int y)
127648104Syokota{
127748104Syokota    int off;	/* byte offset (graphics mode)/word offset (text mode) */
127848104Syokota    int poff;	/* pixel offset */
127948104Syokota    int roff;	/* row offset */
128048104Syokota    int ppb;	/* pixels per byte */
128148104Syokota
128248104Syokota    if ((adp->va_type != KD_VGA) && (adp->va_type != KD_EGA))
128348104Syokota	x &= ~7;
128448104Syokota    if (adp->va_info.vi_flags & V_INFO_GRAPHICS) {
128548104Syokota	ppb = 8/(adp->va_info.vi_depth/adp->va_info.vi_planes);
128648104Syokota	off = y*adp->va_line_width + x/ppb;
128748104Syokota	roff = 0;
128848104Syokota	poff = x%ppb;
128948104Syokota    } else {
129048104Syokota	if ((adp->va_type == KD_VGA) || (adp->va_type == KD_EGA)) {
129148104Syokota	    outb(TSIDX, 1);
129248104Syokota	    if (inb(TSREG) & 1)
129348104Syokota		ppb = 9;
129448104Syokota	    else
129548104Syokota		ppb = 8;
129648104Syokota	} else {
129748104Syokota	    ppb = 8;
129848104Syokota	}
129948104Syokota	off = y/adp->va_info.vi_cheight*adp->va_line_width + x/ppb;
130048104Syokota	roff = y%adp->va_info.vi_cheight;
130148104Syokota	/* FIXME: is this correct? XXX */
130248104Syokota	if (ppb == 8)
130348104Syokota	    poff = x%ppb;
130448104Syokota	else
130548104Syokota	    poff = (x + 8)%ppb;
130648104Syokota    }
130748104Syokota
130848104Syokota    /* start address */
130948104Syokota    outb(adp->va_crtc_addr, 0xc);		/* high */
131048104Syokota    outb(adp->va_crtc_addr + 1, off >> 8);
131148104Syokota    outb(adp->va_crtc_addr, 0xd);		/* low */
131248104Syokota    outb(adp->va_crtc_addr + 1, off & 0xff);
131348104Syokota
131448104Syokota    /* horizontal pel pan */
131548104Syokota    if ((adp->va_type == KD_VGA) || (adp->va_type == KD_EGA)) {
131648104Syokota	inb(adp->va_crtc_addr + 6);
131748104Syokota	outb(ATC, 0x13 | 0x20);
131848104Syokota	outb(ATC, poff);
131948104Syokota	inb(adp->va_crtc_addr + 6);
132048104Syokota	outb(ATC, 0x20);
132148104Syokota    }
132248104Syokota
132348104Syokota    /* preset raw scan */
132448104Syokota    outb(adp->va_crtc_addr, 8);
132548104Syokota    outb(adp->va_crtc_addr + 1, roff);
132648104Syokota
132748104Syokota    adp->va_disp_start.x = x;
132848104Syokota    adp->va_disp_start.y = y;
132948104Syokota    return 0;
133048104Syokota}
133148104Syokota
1332138891Sru#ifndef VGA_NO_MODE_CHANGE
1333114383Speter#if defined(__i386__) || defined(__amd64__)	/* XXX */
133448104Syokotastatic void
133548104Syokotafill(int val, void *d, size_t size)
133648104Syokota{
133748104Syokota    u_char *p = d;
133848104Syokota
133948104Syokota    while (size-- > 0)
134048104Syokota	*p++ = val;
134148104Syokota}
134248104Syokota#endif /* __i386__ */
134348104Syokota
134448104Syokotastatic void
134548104Syokotafilll_io(int val, vm_offset_t d, size_t size)
134648104Syokota{
134748104Syokota    while (size-- > 0) {
134848104Syokota	writel(d, val);
134948104Syokota	d += sizeof(u_int32_t);
135048104Syokota    }
135148104Syokota}
1352138891Sru#endif /* !VGA_NO_MODE_CHANGE */
135348104Syokota
135448104Syokota/* entry points */
135548104Syokota
135648238Speter#if 0
135748104Syokotastatic int
135848104Syokotavga_nop(void)
135948104Syokota{
136048104Syokota    return 0;
136148104Syokota}
136248238Speter#endif
136348104Syokota
136448104Syokotastatic int
136548104Syokotavga_error(void)
136648104Syokota{
136748104Syokota    return ENODEV;
136848104Syokota}
136948104Syokota
137048104Syokotastatic int
137148104Syokotavga_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
137248104Syokota{
137348104Syokota    probe_adapters();
137448104Syokota    if (unit >= biosadapters)
137548104Syokota	return ENXIO;
137648104Syokota
137748104Syokota    *adpp = &biosadapter[unit];
137848104Syokota
137948104Syokota    return 0;
138048104Syokota}
138148104Syokota
138248104Syokotastatic int
138348104Syokotavga_init(int unit, video_adapter_t *adp, int flags)
138448104Syokota{
138548104Syokota    if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp))
138648104Syokota	return ENXIO;
138748104Syokota
138848104Syokota    if (!init_done(adp)) {
138948104Syokota	/* nothing to do really... */
139048104Syokota	adp->va_flags |= V_ADP_INITIALIZED;
139148104Syokota    }
139248104Syokota
139348104Syokota    if (!config_done(adp)) {
139448104Syokota	if (vid_register(adp) < 0)
139548104Syokota		return ENXIO;
139648104Syokota	adp->va_flags |= V_ADP_REGISTERED;
139748104Syokota    }
139848104Syokota    if (vga_sub_configure != NULL)
139948104Syokota	(*vga_sub_configure)(0);
140048104Syokota
140148104Syokota    return 0;
140248104Syokota}
140348104Syokota
140448104Syokota/*
140548104Syokota * get_info():
140648104Syokota * Return the video_info structure of the requested video mode.
140748104Syokota *
140848104Syokota * all adapters
140948104Syokota */
141048104Syokotastatic int
141148104Syokotavga_get_info(video_adapter_t *adp, int mode, video_info_t *info)
141248104Syokota{
141348104Syokota    int i;
141448104Syokota
141548104Syokota    if (!vga_init_done)
141648104Syokota	return ENXIO;
141748104Syokota
141848104Syokota    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
141948104Syokota#ifndef VGA_NO_MODE_CHANGE
142048104Syokota    if (adp->va_flags & V_ADP_MODECHANGE) {
142148104Syokota	/*
142248104Syokota	 * If the parameter table entry for this mode is not found,
142348104Syokota	 * the mode is not supported...
142448104Syokota	 */
142548104Syokota	if (get_mode_param(mode) == NULL)
142648104Syokota	    return EINVAL;
142748104Syokota    } else
142848104Syokota#endif /* VGA_NO_MODE_CHANGE */
142948104Syokota    {
143048104Syokota	/*
143148104Syokota	 * Even if we don't support video mode switching on this adapter,
143248104Syokota	 * the information on the initial (thus current) video mode
143348104Syokota	 * should be made available.
143448104Syokota	 */
143548104Syokota	if (mode != adp->va_initial_mode)
143648104Syokota	    return EINVAL;
143748104Syokota    }
143848104Syokota
143948104Syokota    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
144048104Syokota	if (bios_vmode[i].vi_mode == NA)
144148104Syokota	    continue;
144248104Syokota	if (mode == bios_vmode[i].vi_mode) {
144348104Syokota	    *info = bios_vmode[i];
144448104Syokota	    /* XXX */
144548104Syokota	    info->vi_buffer_size = info->vi_window_size*info->vi_planes;
144648104Syokota	    return 0;
144748104Syokota	}
144848104Syokota    }
144948104Syokota    return EINVAL;
145048104Syokota}
145148104Syokota
145248104Syokota/*
145348104Syokota * query_mode():
145448104Syokota * Find a video mode matching the requested parameters.
145548104Syokota * Fields filled with 0 are considered "don't care" fields and
145648104Syokota * match any modes.
145748104Syokota *
145848104Syokota * all adapters
145948104Syokota */
146048104Syokotastatic int
146148104Syokotavga_query_mode(video_adapter_t *adp, video_info_t *info)
146248104Syokota{
146348104Syokota    int i;
146448104Syokota
146548104Syokota    if (!vga_init_done)
146654258Syokota	return ENXIO;
146748104Syokota
146848104Syokota    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
146948104Syokota	if (bios_vmode[i].vi_mode == NA)
147048104Syokota	    continue;
147148104Syokota
147248104Syokota	if ((info->vi_width != 0)
147348104Syokota	    && (info->vi_width != bios_vmode[i].vi_width))
147448104Syokota		continue;
147548104Syokota	if ((info->vi_height != 0)
147648104Syokota	    && (info->vi_height != bios_vmode[i].vi_height))
147748104Syokota		continue;
147848104Syokota	if ((info->vi_cwidth != 0)
147948104Syokota	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
148048104Syokota		continue;
148148104Syokota	if ((info->vi_cheight != 0)
148248104Syokota	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
148348104Syokota		continue;
148448104Syokota	if ((info->vi_depth != 0)
148548104Syokota	    && (info->vi_depth != bios_vmode[i].vi_depth))
148648104Syokota		continue;
148748104Syokota	if ((info->vi_planes != 0)
148848104Syokota	    && (info->vi_planes != bios_vmode[i].vi_planes))
148948104Syokota		continue;
149048104Syokota	/* XXX: should check pixel format, memory model */
149148104Syokota	if ((info->vi_flags != 0)
149248104Syokota	    && (info->vi_flags != bios_vmode[i].vi_flags))
149348104Syokota		continue;
149448104Syokota
149548104Syokota	/* verify if this mode is supported on this adapter */
149654258Syokota	if (vga_get_info(adp, bios_vmode[i].vi_mode, info))
149748104Syokota		continue;
149854258Syokota	return 0;
149948104Syokota    }
150054258Syokota    return ENODEV;
150148104Syokota}
150248104Syokota
150348104Syokota/*
150448104Syokota * set_mode():
150548104Syokota * Change the video mode.
150648104Syokota *
150748104Syokota * EGA/VGA
150848104Syokota */
150948104Syokota
151048104Syokota#ifndef VGA_NO_MODE_CHANGE
151148104Syokota#ifdef VGA_WIDTH90
151248104Syokotastatic void
151348104Syokotaset_width90(adp_state_t *params)
151448104Syokota{
151548104Syokota    /*
151648104Syokota     * Based on code submitted by Kelly Yancey (kbyanc@freedomnet.com)
151748104Syokota     * and alexv@sui.gda.itesm.mx.
151848104Syokota     */
151948104Syokota    params->regs[5] |= 1;		/* toggle 8 pixel wide fonts */
152048104Syokota    params->regs[10+0x0] = 0x6b;
152148104Syokota    params->regs[10+0x1] = 0x59;
152248104Syokota    params->regs[10+0x2] = 0x5a;
152348104Syokota    params->regs[10+0x3] = 0x8e;
152448104Syokota    params->regs[10+0x4] = 0x5e;
152548104Syokota    params->regs[10+0x5] = 0x8a;
152648104Syokota    params->regs[10+0x13] = 45;
152748104Syokota    params->regs[35+0x13] = 0;
152848104Syokota}
152948104Syokota#endif /* VGA_WIDTH90 */
153048104Syokota#endif /* !VGA_NO_MODE_CHANGE */
153148104Syokota
153248104Syokotastatic int
153348104Syokotavga_set_mode(video_adapter_t *adp, int mode)
153448104Syokota{
153548104Syokota#ifndef VGA_NO_MODE_CHANGE
153648104Syokota    video_info_t info;
153748104Syokota    adp_state_t params;
153848104Syokota
153948104Syokota    prologue(adp, V_ADP_MODECHANGE, ENODEV);
154048104Syokota
154148104Syokota    mode = map_gen_mode_num(adp->va_type,
154248104Syokota			    adp->va_flags & V_ADP_COLOR, mode);
154348104Syokota    if (vga_get_info(adp, mode, &info))
154448104Syokota	return EINVAL;
154548104Syokota
154648104Syokota#if VGA_DEBUG > 1
154748104Syokota    printf("vga_set_mode(): setting mode %d\n", mode);
154848104Syokota#endif
154948104Syokota
155048104Syokota    params.sig = V_STATE_SIG;
155148104Syokota    bcopy(get_mode_param(mode), params.regs, sizeof(params.regs));
155248104Syokota
155348104Syokota    switch (mode) {
155448104Syokota#ifdef VGA_WIDTH90
155548104Syokota    case M_VGA_C90x60: case M_VGA_M90x60:
155648104Syokota	set_width90(&params);
1557102412Scharnier	/* FALLTHROUGH */
155848104Syokota#endif
155948104Syokota    case M_VGA_C80x60: case M_VGA_M80x60:
156048104Syokota	params.regs[2]  = 0x08;
156148104Syokota	params.regs[19] = 0x47;
156248104Syokota	goto special_480l;
156348104Syokota
156448104Syokota#ifdef VGA_WIDTH90
156548104Syokota    case M_VGA_C90x30: case M_VGA_M90x30:
156648104Syokota	set_width90(&params);
1567102412Scharnier	/* FALLTHROUGH */
156848104Syokota#endif
156948104Syokota    case M_VGA_C80x30: case M_VGA_M80x30:
157048104Syokota	params.regs[19] = 0x4f;
157148104Syokotaspecial_480l:
157248104Syokota	params.regs[9] |= 0xc0;
157348104Syokota	params.regs[16] = 0x08;
157448104Syokota	params.regs[17] = 0x3e;
157548104Syokota	params.regs[26] = 0xea;
157648104Syokota	params.regs[28] = 0xdf;
157748104Syokota	params.regs[31] = 0xe7;
157848104Syokota	params.regs[32] = 0x04;
157948104Syokota	goto setup_mode;
158048104Syokota
158148104Syokota#ifdef VGA_WIDTH90
158248104Syokota    case M_VGA_C90x43: case M_VGA_M90x43:
158348104Syokota	set_width90(&params);
1584102412Scharnier	/* FALLTHROUGH */
158548104Syokota#endif
158648104Syokota    case M_ENH_C80x43: case M_ENH_B80x43:
158748104Syokota	params.regs[28] = 87;
158848104Syokota	goto special_80x50;
158948104Syokota
159048104Syokota#ifdef VGA_WIDTH90
159148104Syokota    case M_VGA_C90x50: case M_VGA_M90x50:
159248104Syokota	set_width90(&params);
1593102412Scharnier	/* FALLTHROUGH */
159448104Syokota#endif
159548104Syokota    case M_VGA_C80x50: case M_VGA_M80x50:
159648104Syokotaspecial_80x50:
159748104Syokota	params.regs[2] = 8;
159848104Syokota	params.regs[19] = 7;
159948104Syokota	goto setup_mode;
160048104Syokota
160148104Syokota#ifdef VGA_WIDTH90
160248104Syokota    case M_VGA_C90x25: case M_VGA_M90x25:
160348104Syokota	set_width90(&params);
1604102412Scharnier	/* FALLTHROUGH */
160548104Syokota#endif
160648104Syokota    case M_VGA_C40x25: case M_VGA_C80x25:
160748104Syokota    case M_VGA_M80x25:
160848104Syokota    case M_B40x25:     case M_C40x25:
160948104Syokota    case M_B80x25:     case M_C80x25:
161048104Syokota    case M_ENH_B40x25: case M_ENH_C40x25:
161148104Syokota    case M_ENH_B80x25: case M_ENH_C80x25:
161248104Syokota    case M_EGAMONO80x25:
161348104Syokota
161448104Syokotasetup_mode:
161548104Syokota	vga_load_state(adp, &params);
161648104Syokota	break;
161748104Syokota
161848104Syokota    case M_VGA_MODEX:
161948104Syokota	/* "unchain" the VGA mode */
162048104Syokota	params.regs[5-1+0x04] &= 0xf7;
162148104Syokota	params.regs[5-1+0x04] |= 0x04;
162248104Syokota	/* turn off doubleword mode */
162348104Syokota	params.regs[10+0x14] &= 0xbf;
162480203Skris	/* turn off word addressing */
162548104Syokota	params.regs[10+0x17] |= 0x40;
162648104Syokota	/* set logical screen width */
162748104Syokota	params.regs[10+0x13] = 80;
162848104Syokota	/* set 240 lines */
162948104Syokota	params.regs[10+0x11] = 0x2c;
163048104Syokota	params.regs[10+0x06] = 0x0d;
163148104Syokota	params.regs[10+0x07] = 0x3e;
163248104Syokota	params.regs[10+0x10] = 0xea;
163348104Syokota	params.regs[10+0x11] = 0xac;
163448104Syokota	params.regs[10+0x12] = 0xdf;
163548104Syokota	params.regs[10+0x15] = 0xe7;
163648104Syokota	params.regs[10+0x16] = 0x06;
163748104Syokota	/* set vertical sync polarity to reflect aspect ratio */
163848104Syokota	params.regs[9] = 0xe3;
163948104Syokota	goto setup_grmode;
164048104Syokota
164148104Syokota    case M_BG320:     case M_CG320:     case M_BG640:
164248104Syokota    case M_CG320_D:   case M_CG640_E:
164348104Syokota    case M_CG640x350: case M_ENH_CG640:
164448104Syokota    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
164548104Syokota
164648104Syokotasetup_grmode:
164748104Syokota	vga_load_state(adp, &params);
164848104Syokota	break;
164948104Syokota
165048104Syokota    default:
165148104Syokota	return EINVAL;
165248104Syokota    }
165348104Syokota
165448104Syokota    adp->va_mode = mode;
165548104Syokota    info.vi_flags &= ~V_INFO_LINEAR; /* XXX */
165648104Syokota    update_adapter_info(adp, &info);
165748104Syokota
165848104Syokota    /* move hardware cursor out of the way */
1659174985Swkoszek    vidd_set_hw_cursor(adp, -1, -1);
166048104Syokota
166148104Syokota    return 0;
166248104Syokota#else /* VGA_NO_MODE_CHANGE */
166348104Syokota    return ENODEV;
166448104Syokota#endif /* VGA_NO_MODE_CHANGE */
166548104Syokota}
166648104Syokota
166748104Syokota#ifndef VGA_NO_FONT_LOADING
166848104Syokota
166948104Syokotastatic void
167048104Syokotaset_font_mode(video_adapter_t *adp, u_char *buf)
167148104Syokota{
167248104Syokota    u_char *mp;
167348104Syokota    int s;
167448104Syokota
167548104Syokota    s = splhigh();
167648104Syokota
167748104Syokota    /* save register values */
167848104Syokota    if (adp->va_type == KD_VGA) {
167948104Syokota	outb(TSIDX, 0x02); buf[0] = inb(TSREG);
168048104Syokota	outb(TSIDX, 0x04); buf[1] = inb(TSREG);
168148104Syokota	outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
168248104Syokota	outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
168348104Syokota	outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
168448104Syokota	inb(adp->va_crtc_addr + 6);
168548104Syokota	outb(ATC, 0x10); buf[5] = inb(ATC + 1);
168648104Syokota    } else /* if (adp->va_type == KD_EGA) */ {
168748104Syokota	/*
168848104Syokota	 * EGA cannot be read; copy parameters from the mode parameter
168948104Syokota	 * table.
169048104Syokota	 */
169148104Syokota	mp = get_mode_param(adp->va_mode);
169248104Syokota	buf[0] = mp[5 + 0x02 - 1];
169348104Syokota	buf[1] = mp[5 + 0x04 - 1];
169448104Syokota	buf[2] = mp[55 + 0x04];
169548104Syokota	buf[3] = mp[55 + 0x05];
169648104Syokota	buf[4] = mp[55 + 0x06];
169748104Syokota	buf[5] = mp[35 + 0x10];
169848104Syokota    }
169948104Syokota
170048104Syokota    /* setup vga for loading fonts */
170148104Syokota    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
170248104Syokota    outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
170348104Syokota    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
170448104Syokota    outb(ATC, 0x20);				/* enable palette */
170548104Syokota
1706153072Sru#ifdef VGA_SLOW_IOACCESS
170748104Syokota#ifdef VGA_ALT_SEQACCESS
170848104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x01);
170948104Syokota#endif
171048104Syokota    outb(TSIDX, 0x02); outb(TSREG, 0x04);
171148104Syokota    outb(TSIDX, 0x04); outb(TSREG, 0x07);
171248104Syokota#ifdef VGA_ALT_SEQACCESS
171348104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x03);
171448104Syokota#endif
171548104Syokota    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
171648104Syokota    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
171748104Syokota    outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
171848104Syokota#else /* VGA_SLOW_IOACCESS */
171948104Syokota#ifdef VGA_ALT_SEQACCESS
172048104Syokota    outw(TSIDX, 0x0100);
172148104Syokota#endif
172248104Syokota    outw(TSIDX, 0x0402);
172348104Syokota    outw(TSIDX, 0x0704);
172448104Syokota#ifdef VGA_ALT_SEQACCESS
172548104Syokota    outw(TSIDX, 0x0300);
172648104Syokota#endif
172748104Syokota    outw(GDCIDX, 0x0204);
172848104Syokota    outw(GDCIDX, 0x0005);
172948104Syokota    outw(GDCIDX, 0x0406);               /* addr = a0000, 64kb */
173048104Syokota#endif /* VGA_SLOW_IOACCESS */
173148104Syokota
173248104Syokota    splx(s);
173348104Syokota}
173448104Syokota
173548104Syokotastatic void
173648104Syokotaset_normal_mode(video_adapter_t *adp, u_char *buf)
173748104Syokota{
173848104Syokota    int s;
173948104Syokota
174048104Syokota    s = splhigh();
174148104Syokota
174248104Syokota    /* setup vga for normal operation mode again */
174348104Syokota    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
174448104Syokota    outb(ATC, 0x10); outb(ATC, buf[5]);
174548104Syokota    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
174648104Syokota    outb(ATC, 0x20);				/* enable palette */
174748104Syokota
1748153072Sru#ifdef VGA_SLOW_IOACCESS
174948104Syokota#ifdef VGA_ALT_SEQACCESS
175048104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x01);
175148104Syokota#endif
175248104Syokota    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
175348104Syokota    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
175448104Syokota#ifdef VGA_ALT_SEQACCESS
175548104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x03);
175648104Syokota#endif
175748104Syokota    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
175848104Syokota    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
175948104Syokota    if (adp->va_crtc_addr == MONO_CRTC) {
176048104Syokota	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
176148104Syokota    } else {
176248104Syokota	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
176348104Syokota    }
176448104Syokota#else /* VGA_SLOW_IOACCESS */
176548104Syokota#ifdef VGA_ALT_SEQACCESS
176648104Syokota    outw(TSIDX, 0x0100);
176748104Syokota#endif
176848104Syokota    outw(TSIDX, 0x0002 | (buf[0] << 8));
176948104Syokota    outw(TSIDX, 0x0004 | (buf[1] << 8));
177048104Syokota#ifdef VGA_ALT_SEQACCESS
177148104Syokota    outw(TSIDX, 0x0300);
177248104Syokota#endif
177348104Syokota    outw(GDCIDX, 0x0004 | (buf[2] << 8));
177448104Syokota    outw(GDCIDX, 0x0005 | (buf[3] << 8));
177548104Syokota    if (adp->va_crtc_addr == MONO_CRTC)
177648104Syokota        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
177748104Syokota    else
177848104Syokota        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
177948104Syokota#endif /* VGA_SLOW_IOACCESS */
178048104Syokota
178148104Syokota    splx(s);
178248104Syokota}
178348104Syokota
178448104Syokota#endif /* VGA_NO_FONT_LOADING */
178548104Syokota
178648104Syokota/*
178748104Syokota * save_font():
178848104Syokota * Read the font data in the requested font page from the video adapter.
178948104Syokota *
179048104Syokota * EGA/VGA
179148104Syokota */
179248104Syokotastatic int
1793150686Smariusvga_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
1794150686Smarius	      u_char *data, int ch, int count)
179548104Syokota{
179648104Syokota#ifndef VGA_NO_FONT_LOADING
179748104Syokota    u_char buf[PARAM_BUFSIZE];
1798115253Speter    vm_offset_t segment;
179948104Syokota    int c;
180048104Syokota#ifdef VGA_ALT_SEQACCESS
180148104Syokota    int s;
180248104Syokota    u_char val = 0;
180348104Syokota#endif
180448104Syokota
180548104Syokota    prologue(adp, V_ADP_FONT, ENODEV);
180648104Syokota
180748104Syokota    if (fontsize < 14) {
180848104Syokota	/* FONT_8 */
180948104Syokota	fontsize = 8;
181048104Syokota    } else if (fontsize >= 32) {
181148104Syokota	fontsize = 32;
181248104Syokota    } else if (fontsize >= 16) {
181348104Syokota	/* FONT_16 */
181448104Syokota	fontsize = 16;
181548104Syokota    } else {
181648104Syokota	/* FONT_14 */
181748104Syokota	fontsize = 14;
181848104Syokota    }
181948104Syokota
1820150686Smarius    if (page < 0 || page >= 8 || fontwidth != 8)
182148104Syokota	return EINVAL;
182248104Syokota    segment = FONT_BUF + 0x4000*page;
182348104Syokota    if (page > 3)
182448104Syokota	segment -= 0xe000;
182548104Syokota
182648104Syokota#ifdef VGA_ALT_SEQACCESS
182748104Syokota    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
182848104Syokota	s = splhigh();
182948104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x01);
183048104Syokota	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
183148104Syokota	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
183248104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x03);
183348104Syokota	splx(s);
183448104Syokota    }
183548104Syokota#endif
183648104Syokota
183748104Syokota    set_font_mode(adp, buf);
183848104Syokota    if (fontsize == 32) {
1839114383Speter	bcopy_fromio((uintptr_t)segment + ch*32, data, fontsize*count);
184048104Syokota    } else {
184148104Syokota	for (c = ch; count > 0; ++c, --count) {
1842114383Speter	    bcopy_fromio((uintptr_t)segment + c*32, data, fontsize);
184348104Syokota	    data += fontsize;
184448104Syokota	}
184548104Syokota    }
184648104Syokota    set_normal_mode(adp, buf);
184748104Syokota
184848104Syokota#ifdef VGA_ALT_SEQACCESS
184948104Syokota    if (adp->va_type == KD_VGA) {
185048104Syokota	s = splhigh();
185148104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x01);
185248104Syokota	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
185348104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x03);
185448104Syokota	splx(s);
185548104Syokota    }
185648104Syokota#endif
185748104Syokota
185848104Syokota    return 0;
185948104Syokota#else /* VGA_NO_FONT_LOADING */
186048104Syokota    return ENODEV;
186148104Syokota#endif /* VGA_NO_FONT_LOADING */
186248104Syokota}
186348104Syokota
186448104Syokota/*
186548104Syokota * load_font():
186648104Syokota * Set the font data in the requested font page.
186748104Syokota * NOTE: it appears that some recent video adapters do not support
186848104Syokota * the font page other than 0... XXX
186948104Syokota *
187048104Syokota * EGA/VGA
187148104Syokota */
187248104Syokotastatic int
1873150686Smariusvga_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
1874150686Smarius	      u_char *data, int ch, int count)
187548104Syokota{
187648104Syokota#ifndef VGA_NO_FONT_LOADING
187748104Syokota    u_char buf[PARAM_BUFSIZE];
1878115253Speter    vm_offset_t segment;
187948104Syokota    int c;
188048104Syokota#ifdef VGA_ALT_SEQACCESS
188148104Syokota    int s;
188248104Syokota    u_char val = 0;
188348104Syokota#endif
188448104Syokota
188548104Syokota    prologue(adp, V_ADP_FONT, ENODEV);
188648104Syokota
188748104Syokota    if (fontsize < 14) {
188848104Syokota	/* FONT_8 */
188948104Syokota	fontsize = 8;
189048104Syokota    } else if (fontsize >= 32) {
189148104Syokota	fontsize = 32;
189248104Syokota    } else if (fontsize >= 16) {
189348104Syokota	/* FONT_16 */
189448104Syokota	fontsize = 16;
189548104Syokota    } else {
189648104Syokota	/* FONT_14 */
189748104Syokota	fontsize = 14;
189848104Syokota    }
189948104Syokota
1900150686Smarius    if (page < 0 || page >= 8 || fontwidth != 8)
190148104Syokota	return EINVAL;
190248104Syokota    segment = FONT_BUF + 0x4000*page;
190348104Syokota    if (page > 3)
190448104Syokota	segment -= 0xe000;
190548104Syokota
190648104Syokota#ifdef VGA_ALT_SEQACCESS
190748104Syokota    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
190848104Syokota	s = splhigh();
190948104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x01);
191048104Syokota	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
191148104Syokota	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
191248104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x03);
191348104Syokota	splx(s);
191448104Syokota    }
191548104Syokota#endif
191648104Syokota
191748104Syokota    set_font_mode(adp, buf);
191848104Syokota    if (fontsize == 32) {
1919114383Speter	bcopy_toio(data, (uintptr_t)segment + ch*32, fontsize*count);
192048104Syokota    } else {
192148104Syokota	for (c = ch; count > 0; ++c, --count) {
1922114383Speter	    bcopy_toio(data, (uintptr_t)segment + c*32, fontsize);
192348104Syokota	    data += fontsize;
192448104Syokota	}
192548104Syokota    }
192648104Syokota    set_normal_mode(adp, buf);
192748104Syokota
192848104Syokota#ifdef VGA_ALT_SEQACCESS
192948104Syokota    if (adp->va_type == KD_VGA) {
193048104Syokota	s = splhigh();
193148104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x01);
193248104Syokota	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
193348104Syokota	outb(TSIDX, 0x00); outb(TSREG, 0x03);
193448104Syokota	splx(s);
193548104Syokota    }
193648104Syokota#endif
193748104Syokota
193848104Syokota    return 0;
193948104Syokota#else /* VGA_NO_FONT_LOADING */
194048104Syokota    return ENODEV;
194148104Syokota#endif /* VGA_NO_FONT_LOADING */
194248104Syokota}
194348104Syokota
194448104Syokota/*
194548104Syokota * show_font():
194648104Syokota * Activate the requested font page.
194748104Syokota * NOTE: it appears that some recent video adapters do not support
194848104Syokota * the font page other than 0... XXX
194948104Syokota *
195048104Syokota * EGA/VGA
195148104Syokota */
195248104Syokotastatic int
195348104Syokotavga_show_font(video_adapter_t *adp, int page)
195448104Syokota{
195548104Syokota#ifndef VGA_NO_FONT_LOADING
195648104Syokota    static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
195748104Syokota    int s;
195848104Syokota
195948104Syokota    prologue(adp, V_ADP_FONT, ENODEV);
196048104Syokota    if (page < 0 || page >= 8)
196148104Syokota	return EINVAL;
196248104Syokota
196348104Syokota    s = splhigh();
196448104Syokota    outb(TSIDX, 0x03); outb(TSREG, cg[page]);
196548104Syokota    splx(s);
196648104Syokota
196748104Syokota    return 0;
196848104Syokota#else /* VGA_NO_FONT_LOADING */
196948104Syokota    return ENODEV;
197048104Syokota#endif /* VGA_NO_FONT_LOADING */
197148104Syokota}
197248104Syokota
197348104Syokota/*
197448104Syokota * save_palette():
197548104Syokota * Read DAC values. The values have expressed in 8 bits.
197648104Syokota *
197748104Syokota * VGA
197848104Syokota */
197948104Syokotastatic int
198048104Syokotavga_save_palette(video_adapter_t *adp, u_char *palette)
198148104Syokota{
1982205604Sjkim    int bits;
198348104Syokota    int i;
198448104Syokota
198548104Syokota    prologue(adp, V_ADP_PALETTE, ENODEV);
198648104Syokota
198748104Syokota    /*
198848104Syokota     * We store 8 bit values in the palette buffer, while the standard
198948104Syokota     * VGA has 6 bit DAC .
199048104Syokota     */
199148104Syokota    outb(PALRADR, 0x00);
1992205604Sjkim    bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
199348104Syokota    for (i = 0; i < 256*3; ++i)
1994205604Sjkim	palette[i] = inb(PALDATA) << bits;
199548104Syokota    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
199648104Syokota    return 0;
199748104Syokota}
199848104Syokota
199948104Syokotastatic int
200048104Syokotavga_save_palette2(video_adapter_t *adp, int base, int count,
200148104Syokota		  u_char *r, u_char *g, u_char *b)
200248104Syokota{
2003205604Sjkim    int bits;
200448104Syokota    int i;
200548104Syokota
200648104Syokota    prologue(adp, V_ADP_PALETTE, ENODEV);
200748104Syokota
200848104Syokota    outb(PALRADR, base);
2009205604Sjkim    bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
201048104Syokota    for (i = 0; i < count; ++i) {
2011205604Sjkim	r[i] = inb(PALDATA) << bits;
2012205604Sjkim	g[i] = inb(PALDATA) << bits;
2013205604Sjkim	b[i] = inb(PALDATA) << bits;
201448104Syokota    }
201548104Syokota    inb(adp->va_crtc_addr + 6);		/* reset flip/flop */
201648104Syokota    return 0;
201748104Syokota}
201848104Syokota
201948104Syokota/*
202048104Syokota * load_palette():
202148104Syokota * Set DAC values.
202248104Syokota *
202348104Syokota * VGA
202448104Syokota */
202548104Syokotastatic int
202648104Syokotavga_load_palette(video_adapter_t *adp, u_char *palette)
202748104Syokota{
2028205604Sjkim    int bits;
202948104Syokota    int i;
203048104Syokota
203148104Syokota    prologue(adp, V_ADP_PALETTE, ENODEV);
203248104Syokota
203348104Syokota    outb(PIXMASK, 0xff);		/* no pixelmask */
203448104Syokota    outb(PALWADR, 0x00);
2035205604Sjkim    bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
203648104Syokota    for (i = 0; i < 256*3; ++i)
2037205604Sjkim	outb(PALDATA, palette[i] >> bits);
203848104Syokota    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
203948104Syokota    outb(ATC, 0x20);			/* enable palette */
204048104Syokota    return 0;
204148104Syokota}
204248104Syokota
204348104Syokotastatic int
204448104Syokotavga_load_palette2(video_adapter_t *adp, int base, int count,
204548104Syokota		  u_char *r, u_char *g, u_char *b)
204648104Syokota{
2047205604Sjkim    int bits;
204848104Syokota    int i;
204948104Syokota
205048104Syokota    prologue(adp, V_ADP_PALETTE, ENODEV);
205148104Syokota
205248104Syokota    outb(PIXMASK, 0xff);		/* no pixelmask */
205348104Syokota    outb(PALWADR, base);
2054205604Sjkim    bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
205548104Syokota    for (i = 0; i < count; ++i) {
2056205604Sjkim	outb(PALDATA, r[i] >> bits);
2057205604Sjkim	outb(PALDATA, g[i] >> bits);
2058205604Sjkim	outb(PALDATA, b[i] >> bits);
205948104Syokota    }
206048104Syokota    inb(adp->va_crtc_addr + 6);		/* reset flip/flop */
206148104Syokota    outb(ATC, 0x20);			/* enable palette */
206248104Syokota    return 0;
206348104Syokota}
206448104Syokota
206548104Syokota/*
206648104Syokota * set_border():
206748104Syokota * Change the border color.
206848104Syokota *
206948104Syokota * CGA/EGA/VGA
207048104Syokota */
207148104Syokotastatic int
207248104Syokotavga_set_border(video_adapter_t *adp, int color)
207348104Syokota{
207448104Syokota    prologue(adp, V_ADP_BORDER, ENODEV);
207548104Syokota
207648104Syokota    switch (adp->va_type) {
207748104Syokota    case KD_EGA:
207848104Syokota    case KD_VGA:
207948104Syokota	inb(adp->va_crtc_addr + 6);	/* reset flip-flop */
208048104Syokota	outb(ATC, 0x31); outb(ATC, color & 0xff);
208148104Syokota	break;
208248104Syokota    case KD_CGA:
208348104Syokota	outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */
208448104Syokota	break;
208548104Syokota    case KD_MONO:
208648104Syokota    case KD_HERCULES:
208748104Syokota    default:
208848104Syokota	break;
208948104Syokota    }
209048104Syokota    return 0;
209148104Syokota}
209248104Syokota
209348104Syokota/*
209448104Syokota * save_state():
209548104Syokota * Read video register values.
209648104Syokota * NOTE: this function only reads the standard EGA/VGA registers.
209748104Syokota * any extra/extended registers of SVGA adapters are not saved.
209848104Syokota *
209948104Syokota * VGA
210048104Syokota */
210148104Syokotastatic int
210248104Syokotavga_save_state(video_adapter_t *adp, void *p, size_t size)
210348104Syokota{
210448104Syokota    video_info_t info;
210548104Syokota    u_char *buf;
210648104Syokota    int crtc_addr;
210748104Syokota    int i, j;
210848104Syokota    int s;
210948104Syokota
211048104Syokota    if (size == 0) {
211148104Syokota	/* return the required buffer size */
211248104Syokota	prologue(adp, V_ADP_STATESAVE, 0);
211348104Syokota	return sizeof(adp_state_t);
211448104Syokota    } else {
211548104Syokota	prologue(adp, V_ADP_STATESAVE, ENODEV);
211648104Syokota	if (size < sizeof(adp_state_t))
211748104Syokota	    return EINVAL;
211848104Syokota    }
211948104Syokota
212048104Syokota    ((adp_state_t *)p)->sig = V_STATE_SIG;
212148104Syokota    buf = ((adp_state_t *)p)->regs;
212248104Syokota    bzero(buf, V_MODE_PARAM_SIZE);
212348104Syokota    crtc_addr = adp->va_crtc_addr;
212448104Syokota
212548104Syokota    s = splhigh();
212648104Syokota
212748104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
212848104Syokota    for (i = 0, j = 5; i < 4; i++) {
212948104Syokota	outb(TSIDX, i + 1);
213048104Syokota	buf[j++]  =  inb(TSREG);
213148104Syokota    }
213248104Syokota    buf[9]  =  inb(MISC + 10);			/* dot-clock */
213348104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
213448104Syokota
213548104Syokota    for (i = 0, j = 10; i < 25; i++) {		/* crtc */
213648104Syokota	outb(crtc_addr, i);
213748104Syokota	buf[j++]  =  inb(crtc_addr + 1);
213848104Syokota    }
213948104Syokota    for (i = 0, j = 35; i < 20; i++) {		/* attribute ctrl */
214048104Syokota        inb(crtc_addr + 6);			/* reset flip-flop */
214148104Syokota	outb(ATC, i);
214248104Syokota	buf[j++]  =  inb(ATC + 1);
214348104Syokota    }
214448104Syokota    for (i = 0, j = 55; i < 9; i++) {		/* graph data ctrl */
214548104Syokota	outb(GDCIDX, i);
214648104Syokota	buf[j++]  =  inb(GDCREG);
214748104Syokota    }
214848104Syokota    inb(crtc_addr + 6);				/* reset flip-flop */
214948104Syokota    outb(ATC, 0x20);				/* enable palette */
215048104Syokota
215148104Syokota    splx(s);
215248104Syokota
215348104Syokota#if 1
215448104Syokota    if (vga_get_info(adp, adp->va_mode, &info) == 0) {
215548104Syokota	if (info.vi_flags & V_INFO_GRAPHICS) {
215648104Syokota	    buf[0] = info.vi_width/info.vi_cwidth; /* COLS */
215748104Syokota	    buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */
215848104Syokota	} else {
215948104Syokota	    buf[0] = info.vi_width;		/* COLS */
216048104Syokota	    buf[1] = info.vi_height - 1;	/* ROWS */
216148104Syokota	}
216248104Syokota	buf[2] = info.vi_cheight;		/* POINTS */
216348104Syokota    } else {
216448104Syokota	/* XXX: shouldn't be happening... */
216548104Syokota	printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
216648104Syokota	       adp->va_unit, adp->va_name);
216748104Syokota    }
216848104Syokota#else
216948104Syokota    buf[0] = readb(BIOS_PADDRTOVADDR(0x44a));	/* COLS */
217048104Syokota    buf[1] = readb(BIOS_PADDRTOVADDR(0x484));	/* ROWS */
217148104Syokota    buf[2] = readb(BIOS_PADDRTOVADDR(0x485));	/* POINTS */
217248104Syokota    buf[3] = readb(BIOS_PADDRTOVADDR(0x44c));
217348104Syokota    buf[4] = readb(BIOS_PADDRTOVADDR(0x44d));
217448104Syokota#endif
217548104Syokota
217648104Syokota    return 0;
217748104Syokota}
217848104Syokota
217948104Syokota/*
218048104Syokota * load_state():
218148104Syokota * Set video registers at once.
218248104Syokota * NOTE: this function only updates the standard EGA/VGA registers.
218348104Syokota * any extra/extended registers of SVGA adapters are not changed.
218448104Syokota *
218548104Syokota * EGA/VGA
218648104Syokota */
218748104Syokotastatic int
218848104Syokotavga_load_state(video_adapter_t *adp, void *p)
218948104Syokota{
219048104Syokota    u_char *buf;
219148104Syokota    int crtc_addr;
219248104Syokota    int s;
219348104Syokota    int i;
219448104Syokota
219548104Syokota    prologue(adp, V_ADP_STATELOAD, ENODEV);
219648104Syokota    if (((adp_state_t *)p)->sig != V_STATE_SIG)
219748104Syokota	return EINVAL;
219848104Syokota
219948104Syokota    buf = ((adp_state_t *)p)->regs;
220048104Syokota    crtc_addr = adp->va_crtc_addr;
220148104Syokota
220248104Syokota#if VGA_DEBUG > 1
220348104Syokota    dump_buffer(buf, V_MODE_PARAM_SIZE);
220448104Syokota#endif
220548104Syokota
220648104Syokota    s = splhigh();
220748104Syokota
220848104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
220948104Syokota    for (i = 0; i < 4; ++i) {			/* program sequencer */
221048104Syokota	outb(TSIDX, i + 1);
221148104Syokota	outb(TSREG, buf[i + 5]);
221248104Syokota    }
221348104Syokota    outb(MISC, buf[9]);				/* set dot-clock */
221448104Syokota    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
221548104Syokota    outb(crtc_addr, 0x11);
221648104Syokota    outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F);
221748104Syokota    for (i = 0; i < 25; ++i) {			/* program crtc */
221848104Syokota	outb(crtc_addr, i);
221948104Syokota	outb(crtc_addr + 1, buf[i + 10]);
222048104Syokota    }
222148104Syokota    inb(crtc_addr+6);				/* reset flip-flop */
222248104Syokota    for (i = 0; i < 20; ++i) {			/* program attribute ctrl */
222348104Syokota	outb(ATC, i);
222448104Syokota	outb(ATC, buf[i + 35]);
222548104Syokota    }
222648104Syokota    for (i = 0; i < 9; ++i) {			/* program graph data ctrl */
222748104Syokota	outb(GDCIDX, i);
222848104Syokota	outb(GDCREG, buf[i + 55]);
222948104Syokota    }
223048104Syokota    inb(crtc_addr + 6);				/* reset flip-flop */
223148104Syokota    outb(ATC, 0x20);				/* enable palette */
223248104Syokota
2233153072Sru#ifdef notyet /* a temporary workaround for kernel panic, XXX */
223448104Syokota#ifndef VGA_NO_BIOS
223548104Syokota    if (adp->va_unit == V_ADP_PRIMARY) {
223648104Syokota	writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]);	/* COLS */
223748104Syokota	writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */
223848104Syokota	writeb(BIOS_PADDRTOVADDR(0x485), buf[2]);	/* POINTS */
223948104Syokota#if 0
224048104Syokota	writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]);
224148104Syokota	writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]);
224248104Syokota#endif
224348104Syokota    }
224448104Syokota#endif /* VGA_NO_BIOS */
224548104Syokota#endif /* notyet */
224648104Syokota
224748104Syokota    splx(s);
224848104Syokota    return 0;
224948104Syokota}
225048104Syokota
225148104Syokota/*
225248104Syokota * set_origin():
225348104Syokota * Change the origin (window mapping) of the banked frame buffer.
225448104Syokota */
225548104Syokotastatic int
225648104Syokotavga_set_origin(video_adapter_t *adp, off_t offset)
225748104Syokota{
225848104Syokota    /*
225948104Syokota     * The standard video modes do not require window mapping;
226048104Syokota     * always return error.
226148104Syokota     */
226248104Syokota    return ENODEV;
226348104Syokota}
226448104Syokota
226548104Syokota/*
226648104Syokota * read_hw_cursor():
226748104Syokota * Read the position of the hardware text cursor.
226848104Syokota *
226948104Syokota * all adapters
227048104Syokota */
227148104Syokotastatic int
227248104Syokotavga_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
227348104Syokota{
227448104Syokota    u_int16_t off;
227548104Syokota    int s;
227648104Syokota
227748104Syokota    if (!vga_init_done)
227848104Syokota	return ENXIO;
227948104Syokota
228048104Syokota    if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
228148104Syokota	return ENODEV;
228248104Syokota
228348104Syokota    s = spltty();
228448104Syokota    outb(adp->va_crtc_addr, 14);
228548104Syokota    off = inb(adp->va_crtc_addr + 1);
228648104Syokota    outb(adp->va_crtc_addr, 15);
228748104Syokota    off = (off << 8) | inb(adp->va_crtc_addr + 1);
228848104Syokota    splx(s);
228948104Syokota
229048104Syokota    *row = off / adp->va_info.vi_width;
229148104Syokota    *col = off % adp->va_info.vi_width;
229248104Syokota
229348104Syokota    return 0;
229448104Syokota}
229548104Syokota
229648104Syokota/*
229748104Syokota * set_hw_cursor():
229848104Syokota * Move the hardware text cursor.  If col and row are both -1,
229948104Syokota * the cursor won't be shown.
230048104Syokota *
230148104Syokota * all adapters
230248104Syokota */
230348104Syokotastatic int
230448104Syokotavga_set_hw_cursor(video_adapter_t *adp, int col, int row)
230548104Syokota{
230648104Syokota    u_int16_t off;
230748104Syokota    int s;
230848104Syokota
230948104Syokota    if (!vga_init_done)
231048104Syokota	return ENXIO;
231148104Syokota
231248104Syokota    if ((col == -1) && (row == -1)) {
231348104Syokota	off = -1;
231448104Syokota    } else {
231548104Syokota	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
231648104Syokota	    return ENODEV;
231748104Syokota	off = row*adp->va_info.vi_width + col;
231848104Syokota    }
231948104Syokota
232048104Syokota    s = spltty();
232148104Syokota    outb(adp->va_crtc_addr, 14);
232248104Syokota    outb(adp->va_crtc_addr + 1, off >> 8);
232348104Syokota    outb(adp->va_crtc_addr, 15);
232448104Syokota    outb(adp->va_crtc_addr + 1, off & 0x00ff);
232548104Syokota    splx(s);
232648104Syokota
232748104Syokota    return 0;
232848104Syokota}
232948104Syokota
233048104Syokota/*
233148104Syokota * set_hw_cursor_shape():
233248104Syokota * Change the shape of the hardware text cursor. If the height is
233348104Syokota * zero or negative, the cursor won't be shown.
233448104Syokota *
233548104Syokota * all adapters
233648104Syokota */
233748104Syokotastatic int
233848104Syokotavga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
233948104Syokota			int celsize, int blink)
234048104Syokota{
234148104Syokota    int s;
234248104Syokota
234348104Syokota    if (!vga_init_done)
234448104Syokota	return ENXIO;
234548104Syokota
234648104Syokota    s = spltty();
234748104Syokota    switch (adp->va_type) {
234848104Syokota    case KD_VGA:
234948104Syokota    case KD_CGA:
235048104Syokota    case KD_MONO:
235148104Syokota    case KD_HERCULES:
235248104Syokota    default:
235348104Syokota	if (height <= 0) {
235448104Syokota	    /* make the cursor invisible */
235548104Syokota	    outb(adp->va_crtc_addr, 10);
235648104Syokota	    outb(adp->va_crtc_addr + 1, 32);
235748104Syokota	    outb(adp->va_crtc_addr, 11);
235848104Syokota	    outb(adp->va_crtc_addr + 1, 0);
235948104Syokota	} else {
236048104Syokota	    outb(adp->va_crtc_addr, 10);
236148104Syokota	    outb(adp->va_crtc_addr + 1, celsize - base - height);
236248104Syokota	    outb(adp->va_crtc_addr, 11);
236348104Syokota	    outb(adp->va_crtc_addr + 1, celsize - base - 1);
236448104Syokota	}
236548104Syokota	break;
236648104Syokota    case KD_EGA:
236748104Syokota	if (height <= 0) {
236848104Syokota	    /* make the cursor invisible */
236948104Syokota	    outb(adp->va_crtc_addr, 10);
237048104Syokota	    outb(adp->va_crtc_addr + 1, celsize);
237148104Syokota	    outb(adp->va_crtc_addr, 11);
237248104Syokota	    outb(adp->va_crtc_addr + 1, 0);
237348104Syokota	} else {
237448104Syokota	    outb(adp->va_crtc_addr, 10);
237548104Syokota	    outb(adp->va_crtc_addr + 1, celsize - base - height);
237648104Syokota	    outb(adp->va_crtc_addr, 11);
237748104Syokota	    outb(adp->va_crtc_addr + 1, celsize - base);
237848104Syokota	}
237948104Syokota	break;
238048104Syokota    }
238148104Syokota    splx(s);
238248104Syokota
238348104Syokota    return 0;
238448104Syokota}
238548104Syokota
238648104Syokota/*
238748104Syokota * blank_display()
238848104Syokota * Put the display in power save/power off mode.
238948104Syokota *
239048104Syokota * all adapters
239148104Syokota */
239248104Syokotastatic int
239348104Syokotavga_blank_display(video_adapter_t *adp, int mode)
239448104Syokota{
239548104Syokota    u_char val;
239648104Syokota    int s;
239748104Syokota
239848104Syokota    s = splhigh();
239948104Syokota    switch (adp->va_type) {
240048104Syokota    case KD_VGA:
240148104Syokota	switch (mode) {
240248104Syokota	case V_DISPLAY_SUSPEND:
240348104Syokota	case V_DISPLAY_STAND_BY:
240448104Syokota	    outb(TSIDX, 0x01);
240548104Syokota	    val = inb(TSREG);
240648104Syokota	    outb(TSIDX, 0x01);
240748104Syokota	    outb(TSREG, val | 0x20);
240848104Syokota	    outb(adp->va_crtc_addr, 0x17);
240948104Syokota	    val = inb(adp->va_crtc_addr + 1);
241048104Syokota	    outb(adp->va_crtc_addr + 1, val & ~0x80);
241148104Syokota	    break;
241248104Syokota	case V_DISPLAY_BLANK:
241348104Syokota	    outb(TSIDX, 0x01);
241448104Syokota	    val = inb(TSREG);
241548104Syokota	    outb(TSIDX, 0x01);
241648104Syokota	    outb(TSREG, val | 0x20);
241748104Syokota	    break;
241848104Syokota	case V_DISPLAY_ON:
241948104Syokota	    outb(TSIDX, 0x01);
242048104Syokota	    val = inb(TSREG);
242148104Syokota	    outb(TSIDX, 0x01);
242248104Syokota	    outb(TSREG, val & 0xDF);
242348104Syokota	    outb(adp->va_crtc_addr, 0x17);
242448104Syokota	    val = inb(adp->va_crtc_addr + 1);
242548104Syokota	    outb(adp->va_crtc_addr + 1, val | 0x80);
242648104Syokota	    break;
242748104Syokota	}
242848104Syokota	break;
242948104Syokota
243048104Syokota    case KD_EGA:
243148104Syokota	/* no support yet */
243281455Syokota	splx(s);
243348104Syokota	return ENODEV;
243448104Syokota
243548104Syokota    case KD_CGA:
243648104Syokota	switch (mode) {
243748104Syokota	case V_DISPLAY_SUSPEND:
243848104Syokota	case V_DISPLAY_STAND_BY:
243948104Syokota	case V_DISPLAY_BLANK:
244048104Syokota	    outb(adp->va_crtc_addr + 4, 0x25);
244148104Syokota	    break;
244248104Syokota	case V_DISPLAY_ON:
244348104Syokota	    outb(adp->va_crtc_addr + 4, 0x2d);
244448104Syokota	    break;
244548104Syokota	}
244648104Syokota	break;
244748104Syokota
244848104Syokota    case KD_MONO:
244948104Syokota    case KD_HERCULES:
245048104Syokota	switch (mode) {
245148104Syokota	case V_DISPLAY_SUSPEND:
245248104Syokota	case V_DISPLAY_STAND_BY:
245348104Syokota	case V_DISPLAY_BLANK:
245448104Syokota	    outb(adp->va_crtc_addr + 4, 0x21);
245548104Syokota	    break;
245648104Syokota	case V_DISPLAY_ON:
245748104Syokota	    outb(adp->va_crtc_addr + 4, 0x29);
245848104Syokota	    break;
245948104Syokota	}
246048104Syokota	break;
246148104Syokota    default:
246248104Syokota	break;
246348104Syokota    }
246448104Syokota    splx(s);
246548104Syokota
246648104Syokota    return 0;
246748104Syokota}
246848104Syokota
246948104Syokota/*
247048104Syokota * mmap():
247148104Syokota * Mmap frame buffer.
247248104Syokota *
247348104Syokota * all adapters
247448104Syokota */
247548104Syokotastatic int
2476201223Srnolandvga_mmap_buf(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
2477201223Srnoland   	     int prot, vm_memattr_t *memattr)
247848104Syokota{
247948104Syokota    if (adp->va_info.vi_flags & V_INFO_LINEAR)
248048104Syokota	return -1;
248148104Syokota
248248104Syokota#if VGA_DEBUG > 0
2483106662Sjhb    printf("vga_mmap_buf(): window:0x%jx, offset:0x%jx\n",
2484106662Sjhb	   (uintmax_t)adp->va_info.vi_window, (uintmax_t)offset);
248548104Syokota#endif
248648104Syokota
248748104Syokota    /* XXX: is this correct? */
248848104Syokota    if (offset > adp->va_window_size - PAGE_SIZE)
248948104Syokota	return -1;
249048104Syokota
2491111462Smux    *paddr = adp->va_info.vi_window + offset;
2492111462Smux    return 0;
249348104Syokota}
249448104Syokota
249548104Syokota#ifndef VGA_NO_MODE_CHANGE
249648104Syokota
249748104Syokotastatic void
249848104Syokotaplanar_fill(video_adapter_t *adp, int val)
249948104Syokota{
250048104Syokota    int length;
250148104Syokota    int at;			/* position in the frame buffer */
250248104Syokota    int l;
250348104Syokota
250448104Syokota    outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
250548104Syokota    outw(GDCIDX, 0x0003);		/* data rotate/function select */
250648104Syokota    outw(GDCIDX, 0x0f01);		/* set/reset enable */
250748104Syokota    outw(GDCIDX, 0xff08);		/* bit mask */
250848104Syokota    outw(GDCIDX, (val << 8) | 0x00);	/* set/reset */
250948104Syokota    at = 0;
251048104Syokota    length = adp->va_line_width*adp->va_info.vi_height;
251148104Syokota    while (length > 0) {
251248104Syokota	l = imin(length, adp->va_window_size);
2513174985Swkoszek	vidd_set_win_org(adp, at);
251448104Syokota	bzero_io(adp->va_window, l);
251548104Syokota	length -= l;
251648104Syokota	at += l;
251748104Syokota    }
251848104Syokota    outw(GDCIDX, 0x0000);		/* set/reset */
251948104Syokota    outw(GDCIDX, 0x0001);		/* set/reset enable */
252048104Syokota}
252148104Syokota
252248104Syokotastatic void
252348104Syokotapacked_fill(video_adapter_t *adp, int val)
252448104Syokota{
252548104Syokota    int length;
252648104Syokota    int at;			/* position in the frame buffer */
252748104Syokota    int l;
252848104Syokota
252948104Syokota    at = 0;
253048104Syokota    length = adp->va_line_width*adp->va_info.vi_height;
253148104Syokota    while (length > 0) {
253248104Syokota	l = imin(length, adp->va_window_size);
2533174985Swkoszek	vidd_set_win_org(adp, at);
253448104Syokota	fill_io(val, adp->va_window, l);
253548104Syokota	length -= l;
253648104Syokota	at += l;
253748104Syokota    }
253848104Syokota}
253948104Syokota
254048104Syokotastatic void
254148104Syokotadirect_fill(video_adapter_t *adp, int val)
254248104Syokota{
254348104Syokota    int length;
254448104Syokota    int at;			/* position in the frame buffer */
254548104Syokota    int l;
254648104Syokota
254748104Syokota    at = 0;
254848104Syokota    length = adp->va_line_width*adp->va_info.vi_height;
254948104Syokota    while (length > 0) {
255048104Syokota	l = imin(length, adp->va_window_size);
2551174985Swkoszek	vidd_set_win_org(adp, at);
255248104Syokota	switch (adp->va_info.vi_pixel_size) {
255348104Syokota	case sizeof(u_int16_t):
255448104Syokota	    fillw_io(val, adp->va_window, l/sizeof(u_int16_t));
255548104Syokota	    break;
255648104Syokota	case 3:
255748104Syokota	    /* FIXME */
255848104Syokota	    break;
255948104Syokota	case sizeof(u_int32_t):
256048104Syokota	    filll_io(val, adp->va_window, l/sizeof(u_int32_t));
256148104Syokota	    break;
256248104Syokota	}
256348104Syokota	length -= l;
256448104Syokota	at += l;
256548104Syokota    }
256648104Syokota}
256748104Syokota
256848104Syokotastatic int
256948104Syokotavga_clear(video_adapter_t *adp)
257048104Syokota{
257148104Syokota    switch (adp->va_info.vi_mem_model) {
257248104Syokota    case V_INFO_MM_TEXT:
257348104Syokota	/* do nothing? XXX */
257448104Syokota	break;
257548104Syokota    case V_INFO_MM_PLANAR:
257648104Syokota	planar_fill(adp, 0);
257748104Syokota	break;
257848104Syokota    case V_INFO_MM_PACKED:
257948104Syokota	packed_fill(adp, 0);
258048104Syokota	break;
258148104Syokota    case V_INFO_MM_DIRECT:
258248104Syokota	direct_fill(adp, 0);
258348104Syokota	break;
258448104Syokota    }
258548104Syokota    return 0;
258648104Syokota}
258748104Syokota
258848104Syokota#ifdef notyet
258948104Syokotastatic void
259048104Syokotaplanar_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
259148104Syokota{
259248104Syokota    int banksize;
259348104Syokota    int bank;
259448104Syokota    int pos;
259548104Syokota    int offset;			/* offset within window */
259648104Syokota    int bx;
259748104Syokota    int l;
259848104Syokota
259948104Syokota    outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
260048104Syokota    outw(GDCIDX, 0x0003);		/* data rotate/function select */
260148104Syokota    outw(GDCIDX, 0x0f01);		/* set/reset enable */
260248104Syokota    outw(GDCIDX, 0xff08);		/* bit mask */
260348104Syokota    outw(GDCIDX, (val << 8) | 0x00); /* set/reset */
260448104Syokota
260548104Syokota    banksize = adp->va_window_size;
260648104Syokota    bank = -1;
260748104Syokota    while (cy > 0) {
260848104Syokota	pos = adp->va_line_width*y + x/8;
260948104Syokota	if (bank != pos/banksize) {
2610174985Swkoszek	    vidd_set_win_org(adp, pos);
261148104Syokota	    bank = pos/banksize;
261248104Syokota	}
261348104Syokota	offset = pos%banksize;
261448104Syokota	bx = (x + cx)/8 - x/8;
261548104Syokota	if (x % 8) {
261648104Syokota	    outw(GDCIDX, ((0xff00 >> (x % 8)) & 0xff00) | 0x08);
261748104Syokota	    writeb(adp->va_window + offset, 0);
261848104Syokota	    ++offset;
261948104Syokota	    --bx;
262048104Syokota	    if (offset >= banksize) {
262148104Syokota		offset = 0;
262248104Syokota		++bank;		/* next bank */
2623174985Swkoszek		vidd_set_win_org(adp, bank*banksize);
262448104Syokota	    }
262548104Syokota	    outw(GDCIDX, 0xff08);	/* bit mask */
262648104Syokota	}
262748104Syokota	while (bx > 0) {
262848104Syokota	    l = imin(bx, banksize);
262948104Syokota	    bzero_io(adp->va_window + offset, l);
263048104Syokota	    offset += l;
263148104Syokota	    bx -= l;
263248104Syokota	    if (offset >= banksize) {
263348104Syokota		offset = 0;
263448104Syokota		++bank;		/* next bank */
2635174985Swkoszek		vidd_set_win_org(adp, bank*banksize);
263648104Syokota	    }
263748104Syokota	}
263848104Syokota	if ((x + cx) % 8) {
263948104Syokota	    outw(GDCIDX, (~(0xff00 >> ((x + cx) % 8)) & 0xff00) | 0x08);
264048104Syokota	    writeb(adp->va_window + offset, 0);
264148104Syokota	    ++offset;
264248104Syokota	    if (offset >= banksize) {
264348104Syokota		offset = 0;
264448104Syokota		++bank;		/* next bank */
2645174985Swkoszek		vidd_set_win_org(adp, bank*banksize);
264648104Syokota	    }
264748104Syokota	    outw(GDCIDX, 0xff08);	/* bit mask */
264848104Syokota	}
264948104Syokota	++y;
265048104Syokota	--cy;
265148104Syokota    }
265248104Syokota
265348104Syokota    outw(GDCIDX, 0xff08);		/* bit mask */
265448104Syokota    outw(GDCIDX, 0x0000);		/* set/reset */
265548104Syokota    outw(GDCIDX, 0x0001);		/* set/reset enable */
265648104Syokota}
265748104Syokota
265848104Syokotastatic void
265948104Syokotapacked_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
266048104Syokota{
266148104Syokota    int banksize;
266248104Syokota    int bank;
266348104Syokota    int pos;
266448104Syokota    int offset;			/* offset within window */
266548104Syokota    int end;
266648104Syokota
266748104Syokota    banksize = adp->va_window_size;
266848104Syokota    bank = -1;
266948104Syokota    cx *= adp->va_info.vi_pixel_size;
267048104Syokota    while (cy > 0) {
267148104Syokota	pos = adp->va_line_width*y + x*adp->va_info.vi_pixel_size;
267248104Syokota	if (bank != pos/banksize) {
2673174985Swkoszek	    vidd_set_win_org(adp, pos);
267448104Syokota	    bank = pos/banksize;
267548104Syokota	}
267648104Syokota	offset = pos%banksize;
267748104Syokota	end = imin(offset + cx, banksize);
267848104Syokota	fill_io(val, adp->va_window + offset,
267948104Syokota		(end - offset)/adp->va_info.vi_pixel_size);
268048104Syokota	/* the line may cross the window boundary */
268148104Syokota	if (offset + cx > banksize) {
268248104Syokota	    ++bank;		/* next bank */
2683174985Swkoszek	    vidd_set_win_org(adp, bank*banksize);
268448104Syokota	    end = offset + cx - banksize;
268548104Syokota	    fill_io(val, adp->va_window, end/adp->va_info.vi_pixel_size);
268648104Syokota	}
268748104Syokota	++y;
268848104Syokota	--cy;
268948104Syokota    }
269048104Syokota}
269148104Syokota
269248104Syokotastatic void
269348104Syokotadirect_fill_rect16(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
269448104Syokota{
269548104Syokota    int banksize;
269648104Syokota    int bank;
269748104Syokota    int pos;
269848104Syokota    int offset;			/* offset within window */
269948104Syokota    int end;
270048104Syokota
270148104Syokota    /*
270248104Syokota     * XXX: the function assumes that banksize is a muliple of
270348104Syokota     * sizeof(u_int16_t).
270448104Syokota     */
270548104Syokota    banksize = adp->va_window_size;
270648104Syokota    bank = -1;
270748104Syokota    cx *= sizeof(u_int16_t);
270848104Syokota    while (cy > 0) {
270948104Syokota	pos = adp->va_line_width*y + x*sizeof(u_int16_t);
271048104Syokota	if (bank != pos/banksize) {
2711174985Swkoszek	    vidd_set_win_org(adp, pos);
271248104Syokota	    bank = pos/banksize;
271348104Syokota	}
271448104Syokota	offset = pos%banksize;
271548104Syokota	end = imin(offset + cx, banksize);
271648104Syokota	fillw_io(val, adp->va_window + offset,
271748104Syokota		 (end - offset)/sizeof(u_int16_t));
271848104Syokota	/* the line may cross the window boundary */
271948104Syokota	if (offset + cx > banksize) {
272048104Syokota	    ++bank;		/* next bank */
2721174985Swkoszek	    vidd_set_win_org(adp, bank*banksize);
272248104Syokota	    end = offset + cx - banksize;
272348104Syokota	    fillw_io(val, adp->va_window, end/sizeof(u_int16_t));
272448104Syokota	}
272548104Syokota	++y;
272648104Syokota	--cy;
272748104Syokota    }
272848104Syokota}
272948104Syokota
273048104Syokotastatic void
273148104Syokotadirect_fill_rect24(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
273248104Syokota{
273348104Syokota    int banksize;
273448104Syokota    int bank;
273548104Syokota    int pos;
273648104Syokota    int offset;			/* offset within window */
273748104Syokota    int end;
273848104Syokota    int i;
273948104Syokota    int j;
274048104Syokota    u_int8_t b[3];
274148104Syokota
274248104Syokota    b[0] = val & 0x0000ff;
274348104Syokota    b[1] = (val >> 8) & 0x0000ff;
274448104Syokota    b[2] = (val >> 16) & 0x0000ff;
274548104Syokota    banksize = adp->va_window_size;
274648104Syokota    bank = -1;
274748104Syokota    cx *= 3;
274848104Syokota    while (cy > 0) {
274948104Syokota	pos = adp->va_line_width*y + x*3;
275048104Syokota	if (bank != pos/banksize) {
2751174985Swkoszek	    vidd_set_win_org(adp, pos);
275248104Syokota	    bank = pos/banksize;
275348104Syokota	}
275448104Syokota	offset = pos%banksize;
275548104Syokota	end = imin(offset + cx, banksize);
275648104Syokota	for (i = 0, j = offset; j < end; i = (++i)%3, ++j) {
275748104Syokota	    writeb(adp->va_window + j, b[i]);
275848104Syokota	}
275948104Syokota	/* the line may cross the window boundary */
276048104Syokota	if (offset + cx >= banksize) {
276148104Syokota	    ++bank;		/* next bank */
2762174985Swkoszek	    vidd_set_win_org(adp, bank*banksize);
276348104Syokota	    j = 0;
276448104Syokota	    end = offset + cx - banksize;
276548104Syokota	    for (; j < end; i = (++i)%3, ++j) {
276648104Syokota		writeb(adp->va_window + j, b[i]);
276748104Syokota	    }
276848104Syokota	}
276948104Syokota	++y;
277048104Syokota	--cy;
277148104Syokota    }
277248104Syokota}
277348104Syokota
277448104Syokotastatic void
277548104Syokotadirect_fill_rect32(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
277648104Syokota{
277748104Syokota    int banksize;
277848104Syokota    int bank;
277948104Syokota    int pos;
278048104Syokota    int offset;			/* offset within window */
278148104Syokota    int end;
278248104Syokota
278348104Syokota    /*
278448104Syokota     * XXX: the function assumes that banksize is a muliple of
278548104Syokota     * sizeof(u_int32_t).
278648104Syokota     */
278748104Syokota    banksize = adp->va_window_size;
278848104Syokota    bank = -1;
278948104Syokota    cx *= sizeof(u_int32_t);
279048104Syokota    while (cy > 0) {
279148104Syokota	pos = adp->va_line_width*y + x*sizeof(u_int32_t);
279248104Syokota	if (bank != pos/banksize) {
2793174985Swkoszek	    vidd_set_win_org(adp, pos);
279448104Syokota	    bank = pos/banksize;
279548104Syokota	}
279648104Syokota	offset = pos%banksize;
279748104Syokota	end = imin(offset + cx, banksize);
279848104Syokota	filll_io(val, adp->va_window + offset,
279948104Syokota		 (end - offset)/sizeof(u_int32_t));
280048104Syokota	/* the line may cross the window boundary */
280148104Syokota	if (offset + cx > banksize) {
280248104Syokota	    ++bank;		/* next bank */
2803174985Swkoszek	    vidd_set_win_org(adp, bank*banksize);
280448104Syokota	    end = offset + cx - banksize;
280548104Syokota	    filll_io(val, adp->va_window, end/sizeof(u_int32_t));
280648104Syokota	}
280748104Syokota	++y;
280848104Syokota	--cy;
280948104Syokota    }
281048104Syokota}
281148104Syokota
281248104Syokotastatic int
281348104Syokotavga_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
281448104Syokota{
281548104Syokota    switch (adp->va_info.vi_mem_model) {
281648104Syokota    case V_INFO_MM_TEXT:
281748104Syokota	/* do nothing? XXX */
281848104Syokota	break;
281948104Syokota    case V_INFO_MM_PLANAR:
282048104Syokota	planar_fill_rect(adp, val, x, y, cx, cy);
282148104Syokota	break;
282248104Syokota    case V_INFO_MM_PACKED:
282348104Syokota	packed_fill_rect(adp, val, x, y, cx, cy);
282448104Syokota	break;
282548104Syokota    case V_INFO_MM_DIRECT:
282648104Syokota	switch (adp->va_info.vi_pixel_size) {
282748104Syokota	case sizeof(u_int16_t):
282848104Syokota	    direct_fill_rect16(adp, val, x, y, cx, cy);
282948104Syokota	    break;
283048104Syokota	case 3:
283148104Syokota	    direct_fill_rect24(adp, val, x, y, cx, cy);
283248104Syokota	    break;
283348104Syokota	case sizeof(u_int32_t):
283448104Syokota	    direct_fill_rect32(adp, val, x, y, cx, cy);
283548104Syokota	    break;
283648104Syokota	}
283748104Syokota	break;
283848104Syokota    }
283948104Syokota    return 0;
284048104Syokota}
284148104Syokota#else /* !notyet */
284248104Syokotastatic int
284348104Syokotavga_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
284448104Syokota{
284548104Syokota    return ENODEV;
284648104Syokota}
284748104Syokota#endif /* notyet */
284848104Syokota
284948104Syokotastatic int
285048104Syokotavga_bitblt(video_adapter_t *adp,...)
285148104Syokota{
285248104Syokota    /* FIXME */
285348104Syokota    return ENODEV;
285448104Syokota}
285548104Syokota
285648104Syokota#endif /* !VGA_NO_MODE_CHANGE */
285748104Syokota
285848104Syokotastatic int
285948104Syokotaget_palette(video_adapter_t *adp, int base, int count,
286048104Syokota	    u_char *red, u_char *green, u_char *blue, u_char *trans)
286148104Syokota{
286248104Syokota    u_char *r;
286348104Syokota    u_char *g;
286448104Syokota    u_char *b;
286548104Syokota
2866127792Snectar    if (count < 0 || base < 0 || count > 256 || base > 256 ||
2867127792Snectar	base + count > 256)
286848104Syokota	return EINVAL;
286948104Syokota
2870111119Simp    r = malloc(count*3, M_DEVBUF, M_WAITOK);
287148104Syokota    g = r + count;
287248104Syokota    b = g + count;
2873104389Sphk    if (vga_save_palette2(adp, base, count, r, g, b)) {
2874104389Sphk	free(r, M_DEVBUF);
287548104Syokota	return ENODEV;
2876104389Sphk    }
287748104Syokota    copyout(r, red, count);
287848104Syokota    copyout(g, green, count);
287948104Syokota    copyout(b, blue, count);
288048104Syokota    if (trans != NULL) {
288148104Syokota	bzero(r, count);
288248104Syokota	copyout(r, trans, count);
288348104Syokota    }
288448104Syokota    free(r, M_DEVBUF);
288548104Syokota
288648104Syokota    return 0;
288748104Syokota}
288848104Syokota
288948104Syokotastatic int
289048104Syokotaset_palette(video_adapter_t *adp, int base, int count,
289148104Syokota	    u_char *red, u_char *green, u_char *blue, u_char *trans)
289248104Syokota{
289348104Syokota    u_char *r;
289448104Syokota    u_char *g;
289548104Syokota    u_char *b;
289648104Syokota    int err;
289748104Syokota
2898127792Snectar    if (count < 0 || base < 0 || count > 256 || base > 256 ||
2899127792Snectar	base + count > 256)
290048104Syokota	return EINVAL;
290148104Syokota
2902111119Simp    r = malloc(count*3, M_DEVBUF, M_WAITOK);
290348104Syokota    g = r + count;
290448104Syokota    b = g + count;
2905144146Ssam    err = copyin(red, r, count);
2906144146Ssam    if (!err)
2907144146Ssam        err = copyin(green, g, count);
2908144146Ssam    if (!err)
2909144146Ssam        err = copyin(blue, b, count);
2910144146Ssam    if (!err)
2911144146Ssam        err = vga_load_palette2(adp, base, count, r, g, b);
291248104Syokota    free(r, M_DEVBUF);
291348104Syokota
291448104Syokota    return (err ? ENODEV : 0);
291548104Syokota}
291648104Syokota
291748104Syokotastatic int
291848104Syokotavga_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
291948104Syokota{
292048104Syokota    switch (cmd) {
292148104Syokota    case FBIO_GETWINORG:	/* get frame buffer window origin */
292248104Syokota	*(u_int *)arg = 0;
292348104Syokota	return 0;
292448104Syokota
292548104Syokota    case FBIO_SETWINORG:	/* set frame buffer window origin */
292648104Syokota	return ENODEV;
292748104Syokota
292848104Syokota    case FBIO_SETDISPSTART:	/* set display start address */
292948104Syokota	return (set_display_start(adp,
293048104Syokota				  ((video_display_start_t *)arg)->x,
293148104Syokota			  	  ((video_display_start_t *)arg)->y)
293248104Syokota		? ENODEV : 0);
293348104Syokota
293448104Syokota    case FBIO_SETLINEWIDTH:	/* set scan line length in pixel */
293548104Syokota	return (set_line_length(adp, *(u_int *)arg) ? ENODEV : 0);
293648104Syokota
293748104Syokota    case FBIO_GETPALETTE:	/* get color palette */
293848104Syokota	return get_palette(adp, ((video_color_palette_t *)arg)->index,
293948104Syokota			   ((video_color_palette_t *)arg)->count,
294048104Syokota			   ((video_color_palette_t *)arg)->red,
294148104Syokota			   ((video_color_palette_t *)arg)->green,
294248104Syokota			   ((video_color_palette_t *)arg)->blue,
294348104Syokota			   ((video_color_palette_t *)arg)->transparent);
294448104Syokota
294548104Syokota    case FBIO_SETPALETTE:	/* set color palette */
294648104Syokota	return set_palette(adp, ((video_color_palette_t *)arg)->index,
294748104Syokota			   ((video_color_palette_t *)arg)->count,
294848104Syokota			   ((video_color_palette_t *)arg)->red,
294948104Syokota			   ((video_color_palette_t *)arg)->green,
295048104Syokota			   ((video_color_palette_t *)arg)->blue,
295148104Syokota			   ((video_color_palette_t *)arg)->transparent);
295248104Syokota
295348104Syokota    case FBIOGTYPE:		/* get frame buffer type info. */
295448104Syokota	((struct fbtype *)arg)->fb_type = fb_type(adp->va_type);
295548104Syokota	((struct fbtype *)arg)->fb_height = adp->va_info.vi_height;
295648104Syokota	((struct fbtype *)arg)->fb_width = adp->va_info.vi_width;
295748104Syokota	((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth;
295848104Syokota	if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8))
295948104Syokota	    ((struct fbtype *)arg)->fb_cmsize = 0;
296048104Syokota	else
296148104Syokota	    ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth;
296248104Syokota	((struct fbtype *)arg)->fb_size = adp->va_buffer_size;
296348104Syokota	return 0;
296448104Syokota
296548104Syokota    case FBIOGETCMAP:		/* get color palette */
296648104Syokota	return get_palette(adp, ((struct fbcmap *)arg)->index,
296748104Syokota			   ((struct fbcmap *)arg)->count,
296848104Syokota			   ((struct fbcmap *)arg)->red,
296948104Syokota			   ((struct fbcmap *)arg)->green,
297048104Syokota			   ((struct fbcmap *)arg)->blue, NULL);
297148104Syokota
297248104Syokota    case FBIOPUTCMAP:		/* set color palette */
297348104Syokota	return set_palette(adp, ((struct fbcmap *)arg)->index,
297448104Syokota			   ((struct fbcmap *)arg)->count,
297548104Syokota			   ((struct fbcmap *)arg)->red,
297648104Syokota			   ((struct fbcmap *)arg)->green,
297748104Syokota			   ((struct fbcmap *)arg)->blue, NULL);
297848104Syokota
297948104Syokota    default:
298048104Syokota	return fb_commonioctl(adp, cmd, arg);
298148104Syokota    }
298248104Syokota}
298348104Syokota
298448104Syokotastatic void
298548104Syokotadump_buffer(u_char *buf, size_t len)
298648104Syokota{
298748104Syokota    int i;
298848104Syokota
298948104Syokota    for(i = 0; i < len;) {
299048104Syokota	printf("%02x ", buf[i]);
299148104Syokota	if ((++i % 16) == 0)
299248104Syokota	    printf("\n");
299348104Syokota    }
299448104Syokota}
299548104Syokota
299648104Syokota/*
299748104Syokota * diag():
299848104Syokota * Print some information about the video adapter and video modes,
299948104Syokota * with requested level of details.
300048104Syokota *
300148104Syokota * all adapters
300248104Syokota */
300348104Syokotastatic int
300448104Syokotavga_diag(video_adapter_t *adp, int level)
300548104Syokota{
300648104Syokota    u_char *mp;
300748104Syokota#if FB_DEBUG > 1
300848104Syokota    video_info_t info;
300948104Syokota    int i;
301048104Syokota#endif
301148104Syokota
301248104Syokota    if (!vga_init_done)
301348104Syokota	return ENXIO;
301448104Syokota
301548104Syokota#if FB_DEBUG > 1
301648104Syokota#ifndef VGA_NO_BIOS
301748104Syokota    printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n",
301848104Syokota	   rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488)));
301948104Syokota    printf("vga: CRTC:0x%x, video option:0x%02x, ",
302048104Syokota	   readw(BIOS_PADDRTOVADDR(0x463)),
302148104Syokota	   readb(BIOS_PADDRTOVADDR(0x487)));
302248104Syokota    printf("rows:%d, cols:%d, font height:%d\n",
302348104Syokota	   readb(BIOS_PADDRTOVADDR(0x44a)),
302448104Syokota	   readb(BIOS_PADDRTOVADDR(0x484)) + 1,
302548104Syokota	   readb(BIOS_PADDRTOVADDR(0x485)));
302648104Syokota#endif /* VGA_NO_BIOS */
302748104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
302848104Syokota    printf("vga: param table EGA/VGA:%p", video_mode_ptr);
302948104Syokota    printf(", CGA/MDA:%p\n", video_mode_ptr2);
303048104Syokota    printf("vga: rows_offset:%d\n", rows_offset);
303148104Syokota#endif
303248104Syokota#endif /* FB_DEBUG > 1 */
303348104Syokota
303448104Syokota    fb_dump_adp_info(VGA_DRIVER_NAME, adp, level);
303548104Syokota
303648104Syokota#if FB_DEBUG > 1
303748104Syokota    if (adp->va_flags & V_ADP_MODECHANGE) {
303848104Syokota	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
303948104Syokota	    if (bios_vmode[i].vi_mode == NA)
304048104Syokota		continue;
304148104Syokota	    if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
304248104Syokota		continue;
304348104Syokota	    fb_dump_mode_info(VGA_DRIVER_NAME, adp, &bios_vmode[i], level);
304448104Syokota	}
304548104Syokota    } else {
304648104Syokota	vga_get_info(adp, adp->va_initial_mode, &info);	/* shouldn't fail */
304748104Syokota	fb_dump_mode_info(VGA_DRIVER_NAME, adp, &info, level);
304848104Syokota    }
304948104Syokota#endif /* FB_DEBUG > 1 */
305048104Syokota
305148104Syokota    if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA))
305248104Syokota	return 0;
305348104Syokota#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
305448104Syokota    if (video_mode_ptr == NULL)
305548104Syokota	printf("vga%d: %s: WARNING: video mode switching is not "
305648104Syokota	       "fully supported on this adapter\n",
305748104Syokota	       adp->va_unit, adp->va_name);
305848104Syokota#endif
305948104Syokota    if (level <= 0)
306048104Syokota	return 0;
306148104Syokota
306248104Syokota    if (adp->va_type == KD_VGA) {
306348104Syokota	printf("VGA parameters upon power-up\n");
306448104Syokota	dump_buffer(adpstate.regs, sizeof(adpstate.regs));
306548104Syokota	printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode);
306648104Syokota	dump_buffer(adpstate2.regs, sizeof(adpstate2.regs));
306748104Syokota    }
306848104Syokota
306948104Syokota    mp = get_mode_param(adp->va_initial_mode);
307048104Syokota    if (mp == NULL)	/* this shouldn't be happening */
307148104Syokota	return 0;
307248104Syokota    printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode);
307348104Syokota    dump_buffer(mp, V_MODE_PARAM_SIZE);
307448104Syokota
307548104Syokota    return 0;
307648104Syokota}
3077