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