vga.c revision 130585
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 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/fb/vga.c 130585 2004-06-16 09:47:26Z phk $");
33
34#include "opt_vga.h"
35#include "opt_fb.h"
36#include "opt_syscons.h"	/* should be removed in the future, XXX */
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/conf.h>
42#include <sys/fcntl.h>
43#include <sys/malloc.h>
44#include <sys/fbio.h>
45
46#include <vm/vm.h>
47#include <vm/vm_param.h>
48#include <vm/pmap.h>
49
50#include <machine/md_var.h>
51#ifdef __i386__
52#include <machine/pc/bios.h>
53#endif
54#include <machine/bus.h>
55
56#include <dev/fb/fbreg.h>
57#include <dev/fb/vgareg.h>
58
59#include <isa/isareg.h>
60
61#ifndef VGA_DEBUG
62#define VGA_DEBUG		0
63#endif
64
65/* XXX machine/pc/bios.h has got too much i386-specific stuff in it */
66#ifndef BIOS_PADDRTOVADDR
67#if !defined(__amd64__)
68#define	BIOS_PADDRTOVADDR(x)	(x)
69#else
70#define BIOS_PADDRTOVADDR(x)	((x) + KERNBASE)
71#endif
72#endif
73
74int
75vga_probe_unit(int unit, video_adapter_t *buf, int flags)
76{
77	video_adapter_t *adp;
78	video_switch_t *sw;
79	int error;
80
81	sw = vid_get_switch(VGA_DRIVER_NAME);
82	if (sw == NULL)
83		return 0;
84	error = (*sw->probe)(unit, &adp, NULL, flags);
85	if (error)
86		return error;
87	bcopy(adp, buf, sizeof(*buf));
88	return 0;
89}
90
91int
92vga_attach_unit(int unit, vga_softc_t *sc, int flags)
93{
94	video_switch_t *sw;
95	int error;
96
97	sw = vid_get_switch(VGA_DRIVER_NAME);
98	if (sw == NULL)
99		return ENXIO;
100
101	error = (*sw->probe)(unit, &sc->adp, NULL, flags);
102	if (error)
103		return error;
104	return (*sw->init)(unit, sc->adp, flags);
105}
106
107/* cdev driver functions */
108
109#ifdef FB_INSTALL_CDEV
110
111int
112vga_open(struct cdev *dev, vga_softc_t *sc, int flag, int mode, struct thread *td)
113{
114	if (sc == NULL)
115		return ENXIO;
116	if (mode & (O_CREAT | O_APPEND | O_TRUNC))
117		return ENODEV;
118
119	return genfbopen(&sc->gensc, sc->adp, flag, mode, td);
120}
121
122int
123vga_close(struct cdev *dev, vga_softc_t *sc, int flag, int mode, struct thread *td)
124{
125	return genfbclose(&sc->gensc, sc->adp, flag, mode, td);
126}
127
128int
129vga_read(struct cdev *dev, vga_softc_t *sc, struct uio *uio, int flag)
130{
131	return genfbread(&sc->gensc, sc->adp, uio, flag);
132}
133
134int
135vga_write(struct cdev *dev, vga_softc_t *sc, struct uio *uio, int flag)
136{
137	return genfbread(&sc->gensc, sc->adp, uio, flag);
138}
139
140int
141vga_ioctl(struct cdev *dev, vga_softc_t *sc, u_long cmd, caddr_t arg, int flag,
142	  struct thread *td)
143{
144	return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td);
145}
146
147int
148vga_mmap(struct cdev *dev, vga_softc_t *sc, vm_offset_t offset, vm_offset_t *paddr,
149	 int prot)
150{
151	return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot);
152}
153
154#endif /* FB_INSTALL_CDEV */
155
156/* LOW-LEVEL */
157
158#include <machine/clock.h>
159#ifdef __i386__
160#include <machine/pc/vesa.h>
161#endif
162
163#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
164#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
165#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
166
167/* for compatibility with old kernel options */
168#ifdef SC_ALT_SEQACCESS
169#undef SC_ALT_SEQACCESS
170#undef VGA_ALT_SEQACCESS
171#define VGA_ALT_SEQACCESS	1
172#endif
173
174#ifdef SLOW_VGA
175#undef SLOW_VGA
176#undef VGA_SLOW_IOACCESS
177#define VGA_SLOW_IOACCESS	1
178#endif
179
180/* architecture dependent option */
181#ifndef __i386__
182#define VGA_NO_BIOS		1
183#endif
184
185/* this should really be in `rtc.h' */
186#define RTC_EQUIPMENT           0x14
187
188/* various sizes */
189#define V_MODE_MAP_SIZE		(M_VGA_CG320 + 1)
190#define V_MODE_PARAM_SIZE	64
191
192/* video adapter state buffer */
193struct adp_state {
194    int			sig;
195#define V_STATE_SIG	0x736f6962
196    u_char		regs[V_MODE_PARAM_SIZE];
197};
198typedef struct adp_state adp_state_t;
199
200/* video adapter information */
201#define DCC_MONO	0
202#define DCC_CGA40	1
203#define DCC_CGA80	2
204#define DCC_EGAMONO	3
205#define DCC_EGA40	4
206#define DCC_EGA80	5
207
208/*
209 * NOTE: `va_window' should have a virtual address, but is initialized
210 * with a physical address in the following table, as verify_adapter()
211 * will perform address conversion at run-time.
212 */
213static video_adapter_t adapter_init_value[] = {
214    /* DCC_MONO */
215    { 0, KD_MONO, "mda", 0, 0, 0, 	    IO_MDA, IO_MDASIZE, MONO_CRTC,
216      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
217      0, 0, 0, 0, 7, 0, },
218    /* DCC_CGA40 */
219    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
220      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
221      0, 0, 0, 0, 3, 0, },
222    /* DCC_CGA80 */
223    { 0, KD_CGA,  "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC,
224      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
225      0, 0, 0, 0, 3, 0, },
226    /* DCC_EGAMONO */
227    { 0, KD_EGA,  "ega", 0, 0, 0,	    IO_MDA, 48,	  MONO_CRTC,
228      EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE,
229      0, 0, 0, 0, 7, 0, },
230    /* DCC_EGA40 */
231    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
232      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
233      0, 0, 0, 0, 3, 0, },
234    /* DCC_EGA80 */
235    { 0, KD_EGA,  "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48,	  COLOR_CRTC,
236      EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE,
237      0, 0, 0, 0, 3, 0, },
238};
239
240static video_adapter_t	biosadapter[2];
241static int		biosadapters = 0;
242
243/* video driver declarations */
244static int			vga_configure(int flags);
245       int			(*vga_sub_configure)(int flags);
246#if 0
247static int			vga_nop(void);
248#endif
249static int			vga_error(void);
250static vi_probe_t		vga_probe;
251static vi_init_t		vga_init;
252static vi_get_info_t		vga_get_info;
253static vi_query_mode_t		vga_query_mode;
254static vi_set_mode_t		vga_set_mode;
255static vi_save_font_t		vga_save_font;
256static vi_load_font_t		vga_load_font;
257static vi_show_font_t		vga_show_font;
258static vi_save_palette_t	vga_save_palette;
259static vi_load_palette_t	vga_load_palette;
260static vi_set_border_t		vga_set_border;
261static vi_save_state_t		vga_save_state;
262static vi_load_state_t		vga_load_state;
263static vi_set_win_org_t		vga_set_origin;
264static vi_read_hw_cursor_t	vga_read_hw_cursor;
265static vi_set_hw_cursor_t	vga_set_hw_cursor;
266static vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
267static vi_blank_display_t	vga_blank_display;
268static vi_mmap_t		vga_mmap_buf;
269static vi_ioctl_t		vga_dev_ioctl;
270#ifndef VGA_NO_MODE_CHANGE
271static vi_clear_t		vga_clear;
272static vi_fill_rect_t		vga_fill_rect;
273static vi_bitblt_t		vga_bitblt;
274#else /* VGA_NO_MODE_CHANGE */
275#define vga_clear		(vi_clear_t *)vga_error
276#define vga_fill_rect		(vi_fill_rect_t *)vga_error
277#define vga_bitblt		(vi_bitblt_t *)vga_error
278#endif
279static vi_diag_t		vga_diag;
280
281static video_switch_t vgavidsw = {
282	vga_probe,
283	vga_init,
284	vga_get_info,
285	vga_query_mode,
286	vga_set_mode,
287	vga_save_font,
288	vga_load_font,
289	vga_show_font,
290	vga_save_palette,
291	vga_load_palette,
292	vga_set_border,
293	vga_save_state,
294	vga_load_state,
295	vga_set_origin,
296	vga_read_hw_cursor,
297	vga_set_hw_cursor,
298	vga_set_hw_cursor_shape,
299	vga_blank_display,
300	vga_mmap_buf,
301	vga_dev_ioctl,
302	vga_clear,
303	vga_fill_rect,
304	vga_bitblt,
305	vga_error,
306	vga_error,
307	vga_diag,
308};
309
310VIDEO_DRIVER(mda, vgavidsw, NULL);
311VIDEO_DRIVER(cga, vgavidsw, NULL);
312VIDEO_DRIVER(ega, vgavidsw, NULL);
313VIDEO_DRIVER(vga, vgavidsw, vga_configure);
314
315/* VGA BIOS standard video modes */
316#define EOT		(-1)
317#define NA		(-2)
318
319static video_info_t bios_vmode[] = {
320    /* CGA */
321    { M_B40x25,     V_INFO_COLOR, 40, 25, 8,  8, 2, 1,
322      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
323    { M_C40x25,     V_INFO_COLOR, 40, 25, 8,  8, 4, 1,
324      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
325    { M_B80x25,     V_INFO_COLOR, 80, 25, 8,  8, 2, 1,
326      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
327    { M_C80x25,     V_INFO_COLOR, 80, 25, 8,  8, 4, 1,
328      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
329    /* EGA */
330    { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1,
331      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
332    { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1,
333      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
334    { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1,
335      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
336    { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1,
337      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
338    /* VGA */
339    { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1,
340      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
341    { M_VGA_M80x25, 0,            80, 25, 8, 16, 2, 1,
342      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
343    { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
344      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
345    /* MDA */
346    { M_EGAMONO80x25, 0,          80, 25, 8, 14, 2, 1,
347      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
348    /* EGA */
349    { M_ENH_B80x43, 0,            80, 43, 8,  8, 2, 1,
350      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
351    { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8,  8, 4, 1,
352      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
353    /* VGA */
354    { M_VGA_M80x30, 0,            80, 30, 8, 16, 2, 1,
355      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
356    { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
357      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
358    { M_VGA_M80x50, 0,            80, 50, 8,  8, 2, 1,
359      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
360    { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8,  8, 4, 1,
361      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
362    { M_VGA_M80x60, 0,            80, 60, 8,  8, 2, 1,
363      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
364    { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8,  8, 4, 1,
365      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
366
367#ifndef VGA_NO_MODE_CHANGE
368
369#ifdef VGA_WIDTH90
370    { M_VGA_M90x25, 0,            90, 25, 8, 16, 2, 1,
371      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
372    { M_VGA_C90x25, V_INFO_COLOR, 90, 25, 8, 16, 4, 1,
373      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
374    { M_VGA_M90x30, 0,            90, 30, 8, 16, 2, 1,
375      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
376    { M_VGA_C90x30, V_INFO_COLOR, 90, 30, 8, 16, 4, 1,
377      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
378    { M_VGA_M90x43, 0,            90, 43, 8,  8, 2, 1,
379      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
380    { M_VGA_C90x43, V_INFO_COLOR, 90, 43, 8,  8, 4, 1,
381      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
382    { M_VGA_M90x50, 0,            90, 50, 8,  8, 2, 1,
383      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
384    { M_VGA_C90x50, V_INFO_COLOR, 90, 50, 8,  8, 4, 1,
385      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
386    { M_VGA_M90x60, 0,            90, 60, 8,  8, 2, 1,
387      MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
388    { M_VGA_C90x60, V_INFO_COLOR, 90, 60, 8,  8, 4, 1,
389      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
390#endif /* VGA_WIDTH90 */
391
392    /* CGA */
393    { M_BG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
394      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_CGA },
395    { M_CG320,      V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 2, 1,
396      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_CGA },
397    { M_BG640,      V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 1, 1,
398      CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0, V_INFO_MM_CGA },
399    /* EGA */
400    { M_CG320_D,    V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 4, 4,
401      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
402      V_INFO_MM_PLANAR },
403    { M_CG640_E,    V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8,  8, 4, 4,
404      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
405      V_INFO_MM_PLANAR },
406    { M_EGAMONOAPA, V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
407      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 ,
408      V_INFO_MM_PLANAR },
409    { M_ENHMONOAPA2,V_INFO_GRAPHICS,                640, 350, 8, 14, 4, 4,
410      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
411      V_INFO_MM_PLANAR },
412    { M_CG640x350,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2,
413      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
414      V_INFO_MM_PLANAR },
415    { M_ENH_CG640,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4,
416      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
417      V_INFO_MM_PLANAR },
418    /* VGA */
419    { M_BG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
420      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
421      V_INFO_MM_PLANAR },
422    { M_CG640x480,  V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4,
423      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 ,
424      V_INFO_MM_PLANAR },
425    { M_VGA_CG320,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8,  8, 8, 1,
426      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
427      V_INFO_MM_PACKED, 1 },
428    { M_VGA_MODEX,  V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8,  8, 8, 4,
429      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
430      V_INFO_MM_VGAX, 1 },
431#endif /* VGA_NO_MODE_CHANGE */
432
433    { EOT },
434};
435
436static int		vga_init_done = FALSE;
437#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
438static u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
439static u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
440#endif
441static u_char		*mode_map[V_MODE_MAP_SIZE];
442static adp_state_t	adpstate;
443static adp_state_t	adpstate2;
444static int		rows_offset = 1;
445
446/* local macros and functions */
447#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
448
449#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
450static void map_mode_table(u_char *map[], u_char *table, int max);
451#endif
452static void clear_mode_map(video_adapter_t *adp, u_char *map[], int max,
453			   int color);
454#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
455static int map_mode_num(int mode);
456#endif
457static int map_gen_mode_num(int type, int color, int mode);
458static int map_bios_mode_num(int type, int color, int bios_mode);
459static u_char *get_mode_param(int mode);
460#ifndef VGA_NO_BIOS
461static void fill_adapter_param(int code, video_adapter_t *adp);
462#endif
463static int verify_adapter(video_adapter_t *adp);
464static void update_adapter_info(video_adapter_t *adp, video_info_t *info);
465#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
466#define COMP_IDENTICAL	0
467#define COMP_SIMILAR	1
468#define COMP_DIFFERENT	2
469static int comp_adpregs(u_char *buf1, u_char *buf2);
470#endif
471static int probe_adapters(void);
472static int set_line_length(video_adapter_t *adp, int pixel);
473static int set_display_start(video_adapter_t *adp, int x, int y);
474static void filll_io(int val, vm_offset_t d, size_t size);
475
476#ifndef VGA_NO_MODE_CHANGE
477#ifdef VGA_WIDTH90
478static void set_width90(adp_state_t *params);
479#endif
480#endif /* !VGA_NO_MODE_CHANGE */
481
482#ifndef VGA_NO_FONT_LOADING
483#define PARAM_BUFSIZE	6
484static void set_font_mode(video_adapter_t *adp, u_char *buf);
485static void set_normal_mode(video_adapter_t *adp, u_char *buf);
486#endif
487
488#ifndef VGA_NO_MODE_CHANGE
489static void planar_fill(video_adapter_t *adp, int val);
490static void packed_fill(video_adapter_t *adp, int val);
491static void direct_fill(video_adapter_t *adp, int val);
492#ifdef notyet
493static void planar_fill_rect(video_adapter_t *adp, int val, int x, int y,
494			     int cx, int cy);
495static void packed_fill_rect(video_adapter_t *adp, int val, int x, int y,
496			     int cx, int cy);
497static void direct_fill_rect16(video_adapter_t *adp, int val, int x, int y,
498			       int cx, int cy);
499static void direct_fill_rect24(video_adapter_t *adp, int val, int x, int y,
500			       int cx, int cy);
501static void direct_fill_rect32(video_adapter_t *adp, int val, int x, int y,
502			       int cx, int cy);
503#endif /* notyet */
504#endif /* !VGA_NO_MODE_CHANGE */
505
506static void dump_buffer(u_char *buf, size_t len);
507
508#define	ISMAPPED(pa, width)				\
509	(((pa) <= (u_long)0x1000 - (width)) 		\
510	 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
511
512#define	prologue(adp, flag, err)			\
513	if (!vga_init_done || !((adp)->va_flags & (flag)))	\
514	    return (err)
515
516/* a backdoor for the console driver */
517static int
518vga_configure(int flags)
519{
520    int i;
521
522    probe_adapters();
523    for (i = 0; i < biosadapters; ++i) {
524	if (!probe_done(&biosadapter[i]))
525	    continue;
526	biosadapter[i].va_flags |= V_ADP_INITIALIZED;
527	if (!config_done(&biosadapter[i])) {
528	    if (vid_register(&biosadapter[i]) < 0)
529		continue;
530	    biosadapter[i].va_flags |= V_ADP_REGISTERED;
531	}
532    }
533    if (vga_sub_configure != NULL)
534	(*vga_sub_configure)(flags);
535
536    return biosadapters;
537}
538
539/* local subroutines */
540
541#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
542/* construct the mode parameter map */
543static void
544map_mode_table(u_char *map[], u_char *table, int max)
545{
546    int i;
547
548    for(i = 0; i < max; ++i)
549	map[i] = table + i*V_MODE_PARAM_SIZE;
550    for(; i < V_MODE_MAP_SIZE; ++i)
551	map[i] = NULL;
552}
553#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
554
555static void
556clear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color)
557{
558    video_info_t info;
559    int i;
560
561    /*
562     * NOTE: we don't touch `bios_vmode[]' because it is shared
563     * by all adapters.
564     */
565    for(i = 0; i < max; ++i) {
566	if (vga_get_info(adp, i, &info))
567	    continue;
568	if ((info.vi_flags & V_INFO_COLOR) != color)
569	    map[i] = NULL;
570    }
571}
572
573#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
574/* map the non-standard video mode to a known mode number */
575static int
576map_mode_num(int mode)
577{
578    static struct {
579        int from;
580        int to;
581    } mode_map[] = {
582        { M_ENH_B80x43, M_ENH_B80x25 },
583        { M_ENH_C80x43, M_ENH_C80x25 },
584        { M_VGA_M80x30, M_VGA_M80x25 },
585        { M_VGA_C80x30, M_VGA_C80x25 },
586        { M_VGA_M80x50, M_VGA_M80x25 },
587        { M_VGA_C80x50, M_VGA_C80x25 },
588        { M_VGA_M80x60, M_VGA_M80x25 },
589        { M_VGA_C80x60, M_VGA_C80x25 },
590#ifdef VGA_WIDTH90
591        { M_VGA_M90x25, M_VGA_M80x25 },
592        { M_VGA_C90x25, M_VGA_C80x25 },
593        { M_VGA_M90x30, M_VGA_M80x25 },
594        { M_VGA_C90x30, M_VGA_C80x25 },
595        { M_VGA_M90x43, M_ENH_B80x25 },
596        { M_VGA_C90x43, M_ENH_C80x25 },
597        { M_VGA_M90x50, M_VGA_M80x25 },
598        { M_VGA_C90x50, M_VGA_C80x25 },
599        { M_VGA_M90x60, M_VGA_M80x25 },
600        { M_VGA_C90x60, M_VGA_C80x25 },
601#endif
602        { M_VGA_MODEX,  M_VGA_CG320 },
603    };
604    int i;
605
606    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
607        if (mode_map[i].from == mode)
608            return mode_map[i].to;
609    }
610    return mode;
611}
612#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
613
614/* map a generic video mode to a known mode number */
615static int
616map_gen_mode_num(int type, int color, int mode)
617{
618    static struct {
619	int from;
620	int to_color;
621	int to_mono;
622    } mode_map[] = {
623	{ M_TEXT_80x30,	M_VGA_C80x30, M_VGA_M80x30, },
624	{ M_TEXT_80x43,	M_ENH_C80x43, M_ENH_B80x43, },
625	{ M_TEXT_80x50,	M_VGA_C80x50, M_VGA_M80x50, },
626	{ M_TEXT_80x60,	M_VGA_C80x60, M_VGA_M80x60, },
627    };
628    int i;
629
630    if (mode == M_TEXT_80x25) {
631	switch (type) {
632
633	case KD_VGA:
634	    if (color)
635		return M_VGA_C80x25;
636	    else
637		return M_VGA_M80x25;
638	    break;
639
640	case KD_EGA:
641	    if (color)
642		return M_ENH_C80x25;
643	    else
644		return M_EGAMONO80x25;
645	    break;
646
647	case KD_CGA:
648	    return M_C80x25;
649
650	case KD_MONO:
651	case KD_HERCULES:
652	    return M_EGAMONO80x25;	/* XXX: this name is confusing */
653
654 	default:
655	    return -1;
656	}
657    }
658
659    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
660        if (mode_map[i].from == mode)
661            return ((color) ? mode_map[i].to_color : mode_map[i].to_mono);
662    }
663    return mode;
664}
665
666/* turn the BIOS video number into our video mode number */
667static int
668map_bios_mode_num(int type, int color, int bios_mode)
669{
670    static int cga_modes[7] = {
671	M_B40x25, M_C40x25,		/* 0, 1 */
672	M_B80x25, M_C80x25,		/* 2, 3 */
673	M_BG320, M_CG320,
674	M_BG640,
675    };
676    static int ega_modes[17] = {
677	M_ENH_B40x25, M_ENH_C40x25,	/* 0, 1 */
678	M_ENH_B80x25, M_ENH_C80x25,	/* 2, 3 */
679	M_BG320, M_CG320,
680	M_BG640,
681	M_EGAMONO80x25,			/* 7 */
682	8, 9, 10, 11, 12,
683	M_CG320_D,
684	M_CG640_E,
685	M_ENHMONOAPA2,			/* XXX: video momery > 64K */
686	M_ENH_CG640,			/* XXX: video momery > 64K */
687    };
688    static int vga_modes[20] = {
689	M_VGA_C40x25, M_VGA_C40x25,	/* 0, 1 */
690	M_VGA_C80x25, M_VGA_C80x25,	/* 2, 3 */
691	M_BG320, M_CG320,
692	M_BG640,
693	M_VGA_M80x25,			/* 7 */
694	8, 9, 10, 11, 12,
695	M_CG320_D,
696	M_CG640_E,
697	M_ENHMONOAPA2,
698	M_ENH_CG640,
699	M_BG640x480, M_CG640x480,
700	M_VGA_CG320,
701    };
702
703    switch (type) {
704
705    case KD_VGA:
706	if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0]))
707	    return vga_modes[bios_mode];
708	else if (color)
709	    return M_VGA_C80x25;
710	else
711	    return M_VGA_M80x25;
712	break;
713
714    case KD_EGA:
715	if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0]))
716	    return ega_modes[bios_mode];
717	else if (color)
718	    return M_ENH_C80x25;
719	else
720	    return M_EGAMONO80x25;
721	break;
722
723    case KD_CGA:
724	if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0]))
725	    return cga_modes[bios_mode];
726	else
727	    return M_C80x25;
728	break;
729
730    case KD_MONO:
731    case KD_HERCULES:
732	return M_EGAMONO80x25;		/* XXX: this name is confusing */
733
734    default:
735	break;
736    }
737    return -1;
738}
739
740/* look up a parameter table entry */
741static u_char
742*get_mode_param(int mode)
743{
744#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
745    if (mode >= V_MODE_MAP_SIZE)
746	mode = map_mode_num(mode);
747#endif
748    if ((mode >= 0) && (mode < V_MODE_MAP_SIZE))
749	return mode_map[mode];
750    else
751	return NULL;
752}
753
754#ifndef VGA_NO_BIOS
755static void
756fill_adapter_param(int code, video_adapter_t *adp)
757{
758    static struct {
759	int primary;
760	int secondary;
761    } dcc[] = {
762	{ DCC_MONO, 			DCC_EGA40 /* CGA monitor */ },
763	{ DCC_MONO, 			DCC_EGA80 /* CGA monitor */ },
764	{ DCC_MONO, 			DCC_EGA80 },
765	{ DCC_MONO, 			DCC_EGA80 },
766	{ DCC_CGA40, 			DCC_EGAMONO },
767	{ DCC_CGA80, 			DCC_EGAMONO },
768	{ DCC_EGA40 /* CGA monitor */, 	DCC_MONO},
769	{ DCC_EGA80 /* CGA monitor */, 	DCC_MONO},
770	{ DCC_EGA80,			DCC_MONO },
771	{ DCC_EGA80, 			DCC_MONO },
772	{ DCC_EGAMONO, 			DCC_CGA40 },
773	{ DCC_EGAMONO, 			DCC_CGA80 },
774    };
775
776    if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) {
777	adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
778	adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
779    } else {
780	adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary];
781	adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary];
782    }
783}
784#endif /* VGA_NO_BIOS */
785
786static int
787verify_adapter(video_adapter_t *adp)
788{
789    vm_offset_t buf;
790    u_int16_t v;
791#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
792    u_int32_t p;
793#endif
794
795    buf = BIOS_PADDRTOVADDR(adp->va_window);
796    v = readw(buf);
797    writew(buf, 0xA55A);
798    if (readw(buf) != 0xA55A)
799	return ENXIO;
800    writew(buf, v);
801
802    switch (adp->va_type) {
803
804    case KD_EGA:
805	outb(adp->va_crtc_addr, 7);
806	if (inb(adp->va_crtc_addr) == 7) {
807	    adp->va_type = KD_VGA;
808	    adp->va_name = "vga";
809	    adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE;
810	}
811	adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER;
812	/* the color adapter may be in the 40x25 mode... XXX */
813
814#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
815	/* get the BIOS video mode pointer */
816	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8);
817	p = BIOS_SADDRTOLADDR(p);
818	if (ISMAPPED(p, sizeof(u_int32_t))) {
819	    p = *(u_int32_t *)BIOS_PADDRTOVADDR(p);
820	    p = BIOS_SADDRTOLADDR(p);
821	    if (ISMAPPED(p, V_MODE_PARAM_SIZE))
822		video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p);
823	}
824#endif
825	break;
826
827    case KD_CGA:
828	adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER;
829	/* may be in the 40x25 mode... XXX */
830#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
831	/* get the BIOS video mode pointer */
832	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
833	p = BIOS_SADDRTOLADDR(p);
834	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
835#endif
836	break;
837
838    case KD_MONO:
839#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
840	/* get the BIOS video mode pointer */
841	p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4);
842	p = BIOS_SADDRTOLADDR(p);
843	video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p);
844#endif
845	break;
846    }
847
848    return 0;
849}
850
851static void
852update_adapter_info(video_adapter_t *adp, video_info_t *info)
853{
854    adp->va_flags &= ~V_ADP_COLOR;
855    adp->va_flags |=
856	(info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
857    adp->va_crtc_addr =
858	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
859    adp->va_window = BIOS_PADDRTOVADDR(info->vi_window);
860    adp->va_window_size = info->vi_window_size;
861    adp->va_window_gran = info->vi_window_gran;
862    adp->va_window_orig = 0;
863    /* XXX */
864    adp->va_buffer = info->vi_buffer;
865    adp->va_buffer_size = info->vi_buffer_size;
866    if (info->vi_mem_model == V_INFO_MM_VGAX) {
867	adp->va_line_width = info->vi_width/2;
868    } else if (info->vi_flags & V_INFO_GRAPHICS) {
869	switch (info->vi_depth/info->vi_planes) {
870	case 1:
871	    adp->va_line_width = info->vi_width/8;
872	    break;
873	case 2:
874	    adp->va_line_width = info->vi_width/4;
875	    break;
876	case 4:
877	    adp->va_line_width = info->vi_width/2;
878	    break;
879	case 8:
880	default: /* shouldn't happen */
881	    adp->va_line_width = info->vi_width;
882	    break;
883	}
884    } else {
885	adp->va_line_width = info->vi_width;
886    }
887    adp->va_disp_start.x = 0;
888    adp->va_disp_start.y = 0;
889    bcopy(info, &adp->va_info, sizeof(adp->va_info));
890}
891
892#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
893/* compare two parameter table entries */
894static int
895comp_adpregs(u_char *buf1, u_char *buf2)
896{
897    static struct {
898        u_char mask;
899    } params[V_MODE_PARAM_SIZE] = {
900	{0xff}, {0x00}, {0xff}, 		/* COLS}, ROWS}, POINTS */
901	{0x00}, {0x00}, 			/* page length */
902	{0xfe}, {0xff}, {0xff}, {0xff},		/* sequencer registers */
903	{0xf3},					/* misc register */
904	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},	/* CRTC */
905	{0xff}, {0xff}, {0xff}, {0x7f}, {0xff},
906	{0x00}, {0x00}, {0x00}, {0x00}, {0x00},
907	{0x00}, {0xff}, {0x7f}, {0xff}, {0xff},
908	{0x7f}, {0xff}, {0xff}, {0xef}, {0xff},
909	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* attribute controller regs */
910	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
911	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},
912	{0xff}, {0xff}, {0xff}, {0xff}, {0xf0},
913	{0xff}, {0xff}, {0xff}, {0xff}, {0xff},	/* GDC register */
914	{0xff}, {0xff}, {0xff}, {0xff},
915    };
916    int identical = TRUE;
917    int i;
918
919    if ((buf1 == NULL) || (buf2 == NULL))
920	return COMP_DIFFERENT;
921
922    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
923	if (params[i].mask == 0)	/* don't care */
924	    continue;
925	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
926	    return COMP_DIFFERENT;
927	if (buf1[i] != buf2[i])
928	    identical = FALSE;
929    }
930    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
931}
932#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */
933
934/* probe video adapters and return the number of detected adapters */
935static int
936probe_adapters(void)
937{
938    video_adapter_t *adp;
939    video_info_t info;
940#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
941    u_char *mp;
942#endif
943    int i;
944
945    /* do this test only once */
946    if (vga_init_done)
947	return biosadapters;
948    vga_init_done = TRUE;
949
950    /*
951     * Locate display adapters.
952     * The AT architecture supports upto two adapters. `syscons' allows
953     * the following combinations of adapters:
954     *     1) MDA + CGA
955     *     2) MDA + EGA/VGA color
956     *     3) CGA + EGA/VGA mono
957     * Note that `syscons' doesn't bother with MCGA as it is only
958     * avaiable for low end PS/2 models which has 80286 or earlier CPUs,
959     * thus, they are not running FreeBSD!
960     * When there are two adapaters in the system, one becomes `primary'
961     * and the other `secondary'. The EGA adapter has a set of DIP
962     * switches on board for this information and the EGA BIOS copies
963     * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88).
964     * The VGA BIOS has more sophisticated mechanism and has this
965     * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains
966     * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH.
967     */
968
969    /*
970     * Check rtc and BIOS data area.
971     * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead
972     * copy of RTC_EQUIPMENT.  Bits 4 and 5 of ETC_EQUIPMENT are
973     * zeros for EGA and VGA.  However, the EGA/VGA BIOS sets
974     * these bits in BIOSDATA_EQUIPMENT according to the monitor
975     * type detected.
976     */
977#ifndef VGA_NO_BIOS
978    if (*(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8)) {
979	/* EGA/VGA BIOS is present */
980	fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
981			   biosadapter);
982    } else {
983	switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
984	case 0:
985	    /* EGA/VGA: shouldn't be happening */
986	    fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f,
987			       biosadapter);
988	    break;
989	case 1:
990	    /* CGA 40x25 */
991	    /* FIXME: switch to the 80x25 mode? XXX */
992	    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40];
993	    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
994	    break;
995	case 2:
996	    /* CGA 80x25 */
997	    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80];
998	    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
999	    break;
1000	case 3:
1001	    /* MDA */
1002	    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO];
1003	    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80];
1004	    break;
1005	}
1006    }
1007#else
1008    /* assume EGA/VGA? XXX */
1009    biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80];
1010    biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO];
1011#endif /* VGA_NO_BIOS */
1012
1013    biosadapters = 0;
1014    if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) {
1015	++biosadapters;
1016	biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED;
1017	biosadapter[V_ADP_SECONDARY].va_mode =
1018	    biosadapter[V_ADP_SECONDARY].va_initial_mode =
1019	    map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type,
1020			      biosadapter[V_ADP_SECONDARY].va_flags
1021				  & V_ADP_COLOR,
1022			      biosadapter[V_ADP_SECONDARY].va_initial_bios_mode);
1023    } else {
1024	biosadapter[V_ADP_SECONDARY].va_type = -1;
1025    }
1026    if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) {
1027	++biosadapters;
1028	biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED;
1029#ifndef VGA_NO_BIOS
1030	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode =
1031	    readb(BIOS_PADDRTOVADDR(0x449));
1032#else
1033	biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3;	/* XXX */
1034#endif
1035	biosadapter[V_ADP_PRIMARY].va_mode =
1036	    biosadapter[V_ADP_PRIMARY].va_initial_mode =
1037	    map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type,
1038			      biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR,
1039			      biosadapter[V_ADP_PRIMARY].va_initial_bios_mode);
1040    } else {
1041	biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY];
1042	biosadapter[V_ADP_SECONDARY].va_type = -1;
1043    }
1044    if (biosadapters == 0)
1045	return biosadapters;
1046    biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY;
1047    biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY;
1048
1049#if 0 /* we don't need these... */
1050    fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...);
1051    fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...);
1052#endif
1053
1054#if notyet
1055    /*
1056     * We cannot have two video adapter of the same type; there must be
1057     * only one of color or mono adapter, or one each of them.
1058     */
1059    if (biosadapters > 1) {
1060	if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags)
1061	      & V_ADP_COLOR))
1062	    /* we have two mono or color adapters!! */
1063	    return (biosadapters = 0);
1064    }
1065#endif
1066
1067    /*
1068     * Ensure a zero start address. The registers are w/o
1069     * for old hardware so it's too hard to relocate the active screen
1070     * memory.
1071     * This must be done before vga_save_state() for VGA.
1072     */
1073    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12);
1074    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
1075    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13);
1076    outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0);
1077
1078    /* the video mode parameter table in EGA/VGA BIOS */
1079    /* NOTE: there can be only one EGA/VGA, wheather color or mono,
1080     * recognized by the video BIOS.
1081     */
1082    if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) ||
1083	(biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) {
1084	adp = &biosadapter[V_ADP_PRIMARY];
1085    } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) ||
1086	       (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) {
1087	adp = &biosadapter[V_ADP_SECONDARY];
1088    } else {
1089	adp = NULL;
1090    }
1091    bzero(mode_map, sizeof(mode_map));
1092    if (adp != NULL) {
1093	if (adp->va_type == KD_VGA) {
1094	    vga_save_state(adp, &adpstate, sizeof(adpstate));
1095#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
1096	    mode_map[adp->va_initial_mode] = adpstate.regs;
1097	    rows_offset = 1;
1098#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1099	    if (video_mode_ptr == NULL) {
1100		mode_map[adp->va_initial_mode] = adpstate.regs;
1101		rows_offset = 1;
1102	    } else {
1103		/* discard the table if we are not familiar with it... */
1104		map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
1105		mp = get_mode_param(adp->va_initial_mode);
1106		if (mp != NULL)
1107		    bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs));
1108		switch (comp_adpregs(adpstate.regs, mp)) {
1109		case COMP_IDENTICAL:
1110		    /*
1111		     * OK, this parameter table looks reasonably familiar
1112		     * to us...
1113		     */
1114		    /*
1115		     * This is a kludge for Toshiba DynaBook SS433
1116		     * whose BIOS video mode table entry has the actual #
1117		     * of rows at the offset 1; BIOSes from other
1118		     * manufacturers store the # of rows - 1 there. XXX
1119		     */
1120		    rows_offset = adpstate.regs[1] + 1 - mp[1];
1121		    break;
1122
1123		case COMP_SIMILAR:
1124		    /*
1125		     * Not exactly the same, but similar enough to be
1126		     * trusted. However, use the saved register values
1127		     * for the initial mode and other modes which are
1128		     * based on the initial mode.
1129		     */
1130		    mode_map[adp->va_initial_mode] = adpstate.regs;
1131		    rows_offset = adpstate.regs[1] + 1 - mp[1];
1132		    adpstate.regs[1] -= rows_offset - 1;
1133		    break;
1134
1135		case COMP_DIFFERENT:
1136		default:
1137		    /*
1138		     * Don't use the paramter table in BIOS. It doesn't
1139		     * look familiar to us. Video mode switching is allowed
1140		     * only if the new mode is the same as or based on
1141		     * the initial mode.
1142		     */
1143		    video_mode_ptr = NULL;
1144		    bzero(mode_map, sizeof(mode_map));
1145		    mode_map[adp->va_initial_mode] = adpstate.regs;
1146		    rows_offset = 1;
1147		    break;
1148		}
1149	    }
1150#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1151
1152#ifndef VGA_NO_MODE_CHANGE
1153	    adp->va_flags |= V_ADP_MODECHANGE;
1154#endif
1155#ifndef VGA_NO_FONT_LOADING
1156	    adp->va_flags |= V_ADP_FONT;
1157#endif
1158	} else if (adp->va_type == KD_EGA) {
1159#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE)
1160	    rows_offset = 1;
1161#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1162	    if (video_mode_ptr == NULL) {
1163		rows_offset = 1;
1164	    } else {
1165		map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1);
1166		/* XXX how can one validate the EGA table... */
1167		mp = get_mode_param(adp->va_initial_mode);
1168		if (mp != NULL) {
1169		    adp->va_flags |= V_ADP_MODECHANGE;
1170#ifndef VGA_NO_FONT_LOADING
1171		    adp->va_flags |= V_ADP_FONT;
1172#endif
1173		    rows_offset = 1;
1174		} else {
1175		    /*
1176		     * This is serious. We will not be able to switch video
1177		     * modes at all...
1178		     */
1179		    video_mode_ptr = NULL;
1180		    bzero(mode_map, sizeof(mode_map));
1181		    rows_offset = 1;
1182                }
1183	    }
1184#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */
1185	}
1186    }
1187
1188    /* remove conflicting modes if we have more than one adapter */
1189    if (biosadapters > 0) {
1190	for (i = 0; i < biosadapters; ++i) {
1191	    if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE))
1192		continue;
1193	    clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1,
1194			   (biosadapter[i].va_flags & V_ADP_COLOR) ?
1195			       V_INFO_COLOR : 0);
1196	    if ((biosadapter[i].va_type == KD_VGA)
1197		|| (biosadapter[i].va_type == KD_EGA)) {
1198		biosadapter[i].va_io_base =
1199		    (biosadapter[i].va_flags & V_ADP_COLOR) ?
1200			IO_VGA : IO_MDA;
1201		biosadapter[i].va_io_size = 32;
1202	    }
1203	}
1204    }
1205
1206    /* buffer address */
1207    vga_get_info(&biosadapter[V_ADP_PRIMARY],
1208		 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info);
1209    info.vi_flags &= ~V_INFO_LINEAR; /* XXX */
1210    update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info);
1211
1212    if (biosadapters > 1) {
1213	vga_get_info(&biosadapter[V_ADP_SECONDARY],
1214		     biosadapter[V_ADP_SECONDARY].va_initial_mode, &info);
1215	info.vi_flags &= ~V_INFO_LINEAR; /* XXX */
1216	update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info);
1217    }
1218
1219    /*
1220     * XXX: we should verify the following values for the primary adapter...
1221     * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
1222     * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
1223     *                     ? 0 : V_ADP_COLOR;
1224     * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
1225     * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
1226     * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
1227     * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
1228     */
1229
1230    return biosadapters;
1231}
1232
1233/* set the scan line length in pixel */
1234static int
1235set_line_length(video_adapter_t *adp, int pixel)
1236{
1237    u_char *mp;
1238    int ppw;	/* pixels per word */
1239    int bpl;	/* bytes per line */
1240    int count;
1241
1242    if ((adp->va_type != KD_VGA) && (adp->va_type != KD_EGA))
1243	return ENODEV;
1244    mp = get_mode_param(adp->va_mode);
1245    if (mp == NULL)
1246	return EINVAL;
1247
1248    switch (adp->va_info.vi_mem_model) {
1249    case V_INFO_MM_PLANAR:
1250	ppw = 16/(adp->va_info.vi_depth/adp->va_info.vi_planes);
1251	count = (pixel + ppw - 1)/ppw/2;
1252	bpl = ((pixel + ppw - 1)/ppw/2)*4;
1253	break;
1254    case V_INFO_MM_PACKED:
1255	count = (pixel + 7)/8;
1256	bpl = ((pixel + 7)/8)*8;
1257	break;
1258    case V_INFO_MM_TEXT:
1259	count = (pixel + 7)/8;			/* columns */
1260	bpl = (pixel + 7)/8;			/* columns */
1261	break;
1262    default:
1263	return ENODEV;
1264    }
1265
1266    if (mp[10 + 0x17] & 0x40)			/* CRTC mode control reg */
1267	count *= 2;				/* byte mode */
1268    outb(adp->va_crtc_addr, 0x13);
1269    outb(adp->va_crtc_addr + 1, count);
1270    adp->va_line_width = bpl;
1271
1272    return 0;
1273}
1274
1275static int
1276set_display_start(video_adapter_t *adp, int x, int y)
1277{
1278    int off;	/* byte offset (graphics mode)/word offset (text mode) */
1279    int poff;	/* pixel offset */
1280    int roff;	/* row offset */
1281    int ppb;	/* pixels per byte */
1282
1283    if ((adp->va_type != KD_VGA) && (adp->va_type != KD_EGA))
1284	x &= ~7;
1285    if (adp->va_info.vi_flags & V_INFO_GRAPHICS) {
1286	ppb = 8/(adp->va_info.vi_depth/adp->va_info.vi_planes);
1287	off = y*adp->va_line_width + x/ppb;
1288	roff = 0;
1289	poff = x%ppb;
1290    } else {
1291	if ((adp->va_type == KD_VGA) || (adp->va_type == KD_EGA)) {
1292	    outb(TSIDX, 1);
1293	    if (inb(TSREG) & 1)
1294		ppb = 9;
1295	    else
1296		ppb = 8;
1297	} else {
1298	    ppb = 8;
1299	}
1300	off = y/adp->va_info.vi_cheight*adp->va_line_width + x/ppb;
1301	roff = y%adp->va_info.vi_cheight;
1302	/* FIXME: is this correct? XXX */
1303	if (ppb == 8)
1304	    poff = x%ppb;
1305	else
1306	    poff = (x + 8)%ppb;
1307    }
1308
1309    /* start address */
1310    outb(adp->va_crtc_addr, 0xc);		/* high */
1311    outb(adp->va_crtc_addr + 1, off >> 8);
1312    outb(adp->va_crtc_addr, 0xd);		/* low */
1313    outb(adp->va_crtc_addr + 1, off & 0xff);
1314
1315    /* horizontal pel pan */
1316    if ((adp->va_type == KD_VGA) || (adp->va_type == KD_EGA)) {
1317	inb(adp->va_crtc_addr + 6);
1318	outb(ATC, 0x13 | 0x20);
1319	outb(ATC, poff);
1320	inb(adp->va_crtc_addr + 6);
1321	outb(ATC, 0x20);
1322    }
1323
1324    /* preset raw scan */
1325    outb(adp->va_crtc_addr, 8);
1326    outb(adp->va_crtc_addr + 1, roff);
1327
1328    adp->va_disp_start.x = x;
1329    adp->va_disp_start.y = y;
1330    return 0;
1331}
1332
1333#if defined(__i386__) || defined(__amd64__)	/* XXX */
1334static void
1335fill(int val, void *d, size_t size)
1336{
1337    u_char *p = d;
1338
1339    while (size-- > 0)
1340	*p++ = val;
1341}
1342#endif /* __i386__ */
1343
1344static void
1345filll_io(int val, vm_offset_t d, size_t size)
1346{
1347    while (size-- > 0) {
1348	writel(d, val);
1349	d += sizeof(u_int32_t);
1350    }
1351}
1352
1353/* entry points */
1354
1355#if 0
1356static int
1357vga_nop(void)
1358{
1359    return 0;
1360}
1361#endif
1362
1363static int
1364vga_error(void)
1365{
1366    return ENODEV;
1367}
1368
1369static int
1370vga_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
1371{
1372    probe_adapters();
1373    if (unit >= biosadapters)
1374	return ENXIO;
1375
1376    *adpp = &biosadapter[unit];
1377
1378    return 0;
1379}
1380
1381static int
1382vga_init(int unit, video_adapter_t *adp, int flags)
1383{
1384    if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp))
1385	return ENXIO;
1386
1387    if (!init_done(adp)) {
1388	/* nothing to do really... */
1389	adp->va_flags |= V_ADP_INITIALIZED;
1390    }
1391
1392    if (!config_done(adp)) {
1393	if (vid_register(adp) < 0)
1394		return ENXIO;
1395	adp->va_flags |= V_ADP_REGISTERED;
1396    }
1397    if (vga_sub_configure != NULL)
1398	(*vga_sub_configure)(0);
1399
1400    return 0;
1401}
1402
1403/*
1404 * get_info():
1405 * Return the video_info structure of the requested video mode.
1406 *
1407 * all adapters
1408 */
1409static int
1410vga_get_info(video_adapter_t *adp, int mode, video_info_t *info)
1411{
1412    int i;
1413
1414    if (!vga_init_done)
1415	return ENXIO;
1416
1417    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
1418#ifndef VGA_NO_MODE_CHANGE
1419    if (adp->va_flags & V_ADP_MODECHANGE) {
1420	/*
1421	 * If the parameter table entry for this mode is not found,
1422	 * the mode is not supported...
1423	 */
1424	if (get_mode_param(mode) == NULL)
1425	    return EINVAL;
1426    } else
1427#endif /* VGA_NO_MODE_CHANGE */
1428    {
1429	/*
1430	 * Even if we don't support video mode switching on this adapter,
1431	 * the information on the initial (thus current) video mode
1432	 * should be made available.
1433	 */
1434	if (mode != adp->va_initial_mode)
1435	    return EINVAL;
1436    }
1437
1438    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1439	if (bios_vmode[i].vi_mode == NA)
1440	    continue;
1441	if (mode == bios_vmode[i].vi_mode) {
1442	    *info = bios_vmode[i];
1443	    /* XXX */
1444	    info->vi_buffer_size = info->vi_window_size*info->vi_planes;
1445	    return 0;
1446	}
1447    }
1448    return EINVAL;
1449}
1450
1451/*
1452 * query_mode():
1453 * Find a video mode matching the requested parameters.
1454 * Fields filled with 0 are considered "don't care" fields and
1455 * match any modes.
1456 *
1457 * all adapters
1458 */
1459static int
1460vga_query_mode(video_adapter_t *adp, video_info_t *info)
1461{
1462    int i;
1463
1464    if (!vga_init_done)
1465	return ENXIO;
1466
1467    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
1468	if (bios_vmode[i].vi_mode == NA)
1469	    continue;
1470
1471	if ((info->vi_width != 0)
1472	    && (info->vi_width != bios_vmode[i].vi_width))
1473		continue;
1474	if ((info->vi_height != 0)
1475	    && (info->vi_height != bios_vmode[i].vi_height))
1476		continue;
1477	if ((info->vi_cwidth != 0)
1478	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
1479		continue;
1480	if ((info->vi_cheight != 0)
1481	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
1482		continue;
1483	if ((info->vi_depth != 0)
1484	    && (info->vi_depth != bios_vmode[i].vi_depth))
1485		continue;
1486	if ((info->vi_planes != 0)
1487	    && (info->vi_planes != bios_vmode[i].vi_planes))
1488		continue;
1489	/* XXX: should check pixel format, memory model */
1490	if ((info->vi_flags != 0)
1491	    && (info->vi_flags != bios_vmode[i].vi_flags))
1492		continue;
1493
1494	/* verify if this mode is supported on this adapter */
1495	if (vga_get_info(adp, bios_vmode[i].vi_mode, info))
1496		continue;
1497	return 0;
1498    }
1499    return ENODEV;
1500}
1501
1502/*
1503 * set_mode():
1504 * Change the video mode.
1505 *
1506 * EGA/VGA
1507 */
1508
1509#ifndef VGA_NO_MODE_CHANGE
1510#ifdef VGA_WIDTH90
1511static void
1512set_width90(adp_state_t *params)
1513{
1514    /*
1515     * Based on code submitted by Kelly Yancey (kbyanc@freedomnet.com)
1516     * and alexv@sui.gda.itesm.mx.
1517     */
1518    params->regs[5] |= 1;		/* toggle 8 pixel wide fonts */
1519    params->regs[10+0x0] = 0x6b;
1520    params->regs[10+0x1] = 0x59;
1521    params->regs[10+0x2] = 0x5a;
1522    params->regs[10+0x3] = 0x8e;
1523    params->regs[10+0x4] = 0x5e;
1524    params->regs[10+0x5] = 0x8a;
1525    params->regs[10+0x13] = 45;
1526    params->regs[35+0x13] = 0;
1527}
1528#endif /* VGA_WIDTH90 */
1529#endif /* !VGA_NO_MODE_CHANGE */
1530
1531static int
1532vga_set_mode(video_adapter_t *adp, int mode)
1533{
1534#ifndef VGA_NO_MODE_CHANGE
1535    video_info_t info;
1536    adp_state_t params;
1537
1538    prologue(adp, V_ADP_MODECHANGE, ENODEV);
1539
1540    mode = map_gen_mode_num(adp->va_type,
1541			    adp->va_flags & V_ADP_COLOR, mode);
1542    if (vga_get_info(adp, mode, &info))
1543	return EINVAL;
1544
1545#if VGA_DEBUG > 1
1546    printf("vga_set_mode(): setting mode %d\n", mode);
1547#endif
1548
1549    params.sig = V_STATE_SIG;
1550    bcopy(get_mode_param(mode), params.regs, sizeof(params.regs));
1551
1552    switch (mode) {
1553#ifdef VGA_WIDTH90
1554    case M_VGA_C90x60: case M_VGA_M90x60:
1555	set_width90(&params);
1556	/* FALLTHROUGH */
1557#endif
1558    case M_VGA_C80x60: case M_VGA_M80x60:
1559	params.regs[2]  = 0x08;
1560	params.regs[19] = 0x47;
1561	goto special_480l;
1562
1563#ifdef VGA_WIDTH90
1564    case M_VGA_C90x30: case M_VGA_M90x30:
1565	set_width90(&params);
1566	/* FALLTHROUGH */
1567#endif
1568    case M_VGA_C80x30: case M_VGA_M80x30:
1569	params.regs[19] = 0x4f;
1570special_480l:
1571	params.regs[9] |= 0xc0;
1572	params.regs[16] = 0x08;
1573	params.regs[17] = 0x3e;
1574	params.regs[26] = 0xea;
1575	params.regs[28] = 0xdf;
1576	params.regs[31] = 0xe7;
1577	params.regs[32] = 0x04;
1578	goto setup_mode;
1579
1580#ifdef VGA_WIDTH90
1581    case M_VGA_C90x43: case M_VGA_M90x43:
1582	set_width90(&params);
1583	/* FALLTHROUGH */
1584#endif
1585    case M_ENH_C80x43: case M_ENH_B80x43:
1586	params.regs[28] = 87;
1587	goto special_80x50;
1588
1589#ifdef VGA_WIDTH90
1590    case M_VGA_C90x50: case M_VGA_M90x50:
1591	set_width90(&params);
1592	/* FALLTHROUGH */
1593#endif
1594    case M_VGA_C80x50: case M_VGA_M80x50:
1595special_80x50:
1596	params.regs[2] = 8;
1597	params.regs[19] = 7;
1598	goto setup_mode;
1599
1600#ifdef VGA_WIDTH90
1601    case M_VGA_C90x25: case M_VGA_M90x25:
1602	set_width90(&params);
1603	/* FALLTHROUGH */
1604#endif
1605    case M_VGA_C40x25: case M_VGA_C80x25:
1606    case M_VGA_M80x25:
1607    case M_B40x25:     case M_C40x25:
1608    case M_B80x25:     case M_C80x25:
1609    case M_ENH_B40x25: case M_ENH_C40x25:
1610    case M_ENH_B80x25: case M_ENH_C80x25:
1611    case M_EGAMONO80x25:
1612
1613setup_mode:
1614	vga_load_state(adp, &params);
1615	break;
1616
1617    case M_VGA_MODEX:
1618	/* "unchain" the VGA mode */
1619	params.regs[5-1+0x04] &= 0xf7;
1620	params.regs[5-1+0x04] |= 0x04;
1621	/* turn off doubleword mode */
1622	params.regs[10+0x14] &= 0xbf;
1623	/* turn off word addressing */
1624	params.regs[10+0x17] |= 0x40;
1625	/* set logical screen width */
1626	params.regs[10+0x13] = 80;
1627	/* set 240 lines */
1628	params.regs[10+0x11] = 0x2c;
1629	params.regs[10+0x06] = 0x0d;
1630	params.regs[10+0x07] = 0x3e;
1631	params.regs[10+0x10] = 0xea;
1632	params.regs[10+0x11] = 0xac;
1633	params.regs[10+0x12] = 0xdf;
1634	params.regs[10+0x15] = 0xe7;
1635	params.regs[10+0x16] = 0x06;
1636	/* set vertical sync polarity to reflect aspect ratio */
1637	params.regs[9] = 0xe3;
1638	goto setup_grmode;
1639
1640    case M_BG320:     case M_CG320:     case M_BG640:
1641    case M_CG320_D:   case M_CG640_E:
1642    case M_CG640x350: case M_ENH_CG640:
1643    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
1644
1645setup_grmode:
1646	vga_load_state(adp, &params);
1647	break;
1648
1649    default:
1650	return EINVAL;
1651    }
1652
1653    adp->va_mode = mode;
1654    info.vi_flags &= ~V_INFO_LINEAR; /* XXX */
1655    update_adapter_info(adp, &info);
1656
1657    /* move hardware cursor out of the way */
1658    (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
1659
1660    return 0;
1661#else /* VGA_NO_MODE_CHANGE */
1662    return ENODEV;
1663#endif /* VGA_NO_MODE_CHANGE */
1664}
1665
1666#ifndef VGA_NO_FONT_LOADING
1667
1668static void
1669set_font_mode(video_adapter_t *adp, u_char *buf)
1670{
1671    u_char *mp;
1672    int s;
1673
1674    s = splhigh();
1675
1676    /* save register values */
1677    if (adp->va_type == KD_VGA) {
1678	outb(TSIDX, 0x02); buf[0] = inb(TSREG);
1679	outb(TSIDX, 0x04); buf[1] = inb(TSREG);
1680	outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
1681	outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
1682	outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
1683	inb(adp->va_crtc_addr + 6);
1684	outb(ATC, 0x10); buf[5] = inb(ATC + 1);
1685    } else /* if (adp->va_type == KD_EGA) */ {
1686	/*
1687	 * EGA cannot be read; copy parameters from the mode parameter
1688	 * table.
1689	 */
1690	mp = get_mode_param(adp->va_mode);
1691	buf[0] = mp[5 + 0x02 - 1];
1692	buf[1] = mp[5 + 0x04 - 1];
1693	buf[2] = mp[55 + 0x04];
1694	buf[3] = mp[55 + 0x05];
1695	buf[4] = mp[55 + 0x06];
1696	buf[5] = mp[35 + 0x10];
1697    }
1698
1699    /* setup vga for loading fonts */
1700    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1701    outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
1702    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1703    outb(ATC, 0x20);				/* enable palette */
1704
1705#if VGA_SLOW_IOACCESS
1706#ifdef VGA_ALT_SEQACCESS
1707    outb(TSIDX, 0x00); outb(TSREG, 0x01);
1708#endif
1709    outb(TSIDX, 0x02); outb(TSREG, 0x04);
1710    outb(TSIDX, 0x04); outb(TSREG, 0x07);
1711#ifdef VGA_ALT_SEQACCESS
1712    outb(TSIDX, 0x00); outb(TSREG, 0x03);
1713#endif
1714    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
1715    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
1716    outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
1717#else /* VGA_SLOW_IOACCESS */
1718#ifdef VGA_ALT_SEQACCESS
1719    outw(TSIDX, 0x0100);
1720#endif
1721    outw(TSIDX, 0x0402);
1722    outw(TSIDX, 0x0704);
1723#ifdef VGA_ALT_SEQACCESS
1724    outw(TSIDX, 0x0300);
1725#endif
1726    outw(GDCIDX, 0x0204);
1727    outw(GDCIDX, 0x0005);
1728    outw(GDCIDX, 0x0406);               /* addr = a0000, 64kb */
1729#endif /* VGA_SLOW_IOACCESS */
1730
1731    splx(s);
1732}
1733
1734static void
1735set_normal_mode(video_adapter_t *adp, u_char *buf)
1736{
1737    int s;
1738
1739    s = splhigh();
1740
1741    /* setup vga for normal operation mode again */
1742    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1743    outb(ATC, 0x10); outb(ATC, buf[5]);
1744    inb(adp->va_crtc_addr + 6);			/* reset flip-flop */
1745    outb(ATC, 0x20);				/* enable palette */
1746
1747#if VGA_SLOW_IOACCESS
1748#ifdef VGA_ALT_SEQACCESS
1749    outb(TSIDX, 0x00); outb(TSREG, 0x01);
1750#endif
1751    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
1752    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
1753#ifdef VGA_ALT_SEQACCESS
1754    outb(TSIDX, 0x00); outb(TSREG, 0x03);
1755#endif
1756    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
1757    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
1758    if (adp->va_crtc_addr == MONO_CRTC) {
1759	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
1760    } else {
1761	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
1762    }
1763#else /* VGA_SLOW_IOACCESS */
1764#ifdef VGA_ALT_SEQACCESS
1765    outw(TSIDX, 0x0100);
1766#endif
1767    outw(TSIDX, 0x0002 | (buf[0] << 8));
1768    outw(TSIDX, 0x0004 | (buf[1] << 8));
1769#ifdef VGA_ALT_SEQACCESS
1770    outw(TSIDX, 0x0300);
1771#endif
1772    outw(GDCIDX, 0x0004 | (buf[2] << 8));
1773    outw(GDCIDX, 0x0005 | (buf[3] << 8));
1774    if (adp->va_crtc_addr == MONO_CRTC)
1775        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
1776    else
1777        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
1778#endif /* VGA_SLOW_IOACCESS */
1779
1780    splx(s);
1781}
1782
1783#endif /* VGA_NO_FONT_LOADING */
1784
1785/*
1786 * save_font():
1787 * Read the font data in the requested font page from the video adapter.
1788 *
1789 * EGA/VGA
1790 */
1791static int
1792vga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
1793	      int ch, int count)
1794{
1795#ifndef VGA_NO_FONT_LOADING
1796    u_char buf[PARAM_BUFSIZE];
1797    vm_offset_t segment;
1798    int c;
1799#ifdef VGA_ALT_SEQACCESS
1800    int s;
1801    u_char val = 0;
1802#endif
1803
1804    prologue(adp, V_ADP_FONT, ENODEV);
1805
1806    if (fontsize < 14) {
1807	/* FONT_8 */
1808	fontsize = 8;
1809    } else if (fontsize >= 32) {
1810	fontsize = 32;
1811    } else if (fontsize >= 16) {
1812	/* FONT_16 */
1813	fontsize = 16;
1814    } else {
1815	/* FONT_14 */
1816	fontsize = 14;
1817    }
1818
1819    if (page < 0 || page >= 8)
1820	return EINVAL;
1821    segment = FONT_BUF + 0x4000*page;
1822    if (page > 3)
1823	segment -= 0xe000;
1824
1825#ifdef VGA_ALT_SEQACCESS
1826    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
1827	s = splhigh();
1828	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1829	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
1830	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1831	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1832	splx(s);
1833    }
1834#endif
1835
1836    set_font_mode(adp, buf);
1837    if (fontsize == 32) {
1838	bcopy_fromio((uintptr_t)segment + ch*32, data, fontsize*count);
1839    } else {
1840	for (c = ch; count > 0; ++c, --count) {
1841	    bcopy_fromio((uintptr_t)segment + c*32, data, fontsize);
1842	    data += fontsize;
1843	}
1844    }
1845    set_normal_mode(adp, buf);
1846
1847#ifdef VGA_ALT_SEQACCESS
1848    if (adp->va_type == KD_VGA) {
1849	s = splhigh();
1850	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1851	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
1852	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1853	splx(s);
1854    }
1855#endif
1856
1857    return 0;
1858#else /* VGA_NO_FONT_LOADING */
1859    return ENODEV;
1860#endif /* VGA_NO_FONT_LOADING */
1861}
1862
1863/*
1864 * load_font():
1865 * Set the font data in the requested font page.
1866 * NOTE: it appears that some recent video adapters do not support
1867 * the font page other than 0... XXX
1868 *
1869 * EGA/VGA
1870 */
1871static int
1872vga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
1873	      int ch, int count)
1874{
1875#ifndef VGA_NO_FONT_LOADING
1876    u_char buf[PARAM_BUFSIZE];
1877    vm_offset_t segment;
1878    int c;
1879#ifdef VGA_ALT_SEQACCESS
1880    int s;
1881    u_char val = 0;
1882#endif
1883
1884    prologue(adp, V_ADP_FONT, ENODEV);
1885
1886    if (fontsize < 14) {
1887	/* FONT_8 */
1888	fontsize = 8;
1889    } else if (fontsize >= 32) {
1890	fontsize = 32;
1891    } else if (fontsize >= 16) {
1892	/* FONT_16 */
1893	fontsize = 16;
1894    } else {
1895	/* FONT_14 */
1896	fontsize = 14;
1897    }
1898
1899    if (page < 0 || page >= 8)
1900	return EINVAL;
1901    segment = FONT_BUF + 0x4000*page;
1902    if (page > 3)
1903	segment -= 0xe000;
1904
1905#ifdef VGA_ALT_SEQACCESS
1906    if (adp->va_type == KD_VGA) {	/* what about EGA? XXX */
1907	s = splhigh();
1908	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1909	outb(TSIDX, 0x01); val = inb(TSREG);	/* disable screen */
1910	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1911	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1912	splx(s);
1913    }
1914#endif
1915
1916    set_font_mode(adp, buf);
1917    if (fontsize == 32) {
1918	bcopy_toio(data, (uintptr_t)segment + ch*32, fontsize*count);
1919    } else {
1920	for (c = ch; count > 0; ++c, --count) {
1921	    bcopy_toio(data, (uintptr_t)segment + c*32, fontsize);
1922	    data += fontsize;
1923	}
1924    }
1925    set_normal_mode(adp, buf);
1926
1927#ifdef VGA_ALT_SEQACCESS
1928    if (adp->va_type == KD_VGA) {
1929	s = splhigh();
1930	outb(TSIDX, 0x00); outb(TSREG, 0x01);
1931	outb(TSIDX, 0x01); outb(TSREG, val & 0xdf);	/* enable screen */
1932	outb(TSIDX, 0x00); outb(TSREG, 0x03);
1933	splx(s);
1934    }
1935#endif
1936
1937    return 0;
1938#else /* VGA_NO_FONT_LOADING */
1939    return ENODEV;
1940#endif /* VGA_NO_FONT_LOADING */
1941}
1942
1943/*
1944 * show_font():
1945 * Activate the requested font page.
1946 * NOTE: it appears that some recent video adapters do not support
1947 * the font page other than 0... XXX
1948 *
1949 * EGA/VGA
1950 */
1951static int
1952vga_show_font(video_adapter_t *adp, int page)
1953{
1954#ifndef VGA_NO_FONT_LOADING
1955    static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
1956    int s;
1957
1958    prologue(adp, V_ADP_FONT, ENODEV);
1959    if (page < 0 || page >= 8)
1960	return EINVAL;
1961
1962    s = splhigh();
1963    outb(TSIDX, 0x03); outb(TSREG, cg[page]);
1964    splx(s);
1965
1966    return 0;
1967#else /* VGA_NO_FONT_LOADING */
1968    return ENODEV;
1969#endif /* VGA_NO_FONT_LOADING */
1970}
1971
1972/*
1973 * save_palette():
1974 * Read DAC values. The values have expressed in 8 bits.
1975 *
1976 * VGA
1977 */
1978static int
1979vga_save_palette(video_adapter_t *adp, u_char *palette)
1980{
1981    int i;
1982
1983    prologue(adp, V_ADP_PALETTE, ENODEV);
1984
1985    /*
1986     * We store 8 bit values in the palette buffer, while the standard
1987     * VGA has 6 bit DAC .
1988     */
1989    outb(PALRADR, 0x00);
1990    for (i = 0; i < 256*3; ++i)
1991	palette[i] = inb(PALDATA) << 2;
1992    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
1993    return 0;
1994}
1995
1996static int
1997vga_save_palette2(video_adapter_t *adp, int base, int count,
1998		  u_char *r, u_char *g, u_char *b)
1999{
2000    int i;
2001
2002    prologue(adp, V_ADP_PALETTE, ENODEV);
2003
2004    outb(PALRADR, base);
2005    for (i = 0; i < count; ++i) {
2006	r[i] = inb(PALDATA) << 2;
2007	g[i] = inb(PALDATA) << 2;
2008	b[i] = inb(PALDATA) << 2;
2009    }
2010    inb(adp->va_crtc_addr + 6);		/* reset flip/flop */
2011    return 0;
2012}
2013
2014/*
2015 * load_palette():
2016 * Set DAC values.
2017 *
2018 * VGA
2019 */
2020static int
2021vga_load_palette(video_adapter_t *adp, u_char *palette)
2022{
2023    int i;
2024
2025    prologue(adp, V_ADP_PALETTE, ENODEV);
2026
2027    outb(PIXMASK, 0xff);		/* no pixelmask */
2028    outb(PALWADR, 0x00);
2029    for (i = 0; i < 256*3; ++i)
2030	outb(PALDATA, palette[i] >> 2);
2031    inb(adp->va_crtc_addr + 6);	/* reset flip/flop */
2032    outb(ATC, 0x20);			/* enable palette */
2033    return 0;
2034}
2035
2036static int
2037vga_load_palette2(video_adapter_t *adp, int base, int count,
2038		  u_char *r, u_char *g, u_char *b)
2039{
2040    int i;
2041
2042    prologue(adp, V_ADP_PALETTE, ENODEV);
2043
2044    outb(PIXMASK, 0xff);		/* no pixelmask */
2045    outb(PALWADR, base);
2046    for (i = 0; i < count; ++i) {
2047	outb(PALDATA, r[i] >> 2);
2048	outb(PALDATA, g[i] >> 2);
2049	outb(PALDATA, b[i] >> 2);
2050    }
2051    inb(adp->va_crtc_addr + 6);		/* reset flip/flop */
2052    outb(ATC, 0x20);			/* enable palette */
2053    return 0;
2054}
2055
2056/*
2057 * set_border():
2058 * Change the border color.
2059 *
2060 * CGA/EGA/VGA
2061 */
2062static int
2063vga_set_border(video_adapter_t *adp, int color)
2064{
2065    prologue(adp, V_ADP_BORDER, ENODEV);
2066
2067    switch (adp->va_type) {
2068    case KD_EGA:
2069    case KD_VGA:
2070	inb(adp->va_crtc_addr + 6);	/* reset flip-flop */
2071	outb(ATC, 0x31); outb(ATC, color & 0xff);
2072	break;
2073    case KD_CGA:
2074	outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */
2075	break;
2076    case KD_MONO:
2077    case KD_HERCULES:
2078    default:
2079	break;
2080    }
2081    return 0;
2082}
2083
2084/*
2085 * save_state():
2086 * Read video register values.
2087 * NOTE: this function only reads the standard EGA/VGA registers.
2088 * any extra/extended registers of SVGA adapters are not saved.
2089 *
2090 * VGA
2091 */
2092static int
2093vga_save_state(video_adapter_t *adp, void *p, size_t size)
2094{
2095    video_info_t info;
2096    u_char *buf;
2097    int crtc_addr;
2098    int i, j;
2099    int s;
2100
2101    if (size == 0) {
2102	/* return the required buffer size */
2103	prologue(adp, V_ADP_STATESAVE, 0);
2104	return sizeof(adp_state_t);
2105    } else {
2106	prologue(adp, V_ADP_STATESAVE, ENODEV);
2107	if (size < sizeof(adp_state_t))
2108	    return EINVAL;
2109    }
2110
2111    ((adp_state_t *)p)->sig = V_STATE_SIG;
2112    buf = ((adp_state_t *)p)->regs;
2113    bzero(buf, V_MODE_PARAM_SIZE);
2114    crtc_addr = adp->va_crtc_addr;
2115
2116    s = splhigh();
2117
2118    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
2119    for (i = 0, j = 5; i < 4; i++) {
2120	outb(TSIDX, i + 1);
2121	buf[j++]  =  inb(TSREG);
2122    }
2123    buf[9]  =  inb(MISC + 10);			/* dot-clock */
2124    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
2125
2126    for (i = 0, j = 10; i < 25; i++) {		/* crtc */
2127	outb(crtc_addr, i);
2128	buf[j++]  =  inb(crtc_addr + 1);
2129    }
2130    for (i = 0, j = 35; i < 20; i++) {		/* attribute ctrl */
2131        inb(crtc_addr + 6);			/* reset flip-flop */
2132	outb(ATC, i);
2133	buf[j++]  =  inb(ATC + 1);
2134    }
2135    for (i = 0, j = 55; i < 9; i++) {		/* graph data ctrl */
2136	outb(GDCIDX, i);
2137	buf[j++]  =  inb(GDCREG);
2138    }
2139    inb(crtc_addr + 6);				/* reset flip-flop */
2140    outb(ATC, 0x20);				/* enable palette */
2141
2142    splx(s);
2143
2144#if 1
2145    if (vga_get_info(adp, adp->va_mode, &info) == 0) {
2146	if (info.vi_flags & V_INFO_GRAPHICS) {
2147	    buf[0] = info.vi_width/info.vi_cwidth; /* COLS */
2148	    buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */
2149	} else {
2150	    buf[0] = info.vi_width;		/* COLS */
2151	    buf[1] = info.vi_height - 1;	/* ROWS */
2152	}
2153	buf[2] = info.vi_cheight;		/* POINTS */
2154    } else {
2155	/* XXX: shouldn't be happening... */
2156	printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
2157	       adp->va_unit, adp->va_name);
2158    }
2159#else
2160    buf[0] = readb(BIOS_PADDRTOVADDR(0x44a));	/* COLS */
2161    buf[1] = readb(BIOS_PADDRTOVADDR(0x484));	/* ROWS */
2162    buf[2] = readb(BIOS_PADDRTOVADDR(0x485));	/* POINTS */
2163    buf[3] = readb(BIOS_PADDRTOVADDR(0x44c));
2164    buf[4] = readb(BIOS_PADDRTOVADDR(0x44d));
2165#endif
2166
2167    return 0;
2168}
2169
2170/*
2171 * load_state():
2172 * Set video registers at once.
2173 * NOTE: this function only updates the standard EGA/VGA registers.
2174 * any extra/extended registers of SVGA adapters are not changed.
2175 *
2176 * EGA/VGA
2177 */
2178static int
2179vga_load_state(video_adapter_t *adp, void *p)
2180{
2181    u_char *buf;
2182    int crtc_addr;
2183    int s;
2184    int i;
2185
2186    prologue(adp, V_ADP_STATELOAD, ENODEV);
2187    if (((adp_state_t *)p)->sig != V_STATE_SIG)
2188	return EINVAL;
2189
2190    buf = ((adp_state_t *)p)->regs;
2191    crtc_addr = adp->va_crtc_addr;
2192
2193#if VGA_DEBUG > 1
2194    dump_buffer(buf, V_MODE_PARAM_SIZE);
2195#endif
2196
2197    s = splhigh();
2198
2199    outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
2200    for (i = 0; i < 4; ++i) {			/* program sequencer */
2201	outb(TSIDX, i + 1);
2202	outb(TSREG, buf[i + 5]);
2203    }
2204    outb(MISC, buf[9]);				/* set dot-clock */
2205    outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
2206    outb(crtc_addr, 0x11);
2207    outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F);
2208    for (i = 0; i < 25; ++i) {			/* program crtc */
2209	outb(crtc_addr, i);
2210	outb(crtc_addr + 1, buf[i + 10]);
2211    }
2212    inb(crtc_addr+6);				/* reset flip-flop */
2213    for (i = 0; i < 20; ++i) {			/* program attribute ctrl */
2214	outb(ATC, i);
2215	outb(ATC, buf[i + 35]);
2216    }
2217    for (i = 0; i < 9; ++i) {			/* program graph data ctrl */
2218	outb(GDCIDX, i);
2219	outb(GDCREG, buf[i + 55]);
2220    }
2221    inb(crtc_addr + 6);				/* reset flip-flop */
2222    outb(ATC, 0x20);				/* enable palette */
2223
2224#if notyet /* a temporary workaround for kernel panic, XXX */
2225#ifndef VGA_NO_BIOS
2226    if (adp->va_unit == V_ADP_PRIMARY) {
2227	writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]);	/* COLS */
2228	writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */
2229	writeb(BIOS_PADDRTOVADDR(0x485), buf[2]);	/* POINTS */
2230#if 0
2231	writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]);
2232	writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]);
2233#endif
2234    }
2235#endif /* VGA_NO_BIOS */
2236#endif /* notyet */
2237
2238    splx(s);
2239    return 0;
2240}
2241
2242/*
2243 * set_origin():
2244 * Change the origin (window mapping) of the banked frame buffer.
2245 */
2246static int
2247vga_set_origin(video_adapter_t *adp, off_t offset)
2248{
2249    /*
2250     * The standard video modes do not require window mapping;
2251     * always return error.
2252     */
2253    return ENODEV;
2254}
2255
2256/*
2257 * read_hw_cursor():
2258 * Read the position of the hardware text cursor.
2259 *
2260 * all adapters
2261 */
2262static int
2263vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
2264{
2265    u_int16_t off;
2266    int s;
2267
2268    if (!vga_init_done)
2269	return ENXIO;
2270
2271    if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
2272	return ENODEV;
2273
2274    s = spltty();
2275    outb(adp->va_crtc_addr, 14);
2276    off = inb(adp->va_crtc_addr + 1);
2277    outb(adp->va_crtc_addr, 15);
2278    off = (off << 8) | inb(adp->va_crtc_addr + 1);
2279    splx(s);
2280
2281    *row = off / adp->va_info.vi_width;
2282    *col = off % adp->va_info.vi_width;
2283
2284    return 0;
2285}
2286
2287/*
2288 * set_hw_cursor():
2289 * Move the hardware text cursor.  If col and row are both -1,
2290 * the cursor won't be shown.
2291 *
2292 * all adapters
2293 */
2294static int
2295vga_set_hw_cursor(video_adapter_t *adp, int col, int row)
2296{
2297    u_int16_t off;
2298    int s;
2299
2300    if (!vga_init_done)
2301	return ENXIO;
2302
2303    if ((col == -1) && (row == -1)) {
2304	off = -1;
2305    } else {
2306	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
2307	    return ENODEV;
2308	off = row*adp->va_info.vi_width + col;
2309    }
2310
2311    s = spltty();
2312    outb(adp->va_crtc_addr, 14);
2313    outb(adp->va_crtc_addr + 1, off >> 8);
2314    outb(adp->va_crtc_addr, 15);
2315    outb(adp->va_crtc_addr + 1, off & 0x00ff);
2316    splx(s);
2317
2318    return 0;
2319}
2320
2321/*
2322 * set_hw_cursor_shape():
2323 * Change the shape of the hardware text cursor. If the height is
2324 * zero or negative, the cursor won't be shown.
2325 *
2326 * all adapters
2327 */
2328static int
2329vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
2330			int celsize, int blink)
2331{
2332    int s;
2333
2334    if (!vga_init_done)
2335	return ENXIO;
2336
2337    s = spltty();
2338    switch (adp->va_type) {
2339    case KD_VGA:
2340    case KD_CGA:
2341    case KD_MONO:
2342    case KD_HERCULES:
2343    default:
2344	if (height <= 0) {
2345	    /* make the cursor invisible */
2346	    outb(adp->va_crtc_addr, 10);
2347	    outb(adp->va_crtc_addr + 1, 32);
2348	    outb(adp->va_crtc_addr, 11);
2349	    outb(adp->va_crtc_addr + 1, 0);
2350	} else {
2351	    outb(adp->va_crtc_addr, 10);
2352	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2353	    outb(adp->va_crtc_addr, 11);
2354	    outb(adp->va_crtc_addr + 1, celsize - base - 1);
2355	}
2356	break;
2357    case KD_EGA:
2358	if (height <= 0) {
2359	    /* make the cursor invisible */
2360	    outb(adp->va_crtc_addr, 10);
2361	    outb(adp->va_crtc_addr + 1, celsize);
2362	    outb(adp->va_crtc_addr, 11);
2363	    outb(adp->va_crtc_addr + 1, 0);
2364	} else {
2365	    outb(adp->va_crtc_addr, 10);
2366	    outb(adp->va_crtc_addr + 1, celsize - base - height);
2367	    outb(adp->va_crtc_addr, 11);
2368	    outb(adp->va_crtc_addr + 1, celsize - base);
2369	}
2370	break;
2371    }
2372    splx(s);
2373
2374    return 0;
2375}
2376
2377/*
2378 * blank_display()
2379 * Put the display in power save/power off mode.
2380 *
2381 * all adapters
2382 */
2383static int
2384vga_blank_display(video_adapter_t *adp, int mode)
2385{
2386    u_char val;
2387    int s;
2388
2389    s = splhigh();
2390    switch (adp->va_type) {
2391    case KD_VGA:
2392	switch (mode) {
2393	case V_DISPLAY_SUSPEND:
2394	case V_DISPLAY_STAND_BY:
2395	    outb(TSIDX, 0x01);
2396	    val = inb(TSREG);
2397	    outb(TSIDX, 0x01);
2398	    outb(TSREG, val | 0x20);
2399	    outb(adp->va_crtc_addr, 0x17);
2400	    val = inb(adp->va_crtc_addr + 1);
2401	    outb(adp->va_crtc_addr + 1, val & ~0x80);
2402	    break;
2403	case V_DISPLAY_BLANK:
2404	    outb(TSIDX, 0x01);
2405	    val = inb(TSREG);
2406	    outb(TSIDX, 0x01);
2407	    outb(TSREG, val | 0x20);
2408	    break;
2409	case V_DISPLAY_ON:
2410	    outb(TSIDX, 0x01);
2411	    val = inb(TSREG);
2412	    outb(TSIDX, 0x01);
2413	    outb(TSREG, val & 0xDF);
2414	    outb(adp->va_crtc_addr, 0x17);
2415	    val = inb(adp->va_crtc_addr + 1);
2416	    outb(adp->va_crtc_addr + 1, val | 0x80);
2417	    break;
2418	}
2419	break;
2420
2421    case KD_EGA:
2422	/* no support yet */
2423	splx(s);
2424	return ENODEV;
2425
2426    case KD_CGA:
2427	switch (mode) {
2428	case V_DISPLAY_SUSPEND:
2429	case V_DISPLAY_STAND_BY:
2430	case V_DISPLAY_BLANK:
2431	    outb(adp->va_crtc_addr + 4, 0x25);
2432	    break;
2433	case V_DISPLAY_ON:
2434	    outb(adp->va_crtc_addr + 4, 0x2d);
2435	    break;
2436	}
2437	break;
2438
2439    case KD_MONO:
2440    case KD_HERCULES:
2441	switch (mode) {
2442	case V_DISPLAY_SUSPEND:
2443	case V_DISPLAY_STAND_BY:
2444	case V_DISPLAY_BLANK:
2445	    outb(adp->va_crtc_addr + 4, 0x21);
2446	    break;
2447	case V_DISPLAY_ON:
2448	    outb(adp->va_crtc_addr + 4, 0x29);
2449	    break;
2450	}
2451	break;
2452    default:
2453	break;
2454    }
2455    splx(s);
2456
2457    return 0;
2458}
2459
2460/*
2461 * mmap():
2462 * Mmap frame buffer.
2463 *
2464 * all adapters
2465 */
2466static int
2467vga_mmap_buf(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr,
2468   	     int prot)
2469{
2470    if (adp->va_info.vi_flags & V_INFO_LINEAR)
2471	return -1;
2472
2473#if VGA_DEBUG > 0
2474    printf("vga_mmap_buf(): window:0x%jx, offset:0x%jx\n",
2475	   (uintmax_t)adp->va_info.vi_window, (uintmax_t)offset);
2476#endif
2477
2478    /* XXX: is this correct? */
2479    if (offset > adp->va_window_size - PAGE_SIZE)
2480	return -1;
2481
2482    *paddr = adp->va_info.vi_window + offset;
2483    return 0;
2484}
2485
2486#ifndef VGA_NO_MODE_CHANGE
2487
2488static void
2489planar_fill(video_adapter_t *adp, int val)
2490{
2491    int length;
2492    int at;			/* position in the frame buffer */
2493    int l;
2494
2495    outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
2496    outw(GDCIDX, 0x0003);		/* data rotate/function select */
2497    outw(GDCIDX, 0x0f01);		/* set/reset enable */
2498    outw(GDCIDX, 0xff08);		/* bit mask */
2499    outw(GDCIDX, (val << 8) | 0x00);	/* set/reset */
2500    at = 0;
2501    length = adp->va_line_width*adp->va_info.vi_height;
2502    while (length > 0) {
2503	l = imin(length, adp->va_window_size);
2504	(*vidsw[adp->va_index]->set_win_org)(adp, at);
2505	bzero_io(adp->va_window, l);
2506	length -= l;
2507	at += l;
2508    }
2509    outw(GDCIDX, 0x0000);		/* set/reset */
2510    outw(GDCIDX, 0x0001);		/* set/reset enable */
2511}
2512
2513static void
2514packed_fill(video_adapter_t *adp, int val)
2515{
2516    int length;
2517    int at;			/* position in the frame buffer */
2518    int l;
2519
2520    at = 0;
2521    length = adp->va_line_width*adp->va_info.vi_height;
2522    while (length > 0) {
2523	l = imin(length, adp->va_window_size);
2524	(*vidsw[adp->va_index]->set_win_org)(adp, at);
2525	fill_io(val, adp->va_window, l);
2526	length -= l;
2527	at += l;
2528    }
2529}
2530
2531static void
2532direct_fill(video_adapter_t *adp, int val)
2533{
2534    int length;
2535    int at;			/* position in the frame buffer */
2536    int l;
2537
2538    at = 0;
2539    length = adp->va_line_width*adp->va_info.vi_height;
2540    while (length > 0) {
2541	l = imin(length, adp->va_window_size);
2542	(*vidsw[adp->va_index]->set_win_org)(adp, at);
2543	switch (adp->va_info.vi_pixel_size) {
2544	case sizeof(u_int16_t):
2545	    fillw_io(val, adp->va_window, l/sizeof(u_int16_t));
2546	    break;
2547	case 3:
2548	    /* FIXME */
2549	    break;
2550	case sizeof(u_int32_t):
2551	    filll_io(val, adp->va_window, l/sizeof(u_int32_t));
2552	    break;
2553	}
2554	length -= l;
2555	at += l;
2556    }
2557}
2558
2559static int
2560vga_clear(video_adapter_t *adp)
2561{
2562    switch (adp->va_info.vi_mem_model) {
2563    case V_INFO_MM_TEXT:
2564	/* do nothing? XXX */
2565	break;
2566    case V_INFO_MM_PLANAR:
2567	planar_fill(adp, 0);
2568	break;
2569    case V_INFO_MM_PACKED:
2570	packed_fill(adp, 0);
2571	break;
2572    case V_INFO_MM_DIRECT:
2573	direct_fill(adp, 0);
2574	break;
2575    }
2576    return 0;
2577}
2578
2579#ifdef notyet
2580static void
2581planar_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2582{
2583    int banksize;
2584    int bank;
2585    int pos;
2586    int offset;			/* offset within window */
2587    int bx;
2588    int l;
2589
2590    outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
2591    outw(GDCIDX, 0x0003);		/* data rotate/function select */
2592    outw(GDCIDX, 0x0f01);		/* set/reset enable */
2593    outw(GDCIDX, 0xff08);		/* bit mask */
2594    outw(GDCIDX, (val << 8) | 0x00); /* set/reset */
2595
2596    banksize = adp->va_window_size;
2597    bank = -1;
2598    while (cy > 0) {
2599	pos = adp->va_line_width*y + x/8;
2600	if (bank != pos/banksize) {
2601	    (*vidsw[adp->va_index]->set_win_org)(adp, pos);
2602	    bank = pos/banksize;
2603	}
2604	offset = pos%banksize;
2605	bx = (x + cx)/8 - x/8;
2606	if (x % 8) {
2607	    outw(GDCIDX, ((0xff00 >> (x % 8)) & 0xff00) | 0x08);
2608	    writeb(adp->va_window + offset, 0);
2609	    ++offset;
2610	    --bx;
2611	    if (offset >= banksize) {
2612		offset = 0;
2613		++bank;		/* next bank */
2614		(*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2615	    }
2616	    outw(GDCIDX, 0xff08);	/* bit mask */
2617	}
2618	while (bx > 0) {
2619	    l = imin(bx, banksize);
2620	    bzero_io(adp->va_window + offset, l);
2621	    offset += l;
2622	    bx -= l;
2623	    if (offset >= banksize) {
2624		offset = 0;
2625		++bank;		/* next bank */
2626		(*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2627	    }
2628	}
2629	if ((x + cx) % 8) {
2630	    outw(GDCIDX, (~(0xff00 >> ((x + cx) % 8)) & 0xff00) | 0x08);
2631	    writeb(adp->va_window + offset, 0);
2632	    ++offset;
2633	    if (offset >= banksize) {
2634		offset = 0;
2635		++bank;		/* next bank */
2636		(*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2637	    }
2638	    outw(GDCIDX, 0xff08);	/* bit mask */
2639	}
2640	++y;
2641	--cy;
2642    }
2643
2644    outw(GDCIDX, 0xff08);		/* bit mask */
2645    outw(GDCIDX, 0x0000);		/* set/reset */
2646    outw(GDCIDX, 0x0001);		/* set/reset enable */
2647}
2648
2649static void
2650packed_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2651{
2652    int banksize;
2653    int bank;
2654    int pos;
2655    int offset;			/* offset within window */
2656    int end;
2657
2658    banksize = adp->va_window_size;
2659    bank = -1;
2660    cx *= adp->va_info.vi_pixel_size;
2661    while (cy > 0) {
2662	pos = adp->va_line_width*y + x*adp->va_info.vi_pixel_size;
2663	if (bank != pos/banksize) {
2664	    (*vidsw[adp->va_index]->set_win_org)(adp, pos);
2665	    bank = pos/banksize;
2666	}
2667	offset = pos%banksize;
2668	end = imin(offset + cx, banksize);
2669	fill_io(val, adp->va_window + offset,
2670		(end - offset)/adp->va_info.vi_pixel_size);
2671	/* the line may cross the window boundary */
2672	if (offset + cx > banksize) {
2673	    ++bank;		/* next bank */
2674	    (*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2675	    end = offset + cx - banksize;
2676	    fill_io(val, adp->va_window, end/adp->va_info.vi_pixel_size);
2677	}
2678	++y;
2679	--cy;
2680    }
2681}
2682
2683static void
2684direct_fill_rect16(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2685{
2686    int banksize;
2687    int bank;
2688    int pos;
2689    int offset;			/* offset within window */
2690    int end;
2691
2692    /*
2693     * XXX: the function assumes that banksize is a muliple of
2694     * sizeof(u_int16_t).
2695     */
2696    banksize = adp->va_window_size;
2697    bank = -1;
2698    cx *= sizeof(u_int16_t);
2699    while (cy > 0) {
2700	pos = adp->va_line_width*y + x*sizeof(u_int16_t);
2701	if (bank != pos/banksize) {
2702	    (*vidsw[adp->va_index]->set_win_org)(adp, pos);
2703	    bank = pos/banksize;
2704	}
2705	offset = pos%banksize;
2706	end = imin(offset + cx, banksize);
2707	fillw_io(val, adp->va_window + offset,
2708		 (end - offset)/sizeof(u_int16_t));
2709	/* the line may cross the window boundary */
2710	if (offset + cx > banksize) {
2711	    ++bank;		/* next bank */
2712	    (*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2713	    end = offset + cx - banksize;
2714	    fillw_io(val, adp->va_window, end/sizeof(u_int16_t));
2715	}
2716	++y;
2717	--cy;
2718    }
2719}
2720
2721static void
2722direct_fill_rect24(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2723{
2724    int banksize;
2725    int bank;
2726    int pos;
2727    int offset;			/* offset within window */
2728    int end;
2729    int i;
2730    int j;
2731    u_int8_t b[3];
2732
2733    b[0] = val & 0x0000ff;
2734    b[1] = (val >> 8) & 0x0000ff;
2735    b[2] = (val >> 16) & 0x0000ff;
2736    banksize = adp->va_window_size;
2737    bank = -1;
2738    cx *= 3;
2739    while (cy > 0) {
2740	pos = adp->va_line_width*y + x*3;
2741	if (bank != pos/banksize) {
2742	    (*vidsw[adp->va_index]->set_win_org)(adp, pos);
2743	    bank = pos/banksize;
2744	}
2745	offset = pos%banksize;
2746	end = imin(offset + cx, banksize);
2747	for (i = 0, j = offset; j < end; i = (++i)%3, ++j) {
2748	    writeb(adp->va_window + j, b[i]);
2749	}
2750	/* the line may cross the window boundary */
2751	if (offset + cx >= banksize) {
2752	    ++bank;		/* next bank */
2753	    (*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2754	    j = 0;
2755	    end = offset + cx - banksize;
2756	    for (; j < end; i = (++i)%3, ++j) {
2757		writeb(adp->va_window + j, b[i]);
2758	    }
2759	}
2760	++y;
2761	--cy;
2762    }
2763}
2764
2765static void
2766direct_fill_rect32(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2767{
2768    int banksize;
2769    int bank;
2770    int pos;
2771    int offset;			/* offset within window */
2772    int end;
2773
2774    /*
2775     * XXX: the function assumes that banksize is a muliple of
2776     * sizeof(u_int32_t).
2777     */
2778    banksize = adp->va_window_size;
2779    bank = -1;
2780    cx *= sizeof(u_int32_t);
2781    while (cy > 0) {
2782	pos = adp->va_line_width*y + x*sizeof(u_int32_t);
2783	if (bank != pos/banksize) {
2784	    (*vidsw[adp->va_index]->set_win_org)(adp, pos);
2785	    bank = pos/banksize;
2786	}
2787	offset = pos%banksize;
2788	end = imin(offset + cx, banksize);
2789	filll_io(val, adp->va_window + offset,
2790		 (end - offset)/sizeof(u_int32_t));
2791	/* the line may cross the window boundary */
2792	if (offset + cx > banksize) {
2793	    ++bank;		/* next bank */
2794	    (*vidsw[adp->va_index]->set_win_org)(adp, bank*banksize);
2795	    end = offset + cx - banksize;
2796	    filll_io(val, adp->va_window, end/sizeof(u_int32_t));
2797	}
2798	++y;
2799	--cy;
2800    }
2801}
2802
2803static int
2804vga_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2805{
2806    switch (adp->va_info.vi_mem_model) {
2807    case V_INFO_MM_TEXT:
2808	/* do nothing? XXX */
2809	break;
2810    case V_INFO_MM_PLANAR:
2811	planar_fill_rect(adp, val, x, y, cx, cy);
2812	break;
2813    case V_INFO_MM_PACKED:
2814	packed_fill_rect(adp, val, x, y, cx, cy);
2815	break;
2816    case V_INFO_MM_DIRECT:
2817	switch (adp->va_info.vi_pixel_size) {
2818	case sizeof(u_int16_t):
2819	    direct_fill_rect16(adp, val, x, y, cx, cy);
2820	    break;
2821	case 3:
2822	    direct_fill_rect24(adp, val, x, y, cx, cy);
2823	    break;
2824	case sizeof(u_int32_t):
2825	    direct_fill_rect32(adp, val, x, y, cx, cy);
2826	    break;
2827	}
2828	break;
2829    }
2830    return 0;
2831}
2832#else /* !notyet */
2833static int
2834vga_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
2835{
2836    return ENODEV;
2837}
2838#endif /* notyet */
2839
2840static int
2841vga_bitblt(video_adapter_t *adp,...)
2842{
2843    /* FIXME */
2844    return ENODEV;
2845}
2846
2847#endif /* !VGA_NO_MODE_CHANGE */
2848
2849static int
2850get_palette(video_adapter_t *adp, int base, int count,
2851	    u_char *red, u_char *green, u_char *blue, u_char *trans)
2852{
2853    u_char *r;
2854    u_char *g;
2855    u_char *b;
2856
2857    if (count < 0 || base < 0 || count > 256 || base > 256 ||
2858	base + count > 256)
2859	return EINVAL;
2860
2861    r = malloc(count*3, M_DEVBUF, M_WAITOK);
2862    g = r + count;
2863    b = g + count;
2864    if (vga_save_palette2(adp, base, count, r, g, b)) {
2865	free(r, M_DEVBUF);
2866	return ENODEV;
2867    }
2868    copyout(r, red, count);
2869    copyout(g, green, count);
2870    copyout(b, blue, count);
2871    if (trans != NULL) {
2872	bzero(r, count);
2873	copyout(r, trans, count);
2874    }
2875    free(r, M_DEVBUF);
2876
2877    return 0;
2878}
2879
2880static int
2881set_palette(video_adapter_t *adp, int base, int count,
2882	    u_char *red, u_char *green, u_char *blue, u_char *trans)
2883{
2884    u_char *r;
2885    u_char *g;
2886    u_char *b;
2887    int err;
2888
2889    if (count < 0 || base < 0 || count > 256 || base > 256 ||
2890	base + count > 256)
2891	return EINVAL;
2892
2893    r = malloc(count*3, M_DEVBUF, M_WAITOK);
2894    g = r + count;
2895    b = g + count;
2896    copyin(red, r, count);
2897    copyin(green, g, count);
2898    copyin(blue, b, count);
2899    err = vga_load_palette2(adp, base, count, r, g, b);
2900    free(r, M_DEVBUF);
2901
2902    return (err ? ENODEV : 0);
2903}
2904
2905static int
2906vga_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
2907{
2908    switch (cmd) {
2909    case FBIO_GETWINORG:	/* get frame buffer window origin */
2910	*(u_int *)arg = 0;
2911	return 0;
2912
2913    case FBIO_SETWINORG:	/* set frame buffer window origin */
2914	return ENODEV;
2915
2916    case FBIO_SETDISPSTART:	/* set display start address */
2917	return (set_display_start(adp,
2918				  ((video_display_start_t *)arg)->x,
2919			  	  ((video_display_start_t *)arg)->y)
2920		? ENODEV : 0);
2921
2922    case FBIO_SETLINEWIDTH:	/* set scan line length in pixel */
2923	return (set_line_length(adp, *(u_int *)arg) ? ENODEV : 0);
2924
2925    case FBIO_GETPALETTE:	/* get color palette */
2926	return get_palette(adp, ((video_color_palette_t *)arg)->index,
2927			   ((video_color_palette_t *)arg)->count,
2928			   ((video_color_palette_t *)arg)->red,
2929			   ((video_color_palette_t *)arg)->green,
2930			   ((video_color_palette_t *)arg)->blue,
2931			   ((video_color_palette_t *)arg)->transparent);
2932
2933    case FBIO_SETPALETTE:	/* set color palette */
2934	return set_palette(adp, ((video_color_palette_t *)arg)->index,
2935			   ((video_color_palette_t *)arg)->count,
2936			   ((video_color_palette_t *)arg)->red,
2937			   ((video_color_palette_t *)arg)->green,
2938			   ((video_color_palette_t *)arg)->blue,
2939			   ((video_color_palette_t *)arg)->transparent);
2940
2941    case FBIOGTYPE:		/* get frame buffer type info. */
2942	((struct fbtype *)arg)->fb_type = fb_type(adp->va_type);
2943	((struct fbtype *)arg)->fb_height = adp->va_info.vi_height;
2944	((struct fbtype *)arg)->fb_width = adp->va_info.vi_width;
2945	((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth;
2946	if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8))
2947	    ((struct fbtype *)arg)->fb_cmsize = 0;
2948	else
2949	    ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth;
2950	((struct fbtype *)arg)->fb_size = adp->va_buffer_size;
2951	return 0;
2952
2953    case FBIOGETCMAP:		/* get color palette */
2954	return get_palette(adp, ((struct fbcmap *)arg)->index,
2955			   ((struct fbcmap *)arg)->count,
2956			   ((struct fbcmap *)arg)->red,
2957			   ((struct fbcmap *)arg)->green,
2958			   ((struct fbcmap *)arg)->blue, NULL);
2959
2960    case FBIOPUTCMAP:		/* set color palette */
2961	return set_palette(adp, ((struct fbcmap *)arg)->index,
2962			   ((struct fbcmap *)arg)->count,
2963			   ((struct fbcmap *)arg)->red,
2964			   ((struct fbcmap *)arg)->green,
2965			   ((struct fbcmap *)arg)->blue, NULL);
2966
2967    default:
2968	return fb_commonioctl(adp, cmd, arg);
2969    }
2970}
2971
2972static void
2973dump_buffer(u_char *buf, size_t len)
2974{
2975    int i;
2976
2977    for(i = 0; i < len;) {
2978	printf("%02x ", buf[i]);
2979	if ((++i % 16) == 0)
2980	    printf("\n");
2981    }
2982}
2983
2984/*
2985 * diag():
2986 * Print some information about the video adapter and video modes,
2987 * with requested level of details.
2988 *
2989 * all adapters
2990 */
2991static int
2992vga_diag(video_adapter_t *adp, int level)
2993{
2994    u_char *mp;
2995#if FB_DEBUG > 1
2996    video_info_t info;
2997    int i;
2998#endif
2999
3000    if (!vga_init_done)
3001	return ENXIO;
3002
3003#if FB_DEBUG > 1
3004#ifndef VGA_NO_BIOS
3005    printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n",
3006	   rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488)));
3007    printf("vga: CRTC:0x%x, video option:0x%02x, ",
3008	   readw(BIOS_PADDRTOVADDR(0x463)),
3009	   readb(BIOS_PADDRTOVADDR(0x487)));
3010    printf("rows:%d, cols:%d, font height:%d\n",
3011	   readb(BIOS_PADDRTOVADDR(0x44a)),
3012	   readb(BIOS_PADDRTOVADDR(0x484)) + 1,
3013	   readb(BIOS_PADDRTOVADDR(0x485)));
3014#endif /* VGA_NO_BIOS */
3015#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
3016    printf("vga: param table EGA/VGA:%p", video_mode_ptr);
3017    printf(", CGA/MDA:%p\n", video_mode_ptr2);
3018    printf("vga: rows_offset:%d\n", rows_offset);
3019#endif
3020#endif /* FB_DEBUG > 1 */
3021
3022    fb_dump_adp_info(VGA_DRIVER_NAME, adp, level);
3023
3024#if FB_DEBUG > 1
3025    if (adp->va_flags & V_ADP_MODECHANGE) {
3026	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
3027	    if (bios_vmode[i].vi_mode == NA)
3028		continue;
3029	    if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
3030		continue;
3031	    fb_dump_mode_info(VGA_DRIVER_NAME, adp, &bios_vmode[i], level);
3032	}
3033    } else {
3034	vga_get_info(adp, adp->va_initial_mode, &info);	/* shouldn't fail */
3035	fb_dump_mode_info(VGA_DRIVER_NAME, adp, &info, level);
3036    }
3037#endif /* FB_DEBUG > 1 */
3038
3039    if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA))
3040	return 0;
3041#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
3042    if (video_mode_ptr == NULL)
3043	printf("vga%d: %s: WARNING: video mode switching is not "
3044	       "fully supported on this adapter\n",
3045	       adp->va_unit, adp->va_name);
3046#endif
3047    if (level <= 0)
3048	return 0;
3049
3050    if (adp->va_type == KD_VGA) {
3051	printf("VGA parameters upon power-up\n");
3052	dump_buffer(adpstate.regs, sizeof(adpstate.regs));
3053	printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode);
3054	dump_buffer(adpstate2.regs, sizeof(adpstate2.regs));
3055    }
3056
3057    mp = get_mode_param(adp->va_initial_mode);
3058    if (mp == NULL)	/* this shouldn't be happening */
3059	return 0;
3060    printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode);
3061    dump_buffer(mp, V_MODE_PARAM_SIZE);
3062
3063    return 0;
3064}
3065