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