1 /* 2 * PROJECT: ReactOS Bochs graphics card driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Bochs graphics card driver 5 * COPYRIGHT: Copyright 2022 Hervé Poussineau <hpoussin@reactos.org> 6 */ 7 8 #include "bochsmp.h" 9 10 static const BOCHS_SIZE BochsAvailableResolutions[] = { 11 { 640, 480 }, // VGA 12 { 800, 600 }, // SVGA 13 { 1024, 600 }, // WSVGA 14 { 1024, 768 }, // XGA 15 { 1152, 864 }, // XGA+ 16 { 1280, 720 }, // WXGA-H 17 { 1280, 768 }, // WXGA 18 { 1280, 960 }, // SXGA- 19 { 1280, 1024 }, // SXGA 20 { 1368, 768 }, // HD ready 21 { 1400, 1050 }, // SXGA+ 22 { 1440, 900 }, // WSXGA 23 { 1600, 900 }, // HD+ 24 { 1600, 1200 }, // UXGA 25 { 1680, 1050 }, // WSXGA+ 26 { 1920, 1080 }, // FHD 27 { 2048, 1536 }, // QXGA 28 { 2560, 1440 }, // WQHD 29 { 2560, 1600 }, // WQXGA 30 { 2560, 2048 }, // QSXGA 31 { 2800, 2100 }, // QSXGA+ 32 { 3200, 2400 }, // QUXGA 33 { 3840, 2160 }, // 4K UHD-1 34 }; 35 36 CODE_SEG("PAGE") 37 static VOID 38 BochsFreeResources( 39 _Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension) 40 { 41 if (DeviceExtension->AvailableModeInfo) 42 { 43 VideoPortFreePool(DeviceExtension, DeviceExtension->AvailableModeInfo); 44 DeviceExtension->AvailableModeInfo = NULL; 45 } 46 } 47 48 CODE_SEG("PAGE") 49 static VOID 50 BochsWriteDispI( 51 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 52 _In_ ULONG Index, 53 _In_ USHORT Value) 54 { 55 if (DeviceExtension->IoPorts.RangeInIoSpace) 56 { 57 VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_INDEX), Index); 58 VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_DATA), Value); 59 } 60 else 61 { 62 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x500 + Index * 2), Value); 63 } 64 } 65 66 CODE_SEG("PAGE") 67 static USHORT 68 BochsReadDispI( 69 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 70 _In_ ULONG Index) 71 { 72 if (DeviceExtension->IoPorts.RangeInIoSpace) 73 { 74 VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_INDEX), Index); 75 return VideoPortReadPortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_DATA)); 76 } 77 else 78 { 79 return VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x500 + Index * 2)); 80 } 81 } 82 83 CODE_SEG("PAGE") 84 static BOOLEAN 85 BochsWriteDispIAndCheck( 86 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 87 _In_ ULONG Index, 88 _In_ USHORT Value) 89 { 90 BochsWriteDispI(DeviceExtension, Index, Value); 91 return BochsReadDispI(DeviceExtension, Index) == Value; 92 } 93 94 CODE_SEG("PAGE") 95 static BOOLEAN 96 BochsInitializeSuitableModeInfo( 97 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 98 _In_ ULONG PotentialModeCount) 99 { 100 ULONG i, ModeCount = 0; 101 102 for (i = 0; i < ARRAYSIZE(BochsAvailableResolutions) && ModeCount < PotentialModeCount; i++) 103 { 104 if (BochsAvailableResolutions[i].XResolution > DeviceExtension->MaxXResolution) 105 continue; 106 if (BochsAvailableResolutions[i].YResolution > DeviceExtension->MaxYResolution) 107 continue; 108 if (BochsAvailableResolutions[i].XResolution * BochsAvailableResolutions[i].YResolution * 4 > DeviceExtension->VramSize64K * 64 * 1024) 109 continue; 110 DeviceExtension->AvailableModeInfo[ModeCount++] = BochsAvailableResolutions[i]; 111 } 112 113 if (ModeCount == 0) 114 { 115 VideoDebugPrint((Error, "Bochs: no suitable modes available!\n")); 116 return FALSE; 117 } 118 119 DeviceExtension->AvailableModeCount = ModeCount; 120 return TRUE; 121 } 122 123 CODE_SEG("PAGE") 124 static BOOLEAN 125 BochsGetControllerInfo( 126 _Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension) 127 { 128 USHORT Version; 129 WCHAR ChipType[5]; 130 ULONG SizeInBytes; 131 132 /* Detect DISPI version */ 133 for (Version = VBE_DISPI_ID5; Version >= VBE_DISPI_ID0; Version--) 134 { 135 if (BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_ID, Version)) 136 break; 137 } 138 if (Version < VBE_DISPI_ID0) 139 { 140 VideoDebugPrint((Error, "Bochs: VBE extension signature incorrect\n")); 141 return FALSE; 142 } 143 VideoDebugPrint((Error, "Bochs: detected version 0x%04x\n", Version)); 144 if (Version < VBE_DISPI_ID2) 145 { 146 /* Too old (no 32 bpp support, no linear frame buffer) */ 147 VideoDebugPrint((Error, "Bochs: VBE extension too old (0x%04x)\n", Version)); 148 return FALSE; 149 } 150 151 if (Version <= VBE_DISPI_ID2) 152 { 153 DeviceExtension->MaxXResolution = 1024; 154 DeviceExtension->MaxYResolution = 768; 155 } 156 else 157 { 158 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_GETCAPS); 159 DeviceExtension->MaxXResolution = BochsReadDispI(DeviceExtension, VBE_DISPI_INDEX_XRES); 160 DeviceExtension->MaxYResolution = BochsReadDispI(DeviceExtension, VBE_DISPI_INDEX_YRES); 161 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); 162 /* Workaround bug in QEMU bochs-display */ 163 if (DeviceExtension->MaxXResolution == 0 && DeviceExtension->MaxYResolution == 0) 164 { 165 DeviceExtension->MaxXResolution = 1024; 166 DeviceExtension->MaxYResolution = 768; 167 } 168 } 169 if (Version < VBE_DISPI_ID4) 170 { 171 DeviceExtension->VramSize64K = 4 * 1024 / 64; /* 4 MB */ 172 } 173 else if (Version == VBE_DISPI_ID4) 174 { 175 DeviceExtension->VramSize64K = 8 * 1024 / 64; /* 8 MB */ 176 } 177 else 178 { 179 DeviceExtension->VramSize64K = BochsReadDispI(DeviceExtension, VBE_DISPI_INDEX_VIDEO_MEMORY_64K); 180 } 181 VideoDebugPrint((Info, "Bochs: capabilities %dx%d (%d MB)\n", 182 DeviceExtension->MaxXResolution, 183 DeviceExtension->MaxYResolution, 184 DeviceExtension->VramSize64K * 64 / 1024)); 185 186 /* Store information in registry */ 187 #define HEX(c) (((c) >= 0 && (c) <= 9) ? (c) + L'0' : (c) - 10 + L'A') 188 ChipType[0] = HEX((Version >> 12) & 0xf); 189 ChipType[1] = HEX((Version >> 8) & 0xf); 190 ChipType[2] = HEX((Version >> 4) & 0xf); 191 ChipType[3] = HEX(Version & 0xf); 192 ChipType[4] = UNICODE_NULL; 193 VideoPortSetRegistryParameters(DeviceExtension, L"HardwareInformation.ChipType", ChipType, sizeof(ChipType)); 194 SizeInBytes = DeviceExtension->VramSize64K * 64 * 1024; 195 VideoPortSetRegistryParameters(DeviceExtension, L"HardwareInformation.MemorySize", &SizeInBytes, sizeof(SizeInBytes)); 196 return TRUE; 197 } 198 199 CODE_SEG("PAGE") 200 static VOID 201 BochsGetModeInfo( 202 _In_ PBOCHS_SIZE AvailableModeInfo, 203 _Out_ PVIDEO_MODE_INFORMATION ModeInfo, 204 _In_ ULONG Index) 205 { 206 VideoDebugPrint((Info, "Bochs: Filling details of mode #%d\n", Index)); 207 208 ModeInfo->Length = sizeof(*ModeInfo); 209 ModeInfo->ModeIndex = Index; 210 ModeInfo->VisScreenWidth = AvailableModeInfo->XResolution; 211 ModeInfo->VisScreenHeight = AvailableModeInfo->YResolution; 212 ModeInfo->ScreenStride = AvailableModeInfo->XResolution * 4; 213 ModeInfo->NumberOfPlanes = 1; 214 ModeInfo->BitsPerPlane = 32; 215 ModeInfo->Frequency = 60; 216 217 /* 960 DPI appears to be common */ 218 ModeInfo->XMillimeter = AvailableModeInfo->XResolution * 254 / 960; 219 ModeInfo->YMillimeter = AvailableModeInfo->YResolution * 254 / 960; 220 ModeInfo->NumberRedBits = 8; 221 ModeInfo->NumberGreenBits = 8; 222 ModeInfo->NumberBlueBits = 8; 223 ModeInfo->RedMask = 0xff0000; 224 ModeInfo->GreenMask = 0x00ff00; 225 ModeInfo->BlueMask = 0x0000ff; 226 227 ModeInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN; 228 ModeInfo->VideoMemoryBitmapWidth = AvailableModeInfo->XResolution; 229 ModeInfo->VideoMemoryBitmapHeight = AvailableModeInfo->YResolution; 230 } 231 232 CODE_SEG("PAGE") 233 static BOOLEAN 234 BochsMapVideoMemory( 235 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 236 _In_ PVIDEO_MEMORY RequestedAddress, 237 _Out_ PVIDEO_MEMORY_INFORMATION MapInformation, 238 _Out_ PSTATUS_BLOCK StatusBlock) 239 { 240 VP_STATUS Status; 241 PHYSICAL_ADDRESS VideoMemory; 242 ULONG MemSpace = VIDEO_MEMORY_SPACE_MEMORY; 243 244 VideoDebugPrint((Info, "Bochs: BochsMapVideoMemory Entry\n")); 245 246 VideoMemory = DeviceExtension->FrameBuffer.RangeStart; 247 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress; 248 MapInformation->VideoRamLength = 4 * 249 DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode].XResolution * 250 DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode].YResolution; 251 252 Status = VideoPortMapMemory(DeviceExtension, 253 VideoMemory, 254 &MapInformation->VideoRamLength, 255 &MemSpace, 256 &MapInformation->VideoRamBase); 257 if (Status != NO_ERROR) 258 { 259 VideoDebugPrint((Error, "BochsMapVideoMemory - VideoPortMapMemory failed status:%x\n", Status)); 260 StatusBlock->Status = Status; 261 return FALSE; 262 } 263 264 MapInformation->FrameBufferBase = MapInformation->VideoRamBase; 265 MapInformation->FrameBufferLength = MapInformation->VideoRamLength; 266 StatusBlock->Information = sizeof(*MapInformation); 267 StatusBlock->Status = NO_ERROR; 268 269 VideoDebugPrint((Info, "Bochs:BochsMapVideoMemory Exit VideoRamBase: %p VideoRamLength: 0x%x PhysBasePtr: 0x%x\n", 270 MapInformation->VideoRamBase, MapInformation->VideoRamLength, (ULONG)VideoMemory.QuadPart)); 271 return TRUE; 272 } 273 274 CODE_SEG("PAGE") 275 static BOOLEAN NTAPI 276 BochsUnmapVideoMemory( 277 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 278 _In_ PVIDEO_MEMORY VideoMemory, 279 _Out_ PSTATUS_BLOCK StatusBlock) 280 { 281 VP_STATUS Status; 282 283 VideoDebugPrint((Info, "Bochs: BochsUnmapVideoMemory Entry VideoRamBase:%p\n", VideoMemory->RequestedVirtualAddress)); 284 285 Status = VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL); 286 if (Status != NO_ERROR) 287 { 288 VideoDebugPrint((Error, "Bochs: BochsUnmapVideoMemory Failed to unmap memory:%p Status:%x\n", 289 VideoMemory->RequestedVirtualAddress, 290 Status)); 291 } 292 293 StatusBlock->Status = Status; 294 295 VideoDebugPrint((Info, "Bochs: BochsUnmapVideoMemory Exit status:%x\n", Status)); 296 return (Status == NO_ERROR); 297 } 298 299 CODE_SEG("PAGE") 300 static BOOLEAN 301 BochsQueryNumAvailableModes( 302 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 303 _Out_ PVIDEO_NUM_MODES AvailableModes, 304 _Out_ PSTATUS_BLOCK StatusBlock) 305 { 306 AvailableModes->NumModes = DeviceExtension->AvailableModeCount; 307 AvailableModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION); 308 309 StatusBlock->Information = sizeof(*AvailableModes); 310 StatusBlock->Status = NO_ERROR; 311 return TRUE; 312 } 313 314 CODE_SEG("PAGE") 315 static BOOLEAN 316 BochsQueryAvailableModes( 317 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 318 _Out_ PVIDEO_MODE_INFORMATION ReturnedModes, 319 _Out_ PSTATUS_BLOCK StatusBlock) 320 { 321 ULONG Count; 322 PBOCHS_SIZE AvailableModeInfo; 323 PVIDEO_MODE_INFORMATION ModeInfo; 324 325 for (Count = 0, AvailableModeInfo = DeviceExtension->AvailableModeInfo, ModeInfo = ReturnedModes; 326 Count < DeviceExtension->AvailableModeCount; 327 Count++, AvailableModeInfo++, ModeInfo++) 328 { 329 VideoPortZeroMemory(ModeInfo, sizeof(*ModeInfo)); 330 BochsGetModeInfo(AvailableModeInfo, ModeInfo, Count); 331 } 332 333 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->AvailableModeCount; 334 StatusBlock->Status = NO_ERROR; 335 336 return TRUE; 337 } 338 339 CODE_SEG("PAGE") 340 static BOOLEAN 341 BochsSetCurrentMode( 342 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 343 _In_ PVIDEO_MODE RequestedMode, 344 _Out_ PSTATUS_BLOCK StatusBlock) 345 { 346 PBOCHS_SIZE AvailableModeInfo; 347 /* Mask the two high-order bits, which can be set to request special behavior */ 348 ULONG ModeRequested = RequestedMode->RequestedMode & 0x3fffffff; 349 BOOLEAN Ret; 350 351 VideoDebugPrint((Info, "Bochs:BochsSetCurrentMode Entry\n")); 352 353 if (ModeRequested >= DeviceExtension->AvailableModeCount) 354 { 355 VideoDebugPrint((Error, "Bochs: set current mode - invalid parameter\n")); 356 StatusBlock->Status = ERROR_INVALID_PARAMETER; 357 return FALSE; 358 } 359 360 AvailableModeInfo = &DeviceExtension->AvailableModeInfo[ModeRequested]; 361 362 /* Set the mode characteristics */ 363 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); 364 Ret = BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_XRES, AvailableModeInfo->XResolution) && 365 BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_YRES, AvailableModeInfo->YResolution) && 366 BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_BPP, 32); 367 /* Always enable screen, even if display settings change failed */ 368 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_LFB_ENABLED | VBE_DISPI_ENABLED); 369 if (!Ret) 370 { 371 VideoDebugPrint((Error, "Bochs: failed to change mode\n")); 372 return FALSE; 373 } 374 375 /* Enable VGA (QEMU secondary-vga disables it by default) */ 376 if (!DeviceExtension->IoPorts.RangeInIoSpace) 377 { 378 /* Discard AR flip-flip */ 379 (VOID)VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x41A)); 380 /* Enable display */ 381 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x400), 0x20); 382 } 383 384 DeviceExtension->CurrentMode = (USHORT)ModeRequested; 385 StatusBlock->Status = NO_ERROR; 386 387 VideoDebugPrint((Info, "Bochs:BochsSetCurrentMode Exit Mode:%d\n", ModeRequested)); 388 return TRUE; 389 } 390 391 CODE_SEG("PAGE") 392 static BOOLEAN 393 BochsQueryCurrentMode( 394 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 395 _Out_ PVIDEO_MODE_INFORMATION VideoModeInfo, 396 _Out_ PSTATUS_BLOCK StatusBlock) 397 { 398 PBOCHS_SIZE AvailableModeInfo; 399 400 if (DeviceExtension->CurrentMode > DeviceExtension->AvailableModeCount) 401 { 402 StatusBlock->Status = ERROR_INVALID_PARAMETER; 403 return FALSE; 404 } 405 406 AvailableModeInfo = &DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode]; 407 VideoPortZeroMemory(VideoModeInfo, sizeof(*VideoModeInfo)); 408 BochsGetModeInfo(AvailableModeInfo, VideoModeInfo, DeviceExtension->CurrentMode); 409 410 StatusBlock->Information = sizeof(*VideoModeInfo); 411 StatusBlock->Status = NO_ERROR; 412 return TRUE; 413 } 414 415 CODE_SEG("PAGE") 416 static BOOLEAN 417 BochsResetDevice( 418 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 419 _Out_ PSTATUS_BLOCK StatusBlock) 420 { 421 VideoDebugPrint((Info, "Bochs:BochsResetDevice Entry\n")); 422 423 StatusBlock->Status = NO_ERROR; 424 425 VideoDebugPrint((Info, "Bochs:BochsResetDevice Exit\n")); 426 return TRUE; 427 } 428 429 CODE_SEG("PAGE") 430 static BOOLEAN 431 BochsGetChildState( 432 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension, 433 _Out_ PULONG pChildState, 434 _Out_ PSTATUS_BLOCK StatusBlock) 435 { 436 *pChildState = VIDEO_CHILD_ACTIVE; 437 438 StatusBlock->Information = sizeof(*pChildState); 439 StatusBlock->Status = NO_ERROR; 440 return TRUE; 441 } 442 443 CODE_SEG("PAGE") 444 VP_STATUS NTAPI 445 BochsFindAdapter( 446 _In_ PVOID HwDeviceExtension, 447 _In_ PVOID HwContext, 448 _In_ PWSTR ArgumentString, 449 _In_ PVIDEO_PORT_CONFIG_INFO ConfigInfo, 450 _In_ PUCHAR Again) 451 { 452 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension; 453 VIDEO_ACCESS_RANGE AccessRanges[2] = {0}; 454 455 if (ConfigInfo->Length < sizeof(*ConfigInfo)) 456 return ERROR_INVALID_PARAMETER; 457 458 if (VideoPortGetAccessRanges(DeviceExtension, 0, NULL, ARRAYSIZE(AccessRanges), AccessRanges, NULL, NULL, NULL) != NO_ERROR) 459 { 460 VideoDebugPrint((Error, "Bochs: failed to get access ranges\n")); 461 return ERROR_DEV_NOT_EXIST; 462 } 463 464 /* Framebuffer */ 465 DeviceExtension->FrameBuffer.RangeStart = AccessRanges[0].RangeStart; 466 DeviceExtension->FrameBuffer.RangeLength = AccessRanges[0].RangeLength; 467 DeviceExtension->FrameBuffer.RangeInIoSpace = AccessRanges[0].RangeInIoSpace; 468 469 /* I/O ports */ 470 if (AccessRanges[1].RangeLength == 0) 471 { 472 /* Set default values */ 473 AccessRanges[1].RangeStart.LowPart = VBE_DISPI_IOPORT_INDEX; 474 AccessRanges[1].RangeLength = 2; 475 AccessRanges[1].RangeInIoSpace = TRUE; 476 if (VideoPortVerifyAccessRanges(DeviceExtension, 1, &AccessRanges[1]) != NO_ERROR) 477 { 478 VideoDebugPrint((Error, "Bochs: failed to claim I/O range 0x%x-0x%x\n", 479 VBE_DISPI_IOPORT_INDEX, 480 VBE_DISPI_IOPORT_INDEX + 1)); 481 return ERROR_DEV_NOT_EXIST; 482 } 483 } 484 else if (AccessRanges[1].RangeLength != 0x1000) 485 { 486 VideoDebugPrint((Error, "Bochs: invalid access ranges (size 0x%x)\n", AccessRanges[1].RangeLength)); 487 return ERROR_DEV_NOT_EXIST; 488 } 489 DeviceExtension->IoPorts.RangeStart = AccessRanges[1].RangeStart; 490 DeviceExtension->IoPorts.RangeLength = AccessRanges[1].RangeLength; 491 DeviceExtension->IoPorts.RangeInIoSpace = AccessRanges[1].RangeInIoSpace; 492 493 DeviceExtension->IoPorts.Mapped = VideoPortGetDeviceBase(DeviceExtension, 494 DeviceExtension->IoPorts.RangeStart, 495 DeviceExtension->IoPorts.RangeLength, 496 DeviceExtension->IoPorts.RangeInIoSpace 497 ? VIDEO_MEMORY_SPACE_IO 498 : VIDEO_MEMORY_SPACE_MEMORY); 499 if (!DeviceExtension->IoPorts.Mapped) 500 { 501 VideoDebugPrint((Error, "Bochs: failed to map dispi interface\n")); 502 return ERROR_DEV_NOT_EXIST; 503 } 504 VideoDebugPrint((Info, "Bochs: address 0x%x mapped to 0x%p\n", 505 DeviceExtension->IoPorts.RangeStart.LowPart, 506 DeviceExtension->IoPorts.Mapped)); 507 508 return NO_ERROR; 509 } 510 511 CODE_SEG("PAGE") 512 BOOLEAN NTAPI 513 BochsInitialize( 514 _In_ PVOID HwDeviceExtension) 515 { 516 ULONG PotentialModeCount = 0; 517 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension; 518 519 VideoDebugPrint((Info, "Bochs: BochsInitialize\n")); 520 521 if (!BochsGetControllerInfo(DeviceExtension)) 522 { 523 BochsFreeResources(DeviceExtension); 524 return FALSE; 525 } 526 527 PotentialModeCount = ARRAYSIZE(BochsAvailableResolutions); 528 DeviceExtension->AvailableModeInfo = VideoPortAllocatePool(HwDeviceExtension, 529 VpPagedPool, 530 PotentialModeCount * sizeof(BOCHS_SIZE), 531 BOCHS_TAG); 532 if (!DeviceExtension->AvailableModeInfo) 533 { 534 VideoDebugPrint((Error, "Bochs: insufficient resources\n")); 535 BochsFreeResources(DeviceExtension); 536 return FALSE; 537 } 538 539 if (!BochsInitializeSuitableModeInfo(DeviceExtension, PotentialModeCount)) 540 { 541 BochsFreeResources(DeviceExtension); 542 return FALSE; 543 } 544 545 return TRUE; 546 } 547 548 CODE_SEG("PAGE") 549 BOOLEAN NTAPI 550 BochsStartIO( 551 _In_ PVOID HwDeviceExtension, 552 _Inout_ PVIDEO_REQUEST_PACKET RequestPacket) 553 { 554 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension; 555 556 VideoDebugPrint((Info, "Bochs: BochsStartIO\n")); 557 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION; 558 559 switch (RequestPacket->IoControlCode) 560 { 561 case IOCTL_VIDEO_MAP_VIDEO_MEMORY: 562 { 563 VideoDebugPrint((Info, "BochsStartIO - Map video memory\n")); 564 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) 565 { 566 VideoDebugPrint((Error, "BochsStartIO - invalid input parameter\n")); 567 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 568 return FALSE; 569 } 570 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION)) 571 { 572 VideoDebugPrint((Error, "BochsStartIO - Insufficent output buffer\n")); 573 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 574 return FALSE; 575 } 576 return BochsMapVideoMemory(DeviceExtension, 577 (PVIDEO_MEMORY)RequestPacket->InputBuffer, 578 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer, 579 RequestPacket->StatusBlock); 580 } 581 582 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: 583 { 584 VideoDebugPrint((Info, "BochsStartIO - Unmap video memory\n")); 585 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) 586 { 587 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 588 return FALSE; 589 } 590 return BochsUnmapVideoMemory(DeviceExtension, 591 (PVIDEO_MEMORY)RequestPacket->InputBuffer, 592 RequestPacket->StatusBlock); 593 } 594 595 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES: 596 { 597 VideoDebugPrint((Info, "BochsStartIO - Query num available modes\n")); 598 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES)) 599 { 600 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 601 return FALSE; 602 } 603 return BochsQueryNumAvailableModes(DeviceExtension, 604 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer, 605 RequestPacket->StatusBlock); 606 } 607 608 case IOCTL_VIDEO_QUERY_AVAIL_MODES: 609 { 610 VideoDebugPrint((Info, "BochsStartIO - Query available modes\n")); 611 if (RequestPacket->OutputBufferLength < DeviceExtension->AvailableModeCount * sizeof(VIDEO_MODE_INFORMATION)) 612 { 613 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 614 return FALSE; 615 } 616 return BochsQueryAvailableModes(DeviceExtension, 617 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer, 618 RequestPacket->StatusBlock); 619 } 620 621 case IOCTL_VIDEO_SET_CURRENT_MODE: 622 { 623 VideoDebugPrint((Info, "BochsStartIO - Set current mode\n")); 624 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) 625 { 626 VideoDebugPrint((Error, "Bochs: set current mode - invalid parameter\n")); 627 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 628 return FALSE; 629 } 630 return BochsSetCurrentMode(DeviceExtension, 631 (PVIDEO_MODE)RequestPacket->InputBuffer, 632 RequestPacket->StatusBlock); 633 } 634 635 case IOCTL_VIDEO_QUERY_CURRENT_MODE: 636 { 637 VideoDebugPrint((Info, "BochsStartIO - Query current mode\n")); 638 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION)) 639 { 640 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 641 return FALSE; 642 } 643 return BochsQueryCurrentMode(DeviceExtension, 644 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer, 645 RequestPacket->StatusBlock); 646 } 647 648 case IOCTL_VIDEO_RESET_DEVICE: 649 { 650 VideoDebugPrint((Info, "BochsStartIO - Reset device\n")); 651 return BochsResetDevice(DeviceExtension, 652 RequestPacket->StatusBlock); 653 } 654 655 case IOCTL_VIDEO_GET_CHILD_STATE: 656 { 657 VideoDebugPrint((Info, "BochsStartIO - Get child state\n")); 658 if (RequestPacket->OutputBufferLength < sizeof(ULONG)) 659 { 660 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER; 661 return FALSE; 662 } 663 return BochsGetChildState(DeviceExtension, 664 (PULONG)RequestPacket->OutputBuffer, 665 RequestPacket->StatusBlock); 666 } 667 668 default: 669 { 670 VideoDebugPrint((Warn, "BochsStartIO - Unknown IOCTL - 0x%08x\n", 671 RequestPacket->IoControlCode)); 672 break; 673 } 674 } 675 676 return FALSE; 677 } 678 679 CODE_SEG("PAGE") 680 VP_STATUS NTAPI 681 BochsSetPowerState( 682 _In_ PVOID HwDeviceExtension, 683 _In_ ULONG HwId, 684 _In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl) 685 { 686 return NO_ERROR; 687 } 688 689 CODE_SEG("PAGE") 690 VP_STATUS NTAPI 691 BochsGetPowerState( 692 _In_ PVOID HwDeviceExtension, 693 _In_ ULONG HwId, 694 _Out_ PVIDEO_POWER_MANAGEMENT VideoPowerControl) 695 { 696 return ERROR_DEVICE_REINITIALIZATION_NEEDED; 697 } 698 699 CODE_SEG("PAGE") 700 VP_STATUS NTAPI 701 BochsGetVideoChildDescriptor( 702 _In_ PVOID HwDeviceExtension, 703 _In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, 704 _Out_ PVIDEO_CHILD_TYPE VideoChildType, 705 _Out_ PUCHAR pChildDescriptor, 706 _Out_ PULONG UId, 707 _Out_ PULONG pUnused) 708 { 709 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension; 710 711 VideoDebugPrint((Info, "Bochs: BochsGetVideoChildDescriptor Entry\n")); 712 713 if (ChildEnumInfo->Size < sizeof(*VideoChildType)) 714 return VIDEO_ENUM_NO_MORE_DEVICES; 715 716 if (ChildEnumInfo->ChildIndex == 0) 717 { 718 /* Ignore ACPI enumerations */ 719 return VIDEO_ENUM_INVALID_DEVICE; 720 } 721 722 *pUnused = 0; 723 if (ChildEnumInfo->ChildIndex == DISPLAY_ADAPTER_HW_ID) 724 { 725 *VideoChildType = VideoChip; 726 return VIDEO_ENUM_MORE_DEVICES; 727 } 728 729 if (ChildEnumInfo->ChildIndex != 1) 730 return VIDEO_ENUM_NO_MORE_DEVICES; 731 732 *UId = 0; 733 *VideoChildType = Monitor; 734 735 if (pChildDescriptor && 736 ChildEnumInfo->ChildDescriptorSize >= VBE_EDID_SIZE && 737 !DeviceExtension->IoPorts.RangeInIoSpace) 738 { 739 memcpy(pChildDescriptor, 740 DeviceExtension->IoPorts.Mapped, 741 VBE_EDID_SIZE); 742 } 743 744 VideoDebugPrint((Info, "Bochs: BochsGetVideoChildDescriptor Exit Uid:%d\n", ChildEnumInfo->ChildIndex)); 745 746 return VIDEO_ENUM_MORE_DEVICES; 747 } 748 749 ULONG NTAPI 750 DriverEntry(PVOID Context1, PVOID Context2) 751 { 752 VIDEO_HW_INITIALIZATION_DATA VideoInitData; 753 754 VideoDebugPrint((Info, "Bochs: DriverEntry\n")); 755 VideoPortZeroMemory(&VideoInitData, sizeof(VideoInitData)); 756 VideoInitData.HwInitDataSize = sizeof(VideoInitData); 757 VideoInitData.HwFindAdapter = BochsFindAdapter; 758 VideoInitData.HwInitialize = BochsInitialize; 759 VideoInitData.HwStartIO = BochsStartIO; 760 VideoInitData.HwDeviceExtensionSize = sizeof(BOCHS_DEVICE_EXTENSION); 761 VideoInitData.HwSetPowerState = BochsSetPowerState; 762 VideoInitData.HwGetPowerState = BochsGetPowerState; 763 VideoInitData.HwGetVideoChildDescriptor = BochsGetVideoChildDescriptor; 764 765 return VideoPortInitialize(Context1, Context2, &VideoInitData, NULL); 766 } 767