Sync with trunk rev.61910 to get latest improvements and bugfixes.
[reactos.git] / win32ss / drivers / 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 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 VbeModeInfo = &VbeInfo->Modes;
217 if (!VbeInfo) return;
218
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,
227 4);
228 if (Status != NO_ERROR) return;
229
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)
238 {
239 VideoDebugPrint((0, "BiosArguments.Eax %lx\n", BiosArguments.Eax));
240 return;
241 }
242 Status = VgaExtension->Int10Interface.Int10ReadMemory(Context,
243 TrampolineMemorySegment,
244 TrampolineMemoryOffset,
245 VbeInfo,
246 512);
247 if (Status != NO_ERROR) return;
248
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;
255
256 /* Read modes */
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),
261 VbeInfo->ModeArray,
262 128 * sizeof(USHORT));
263 if (Status != NO_ERROR) return;
264 VideoDebugPrint((0, "Read modes at: %p\n", VbeInfo->ModeArray));
265
266 /* Count modes, check for new 4bpp SVGA modes */
267 ThisMode = VbeInfo->ModeArray;
268 ModeResult = VbeInfo->ModeArray[0];
269 while (ModeResult != 0xFFFF)
270 {
271 Mode = ModeResult & 0x1FF;
272 VideoDebugPrint((0, "Mode found: %lx\n", Mode));
273 if ((Mode == 0x102) || (Mode == 0x6A)) FourBppModeFound = TRUE;
274 ModeResult = *++ThisMode;
275 NewModes++;
276 }
277
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;
281
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));
286
287 /* Apply fixup for Intel Brookdale */
288 if (g_bIntelBrookdaleBIOS)
289 {
290 VideoDebugPrint((0, "Intel Brookdale-G Video BIOS Not Support!\n"));
291 while (TRUE);
292 }
293
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));
299 while (NewModes--)
300 {
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,
314 VbeModeInfo,
315 256);
316 if (Status != NO_ERROR) goto Next;
317
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)) ?
325 TRUE : FALSE;
326
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))
333 {
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));
343
344 /* Set flags */
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;
348
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));
353
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));
358
359 /* Do linear or banked frame buffers */
360 VgaMode->FrameBufferBase = 0;
361 if (!LinearAddressing)
362 {
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));
368
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));
376
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);
386 }
387 else
388 {
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));
396
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));
404
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;
413
414 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
415 VgaMode->Mode |= (VBE_MODE_LINEAR_FRAMEBUFFER << 16);
416 }
417
418 /* Override bank switch if not support by card */
419 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NO_BANK_SWITCH) VgaMode->NoBankSwitch = TRUE;
420
421 /* Next */
422 if (ScreenSize <= TotalMemory)
423 {
424 VgaMode++;
425 ModeCount++;
426 }
427 }
428 Next:
429 /* Next */
430 ThisMode++;
431 }
432
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)
436 {
437 /* Try map physical buffer and free if worked */
438 PhysicalAddress.QuadPart = VgaMode->PhysBase;
439 BaseAddress = VideoPortGetDeviceBase(VgaExtension, PhysicalAddress, 4 * 1024, FALSE);
440 if (BaseAddress)
441 {
442 VideoPortFreeDeviceBase(VgaExtension, BaseAddress);
443 }
444 else
445 {
446 /* Not work, so throw out VBE data */
447 ModeCount = 0;
448 }
449 }
450
451 /* Cleanup sucess path */
452 VideoPortFreePool(VgaExtension, VbeInfo);
453 VgaExtension->Int10Interface.Int10FreeBuffer(Context,
454 TrampolineMemorySegment,
455 TrampolineMemoryOffset);
456 NumVideoModes += ModeCount;
457 return;
458
459 Cleanup:
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);
466 }
467
468 /* EOF */