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