- Use LinBytesPerScanLine (value for linar framebuffer modes) instead of BytesPerScan...
[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 return VBEResetDevice(DeviceExtension, NULL);
527 }
528
529 /*
530 * VBEGetPowerState
531 *
532 * Queries whether the device can support the requested power state.
533 */
534
535 VP_STATUS STDCALL
536 VBEGetPowerState(
537 PVOID HwDeviceExtension,
538 ULONG HwId,
539 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
540 {
541 INT10_BIOS_ARGUMENTS BiosRegisters;
542 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
543 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
544
545 if (HwId != DISPLAY_ADAPTER_HW_ID ||
546 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT))
547 return ERROR_INVALID_FUNCTION;
548
549 /*
550 * Get general power support information.
551 */
552
553 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
554 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
555 BiosRegisters.Ebx = 0;
556 BiosRegisters.Edi = 0;
557 BiosRegisters.SegEs = 0;
558 VBEDeviceExtension->Int10Interface.Int10CallBios(
559 VBEDeviceExtension->Int10Interface.Context,
560 &BiosRegisters);
561
562 if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
563 return ERROR_NOT_SUPPORTED;
564 if (BiosRegisters.Eax != VBE_SUCCESS)
565 return ERROR_INVALID_FUNCTION;
566
567 /*
568 * Get current power state.
569 */
570
571 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
572 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
573 BiosRegisters.Ebx = 0x2;
574 BiosRegisters.Edi = 0;
575 BiosRegisters.SegEs = 0;
576 VBEDeviceExtension->Int10Interface.Int10CallBios(
577 VBEDeviceExtension->Int10Interface.Context,
578 &BiosRegisters);
579
580 if (BiosRegisters.Eax == VBE_SUCCESS)
581 {
582 VideoPowerControl->DPMSVersion = BiosRegisters.Ebx & 0xFF;
583 switch (BiosRegisters.Ebx >> 8)
584 {
585 case 0: VideoPowerControl->PowerState = VideoPowerOn; break;
586 case 1: VideoPowerControl->PowerState = VideoPowerStandBy; break;
587 case 2: VideoPowerControl->PowerState = VideoPowerSuspend; break;
588 case 4: VideoPowerControl->PowerState = VideoPowerOff; break;
589 case 5: VideoPowerControl->PowerState = VideoPowerOn; break;
590 default: VideoPowerControl->PowerState = VideoPowerUnspecified;
591 }
592
593 return NO_ERROR;
594 }
595
596 return ERROR_NOT_SUPPORTED;
597 }
598
599 /*
600 * VBESetPowerState
601 *
602 * Sets the power state of the specified device
603 */
604
605 VP_STATUS STDCALL
606 VBESetPowerState(
607 PVOID HwDeviceExtension,
608 ULONG HwId,
609 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
610 {
611 INT10_BIOS_ARGUMENTS BiosRegisters;
612 PVBE_DEVICE_EXTENSION VBEDeviceExtension =
613 (PVBE_DEVICE_EXTENSION)HwDeviceExtension;
614
615 if (HwId != DISPLAY_ADAPTER_HW_ID ||
616 VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT) ||
617 VideoPowerControl->PowerState < VideoPowerOn ||
618 VideoPowerControl->PowerState > VideoPowerHibernate)
619 return ERROR_INVALID_FUNCTION;
620
621 if (VideoPowerControl->PowerState == VideoPowerHibernate)
622 return NO_ERROR;
623
624 /*
625 * Set current power state.
626 */
627
628 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
629 BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
630 BiosRegisters.Ebx = 1;
631 BiosRegisters.Edi = 0;
632 BiosRegisters.SegEs = 0;
633 switch (VideoPowerControl->PowerState)
634 {
635 case VideoPowerStandBy: BiosRegisters.Ebx |= 0x100; break;
636 case VideoPowerSuspend: BiosRegisters.Ebx |= 0x200; break;
637 case VideoPowerOff: BiosRegisters.Ebx |= 0x400; break;
638 }
639
640 VBEDeviceExtension->Int10Interface.Int10CallBios(
641 VBEDeviceExtension->Int10Interface.Context,
642 &BiosRegisters);
643
644 if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
645 return ERROR_NOT_SUPPORTED;
646 if (BiosRegisters.Eax != VBE_SUCCESS)
647 return ERROR_INVALID_FUNCTION;
648
649 return VBE_SUCCESS;
650 }
651
652 /*
653 * VBESetCurrentMode
654 *
655 * Sets the adapter to the specified operating mode.
656 */
657
658 BOOL FASTCALL
659 VBESetCurrentMode(
660 PVBE_DEVICE_EXTENSION DeviceExtension,
661 PVIDEO_MODE RequestedMode,
662 PSTATUS_BLOCK StatusBlock)
663 {
664 INT10_BIOS_ARGUMENTS BiosRegisters;
665
666 if (RequestedMode->RequestedMode >= DeviceExtension->ModeCount)
667 {
668 return ERROR_INVALID_PARAMETER;
669 }
670
671 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
672 BiosRegisters.Eax = VBE_SET_VBE_MODE;
673 BiosRegisters.Ebx = DeviceExtension->ModeNumbers[RequestedMode->RequestedMode];
674 DeviceExtension->Int10Interface.Int10CallBios(
675 DeviceExtension->Int10Interface.Context,
676 &BiosRegisters);
677
678 if (BiosRegisters.Eax == VBE_SUCCESS)
679 {
680 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
681 }
682 else
683 {
684 DPRINT(("VBEMP: VBESetCurrentMode failed (%x)\n", BiosRegisters.Eax));
685 DeviceExtension->CurrentMode = -1;
686 }
687
688 return BiosRegisters.Eax == VBE_SUCCESS;
689 }
690
691 /*
692 * VBEResetDevice
693 *
694 * Resets the video hardware to the default mode, to which it was initialized
695 * at system boot.
696 */
697
698 BOOL FASTCALL
699 VBEResetDevice(
700 PVBE_DEVICE_EXTENSION DeviceExtension,
701 PSTATUS_BLOCK StatusBlock)
702 {
703 INT10_BIOS_ARGUMENTS BiosRegisters;
704
705 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
706 BiosRegisters.Eax = VBE_SET_VBE_MODE;
707 BiosRegisters.Ebx = 0x3;
708 DeviceExtension->Int10Interface.Int10CallBios(
709 DeviceExtension->Int10Interface.Context,
710 &BiosRegisters);
711
712 return BiosRegisters.Eax == VBE_SUCCESS;
713 }
714
715 /*
716 * VBEMapVideoMemory
717 *
718 * Maps the video hardware frame buffer and video RAM into the virtual address
719 * space of the requestor.
720 */
721
722 BOOL FASTCALL
723 VBEMapVideoMemory(
724 PVBE_DEVICE_EXTENSION DeviceExtension,
725 PVIDEO_MEMORY RequestedAddress,
726 PVIDEO_MEMORY_INFORMATION MapInformation,
727 PSTATUS_BLOCK StatusBlock)
728 {
729 PHYSICAL_ADDRESS FrameBuffer;
730 ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
731
732 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
733
734 if (DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].ModeAttributes &
735 VBE_MODEATTR_LINEAR)
736 {
737 FrameBuffer.QuadPart =
738 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].PhysBasePtr;
739 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
740 if (DeviceExtension->VbeInfo.Version < 0x300)
741 {
742 MapInformation->VideoRamLength =
743 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].BytesPerScanLine *
744 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
745 }
746 else
747 {
748 MapInformation->VideoRamLength =
749 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].LinBytesPerScanLine *
750 DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
751 }
752 }
753 #ifdef VBE12_SUPPORT
754 else
755 {
756 FrameBuffer.QuadPart = 0xA0000;
757 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
758 MapInformation->VideoRamLength = 0x10000;
759 }
760 #endif
761
762 VideoPortMapMemory(DeviceExtension, FrameBuffer,
763 &MapInformation->VideoRamLength, &inIoSpace,
764 &MapInformation->VideoRamBase);
765
766 MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
767 MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
768
769 return TRUE;
770 }
771
772 /*
773 * VBEUnmapVideoMemory
774 *
775 * Releases a mapping between the virtual address space and the adapter's
776 * frame buffer and video RAM.
777 */
778
779 BOOL FASTCALL
780 VBEUnmapVideoMemory(
781 PVBE_DEVICE_EXTENSION DeviceExtension,
782 PVIDEO_MEMORY VideoMemory,
783 PSTATUS_BLOCK StatusBlock)
784 {
785 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress,
786 NULL);
787 return TRUE;
788 }
789
790 /*
791 * VBEQueryNumAvailModes
792 *
793 * Returns the number of video modes supported by the adapter and the size
794 * in bytes of the video mode information, which can be used to allocate a
795 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
796 */
797
798 BOOL FASTCALL
799 VBEQueryNumAvailModes(
800 PVBE_DEVICE_EXTENSION DeviceExtension,
801 PVIDEO_NUM_MODES Modes,
802 PSTATUS_BLOCK StatusBlock)
803 {
804 Modes->NumModes = DeviceExtension->ModeCount;
805 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
806 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
807 return TRUE;
808 }
809
810 /*
811 * VBEQueryMode
812 *
813 * Returns information about one particular video mode.
814 */
815
816 VOID FASTCALL
817 VBEQueryMode(
818 PVBE_DEVICE_EXTENSION DeviceExtension,
819 PVIDEO_MODE_INFORMATION VideoMode,
820 ULONG VideoModeId)
821 {
822 PVBE_MODEINFO VBEMode = &DeviceExtension->ModeInfo[VideoModeId];
823
824 VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
825 VideoMode->ModeIndex = VideoModeId;
826 VideoMode->VisScreenWidth = VBEMode->XResolution;
827 VideoMode->VisScreenHeight = VBEMode->YResolution;
828 if (DeviceExtension->VbeInfo.Version < 0x300)
829 VideoMode->ScreenStride = VBEMode->BytesPerScanLine;
830 else
831 VideoMode->ScreenStride = VBEMode->LinBytesPerScanLine;
832 VideoMode->NumberOfPlanes = VBEMode->NumberOfPlanes;
833 VideoMode->BitsPerPlane = VBEMode->BitsPerPixel / VBEMode->NumberOfPlanes;
834 VideoMode->Frequency = 1;
835 VideoMode->XMillimeter = 0; /* FIXME */
836 VideoMode->YMillimeter = 0; /* FIXME */
837 if (VBEMode->BitsPerPixel > 8)
838 {
839 if (DeviceExtension->VbeInfo.Version < 0x300)
840 {
841 VideoMode->NumberRedBits = VBEMode->RedMaskSize;
842 VideoMode->NumberGreenBits = VBEMode->GreenMaskSize;
843 VideoMode->NumberBlueBits = VBEMode->BlueMaskSize;
844 VideoMode->RedMask = ((1 << VBEMode->RedMaskSize) - 1) << VBEMode->RedFieldPosition;
845 VideoMode->GreenMask = ((1 << VBEMode->GreenMaskSize) - 1) << VBEMode->GreenFieldPosition;
846 VideoMode->BlueMask = ((1 << VBEMode->BlueMaskSize) - 1) << VBEMode->BlueFieldPosition;
847 }
848 else
849 {
850 VideoMode->NumberRedBits = VBEMode->LinRedMaskSize;
851 VideoMode->NumberGreenBits = VBEMode->LinGreenMaskSize;
852 VideoMode->NumberBlueBits = VBEMode->LinBlueMaskSize;
853 VideoMode->RedMask = ((1 << VBEMode->LinRedMaskSize) - 1) << VBEMode->LinRedFieldPosition;
854 VideoMode->GreenMask = ((1 << VBEMode->LinGreenMaskSize) - 1) << VBEMode->LinGreenFieldPosition;
855 VideoMode->BlueMask = ((1 << VBEMode->LinBlueMaskSize) - 1) << VBEMode->LinBlueFieldPosition;
856 }
857 }
858 else
859 {
860 VideoMode->NumberRedBits =
861 VideoMode->NumberGreenBits =
862 VideoMode->NumberBlueBits = 6;
863 VideoMode->RedMask =
864 VideoMode->GreenMask =
865 VideoMode->BlueMask = 0;
866 }
867 VideoMode->VideoMemoryBitmapWidth = VBEMode->XResolution;
868 VideoMode->VideoMemoryBitmapHeight = VBEMode->YResolution;
869 VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
870 VIDEO_MODE_NO_OFF_SCREEN;
871 if (VideoMode->BitsPerPlane <= 8)
872 VideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN;
873 VideoMode->DriverSpecificAttributeFlags = 0;
874 }
875
876 /*
877 * VBEQueryAvailModes
878 *
879 * Returns information about each video mode supported by the adapter.
880 */
881
882 BOOL FASTCALL
883 VBEQueryAvailModes(
884 PVBE_DEVICE_EXTENSION DeviceExtension,
885 PVIDEO_MODE_INFORMATION ReturnedModes,
886 PSTATUS_BLOCK StatusBlock)
887 {
888 ULONG CurrentModeId;
889 PVIDEO_MODE_INFORMATION CurrentMode;
890 PVBE_MODEINFO CurrentVBEMode;
891
892 for (CurrentModeId = 0, CurrentMode = ReturnedModes,
893 CurrentVBEMode = DeviceExtension->ModeInfo;
894 CurrentModeId < DeviceExtension->ModeCount;
895 CurrentModeId++, CurrentMode++, CurrentVBEMode++)
896 {
897 VBEQueryMode(DeviceExtension, CurrentMode, CurrentModeId);
898 }
899
900 StatusBlock->Information =
901 sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->ModeCount;
902
903 return TRUE;
904 }
905
906 /*
907 * VBEQueryCurrentMode
908 *
909 * Returns information about current video mode.
910 */
911
912 BOOL FASTCALL
913 VBEQueryCurrentMode(
914 PVBE_DEVICE_EXTENSION DeviceExtension,
915 PVIDEO_MODE_INFORMATION VideoModeInfo,
916 PSTATUS_BLOCK StatusBlock)
917 {
918 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
919
920 VBEQueryMode(
921 DeviceExtension,
922 VideoModeInfo,
923 DeviceExtension->CurrentMode);
924
925 return TRUE;
926 }
927
928 /*
929 * VBESetColorRegisters
930 *
931 * Sets the adapter's color registers to the specified RGB values. There
932 * are code paths in this function, one generic and one for VGA compatible
933 * controllers. The latter is needed for Bochs, where the generic one isn't
934 * yet implemented.
935 */
936
937 BOOL FASTCALL
938 VBESetColorRegisters(
939 PVBE_DEVICE_EXTENSION DeviceExtension,
940 PVIDEO_CLUT ColorLookUpTable,
941 PSTATUS_BLOCK StatusBlock)
942 {
943 INT10_BIOS_ARGUMENTS BiosRegisters;
944 ULONG Entry;
945 PULONG OutputEntry;
946 ULONG OutputBuffer[256];
947
948 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
949 return FALSE;
950
951 /*
952 * For VGA compatible adapters program the color registers directly.
953 */
954
955 if (!(DeviceExtension->VbeInfo.Capabilities & 2))
956 {
957 for (Entry = ColorLookUpTable->FirstEntry;
958 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
959 Entry++)
960 {
961 VideoPortWritePortUchar((PUCHAR)0x03c8, Entry);
962 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
963 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
964 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
965 }
966
967 return TRUE;
968 }
969 else
970 {
971 /*
972 * We can't just copy the values, because we need to swap the Red
973 * and Blue values.
974 */
975
976 for (Entry = ColorLookUpTable->FirstEntry,
977 OutputEntry = OutputBuffer;
978 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
979 Entry++, OutputEntry++)
980 {
981 *OutputEntry =
982 (ColorLookUpTable->LookupTable[Entry].RgbArray.Red << 16) |
983 (ColorLookUpTable->LookupTable[Entry].RgbArray.Green << 8) |
984 (ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
985 }
986
987 DeviceExtension->Int10Interface.Int10WriteMemory(
988 DeviceExtension->Int10Interface.Context,
989 DeviceExtension->TrampolineMemorySegment,
990 DeviceExtension->TrampolineMemoryOffset,
991 OutputBuffer,
992 (OutputEntry - OutputBuffer) * sizeof(ULONG));
993
994 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
995 BiosRegisters.Eax = VBE_SET_GET_PALETTE_DATA;
996 BiosRegisters.Ebx = 0;
997 BiosRegisters.Ecx = ColorLookUpTable->NumEntries;
998 BiosRegisters.Edx = ColorLookUpTable->FirstEntry;
999 BiosRegisters.Edi = DeviceExtension->TrampolineMemoryOffset;
1000 BiosRegisters.SegEs = DeviceExtension->TrampolineMemorySegment;
1001 DeviceExtension->Int10Interface.Int10CallBios(
1002 DeviceExtension->Int10Interface.Context,
1003 &BiosRegisters);
1004
1005 return BiosRegisters.Eax == VBE_SUCCESS;
1006 }
1007 }