Detect Bad graphic Bios, Some graphice card report VBE 2.0 when the are VBE 1.2....
[reactos.git] / reactos / drivers / video / miniport / vbe / vbemp.c
1 /*
2 * ReactOS VBE miniport video driver
3 * Copyright (C) 2004 Filip Navara
4 *
5 * Power Management and VBE 1.2 support
6 * Copyright (C) 2004 Magnus Olsen
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * TODO:
23 * - Check input parameters everywhere.
24 * - Call VideoPortVerifyAccessRanges to reserve the memory we're about
25 * to map.
26 */
27
28 /* INCLUDES *******************************************************************/
29
30 #include "vbemp.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
36
37 VP_STATUS STDCALL
38 DriverEntry(IN PVOID Context1, IN PVOID Context2)
39 {
40 VIDEO_HW_INITIALIZATION_DATA InitData;
41
42 VideoPortZeroMemory(&InitData, sizeof(InitData));
43 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
44 InitData.HwFindAdapter = VBEFindAdapter;
45 InitData.HwInitialize = VBEInitialize;
46 InitData.HwStartIO = VBEStartIO;
47 InitData.HwResetHw = VBEResetHw;
48 InitData.HwGetPowerState = VBEGetPowerState;
49 InitData.HwSetPowerState = VBESetPowerState;
50 InitData.HwDeviceExtensionSize = sizeof(VBE_DEVICE_EXTENSION);
51
52 return VideoPortInitialize(Context1, Context2, &InitData, NULL);
53 }
54
55 /*
56 * VBEFindAdapter
57 *
58 * Should detect a VBE compatible display adapter, but it's not possible
59 * to use video port Int 10 services at this time during initialization,
60 * so we always return NO_ERROR and do the real work in VBEInitialize.
61 */
62
63 VP_STATUS STDCALL
64 VBEFindAdapter(
65 IN PVOID HwDeviceExtension,
66 IN PVOID HwContext,
67 IN PWSTR ArgumentString,
68 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
69 OUT PUCHAR Again)
70 {
71 return NO_ERROR;
72 }
73
74 /*
75 * VBESortModesCallback
76 *
77 * Helper function for sorting video mode list.
78 */
79
80 static int
81 VBESortModesCallback(PVBE_MODEINFO VbeModeInfoA, PVBE_MODEINFO VbeModeInfoB)
82 {
83 DPRINT("VBESortModesCallback: %dx%dx%d / %dx%dx%d\n",
84 VbeModeInfoA->XResolution, VbeModeInfoA->YResolution,
85 VbeModeInfoA->BitsPerPixel,
86 VbeModeInfoB->XResolution, VbeModeInfoB->YResolution,
87 VbeModeInfoB->BitsPerPixel);
88
89 /*
90 * FIXME: Until some reasonable method for changing video modes will
91 * be available we favor more bits per pixel. It should be changed
92 * later.
93 */
94 if (VbeModeInfoA->BitsPerPixel < VbeModeInfoB->BitsPerPixel) return -1;
95 if (VbeModeInfoA->BitsPerPixel > VbeModeInfoB->BitsPerPixel) return 1;
96 if (VbeModeInfoA->XResolution < VbeModeInfoB->XResolution) return -1;
97 if (VbeModeInfoA->XResolution > VbeModeInfoB->XResolution) return 1;
98 if (VbeModeInfoA->YResolution < VbeModeInfoB->YResolution) return -1;
99 if (VbeModeInfoA->YResolution > VbeModeInfoB->YResolution) return 1;
100 return 0;
101 }
102
103 /*
104 * VBESortModes
105 *
106 * Simple function for sorting the video mode list. Uses bubble sort.
107 */
108
109 VOID FASTCALL
110 VBESortModes(PVBE_DEVICE_EXTENSION DeviceExtension)
111 {
112 BOOLEAN Finished = FALSE;
113 ULONG Pos;
114 int Result;
115 VBE_MODEINFO TempModeInfo;
116 WORD TempModeNumber;
117
118 while (!Finished)
119 {
120 Finished = TRUE;
121 for (Pos = 0; Pos < DeviceExtension->ModeCount - 1; Pos++)
122 {
123 Result = VBESortModesCallback(
124 DeviceExtension->ModeInfo + Pos,
125 DeviceExtension->ModeInfo + Pos + 1);
126 if (Result > 0)
127 {
128 Finished = FALSE;
129
130 VideoPortMoveMemory(
131 &TempModeInfo,
132 DeviceExtension->ModeInfo + Pos,
133 sizeof(VBE_MODEINFO));
134 TempModeNumber = DeviceExtension->ModeNumbers[Pos];
135
136 VideoPortMoveMemory(
137 DeviceExtension->ModeInfo + Pos,
138 DeviceExtension->ModeInfo + Pos + 1,
139 sizeof(VBE_MODEINFO));
140 DeviceExtension->ModeNumbers[Pos] =
141 DeviceExtension->ModeNumbers[Pos + 1];
142
143 VideoPortMoveMemory(
144 DeviceExtension->ModeInfo + Pos + 1,
145 &TempModeInfo,
146 sizeof(VBE_MODEINFO));
147 DeviceExtension->ModeNumbers[Pos + 1] = TempModeNumber;
148 }
149 }
150 }
151 }
152
153 /*
154 * VBEInitialize
155 *
156 * Performs the first initialization of the adapter, after the HAL has given
157 * up control of the video hardware to the video port driver.
158 *
159 * This function performs these steps:
160 * - Gets global VBE information and finds if VBE BIOS is present.
161 * - Builds the internal mode list using the list of modes provided by
162 * the VBE.
163 */
164
165 BOOLEAN STDCALL
166 VBEInitialize(PVOID HwDeviceExtension)
167 {
168 INT10_BIOS_ARGUMENTS BiosRegisters;
169 VP_STATUS Status;
170 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
171 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
172 ULONG Length;
173 ULONG ModeCount;
174 ULONG SuitableModeCount;
175 USHORT ModeTemp;
176 ULONG CurrentMode;
177 PVBE_MODEINFO VbeModeInfo;
178
179 /*
180 * Get the Int 10 interface that we will use for allocating real
181 * mode memory and calling the video BIOS.
182 */
183
184 VBEDeviceExtension->Int10Interface.Version = VIDEO_PORT_INT10_INTERFACE_VERSION_1;
185 VBEDeviceExtension->Int10Interface.Size = sizeof(VIDEO_PORT_INT10_INTERFACE);
186 Status = VideoPortQueryServices(
187 HwDeviceExtension,
188 VideoPortServicesInt10,
189 (PINTERFACE)&VBEDeviceExtension->Int10Interface);
190
191 if (Status != NO_ERROR)
192 {
193 DPRINT1("Failed to get Int 10 service functions (Status %x)\n", Status);
194 return FALSE;
195 }
196
197 /*
198 * Allocate a bit of memory that will be later used for VBE transport
199 * buffer. This memory must be accessible from V86 mode so it must fit
200 * in the first megabyte of physical memory.
201 */
202
203 Length = 0x400;
204 Status = VBEDeviceExtension->Int10Interface.Int10AllocateBuffer(
205 VBEDeviceExtension->Int10Interface.Context,
206 &VBEDeviceExtension->TrampolineMemorySegment,
207 &VBEDeviceExtension->TrampolineMemoryOffset,
208 &Length);
209
210 if (Status != NO_ERROR)
211 {
212 DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status);
213 return FALSE;
214 }
215
216 /*
217 * Get the VBE general information.
218 */
219
220 VBEDeviceExtension->Int10Interface.Int10WriteMemory(
221 VBEDeviceExtension->Int10Interface.Context,
222 VBEDeviceExtension->TrampolineMemorySegment,
223 VBEDeviceExtension->TrampolineMemoryOffset,
224 "VBE2",
225 4);
226
227 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
228 BiosRegisters.Eax = VBE_GET_CONTROLLER_INFORMATION;
229 BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset;
230 BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment;
231 VBEDeviceExtension->Int10Interface.Int10CallBios(
232 VBEDeviceExtension->Int10Interface.Context,
233 &BiosRegisters);
234
235 if (BiosRegisters.Eax == VBE_SUCCESS)
236 {
237 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
238 VBEDeviceExtension->Int10Interface.Context,
239 VBEDeviceExtension->TrampolineMemorySegment,
240 VBEDeviceExtension->TrampolineMemoryOffset,
241 &VBEDeviceExtension->VbeInfo,
242 sizeof(VBEDeviceExtension->VbeInfo));
243
244 /* Dectect Bad VBE BIOS some Graphice card report 0x200 when they are VBE 1.2 */
245 if (VBEDeviceExtension->VbeInfo.OemVendorNamePtr == 0 && VBEDeviceExtension->VbeInfo.Version == 0x200)
246 {
247 VBEDeviceExtension->VbeInfo.Version = 0x102;
248 }
249
250
251 DPRINT("VBE BIOS Present (%d.%d, %8ld Kb)\n",
252 VBEDeviceExtension->VbeInfo.Version / 0x100,
253 VBEDeviceExtension->VbeInfo.Version & 0xFF,
254 VBEDeviceExtension->VbeInfo.TotalMemory * 16);
255
256 #ifdef VBE12_SUPPORT
257 if (VBEDeviceExtension->VbeInfo.Version < 0x102)
258 #else
259 if (VBEDeviceExtension->VbeInfo.Version < 0x200)
260 #endif
261 {
262 DPRINT("VBE BIOS present, but incompatible version.\n");
263 return FALSE;
264 }
265 }
266 else
267 {
268 DPRINT("No VBE BIOS found.\n");
269 return FALSE;
270 }
271
272 /*
273 * Build a mode list here that can be later used by
274 * IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES and IOCTL_VIDEO_QUERY_AVAIL_MODES
275 * calls.
276 */
277
278 /*
279 * Get the number of supported video modes.
280 *
281 * No need to be map the memory. It's either in the video BIOS memory or
282 * in our trampoline memory. In either case the memory is already mapped.
283 */
284
285 for (ModeCount = 0; ; ModeCount++)
286 {
287 /* Read the VBE mode number. */
288 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
289 VBEDeviceExtension->Int10Interface.Context,
290 HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr),
291 LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (ModeCount << 1),
292 &ModeTemp,
293 sizeof(ModeTemp));
294
295 /* End of list? */
296 if (ModeTemp == 0xFFFF || ModeTemp == 0)
297 break;
298 }
299
300 /*
301 * Allocate space for video modes information.
302 */
303
304 VBEDeviceExtension->ModeInfo =
305 ExAllocatePool(PagedPool, ModeCount * sizeof(VBE_MODEINFO));
306 VBEDeviceExtension->ModeNumbers =
307 ExAllocatePool(PagedPool, ModeCount * sizeof(WORD));
308
309 /*
310 * Get the actual mode infos.
311 */
312
313 for (CurrentMode = 0, SuitableModeCount = 0;
314 CurrentMode < ModeCount;
315 CurrentMode++)
316 {
317 /* Read the VBE mode number. */
318 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
319 VBEDeviceExtension->Int10Interface.Context,
320 HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr),
321 LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (CurrentMode << 1),
322 &ModeTemp,
323 sizeof(ModeTemp));
324
325 /* Call VBE BIOS to read the mode info. */
326 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
327 BiosRegisters.Eax = VBE_GET_MODE_INFORMATION;
328 BiosRegisters.Ecx = ModeTemp;
329 BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset + 0x200;
330 BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment;
331 VBEDeviceExtension->Int10Interface.Int10CallBios(
332 VBEDeviceExtension->Int10Interface.Context,
333 &BiosRegisters);
334
335 /* Read the VBE mode info. */
336 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
337 VBEDeviceExtension->Int10Interface.Context,
338 VBEDeviceExtension->TrampolineMemorySegment,
339 VBEDeviceExtension->TrampolineMemoryOffset + 0x200,
340 VBEDeviceExtension->ModeInfo + SuitableModeCount,
341 sizeof(VBE_MODEINFO));
342
343 VbeModeInfo = VBEDeviceExtension->ModeInfo + SuitableModeCount;
344
345 /* Is this mode acceptable? */
346 if (BiosRegisters.Eax == VBE_SUCCESS &&
347 VbeModeInfo->XResolution >= 640 &&
348 VbeModeInfo->YResolution >= 480 &&
349 (VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_PACKEDPIXEL ||
350 VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_DIRECTCOLOR))
351 {
352 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_LINEAR)
353 {
354 VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp | 0x4000;
355 SuitableModeCount++;
356 }
357 #ifdef VBE12_SUPPORT
358 else
359 {
360 VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp;
361 SuitableModeCount++;
362 }
363 #endif
364 }
365 }
366
367 if (SuitableModeCount == 0)
368 {
369 DPRINT("VBEMP: No video modes supported\n");
370 return FALSE;
371 }
372
373 VBEDeviceExtension->ModeCount = SuitableModeCount;
374
375 /*
376 * Sort the video mode list according to resolution and bits per pixel.
377 */
378
379 VBESortModes(VBEDeviceExtension);
380
381 /*
382 * Print the supported video modes when NDEBUG is not set.
383 */
384
385 #ifndef NDEBUG
386 for (CurrentMode = 0;
387 CurrentMode < SuitableModeCount;
388 CurrentMode++)
389 {
390 DPRINT("%dx%dx%d\n",
391 VBEDeviceExtension->ModeInfo[CurrentMode].XResolution,
392 VBEDeviceExtension->ModeInfo[CurrentMode].YResolution,
393 VBEDeviceExtension->ModeInfo[CurrentMode].BitsPerPixel);
394 }
395 #endif
396
397 return TRUE;
398 }
399
400 /*
401 * VBEStartIO
402 *
403 * Processes the specified Video Request Packet.
404 */
405
406 BOOLEAN STDCALL
407 VBEStartIO(
408 PVOID HwDeviceExtension,
409 PVIDEO_REQUEST_PACKET RequestPacket)
410 {
411 BOOL Result;
412
413 RequestPacket->StatusBlock->Status = STATUS_UNSUCCESSFUL;
414
415 switch (RequestPacket->IoControlCode)
416 {
417 case IOCTL_VIDEO_SET_CURRENT_MODE:
418 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
419 {
420 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
421 return TRUE;
422 }
423 Result = VBESetCurrentMode(
424 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
425 (PVIDEO_MODE)RequestPacket->InputBuffer,
426 RequestPacket->StatusBlock);
427 break;
428
429 case IOCTL_VIDEO_RESET_DEVICE:
430 Result = VBEResetDevice(
431 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
432 RequestPacket->StatusBlock);
433 break;
434
435 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
436 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
437 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
438 {
439 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
440 return TRUE;
441 }
442 Result = VBEMapVideoMemory(
443 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
444 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
445 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
446 RequestPacket->StatusBlock);
447 break;
448
449 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
450 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
451 {
452 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
453 return TRUE;
454 }
455 Result = VBEUnmapVideoMemory(
456 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
457 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
458 RequestPacket->StatusBlock);
459 break;
460
461 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
462 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
463 {
464 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
465 return TRUE;
466 }
467 Result = VBEQueryNumAvailModes(
468 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
469 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
470 RequestPacket->StatusBlock);
471 break;
472
473 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
474 if (RequestPacket->OutputBufferLength <
475 ((PVBE_DEVICE_EXTENSION)HwDeviceExtension)->ModeCount * sizeof(VIDEO_MODE_INFORMATION))
476 {
477 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
478 return TRUE;
479 }
480 Result = VBEQueryAvailModes(
481 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
482 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
483 RequestPacket->StatusBlock);
484 break;
485
486 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
487 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
488 RequestPacket->InputBufferLength <
489 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
490 FIELD_OFFSET(VIDEO_CLUT, LookupTable))
491 {
492 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
493 return TRUE;
494 }
495 Result = VBESetColorRegisters(
496 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
497 (PVIDEO_CLUT)RequestPacket->InputBuffer,
498 RequestPacket->StatusBlock);
499 break;
500
501 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
502 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
503 {
504 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
505 return TRUE;
506 }
507 Result = VBEQueryCurrentMode(
508 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
509 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
510 RequestPacket->StatusBlock);
511 break;
512
513 default:
514 RequestPacket->StatusBlock->Status = STATUS_NOT_IMPLEMENTED;
515 return FALSE;
516 }
517
518 if (Result)
519 RequestPacket->StatusBlock->Status = STATUS_SUCCESS;
520
521 return TRUE;
522 }
523
524 /*
525 * VBEResetHw
526 *
527 * This function is called to reset the hardware to a known state.
528 */
529
530 BOOLEAN STDCALL
531 VBEResetHw(
532 PVOID DeviceExtension,
533 ULONG Columns,
534 ULONG Rows)
535 {
536 INT10_BIOS_ARGUMENTS BiosRegisters;
537 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
538 (PVBE_DEVICE_EXTENSION)DeviceExtension;
539
540 if (!VBEResetDevice(DeviceExtension, NULL))
541 return FALSE;
542
543 /* Change number of columns/rows */
544 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
545
546 if (Columns == 80 && Rows == 25)
547 {
548 /* Default text size, don't change anything. */
549 return TRUE;
550 }
551 else if (Columns == 80 && Rows == 28)
552 {
553 /* Use 9x14 font (80x28) */
554 BiosRegisters.Eax = 0x1111;
555 }
556 else if (Columns == 80 && Rows == 43)
557 {
558 /* Use 8x8 font in 350 scans mode (80x43) */
559 BiosRegisters.Eax = 0x1201;
560 BiosRegisters.Ebx = 0x30;
561 VBEDeviceExtension->Int10Interface.Int10CallBios(
562 VBEDeviceExtension->Int10Interface.Context,
563 &BiosRegisters);
564
565 BiosRegisters.Eax = 0x3;
566 BiosRegisters.Ebx = 0;
567 VBEDeviceExtension->Int10Interface.Int10CallBios(
568 VBEDeviceExtension->Int10Interface.Context,
569 &BiosRegisters);
570
571 BiosRegisters.Eax = 0x1112;
572 }
573 else if (Columns == 80 && Rows == 50)
574 {
575 /* Use 8x8 font (80x50) */
576 BiosRegisters.Eax = 0x1112;
577 }
578 else
579 return FALSE;
580
581 VBEDeviceExtension->Int10Interface.Int10CallBios(
582 VBEDeviceExtension->Int10Interface.Context,
583 &BiosRegisters);
584
585 return TRUE;
586 }
587
588 /*
589 * VBEGetPowerState
590 *
591 * Queries whether the device can support the requested power state.
592 */
593
594 VP_STATUS STDCALL
595 VBEGetPowerState(
596 PVOID HwDeviceExtension,
597 ULONG HwId,
598 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
599 {
600 INT10_BIOS_ARGUMENTS BiosRegisters;
601 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
602 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
603
604 if (HwId != DISPLAY_ADAPTER_HW_ID ||
605 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT))
606 return ERROR_INVALID_FUNCTION;
607
608 /*
609 * Get general power support information.
610 */
611
612 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
613 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
614 BiosRegisters.Ebx = 0;
615 BiosRegisters.Edi = 0;
616 BiosRegisters.SegEs = 0;
617 VBEDeviceExtension->Int10Interface.Int10CallBios(
618 VBEDeviceExtension->Int10Interface.Context,
619 &BiosRegisters);
620
621 if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
622 return ERROR_NOT_SUPPORTED;
623 if (BiosRegisters.Eax != VBE_SUCCESS)
624 return ERROR_INVALID_FUNCTION;
625
626 /*
627 * Get current power state.
628 */
629
630 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
631 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
632 BiosRegisters.Ebx = 0x2;
633 BiosRegisters.Edi = 0;
634 BiosRegisters.SegEs = 0;
635 VBEDeviceExtension->Int10Interface.Int10CallBios(
636 VBEDeviceExtension->Int10Interface.Context,
637 &BiosRegisters);
638
639 if (BiosRegisters.Eax == VBE_SUCCESS)
640 {
641 VideoPowerControl->DPMSVersion = BiosRegisters.Ebx & 0xFF;
642 switch (BiosRegisters.Ebx >> 8)
643 {
644 case 0: VideoPowerControl->PowerState = VideoPowerOn; break;
645 case 1: VideoPowerControl->PowerState = VideoPowerStandBy; break;
646 case 2: VideoPowerControl->PowerState = VideoPowerSuspend; break;
647 case 4: VideoPowerControl->PowerState = VideoPowerOff; break;
648 case 5: VideoPowerControl->PowerState = VideoPowerOn; break;
649 default: VideoPowerControl->PowerState = VideoPowerUnspecified;
650 }
651
652 return NO_ERROR;
653 }
654
655 return ERROR_NOT_SUPPORTED;
656 }
657
658 /*
659 * VBESetPowerState
660 *
661 * Sets the power state of the specified device
662 */
663
664 VP_STATUS STDCALL
665 VBESetPowerState(
666 PVOID HwDeviceExtension,
667 ULONG HwId,
668 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
669 {
670 INT10_BIOS_ARGUMENTS BiosRegisters;
671 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
672 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
673
674 if (HwId != DISPLAY_ADAPTER_HW_ID ||
675 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT) ||
676 VideoPowerControl->PowerState < VideoPowerOn ||
677 VideoPowerControl->PowerState > VideoPowerHibernate)
678 return ERROR_INVALID_FUNCTION;
679
680 if (VideoPowerControl->PowerState == VideoPowerHibernate)
681 return NO_ERROR;
682
683 /*
684 * Set current power state.
685 */
686
687 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
688 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
689 BiosRegisters.Ebx = 1;
690 BiosRegisters.Edi = 0;
691 BiosRegisters.SegEs = 0;
692 switch (VideoPowerControl->PowerState)
693 {
694 case VideoPowerStandBy: BiosRegisters.Ebx |= 0x100; break;
695 case VideoPowerSuspend: BiosRegisters.Ebx |= 0x200; break;
696 case VideoPowerOff: BiosRegisters.Ebx |= 0x400; break;
697 }
698
699 VBEDeviceExtension->Int10Interface.Int10CallBios(
700 VBEDeviceExtension->Int10Interface.Context,
701 &BiosRegisters);
702
703 if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
704 return ERROR_NOT_SUPPORTED;
705 if (BiosRegisters.Eax != VBE_SUCCESS)
706 return ERROR_INVALID_FUNCTION;
707
708 return VBE_SUCCESS;
709 }
710
711 /*
712 * VBESetCurrentMode
713 *
714 * Sets the adapter to the specified operating mode.
715 */
716
717 BOOL FASTCALL
718 VBESetCurrentMode(
719 PVBE_DEVICE_EXTENSION DeviceExtension,
720 PVIDEO_MODE RequestedMode,
721 PSTATUS_BLOCK StatusBlock)
722 {
723 INT10_BIOS_ARGUMENTS BiosRegisters;
724
725 if (RequestedMode->RequestedMode >= DeviceExtension->ModeCount)
726 {
727 return ERROR_INVALID_PARAMETER;
728 }
729
730 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
731 BiosRegisters.Eax = VBE_SET_VBE_MODE;
732 BiosRegisters.Ebx = DeviceExtension->ModeNumbers[RequestedMode->RequestedMode];
733 DeviceExtension->Int10Interface.Int10CallBios(
734 DeviceExtension->Int10Interface.Context,
735 &BiosRegisters);
736
737 if (BiosRegisters.Eax == VBE_SUCCESS)
738 {
739 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
740 }
741 else
742 {
743 DPRINT1("VBEMP: VBESetCurrentMode failed (%x)\n", BiosRegisters.Eax);
744 DeviceExtension->CurrentMode = -1;
745 }
746
747 return BiosRegisters.Eax == VBE_SUCCESS;
748 }
749
750 /*
751 * VBEResetDevice
752 *
753 * Resets the video hardware to the default mode, to which it was initialized
754 * at system boot.
755 */
756
757 BOOL FASTCALL
758 VBEResetDevice(
759 PVBE_DEVICE_EXTENSION DeviceExtension,
760 PSTATUS_BLOCK StatusBlock)
761 {
762 INT10_BIOS_ARGUMENTS BiosRegisters;
763
764 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
765 BiosRegisters.Eax = VBE_SET_VBE_MODE;
766 BiosRegisters.Ebx = 0x3;
767 DeviceExtension->Int10Interface.Int10CallBios(
768 DeviceExtension->Int10Interface.Context,
769 &BiosRegisters);
770
771 return BiosRegisters.Eax == VBE_SUCCESS;
772 }
773
774 /*
775 * VBEMapVideoMemory
776 *
777 * Maps the video hardware frame buffer and video RAM into the virtual address
778 * space of the requestor.
779 */
780
781 BOOL FASTCALL
782 VBEMapVideoMemory(
783 PVBE_DEVICE_EXTENSION DeviceExtension,
784 PVIDEO_MEMORY RequestedAddress,
785 PVIDEO_MEMORY_INFORMATION MapInformation,
786 PSTATUS_BLOCK StatusBlock)
787 {
788 PHYSICAL_ADDRESS FrameBuffer;
789 ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
790
791 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
792
793 if (DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].ModeAttributes &
794 VBE_MODEATTR_LINEAR)
795 {
796 FrameBuffer.QuadPart =
797 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].PhysBasePtr;
798 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
799 if (DeviceExtension->VbeInfo.Version < 0x300)
800 {
801 MapInformation->VideoRamLength =
802 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].BytesPerScanLine *
803 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
804 }
805 else
806 {
807 MapInformation->VideoRamLength =
808 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].LinBytesPerScanLine *
809 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
810 }
811 }
812 #ifdef VBE12_SUPPORT
813 else
814 {
815 FrameBuffer.QuadPart = 0xA0000;
816 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
817 MapInformation->VideoRamLength = 0x10000;
818 }
819 #endif
820
821 VideoPortMapMemory(DeviceExtension, FrameBuffer,
822 &MapInformation->VideoRamLength, &inIoSpace,
823 &MapInformation->VideoRamBase);
824
825 MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
826 MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
827
828 return TRUE;
829 }
830
831 /*
832 * VBEUnmapVideoMemory
833 *
834 * Releases a mapping between the virtual address space and the adapter's
835 * frame buffer and video RAM.
836 */
837
838 BOOL FASTCALL
839 VBEUnmapVideoMemory(
840 PVBE_DEVICE_EXTENSION DeviceExtension,
841 PVIDEO_MEMORY VideoMemory,
842 PSTATUS_BLOCK StatusBlock)
843 {
844 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress,
845 NULL);
846 return TRUE;
847 }
848
849 /*
850 * VBEQueryNumAvailModes
851 *
852 * Returns the number of video modes supported by the adapter and the size
853 * in bytes of the video mode information, which can be used to allocate a
854 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
855 */
856
857 BOOL FASTCALL
858 VBEQueryNumAvailModes(
859 PVBE_DEVICE_EXTENSION DeviceExtension,
860 PVIDEO_NUM_MODES Modes,
861 PSTATUS_BLOCK StatusBlock)
862 {
863 Modes->NumModes = DeviceExtension->ModeCount;
864 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
865 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
866 return TRUE;
867 }
868
869 /*
870 * VBEQueryMode
871 *
872 * Returns information about one particular video mode.
873 */
874
875 VOID FASTCALL
876 VBEQueryMode(
877 PVBE_DEVICE_EXTENSION DeviceExtension,
878 PVIDEO_MODE_INFORMATION VideoMode,
879 ULONG VideoModeId)
880 {
881 PVBE_MODEINFO VBEMode = &DeviceExtension->ModeInfo[VideoModeId];
882
883 VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
884 VideoMode->ModeIndex = VideoModeId;
885 VideoMode->VisScreenWidth = VBEMode->XResolution;
886 VideoMode->VisScreenHeight = VBEMode->YResolution;
887 if (DeviceExtension->VbeInfo.Version < 0x300)
888 VideoMode->ScreenStride = VBEMode->BytesPerScanLine;
889 else
890 VideoMode->ScreenStride = VBEMode->LinBytesPerScanLine;
891 VideoMode->NumberOfPlanes = VBEMode->NumberOfPlanes;
892 VideoMode->BitsPerPlane = VBEMode->BitsPerPixel / VBEMode->NumberOfPlanes;
893 VideoMode->Frequency = 1;
894 VideoMode->XMillimeter = 0; /* FIXME */
895 VideoMode->YMillimeter = 0; /* FIXME */
896 if (VBEMode->BitsPerPixel > 8)
897 {
898 /*
899 * Always report 16bpp modes and not 15bpp mode...
900 */
901 if (VBEMode->BitsPerPixel == 15 && VBEMode->NumberOfPlanes == 1)
902 {
903 VideoMode->BitsPerPlane = 16;
904 }
905
906 if (DeviceExtension->VbeInfo.Version < 0x300)
907 {
908 VideoMode->NumberRedBits = VBEMode->RedMaskSize;
909 VideoMode->NumberGreenBits = VBEMode->GreenMaskSize;
910 VideoMode->NumberBlueBits = VBEMode->BlueMaskSize;
911 VideoMode->RedMask = ((1 << VBEMode->RedMaskSize) - 1) << VBEMode->RedFieldPosition;
912 VideoMode->GreenMask = ((1 << VBEMode->GreenMaskSize) - 1) << VBEMode->GreenFieldPosition;
913 VideoMode->BlueMask = ((1 << VBEMode->BlueMaskSize) - 1) << VBEMode->BlueFieldPosition;
914 }
915 else
916 {
917 VideoMode->NumberRedBits = VBEMode->LinRedMaskSize;
918 VideoMode->NumberGreenBits = VBEMode->LinGreenMaskSize;
919 VideoMode->NumberBlueBits = VBEMode->LinBlueMaskSize;
920 VideoMode->RedMask = ((1 << VBEMode->LinRedMaskSize) - 1) << VBEMode->LinRedFieldPosition;
921 VideoMode->GreenMask = ((1 << VBEMode->LinGreenMaskSize) - 1) << VBEMode->LinGreenFieldPosition;
922 VideoMode->BlueMask = ((1 << VBEMode->LinBlueMaskSize) - 1) << VBEMode->LinBlueFieldPosition;
923 }
924 }
925 else
926 {
927 VideoMode->NumberRedBits =
928 VideoMode->NumberGreenBits =
929 VideoMode->NumberBlueBits = 6;
930 VideoMode->RedMask =
931 VideoMode->GreenMask =
932 VideoMode->BlueMask = 0;
933 }
934 VideoMode->VideoMemoryBitmapWidth = VBEMode->XResolution;
935 VideoMode->VideoMemoryBitmapHeight = VBEMode->YResolution;
936 VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
937 VIDEO_MODE_NO_OFF_SCREEN;
938 if (VideoMode->BitsPerPlane <= 8)
939 VideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN;
940 VideoMode->DriverSpecificAttributeFlags = 0;
941 }
942
943 /*
944 * VBEQueryAvailModes
945 *
946 * Returns information about each video mode supported by the adapter.
947 */
948
949 BOOL FASTCALL
950 VBEQueryAvailModes(
951 PVBE_DEVICE_EXTENSION DeviceExtension,
952 PVIDEO_MODE_INFORMATION ReturnedModes,
953 PSTATUS_BLOCK StatusBlock)
954 {
955 ULONG CurrentModeId;
956 PVIDEO_MODE_INFORMATION CurrentMode;
957 PVBE_MODEINFO CurrentVBEMode;
958
959 for (CurrentModeId = 0, CurrentMode = ReturnedModes,
960 CurrentVBEMode = DeviceExtension->ModeInfo;
961 CurrentModeId < DeviceExtension->ModeCount;
962 CurrentModeId++, CurrentMode++, CurrentVBEMode++)
963 {
964 VBEQueryMode(DeviceExtension, CurrentMode, CurrentModeId);
965 }
966
967 StatusBlock->Information =
968 sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->ModeCount;
969
970 return TRUE;
971 }
972
973 /*
974 * VBEQueryCurrentMode
975 *
976 * Returns information about current video mode.
977 */
978
979 BOOL FASTCALL
980 VBEQueryCurrentMode(
981 PVBE_DEVICE_EXTENSION DeviceExtension,
982 PVIDEO_MODE_INFORMATION VideoModeInfo,
983 PSTATUS_BLOCK StatusBlock)
984 {
985 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
986
987 VBEQueryMode(
988 DeviceExtension,
989 VideoModeInfo,
990 DeviceExtension->CurrentMode);
991
992 return TRUE;
993 }
994
995 /*
996 * VBESetColorRegisters
997 *
998 * Sets the adapter's color registers to the specified RGB values. There
999 * are code paths in this function, one generic and one for VGA compatible
1000 * controllers. The latter is needed for Bochs, where the generic one isn't
1001 * yet implemented.
1002 */
1003
1004 BOOL FASTCALL
1005 VBESetColorRegisters(
1006 PVBE_DEVICE_EXTENSION DeviceExtension,
1007 PVIDEO_CLUT ColorLookUpTable,
1008 PSTATUS_BLOCK StatusBlock)
1009 {
1010 INT10_BIOS_ARGUMENTS BiosRegisters;
1011 ULONG Entry;
1012 PULONG OutputEntry;
1013 ULONG OutputBuffer[256];
1014
1015 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
1016 return FALSE;
1017
1018 /*
1019 * For VGA compatible adapters program the color registers directly.
1020 */
1021
1022 if (!(DeviceExtension->VbeInfo.Capabilities & 2))
1023 {
1024 for (Entry = ColorLookUpTable->FirstEntry;
1025 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
1026 Entry++)
1027 {
1028 VideoPortWritePortUchar((PUCHAR)0x03c8, Entry);
1029 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
1030 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
1031 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
1032 }
1033
1034 return TRUE;
1035 }
1036 else
1037 {
1038 /*
1039 * We can't just copy the values, because we need to swap the Red
1040 * and Blue values.
1041 */
1042
1043 for (Entry = ColorLookUpTable->FirstEntry,
1044 OutputEntry = OutputBuffer;
1045 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
1046 Entry++, OutputEntry++)
1047 {
1048 *OutputEntry =
1049 (ColorLookUpTable->LookupTable[Entry].RgbArray.Red << 16) |
1050 (ColorLookUpTable->LookupTable[Entry].RgbArray.Green << 8) |
1051 (ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
1052 }
1053
1054 DeviceExtension->Int10Interface.Int10WriteMemory(
1055 DeviceExtension->Int10Interface.Context,
1056 DeviceExtension->TrampolineMemorySegment,
1057 DeviceExtension->TrampolineMemoryOffset,
1058 OutputBuffer,
1059 (OutputEntry - OutputBuffer) * sizeof(ULONG));
1060
1061 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
1062 BiosRegisters.Eax = VBE_SET_GET_PALETTE_DATA;
1063 BiosRegisters.Ebx = 0;
1064 BiosRegisters.Ecx = ColorLookUpTable->NumEntries;
1065 BiosRegisters.Edx = ColorLookUpTable->FirstEntry;
1066 BiosRegisters.Edi = DeviceExtension->TrampolineMemoryOffset;
1067 BiosRegisters.SegEs = DeviceExtension->TrampolineMemorySegment;
1068 DeviceExtension->Int10Interface.Int10CallBios(
1069 DeviceExtension->Int10Interface.Context,
1070 &BiosRegisters);
1071
1072 return BiosRegisters.Eax == VBE_SUCCESS;
1073 }
1074 }