vga_isa.c revision 47618
1/*-
2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3 * Copyright (c) 1992-1998 S�ren Schmidt
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer as
11 *    the first lines of this file unmodified.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * $Id: vga_isa.c,v 1.8 1999/05/09 16:39:24 peter Exp $
30 */
31
32#include "vga.h"
33#include "opt_vga.h"
34#include "opt_fb.h"
35#include "opt_syscons.h"	/* should be removed in the future, XXX */
36
37#if NVGA > 0
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/bus.h>
43#include <sys/malloc.h>
44
45#include <vm/vm.h>
46#include <vm/pmap.h>
47
48#include <machine/console.h>
49#include <machine/md_var.h>
50#include <machine/pc/bios.h>
51
52#include <dev/fb/fbreg.h>
53#include <dev/fb/vgareg.h>
54
55#include <isa/isareg.h>
56#include <isa/isavar.h>
57
58#define DRIVER_NAME		"vga"
59
60/* cdev driver declaration */
61
62#define ISAVGA_UNIT(dev)	minor(dev)
63#define ISAVGA_MKMINOR(unit)	(unit)
64
65typedef struct isavga_softc {
66	video_adapter_t	*adp;
67} isavga_softc_t;
68
69#define ISAVGA_SOFTC(unit)		\
70	((isavga_softc_t *)devclass_get_softc(isavga_devclass, unit))
71
72devclass_t		isavga_devclass;
73
74static int		isavga_probe(device_t dev);
75static int		isavga_attach(device_t dev);
76
77static device_method_t isavga_methods[] = {
78	DEVMETHOD(device_probe,		isavga_probe),
79	DEVMETHOD(device_attach,	isavga_attach),
80	{ 0, 0 }
81};
82
83static driver_t isavga_driver = {
84	DRIVER_NAME,
85	isavga_methods,
86	sizeof(isavga_softc_t),
87};
88
89DRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0);
90
91static int		isavga_probe_unit(int unit, isavga_softc_t *sc,
92					  int flags);
93static int		isavga_attach_unit(int unit, isavga_softc_t *sc,
94					   int flags);
95
96#ifdef FB_INSTALL_CDEV
97
98static d_open_t		isavgaopen;
99static d_close_t	isavgaclose;
100static d_read_t		isavgaread;
101static d_ioctl_t	isavgaioctl;
102
103static struct  cdevsw vga_cdevsw = {
104	isavgaopen,	isavgaclose,	noread,		nowrite,	/* ?? */
105	isavgaioctl,	nostop,		nullreset,	nodevtotty,
106	seltrue,	nommap,		NULL,		DRIVER_NAME,
107	NULL,		-1,		nodump,		nopsize,
108};
109
110#endif /* FB_INSTALL_CDEV */
111
112static int
113isavga_probe(device_t dev)
114{
115	isavga_softc_t *sc;
116
117	/* No pnp support */
118	if (isa_get_vendorid(dev))
119		return (ENXIO);
120
121	device_set_desc(dev, "Generic ISA VGA");
122	sc = device_get_softc(dev);
123	return isavga_probe_unit(device_get_unit(dev), sc, isa_get_flags(dev));
124}
125
126static int
127isavga_attach(device_t dev)
128{
129	isavga_softc_t *sc;
130
131	sc = device_get_softc(dev);
132	return isavga_attach_unit(device_get_unit(dev), sc, isa_get_flags(dev));
133}
134
135static int
136isavga_probe_unit(int unit, isavga_softc_t *sc, int flags)
137{
138	video_switch_t *sw;
139
140	bzero(sc, sizeof(*sc));
141	sw = vid_get_switch(DRIVER_NAME);
142	if (sw == NULL)
143		return 0;
144	return (*sw->probe)(unit, &sc->adp, NULL, flags);
145}
146
147static int
148isavga_attach_unit(int unit, isavga_softc_t *sc, int flags)
149{
150	video_switch_t *sw;
151	int error;
152
153	sw = vid_get_switch(DRIVER_NAME);
154	if (sw == NULL)
155		return ENXIO;
156
157	error = (*sw->init)(unit, sc->adp, flags);
158	if (error)
159		return ENXIO;
160
161#ifdef FB_INSTALL_CDEV
162	/* attach a virtual frame buffer device */
163	error = fb_attach(makedev(0, ISAVGA_MKMINOR(unit)), scp->adp,
164			  &vga_cdevsw);
165	if (error)
166		return error;
167#endif /* FB_INSTALL_CDEV */
168
169	if (bootverbose)
170		(*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose);
171
172	return 0;
173}
174
175/* LOW-LEVEL */
176
177#include <machine/clock.h>
178#include <machine/pc/vesa.h>
179
180#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
181#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
182#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
183
184/* for compatibility with old kernel options */
185#ifdef SC_ALT_SEQACCESS
186#undef SC_ALT_SEQACCESS
187#undef VGA_ALT_SEQACCESS
188#define VGA_ALT_SEQACCESS	1
189#endif
190
191#ifdef SLOW_VGA
192#undef SLOW_VGA
193#undef VGA_SLOW_IOACCESS
194#define VGA_SLOW_IOACCESS	1
195#endif
196
197/* architecture dependent option */
198#ifdef __alpha__
199#define VGA_NO_BIOS		1
200#endif
201
202/* this should really be in `rtc.h' */
203#define RTC_EQUIPMENT           0x14
204
205/* various sizes */
206#define V_MODE_MAP_SIZE		(M_VGA_CG320 + 1)
207#define V_MODE_PARAM_SIZE	64
208
209/* video adapter state buffer */
210struct adp_state {
211    int			sig;
212#define V_STATE_SIG	0x736f6962
213    u_char		regs[V_MODE_PARAM_SIZE];
214};
215typedef struct adp_state adp_state_t;
216
217/* video adapter information */
218#define DCC_MONO	0
219#define DCC_CGA40	1
220#define DCC_CGA80	2
221#define DCC_EGAMONO	3
222#define DCC_EGA40	4
223#define DCC_EGA80	5
224
225/*
226 * NOTE: `va_window' should have a virtual address, but is initialized
227 * with a physical address in the following table, as verify_adapter()
228 * will perform address conversion at run-time.
229 */
230static video_adapter_t adapter_init_value[] = {
231    /* DCC_MONO */
232    { 0, KD_MONO, "mda", 0, 0, 0, 	    IO_MDA, IO_MDASIZE, MONO_CRTC,
233      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
234      0, 0, 0, 7, 0, },
235    /* DCC_CGA40 */
236    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
237      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
238      0, 0, 0, 3, 0, },
239    /* DCC_CGA80 */
240    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
241      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
242      0, 0, 0, 3, 0, },
243    /* DCC_EGAMONO */
244    { 0, KD_EGA,  "ega", 0, 0, 0,	    IO_MDA, 48,	  MONO_CRTC,
245      EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
246      0, 0, 0, 7, 0, },
247    /* DCC_EGA40 */
248    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
249      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
250      0, 0, 0, 3, 0, },
251    /* DCC_EGA80 */
252    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
253      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
254      0, 0, 0, 3, 0, },
255};
256
257static video_adapter_t	biosadapter[2];
258static int		biosadapters = 0;
259
260/* video driver declarations */
261static int			vga_configure(int flags);
262       int			(*vga_sub_configure)(int flags);
263static int			vga_nop(void);
264static vi_probe_t		vga_probe;
265static vi_init_t		vga_init;
266static vi_get_info_t		vga_get_info;
267static vi_query_mode_t		vga_query_mode;
268static vi_set_mode_t		vga_set_mode;
269static vi_save_font_t		vga_save_font;
270static vi_load_font_t		vga_load_font;
271static vi_show_font_t		vga_show_font;
272static vi_save_palette_t	vga_save_palette;
273static vi_load_palette_t	vga_load_palette;
274static vi_set_border_t		vga_set_border;
275static vi_save_state_t		vga_save_state;
276static vi_load_state_t		vga_load_state;
277static vi_set_win_org_t		vga_set_origin;
278static vi_read_hw_cursor_t	vga_read_hw_cursor;
279static vi_set_hw_cursor_t	vga_set_hw_cursor;
280static vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
281static vi_mmap_t		vga_mmap;
282static vi_diag_t		vga_diag;
283
284static video_switch_t vgavidsw = {
285	vga_probe,
286	vga_init,
287	vga_get_info,
288	vga_query_mode,
289	vga_set_mode,
290	vga_save_font,
291	vga_load_font,
292	vga_show_font,
293	vga_save_palette,
294	vga_load_palette,
295	vga_set_border,
296	vga_save_state,
297	vga_load_state,
298	vga_set_origin,
299	vga_read_hw_cursor,
300	vga_set_hw_cursor,
301	vga_set_hw_cursor_shape,
302	(vi_blank_display_t *)vga_nop,
303	vga_mmap,
304	vga_diag,
305};
306
307VIDEO_DRIVER(mda, vgavidsw, NULL);
308VIDEO_DRIVER(cga, vgavidsw, NULL);
309VIDEO_DRIVER(ega, vgavidsw, NULL);
310VIDEO_DRIVER(vga, vgavidsw, vga_configure);
311
312/* VGA BIOS standard video modes */
313#define EOT		(-1)
314#define NA		(-2)
315
316static video_info_t bios_vmode[] = {
317    /* CGA */
318    { M_B40x25,     V_INFO_COLOR, 40, 25, 8,  8, 2, 1,
319      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
320    { M_C40x25,     V_INFO_COLOR, 40, 25, 8,  8, 4, 1,
321      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
322    { M_B80x25,     V_INFO_COLOR, 80, 25, 8,  8, 2, 1,
323      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
324    { M_C80x25,     V_INFO_COLOR, 80, 25, 8,  8, 4, 1,
325      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
326    /* EGA */
327    { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1,
328      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
329    { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1,
330      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
331    { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1,
332      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
333    { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1,
334      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
335    /* VGA */
336    { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1,
337      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
338    { M_VGA_M80x25, 0,            80, 25, 8, 16, 2, 1,
339      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
340    { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
341      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
342    /* MDA */
343    { M_EGAMONO80x25, 0,          80, 25, 8, 14, 2, 1,
344      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
345    /* EGA */
346    { M_ENH_B80x43, V_INFO_COLOR, 80, 43, 8,  8, 2, 1,
347      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
348    { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8,  8, 4, 1,
349      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
350    /* VGA */
351    { M_VGA_M80x30, 0,            80, 30, 8, 16, 2, 1,
352      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
353    { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
354      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
355    { M_VGA_M80x50, 0,            80, 50, 8,  8, 2, 1,
356      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
357    { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8,  8, 4, 1,
358      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
359    { M_VGA_M80x60, 0,            80, 60, 8,  8, 2, 1,
360      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 },
361    { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8,  8, 4, 1,
362      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
363#ifndef VGA_NO_MODE_CHANGE
364    /* CGA */
365    { M_BG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
366      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
367    { M_CG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
368      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
369    { M_BG640,      V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 1, 1,
370      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 },
371    /* EGA */
372    { M_CG320_D,    V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 4, 4,
373      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
374    { M_CG640_E,    V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 4, 4,
375      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
376    { M_EGAMONOAPA, V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
377      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 },
378    { M_ENHMONOAPA2,V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
379      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
380    { M_CG640x350,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2,
381      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
382    { M_ENH_CG640,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4,
383      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
384    /* VGA */
385    { M_BG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
386      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
387    { M_CG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
388      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
389    { M_VGA_CG320,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 8, 1,
390      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
391    { M_VGA_MODEX,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8,  8, 8, 1,
392      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 },
393#endif /* VGA_NO_MODE_CHANGE */
394
395    { EOT },
396};
397
398static int		init_done = FALSE;
399#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
400static u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
401static u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
402#endif
403static u_char		*mode_map[V_MODE_MAP_SIZE];
404static adp_state_t	adpstate;
405static adp_state_t	adpstate2;
406static int		rows_offset = 1;
407
408/* local macros and functions */
409#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
410
411#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
412static void map_mode_table(u_char *map[], u_char *table, int max);
413#endif
414static void clear_mode_map(video_adapter_t *adp, u_char *map[], int max,
415			   int color);
416#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
417static int map_mode_num(int mode);
418#endif
419static int map_gen_mode_num(int type, int color, int mode);
420static int map_bios_mode_num(int type, int color, int bios_mode);
421static u_char *get_mode_param(int mode);
422#ifndef VGA_NO_BIOS
423static void fill_adapter_param(int code, video_adapter_t *adp);
424#endif
425static int verify_adapter(video_adapter_t *adp);
426static void update_adapter_info(video_adapter_t *adp, video_info_t *info);
427#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
428#define COMP_IDENTICAL	0
429#define COMP_SIMILAR	1
430#define COMP_DIFFERENT	2
431static int comp_adpregs(u_char *buf1, u_char *buf2);
432#endif
433static int probe_adapters(void);
434
435#ifndef VGA_NO_FONT_LOADING
436#define PARAM_BUFSIZE	6
437static void set_font_mode(video_adapter_t *adp, u_char *buf);
438static void set_normal_mode(video_adapter_t *adp, u_char *buf);
439#endif
440
441static void dump_buffer(u_char *buf, size_t len);
442
443#define	ISMAPPED(pa, width)				\
444	(((pa) <= (u_long)0x1000 - (width)) 		\
445	 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
446
447#define	prologue(adp, flag, err)			\
448	if (!init_done || !((adp)->va_flags & (flag)))	\
449	    return (err)
450
451/* a backdoor for the console driver */
452static int
453vga_configure(int flags)
454{
455    int i;
456
457    probe_adapters();
458    for (i = 0; i < biosadapters; ++i) {
459	if (!probe_done(&biosadapter[i]))
460	    continue;
461	biosadapter[i].va_flags |= V_ADP_INITIALIZED;
462	if (!config_done(&biosadapter[i])) {
463	    if (vid_register(&biosadapter[i]) < 0)
464		continue;
465	    biosadapter[i].va_flags |= V_ADP_REGISTERED;
466	}
467    }
468    if (vga_sub_configure != NULL)
469	(*vga_sub_configure)(flags);
470
471    return biosadapters;
472}
473
474/* local subroutines */
475
476#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
477/* construct the mode parameter map */
478static void
479map_mode_table(u_char *map[], u_char *table, int max)
480{
481    int i;
482
483    for(i = 0; i < max; ++i)
484	map[i] = table + i*V_MODE_PARAM_SIZE;
485    for(; i < V_MODE_MAP_SIZE; ++i)
486	map[i] = NULL;
487}
488#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
489
490static void
491clear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color)
492{
493    video_info_t info;
494    int i;
495
496    /*
497     * NOTE: we don't touch `bios_vmode[]' because it is shared
498     * by all adapters.
499     */
500    for(i = 0; i < max; ++i) {
501	if (vga_get_info(adp, i, &info))
502	    continue;
503	if ((info.vi_flags & V_INFO_COLOR) != color)
504	    map[i] = NULL;
505    }
506}
507
508#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
509/* map the non-standard video mode to a known mode number */
510static int
511map_mode_num(int mode)
512{
513    static struct {
514        int from;
515        int to;
516    } mode_map[] = {
517        { M_ENH_B80x43, M_ENH_B80x25 },
518        { M_ENH_C80x43, M_ENH_C80x25 },
519        { M_VGA_M80x30, M_VGA_M80x25 },
520        { M_VGA_C80x30, M_VGA_C80x25 },
521        { M_VGA_M80x50, M_VGA_M80x25 },
522        { M_VGA_C80x50, M_VGA_C80x25 },
523        { M_VGA_M80x60, M_VGA_M80x25 },
524        { M_VGA_C80x60, M_VGA_C80x25 },
525        { M_VGA_MODEX,  M_VGA_CG320 },
526    };
527    int i;
528
529    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
530        if (mode_map[i].from == mode)
531            return mode_map[i].to;
532    }
533    return mode;
534}
535#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
536
537/* map a generic video mode to a known mode number */
538static int
539map_gen_mode_num(int type, int color, int mode)
540{
541    static struct {
542	int from;
543	int to_color;
544	int to_mono;
545    } mode_map[] = {
546	{ M_TEXT_80x30,	M_VGA_C80x30, M_VGA_M80x30, },
547	{ M_TEXT_80x43,	M_ENH_C80x43, M_ENH_B80x43, },
548	{ M_TEXT_80x50,	M_VGA_C80x50, M_VGA_M80x50, },
549	{ M_TEXT_80x60,	M_VGA_C80x60, M_VGA_M80x60, },
550    };
551    int i;
552
553    if (mode == M_TEXT_80x25) {
554	switch (type) {
555
556	case KD_VGA:
557	    if (color)
558		return M_VGA_C80x25;
559	    else
560		return M_VGA_M80x25;
561	    break;
562
563	case KD_EGA:
564	    if (color)
565		return M_ENH_C80x25;
566	    else
567		return M_EGAMONO80x25;
568	    break;
569
570	case KD_CGA:
571	    return M_C80x25;
572
573	case KD_MONO:
574	case KD_HERCULES:
575	    return M_EGAMONO80x25;	/* XXX: this name is confusing */
576
577 	default:
578	    return -1;
579	}
580    }
581
582    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
583        if (mode_map[i].from == mode)
584            return ((color) ? mode_map[i].to_color : mode_map[i].to_mono);
585    }
586    return mode;
587}
588
589/* turn the BIOS video number into our video mode number */
590static int
591map_bios_mode_num(int type, int color, int bios_mode)
592{
593    static int cga_modes[7] = {
594	M_B40x25, M_C40x25,		/* 0, 1 */
595	M_B80x25, M_C80x25,		/* 2, 3 */
596	M_BG320, M_CG320,
597	M_BG640,
598    };
599    static int ega_modes[17] = {
600	M_ENH_B40x25, M_ENH_C40x25,	/* 0, 1 */
601	M_ENH_B80x25, M_ENH_C80x25,	/* 2, 3 */
602	M_BG320, M_CG320,
603	M_BG640,
604	M_EGAMONO80x25,			/* 7 */
605	8, 9, 10, 11, 12,
606	M_CG320_D,
607	M_CG640_E,
608	M_ENHMONOAPA2,			/* XXX: video momery > 64K */
609	M_ENH_CG640,			/* XXX: video momery > 64K */
610    };
611    static int vga_modes[20] = {
612	M_VGA_C40x25, M_VGA_C40x25,	/* 0, 1 */
613	M_VGA_C80x25, M_VGA_C80x25,	/* 2, 3 */
614	M_BG320, M_CG320,
615	M_BG640,
616	M_VGA_M80x25,			/* 7 */
617	8, 9, 10, 11, 12,
618	M_CG320_D,
619	M_CG640_E,
620	M_ENHMONOAPA2,
621	M_ENH_CG640,
622	M_BG640x480, M_CG640x480,
623	M_VGA_CG320,
624    };
625
626    switch (type) {
627
628    case KD_VGA:
629	if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0]))
630	    return vga_modes[bios_mode];
631	else if (color)
632	    return M_VGA_C80x25;
633	else
634	    return M_VGA_M80x25;
635	break;
636
637    case KD_EGA:
638	if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0]))
639	    return ega_modes[bios_mode];
640	else if (color)
641	    return M_ENH_C80x25;
642	else
643	    return M_EGAMONO80x25;
644	break;
645
646    case KD_CGA:
647	if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0]))
648	    return cga_modes[bios_mode];
649	else
650	    return M_C80x25;
651	break;
652
653    case KD_MONO:
654    case KD_HERCULES:
655	return M_EGAMONO80x25;		/* XXX: this name is confusing */
656
657    default:
658	break;
659    }
660    return -1;
661}
662
663/* look up a parameter table entry */
664static u_char
665*get_mode_param(int mode)
666{
667#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
668    if (mode >= V_MODE_MAP_SIZE)
669	mode = map_mode_num(mode);
670#endif
671    if ((mode >= 0) && (mode < V_MODE_MAP_SIZE))
672	return mode_map[mode];
673    else
674	return NULL;
675}
676
677#ifndef VGA_NO_BIOS
678static void
679fill_adapter_param(int code, video_adapter_t *adp)
680{
681    static struct {
682	int primary;
683	int secondary;
684    } dcc[] = {
685	{ DCC_MONO, 			DCC_EGA40 /* CGA monitor */ },
686	{ DCC_MONO, 			DCC_EGA80 /* CGA monitor */ },
687	{ DCC_MONO, 			DCC_EGA80 /* CGA emulation */ },
688	{ DCC_MONO, 			DCC_EGA80 },
689	{ DCC_CGA40, 			DCC_EGAMONO },
690	{ DCC_CGA80, 			DCC_EGAMONO },
691	{ DCC_EGA40 /* CGA monitor */, 	DCC_MONO},
692	{ DCC_EGA80 /* CGA monitor */, 	DCC_MONO},
693	{ DCC_EGA80 /* CGA emulation */,DCC_MONO },
694	{ DCC_EGA80, 			DCC_MONO },
695	{ DCC_EGAMONO, 			DCC_CGA40 },
696	{ DCC_EGAMONO, 			DCC_CGA40 },
697    };
698
699    if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) {
700	adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
701	adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
702    } else {
703	adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary];
704	adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary];
705    }
706}
707#endif /* VGA_NO_BIOS */
708
709static int
710verify_adapter(video_adapter_t *adp)
711{
712    vm_offset_t buf;
713    u_int16_t v;
714#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
715    u_int32_t p;
716#endif
717
718    buf = BIOS_PADDRTOVADDR(adp->va_window);
719    v = readw(buf);
720    writew(buf, 0xA55A);
721    if (readw(buf) != 0xA55A)
722	return 1;
723    writew(buf, v);
724
725    switch (adp->va_type) {
726
727    case KD_EGA:
728	outb(adp->va_crtc_addr, 7);
729	if (inb(adp->va_crtc_addr) == 7) {
730	    adp->va_type = KD_VGA;
731	    adp->va_name = "vga";
732	    adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE;
733	}
734	adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER;
735	/* the color adapter may be in the 40x25 mode... XXX */
736
737#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
738	/* get the BIOS video mode pointer */
739	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8);
740	p = BIOS_SADDRTOLADDR(p);
741	if (ISMAPPED(p, sizeof(u_int32_t))) {
742	    p = *(u_int32_t *)BIOS_PADDRTOVADDR(p);
743	    p = BIOS_SADDRTOLADDR(p);
744	    if (ISMAPPED(p, V_MODE_PARAM_SIZE))
745		video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p);
746	}
747#endif
748	break;
749
750    case KD_CGA:
751	adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER;
752	/* may be in the 40x25 mode... XXX */
753#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
754	/* get the BIOS video mode pointer */
755	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
756	p = BIOS_SADDRTOLADDR(p);
757	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
758#endif
759	break;
760
761    case KD_MONO:
762#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
763	/* get the BIOS video mode pointer */
764	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
765	p = BIOS_SADDRTOLADDR(p);
766	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
767#endif
768	break;
769    }
770
771    return 0;
772}
773
774static void
775update_adapter_info(video_adapter_t *adp, video_info_t *info)
776{
777    adp->va_flags &= ~V_ADP_COLOR;
778    adp->va_flags |=
779	(info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
780    adp->va_crtc_addr =
781	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
782    adp->va_window = BIOS_PADDRTOVADDR(info->vi_window);
783    adp->va_window_size = info->vi_window_size;
784    adp->va_window_gran = info->vi_window_gran;
785    if (info->vi_buffer_size == 0) {
786    	adp->va_buffer = 0;
787    	adp->va_buffer_size = 0;
788    } else {
789    	adp->va_buffer = BIOS_PADDRTOVADDR(info->vi_buffer);
790    	adp->va_buffer_size = info->vi_buffer_size;
791    }
792    if (info->vi_flags & V_INFO_GRAPHICS) {
793	switch (info->vi_depth/info->vi_planes) {
794	case 1:
795	    adp->va_line_width = info->vi_width/8;
796	    break;
797	case 2:
798	    adp->va_line_width = info->vi_width/4;
799	    break;
800	case 4:
801	    adp->va_line_width = info->vi_width/2;
802	    break;
803	case 8:
804	default: /* shouldn't happen */
805	    adp->va_line_width = info->vi_width;
806	    break;
807	}
808    } else {
809	adp->va_line_width = info->vi_width;
810    }
811    bcopy(info, &adp->va_info, sizeof(adp->va_info));
812}
813
814#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
815/* compare two parameter table entries */
816static int
817comp_adpregs(u_char *buf1, u_char *buf2)
818{
819    static struct {
820        u_char mask;
821    } params[V_MODE_PARAM_SIZE] = {
822	{0xff}, {0x00}, {0xff}, 		/* COLS, ROWS, POINTS */
823	{0x00}, {0x00}, 			/* page length */
824	{0xfe}, {0xff}, {0xff}, {0xff},		/* sequencer registers */
825	{0xf3},					/* misc register */
826	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},	/* CRTC */
827	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},
828	{0x00}, {0x00}, {0x00}, {0x00}, {0x00},
829	{0x00}, {0xff}, {0x7f}, {0xff}, {0xff},
830	{0x7f}, {0xff}, {0xff}, {0xef}, {0xff},
831	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* attribute controller regs */
832	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
833	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
834	{0xff}, {0xff}, {0xff}, {0xff}, {0xf0},
835	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* GDC register */
836	{0xff}, {0xff}, {0xff}, {0xff},
837    };
838    int identical = TRUE;
839    int i;
840
841    if ((buf1 == NULL) || (buf2 == NULL))
842	return COMP_DIFFERENT;
843
844    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
845	if (params[i].mask == 0)	/* don't care */
846	    continue;
847	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
848	    return COMP_DIFFERENT;
849	if (buf1[i] != buf2[i])
850	    identical = FALSE;
851    }
852    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
853}
854#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
855
856/* probe video adapters and return the number of detected adapters */
857static int
858probe_adapters(void)
859{
860    video_adapter_t *adp;
861    video_info_t info;
862    int i;
863
864    /* do this test only once */
865    if (init_done)
866	return biosadapters;
867    init_done = TRUE;
868
869    /*
870     * Locate display adapters.
871     * The AT architecture supports upto two adapters. `syscons' allows
872     * the following combinations of adapters:
873     *     1) MDA + CGA
874     *     2) MDA + EGA/VGA color
875     *     3) CGA + EGA/VGA mono
876     * Note that `syscons' doesn't bother with MCGA as it is only
877     * avaiable for low end PS/2 models which has 80286 or earlier CPUs,
878     * thus, they are not running FreeBSD!
879     * When there are two adapaters in the system, one becomes `primary'
880     * and the other `secondary'. The EGA adapter has a set of DIP
881     * switches on board for this information and the EGA BIOS copies
882     * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88).
883     * The VGA BIOS has more sophisticated mechanism and has this
884     * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains
885     * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH.
886     */
887
888    /*
889     * Check rtc and BIOS data area.
890     * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead
891     * copy of RTC_EQUIPMENT.  Bits 4 and 5 of ETC_EQUIPMENT are
892     * zeros for EGA and VGA.  However, the EGA/VGA BIOS sets
893     * these bits in BIOSDATA_EQUIPMENT according to the monitor
894     * type detected.
895     */
896#ifndef VGA_NO_BIOS
897    switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
898    case 0:
899	/* EGA/VGA */
900	fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
901			   biosadapter);
902	break;
903    case 1:
904	/* CGA 40x25 */
905	/* FIXME: switch to the 80x25 mode? XXX */
906	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40];
907	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
908	break;
909    case 2:
910	/* CGA 80x25 */
911	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80];
912	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
913	break;
914    case 3:
915	/* MDA */
916	biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
917	biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
918	break;
919    }
920#else
921    /* assume EGA/VGA? XXX */
922    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80];
923    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
924#endif /* VGA_NO_BIOS */
925
926    biosadapters = 0;
927    if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) {
928	++biosadapters;
929	biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED;
930	biosadapter[V_ADP_SECONDARY].va_mode =
931	    biosadapter[V_ADP_SECONDARY].va_initial_mode =
932	    map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type,
933			      biosadapter[V_ADP_SECONDARY].va_flags
934				  & V_ADP_COLOR,
935			      biosadapter[V_ADP_SECONDARY].va_initial_bios_mode);
936    } else {
937	biosadapter[V_ADP_SECONDARY].va_type = -1;
938    }
939    if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) {
940	++biosadapters;
941	biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED;
942#ifndef VGA_NO_BIOS
943	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode =
944	    readb(BIOS_PADDRTOVADDR(0x449));
945#else
946	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3;	/* XXX */
947#endif
948	biosadapter[V_ADP_PRIMARY].va_mode =
949	    biosadapter[V_ADP_PRIMARY].va_initial_mode =
950	    map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type,
951			      biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR,
952			      biosadapter[V_ADP_PRIMARY].va_initial_bios_mode);
953    } else {
954	biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY];
955	biosadapter[V_ADP_SECONDARY].va_type = -1;
956    }
957    if (biosadapters == 0)
958	return biosadapters;
959    biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY;
960    biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY;
961
962#if 0 /* we don't need these... */
963    fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...);
964    fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...);
965#endif
966
967#if 0
968    /*
969     * We cannot have two video adapter of the same type; there must be
970     * only one of color or mono adapter, or one each of them.
971     */
972    if (biosadapters > 1) {
973	if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags)
974	      & V_ADP_COLOR))
975	    /* we have two mono or color adapters!! */
976	    return (biosadapters = 0);
977    }
978#endif
979
980    /*
981     * Ensure a zero start address.  This is mainly to recover after
982     * switching from pcvt using userconfig().  The registers are w/o
983     * for old hardware so it's too hard to relocate the active screen
984     * memory.
985     * This must be done before vga_save_state() for VGA.
986     */
987    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12);
988    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
989    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13);
990    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
991
992    /* the video mode parameter table in EGA/VGA BIOS */
993    /* NOTE: there can be only one EGA/VGA, wheather color or mono,
994     * recognized by the video BIOS.
995     */
996    if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) ||
997	(biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) {
998	adp = &biosadapter[V_ADP_PRIMARY];
999    } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) ||
1000	       (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) {
1001	adp = &biosadapter[V_ADP_SECONDARY];
1002    } else {
1003	adp = NULL;
1004    }
1005    bzero(mode_map, sizeof(mode_map));
1006    if (adp != NULL) {
1007	if (adp->va_type == KD_VGA) {
1008	    vga_save_state(adp, &adpstate, sizeof(adpstate));
1009#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
1010	    mode_map[adp->va_initial_mode] = adpstate.regs;
1011	    rows_offset = 1;
1012#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1013	    if (video_mode_ptr == NULL) {
1014		mode_map[adp->va_initial_mode] = adpstate.regs;
1015		rows_offset = 1;
1016	    } else {
1017		/* discard the table if we are not familiar with it... */
1018		u_char *mp;
1019		map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
1020		mp = get_mode_param(adp->va_initial_mode);
1021		if (mp != NULL)
1022		    bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs));
1023		switch (comp_adpregs(adpstate.regs, mp)) {
1024		case COMP_IDENTICAL:
1025		    /*
1026		     * OK, this parameter table looks reasonably familiar
1027		     * to us...
1028		     */
1029		    /*
1030		     * This is a kludge for Toshiba DynaBook SS433
1031		     * whose BIOS video mode table entry has the actual #
1032		     * of rows at the offset 1; BIOSes from other
1033		     * manufacturers store the # of rows - 1 there. XXX
1034		     */
1035		    rows_offset = adpstate.regs[1] + 1 - mp[1];
1036		    break;
1037
1038		case COMP_SIMILAR:
1039		    /*
1040		     * Not exactly the same, but similar enough to be
1041		     * trusted. However, use the saved register values
1042		     * for the initial mode and other modes which are
1043		     * based on the initial mode.
1044		     */
1045		    mode_map[adp->va_initial_mode] = adpstate.regs;
1046		    rows_offset = adpstate.regs[1] + 1 - mp[1];
1047		    adpstate.regs[1] -= rows_offset - 1;
1048		    break;
1049
1050		case COMP_DIFFERENT:
1051		default:
1052		    /*
1053		     * Don't use the paramter table in BIOS. It doesn't
1054		     * look familiar to us. Video mode switching is allowed
1055		     * only if the new mode is the same as or based on
1056		     * the initial mode.
1057		     */
1058		    video_mode_ptr = NULL;
1059		    bzero(mode_map, sizeof(mode_map));
1060		    mode_map[adp->va_initial_mode] = adpstate.regs;
1061		    rows_offset = 1;
1062		    break;
1063		}
1064	    }
1065#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1066
1067#ifndef VGA_NO_MODE_CHANGE
1068	    adp->va_flags |= V_ADP_MODECHANGE;
1069#endif
1070#ifndef VGA_NO_FONT_LOADING
1071	    adp->va_flags |= V_ADP_FONT;
1072#endif
1073	} else if (adp->va_type == KD_EGA) {
1074#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
1075	    rows_offset = 1;
1076#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1077	    if (video_mode_ptr == NULL) {
1078		rows_offset = 1;
1079	    } else {
1080		u_char *mp;
1081		map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1);
1082		/* XXX how can one validate the EGA table... */
1083		mp = get_mode_param(adp->va_initial_mode);
1084		if (mp != NULL) {
1085		    adp->va_flags |= V_ADP_MODECHANGE;
1086#ifndef VGA_NO_FONT_LOADING
1087		    adp->va_flags |= V_ADP_FONT;
1088#endif
1089		    rows_offset = 1;
1090		} else {
1091		    /*
1092		     * This is serious. We will not be able to switch video
1093		     * modes at all...
1094		     */
1095		    video_mode_ptr = NULL;
1096		    bzero(mode_map, sizeof(mode_map));
1097		    rows_offset = 1;
1098                }
1099	    }
1100#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1101	}
1102    }
1103
1104    /* remove conflicting modes if we have more than one adapter */
1105    if (biosadapters > 1) {
1106	for (i = 0; i < biosadapters; ++i) {
1107	    if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE))
1108		continue;
1109	    clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1,
1110			   (biosadapter[i].va_flags & V_ADP_COLOR) ?
1111			       V_INFO_COLOR : 0);
1112	    if ((biosadapter[i].va_type == KD_VGA)
1113		|| (biosadapter[i].va_type == KD_EGA)) {
1114		biosadapter[i].va_io_base =
1115		    (biosadapter[i].va_flags & V_ADP_COLOR) ?
1116			IO_VGA : IO_MDA;
1117		biosadapter[i].va_io_size = 32;
1118	    }
1119	}
1120    }
1121
1122    /* buffer address */
1123    vga_get_info(&biosadapter[V_ADP_PRIMARY],
1124		 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info);
1125    update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info);
1126
1127    if (biosadapters > 1) {
1128	vga_get_info(&biosadapter[V_ADP_SECONDARY],
1129		     biosadapter[V_ADP_SECONDARY].va_initial_mode, &info);
1130	update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info);
1131    }
1132
1133    /*
1134     * XXX: we should verify the following values for the primary adapter...
1135     * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
1136     * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
1137     *                     ? 0 : V_ADP_COLOR;
1138     * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
1139     * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
1140     * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
1141     * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
1142     */
1143
1144    return biosadapters;
1145}
1146
1147/* entry points */
1148
1149static int
1150vga_nop(void)
1151{
1152    return 0;
1153}
1154
1155static int
1156vga_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
1157{
1158    probe_adapters();
1159    if (unit >= biosadapters)
1160	return ENXIO;
1161
1162    *adpp = &biosadapter[unit];
1163
1164    return 0;
1165}
1166
1167static int
1168vga_init(int unit, video_adapter_t *adp, int flags)
1169{
1170    if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp))
1171	return ENXIO;
1172
1173    if (!init_done(adp)) {
1174	/* nothing to do really... */
1175	adp->va_flags |= V_ADP_INITIALIZED;
1176    }
1177
1178    if (!config_done(adp)) {
1179	if (vid_register(adp) < 0)
1180		return ENXIO;
1181	adp->va_flags |= V_ADP_REGISTERED;
1182    }
1183    if (vga_sub_configure != NULL)
1184	(*vga_sub_configure)(0);
1185
1186    return 0;
1187}
1188
1189/*
1190 * get_info():
1191 * Return the video_info structure of the requested video mode.
1192 *
1193 * all adapters
1194 */
1195static int
1196vga_get_info(video_adapter_t *adp, int mode, video_info_t *info)
1197{
1198    int i;
1199
1200    if (!init_done)
1201	return 1;
1202
1203    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
1204#ifndef VGA_NO_MODE_CHANGE
1205    if (adp->va_flags & V_ADP_MODECHANGE) {
1206	/*
1207	 * If the parameter table entry for this mode is not found,
1208	 * the mode is not supported...
1209	 */
1210	if (get_mode_param(mode) == NULL)
1211	    return 1;
1212    } else
1213#endif /* VGA_NO_MODE_CHANGE */
1214    {
1215	/*
1216	 * Even if we don't support video mode switching on this adapter,
1217	 * the information on the initial (thus current) video mode
1218	 * should be made available.
1219	 */
1220	if (mode != adp->va_initial_mode)
1221	    return 1;
1222    }
1223
1224    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1225	if (bios_vmode[i].vi_mode == NA)
1226	    continue;
1227	if (mode == bios_vmode[i].vi_mode) {
1228	    *info = bios_vmode[i];
1229	    return 0;
1230	}
1231    }
1232    return 1;
1233}
1234
1235/*
1236 * query_mode():
1237 * Find a video mode matching the requested parameters.
1238 * Fields filled with 0 are considered "don't care" fields and
1239 * match any modes.
1240 *
1241 * all adapters
1242 */
1243static int
1244vga_query_mode(video_adapter_t *adp, video_info_t *info)
1245{
1246    video_info_t buf;
1247    int i;
1248
1249    if (!init_done)
1250	return -1;
1251
1252    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1253	if (bios_vmode[i].vi_mode == NA)
1254	    continue;
1255
1256	if ((info->vi_width != 0)
1257	    && (info->vi_width != bios_vmode[i].vi_width))
1258		continue;
1259	if ((info->vi_height != 0)
1260	    && (info->vi_height != bios_vmode[i].vi_height))
1261		continue;
1262	if ((info->vi_cwidth != 0)
1263	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
1264		continue;
1265	if ((info->vi_cheight != 0)
1266	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
1267		continue;
1268	if ((info->vi_depth != 0)
1269	    && (info->vi_depth != bios_vmode[i].vi_depth))
1270		continue;
1271	if ((info->vi_planes != 0)
1272	    && (info->vi_planes != bios_vmode[i].vi_planes))
1273		continue;
1274	/* XXX: should check pixel format, memory model */
1275	if ((info->vi_flags != 0)
1276	    && (info->vi_flags != bios_vmode[i].vi_flags))
1277		continue;
1278
1279	/* verify if this mode is supported on this adapter */
1280	if (vga_get_info(adp, bios_vmode[i].vi_mode, &buf))
1281		continue;
1282	return bios_vmode[i].vi_mode;
1283    }
1284    return -1;
1285}
1286
1287/*
1288 * set_mode():
1289 * Change the video mode.
1290 *
1291 * EGA/VGA
1292 */
1293static int
1294vga_set_mode(video_adapter_t *adp, int mode)
1295{
1296#ifndef VGA_NO_MODE_CHANGE
1297    video_info_t info;
1298    adp_state_t params;
1299
1300    prologue(adp, V_ADP_MODECHANGE, 1);
1301
1302    mode = map_gen_mode_num(adp->va_type,
1303			    adp->va_flags & V_ADP_COLOR, mode);
1304    if (vga_get_info(adp, mode, &info))
1305	return 1;
1306    params.sig = V_STATE_SIG;
1307    bcopy(get_mode_param(mode), params.regs, sizeof(params.regs));
1308
1309    switch (mode) {
1310    case M_VGA_C80x60: case M_VGA_M80x60:
1311	params.regs[2]  = 0x08;
1312	params.regs[19] = 0x47;
1313	goto special_480l;
1314
1315    case M_VGA_C80x30: case M_VGA_M80x30:
1316	params.regs[19] = 0x4f;
1317special_480l:
1318	params.regs[9] |= 0xc0;
1319	params.regs[16] = 0x08;
1320	params.regs[17] = 0x3e;
1321	params.regs[26] = 0xea;
1322	params.regs[28] = 0xdf;
1323	params.regs[31] = 0xe7;
1324	params.regs[32] = 0x04;
1325	goto setup_mode;
1326
1327    case M_ENH_C80x43: case M_ENH_B80x43:
1328	params.regs[28] = 87;
1329	goto special_80x50;
1330
1331    case M_VGA_C80x50: case M_VGA_M80x50:
1332special_80x50:
1333	params.regs[2] = 8;
1334	params.regs[19] = 7;
1335	goto setup_mode;
1336
1337    case M_VGA_C40x25: case M_VGA_C80x25:
1338    case M_VGA_M80x25:
1339    case M_B40x25:     case M_C40x25:
1340    case M_B80x25:     case M_C80x25:
1341    case M_ENH_B40x25: case M_ENH_C40x25:
1342    case M_ENH_B80x25: case M_ENH_C80x25:
1343    case M_EGAMONO80x25:
1344
1345setup_mode:
1346	vga_load_state(adp, &params);
1347	break;
1348
1349    case M_VGA_MODEX:
1350	/* "unchain" the VGA mode */
1351	params.regs[5-1+0x04] &= 0xf7;
1352	params.regs[5-1+0x04] |= 0x04;
1353	/* turn off doubleword mode */
1354	params.regs[10+0x14] &= 0xbf;
1355	/* turn off word adressing */
1356	params.regs[10+0x17] |= 0x40;
1357	/* set logical screen width */
1358	params.regs[10+0x13] = 80;
1359	/* set 240 lines */
1360	params.regs[10+0x11] = 0x2c;
1361	params.regs[10+0x06] = 0x0d;
1362	params.regs[10+0x07] = 0x3e;
1363	params.regs[10+0x10] = 0xea;
1364	params.regs[10+0x11] = 0xac;
1365	params.regs[10+0x12] = 0xdf;
1366	params.regs[10+0x15] = 0xe7;
1367	params.regs[10+0x16] = 0x06;
1368	/* set vertical sync polarity to reflect aspect ratio */
1369	params.regs[9] = 0xe3;
1370	goto setup_grmode;
1371
1372    case M_BG320:     case M_CG320:     case M_BG640:
1373    case M_CG320_D:   case M_CG640_E:
1374    case M_CG640x350: case M_ENH_CG640:
1375    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
1376
1377setup_grmode:
1378	vga_load_state(adp, &params);
1379	break;
1380
1381    default:
1382	return 1;
1383    }
1384
1385    adp->va_mode = mode;
1386    update_adapter_info(adp, &info);
1387
1388    /* move hardware cursor out of the way */
1389    (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
1390
1391    return 0;
1392#else /* VGA_NO_MODE_CHANGE */
1393    return 1;
1394#endif /* VGA_NO_MODE_CHANGE */
1395}
1396
1397#ifndef VGA_NO_FONT_LOADING
1398
1399static void
1400set_font_mode(video_adapter_t *adp, u_char *buf)
1401{
1402    u_char *mp;
1403    int s;
1404
1405    s = splhigh();
1406
1407    /* save register values */
1408    if (adp->va_type == KD_VGA) {
1409	outb(TSIDX, 0x02); buf[0] = inb(TSREG);
1410	outb(TSIDX, 0x04); buf[1] = inb(TSREG);
1411	outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
1412	outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
1413	outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
1414	inb(adp->va_crtc_addr + 6);
1415	outb(ATC, 0x10); buf[5] = inb(ATC + 1);
1416    } else /* if (adp->va_type == KD_EGA) */ {
1417	/*
1418	 * EGA cannot be read; copy parameters from the mode parameter
1419	 * table.
1420	 */
1421	mp = get_mode_param(adp->va_mode);
1422	buf[0] = mp[5 + 0x02 - 1];
1423	buf[1] = mp[5 + 0x04 - 1];
1424	buf[2] = mp[55 + 0x04];
1425	buf[3] = mp[55 + 0x05];
1426	buf[4] = mp[55 + 0x06];
1427	buf[5] = mp[35 + 0x10];
1428    }
1429
1430    /* setup vga for loading fonts */
1431    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1432    outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
1433    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1434    outb(ATC, 0x20);				/* enable palette */
1435
1436#if VGA_SLOW_IOACCESS
1437#ifdef VGA_ALT_SEQACCESS
1438    outb(TSIDX, 0x00); outb(TSREG, 0x01);
1439#endif
1440    outb(TSIDX, 0x02); outb(TSREG, 0x04);
1441    outb(TSIDX, 0x04); outb(TSREG, 0x07);
1442#ifdef VGA_ALT_SEQACCESS
1443    outb(TSIDX, 0x00); outb(TSREG, 0x03);
1444#endif
1445    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
1446    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
1447    outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
1448#else /* VGA_SLOW_IOACCESS */
1449#ifdef VGA_ALT_SEQACCESS
1450    outw(TSIDX, 0x0100);
1451#endif
1452    outw(TSIDX, 0x0402);
1453    outw(TSIDX, 0x0704);
1454#ifdef VGA_ALT_SEQACCESS
1455    outw(TSIDX, 0x0300);
1456#endif
1457    outw(GDCIDX, 0x0204);
1458    outw(GDCIDX, 0x0005);
1459    outw(GDCIDX, 0x0406);               /* addr = a0000, 64kb */
1460#endif /* VGA_SLOW_IOACCESS */
1461
1462    splx(s);
1463}
1464
1465static void
1466set_normal_mode(video_adapter_t *adp, u_char *buf)
1467{
1468    int s;
1469
1470    s = splhigh();
1471
1472    /* setup vga for normal operation mode again */
1473    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1474    outb(ATC, 0x10); outb(ATC, buf[5]);
1475    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1476    outb(ATC, 0x20);				/* enable palette */
1477
1478#if VGA_SLOW_IOACCESS
1479#ifdef VGA_ALT_SEQACCESS
1480    outb(TSIDX, 0x00); outb(TSREG, 0x01);
1481#endif
1482    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
1483    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
1484#ifdef VGA_ALT_SEQACCESS
1485    outb(TSIDX, 0x00); outb(TSREG, 0x03);
1486#endif
1487    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
1488    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
1489    if (adp->va_crtc_addr == MONO_CRTC) {
1490	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
1491    } else {
1492	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
1493    }
1494#else /* VGA_SLOW_IOACCESS */
1495#ifdef VGA_ALT_SEQACCESS
1496    outw(TSIDX, 0x0100);
1497#endif
1498    outw(TSIDX, 0x0002 | (buf[0] << 8));
1499    outw(TSIDX, 0x0004 | (buf[1] << 8));
1500#ifdef VGA_ALT_SEQACCESS
1501    outw(TSIDX, 0x0300);
1502#endif
1503    outw(GDCIDX, 0x0004 | (buf[2] << 8));
1504    outw(GDCIDX, 0x0005 | (buf[3] << 8));
1505    if (adp->va_crtc_addr == MONO_CRTC)
1506        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
1507    else
1508        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
1509#endif /* VGA_SLOW_IOACCESS */
1510
1511    splx(s);
1512}
1513
1514#endif /* VGA_NO_FONT_LOADING */
1515
1516/*
1517 * save_font():
1518 * Read the font data in the requested font page from the video adapter.
1519 *
1520 * EGA/VGA
1521 */
1522static int
1523vga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
1524	      int ch, int count)
1525{
1526#ifndef VGA_NO_FONT_LOADING
1527    u_char buf[PARAM_BUFSIZE];
1528    u_int32_t segment;
1529    int c;
1530#ifdef VGA_ALT_SEQACCESS
1531    int s;
1532    u_char val = 0;
1533#endif
1534
1535    prologue(adp, V_ADP_FONT, 1);
1536
1537    if (fontsize < 14) {
1538	/* FONT_8 */
1539	fontsize = 8;
1540    } else if (fontsize >= 32) {
1541	fontsize = 32;
1542    } else if (fontsize >= 16) {
1543	/* FONT_16 */
1544	fontsize = 16;
1545    } else {
1546	/* FONT_14 */
1547	fontsize = 14;
1548    }
1549
1550    if (page < 0 || page >= 8)
1551	return 1;
1552    segment = FONT_BUF + 0x4000*page;
1553    if (page > 3)
1554	segment -= 0xe000;
1555
1556#ifdef VGA_ALT_SEQACCESS
1557    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
1558	s = splhigh();
1559	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1560	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
1561	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1562	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1563	splx(s);
1564    }
1565#endif
1566
1567    set_font_mode(adp, buf);
1568    if (fontsize == 32) {
1569	bcopy_fromio(segment + ch*32, data, fontsize*count);
1570    } else {
1571	for (c = ch; count > 0; ++c, --count) {
1572	    bcopy_fromio(segment + c*32, data, fontsize);
1573	    data += fontsize;
1574	}
1575    }
1576    set_normal_mode(adp, buf);
1577
1578#ifdef VGA_ALT_SEQACCESS
1579    if (adp->va_type == KD_VGA) {
1580	s = splhigh();
1581	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1582	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
1583	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1584	splx(s);
1585    }
1586#endif
1587
1588    return 0;
1589#else /* VGA_NO_FONT_LOADING */
1590    return 1;
1591#endif /* VGA_NO_FONT_LOADING */
1592}
1593
1594/*
1595 * load_font():
1596 * Set the font data in the requested font page.
1597 * NOTE: it appears that some recent video adapters do not support
1598 * the font page other than 0... XXX
1599 *
1600 * EGA/VGA
1601 */
1602static int
1603vga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
1604	      int ch, int count)
1605{
1606#ifndef VGA_NO_FONT_LOADING
1607    u_char buf[PARAM_BUFSIZE];
1608    u_int32_t segment;
1609    int c;
1610#ifdef VGA_ALT_SEQACCESS
1611    int s;
1612    u_char val = 0;
1613#endif
1614
1615    prologue(adp, V_ADP_FONT, 1);
1616
1617    if (fontsize < 14) {
1618	/* FONT_8 */
1619	fontsize = 8;
1620    } else if (fontsize >= 32) {
1621	fontsize = 32;
1622    } else if (fontsize >= 16) {
1623	/* FONT_16 */
1624	fontsize = 16;
1625    } else {
1626	/* FONT_14 */
1627	fontsize = 14;
1628    }
1629
1630    if (page < 0 || page >= 8)
1631	return 1;
1632    segment = FONT_BUF + 0x4000*page;
1633    if (page > 3)
1634	segment -= 0xe000;
1635
1636#ifdef VGA_ALT_SEQACCESS
1637    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
1638	s = splhigh();
1639	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1640	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
1641	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1642	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1643	splx(s);
1644    }
1645#endif
1646
1647    set_font_mode(adp, buf);
1648    if (fontsize == 32) {
1649	bcopy_toio(data, segment + ch*32, fontsize*count);
1650    } else {
1651	for (c = ch; count > 0; ++c, --count) {
1652	    bcopy_toio(data, segment + c*32, fontsize);
1653	    data += fontsize;
1654	}
1655    }
1656    set_normal_mode(adp, buf);
1657
1658#ifdef VGA_ALT_SEQACCESS
1659    if (adp->va_type == KD_VGA) {
1660	s = splhigh();
1661	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1662	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
1663	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1664	splx(s);
1665    }
1666#endif
1667
1668    return 0;
1669#else /* VGA_NO_FONT_LOADING */
1670    return 1;
1671#endif /* VGA_NO_FONT_LOADING */
1672}
1673
1674/*
1675 * show_font():
1676 * Activate the requested font page.
1677 * NOTE: it appears that some recent video adapters do not support
1678 * the font page other than 0... XXX
1679 *
1680 * EGA/VGA
1681 */
1682static int
1683vga_show_font(video_adapter_t *adp, int page)
1684{
1685#ifndef VGA_NO_FONT_LOADING
1686    static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
1687    int s;
1688
1689    prologue(adp, V_ADP_FONT, 1);
1690    if (page < 0 || page >= 8)
1691	return 1;
1692
1693    s = splhigh();
1694    outb(TSIDX, 0x03); outb(TSREG, cg[page]);
1695    splx(s);
1696
1697    return 0;
1698#else /* VGA_NO_FONT_LOADING */
1699    return 1;
1700#endif /* VGA_NO_FONT_LOADING */
1701}
1702
1703/*
1704 * save_palette():
1705 * Read DAC values. The values have expressed in 8 bits.
1706 *
1707 * VGA
1708 */
1709static int
1710vga_save_palette(video_adapter_t *adp, u_char *palette)
1711{
1712    int i;
1713
1714    prologue(adp, V_ADP_PALETTE, 1);
1715
1716    /*
1717     * We store 8 bit values in the palette buffer, while the standard
1718     * VGA has 6 bit DAC .
1719     */
1720    outb(PALRADR, 0x00);
1721    for (i = 0; i < 256*3; ++i)
1722	palette[i] = inb(PALDATA) << 2;
1723    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
1724    return 0;
1725}
1726
1727/*
1728 * load_palette():
1729 * Set DAC values.
1730 *
1731 * VGA
1732 */
1733static int
1734vga_load_palette(video_adapter_t *adp, u_char *palette)
1735{
1736    int i;
1737
1738    prologue(adp, V_ADP_PALETTE, 1);
1739
1740    outb(PIXMASK, 0xff);		/* no pixelmask */
1741    outb(PALWADR, 0x00);
1742    for (i = 0; i < 256*3; ++i)
1743	outb(PALDATA, palette[i] >> 2);
1744    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
1745    outb(ATC, 0x20);			/* enable palette */
1746    return 0;
1747}
1748
1749/*
1750 * set_border():
1751 * Change the border color.
1752 *
1753 * CGA/EGA/VGA
1754 */
1755static int
1756vga_set_border(video_adapter_t *adp, int color)
1757{
1758    prologue(adp, V_ADP_BORDER, 1);
1759
1760    switch (adp->va_type) {
1761    case KD_EGA:
1762    case KD_VGA:
1763	inb(adp->va_crtc_addr + 6);	/* reset flip-flop */
1764	outb(ATC, 0x31); outb(ATC, color & 0xff);
1765	break;
1766    case KD_CGA:
1767	outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */
1768	break;
1769    case KD_MONO:
1770    case KD_HERCULES:
1771    default:
1772	break;
1773    }
1774    return 0;
1775}
1776
1777/*
1778 * save_state():
1779 * Read video register values.
1780 * NOTE: this function only reads the standard EGA/VGA registers.
1781 * any extra/extended registers of SVGA adapters are not saved.
1782 *
1783 * VGA
1784 */
1785static int
1786vga_save_state(video_adapter_t *adp, void *p, size_t size)
1787{
1788    video_info_t info;
1789    u_char *buf;
1790    int crtc_addr;
1791    int i, j;
1792    int s;
1793
1794    if (size == 0) {
1795	/* return the required buffer size */
1796	prologue(adp, V_ADP_STATESAVE, 0);
1797	return sizeof(adp_state_t);
1798    } else {
1799	prologue(adp, V_ADP_STATESAVE, 1);
1800	if (size < sizeof(adp_state_t))
1801	    return 1;
1802    }
1803
1804    ((adp_state_t *)p)->sig = V_STATE_SIG;
1805    buf = ((adp_state_t *)p)->regs;
1806    bzero(buf, V_MODE_PARAM_SIZE);
1807    crtc_addr = adp->va_crtc_addr;
1808
1809    s = splhigh();
1810
1811    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
1812    for (i = 0, j = 5; i < 4; i++) {
1813	outb(TSIDX, i + 1);
1814	buf[j++]  =  inb(TSREG);
1815    }
1816    buf[9]  =  inb(MISC + 10);			/* dot-clock */
1817    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
1818
1819    for (i = 0, j = 10; i < 25; i++) {		/* crtc */
1820	outb(crtc_addr, i);
1821	buf[j++]  =  inb(crtc_addr + 1);
1822    }
1823    for (i = 0, j = 35; i < 20; i++) {		/* attribute ctrl */
1824        inb(crtc_addr + 6);			/* reset flip-flop */
1825	outb(ATC, i);
1826	buf[j++]  =  inb(ATC + 1);
1827    }
1828    for (i = 0, j = 55; i < 9; i++) {		/* graph data ctrl */
1829	outb(GDCIDX, i);
1830	buf[j++]  =  inb(GDCREG);
1831    }
1832    inb(crtc_addr + 6);				/* reset flip-flop */
1833    outb(ATC, 0x20);				/* enable palette */
1834
1835    splx(s);
1836
1837#if 1
1838    if (vga_get_info(adp, adp->va_mode, &info) == 0) {
1839	if (info.vi_flags & V_INFO_GRAPHICS) {
1840	    buf[0] = info.vi_width/info.vi_cwidth; /* COLS */
1841	    buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */
1842	} else {
1843	    buf[0] = info.vi_width;		/* COLS */
1844	    buf[1] = info.vi_height - 1;	/* ROWS */
1845	}
1846	buf[2] = info.vi_cheight;		/* POINTS */
1847    } else {
1848	/* XXX: shouldn't be happening... */
1849	printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
1850	       adp->va_unit, adp->va_name);
1851    }
1852#else
1853    buf[0] = readb(BIOS_PADDRTOVADDR(0x44a));	/* COLS */
1854    buf[1] = readb(BIOS_PADDRTOVADDR(0x484));	/* ROWS */
1855    buf[2] = readb(BIOS_PADDRTOVADDR(0x485));	/* POINTS */
1856    buf[3] = readb(BIOS_PADDRTOVADDR(0x44c));
1857    buf[4] = readb(BIOS_PADDRTOVADDR(0x44d));
1858#endif
1859
1860    return 0;
1861}
1862
1863/*
1864 * load_state():
1865 * Set video registers at once.
1866 * NOTE: this function only updates the standard EGA/VGA registers.
1867 * any extra/extended registers of SVGA adapters are not changed.
1868 *
1869 * EGA/VGA
1870 */
1871static int
1872vga_load_state(video_adapter_t *adp, void *p)
1873{
1874    u_char *buf;
1875    int crtc_addr;
1876    int s;
1877    int i;
1878
1879    prologue(adp, V_ADP_STATELOAD, 1);
1880    if (((adp_state_t *)p)->sig != V_STATE_SIG)
1881	return 1;
1882
1883    buf = ((adp_state_t *)p)->regs;
1884    crtc_addr = adp->va_crtc_addr;
1885
1886    s = splhigh();
1887
1888    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
1889    for (i = 0; i < 4; ++i) {			/* program sequencer */
1890	outb(TSIDX, i + 1);
1891	outb(TSREG, buf[i + 5]);
1892    }
1893    outb(MISC, buf[9]);				/* set dot-clock */
1894    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
1895    outb(crtc_addr, 0x11);
1896    outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F);
1897    for (i = 0; i < 25; ++i) {			/* program crtc */
1898	outb(crtc_addr, i);
1899	outb(crtc_addr + 1, buf[i + 10]);
1900    }
1901    inb(crtc_addr+6);				/* reset flip-flop */
1902    for (i = 0; i < 20; ++i) {			/* program attribute ctrl */
1903	outb(ATC, i);
1904	outb(ATC, buf[i + 35]);
1905    }
1906    for (i = 0; i < 9; ++i) {			/* program graph data ctrl */
1907	outb(GDCIDX, i);
1908	outb(GDCREG, buf[i + 55]);
1909    }
1910    inb(crtc_addr + 6);				/* reset flip-flop */
1911    outb(ATC, 0x20);				/* enable palette */
1912
1913#if notyet /* a temporary workaround for kernel panic, XXX */
1914#ifndef VGA_NO_BIOS
1915    if (adp->va_unit == V_ADP_PRIMARY) {
1916	writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]);	/* COLS */
1917	writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */
1918	writeb(BIOS_PADDRTOVADDR(0x485), buf[2]);	/* POINTS */
1919#if 0
1920	writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]);
1921	writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]);
1922#endif
1923    }
1924#endif /* VGA_NO_BIOS */
1925#endif /* notyet */
1926
1927    splx(s);
1928    return 0;
1929}
1930
1931/*
1932 * set_origin():
1933 * Change the origin (window mapping) of the banked frame buffer.
1934 */
1935static int
1936vga_set_origin(video_adapter_t *adp, off_t offset)
1937{
1938    /*
1939     * The standard video modes do not require window mapping;
1940     * always return error.
1941     */
1942    return 1;
1943}
1944
1945/*
1946 * read_hw_cursor():
1947 * Read the position of the hardware text cursor.
1948 *
1949 * all adapters
1950 */
1951static int
1952vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
1953{
1954    u_int16_t off;
1955    int s;
1956
1957    if (!init_done)
1958	return 1;
1959
1960    if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
1961	return 1;
1962
1963    s = spltty();
1964    outb(adp->va_crtc_addr, 14);
1965    off = inb(adp->va_crtc_addr + 1);
1966    outb(adp->va_crtc_addr, 15);
1967    off = (off << 8) | inb(adp->va_crtc_addr + 1);
1968    splx(s);
1969
1970    *row = off / adp->va_info.vi_width;
1971    *col = off % adp->va_info.vi_width;
1972
1973    return 0;
1974}
1975
1976/*
1977 * set_hw_cursor():
1978 * Move the hardware text cursor.  If col and row are both -1,
1979 * the cursor won't be shown.
1980 *
1981 * all adapters
1982 */
1983static int
1984vga_set_hw_cursor(video_adapter_t *adp, int col, int row)
1985{
1986    u_int16_t off;
1987    int s;
1988
1989    if (!init_done)
1990	return 1;
1991
1992    if ((col == -1) && (row == -1)) {
1993	off = -1;
1994    } else {
1995	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
1996	    return 1;
1997	off = row*adp->va_info.vi_width + col;
1998    }
1999
2000    s = spltty();
2001    outb(adp->va_crtc_addr, 14);
2002    outb(adp->va_crtc_addr + 1, off >> 8);
2003    outb(adp->va_crtc_addr, 15);
2004    outb(adp->va_crtc_addr + 1, off & 0x00ff);
2005    splx(s);
2006
2007    return 0;
2008}
2009
2010/*
2011 * set_hw_cursor_shape():
2012 * Change the shape of the hardware text cursor. If the height is
2013 * zero or negative, the cursor won't be shown.
2014 *
2015 * all adapters
2016 */
2017static int
2018vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
2019			int celsize, int blink)
2020{
2021    int s;
2022
2023    if (!init_done)
2024	return 1;
2025
2026    s = spltty();
2027    switch (adp->va_type) {
2028    case KD_VGA:
2029    case KD_CGA:
2030    case KD_MONO:
2031    case KD_HERCULES:
2032    default:
2033	if (height <= 0) {
2034	    /* make the cursor invisible */
2035	    outb(adp->va_crtc_addr, 10);
2036	    outb(adp->va_crtc_addr + 1, 32);
2037	    outb(adp->va_crtc_addr, 11);
2038	    outb(adp->va_crtc_addr + 1, 0);
2039	} else {
2040	    outb(adp->va_crtc_addr, 10);
2041	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2042	    outb(adp->va_crtc_addr, 11);
2043	    outb(adp->va_crtc_addr + 1, celsize - base - 1);
2044	}
2045	break;
2046    case KD_EGA:
2047	if (height <= 0) {
2048	    /* make the cursor invisible */
2049	    outb(adp->va_crtc_addr, 10);
2050	    outb(adp->va_crtc_addr + 1, celsize);
2051	    outb(adp->va_crtc_addr, 11);
2052	    outb(adp->va_crtc_addr + 1, 0);
2053	} else {
2054	    outb(adp->va_crtc_addr, 10);
2055	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2056	    outb(adp->va_crtc_addr, 11);
2057	    outb(adp->va_crtc_addr + 1, celsize - base);
2058	}
2059	break;
2060    }
2061    splx(s);
2062
2063    return 0;
2064}
2065
2066/*
2067 * mmap():
2068 * Mmap frame buffer.
2069 *
2070 * all adapters
2071 */
2072static int
2073vga_mmap(video_adapter_t *adp, vm_offset_t offset)
2074{
2075    if (offset > 0x20000 - PAGE_SIZE)
2076	return -1;
2077#ifdef __i386__
2078    return i386_btop((VIDEO_BUF_BASE + offset));
2079#endif
2080#ifdef __alpha__
2081    return alpha_btop((VIDEO_BUF_BASE + offset));
2082#endif
2083}
2084
2085static void
2086dump_buffer(u_char *buf, size_t len)
2087{
2088    int i;
2089
2090    for(i = 0; i < len;) {
2091	printf("%02x ", buf[i]);
2092	if ((++i % 16) == 0)
2093	    printf("\n");
2094    }
2095}
2096
2097/*
2098 * diag():
2099 * Print some information about the video adapter and video modes,
2100 * with requested level of details.
2101 *
2102 * all adapters
2103 */
2104static int
2105vga_diag(video_adapter_t *adp, int level)
2106{
2107#if FB_DEBUG > 1
2108    video_info_t info;
2109#endif
2110    u_char *mp;
2111
2112    if (!init_done)
2113	return 1;
2114
2115#if FB_DEBUG > 1
2116#ifndef VGA_NO_BIOS
2117    printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n",
2118	   rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488)));
2119    printf("vga: CRTC:0x%x, video option:0x%02x, ",
2120	   readw(BIOS_PADDRTOVADDR(0x463)),
2121	   readb(BIOS_PADDRTOVADDR(0x487)));
2122    printf("rows:%d, cols:%d, font height:%d\n",
2123	   readb(BIOS_PADDRTOVADDR(0x44a)),
2124	   readb(BIOS_PADDRTOVADDR(0x484)) + 1,
2125	   readb(BIOS_PADDRTOVADDR(0x485)));
2126#endif /* VGA_NO_BIOS */
2127#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
2128    printf("vga: param table EGA/VGA:%p", video_mode_ptr);
2129    printf(", CGA/MDA:%p\n", video_mode_ptr2);
2130#endif
2131    printf("vga: rows_offset:%d\n", rows_offset);
2132#endif /* FB_DEBUG > 1 */
2133
2134    fb_dump_adp_info(DRIVER_NAME, adp, level);
2135
2136#if FB_DEBUG > 1
2137    if (adp->va_flags & V_ADP_MODECHANGE) {
2138	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
2139	    if (bios_vmode[i].vi_mode == NA)
2140		continue;
2141	    if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
2142		continue;
2143	    fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
2144	}
2145    } else {
2146	vga_get_info(adp, adp->va_initial_mode, &info);	/* shouldn't fail */
2147	fb_dump_mode_info(DRIVER_NAME, adp, &info, level);
2148    }
2149#endif /* FB_DEBUG > 1 */
2150
2151    if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA))
2152	return 0;
2153#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
2154    if (video_mode_ptr == NULL)
2155	printf("vga%d: %s: WARNING: video mode switching is not "
2156	       "fully supported on this adapter\n",
2157	       adp->va_unit, adp->va_name);
2158#endif
2159    if (level <= 0)
2160	return 0;
2161
2162    if (adp->va_type == KD_VGA) {
2163	printf("VGA parameters upon power-up\n");
2164	dump_buffer(adpstate.regs, sizeof(adpstate.regs));
2165	printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode);
2166	dump_buffer(adpstate2.regs, sizeof(adpstate2.regs));
2167    }
2168
2169    mp = get_mode_param(adp->va_initial_mode);
2170    if (mp == NULL)	/* this shouldn't be happening */
2171	return 0;
2172    printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode);
2173    dump_buffer(mp, V_MODE_PARAM_SIZE);
2174
2175    return 0;
2176}
2177
2178#endif /* NVGA > 0 */
2179