1 /*- 2 * Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith 3 * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer as 11 * the first lines of this file unmodified. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_vga.h" 32 #include "opt_vesa.h" 33 34 #ifndef VGA_NO_MODE_CHANGE 35 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/module.h> 41 #include <sys/malloc.h> 42 #include <sys/fbio.h> 43 44 #include <vm/vm.h> 45 #include <vm/vm_extern.h> 46 #include <vm/vm_kern.h> 47 #include <vm/vm_param.h> 48 #include <vm/pmap.h> 49 50 #include <machine/pc/bios.h> 51 #include <dev/fb/vesa.h> 52 53 #include <dev/fb/fbreg.h> 54 #include <dev/fb/vgareg.h> 55 56 #include <dev/pci/pcivar.h> 57 58 #include <isa/isareg.h> 59 60 #include <compat/x86bios/x86bios.h> 61 62 #define VESA_VIA_CLE266 "VIA CLE266\r\n" 63 64 #ifndef VESA_DEBUG 65 #define VESA_DEBUG 0 66 #endif 67 68 /* VESA video adapter state buffer stub */ 69 struct adp_state { 70 int sig; 71 #define V_STATE_SIG 0x61736576 72 u_char regs[1]; 73 }; 74 typedef struct adp_state adp_state_t; 75 76 static void *vesa_state_buf = NULL; 77 static uint32_t vesa_state_buf_offs = 0; 78 static ssize_t vesa_state_buf_size = 0; 79 80 static u_char *vesa_palette = NULL; 81 static uint32_t vesa_palette_offs = 0; 82 #define VESA_PALETTE_SIZE (256 * 4) 83 84 /* VESA video adapter */ 85 static video_adapter_t *vesa_adp = NULL; 86 87 /* VESA functions */ 88 #if 0 89 static int vesa_nop(void); 90 #endif 91 static int vesa_error(void); 92 static vi_probe_t vesa_probe; 93 static vi_init_t vesa_init; 94 static vi_get_info_t vesa_get_info; 95 static vi_query_mode_t vesa_query_mode; 96 static vi_set_mode_t vesa_set_mode; 97 static vi_save_font_t vesa_save_font; 98 static vi_load_font_t vesa_load_font; 99 static vi_show_font_t vesa_show_font; 100 static vi_save_palette_t vesa_save_palette; 101 static vi_load_palette_t vesa_load_palette; 102 static vi_set_border_t vesa_set_border; 103 static vi_save_state_t vesa_save_state; 104 static vi_load_state_t vesa_load_state; 105 static vi_set_win_org_t vesa_set_origin; 106 static vi_read_hw_cursor_t vesa_read_hw_cursor; 107 static vi_set_hw_cursor_t vesa_set_hw_cursor; 108 static vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape; 109 static vi_blank_display_t vesa_blank_display; 110 static vi_mmap_t vesa_mmap; 111 static vi_ioctl_t vesa_ioctl; 112 static vi_clear_t vesa_clear; 113 static vi_fill_rect_t vesa_fill_rect; 114 static vi_bitblt_t vesa_bitblt; 115 static vi_diag_t vesa_diag; 116 static int vesa_bios_info(int level); 117 118 static video_switch_t vesavidsw = { 119 vesa_probe, 120 vesa_init, 121 vesa_get_info, 122 vesa_query_mode, 123 vesa_set_mode, 124 vesa_save_font, 125 vesa_load_font, 126 vesa_show_font, 127 vesa_save_palette, 128 vesa_load_palette, 129 vesa_set_border, 130 vesa_save_state, 131 vesa_load_state, 132 vesa_set_origin, 133 vesa_read_hw_cursor, 134 vesa_set_hw_cursor, 135 vesa_set_hw_cursor_shape, 136 vesa_blank_display, 137 vesa_mmap, 138 vesa_ioctl, 139 vesa_clear, 140 vesa_fill_rect, 141 vesa_bitblt, 142 vesa_error, 143 vesa_error, 144 vesa_diag, 145 }; 146 147 static video_switch_t *prevvidsw; 148 149 /* VESA BIOS video modes */ 150 #define VESA_MAXMODES 64 151 #define EOT (-1) 152 #define NA (-2) 153 154 #define MODE_TABLE_DELTA 8 155 156 static int vesa_vmode_max = 0; 157 static video_info_t vesa_vmode_empty = { EOT }; 158 static video_info_t *vesa_vmode = &vesa_vmode_empty; 159 160 static int vesa_init_done = FALSE; 161 static int has_vesa_bios = FALSE; 162 static struct vesa_info *vesa_adp_info = NULL; 163 static u_int16_t *vesa_vmodetab = NULL; 164 static char *vesa_oemstr = NULL; 165 static char *vesa_venderstr = NULL; 166 static char *vesa_prodstr = NULL; 167 static char *vesa_revstr = NULL; 168 169 /* local macros and functions */ 170 #define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 171 172 static int int10_set_mode(int mode); 173 static int vesa_bios_post(void); 174 static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode, int flags); 175 static int vesa_bios_set_mode(int mode); 176 #if 0 177 static int vesa_bios_get_dac(void); 178 #endif 179 static int vesa_bios_set_dac(int bits); 180 static int vesa_bios_save_palette(int start, int colors, u_char *palette, 181 int bits); 182 static int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, 183 u_char *b, int bits); 184 static int vesa_bios_load_palette(int start, int colors, u_char *palette, 185 int bits); 186 static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, 187 u_char *b, int bits); 188 #define STATE_SIZE 0 189 #define STATE_SAVE 1 190 #define STATE_LOAD 2 191 #define STATE_HW (1<<0) 192 #define STATE_DATA (1<<1) 193 #define STATE_DAC (1<<2) 194 #define STATE_REG (1<<3) 195 #define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 196 #define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 197 static ssize_t vesa_bios_state_buf_size(void); 198 static int vesa_bios_save_restore(int code, void *p); 199 #ifdef MODE_TABLE_BROKEN 200 static int vesa_bios_get_line_length(void); 201 #endif 202 static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); 203 #if 0 204 static int vesa_bios_get_start(int *x, int *y); 205 #endif 206 static int vesa_bios_set_start(int x, int y); 207 static int vesa_map_gen_mode_num(int type, int color, int mode); 208 static int vesa_translate_flags(u_int16_t vflags); 209 static int vesa_translate_mmodel(u_int8_t vmodel); 210 static int vesa_get_bpscanline(struct vesa_mode *vmode); 211 static int vesa_bios_init(void); 212 static void vesa_clear_modes(video_info_t *info, int color); 213 214 #if 0 215 static int vesa_get_origin(video_adapter_t *adp, off_t *offset); 216 #endif 217 218 /* INT 10 BIOS calls */ 219 static int 220 int10_set_mode(int mode) 221 { 222 x86regs_t regs; 223 224 x86bios_init_regs(®s); 225 regs.R_AL = mode; 226 227 x86bios_intr(®s, 0x10); 228 229 return (0); 230 } 231 232 static int 233 vesa_bios_post(void) 234 { 235 x86regs_t regs; 236 devclass_t dc; 237 device_t *devs; 238 device_t dev; 239 int count, i, is_pci; 240 241 if (x86bios_get_orm(0xc0000) == NULL) 242 return (1); 243 244 dev = NULL; 245 is_pci = 0; 246 247 /* Find the matching PCI video controller. */ 248 dc = devclass_find("vgapci"); 249 if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { 250 for (i = 0; i < count; i++) 251 if (device_get_flags(devs[i]) != 0 && 252 x86bios_match_device(0xc0000, devs[i])) { 253 dev = devs[i]; 254 is_pci = 1; 255 break; 256 } 257 free(devs, M_TEMP); 258 } 259 260 /* Try VGA if a PCI device is not found. */ 261 if (dev == NULL) { 262 dc = devclass_find(VGA_DRIVER_NAME); 263 if (dc != NULL) 264 dev = devclass_get_device(dc, 0); 265 } 266 267 if (bootverbose) 268 printf("%s: calling BIOS POST\n", 269 dev == NULL ? "VESA" : device_get_nameunit(dev)); 270 271 x86bios_init_regs(®s); 272 if (is_pci) { 273 regs.R_AH = pci_get_bus(dev); 274 regs.R_AL = (pci_get_slot(dev) << 3) | 275 (pci_get_function(dev) & 0x07); 276 } 277 regs.R_DL = 0x80; 278 x86bios_call(®s, 0xc000, 0x0003); 279 280 if (x86bios_get_intr(0x10) == 0) 281 return (1); 282 283 return (0); 284 } 285 286 /* VESA BIOS calls */ 287 static int 288 vesa_bios_get_mode(int mode, struct vesa_mode *vmode, int flags) 289 { 290 x86regs_t regs; 291 uint32_t offs; 292 void *buf; 293 294 buf = x86bios_alloc(&offs, sizeof(*vmode), flags); 295 if (buf == NULL) 296 return (1); 297 298 x86bios_init_regs(®s); 299 regs.R_AX = 0x4f01; 300 regs.R_CX = mode; 301 302 regs.R_ES = X86BIOS_PHYSTOSEG(offs); 303 regs.R_DI = X86BIOS_PHYSTOOFF(offs); 304 305 x86bios_intr(®s, 0x10); 306 307 if (regs.R_AX != 0x004f) { 308 x86bios_free(buf, sizeof(*vmode)); 309 return (1); 310 } 311 312 bcopy(buf, vmode, sizeof(*vmode)); 313 x86bios_free(buf, sizeof(*vmode)); 314 315 return (0); 316 } 317 318 static int 319 vesa_bios_set_mode(int mode) 320 { 321 x86regs_t regs; 322 323 x86bios_init_regs(®s); 324 regs.R_AX = 0x4f02; 325 regs.R_BX = mode; 326 327 x86bios_intr(®s, 0x10); 328 329 return (regs.R_AX != 0x004f); 330 } 331 332 #if 0 333 static int 334 vesa_bios_get_dac(void) 335 { 336 x86regs_t regs; 337 338 x86bios_init_regs(®s); 339 regs.R_AX = 0x4f08; 340 regs.R_BL = 1; 341 342 x86bios_intr(®s, 0x10); 343 344 if (regs.R_AX != 0x004f) 345 return (6); 346 347 return (regs.R_BH); 348 } 349 #endif 350 351 static int 352 vesa_bios_set_dac(int bits) 353 { 354 x86regs_t regs; 355 356 x86bios_init_regs(®s); 357 regs.R_AX = 0x4f08; 358 /* regs.R_BL = 0; */ 359 regs.R_BH = bits; 360 361 x86bios_intr(®s, 0x10); 362 363 if (regs.R_AX != 0x004f) 364 return (6); 365 366 return (regs.R_BH); 367 } 368 369 static int 370 vesa_bios_save_palette(int start, int colors, u_char *palette, int bits) 371 { 372 x86regs_t regs; 373 int i; 374 375 x86bios_init_regs(®s); 376 regs.R_AX = 0x4f09; 377 regs.R_BL = 1; 378 regs.R_CX = colors; 379 regs.R_DX = start; 380 381 regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 382 regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 383 384 x86bios_intr(®s, 0x10); 385 386 if (regs.R_AX != 0x004f) 387 return (1); 388 389 bits = 8 - bits; 390 for (i = 0; i < colors; ++i) { 391 palette[i * 3] = vesa_palette[i * 4 + 2] << bits; 392 palette[i * 3 + 1] = vesa_palette[i * 4 + 1] << bits; 393 palette[i * 3 + 2] = vesa_palette[i * 4] << bits; 394 } 395 396 return (0); 397 } 398 399 static int 400 vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 401 int bits) 402 { 403 x86regs_t regs; 404 int i; 405 406 x86bios_init_regs(®s); 407 regs.R_AX = 0x4f09; 408 regs.R_BL = 1; 409 regs.R_CX = colors; 410 regs.R_DX = start; 411 412 regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 413 regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 414 415 x86bios_intr(®s, 0x10); 416 417 if (regs.R_AX != 0x004f) 418 return (1); 419 420 bits = 8 - bits; 421 for (i = 0; i < colors; ++i) { 422 r[i] = vesa_palette[i * 4 + 2] << bits; 423 g[i] = vesa_palette[i * 4 + 1] << bits; 424 b[i] = vesa_palette[i * 4] << bits; 425 } 426 427 return (0); 428 } 429 430 static int 431 vesa_bios_load_palette(int start, int colors, u_char *palette, int bits) 432 { 433 x86regs_t regs; 434 int i; 435 436 x86bios_init_regs(®s); 437 regs.R_AX = 0x4f09; 438 /* regs.R_BL = 0; */ 439 regs.R_CX = colors; 440 regs.R_DX = start; 441 442 regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 443 regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 444 445 bits = 8 - bits; 446 for (i = 0; i < colors; ++i) { 447 vesa_palette[i * 4] = palette[i * 3 + 2] >> bits; 448 vesa_palette[i * 4 + 1] = palette[i * 3 + 1] >> bits; 449 vesa_palette[i * 4 + 2] = palette[i * 3] >> bits; 450 vesa_palette[i * 4 + 3] = 0; 451 } 452 x86bios_intr(®s, 0x10); 453 454 return (regs.R_AX != 0x004f); 455 } 456 457 static int 458 vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 459 int bits) 460 { 461 x86regs_t regs; 462 int i; 463 464 x86bios_init_regs(®s); 465 regs.R_AX = 0x4f09; 466 /* regs.R_BL = 0; */ 467 regs.R_CX = colors; 468 regs.R_DX = start; 469 470 regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 471 regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 472 473 bits = 8 - bits; 474 for (i = 0; i < colors; ++i) { 475 vesa_palette[i * 4] = b[i] >> bits; 476 vesa_palette[i * 4 + 1] = g[i] >> bits; 477 vesa_palette[i * 4 + 2] = r[i] >> bits; 478 vesa_palette[i * 4 + 3] = 0; 479 } 480 x86bios_intr(®s, 0x10); 481 482 return (regs.R_AX != 0x004f); 483 } 484 485 static ssize_t 486 vesa_bios_state_buf_size(void) 487 { 488 x86regs_t regs; 489 490 x86bios_init_regs(®s); 491 regs.R_AX = 0x4f04; 492 /* regs.R_DL = STATE_SIZE; */ 493 regs.R_CX = STATE_MOST; 494 495 x86bios_intr(®s, 0x10); 496 497 if (regs.R_AX != 0x004f) 498 return (0); 499 500 return (regs.R_BX * 64); 501 } 502 503 static int 504 vesa_bios_save_restore(int code, void *p) 505 { 506 x86regs_t regs; 507 508 if (code != STATE_SAVE && code != STATE_LOAD) 509 return (1); 510 511 x86bios_init_regs(®s); 512 regs.R_AX = 0x4f04; 513 regs.R_DL = code; 514 regs.R_CX = STATE_MOST; 515 516 regs.R_ES = X86BIOS_PHYSTOSEG(vesa_state_buf_offs); 517 regs.R_BX = X86BIOS_PHYSTOOFF(vesa_state_buf_offs); 518 519 switch (code) { 520 case STATE_SAVE: 521 x86bios_intr(®s, 0x10); 522 bcopy(vesa_state_buf, p, vesa_state_buf_size); 523 break; 524 case STATE_LOAD: 525 bcopy(p, vesa_state_buf, vesa_state_buf_size); 526 x86bios_intr(®s, 0x10); 527 break; 528 } 529 530 return (regs.R_AX != 0x004f); 531 } 532 533 #ifdef MODE_TABLE_BROKEN 534 static int 535 vesa_bios_get_line_length(void) 536 { 537 x86regs_t regs; 538 539 x86bios_init_regs(®s); 540 regs.R_AX = 0x4f06; 541 regs.R_BL = 1; 542 543 x86bios_intr(®s, 0x10); 544 545 if (regs.R_AX != 0x004f) 546 return (-1); 547 548 return (regs.R_BX); 549 } 550 #endif 551 552 static int 553 vesa_bios_set_line_length(int pixel, int *bytes, int *lines) 554 { 555 x86regs_t regs; 556 557 x86bios_init_regs(®s); 558 regs.R_AX = 0x4f06; 559 /* regs.R_BL = 0; */ 560 regs.R_CX = pixel; 561 562 x86bios_intr(®s, 0x10); 563 564 #if VESA_DEBUG > 1 565 printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); 566 #endif 567 if (regs.R_AX != 0x004f) 568 return (-1); 569 570 if (bytes != NULL) 571 *bytes = regs.R_BX; 572 if (lines != NULL) 573 *lines = regs.R_DX; 574 575 return (0); 576 } 577 578 #if 0 579 static int 580 vesa_bios_get_start(int *x, int *y) 581 { 582 x86regs_t regs; 583 584 x86bios_init_regs(®s); 585 regs.R_AX = 0x4f07; 586 regs.R_BL = 1; 587 588 x86bios_intr(®s, 0x10); 589 590 if (regs.R_AX != 0x004f) 591 return (-1); 592 593 *x = regs.R_CX; 594 *y = regs.R_DX; 595 596 return (0); 597 } 598 #endif 599 600 static int 601 vesa_bios_set_start(int x, int y) 602 { 603 x86regs_t regs; 604 605 x86bios_init_regs(®s); 606 regs.R_AX = 0x4f07; 607 regs.R_BL = 0x80; 608 regs.R_CX = x; 609 regs.R_DX = y; 610 611 x86bios_intr(®s, 0x10); 612 613 return (regs.R_AX != 0x004f); 614 } 615 616 /* map a generic video mode to a known mode */ 617 static int 618 vesa_map_gen_mode_num(int type, int color, int mode) 619 { 620 static struct { 621 int from; 622 int to; 623 } mode_map[] = { 624 { M_TEXT_132x25, M_VESA_C132x25 }, 625 { M_TEXT_132x43, M_VESA_C132x43 }, 626 { M_TEXT_132x50, M_VESA_C132x50 }, 627 { M_TEXT_132x60, M_VESA_C132x60 }, 628 }; 629 int i; 630 631 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 632 if (mode_map[i].from == mode) 633 return (mode_map[i].to); 634 } 635 return (mode); 636 } 637 638 static int 639 vesa_translate_flags(u_int16_t vflags) 640 { 641 static struct { 642 u_int16_t mask; 643 int set; 644 int reset; 645 } ftable[] = { 646 { V_MODECOLOR, V_INFO_COLOR, 0 }, 647 { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 648 { V_MODELFB, V_INFO_LINEAR, 0 }, 649 { V_MODENONVGA, V_INFO_NONVGA, 0 }, 650 }; 651 int flags; 652 int i; 653 654 for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 655 flags |= (vflags & ftable[i].mask) ? 656 ftable[i].set : ftable[i].reset; 657 } 658 return (flags); 659 } 660 661 static int 662 vesa_translate_mmodel(u_int8_t vmodel) 663 { 664 static struct { 665 u_int8_t vmodel; 666 int mmodel; 667 } mtable[] = { 668 { V_MMTEXT, V_INFO_MM_TEXT }, 669 { V_MMCGA, V_INFO_MM_CGA }, 670 { V_MMHGC, V_INFO_MM_HGC }, 671 { V_MMEGA, V_INFO_MM_PLANAR }, 672 { V_MMPACKED, V_INFO_MM_PACKED }, 673 { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, 674 }; 675 int i; 676 677 for (i = 0; mtable[i].mmodel >= 0; ++i) { 678 if (mtable[i].vmodel == vmodel) 679 return (mtable[i].mmodel); 680 } 681 return (V_INFO_MM_OTHER); 682 } 683 684 static int 685 vesa_get_bpscanline(struct vesa_mode *vmode) 686 { 687 int bpsl; 688 689 if ((vmode->v_modeattr & V_MODEGRAPHICS) != 0) { 690 /* Find the minimum length. */ 691 switch (vmode->v_bpp / vmode->v_planes) { 692 case 1: 693 bpsl = vmode->v_width / 8; 694 break; 695 case 2: 696 bpsl = vmode->v_width / 4; 697 break; 698 case 4: 699 bpsl = vmode->v_width / 2; 700 break; 701 default: 702 bpsl = vmode->v_width * ((vmode->v_bpp + 7) / 8); 703 bpsl /= vmode->v_planes; 704 break; 705 } 706 707 /* Use VBE 3.0 information if it looks sane. */ 708 if ((vmode->v_modeattr & V_MODELFB) != 0 && 709 vesa_adp_info->v_version >= 0x0300 && 710 vmode->v_linbpscanline > bpsl) 711 return (vmode->v_linbpscanline); 712 713 /* Return the minimum if the mode table looks absurd. */ 714 if (vmode->v_bpscanline < bpsl) 715 return (bpsl); 716 } 717 718 return (vmode->v_bpscanline); 719 } 720 721 #define VESA_MAXSTR 256 722 723 #define VESA_STRCPY(dst, src) do { \ 724 char *str; \ 725 int i; \ 726 dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ 727 str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ 728 for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ 729 dst[i] = str[i]; \ 730 dst[i] = '\0'; \ 731 } while (0) 732 733 static int 734 vesa_bios_init(void) 735 { 736 struct vesa_mode vmode; 737 struct vesa_info *buf; 738 video_info_t *p; 739 x86regs_t regs; 740 size_t bsize; 741 size_t msize; 742 void *vmbuf; 743 uint32_t offs; 744 uint16_t vers; 745 int is_via_cle266; 746 int modes; 747 int i; 748 749 if (vesa_init_done) 750 return (0); 751 752 has_vesa_bios = FALSE; 753 vesa_adp_info = NULL; 754 vesa_vmode_max = 0; 755 vesa_vmode[0].vi_mode = EOT; 756 757 /* 758 * If the VBE real mode interrupt vector is not found, try BIOS POST. 759 */ 760 if (x86bios_get_intr(0x10) == 0) { 761 if (vesa_bios_post() != 0) 762 return (1); 763 if (bootverbose) { 764 offs = x86bios_get_intr(0x10); 765 printf("VESA: interrupt vector installed (0x%x)\n", 766 BIOS_SADDRTOLADDR(offs)); 767 } 768 } 769 770 x86bios_init_regs(®s); 771 regs.R_AX = 0x4f00; 772 773 vmbuf = x86bios_alloc(&offs, sizeof(*buf), M_WAITOK); 774 775 regs.R_ES = X86BIOS_PHYSTOSEG(offs); 776 regs.R_DI = X86BIOS_PHYSTOOFF(offs); 777 778 bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ 779 x86bios_intr(®s, 0x10); 780 781 if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) 782 goto fail; 783 784 vesa_adp_info = buf = malloc(sizeof(*buf), M_DEVBUF, M_WAITOK); 785 bcopy(vmbuf, buf, sizeof(*buf)); 786 787 if (bootverbose) { 788 printf("VESA: information block\n"); 789 hexdump(buf, sizeof(*buf), NULL, HD_OMIT_CHARS); 790 } 791 792 vers = buf->v_version = le16toh(buf->v_version); 793 buf->v_oemstr = le32toh(buf->v_oemstr); 794 buf->v_flags = le32toh(buf->v_flags); 795 buf->v_modetable = le32toh(buf->v_modetable); 796 buf->v_memsize = le16toh(buf->v_memsize); 797 buf->v_revision = le16toh(buf->v_revision); 798 buf->v_venderstr = le32toh(buf->v_venderstr); 799 buf->v_prodstr = le32toh(buf->v_prodstr); 800 buf->v_revstr = le32toh(buf->v_revstr); 801 802 if (vers < 0x0102) { 803 printf("VESA: VBE version %d.%d is not supported; " 804 "version 1.2 or later is required.\n", 805 ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), 806 ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); 807 goto fail; 808 } 809 810 VESA_STRCPY(vesa_oemstr, buf->v_oemstr); 811 if (vers >= 0x0200) { 812 VESA_STRCPY(vesa_venderstr, buf->v_venderstr); 813 VESA_STRCPY(vesa_prodstr, buf->v_prodstr); 814 VESA_STRCPY(vesa_revstr, buf->v_revstr); 815 } 816 is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, 817 sizeof(VESA_VIA_CLE266)) == 0; 818 819 if (buf->v_modetable == 0) 820 goto fail; 821 822 msize = (size_t)buf->v_memsize * 64 * 1024; 823 824 vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf->v_modetable)); 825 826 for (i = 0, modes = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && 827 (vesa_vmodetab[i] != 0xffff); ++i) { 828 vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); 829 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode, M_WAITOK)) 830 continue; 831 832 vmode.v_modeattr = le16toh(vmode.v_modeattr); 833 vmode.v_wgran = le16toh(vmode.v_wgran); 834 vmode.v_wsize = le16toh(vmode.v_wsize); 835 vmode.v_waseg = le16toh(vmode.v_waseg); 836 vmode.v_wbseg = le16toh(vmode.v_wbseg); 837 vmode.v_posfunc = le32toh(vmode.v_posfunc); 838 vmode.v_bpscanline = le16toh(vmode.v_bpscanline); 839 vmode.v_width = le16toh(vmode.v_width); 840 vmode.v_height = le16toh(vmode.v_height); 841 vmode.v_lfb = le32toh(vmode.v_lfb); 842 vmode.v_offscreen = le32toh(vmode.v_offscreen); 843 vmode.v_offscreensize = le16toh(vmode.v_offscreensize); 844 vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); 845 vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 846 847 /* reject unsupported modes */ 848 #if 0 849 if ((vmode.v_modeattr & 850 (V_MODESUPP | V_MODEOPTINFO | V_MODENONVGA)) != 851 (V_MODESUPP | V_MODEOPTINFO)) 852 continue; 853 #else 854 if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { 855 #if VESA_DEBUG > 1 856 printf("Rejecting VESA %s mode: %d x %d x %d bpp " 857 " attr = %x\n", 858 vmode.v_modeattr & V_MODEGRAPHICS ? 859 "graphics" : "text", 860 vmode.v_width, vmode.v_height, vmode.v_bpp, 861 vmode.v_modeattr); 862 #endif 863 continue; 864 } 865 #endif 866 867 bsize = vesa_get_bpscanline(&vmode) * vmode.v_height; 868 if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0) 869 bsize *= vmode.v_planes; 870 871 /* Does it have enough memory to support this mode? */ 872 if (msize < bsize) { 873 #if VESA_DEBUG > 1 874 printf("Rejecting VESA %s mode: %d x %d x %d bpp " 875 " attr = %x, not enough memory\n", 876 vmode.v_modeattr & V_MODEGRAPHICS ? 877 "graphics" : "text", 878 vmode.v_width, vmode.v_height, vmode.v_bpp, 879 vmode.v_modeattr); 880 #endif 881 continue; 882 } 883 884 /* expand the array if necessary */ 885 if (modes >= vesa_vmode_max) { 886 vesa_vmode_max += MODE_TABLE_DELTA; 887 p = malloc(sizeof(*vesa_vmode) * (vesa_vmode_max + 1), 888 M_DEVBUF, M_WAITOK); 889 #if VESA_DEBUG > 1 890 printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", 891 modes, vesa_vmode_max); 892 #endif 893 if (modes > 0) { 894 bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); 895 free(vesa_vmode, M_DEVBUF); 896 } 897 vesa_vmode = p; 898 } 899 900 #if VESA_DEBUG > 1 901 printf("Found VESA %s mode: %d x %d x %d bpp\n", 902 vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 903 vmode.v_width, vmode.v_height, vmode.v_bpp); 904 #endif 905 if (is_via_cle266) { 906 if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { 907 vmode.v_width &= 0xff; 908 vmode.v_waseg = 0xb8000 >> 4; 909 } 910 } 911 912 /* copy some fields */ 913 bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 914 vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 915 vesa_vmode[modes].vi_width = vmode.v_width; 916 vesa_vmode[modes].vi_height = vmode.v_height; 917 vesa_vmode[modes].vi_depth = vmode.v_bpp; 918 vesa_vmode[modes].vi_planes = vmode.v_planes; 919 vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 920 vesa_vmode[modes].vi_cheight = vmode.v_cheight; 921 vesa_vmode[modes].vi_window = (vm_offset_t)vmode.v_waseg << 4; 922 /* XXX window B */ 923 vesa_vmode[modes].vi_window_size = vmode.v_wsize * 1024; 924 vesa_vmode[modes].vi_window_gran = vmode.v_wgran * 1024; 925 if (vmode.v_modeattr & V_MODELFB) 926 vesa_vmode[modes].vi_buffer = vmode.v_lfb; 927 vesa_vmode[modes].vi_buffer_size = bsize; 928 vesa_vmode[modes].vi_mem_model = 929 vesa_translate_mmodel(vmode.v_memmodel); 930 switch (vesa_vmode[modes].vi_mem_model) { 931 case V_INFO_MM_DIRECT: 932 if ((vmode.v_modeattr & V_MODELFB) != 0 && 933 vers >= 0x0300) { 934 vesa_vmode[modes].vi_pixel_fields[0] = 935 vmode.v_linredfieldpos; 936 vesa_vmode[modes].vi_pixel_fields[1] = 937 vmode.v_lingreenfieldpos; 938 vesa_vmode[modes].vi_pixel_fields[2] = 939 vmode.v_linbluefieldpos; 940 vesa_vmode[modes].vi_pixel_fields[3] = 941 vmode.v_linresfieldpos; 942 vesa_vmode[modes].vi_pixel_fsizes[0] = 943 vmode.v_linredmasksize; 944 vesa_vmode[modes].vi_pixel_fsizes[1] = 945 vmode.v_lingreenmasksize; 946 vesa_vmode[modes].vi_pixel_fsizes[2] = 947 vmode.v_linbluemasksize; 948 vesa_vmode[modes].vi_pixel_fsizes[3] = 949 vmode.v_linresmasksize; 950 } else { 951 vesa_vmode[modes].vi_pixel_fields[0] = 952 vmode.v_redfieldpos; 953 vesa_vmode[modes].vi_pixel_fields[1] = 954 vmode.v_greenfieldpos; 955 vesa_vmode[modes].vi_pixel_fields[2] = 956 vmode.v_bluefieldpos; 957 vesa_vmode[modes].vi_pixel_fields[3] = 958 vmode.v_resfieldpos; 959 vesa_vmode[modes].vi_pixel_fsizes[0] = 960 vmode.v_redmasksize; 961 vesa_vmode[modes].vi_pixel_fsizes[1] = 962 vmode.v_greenmasksize; 963 vesa_vmode[modes].vi_pixel_fsizes[2] = 964 vmode.v_bluemasksize; 965 vesa_vmode[modes].vi_pixel_fsizes[3] = 966 vmode.v_resmasksize; 967 } 968 /* FALLTHROUGH */ 969 case V_INFO_MM_PACKED: 970 vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8; 971 break; 972 } 973 vesa_vmode[modes].vi_flags = 974 vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; 975 976 ++modes; 977 } 978 vesa_vmode[modes].vi_mode = EOT; 979 980 if (bootverbose) 981 printf("VESA: %d mode(s) found\n", modes); 982 983 has_vesa_bios = (modes > 0); 984 if (!has_vesa_bios) 985 goto fail; 986 987 x86bios_free(vmbuf, sizeof(*buf)); 988 989 vesa_state_buf_size = vesa_bios_state_buf_size(); 990 vesa_palette = x86bios_alloc(&vesa_palette_offs, 991 VESA_PALETTE_SIZE + vesa_state_buf_size, M_WAITOK); 992 if (vesa_state_buf_size > 0) { 993 vesa_state_buf = vesa_palette + VESA_PALETTE_SIZE; 994 vesa_state_buf_offs = vesa_palette_offs + VESA_PALETTE_SIZE; 995 } 996 997 return (0); 998 999 fail: 1000 if (vmbuf != NULL) 1001 x86bios_free(vmbuf, sizeof(buf)); 1002 if (vesa_adp_info != NULL) { 1003 free(vesa_adp_info, M_DEVBUF); 1004 vesa_adp_info = NULL; 1005 } 1006 if (vesa_oemstr != NULL) { 1007 free(vesa_oemstr, M_DEVBUF); 1008 vesa_oemstr = NULL; 1009 } 1010 if (vesa_venderstr != NULL) { 1011 free(vesa_venderstr, M_DEVBUF); 1012 vesa_venderstr = NULL; 1013 } 1014 if (vesa_prodstr != NULL) { 1015 free(vesa_prodstr, M_DEVBUF); 1016 vesa_prodstr = NULL; 1017 } 1018 if (vesa_revstr != NULL) { 1019 free(vesa_revstr, M_DEVBUF); 1020 vesa_revstr = NULL; 1021 } 1022 return (1); 1023 } 1024 1025 static void 1026 vesa_clear_modes(video_info_t *info, int color) 1027 { 1028 while (info->vi_mode != EOT) { 1029 if ((info->vi_flags & V_INFO_COLOR) != color) 1030 info->vi_mode = NA; 1031 ++info; 1032 } 1033 } 1034 1035 /* entry points */ 1036 1037 static int 1038 vesa_configure(int flags) 1039 { 1040 video_adapter_t *adp; 1041 int adapters; 1042 int error; 1043 int i; 1044 1045 if (vesa_init_done) 1046 return (0); 1047 if (flags & VIO_PROBE_ONLY) 1048 return (0); 1049 1050 /* 1051 * If the VESA module has already been loaded, abort loading 1052 * the module this time. 1053 */ 1054 for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { 1055 if (adp->va_flags & V_ADP_VESA) 1056 return (ENXIO); 1057 if (adp->va_type == KD_VGA) 1058 break; 1059 } 1060 1061 /* 1062 * The VGA adapter is not found. This is because either 1063 * 1) the VGA driver has not been initialized, or 2) the VGA card 1064 * is not present. If 1) is the case, we shall defer 1065 * initialization for now and try again later. 1066 */ 1067 if (adp == NULL) { 1068 vga_sub_configure = vesa_configure; 1069 return (ENODEV); 1070 } 1071 1072 /* count number of registered adapters */ 1073 for (++i; vid_get_adapter(i) != NULL; ++i) 1074 ; 1075 adapters = i; 1076 1077 /* call VESA BIOS */ 1078 vesa_adp = adp; 1079 if (vesa_bios_init()) { 1080 vesa_adp = NULL; 1081 return (ENXIO); 1082 } 1083 vesa_adp->va_flags |= V_ADP_VESA; 1084 1085 /* remove conflicting modes if we have more than one adapter */ 1086 if (adapters > 1) { 1087 vesa_clear_modes(vesa_vmode, 1088 (vesa_adp->va_flags & V_ADP_COLOR) ? 1089 V_INFO_COLOR : 0); 1090 } 1091 1092 if ((error = vesa_load_ioctl()) == 0) { 1093 prevvidsw = vidsw[vesa_adp->va_index]; 1094 vidsw[vesa_adp->va_index] = &vesavidsw; 1095 vesa_init_done = TRUE; 1096 } else { 1097 vesa_adp = NULL; 1098 return (error); 1099 } 1100 1101 return (0); 1102 } 1103 1104 #if 0 1105 static int 1106 vesa_nop(void) 1107 { 1108 1109 return (0); 1110 } 1111 #endif 1112 1113 static int 1114 vesa_error(void) 1115 { 1116 1117 return (1); 1118 } 1119 1120 static int 1121 vesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 1122 { 1123 1124 return ((*prevvidsw->probe)(unit, adpp, arg, flags)); 1125 } 1126 1127 static int 1128 vesa_init(int unit, video_adapter_t *adp, int flags) 1129 { 1130 1131 return ((*prevvidsw->init)(unit, adp, flags)); 1132 } 1133 1134 static int 1135 vesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) 1136 { 1137 int i; 1138 1139 if ((*prevvidsw->get_info)(adp, mode, info) == 0) 1140 return (0); 1141 1142 if (adp != vesa_adp) 1143 return (1); 1144 1145 mode = vesa_map_gen_mode_num(vesa_adp->va_type, 1146 vesa_adp->va_flags & V_ADP_COLOR, mode); 1147 for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 1148 if (vesa_vmode[i].vi_mode == NA) 1149 continue; 1150 if (vesa_vmode[i].vi_mode == mode) { 1151 *info = vesa_vmode[i]; 1152 return (0); 1153 } 1154 } 1155 return (1); 1156 } 1157 1158 static int 1159 vesa_query_mode(video_adapter_t *adp, video_info_t *info) 1160 { 1161 int i; 1162 1163 if ((*prevvidsw->query_mode)(adp, info) == 0) 1164 return (0); 1165 if (adp != vesa_adp) 1166 return (ENODEV); 1167 1168 for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 1169 if ((info->vi_width != 0) 1170 && (info->vi_width != vesa_vmode[i].vi_width)) 1171 continue; 1172 if ((info->vi_height != 0) 1173 && (info->vi_height != vesa_vmode[i].vi_height)) 1174 continue; 1175 if ((info->vi_cwidth != 0) 1176 && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 1177 continue; 1178 if ((info->vi_cheight != 0) 1179 && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 1180 continue; 1181 if ((info->vi_depth != 0) 1182 && (info->vi_depth != vesa_vmode[i].vi_depth)) 1183 continue; 1184 if ((info->vi_planes != 0) 1185 && (info->vi_planes != vesa_vmode[i].vi_planes)) 1186 continue; 1187 /* pixel format, memory model */ 1188 if ((info->vi_flags != 0) 1189 && (info->vi_flags != vesa_vmode[i].vi_flags)) 1190 continue; 1191 *info = vesa_vmode[i]; 1192 return (0); 1193 } 1194 return (ENODEV); 1195 } 1196 1197 static int 1198 vesa_set_mode(video_adapter_t *adp, int mode) 1199 { 1200 video_info_t info; 1201 1202 if (adp != vesa_adp) 1203 return ((*prevvidsw->set_mode)(adp, mode)); 1204 1205 mode = vesa_map_gen_mode_num(adp->va_type, 1206 adp->va_flags & V_ADP_COLOR, mode); 1207 #if VESA_DEBUG > 0 1208 printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 1209 adp->va_mode, adp->va_mode, mode, mode); 1210 #endif 1211 /* 1212 * If the current mode is a VESA mode and the new mode is not, 1213 * restore the state of the adapter first by setting one of the 1214 * standard VGA mode, so that non-standard, extended SVGA registers 1215 * are set to the state compatible with the standard VGA modes. 1216 * Otherwise (*prevvidsw->set_mode)() may not be able to set up 1217 * the new mode correctly. 1218 */ 1219 if (VESA_MODE(adp->va_mode)) { 1220 if (!VESA_MODE(mode) && 1221 (*prevvidsw->get_info)(adp, mode, &info) == 0) { 1222 if ((adp->va_flags & V_ADP_DAC8) != 0) { 1223 vesa_bios_set_dac(6); 1224 adp->va_flags &= ~V_ADP_DAC8; 1225 } 1226 int10_set_mode(adp->va_initial_bios_mode); 1227 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1228 pmap_unmapdev(adp->va_buffer, 1229 vesa_adp_info->v_memsize * 64 * 1024); 1230 /* 1231 * Once (*prevvidsw->get_info)() succeeded, 1232 * (*prevvidsw->set_mode)() below won't fail... 1233 */ 1234 } 1235 } 1236 1237 /* we may not need to handle this mode after all... */ 1238 if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) 1239 return (0); 1240 1241 /* is the new mode supported? */ 1242 if (vesa_get_info(adp, mode, &info)) 1243 return (1); 1244 /* assert(VESA_MODE(mode)); */ 1245 1246 #if VESA_DEBUG > 0 1247 printf("VESA: about to set a VESA mode...\n"); 1248 #endif 1249 /* don't use the linear frame buffer for text modes. XXX */ 1250 if (!(info.vi_flags & V_INFO_GRAPHICS)) 1251 info.vi_flags &= ~V_INFO_LINEAR; 1252 1253 if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) 1254 return (1); 1255 1256 /* Palette format is reset by the above VBE function call. */ 1257 adp->va_flags &= ~V_ADP_DAC8; 1258 1259 if ((vesa_adp_info->v_flags & V_DAC8) != 0 && 1260 (info.vi_flags & V_INFO_GRAPHICS) != 0 && 1261 vesa_bios_set_dac(8) > 6) 1262 adp->va_flags |= V_ADP_DAC8; 1263 1264 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1265 pmap_unmapdev(adp->va_buffer, 1266 vesa_adp_info->v_memsize * 64 * 1024); 1267 1268 #if VESA_DEBUG > 0 1269 printf("VESA: mode set!\n"); 1270 #endif 1271 vesa_adp->va_mode = mode; 1272 vesa_adp->va_flags &= ~V_ADP_COLOR; 1273 vesa_adp->va_flags |= 1274 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 1275 vesa_adp->va_crtc_addr = 1276 (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1277 1278 vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height; 1279 if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1280 vesa_adp->va_line_width /= info.vi_planes; 1281 1282 #ifdef MODE_TABLE_BROKEN 1283 /* If VBE function returns bigger bytes per scan line, use it. */ 1284 { 1285 int bpsl = vesa_bios_get_line_length(); 1286 if (bpsl > vesa_adp->va_line_width) { 1287 vesa_adp->va_line_width = bpsl; 1288 info.vi_buffer_size = bpsl * info.vi_height; 1289 if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1290 info.vi_buffer_size *= info.vi_planes; 1291 } 1292 } 1293 #endif 1294 1295 if (info.vi_flags & V_INFO_LINEAR) { 1296 #if VESA_DEBUG > 1 1297 printf("VESA: setting up LFB\n"); 1298 #endif 1299 vesa_adp->va_buffer = 1300 (vm_offset_t)pmap_mapdev_attr(info.vi_buffer, 1301 vesa_adp_info->v_memsize * 64 * 1024, PAT_WRITE_COMBINING); 1302 vesa_adp->va_window = vesa_adp->va_buffer; 1303 vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes; 1304 vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes; 1305 } else { 1306 vesa_adp->va_buffer = 0; 1307 vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); 1308 vesa_adp->va_window_size = info.vi_window_size; 1309 vesa_adp->va_window_gran = info.vi_window_gran; 1310 } 1311 vesa_adp->va_buffer_size = info.vi_buffer_size; 1312 vesa_adp->va_window_orig = 0; 1313 vesa_adp->va_disp_start.x = 0; 1314 vesa_adp->va_disp_start.y = 0; 1315 #if VESA_DEBUG > 0 1316 printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", 1317 info.vi_width, vesa_adp->va_line_width); 1318 #endif 1319 bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); 1320 1321 /* move hardware cursor out of the way */ 1322 (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); 1323 1324 return (0); 1325 } 1326 1327 static int 1328 vesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1329 u_char *data, int ch, int count) 1330 { 1331 1332 return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, 1333 ch, count)); 1334 } 1335 1336 static int 1337 vesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1338 u_char *data, int ch, int count) 1339 { 1340 1341 return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, 1342 ch, count)); 1343 } 1344 1345 static int 1346 vesa_show_font(video_adapter_t *adp, int page) 1347 { 1348 1349 return ((*prevvidsw->show_font)(adp, page)); 1350 } 1351 1352 static int 1353 vesa_save_palette(video_adapter_t *adp, u_char *palette) 1354 { 1355 int bits; 1356 1357 if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1358 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1359 if (vesa_bios_save_palette(0, 256, palette, bits) == 0) 1360 return (0); 1361 } 1362 1363 return ((*prevvidsw->save_palette)(adp, palette)); 1364 } 1365 1366 static int 1367 vesa_load_palette(video_adapter_t *adp, u_char *palette) 1368 { 1369 int bits; 1370 1371 if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1372 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1373 if (vesa_bios_load_palette(0, 256, palette, bits) == 0) 1374 return (0); 1375 } 1376 1377 return ((*prevvidsw->load_palette)(adp, palette)); 1378 } 1379 1380 static int 1381 vesa_set_border(video_adapter_t *adp, int color) 1382 { 1383 1384 return ((*prevvidsw->set_border)(adp, color)); 1385 } 1386 1387 static int 1388 vesa_save_state(video_adapter_t *adp, void *p, size_t size) 1389 { 1390 1391 if (adp != vesa_adp) 1392 return ((*prevvidsw->save_state)(adp, p, size)); 1393 1394 if (vesa_state_buf_size == 0) 1395 return (1); 1396 if (size == 0) 1397 return (offsetof(adp_state_t, regs) + vesa_state_buf_size); 1398 if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) 1399 return (1); 1400 1401 ((adp_state_t *)p)->sig = V_STATE_SIG; 1402 bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 1403 return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs)); 1404 } 1405 1406 static int 1407 vesa_load_state(video_adapter_t *adp, void *p) 1408 { 1409 1410 if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) 1411 return ((*prevvidsw->load_state)(adp, p)); 1412 1413 if (vesa_state_buf_size == 0) 1414 return (1); 1415 1416 /* Try BIOS POST to restore a sane state. */ 1417 (void)vesa_bios_post(); 1418 (void)int10_set_mode(adp->va_initial_bios_mode); 1419 (void)vesa_set_mode(adp, adp->va_mode); 1420 1421 return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs)); 1422 } 1423 1424 #if 0 1425 static int 1426 vesa_get_origin(video_adapter_t *adp, off_t *offset) 1427 { 1428 x86regs_t regs; 1429 1430 x86bios_init_regs(®s); 1431 regs.R_AX = 0x4f05; 1432 regs.R_BL = 0x10; 1433 1434 x86bios_intr(®s, 0x10); 1435 1436 if (regs.R_AX != 0x004f) 1437 return (1); 1438 *offset = regs.DX * adp->va_window_gran; 1439 1440 return (0); 1441 } 1442 #endif 1443 1444 static int 1445 vesa_set_origin(video_adapter_t *adp, off_t offset) 1446 { 1447 x86regs_t regs; 1448 1449 /* 1450 * This function should return as quickly as possible to 1451 * maintain good performance of the system. For this reason, 1452 * error checking is kept minimal and let the VESA BIOS to 1453 * detect error. 1454 */ 1455 if (adp != vesa_adp) 1456 return ((*prevvidsw->set_win_org)(adp, offset)); 1457 1458 /* if this is a linear frame buffer, do nothing */ 1459 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1460 return (0); 1461 /* XXX */ 1462 if (adp->va_window_gran == 0) 1463 return (1); 1464 1465 x86bios_init_regs(®s); 1466 regs.R_AX = 0x4f05; 1467 regs.R_DX = offset / adp->va_window_gran; 1468 1469 x86bios_intr(®s, 0x10); 1470 1471 if (regs.R_AX != 0x004f) 1472 return (1); 1473 1474 x86bios_init_regs(®s); 1475 regs.R_AX = 0x4f05; 1476 regs.R_BL = 1; 1477 regs.R_DX = offset / adp->va_window_gran; 1478 x86bios_intr(®s, 0x10); 1479 1480 adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; 1481 return (0); /* XXX */ 1482 } 1483 1484 static int 1485 vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1486 { 1487 1488 return ((*prevvidsw->read_hw_cursor)(adp, col, row)); 1489 } 1490 1491 static int 1492 vesa_set_hw_cursor(video_adapter_t *adp, int col, int row) 1493 { 1494 1495 return ((*prevvidsw->set_hw_cursor)(adp, col, row)); 1496 } 1497 1498 static int 1499 vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1500 int celsize, int blink) 1501 { 1502 1503 return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, 1504 blink)); 1505 } 1506 1507 static int 1508 vesa_blank_display(video_adapter_t *adp, int mode) 1509 { 1510 1511 /* XXX: use VESA DPMS */ 1512 return ((*prevvidsw->blank_display)(adp, mode)); 1513 } 1514 1515 static int 1516 vesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 1517 int prot, vm_memattr_t *memattr) 1518 { 1519 1520 #if VESA_DEBUG > 0 1521 printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n", 1522 adp->va_info.vi_window, adp->va_info.vi_buffer, offset); 1523 #endif 1524 1525 if ((adp == vesa_adp) && 1526 (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { 1527 /* va_window_size == va_buffer_size/vi_planes */ 1528 /* XXX: is this correct? */ 1529 if (offset > adp->va_window_size - PAGE_SIZE) 1530 return (-1); 1531 *paddr = adp->va_info.vi_buffer + offset; 1532 return (0); 1533 } 1534 return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr)); 1535 } 1536 1537 static int 1538 vesa_clear(video_adapter_t *adp) 1539 { 1540 1541 return ((*prevvidsw->clear)(adp)); 1542 } 1543 1544 static int 1545 vesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1546 { 1547 1548 return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); 1549 } 1550 1551 static int 1552 vesa_bitblt(video_adapter_t *adp,...) 1553 { 1554 1555 /* FIXME */ 1556 return (1); 1557 } 1558 1559 static int 1560 get_palette(video_adapter_t *adp, int base, int count, 1561 u_char *red, u_char *green, u_char *blue, u_char *trans) 1562 { 1563 u_char *r; 1564 u_char *g; 1565 u_char *b; 1566 int bits; 1567 int error; 1568 1569 if (base < 0 || base >= 256 || count < 0 || count > 256) 1570 return (1); 1571 if ((base + count) > 256) 1572 return (1); 1573 if (!VESA_MODE(adp->va_mode)) 1574 return (1); 1575 1576 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1577 r = malloc(count * 3, M_DEVBUF, M_WAITOK); 1578 g = r + count; 1579 b = g + count; 1580 error = vesa_bios_save_palette2(base, count, r, g, b, bits); 1581 if (error == 0) { 1582 copyout(r, red, count); 1583 copyout(g, green, count); 1584 copyout(b, blue, count); 1585 if (trans != NULL) { 1586 bzero(r, count); 1587 copyout(r, trans, count); 1588 } 1589 } 1590 free(r, M_DEVBUF); 1591 1592 return (error); 1593 } 1594 1595 static int 1596 set_palette(video_adapter_t *adp, int base, int count, 1597 u_char *red, u_char *green, u_char *blue, u_char *trans) 1598 { 1599 u_char *r; 1600 u_char *g; 1601 u_char *b; 1602 int bits; 1603 int error; 1604 1605 if (base < 0 || base >= 256 || count < 0 || count > 256) 1606 return (1); 1607 if ((base + count) > 256) 1608 return (1); 1609 if (!VESA_MODE(adp->va_mode)) 1610 return (1); 1611 1612 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1613 r = malloc(count * 3, M_DEVBUF, M_WAITOK); 1614 g = r + count; 1615 b = g + count; 1616 copyin(red, r, count); 1617 copyin(green, g, count); 1618 copyin(blue, b, count); 1619 1620 error = vesa_bios_load_palette2(base, count, r, g, b, bits); 1621 free(r, M_DEVBUF); 1622 1623 return (error); 1624 } 1625 1626 static int 1627 vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1628 { 1629 int bytes; 1630 1631 if (adp != vesa_adp) 1632 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1633 1634 switch (cmd) { 1635 case FBIO_SETWINORG: /* set frame buffer window origin */ 1636 if (!VESA_MODE(adp->va_mode)) 1637 return (*prevvidsw->ioctl)(adp, cmd, arg); 1638 return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); 1639 1640 case FBIO_SETDISPSTART: /* set display start address */ 1641 if (!VESA_MODE(adp->va_mode)) 1642 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1643 if (vesa_bios_set_start(((video_display_start_t *)arg)->x, 1644 ((video_display_start_t *)arg)->y)) 1645 return (ENODEV); 1646 adp->va_disp_start.x = ((video_display_start_t *)arg)->x; 1647 adp->va_disp_start.y = ((video_display_start_t *)arg)->y; 1648 return (0); 1649 1650 case FBIO_SETLINEWIDTH: /* set line length in pixel */ 1651 if (!VESA_MODE(adp->va_mode)) 1652 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1653 if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) 1654 return (ENODEV); 1655 adp->va_line_width = bytes; 1656 #if VESA_DEBUG > 1 1657 printf("new line width:%d\n", adp->va_line_width); 1658 #endif 1659 return (0); 1660 1661 case FBIO_GETPALETTE: /* get color palette */ 1662 if (get_palette(adp, ((video_color_palette_t *)arg)->index, 1663 ((video_color_palette_t *)arg)->count, 1664 ((video_color_palette_t *)arg)->red, 1665 ((video_color_palette_t *)arg)->green, 1666 ((video_color_palette_t *)arg)->blue, 1667 ((video_color_palette_t *)arg)->transparent)) 1668 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1669 return (0); 1670 1671 1672 case FBIO_SETPALETTE: /* set color palette */ 1673 if (set_palette(adp, ((video_color_palette_t *)arg)->index, 1674 ((video_color_palette_t *)arg)->count, 1675 ((video_color_palette_t *)arg)->red, 1676 ((video_color_palette_t *)arg)->green, 1677 ((video_color_palette_t *)arg)->blue, 1678 ((video_color_palette_t *)arg)->transparent)) 1679 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1680 return (0); 1681 1682 case FBIOGETCMAP: /* get color palette */ 1683 if (get_palette(adp, ((struct fbcmap *)arg)->index, 1684 ((struct fbcmap *)arg)->count, 1685 ((struct fbcmap *)arg)->red, 1686 ((struct fbcmap *)arg)->green, 1687 ((struct fbcmap *)arg)->blue, NULL)) 1688 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1689 return (0); 1690 1691 case FBIOPUTCMAP: /* set color palette */ 1692 if (set_palette(adp, ((struct fbcmap *)arg)->index, 1693 ((struct fbcmap *)arg)->count, 1694 ((struct fbcmap *)arg)->red, 1695 ((struct fbcmap *)arg)->green, 1696 ((struct fbcmap *)arg)->blue, NULL)) 1697 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1698 return (0); 1699 1700 default: 1701 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1702 } 1703 } 1704 1705 static int 1706 vesa_diag(video_adapter_t *adp, int level) 1707 { 1708 int error; 1709 1710 /* call the previous handler first */ 1711 error = (*prevvidsw->diag)(adp, level); 1712 if (error) 1713 return (error); 1714 1715 if (adp != vesa_adp) 1716 return (1); 1717 1718 if (level <= 0) 1719 return (0); 1720 1721 return (0); 1722 } 1723 1724 static int 1725 vesa_bios_info(int level) 1726 { 1727 #if VESA_DEBUG > 1 1728 struct vesa_mode vmode; 1729 int i; 1730 #endif 1731 uint16_t vers; 1732 1733 vers = vesa_adp_info->v_version; 1734 1735 if (bootverbose) { 1736 /* general adapter information */ 1737 printf( 1738 "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 1739 (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), 1740 ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), 1741 vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 1742 vesa_vmodetab, vesa_adp_info->v_modetable); 1743 1744 /* OEM string */ 1745 if (vesa_oemstr != NULL) 1746 printf("VESA: %s\n", vesa_oemstr); 1747 } 1748 1749 if (level <= 0) 1750 return (0); 1751 1752 if (vers >= 0x0200 && bootverbose) { 1753 /* vender name, product name, product revision */ 1754 printf("VESA: %s %s %s\n", 1755 (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", 1756 (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", 1757 (vesa_revstr != NULL) ? vesa_revstr : "?"); 1758 } 1759 1760 #if VESA_DEBUG > 1 1761 /* mode information */ 1762 for (i = 0; 1763 (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 1764 && (vesa_vmodetab[i] != 0xffff); ++i) { 1765 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode, M_NOWAIT)) 1766 continue; 1767 1768 /* print something for diagnostic purpose */ 1769 printf("VESA: mode:0x%03x, flags:0x%04x", 1770 vesa_vmodetab[i], vmode.v_modeattr); 1771 if (vmode.v_modeattr & V_MODEOPTINFO) { 1772 if (vmode.v_modeattr & V_MODEGRAPHICS) { 1773 printf(", G %dx%dx%d %d, ", 1774 vmode.v_width, vmode.v_height, 1775 vmode.v_bpp, vmode.v_planes); 1776 } else { 1777 printf(", T %dx%d, ", 1778 vmode.v_width, vmode.v_height); 1779 } 1780 printf("font:%dx%d, ", 1781 vmode.v_cwidth, vmode.v_cheight); 1782 printf("pages:%d, mem:%d", 1783 vmode.v_ipages + 1, vmode.v_memmodel); 1784 } 1785 if (vmode.v_modeattr & V_MODELFB) { 1786 printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", 1787 vmode.v_lfb, vmode.v_offscreen, 1788 vmode.v_offscreensize*1024); 1789 } 1790 printf("\n"); 1791 printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 1792 vmode.v_waseg, vmode.v_waattr, 1793 vmode.v_wbseg, vmode.v_wbattr); 1794 printf("size:%dk, gran:%dk\n", 1795 vmode.v_wsize, vmode.v_wgran); 1796 } 1797 #endif /* VESA_DEBUG > 1 */ 1798 1799 return (0); 1800 } 1801 1802 /* module loading */ 1803 1804 static int 1805 vesa_load(void) 1806 { 1807 int error; 1808 int s; 1809 1810 if (vesa_init_done) 1811 return (0); 1812 1813 /* locate a VGA adapter */ 1814 s = spltty(); 1815 vesa_adp = NULL; 1816 error = vesa_configure(0); 1817 splx(s); 1818 1819 if (error == 0) 1820 vesa_bios_info(bootverbose); 1821 1822 return (error); 1823 } 1824 1825 static int 1826 vesa_unload(void) 1827 { 1828 u_char palette[256*3]; 1829 int error; 1830 int s; 1831 1832 /* if the adapter is currently in a VESA mode, don't unload */ 1833 if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 1834 return (EBUSY); 1835 /* 1836 * FIXME: if there is at least one vty which is in a VESA mode, 1837 * we shouldn't be unloading! XXX 1838 */ 1839 1840 s = spltty(); 1841 if ((error = vesa_unload_ioctl()) == 0) { 1842 if (vesa_adp != NULL) { 1843 if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) { 1844 vesa_bios_save_palette(0, 256, palette, 8); 1845 vesa_bios_set_dac(6); 1846 vesa_adp->va_flags &= ~V_ADP_DAC8; 1847 vesa_bios_load_palette(0, 256, palette, 6); 1848 } 1849 vesa_adp->va_flags &= ~V_ADP_VESA; 1850 vidsw[vesa_adp->va_index] = prevvidsw; 1851 } 1852 } 1853 splx(s); 1854 1855 if (vesa_adp_info != NULL) 1856 free(vesa_adp_info, M_DEVBUF); 1857 if (vesa_oemstr != NULL) 1858 free(vesa_oemstr, M_DEVBUF); 1859 if (vesa_venderstr != NULL) 1860 free(vesa_venderstr, M_DEVBUF); 1861 if (vesa_prodstr != NULL) 1862 free(vesa_prodstr, M_DEVBUF); 1863 if (vesa_revstr != NULL) 1864 free(vesa_revstr, M_DEVBUF); 1865 if (vesa_vmode != &vesa_vmode_empty) 1866 free(vesa_vmode, M_DEVBUF); 1867 if (vesa_palette != NULL) 1868 x86bios_free(vesa_palette, 1869 VESA_PALETTE_SIZE + vesa_state_buf_size); 1870 return (error); 1871 } 1872 1873 static int 1874 vesa_mod_event(module_t mod, int type, void *data) 1875 { 1876 1877 switch (type) { 1878 case MOD_LOAD: 1879 return (vesa_load()); 1880 case MOD_UNLOAD: 1881 return (vesa_unload()); 1882 } 1883 return (EOPNOTSUPP); 1884 } 1885 1886 static moduledata_t vesa_mod = { 1887 "vesa", 1888 vesa_mod_event, 1889 NULL, 1890 }; 1891 1892 DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1893 MODULE_DEPEND(vesa, x86bios, 1, 1, 1); 1894 1895 #endif /* VGA_NO_MODE_CHANGE */ 1896