Sync with trunk (r48123)
[reactos.git] / drivers / video / miniport / vga_new / vbemodes.c
1 /*
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
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 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,
71 VbeModeInfo,
72 sizeof(VBE_MODE_INFO));
73 if (Status != NO_ERROR) return 0;
74
75 /* Return phys address and cleanup */
76 BaseAddress = VbeModeInfo->PhysBasePtr;
77 VgaExtension->Int10Interface.Int10FreeBuffer(Context,
78 TrampolineMemorySegment,
79 TrampolineMemoryOffset);
80 VideoPortFreePool(VgaExtension, VbeModeInfo);
81 return BaseAddress;
82 }
83
84 VP_STATUS
85 NTAPI
86 VbeSetMode(IN PHW_DEVICE_EXTENSION VgaDeviceExtension,
87 IN PVIDEOMODE VgaMode,
88 OUT PULONG PhysPtrChange)
89 {
90 VP_STATUS Status;
91 VIDEO_X86_BIOS_ARGUMENTS BiosArguments;
92 ULONG ModeIndex;
93 ULONG BaseAddress;
94
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;
102
103 /* Check for VESA mode */
104 if (ModeIndex >> 16)
105 {
106 /* Mode set fail */
107 if (BiosArguments.Eax != VBE_SUCCESS) return ERROR_INVALID_PARAMETER;
108
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))
115 {
116 return ERROR_INVALID_PARAMETER;
117 }
118
119 /* Set logical scanline width if different from physical */
120 if (VgaMode->LogicalWidth != VgaMode->hres)
121 {
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))
130 {
131 return ERROR_INVALID_PARAMETER;
132 }
133 }
134 }
135
136 /* Get VRAM address to update changes */
137 BaseAddress = VbeGetVideoMemoryBaseAddress(VgaDeviceExtension, VgaMode);
138 if ((BaseAddress) && (VgaMode->PhysBase != BaseAddress))
139 {
140 *PhysPtrChange = TRUE;
141 VgaMode->PhysBase = BaseAddress;
142 }
143
144 return NO_ERROR;
145 }
146
147 VOID
148 NTAPI
149 InitializeModeTable(IN PHW_DEVICE_EXTENSION VgaExtension)
150 {
151 ULONG ModeCount = 0;
152 ULONG Length = 4 * 1024;
153 ULONG TotalMemory;
154 VP_STATUS Status;
155 INT10_BIOS_ARGUMENTS BiosArguments;
156 PVBE_INFO VbeInfo;
157 PVBE_MODE_INFO VbeModeInfo;
158 PVOID Context;
159 USHORT TrampolineMemorySegment;
160 USHORT TrampolineMemoryOffset;
161 ULONG VbeVersion;
162 ULONG NewModes = 0;
163 BOOLEAN FourBppModeFound = FALSE;
164 USHORT ModeResult;
165 USHORT Mode;
166 PUSHORT ThisMode;
167 BOOLEAN LinearAddressing;
168 ULONG Size, ScreenSize;
169 PVIDEOMODE VgaMode;
170 PVOID BaseAddress;
171 ULONG ScreenStride = 0;
172 PHYSICAL_ADDRESS PhysicalAddress;
173
174 /* Enable only default vga modes if no vesa */
175 VgaModeList = ModesVGA;
176 if (VideoPortIsNoVesa())
177 {
178 VgaExtension->Int10Interface.Size = 0;
179 VgaExtension->Int10Interface.Version = 0;
180 return;
181 }
182
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))
189 {
190 VgaExtension->Int10Interface.Size = 0;
191 VgaExtension->Int10Interface.Version = 0;
192 }
193
194 /* Add ref */
195 //VideoPortDebugPrint(0, "have int10 iface\n");
196 VgaExtension->Int10Interface.InterfaceReference(VgaExtension->Int10Interface.Context);
197 Context = VgaExtension->Int10Interface.Context;
198
199 /* Allocate scratch area and context */
200 Status = VgaExtension->Int10Interface.Int10AllocateBuffer(Context,
201 &TrampolineMemorySegment,
202 &TrampolineMemoryOffset,
203 &Length);
204 if (Status != NO_ERROR) return;
205 VbeInfo = VideoPortAllocatePool(VgaExtension, 1, sizeof(VBE_INFO), ' agV');
206 VbeModeInfo = &VbeInfo->Modes;
207 if (!VbeInfo) return;
208
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,
216 VbeInfo,
217 512);
218 if (Status != NO_ERROR) return;
219
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,
230 VbeInfo,
231 512);
232 if (Status != NO_ERROR) return;
233
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;
240
241 /* Read modes */
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),
246 VbeInfo->ModeArray,
247 128 * sizeof(USHORT));
248 if (Status != NO_ERROR) return;
249 //VideoPortDebugPrint(0, "Read modes at: %p\n", VbeInfo->ModeArray);
250
251 /* Count modes, check for new 4bpp SVGA modes */
252 ThisMode = VbeInfo->ModeArray;
253 ModeResult = VbeInfo->ModeArray[0];
254 while (ModeResult != 0xFFFF)
255 {
256 Mode = ModeResult & 0x1FF;
257 //VideoPortDebugPrint(0, "Mode found: %lx\n", Mode);
258 if ((Mode == 0x102) || (Mode == 0x6A)) FourBppModeFound = TRUE;
259 ModeResult = *++ThisMode;
260 NewModes++;
261 }
262
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;
266
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));
271
272 /* Apply fixup for Intel Brookdale */
273 if (g_bIntelBrookdaleBIOS)
274 {
275 VideoPortDebugPrint(0, "Intel Brookdale-G Video BIOS Not Support!\n");
276 while (TRUE);
277 }
278
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);
284 while (NewModes--)
285 {
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,
297 VbeModeInfo,
298 256);
299 if (Status != NO_ERROR) goto Next;
300
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)) ?
308 TRUE : FALSE;
309
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))
316 {
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);
326
327 /* Set flags */
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;
331
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);
336
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);
341
342 /* Do linear or banked frame buffers */
343 VgaMode->FrameBufferBase = 0;
344 if (!LinearAddressing)
345 {
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);
350
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);
358
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);
368 }
369 else
370 {
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);
377
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);
385
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;
394
395 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
396 VgaMode->Mode |= (VBE_MODE_LINEAR_FRAMEBUFFER << 16);
397 }
398
399 /* Override bank switch if not support by card */
400 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NO_BANK_SWITCH) VgaMode->NoBankSwitch = TRUE;
401
402 /* Next */
403 if (ScreenSize <= TotalMemory)
404 {
405 VgaMode++;
406 ModeCount++;
407 }
408 }
409 Next:
410 /* Next */
411 ThisMode++;
412 }
413
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)
417 {
418 /* Try map physical buffer and free if worked */
419 PhysicalAddress.QuadPart = VgaMode->PhysBase;
420 BaseAddress = VideoPortGetDeviceBase(VgaExtension, PhysicalAddress, 4 * 1024, FALSE);
421 if (BaseAddress)
422 {
423 VideoPortFreeDeviceBase(VgaExtension, BaseAddress);
424 }
425 else
426 {
427 /* Not work, so throw out VBE data */
428 ModeCount = 0;
429 }
430 }
431
432 /* Cleanup sucess path */
433 VideoPortFreePool(VgaExtension, VbeInfo);
434 VgaExtension->Int10Interface.Int10FreeBuffer(Context,
435 TrampolineMemorySegment,
436 TrampolineMemoryOffset);
437 NumVideoModes += ModeCount;
438 return;
439
440 Cleanup:
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);
447 }
448
449 /* EOF */