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