1 /* 2 * ReactOS VBE miniport video driver 3 * Copyright (C) 2004 Filip Navara 4 * 5 * Power Management and VBE 1.2 support 6 * Copyright (C) 2004 Magnus Olsen 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 2 11 * of the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * TODO: 23 * - Check input parameters everywhere. 24 * - Call VideoPortVerifyAccessRanges to reserve the memory we're about 25 * to map. 26 */ 27 28 /* INCLUDES *******************************************************************/ 29 30 #include "vbemp.h" 31 32 #include <devioctl.h> 33 34 #undef LOWORD 35 #undef HIWORD 36 #define LOWORD(l) ((USHORT)((ULONG_PTR)(l))) 37 #define HIWORD(l) ((USHORT)(((ULONG_PTR)(l)>>16)&0xFFFF)) 38 39 VIDEO_ACCESS_RANGE VBEAccessRange[] = 40 { 41 { {{0x3b0}}, 0x3bb - 0x3b0 + 1, 1, 1, 0 }, 42 { {{0x3c0}}, 0x3df - 0x3c0 + 1, 1, 1, 0 }, 43 { {{0xa0000}}, 0x20000, 0, 1, 0 }, 44 }; 45 46 /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ 47 48 ULONG NTAPI 49 DriverEntry(IN PVOID Context1, IN PVOID Context2) 50 { 51 VIDEO_HW_INITIALIZATION_DATA InitData; 52 53 VideoPortZeroMemory(&InitData, sizeof(InitData)); 54 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA); 55 InitData.HwFindAdapter = VBEFindAdapter; 56 InitData.HwInitialize = VBEInitialize; 57 InitData.HwStartIO = VBEStartIO; 58 InitData.HwResetHw = VBEResetHw; 59 InitData.HwGetPowerState = VBEGetPowerState; 60 InitData.HwSetPowerState = VBESetPowerState; 61 InitData.HwGetVideoChildDescriptor = VBEGetVideoChildDescriptor; 62 InitData.HwDeviceExtensionSize = sizeof(VBE_DEVICE_EXTENSION); 63 InitData.HwLegacyResourceList = VBEAccessRange; 64 InitData.HwLegacyResourceCount = ARRAYSIZE(VBEAccessRange); 65 66 return VideoPortInitialize(Context1, Context2, &InitData, NULL); 67 } 68 69 /* 70 * VBEFindAdapter 71 * 72 * Should detect a VBE compatible display adapter, but it's not possible 73 * to use video port Int 10 services at this time during initialization, 74 * so we always return NO_ERROR and do the real work in VBEInitialize. 75 */ 76 77 VP_STATUS NTAPI 78 VBEFindAdapter( 79 IN PVOID HwDeviceExtension, 80 IN PVOID HwContext, 81 IN PWSTR ArgumentString, 82 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo, 83 OUT PUCHAR Again) 84 { 85 if (VideoPortIsNoVesa()) 86 return ERROR_DEV_NOT_EXIST; 87 88 if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) 89 return ERROR_INVALID_PARAMETER; 90 91 ConfigInfo->VdmPhysicalVideoMemoryAddress = VBEAccessRange[2].RangeStart; 92 ConfigInfo->VdmPhysicalVideoMemoryLength = VBEAccessRange[2].RangeLength; 93 return NO_ERROR; 94 } 95 96 /* 97 * VBESortModesCallback 98 * 99 * Helper function for sorting video mode list. 100 */ 101 102 static int 103 VBESortModesCallback(PVBE_MODEINFO VbeModeInfoA, PVBE_MODEINFO VbeModeInfoB) 104 { 105 /* 106 * FIXME: Until some reasonable method for changing video modes will 107 * be available we favor more bits per pixel. It should be changed 108 * later. 109 */ 110 if (VbeModeInfoA->BitsPerPixel < VbeModeInfoB->BitsPerPixel) return -1; 111 if (VbeModeInfoA->BitsPerPixel > VbeModeInfoB->BitsPerPixel) return 1; 112 if (VbeModeInfoA->XResolution < VbeModeInfoB->XResolution) return -1; 113 if (VbeModeInfoA->XResolution > VbeModeInfoB->XResolution) return 1; 114 if (VbeModeInfoA->YResolution < VbeModeInfoB->YResolution) return -1; 115 if (VbeModeInfoA->YResolution > VbeModeInfoB->YResolution) return 1; 116 return 0; 117 } 118 119 /* 120 * VBESortModes 121 * 122 * Simple function for sorting the video mode list. Uses bubble sort. 123 */ 124 125 VOID FASTCALL 126 VBESortModes(PVBE_DEVICE_EXTENSION DeviceExtension) 127 { 128 BOOLEAN Finished = FALSE; 129 ULONG Pos; 130 int Result; 131 VBE_MODEINFO TempModeInfo; 132 USHORT TempModeNumber; 133 134 while (!Finished) 135 { 136 Finished = TRUE; 137 for (Pos = 0; Pos < DeviceExtension->ModeCount - 1; Pos++) 138 { 139 Result = VBESortModesCallback( 140 DeviceExtension->ModeInfo + Pos, 141 DeviceExtension->ModeInfo + Pos + 1); 142 if (Result > 0) 143 { 144 Finished = FALSE; 145 146 VideoPortMoveMemory( 147 &TempModeInfo, 148 DeviceExtension->ModeInfo + Pos, 149 sizeof(VBE_MODEINFO)); 150 TempModeNumber = DeviceExtension->ModeNumbers[Pos]; 151 152 VideoPortMoveMemory( 153 DeviceExtension->ModeInfo + Pos, 154 DeviceExtension->ModeInfo + Pos + 1, 155 sizeof(VBE_MODEINFO)); 156 DeviceExtension->ModeNumbers[Pos] = 157 DeviceExtension->ModeNumbers[Pos + 1]; 158 159 VideoPortMoveMemory( 160 DeviceExtension->ModeInfo + Pos + 1, 161 &TempModeInfo, 162 sizeof(VBE_MODEINFO)); 163 DeviceExtension->ModeNumbers[Pos + 1] = TempModeNumber; 164 } 165 } 166 } 167 } 168 169 /* 170 * VBEInitialize 171 * 172 * Performs the first initialization of the adapter, after the HAL has given 173 * up control of the video hardware to the video port driver. 174 * 175 * This function performs these steps: 176 * - Gets global VBE information and finds if VBE BIOS is present. 177 * - Builds the internal mode list using the list of modes provided by 178 * the VBE. 179 */ 180 181 BOOLEAN NTAPI 182 VBEInitialize(PVOID HwDeviceExtension) 183 { 184 INT10_BIOS_ARGUMENTS BiosRegisters; 185 VP_STATUS Status; 186 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 187 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 188 ULONG Length; 189 ULONG ModeCount; 190 ULONG SuitableModeCount; 191 USHORT ModeTemp; 192 ULONG CurrentMode; 193 PVBE_MODEINFO VbeModeInfo; 194 195 if (VideoPortIsNoVesa()) 196 { 197 VBEDeviceExtension->Int10Interface.Version = 0; 198 VBEDeviceExtension->Int10Interface.Size = 0; 199 return FALSE; 200 } 201 202 /* 203 * Get the Int 10 interface that we will use for allocating real 204 * mode memory and calling the video BIOS. 205 */ 206 207 VBEDeviceExtension->Int10Interface.Version = VIDEO_PORT_INT10_INTERFACE_VERSION_1; 208 VBEDeviceExtension->Int10Interface.Size = sizeof(VIDEO_PORT_INT10_INTERFACE); 209 Status = VideoPortQueryServices( 210 HwDeviceExtension, 211 VideoPortServicesInt10, 212 (PINTERFACE)&VBEDeviceExtension->Int10Interface); 213 214 if (Status != NO_ERROR) 215 { 216 VideoPortDebugPrint(Error, "Failed to get Int 10 service functions (Status %x)\n", Status); 217 return FALSE; 218 } 219 220 /* 221 * Allocate a bit of memory that will be later used for VBE transport 222 * buffer. This memory must be accessible from V86 mode so it must fit 223 * in the first megabyte of physical memory. 224 */ 225 226 Length = 0x400; 227 Status = VBEDeviceExtension->Int10Interface.Int10AllocateBuffer( 228 VBEDeviceExtension->Int10Interface.Context, 229 &VBEDeviceExtension->TrampolineMemorySegment, 230 &VBEDeviceExtension->TrampolineMemoryOffset, 231 &Length); 232 233 if (Status != NO_ERROR) 234 { 235 VideoPortDebugPrint(Error, "Failed to allocate virtual memory (Status %x)\n", Status); 236 return FALSE; 237 } 238 239 /* 240 * Get the VBE general information. 241 */ 242 243 VBEDeviceExtension->Int10Interface.Int10WriteMemory( 244 VBEDeviceExtension->Int10Interface.Context, 245 VBEDeviceExtension->TrampolineMemorySegment, 246 VBEDeviceExtension->TrampolineMemoryOffset, 247 "VBE2", 248 4); 249 250 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 251 BiosRegisters.Eax = VBE_GET_CONTROLLER_INFORMATION; 252 BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset; 253 BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment; 254 VBEDeviceExtension->Int10Interface.Int10CallBios( 255 VBEDeviceExtension->Int10Interface.Context, 256 &BiosRegisters); 257 258 if (VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS) 259 { 260 VBEDeviceExtension->Int10Interface.Int10ReadMemory( 261 VBEDeviceExtension->Int10Interface.Context, 262 VBEDeviceExtension->TrampolineMemorySegment, 263 VBEDeviceExtension->TrampolineMemoryOffset, 264 &VBEDeviceExtension->VbeInfo, 265 sizeof(VBEDeviceExtension->VbeInfo)); 266 267 /* Verify the VBE signature. */ 268 if (VideoPortCompareMemory(VBEDeviceExtension->VbeInfo.Signature, "VESA", 4) != 4) 269 { 270 VideoPortDebugPrint(Error, "No VBE BIOS present\n"); 271 return FALSE; 272 } 273 274 VideoPortDebugPrint(Trace, "VBE BIOS Present (%d.%d, %8ld Kb)\n", 275 VBEDeviceExtension->VbeInfo.Version / 0x100, 276 VBEDeviceExtension->VbeInfo.Version & 0xFF, 277 VBEDeviceExtension->VbeInfo.TotalMemory * 64); 278 279 #ifdef VBE12_SUPPORT 280 if (VBEDeviceExtension->VbeInfo.Version < 0x102) 281 #else 282 if (VBEDeviceExtension->VbeInfo.Version < 0x200) 283 #endif 284 { 285 VideoPortDebugPrint(Error, "VBE BIOS present, but incompatible version %d.%d\n", 286 VBEDeviceExtension->VbeInfo.Version / 0x100, 287 VBEDeviceExtension->VbeInfo.Version & 0xFF); 288 return FALSE; 289 } 290 } 291 else 292 { 293 VideoPortDebugPrint(Error, "No VBE BIOS found.\n"); 294 return FALSE; 295 } 296 297 /* 298 * Build a mode list here that can be later used by 299 * IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES and IOCTL_VIDEO_QUERY_AVAIL_MODES 300 * calls. 301 */ 302 303 /* 304 * Get the number of supported video modes. 305 * 306 * No need to be map the memory. It's either in the video BIOS memory or 307 * in our trampoline memory. In either case the memory is already mapped. 308 */ 309 310 for (ModeCount = 0; ; ModeCount++) 311 { 312 /* Read the VBE mode number. */ 313 VBEDeviceExtension->Int10Interface.Int10ReadMemory( 314 VBEDeviceExtension->Int10Interface.Context, 315 HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr), 316 LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (ModeCount << 1), 317 &ModeTemp, 318 sizeof(ModeTemp)); 319 320 /* End of list? */ 321 if (ModeTemp == 0xFFFF || ModeTemp == 0) 322 break; 323 } 324 325 /* 326 * Allocate space for video modes information. 327 */ 328 329 VBEDeviceExtension->ModeInfo = 330 VideoPortAllocatePool(HwDeviceExtension, VpPagedPool, ModeCount * sizeof(VBE_MODEINFO), TAG_VBE); 331 VBEDeviceExtension->ModeNumbers = 332 VideoPortAllocatePool(HwDeviceExtension, VpPagedPool, ModeCount * sizeof(USHORT), TAG_VBE); 333 334 /* 335 * Get the actual mode infos. 336 */ 337 338 for (CurrentMode = 0, SuitableModeCount = 0; 339 CurrentMode < ModeCount; 340 CurrentMode++) 341 { 342 /* Read the VBE mode number. */ 343 VBEDeviceExtension->Int10Interface.Int10ReadMemory( 344 VBEDeviceExtension->Int10Interface.Context, 345 HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr), 346 LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (CurrentMode << 1), 347 &ModeTemp, 348 sizeof(ModeTemp)); 349 350 /* Call VBE BIOS to read the mode info. */ 351 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 352 BiosRegisters.Eax = VBE_GET_MODE_INFORMATION; 353 BiosRegisters.Ecx = ModeTemp; 354 BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset + 0x200; 355 BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment; 356 VBEDeviceExtension->Int10Interface.Int10CallBios( 357 VBEDeviceExtension->Int10Interface.Context, 358 &BiosRegisters); 359 360 /* Read the VBE mode info. */ 361 VBEDeviceExtension->Int10Interface.Int10ReadMemory( 362 VBEDeviceExtension->Int10Interface.Context, 363 VBEDeviceExtension->TrampolineMemorySegment, 364 VBEDeviceExtension->TrampolineMemoryOffset + 0x200, 365 VBEDeviceExtension->ModeInfo + SuitableModeCount, 366 sizeof(VBE_MODEINFO)); 367 368 VbeModeInfo = VBEDeviceExtension->ModeInfo + SuitableModeCount; 369 370 /* Is this mode acceptable? */ 371 if (VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS && 372 VbeModeInfo->XResolution >= 640 && 373 VbeModeInfo->YResolution >= 480 && 374 (VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_PACKEDPIXEL || 375 VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_DIRECTCOLOR) && 376 VbeModeInfo->PhysBasePtr != 0) 377 { 378 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_LINEAR) 379 { 380 /* Bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 */ 381 // if (ModeTemp & 0x4000) 382 //{ 383 VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp | 0x4000; 384 SuitableModeCount++; 385 //} 386 } 387 #ifdef VBE12_SUPPORT 388 else 389 { 390 VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp; 391 SuitableModeCount++; 392 } 393 #endif 394 } 395 } 396 397 398 if (SuitableModeCount == 0) 399 { 400 401 VideoPortDebugPrint(Warn, "VBEMP: No video modes supported\n"); 402 return FALSE; 403 } 404 405 VBEDeviceExtension->ModeCount = SuitableModeCount; 406 407 /* 408 * Sort the video mode list according to resolution and bits per pixel. 409 */ 410 411 VBESortModes(VBEDeviceExtension); 412 413 /* 414 * Print the supported video modes. 415 */ 416 417 for (CurrentMode = 0; 418 CurrentMode < SuitableModeCount; 419 CurrentMode++) 420 { 421 VideoPortDebugPrint(Trace, "%dx%dx%d\n", 422 VBEDeviceExtension->ModeInfo[CurrentMode].XResolution, 423 VBEDeviceExtension->ModeInfo[CurrentMode].YResolution, 424 VBEDeviceExtension->ModeInfo[CurrentMode].BitsPerPixel); 425 } 426 427 /* 428 * Enumerate our children. 429 */ 430 VideoPortEnumerateChildren(HwDeviceExtension, NULL); 431 432 return TRUE; 433 } 434 435 /* 436 * VBEStartIO 437 * 438 * Processes the specified Video Request Packet. 439 */ 440 441 BOOLEAN NTAPI 442 VBEStartIO( 443 PVOID HwDeviceExtension, 444 PVIDEO_REQUEST_PACKET RequestPacket) 445 { 446 BOOLEAN Result; 447 448 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION; 449 450 switch (RequestPacket->IoControlCode) 451 { 452 case IOCTL_VIDEO_SET_CURRENT_MODE: 453 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) 454 { 455 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 456 return TRUE; 457 } 458 Result = VBESetCurrentMode( 459 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 460 (PVIDEO_MODE)RequestPacket->InputBuffer, 461 RequestPacket->StatusBlock); 462 break; 463 464 case IOCTL_VIDEO_RESET_DEVICE: 465 Result = VBEResetDevice( 466 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 467 RequestPacket->StatusBlock); 468 break; 469 470 case IOCTL_VIDEO_MAP_VIDEO_MEMORY: 471 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) || 472 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) 473 { 474 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 475 return TRUE; 476 } 477 Result = VBEMapVideoMemory( 478 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 479 (PVIDEO_MEMORY)RequestPacket->InputBuffer, 480 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer, 481 RequestPacket->StatusBlock); 482 break; 483 484 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: 485 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) 486 { 487 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 488 return TRUE; 489 } 490 Result = VBEUnmapVideoMemory( 491 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 492 (PVIDEO_MEMORY)RequestPacket->InputBuffer, 493 RequestPacket->StatusBlock); 494 break; 495 496 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES: 497 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES)) 498 { 499 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 500 return TRUE; 501 } 502 Result = VBEQueryNumAvailModes( 503 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 504 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer, 505 RequestPacket->StatusBlock); 506 break; 507 508 case IOCTL_VIDEO_QUERY_AVAIL_MODES: 509 if (RequestPacket->OutputBufferLength < 510 ((PVBE_DEVICE_EXTENSION)HwDeviceExtension)->ModeCount * sizeof(VIDEO_MODE_INFORMATION)) 511 { 512 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 513 return TRUE; 514 } 515 Result = VBEQueryAvailModes( 516 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 517 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer, 518 RequestPacket->StatusBlock); 519 break; 520 521 case IOCTL_VIDEO_SET_COLOR_REGISTERS: 522 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) || 523 RequestPacket->InputBufferLength < 524 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) + 525 FIELD_OFFSET(VIDEO_CLUT, LookupTable)) 526 { 527 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 528 return TRUE; 529 } 530 Result = VBESetColorRegisters( 531 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 532 (PVIDEO_CLUT)RequestPacket->InputBuffer, 533 RequestPacket->StatusBlock); 534 break; 535 536 case IOCTL_VIDEO_QUERY_CURRENT_MODE: 537 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION)) 538 { 539 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 540 return TRUE; 541 } 542 Result = VBEQueryCurrentMode( 543 (PVBE_DEVICE_EXTENSION)HwDeviceExtension, 544 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer, 545 RequestPacket->StatusBlock); 546 break; 547 548 default: 549 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION; 550 return FALSE; 551 } 552 553 if (Result) 554 RequestPacket->StatusBlock->Status = NO_ERROR; 555 556 return TRUE; 557 } 558 559 /* 560 * VBEResetHw 561 * 562 * This function is called to reset the hardware to a known state. 563 */ 564 565 BOOLEAN NTAPI 566 VBEResetHw( 567 PVOID DeviceExtension, 568 ULONG Columns, 569 ULONG Rows) 570 { 571 /* Return FALSE to let HAL reset the display with INT10 */ 572 return FALSE; 573 } 574 575 /* 576 * VBEGetPowerState 577 * 578 * Queries whether the device can support the requested power state. 579 */ 580 581 VP_STATUS NTAPI 582 VBEGetPowerState( 583 PVOID HwDeviceExtension, 584 ULONG HwId, 585 PVIDEO_POWER_MANAGEMENT VideoPowerControl) 586 { 587 INT10_BIOS_ARGUMENTS BiosRegisters; 588 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 589 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 590 591 if (HwId != DISPLAY_ADAPTER_HW_ID || 592 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT)) 593 return ERROR_INVALID_FUNCTION; 594 595 /* 596 * Get general power support information. 597 */ 598 599 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 600 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS; 601 BiosRegisters.Ebx = 0; 602 BiosRegisters.Edi = 0; 603 BiosRegisters.SegEs = 0; 604 VBEDeviceExtension->Int10Interface.Int10CallBios( 605 VBEDeviceExtension->Int10Interface.Context, 606 &BiosRegisters); 607 608 if ( VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_NOT_SUPPORTED) 609 return ERROR_DEV_NOT_EXIST; 610 if (VBE_GETRETURNCODE(BiosRegisters.Eax) != VBE_SUCCESS) 611 return ERROR_INVALID_FUNCTION; 612 613 /* 614 * Get current power state. 615 */ 616 617 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 618 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS; 619 BiosRegisters.Ebx = 0x2; 620 BiosRegisters.Edi = 0; 621 BiosRegisters.SegEs = 0; 622 VBEDeviceExtension->Int10Interface.Int10CallBios( 623 VBEDeviceExtension->Int10Interface.Context, 624 &BiosRegisters); 625 626 if (VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS) 627 { 628 VideoPowerControl->DPMSVersion = BiosRegisters.Ebx & 0xFF; 629 switch (BiosRegisters.Ebx >> 8) 630 { 631 case 0: VideoPowerControl->PowerState = VideoPowerOn; break; 632 case 1: VideoPowerControl->PowerState = VideoPowerStandBy; break; 633 case 2: VideoPowerControl->PowerState = VideoPowerSuspend; break; 634 case 4: VideoPowerControl->PowerState = VideoPowerOff; break; 635 case 5: VideoPowerControl->PowerState = VideoPowerOn; break; 636 default: VideoPowerControl->PowerState = VideoPowerUnspecified; 637 } 638 639 return NO_ERROR; 640 } 641 642 return ERROR_DEV_NOT_EXIST; 643 } 644 645 /* 646 * VBESetPowerState 647 * 648 * Sets the power state of the specified device 649 */ 650 651 VP_STATUS NTAPI 652 VBESetPowerState( 653 PVOID HwDeviceExtension, 654 ULONG HwId, 655 PVIDEO_POWER_MANAGEMENT VideoPowerControl) 656 { 657 INT10_BIOS_ARGUMENTS BiosRegisters; 658 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 659 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 660 661 if (HwId != DISPLAY_ADAPTER_HW_ID || 662 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT) || 663 VideoPowerControl->PowerState < VideoPowerOn || 664 VideoPowerControl->PowerState > VideoPowerHibernate) 665 return ERROR_INVALID_FUNCTION; 666 667 if (VideoPowerControl->PowerState == VideoPowerHibernate) 668 return NO_ERROR; 669 670 /* 671 * Set current power state. 672 */ 673 674 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 675 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS; 676 BiosRegisters.Ebx = 1; 677 BiosRegisters.Edi = 0; 678 BiosRegisters.SegEs = 0; 679 switch (VideoPowerControl->PowerState) 680 { 681 case VideoPowerStandBy: BiosRegisters.Ebx |= 0x100; break; 682 case VideoPowerSuspend: BiosRegisters.Ebx |= 0x200; break; 683 case VideoPowerOff: BiosRegisters.Ebx |= 0x400; break; 684 } 685 686 VBEDeviceExtension->Int10Interface.Int10CallBios( 687 VBEDeviceExtension->Int10Interface.Context, 688 &BiosRegisters); 689 690 if (VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_NOT_SUPPORTED) 691 return ERROR_DEV_NOT_EXIST; 692 if (VBE_GETRETURNCODE(BiosRegisters.Eax) != VBE_SUCCESS) 693 return ERROR_INVALID_FUNCTION; 694 695 return VBE_SUCCESS; 696 } 697 698 /* 699 * VBESetCurrentMode 700 * 701 * Sets the adapter to the specified operating mode. 702 */ 703 704 BOOLEAN FASTCALL 705 VBESetCurrentMode( 706 PVBE_DEVICE_EXTENSION DeviceExtension, 707 PVIDEO_MODE RequestedMode, 708 PSTATUS_BLOCK StatusBlock) 709 { 710 INT10_BIOS_ARGUMENTS BiosRegisters; 711 712 if (RequestedMode->RequestedMode >= DeviceExtension->ModeCount) 713 { 714 return ERROR_INVALID_PARAMETER; 715 } 716 717 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 718 BiosRegisters.Eax = VBE_SET_VBE_MODE; 719 BiosRegisters.Ebx = DeviceExtension->ModeNumbers[RequestedMode->RequestedMode]; 720 DeviceExtension->Int10Interface.Int10CallBios( 721 DeviceExtension->Int10Interface.Context, 722 &BiosRegisters); 723 724 if (VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS) 725 { 726 DeviceExtension->CurrentMode = RequestedMode->RequestedMode; 727 } 728 else 729 { 730 VideoPortDebugPrint(Error, "VBEMP: VBESetCurrentMode failed (%x)\n", BiosRegisters.Eax); 731 DeviceExtension->CurrentMode = -1; 732 } 733 734 return VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS; 735 } 736 737 /* 738 * VBEResetDevice 739 * 740 * Resets the video hardware to the default mode, to which it was initialized 741 * at system boot. 742 */ 743 744 BOOLEAN FASTCALL 745 VBEResetDevice( 746 PVBE_DEVICE_EXTENSION DeviceExtension, 747 PSTATUS_BLOCK StatusBlock) 748 { 749 INT10_BIOS_ARGUMENTS BiosRegisters; 750 751 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 752 BiosRegisters.Eax = VBE_SET_VBE_MODE; 753 BiosRegisters.Ebx = 0x3; 754 DeviceExtension->Int10Interface.Int10CallBios( 755 DeviceExtension->Int10Interface.Context, 756 &BiosRegisters); 757 758 return VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS; 759 } 760 761 /* 762 * VBEMapVideoMemory 763 * 764 * Maps the video hardware frame buffer and video RAM into the virtual address 765 * space of the requestor. 766 */ 767 768 BOOLEAN FASTCALL 769 VBEMapVideoMemory( 770 PVBE_DEVICE_EXTENSION DeviceExtension, 771 PVIDEO_MEMORY RequestedAddress, 772 PVIDEO_MEMORY_INFORMATION MapInformation, 773 PSTATUS_BLOCK StatusBlock) 774 { 775 PHYSICAL_ADDRESS FrameBuffer; 776 ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY; 777 778 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION); 779 780 if (DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].ModeAttributes & 781 VBE_MODEATTR_LINEAR) 782 { 783 FrameBuffer.QuadPart = 784 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].PhysBasePtr; 785 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress; 786 if (DeviceExtension->VbeInfo.Version < 0x300) 787 { 788 MapInformation->VideoRamLength = 789 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].BytesPerScanLine * 790 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution; 791 } 792 else 793 { 794 MapInformation->VideoRamLength = 795 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].LinBytesPerScanLine * 796 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution; 797 } 798 } 799 #ifdef VBE12_SUPPORT 800 else 801 { 802 FrameBuffer.QuadPart = 0xA0000; 803 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress; 804 MapInformation->VideoRamLength = 0x10000; 805 } 806 #endif 807 808 VideoPortMapMemory(DeviceExtension, FrameBuffer, 809 &MapInformation->VideoRamLength, &inIoSpace, 810 &MapInformation->VideoRamBase); 811 812 MapInformation->FrameBufferBase = MapInformation->VideoRamBase; 813 MapInformation->FrameBufferLength = MapInformation->VideoRamLength; 814 815 return TRUE; 816 } 817 818 /* 819 * VBEUnmapVideoMemory 820 * 821 * Releases a mapping between the virtual address space and the adapter's 822 * frame buffer and video RAM. 823 */ 824 825 BOOLEAN FASTCALL 826 VBEUnmapVideoMemory( 827 PVBE_DEVICE_EXTENSION DeviceExtension, 828 PVIDEO_MEMORY VideoMemory, 829 PSTATUS_BLOCK StatusBlock) 830 { 831 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, 832 NULL); 833 return TRUE; 834 } 835 836 /* 837 * VBEQueryNumAvailModes 838 * 839 * Returns the number of video modes supported by the adapter and the size 840 * in bytes of the video mode information, which can be used to allocate a 841 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request. 842 */ 843 844 BOOLEAN FASTCALL 845 VBEQueryNumAvailModes( 846 PVBE_DEVICE_EXTENSION DeviceExtension, 847 PVIDEO_NUM_MODES Modes, 848 PSTATUS_BLOCK StatusBlock) 849 { 850 Modes->NumModes = DeviceExtension->ModeCount; 851 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION); 852 StatusBlock->Information = sizeof(VIDEO_NUM_MODES); 853 return TRUE; 854 } 855 856 /* 857 * VBEQueryMode 858 * 859 * Returns information about one particular video mode. 860 */ 861 862 VOID FASTCALL 863 VBEQueryMode( 864 PVBE_DEVICE_EXTENSION DeviceExtension, 865 PVIDEO_MODE_INFORMATION VideoMode, 866 ULONG VideoModeId) 867 { 868 PVBE_MODEINFO VBEMode = &DeviceExtension->ModeInfo[VideoModeId]; 869 ULONG dpi; 870 871 VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION); 872 VideoMode->ModeIndex = VideoModeId; 873 VideoMode->VisScreenWidth = VBEMode->XResolution; 874 VideoMode->VisScreenHeight = VBEMode->YResolution; 875 if (DeviceExtension->VbeInfo.Version < 0x300) 876 VideoMode->ScreenStride = VBEMode->BytesPerScanLine; 877 else 878 VideoMode->ScreenStride = VBEMode->LinBytesPerScanLine; 879 VideoMode->NumberOfPlanes = VBEMode->NumberOfPlanes; 880 VideoMode->BitsPerPlane = VBEMode->BitsPerPixel / VBEMode->NumberOfPlanes; 881 VideoMode->Frequency = 1; 882 883 /* Assume 96DPI and 25.4 millimeters per inch, round to nearest */ 884 dpi = 96; 885 VideoMode->XMillimeter = ((ULONGLONG)VBEMode->XResolution * 254 + (dpi * 5)) / (dpi * 10); 886 VideoMode->YMillimeter = ((ULONGLONG)VBEMode->YResolution * 254 + (dpi * 5)) / (dpi * 10); 887 888 if (VBEMode->BitsPerPixel > 8) 889 { 890 /* 891 * Always report 16bpp modes and not 15bpp mode... 892 */ 893 if (VBEMode->BitsPerPixel == 15 && VBEMode->NumberOfPlanes == 1) 894 { 895 VideoMode->BitsPerPlane = 16; 896 } 897 898 if (DeviceExtension->VbeInfo.Version < 0x300) 899 { 900 VideoMode->NumberRedBits = VBEMode->RedMaskSize; 901 VideoMode->NumberGreenBits = VBEMode->GreenMaskSize; 902 VideoMode->NumberBlueBits = VBEMode->BlueMaskSize; 903 VideoMode->RedMask = ((1 << VBEMode->RedMaskSize) - 1) << VBEMode->RedFieldPosition; 904 VideoMode->GreenMask = ((1 << VBEMode->GreenMaskSize) - 1) << VBEMode->GreenFieldPosition; 905 VideoMode->BlueMask = ((1 << VBEMode->BlueMaskSize) - 1) << VBEMode->BlueFieldPosition; 906 } 907 else 908 { 909 VideoMode->NumberRedBits = VBEMode->LinRedMaskSize; 910 VideoMode->NumberGreenBits = VBEMode->LinGreenMaskSize; 911 VideoMode->NumberBlueBits = VBEMode->LinBlueMaskSize; 912 VideoMode->RedMask = ((1 << VBEMode->LinRedMaskSize) - 1) << VBEMode->LinRedFieldPosition; 913 VideoMode->GreenMask = ((1 << VBEMode->LinGreenMaskSize) - 1) << VBEMode->LinGreenFieldPosition; 914 VideoMode->BlueMask = ((1 << VBEMode->LinBlueMaskSize) - 1) << VBEMode->LinBlueFieldPosition; 915 } 916 } 917 else 918 { 919 VideoMode->NumberRedBits = 920 VideoMode->NumberGreenBits = 921 VideoMode->NumberBlueBits = 6; 922 VideoMode->RedMask = 923 VideoMode->GreenMask = 924 VideoMode->BlueMask = 0; 925 } 926 VideoMode->VideoMemoryBitmapWidth = VBEMode->XResolution; 927 VideoMode->VideoMemoryBitmapHeight = VBEMode->YResolution; 928 VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | 929 VIDEO_MODE_NO_OFF_SCREEN; 930 if (VideoMode->BitsPerPlane <= 8) 931 VideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN; 932 VideoMode->DriverSpecificAttributeFlags = 0; 933 } 934 935 /* 936 * VBEQueryAvailModes 937 * 938 * Returns information about each video mode supported by the adapter. 939 */ 940 941 BOOLEAN FASTCALL 942 VBEQueryAvailModes( 943 PVBE_DEVICE_EXTENSION DeviceExtension, 944 PVIDEO_MODE_INFORMATION ReturnedModes, 945 PSTATUS_BLOCK StatusBlock) 946 { 947 ULONG CurrentModeId; 948 PVIDEO_MODE_INFORMATION CurrentMode; 949 PVBE_MODEINFO CurrentVBEMode; 950 951 for (CurrentModeId = 0, CurrentMode = ReturnedModes, 952 CurrentVBEMode = DeviceExtension->ModeInfo; 953 CurrentModeId < DeviceExtension->ModeCount; 954 CurrentModeId++, CurrentMode++, CurrentVBEMode++) 955 { 956 VBEQueryMode(DeviceExtension, CurrentMode, CurrentModeId); 957 } 958 959 StatusBlock->Information = 960 sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->ModeCount; 961 962 return TRUE; 963 } 964 965 /* 966 * VBEQueryCurrentMode 967 * 968 * Returns information about current video mode. 969 */ 970 971 BOOLEAN FASTCALL 972 VBEQueryCurrentMode( 973 PVBE_DEVICE_EXTENSION DeviceExtension, 974 PVIDEO_MODE_INFORMATION VideoModeInfo, 975 PSTATUS_BLOCK StatusBlock) 976 { 977 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION); 978 979 VBEQueryMode( 980 DeviceExtension, 981 VideoModeInfo, 982 DeviceExtension->CurrentMode); 983 984 return TRUE; 985 } 986 987 /* 988 * VBESetColorRegisters 989 * 990 * Sets the adapter's color registers to the specified RGB values. There 991 * are code paths in this function, one generic and one for VGA compatible 992 * controllers. The latter is needed for Bochs, where the generic one isn't 993 * yet implemented. 994 */ 995 996 BOOLEAN FASTCALL 997 VBESetColorRegisters( 998 PVBE_DEVICE_EXTENSION DeviceExtension, 999 PVIDEO_CLUT ColorLookUpTable, 1000 PSTATUS_BLOCK StatusBlock) 1001 { 1002 INT10_BIOS_ARGUMENTS BiosRegisters; 1003 ULONG Entry; 1004 PULONG OutputEntry; 1005 ULONG OutputBuffer[256]; 1006 1007 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256) 1008 return FALSE; 1009 1010 /* 1011 * For VGA compatible adapters program the color registers directly. 1012 */ 1013 1014 if (!(DeviceExtension->VbeInfo.Capabilities & 2)) 1015 { 1016 for (Entry = ColorLookUpTable->FirstEntry; 1017 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry; 1018 Entry++) 1019 { 1020 VideoPortWritePortUchar((PUCHAR)0x03c8, Entry); 1021 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red); 1022 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green); 1023 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue); 1024 } 1025 1026 return TRUE; 1027 } 1028 else 1029 { 1030 /* 1031 * We can't just copy the values, because we need to swap the Red 1032 * and Blue values. 1033 */ 1034 1035 for (Entry = ColorLookUpTable->FirstEntry, 1036 OutputEntry = OutputBuffer; 1037 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry; 1038 Entry++, OutputEntry++) 1039 { 1040 *OutputEntry = 1041 (ColorLookUpTable->LookupTable[Entry].RgbArray.Red << 16) | 1042 (ColorLookUpTable->LookupTable[Entry].RgbArray.Green << 8) | 1043 (ColorLookUpTable->LookupTable[Entry].RgbArray.Blue); 1044 } 1045 1046 DeviceExtension->Int10Interface.Int10WriteMemory( 1047 DeviceExtension->Int10Interface.Context, 1048 DeviceExtension->TrampolineMemorySegment, 1049 DeviceExtension->TrampolineMemoryOffset, 1050 OutputBuffer, 1051 (OutputEntry - OutputBuffer) * sizeof(ULONG)); 1052 1053 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 1054 BiosRegisters.Eax = VBE_SET_GET_PALETTE_DATA; 1055 BiosRegisters.Ebx = 0; 1056 BiosRegisters.Ecx = ColorLookUpTable->NumEntries; 1057 BiosRegisters.Edx = ColorLookUpTable->FirstEntry; 1058 BiosRegisters.Edi = DeviceExtension->TrampolineMemoryOffset; 1059 BiosRegisters.SegEs = DeviceExtension->TrampolineMemorySegment; 1060 DeviceExtension->Int10Interface.Int10CallBios( 1061 DeviceExtension->Int10Interface.Context, 1062 &BiosRegisters); 1063 1064 return VBE_GETRETURNCODE(BiosRegisters.Eax) == VBE_SUCCESS; 1065 } 1066 } 1067