xref: /freebsd/sys/dev/fb/vga.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
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$");
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 
74 int
75 vga_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 
91 int
92 vga_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 
111 int
112 vga_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 
122 int
123 vga_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 
128 int
129 vga_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 
134 int
135 vga_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 
140 int
141 vga_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 
147 int
148 vga_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 */
193 struct adp_state {
194     int			sig;
195 #define V_STATE_SIG	0x736f6962
196     u_char		regs[V_MODE_PARAM_SIZE];
197 };
198 typedef 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  */
213 static 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 
240 static video_adapter_t	biosadapter[2];
241 static int		biosadapters = 0;
242 
243 /* video driver declarations */
244 static int			vga_configure(int flags);
245        int			(*vga_sub_configure)(int flags);
246 #if 0
247 static int			vga_nop(void);
248 #endif
249 static int			vga_error(void);
250 static vi_probe_t		vga_probe;
251 static vi_init_t		vga_init;
252 static vi_get_info_t		vga_get_info;
253 static vi_query_mode_t		vga_query_mode;
254 static vi_set_mode_t		vga_set_mode;
255 static vi_save_font_t		vga_save_font;
256 static vi_load_font_t		vga_load_font;
257 static vi_show_font_t		vga_show_font;
258 static vi_save_palette_t	vga_save_palette;
259 static vi_load_palette_t	vga_load_palette;
260 static vi_set_border_t		vga_set_border;
261 static vi_save_state_t		vga_save_state;
262 static vi_load_state_t		vga_load_state;
263 static vi_set_win_org_t		vga_set_origin;
264 static vi_read_hw_cursor_t	vga_read_hw_cursor;
265 static vi_set_hw_cursor_t	vga_set_hw_cursor;
266 static vi_set_hw_cursor_shape_t	vga_set_hw_cursor_shape;
267 static vi_blank_display_t	vga_blank_display;
268 static vi_mmap_t		vga_mmap_buf;
269 static vi_ioctl_t		vga_dev_ioctl;
270 #ifndef VGA_NO_MODE_CHANGE
271 static vi_clear_t		vga_clear;
272 static vi_fill_rect_t		vga_fill_rect;
273 static 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
279 static vi_diag_t		vga_diag;
280 
281 static 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 
310 VIDEO_DRIVER(mda, vgavidsw, NULL);
311 VIDEO_DRIVER(cga, vgavidsw, NULL);
312 VIDEO_DRIVER(ega, vgavidsw, NULL);
313 VIDEO_DRIVER(vga, vgavidsw, vga_configure);
314 
315 /* VGA BIOS standard video modes */
316 #define EOT		(-1)
317 #define NA		(-2)
318 
319 static 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 
436 static int		vga_init_done = FALSE;
437 #if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE)
438 static u_char		*video_mode_ptr = NULL;		/* EGA/VGA */
439 static u_char		*video_mode_ptr2 = NULL;	/* CGA/MDA */
440 #endif
441 static u_char		*mode_map[V_MODE_MAP_SIZE];
442 static adp_state_t	adpstate;
443 static adp_state_t	adpstate2;
444 static 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)
450 static void map_mode_table(u_char *map[], u_char *table, int max);
451 #endif
452 static 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)
455 static int map_mode_num(int mode);
456 #endif
457 static int map_gen_mode_num(int type, int color, int mode);
458 static int map_bios_mode_num(int type, int color, int bios_mode);
459 static u_char *get_mode_param(int mode);
460 #ifndef VGA_NO_BIOS
461 static void fill_adapter_param(int code, video_adapter_t *adp);
462 #endif
463 static int verify_adapter(video_adapter_t *adp);
464 static 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
469 static int comp_adpregs(u_char *buf1, u_char *buf2);
470 #endif
471 static int probe_adapters(void);
472 static int set_line_length(video_adapter_t *adp, int pixel);
473 static int set_display_start(video_adapter_t *adp, int x, int y);
474 static void filll_io(int val, vm_offset_t d, size_t size);
475 
476 #ifndef VGA_NO_MODE_CHANGE
477 #ifdef VGA_WIDTH90
478 static 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
484 static void set_font_mode(video_adapter_t *adp, u_char *buf);
485 static void set_normal_mode(video_adapter_t *adp, u_char *buf);
486 #endif
487 
488 #ifndef VGA_NO_MODE_CHANGE
489 static void planar_fill(video_adapter_t *adp, int val);
490 static void packed_fill(video_adapter_t *adp, int val);
491 static void direct_fill(video_adapter_t *adp, int val);
492 #ifdef notyet
493 static void planar_fill_rect(video_adapter_t *adp, int val, int x, int y,
494 			     int cx, int cy);
495 static void packed_fill_rect(video_adapter_t *adp, int val, int x, int y,
496 			     int cx, int cy);
497 static void direct_fill_rect16(video_adapter_t *adp, int val, int x, int y,
498 			       int cx, int cy);
499 static void direct_fill_rect24(video_adapter_t *adp, int val, int x, int y,
500 			       int cx, int cy);
501 static 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 
506 static 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 */
517 static int
518 vga_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 */
543 static void
544 map_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 
555 static void
556 clear_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 */
575 static int
576 map_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 */
615 static int
616 map_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 */
667 static int
668 map_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 */
741 static 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
755 static void
756 fill_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 
786 static int
787 verify_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 
851 static void
852 update_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 */
894 static int
895 comp_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 */
935 static int
936 probe_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 */
1234 static int
1235 set_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 
1275 static int
1276 set_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 */
1334 static void
1335 fill(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 
1344 static void
1345 filll_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
1356 static int
1357 vga_nop(void)
1358 {
1359     return 0;
1360 }
1361 #endif
1362 
1363 static int
1364 vga_error(void)
1365 {
1366     return ENODEV;
1367 }
1368 
1369 static int
1370 vga_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 
1381 static int
1382 vga_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  */
1409 static int
1410 vga_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  */
1459 static int
1460 vga_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
1511 static void
1512 set_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 
1531 static int
1532 vga_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;
1570 special_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:
1595 special_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 
1613 setup_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 
1645 setup_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 
1668 static void
1669 set_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 
1734 static void
1735 set_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  */
1791 static int
1792 vga_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  */
1871 static int
1872 vga_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  */
1951 static int
1952 vga_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  */
1978 static int
1979 vga_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 
1996 static int
1997 vga_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  */
2020 static int
2021 vga_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 
2036 static int
2037 vga_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  */
2062 static int
2063 vga_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  */
2092 static int
2093 vga_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  */
2178 static int
2179 vga_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  */
2246 static int
2247 vga_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  */
2262 static int
2263 vga_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  */
2294 static int
2295 vga_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  */
2328 static int
2329 vga_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  */
2383 static int
2384 vga_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  */
2466 static int
2467 vga_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 
2488 static void
2489 planar_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 
2513 static void
2514 packed_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 
2531 static void
2532 direct_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 
2559 static int
2560 vga_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
2580 static void
2581 planar_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 
2649 static void
2650 packed_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 
2683 static void
2684 direct_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 
2721 static void
2722 direct_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 
2765 static void
2766 direct_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 
2803 static int
2804 vga_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 */
2833 static int
2834 vga_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 
2840 static int
2841 vga_bitblt(video_adapter_t *adp,...)
2842 {
2843     /* FIXME */
2844     return ENODEV;
2845 }
2846 
2847 #endif /* !VGA_NO_MODE_CHANGE */
2848 
2849 static int
2850 get_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 
2880 static int
2881 set_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 
2905 static int
2906 vga_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 
2972 static void
2973 dump_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  */
2991 static int
2992 vga_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