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