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