[WIN32SS::DRIVERS] Improve the FILE header section. Brought to you by Adam Stachowicz...
[reactos.git] / reactos / 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: win32ss/drivers/miniport/vga_new/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 if (!VbeInfo) return;
217
218 VbeModeInfo = &VbeInfo->Modes;
219
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,
228 4);
229 if (Status != NO_ERROR) return;
230
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)
239 {
240 VideoDebugPrint((0, "BiosArguments.Eax %lx\n", BiosArguments.Eax));
241 return;
242 }
243 Status = VgaExtension->Int10Interface.Int10ReadMemory(Context,
244 TrampolineMemorySegment,
245 TrampolineMemoryOffset,
246 VbeInfo,
247 512);
248 if (Status != NO_ERROR) return;
249
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;
256
257 /* Read modes */
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),
262 VbeInfo->ModeArray,
263 128 * sizeof(USHORT));
264 if (Status != NO_ERROR) return;
265 VideoDebugPrint((0, "Read modes at: %p\n", VbeInfo->ModeArray));
266
267 /* Count modes, check for new 4bpp SVGA modes */
268 ThisMode = VbeInfo->ModeArray;
269 ModeResult = VbeInfo->ModeArray[0];
270 while (ModeResult != 0xFFFF)
271 {
272 Mode = ModeResult & 0x1FF;
273 VideoDebugPrint((0, "Mode found: %lx\n", Mode));
274 if ((Mode == 0x102) || (Mode == 0x6A)) FourBppModeFound = TRUE;
275 ModeResult = *++ThisMode;
276 NewModes++;
277 }
278
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;
282
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));
287
288 /* Apply fixup for Intel Brookdale */
289 if (g_bIntelBrookdaleBIOS)
290 {
291 VideoDebugPrint((0, "Intel Brookdale-G Video BIOS Not Support!\n"));
292 while (TRUE);
293 }
294
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));
300 while (NewModes--)
301 {
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,
315 VbeModeInfo,
316 256);
317 if (Status != NO_ERROR) goto Next;
318
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)) ?
326 TRUE : FALSE;
327
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))
334 {
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));
344
345 /* Set flags */
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;
349
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));
354
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));
359
360 /* Do linear or banked frame buffers */
361 VgaMode->FrameBufferBase = 0;
362 if (!LinearAddressing)
363 {
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));
369
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));
377
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);
387 }
388 else
389 {
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));
397
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));
405
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;
414
415 /* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
416 VgaMode->Mode |= (VBE_MODE_LINEAR_FRAMEBUFFER << 16);
417 }
418
419 /* Override bank switch if not support by card */
420 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NO_BANK_SWITCH) VgaMode->NoBankSwitch = TRUE;
421
422 /* Next */
423 if (ScreenSize <= TotalMemory)
424 {
425 VgaMode++;
426 ModeCount++;
427 }
428 }
429 Next:
430 /* Next */
431 ThisMode++;
432 }
433
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)
437 {
438 /* Try map physical buffer and free if worked */
439 PhysicalAddress.QuadPart = VgaMode->PhysBase;
440 BaseAddress = VideoPortGetDeviceBase(VgaExtension, PhysicalAddress, 4 * 1024, FALSE);
441 if (BaseAddress)
442 {
443 VideoPortFreeDeviceBase(VgaExtension, BaseAddress);
444 }
445 else
446 {
447 /* Not work, so throw out VBE data */
448 ModeCount = 0;
449 }
450 }
451
452 /* Cleanup sucess path */
453 VideoPortFreePool(VgaExtension, VbeInfo);
454 VgaExtension->Int10Interface.Int10FreeBuffer(Context,
455 TrampolineMemorySegment,
456 TrampolineMemoryOffset);
457 NumVideoModes += ModeCount;
458 return;
459
460 Cleanup:
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);
467 }
468
469 /* EOF */