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 i, j; 1415 1416 if (size == 0) { 1417 /* return the required buffer size */ 1418 prologue(adp, V_ADP_STATESAVE, 0); 1419 return sizeof(adp_state_t); 1420 } else { 1421 prologue(adp, V_ADP_STATESAVE, ENODEV); 1422 if (size < sizeof(adp_state_t)) 1423 return EINVAL; 1424 } 1425 ((adp_state_t *)p)->sig = V_STATE_SIG; 1426 buf = ((adp_state_t *)p)->regs; 1427 bzero(buf, V_MODE_PARAM_SIZE); 1428 1429 crit_enter(); 1430 1431 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1432 for (i = 0, j = 5; i < 4; i++) { 1433 outb(TSIDX, i + 1); 1434 buf[j++] = inb(TSREG); 1435 } 1436 buf[9] = inb(MISC + 10); /* dot-clock */ 1437 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1438 1439 for (i = 0, j = 10; i < 25; i++) { /* crtc */ 1440 outb(CRTC, i); 1441 buf[j++] = inb(CRTC + 1); 1442 } 1443 for (i = 0, j = 35; i < 20; i++) { /* attribute ctrl */ 1444 inb(CRTC + 6); /* reset flip-flop */ 1445 outb(ATC, i); 1446 buf[j++] = inb(ATC + 1); 1447 } 1448 for (i = 0, j = 55; i < 9; i++) { /* graph data ctrl */ 1449 outb(GDCIDX, i); 1450 buf[j++] = inb(GDCREG); 1451 } 1452 inb(CRTC + 6); /* reset flip-flop */ 1453 outb(ATC, 0x20); /* enable palette */ 1454 1455 crit_exit(); 1456 1457 #if 1 1458 if (vga_get_info(adp, adp->va_mode, &info) == 0) { 1459 if (info.vi_flags & V_INFO_GRAPHICS) { 1460 buf[0] = info.vi_width/info.vi_cwidth; /* COLS */ 1461 buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */ 1462 } else { 1463 buf[0] = info.vi_width; /* COLS */ 1464 buf[1] = info.vi_height - 1; /* ROWS */ 1465 } 1466 buf[2] = info.vi_cheight; /* POINTS */ 1467 } else { 1468 /* XXX: shouldn't be happening... */ 1469 kprintf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n", 1470 adp->va_unit, adp->va_name); 1471 } 1472 #else 1473 buf[0] = readb(BIOS_PADDRTOVADDR(0x44a)); /* COLS */ 1474 buf[1] = readb(BIOS_PADDRTOVADDR(0x484)); /* ROWS */ 1475 buf[2] = readb(BIOS_PADDRTOVADDR(0x485)); /* POINTS */ 1476 buf[3] = readb(BIOS_PADDRTOVADDR(0x44c)); 1477 buf[4] = readb(BIOS_PADDRTOVADDR(0x44d)); 1478 #endif 1479 1480 return 0; 1481 } 1482 1483 /* 1484 * load_state(): 1485 * Set video registers at once. 1486 * NOTE: this function only updates the standard VGA registers. 1487 * any extra/extended registers of SVGA adapters are not changed. 1488 */ 1489 static int 1490 vga_load_state(video_adapter_t *adp, void *p) 1491 { 1492 u_char *buf; 1493 int i; 1494 1495 prologue(adp, V_ADP_STATELOAD, ENODEV); 1496 if (((adp_state_t *)p)->sig != V_STATE_SIG) 1497 return EINVAL; 1498 1499 buf = ((adp_state_t *)p)->regs; 1500 1501 #if VGA_DEBUG > 1 1502 hexdump(buf, V_MODE_PARAM_SIZE, NULL, HD_OMIT_CHARS | HD_OMIT_COUNT); 1503 #endif 1504 1505 crit_enter(); 1506 1507 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1508 for (i = 0; i < 4; ++i) { /* program sequencer */ 1509 outb(TSIDX, i + 1); 1510 outb(TSREG, buf[i + 5]); 1511 } 1512 outb(MISC, buf[9]); /* set dot-clock */ 1513 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1514 outb(CRTC, 0x11); 1515 outb(CRTC + 1, inb(CRTC + 1) & 0x7F); 1516 for (i = 0; i < 25; ++i) { /* program crtc */ 1517 outb(CRTC, i); 1518 outb(CRTC + 1, buf[i + 10]); 1519 } 1520 inb(CRTC + 6); /* reset flip-flop */ 1521 for (i = 0; i < 20; ++i) { /* program attribute ctrl */ 1522 outb(ATC, i); 1523 outb(ATC, buf[i + 35]); 1524 } 1525 for (i = 0; i < 9; ++i) { /* program graph data ctrl */ 1526 outb(GDCIDX, i); 1527 outb(GDCREG, buf[i + 55]); 1528 } 1529 inb(CRTC + 6); /* reset flip-flop */ 1530 outb(ATC, 0x20); /* enable palette */ 1531 1532 #if 0 /* XXX a temporary workaround for kernel panic */ 1533 #ifndef VGA_NO_MODE_CHANGE 1534 if (adp->va_unit == V_ADP_PRIMARY) { 1535 writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]); /* COLS */ 1536 writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */ 1537 writeb(BIOS_PADDRTOVADDR(0x485), buf[2]); /* POINTS */ 1538 #if 0 1539 writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]); 1540 writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]); 1541 #endif 1542 } 1543 #endif /* !VGA_NO_MODE_CHANGE */ 1544 #endif /* XXX */ 1545 1546 crit_exit(); 1547 return 0; 1548 } 1549 1550 /* 1551 * set_origin(): 1552 * Change the origin (window mapping) of the banked frame buffer. 1553 */ 1554 static int 1555 vga_set_origin(video_adapter_t *adp, off_t offset) 1556 { 1557 /* 1558 * The standard video modes do not require window mapping; 1559 * always return error. 1560 */ 1561 return ENODEV; 1562 } 1563 1564 /* 1565 * read_hw_cursor(): 1566 * Read the position of the hardware text cursor. 1567 */ 1568 static int 1569 vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1570 { 1571 u_int16_t off; 1572 1573 if (!vga_init_done) 1574 return ENXIO; 1575 1576 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1577 return ENODEV; 1578 1579 crit_enter(); 1580 outb(CRTC, 14); 1581 off = inb(CRTC + 1); 1582 outb(CRTC, 15); 1583 off = (off << 8) | inb(CRTC + 1); 1584 crit_exit(); 1585 1586 *row = off / adp->va_info.vi_width; 1587 *col = off % adp->va_info.vi_width; 1588 1589 return 0; 1590 } 1591 1592 /* 1593 * set_hw_cursor(): 1594 * Move the hardware text cursor. If col and row are both -1, 1595 * the cursor won't be shown. 1596 */ 1597 static int 1598 vga_set_hw_cursor(video_adapter_t *adp, int col, int row) 1599 { 1600 u_int16_t off; 1601 1602 if (!vga_init_done) 1603 return ENXIO; 1604 1605 if ((col == -1) && (row == -1)) { 1606 off = -1; 1607 } else { 1608 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1609 return ENODEV; 1610 off = row*adp->va_info.vi_width + col; 1611 } 1612 1613 crit_enter(); 1614 outb(CRTC, 14); 1615 outb(CRTC + 1, off >> 8); 1616 outb(CRTC, 15); 1617 outb(CRTC + 1, off & 0x00ff); 1618 crit_exit(); 1619 1620 return 0; 1621 } 1622 1623 /* 1624 * set_hw_cursor_shape(): 1625 * Change the shape of the hardware text cursor. If the height is 1626 * zero or negative, the cursor won't be shown. 1627 */ 1628 static int 1629 vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1630 int celsize, int blink) 1631 { 1632 if (!vga_init_done) 1633 return ENXIO; 1634 1635 crit_enter(); 1636 if (height <= 0) { 1637 /* make the cursor invisible */ 1638 outb(CRTC, 10); 1639 outb(CRTC + 1, 32); 1640 outb(CRTC, 11); 1641 outb(CRTC + 1, 0); 1642 } else { 1643 outb(CRTC, 10); 1644 outb(CRTC + 1, celsize - base - height); 1645 outb(CRTC, 11); 1646 outb(CRTC + 1, celsize - base - 1); 1647 } 1648 crit_exit(); 1649 1650 return 0; 1651 } 1652 1653 /* 1654 * blank_display() 1655 * Put the display in power save/power off mode. 1656 */ 1657 static int 1658 vga_blank_display(video_adapter_t *adp, int mode) 1659 { 1660 u_char val; 1661 1662 crit_enter(); 1663 switch (mode) { 1664 case V_DISPLAY_SUSPEND: 1665 case V_DISPLAY_STAND_BY: 1666 outb(TSIDX, 0x01); 1667 val = inb(TSREG); 1668 outb(TSIDX, 0x01); 1669 outb(TSREG, val | 0x20); 1670 outb(CRTC, 0x17); 1671 val = inb(CRTC + 1); 1672 outb(CRTC + 1, val & ~0x80); 1673 break; 1674 case V_DISPLAY_OFF: 1675 outb(TSIDX, 0x01); 1676 val = inb(TSREG); 1677 outb(TSIDX, 0x01); 1678 outb(TSREG, val | 0x20); 1679 break; 1680 case V_DISPLAY_ON: 1681 outb(TSIDX, 0x01); 1682 val = inb(TSREG); 1683 outb(TSIDX, 0x01); 1684 outb(TSREG, val & 0xDF); 1685 outb(CRTC, 0x17); 1686 val = inb(CRTC + 1); 1687 outb(CRTC + 1, val | 0x80); 1688 break; 1689 } 1690 crit_exit(); 1691 1692 return 0; 1693 } 1694 1695 /* 1696 * mmap(): 1697 * Mmap frame buffer. 1698 */ 1699 static int 1700 vga_mmap_buf(video_adapter_t *adp, vm_offset_t offset, int prot) 1701 { 1702 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1703 return -1; 1704 1705 #if VGA_DEBUG > 0 1706 kprintf("vga_mmap_buf(): window:0x%x, offset:%p\n", 1707 adp->va_info.vi_window, (void *)offset); 1708 #endif 1709 1710 /* XXX: is this correct? */ 1711 if (offset > adp->va_window_size - PAGE_SIZE) 1712 return -1; 1713 1714 #if defined(__x86_64__) 1715 return x86_64_btop(adp->va_info.vi_window + offset); 1716 #else 1717 #error "vga_mmap_buf needs to return something" 1718 #endif 1719 } 1720 1721 #ifndef VGA_NO_MODE_CHANGE 1722 1723 static void 1724 planar_fill(video_adapter_t *adp, int val) 1725 { 1726 int length; 1727 int at; /* position in the frame buffer */ 1728 int l; 1729 1730 lwkt_gettoken(&tty_token); 1731 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1732 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1733 outw(GDCIDX, 0x0f01); /* set/reset enable */ 1734 outw(GDCIDX, 0xff08); /* bit mask */ 1735 outw(GDCIDX, (val << 8) | 0x00); /* set/reset */ 1736 at = 0; 1737 length = adp->va_line_width*adp->va_info.vi_height; 1738 while (length > 0) { 1739 l = imin(length, adp->va_window_size); 1740 (*vidsw[adp->va_index]->set_win_org)(adp, at); 1741 bzero_io(adp->va_window, l); 1742 length -= l; 1743 at += l; 1744 } 1745 outw(GDCIDX, 0x0000); /* set/reset */ 1746 outw(GDCIDX, 0x0001); /* set/reset enable */ 1747 lwkt_reltoken(&tty_token); 1748 } 1749 1750 static void 1751 packed_fill(video_adapter_t *adp, int val) 1752 { 1753 int length; 1754 int at; /* position in the frame buffer */ 1755 int l; 1756 1757 lwkt_gettoken(&tty_token); 1758 at = 0; 1759 length = adp->va_line_width*adp->va_info.vi_height; 1760 while (length > 0) { 1761 l = imin(length, adp->va_window_size); 1762 (*vidsw[adp->va_index]->set_win_org)(adp, at); 1763 fill_io(val, adp->va_window, l); 1764 length -= l; 1765 at += l; 1766 } 1767 lwkt_reltoken(&tty_token); 1768 } 1769 1770 static void 1771 direct_fill(video_adapter_t *adp, int val) 1772 { 1773 int length; 1774 int at; /* position in the frame buffer */ 1775 int l; 1776 1777 lwkt_gettoken(&tty_token); 1778 at = 0; 1779 length = adp->va_line_width*adp->va_info.vi_height; 1780 while (length > 0) { 1781 l = imin(length, adp->va_window_size); 1782 (*vidsw[adp->va_index]->set_win_org)(adp, at); 1783 switch (adp->va_info.vi_pixel_size) { 1784 case sizeof(u_int16_t): 1785 fillw_io(val, adp->va_window, l/sizeof(u_int16_t)); 1786 break; 1787 case 3: 1788 /* FIXME */ 1789 break; 1790 case sizeof(u_int32_t): 1791 filll_io(val, adp->va_window, l/sizeof(u_int32_t)); 1792 break; 1793 } 1794 length -= l; 1795 at += l; 1796 } 1797 lwkt_reltoken(&tty_token); 1798 } 1799 1800 static int 1801 vga_clear(video_adapter_t *adp) 1802 { 1803 switch (adp->va_info.vi_mem_model) { 1804 case V_INFO_MM_TEXT: 1805 /* do nothing? XXX */ 1806 break; 1807 case V_INFO_MM_PLANAR: 1808 planar_fill(adp, 0); 1809 break; 1810 case V_INFO_MM_PACKED: 1811 packed_fill(adp, 0); 1812 break; 1813 case V_INFO_MM_DIRECT: 1814 direct_fill(adp, 0); 1815 break; 1816 } 1817 return 0; 1818 } 1819 1820 static int 1821 vga_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1822 { 1823 return ENODEV; 1824 } 1825 1826 static int 1827 vga_bitblt(video_adapter_t *adp,...) 1828 { 1829 /* FIXME */ 1830 return ENODEV; 1831 } 1832 1833 #endif /* !VGA_NO_MODE_CHANGE */ 1834 1835 static int 1836 get_palette(video_adapter_t *adp, int base, int count, 1837 u_char *red, u_char *green, u_char *blue, u_char *trans) 1838 { 1839 u_char *r; 1840 u_char *g; 1841 u_char *b; 1842 1843 if (count < 0 || base < 0 || count > 256 || base > 256 || 1844 base + count > 256) 1845 return EINVAL; 1846 1847 r = kmalloc(count*3, M_DEVBUF, M_WAITOK); 1848 g = r + count; 1849 b = g + count; 1850 if (vga_save_palette2(adp, base, count, r, g, b)) { 1851 kfree(r, M_DEVBUF); 1852 return ENODEV; 1853 } 1854 copyout(r, red, count); 1855 copyout(g, green, count); 1856 copyout(b, blue, count); 1857 if (trans != NULL) { 1858 bzero(r, count); 1859 copyout(r, trans, count); 1860 } 1861 kfree(r, M_DEVBUF); 1862 1863 return 0; 1864 } 1865 1866 static int 1867 set_palette(video_adapter_t *adp, int base, int count, 1868 u_char *red, u_char *green, u_char *blue, u_char *trans) 1869 { 1870 u_char *r; 1871 u_char *g; 1872 u_char *b; 1873 int err; 1874 1875 if (count < 0 || base < 0 || count > 256 || base > 256 || 1876 base + count > 256) 1877 return EINVAL; 1878 1879 r = kmalloc(count*3, M_DEVBUF, M_WAITOK); 1880 g = r + count; 1881 b = g + count; 1882 err = copyin(red, r, count); 1883 if (!err) 1884 err = copyin(green, g, count); 1885 if (!err) 1886 err = copyin(blue, b, count); 1887 if (!err) 1888 err = vga_load_palette2(adp, base, count, r, g, b); 1889 kfree(r, M_DEVBUF); 1890 1891 return (err ? ENODEV : 0); 1892 } 1893 1894 static int 1895 vga_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1896 { 1897 switch (cmd) { 1898 case FBIO_GETWINORG: /* get frame buffer window origin */ 1899 *(u_int *)arg = 0; 1900 return 0; 1901 1902 case FBIO_SETWINORG: /* set frame buffer window origin */ 1903 return ENODEV; 1904 1905 case FBIO_SETDISPSTART: /* set display start address */ 1906 return (set_display_start(adp, 1907 ((video_display_start_t *)arg)->x, 1908 ((video_display_start_t *)arg)->y) 1909 ? ENODEV : 0); 1910 1911 case FBIO_SETLINEWIDTH: /* set scan line length in pixel */ 1912 return (set_line_length(adp, *(u_int *)arg) ? ENODEV : 0); 1913 1914 case FBIO_GETPALETTE: /* get color palette */ 1915 return get_palette(adp, ((video_color_palette_t *)arg)->index, 1916 ((video_color_palette_t *)arg)->count, 1917 ((video_color_palette_t *)arg)->red, 1918 ((video_color_palette_t *)arg)->green, 1919 ((video_color_palette_t *)arg)->blue, 1920 ((video_color_palette_t *)arg)->transparent); 1921 1922 case FBIO_SETPALETTE: /* set color palette */ 1923 return set_palette(adp, ((video_color_palette_t *)arg)->index, 1924 ((video_color_palette_t *)arg)->count, 1925 ((video_color_palette_t *)arg)->red, 1926 ((video_color_palette_t *)arg)->green, 1927 ((video_color_palette_t *)arg)->blue, 1928 ((video_color_palette_t *)arg)->transparent); 1929 1930 case FBIOGTYPE: /* get frame buffer type info. */ 1931 ((struct fbtype *)arg)->fb_type = fb_type(adp->va_type); 1932 ((struct fbtype *)arg)->fb_height = adp->va_info.vi_height; 1933 ((struct fbtype *)arg)->fb_width = adp->va_info.vi_width; 1934 ((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth; 1935 if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8)) 1936 ((struct fbtype *)arg)->fb_cmsize = 0; 1937 else 1938 ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth; 1939 ((struct fbtype *)arg)->fb_size = adp->va_buffer_size; 1940 return 0; 1941 1942 case FBIOGETCMAP: /* get color palette */ 1943 return get_palette(adp, ((struct fbcmap *)arg)->index, 1944 ((struct fbcmap *)arg)->count, 1945 ((struct fbcmap *)arg)->red, 1946 ((struct fbcmap *)arg)->green, 1947 ((struct fbcmap *)arg)->blue, NULL); 1948 1949 case FBIOPUTCMAP: /* set color palette */ 1950 return set_palette(adp, ((struct fbcmap *)arg)->index, 1951 ((struct fbcmap *)arg)->count, 1952 ((struct fbcmap *)arg)->red, 1953 ((struct fbcmap *)arg)->green, 1954 ((struct fbcmap *)arg)->blue, NULL); 1955 1956 default: 1957 return fb_commonioctl(adp, cmd, arg); 1958 } 1959 } 1960 1961 /* 1962 * diag(): 1963 * Print some information about the video adapter and video modes, 1964 * with requested level of details. 1965 */ 1966 static int 1967 vga_diag(video_adapter_t *adp, int level) 1968 { 1969 u_char *mp; 1970 #if FB_DEBUG > 1 1971 video_info_t info; 1972 int i; 1973 #endif 1974 1975 if (!vga_init_done) 1976 return ENXIO; 1977 1978 #if FB_DEBUG > 1 1979 #ifndef VGA_NO_MODE_CHANGE 1980 kprintf("vga: DCC code:0x%02x\n", 1981 readb(BIOS_PADDRTOVADDR(0x488))); 1982 kprintf("vga: CRTC:0x%x, video option:0x%02x, ", 1983 readw(BIOS_PADDRTOVADDR(0x463)), 1984 readb(BIOS_PADDRTOVADDR(0x487))); 1985 kprintf("rows:%d, cols:%d, font height:%d\n", 1986 readb(BIOS_PADDRTOVADDR(0x44a)), 1987 readb(BIOS_PADDRTOVADDR(0x484)) + 1, 1988 readb(BIOS_PADDRTOVADDR(0x485))); 1989 kprintf("vga: param table:%p\n", video_mode_ptr); 1990 kprintf("vga: rows_offset:%d\n", rows_offset); 1991 #endif 1992 #endif /* FB_DEBUG > 1 */ 1993 1994 fb_dump_adp_info(VGA_DRIVER_NAME, adp, level); 1995 1996 #if FB_DEBUG > 1 1997 if (adp->va_flags & V_ADP_MODECHANGE) { 1998 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1999 if (bios_vmode[i].vi_mode == NA) 2000 continue; 2001 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 2002 continue; 2003 fb_dump_mode_info(VGA_DRIVER_NAME, adp, &bios_vmode[i], level); 2004 } 2005 } else { 2006 vga_get_info(adp, adp->va_initial_mode, &info); /* shouldn't fail */ 2007 fb_dump_mode_info(VGA_DRIVER_NAME, adp, &info, level); 2008 } 2009 #endif /* FB_DEBUG > 1 */ 2010 2011 #ifndef VGA_NO_MODE_CHANGE 2012 if (video_mode_ptr == NULL) 2013 kprintf("vga%d: %s: WARNING: video mode switching is not " 2014 "fully supported on this adapter\n", 2015 adp->va_unit, adp->va_name); 2016 #endif 2017 if (level <= 0) 2018 return 0; 2019 2020 kprintf("VGA parameters upon power-up\n"); 2021 hexdump(adpstate.regs, sizeof(adpstate.regs), NULL, 2022 HD_OMIT_CHARS | HD_OMIT_COUNT); 2023 2024 mp = get_mode_param(adp->va_initial_mode); 2025 if (mp == NULL) /* this shouldn't be happening */ 2026 return 0; 2027 kprintf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode); 2028 hexdump(adpstate2.regs, sizeof(adpstate2.regs), NULL, 2029 HD_OMIT_CHARS | HD_OMIT_COUNT); 2030 kprintf("VGA parameters to be used for mode %d\n", adp->va_initial_mode); 2031 hexdump(mp, V_MODE_PARAM_SIZE, NULL, HD_OMIT_CHARS | HD_OMIT_COUNT); 2032 2033 return 0; 2034 } 2035