2 * PROJECT: ReactOS VGA Miniport Driver
3 * LICENSE: Microsoft NT4 DDK Sample Code License
4 * FILE: boot/drivers/video/miniport/vga/modeset.c
5 * PURPOSE: Handles switching to Standard VGA Modes for compatible cards
6 * PROGRAMMERS: Copyright (c) 1992 Microsoft Corporation
7 * ReactOS Portable Systems Group
14 VgaInterpretCmdStream(
15 PHW_DEVICE_EXTENSION HwDeviceExtension
,
22 PHW_DEVICE_EXTENSION HwDeviceExtension
,
25 // eVb: 2.1 [SET MODE] - Add new output parameter for framebuffer update functionality
32 VgaQueryAvailableModes(
33 PHW_DEVICE_EXTENSION HwDeviceExtension
,
34 PVIDEO_MODE_INFORMATION ModeInformation
,
35 ULONG ModeInformationSize
,
41 VgaQueryNumberOfAvailableModes(
42 PHW_DEVICE_EXTENSION HwDeviceExtension
,
43 PVIDEO_NUM_MODES NumModes
,
51 PHW_DEVICE_EXTENSION HwDeviceExtension
,
52 PVIDEO_MODE_INFORMATION ModeInformation
,
53 ULONG ModeInformationSize
,
60 PHW_DEVICE_EXTENSION HwDeviceExtension
63 #if defined(ALLOC_PRAGMA)
64 #pragma alloc_text(PAGE,VgaInterpretCmdStream)
65 #pragma alloc_text(PAGE,VgaSetMode)
66 #pragma alloc_text(PAGE,VgaQueryAvailableModes)
67 #pragma alloc_text(PAGE,VgaQueryNumberOfAvailableModes)
68 #pragma alloc_text(PAGE,VgaZeroVideoMemory)
71 //---------------------------------------------------------------------------
74 VgaInterpretCmdStream(
75 PHW_DEVICE_EXTENSION HwDeviceExtension
,
83 Interprets the appropriate command array to set up VGA registers for the
84 requested mode. Typically used to set the VGA into a particular mode by
85 programming all of the registers
89 HwDeviceExtension - Pointer to the miniport driver's device extension.
91 pusCmdStream - array of commands to be interpreted.
95 The status of the operation (can only fail on a bad command); TRUE for
96 success, FALSE for failure.
109 if (pusCmdStream
== NULL
) {
111 VideoDebugPrint((1, "VgaInterpretCmdStream - Invalid pusCmdStream\n"));
115 ulBase
= (ULONG
)HwDeviceExtension
->IOAddress
;
118 // Now set the adapter to the desired mode.
121 while ((ulCmd
= *pusCmdStream
++) != EOD
) {
124 // Determine major command type
127 switch (ulCmd
& 0xF0) {
130 // Basic input/output command
136 // Determine type of inout instruction
142 // Out instruction. Single or multiple outs?
145 if (!(ulCmd
& MULTI
)) {
148 // Single out. Byte or word out?
157 ulPort
= *pusCmdStream
++;
158 jValue
= (UCHAR
) *pusCmdStream
++;
159 VideoPortWritePortUchar((PUCHAR
)(ulBase
+ulPort
),
168 ulPort
= *pusCmdStream
++;
169 usValue
= *pusCmdStream
++;
170 VideoPortWritePortUshort((PUSHORT
)(ulBase
+ulPort
),
178 // Output a string of values
179 // Byte or word outs?
185 // String byte outs. Do in a loop; can't use
186 // VideoPortWritePortBufferUchar because the data
190 ulPort
= ulBase
+ *pusCmdStream
++;
191 culCount
= *pusCmdStream
++;
194 jValue
= (UCHAR
) *pusCmdStream
++;
195 VideoPortWritePortUchar((PUCHAR
)ulPort
,
206 ulPort
= *pusCmdStream
++;
207 culCount
= *pusCmdStream
++;
208 VideoPortWritePortBufferUshort((PUSHORT
)
209 (ulBase
+ ulPort
), pusCmdStream
, culCount
);
210 pusCmdStream
+= culCount
;
219 // Currently, string in instructions aren't supported; all
220 // in instructions are handled as single-byte ins
230 ulPort
= *pusCmdStream
++;
231 jValue
= VideoPortReadPortUchar((PUCHAR
)ulBase
+ulPort
);
239 ulPort
= *pusCmdStream
++;
240 usValue
= VideoPortReadPortUshort((PUSHORT
)
250 // Higher-level input/output commands
256 // Determine type of metaout command, based on minor
259 switch (ulCmd
& 0x0F) {
267 ulPort
= ulBase
+ *pusCmdStream
++;
268 culCount
= *pusCmdStream
++;
269 ulIndex
= *pusCmdStream
++;
273 usValue
= (USHORT
) (ulIndex
+
274 (((ULONG
)(*pusCmdStream
++)) << 8));
275 VideoPortWritePortUshort((PUSHORT
)ulPort
, usValue
);
284 // Masked out (read, AND, XOR, write)
289 ulPort
= *pusCmdStream
++;
290 jValue
= VideoPortReadPortUchar((PUCHAR
)ulBase
+ulPort
);
291 jValue
&= *pusCmdStream
++;
292 jValue
^= *pusCmdStream
++;
293 VideoPortWritePortUchar((PUCHAR
)ulBase
+ ulPort
,
298 // Attribute Controller out
303 ulPort
= ulBase
+ *pusCmdStream
++;
304 culCount
= *pusCmdStream
++;
305 ulIndex
= *pusCmdStream
++;
309 // Write Attribute Controller index
310 VideoPortWritePortUchar((PUCHAR
)ulPort
,
313 // Write Attribute Controller data
314 jValue
= (UCHAR
) *pusCmdStream
++;
315 VideoPortWritePortUchar((PUCHAR
)ulPort
, jValue
);
324 // None of the above; error
344 // Unknown command; error
357 } // end VgaInterpretCmdStream()
362 PHW_DEVICE_EXTENSION HwDeviceExtension
,
365 // eVb: 2.2 [SET MODE] - Add new output parameter for framebuffer update functionality
374 This routine sets the vga into the requested mode.
378 HwDeviceExtension - Pointer to the miniport driver's device extension.
380 Mode - Pointer to the structure containing the information about the
383 ModeSize - Length of the input buffer supplied by the user.
387 ERROR_INSUFFICIENT_BUFFER if the input buffer was not large enough
390 ERROR_INVALID_PARAMETER if the mode number is invalid.
392 NO_ERROR if the operation completed successfully.
397 PVIDEOMODE pRequestedMode
;
399 ULONG RequestedModeNum
;
400 // eVb: 2.3 [SET MODE] - Add new output parameter for framebuffer update functionality
401 *PhysPtrChange
= FALSE
;
404 // Check if the size of the data in the input buffer is large enough.
407 if (ModeSize
< sizeof(VIDEO_MODE
))
409 return ERROR_INSUFFICIENT_BUFFER
;
413 // Extract the clear memory, and map linear bits.
416 RequestedModeNum
= Mode
->RequestedMode
&
417 ~(VIDEO_MODE_NO_ZERO_MEMORY
| VIDEO_MODE_MAP_MEM_LINEAR
);
420 if (!(Mode
->RequestedMode
& VIDEO_MODE_NO_ZERO_MEMORY
))
423 VgaZeroVideoMemory(HwDeviceExtension
);
428 // Check to see if we are requesting a valid mode
430 // eVb: 2.4 [CIRRUS] - Remove Cirrus-specific check for valid mode
431 if ( (RequestedModeNum
>= NumVideoModes
) )
434 VideoDebugPrint((0, "Invalide Mode Number = %d!\n", RequestedModeNum
));
436 return ERROR_INVALID_PARAMETER
;
439 VideoDebugPrint((2, "Attempting to set mode %d\n",
441 // eVb: 2.5 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
442 pRequestedMode
= &VgaModeList
[RequestedModeNum
];
444 VideoDebugPrint((2, "Info on Requested Mode:\n"
445 "\tResolution: %dx%d\n",
446 pRequestedMode
->hres
,
447 pRequestedMode
->vres
));
450 // VESA BIOS mode switch
452 // eVb: 2.6 [VBE] - VBE Mode Switch Support
453 status
= VbeSetMode(HwDeviceExtension
, pRequestedMode
, PhysPtrChange
);
454 if (status
== ERROR_INVALID_FUNCTION
)
460 if (!pRequestedMode
->CmdStream
) return ERROR_INVALID_FUNCTION
;
461 if (!VgaInterpretCmdStream(HwDeviceExtension
, pRequestedMode
->CmdStream
)) return ERROR_INVALID_FUNCTION
;
464 else if (status
!= NO_ERROR
) return status
;
466 // eVb: 2.7 [MODE-X] - Windows VGA Miniport Supports Mode-X, we should too
471 if (pRequestedMode
->hres
== 320)
473 VideoPortDebugPrint(0, "ModeX not support!!!\n");
474 return ERROR_INVALID_PARAMETER
;
481 if (!(pRequestedMode
->fbType
& VIDEO_MODE_GRAPHICS
))
483 // eVb: 2.8 [TODO] - This code path is not implemented yet
484 VideoPortDebugPrint(0, "Text-mode not support!!!\n");
485 return ERROR_INVALID_PARAMETER
;
491 // Update the location of the physical frame buffer within video memory.
493 // eVb: 2.9 [VBE] - Linear and banked support is unified in VGA, unlike Cirrus
494 HwDeviceExtension
->PhysicalVideoMemoryBase
.LowPart
= pRequestedMode
->PhysBase
;
495 HwDeviceExtension
->PhysicalVideoMemoryLength
= pRequestedMode
->PhysSize
;
497 HwDeviceExtension
->PhysicalFrameLength
=
498 pRequestedMode
->FrameBufferSize
;
500 HwDeviceExtension
->PhysicalFrameOffset
.LowPart
=
501 pRequestedMode
->FrameBufferBase
;
505 // Store the new mode value.
508 HwDeviceExtension
->CurrentMode
= pRequestedMode
;
509 HwDeviceExtension
->ModeIndex
= Mode
->RequestedMode
;
517 VgaQueryAvailableModes(
518 PHW_DEVICE_EXTENSION HwDeviceExtension
,
519 PVIDEO_MODE_INFORMATION ModeInformation
,
520 ULONG ModeInformationSize
,
528 This routine returns the list of all available available modes on the
533 HwDeviceExtension - Pointer to the miniport driver's device extension.
535 ModeInformation - Pointer to the output buffer supplied by the user.
536 This is where the list of all valid modes is stored.
538 ModeInformationSize - Length of the output buffer supplied by the user.
540 OutputSize - Pointer to a buffer in which to return the actual size of
541 the data in the buffer. If the buffer was not large enough, this
542 contains the minimum required buffer size.
546 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
547 for the data being returned.
549 NO_ERROR if the operation completed successfully.
554 PVIDEO_MODE_INFORMATION videoModes
= ModeInformation
;
558 // Find out the size of the data to be put in the buffer and return
559 // that in the status information (whether or not the information is
560 // there). If the buffer passed in is not large enough return an
561 // appropriate error code.
564 if (ModeInformationSize
< (*OutputSize
=
565 // eVb: 2.10 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
568 sizeof(VIDEO_MODE_INFORMATION
)) ) {
570 return ERROR_INSUFFICIENT_BUFFER
;
575 // For each mode supported by the card, store the mode characteristics
576 // in the output buffer.
579 for (i
= 0; i
< NumVideoModes
; i
++)
581 videoModes
->Length
= sizeof(VIDEO_MODE_INFORMATION
);
582 videoModes
->ModeIndex
= i
;
583 // eVb: 2.11 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
584 videoModes
->VisScreenWidth
= VgaModeList
[i
].hres
;
585 videoModes
->ScreenStride
= VgaModeList
[i
].wbytes
;
586 videoModes
->VisScreenHeight
= VgaModeList
[i
].vres
;
587 videoModes
->NumberOfPlanes
= VgaModeList
[i
].numPlanes
;
588 videoModes
->BitsPerPlane
= VgaModeList
[i
].bitsPerPlane
;
589 videoModes
->Frequency
= VgaModeList
[i
].Frequency
;
590 videoModes
->XMillimeter
= 320; // temporary hardcoded constant
591 videoModes
->YMillimeter
= 240; // temporary hardcoded constant
592 videoModes
->AttributeFlags
= VgaModeList
[i
].fbType
;
595 if ((VgaModeList
[i
].bitsPerPlane
== 32) ||
596 (VgaModeList
[i
].bitsPerPlane
== 24))
599 videoModes
->NumberRedBits
= 8;
600 videoModes
->NumberGreenBits
= 8;
601 videoModes
->NumberBlueBits
= 8;
602 videoModes
->RedMask
= 0xff0000;
603 videoModes
->GreenMask
= 0x00ff00;
604 videoModes
->BlueMask
= 0x0000ff;
607 else if (VgaModeList
[i
].bitsPerPlane
== 16)
610 videoModes
->NumberRedBits
= 6;
611 videoModes
->NumberGreenBits
= 6;
612 videoModes
->NumberBlueBits
= 6;
613 videoModes
->RedMask
= 0x1F << 11;
614 videoModes
->GreenMask
= 0x3F << 5;
615 videoModes
->BlueMask
= 0x1F;
618 // eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
619 else if (VgaModeList
[i
].bitsPerPlane
== 15)
622 videoModes
->NumberRedBits
= 6;
623 videoModes
->NumberGreenBits
= 6;
624 videoModes
->NumberBlueBits
= 6;
625 videoModes
->RedMask
= 0x3E << 9;
626 videoModes
->GreenMask
= 0x1F << 5;
627 videoModes
->BlueMask
= 0x1F;
633 videoModes
->NumberRedBits
= 6;
634 videoModes
->NumberGreenBits
= 6;
635 videoModes
->NumberBlueBits
= 6;
636 videoModes
->RedMask
= 0;
637 videoModes
->GreenMask
= 0;
638 videoModes
->BlueMask
= 0;
641 // eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
642 videoModes
->AttributeFlags
|= VIDEO_MODE_PALETTE_DRIVEN
|
643 VIDEO_MODE_MANAGED_PALETTE
;
651 } // end VgaGetAvailableModes()
655 VgaQueryNumberOfAvailableModes(
656 PHW_DEVICE_EXTENSION HwDeviceExtension
,
657 PVIDEO_NUM_MODES NumModes
,
666 This routine returns the number of available modes for this particular
671 HwDeviceExtension - Pointer to the miniport driver's device extension.
673 NumModes - Pointer to the output buffer supplied by the user. This is
674 where the number of modes is stored.
676 NumModesSize - Length of the output buffer supplied by the user.
678 OutputSize - Pointer to a buffer in which to return the actual size of
679 the data in the buffer.
683 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
684 for the data being returned.
686 NO_ERROR if the operation completed successfully.
692 // Find out the size of the data to be put in the the buffer and return
693 // that in the status information (whether or not the information is
694 // there). If the buffer passed in is not large enough return an
695 // appropriate error code.
698 if (NumModesSize
< (*OutputSize
= sizeof(VIDEO_NUM_MODES
)) ) {
700 return ERROR_INSUFFICIENT_BUFFER
;
705 // Store the number of modes into the buffer.
708 // eVb: 2.14 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
709 NumModes
->NumModes
= NumVideoModes
;
711 NumModes
->ModeInformationLength
= sizeof(VIDEO_MODE_INFORMATION
);
715 } // end VgaGetNumberOfAvailableModes()
720 PHW_DEVICE_EXTENSION HwDeviceExtension
,
721 PVIDEO_MODE_INFORMATION ModeInformation
,
722 ULONG ModeInformationSize
,
730 This routine returns a description of the current video mode.
734 HwDeviceExtension - Pointer to the miniport driver's device extension.
736 ModeInformation - Pointer to the output buffer supplied by the user.
737 This is where the current mode information is stored.
739 ModeInformationSize - Length of the output buffer supplied by the user.
741 OutputSize - Pointer to a buffer in which to return the actual size of
742 the data in the buffer. If the buffer was not large enough, this
743 contains the minimum required buffer size.
747 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
748 for the data being returned.
750 NO_ERROR if the operation completed successfully.
756 // check if a mode has been set
759 if (HwDeviceExtension
->CurrentMode
== NULL
) {
761 return ERROR_INVALID_FUNCTION
;
766 // Find out the size of the data to be put in the the buffer and return
767 // that in the status information (whether or not the information is
768 // there). If the buffer passed in is not large enough return an
769 // appropriate error code.
772 if (ModeInformationSize
< (*OutputSize
= sizeof(VIDEO_MODE_INFORMATION
))) {
774 return ERROR_INSUFFICIENT_BUFFER
;
779 // Store the characteristics of the current mode into the buffer.
782 ModeInformation
->Length
= sizeof(VIDEO_MODE_INFORMATION
);
783 ModeInformation
->ModeIndex
= HwDeviceExtension
->ModeIndex
;
784 ModeInformation
->VisScreenWidth
= HwDeviceExtension
->CurrentMode
->hres
;
785 ModeInformation
->ScreenStride
= HwDeviceExtension
->CurrentMode
->wbytes
;
786 ModeInformation
->VisScreenHeight
= HwDeviceExtension
->CurrentMode
->vres
;
787 ModeInformation
->NumberOfPlanes
= HwDeviceExtension
->CurrentMode
->numPlanes
;
788 ModeInformation
->BitsPerPlane
= HwDeviceExtension
->CurrentMode
->bitsPerPlane
;
789 ModeInformation
->Frequency
= HwDeviceExtension
->CurrentMode
->Frequency
;
790 ModeInformation
->XMillimeter
= 320; // temporary hardcoded constant
791 ModeInformation
->YMillimeter
= 240; // temporary hardcoded constant
793 ModeInformation
->AttributeFlags
= HwDeviceExtension
->CurrentMode
->fbType
;
795 if ((ModeInformation
->BitsPerPlane
== 32) ||
796 (ModeInformation
->BitsPerPlane
== 24))
799 ModeInformation
->NumberRedBits
= 8;
800 ModeInformation
->NumberGreenBits
= 8;
801 ModeInformation
->NumberBlueBits
= 8;
802 ModeInformation
->RedMask
= 0xff0000;
803 ModeInformation
->GreenMask
= 0x00ff00;
804 ModeInformation
->BlueMask
= 0x0000ff;
807 else if (ModeInformation
->BitsPerPlane
== 16)
810 ModeInformation
->NumberRedBits
= 6;
811 ModeInformation
->NumberGreenBits
= 6;
812 ModeInformation
->NumberBlueBits
= 6;
813 ModeInformation
->RedMask
= 0x1F << 11;
814 ModeInformation
->GreenMask
= 0x3F << 5;
815 ModeInformation
->BlueMask
= 0x1F;
818 // eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
819 else if (ModeInformation
->BitsPerPlane
== 15)
822 ModeInformation
->NumberRedBits
= 6;
823 ModeInformation
->NumberGreenBits
= 6;
824 ModeInformation
->NumberBlueBits
= 6;
825 ModeInformation
->RedMask
= 0x3E << 9;
826 ModeInformation
->GreenMask
= 0x1F << 5;
827 ModeInformation
->BlueMask
= 0x1F;
833 ModeInformation
->NumberRedBits
= 6;
834 ModeInformation
->NumberGreenBits
= 6;
835 ModeInformation
->NumberBlueBits
= 6;
836 ModeInformation
->RedMask
= 0;
837 ModeInformation
->GreenMask
= 0;
838 ModeInformation
->BlueMask
= 0;
841 // eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
842 ModeInformation
->AttributeFlags
|= VIDEO_MODE_PALETTE_DRIVEN
|
843 VIDEO_MODE_MANAGED_PALETTE
;
848 } // end VgaQueryCurrentMode()
853 PHW_DEVICE_EXTENSION HwDeviceExtension
860 This routine zeros the first 256K on the VGA.
864 HwDeviceExtension - Pointer to the miniport driver's device extension.
876 // Map font buffer at A0000
879 VgaInterpretCmdStream(HwDeviceExtension
, EnableA000Data
);
882 // Enable all planes.
885 VideoPortWritePortUchar(HwDeviceExtension
->IOAddress
+ SEQ_ADDRESS_PORT
,
888 temp
= VideoPortReadPortUchar(HwDeviceExtension
->IOAddress
+
889 SEQ_DATA_PORT
) | (UCHAR
)0x0F;
891 VideoPortWritePortUchar(HwDeviceExtension
->IOAddress
+ SEQ_DATA_PORT
,
894 VideoPortZeroDeviceMemory(HwDeviceExtension
->VideoMemoryAddress
, 0xFFFF);
896 VgaInterpretCmdStream(HwDeviceExtension
, DisableA000Color
);