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 return ENODEV; 1119 #endif /* VGA_NO_MODE_CHANGE */ 1120 } 1121 1122 #ifndef VGA_NO_FONT_LOADING 1123 1124 static void 1125 set_font_mode(video_adapter_t *adp, u_char *buf) 1126 { 1127 crit_enter(); 1128 1129 /* save register values */ 1130 outb(TSIDX, 0x02); buf[0] = inb(TSREG); 1131 outb(TSIDX, 0x04); buf[1] = inb(TSREG); 1132 outb(GDCIDX, 0x04); buf[2] = inb(GDCREG); 1133 outb(GDCIDX, 0x05); buf[3] = inb(GDCREG); 1134 outb(GDCIDX, 0x06); buf[4] = inb(GDCREG); 1135 inb(CRTC + 6); 1136 outb(ATC, 0x10); buf[5] = inb(ATC + 1); 1137 1138 /* setup vga for loading fonts */ 1139 inb(CRTC + 6); /* reset flip-flop */ 1140 outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01); 1141 inb(CRTC + 6); /* reset flip-flop */ 1142 outb(ATC, 0x20); /* enable palette */ 1143 outw(TSIDX, 0x0402); 1144 outw(TSIDX, 0x0704); 1145 outw(GDCIDX, 0x0204); 1146 outw(GDCIDX, 0x0005); 1147 outw(GDCIDX, 0x0406); /* addr = a0000, 64kb */ 1148 1149 crit_exit(); 1150 } 1151 1152 static void 1153 set_normal_mode(video_adapter_t *adp, u_char *buf) 1154 { 1155 crit_enter(); 1156 1157 /* setup vga for normal operation mode again */ 1158 inb(CRTC + 6); /* reset flip-flop */ 1159 outb(ATC, 0x10); outb(ATC, buf[5]); 1160 inb(CRTC + 6); /* reset flip-flop */ 1161 outb(ATC, 0x20); /* enable palette */ 1162 outw(TSIDX, 0x0002 | (buf[0] << 8)); 1163 outw(TSIDX, 0x0004 | (buf[1] << 8)); 1164 outw(GDCIDX, 0x0004 | (buf[2] << 8)); 1165 outw(GDCIDX, 0x0005 | (buf[3] << 8)); 1166 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8)); 1167 1168 crit_exit(); 1169 } 1170 1171 #endif /* VGA_NO_FONT_LOADING */ 1172 1173 /* 1174 * save_font(): 1175 * Read the font data in the requested font page from the video adapter. 1176 */ 1177 static int 1178 vga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data, 1179 int ch, int count) 1180 { 1181 #ifndef VGA_NO_FONT_LOADING 1182 u_char buf[PARAM_BUFSIZE]; 1183 vm_offset_t segment; 1184 int c; 1185 1186 prologue(adp, V_ADP_FONT, ENODEV); 1187 1188 if (fontsize < 14) { 1189 /* FONT_8 */ 1190 fontsize = 8; 1191 } else if (fontsize >= 32) { 1192 fontsize = 32; 1193 } else if (fontsize >= 16) { 1194 /* FONT_16 */ 1195 fontsize = 16; 1196 } else { 1197 /* FONT_14 */ 1198 fontsize = 14; 1199 } 1200 1201 if (page < 0 || page >= 8) 1202 return EINVAL; 1203 segment = FONT_BUF + 0x4000*page; 1204 if (page > 3) 1205 segment -= 0xe000; 1206 1207 set_font_mode(adp, buf); 1208 if (fontsize == 32) { 1209 bcopy_fromio((uintptr_t)segment + ch*32, data, fontsize*count); 1210 } else { 1211 for (c = ch; count > 0; ++c, --count) { 1212 bcopy_fromio((uintptr_t)segment + c*32, data, fontsize); 1213 data += fontsize; 1214 } 1215 } 1216 set_normal_mode(adp, buf); 1217 1218 return 0; 1219 #else /* VGA_NO_FONT_LOADING */ 1220 return ENODEV; 1221 #endif /* VGA_NO_FONT_LOADING */ 1222 } 1223 1224 /* 1225 * load_font(): 1226 * Set the font data in the requested font page. 1227 * NOTE: it appears that some recent video adapters do not support 1228 * the font page other than 0... XXX 1229 */ 1230 static int 1231 vga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data, 1232 int ch, int count) 1233 { 1234 #ifndef VGA_NO_FONT_LOADING 1235 u_char buf[PARAM_BUFSIZE]; 1236 vm_offset_t segment; 1237 int c; 1238 1239 prologue(adp, V_ADP_FONT, ENODEV); 1240 1241 if (fontsize < 14) { 1242 /* FONT_8 */ 1243 fontsize = 8; 1244 } else if (fontsize >= 32) { 1245 fontsize = 32; 1246 } else if (fontsize >= 16) { 1247 /* FONT_16 */ 1248 fontsize = 16; 1249 } else { 1250 /* FONT_14 */ 1251 fontsize = 14; 1252 } 1253 1254 if (page < 0 || page >= 8) 1255 return EINVAL; 1256 segment = FONT_BUF + 0x4000*page; 1257 if (page > 3) 1258 segment -= 0xe000; 1259 1260 set_font_mode(adp, buf); 1261 if (fontsize == 32) { 1262 bcopy_toio(data, (uintptr_t)segment + ch*32, fontsize*count); 1263 } else { 1264 for (c = ch; count > 0; ++c, --count) { 1265 bcopy_toio(data, (uintptr_t)segment + c*32, fontsize); 1266 data += fontsize; 1267 } 1268 } 1269 set_normal_mode(adp, buf); 1270 1271 return 0; 1272 #else /* VGA_NO_FONT_LOADING */ 1273 return ENODEV; 1274 #endif /* VGA_NO_FONT_LOADING */ 1275 } 1276 1277 /* 1278 * show_font(): 1279 * Activate the requested font page. 1280 * NOTE: it appears that some recent video adapters do not support 1281 * the font page other than 0... XXX 1282 */ 1283 static int 1284 vga_show_font(video_adapter_t *adp, int page) 1285 { 1286 #ifndef VGA_NO_FONT_LOADING 1287 static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f }; 1288 1289 prologue(adp, V_ADP_FONT, ENODEV); 1290 if (page < 0 || page >= 8) 1291 return EINVAL; 1292 1293 crit_enter(); 1294 outb(TSIDX, 0x03); outb(TSREG, cg[page]); 1295 crit_exit(); 1296 1297 return 0; 1298 #else /* VGA_NO_FONT_LOADING */ 1299 return ENODEV; 1300 #endif /* VGA_NO_FONT_LOADING */ 1301 } 1302 1303 /* 1304 * save_palette(): 1305 * Read DAC values. The values have expressed in 8 bits. 1306 * 1307 * VGA 1308 */ 1309 static int 1310 vga_save_palette(video_adapter_t *adp, u_char *palette) 1311 { 1312 int i; 1313 1314 prologue(adp, V_ADP_PALETTE, ENODEV); 1315 1316 /* 1317 * We store 8 bit values in the palette buffer, while the standard 1318 * VGA has 6 bit DAC . 1319 */ 1320 outb(PALRADR, 0x00); 1321 for (i = 0; i < 256*3; ++i) 1322 palette[i] = inb(PALDATA) << 2; 1323 inb(CRTC + 6); /* reset flip/flop */ 1324 return 0; 1325 } 1326 1327 static int 1328 vga_save_palette2(video_adapter_t *adp, int base, int count, 1329 u_char *r, u_char *g, u_char *b) 1330 { 1331 int i; 1332 1333 prologue(adp, V_ADP_PALETTE, ENODEV); 1334 1335 outb(PALRADR, base); 1336 for (i = 0; i < count; ++i) { 1337 r[i] = inb(PALDATA) << 2; 1338 g[i] = inb(PALDATA) << 2; 1339 b[i] = inb(PALDATA) << 2; 1340 } 1341 inb(CRTC + 6); /* reset flip/flop */ 1342 return 0; 1343 } 1344 1345 /* 1346 * load_palette(): 1347 * Set DAC values. 1348 * 1349 * VGA 1350 */ 1351 static int 1352 vga_load_palette(video_adapter_t *adp, const u_char *palette) 1353 { 1354 int i; 1355 1356 prologue(adp, V_ADP_PALETTE, ENODEV); 1357 1358 outb(PIXMASK, 0xff); /* no pixelmask */ 1359 outb(PALWADR, 0x00); 1360 for (i = 0; i < 256*3; ++i) 1361 outb(PALDATA, palette[i] >> 2); 1362 inb(CRTC + 6); /* reset flip/flop */ 1363 outb(ATC, 0x20); /* enable palette */ 1364 return 0; 1365 } 1366 1367 static int 1368 vga_load_palette2(video_adapter_t *adp, int base, int count, 1369 u_char *r, u_char *g, u_char *b) 1370 { 1371 int i; 1372 1373 prologue(adp, V_ADP_PALETTE, ENODEV); 1374 1375 outb(PIXMASK, 0xff); /* no pixelmask */ 1376 outb(PALWADR, base); 1377 for (i = 0; i < count; ++i) { 1378 outb(PALDATA, r[i] >> 2); 1379 outb(PALDATA, g[i] >> 2); 1380 outb(PALDATA, b[i] >> 2); 1381 } 1382 inb(CRTC + 6); /* reset flip/flop */ 1383 outb(ATC, 0x20); /* enable palette */ 1384 return 0; 1385 } 1386 1387 /* 1388 * set_border(): 1389 * Change the border color. 1390 */ 1391 static int 1392 vga_set_border(video_adapter_t *adp, int color) 1393 { 1394 prologue(adp, V_ADP_BORDER, ENODEV); 1395 1396 inb(CRTC + 6); /* reset flip-flop */ 1397 outb(ATC, 0x31); outb(ATC, color & 0xff); 1398 1399 return 0; 1400 } 1401 1402 /* 1403 * save_state(): 1404 * Read video register values. 1405 * NOTE: this function only reads the standard VGA registers. 1406 * any extra/extended registers of SVGA adapters are not saved. 1407 */ 1408 static int 1409 vga_save_state(video_adapter_t *adp, void *p, size_t size) 1410 { 1411 video_info_t info; 1412 u_char *buf; 1413 int i, j; 1414 1415 if (size == 0) { 1416 /* return the required buffer size */ 1417 prologue(adp, V_ADP_STATESAVE, 0); 1418 return sizeof(adp_state_t); 1419 } else { 1420 prologue(adp, V_ADP_STATESAVE, ENODEV); 1421 if (size < sizeof(adp_state_t)) 1422 return EINVAL; 1423 } 1424 ((adp_state_t *)p)->sig = V_STATE_SIG; 1425 buf = ((adp_state_t *)p)->regs; 1426 bzero(buf, V_MODE_PARAM_SIZE); 1427 1428 crit_enter(); 1429 1430 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1431 for (i = 0, j = 5; i < 4; i++) { 1432 outb(TSIDX, i + 1); 1433 buf[j++] = inb(TSREG); 1434 } 1435 buf[9] = inb(MISC + 10); /* dot-clock */ 1436 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1437 1438 for (i = 0, j = 10; i < 25; i++) { /* crtc */ 1439 outb(CRTC, i); 1440 buf[j++] = inb(CRTC + 1); 1441 } 1442 for (i = 0, j = 35; i < 20; i++) { /* attribute ctrl */ 1443 inb(CRTC + 6); /* reset flip-flop */ 1444 outb(ATC, i); 1445 buf[j++] = inb(ATC + 1); 1446 } 1447 for (i = 0, j = 55; i < 9; i++) { /* graph data ctrl */ 1448 outb(GDCIDX, i); 1449 buf[j++] = inb(GDCREG); 1450 } 1451 inb(CRTC + 6); /* reset flip-flop */ 1452 outb(ATC, 0x20); /* enable palette */ 1453 1454 crit_exit(); 1455 1456 #if 1 1457 if (vga_get_info(adp, adp->va_mode, &info) == 0) { 1458 if (info.vi_flags & V_INFO_GRAPHICS) { 1459 buf[0] = info.vi_width/info.vi_cwidth; /* COLS */ 1460 buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */ 1461 } else { 1462 buf[0] = info.vi_width; /* COLS */ 1463 buf[1] = info.vi_height - 1; /* ROWS */ 1464 } 1465 buf[2] = info.vi_cheight; /* POINTS */ 1466 } else { 1467 /* XXX: shouldn't be happening... */ 1468 kprintf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n", 1469 adp->va_unit, adp->va_name); 1470 } 1471 #else 1472 buf[0] = readb(BIOS_PADDRTOVADDR(0x44a)); /* COLS */ 1473 buf[1] = readb(BIOS_PADDRTOVADDR(0x484)); /* ROWS */ 1474 buf[2] = readb(BIOS_PADDRTOVADDR(0x485)); /* POINTS */ 1475 buf[3] = readb(BIOS_PADDRTOVADDR(0x44c)); 1476 buf[4] = readb(BIOS_PADDRTOVADDR(0x44d)); 1477 #endif 1478 1479 return 0; 1480 } 1481 1482 /* 1483 * load_state(): 1484 * Set video registers at once. 1485 * NOTE: this function only updates the standard VGA registers. 1486 * any extra/extended registers of SVGA adapters are not changed. 1487 */ 1488 static int 1489 vga_load_state(video_adapter_t *adp, void *p) 1490 { 1491 u_char *buf; 1492 int i; 1493 1494 prologue(adp, V_ADP_STATELOAD, ENODEV); 1495 if (((adp_state_t *)p)->sig != V_STATE_SIG) 1496 return EINVAL; 1497 1498 buf = ((adp_state_t *)p)->regs; 1499 1500 #if VGA_DEBUG > 1 1501 hexdump(buf, V_MODE_PARAM_SIZE, NULL, HD_OMIT_CHARS | HD_OMIT_COUNT); 1502 #endif 1503 1504 crit_enter(); 1505 1506 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1507 for (i = 0; i < 4; ++i) { /* program sequencer */ 1508 outb(TSIDX, i + 1); 1509 outb(TSREG, buf[i + 5]); 1510 } 1511 outb(MISC, buf[9]); /* set dot-clock */ 1512 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1513 outb(CRTC, 0x11); 1514 outb(CRTC + 1, inb(CRTC + 1) & 0x7F); 1515 for (i = 0; i < 25; ++i) { /* program crtc */ 1516 outb(CRTC, i); 1517 outb(CRTC + 1, buf[i + 10]); 1518 } 1519 inb(CRTC + 6); /* reset flip-flop */ 1520 for (i = 0; i < 20; ++i) { /* program attribute ctrl */ 1521 outb(ATC, i); 1522 outb(ATC, buf[i + 35]); 1523 } 1524 for (i = 0; i < 9; ++i) { /* program graph data ctrl */ 1525 outb(GDCIDX, i); 1526 outb(GDCREG, buf[i + 55]); 1527 } 1528 inb(CRTC + 6); /* reset flip-flop */ 1529 outb(ATC, 0x20); /* enable palette */ 1530 1531 #if 0 /* XXX a temporary workaround for kernel panic */ 1532 #ifndef VGA_NO_MODE_CHANGE 1533 if (adp->va_unit == V_ADP_PRIMARY) { 1534 writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]); /* COLS */ 1535 writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */ 1536 writeb(BIOS_PADDRTOVADDR(0x485), buf[2]); /* POINTS */ 1537 #if 0 1538 writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]); 1539 writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]); 1540 #endif 1541 } 1542 #endif /* !VGA_NO_MODE_CHANGE */ 1543 #endif /* XXX */ 1544 1545 crit_exit(); 1546 return 0; 1547 } 1548 1549 /* 1550 * set_origin(): 1551 * Change the origin (window mapping) of the banked frame buffer. 1552 */ 1553 static int 1554 vga_set_origin(video_adapter_t *adp, off_t offset) 1555 { 1556 /* 1557 * The standard video modes do not require window mapping; 1558 * always return error. 1559 */ 1560 return ENODEV; 1561 } 1562 1563 /* 1564 * read_hw_cursor(): 1565 * Read the position of the hardware text cursor. 1566 */ 1567 static int 1568 vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1569 { 1570 u_int16_t off; 1571 1572 if (!vga_init_done) 1573 return ENXIO; 1574 1575 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1576 return ENODEV; 1577 1578 crit_enter(); 1579 outb(CRTC, 14); 1580 off = inb(CRTC + 1); 1581 outb(CRTC, 15); 1582 off = (off << 8) | inb(CRTC + 1); 1583 crit_exit(); 1584 1585 *row = off / adp->va_info.vi_width; 1586 *col = off % adp->va_info.vi_width; 1587 1588 return 0; 1589 } 1590 1591 /* 1592 * set_hw_cursor(): 1593 * Move the hardware text cursor. If col and row are both -1, 1594 * the cursor won't be shown. 1595 */ 1596 static int 1597 vga_set_hw_cursor(video_adapter_t *adp, int col, int row) 1598 { 1599 u_int16_t off; 1600 1601 if (!vga_init_done) 1602 return ENXIO; 1603 1604 if ((col == -1) && (row == -1)) { 1605 off = -1; 1606 } else { 1607 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1608 return ENODEV; 1609 off = row*adp->va_info.vi_width + col; 1610 } 1611 1612 crit_enter(); 1613 outb(CRTC, 14); 1614 outb(CRTC + 1, off >> 8); 1615 outb(CRTC, 15); 1616 outb(CRTC + 1, off & 0x00ff); 1617 crit_exit(); 1618 1619 return 0; 1620 } 1621 1622 /* 1623 * set_hw_cursor_shape(): 1624 * Change the shape of the hardware text cursor. If the height is 1625 * zero or negative, the cursor won't be shown. 1626 */ 1627 static int 1628 vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1629 int celsize, int blink) 1630 { 1631 if (!vga_init_done) 1632 return ENXIO; 1633 1634 crit_enter(); 1635 if (height <= 0) { 1636 /* make the cursor invisible */ 1637 outb(CRTC, 10); 1638 outb(CRTC + 1, 32); 1639 outb(CRTC, 11); 1640 outb(CRTC + 1, 0); 1641 } else { 1642 outb(CRTC, 10); 1643 outb(CRTC + 1, celsize - base - height); 1644 outb(CRTC, 11); 1645 outb(CRTC + 1, celsize - base - 1); 1646 } 1647 crit_exit(); 1648 1649 return 0; 1650 } 1651 1652 /* 1653 * blank_display() 1654 * Put the display in power save/power off mode. 1655 */ 1656 static int 1657 vga_blank_display(video_adapter_t *adp, int mode) 1658 { 1659 u_char val; 1660 1661 crit_enter(); 1662 switch (mode) { 1663 case V_DISPLAY_SUSPEND: 1664 case V_DISPLAY_STAND_BY: 1665 outb(TSIDX, 0x01); 1666 val = inb(TSREG); 1667 outb(TSIDX, 0x01); 1668 outb(TSREG, val | 0x20); 1669 outb(CRTC, 0x17); 1670 val = inb(CRTC + 1); 1671 outb(CRTC + 1, val & ~0x80); 1672 break; 1673 case V_DISPLAY_OFF: 1674 outb(TSIDX, 0x01); 1675 val = inb(TSREG); 1676 outb(TSIDX, 0x01); 1677 outb(TSREG, val | 0x20); 1678 break; 1679 case V_DISPLAY_ON: 1680 outb(TSIDX, 0x01); 1681 val = inb(TSREG); 1682 outb(TSIDX, 0x01); 1683 outb(TSREG, val & 0xDF); 1684 outb(CRTC, 0x17); 1685 val = inb(CRTC + 1); 1686 outb(CRTC + 1, val | 0x80); 1687 break; 1688 } 1689 crit_exit(); 1690 1691 return 0; 1692 } 1693 1694 /* 1695 * mmap(): 1696 * Mmap frame buffer. 1697 */ 1698 static int 1699 vga_mmap_buf(video_adapter_t *adp, vm_offset_t offset, int prot) 1700 { 1701 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1702 return -1; 1703 1704 #if VGA_DEBUG > 0 1705 kprintf("vga_mmap_buf(): window:0x%x, offset:%p\n", 1706 adp->va_info.vi_window, (void *)offset); 1707 #endif 1708 1709 /* XXX: is this correct? */ 1710 if (offset > adp->va_window_size - PAGE_SIZE) 1711 return -1; 1712 1713 #if defined(__x86_64__) 1714 return x86_64_btop(adp->va_info.vi_window + offset); 1715 #else 1716 #error "vga_mmap_buf needs to return something" 1717 #endif 1718 } 1719 1720 #ifndef VGA_NO_MODE_CHANGE 1721 1722 static void 1723 planar_fill(video_adapter_t *adp, int val) 1724 { 1725 int length; 1726 int at; /* position in the frame buffer */ 1727 int l; 1728 1729 lwkt_gettoken(&tty_token); 1730 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1731 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1732 outw(GDCIDX, 0x0f01); /* set/reset enable */ 1733 outw(GDCIDX, 0xff08); /* bit mask */ 1734 outw(GDCIDX, (val << 8) | 0x00); /* set/reset */ 1735 at = 0; 1736 length = adp->va_line_width*adp->va_info.vi_height; 1737 while (length > 0) { 1738 l = imin(length, adp->va_window_size); 1739 (*vidsw[adp->va_index]->set_win_org)(adp, at); 1740 bzero_io(adp->va_window, l); 1741 length -= l; 1742 at += l; 1743 } 1744 outw(GDCIDX, 0x0000); /* set/reset */ 1745 outw(GDCIDX, 0x0001); /* set/reset enable */ 1746 lwkt_reltoken(&tty_token); 1747 } 1748 1749 static void 1750 packed_fill(video_adapter_t *adp, int val) 1751 { 1752 int length; 1753 int at; /* position in the frame buffer */ 1754 int l; 1755 1756 lwkt_gettoken(&tty_token); 1757 at = 0; 1758 length = adp->va_line_width*adp->va_info.vi_height; 1759 while (length > 0) { 1760 l = imin(length, adp->va_window_size); 1761 (*vidsw[adp->va_index]->set_win_org)(adp, at); 1762 fill_io(val, adp->va_window, l); 1763 length -= l; 1764 at += l; 1765 } 1766 lwkt_reltoken(&tty_token); 1767 } 1768 1769 static void 1770 direct_fill(video_adapter_t *adp, int val) 1771 { 1772 int length; 1773 int at; /* position in the frame buffer */ 1774 int l; 1775 1776 lwkt_gettoken(&tty_token); 1777 at = 0; 1778 length = adp->va_line_width*adp->va_info.vi_height; 1779 while (length > 0) { 1780 l = imin(length, adp->va_window_size); 1781 (*vidsw[adp->va_index]->set_win_org)(adp, at); 1782 switch (adp->va_info.vi_pixel_size) { 1783 case sizeof(u_int16_t): 1784 fillw_io(val, adp->va_window, l/sizeof(u_int16_t)); 1785 break; 1786 case 3: 1787 /* FIXME */ 1788 break; 1789 case sizeof(u_int32_t): 1790 filll_io(val, adp->va_window, l/sizeof(u_int32_t)); 1791 break; 1792 } 1793 length -= l; 1794 at += l; 1795 } 1796 lwkt_reltoken(&tty_token); 1797 } 1798 1799 static int 1800 vga_clear(video_adapter_t *adp) 1801 { 1802 switch (adp->va_info.vi_mem_model) { 1803 case V_INFO_MM_TEXT: 1804 /* do nothing? XXX */ 1805 break; 1806 case V_INFO_MM_PLANAR: 1807 planar_fill(adp, 0); 1808 break; 1809 case V_INFO_MM_PACKED: 1810 packed_fill(adp, 0); 1811 break; 1812 case V_INFO_MM_DIRECT: 1813 direct_fill(adp, 0); 1814 break; 1815 } 1816 return 0; 1817 } 1818 1819 static int 1820 vga_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1821 { 1822 return ENODEV; 1823 } 1824 1825 static int 1826 vga_bitblt(video_adapter_t *adp,...) 1827 { 1828 /* FIXME */ 1829 return ENODEV; 1830 } 1831 1832 #endif /* !VGA_NO_MODE_CHANGE */ 1833 1834 static int 1835 get_palette(video_adapter_t *adp, int base, int count, 1836 u_char *red, u_char *green, u_char *blue, u_char *trans) 1837 { 1838 u_char *r; 1839 u_char *g; 1840 u_char *b; 1841 1842 if (count < 0 || base < 0 || count > 256 || base > 256 || 1843 base + count > 256) 1844 return EINVAL; 1845 1846 r = kmalloc(count*3, M_DEVBUF, M_WAITOK); 1847 g = r + count; 1848 b = g + count; 1849 if (vga_save_palette2(adp, base, count, r, g, b)) { 1850 kfree(r, M_DEVBUF); 1851 return ENODEV; 1852 } 1853 copyout(r, red, count); 1854 copyout(g, green, count); 1855 copyout(b, blue, count); 1856 if (trans != NULL) { 1857 bzero(r, count); 1858 copyout(r, trans, count); 1859 } 1860 kfree(r, M_DEVBUF); 1861 1862 return 0; 1863 } 1864 1865 static int 1866 set_palette(video_adapter_t *adp, int base, int count, 1867 u_char *red, u_char *green, u_char *blue, u_char *trans) 1868 { 1869 u_char *r; 1870 u_char *g; 1871 u_char *b; 1872 int err; 1873 1874 if (count < 0 || base < 0 || count > 256 || base > 256 || 1875 base + count > 256) 1876 return EINVAL; 1877 1878 r = kmalloc(count*3, M_DEVBUF, M_WAITOK); 1879 g = r + count; 1880 b = g + count; 1881 err = copyin(red, r, count); 1882 if (!err) 1883 err = copyin(green, g, count); 1884 if (!err) 1885 err = copyin(blue, b, count); 1886 if (!err) 1887 err = vga_load_palette2(adp, base, count, r, g, b); 1888 kfree(r, M_DEVBUF); 1889 1890 return (err ? ENODEV : 0); 1891 } 1892 1893 static int 1894 vga_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1895 { 1896 switch (cmd) { 1897 case FBIO_GETWINORG: /* get frame buffer window origin */ 1898 *(u_int *)arg = 0; 1899 return 0; 1900 1901 case FBIO_SETWINORG: /* set frame buffer window origin */ 1902 return ENODEV; 1903 1904 case FBIO_SETDISPSTART: /* set display start address */ 1905 return (set_display_start(adp, 1906 ((video_display_start_t *)arg)->x, 1907 ((video_display_start_t *)arg)->y) 1908 ? ENODEV : 0); 1909 1910 case FBIO_SETLINEWIDTH: /* set scan line length in pixel */ 1911 return (set_line_length(adp, *(u_int *)arg) ? ENODEV : 0); 1912 1913 case FBIO_GETPALETTE: /* get color palette */ 1914 return get_palette(adp, ((video_color_palette_t *)arg)->index, 1915 ((video_color_palette_t *)arg)->count, 1916 ((video_color_palette_t *)arg)->red, 1917 ((video_color_palette_t *)arg)->green, 1918 ((video_color_palette_t *)arg)->blue, 1919 ((video_color_palette_t *)arg)->transparent); 1920 1921 case FBIO_SETPALETTE: /* set color palette */ 1922 return set_palette(adp, ((video_color_palette_t *)arg)->index, 1923 ((video_color_palette_t *)arg)->count, 1924 ((video_color_palette_t *)arg)->red, 1925 ((video_color_palette_t *)arg)->green, 1926 ((video_color_palette_t *)arg)->blue, 1927 ((video_color_palette_t *)arg)->transparent); 1928 1929 case FBIOGTYPE: /* get frame buffer type info. */ 1930 ((struct fbtype *)arg)->fb_type = fb_type(adp->va_type); 1931 ((struct fbtype *)arg)->fb_height = adp->va_info.vi_height; 1932 ((struct fbtype *)arg)->fb_width = adp->va_info.vi_width; 1933 ((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth; 1934 if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8)) 1935 ((struct fbtype *)arg)->fb_cmsize = 0; 1936 else 1937 ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth; 1938 ((struct fbtype *)arg)->fb_size = adp->va_buffer_size; 1939 return 0; 1940 1941 case FBIOGETCMAP: /* get color palette */ 1942 return get_palette(adp, ((struct fbcmap *)arg)->index, 1943 ((struct fbcmap *)arg)->count, 1944 ((struct fbcmap *)arg)->red, 1945 ((struct fbcmap *)arg)->green, 1946 ((struct fbcmap *)arg)->blue, NULL); 1947 1948 case FBIOPUTCMAP: /* set color palette */ 1949 return set_palette(adp, ((struct fbcmap *)arg)->index, 1950 ((struct fbcmap *)arg)->count, 1951 ((struct fbcmap *)arg)->red, 1952 ((struct fbcmap *)arg)->green, 1953 ((struct fbcmap *)arg)->blue, NULL); 1954 1955 default: 1956 return fb_commonioctl(adp, cmd, arg); 1957 } 1958 } 1959 1960 /* 1961 * diag(): 1962 * Print some information about the video adapter and video modes, 1963 * with requested level of details. 1964 */ 1965 static int 1966 vga_diag(video_adapter_t *adp, int level) 1967 { 1968 u_char *mp; 1969 #if FB_DEBUG > 1 1970 video_info_t info; 1971 int i; 1972 #endif 1973 1974 if (!vga_init_done) 1975 return ENXIO; 1976 1977 #if FB_DEBUG > 1 1978 #ifndef VGA_NO_MODE_CHANGE 1979 kprintf("vga: DCC code:0x%02x\n", 1980 readb(BIOS_PADDRTOVADDR(0x488))); 1981 kprintf("vga: CRTC:0x%x, video option:0x%02x, ", 1982 readw(BIOS_PADDRTOVADDR(0x463)), 1983 readb(BIOS_PADDRTOVADDR(0x487))); 1984 kprintf("rows:%d, cols:%d, font height:%d\n", 1985 readb(BIOS_PADDRTOVADDR(0x44a)), 1986 readb(BIOS_PADDRTOVADDR(0x484)) + 1, 1987 readb(BIOS_PADDRTOVADDR(0x485))); 1988 kprintf("vga: param table:%p\n", video_mode_ptr); 1989 kprintf("vga: rows_offset:%d\n", rows_offset); 1990 #endif 1991 #endif /* FB_DEBUG > 1 */ 1992 1993 fb_dump_adp_info(VGA_DRIVER_NAME, adp, level); 1994 1995 #if FB_DEBUG > 1 1996 if (adp->va_flags & V_ADP_MODECHANGE) { 1997 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1998 if (bios_vmode[i].vi_mode == NA) 1999 continue; 2000 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 2001 continue; 2002 fb_dump_mode_info(VGA_DRIVER_NAME, adp, &bios_vmode[i], level); 2003 } 2004 } else { 2005 vga_get_info(adp, adp->va_initial_mode, &info); /* shouldn't fail */ 2006 fb_dump_mode_info(VGA_DRIVER_NAME, adp, &info, level); 2007 } 2008 #endif /* FB_DEBUG > 1 */ 2009 2010 #ifndef VGA_NO_MODE_CHANGE 2011 if (video_mode_ptr == NULL) 2012 kprintf("vga%d: %s: WARNING: video mode switching is not " 2013 "fully supported on this adapter\n", 2014 adp->va_unit, adp->va_name); 2015 #endif 2016 if (level <= 0) 2017 return 0; 2018 2019 kprintf("VGA parameters upon power-up\n"); 2020 hexdump(adpstate.regs, sizeof(adpstate.regs), NULL, 2021 HD_OMIT_CHARS | HD_OMIT_COUNT); 2022 2023 mp = get_mode_param(adp->va_initial_mode); 2024 if (mp == NULL) /* this shouldn't be happening */ 2025 return 0; 2026 kprintf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode); 2027 hexdump(adpstate2.regs, sizeof(adpstate2.regs), NULL, 2028 HD_OMIT_CHARS | HD_OMIT_COUNT); 2029 kprintf("VGA parameters to be used for mode %d\n", adp->va_initial_mode); 2030 hexdump(mp, V_MODE_PARAM_SIZE, NULL, HD_OMIT_CHARS | HD_OMIT_COUNT); 2031 2032 return 0; 2033 } 2034