2 * PROJECT: ReactOS VGA Miniport Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/drivers/video/miniport/vga/vbemodes.c
5 * PURPOSE: Mode Initialization and Mode Set for VBE-compatible cards
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 /* FUNCTIONS ******************************************************************/
17 RaiseToPower2Ulong(IN ULONG Value
)
19 ULONG SquaredResult
= Value
;
20 if ((Value
- 1) & Value
) for (SquaredResult
= 1; (SquaredResult
< Value
) && (SquaredResult
); SquaredResult
*= 2);
26 RaiseToPower2(IN USHORT Value
)
28 ULONG SquaredResult
= Value
;
29 if ((Value
- 1) & Value
) for (SquaredResult
= 1; (SquaredResult
< Value
) && (SquaredResult
); SquaredResult
*= 2);
35 VbeGetVideoMemoryBaseAddress(IN PHW_DEVICE_EXTENSION VgaExtension
,
36 IN PVIDEOMODE VgaMode
)
38 ULONG Length
= 4 * 1024;
39 USHORT TrampolineMemorySegment
, TrampolineMemoryOffset
;
41 INT10_BIOS_ARGUMENTS BiosArguments
;
42 PVBE_MODE_INFO VbeModeInfo
;
46 /* Need linear and INT10 interface */
47 if (!(VgaMode
->fbType
& VIDEO_MODE_BANKED
)) return 0;
48 if (VgaExtension
->Int10Interface
.Size
) return 0;
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
,
58 if (Status
!= NO_ERROR
) return 0;
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
)
70 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
71 TrampolineMemorySegment
,
72 TrampolineMemoryOffset
,
74 sizeof(VBE_MODE_INFO
));
75 if (Status
!= NO_ERROR
) return 0;
77 /* Return phys address and cleanup */
78 BaseAddress
= VbeModeInfo
->PhysBasePtr
;
79 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
80 TrampolineMemorySegment
,
81 TrampolineMemoryOffset
);
82 VideoPortFreePool(VgaExtension
, VbeModeInfo
);
88 VbeSetMode(IN PHW_DEVICE_EXTENSION VgaDeviceExtension
,
89 IN PVIDEOMODE VgaMode
,
90 OUT PULONG PhysPtrChange
)
93 VIDEO_X86_BIOS_ARGUMENTS BiosArguments
;
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
)
106 VideoDebugPrint((0, "Changing VBE mode failed, Eax %lx", BiosArguments
.Eax
));
107 return ERROR_INVALID_PARAMETER
;
110 /* Check for VESA mode */
114 if (VBE_GETRETURNCODE(BiosArguments
.Eax
) != VBE_SUCCESS
)
115 return ERROR_INVALID_PARAMETER
;
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
))
125 return ERROR_INVALID_PARAMETER
;
128 /* Set logical scanline width if different from physical */
129 if (VgaMode
->LogicalWidth
!= VgaMode
->hres
)
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
))
141 return ERROR_INVALID_PARAMETER
;
146 /* Get VRAM address to update changes */
147 BaseAddress
= VbeGetVideoMemoryBaseAddress(VgaDeviceExtension
, VgaMode
);
148 if ((BaseAddress
) && (VgaMode
->PhysBase
!= BaseAddress
))
150 *PhysPtrChange
= TRUE
;
151 VgaMode
->PhysBase
= BaseAddress
;
159 InitializeModeTable(IN PHW_DEVICE_EXTENSION VgaExtension
)
162 ULONG Length
= 4 * 1024;
165 INT10_BIOS_ARGUMENTS BiosArguments
;
167 PVBE_MODE_INFO VbeModeInfo
;
169 USHORT TrampolineMemorySegment
;
170 USHORT TrampolineMemoryOffset
;
173 BOOLEAN FourBppModeFound
= FALSE
;
177 BOOLEAN LinearAddressing
;
178 ULONG Size
, ScreenSize
;
182 PHYSICAL_ADDRESS PhysicalAddress
;
184 /* Enable only default vga modes if no vesa */
185 VgaModeList
= ModesVGA
;
186 if (VideoPortIsNoVesa())
188 VgaExtension
->Int10Interface
.Size
= 0;
189 VgaExtension
->Int10Interface
.Version
= 0;
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
))
200 VgaExtension
->Int10Interface
.Size
= 0;
201 VgaExtension
->Int10Interface
.Version
= 0;
205 VideoDebugPrint((0, "have int10 iface\n"));
206 VgaExtension
->Int10Interface
.InterfaceReference(VgaExtension
->Int10Interface
.Context
);
207 Context
= VgaExtension
->Int10Interface
.Context
;
209 /* Allocate scratch area and context */
210 Status
= VgaExtension
->Int10Interface
.Int10AllocateBuffer(Context
,
211 &TrampolineMemorySegment
,
212 &TrampolineMemoryOffset
,
214 if (Status
!= NO_ERROR
) return;
215 VbeInfo
= VideoPortAllocatePool(VgaExtension
, 1, sizeof(VBE_INFO
), ' agV');
216 VbeModeInfo
= &VbeInfo
->Modes
;
217 if (!VbeInfo
) return;
219 /* Init VBE data and write to card buffer */
220 VideoDebugPrint((0, "have int10 data\n"));
221 VbeInfo
->ModeArray
[128] = 0xFFFF;
222 VbeInfo
->Info
.Signature
= VBE2_MAGIC
;
223 Status
= VgaExtension
->Int10Interface
.Int10WriteMemory(Context
,
224 TrampolineMemorySegment
,
225 TrampolineMemoryOffset
,
226 &VbeInfo
->Info
.Signature
,
228 if (Status
!= NO_ERROR
) return;
230 /* Get controller info */
231 VideoPortZeroMemory(&BiosArguments
, sizeof(BiosArguments
));
232 BiosArguments
.Edi
= TrampolineMemoryOffset
;
233 BiosArguments
.SegEs
= TrampolineMemorySegment
;
234 BiosArguments
.Eax
= VBE_GET_CONTROLLER_INFORMATION
;
235 Status
= VgaExtension
->Int10Interface
.Int10CallBios(Context
, &BiosArguments
);
236 if (Status
!= NO_ERROR
) return;
237 if(VBE_GETRETURNCODE(BiosArguments
.Eax
) != VBE_SUCCESS
)
239 VideoDebugPrint((0, "BiosArguments.Eax %lx\n", BiosArguments
.Eax
));
242 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
243 TrampolineMemorySegment
,
244 TrampolineMemoryOffset
,
247 if (Status
!= NO_ERROR
) return;
249 /* Check correct VBE BIOS */
250 VideoDebugPrint((0, "have vbe data\n"));
251 TotalMemory
= VbeInfo
->Info
.TotalMemory
<< 16;
252 VbeVersion
= VbeInfo
->Info
.Version
;
253 VideoDebugPrint((0, "vbe version %lx memory %lx\n", VbeVersion
, TotalMemory
));
254 if (!ValidateVbeInfo(VgaExtension
, VbeInfo
)) return;
257 VideoDebugPrint((0, "read modes from %p\n", VbeInfo
->Info
.VideoModePtr
));
258 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
259 HIWORD(VbeInfo
->Info
.VideoModePtr
),
260 LOWORD(VbeInfo
->Info
.VideoModePtr
),
262 128 * sizeof(USHORT
));
263 if (Status
!= NO_ERROR
) return;
264 VideoDebugPrint((0, "Read modes at: %p\n", VbeInfo
->ModeArray
));
266 /* Count modes, check for new 4bpp SVGA modes */
267 ThisMode
= VbeInfo
->ModeArray
;
268 ModeResult
= VbeInfo
->ModeArray
[0];
269 while (ModeResult
!= 0xFFFF)
271 Mode
= ModeResult
& 0x1FF;
272 VideoDebugPrint((0, "Mode found: %lx\n", Mode
));
273 if ((Mode
== 0x102) || (Mode
== 0x6A)) FourBppModeFound
= TRUE
;
274 ModeResult
= *++ThisMode
;
278 /* Remove the built-in mode if not supported by card and check max modes */
279 if (!FourBppModeFound
) --NumVideoModes
;
280 if ((NewModes
>= 128) && (NumVideoModes
> 8)) goto Cleanup
;
282 /* Switch to new SVGA mode list, copy VGA modes */
283 VgaModeList
= VideoPortAllocatePool(VgaExtension
, 1, (NewModes
+ NumVideoModes
) * sizeof(VIDEOMODE
), ' agV');
284 if (!VgaModeList
) goto Cleanup
;
285 VideoPortMoveMemory(VgaModeList
, ModesVGA
, NumVideoModes
* sizeof(VIDEOMODE
));
287 /* Apply fixup for Intel Brookdale */
288 if (g_bIntelBrookdaleBIOS
)
290 VideoDebugPrint((0, "Intel Brookdale-G Video BIOS Not Support!\n"));
294 /* Scan SVGA modes */
295 VideoDebugPrint((0, "Static modes: %d\n", NumVideoModes
));
296 VgaMode
= &VgaModeList
[NumVideoModes
];
297 ThisMode
= VbeInfo
->ModeArray
;
298 VideoDebugPrint((0, "new modes: %d\n", NewModes
));
301 /* Get info on mode */
302 VideoDebugPrint((0, "Getting info of mode %lx.\n", *ThisMode
));
303 VideoPortZeroMemory(&BiosArguments
, sizeof(BiosArguments
));
304 BiosArguments
.Eax
= VBE_GET_MODE_INFORMATION
;
305 BiosArguments
.Ecx
= *ThisMode
;
306 BiosArguments
.Edi
= TrampolineMemoryOffset
;
307 BiosArguments
.SegEs
= TrampolineMemorySegment
;
308 Status
= VgaExtension
->Int10Interface
.Int10CallBios(Context
, &BiosArguments
);
309 if (Status
!= NO_ERROR
) goto Next
;
310 if (VBE_GETRETURNCODE(BiosArguments
.Eax
) != VBE_SUCCESS
) goto Next
;
311 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
312 TrampolineMemorySegment
,
313 TrampolineMemoryOffset
,
316 if (Status
!= NO_ERROR
) goto Next
;
318 /* Parse graphics modes only if linear framebuffer support */
319 VideoDebugPrint((0, "attr: %lx\n", VbeModeInfo
->ModeAttributes
));
320 if (!(VbeModeInfo
->ModeAttributes
& (VBE_MODEATTR_VALID
|
321 VBE_MODEATTR_GRAPHICS
))) goto Next
;
322 LinearAddressing
= ((VbeVersion
>= 0x200) &&
323 (VbeModeInfo
->PhysBasePtr
) &&
324 (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_LINEAR
)) ?
327 /* Check SVGA modes if 8bpp or higher */
328 VideoDebugPrint((0, "PhysBase: %lx\n", VbeModeInfo
->PhysBasePtr
));
329 if ((VbeModeInfo
->XResolution
>= 640) &&
330 (VbeModeInfo
->YResolution
>= 480) &&
331 (VbeModeInfo
->NumberOfPlanes
>= 1) &&
332 (VbeModeInfo
->BitsPerPixel
>= 8))
334 /* Copy VGA mode info */
335 VideoPortZeroMemory(VgaMode
, sizeof(VIDEOMODE
));
336 VgaMode
->numPlanes
= VbeModeInfo
->NumberOfPlanes
;
337 VgaMode
->hres
= VbeModeInfo
->XResolution
;
338 VgaMode
->vres
= VbeModeInfo
->YResolution
;
339 VgaMode
->Frequency
= 1;
340 VgaMode
->Mode
= (*ThisMode
<< 16) | VBE_SET_VBE_MODE
;
341 VgaMode
->Granularity
= VbeModeInfo
->WinGranularity
<< 10;
342 VideoDebugPrint((0, "Mode %lx (Granularity %d)\n", VgaMode
->Mode
, VgaMode
->Granularity
));
345 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_COLOR
) VgaMode
->fbType
|= VIDEO_MODE_COLOR
;
346 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_GRAPHICS
) VgaMode
->fbType
|= VIDEO_MODE_GRAPHICS
;
347 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_NON_VGA
) VgaMode
->NonVgaMode
= TRUE
;
349 /* If no char data, say 80x25 */
350 VgaMode
->col
= VbeModeInfo
->XCharSize
? VbeModeInfo
->XResolution
/ VbeModeInfo
->XCharSize
: 80;
351 VgaMode
->row
= VbeModeInfo
->YCharSize
? VbeModeInfo
->YResolution
/ VbeModeInfo
->YCharSize
: 25;
352 VideoDebugPrint((0, "%d by %d rows\n", VgaMode
->col
, VgaMode
->row
));
354 /* Check RGB555 (15bpp only) */
355 VgaMode
->bitsPerPlane
= VbeModeInfo
->BitsPerPixel
/ VbeModeInfo
->NumberOfPlanes
;
356 if ((VgaMode
->bitsPerPlane
== 16) && (VbeModeInfo
->GreenMaskSize
== 5)) VgaMode
->bitsPerPlane
= 15;
357 VideoDebugPrint((0, "BPP: %d\n", VgaMode
->bitsPerPlane
));
359 /* Do linear or banked frame buffers */
360 VgaMode
->FrameBufferBase
= 0;
361 if (!LinearAddressing
)
363 /* Read the screen stride (scanline size) */
364 ScreenStride
= RaiseToPower2(VbeModeInfo
->BytesPerScanLine
);
365 //ASSERT(ScreenStride <= MAX_USHORT);
366 VgaMode
->wbytes
= (USHORT
)ScreenStride
;
367 VideoDebugPrint((0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo
->BytesPerScanLine
, VgaMode
->wbytes
));
369 /* Size of frame buffer is Height X ScanLine, align to bank/page size */
370 ScreenSize
= VgaMode
->hres
* ScreenStride
;
371 VideoDebugPrint((0, "Size: %lx\n", ScreenSize
));
372 Size
= (ScreenSize
+ ((64 * 1024) - 1)) & ((64 * 1024) - 1);
373 VideoDebugPrint((0, "Size: %lx\n", ScreenSize
));
374 if (Size
> TotalMemory
) Size
= (Size
+ ((4 * 1024) - 1)) & ((4 * 1024) - 1);
375 VideoDebugPrint((0, "Size: %lx\n", ScreenSize
));
377 /* Banked VGA at 0xA0000 (64K) */
378 VideoDebugPrint((0, "Final size: %lx\n", Size
));
379 VgaMode
->fbType
|= VIDEO_MODE_BANKED
;
380 VgaMode
->sbytes
= Size
;
381 VgaMode
->PhysSize
= 64 * 1024;
382 VgaMode
->FrameBufferSize
= 64 * 1024;
383 VgaMode
->NoBankSwitch
= TRUE
;
384 VgaMode
->PhysBase
= 0xA0000;
385 VgaMode
->LogicalWidth
= RaiseToPower2(VgaMode
->hres
);
389 /* VBE 3.00+ has specific field, read legacy field if not */
390 VideoDebugPrint((0, "LINEAR MODE!!!\n"));
391 ScreenStride
= (VbeVersion
>= 0x300) ? VbeModeInfo
->LinBytesPerScanLine
: 0;
392 if (!ScreenStride
) ScreenStride
= VbeModeInfo
->BytesPerScanLine
;
393 //ASSERT(ScreenStride <= MAX_USHORT);
394 VgaMode
->wbytes
= (USHORT
)ScreenStride
;
395 VideoDebugPrint((0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo
->BytesPerScanLine
, VgaMode
->wbytes
));
397 /* Size of frame buffer is Height X ScanLine, align to page size */
398 ScreenSize
= VgaMode
->hres
* LOWORD(VgaMode
->wbytes
);
399 VideoDebugPrint((0, "Size: %lx\n", ScreenSize
));
400 Size
= RaiseToPower2Ulong(ScreenSize
);
401 VideoDebugPrint((0, "Size: %lx\n", ScreenSize
));
402 if (Size
> TotalMemory
) Size
= (Size
+ ((4 * 1024) - 1)) & ((4 * 1024) - 1);
403 VideoDebugPrint((0, "Size: %lx\n", ScreenSize
));
405 /* Linear VGA must read settings from VBE */
406 VgaMode
->fbType
|= VIDEO_MODE_LINEAR
;
407 VgaMode
->sbytes
= Size
;
408 VgaMode
->PhysSize
= Size
;
409 VgaMode
->FrameBufferSize
= Size
;
410 VgaMode
->NoBankSwitch
= FALSE
;
411 VgaMode
->PhysBase
= VbeModeInfo
->PhysBasePtr
;
412 VgaMode
->LogicalWidth
= VgaMode
->hres
;
414 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
415 VgaMode
->Mode
|= (VBE_MODE_LINEAR_FRAMEBUFFER
<< 16);
418 /* Override bank switch if not support by card */
419 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_NO_BANK_SWITCH
) VgaMode
->NoBankSwitch
= TRUE
;
422 if (ScreenSize
<= TotalMemory
)
433 /* Check if last mode was color to do test */
434 VideoDebugPrint((0, "mode scan complete. Total modes: %d\n", ModeCount
));
435 if (--VgaMode
->fbType
& VIDEO_MODE_COLOR
)
437 /* Try map physical buffer and free if worked */
438 PhysicalAddress
.QuadPart
= VgaMode
->PhysBase
;
439 BaseAddress
= VideoPortGetDeviceBase(VgaExtension
, PhysicalAddress
, 4 * 1024, FALSE
);
442 VideoPortFreeDeviceBase(VgaExtension
, BaseAddress
);
446 /* Not work, so throw out VBE data */
451 /* Cleanup sucess path */
452 VideoPortFreePool(VgaExtension
, VbeInfo
);
453 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
454 TrampolineMemorySegment
,
455 TrampolineMemoryOffset
);
456 NumVideoModes
+= ModeCount
;
460 /* Cleanup failure path, reset standard VGA and free memory */
461 VgaModeList
= ModesVGA
;
462 VideoPortFreePool(VgaExtension
, VbeInfo
);
463 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
464 TrampolineMemorySegment
,
465 TrampolineMemoryOffset
);