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 BiosArguments
.Ecx
= HIWORD(VgaMode
->Mode
);
62 BiosArguments
.Edi
= TrampolineMemorySegment
;
63 BiosArguments
.SegEs
= TrampolineMemoryOffset
;
64 BiosArguments
.Eax
= VBE_GET_MODE_INFORMATION
;
65 Status
= VgaExtension
->Int10Interface
.Int10CallBios(Context
, &BiosArguments
);
66 if (Status
!= NO_ERROR
) return 0;
67 if (BiosArguments
.Eax
!= VBE_SUCCESS
) return 0;
68 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
69 TrampolineMemorySegment
,
70 TrampolineMemoryOffset
,
72 sizeof(VBE_MODE_INFO
));
73 if (Status
!= NO_ERROR
) return 0;
75 /* Return phys address and cleanup */
76 BaseAddress
= VbeModeInfo
->PhysBasePtr
;
77 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
78 TrampolineMemorySegment
,
79 TrampolineMemoryOffset
);
80 VideoPortFreePool(VgaExtension
, VbeModeInfo
);
86 VbeSetMode(IN PHW_DEVICE_EXTENSION VgaDeviceExtension
,
87 IN PVIDEOMODE VgaMode
,
88 OUT PULONG PhysPtrChange
)
91 VIDEO_X86_BIOS_ARGUMENTS BiosArguments
;
95 VideoPortZeroMemory(&BiosArguments
, sizeof(BiosArguments
));
96 ModeIndex
= VgaMode
->Mode
;
97 BiosArguments
.Eax
= ModeIndex
& 0x0000FFFF;
98 BiosArguments
.Ebx
= ModeIndex
>> 16;
99 VideoPortDebugPrint(0, "Switching to %lx %lx\n", BiosArguments
.Eax
, BiosArguments
.Ebx
);
100 Status
= VideoPortInt10(VgaDeviceExtension
, &BiosArguments
);
101 if (Status
!= NO_ERROR
) return Status
;
103 /* Check for VESA mode */
107 if (BiosArguments
.Eax
!= VBE_SUCCESS
) return ERROR_INVALID_PARAMETER
;
109 /* Check current mode is desired mode */
110 BiosArguments
.Eax
= VBE_GET_CURRENT_VBE_MODE
;
111 Status
= VideoPortInt10(VgaDeviceExtension
, &BiosArguments
);
112 if ((Status
== NO_ERROR
) &&
113 (BiosArguments
.Eax
== VBE_SUCCESS
) &&
114 ((BiosArguments
.Ebx
^ (ModeIndex
>> 16)) & VBE_MODE_BITS
))
116 return ERROR_INVALID_PARAMETER
;
119 /* Set logical scanline width if different from physical */
120 if (VgaMode
->LogicalWidth
!= VgaMode
->hres
)
122 /* Check setting works after being set */
123 BiosArguments
.Eax
= VBE_SET_GET_LOGICAL_SCAN_LINE_LENGTH
;
124 BiosArguments
.Ecx
= VgaMode
->LogicalWidth
;
125 BiosArguments
.Ebx
= 0;
126 Status
= VideoPortInt10(VgaDeviceExtension
, &BiosArguments
);
127 if ((Status
!= NO_ERROR
) ||
128 (BiosArguments
.Eax
!= VBE_SUCCESS
) ||
129 (BiosArguments
.Ecx
!= VgaMode
->LogicalWidth
))
131 return ERROR_INVALID_PARAMETER
;
136 /* Get VRAM address to update changes */
137 BaseAddress
= VbeGetVideoMemoryBaseAddress(VgaDeviceExtension
, VgaMode
);
138 if ((BaseAddress
) && (VgaMode
->PhysBase
!= BaseAddress
))
140 *PhysPtrChange
= TRUE
;
141 VgaMode
->PhysBase
= BaseAddress
;
149 InitializeModeTable(IN PHW_DEVICE_EXTENSION VgaExtension
)
152 ULONG Length
= 4 * 1024;
155 INT10_BIOS_ARGUMENTS BiosArguments
;
157 PVBE_MODE_INFO VbeModeInfo
;
159 USHORT TrampolineMemorySegment
;
160 USHORT TrampolineMemoryOffset
;
163 BOOLEAN FourBppModeFound
= FALSE
;
167 BOOLEAN LinearAddressing
;
168 ULONG Size
, ScreenSize
;
171 ULONG ScreenStride
= 0;
172 PHYSICAL_ADDRESS PhysicalAddress
;
174 /* Enable only default vga modes if no vesa */
175 VgaModeList
= ModesVGA
;
176 if (VideoPortIsNoVesa())
178 VgaExtension
->Int10Interface
.Size
= 0;
179 VgaExtension
->Int10Interface
.Version
= 0;
183 /* Query INT10 interface */
184 VgaExtension
->Int10Interface
.Version
= VIDEO_PORT_INT10_INTERFACE_VERSION_1
;
185 VgaExtension
->Int10Interface
.Size
= sizeof(VIDEO_PORT_INT10_INTERFACE
);
186 if (VideoPortQueryServices(VgaExtension
,
187 VideoPortServicesInt10
,
188 (PINTERFACE
)&VgaExtension
->Int10Interface
))
190 VgaExtension
->Int10Interface
.Size
= 0;
191 VgaExtension
->Int10Interface
.Version
= 0;
195 //VideoPortDebugPrint(0, "have int10 iface\n");
196 VgaExtension
->Int10Interface
.InterfaceReference(VgaExtension
->Int10Interface
.Context
);
197 Context
= VgaExtension
->Int10Interface
.Context
;
199 /* Allocate scratch area and context */
200 Status
= VgaExtension
->Int10Interface
.Int10AllocateBuffer(Context
,
201 &TrampolineMemorySegment
,
202 &TrampolineMemoryOffset
,
204 if (Status
!= NO_ERROR
) return;
205 VbeInfo
= VideoPortAllocatePool(VgaExtension
, 1, sizeof(VBE_INFO
), ' agV');
206 VbeModeInfo
= &VbeInfo
->Modes
;
207 if (!VbeInfo
) return;
209 /* Init VBE data and write to card buffer */
210 //VideoPortDebugPrint(0, "have int10 data\n");
211 VbeInfo
->ModeArray
[128] = 0xFFFF;
212 strcpy(VbeInfo
->Info
.Signature
, "VBE2");
213 Status
= VgaExtension
->Int10Interface
.Int10WriteMemory(Context
,
214 TrampolineMemorySegment
,
215 TrampolineMemoryOffset
,
218 if (Status
!= NO_ERROR
) return;
220 /* Get controller info */
221 BiosArguments
.Edi
= TrampolineMemoryOffset
;
222 BiosArguments
.SegEs
= TrampolineMemorySegment
;
223 BiosArguments
.Eax
= VBE_GET_CONTROLLER_INFORMATION
;
224 Status
= VgaExtension
->Int10Interface
.Int10CallBios(Context
, &BiosArguments
);
225 if (Status
!= NO_ERROR
) return;
226 if (BiosArguments
.Eax
!= VBE_SUCCESS
) return;
227 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
228 TrampolineMemorySegment
,
229 TrampolineMemoryOffset
,
232 if (Status
!= NO_ERROR
) return;
234 /* Check correct VBE BIOS */
235 //VideoPortDebugPrint(0, "have vbe data\n");
236 TotalMemory
= VbeInfo
->Info
.TotalMemory
<< 16;
237 VbeVersion
= VbeInfo
->Info
.Version
;
238 VideoPortDebugPrint(0, "vbe version %lx memory %lx\n", VbeVersion
, TotalMemory
);
239 if (!ValidateVbeInfo(VgaExtension
, VbeInfo
)) return;
242 //VideoPortDebugPrint(0, "read modes from %p\n", VbeInfo->Info.VideoModePtr);
243 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
244 HIWORD(VbeInfo
->Info
.VideoModePtr
),
245 LOWORD(VbeInfo
->Info
.VideoModePtr
),
247 128 * sizeof(USHORT
));
248 if (Status
!= NO_ERROR
) return;
249 //VideoPortDebugPrint(0, "Read modes at: %p\n", VbeInfo->ModeArray);
251 /* Count modes, check for new 4bpp SVGA modes */
252 ThisMode
= VbeInfo
->ModeArray
;
253 ModeResult
= VbeInfo
->ModeArray
[0];
254 while (ModeResult
!= 0xFFFF)
256 Mode
= ModeResult
& 0x1FF;
257 //VideoPortDebugPrint(0, "Mode found: %lx\n", Mode);
258 if ((Mode
== 0x102) || (Mode
== 0x6A)) FourBppModeFound
= TRUE
;
259 ModeResult
= *++ThisMode
;
263 /* Remove the built-in mode if not supported by card and check max modes */
264 if (!FourBppModeFound
) --NumVideoModes
;
265 if ((NewModes
>= 128) && (NumVideoModes
> 8)) goto Cleanup
;
267 /* Switch to new SVGA mode list, copy VGA modes */
268 VgaModeList
= VideoPortAllocatePool(VgaExtension
, 1, (NewModes
+ NumVideoModes
) * sizeof(VIDEOMODE
), ' agV');
269 if (!VgaModeList
) goto Cleanup
;
270 VideoPortMoveMemory(VgaModeList
, ModesVGA
, NumVideoModes
* sizeof(VIDEOMODE
));
272 /* Apply fixup for Intel Brookdale */
273 if (g_bIntelBrookdaleBIOS
)
275 VideoPortDebugPrint(0, "Intel Brookdale-G Video BIOS Not Support!\n");
279 /* Scan SVGA modes */
280 // VideoPortDebugPrint(0, "Static modes: %d\n", NumVideoModes);
281 VgaMode
= &VgaModeList
[NumVideoModes
];
282 ThisMode
= VbeInfo
->ModeArray
;
283 //VideoPortDebugPrint(0, "new modes: %d\n", NewModes);
286 /* Get info on mode */
287 BiosArguments
.Eax
= VBE_GET_MODE_INFORMATION
;
288 BiosArguments
.Ecx
= *ThisMode
;
289 BiosArguments
.Edi
= TrampolineMemoryOffset
;
290 BiosArguments
.SegEs
= TrampolineMemorySegment
;
291 Status
= VgaExtension
->Int10Interface
.Int10CallBios(Context
, &BiosArguments
);
292 if (Status
!= NO_ERROR
) goto Next
;
293 if (BiosArguments
.Eax
!= VBE_SUCCESS
) goto Next
;
294 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
295 TrampolineMemorySegment
,
296 TrampolineMemoryOffset
,
299 if (Status
!= NO_ERROR
) goto Next
;
301 /* Parse graphics modes only if linear framebuffer support */
302 //VideoPortDebugPrint(0, "attr: %lx\n", VbeModeInfo->ModeAttributes);
303 if (!(VbeModeInfo
->ModeAttributes
& (VBE_MODEATTR_VALID
|
304 VBE_MODEATTR_GRAPHICS
))) goto Next
;
305 LinearAddressing
= ((VbeVersion
>= 0x200) &&
306 (VbeModeInfo
->PhysBasePtr
) &&
307 (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_LINEAR
)) ?
310 /* Check SVGA modes if 8bpp or higher */
311 //VideoPortDebugPrint(0, "PhysBase: %lx\n", VbeModeInfo->PhysBasePtr);
312 if ((VbeModeInfo
->XResolution
>= 640) &&
313 (VbeModeInfo
->YResolution
>= 480) &&
314 (VbeModeInfo
->NumberOfPlanes
>= 1) &&
315 (VbeModeInfo
->BitsPerPixel
>= 8))
317 /* Copy VGA mode info */
318 VideoPortZeroMemory(VgaMode
, sizeof(VIDEOMODE
));
319 VgaMode
->numPlanes
= VbeModeInfo
->NumberOfPlanes
;
320 VgaMode
->hres
= VbeModeInfo
->XResolution
;
321 VgaMode
->vres
= VbeModeInfo
->YResolution
;
322 VgaMode
->Frequency
= 1;
323 VgaMode
->Mode
= (*ThisMode
<< 16) | VBE_SET_VBE_MODE
;
324 VgaMode
->Granularity
= VbeModeInfo
->WinGranularity
<< 10;
325 //VideoPortDebugPrint(0, "Mode %lx (Granularity %d)\n", VgaMode->Mode, VgaMode->Granularity);
328 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_COLOR
) VgaMode
->fbType
|= VIDEO_MODE_COLOR
;
329 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_GRAPHICS
) VgaMode
->fbType
|= VIDEO_MODE_GRAPHICS
;
330 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_NON_VGA
) VgaMode
->NonVgaMode
= TRUE
;
332 /* If no char data, say 80x25 */
333 VgaMode
->col
= VbeModeInfo
->XCharSize
? VbeModeInfo
->XResolution
/ VbeModeInfo
->XCharSize
: 80;
334 VgaMode
->row
= VbeModeInfo
->YCharSize
? VbeModeInfo
->YResolution
/ VbeModeInfo
->YCharSize
: 25;
335 //VideoPortDebugPrint(0, "%d by %d rows\n", VgaMode->Columns, VgaMode->Rows);
337 /* Check RGB555 (15bpp only) */
338 VgaMode
->bitsPerPlane
= VbeModeInfo
->BitsPerPixel
/ VbeModeInfo
->NumberOfPlanes
;
339 if ((VgaMode
->bitsPerPlane
== 16) && (VbeModeInfo
->GreenMaskSize
== 5)) VgaMode
->bitsPerPlane
= 15;
340 //VideoPortDebugPrint(0, "BPP: %d\n", VgaMode->BitsPerPlane);
342 /* Do linear or banked frame buffers */
343 VgaMode
->FrameBufferBase
= 0;
344 if (!LinearAddressing
)
346 /* Read the screen stride (scanline size) */
347 ScreenStride
= RaiseToPower2(VbeModeInfo
->BytesPerScanLine
);
348 VgaMode
->wbytes
= ScreenStride
;
349 //VideoPortDebugPrint(0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo->BytesPerScanLine, VgaMode->Stride);
351 /* Size of frame buffer is Height X ScanLine, align to bank/page size */
352 ScreenSize
= VgaMode
->hres
* ScreenStride
;
353 //VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
354 Size
= (ScreenSize
+ ((64 * 1024) - 1)) & ((64 * 1024) - 1);
355 //VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
356 if (Size
> TotalMemory
) Size
= (Size
+ ((4 * 1024) - 1)) & ((4 * 1024) - 1);
357 //VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
359 /* Banked VGA at 0xA0000 (64K) */
360 //VideoPortDebugPrint(0, "Final size: %lx\n", Size);
361 VgaMode
->fbType
|= VIDEO_MODE_BANKED
;
362 VgaMode
->sbytes
= Size
;
363 VgaMode
->PhysSize
= 64 * 1024;
364 VgaMode
->FrameBufferSize
= 64 * 1024;
365 VgaMode
->NoBankSwitch
= TRUE
;
366 VgaMode
->PhysBase
= 0xA0000;
367 VgaMode
->LogicalWidth
= RaiseToPower2(VgaMode
->hres
);
371 /* VBE 3.00+ has specific field, read legacy field if not */
372 //VideoPortDebugPrint(0, "LINEAR MODE!!!\n");
373 ScreenStride
= (VbeVersion
>= 0x300) ? VbeModeInfo
->LinBytesPerScanLine
: 0;
374 if (!ScreenStride
) ScreenStride
= VbeModeInfo
->BytesPerScanLine
;
375 VgaMode
->wbytes
= ScreenStride
;
376 //VideoPortDebugPrint(0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo->BytesPerScanLine, VgaMode->Stride);
378 /* Size of frame buffer is Height X ScanLine, align to page size */
379 ScreenSize
= VgaMode
->hres
* LOWORD(VgaMode
->wbytes
);
380 //VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
381 Size
= RaiseToPower2Ulong(ScreenSize
);
382 //VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
383 if (Size
> TotalMemory
) Size
= (Size
+ ((4 * 1024) - 1)) & ((4 * 1024) - 1);
384 //VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
386 /* Linear VGA must read settings from VBE */
387 VgaMode
->fbType
|= VIDEO_MODE_LINEAR
;
388 VgaMode
->sbytes
= Size
;
389 VgaMode
->PhysSize
= Size
;
390 VgaMode
->FrameBufferSize
= Size
;
391 VgaMode
->NoBankSwitch
= FALSE
;
392 VgaMode
->PhysBase
= VbeModeInfo
->PhysBasePtr
;
393 VgaMode
->LogicalWidth
= VgaMode
->hres
;
395 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
396 VgaMode
->Mode
|= (VBE_MODE_LINEAR_FRAMEBUFFER
<< 16);
399 /* Override bank switch if not support by card */
400 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_NO_BANK_SWITCH
) VgaMode
->NoBankSwitch
= TRUE
;
403 if (ScreenSize
<= TotalMemory
)
414 /* Check if last mode was color to do test */
415 VideoPortDebugPrint(0, "mode scan complete. Total modes: %d\n", ModeCount
);
416 if (--VgaMode
->fbType
& VIDEO_MODE_COLOR
)
418 /* Try map physical buffer and free if worked */
419 PhysicalAddress
.QuadPart
= VgaMode
->PhysBase
;
420 BaseAddress
= VideoPortGetDeviceBase(VgaExtension
, PhysicalAddress
, 4 * 1024, FALSE
);
423 VideoPortFreeDeviceBase(VgaExtension
, BaseAddress
);
427 /* Not work, so throw out VBE data */
432 /* Cleanup sucess path */
433 VideoPortFreePool(VgaExtension
, VbeInfo
);
434 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
435 TrampolineMemorySegment
,
436 TrampolineMemoryOffset
);
437 NumVideoModes
+= ModeCount
;
441 /* Cleanup failure path, reset standard VGA and free memory */
442 VgaModeList
= ModesVGA
;
443 VideoPortFreePool(VgaExtension
, VbeInfo
);
444 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
445 TrampolineMemorySegment
,
446 TrampolineMemoryOffset
);