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
13 VgaInterpretCmdStream(
14 PHW_DEVICE_EXTENSION HwDeviceExtension
,
20 PHW_DEVICE_EXTENSION HwDeviceExtension
,
23 // eVb: 2.1 [SET MODE] - Add new output parameter for framebuffer update functionality
29 VgaQueryAvailableModes(
30 PHW_DEVICE_EXTENSION HwDeviceExtension
,
31 PVIDEO_MODE_INFORMATION ModeInformation
,
32 ULONG ModeInformationSize
,
37 VgaQueryNumberOfAvailableModes(
38 PHW_DEVICE_EXTENSION HwDeviceExtension
,
39 PVIDEO_NUM_MODES NumModes
,
46 PHW_DEVICE_EXTENSION HwDeviceExtension
,
47 PVIDEO_MODE_INFORMATION ModeInformation
,
48 ULONG ModeInformationSize
,
54 PHW_DEVICE_EXTENSION HwDeviceExtension
57 #if defined(ALLOC_PRAGMA)
58 #pragma alloc_text(PAGE,VgaInterpretCmdStream)
59 #pragma alloc_text(PAGE,VgaSetMode)
60 #pragma alloc_text(PAGE,VgaQueryAvailableModes)
61 #pragma alloc_text(PAGE,VgaQueryNumberOfAvailableModes)
62 #pragma alloc_text(PAGE,VgaZeroVideoMemory)
65 //---------------------------------------------------------------------------
67 VgaInterpretCmdStream(
68 PHW_DEVICE_EXTENSION HwDeviceExtension
,
76 Interprets the appropriate command array to set up VGA registers for the
77 requested mode. Typically used to set the VGA into a particular mode by
78 programming all of the registers
82 HwDeviceExtension - Pointer to the miniport driver's device extension.
84 pusCmdStream - array of commands to be interpreted.
88 The status of the operation (can only fail on a bad command); TRUE for
89 success, FALSE for failure.
102 if (pusCmdStream
== NULL
) {
104 VideoDebugPrint((1, "VgaInterpretCmdStream - Invalid pusCmdStream\n"));
108 ulBase
= (ULONG
)HwDeviceExtension
->IOAddress
;
111 // Now set the adapter to the desired mode.
114 while ((ulCmd
= *pusCmdStream
++) != EOD
) {
117 // Determine major command type
120 switch (ulCmd
& 0xF0) {
123 // Basic input/output command
129 // Determine type of inout instruction
135 // Out instruction. Single or multiple outs?
138 if (!(ulCmd
& MULTI
)) {
141 // Single out. Byte or word out?
150 ulPort
= *pusCmdStream
++;
151 jValue
= (UCHAR
) *pusCmdStream
++;
152 VideoPortWritePortUchar((PUCHAR
)(ulBase
+ulPort
),
161 ulPort
= *pusCmdStream
++;
162 usValue
= *pusCmdStream
++;
163 VideoPortWritePortUshort((PUSHORT
)(ulBase
+ulPort
),
171 // Output a string of values
172 // Byte or word outs?
178 // String byte outs. Do in a loop; can't use
179 // VideoPortWritePortBufferUchar because the data
183 ulPort
= ulBase
+ *pusCmdStream
++;
184 culCount
= *pusCmdStream
++;
187 jValue
= (UCHAR
) *pusCmdStream
++;
188 VideoPortWritePortUchar((PUCHAR
)ulPort
,
199 ulPort
= *pusCmdStream
++;
200 culCount
= *pusCmdStream
++;
201 VideoPortWritePortBufferUshort((PUSHORT
)
202 (ulBase
+ ulPort
), pusCmdStream
, culCount
);
203 pusCmdStream
+= culCount
;
212 // Currently, string in instructions aren't supported; all
213 // in instructions are handled as single-byte ins
223 ulPort
= *pusCmdStream
++;
224 jValue
= VideoPortReadPortUchar((PUCHAR
)ulBase
+ulPort
);
232 ulPort
= *pusCmdStream
++;
233 usValue
= VideoPortReadPortUshort((PUSHORT
)
243 // Higher-level input/output commands
249 // Determine type of metaout command, based on minor
252 switch (ulCmd
& 0x0F) {
260 ulPort
= ulBase
+ *pusCmdStream
++;
261 culCount
= *pusCmdStream
++;
262 ulIndex
= *pusCmdStream
++;
266 usValue
= (USHORT
) (ulIndex
+
267 (((ULONG
)(*pusCmdStream
++)) << 8));
268 VideoPortWritePortUshort((PUSHORT
)ulPort
, usValue
);
277 // Masked out (read, AND, XOR, write)
282 ulPort
= *pusCmdStream
++;
283 jValue
= VideoPortReadPortUchar((PUCHAR
)ulBase
+ulPort
);
284 jValue
&= *pusCmdStream
++;
285 jValue
^= *pusCmdStream
++;
286 VideoPortWritePortUchar((PUCHAR
)ulBase
+ ulPort
,
291 // Attribute Controller out
296 ulPort
= ulBase
+ *pusCmdStream
++;
297 culCount
= *pusCmdStream
++;
298 ulIndex
= *pusCmdStream
++;
302 // Write Attribute Controller index
303 VideoPortWritePortUchar((PUCHAR
)ulPort
,
306 // Write Attribute Controller data
307 jValue
= (UCHAR
) *pusCmdStream
++;
308 VideoPortWritePortUchar((PUCHAR
)ulPort
, jValue
);
317 // None of the above; error
337 // Unknown command; error
350 } // end VgaInterpretCmdStream()
355 PHW_DEVICE_EXTENSION HwDeviceExtension
,
358 // eVb: 2.2 [SET MODE] - Add new output parameter for framebuffer update functionality
367 This routine sets the vga into the requested mode.
371 HwDeviceExtension - Pointer to the miniport driver's device extension.
373 Mode - Pointer to the structure containing the information about the
376 ModeSize - Length of the input buffer supplied by the user.
380 ERROR_INSUFFICIENT_BUFFER if the input buffer was not large enough
383 ERROR_INVALID_PARAMETER if the mode number is invalid.
385 NO_ERROR if the operation completed successfully.
390 PVIDEOMODE pRequestedMode
;
392 ULONG RequestedModeNum
;
393 // eVb: 2.3 [SET MODE] - Add new output parameter for framebuffer update functionality
394 *PhysPtrChange
= FALSE
;
397 // Check if the size of the data in the input buffer is large enough.
400 if (ModeSize
< sizeof(VIDEO_MODE
))
402 return ERROR_INSUFFICIENT_BUFFER
;
406 // Extract the clear memory, and map linear bits.
409 RequestedModeNum
= Mode
->RequestedMode
&
410 ~(VIDEO_MODE_NO_ZERO_MEMORY
| VIDEO_MODE_MAP_MEM_LINEAR
);
413 if (!(Mode
->RequestedMode
& VIDEO_MODE_NO_ZERO_MEMORY
))
416 VgaZeroVideoMemory(HwDeviceExtension
);
421 // Check to see if we are requesting a valid mode
423 // eVb: 2.4 [CIRRUS] - Remove Cirrus-specific check for valid mode
424 if ( (RequestedModeNum
>= NumVideoModes
) )
427 VideoDebugPrint((0, "Invalide Mode Number = %d!\n", RequestedModeNum
));
429 return ERROR_INVALID_PARAMETER
;
432 VideoDebugPrint((2, "Attempting to set mode %d\n",
434 // eVb: 2.5 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
435 pRequestedMode
= &VgaModeList
[RequestedModeNum
];
437 VideoDebugPrint((2, "Info on Requested Mode:\n"
438 "\tResolution: %dx%d\n",
439 pRequestedMode
->hres
,
440 pRequestedMode
->vres
));
443 // VESA BIOS mode switch
445 // eVb: 2.6 [VBE] - VBE Mode Switch Support
446 status
= VbeSetMode(HwDeviceExtension
, pRequestedMode
, PhysPtrChange
);
447 if (status
== ERROR_INVALID_FUNCTION
)
453 if (!pRequestedMode
->CmdStream
) return ERROR_INVALID_FUNCTION
;
454 if (!VgaInterpretCmdStream(HwDeviceExtension
, pRequestedMode
->CmdStream
)) return ERROR_INVALID_FUNCTION
;
457 else if (status
!= NO_ERROR
) return status
;
459 // eVb: 2.7 [MODE-X] - Windows VGA Miniport Supports Mode-X, we should too
464 if (pRequestedMode
->hres
== 320)
466 VideoPortDebugPrint(0, "ModeX not support!!!\n");
467 return ERROR_INVALID_PARAMETER
;
474 if (!(pRequestedMode
->fbType
& VIDEO_MODE_GRAPHICS
))
476 // eVb: 2.8 [TODO] - This code path is not implemented yet
477 VideoPortDebugPrint(0, "Text-mode not support!!!\n");
478 return ERROR_INVALID_PARAMETER
;
484 // Update the location of the physical frame buffer within video memory.
486 // eVb: 2.9 [VBE] - Linear and banked support is unified in VGA, unlike Cirrus
487 HwDeviceExtension
->PhysicalVideoMemoryBase
.LowPart
= pRequestedMode
->PhysBase
;
488 HwDeviceExtension
->PhysicalVideoMemoryLength
= pRequestedMode
->PhysSize
;
490 HwDeviceExtension
->PhysicalFrameLength
=
491 pRequestedMode
->FrameBufferSize
;
493 HwDeviceExtension
->PhysicalFrameOffset
.LowPart
=
494 pRequestedMode
->FrameBufferBase
;
498 // Store the new mode value.
501 HwDeviceExtension
->CurrentMode
= pRequestedMode
;
502 HwDeviceExtension
->ModeIndex
= Mode
->RequestedMode
;
509 VgaQueryAvailableModes(
510 PHW_DEVICE_EXTENSION HwDeviceExtension
,
511 PVIDEO_MODE_INFORMATION ModeInformation
,
512 ULONG ModeInformationSize
,
520 This routine returns the list of all available available modes on the
525 HwDeviceExtension - Pointer to the miniport driver's device extension.
527 ModeInformation - Pointer to the output buffer supplied by the user.
528 This is where the list of all valid modes is stored.
530 ModeInformationSize - Length of the output buffer supplied by the user.
532 OutputSize - Pointer to a buffer in which to return the actual size of
533 the data in the buffer. If the buffer was not large enough, this
534 contains the minimum required buffer size.
538 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
539 for the data being returned.
541 NO_ERROR if the operation completed successfully.
546 PVIDEO_MODE_INFORMATION videoModes
= ModeInformation
;
550 // Find out the size of the data to be put in the buffer and return
551 // that in the status information (whether or not the information is
552 // there). If the buffer passed in is not large enough return an
553 // appropriate error code.
556 if (ModeInformationSize
< (*OutputSize
=
557 // eVb: 2.10 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
560 sizeof(VIDEO_MODE_INFORMATION
)) ) {
562 return ERROR_INSUFFICIENT_BUFFER
;
567 // For each mode supported by the card, store the mode characteristics
568 // in the output buffer.
571 for (i
= 0; i
< NumVideoModes
; i
++)
573 videoModes
->Length
= sizeof(VIDEO_MODE_INFORMATION
);
574 videoModes
->ModeIndex
= i
;
575 // eVb: 2.11 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
576 videoModes
->VisScreenWidth
= VgaModeList
[i
].hres
;
577 videoModes
->ScreenStride
= VgaModeList
[i
].wbytes
;
578 videoModes
->VisScreenHeight
= VgaModeList
[i
].vres
;
579 videoModes
->NumberOfPlanes
= VgaModeList
[i
].numPlanes
;
580 videoModes
->BitsPerPlane
= VgaModeList
[i
].bitsPerPlane
;
581 videoModes
->Frequency
= VgaModeList
[i
].Frequency
;
582 videoModes
->XMillimeter
= 320; // temporary hardcoded constant
583 videoModes
->YMillimeter
= 240; // temporary hardcoded constant
584 videoModes
->AttributeFlags
= VgaModeList
[i
].fbType
;
587 if ((VgaModeList
[i
].bitsPerPlane
== 32) ||
588 (VgaModeList
[i
].bitsPerPlane
== 24))
591 videoModes
->NumberRedBits
= 8;
592 videoModes
->NumberGreenBits
= 8;
593 videoModes
->NumberBlueBits
= 8;
594 videoModes
->RedMask
= 0xff0000;
595 videoModes
->GreenMask
= 0x00ff00;
596 videoModes
->BlueMask
= 0x0000ff;
599 else if (VgaModeList
[i
].bitsPerPlane
== 16)
602 videoModes
->NumberRedBits
= 6;
603 videoModes
->NumberGreenBits
= 6;
604 videoModes
->NumberBlueBits
= 6;
605 videoModes
->RedMask
= 0x1F << 11;
606 videoModes
->GreenMask
= 0x3F << 5;
607 videoModes
->BlueMask
= 0x1F;
610 // eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
611 else if (VgaModeList
[i
].bitsPerPlane
== 15)
614 videoModes
->NumberRedBits
= 6;
615 videoModes
->NumberGreenBits
= 6;
616 videoModes
->NumberBlueBits
= 6;
617 videoModes
->RedMask
= 0x3E << 9;
618 videoModes
->GreenMask
= 0x1F << 5;
619 videoModes
->BlueMask
= 0x1F;
625 videoModes
->NumberRedBits
= 6;
626 videoModes
->NumberGreenBits
= 6;
627 videoModes
->NumberBlueBits
= 6;
628 videoModes
->RedMask
= 0;
629 videoModes
->GreenMask
= 0;
630 videoModes
->BlueMask
= 0;
633 // eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
634 videoModes
->AttributeFlags
|= VIDEO_MODE_PALETTE_DRIVEN
|
635 VIDEO_MODE_MANAGED_PALETTE
;
643 } // end VgaGetAvailableModes()
646 VgaQueryNumberOfAvailableModes(
647 PHW_DEVICE_EXTENSION HwDeviceExtension
,
648 PVIDEO_NUM_MODES NumModes
,
657 This routine returns the number of available modes for this particular
662 HwDeviceExtension - Pointer to the miniport driver's device extension.
664 NumModes - Pointer to the output buffer supplied by the user. This is
665 where the number of modes is stored.
667 NumModesSize - Length of the output buffer supplied by the user.
669 OutputSize - Pointer to a buffer in which to return the actual size of
670 the data in the buffer.
674 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
675 for the data being returned.
677 NO_ERROR if the operation completed successfully.
683 // Find out the size of the data to be put in the the buffer and return
684 // that in the status information (whether or not the information is
685 // there). If the buffer passed in is not large enough return an
686 // appropriate error code.
689 if (NumModesSize
< (*OutputSize
= sizeof(VIDEO_NUM_MODES
)) ) {
691 return ERROR_INSUFFICIENT_BUFFER
;
696 // Store the number of modes into the buffer.
699 // eVb: 2.14 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
700 NumModes
->NumModes
= NumVideoModes
;
702 NumModes
->ModeInformationLength
= sizeof(VIDEO_MODE_INFORMATION
);
706 } // end VgaGetNumberOfAvailableModes()
710 PHW_DEVICE_EXTENSION HwDeviceExtension
,
711 PVIDEO_MODE_INFORMATION ModeInformation
,
712 ULONG ModeInformationSize
,
720 This routine returns a description of the current video mode.
724 HwDeviceExtension - Pointer to the miniport driver's device extension.
726 ModeInformation - Pointer to the output buffer supplied by the user.
727 This is where the current mode information is stored.
729 ModeInformationSize - Length of the output buffer supplied by the user.
731 OutputSize - Pointer to a buffer in which to return the actual size of
732 the data in the buffer. If the buffer was not large enough, this
733 contains the minimum required buffer size.
737 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
738 for the data being returned.
740 NO_ERROR if the operation completed successfully.
746 // check if a mode has been set
749 if (HwDeviceExtension
->CurrentMode
== NULL
) {
751 return ERROR_INVALID_FUNCTION
;
756 // Find out the size of the data to be put in the the buffer and return
757 // that in the status information (whether or not the information is
758 // there). If the buffer passed in is not large enough return an
759 // appropriate error code.
762 if (ModeInformationSize
< (*OutputSize
= sizeof(VIDEO_MODE_INFORMATION
))) {
764 return ERROR_INSUFFICIENT_BUFFER
;
769 // Store the characteristics of the current mode into the buffer.
772 ModeInformation
->Length
= sizeof(VIDEO_MODE_INFORMATION
);
773 ModeInformation
->ModeIndex
= HwDeviceExtension
->ModeIndex
;
774 ModeInformation
->VisScreenWidth
= HwDeviceExtension
->CurrentMode
->hres
;
775 ModeInformation
->ScreenStride
= HwDeviceExtension
->CurrentMode
->wbytes
;
776 ModeInformation
->VisScreenHeight
= HwDeviceExtension
->CurrentMode
->vres
;
777 ModeInformation
->NumberOfPlanes
= HwDeviceExtension
->CurrentMode
->numPlanes
;
778 ModeInformation
->BitsPerPlane
= HwDeviceExtension
->CurrentMode
->bitsPerPlane
;
779 ModeInformation
->Frequency
= HwDeviceExtension
->CurrentMode
->Frequency
;
780 ModeInformation
->XMillimeter
= 320; // temporary hardcoded constant
781 ModeInformation
->YMillimeter
= 240; // temporary hardcoded constant
783 ModeInformation
->AttributeFlags
= HwDeviceExtension
->CurrentMode
->fbType
;
785 if ((ModeInformation
->BitsPerPlane
== 32) ||
786 (ModeInformation
->BitsPerPlane
== 24))
789 ModeInformation
->NumberRedBits
= 8;
790 ModeInformation
->NumberGreenBits
= 8;
791 ModeInformation
->NumberBlueBits
= 8;
792 ModeInformation
->RedMask
= 0xff0000;
793 ModeInformation
->GreenMask
= 0x00ff00;
794 ModeInformation
->BlueMask
= 0x0000ff;
797 else if (ModeInformation
->BitsPerPlane
== 16)
800 ModeInformation
->NumberRedBits
= 6;
801 ModeInformation
->NumberGreenBits
= 6;
802 ModeInformation
->NumberBlueBits
= 6;
803 ModeInformation
->RedMask
= 0x1F << 11;
804 ModeInformation
->GreenMask
= 0x3F << 5;
805 ModeInformation
->BlueMask
= 0x1F;
808 // eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
809 else if (ModeInformation
->BitsPerPlane
== 15)
812 ModeInformation
->NumberRedBits
= 6;
813 ModeInformation
->NumberGreenBits
= 6;
814 ModeInformation
->NumberBlueBits
= 6;
815 ModeInformation
->RedMask
= 0x3E << 9;
816 ModeInformation
->GreenMask
= 0x1F << 5;
817 ModeInformation
->BlueMask
= 0x1F;
823 ModeInformation
->NumberRedBits
= 6;
824 ModeInformation
->NumberGreenBits
= 6;
825 ModeInformation
->NumberBlueBits
= 6;
826 ModeInformation
->RedMask
= 0;
827 ModeInformation
->GreenMask
= 0;
828 ModeInformation
->BlueMask
= 0;
831 // eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
832 ModeInformation
->AttributeFlags
|= VIDEO_MODE_PALETTE_DRIVEN
|
833 VIDEO_MODE_MANAGED_PALETTE
;
838 } // end VgaQueryCurrentMode()
843 PHW_DEVICE_EXTENSION HwDeviceExtension
850 This routine zeros the first 256K on the VGA.
854 HwDeviceExtension - Pointer to the miniport driver's device extension.
866 // Map font buffer at A0000
869 VgaInterpretCmdStream(HwDeviceExtension
, EnableA000Data
);
872 // Enable all planes.
875 VideoPortWritePortUchar(HwDeviceExtension
->IOAddress
+ SEQ_ADDRESS_PORT
,
878 temp
= VideoPortReadPortUchar(HwDeviceExtension
->IOAddress
+
879 SEQ_DATA_PORT
) | (UCHAR
)0x0F;
881 VideoPortWritePortUchar(HwDeviceExtension
->IOAddress
+ SEQ_DATA_PORT
,
884 VideoPortZeroDeviceMemory(HwDeviceExtension
->VideoMemoryAddress
, 0xFFFF);
886 VgaInterpretCmdStream(HwDeviceExtension
, DisableA000Color
);