1 /* 2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory 3 * PROJECT: ReactOS Virtual DOS Machine 4 * FILE: subsystems/mvdm/ntvdm/bios/bios32/vbe.c 5 * PURPOSE: VDM VESA BIOS Extensions (for the Cirrus CL-GD5434 emulated card) 6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "ntvdm.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 #include "emulator.h" 17 #include "cpu/cpu.h" 18 #include "bios32p.h" 19 #include "hardware/video/svga.h" 20 21 #include "vbe.h" 22 23 #include "io.h" 24 25 /* PRIVATE VARIABLES **********************************************************/ 26 27 static const VBE_MODE_INFO VbeMode_640x480x256_Info = 28 { 29 /* Attributes */ 30 VBE_MODE_SUPPORTED 31 | VBE_MODE_OPTIONAL_INFO 32 // | VBE_MODE_BIOS_SUPPORT 33 | VBE_MODE_COLOR 34 | VBE_MODE_GRAPHICS, 35 36 /* Window A attributes */ 37 VBE_WINDOW_EXISTS | VBE_WINDOW_READABLE | VBE_WINDOW_WRITABLE, 38 /* Window B attributes */ 39 0, 40 41 16, /* Window granularity, in KB */ 42 64, /* Window size, in KB */ 43 0xA000, /* Window A segment, or zero if not supported */ 44 0x0000, /* Window B segment, or zero if not supported */ 45 0x00000000, /* Window position function pointer */ 46 640, /* Bytes per scanline */ 47 640, /* Width */ 48 480, /* Height */ 49 8, /* Character cell width */ 50 16, /* Character cell height */ 51 1, /* Number of memory planes */ 52 8, /* Bits per pixel */ 53 1, /* Number of banks */ 54 VBE_MODEL_PACKED, /* Memory model */ 55 0, /* Bank size */ 56 11, /* Number of image pages */ 57 0, /* Reserved field */ 58 0, /* Red mask size */ 59 0, /* Red field position */ 60 0, /* Green mask size */ 61 0, /* Green field position */ 62 0, /* Blue mask size */ 63 0, /* Blue field position */ 64 0, /* Reserved mask size */ 65 0, /* Reserved field position */ 66 0, /* Direct color info */ 67 }; 68 69 static SVGA_REGISTERS VbeMode_640x480x256_Registers = 70 { 71 /* Miscellaneous Register */ 72 0x63, 73 74 /* Hidden Register */ 75 0x00, 76 77 /* Sequencer Registers */ 78 { 79 0x03, 0x21, 0x0F, 0x00, 0x0E, 0x00, 0x12, 0x11, 0x00, 0x00, 0x18, 0x58, 80 0x58, 0x58, 0x58, 0x98, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x20, 81 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x2D 82 }, 83 84 /* CRTC Registers */ 85 { 86 0x5F, 0x4F, 0x4F, 0x80, 0x52, 0x1E, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00, 87 0x00, 0x00, 0x00, 0x00, 0xEA, 0x2C, 0xDF, 0x50, 0x40, 0xDF, 0x0B, 0xC3, 88 0xFF, 0x00, 0x00, 0x22, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 89 0x80, 0x00, 0x20, 0xB8 90 }, 91 92 /* GC Registers */ 93 { 94 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x00, 0x20, 95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 98 0x00, 0x00, 0x00, 0x00 99 }, 100 101 /* AC Registers */ 102 { 103 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 104 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00 105 } 106 }; 107 108 static const VBE_MODE_INFO VbeMode_800x600x256_Info = 109 { 110 /* Attributes */ 111 VBE_MODE_SUPPORTED 112 | VBE_MODE_OPTIONAL_INFO 113 // | VBE_MODE_BIOS_SUPPORT 114 | VBE_MODE_COLOR 115 | VBE_MODE_GRAPHICS, 116 117 /* Window A attributes */ 118 VBE_WINDOW_EXISTS | VBE_WINDOW_READABLE | VBE_WINDOW_WRITABLE, 119 /* Window B attributes */ 120 0, 121 122 16, /* Window granularity, in KB */ 123 64, /* Window size, in KB */ 124 0xA000, /* Window A segment, or zero if not supported */ 125 0x0000, /* Window B segment, or zero if not supported */ 126 0x00000000, /* Window position function pointer */ 127 800, /* Bytes per scanline */ 128 800, /* Width */ 129 600, /* Height */ 130 8, /* Character cell width */ 131 16, /* Character cell height */ 132 1, /* Number of memory planes */ 133 8, /* Bits per pixel */ 134 1, /* Number of banks */ 135 VBE_MODEL_PACKED, /* Memory model */ 136 0, /* Bank size */ 137 7, /* Number of image pages */ 138 0, /* Reserved field */ 139 0, /* Red mask size */ 140 0, /* Red field position */ 141 0, /* Green mask size */ 142 0, /* Green field position */ 143 0, /* Blue mask size */ 144 0, /* Blue field position */ 145 0, /* Reserved mask size */ 146 0, /* Reserved field position */ 147 0, /* Direct color info */ 148 }; 149 150 static SVGA_REGISTERS VbeMode_800x600x256_Registers = 151 { 152 /* Miscellaneous Register */ 153 0x63, 154 155 /* Hidden Register */ 156 0x00, 157 158 /* Sequencer Registers */ 159 { 160 0x03, 0x21, 0x0F, 0x00, 0x0E, 0x00, 0x12, 0x11, 0x00, 0x00, 0x18, 0x23, 161 0x23, 0x23, 0x23, 0x98, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x20, 162 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x2D 163 }, 164 165 /* CRTC Registers */ 166 { 167 0x7D, 0x63, 0x63, 0x80, 0x6B, 0x1A, 0x98, 0xF0, 0x00, 0x60, 0x00, 0x00, 168 0x00, 0x00, 0x00, 0x00, 0x7D, 0x23, 0x57, 0x64, 0x40, 0x57, 0x98, 0xC3, 169 0xFF, 0x00, 0x00, 0x22, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 170 0x80, 0x00, 0x20, 0xB8 171 }, 172 173 /* GC Registers */ 174 { 175 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x00, 0x20, 176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 177 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 179 0x00, 0x00, 0x00, 0x00 180 }, 181 182 /* AC Registers */ 183 { 184 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 185 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00 186 } 187 }; 188 189 static const VBE_MODE Modes[VBE_MODE_COUNT] = 190 { 191 { 0x14, 0xFFFF, NULL , NULL /* TODO */ }, 192 { 0x54, 0x10A , NULL /* TODO */ , NULL /* TODO */ }, 193 { 0x55, 0x109 , NULL /* TODO */ , NULL /* TODO */ }, 194 { 0x58, 0x102 , NULL /* TODO */ , NULL /* TODO */ }, 195 { 0x5C, 0x103 , &VbeMode_800x600x256_Info, &VbeMode_800x600x256_Registers }, 196 { 0x5D, 0x104 , NULL /* TODO */ , NULL /* TODO */ }, 197 { 0x5E, 0x100 , NULL /* TODO */ , NULL /* TODO */ }, 198 { 0x5F, 0x101 , &VbeMode_640x480x256_Info, &VbeMode_640x480x256_Registers }, 199 { 0x60, 0x105 , NULL /* TODO */ , NULL /* TODO */ }, 200 { 0x64, 0x111 , NULL /* TODO */ , NULL /* TODO */ }, 201 { 0x65, 0x114 , NULL /* TODO */ , NULL /* TODO */ }, 202 { 0x66, 0x110 , NULL /* TODO */ , NULL /* TODO */ }, 203 { 0x67, 0x113 , NULL /* TODO */ , NULL /* TODO */ }, 204 { 0x68, 0x116 , NULL /* TODO */ , NULL /* TODO */ }, 205 { 0x69, 0x119 , NULL /* TODO */ , NULL /* TODO */ }, 206 { 0x6C, 0x106 , NULL /* TODO */ , NULL /* TODO */ }, 207 { 0x6D, 0x107 , NULL /* TODO */ , NULL /* TODO */ }, 208 { 0x71, 0x112 , NULL /* TODO */ , NULL /* TODO */ }, 209 { 0x72, 0xFFFF, NULL , NULL /* TODO */ }, 210 { 0x73, 0xFFFF, NULL , NULL /* TODO */ }, 211 { 0x74, 0x117 , NULL /* TODO */ , NULL /* TODO */ }, 212 { 0x75, 0x11A , NULL /* TODO */ , NULL /* TODO */ }, 213 { 0x76, 0xFFFF, NULL , NULL /* TODO */ }, 214 { 0x78, 0x115 , NULL /* TODO */ , NULL /* TODO */ }, 215 { 0x79, 0x118 , NULL /* TODO */ , NULL /* TODO */ }, 216 }; 217 218 /* PRIVATE FUNCTIONS **********************************************************/ 219 220 PCVBE_MODE VbeGetModeByNumber(WORD Number) 221 { 222 INT i; 223 224 Number &= 0x1FF; 225 226 /* Find the mode */ 227 for (i = 0; i < VBE_MODE_COUNT; i++) 228 { 229 if ((!(Number & 0x100) && (Number == Modes[i].Number)) 230 || ((Number & 0x100) && (Number== Modes[i].VesaNumber))) 231 { 232 return &Modes[i]; 233 } 234 } 235 236 return NULL; 237 } 238 239 /* This function is based on VgaSetRegisters in vidbios.c */ 240 static VOID VbeSetExtendedRegisters(PSVGA_REGISTERS Registers) 241 { 242 UINT i; 243 244 /* Disable interrupts */ 245 BOOLEAN Interrupts = getIF(); 246 setIF(0); 247 248 /* 249 * Set the CRT base address according to the selected mode, 250 * monochrome or color. The following macros: 251 * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then 252 * used to access the correct VGA I/O ports. 253 */ 254 Bda->CrtBasePort = (Registers->Misc & 0x01) ? VGA_CRTC_INDEX_COLOR 255 : VGA_CRTC_INDEX_MONO; 256 /* Bit 1 indicates whether display is color (0) or monochrome (1) */ 257 Bda->VGAOptions = (Bda->VGAOptions & 0xFD) | (!(Registers->Misc & 0x01) << 1); 258 Bda->CrtModeControl = (Bda->CrtModeControl & 0xFB) | (!(Registers->Misc & 0x01) << 1); 259 260 /* Update blink bit in BDA */ 261 if (Registers->Attribute[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_BLINK) 262 Bda->CrtModeControl |= (1 << 5); 263 else 264 Bda->CrtModeControl &= ~(1 << 5); 265 266 /* Turn the video off */ 267 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); 268 IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) | VGA_SEQ_CLOCK_SD); 269 270 /* Write the misc register */ 271 IOWriteB(VGA_MISC_WRITE, Registers->Misc); 272 273 /* Synchronous reset on */ 274 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); 275 IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR ); 276 277 /* Write the sequencer registers */ 278 for (i = 1; i < SVGA_SEQ_MAX_REG; i++) 279 { 280 if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG) 281 { 282 IOWriteB(VGA_SEQ_INDEX, i); 283 IOWriteB(VGA_SEQ_DATA , Registers->Sequencer[i]); 284 } 285 } 286 287 /* Synchronous reset off */ 288 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); 289 IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR); 290 291 /* Unlock CRTC registers 0-7 */ 292 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG); 293 IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) | 0x80); 294 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_VERT_RETRACE_REG); 295 IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) & ~0x80); 296 // Make sure they remain unlocked 297 Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80; 298 Registers->CRT[VGA_CRTC_END_VERT_RETRACE_REG] &= ~0x80; 299 300 /* Write the CRTC registers */ 301 for (i = 0; i < SVGA_CRTC_MAX_REG; i++) 302 { 303 if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG) 304 { 305 IOWriteB(VGA_CRTC_INDEX, i); 306 IOWriteB(VGA_CRTC_DATA , Registers->CRT[i]); 307 } 308 } 309 310 /* Write the GC registers */ 311 for (i = 0; i < SVGA_GC_MAX_REG; i++) 312 { 313 if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG 314 && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG)) 315 { 316 IOWriteB(VGA_GC_INDEX, i); 317 IOWriteB(VGA_GC_DATA , Registers->Graphics[i]); 318 } 319 } 320 321 /* Write the AC registers */ 322 for (i = 0; i < VGA_AC_MAX_REG; i++) 323 { 324 /* Write the index */ 325 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state 326 IOWriteB(VGA_AC_INDEX, i); 327 328 /* Write the data */ 329 IOWriteB(VGA_AC_WRITE, Registers->Attribute[i]); 330 } 331 332 /* Perform 4 dummy reads from the DAC mask to access the hidden register */ 333 for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK); 334 335 /* Set the hidden register */ 336 IOWriteB(VGA_DAC_MASK, Registers->Hidden); 337 338 /* Set the PEL mask */ 339 IOWriteB(VGA_DAC_MASK, 0xFF); 340 341 /* Enable screen and disable palette access */ 342 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state 343 IOWriteB(VGA_AC_INDEX, 0x20); 344 345 /* Turn the video on */ 346 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); 347 IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) & ~VGA_SEQ_CLOCK_SD); 348 349 /* Restore interrupts */ 350 setIF(Interrupts); 351 } 352 353 354 /* PUBLIC FUNCTIONS ***********************************************************/ 355 356 BOOLEAN WINAPI VbeSetExtendedVideoMode(BYTE ModeNumber) 357 { 358 PCVBE_MODE Mode = VbeGetModeByNumber(ModeNumber); 359 if (Mode == NULL) return FALSE; 360 361 /* At this point, Mode->Registers shouldn't be NULL unless the mode is unimplemented */ 362 if (Mode->Registers == NULL) 363 { 364 DPRINT1("Extended video mode %02X still UNIMPLEMENTED.\n", ModeNumber); 365 return FALSE; 366 } 367 368 /* Set the registers */ 369 VbeSetExtendedRegisters(Mode->Registers); 370 371 /* Update the current video mode in the BDA */ 372 Bda->VideoMode = ModeNumber; 373 374 /* Clear the screen */ 375 VgaClearMemory(); 376 377 return TRUE; 378 } 379 380 VOID WINAPI VbeResetExtendedRegisters(VOID) 381 { 382 BYTE i; 383 384 /* Disable interrupts */ 385 BOOLEAN Interrupts = getIF(); 386 setIF(0); 387 388 /* Turn the video off */ 389 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); 390 IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) | VGA_SEQ_CLOCK_SD); 391 392 /* Synchronous reset on */ 393 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); 394 IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR ); 395 396 /* Clear the extended sequencer registers, except for the VCLKs and MCLK */ 397 for (i = SVGA_SEQ_EXT_MODE_REG; i < SVGA_SEQ_VCLK0_DENOMINATOR_REG; i++) 398 { 399 if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG 400 && (i < SVGA_SEQ_VCLK0_NUMERATOR_REG || i > SVGA_SEQ_VCLK3_NUMERATOR_REG)) 401 { 402 IOWriteB(VGA_SEQ_INDEX, i); 403 IOWriteB(VGA_SEQ_DATA, 0x00); 404 } 405 } 406 407 /* Reset the VCLKs */ 408 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK0_NUMERATOR_REG); 409 IOWriteB(VGA_SEQ_DATA, 0x66); 410 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK0_DENOMINATOR_REG); 411 IOWriteB(VGA_SEQ_DATA, 0x3B); 412 413 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK1_NUMERATOR_REG); 414 IOWriteB(VGA_SEQ_DATA, 0x5B); 415 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK1_DENOMINATOR_REG); 416 IOWriteB(VGA_SEQ_DATA, 0x2F); 417 418 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK2_NUMERATOR_REG); 419 IOWriteB(VGA_SEQ_DATA, 0x45); 420 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK2_DENOMINATOR_REG); 421 IOWriteB(VGA_SEQ_DATA, 0x30); 422 423 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK3_NUMERATOR_REG); 424 IOWriteB(VGA_SEQ_DATA, 0x7E); 425 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_VCLK3_DENOMINATOR_REG); 426 IOWriteB(VGA_SEQ_DATA, 0x33); 427 428 /* Reset the MCLK */ 429 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_MCLK_REG); 430 IOWriteB(VGA_SEQ_DATA, 0x1C); 431 432 /* Synchronous reset off */ 433 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); 434 IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR); 435 436 /* Reset the extended CRTC registers */ 437 for (i = SVGA_CRTC_INTERLACE_END_REG; i < SVGA_CRTC_MAX_REG; i++) 438 { 439 if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG) 440 { 441 IOWriteB(VGA_CRTC_INDEX, i); 442 IOWriteB(VGA_CRTC_DATA, 0x00); 443 } 444 } 445 446 /* Reset the extended GC registers */ 447 for (i = SVGA_GC_OFFSET_0_REG; i < SVGA_GC_MAX_REG; i++) 448 { 449 if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG 450 && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG)) 451 { 452 IOWriteB(VGA_GC_INDEX, i); 453 IOWriteB(VGA_GC_DATA, 0x00); 454 } 455 } 456 457 /* 458 * And finally, reset the hidden register. This requires 4 dummy reads from 459 * the DAC mask register. 460 */ 461 for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK); 462 IOWriteB(VGA_DAC_MASK, 0x00); 463 464 /* Turn the video on */ 465 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); 466 IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) & ~VGA_SEQ_CLOCK_SD); 467 468 /* Restore interrupts */ 469 setIF(Interrupts); 470 } 471 472 VOID WINAPI VbeService(LPWORD Stack) 473 { 474 INT i; 475 476 switch (getAL()) 477 { 478 /* Get VBE Information */ 479 case 0x00: 480 { 481 VBE_INFORMATION Info; 482 PWORD Data = (PWORD)&Info; 483 484 /* Function recognized */ 485 setAL(0x4F); 486 487 ZeroMemory(&Info, sizeof(VBE_INFORMATION)); 488 Info.Signature = 'ASEV'; 489 Info.Version = 0x0102; 490 Info.OemName = OEM_NAME_PTR; 491 Info.Capabilities = 0; 492 Info.ModeList = MAKELONG(LOWORD(getDI() 493 + FIELD_OFFSET(VBE_INFORMATION, ModeListBuffer)), 494 getES()); 495 Info.VideoMemory = HIWORD(SVGA_BANK_SIZE * VGA_NUM_BANKS); 496 497 /* Fill the mode list */ 498 for (i = 0; i < VBE_MODE_COUNT; i++) 499 { 500 /* Some modes don't have VESA numbers */ 501 if (Modes[i].VesaNumber != 0xFFFF) 502 { 503 Info.ModeListBuffer[i] = Modes[i].VesaNumber; 504 } 505 } 506 507 Info.ModeListBuffer[VBE_MODE_COUNT] = 0xFFFF; 508 509 /* Copy the data to the caller */ 510 for (i = 0; i < sizeof(VBE_INFORMATION) / sizeof(WORD); i++) 511 { 512 *(PWORD)SEG_OFF_TO_PTR(getES(), LOWORD(getDI() + i * 2)) = Data[i]; 513 } 514 515 setAH(0); 516 break; 517 } 518 519 /* Get VBE Mode Information */ 520 case 0x01: 521 { 522 PCVBE_MODE Mode = VbeGetModeByNumber(getCX()); 523 PWORD Data = NULL; 524 525 /* Function recognized */ 526 setAL(0x4F); 527 528 if (Mode == NULL) 529 { 530 /* Mode not found */ 531 setAH(1); 532 break; 533 } 534 535 Data = (PWORD)Mode->Info; 536 if (Data == NULL) 537 { 538 DPRINT1("WARNING: The mode information for mode %02X (%03X) is missing!\n", 539 Mode->Number, 540 Mode->VesaNumber); 541 542 setAH(1); 543 break; 544 } 545 546 /* Clear the buffer */ 547 for (i = 0; i < 128; i++) 548 { 549 *(PWORD)SEG_OFF_TO_PTR(getES(), LOWORD(getDI() + i * 2)) = 0; 550 } 551 552 /* Copy the data to the caller */ 553 for (i = 0; i < sizeof(VBE_MODE_INFO) / sizeof(WORD); i++) 554 { 555 *(PWORD)SEG_OFF_TO_PTR(getES(), LOWORD(getDI() + i * 2)) = Data[i]; 556 } 557 558 setAH(0); 559 break; 560 } 561 562 /* Set VBE Mode */ 563 case 0x02: 564 { 565 WORD VesaNumber = getBX(); 566 setAL(0x4F); 567 568 if (VesaNumber <= BIOS_MAX_VIDEO_MODE) 569 { 570 /* Call the VGA BIOS */ 571 setAH(0x00); 572 setAL(VesaNumber); 573 Int32Call(&BiosContext, BIOS_VIDEO_INTERRUPT); 574 575 setAH(Bda->VideoMode != VesaNumber); 576 } 577 else 578 { 579 /* This is an extended video mode */ 580 PCVBE_MODE Mode = VbeGetModeByNumber(VesaNumber); 581 582 if (Mode) setAH(!VbeSetExtendedVideoMode(Mode->Number)); 583 else setAH(1); 584 } 585 586 break; 587 } 588 589 /* Get Current VBE Mode */ 590 case 0x03: 591 { 592 PCVBE_MODE Mode = VbeGetModeByNumber(Bda->VideoMode); 593 594 setAL(0x4F); 595 596 if (Mode) 597 { 598 setBX(Mode->VesaNumber != 0xFFFF 599 ? Mode->VesaNumber : Mode->Number); 600 setAH(0); 601 } 602 else 603 { 604 setAH(1); 605 } 606 607 break; 608 } 609 610 /* CPU Video Memory Control */ 611 case 0x05: 612 { 613 BYTE Window = getBL(); 614 BYTE OldGcIndex = IOReadB(VGA_GC_INDEX); 615 616 switch (getBH()) 617 { 618 /* Select Memory Window */ 619 case 0: 620 { 621 setAL(0x4F); 622 623 if (getDH() != 0) 624 { 625 /* Offset too high */ 626 setAH(1); 627 break; 628 } 629 630 IOWriteB(VGA_GC_INDEX, (Window == 0) ? SVGA_GC_OFFSET_0_REG : SVGA_GC_OFFSET_1_REG); 631 IOWriteB(VGA_GC_DATA, getDL()); 632 633 setAH(0); 634 break; 635 } 636 637 /* Return Memory Window */ 638 case 1: 639 { 640 IOWriteB(VGA_GC_INDEX, (Window == 0) ? SVGA_GC_OFFSET_0_REG : SVGA_GC_OFFSET_1_REG); 641 setDX(IOReadB(VGA_GC_DATA)); 642 643 setAX(0x004F); 644 break; 645 } 646 647 default: 648 { 649 DPRINT("VESA INT 0x10, AL = 0x05, Unknown subfunction: %02X", getBH()); 650 } 651 } 652 653 IOWriteB(VGA_GC_INDEX, OldGcIndex); 654 break; 655 } 656 657 /* Get/Set Display Start */ 658 case 0x07: 659 { 660 DWORD StartAddress; 661 BYTE Value; 662 PCVBE_MODE Mode = VbeGetModeByNumber(Bda->VideoMode); 663 BYTE OldCrtcIndex = IOReadB(VGA_CRTC_INDEX_COLOR); 664 665 if (getBL() & 0x80) 666 { 667 /* Wait for a vertical retrace */ 668 if (!(IOReadB(VGA_INSTAT1_READ_COLOR) & VGA_STAT_VRETRACE)) 669 { 670 setCF(1); 671 break; 672 } 673 674 setCF(0); 675 } 676 677 switch (getBL() & 0x7F) 678 { 679 /* Set Display Start */ 680 case 0x00: 681 { 682 setAL(0x4F); 683 684 if (Mode == NULL || Mode->Info == NULL) 685 { 686 /* This is not a VBE mode */ 687 // TODO: Support anyway, perhaps? It can be done. 688 setAH(0x01); 689 break; 690 } 691 692 StartAddress = getCX() + getDX() * Mode->Info->BytesPerScanline; 693 694 IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_OVERLAY_REG); 695 Value = IOReadB(VGA_CRTC_DATA_COLOR); 696 Value &= ~SVGA_CRTC_EXT_ADDR_BIT19; 697 Value |= (StartAddress >> 12) & SVGA_CRTC_EXT_ADDR_BIT19; 698 IOWriteB(VGA_CRTC_DATA_COLOR, Value); 699 700 IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_EXT_DISPLAY_REG); 701 Value = IOReadB(VGA_CRTC_DATA_COLOR); 702 Value &= ~(SVGA_CRTC_EXT_ADDR_BIT16 | SVGA_CRTC_EXT_ADDR_BITS1718); 703 Value |= (StartAddress >> 16) & SVGA_CRTC_EXT_ADDR_BIT16; 704 Value |= (StartAddress >> 15) & SVGA_CRTC_EXT_ADDR_BITS1718; 705 IOWriteB(VGA_CRTC_DATA_COLOR, Value); 706 707 IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_HIGH_REG); 708 IOWriteB(VGA_CRTC_DATA_COLOR, (StartAddress >> 8) & 0xFF); 709 IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_LOW_REG); 710 IOWriteB(VGA_CRTC_DATA_COLOR, StartAddress & 0xFF); 711 712 setAH(0); 713 break; 714 } 715 716 /* Get Display Start */ 717 case 0x01: 718 { 719 setAL(0x4F); 720 StartAddress = 0; 721 722 if (Mode == NULL || Mode->Info == NULL) 723 { 724 /* This is not a VBE mode */ 725 // TODO: Support anyway, perhaps? It can be done. 726 setAH(0x01); 727 break; 728 } 729 730 IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_OVERLAY_REG); 731 StartAddress = (IOReadB(VGA_CRTC_DATA_COLOR) & SVGA_CRTC_EXT_ADDR_BIT19) << 12; 732 733 IOWriteB(VGA_CRTC_INDEX_COLOR, SVGA_CRTC_EXT_DISPLAY_REG); 734 Value = IOReadB(VGA_CRTC_DATA_COLOR); 735 StartAddress |= (Value & SVGA_CRTC_EXT_ADDR_BIT16) << 16; 736 StartAddress |= (Value & SVGA_CRTC_EXT_ADDR_BITS1718) << 15; 737 738 IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_HIGH_REG); 739 StartAddress |= IOReadB(VGA_CRTC_DATA_COLOR) << 8; 740 IOWriteB(VGA_CRTC_INDEX_COLOR, VGA_CRTC_START_ADDR_LOW_REG); 741 StartAddress |= IOReadB(VGA_CRTC_DATA_COLOR); 742 743 setCX(StartAddress % Mode->Info->BytesPerScanline); 744 setDX(StartAddress / Mode->Info->BytesPerScanline); 745 746 setAH(0); 747 break; 748 } 749 } 750 751 IOWriteB(VGA_CRTC_INDEX_COLOR, OldCrtcIndex); 752 break; 753 } 754 755 default: 756 { 757 DPRINT1("VESA BIOS Extensions function %02Xh NOT IMPLEMENTED!\n", getAL()); 758 break; 759 } 760 } 761 } 762 763 BOOLEAN VbeInitialize(VOID) 764 { 765 BOOLEAN Success; 766 BYTE SeqIndex = IOReadB(VGA_SEQ_INDEX); 767 768 /* Store the OEM name */ 769 strcpy(FAR_POINTER(OEM_NAME_PTR), OEM_NAME); 770 771 /* Unlock SVGA extensions on the card */ 772 IOWriteB(VGA_SEQ_INDEX, SVGA_SEQ_UNLOCK_REG); 773 IOWriteB(VGA_SEQ_DATA, SVGA_SEQ_UNLOCKED); 774 775 /* Check if it worked */ 776 Success = IOReadB(VGA_SEQ_DATA) == SVGA_SEQ_UNLOCKED; 777 778 IOWriteB(VGA_SEQ_INDEX, SeqIndex); 779 return Success; 780 } 781