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