Verify VBE is found and not anything else, is a safe check.
[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 /* Verify VBE is found and not anýthing else */
245 if (strncmp(VBEDeviceExtension->VbeInfo.Signature,"VESA",4) != 0)
246 {
247 DPRINT("No VBE BIOS present\n");
248 return FALSE;
249 }
250
251 /* Dectect Bad VBE BIOS some Graphice card report 0x200 when they are VBE 1.2 */
252 if (VBEDeviceExtension->VbeInfo.OemVendorNamePtr == 0 && VBEDeviceExtension->VbeInfo.Version == 0x200)
253 {
254 VBEDeviceExtension->VbeInfo.Version = 0x102;
255 }
256
257 DPRINT("VBE BIOS Present (%d.%d, %8ld Kb)\n",
258 VBEDeviceExtension->VbeInfo.Version / 0x100,
259 VBEDeviceExtension->VbeInfo.Version & 0xFF,
260 VBEDeviceExtension->VbeInfo.TotalMemory * 64);
261
262 #ifdef VBE12_SUPPORT
263 if (VBEDeviceExtension->VbeInfo.Version < 0x102)
264 #else
265 if (VBEDeviceExtension->VbeInfo.Version < 0x200)
266 #endif
267 {
268 DPRINT("VBE BIOS present, but incompatible version.\n");
269 return FALSE;
270 }
271 }
272 else
273 {
274 DPRINT("No VBE BIOS found.\n");
275 return FALSE;
276 }
277
278 /*
279 * Build a mode list here that can be later used by
280 * IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES and IOCTL_VIDEO_QUERY_AVAIL_MODES
281 * calls.
282 */
283
284 /*
285 * Get the number of supported video modes.
286 *
287 * No need to be map the memory. It's either in the video BIOS memory or
288 * in our trampoline memory. In either case the memory is already mapped.
289 */
290
291 for (ModeCount = 0; ; ModeCount++)
292 {
293 /* Read the VBE mode number. */
294 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
295 VBEDeviceExtension->Int10Interface.Context,
296 HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr),
297 LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (ModeCount << 1),
298 &ModeTemp,
299 sizeof(ModeTemp));
300
301 /* End of list? */
302 if (ModeTemp == 0xFFFF || ModeTemp == 0)
303 break;
304 }
305
306 /*
307 * Allocate space for video modes information.
308 */
309
310 VBEDeviceExtension->ModeInfo =
311 ExAllocatePool(PagedPool, ModeCount * sizeof(VBE_MODEINFO));
312 VBEDeviceExtension->ModeNumbers =
313 ExAllocatePool(PagedPool, ModeCount * sizeof(WORD));
314
315 /*
316 * Get the actual mode infos.
317 */
318
319 for (CurrentMode = 0, SuitableModeCount = 0;
320 CurrentMode < ModeCount;
321 CurrentMode++)
322 {
323 /* Read the VBE mode number. */
324 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
325 VBEDeviceExtension->Int10Interface.Context,
326 HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr),
327 LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (CurrentMode << 1),
328 &ModeTemp,
329 sizeof(ModeTemp));
330
331 /* Call VBE BIOS to read the mode info. */
332 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
333 BiosRegisters.Eax = VBE_GET_MODE_INFORMATION;
334 BiosRegisters.Ecx = ModeTemp;
335 BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset + 0x200;
336 BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment;
337 VBEDeviceExtension->Int10Interface.Int10CallBios(
338 VBEDeviceExtension->Int10Interface.Context,
339 &BiosRegisters);
340
341 /* Read the VBE mode info. */
342 VBEDeviceExtension->Int10Interface.Int10ReadMemory(
343 VBEDeviceExtension->Int10Interface.Context,
344 VBEDeviceExtension->TrampolineMemorySegment,
345 VBEDeviceExtension->TrampolineMemoryOffset + 0x200,
346 VBEDeviceExtension->ModeInfo + SuitableModeCount,
347 sizeof(VBE_MODEINFO));
348
349 VbeModeInfo = VBEDeviceExtension->ModeInfo + SuitableModeCount;
350
351 /* Is this mode acceptable? */
352 if (BiosRegisters.Eax == VBE_SUCCESS &&
353 VbeModeInfo->XResolution >= 640 &&
354 VbeModeInfo->YResolution >= 480 &&
355 (VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_PACKEDPIXEL ||
356 VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_DIRECTCOLOR))
357 {
358 if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_LINEAR)
359 {
360 VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp | 0x4000;
361 SuitableModeCount++;
362 }
363 #ifdef VBE12_SUPPORT
364 else
365 {
366 VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp;
367 SuitableModeCount++;
368 }
369 #endif
370 }
371 }
372
373 if (SuitableModeCount == 0)
374 {
375 DPRINT("VBEMP: No video modes supported\n");
376 return FALSE;
377 }
378
379 VBEDeviceExtension->ModeCount = SuitableModeCount;
380
381 /*
382 * Sort the video mode list according to resolution and bits per pixel.
383 */
384
385 VBESortModes(VBEDeviceExtension);
386
387 /*
388 * Print the supported video modes when NDEBUG is not set.
389 */
390
391 #ifndef NDEBUG
392 for (CurrentMode = 0;
393 CurrentMode < SuitableModeCount;
394 CurrentMode++)
395 {
396 DPRINT("%dx%dx%d\n",
397 VBEDeviceExtension->ModeInfo[CurrentMode].XResolution,
398 VBEDeviceExtension->ModeInfo[CurrentMode].YResolution,
399 VBEDeviceExtension->ModeInfo[CurrentMode].BitsPerPixel);
400 }
401 #endif
402
403 return TRUE;
404 }
405
406 /*
407 * VBEStartIO
408 *
409 * Processes the specified Video Request Packet.
410 */
411
412 BOOLEAN STDCALL
413 VBEStartIO(
414 PVOID HwDeviceExtension,
415 PVIDEO_REQUEST_PACKET RequestPacket)
416 {
417 BOOL Result;
418
419 RequestPacket->StatusBlock->Status = STATUS_UNSUCCESSFUL;
420
421 switch (RequestPacket->IoControlCode)
422 {
423 case IOCTL_VIDEO_SET_CURRENT_MODE:
424 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
425 {
426 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
427 return TRUE;
428 }
429 Result = VBESetCurrentMode(
430 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
431 (PVIDEO_MODE)RequestPacket->InputBuffer,
432 RequestPacket->StatusBlock);
433 break;
434
435 case IOCTL_VIDEO_RESET_DEVICE:
436 Result = VBEResetDevice(
437 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
438 RequestPacket->StatusBlock);
439 break;
440
441 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
442 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
443 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
444 {
445 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
446 return TRUE;
447 }
448 Result = VBEMapVideoMemory(
449 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
450 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
451 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
452 RequestPacket->StatusBlock);
453 break;
454
455 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
456 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
457 {
458 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
459 return TRUE;
460 }
461 Result = VBEUnmapVideoMemory(
462 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
463 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
464 RequestPacket->StatusBlock);
465 break;
466
467 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
468 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
469 {
470 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
471 return TRUE;
472 }
473 Result = VBEQueryNumAvailModes(
474 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
475 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
476 RequestPacket->StatusBlock);
477 break;
478
479 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
480 if (RequestPacket->OutputBufferLength <
481 ((PVBE_DEVICE_EXTENSION)HwDeviceExtension)->ModeCount * sizeof(VIDEO_MODE_INFORMATION))
482 {
483 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
484 return TRUE;
485 }
486 Result = VBEQueryAvailModes(
487 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
488 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
489 RequestPacket->StatusBlock);
490 break;
491
492 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
493 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
494 RequestPacket->InputBufferLength <
495 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
496 FIELD_OFFSET(VIDEO_CLUT, LookupTable))
497 {
498 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
499 return TRUE;
500 }
501 Result = VBESetColorRegisters(
502 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
503 (PVIDEO_CLUT)RequestPacket->InputBuffer,
504 RequestPacket->StatusBlock);
505 break;
506
507 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
508 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
509 {
510 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
511 return TRUE;
512 }
513 Result = VBEQueryCurrentMode(
514 (PVBE_DEVICE_EXTENSION)HwDeviceExtension,
515 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
516 RequestPacket->StatusBlock);
517 break;
518
519 default:
520 RequestPacket->StatusBlock->Status = STATUS_NOT_IMPLEMENTED;
521 return FALSE;
522 }
523
524 if (Result)
525 RequestPacket->StatusBlock->Status = STATUS_SUCCESS;
526
527 return TRUE;
528 }
529
530 /*
531 * VBEResetHw
532 *
533 * This function is called to reset the hardware to a known state.
534 */
535
536 BOOLEAN STDCALL
537 VBEResetHw(
538 PVOID DeviceExtension,
539 ULONG Columns,
540 ULONG Rows)
541 {
542 INT10_BIOS_ARGUMENTS BiosRegisters;
543 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
544 (PVBE_DEVICE_EXTENSION)DeviceExtension;
545
546 if (!VBEResetDevice(DeviceExtension, NULL))
547 return FALSE;
548
549 /* Change number of columns/rows */
550 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
551
552 if (Columns == 80 && Rows == 25)
553 {
554 /* Default text size, don't change anything. */
555 return TRUE;
556 }
557 else if (Columns == 80 && Rows == 28)
558 {
559 /* Use 9x14 font (80x28) */
560 BiosRegisters.Eax = 0x1111;
561 }
562 else if (Columns == 80 && Rows == 43)
563 {
564 /* Use 8x8 font in 350 scans mode (80x43) */
565 BiosRegisters.Eax = 0x1201;
566 BiosRegisters.Ebx = 0x30;
567 VBEDeviceExtension->Int10Interface.Int10CallBios(
568 VBEDeviceExtension->Int10Interface.Context,
569 &BiosRegisters);
570
571 BiosRegisters.Eax = 0x3;
572 BiosRegisters.Ebx = 0;
573 VBEDeviceExtension->Int10Interface.Int10CallBios(
574 VBEDeviceExtension->Int10Interface.Context,
575 &BiosRegisters);
576
577 BiosRegisters.Eax = 0x1112;
578 }
579 else if (Columns == 80 && Rows == 50)
580 {
581 /* Use 8x8 font (80x50) */
582 BiosRegisters.Eax = 0x1112;
583 }
584 else
585 return FALSE;
586
587 VBEDeviceExtension->Int10Interface.Int10CallBios(
588 VBEDeviceExtension->Int10Interface.Context,
589 &BiosRegisters);
590
591 return TRUE;
592 }
593
594 /*
595 * VBEGetPowerState
596 *
597 * Queries whether the device can support the requested power state.
598 */
599
600 VP_STATUS STDCALL
601 VBEGetPowerState(
602 PVOID HwDeviceExtension,
603 ULONG HwId,
604 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
605 {
606 INT10_BIOS_ARGUMENTS BiosRegisters;
607 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
608 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
609
610 if (HwId != DISPLAY_ADAPTER_HW_ID ||
611 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT))
612 return ERROR_INVALID_FUNCTION;
613
614 /*
615 * Get general power support information.
616 */
617
618 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
619 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
620 BiosRegisters.Ebx = 0;
621 BiosRegisters.Edi = 0;
622 BiosRegisters.SegEs = 0;
623 VBEDeviceExtension->Int10Interface.Int10CallBios(
624 VBEDeviceExtension->Int10Interface.Context,
625 &BiosRegisters);
626
627 if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
628 return ERROR_NOT_SUPPORTED;
629 if (BiosRegisters.Eax != VBE_SUCCESS)
630 return ERROR_INVALID_FUNCTION;
631
632 /*
633 * Get current power state.
634 */
635
636 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
637 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
638 BiosRegisters.Ebx = 0x2;
639 BiosRegisters.Edi = 0;
640 BiosRegisters.SegEs = 0;
641 VBEDeviceExtension->Int10Interface.Int10CallBios(
642 VBEDeviceExtension->Int10Interface.Context,
643 &BiosRegisters);
644
645 if (BiosRegisters.Eax == VBE_SUCCESS)
646 {
647 VideoPowerControl->DPMSVersion = BiosRegisters.Ebx & 0xFF;
648 switch (BiosRegisters.Ebx >> 8)
649 {
650 case 0: VideoPowerControl->PowerState = VideoPowerOn; break;
651 case 1: VideoPowerControl->PowerState = VideoPowerStandBy; break;
652 case 2: VideoPowerControl->PowerState = VideoPowerSuspend; break;
653 case 4: VideoPowerControl->PowerState = VideoPowerOff; break;
654 case 5: VideoPowerControl->PowerState = VideoPowerOn; break;
655 default: VideoPowerControl->PowerState = VideoPowerUnspecified;
656 }
657
658 return NO_ERROR;
659 }
660
661 return ERROR_NOT_SUPPORTED;
662 }
663
664 /*
665 * VBESetPowerState
666 *
667 * Sets the power state of the specified device
668 */
669
670 VP_STATUS STDCALL
671 VBESetPowerState(
672 PVOID HwDeviceExtension,
673 ULONG HwId,
674 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
675 {
676 INT10_BIOS_ARGUMENTS BiosRegisters;
677 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
678 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
679
680 if (HwId != DISPLAY_ADAPTER_HW_ID ||
681 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT) ||
682 VideoPowerControl->PowerState < VideoPowerOn ||
683 VideoPowerControl->PowerState > VideoPowerHibernate)
684 return ERROR_INVALID_FUNCTION;
685
686 if (VideoPowerControl->PowerState == VideoPowerHibernate)
687 return NO_ERROR;
688
689 /*
690 * Set current power state.
691 */
692
693 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
694 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
695 BiosRegisters.Ebx = 1;
696 BiosRegisters.Edi = 0;
697 BiosRegisters.SegEs = 0;
698 switch (VideoPowerControl->PowerState)
699 {
700 case VideoPowerStandBy: BiosRegisters.Ebx |= 0x100; break;
701 case VideoPowerSuspend: BiosRegisters.Ebx |= 0x200; break;
702 case VideoPowerOff: BiosRegisters.Ebx |= 0x400; break;
703 }
704
705 VBEDeviceExtension->Int10Interface.Int10CallBios(
706 VBEDeviceExtension->Int10Interface.Context,
707 &BiosRegisters);
708
709 if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
710 return ERROR_NOT_SUPPORTED;
711 if (BiosRegisters.Eax != VBE_SUCCESS)
712 return ERROR_INVALID_FUNCTION;
713
714 return VBE_SUCCESS;
715 }
716
717 /*
718 * VBESetCurrentMode
719 *
720 * Sets the adapter to the specified operating mode.
721 */
722
723 BOOL FASTCALL
724 VBESetCurrentMode(
725 PVBE_DEVICE_EXTENSION DeviceExtension,
726 PVIDEO_MODE RequestedMode,
727 PSTATUS_BLOCK StatusBlock)
728 {
729 INT10_BIOS_ARGUMENTS BiosRegisters;
730
731 if (RequestedMode->RequestedMode >= DeviceExtension->ModeCount)
732 {
733 return ERROR_INVALID_PARAMETER;
734 }
735
736 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
737 BiosRegisters.Eax = VBE_SET_VBE_MODE;
738 BiosRegisters.Ebx = DeviceExtension->ModeNumbers[RequestedMode->RequestedMode];
739 DeviceExtension->Int10Interface.Int10CallBios(
740 DeviceExtension->Int10Interface.Context,
741 &BiosRegisters);
742
743 if (BiosRegisters.Eax == VBE_SUCCESS)
744 {
745 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
746 }
747 else
748 {
749 DPRINT1("VBEMP: VBESetCurrentMode failed (%x)\n", BiosRegisters.Eax);
750 DeviceExtension->CurrentMode = -1;
751 }
752
753 return BiosRegisters.Eax == VBE_SUCCESS;
754 }
755
756 /*
757 * VBEResetDevice
758 *
759 * Resets the video hardware to the default mode, to which it was initialized
760 * at system boot.
761 */
762
763 BOOL FASTCALL
764 VBEResetDevice(
765 PVBE_DEVICE_EXTENSION DeviceExtension,
766 PSTATUS_BLOCK StatusBlock)
767 {
768 INT10_BIOS_ARGUMENTS BiosRegisters;
769
770 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
771 BiosRegisters.Eax = VBE_SET_VBE_MODE;
772 BiosRegisters.Ebx = 0x3;
773 DeviceExtension->Int10Interface.Int10CallBios(
774 DeviceExtension->Int10Interface.Context,
775 &BiosRegisters);
776
777 return BiosRegisters.Eax == VBE_SUCCESS;
778 }
779
780 /*
781 * VBEMapVideoMemory
782 *
783 * Maps the video hardware frame buffer and video RAM into the virtual address
784 * space of the requestor.
785 */
786
787 BOOL FASTCALL
788 VBEMapVideoMemory(
789 PVBE_DEVICE_EXTENSION DeviceExtension,
790 PVIDEO_MEMORY RequestedAddress,
791 PVIDEO_MEMORY_INFORMATION MapInformation,
792 PSTATUS_BLOCK StatusBlock)
793 {
794 PHYSICAL_ADDRESS FrameBuffer;
795 ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
796
797 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
798
799 if (DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].ModeAttributes &
800 VBE_MODEATTR_LINEAR)
801 {
802 FrameBuffer.QuadPart =
803 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].PhysBasePtr;
804 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
805 if (DeviceExtension->VbeInfo.Version < 0x300)
806 {
807 MapInformation->VideoRamLength =
808 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].BytesPerScanLine *
809 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
810 }
811 else
812 {
813 MapInformation->VideoRamLength =
814 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].LinBytesPerScanLine *
815 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
816 }
817 }
818 #ifdef VBE12_SUPPORT
819 else
820 {
821 FrameBuffer.QuadPart = 0xA0000;
822 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
823 MapInformation->VideoRamLength = 0x10000;
824 }
825 #endif
826
827 VideoPortMapMemory(DeviceExtension, FrameBuffer,
828 &MapInformation->VideoRamLength, &inIoSpace,
829 &MapInformation->VideoRamBase);
830
831 MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
832 MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
833
834 return TRUE;
835 }
836
837 /*
838 * VBEUnmapVideoMemory
839 *
840 * Releases a mapping between the virtual address space and the adapter's
841 * frame buffer and video RAM.
842 */
843
844 BOOL FASTCALL
845 VBEUnmapVideoMemory(
846 PVBE_DEVICE_EXTENSION DeviceExtension,
847 PVIDEO_MEMORY VideoMemory,
848 PSTATUS_BLOCK StatusBlock)
849 {
850 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress,
851 NULL);
852 return TRUE;
853 }
854
855 /*
856 * VBEQueryNumAvailModes
857 *
858 * Returns the number of video modes supported by the adapter and the size
859 * in bytes of the video mode information, which can be used to allocate a
860 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
861 */
862
863 BOOL FASTCALL
864 VBEQueryNumAvailModes(
865 PVBE_DEVICE_EXTENSION DeviceExtension,
866 PVIDEO_NUM_MODES Modes,
867 PSTATUS_BLOCK StatusBlock)
868 {
869 Modes->NumModes = DeviceExtension->ModeCount;
870 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
871 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
872 return TRUE;
873 }
874
875 /*
876 * VBEQueryMode
877 *
878 * Returns information about one particular video mode.
879 */
880
881 VOID FASTCALL
882 VBEQueryMode(
883 PVBE_DEVICE_EXTENSION DeviceExtension,
884 PVIDEO_MODE_INFORMATION VideoMode,
885 ULONG VideoModeId)
886 {
887 PVBE_MODEINFO VBEMode = &DeviceExtension->ModeInfo[VideoModeId];
888
889 VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
890 VideoMode->ModeIndex = VideoModeId;
891 VideoMode->VisScreenWidth = VBEMode->XResolution;
892 VideoMode->VisScreenHeight = VBEMode->YResolution;
893 if (DeviceExtension->VbeInfo.Version < 0x300)
894 VideoMode->ScreenStride = VBEMode->BytesPerScanLine;
895 else
896 VideoMode->ScreenStride = VBEMode->LinBytesPerScanLine;
897 VideoMode->NumberOfPlanes = VBEMode->NumberOfPlanes;
898 VideoMode->BitsPerPlane = VBEMode->BitsPerPixel / VBEMode->NumberOfPlanes;
899 VideoMode->Frequency = 1;
900 VideoMode->XMillimeter = 0; /* FIXME */
901 VideoMode->YMillimeter = 0; /* FIXME */
902 if (VBEMode->BitsPerPixel > 8)
903 {
904 /*
905 * Always report 16bpp modes and not 15bpp mode...
906 */
907 if (VBEMode->BitsPerPixel == 15 && VBEMode->NumberOfPlanes == 1)
908 {
909 VideoMode->BitsPerPlane = 16;
910 }
911
912 if (DeviceExtension->VbeInfo.Version < 0x300)
913 {
914 VideoMode->NumberRedBits = VBEMode->RedMaskSize;
915 VideoMode->NumberGreenBits = VBEMode->GreenMaskSize;
916 VideoMode->NumberBlueBits = VBEMode->BlueMaskSize;
917 VideoMode->RedMask = ((1 << VBEMode->RedMaskSize) - 1) << VBEMode->RedFieldPosition;
918 VideoMode->GreenMask = ((1 << VBEMode->GreenMaskSize) - 1) << VBEMode->GreenFieldPosition;
919 VideoMode->BlueMask = ((1 << VBEMode->BlueMaskSize) - 1) << VBEMode->BlueFieldPosition;
920 }
921 else
922 {
923 VideoMode->NumberRedBits = VBEMode->LinRedMaskSize;
924 VideoMode->NumberGreenBits = VBEMode->LinGreenMaskSize;
925 VideoMode->NumberBlueBits = VBEMode->LinBlueMaskSize;
926 VideoMode->RedMask = ((1 << VBEMode->LinRedMaskSize) - 1) << VBEMode->LinRedFieldPosition;
927 VideoMode->GreenMask = ((1 << VBEMode->LinGreenMaskSize) - 1) << VBEMode->LinGreenFieldPosition;
928 VideoMode->BlueMask = ((1 << VBEMode->LinBlueMaskSize) - 1) << VBEMode->LinBlueFieldPosition;
929 }
930 }
931 else
932 {
933 VideoMode->NumberRedBits =
934 VideoMode->NumberGreenBits =
935 VideoMode->NumberBlueBits = 6;
936 VideoMode->RedMask =
937 VideoMode->GreenMask =
938 VideoMode->BlueMask = 0;
939 }
940 VideoMode->VideoMemoryBitmapWidth = VBEMode->XResolution;
941 VideoMode->VideoMemoryBitmapHeight = VBEMode->YResolution;
942 VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
943 VIDEO_MODE_NO_OFF_SCREEN;
944 if (VideoMode->BitsPerPlane <= 8)
945 VideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN;
946 VideoMode->DriverSpecificAttributeFlags = 0;
947 }
948
949 /*
950 * VBEQueryAvailModes
951 *
952 * Returns information about each video mode supported by the adapter.
953 */
954
955 BOOL FASTCALL
956 VBEQueryAvailModes(
957 PVBE_DEVICE_EXTENSION DeviceExtension,
958 PVIDEO_MODE_INFORMATION ReturnedModes,
959 PSTATUS_BLOCK StatusBlock)
960 {
961 ULONG CurrentModeId;
962 PVIDEO_MODE_INFORMATION CurrentMode;
963 PVBE_MODEINFO CurrentVBEMode;
964
965 for (CurrentModeId = 0, CurrentMode = ReturnedModes,
966 CurrentVBEMode = DeviceExtension->ModeInfo;
967 CurrentModeId < DeviceExtension->ModeCount;
968 CurrentModeId++, CurrentMode++, CurrentVBEMode++)
969 {
970 VBEQueryMode(DeviceExtension, CurrentMode, CurrentModeId);
971 }
972
973 StatusBlock->Information =
974 sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->ModeCount;
975
976 return TRUE;
977 }
978
979 /*
980 * VBEQueryCurrentMode
981 *
982 * Returns information about current video mode.
983 */
984
985 BOOL FASTCALL
986 VBEQueryCurrentMode(
987 PVBE_DEVICE_EXTENSION DeviceExtension,
988 PVIDEO_MODE_INFORMATION VideoModeInfo,
989 PSTATUS_BLOCK StatusBlock)
990 {
991 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
992
993 VBEQueryMode(
994 DeviceExtension,
995 VideoModeInfo,
996 DeviceExtension->CurrentMode);
997
998 return TRUE;
999 }
1000
1001 /*
1002 * VBESetColorRegisters
1003 *
1004 * Sets the adapter's color registers to the specified RGB values. There
1005 * are code paths in this function, one generic and one for VGA compatible
1006 * controllers. The latter is needed for Bochs, where the generic one isn't
1007 * yet implemented.
1008 */
1009
1010 BOOL FASTCALL
1011 VBESetColorRegisters(
1012 PVBE_DEVICE_EXTENSION DeviceExtension,
1013 PVIDEO_CLUT ColorLookUpTable,
1014 PSTATUS_BLOCK StatusBlock)
1015 {
1016 INT10_BIOS_ARGUMENTS BiosRegisters;
1017 ULONG Entry;
1018 PULONG OutputEntry;
1019 ULONG OutputBuffer[256];
1020
1021 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
1022 return FALSE;
1023
1024 /*
1025 * For VGA compatible adapters program the color registers directly.
1026 */
1027
1028 if (!(DeviceExtension->VbeInfo.Capabilities & 2))
1029 {
1030 for (Entry = ColorLookUpTable->FirstEntry;
1031 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
1032 Entry++)
1033 {
1034 VideoPortWritePortUchar((PUCHAR)0x03c8, Entry);
1035 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
1036 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
1037 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
1038 }
1039
1040 return TRUE;
1041 }
1042 else
1043 {
1044 /*
1045 * We can't just copy the values, because we need to swap the Red
1046 * and Blue values.
1047 */
1048
1049 for (Entry = ColorLookUpTable->FirstEntry,
1050 OutputEntry = OutputBuffer;
1051 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
1052 Entry++, OutputEntry++)
1053 {
1054 *OutputEntry =
1055 (ColorLookUpTable->LookupTable[Entry].RgbArray.Red << 16) |
1056 (ColorLookUpTable->LookupTable[Entry].RgbArray.Green << 8) |
1057 (ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
1058 }
1059
1060 DeviceExtension->Int10Interface.Int10WriteMemory(
1061 DeviceExtension->Int10Interface.Context,
1062 DeviceExtension->TrampolineMemorySegment,
1063 DeviceExtension->TrampolineMemoryOffset,
1064 OutputBuffer,
1065 (OutputEntry - OutputBuffer) * sizeof(ULONG));
1066
1067 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
1068 BiosRegisters.Eax = VBE_SET_GET_PALETTE_DATA;
1069 BiosRegisters.Ebx = 0;
1070 BiosRegisters.Ecx = ColorLookUpTable->NumEntries;
1071 BiosRegisters.Edx = ColorLookUpTable->FirstEntry;
1072 BiosRegisters.Edi = DeviceExtension->TrampolineMemoryOffset;
1073 BiosRegisters.SegEs = DeviceExtension->TrampolineMemorySegment;
1074 DeviceExtension->Int10Interface.Int10CallBios(
1075 DeviceExtension->Int10Interface.Context,
1076 &BiosRegisters);
1077
1078 return BiosRegisters.Eax == VBE_SUCCESS;
1079 }
1080 }