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