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