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