4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5 * Copyright (c) 1992-1998 Søren Schmidt
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer as
13 * the first lines of this file unmodified.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * $FreeBSD: src/sys/dev/fb/vga.c,v 1.9.2.1 2001/08/11 02:58:44 yokota Exp $
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
41 #include <sys/fcntl.h>
42 #include <sys/malloc.h>
44 #include <sys/thread2.h>
46 #include <bus/isa/isareg.h>
48 #include <machine/clock.h>
49 #include <machine/md_var.h>
51 #include <machine/pc/bios.h>
55 #include <vm/vm_param.h>
66 vga_probe_unit(int unit
, video_adapter_t
*buf
, int flags
)
72 sw
= vid_get_switch(VGA_DRIVER_NAME
);
75 error
= (*sw
->probe
)(unit
, &adp
, NULL
, flags
);
78 bcopy(adp
, buf
, sizeof(*buf
));
83 vga_attach_unit(int unit
, vga_softc_t
*sc
, int flags
)
88 sw
= vid_get_switch(VGA_DRIVER_NAME
);
92 error
= (*sw
->probe
)(unit
, &sc
->adp
, NULL
, flags
);
95 return (*sw
->init
)(unit
, sc
->adp
, flags
);
98 /* cdev driver functions */
100 #ifdef FB_INSTALL_CDEV
105 vga_open(cdev_t dev
, vga_softc_t
*sc
, int flag
, int mode
, struct ucred
*cred
)
109 if (mode
& (O_CREAT
| O_APPEND
| O_TRUNC
))
112 return genfbopen(&sc
->gensc
, sc
->adp
, flag
, mode
, cred
);
116 vga_close(cdev_t dev
, vga_softc_t
*sc
, int flag
, int mode
)
118 return genfbclose(&sc
->gensc
, sc
->adp
, flag
, mode
);
122 vga_read(cdev_t dev
, vga_softc_t
*sc
, struct uio
*uio
, int flag
)
124 return genfbread(&sc
->gensc
, sc
->adp
, uio
, flag
);
128 vga_write(cdev_t dev
, vga_softc_t
*sc
, struct uio
*uio
, int flag
)
130 return genfbread(&sc
->gensc
, sc
->adp
, uio
, flag
);
134 vga_ioctl(cdev_t dev
, vga_softc_t
*sc
, u_long cmd
, caddr_t arg
, int flag
,
137 return genfbioctl(&sc
->gensc
, sc
->adp
, cmd
, arg
, flag
, cred
);
141 vga_mmap(cdev_t dev
, vga_softc_t
*sc
, vm_offset_t offset
, int prot
)
143 return genfbmmap(&sc
->gensc
, sc
->adp
, offset
, prot
);
146 #endif /* FB_INSTALL_CDEV */
150 #define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED)
151 #define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED)
152 #define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED)
155 #define V_MODE_MAP_SIZE (M_VGA_CG320 + 1)
156 #define V_MODE_PARAM_SIZE 64
158 /* video adapter state buffer */
161 #define V_STATE_SIG 0x736f6962
162 u_char regs
[V_MODE_PARAM_SIZE
];
164 typedef struct adp_state adp_state_t
;
167 * NOTE: `va_window' should have a virtual address, but is initialized
168 * with a physical address in the following table, as verify_adapter()
169 * will perform address conversion at run-time.
171 static video_adapter_t biosadapter
= {
172 0, KD_VGA
, VGA_DRIVER_NAME
, 0, 0, V_ADP_COLOR
, IO_VGA
, 32,
173 EGA_BUF_BASE
, EGA_BUF_SIZE
, CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
,
174 0, 0, 0, M_VGA_C80x25
, M_C80x25
, M_VGA_C80x25
177 /* video driver declarations */
178 static int vga_configure(int flags
);
179 int (*vga_sub_configure
)(int flags
);
180 static int vga_error(void);
181 static vi_probe_t vga_probe
;
182 static vi_init_t vga_init
;
183 static vi_get_info_t vga_get_info
;
184 static vi_query_mode_t vga_query_mode
;
185 static vi_set_mode_t vga_set_mode
;
186 static vi_save_font_t vga_save_font
;
187 static vi_load_font_t vga_load_font
;
188 static vi_show_font_t vga_show_font
;
189 static vi_save_palette_t vga_save_palette
;
190 static vi_load_palette_t vga_load_palette
;
191 static vi_set_border_t vga_set_border
;
192 static vi_save_state_t vga_save_state
;
193 static vi_load_state_t vga_load_state
;
194 static vi_set_win_org_t vga_set_origin
;
195 static vi_read_hw_cursor_t vga_read_hw_cursor
;
196 static vi_set_hw_cursor_t vga_set_hw_cursor
;
197 static vi_set_hw_cursor_shape_t vga_set_hw_cursor_shape
;
198 static vi_blank_display_t vga_blank_display
;
199 static vi_mmap_t vga_mmap_buf
;
200 static vi_ioctl_t vga_dev_ioctl
;
201 #ifndef VGA_NO_MODE_CHANGE
202 static vi_clear_t vga_clear
;
203 static vi_fill_rect_t vga_fill_rect
;
204 static vi_bitblt_t vga_bitblt
;
205 #else /* VGA_NO_MODE_CHANGE */
206 #define vga_clear (vi_clear_t *)vga_error
207 #define vga_fill_rect (vi_fill_rect_t *)vga_error
208 #define vga_bitblt (vi_bitblt_t *)vga_error
210 static vi_diag_t vga_diag
;
212 static video_switch_t vgavidsw
= {
229 vga_set_hw_cursor_shape
,
241 VIDEO_DRIVER(vga
, vgavidsw
, vga_configure
);
243 /* VGA BIOS standard video modes */
247 static video_info_t bios_vmode
[] = {
249 { M_B40x25
, V_INFO_COLOR
, 40, 25, 8, 8, 2, 1,
250 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
251 { M_C40x25
, V_INFO_COLOR
, 40, 25, 8, 8, 4, 1,
252 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
253 { M_B80x25
, V_INFO_COLOR
, 80, 25, 8, 8, 2, 1,
254 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
255 { M_C80x25
, V_INFO_COLOR
, 80, 25, 8, 8, 4, 1,
256 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
258 { M_ENH_B40x25
, V_INFO_COLOR
, 40, 25, 8, 14, 2, 1,
259 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
260 { M_ENH_C40x25
, V_INFO_COLOR
, 40, 25, 8, 14, 4, 1,
261 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
262 { M_ENH_B80x25
, V_INFO_COLOR
, 80, 25, 8, 14, 2, 1,
263 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
264 { M_ENH_C80x25
, V_INFO_COLOR
, 80, 25, 8, 14, 4, 1,
265 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
267 { M_VGA_C40x25
, V_INFO_COLOR
, 40, 25, 8, 16, 4, 1,
268 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
269 { M_VGA_M80x25
, 0, 80, 25, 8, 16, 2, 1,
270 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
271 { M_VGA_C80x25
, V_INFO_COLOR
, 80, 25, 8, 16, 4, 1,
272 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
274 { M_EGAMONO80x25
, 0, 80, 25, 8, 14, 2, 1,
275 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
277 { M_ENH_B80x43
, 0, 80, 43, 8, 8, 2, 1,
278 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
279 { M_ENH_C80x43
, V_INFO_COLOR
, 80, 43, 8, 8, 4, 1,
280 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
282 { M_VGA_M80x30
, 0, 80, 30, 8, 16, 2, 1,
283 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
284 { M_VGA_C80x30
, V_INFO_COLOR
, 80, 30, 8, 16, 4, 1,
285 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
286 { M_VGA_M80x50
, 0, 80, 50, 8, 8, 2, 1,
287 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
288 { M_VGA_C80x50
, V_INFO_COLOR
, 80, 50, 8, 8, 4, 1,
289 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
290 { M_VGA_M80x60
, 0, 80, 60, 8, 8, 2, 1,
291 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
292 { M_VGA_C80x60
, V_INFO_COLOR
, 80, 60, 8, 8, 4, 1,
293 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
295 #ifndef VGA_NO_MODE_CHANGE
298 { M_VGA_M90x25
, 0, 90, 25, 8, 16, 2, 1,
299 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
300 { M_VGA_C90x25
, V_INFO_COLOR
, 90, 25, 8, 16, 4, 1,
301 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
302 { M_VGA_M90x30
, 0, 90, 30, 8, 16, 2, 1,
303 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
304 { M_VGA_C90x30
, V_INFO_COLOR
, 90, 30, 8, 16, 4, 1,
305 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
306 { M_VGA_M90x43
, 0, 90, 43, 8, 8, 2, 1,
307 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
308 { M_VGA_C90x43
, V_INFO_COLOR
, 90, 43, 8, 8, 4, 1,
309 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
310 { M_VGA_M90x50
, 0, 90, 50, 8, 8, 2, 1,
311 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
312 { M_VGA_C90x50
, V_INFO_COLOR
, 90, 50, 8, 8, 4, 1,
313 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
314 { M_VGA_M90x60
, 0, 90, 60, 8, 8, 2, 1,
315 MDA_BUF_BASE
, MDA_BUF_SIZE
, MDA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
316 { M_VGA_C90x60
, V_INFO_COLOR
, 90, 60, 8, 8, 4, 1,
317 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_TEXT
},
318 #endif /* VGA_WIDTH90 */
321 { M_BG320
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 320, 200, 8, 8, 2, 1,
322 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_CGA
},
323 { M_CG320
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 320, 200, 8, 8, 2, 1,
324 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_CGA
},
325 { M_BG640
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 640, 200, 8, 8, 1, 1,
326 CGA_BUF_BASE
, CGA_BUF_SIZE
, CGA_BUF_SIZE
, 0, 0, V_INFO_MM_CGA
},
328 { M_CG320_D
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 320, 200, 8, 8, 4, 4,
329 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0,
331 { M_CG640_E
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 640, 200, 8, 8, 4, 4,
332 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0 ,
334 { M_EGAMONOAPA
, V_INFO_GRAPHICS
, 640, 350, 8, 14, 4, 4,
335 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, 64*1024, 0, 0 ,
337 { M_ENHMONOAPA2
,V_INFO_GRAPHICS
, 640, 350, 8, 14, 4, 4,
338 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0 ,
340 { M_CG640x350
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 640, 350, 8, 14, 2, 2,
341 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0 ,
343 { M_ENH_CG640
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 640, 350, 8, 14, 4, 4,
344 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0 ,
347 { M_BG640x480
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 640, 480, 8, 16, 4, 4,
348 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0 ,
350 { M_CG640x480
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 640, 480, 8, 16, 4, 4,
351 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0 ,
353 { M_VGA_CG320
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 320, 200, 8, 8, 8, 1,
354 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0,
355 V_INFO_MM_PACKED
, 1 },
356 { M_VGA_MODEX
, V_INFO_COLOR
| V_INFO_GRAPHICS
, 320, 240, 8, 8, 8, 4,
357 GRAPHICS_BUF_BASE
, GRAPHICS_BUF_SIZE
, GRAPHICS_BUF_SIZE
, 0, 0,
359 #endif /* VGA_NO_MODE_CHANGE */
364 static int vga_init_done
= FALSE
;
365 #ifndef VGA_NO_MODE_CHANGE
366 static u_char
*video_mode_ptr
= NULL
;
368 static u_char
*mode_map
[V_MODE_MAP_SIZE
];
369 static adp_state_t adpstate
;
370 static adp_state_t adpstate2
;
371 static int rows_offset
= 1;
373 /* local macros and functions */
374 #define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
376 #ifndef VGA_NO_MODE_CHANGE
377 static void map_mode_table(u_char
**, u_char
*);
378 static int map_mode_num(int);
379 static int map_bios_mode_num(int);
381 static u_char
*get_mode_param(int);
382 static int verify_adapter(video_adapter_t
*);
383 static void update_adapter_info(video_adapter_t
*, video_info_t
*);
384 static int probe_adapters(void);
385 static int set_line_length(video_adapter_t
*, int);
386 static int set_display_start(video_adapter_t
*, int, int);
388 #ifndef VGA_NO_MODE_CHANGE
390 static void set_width90(adp_state_t
*);
392 #endif /* !VGA_NO_MODE_CHANGE */
394 #ifndef VGA_NO_FONT_LOADING
395 #define PARAM_BUFSIZE 6
396 static void set_font_mode(video_adapter_t
*, u_char
*);
397 static void set_normal_mode(video_adapter_t
*, u_char
*);
400 #ifndef VGA_NO_MODE_CHANGE
401 static void filll_io(int, vm_offset_t
, size_t);
402 static void planar_fill(video_adapter_t
*, int);
403 static void packed_fill(video_adapter_t
*, int);
404 static void direct_fill(video_adapter_t
*, int);
405 #endif /* !VGA_NO_MODE_CHANGE */
407 #define ISMAPPED(pa, width) \
408 (((pa) <= (u_long)0x1000 - (width)) \
409 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width)))
411 #define prologue(adp, flag, err) \
412 if (!vga_init_done || !((adp)->va_flags & (flag))) \
415 /* a backdoor for the console driver */
417 vga_configure(int flags
)
420 if (probe_done(&biosadapter
)) {
421 biosadapter
.va_flags
|= V_ADP_INITIALIZED
;
422 if (!config_done(&biosadapter
) && !(vid_register(&biosadapter
) < 0))
423 biosadapter
.va_flags
|= V_ADP_REGISTERED
;
425 if (vga_sub_configure
!= NULL
)
426 (*vga_sub_configure
)(flags
);
431 /* local subroutines */
433 #ifndef VGA_NO_MODE_CHANGE
434 /* construct the mode parameter map (accept 40x25, 80x25 and 80x30 modes) */
436 map_mode_table(u_char
*map
[], u_char
*table
)
440 for(i
= 0; i
< V_MODE_MAP_SIZE
; ++i
) {
441 map
[i
] = table
+ i
*V_MODE_PARAM_SIZE
;
443 if ((map
[i
][0] == 40 && map
[i
][1] == 24) ||
444 (map
[i
][0] == 80 && (map
[i
][1] == 24 || map
[i
][1] == 29)))
450 #endif /* !VGA_NO_MODE_CHANGE */
452 #ifndef VGA_NO_MODE_CHANGE
453 /* map the non-standard video mode to a known mode number */
455 map_mode_num(int mode
)
461 { M_ENH_B80x43
, M_ENH_B80x25
},
462 { M_ENH_C80x43
, M_ENH_C80x25
},
463 { M_VGA_M80x30
, M_VGA_M80x25
},
464 { M_VGA_C80x30
, M_VGA_C80x25
},
465 { M_VGA_M80x50
, M_VGA_M80x25
},
466 { M_VGA_C80x50
, M_VGA_C80x25
},
467 { M_VGA_M80x60
, M_VGA_M80x25
},
468 { M_VGA_C80x60
, M_VGA_C80x25
},
470 { M_VGA_M90x25
, M_VGA_M80x25
},
471 { M_VGA_C90x25
, M_VGA_C80x25
},
472 { M_VGA_M90x30
, M_VGA_M80x25
},
473 { M_VGA_C90x30
, M_VGA_C80x25
},
474 { M_VGA_M90x43
, M_ENH_B80x25
},
475 { M_VGA_C90x43
, M_ENH_C80x25
},
476 { M_VGA_M90x50
, M_VGA_M80x25
},
477 { M_VGA_C90x50
, M_VGA_C80x25
},
478 { M_VGA_M90x60
, M_VGA_M80x25
},
479 { M_VGA_C90x60
, M_VGA_C80x25
},
481 { M_VGA_MODEX
, M_VGA_CG320
},
485 for (i
= 0; i
< NELEM(mode_map
); ++i
) {
486 if (mode_map
[i
].from
== mode
)
487 return mode_map
[i
].to
;
492 /* turn the BIOS video number into our video mode number */
494 map_bios_mode_num(int bios_mode
)
496 static int vga_modes
[20] = {
497 M_VGA_C40x25
, M_VGA_C40x25
, /* 0, 1 */
498 M_VGA_C80x25
, M_VGA_C80x25
, /* 2, 3 */
501 M_VGA_M80x25
, /* 7 */
507 M_BG640x480
, M_CG640x480
,
511 if (bios_mode
< NELEM(vga_modes
))
512 return vga_modes
[bios_mode
];
516 #endif /* !VGA_NO_MODE_CHANGE */
518 /* look up a parameter table entry */
520 get_mode_param(int mode
)
522 #ifndef VGA_NO_MODE_CHANGE
523 if (mode
>= V_MODE_MAP_SIZE
)
524 mode
= map_mode_num(mode
);
526 if ((mode
>= 0) && (mode
< V_MODE_MAP_SIZE
))
527 return mode_map
[mode
];
533 verify_adapter(video_adapter_t
*adp
)
537 #ifndef VGA_NO_MODE_CHANGE
541 buf
= BIOS_PADDRTOVADDR(adp
->va_window
);
544 if (readw(buf
) != 0xA55A)
552 adp
->va_flags
|= V_ADP_STATELOAD
| V_ADP_STATESAVE
| V_ADP_PALETTE
|
555 #ifndef VGA_NO_MODE_CHANGE
556 /* get the BIOS video mode pointer */
557 p
= *(u_int32_t
*)BIOS_PADDRTOVADDR(0x4a8);
558 p
= BIOS_SADDRTOLADDR(p
);
559 if (ISMAPPED(p
, sizeof(u_int32_t
))) {
560 p
= *(u_int32_t
*)BIOS_PADDRTOVADDR(p
);
561 p
= BIOS_SADDRTOLADDR(p
);
562 if (ISMAPPED(p
, V_MODE_PARAM_SIZE
))
563 video_mode_ptr
= (u_char
*)BIOS_PADDRTOVADDR(p
);
571 update_adapter_info(video_adapter_t
*adp
, video_info_t
*info
)
573 adp
->va_flags
|= V_ADP_COLOR
;
574 adp
->va_window
= BIOS_PADDRTOVADDR(info
->vi_window
);
575 adp
->va_window_size
= info
->vi_window_size
;
576 adp
->va_window_gran
= info
->vi_window_gran
;
577 adp
->va_window_orig
= 0;
579 adp
->va_buffer
= info
->vi_buffer
;
580 adp
->va_buffer_size
= info
->vi_buffer_size
;
581 if (info
->vi_mem_model
== V_INFO_MM_VGAX
) {
582 adp
->va_line_width
= info
->vi_width
/2;
583 } else if (info
->vi_flags
& V_INFO_GRAPHICS
) {
584 switch (info
->vi_depth
/info
->vi_planes
) {
586 adp
->va_line_width
= info
->vi_width
/8;
589 adp
->va_line_width
= info
->vi_width
/4;
592 adp
->va_line_width
= info
->vi_width
/2;
595 default: /* shouldn't happen */
596 adp
->va_line_width
= info
->vi_width
;
600 adp
->va_line_width
= info
->vi_width
;
602 adp
->va_disp_start
.x
= 0;
603 adp
->va_disp_start
.y
= 0;
604 bcopy(info
, &adp
->va_info
, sizeof(adp
->va_info
));
607 /* probe video adapters and return the number of detected adapters */
611 video_adapter_t
*adp
;
613 #ifndef VGA_NO_MODE_CHANGE
618 /* do this test only once */
621 vga_init_done
= TRUE
;
623 if (verify_adapter(&biosadapter
) != 0)
626 biosadapter
.va_flags
|= V_ADP_PROBED
;
627 #ifndef VGA_NO_MODE_CHANGE
628 biosadapter
.va_initial_bios_mode
= readb(BIOS_PADDRTOVADDR(0x449));
629 biosadapter
.va_mode
= biosadapter
.va_initial_mode
=
630 map_bios_mode_num(biosadapter
.va_initial_bios_mode
);
634 * Ensure a zero start address. The registers are w/o for old
635 * hardware so it's too hard to relocate the active screen
637 * This must be done before vga_save_state() for VGA.
644 /* the video mode parameter table in VGA BIOS */
645 /* NOTE: there can be only one VGA recognized by the video BIOS.
648 bzero(mode_map
, sizeof(mode_map
));
649 vga_save_state(adp
, &adpstate
, sizeof(adpstate
));
650 for(i
= 0; i
< 16; i
++)
651 adp
->va_palette_regs
[i
] = adpstate
.regs
[35 + i
];
652 #ifdef VGA_NO_MODE_CHANGE
653 mode_map
[adp
->va_initial_mode
] = adpstate
.regs
;
655 #else /* !VGA_NO_MODE_CHANGE */
656 if (video_mode_ptr
== NULL
) {
657 mode_map
[adp
->va_initial_mode
] = adpstate
.regs
;
660 /* discard modes that we are not familiar with */
661 map_mode_table(mode_map
, video_mode_ptr
);
662 mp
= get_mode_param(adp
->va_initial_mode
);
663 #ifndef VGA_KEEP_POWERON_MODE
665 bcopy(mp
, adpstate2
.regs
, sizeof(adpstate2
.regs
));
666 rows_offset
= adpstate
.regs
[1] + 1 - mp
[1];
670 mode_map
[adp
->va_initial_mode
] = adpstate
.regs
;
674 #endif /* VGA_NO_MODE_CHANGE */
676 #ifndef VGA_NO_MODE_CHANGE
677 adp
->va_flags
|= V_ADP_MODECHANGE
;
679 #ifndef VGA_NO_FONT_LOADING
680 adp
->va_flags
|= V_ADP_FONT
;
683 /* XXX remove conflicting modes */
684 for (i
= 0; i
< M_VGA_CG320
; i
++) {
685 if (vga_get_info(&biosadapter
, i
, &info
))
687 if ((info
.vi_flags
& V_INFO_COLOR
) != V_ADP_COLOR
)
692 vga_get_info(&biosadapter
, biosadapter
.va_initial_mode
, &info
);
693 info
.vi_flags
&= ~V_INFO_LINEAR
; /* XXX */
694 update_adapter_info(&biosadapter
, &info
);
697 * XXX: we should verify the following values for the primary adapter...
698 * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463);
699 * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02)
701 * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a);
702 * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484);
703 * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485);
704 * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c);
710 /* set the scan line length in pixel */
712 set_line_length(video_adapter_t
*adp
, int pixel
)
715 int ppw
; /* pixels per word */
716 int bpl
; /* bytes per line */
719 mp
= get_mode_param(adp
->va_mode
);
723 switch (adp
->va_info
.vi_mem_model
) {
724 case V_INFO_MM_PLANAR
:
725 ppw
= 16/(adp
->va_info
.vi_depth
/adp
->va_info
.vi_planes
);
726 count
= (pixel
+ ppw
- 1)/ppw
/2;
727 bpl
= ((pixel
+ ppw
- 1)/ppw
/2)*4;
729 case V_INFO_MM_PACKED
:
730 count
= (pixel
+ 7)/8;
731 bpl
= ((pixel
+ 7)/8)*8;
734 count
= (pixel
+ 7)/8; /* columns */
735 bpl
= (pixel
+ 7)/8; /* columns */
741 if (mp
[10 + 0x17] & 0x40) /* CRTC mode control reg */
742 count
*= 2; /* byte mode */
744 outb(CRTC
+ 1, count
);
745 adp
->va_line_width
= bpl
;
751 set_display_start(video_adapter_t
*adp
, int x
, int y
)
753 int off
; /* byte offset (graphics mode)/word offset (text mode) */
754 int poff
; /* pixel offset */
755 int roff
; /* row offset */
756 int ppb
; /* pixels per byte */
758 if (adp
->va_info
.vi_flags
& V_INFO_GRAPHICS
) {
759 ppb
= 8/(adp
->va_info
.vi_depth
/adp
->va_info
.vi_planes
);
760 off
= y
*adp
->va_line_width
+ x
/ppb
;
769 off
= y
/adp
->va_info
.vi_cheight
*adp
->va_line_width
+ x
/ppb
;
770 roff
= y
%adp
->va_info
.vi_cheight
;
771 /* FIXME: is this correct? XXX */
779 outb(CRTC
, 0xc); /* high */
780 outb(CRTC
+ 1, off
>> 8);
781 outb(CRTC
, 0xd); /* low */
782 outb(CRTC
+ 1, off
& 0xff);
784 /* horizontal pel pan */
786 outb(ATC
, 0x13 | 0x20);
791 /* preset row scan */
793 outb(CRTC
+ 1, roff
);
795 adp
->va_disp_start
.x
= x
;
796 adp
->va_disp_start
.y
= y
;
800 #ifndef VGA_NO_MODE_CHANGE
801 #if defined(__x86_64__) /* XXX */
803 fill(int val
, void *d
, size_t size
)
810 #endif /* __x86_64__ */
813 filll_io(int val
, vm_offset_t d
, size_t size
)
817 d
+= sizeof(u_int32_t
);
820 #endif /* !VGA_NO_MODE_CHANGE */
831 vga_probe(int unit
, video_adapter_t
**adpp
, void *arg
, int flags
)
837 *adpp
= &biosadapter
;
843 vga_init(int unit
, video_adapter_t
*adp
, int flags
)
845 if ((unit
!= 0) || (adp
== NULL
) || !probe_done(adp
))
848 if (!init_done(adp
)) {
849 /* nothing to do really... */
850 adp
->va_flags
|= V_ADP_INITIALIZED
;
853 if (!config_done(adp
)) {
854 if (vid_register(adp
) < 0)
856 adp
->va_flags
|= V_ADP_REGISTERED
;
858 if (vga_sub_configure
!= NULL
)
859 (*vga_sub_configure
)(0);
866 * Return the video_info structure of the requested video mode.
869 vga_get_info(video_adapter_t
*adp
, int mode
, video_info_t
*info
)
876 #ifndef VGA_NO_MODE_CHANGE
877 if (adp
->va_flags
& V_ADP_MODECHANGE
) {
879 * If the parameter table entry for this mode is not found,
880 * the mode is not supported...
882 if (get_mode_param(mode
) == NULL
)
885 #endif /* VGA_NO_MODE_CHANGE */
888 * Even if we don't support video mode switching on this adapter,
889 * the information on the initial (thus current) video mode
890 * should be made available.
892 if (mode
!= adp
->va_initial_mode
)
896 for (i
= 0; bios_vmode
[i
].vi_mode
!= EOT
; ++i
) {
897 if (bios_vmode
[i
].vi_mode
== NA
)
899 if (mode
== bios_vmode
[i
].vi_mode
) {
900 *info
= bios_vmode
[i
];
902 info
->vi_buffer_size
= info
->vi_window_size
*info
->vi_planes
;
911 * Find a video mode matching the requested parameters.
912 * Fields filled with 0 are considered "don't care" fields and
916 vga_query_mode(video_adapter_t
*adp
, video_info_t
*info
)
923 for (i
= 0; bios_vmode
[i
].vi_mode
!= EOT
; ++i
) {
924 if (bios_vmode
[i
].vi_mode
== NA
)
927 if ((info
->vi_width
!= 0)
928 && (info
->vi_width
!= bios_vmode
[i
].vi_width
))
930 if ((info
->vi_height
!= 0)
931 && (info
->vi_height
!= bios_vmode
[i
].vi_height
))
933 if ((info
->vi_cwidth
!= 0)
934 && (info
->vi_cwidth
!= bios_vmode
[i
].vi_cwidth
))
936 if ((info
->vi_cheight
!= 0)
937 && (info
->vi_cheight
!= bios_vmode
[i
].vi_cheight
))
939 if ((info
->vi_depth
!= 0)
940 && (info
->vi_depth
!= bios_vmode
[i
].vi_depth
))
942 if ((info
->vi_planes
!= 0)
943 && (info
->vi_planes
!= bios_vmode
[i
].vi_planes
))
945 /* XXX: should check pixel format, memory model */
946 if ((info
->vi_flags
!= 0)
947 && (info
->vi_flags
!= bios_vmode
[i
].vi_flags
))
950 /* verify if this mode is supported on this adapter */
951 if (vga_get_info(adp
, bios_vmode
[i
].vi_mode
, info
))
960 * Change the video mode.
963 #ifndef VGA_NO_MODE_CHANGE
966 set_width90(adp_state_t
*params
)
969 * Based on code submitted by Kelly Yancey (kbyanc@freedomnet.com)
970 * and alexv@sui.gda.itesm.mx.
972 params
->regs
[5] |= 1; /* toggle 8 pixel wide fonts */
973 params
->regs
[10+0x0] = 0x6b;
974 params
->regs
[10+0x1] = 0x59;
975 params
->regs
[10+0x2] = 0x5a;
976 params
->regs
[10+0x3] = 0x8e;
977 params
->regs
[10+0x4] = 0x5e;
978 params
->regs
[10+0x5] = 0x8a;
979 params
->regs
[10+0x13] = 45;
980 params
->regs
[35+0x13] = 0;
982 #endif /* VGA_WIDTH90 */
983 #endif /* !VGA_NO_MODE_CHANGE */
986 vga_set_mode(video_adapter_t
*adp
, int mode
)
988 #ifndef VGA_NO_MODE_CHANGE
992 prologue(adp
, V_ADP_MODECHANGE
, ENODEV
);
994 if (vga_get_info(adp
, mode
, &info
))
997 lwkt_gettoken(&tty_token
);
1000 kprintf("vga_set_mode(): setting mode %d\n", mode
);
1003 params
.sig
= V_STATE_SIG
;
1004 bcopy(get_mode_param(mode
), params
.regs
, sizeof(params
.regs
));
1008 case M_VGA_C90x60
: case M_VGA_M90x60
:
1009 set_width90(¶ms
);
1012 case M_VGA_C80x60
: case M_VGA_M80x60
:
1013 params
.regs
[2] = 0x08;
1014 params
.regs
[19] = 0x47;
1018 case M_VGA_C90x30
: case M_VGA_M90x30
:
1019 set_width90(¶ms
);
1022 case M_VGA_C80x30
: case M_VGA_M80x30
:
1023 params
.regs
[19] = 0x4f;
1025 params
.regs
[9] |= 0xc0;
1026 params
.regs
[16] = 0x08;
1027 params
.regs
[17] = 0x3e;
1028 params
.regs
[26] = 0xea;
1029 params
.regs
[28] = 0xdf;
1030 params
.regs
[31] = 0xe7;
1031 params
.regs
[32] = 0x04;
1035 case M_VGA_C90x43
: case M_VGA_M90x43
:
1036 set_width90(¶ms
);
1039 case M_ENH_C80x43
: case M_ENH_B80x43
:
1040 params
.regs
[28] = 87;
1044 case M_VGA_C90x50
: case M_VGA_M90x50
:
1045 set_width90(¶ms
);
1048 case M_VGA_C80x50
: case M_VGA_M80x50
:
1051 params
.regs
[19] = 7;
1055 case M_VGA_C90x25
: case M_VGA_M90x25
:
1056 set_width90(¶ms
);
1059 case M_VGA_C40x25
: case M_VGA_C80x25
:
1061 case M_B40x25
: case M_C40x25
:
1062 case M_B80x25
: case M_C80x25
:
1063 case M_ENH_B40x25
: case M_ENH_C40x25
:
1064 case M_ENH_B80x25
: case M_ENH_C80x25
:
1065 case M_EGAMONO80x25
:
1068 vga_load_state(adp
, ¶ms
);
1072 /* "unchain" the VGA mode */
1073 params
.regs
[5-1+0x04] &= 0xf7;
1074 params
.regs
[5-1+0x04] |= 0x04;
1075 /* turn off doubleword mode */
1076 params
.regs
[10+0x14] &= 0xbf;
1077 /* turn off word addressing */
1078 params
.regs
[10+0x17] |= 0x40;
1079 /* set logical screen width */
1080 params
.regs
[10+0x13] = 80;
1082 params
.regs
[10+0x11] = 0x2c;
1083 params
.regs
[10+0x06] = 0x0d;
1084 params
.regs
[10+0x07] = 0x3e;
1085 params
.regs
[10+0x10] = 0xea;
1086 params
.regs
[10+0x11] = 0xac;
1087 params
.regs
[10+0x12] = 0xdf;
1088 params
.regs
[10+0x15] = 0xe7;
1089 params
.regs
[10+0x16] = 0x06;
1090 /* set vertical sync polarity to reflect aspect ratio */
1091 params
.regs
[9] = 0xe3;
1094 case M_BG320
: case M_CG320
: case M_BG640
:
1095 case M_CG320_D
: case M_CG640_E
:
1096 case M_CG640x350
: case M_ENH_CG640
:
1097 case M_BG640x480
: case M_CG640x480
: case M_VGA_CG320
:
1100 vga_load_state(adp
, ¶ms
);
1104 lwkt_reltoken(&tty_token
);
1108 adp
->va_mode
= mode
;
1109 info
.vi_flags
&= ~V_INFO_LINEAR
; /* XXX */
1110 update_adapter_info(adp
, &info
);
1112 /* move hardware cursor out of the way */
1113 (*vidsw
[adp
->va_index
]->set_hw_cursor
)(adp
, -1, -1);
1115 lwkt_reltoken(&tty_token
);
1117 #else /* VGA_NO_MODE_CHANGE */
1118 lwkt_reltoken(&tty_token
);
1120 #endif /* VGA_NO_MODE_CHANGE */
1123 #ifndef VGA_NO_FONT_LOADING
1126 set_font_mode(video_adapter_t
*adp
, u_char
*buf
)
1130 /* save register values */
1131 outb(TSIDX
, 0x02); buf
[0] = inb(TSREG
);
1132 outb(TSIDX
, 0x04); buf
[1] = inb(TSREG
);
1133 outb(GDCIDX
, 0x04); buf
[2] = inb(GDCREG
);
1134 outb(GDCIDX
, 0x05); buf
[3] = inb(GDCREG
);
1135 outb(GDCIDX
, 0x06); buf
[4] = inb(GDCREG
);
1137 outb(ATC
, 0x10); buf
[5] = inb(ATC
+ 1);
1139 /* setup vga for loading fonts */
1140 inb(CRTC
+ 6); /* reset flip-flop */
1141 outb(ATC
, 0x10); outb(ATC
, buf
[5] & ~0x01);
1142 inb(CRTC
+ 6); /* reset flip-flop */
1143 outb(ATC
, 0x20); /* enable palette */
1144 outw(TSIDX
, 0x0402);
1145 outw(TSIDX
, 0x0704);
1146 outw(GDCIDX
, 0x0204);
1147 outw(GDCIDX
, 0x0005);
1148 outw(GDCIDX
, 0x0406); /* addr = a0000, 64kb */
1154 set_normal_mode(video_adapter_t
*adp
, u_char
*buf
)
1158 /* setup vga for normal operation mode again */
1159 inb(CRTC
+ 6); /* reset flip-flop */
1160 outb(ATC
, 0x10); outb(ATC
, buf
[5]);
1161 inb(CRTC
+ 6); /* reset flip-flop */
1162 outb(ATC
, 0x20); /* enable palette */
1163 outw(TSIDX
, 0x0002 | (buf
[0] << 8));
1164 outw(TSIDX
, 0x0004 | (buf
[1] << 8));
1165 outw(GDCIDX
, 0x0004 | (buf
[2] << 8));
1166 outw(GDCIDX
, 0x0005 | (buf
[3] << 8));
1167 outw(GDCIDX
, 0x0006 | (((buf
[4] & 0x03) | 0x0c)<<8));
1172 #endif /* VGA_NO_FONT_LOADING */
1176 * Read the font data in the requested font page from the video adapter.
1179 vga_save_font(video_adapter_t
*adp
, int page
, int fontsize
, u_char
*data
,
1182 #ifndef VGA_NO_FONT_LOADING
1183 u_char buf
[PARAM_BUFSIZE
];
1184 vm_offset_t segment
;
1187 prologue(adp
, V_ADP_FONT
, ENODEV
);
1189 if (fontsize
< 14) {
1192 } else if (fontsize
>= 32) {
1194 } else if (fontsize
>= 16) {
1202 if (page
< 0 || page
>= 8)
1204 segment
= FONT_BUF
+ 0x4000*page
;
1208 set_font_mode(adp
, buf
);
1209 if (fontsize
== 32) {
1210 bcopy_fromio((uintptr_t)segment
+ ch
*32, data
, fontsize
*count
);
1212 for (c
= ch
; count
> 0; ++c
, --count
) {
1213 bcopy_fromio((uintptr_t)segment
+ c
*32, data
, fontsize
);
1217 set_normal_mode(adp
, buf
);
1220 #else /* VGA_NO_FONT_LOADING */
1222 #endif /* VGA_NO_FONT_LOADING */
1227 * Set the font data in the requested font page.
1228 * NOTE: it appears that some recent video adapters do not support
1229 * the font page other than 0... XXX
1232 vga_load_font(video_adapter_t
*adp
, int page
, int fontsize
, u_char
*data
,
1235 #ifndef VGA_NO_FONT_LOADING
1236 u_char buf
[PARAM_BUFSIZE
];
1237 vm_offset_t segment
;
1240 prologue(adp
, V_ADP_FONT
, ENODEV
);
1242 if (fontsize
< 14) {
1245 } else if (fontsize
>= 32) {
1247 } else if (fontsize
>= 16) {
1255 if (page
< 0 || page
>= 8)
1257 segment
= FONT_BUF
+ 0x4000*page
;
1261 set_font_mode(adp
, buf
);
1262 if (fontsize
== 32) {
1263 bcopy_toio(data
, (uintptr_t)segment
+ ch
*32, fontsize
*count
);
1265 for (c
= ch
; count
> 0; ++c
, --count
) {
1266 bcopy_toio(data
, (uintptr_t)segment
+ c
*32, fontsize
);
1270 set_normal_mode(adp
, buf
);
1273 #else /* VGA_NO_FONT_LOADING */
1275 #endif /* VGA_NO_FONT_LOADING */
1280 * Activate the requested font page.
1281 * NOTE: it appears that some recent video adapters do not support
1282 * the font page other than 0... XXX
1285 vga_show_font(video_adapter_t
*adp
, int page
)
1287 #ifndef VGA_NO_FONT_LOADING
1288 static u_char cg
[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f };
1290 prologue(adp
, V_ADP_FONT
, ENODEV
);
1291 if (page
< 0 || page
>= 8)
1295 outb(TSIDX
, 0x03); outb(TSREG
, cg
[page
]);
1299 #else /* VGA_NO_FONT_LOADING */
1301 #endif /* VGA_NO_FONT_LOADING */
1306 * Read DAC values. The values have expressed in 8 bits.
1311 vga_save_palette(video_adapter_t
*adp
, u_char
*palette
)
1315 prologue(adp
, V_ADP_PALETTE
, ENODEV
);
1318 * We store 8 bit values in the palette buffer, while the standard
1319 * VGA has 6 bit DAC .
1321 outb(PALRADR
, 0x00);
1322 for (i
= 0; i
< 256*3; ++i
)
1323 palette
[i
] = inb(PALDATA
) << 2;
1324 inb(CRTC
+ 6); /* reset flip/flop */
1329 vga_save_palette2(video_adapter_t
*adp
, int base
, int count
,
1330 u_char
*r
, u_char
*g
, u_char
*b
)
1334 prologue(adp
, V_ADP_PALETTE
, ENODEV
);
1336 outb(PALRADR
, base
);
1337 for (i
= 0; i
< count
; ++i
) {
1338 r
[i
] = inb(PALDATA
) << 2;
1339 g
[i
] = inb(PALDATA
) << 2;
1340 b
[i
] = inb(PALDATA
) << 2;
1342 inb(CRTC
+ 6); /* reset flip/flop */
1353 vga_load_palette(video_adapter_t
*adp
, const u_char
*palette
)
1357 prologue(adp
, V_ADP_PALETTE
, ENODEV
);
1359 outb(PIXMASK
, 0xff); /* no pixelmask */
1360 outb(PALWADR
, 0x00);
1361 for (i
= 0; i
< 256*3; ++i
)
1362 outb(PALDATA
, palette
[i
] >> 2);
1363 inb(CRTC
+ 6); /* reset flip/flop */
1364 outb(ATC
, 0x20); /* enable palette */
1369 vga_load_palette2(video_adapter_t
*adp
, int base
, int count
,
1370 u_char
*r
, u_char
*g
, u_char
*b
)
1374 prologue(adp
, V_ADP_PALETTE
, ENODEV
);
1376 outb(PIXMASK
, 0xff); /* no pixelmask */
1377 outb(PALWADR
, base
);
1378 for (i
= 0; i
< count
; ++i
) {
1379 outb(PALDATA
, r
[i
] >> 2);
1380 outb(PALDATA
, g
[i
] >> 2);
1381 outb(PALDATA
, b
[i
] >> 2);
1383 inb(CRTC
+ 6); /* reset flip/flop */
1384 outb(ATC
, 0x20); /* enable palette */
1390 * Change the border color.
1393 vga_set_border(video_adapter_t
*adp
, int color
)
1395 prologue(adp
, V_ADP_BORDER
, ENODEV
);
1397 inb(CRTC
+ 6); /* reset flip-flop */
1398 outb(ATC
, 0x31); outb(ATC
, color
& 0xff);
1405 * Read video register values.
1406 * NOTE: this function only reads the standard VGA registers.
1407 * any extra/extended registers of SVGA adapters are not saved.
1410 vga_save_state(video_adapter_t
*adp
, void *p
, size_t size
)
1417 /* return the required buffer size */
1418 prologue(adp
, V_ADP_STATESAVE
, 0);
1419 return sizeof(adp_state_t
);
1421 prologue(adp
, V_ADP_STATESAVE
, ENODEV
);
1422 if (size
< sizeof(adp_state_t
))
1425 ((adp_state_t
*)p
)->sig
= V_STATE_SIG
;
1426 buf
= ((adp_state_t
*)p
)->regs
;
1427 bzero(buf
, V_MODE_PARAM_SIZE
);
1431 outb(TSIDX
, 0x00); outb(TSREG
, 0x01); /* stop sequencer */
1432 for (i
= 0, j
= 5; i
< 4; i
++) {
1434 buf
[j
++] = inb(TSREG
);
1436 buf
[9] = inb(MISC
+ 10); /* dot-clock */
1437 outb(TSIDX
, 0x00); outb(TSREG
, 0x03); /* start sequencer */
1439 for (i
= 0, j
= 10; i
< 25; i
++) { /* crtc */
1441 buf
[j
++] = inb(CRTC
+ 1);
1443 for (i
= 0, j
= 35; i
< 20; i
++) { /* attribute ctrl */
1444 inb(CRTC
+ 6); /* reset flip-flop */
1446 buf
[j
++] = inb(ATC
+ 1);
1448 for (i
= 0, j
= 55; i
< 9; i
++) { /* graph data ctrl */
1450 buf
[j
++] = inb(GDCREG
);
1452 inb(CRTC
+ 6); /* reset flip-flop */
1453 outb(ATC
, 0x20); /* enable palette */
1458 if (vga_get_info(adp
, adp
->va_mode
, &info
) == 0) {
1459 if (info
.vi_flags
& V_INFO_GRAPHICS
) {
1460 buf
[0] = info
.vi_width
/info
.vi_cwidth
; /* COLS */
1461 buf
[1] = info
.vi_height
/info
.vi_cheight
- 1; /* ROWS */
1463 buf
[0] = info
.vi_width
; /* COLS */
1464 buf
[1] = info
.vi_height
- 1; /* ROWS */
1466 buf
[2] = info
.vi_cheight
; /* POINTS */
1468 /* XXX: shouldn't be happening... */
1469 kprintf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n",
1470 adp
->va_unit
, adp
->va_name
);
1473 buf
[0] = readb(BIOS_PADDRTOVADDR(0x44a)); /* COLS */
1474 buf
[1] = readb(BIOS_PADDRTOVADDR(0x484)); /* ROWS */
1475 buf
[2] = readb(BIOS_PADDRTOVADDR(0x485)); /* POINTS */
1476 buf
[3] = readb(BIOS_PADDRTOVADDR(0x44c));
1477 buf
[4] = readb(BIOS_PADDRTOVADDR(0x44d));
1485 * Set video registers at once.
1486 * NOTE: this function only updates the standard VGA registers.
1487 * any extra/extended registers of SVGA adapters are not changed.
1490 vga_load_state(video_adapter_t
*adp
, void *p
)
1495 prologue(adp
, V_ADP_STATELOAD
, ENODEV
);
1496 if (((adp_state_t
*)p
)->sig
!= V_STATE_SIG
)
1499 buf
= ((adp_state_t
*)p
)->regs
;
1502 hexdump(buf
, V_MODE_PARAM_SIZE
, NULL
, HD_OMIT_CHARS
| HD_OMIT_COUNT
);
1507 outb(TSIDX
, 0x00); outb(TSREG
, 0x01); /* stop sequencer */
1508 for (i
= 0; i
< 4; ++i
) { /* program sequencer */
1510 outb(TSREG
, buf
[i
+ 5]);
1512 outb(MISC
, buf
[9]); /* set dot-clock */
1513 outb(TSIDX
, 0x00); outb(TSREG
, 0x03); /* start sequencer */
1515 outb(CRTC
+ 1, inb(CRTC
+ 1) & 0x7F);
1516 for (i
= 0; i
< 25; ++i
) { /* program crtc */
1518 outb(CRTC
+ 1, buf
[i
+ 10]);
1520 inb(CRTC
+ 6); /* reset flip-flop */
1521 for (i
= 0; i
< 20; ++i
) { /* program attribute ctrl */
1523 outb(ATC
, buf
[i
+ 35]);
1525 for (i
= 0; i
< 9; ++i
) { /* program graph data ctrl */
1527 outb(GDCREG
, buf
[i
+ 55]);
1529 inb(CRTC
+ 6); /* reset flip-flop */
1530 outb(ATC
, 0x20); /* enable palette */
1532 #if 0 /* XXX a temporary workaround for kernel panic */
1533 #ifndef VGA_NO_MODE_CHANGE
1534 if (adp
->va_unit
== V_ADP_PRIMARY
) {
1535 writeb(BIOS_PADDRTOVADDR(0x44a), buf
[0]); /* COLS */
1536 writeb(BIOS_PADDRTOVADDR(0x484), buf
[1] + rows_offset
- 1); /* ROWS */
1537 writeb(BIOS_PADDRTOVADDR(0x485), buf
[2]); /* POINTS */
1539 writeb(BIOS_PADDRTOVADDR(0x44c), buf
[3]);
1540 writeb(BIOS_PADDRTOVADDR(0x44d), buf
[4]);
1543 #endif /* !VGA_NO_MODE_CHANGE */
1552 * Change the origin (window mapping) of the banked frame buffer.
1555 vga_set_origin(video_adapter_t
*adp
, off_t offset
)
1558 * The standard video modes do not require window mapping;
1559 * always return error.
1566 * Read the position of the hardware text cursor.
1569 vga_read_hw_cursor(video_adapter_t
*adp
, int *col
, int *row
)
1576 if (adp
->va_info
.vi_flags
& V_INFO_GRAPHICS
)
1581 off
= inb(CRTC
+ 1);
1583 off
= (off
<< 8) | inb(CRTC
+ 1);
1586 *row
= off
/ adp
->va_info
.vi_width
;
1587 *col
= off
% adp
->va_info
.vi_width
;
1594 * Move the hardware text cursor. If col and row are both -1,
1595 * the cursor won't be shown.
1598 vga_set_hw_cursor(video_adapter_t
*adp
, int col
, int row
)
1605 if ((col
== -1) && (row
== -1)) {
1608 if (adp
->va_info
.vi_flags
& V_INFO_GRAPHICS
)
1610 off
= row
*adp
->va_info
.vi_width
+ col
;
1615 outb(CRTC
+ 1, off
>> 8);
1617 outb(CRTC
+ 1, off
& 0x00ff);
1624 * set_hw_cursor_shape():
1625 * Change the shape of the hardware text cursor. If the height is
1626 * zero or negative, the cursor won't be shown.
1629 vga_set_hw_cursor_shape(video_adapter_t
*adp
, int base
, int height
,
1630 int celsize
, int blink
)
1637 /* make the cursor invisible */
1644 outb(CRTC
+ 1, celsize
- base
- height
);
1646 outb(CRTC
+ 1, celsize
- base
- 1);
1655 * Put the display in power save/power off mode.
1658 vga_blank_display(video_adapter_t
*adp
, int mode
)
1664 case V_DISPLAY_SUSPEND
:
1665 case V_DISPLAY_STAND_BY
:
1669 outb(TSREG
, val
| 0x20);
1671 val
= inb(CRTC
+ 1);
1672 outb(CRTC
+ 1, val
& ~0x80);
1678 outb(TSREG
, val
| 0x20);
1684 outb(TSREG
, val
& 0xDF);
1686 val
= inb(CRTC
+ 1);
1687 outb(CRTC
+ 1, val
| 0x80);
1697 * Mmap frame buffer.
1700 vga_mmap_buf(video_adapter_t
*adp
, vm_offset_t offset
, int prot
)
1702 if (adp
->va_info
.vi_flags
& V_INFO_LINEAR
)
1706 kprintf("vga_mmap_buf(): window:0x%x, offset:%p\n",
1707 adp
->va_info
.vi_window
, (void *)offset
);
1710 /* XXX: is this correct? */
1711 if (offset
> adp
->va_window_size
- PAGE_SIZE
)
1714 #if defined(__x86_64__)
1715 return x86_64_btop(adp
->va_info
.vi_window
+ offset
);
1717 #error "vga_mmap_buf needs to return something"
1721 #ifndef VGA_NO_MODE_CHANGE
1724 planar_fill(video_adapter_t
*adp
, int val
)
1727 int at
; /* position in the frame buffer */
1730 lwkt_gettoken(&tty_token
);
1731 outw(GDCIDX
, 0x0005); /* read mode 0, write mode 0 */
1732 outw(GDCIDX
, 0x0003); /* data rotate/function select */
1733 outw(GDCIDX
, 0x0f01); /* set/reset enable */
1734 outw(GDCIDX
, 0xff08); /* bit mask */
1735 outw(GDCIDX
, (val
<< 8) | 0x00); /* set/reset */
1737 length
= adp
->va_line_width
*adp
->va_info
.vi_height
;
1738 while (length
> 0) {
1739 l
= imin(length
, adp
->va_window_size
);
1740 (*vidsw
[adp
->va_index
]->set_win_org
)(adp
, at
);
1741 bzero_io(adp
->va_window
, l
);
1745 outw(GDCIDX
, 0x0000); /* set/reset */
1746 outw(GDCIDX
, 0x0001); /* set/reset enable */
1747 lwkt_reltoken(&tty_token
);
1751 packed_fill(video_adapter_t
*adp
, int val
)
1754 int at
; /* position in the frame buffer */
1757 lwkt_gettoken(&tty_token
);
1759 length
= adp
->va_line_width
*adp
->va_info
.vi_height
;
1760 while (length
> 0) {
1761 l
= imin(length
, adp
->va_window_size
);
1762 (*vidsw
[adp
->va_index
]->set_win_org
)(adp
, at
);
1763 fill_io(val
, adp
->va_window
, l
);
1767 lwkt_reltoken(&tty_token
);
1771 direct_fill(video_adapter_t
*adp
, int val
)
1774 int at
; /* position in the frame buffer */
1777 lwkt_gettoken(&tty_token
);
1779 length
= adp
->va_line_width
*adp
->va_info
.vi_height
;
1780 while (length
> 0) {
1781 l
= imin(length
, adp
->va_window_size
);
1782 (*vidsw
[adp
->va_index
]->set_win_org
)(adp
, at
);
1783 switch (adp
->va_info
.vi_pixel_size
) {
1784 case sizeof(u_int16_t
):
1785 fillw_io(val
, adp
->va_window
, l
/sizeof(u_int16_t
));
1790 case sizeof(u_int32_t
):
1791 filll_io(val
, adp
->va_window
, l
/sizeof(u_int32_t
));
1797 lwkt_reltoken(&tty_token
);
1801 vga_clear(video_adapter_t
*adp
)
1803 switch (adp
->va_info
.vi_mem_model
) {
1804 case V_INFO_MM_TEXT
:
1805 /* do nothing? XXX */
1807 case V_INFO_MM_PLANAR
:
1808 planar_fill(adp
, 0);
1810 case V_INFO_MM_PACKED
:
1811 packed_fill(adp
, 0);
1813 case V_INFO_MM_DIRECT
:
1814 direct_fill(adp
, 0);
1821 vga_fill_rect(video_adapter_t
*adp
, int val
, int x
, int y
, int cx
, int cy
)
1827 vga_bitblt(video_adapter_t
*adp
,...)
1833 #endif /* !VGA_NO_MODE_CHANGE */
1836 get_palette(video_adapter_t
*adp
, int base
, int count
,
1837 u_char
*red
, u_char
*green
, u_char
*blue
, u_char
*trans
)
1843 if (count
< 0 || base
< 0 || count
> 256 || base
> 256 ||
1847 r
= kmalloc(count
*3, M_DEVBUF
, M_WAITOK
);
1850 if (vga_save_palette2(adp
, base
, count
, r
, g
, b
)) {
1854 copyout(r
, red
, count
);
1855 copyout(g
, green
, count
);
1856 copyout(b
, blue
, count
);
1857 if (trans
!= NULL
) {
1859 copyout(r
, trans
, count
);
1867 set_palette(video_adapter_t
*adp
, int base
, int count
,
1868 u_char
*red
, u_char
*green
, u_char
*blue
, u_char
*trans
)
1875 if (count
< 0 || base
< 0 || count
> 256 || base
> 256 ||
1879 r
= kmalloc(count
*3, M_DEVBUF
, M_WAITOK
);
1882 err
= copyin(red
, r
, count
);
1884 err
= copyin(green
, g
, count
);
1886 err
= copyin(blue
, b
, count
);
1888 err
= vga_load_palette2(adp
, base
, count
, r
, g
, b
);
1891 return (err
? ENODEV
: 0);
1895 vga_dev_ioctl(video_adapter_t
*adp
, u_long cmd
, caddr_t arg
)
1898 case FBIO_GETWINORG
: /* get frame buffer window origin */
1902 case FBIO_SETWINORG
: /* set frame buffer window origin */
1905 case FBIO_SETDISPSTART
: /* set display start address */
1906 return (set_display_start(adp
,
1907 ((video_display_start_t
*)arg
)->x
,
1908 ((video_display_start_t
*)arg
)->y
)
1911 case FBIO_SETLINEWIDTH
: /* set scan line length in pixel */
1912 return (set_line_length(adp
, *(u_int
*)arg
) ? ENODEV
: 0);
1914 case FBIO_GETPALETTE
: /* get color palette */
1915 return get_palette(adp
, ((video_color_palette_t
*)arg
)->index
,
1916 ((video_color_palette_t
*)arg
)->count
,
1917 ((video_color_palette_t
*)arg
)->red
,
1918 ((video_color_palette_t
*)arg
)->green
,
1919 ((video_color_palette_t
*)arg
)->blue
,
1920 ((video_color_palette_t
*)arg
)->transparent
);
1922 case FBIO_SETPALETTE
: /* set color palette */
1923 return set_palette(adp
, ((video_color_palette_t
*)arg
)->index
,
1924 ((video_color_palette_t
*)arg
)->count
,
1925 ((video_color_palette_t
*)arg
)->red
,
1926 ((video_color_palette_t
*)arg
)->green
,
1927 ((video_color_palette_t
*)arg
)->blue
,
1928 ((video_color_palette_t
*)arg
)->transparent
);
1930 case FBIOGTYPE
: /* get frame buffer type info. */
1931 ((struct fbtype
*)arg
)->fb_type
= fb_type(adp
->va_type
);
1932 ((struct fbtype
*)arg
)->fb_height
= adp
->va_info
.vi_height
;
1933 ((struct fbtype
*)arg
)->fb_width
= adp
->va_info
.vi_width
;
1934 ((struct fbtype
*)arg
)->fb_depth
= adp
->va_info
.vi_depth
;
1935 if ((adp
->va_info
.vi_depth
<= 1) || (adp
->va_info
.vi_depth
> 8))
1936 ((struct fbtype
*)arg
)->fb_cmsize
= 0;
1938 ((struct fbtype
*)arg
)->fb_cmsize
= 1 << adp
->va_info
.vi_depth
;
1939 ((struct fbtype
*)arg
)->fb_size
= adp
->va_buffer_size
;
1942 case FBIOGETCMAP
: /* get color palette */
1943 return get_palette(adp
, ((struct fbcmap
*)arg
)->index
,
1944 ((struct fbcmap
*)arg
)->count
,
1945 ((struct fbcmap
*)arg
)->red
,
1946 ((struct fbcmap
*)arg
)->green
,
1947 ((struct fbcmap
*)arg
)->blue
, NULL
);
1949 case FBIOPUTCMAP
: /* set color palette */
1950 return set_palette(adp
, ((struct fbcmap
*)arg
)->index
,
1951 ((struct fbcmap
*)arg
)->count
,
1952 ((struct fbcmap
*)arg
)->red
,
1953 ((struct fbcmap
*)arg
)->green
,
1954 ((struct fbcmap
*)arg
)->blue
, NULL
);
1957 return fb_commonioctl(adp
, cmd
, arg
);
1963 * Print some information about the video adapter and video modes,
1964 * with requested level of details.
1967 vga_diag(video_adapter_t
*adp
, int level
)
1979 #ifndef VGA_NO_MODE_CHANGE
1980 kprintf("vga: DCC code:0x%02x\n",
1981 readb(BIOS_PADDRTOVADDR(0x488)));
1982 kprintf("vga: CRTC:0x%x, video option:0x%02x, ",
1983 readw(BIOS_PADDRTOVADDR(0x463)),
1984 readb(BIOS_PADDRTOVADDR(0x487)));
1985 kprintf("rows:%d, cols:%d, font height:%d\n",
1986 readb(BIOS_PADDRTOVADDR(0x44a)),
1987 readb(BIOS_PADDRTOVADDR(0x484)) + 1,
1988 readb(BIOS_PADDRTOVADDR(0x485)));
1989 kprintf("vga: param table:%p\n", video_mode_ptr
);
1990 kprintf("vga: rows_offset:%d\n", rows_offset
);
1992 #endif /* FB_DEBUG > 1 */
1994 fb_dump_adp_info(VGA_DRIVER_NAME
, adp
, level
);
1997 if (adp
->va_flags
& V_ADP_MODECHANGE
) {
1998 for (i
= 0; bios_vmode
[i
].vi_mode
!= EOT
; ++i
) {
1999 if (bios_vmode
[i
].vi_mode
== NA
)
2001 if (get_mode_param(bios_vmode
[i
].vi_mode
) == NULL
)
2003 fb_dump_mode_info(VGA_DRIVER_NAME
, adp
, &bios_vmode
[i
], level
);
2006 vga_get_info(adp
, adp
->va_initial_mode
, &info
); /* shouldn't fail */
2007 fb_dump_mode_info(VGA_DRIVER_NAME
, adp
, &info
, level
);
2009 #endif /* FB_DEBUG > 1 */
2011 #ifndef VGA_NO_MODE_CHANGE
2012 if (video_mode_ptr
== NULL
)
2013 kprintf("vga%d: %s: WARNING: video mode switching is not "
2014 "fully supported on this adapter\n",
2015 adp
->va_unit
, adp
->va_name
);
2020 kprintf("VGA parameters upon power-up\n");
2021 hexdump(adpstate
.regs
, sizeof(adpstate
.regs
), NULL
,
2022 HD_OMIT_CHARS
| HD_OMIT_COUNT
);
2024 mp
= get_mode_param(adp
->va_initial_mode
);
2025 if (mp
== NULL
) /* this shouldn't be happening */
2027 kprintf("VGA parameters in BIOS for mode %d\n", adp
->va_initial_mode
);
2028 hexdump(adpstate2
.regs
, sizeof(adpstate2
.regs
), NULL
,
2029 HD_OMIT_CHARS
| HD_OMIT_COUNT
);
2030 kprintf("VGA parameters to be used for mode %d\n", adp
->va_initial_mode
);
2031 hexdump(mp
, V_MODE_PARAM_SIZE
, NULL
, HD_OMIT_CHARS
| HD_OMIT_COUNT
);