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
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 if (!VbeInfo
) return;
218 VbeModeInfo
= &VbeInfo
->Modes
;
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
,
229 if (Status
!= NO_ERROR
) return;
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
)
240 VideoDebugPrint((0, "BiosArguments.Eax %lx\n", BiosArguments
.Eax
));
243 Status
= VgaExtension
->Int10Interface
.Int10ReadMemory(Context
,
244 TrampolineMemorySegment
,
245 TrampolineMemoryOffset
,
248 if (Status
!= NO_ERROR
) return;
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;
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
),
263 128 * sizeof(USHORT
));
264 if (Status
!= NO_ERROR
) return;
265 VideoDebugPrint((0, "Read modes at: %p\n", VbeInfo
->ModeArray
));
267 /* Count modes, check for new 4bpp SVGA modes */
268 ThisMode
= VbeInfo
->ModeArray
;
269 ModeResult
= VbeInfo
->ModeArray
[0];
270 while (ModeResult
!= 0xFFFF)
272 Mode
= ModeResult
& 0x1FF;
273 VideoDebugPrint((0, "Mode found: %lx\n", Mode
));
274 if ((Mode
== 0x102) || (Mode
== 0x6A)) FourBppModeFound
= TRUE
;
275 ModeResult
= *++ThisMode
;
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
;
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
));
288 /* Apply fixup for Intel Brookdale */
289 if (g_bIntelBrookdaleBIOS
)
291 VideoDebugPrint((0, "Intel Brookdale-G Video BIOS Not Support!\n"));
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
));
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
,
317 if (Status
!= NO_ERROR
) goto Next
;
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
)) ?
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))
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
));
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
;
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
));
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
));
360 /* Do linear or banked frame buffers */
361 VgaMode
->FrameBufferBase
= 0;
362 if (!LinearAddressing
)
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
));
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
));
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
);
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
));
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
));
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
;
415 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
416 VgaMode
->Mode
|= (VBE_MODE_LINEAR_FRAMEBUFFER
<< 16);
419 /* Override bank switch if not support by card */
420 if (VbeModeInfo
->ModeAttributes
& VBE_MODEATTR_NO_BANK_SWITCH
) VgaMode
->NoBankSwitch
= TRUE
;
423 if (ScreenSize
<= TotalMemory
)
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
)
438 /* Try map physical buffer and free if worked */
439 PhysicalAddress
.QuadPart
= VgaMode
->PhysBase
;
440 BaseAddress
= VideoPortGetDeviceBase(VgaExtension
, PhysicalAddress
, 4 * 1024, FALSE
);
443 VideoPortFreeDeviceBase(VgaExtension
, BaseAddress
);
447 /* Not work, so throw out VBE data */
452 /* Cleanup sucess path */
453 VideoPortFreePool(VgaExtension
, VbeInfo
);
454 VgaExtension
->Int10Interface
.Int10FreeBuffer(Context
,
455 TrampolineMemorySegment
,
456 TrampolineMemoryOffset
);
457 NumVideoModes
+= ModeCount
;
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
);