1 /* 2 * PROJECT: ReactOS VGA Miniport Driver 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: win32ss/drivers/miniport/vga_new/vbemodes.c 5 * PURPOSE: Mode Initialization and Mode Set for VBE-compatible cards 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "vga.h" 12 13 /* FUNCTIONS ******************************************************************/ 14 15 ULONG 16 NTAPI 17 RaiseToPower2Ulong(IN ULONG Value) 18 { 19 ULONG SquaredResult = Value; 20 if ((Value - 1) & Value) for (SquaredResult = 1; (SquaredResult < Value) && (SquaredResult); SquaredResult *= 2); 21 return SquaredResult; 22 } 23 24 ULONG 25 NTAPI 26 RaiseToPower2(IN USHORT Value) 27 { 28 ULONG SquaredResult = Value; 29 if ((Value - 1) & Value) for (SquaredResult = 1; (SquaredResult < Value) && (SquaredResult); SquaredResult *= 2); 30 return SquaredResult; 31 } 32 33 ULONG 34 NTAPI 35 VbeGetVideoMemoryBaseAddress(IN PHW_DEVICE_EXTENSION VgaExtension, 36 IN PVIDEOMODE VgaMode) 37 { 38 ULONG Length = 4 * 1024; 39 USHORT TrampolineMemorySegment, TrampolineMemoryOffset; 40 PVOID Context; 41 INT10_BIOS_ARGUMENTS BiosArguments; 42 PVBE_MODE_INFO VbeModeInfo; 43 ULONG BaseAddress; 44 VP_STATUS Status; 45 46 /* Need linear and INT10 interface */ 47 if (!(VgaMode->fbType & VIDEO_MODE_BANKED)) return 0; 48 if (VgaExtension->Int10Interface.Size) return 0; 49 50 /* Allocate scratch area and context */ 51 VbeModeInfo = VideoPortAllocatePool(VgaExtension, 1, sizeof(VBE_MODE_INFO), ' agV'); 52 if (!VbeModeInfo) return 0; 53 Context = VgaExtension->Int10Interface.Context; 54 Status = VgaExtension->Int10Interface.Int10AllocateBuffer(Context, 55 &TrampolineMemorySegment, 56 &TrampolineMemoryOffset, 57 &Length); 58 if (Status != NO_ERROR) return 0; 59 60 /* Ask VBE BIOS for mode info */ 61 VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments)); 62 BiosArguments.Ecx = HIWORD(VgaMode->Mode); 63 BiosArguments.Edi = TrampolineMemorySegment; 64 BiosArguments.SegEs = TrampolineMemoryOffset; 65 BiosArguments.Eax = VBE_GET_MODE_INFORMATION; 66 Status = VgaExtension->Int10Interface.Int10CallBios(Context, &BiosArguments); 67 if (Status != NO_ERROR) return 0; 68 if (VBE_GETRETURNCODE(BiosArguments.Eax) != VBE_SUCCESS) 69 return 0; 70 Status = VgaExtension->Int10Interface.Int10ReadMemory(Context, 71 TrampolineMemorySegment, 72 TrampolineMemoryOffset, 73 VbeModeInfo, 74 sizeof(VBE_MODE_INFO)); 75 if (Status != NO_ERROR) return 0; 76 77 /* Return phys address and cleanup */ 78 BaseAddress = VbeModeInfo->PhysBasePtr; 79 VgaExtension->Int10Interface.Int10FreeBuffer(Context, 80 TrampolineMemorySegment, 81 TrampolineMemoryOffset); 82 VideoPortFreePool(VgaExtension, VbeModeInfo); 83 return BaseAddress; 84 } 85 86 VP_STATUS 87 NTAPI 88 VbeSetMode(IN PHW_DEVICE_EXTENSION VgaDeviceExtension, 89 IN PVIDEOMODE VgaMode, 90 OUT PULONG PhysPtrChange) 91 { 92 VP_STATUS Status; 93 VIDEO_X86_BIOS_ARGUMENTS BiosArguments; 94 ULONG ModeIndex; 95 ULONG BaseAddress; 96 97 VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments)); 98 ModeIndex = VgaMode->Mode; 99 BiosArguments.Eax = VBE_SET_VBE_MODE; 100 BiosArguments.Ebx = HIWORD(ModeIndex); 101 VideoDebugPrint((0, "Switching to %lx %lx\n", BiosArguments.Eax, BiosArguments.Ebx)); 102 Status = VideoPortInt10(VgaDeviceExtension, &BiosArguments); 103 if (Status != NO_ERROR) return Status; 104 if(VBE_GETRETURNCODE(BiosArguments.Eax) != VBE_SUCCESS) 105 { 106 VideoDebugPrint((0, "Changing VBE mode failed, Eax %lx", BiosArguments.Eax)); 107 return ERROR_INVALID_PARAMETER; 108 } 109 110 /* Check for VESA mode */ 111 if (ModeIndex >> 16) 112 { 113 /* Mode set fail */ 114 if (VBE_GETRETURNCODE(BiosArguments.Eax) != VBE_SUCCESS) 115 return ERROR_INVALID_PARAMETER; 116 117 /* Check current mode is desired mode */ 118 VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments)); 119 BiosArguments.Eax = VBE_GET_CURRENT_VBE_MODE; 120 Status = VideoPortInt10(VgaDeviceExtension, &BiosArguments); 121 if ((Status == NO_ERROR) && 122 (VBE_GETRETURNCODE(BiosArguments.Eax) == VBE_SUCCESS) && 123 ((BiosArguments.Ebx ^ (ModeIndex >> 16)) & VBE_MODE_BITS)) 124 { 125 return ERROR_INVALID_PARAMETER; 126 } 127 128 /* Set logical scanline width if different from physical */ 129 if (VgaMode->LogicalWidth != VgaMode->hres) 130 { 131 /* Check setting works after being set */ 132 VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments)); 133 BiosArguments.Eax = VBE_SET_GET_LOGICAL_SCAN_LINE_LENGTH; 134 BiosArguments.Ecx = VgaMode->LogicalWidth; 135 BiosArguments.Ebx = 0; 136 Status = VideoPortInt10(VgaDeviceExtension, &BiosArguments); 137 if ((Status != NO_ERROR) || 138 (VBE_GETRETURNCODE(BiosArguments.Eax) != VBE_SUCCESS) || 139 (BiosArguments.Ecx != VgaMode->LogicalWidth)) 140 { 141 return ERROR_INVALID_PARAMETER; 142 } 143 } 144 } 145 146 /* Get VRAM address to update changes */ 147 BaseAddress = VbeGetVideoMemoryBaseAddress(VgaDeviceExtension, VgaMode); 148 if ((BaseAddress) && (VgaMode->PhysBase != BaseAddress)) 149 { 150 *PhysPtrChange = TRUE; 151 VgaMode->PhysBase = BaseAddress; 152 } 153 154 return NO_ERROR; 155 } 156 157 VOID 158 NTAPI 159 InitializeModeTable(IN PHW_DEVICE_EXTENSION VgaExtension) 160 { 161 ULONG ModeCount = 0; 162 ULONG Length = 4 * 1024; 163 ULONG TotalMemory; 164 VP_STATUS Status; 165 INT10_BIOS_ARGUMENTS BiosArguments; 166 PVBE_INFO VbeInfo; 167 PVBE_MODE_INFO VbeModeInfo; 168 PVOID Context; 169 USHORT TrampolineMemorySegment; 170 USHORT TrampolineMemoryOffset; 171 ULONG VbeVersion; 172 ULONG NewModes = 0; 173 BOOLEAN FourBppModeFound = FALSE; 174 USHORT ModeResult; 175 USHORT Mode; 176 PUSHORT ThisMode; 177 BOOLEAN LinearAddressing; 178 ULONG Size, ScreenSize; 179 PVIDEOMODE VgaMode; 180 PVOID BaseAddress; 181 ULONG ScreenStride; 182 PHYSICAL_ADDRESS PhysicalAddress; 183 184 /* Enable only default vga modes if no vesa */ 185 VgaModeList = ModesVGA; 186 if (VideoPortIsNoVesa()) 187 { 188 VgaExtension->Int10Interface.Size = 0; 189 VgaExtension->Int10Interface.Version = 0; 190 return; 191 } 192 193 /* Query INT10 interface */ 194 VgaExtension->Int10Interface.Version = VIDEO_PORT_INT10_INTERFACE_VERSION_1; 195 VgaExtension->Int10Interface.Size = sizeof(VIDEO_PORT_INT10_INTERFACE); 196 if (VideoPortQueryServices(VgaExtension, 197 VideoPortServicesInt10, 198 (PINTERFACE)&VgaExtension->Int10Interface)) 199 { 200 VgaExtension->Int10Interface.Size = 0; 201 VgaExtension->Int10Interface.Version = 0; 202 } 203 204 /* Add ref */ 205 VideoDebugPrint((0, "have int10 iface\n")); 206 VgaExtension->Int10Interface.InterfaceReference(VgaExtension->Int10Interface.Context); 207 Context = VgaExtension->Int10Interface.Context; 208 209 /* Allocate scratch area and context */ 210 Status = VgaExtension->Int10Interface.Int10AllocateBuffer(Context, 211 &TrampolineMemorySegment, 212 &TrampolineMemoryOffset, 213 &Length); 214 if (Status != NO_ERROR) return; 215 VbeInfo = VideoPortAllocatePool(VgaExtension, 1, sizeof(VBE_INFO), ' agV'); 216 if (!VbeInfo) return; 217 218 VbeModeInfo = &VbeInfo->Modes; 219 220 /* Init VBE data and write to card buffer */ 221 VideoDebugPrint((0, "have int10 data\n")); 222 VbeInfo->ModeArray[128] = 0xFFFF; 223 VbeInfo->Info.Signature = VBE2_MAGIC; 224 Status = VgaExtension->Int10Interface.Int10WriteMemory(Context, 225 TrampolineMemorySegment, 226 TrampolineMemoryOffset, 227 &VbeInfo->Info.Signature, 228 4); 229 if (Status != NO_ERROR) return; 230 231 /* Get controller info */ 232 VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments)); 233 BiosArguments.Edi = TrampolineMemoryOffset; 234 BiosArguments.SegEs = TrampolineMemorySegment; 235 BiosArguments.Eax = VBE_GET_CONTROLLER_INFORMATION; 236 Status = VgaExtension->Int10Interface.Int10CallBios(Context, &BiosArguments); 237 if (Status != NO_ERROR) return; 238 if(VBE_GETRETURNCODE(BiosArguments.Eax) != VBE_SUCCESS) 239 { 240 VideoDebugPrint((0, "BiosArguments.Eax %lx\n", BiosArguments.Eax)); 241 return; 242 } 243 Status = VgaExtension->Int10Interface.Int10ReadMemory(Context, 244 TrampolineMemorySegment, 245 TrampolineMemoryOffset, 246 VbeInfo, 247 512); 248 if (Status != NO_ERROR) return; 249 250 /* Check correct VBE BIOS */ 251 VideoDebugPrint((0, "have vbe data\n")); 252 TotalMemory = VbeInfo->Info.TotalMemory << 16; 253 VbeVersion = VbeInfo->Info.Version; 254 VideoDebugPrint((0, "vbe version %lx memory %lx\n", VbeVersion, TotalMemory)); 255 if (!ValidateVbeInfo(VgaExtension, VbeInfo)) return; 256 257 /* Read modes */ 258 VideoDebugPrint((0, "read modes from %p\n", VbeInfo->Info.VideoModePtr)); 259 Status = VgaExtension->Int10Interface.Int10ReadMemory(Context, 260 HIWORD(VbeInfo->Info.VideoModePtr), 261 LOWORD(VbeInfo->Info.VideoModePtr), 262 VbeInfo->ModeArray, 263 128 * sizeof(USHORT)); 264 if (Status != NO_ERROR) return; 265 VideoDebugPrint((0, "Read modes at: %p\n", VbeInfo->ModeArray)); 266 267 /* Count modes, check for new 4bpp SVGA modes */ 268 ThisMode = VbeInfo->ModeArray; 269 ModeResult = VbeInfo->ModeArray[0]; 270 while (ModeResult != 0xFFFF) 271 { 272 Mode = ModeResult & 0x1FF; 273 VideoDebugPrint((0, "Mode found: %lx\n", Mode)); 274 if ((Mode == 0x102) || (Mode == 0x6A)) FourBppModeFound = TRUE; 275 ModeResult = *++ThisMode; 276 NewModes++; 277 } 278 279 /* Remove the built-in mode if not supported by card and check max modes */ 280 if (!FourBppModeFound) --NumVideoModes; 281 if ((NewModes >= 128) && (NumVideoModes > 8)) goto Cleanup; 282 283 /* Switch to new SVGA mode list, copy VGA modes */ 284 VgaModeList = VideoPortAllocatePool(VgaExtension, 1, (NewModes + NumVideoModes) * sizeof(VIDEOMODE), ' agV'); 285 if (!VgaModeList) goto Cleanup; 286 VideoPortMoveMemory(VgaModeList, ModesVGA, NumVideoModes * sizeof(VIDEOMODE)); 287 288 /* Apply fixup for Intel Brookdale */ 289 if (g_bIntelBrookdaleBIOS) 290 { 291 VideoDebugPrint((0, "Intel Brookdale-G Video BIOS Not Support!\n")); 292 while (TRUE); 293 } 294 295 /* Scan SVGA modes */ 296 VideoDebugPrint((0, "Static modes: %d\n", NumVideoModes)); 297 VgaMode = &VgaModeList[NumVideoModes]; 298 ThisMode = VbeInfo->ModeArray; 299 VideoDebugPrint((0, "new modes: %d\n", NewModes)); 300 while (NewModes--) 301 { 302 /* Get info on mode */ 303 VideoDebugPrint((0, "Getting info of mode %lx.\n", *ThisMode)); 304 VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments)); 305 BiosArguments.Eax = VBE_GET_MODE_INFORMATION; 306 BiosArguments.Ecx = *ThisMode; 307 BiosArguments.Edi = TrampolineMemoryOffset; 308 BiosArguments.SegEs = TrampolineMemorySegment; 309 Status = VgaExtension->Int10Interface.Int10CallBios(Context, &BiosArguments); 310 if (Status != NO_ERROR) goto Next; 311 if (VBE_GETRETURNCODE(BiosArguments.Eax) != VBE_SUCCESS) goto Next; 312 Status = VgaExtension->Int10Interface.Int10ReadMemory(Context, 313 TrampolineMemorySegment, 314 TrampolineMemoryOffset, 315 VbeModeInfo, 316 256); 317 if (Status != NO_ERROR) goto Next; 318 319 /* Parse graphics modes only if linear framebuffer support */ 320 VideoDebugPrint((0, "attr: %lx\n", VbeModeInfo->ModeAttributes)); 321 if (!(VbeModeInfo->ModeAttributes & (VBE_MODEATTR_VALID | 322 VBE_MODEATTR_GRAPHICS))) goto Next; 323 LinearAddressing = ((VbeVersion >= 0x200) && 324 (VbeModeInfo->PhysBasePtr) && 325 (VbeModeInfo->ModeAttributes & VBE_MODEATTR_LINEAR)) ? 326 TRUE : FALSE; 327 328 /* Check SVGA modes if 8bpp or higher */ 329 VideoDebugPrint((0, "PhysBase: %lx\n", VbeModeInfo->PhysBasePtr)); 330 if ((VbeModeInfo->XResolution >= 640) && 331 (VbeModeInfo->YResolution >= 480) && 332 (VbeModeInfo->NumberOfPlanes >= 1) && 333 (VbeModeInfo->BitsPerPixel >= 8)) 334 { 335 /* Copy VGA mode info */ 336 VideoPortZeroMemory(VgaMode, sizeof(VIDEOMODE)); 337 VgaMode->numPlanes = VbeModeInfo->NumberOfPlanes; 338 VgaMode->hres = VbeModeInfo->XResolution; 339 VgaMode->vres = VbeModeInfo->YResolution; 340 VgaMode->Frequency = 1; 341 VgaMode->Mode = (*ThisMode << 16) | VBE_SET_VBE_MODE; 342 VgaMode->Granularity = VbeModeInfo->WinGranularity << 10; 343 VideoDebugPrint((0, "Mode %lx (Granularity %d)\n", VgaMode->Mode, VgaMode->Granularity)); 344 345 /* Set flags */ 346 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_COLOR) VgaMode->fbType |= VIDEO_MODE_COLOR; 347 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_GRAPHICS) VgaMode->fbType |= VIDEO_MODE_GRAPHICS; 348 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NON_VGA) VgaMode->NonVgaMode = TRUE; 349 350 /* If no char data, say 80x25 */ 351 VgaMode->col = VbeModeInfo->XCharSize ? VbeModeInfo->XResolution / VbeModeInfo->XCharSize : 80; 352 VgaMode->row = VbeModeInfo->YCharSize ? VbeModeInfo->YResolution / VbeModeInfo->YCharSize : 25; 353 VideoDebugPrint((0, "%d by %d rows\n", VgaMode->col, VgaMode->row)); 354 355 /* Check RGB555 (15bpp only) */ 356 VgaMode->bitsPerPlane = VbeModeInfo->BitsPerPixel / VbeModeInfo->NumberOfPlanes; 357 if ((VgaMode->bitsPerPlane == 16) && (VbeModeInfo->GreenMaskSize == 5)) VgaMode->bitsPerPlane = 15; 358 VideoDebugPrint((0, "BPP: %d\n", VgaMode->bitsPerPlane)); 359 360 /* Do linear or banked frame buffers */ 361 VgaMode->FrameBufferBase = 0; 362 if (!LinearAddressing) 363 { 364 /* Read the screen stride (scanline size) */ 365 ScreenStride = RaiseToPower2(VbeModeInfo->BytesPerScanLine); 366 //ASSERT(ScreenStride <= MAX_USHORT); 367 VgaMode->wbytes = (USHORT)ScreenStride; 368 VideoDebugPrint((0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo->BytesPerScanLine, VgaMode->wbytes)); 369 370 /* Size of frame buffer is Height X ScanLine, align to bank/page size */ 371 ScreenSize = VgaMode->hres * ScreenStride; 372 VideoDebugPrint((0, "Size: %lx\n", ScreenSize)); 373 Size = (ScreenSize + ((64 * 1024) - 1)) & ((64 * 1024) - 1); 374 VideoDebugPrint((0, "Size: %lx\n", ScreenSize)); 375 if (Size > TotalMemory) Size = (Size + ((4 * 1024) - 1)) & ((4 * 1024) - 1); 376 VideoDebugPrint((0, "Size: %lx\n", ScreenSize)); 377 378 /* Banked VGA at 0xA0000 (64K) */ 379 VideoDebugPrint((0, "Final size: %lx\n", Size)); 380 VgaMode->fbType |= VIDEO_MODE_BANKED; 381 VgaMode->sbytes = Size; 382 VgaMode->PhysSize = 64 * 1024; 383 VgaMode->FrameBufferSize = 64 * 1024; 384 VgaMode->NoBankSwitch = TRUE; 385 VgaMode->PhysBase = 0xA0000; 386 VgaMode->LogicalWidth = RaiseToPower2(VgaMode->hres); 387 } 388 else 389 { 390 /* VBE 3.00+ has specific field, read legacy field if not */ 391 VideoDebugPrint((0, "LINEAR MODE!!!\n")); 392 ScreenStride = (VbeVersion >= 0x300) ? VbeModeInfo->LinBytesPerScanLine : 0; 393 if (!ScreenStride) ScreenStride = VbeModeInfo->BytesPerScanLine; 394 //ASSERT(ScreenStride <= MAX_USHORT); 395 VgaMode->wbytes = (USHORT)ScreenStride; 396 VideoDebugPrint((0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo->BytesPerScanLine, VgaMode->wbytes)); 397 398 /* Size of frame buffer is Height X ScanLine, align to page size */ 399 ScreenSize = VgaMode->hres * LOWORD(VgaMode->wbytes); 400 VideoDebugPrint((0, "Size: %lx\n", ScreenSize)); 401 Size = RaiseToPower2Ulong(ScreenSize); 402 VideoDebugPrint((0, "Size: %lx\n", ScreenSize)); 403 if (Size > TotalMemory) Size = (Size + ((4 * 1024) - 1)) & ((4 * 1024) - 1); 404 VideoDebugPrint((0, "Size: %lx\n", ScreenSize)); 405 406 /* Linear VGA must read settings from VBE */ 407 VgaMode->fbType |= VIDEO_MODE_LINEAR; 408 VgaMode->sbytes = Size; 409 VgaMode->PhysSize = Size; 410 VgaMode->FrameBufferSize = Size; 411 VgaMode->NoBankSwitch = FALSE; 412 VgaMode->PhysBase = VbeModeInfo->PhysBasePtr; 413 VgaMode->LogicalWidth = VgaMode->hres; 414 415 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */ 416 VgaMode->Mode |= (VBE_MODE_LINEAR_FRAMEBUFFER << 16); 417 } 418 419 /* Override bank switch if not support by card */ 420 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NO_BANK_SWITCH) VgaMode->NoBankSwitch = TRUE; 421 422 /* Next */ 423 if (ScreenSize <= TotalMemory) 424 { 425 VgaMode++; 426 ModeCount++; 427 } 428 } 429 Next: 430 /* Next */ 431 ThisMode++; 432 } 433 434 /* Check if last mode was color to do test */ 435 VideoDebugPrint((0, "mode scan complete. Total modes: %d\n", ModeCount)); 436 if (--VgaMode->fbType & VIDEO_MODE_COLOR) 437 { 438 /* Try map physical buffer and free if worked */ 439 PhysicalAddress.QuadPart = VgaMode->PhysBase; 440 BaseAddress = VideoPortGetDeviceBase(VgaExtension, PhysicalAddress, 4 * 1024, FALSE); 441 if (BaseAddress) 442 { 443 VideoPortFreeDeviceBase(VgaExtension, BaseAddress); 444 } 445 else 446 { 447 /* Not work, so throw out VBE data */ 448 ModeCount = 0; 449 } 450 } 451 452 /* Cleanup sucess path */ 453 VideoPortFreePool(VgaExtension, VbeInfo); 454 VgaExtension->Int10Interface.Int10FreeBuffer(Context, 455 TrampolineMemorySegment, 456 TrampolineMemoryOffset); 457 NumVideoModes += ModeCount; 458 return; 459 460 Cleanup: 461 /* Cleanup failure path, reset standard VGA and free memory */ 462 VgaModeList = ModesVGA; 463 VideoPortFreePool(VgaExtension, VbeInfo); 464 VgaExtension->Int10Interface.Int10FreeBuffer(Context, 465 TrampolineMemorySegment, 466 TrampolineMemoryOffset); 467 } 468 469 /* EOF */ 470