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