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