2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/video/svga.c
5 * PURPOSE: SuperVGA hardware emulation (Cirrus Logic CL-GD5434 compatible)
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
18 #include <bios/vidbios.h>
24 /* PRIVATE VARIABLES **********************************************************/
26 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
27 static CONST DWORD MemorySize
[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
30 * Activate this line if you want to use the real
31 * RegisterConsoleVDM API of ReactOS/Windows.
33 // #define USE_REAL_REGISTERCONSOLEVDM
35 #define USE_REACTOS_COLORS
36 // #define USE_DOSBOX_COLORS
38 #if defined(USE_REACTOS_COLORS)
41 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
43 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
44 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
45 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
46 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
47 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
48 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
49 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
50 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
51 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
52 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
53 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
54 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
55 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
56 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
57 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
58 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
59 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
60 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
61 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
62 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
63 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
64 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
65 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
66 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
67 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
68 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
69 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
70 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
71 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
72 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
73 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
74 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
75 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
76 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
77 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
78 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
79 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
80 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
81 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
82 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
83 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
84 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
85 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
86 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
87 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
88 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
89 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
90 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
91 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
92 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
93 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
94 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
95 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
96 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
97 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
98 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
99 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
100 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
101 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
102 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
103 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
104 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
105 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
106 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
109 #elif defined(USE_DOSBOX_COLORS)
112 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
114 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
115 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
116 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
117 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
118 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
119 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
120 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
121 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
122 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
123 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
124 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
125 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
126 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
127 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
128 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
129 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
131 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
132 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
133 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
134 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
135 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
136 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
137 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
138 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
139 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
140 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
141 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
142 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
143 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
144 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
145 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
146 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
148 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
149 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
150 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
151 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
152 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
153 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
154 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
155 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
156 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
157 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
158 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
159 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
160 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
161 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
162 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
163 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
165 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
166 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
167 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
168 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
169 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
170 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
171 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
172 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
173 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
174 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
175 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
176 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
177 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
178 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
179 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
180 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
186 * Default 16-color palette for foreground and background
187 * (corresponding flags in comments).
188 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
190 static const COLORREF ConsoleColors
[16] =
192 RGB(0, 0, 0), // (Black)
193 RGB(0, 0, 128), // BLUE
194 RGB(0, 128, 0), // GREEN
195 RGB(0, 128, 128), // BLUE | GREEN
196 RGB(128, 0, 0), // RED
197 RGB(128, 0, 128), // BLUE | RED
198 RGB(128, 128, 0), // GREEN | RED
199 RGB(192, 192, 192), // BLUE | GREEN | RED
201 RGB(128, 128, 128), // (Grey) INTENSITY
202 RGB(0, 0, 255), // BLUE | INTENSITY
203 RGB(0, 255, 0), // GREEN | INTENSITY
204 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
205 RGB(255, 0, 0), // RED | INTENSITY
206 RGB(255, 0, 255), // BLUE | RED | INTENSITY
207 RGB(255, 255, 0), // GREEN | RED | INTENSITY
208 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
212 * Console interface -- VGA-mode-agnostic
214 // WARNING! This structure *MUST BE* in sync with the one in consrv/include/conio_winsrv.h
215 typedef struct _CHAR_CELL
219 } CHAR_CELL
, *PCHAR_CELL
;
220 C_ASSERT(sizeof(CHAR_CELL
) == 2);
222 static PVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
223 // either TextFramebuffer or a
224 // valid graphics framebuffer.
225 static HPALETTE TextPaletteHandle
= NULL
;
226 static HPALETTE PaletteHandle
= NULL
;
228 static HANDLE StartEvent
= NULL
;
229 static HANDLE EndEvent
= NULL
;
230 static HANDLE AnotherEvent
= NULL
;
232 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
233 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
236 static HANDLE ScreenBufferHandle
= NULL
;
237 static PVOID OldConsoleFramebuffer
= NULL
;
241 * Text mode -- we always keep a valid text mode framebuffer
242 * even if we are in graphics mode. This is needed in order
243 * to keep a consistent VGA state. However, each time the VGA
244 * detaches from the console (and reattaches to it later on),
245 * this text mode framebuffer is recreated.
247 static HANDLE TextConsoleBuffer
= NULL
;
248 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
249 static COORD TextResolution
= {0};
250 static PCHAR_CELL TextFramebuffer
= NULL
;
255 static HANDLE GraphicsConsoleBuffer
= NULL
;
256 static PVOID GraphicsFramebuffer
= NULL
;
257 static HANDLE ConsoleMutex
= NULL
;
258 /* DoubleVision support */
259 static BOOLEAN DoubleWidth
= FALSE
;
260 static BOOLEAN DoubleHeight
= FALSE
;
266 static BYTE VgaMemory
[VGA_NUM_BANKS
* SVGA_BANK_SIZE
];
268 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
270 static BYTE VgaMiscRegister
;
271 static BYTE VgaFeatureRegister
;
273 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
274 static BYTE VgaSeqRegisters
[SVGA_SEQ_MAX_REG
];
276 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
277 static BYTE VgaCrtcRegisters
[SVGA_CRTC_MAX_REG
];
279 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
280 static BYTE VgaGcRegisters
[SVGA_GC_MAX_REG
];
282 static BOOLEAN VgaAcLatch
= FALSE
;
283 static BOOLEAN VgaAcPalDisable
= TRUE
;
284 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
285 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
287 static BYTE VgaDacMask
= 0xFF;
288 static BYTE VgaDacLatchCounter
= 0;
289 static BYTE VgaDacLatch
[3];
291 static BOOLEAN VgaDacReadWrite
= FALSE
;
292 static WORD VgaDacIndex
= 0;
293 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
295 // static VGA_REGISTERS VgaRegisters;
297 static ULONGLONG VerticalRetraceCycle
= 0ULL;
298 static ULONGLONG HorizontalRetraceCycle
= 0ULL;
299 static PHARDWARE_TIMER VSyncTimer
;
300 static PHARDWARE_TIMER HSyncTimer
;
302 static BOOLEAN NeedsUpdate
= FALSE
;
303 static BOOLEAN ModeChanged
= FALSE
;
304 static BOOLEAN CursorChanged
= FALSE
;
305 static BOOLEAN PaletteChanged
= FALSE
;
307 static UINT SvgaHdrCounter
= 0;
308 static BYTE SvgaHiddenRegister
= 0;
310 typedef enum _SCREEN_MODE
314 } SCREEN_MODE
, *PSCREEN_MODE
;
316 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
317 static COORD CurrResolution
= {0};
319 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
321 /* RegisterConsoleVDM EMULATION ***********************************************/
323 #include <ntddvdeo.h>
325 #ifdef USE_REAL_REGISTERCONSOLEVDM
327 #define __RegisterConsoleVDM RegisterConsoleVDM
328 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
333 * This private buffer, per-console, is used by
334 * RegisterConsoleVDM and InvalidateConsoleDIBits.
336 static COORD VDMBufferSize
= {0};
337 static PCHAR_CELL VDMBuffer
= NULL
;
339 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
340 // for the real RegisterConsoleVDM and
341 // InvalidateConsoleDIBits
345 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
346 IN HANDLE hStartHardwareEvent
,
347 IN HANDLE hEndHardwareEvent
,
348 IN HANDLE hErrorHardwareEvent
,
349 IN DWORD dwUnusedVar
,
350 OUT LPDWORD lpVideoStateLength
,
351 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
352 IN PVOID lpUnusedBuffer
,
353 IN DWORD dwUnusedBufferLength
,
354 IN COORD dwVDMBufferSize
,
355 OUT PVOID
* lpVDMBuffer
)
357 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
358 UNREFERENCED_PARAMETER(dwUnusedVar
);
359 UNREFERENCED_PARAMETER(lpVideoStateLength
);
360 UNREFERENCED_PARAMETER(lpVideoState
);
361 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
362 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
365 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
367 if (lpVDMBuffer
== NULL
) return FALSE
;
369 if (dwRegisterFlags
!= 0)
371 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
372 if (VDMBuffer
!= NULL
) return FALSE
;
374 VDMBufferSize
= dwVDMBufferSize
;
376 /* HACK: Cache -- to be removed in the real implementation */
377 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
379 VDMBufferSize
.X
* VDMBufferSize
.Y
380 * sizeof(*CharBuff
));
383 VDMBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
385 VDMBufferSize
.X
* VDMBufferSize
.Y
386 * sizeof(*VDMBuffer
));
387 *lpVDMBuffer
= VDMBuffer
;
388 return (VDMBuffer
!= NULL
);
392 /* HACK: Cache -- to be removed in the real implementation */
393 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
396 if (VDMBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer
);
399 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
406 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
407 IN PSMALL_RECT lpRect
)
409 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
411 /* HACK: Write the cached data to the console */
413 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
418 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
420 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
422 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
423 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
427 WriteConsoleOutputA(hConsoleOutput
,
434 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
439 /* PRIVATE FUNCTIONS **********************************************************/
441 static inline DWORD
VgaGetAddressSize(VOID
);
442 static VOID
VgaUpdateTextCursor(VOID
);
444 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
446 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
449 static VOID
VgaUpdateCursorPosition(VOID
)
452 * Update the cursor position in the VGA registers.
454 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
455 ConsoleInfo
.dwCursorPosition
.X
;
457 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
458 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
460 VgaUpdateTextCursor();
463 static VOID
ResizeTextConsole(PCOORD Resolution
, PSMALL_RECT WindowSize OPTIONAL
)
467 SHORT oldWidth
, oldHeight
;
470 * Use this trick to effectively resize the console buffer and window,
472 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
473 * is smaller than the current console window size, and:
474 * - SetConsoleWindowInfo fails if the new console window size is larger
475 * than the current console screen buffer size.
479 /* Retrieve the latest console information */
480 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
482 oldWidth
= ConsoleInfo
.srWindow
.Right
- ConsoleInfo
.srWindow
.Left
+ 1;
483 oldHeight
= ConsoleInfo
.srWindow
.Bottom
- ConsoleInfo
.srWindow
.Top
+ 1;
486 * If the current console window is too large to hold the full contents
487 * of the new screen buffer, resize it first.
489 if (oldWidth
> Resolution
->X
|| oldHeight
> Resolution
->Y
)
492 // NOTE: This is not a problem if we move the window back to (0,0)
493 // because when we resize the screen buffer, the window will move back
494 // to where the cursor is. Or, if the screen buffer is not resized,
495 // when we readjust again the window, we will move back to a correct
496 // position. This is what we wanted after all...
499 ConRect
.Left
= ConRect
.Top
= 0;
500 ConRect
.Right
= ConRect
.Left
+ min(oldWidth
, Resolution
->X
) - 1;
501 ConRect
.Bottom
= ConRect
.Top
+ min(oldHeight
, Resolution
->Y
) - 1;
503 Success
= SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
504 if (!Success
) DPRINT1("(resize) SetConsoleWindowInfo(1) failed with error %d\n", GetLastError());
507 /* Resize the screen buffer if needed */
508 if (Resolution
->X
!= ConsoleInfo
.dwSize
.X
|| Resolution
->Y
!= ConsoleInfo
.dwSize
.Y
)
511 * SetConsoleScreenBufferSize automatically takes into account the current
512 * cursor position when it computes starting which row it should copy text
513 * when resizing the sceenbuffer, and scrolls the console window such that
514 * the cursor is placed in it again. We therefore do not need to care about
515 * the cursor position and do the maths ourselves.
517 Success
= SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
518 if (!Success
) DPRINT1("(resize) SetConsoleScreenBufferSize failed with error %d\n", GetLastError());
521 * Setting a new screen buffer size can change other information,
522 * so update the saved console information.
524 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
530 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
531 ConRect
.Bottom
= max(ConsoleInfo
.dwCursorPosition
.Y
, Resolution
->Y
- 1);
532 ConRect
.Top
= ConRect
.Bottom
- Resolution
->Y
+ 1;
534 // NOTE: We may take ConsoleInfo.dwMaximumWindowSize into account
538 ConRect
.Left
= ConRect
.Top
= 0;
539 ConRect
.Right
= ConRect
.Left
+ WindowSize
->Right
- WindowSize
->Left
;
540 ConRect
.Bottom
= ConRect
.Top
+ WindowSize
->Bottom
- WindowSize
->Top
;
543 Success
= SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
544 if (!Success
) DPRINT1("(resize) SetConsoleWindowInfo(2) failed with error %d\n", GetLastError());
546 /* Update the saved console information */
547 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
550 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
554 PVIDEO_HARDWARE_STATE_HEADER State
;
556 #ifdef USE_REAL_REGISTERCONSOLEVDM
557 PCHAR_INFO CharBuff
= NULL
;
560 DWORD AddressSize
, ScanlineSize
;
564 COORD Origin
= { 0, 0 };
566 ASSERT(TextFramebuffer
== NULL
);
568 TextResolution
= *Resolution
;
571 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
572 * in the two following APIs:
573 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
574 * SrvVDMConsoleOperation (corresponding Win32 API: VDMConsoleOperation)
575 * to check whether the current process is a VDM process, and fails otherwise
576 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
578 * It is worth it to notice that also basesrv.dll does the same only for the
579 * BaseSrvIsFirstVDM API...
582 /* Register with the console server */
584 __RegisterConsoleVDM(1,
587 AnotherEvent
, // NULL,
589 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
590 (PVOID
*)&State
, // NULL,
594 (PVOID
*)&TextFramebuffer
);
597 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
602 #ifdef USE_REAL_REGISTERCONSOLEVDM
603 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
605 TextResolution
.X
* TextResolution
.Y
606 * sizeof(*CharBuff
));
610 /* Resize the console */
611 ResizeTextConsole(Resolution
, NULL
);
613 /* Update the saved console information */
614 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
617 * Copy console data into VGA memory
620 /* Read the data from the console into the framebuffer... */
621 ConRect
.Left
= ConRect
.Top
= 0;
622 ConRect
.Right
= TextResolution
.X
;
623 ConRect
.Bottom
= TextResolution
.Y
;
625 ReadConsoleOutputA(TextConsoleBuffer
,
631 /* ... and copy the framebuffer into the VGA memory */
632 AddressSize
= VgaGetAddressSize();
633 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
635 /* Loop through the scanlines */
636 for (i
= 0; i
< TextResolution
.Y
; i
++)
638 /* Loop through the characters */
639 for (j
= 0; j
< TextResolution
.X
; j
++)
641 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
643 /* Store the character in plane 0 */
644 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
646 /* Store the attribute in plane 1 */
647 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
650 /* Move to the next scanline */
651 Address
+= ScanlineSize
;
654 #ifdef USE_REAL_REGISTERCONSOLEVDM
655 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
658 VgaUpdateCursorPosition();
663 static VOID
VgaDetachFromConsoleInternal(VOID
)
667 COORD dummySize
= {0};
669 /* Deregister with the console server */
670 __RegisterConsoleVDM(0,
682 TextFramebuffer
= NULL
;
685 static BOOL
IsConsoleHandle(HANDLE hHandle
)
689 /* Check whether the handle may be that of a console... */
690 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
694 * It may be. Perform another test... The idea comes from the
695 * MSDN description of the WriteConsole API:
697 * "WriteConsole fails if it is used with a standard handle
698 * that is redirected to a file. If an application processes
699 * multilingual output that can be redirected, determine whether
700 * the output handle is a console handle (one method is to call
701 * the GetConsoleMode function and check whether it succeeds).
702 * If the handle is a console handle, call WriteConsole. If the
703 * handle is not a console handle, the output is redirected and
704 * you should call WriteFile to perform the I/O."
706 return GetConsoleMode(hHandle
, &dwMode
);
709 static inline DWORD
VgaGetAddressSize(VOID
)
711 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
713 /* Double-word addressing */
714 return 4; // sizeof(DWORD)
716 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
718 /* Byte addressing */
719 return 1; // sizeof(BYTE)
723 /* Word addressing */
724 return 2; // sizeof(WORD)
728 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
730 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
733 /* Check for chain-4 and odd-even mode */
734 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
736 /* The lowest two bits are the plane number */
737 Plane
= Offset
& 0x03;
740 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
742 /* The LSB is the plane number */
743 Plane
= Offset
& 0x01;
748 /* Use the read mode */
749 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
752 /* Return the offset on plane 0 for read mode 1 */
753 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
) return Offset
;
754 else return Offset
+ Plane
* VGA_BANK_SIZE
;
757 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
759 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
761 /* Check for chain-4 and odd-even mode */
762 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
764 /* Clear the lowest two bits since they're used to select the bank */
767 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
769 /* Clear the lowest bit since it's used to select odd/even */
773 /* Return the offset on plane 0 */
777 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
779 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
780 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
784 /* In write mode 1 just return the latch register */
785 return VgaLatchRegisters
[Plane
];
790 /* Write modes 0 and 3 rotate the data to the right first */
791 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
792 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
796 /* Write mode 2 expands the appropriate bit to all 8 bits */
797 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
803 * In write mode 0, the enable set/reset register decides if the
804 * set/reset bit should be expanded to all 8 bits.
806 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
808 /* Copy the bit from the set/reset register to all 8 bits */
809 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
815 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
816 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
818 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
819 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
820 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
824 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
827 /* Then we expand the bit in the set/reset field */
828 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
831 /* Bits cleared in the bitmask are replaced with latch register bits */
832 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
834 /* Return the byte */
838 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
840 /* Check if this is the first time the rectangle is updated */
843 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
844 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
847 /* Expand the rectangle to include the point */
848 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
849 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
850 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
851 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
853 /* Set the update request flag */
857 static inline ULONG
VgaGetClockFrequency(VOID
)
859 BYTE Numerator
, Denominator
;
861 if (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & SVGA_SEQ_MCLK_VCLK
)
863 /* The VCLK is being generated using the MCLK */
864 ULONG Clock
= (VGA_CLOCK_BASE
* (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & 0x3F)) >> 3;
866 if (VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] & 1)
868 /* Use only half of the MCLK as the VCLK */
875 switch ((VgaMiscRegister
>> 2) & 3)
879 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
];
880 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
];
886 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
];
887 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
];
893 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
];
894 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
];
900 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
];
901 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
];
906 /* The numerator is 7-bit */
907 Numerator
&= ~(1 << 7);
909 /* If bit 7 is clear, the denominator is 5-bit */
910 if (!(Denominator
& (1 << 7))) Denominator
&= ~(1 << 6);
912 /* Bit 0 of the denominator is the post-scalar bit */
913 if (Denominator
& 1) Denominator
&= ~1;
914 else Denominator
>>= 1;
916 /* Return the clock frequency in Hz */
917 return (VGA_CLOCK_BASE
* Numerator
) / Denominator
;
920 static VOID
VgaResetSequencer(VOID
)
922 /* Lock extended SVGA registers */
923 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
925 /* Initialize the VCLKs */
926 VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
] = 0x66;
927 VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
] = 0x3B;
928 VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
] = 0x5B;
929 VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
] = 0x2F;
930 VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
] = 0x45;
931 VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
] = 0x30;
932 VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
] = 0x7E;
933 VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] = 0x33;
935 /* 50 MHz MCLK, not being used as the VCLK */
936 VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] = 0x1C;
939 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
943 /* Copy the colors of the default palette to the DAC and console palette */
944 for (i
= 0; i
< NumOfEntries
; i
++)
946 /* Set the palette entries */
947 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
948 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
949 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
950 Entries
[i
].peFlags
= 0;
952 /* Set the DAC registers */
953 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
954 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
955 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
959 static BOOLEAN
VgaInitializePalette(VOID
)
962 BOOLEAN Result
= FALSE
;
963 LPLOGPALETTE Palette
, TextPalette
;
965 /* Allocate storage space for the palettes */
966 Palette
= RtlAllocateHeap(RtlGetProcessHeap(),
969 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
970 TextPalette
= RtlAllocateHeap(RtlGetProcessHeap(),
973 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
974 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
976 /* Initialize the palettes */
977 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
978 Palette
->palNumEntries
= VGA_MAX_COLORS
;
979 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
981 /* Restore the default graphics palette */
982 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
984 /* Set the default text palette */
985 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
987 /* Set the palette entries */
988 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
989 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
990 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
991 TextPalette
->palPalEntry
[i
].peFlags
= 0;
994 /* Create the palettes */
995 PaletteHandle
= CreatePalette(Palette
);
996 TextPaletteHandle
= CreatePalette(TextPalette
);
998 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
1000 /* The palettes have been created successfully */
1005 /* Free the palettes */
1006 if (Palette
) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette
);
1007 if (TextPalette
) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette
);
1011 /* Something failed, delete the palettes */
1012 if (PaletteHandle
) DeleteObject(PaletteHandle
);
1013 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
1019 static VOID
VgaResetPalette(VOID
)
1021 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1023 /* Restore the default palette */
1024 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1025 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1026 PaletteChanged
= TRUE
;
1029 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
1031 ASSERT(ScreenBuffer
);
1033 /* Set the active buffer and reattach the VDM UI to it */
1034 SetConsoleActiveScreenBuffer(ScreenBuffer
);
1035 ConsoleReattach(ScreenBuffer
);
1038 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
1041 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
1042 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
1043 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
1044 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
1046 LONG Width
= Resolution
->X
;
1047 LONG Height
= Resolution
->Y
;
1049 /* Use DoubleVision mode if the resolution is too small */
1050 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
1051 if (DoubleWidth
) Width
*= 2;
1052 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
1053 if (DoubleHeight
) Height
*= 2;
1055 /* Fill the bitmap info header */
1056 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
1057 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
1058 BitmapInfo
->bmiHeader
.biWidth
= Width
;
1059 BitmapInfo
->bmiHeader
.biHeight
= Height
;
1060 BitmapInfo
->bmiHeader
.biBitCount
= 8;
1061 BitmapInfo
->bmiHeader
.biPlanes
= 1;
1062 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
1063 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
1065 /* Fill the palette data */
1066 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
1068 /* Fill the console graphics buffer info */
1069 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
1070 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
1071 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
1073 /* Create the buffer */
1074 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
1075 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1077 CONSOLE_GRAPHICS_BUFFER
,
1078 &GraphicsBufferInfo
);
1079 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
1081 /* Save the framebuffer address and mutex */
1082 GraphicsFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
1083 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
1085 /* Clear the framebuffer */
1086 RtlZeroMemory(GraphicsFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
1088 /* Set the active buffer */
1089 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
1091 /* The active framebuffer is now the graphics framebuffer */
1092 ConsoleFramebuffer
= GraphicsFramebuffer
;
1094 /* Set the graphics mode palette */
1095 SetConsolePalette(GraphicsConsoleBuffer
,
1097 SYSPAL_NOSTATIC256
);
1099 /* Set the screen mode flag */
1100 ScreenMode
= GRAPHICS_MODE
;
1105 static VOID
VgaLeaveGraphicsMode(VOID
)
1107 /* Release the console framebuffer mutex */
1108 ReleaseMutex(ConsoleMutex
);
1110 /* Switch back to the default console text buffer */
1111 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1113 /* Cleanup the video data */
1114 CloseHandle(ConsoleMutex
);
1115 ConsoleMutex
= NULL
;
1116 GraphicsFramebuffer
= NULL
;
1117 CloseHandle(GraphicsConsoleBuffer
);
1118 GraphicsConsoleBuffer
= NULL
;
1120 /* Reset the active framebuffer */
1121 ConsoleFramebuffer
= NULL
;
1123 DoubleWidth
= FALSE
;
1124 DoubleHeight
= FALSE
;
1127 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1129 /* Switch to the text buffer */
1130 // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
1131 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
1133 /* Adjust the text framebuffer if we changed the resolution */
1134 if (TextResolution
.X
!= Resolution
->X
||
1135 TextResolution
.Y
!= Resolution
->Y
)
1137 VgaDetachFromConsoleInternal();
1140 * VgaAttachToConsoleInternal sets TextResolution
1141 * to the new resolution and updates ConsoleInfo.
1143 if (!VgaAttachToConsoleInternal(Resolution
))
1145 DisplayMessage(L
"An unexpected error occurred!\n");
1146 EmulatorTerminate();
1152 VgaUpdateCursorPosition();
1155 /* The active framebuffer is now the text framebuffer */
1156 ConsoleFramebuffer
= TextFramebuffer
;
1159 * Set the text mode palette.
1161 * INFORMATION: This call should fail on Windows (and therefore
1162 * we get the default palette and our external behaviour is
1163 * just like Windows' one), but it should success on ReactOS
1164 * (so that we get console palette changes even for text-mode
1165 * screen buffers, which is a new feature on ReactOS).
1167 SetConsolePalette(TextConsoleBuffer
,
1169 SYSPAL_NOSTATIC256
);
1171 /* Set the screen mode flag */
1172 ScreenMode
= TEXT_MODE
;
1177 static VOID
VgaLeaveTextMode(VOID
)
1179 /* Reset the active framebuffer */
1180 ConsoleFramebuffer
= NULL
;
1183 static VOID
VgaChangeMode(VOID
)
1185 COORD NewResolution
= VgaGetDisplayResolution();
1186 SCREEN_MODE NewScreenMode
=
1187 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
1191 * Do not switch to a different screen mode + resolution if the new settings
1192 * are the same as the old ones. Just repaint the full screen.
1194 if ((ScreenMode
== NewScreenMode
) && // CurrResolution == NewResolution
1195 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1200 // FIXME: Wouldn't it be preferrable to switch to the new console SB
1201 // *ONLY* if we succeeded in setting the new mode??
1203 /* Leave the current video mode */
1204 if (ScreenMode
== GRAPHICS_MODE
)
1205 VgaLeaveGraphicsMode();
1209 /* Update the current resolution */
1210 CurrResolution
= NewResolution
;
1212 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1214 /* Check if the new mode is alphanumeric */
1215 if (NewScreenMode
== TEXT_MODE
)
1217 /* Enter new text mode */
1218 if (!VgaEnterTextMode(&CurrResolution
))
1220 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1221 EmulatorTerminate();
1227 /* Enter graphics mode */
1228 if (!VgaEnterGraphicsMode(&CurrResolution
))
1230 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1231 EmulatorTerminate();
1238 /* Trigger a full update of the screen */
1240 UpdateRectangle
.Left
= 0;
1241 UpdateRectangle
.Top
= 0;
1242 UpdateRectangle
.Right
= CurrResolution
.X
;
1243 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1245 /* Reset the mode change flag */
1246 ModeChanged
= FALSE
;
1249 static VOID
VgaUpdateFramebuffer(VOID
)
1252 DWORD AddressSize
= VgaGetAddressSize();
1253 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1254 BYTE PresetRowScan
= VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] & 0x1F;
1255 BYTE BytePanning
= (VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] >> 5) & 3;
1256 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1257 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
])
1258 + PresetRowScan
* ScanlineSize
1260 WORD LineCompare
= VgaCrtcRegisters
[VGA_CRTC_LINE_COMPARE_REG
]
1261 | ((VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_LC8
) << 4);
1262 BYTE PixelShift
= VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F;
1265 * If the console framebuffer is NULL, that means something
1266 * went wrong earlier and this is the final display refresh.
1268 if (ConsoleFramebuffer
== NULL
) return;
1270 /* Check if we are in text or graphics mode */
1271 if (ScreenMode
== GRAPHICS_MODE
)
1274 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1275 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1279 * Synchronize access to the graphics framebuffer
1280 * with the console framebuffer mutex.
1282 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1284 /* Shift the high bit right by 1 in odd/even mode */
1285 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1287 InterlaceHighBit
>>= 1;
1290 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1292 /* Halve the line compare value */
1297 /* Divide the line compare value by the maximum scan line */
1298 LineCompare
/= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1301 /* Loop through the scanlines */
1302 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1304 if (i
== LineCompare
)
1306 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_PPM
)
1309 * Disable the pixel shift count and byte panning
1310 * for the rest of the display cycle
1316 /* Reset the address, but assume the preset row scan is 0 */
1317 Address
= BytePanning
;
1320 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1322 /* Odd-numbered line in interlaced mode - set the high bit */
1323 Address
|= InterlaceHighBit
;
1326 /* Loop through the pixels */
1327 for (j
= 0; j
< CurrResolution
.X
; j
++)
1331 /* Apply horizontal pixel panning */
1332 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1334 X
= j
+ (PixelShift
>> 1);
1341 /* Check the shifting mode */
1342 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1344 /* 4 bits shifted from each plane */
1346 /* Check if this is 16 or 256 color mode */
1347 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1349 /* One byte per pixel */
1350 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1351 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1356 /* 4-bits per pixel */
1358 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1359 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1362 /* Check if we should use the highest 4 bits or lowest 4 */
1363 if (((X
/ VGA_NUM_BANKS
) % 2) == 0)
1375 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1377 /* Check if this is 16 or 256 color mode */
1378 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1380 // TODO: NOT IMPLEMENTED
1381 DPRINT1("8-bit interleaved mode is not implemented!\n");
1386 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1387 * then 2 bits shifted from plane 1 and 3 for the next 4
1389 DWORD BankNumber
= (X
/ 4) % 2;
1390 DWORD Offset
= Address
+ (X
/ 8);
1391 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1392 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1394 /* Extract the two bits from each plane */
1395 LowPlaneData
= (LowPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1396 HighPlaneData
= (HighPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1398 /* Combine them into the pixel */
1399 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1404 /* 1 bit shifted from each plane */
1406 /* Check if this is 16 or 256 color mode */
1407 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1409 /* 8 bits per pixel, 2 on each plane */
1411 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1413 /* The data is on plane k, 4 pixels per byte */
1414 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1415 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1418 /* The mask of the first bit in the pair */
1419 BYTE BitMask
= 1 << (((3 - (X
% VGA_NUM_BANKS
)) * 2) + 1);
1421 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1422 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1424 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1425 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1430 /* 4 bits per pixel, 1 on each plane */
1432 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1434 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1435 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1438 /* If the bit on that plane is set, set it */
1439 if (PlaneData
& (1 << (7 - (X
% 8)))) PixelData
|= 1 << k
;
1444 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1447 * In 16 color mode, the value is an index to the AC registers
1448 * if external palette access is disabled, otherwise (in case
1449 * of palette loading) it is a blank pixel.
1451 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1455 /* Take into account DoubleVision mode when checking for pixel updates */
1456 if (DoubleWidth
&& DoubleHeight
)
1458 /* Now check if the resulting pixel data has changed */
1459 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1461 /* Yes, write the new value */
1462 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1463 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1464 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1465 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1467 /* Mark the specified pixel as changed */
1468 VgaMarkForUpdate(i
, j
);
1471 else if (DoubleWidth
&& !DoubleHeight
)
1473 /* Now check if the resulting pixel data has changed */
1474 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1476 /* Yes, write the new value */
1477 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1478 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1480 /* Mark the specified pixel as changed */
1481 VgaMarkForUpdate(i
, j
);
1484 else if (!DoubleWidth
&& DoubleHeight
)
1486 /* Now check if the resulting pixel data has changed */
1487 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1489 /* Yes, write the new value */
1490 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1491 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1493 /* Mark the specified pixel as changed */
1494 VgaMarkForUpdate(i
, j
);
1497 else // if (!DoubleWidth && !DoubleHeight)
1499 /* Now check if the resulting pixel data has changed */
1500 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1502 /* Yes, write the new value */
1503 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1505 /* Mark the specified pixel as changed */
1506 VgaMarkForUpdate(i
, j
);
1511 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1513 /* Clear the high bit */
1514 Address
&= ~InterlaceHighBit
;
1517 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1519 /* Move to the next scanline */
1520 Address
+= ScanlineSize
;
1525 * Release the console framebuffer mutex
1526 * so that we allow for repainting.
1528 ReleaseMutex(ConsoleMutex
);
1534 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1538 * Technically, the horizontal panning and preset row count should
1539 * affect text mode too. However, it works on pixels and not characters,
1540 * so we can't support it currently.
1543 /* Loop through the scanlines */
1544 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1546 /* Loop through the characters */
1547 for (j
= 0; j
< CurrResolution
.X
; j
++)
1549 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1551 /* Plane 0 holds the character itself */
1552 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1554 /* Plane 1 holds the attribute */
1555 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1557 /* Now check if the resulting character data has changed */
1558 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1559 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1561 /* Yes, write the new value */
1562 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1564 /* Mark the specified cell as changed */
1565 VgaMarkForUpdate(i
, j
);
1569 /* Move to the next scanline */
1570 Address
+= ScanlineSize
;
1575 static VOID
VgaUpdateTextCursor(VOID
)
1578 CONSOLE_CURSOR_INFO CursorInfo
;
1580 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1581 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1582 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1584 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1585 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1586 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1587 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1589 /* Just return if we are not in text mode */
1590 if (ScreenMode
!= TEXT_MODE
) return;
1592 if (CursorStart
< CursorEnd
)
1594 /* Visible cursor */
1595 CursorInfo
.bVisible
= CursorVisible
;
1596 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1601 CursorInfo
.bVisible
= FALSE
;
1602 CursorInfo
.dwSize
= 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
1605 /* Add the cursor skew to the location */
1606 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1608 /* Find the coordinates of the new position */
1609 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1610 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1612 DPRINT("VgaUpdateTextCursor: (X = %d ; Y = %d)\n", Position
.X
, Position
.Y
);
1614 /* Update the physical cursor */
1615 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1616 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1618 /* Reset the cursor changed flag */
1619 CursorChanged
= FALSE
;
1622 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1624 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1626 if (Port
!= VGA_DAC_MASK
) SvgaHdrCounter
= 0;
1631 return VgaMiscRegister
;
1633 case VGA_INSTAT0_READ
:
1634 return 0; // Not implemented
1636 case VGA_INSTAT1_READ_MONO
:
1637 case VGA_INSTAT1_READ_COLOR
:
1640 BOOLEAN Vsync
, Hsync
;
1641 ULONGLONG Cycles
= GetCycleCount();
1642 ULONG CyclesPerMicrosecond
= (ULONG
)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1643 ULONG Dots
= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & 1) ? 9 : 8;
1644 ULONG Clock
= VgaGetClockFrequency() / 1000000;
1645 ULONG HorizTotalDots
= ((ULONG
)VgaCrtcRegisters
[VGA_CRTC_HORZ_TOTAL_REG
] + 5) * Dots
;
1646 ULONG VblankStart
, VblankEnd
, HblankStart
, HblankEnd
;
1647 ULONG HblankDuration
, VblankDuration
;
1649 /* Calculate the vertical blanking duration in cycles */
1650 VblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_VERT_BLANKING_REG
] & 0x7F;
1651 VblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_VERT_BLANKING_REG
] & 0x7F;
1652 if (VblankEnd
< VblankStart
) VblankEnd
|= 0x80;
1653 VblankDuration
= ((VblankEnd
- VblankStart
) * HorizTotalDots
1654 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1656 /* Calculate the horizontal blanking duration in cycles */
1657 HblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_HORZ_BLANKING_REG
] & 0x1F;
1658 HblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_BLANKING_REG
] & 0x1F;
1659 if (HblankEnd
< HblankStart
) HblankEnd
|= 0x20;
1660 HblankDuration
= ((HblankEnd
- HblankStart
) * Dots
1661 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1663 Vsync
= (Cycles
- VerticalRetraceCycle
) < (ULONGLONG
)VblankDuration
;
1664 Hsync
= (Cycles
- HorizontalRetraceCycle
) < (ULONGLONG
)HblankDuration
;
1666 /* Reset the AC latch */
1669 /* Reverse the polarity, if needed */
1670 if (VgaMiscRegister
& VGA_MISC_VSYNCP
) Vsync
= !Vsync
;
1671 if (VgaMiscRegister
& VGA_MISC_HSYNCP
) Hsync
= !Hsync
;
1673 /* Set a flag if there is a vertical or horizontal retrace */
1674 if (Vsync
|| Hsync
) Result
|= VGA_STAT_DD
;
1676 /* Set an additional flag if there was a vertical retrace */
1677 if (Vsync
) Result
|= VGA_STAT_VRETRACE
;
1682 case VGA_FEATURE_READ
:
1683 return VgaFeatureRegister
;
1689 return VgaAcRegisters
[VgaAcIndex
];
1695 return VgaSeqRegisters
[VgaSeqIndex
];
1699 if (SvgaHdrCounter
== 4)
1702 return SvgaHiddenRegister
;
1711 case VGA_DAC_READ_INDEX
:
1712 /* This returns the read/write state */
1713 return (VgaDacReadWrite
? 0 : 3);
1715 case VGA_DAC_WRITE_INDEX
:
1720 /* Ignore reads in write mode */
1721 if (!VgaDacReadWrite
)
1723 BYTE Data
= VgaDacRegisters
[VgaDacIndex
* 3 + VgaDacLatchCounter
];
1724 VgaDacLatchCounter
++;
1726 if (VgaDacLatchCounter
== 3)
1728 /* Reset the latch counter and increment the palette index */
1729 VgaDacLatchCounter
= 0;
1731 VgaDacIndex
%= VGA_MAX_COLORS
;
1740 case VGA_CRTC_INDEX_MONO
:
1741 case VGA_CRTC_INDEX_COLOR
:
1742 return VgaCrtcIndex
;
1744 case VGA_CRTC_DATA_MONO
:
1745 case VGA_CRTC_DATA_COLOR
:
1746 return VgaCrtcRegisters
[VgaCrtcIndex
];
1752 return VgaGcRegisters
[VgaGcIndex
];
1755 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1762 static inline VOID
VgaWriteSequencer(BYTE Data
)
1764 /* Save the value */
1765 VgaSeqRegisters
[VgaSeqIndex
& VGA_SEQ_INDEX_MASK
] = Data
;
1767 /* Check the index */
1768 switch (VgaSeqIndex
& VGA_SEQ_INDEX_MASK
)
1770 case SVGA_SEQ_UNLOCK_REG
:
1772 if ((Data
& SVGA_SEQ_UNLOCK_MASK
) == SVGA_SEQ_UNLOCKED
)
1774 /* Unlock SVGA extensions */
1775 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_UNLOCKED
;
1779 /* Lock SVGA extensions */
1780 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
1788 static inline VOID
VgaWriteGc(BYTE Data
)
1790 /* Save the value */
1791 VgaGcRegisters
[VgaGcIndex
& VGA_GC_INDEX_MASK
] = Data
;
1793 /* Check the index */
1794 switch (VgaGcIndex
& VGA_GC_INDEX_MASK
)
1796 case VGA_GC_MISC_REG
:
1798 /* Remove any existing VGA memory hook */
1799 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1801 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1803 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1805 /* Register a memory hook */
1806 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1807 MemorySize
[MemoryMap
],
1812 /* The GC misc register decides if it's text or graphics mode */
1819 static inline VOID
VgaWriteCrtc(BYTE Data
)
1821 /* Save the value */
1822 VgaCrtcRegisters
[VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
] = Data
;
1824 /* Check the index */
1825 switch (VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
)
1827 case VGA_CRTC_END_HORZ_DISP_REG
:
1828 case VGA_CRTC_VERT_DISP_END_REG
:
1829 case VGA_CRTC_OVERFLOW_REG
:
1830 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1832 /* The video mode has changed */
1837 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1838 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1839 case VGA_CRTC_CURSOR_START_REG
:
1840 case VGA_CRTC_CURSOR_END_REG
:
1842 /* Set the cursor changed flag */
1843 CursorChanged
= TRUE
;
1849 static inline VOID
VgaWriteDac(BYTE Data
)
1854 /* Store the value in the latch */
1855 VgaDacLatch
[VgaDacLatchCounter
++] = Data
;
1856 if (VgaDacLatchCounter
< 3) return;
1858 /* Reset the latch counter */
1859 VgaDacLatchCounter
= 0;
1861 /* Set the DAC register values */
1862 VgaDacRegisters
[VgaDacIndex
* 3] = VgaDacLatch
[0];
1863 VgaDacRegisters
[VgaDacIndex
* 3 + 1] = VgaDacLatch
[1];
1864 VgaDacRegisters
[VgaDacIndex
* 3 + 2] = VgaDacLatch
[2];
1866 /* Fill the entry structure */
1867 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacLatch
[0]);
1868 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacLatch
[1]);
1869 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacLatch
[2]);
1872 /* Update the palette entry */
1873 SetPaletteEntries(PaletteHandle
, VgaDacIndex
, 1, &Entry
);
1875 /* Check which text palette entries are affected */
1876 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1878 if (VgaAcRegisters
[i
] == VgaDacIndex
)
1880 /* Update the text palette entry */
1881 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1885 /* Set the palette changed flag */
1886 PaletteChanged
= TRUE
;
1888 /* Update the index */
1890 VgaDacIndex
%= VGA_MAX_COLORS
;
1893 static inline VOID
VgaWriteAc(BYTE Data
)
1897 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1899 /* Save the value */
1900 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1902 if (VgaAcPalDisable
) return;
1904 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1905 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1907 /* Update the AC register */
1908 VgaAcRegisters
[VgaAcIndex
] = Data
;
1910 /* Fill the entry structure */
1911 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1912 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1913 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1916 /* Update the palette entry and set the palette change flag */
1917 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1918 PaletteChanged
= TRUE
;
1923 VgaAcRegisters
[VgaAcIndex
] = Data
;
1927 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1929 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1933 case VGA_MISC_WRITE
:
1935 VgaMiscRegister
= Data
;
1937 if (VgaMiscRegister
& 0x01)
1939 /* Color emulation */
1940 DPRINT1("Color emulation\n");
1942 /* Register the new I/O Ports */
1943 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1944 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1945 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1947 /* Unregister the old ones */
1948 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1949 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1950 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1954 /* Monochrome emulation */
1955 DPRINT1("Monochrome emulation\n");
1957 /* Register the new I/O Ports */
1958 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1959 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1960 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1962 /* Unregister the old ones */
1963 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1964 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1965 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1968 /* Remove any existing VGA memory hook */
1969 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1971 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1973 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1975 /* Register a memory hook */
1976 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1977 MemorySize
[MemoryMap
],
1985 case VGA_FEATURE_WRITE_MONO
:
1986 case VGA_FEATURE_WRITE_COLOR
:
1988 VgaFeatureRegister
= Data
;
1993 // case VGA_AC_WRITE:
1997 /* Change the index */
1998 BYTE Index
= Data
& 0x1F;
1999 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
2002 * Change palette protection by checking for
2003 * the Palette Address Source bit.
2005 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
2009 /* Write the data */
2013 /* Toggle the latch */
2014 VgaAcLatch
= !VgaAcLatch
;
2020 /* Set the sequencer index register */
2021 if ((Data
& 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
2022 && (Data
& 0x1F) != VGA_SEQ_MAX_REG
)
2032 /* Call the sequencer function */
2033 VgaWriteSequencer(Data
);
2039 if (SvgaHdrCounter
== 4) SvgaHiddenRegister
= Data
;
2040 else VgaDacMask
= Data
;
2045 case VGA_DAC_READ_INDEX
:
2047 VgaDacReadWrite
= FALSE
;
2049 VgaDacLatchCounter
= 0;
2053 case VGA_DAC_WRITE_INDEX
:
2055 VgaDacReadWrite
= TRUE
;
2057 VgaDacLatchCounter
= 0;
2063 /* Ignore writes in read mode */
2064 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
2068 case VGA_CRTC_INDEX_MONO
:
2069 case VGA_CRTC_INDEX_COLOR
:
2071 /* Set the CRTC index register */
2072 if (((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_MAX_UNLOCKED_REG
)
2073 && ((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_UNUSED0_REG
2074 || (Data
& VGA_CRTC_INDEX_MASK
) > SVGA_CRTC_UNUSED6_REG
)
2075 && (Data
& VGA_CRTC_INDEX_MASK
) != SVGA_CRTC_UNUSED7_REG
)
2077 VgaCrtcIndex
= Data
;
2083 case VGA_CRTC_DATA_MONO
:
2084 case VGA_CRTC_DATA_COLOR
:
2086 /* Call the CRTC function */
2093 /* Set the GC index register */
2094 if ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_MAX_UNLOCKED_REG
2095 && (Data
& VGA_GC_INDEX_MASK
) != SVGA_GC_UNUSED0_REG
2096 && ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_UNUSED1_REG
2097 || (Data
& VGA_GC_INDEX_MASK
) > SVGA_GC_UNUSED10_REG
))
2107 /* Call the GC function */
2113 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
2120 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
2122 HANDLE ConsoleBufferHandle
= NULL
;
2124 UNREFERENCED_PARAMETER(ElapsedTime
);
2126 /* Set the vertical retrace cycle */
2127 VerticalRetraceCycle
= GetCycleCount();
2129 /* If nothing has changed, just return */
2130 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
2133 /* Change the display mode */
2134 if (ModeChanged
) VgaChangeMode();
2136 /* Change the text cursor appearance */
2137 if (CursorChanged
) VgaUpdateTextCursor();
2141 /* Trigger a full update of the screen */
2143 UpdateRectangle
.Left
= 0;
2144 UpdateRectangle
.Top
= 0;
2145 UpdateRectangle
.Right
= CurrResolution
.X
;
2146 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
2148 PaletteChanged
= FALSE
;
2151 /* Update the contents of the framebuffer */
2152 VgaUpdateFramebuffer();
2154 /* Ignore if there's nothing to update */
2155 if (!NeedsUpdate
) return;
2157 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
2158 UpdateRectangle
.Left
,
2159 UpdateRectangle
.Top
,
2160 UpdateRectangle
.Right
,
2161 UpdateRectangle
.Bottom
);
2163 /* Check if we are in text or graphics mode */
2164 if (ScreenMode
== GRAPHICS_MODE
)
2167 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
2169 /* In DoubleVision mode, scale the update rectangle */
2172 UpdateRectangle
.Left
*= 2;
2173 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
2177 UpdateRectangle
.Top
*= 2;
2178 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
2184 ConsoleBufferHandle
= TextConsoleBuffer
;
2187 /* Redraw the screen */
2188 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
2190 /* Clear the update flag */
2191 NeedsUpdate
= FALSE
;
2194 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
2196 UNREFERENCED_PARAMETER(ElapsedTime
);
2199 HorizontalRetraceCycle
= GetCycleCount();
2202 /* PUBLIC FUNCTIONS ***********************************************************/
2204 COORD
VgaGetDisplayResolution(VOID
)
2207 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
2209 /* The low 8 bits are in the display registers */
2210 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
2211 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
2213 /* Set the top bits from the overflow register */
2214 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
2216 Resolution
.Y
|= 1 << 8;
2218 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
2220 Resolution
.Y
|= 1 << 9;
2223 /* Increase the values by 1 */
2227 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
2229 /* Multiply the horizontal resolution by the 9/8 dot mode */
2230 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
2233 /* The horizontal resolution is halved in 8-bit mode */
2234 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
2237 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
2239 /* Halve the vertical resolution */
2244 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
2245 Resolution
.Y
/= MaximumScanLine
;
2248 /* Return the resolution */
2252 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
2254 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
2255 if (Horizontal
) *Horizontal
= DoubleWidth
;
2256 if (Vertical
) *Vertical
= DoubleHeight
;
2260 VOID
VgaRefreshDisplay(VOID
)
2262 VgaVerticalRetrace(0);
2265 VOID FASTCALL
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2269 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2271 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2273 /* Ignore if video RAM access is disabled */
2274 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
2276 if (!(VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
))
2278 /* Loop through each byte */
2279 for (i
= 0; i
< Size
; i
++)
2281 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
2283 /* Copy the value to the buffer */
2284 BufPtr
[i
] = VgaMemory
[VideoAddress
];
2289 /* Loop through each byte */
2290 for (i
= 0; i
< Size
; i
++)
2294 /* This should always return a plane 0 address for read mode 1 */
2295 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
2297 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2299 /* Don't consider ignored banks */
2300 if (!(VgaGcRegisters
[VGA_GC_COLOR_IGNORE_REG
] & (1 << j
))) continue;
2302 if (VgaGcRegisters
[VGA_GC_COLOR_COMPARE_REG
] & (1 << j
))
2304 /* Comparing with 11111111 */
2305 Result
&= VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2309 /* Comparing with 00000000 */
2310 Result
&= ~(VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)]);
2314 /* Copy the value to the buffer */
2319 /* Load the latch registers */
2320 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
2321 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2322 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2323 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2326 BOOLEAN FASTCALL
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2330 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2332 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2334 /* Ignore if video RAM access is disabled */
2335 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
2337 /* Also ignore if write access to all planes is disabled */
2338 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
2340 /* Loop through each byte */
2341 for (i
= 0; i
< Size
; i
++)
2343 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
2345 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2347 /* Make sure the page is writeable */
2348 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
2350 /* Check if this is chain-4 mode */
2351 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
2353 if (((Address
+ i
) & 0x03) != j
)
2355 /* This plane will not be accessed */
2360 /* Check if this is odd-even mode */
2361 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
2363 if (((Address
+ i
) & 0x01) != (j
& 1))
2365 /* This plane will not be accessed */
2370 /* Copy the value to the VGA memory */
2371 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
2378 VOID
VgaClearMemory(VOID
)
2380 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
2383 VOID
VgaWriteTextModeFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
2386 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
2388 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
2390 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
2392 /* Write the character */
2393 for (j
= 0; j
< Height
; j
++)
2395 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
2398 /* Clear the unused part */
2399 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
2401 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
2406 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
2409 * This function monitors and allows console resizings only if they are triggered by us.
2410 * User-driven resizings via the console properties, or programmatical console resizings
2411 * made by explicit calls to SetConsoleScreenBufferSize by external applications, are forbidden.
2412 * In that case only a console window resize is done in case the size is reduced.
2413 * This protection is enabled in CONSRV side when NTVDM registers as a VDM to CONSRV,
2414 * but we also implement it there in case we are running in STANDALONE mode without
2415 * CONSRV registration.
2417 * The only potential problem we have is that, when this handler is called,
2418 * the console is already resized. In case this corresponds to a forbidden resize,
2419 * we resize the console back to its original size from inside the handler.
2420 * This will trigger a recursive call to the handler, that should be detected.
2423 if (CurrResolution
.X
== ScreenEvent
->dwSize
.X
&&
2424 CurrResolution
.Y
== ScreenEvent
->dwSize
.Y
)
2426 /* Allowed resize, we are OK */
2430 DPRINT1("ScreenEventHandler - Detected forbidden resize! Reset console screenbuffer size back to (X = %d ; Y = %d)\n", CurrResolution
.X
, CurrResolution
.Y
);
2432 // FIXME: If we're detaching, then stop monitoring for changes!!
2434 /* Restore the original console size */
2435 ResizeTextConsole(&CurrResolution
, NULL
);
2437 /* Force refresh of all the screen */
2439 UpdateRectangle
.Left
= 0;
2440 UpdateRectangle
.Top
= 0;
2441 UpdateRectangle
.Right
= CurrResolution
.X
;
2442 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
2443 VgaRefreshDisplay();
2446 BOOL
VgaAttachToConsole(VOID
)
2448 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2449 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2451 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2452 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2454 // VgaDetachFromConsoleInternal();
2457 * VgaAttachToConsoleInternal sets TextResolution
2458 * to the new resolution and updates ConsoleInfo.
2460 if (!VgaAttachToConsoleInternal(&TextResolution
))
2462 DisplayMessage(L
"An unexpected error occurred!\n");
2463 EmulatorTerminate();
2467 /* Restore the original screen buffer */
2468 VgaSetActiveScreenBuffer(ScreenBufferHandle
);
2469 ScreenBufferHandle
= NULL
;
2471 /* Restore the screen state */
2472 if (ScreenMode
== TEXT_MODE
)
2474 /* The text mode framebuffer was recreated */
2475 ConsoleFramebuffer
= TextFramebuffer
;
2479 /* The graphics mode framebuffer is unchanged */
2480 ConsoleFramebuffer
= OldConsoleFramebuffer
;
2482 OldConsoleFramebuffer
= NULL
;
2487 VOID
VgaDetachFromConsole(VOID
)
2489 VgaDetachFromConsoleInternal();
2491 /* Save the screen state */
2492 if (ScreenMode
== TEXT_MODE
)
2493 ScreenBufferHandle
= TextConsoleBuffer
;
2495 ScreenBufferHandle
= GraphicsConsoleBuffer
;
2497 /* Reset the active framebuffer */
2498 OldConsoleFramebuffer
= ConsoleFramebuffer
;
2499 ConsoleFramebuffer
= NULL
;
2501 /* Restore the original console size */
2502 ResizeTextConsole(&OrgConsoleBufferInfo
.dwSize
, &OrgConsoleBufferInfo
.srWindow
);
2504 /* Restore the original cursor shape */
2505 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2507 // FIXME: Should we copy back the screen data to the screen buffer??
2508 // WriteConsoleOutputA(...);
2510 // FIXME: Should we change cursor POSITION??
2511 // VgaUpdateTextCursor();
2513 ///* Update the physical cursor */
2514 //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
2515 //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
2517 /* Restore the old text-mode screen buffer */
2518 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2521 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2523 /* Save the default text-mode console output handle */
2524 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2525 TextConsoleBuffer
= TextHandle
;
2527 /* Save the original cursor and console screen buffer information */
2528 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2529 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2533 ConsoleInfo
= OrgConsoleBufferInfo
;
2535 /* Clear the SEQ, GC, CRTC and AC registers */
2536 RtlZeroMemory(VgaSeqRegisters
, sizeof(VgaSeqRegisters
));
2537 RtlZeroMemory(VgaGcRegisters
, sizeof(VgaGcRegisters
));
2538 RtlZeroMemory(VgaCrtcRegisters
, sizeof(VgaCrtcRegisters
));
2539 RtlZeroMemory(VgaAcRegisters
, sizeof(VgaAcRegisters
));
2541 /* Initialize the VGA palette and fail if it isn't successfully created */
2542 if (!VgaInitializePalette()) return FALSE
;
2543 /***/ VgaResetPalette(); /***/
2545 /* Switch to the text buffer, but do not enter into a text mode */
2546 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2548 /* Reset the sequencer */
2549 VgaResetSequencer();
2551 /* Clear the VGA memory */
2554 /* Register the I/O Ports */
2555 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2556 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2557 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2558 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2559 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2560 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2561 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2562 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2563 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2564 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2565 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2566 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2567 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2569 /* CGA ports for compatibility, unimplemented */
2570 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2571 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2573 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
2574 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
2576 /* Return success */
2580 VOID
VgaCleanup(VOID
)
2582 /* Do a final display refresh */
2583 VgaRefreshDisplay();
2585 DestroyHardwareTimer(VSyncTimer
);
2586 DestroyHardwareTimer(HSyncTimer
);
2588 /* Leave the current video mode */
2589 if (ScreenMode
== GRAPHICS_MODE
)
2590 VgaLeaveGraphicsMode();
2594 VgaDetachFromConsole();
2595 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2597 CloseHandle(AnotherEvent
);
2598 CloseHandle(EndEvent
);
2599 CloseHandle(StartEvent
);