2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: SuperVGA hardware emulation (Cirrus Logic CL-GD5434 compatible)
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 #include <bios/vidbios.h>
22 /* PRIVATE VARIABLES **********************************************************/
24 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
25 static CONST DWORD MemorySize
[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
28 * Activate this line if you want to use the real
29 * RegisterConsoleVDM API of ReactOS/Windows.
31 // #define USE_REAL_REGISTERCONSOLEVDM
33 #define USE_REACTOS_COLORS
34 // #define USE_DOSBOX_COLORS
36 #if defined(USE_REACTOS_COLORS)
39 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
41 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
42 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
43 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
44 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
45 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
46 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
47 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
48 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
49 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
50 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
51 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
52 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
53 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
54 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
55 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
56 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
57 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
58 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
59 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
60 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
61 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
62 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
63 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
64 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
65 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
66 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
67 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
68 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
69 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
70 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
71 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
72 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
73 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
74 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
75 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
76 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
77 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
78 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
79 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
80 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
81 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
82 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
83 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
84 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
85 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
86 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
87 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
88 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
89 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
90 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
91 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
92 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
93 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
94 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
95 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
96 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
97 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
98 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
99 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
100 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
101 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
102 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
103 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
104 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
107 #elif defined(USE_DOSBOX_COLORS)
110 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
112 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
113 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
114 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
115 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
116 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
117 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
118 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
119 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
120 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
121 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
122 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
123 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
124 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
125 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
126 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
127 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
129 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
130 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
131 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
132 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
133 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
134 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
135 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
136 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
137 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
138 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
139 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
140 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
141 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
142 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
143 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
144 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
146 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
147 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
148 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
149 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
150 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
151 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
152 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
153 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
154 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
155 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
156 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
157 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
158 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
159 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
160 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
161 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
163 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
164 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
165 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
166 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
167 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
168 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
169 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
170 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
171 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
172 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
173 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
174 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
175 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
176 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
177 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
178 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
184 * Default 16-color palette for foreground and background
185 * (corresponding flags in comments).
186 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
188 static const COLORREF ConsoleColors
[16] =
190 RGB(0, 0, 0), // (Black)
191 RGB(0, 0, 128), // BLUE
192 RGB(0, 128, 0), // GREEN
193 RGB(0, 128, 128), // BLUE | GREEN
194 RGB(128, 0, 0), // RED
195 RGB(128, 0, 128), // BLUE | RED
196 RGB(128, 128, 0), // GREEN | RED
197 RGB(192, 192, 192), // BLUE | GREEN | RED
199 RGB(128, 128, 128), // (Grey) INTENSITY
200 RGB(0, 0, 255), // BLUE | INTENSITY
201 RGB(0, 255, 0), // GREEN | INTENSITY
202 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
203 RGB(255, 0, 0), // RED | INTENSITY
204 RGB(255, 0, 255), // BLUE | RED | INTENSITY
205 RGB(255, 255, 0), // GREEN | RED | INTENSITY
206 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
210 * Console interface -- VGA-mode-agnostic
212 // WARNING! This structure *MUST BE* in sync with the one in consrv/include/conio_winsrv.h
213 typedef struct _CHAR_CELL
217 } CHAR_CELL
, *PCHAR_CELL
;
218 C_ASSERT(sizeof(CHAR_CELL
) == 2);
220 static PVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
221 // either TextFramebuffer or a
222 // valid graphics framebuffer.
223 static HPALETTE TextPaletteHandle
= NULL
;
224 static HPALETTE PaletteHandle
= NULL
;
226 static HANDLE StartEvent
= NULL
;
227 static HANDLE EndEvent
= NULL
;
228 static HANDLE AnotherEvent
= NULL
;
230 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
231 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
234 static HANDLE ScreenBufferHandle
= NULL
;
235 static LPVOID OldConsoleFramebuffer
= NULL
;
239 * Text mode -- we always keep a valid text mode framebuffer
240 * even if we are in graphics mode. This is needed in order
241 * to keep a consistent VGA state. However, each time the VGA
242 * detaches from the console (and reattaches to it later on),
243 * this text mode framebuffer is recreated.
245 static HANDLE TextConsoleBuffer
= NULL
;
246 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
247 static COORD TextResolution
= {0};
248 static PCHAR_CELL TextFramebuffer
= NULL
;
253 static HANDLE GraphicsConsoleBuffer
= NULL
;
254 static PVOID GraphicsFramebuffer
= NULL
;
255 static HANDLE ConsoleMutex
= NULL
;
256 /* DoubleVision support */
257 static BOOLEAN DoubleWidth
= FALSE
;
258 static BOOLEAN DoubleHeight
= FALSE
;
264 static BYTE VgaMemory
[VGA_NUM_BANKS
* SVGA_BANK_SIZE
];
266 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
268 static BYTE VgaMiscRegister
;
269 static BYTE VgaFeatureRegister
;
271 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
272 static BYTE VgaSeqRegisters
[SVGA_SEQ_MAX_REG
];
274 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
275 static BYTE VgaCrtcRegisters
[SVGA_CRTC_MAX_REG
];
277 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
278 static BYTE VgaGcRegisters
[SVGA_GC_MAX_REG
];
280 static BOOLEAN VgaAcLatch
= FALSE
;
281 static BOOLEAN VgaAcPalDisable
= TRUE
;
282 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
283 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
285 static BYTE VgaDacMask
= 0xFF;
286 static BYTE VgaDacLatchCounter
= 0;
287 static BYTE VgaDacLatch
[3];
289 static BOOLEAN VgaDacReadWrite
= FALSE
;
290 static WORD VgaDacIndex
= 0;
291 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
293 // static VGA_REGISTERS VgaRegisters;
295 static ULONGLONG VerticalRetraceCycle
= 0ULL;
296 static ULONGLONG HorizontalRetraceCycle
= 0ULL;
297 static PHARDWARE_TIMER VSyncTimer
;
298 static PHARDWARE_TIMER HSyncTimer
;
300 static BOOLEAN NeedsUpdate
= FALSE
;
301 static BOOLEAN ModeChanged
= FALSE
;
302 static BOOLEAN CursorChanged
= FALSE
;
303 static BOOLEAN PaletteChanged
= FALSE
;
305 static UINT SvgaHdrCounter
= 0;
306 static BYTE SvgaHiddenRegister
= 0;
308 typedef enum _SCREEN_MODE
312 } SCREEN_MODE
, *PSCREEN_MODE
;
314 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
315 static COORD CurrResolution
= {0};
317 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
319 /* RegisterConsoleVDM EMULATION ***********************************************/
321 #include <ntddvdeo.h>
323 #ifdef USE_REAL_REGISTERCONSOLEVDM
325 #define __RegisterConsoleVDM RegisterConsoleVDM
326 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
331 * This private buffer, per-console, is used by
332 * RegisterConsoleVDM and InvalidateConsoleDIBits.
334 static COORD VDMBufferSize
= {0};
335 static PCHAR_CELL VDMBuffer
= NULL
;
337 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
338 // for the real RegisterConsoleVDM and
339 // InvalidateConsoleDIBits
343 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
344 IN HANDLE hStartHardwareEvent
,
345 IN HANDLE hEndHardwareEvent
,
346 IN HANDLE hErrorHardwareEvent
,
347 IN DWORD dwUnusedVar
,
348 OUT LPDWORD lpVideoStateLength
,
349 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
350 IN PVOID lpUnusedBuffer
,
351 IN DWORD dwUnusedBufferLength
,
352 IN COORD dwVDMBufferSize
,
353 OUT PVOID
* lpVDMBuffer
)
355 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
356 UNREFERENCED_PARAMETER(dwUnusedVar
);
357 UNREFERENCED_PARAMETER(lpVideoStateLength
);
358 UNREFERENCED_PARAMETER(lpVideoState
);
359 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
360 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
363 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
365 if (lpVDMBuffer
== NULL
) return FALSE
;
367 if (dwRegisterFlags
!= 0)
369 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
370 if (VDMBuffer
!= NULL
) return FALSE
;
372 VDMBufferSize
= dwVDMBufferSize
;
374 /* HACK: Cache -- to be removed in the real implementation */
375 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
377 VDMBufferSize
.X
* VDMBufferSize
.Y
378 * sizeof(*CharBuff
));
381 VDMBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
383 VDMBufferSize
.X
* VDMBufferSize
.Y
384 * sizeof(*VDMBuffer
));
385 *lpVDMBuffer
= VDMBuffer
;
386 return (VDMBuffer
!= NULL
);
390 /* HACK: Cache -- to be removed in the real implementation */
391 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
394 if (VDMBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer
);
397 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
404 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
405 IN PSMALL_RECT lpRect
)
407 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
409 /* HACK: Write the cached data to the console */
411 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
416 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
418 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
420 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
421 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
425 WriteConsoleOutputA(hConsoleOutput
,
432 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
437 /* PRIVATE FUNCTIONS **********************************************************/
439 static inline DWORD
VgaGetAddressSize(VOID
);
440 static VOID
VgaUpdateTextCursor(VOID
);
442 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
444 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
447 static VOID
VgaUpdateCursorPosition(VOID
)
450 * Update the cursor position in the VGA registers.
452 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
453 ConsoleInfo
.dwCursorPosition
.X
;
455 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
456 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
458 // VidBiosSyncCursorPosition();
459 VgaUpdateTextCursor();
462 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
466 PVIDEO_HARDWARE_STATE_HEADER State
;
468 #ifdef USE_REAL_REGISTERCONSOLEVDM
469 PCHAR_INFO CharBuff
= NULL
;
472 DWORD AddressSize
, ScanlineSize
;
476 COORD Origin
= { 0, 0 };
478 ASSERT(TextFramebuffer
== NULL
);
480 TextResolution
= *Resolution
;
483 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
484 * in the two following APIs:
485 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
486 * SrvVDMConsoleOperation (corresponding Win32 API: ??)
487 * to check whether the current process is a VDM process, and fails otherwise
488 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
490 * It is worth it to notice that also basesrv.dll does the same only for the
491 * BaseSrvIsFirstVDM API...
494 /* Register with the console server */
496 __RegisterConsoleVDM(1,
499 AnotherEvent
, // NULL,
501 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
502 (PVOID
*)&State
, // NULL,
506 (PVOID
*)&TextFramebuffer
);
509 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
514 #ifdef USE_REAL_REGISTERCONSOLEVDM
515 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
517 TextResolution
.X
* TextResolution
.Y
518 * sizeof(*CharBuff
));
526 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
527 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
528 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
530 * Use this trick to effectively resize the console buffer and window,
532 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
533 * is smaller than the current console window size, and:
534 * - SetConsoleWindowInfo fails if the new console window size is larger
535 * than the current console screen buffer size.
537 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
538 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
539 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
540 /* Update the saved console information */
541 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
544 * Copy console data into VGA memory
548 AddressSize
= VgaGetAddressSize();
549 ConRect
.Left
= ConRect
.Top
= 0;
550 ConRect
.Right
= TextResolution
.X
;
551 ConRect
.Bottom
= TextResolution
.Y
;
552 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
554 /* Read the data from the console into the framebuffer... */
555 ReadConsoleOutputA(TextConsoleBuffer
,
561 /* ... and copy the framebuffer into the VGA memory */
563 /* Loop through the scanlines */
564 for (i
= 0; i
< TextResolution
.Y
; i
++)
566 /* Loop through the characters */
567 for (j
= 0; j
< TextResolution
.X
; j
++)
569 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
571 /* Store the character in plane 0 */
572 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
574 /* Store the attribute in plane 1 */
575 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
578 /* Move to the next scanline */
579 Address
+= ScanlineSize
;
582 #ifdef USE_REAL_REGISTERCONSOLEVDM
583 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
586 VgaUpdateCursorPosition();
591 static VOID
VgaDetachFromConsoleInternal(VOID
)
595 COORD dummySize
= {0};
597 /* Deregister with the console server */
598 __RegisterConsoleVDM(0,
610 TextFramebuffer
= NULL
;
613 static BOOL
IsConsoleHandle(HANDLE hHandle
)
617 /* Check whether the handle may be that of a console... */
618 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
622 * It may be. Perform another test... The idea comes from the
623 * MSDN description of the WriteConsole API:
625 * "WriteConsole fails if it is used with a standard handle
626 * that is redirected to a file. If an application processes
627 * multilingual output that can be redirected, determine whether
628 * the output handle is a console handle (one method is to call
629 * the GetConsoleMode function and check whether it succeeds).
630 * If the handle is a console handle, call WriteConsole. If the
631 * handle is not a console handle, the output is redirected and
632 * you should call WriteFile to perform the I/O."
634 return GetConsoleMode(hHandle
, &dwMode
);
637 static inline DWORD
VgaGetAddressSize(VOID
)
639 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
641 /* Double-word addressing */
642 return 4; // sizeof(DWORD)
644 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
646 /* Byte addressing */
647 return 1; // sizeof(BYTE)
651 /* Word addressing */
652 return 2; // sizeof(WORD)
656 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
658 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
661 /* Check for chain-4 and odd-even mode */
662 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
664 /* The lowest two bits are the plane number */
665 Plane
= Offset
& 0x03;
668 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
670 /* The LSB is the plane number */
671 Plane
= Offset
& 0x01;
676 /* Use the read mode */
677 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
680 /* Return the offset on plane 0 for read mode 1 */
681 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
) return Offset
;
682 else return Offset
+ Plane
* VGA_BANK_SIZE
;
685 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
687 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
689 /* Check for chain-4 and odd-even mode */
690 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
692 /* Clear the lowest two bits since they're used to select the bank */
695 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
697 /* Clear the lowest bit since it's used to select odd/even */
701 /* Return the offset on plane 0 */
705 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
707 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
708 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
712 /* In write mode 1 just return the latch register */
713 return VgaLatchRegisters
[Plane
];
718 /* Write modes 0 and 3 rotate the data to the right first */
719 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
720 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
724 /* Write mode 2 expands the appropriate bit to all 8 bits */
725 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
731 * In write mode 0, the enable set/reset register decides if the
732 * set/reset bit should be expanded to all 8 bits.
734 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
736 /* Copy the bit from the set/reset register to all 8 bits */
737 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
743 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
744 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
746 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
747 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
748 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
752 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
755 /* Then we expand the bit in the set/reset field */
756 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
759 /* Bits cleared in the bitmask are replaced with latch register bits */
760 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
762 /* Return the byte */
766 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
768 /* Check if this is the first time the rectangle is updated */
771 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
772 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
775 /* Expand the rectangle to include the point */
776 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
777 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
778 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
779 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
781 /* Set the update request flag */
785 static inline ULONG
VgaGetClockFrequency(VOID
)
787 BYTE Numerator
, Denominator
;
789 if (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & SVGA_SEQ_MCLK_VCLK
)
791 /* The VCLK is being generated using the MCLK */
792 ULONG Clock
= (VGA_CLOCK_BASE
* (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & 0x3F)) >> 3;
794 if (VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] & 1)
796 /* Use only half of the MCLK as the VCLK */
803 switch ((VgaMiscRegister
>> 2) & 3)
807 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
];
808 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
];
814 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
];
815 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
];
821 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
];
822 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
];
828 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
];
829 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
];
834 /* The numerator is 7-bit */
835 Numerator
&= ~(1 << 7);
837 /* If bit 7 is clear, the denominator is 5-bit */
838 if (!(Denominator
& (1 << 7))) Denominator
&= ~(1 << 6);
840 /* Bit 0 of the denominator is the post-scalar bit */
841 if (Denominator
& 1) Denominator
&= ~1;
842 else Denominator
>>= 1;
844 /* Return the clock frequency in Hz */
845 return (VGA_CLOCK_BASE
* Numerator
) / Denominator
;
848 static VOID
VgaResetSequencer(VOID
)
850 /* Lock extended SVGA registers */
851 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
853 /* Initialize the VCLKs */
854 VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
] = 0x66;
855 VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
] = 0x3B;
856 VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
] = 0x5B;
857 VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
] = 0x2F;
858 VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
] = 0x45;
859 VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
] = 0x30;
860 VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
] = 0x7E;
861 VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] = 0x33;
863 /* 50 MHz MCLK, not being used as the VCLK */
864 VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] = 0x1C;
867 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
871 /* Copy the colors of the default palette to the DAC and console palette */
872 for (i
= 0; i
< NumOfEntries
; i
++)
874 /* Set the palette entries */
875 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
876 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
877 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
878 Entries
[i
].peFlags
= 0;
880 /* Set the DAC registers */
881 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
882 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
883 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
887 static BOOLEAN
VgaInitializePalette(VOID
)
890 BOOLEAN Result
= FALSE
;
891 LPLOGPALETTE Palette
, TextPalette
;
893 /* Allocate storage space for the palettes */
894 Palette
= RtlAllocateHeap(RtlGetProcessHeap(),
897 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
898 TextPalette
= RtlAllocateHeap(RtlGetProcessHeap(),
901 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
902 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
904 /* Initialize the palettes */
905 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
906 Palette
->palNumEntries
= VGA_MAX_COLORS
;
907 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
909 /* Restore the default graphics palette */
910 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
912 /* Set the default text palette */
913 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
915 /* Set the palette entries */
916 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
917 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
918 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
919 TextPalette
->palPalEntry
[i
].peFlags
= 0;
922 /* Create the palettes */
923 PaletteHandle
= CreatePalette(Palette
);
924 TextPaletteHandle
= CreatePalette(TextPalette
);
926 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
928 /* The palettes have been created successfully */
933 /* Free the palettes */
934 if (Palette
) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette
);
935 if (TextPalette
) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette
);
939 /* Something failed, delete the palettes */
940 if (PaletteHandle
) DeleteObject(PaletteHandle
);
941 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
947 static VOID
VgaResetPalette(VOID
)
949 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
951 /* Restore the default palette */
952 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
953 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
954 PaletteChanged
= TRUE
;
957 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
959 ASSERT(ScreenBuffer
);
961 /* Set the active buffer */
962 SetConsoleActiveScreenBuffer(ScreenBuffer
);
964 /* Reinitialize the VDM menu */
966 CreateVdmMenu(ScreenBuffer
);
969 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
972 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
973 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
974 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
975 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
977 LONG Width
= Resolution
->X
;
978 LONG Height
= Resolution
->Y
;
980 /* Use DoubleVision mode if the resolution is too small */
981 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
982 if (DoubleWidth
) Width
*= 2;
983 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
984 if (DoubleHeight
) Height
*= 2;
986 /* Fill the bitmap info header */
987 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
988 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
989 BitmapInfo
->bmiHeader
.biWidth
= Width
;
990 BitmapInfo
->bmiHeader
.biHeight
= Height
;
991 BitmapInfo
->bmiHeader
.biBitCount
= 8;
992 BitmapInfo
->bmiHeader
.biPlanes
= 1;
993 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
994 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
996 /* Fill the palette data */
997 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
999 /* Fill the console graphics buffer info */
1000 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
1001 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
1002 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
1004 /* Create the buffer */
1005 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
1006 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1008 CONSOLE_GRAPHICS_BUFFER
,
1009 &GraphicsBufferInfo
);
1010 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
1012 /* Save the framebuffer address and mutex */
1013 GraphicsFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
1014 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
1016 /* Clear the framebuffer */
1017 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
1019 /* Set the active buffer */
1020 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
1022 /* The active framebuffer is now the graphics framebuffer */
1023 ConsoleFramebuffer
= GraphicsFramebuffer
;
1025 /* Set the graphics mode palette */
1026 SetConsolePalette(GraphicsConsoleBuffer
,
1028 SYSPAL_NOSTATIC256
);
1030 /* Set the screen mode flag */
1031 ScreenMode
= GRAPHICS_MODE
;
1036 static VOID
VgaLeaveGraphicsMode(VOID
)
1038 /* Release the console framebuffer mutex */
1039 ReleaseMutex(ConsoleMutex
);
1041 /* Switch back to the default console text buffer */
1042 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1044 /* Cleanup the video data */
1045 CloseHandle(ConsoleMutex
);
1046 ConsoleMutex
= NULL
;
1047 GraphicsFramebuffer
= NULL
;
1048 CloseHandle(GraphicsConsoleBuffer
);
1049 GraphicsConsoleBuffer
= NULL
;
1051 /* Reset the active framebuffer */
1052 ConsoleFramebuffer
= NULL
;
1054 DoubleWidth
= FALSE
;
1055 DoubleHeight
= FALSE
;
1058 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1060 /* Switch to the text buffer */
1061 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
1063 /* Adjust the text framebuffer if we changed the resolution */
1064 if (TextResolution
.X
!= Resolution
->X
||
1065 TextResolution
.Y
!= Resolution
->Y
)
1067 VgaDetachFromConsoleInternal();
1070 * VgaAttachToConsoleInternal sets TextResolution to the
1071 * new resolution and updates ConsoleInfo.
1073 if (!VgaAttachToConsoleInternal(Resolution
))
1075 DisplayMessage(L
"An unexpected error occurred!\n");
1076 EmulatorTerminate();
1082 VgaUpdateCursorPosition();
1085 /* The active framebuffer is now the text framebuffer */
1086 ConsoleFramebuffer
= TextFramebuffer
;
1089 * Set the text mode palette.
1091 * INFORMATION: This call should fail on Windows (and therefore
1092 * we get the default palette and our external behaviour is
1093 * just like Windows' one), but it should success on ReactOS
1094 * (so that we get console palette changes even for text-mode
1095 * screen-buffers, which is a new feature on ReactOS).
1097 SetConsolePalette(TextConsoleBuffer
,
1099 SYSPAL_NOSTATIC256
);
1101 /* Set the screen mode flag */
1102 ScreenMode
= TEXT_MODE
;
1107 static VOID
VgaLeaveTextMode(VOID
)
1109 /* Reset the active framebuffer */
1110 ConsoleFramebuffer
= NULL
;
1113 static VOID
VgaChangeMode(VOID
)
1115 COORD NewResolution
= VgaGetDisplayResolution();
1116 SCREEN_MODE NewScreenMode
=
1117 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
1121 * Do not switch to a different screen mode + resolution if the new settings
1122 * are the same as the old ones. Just repaint the full screen.
1124 if ((ScreenMode
== NewScreenMode
) && // CurrResolution == NewResolution
1125 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1130 /* Leave the current video mode */
1131 if (ScreenMode
== GRAPHICS_MODE
)
1132 VgaLeaveGraphicsMode();
1136 /* Update the current resolution */
1137 CurrResolution
= NewResolution
;
1139 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1141 /* Check if the new mode is alphanumeric */
1142 if (NewScreenMode
== TEXT_MODE
)
1144 /* Enter new text mode */
1145 if (!VgaEnterTextMode(&CurrResolution
))
1147 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1148 EmulatorTerminate();
1154 /* Enter graphics mode */
1155 if (!VgaEnterGraphicsMode(&CurrResolution
))
1157 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1158 EmulatorTerminate();
1165 /* Trigger a full update of the screen */
1167 UpdateRectangle
.Left
= 0;
1168 UpdateRectangle
.Top
= 0;
1169 UpdateRectangle
.Right
= CurrResolution
.X
;
1170 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1172 /* Reset the mode change flag */
1173 ModeChanged
= FALSE
;
1176 static VOID
VgaUpdateFramebuffer(VOID
)
1179 DWORD AddressSize
= VgaGetAddressSize();
1180 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1181 BYTE PresetRowScan
= VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] & 0x1F;
1182 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1183 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
])
1184 + PresetRowScan
* ScanlineSize
1185 + ((VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] >> 5) & 3);
1188 * If the console framebuffer is NULL, that means something
1189 * went wrong earlier and this is the final display refresh.
1191 if (ConsoleFramebuffer
== NULL
) return;
1193 /* Check if we are in text or graphics mode */
1194 if (ScreenMode
== GRAPHICS_MODE
)
1197 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1198 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1202 * Synchronize access to the graphics framebuffer
1203 * with the console framebuffer mutex.
1205 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1207 /* Shift the high bit right by 1 in odd/even mode */
1208 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1210 InterlaceHighBit
>>= 1;
1213 /* Loop through the scanlines */
1214 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1216 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1218 /* Odd-numbered line in interlaced mode - set the high bit */
1219 Address
|= InterlaceHighBit
;
1222 /* Loop through the pixels */
1223 for (j
= 0; j
< CurrResolution
.X
; j
++)
1227 /* Apply horizontal pixel panning */
1228 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1230 X
= j
+ ((VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F) >> 1);
1234 X
= j
+ (VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F);
1237 /* Check the shifting mode */
1238 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1240 /* 4 bits shifted from each plane */
1242 /* Check if this is 16 or 256 color mode */
1243 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1245 /* One byte per pixel */
1246 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1247 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1252 /* 4-bits per pixel */
1254 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1255 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1258 /* Check if we should use the highest 4 bits or lowest 4 */
1259 if (((X
/ VGA_NUM_BANKS
) % 2) == 0)
1271 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1273 /* Check if this is 16 or 256 color mode */
1274 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1276 // TODO: NOT IMPLEMENTED
1277 DPRINT1("8-bit interleaved mode is not implemented!\n");
1282 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1283 * then 2 bits shifted from plane 1 and 3 for the next 4
1285 DWORD BankNumber
= (X
/ 4) % 2;
1286 DWORD Offset
= Address
+ (X
/ 8);
1287 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1288 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1290 /* Extract the two bits from each plane */
1291 LowPlaneData
= (LowPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1292 HighPlaneData
= (HighPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1294 /* Combine them into the pixel */
1295 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1300 /* 1 bit shifted from each plane */
1302 /* Check if this is 16 or 256 color mode */
1303 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1305 /* 8 bits per pixel, 2 on each plane */
1307 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1309 /* The data is on plane k, 4 pixels per byte */
1310 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1311 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1314 /* The mask of the first bit in the pair */
1315 BYTE BitMask
= 1 << (((3 - (X
% VGA_NUM_BANKS
)) * 2) + 1);
1317 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1318 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1320 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1321 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1326 /* 4 bits per pixel, 1 on each plane */
1328 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1330 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1331 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1334 /* If the bit on that plane is set, set it */
1335 if (PlaneData
& (1 << (7 - (X
% 8)))) PixelData
|= 1 << k
;
1340 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1343 * In 16 color mode, the value is an index to the AC registers
1344 * if external palette access is disabled, otherwise (in case
1345 * of palette loading) it is a blank pixel.
1347 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1351 /* Take into account DoubleVision mode when checking for pixel updates */
1352 if (DoubleWidth
&& DoubleHeight
)
1354 /* Now check if the resulting pixel data has changed */
1355 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1357 /* Yes, write the new value */
1358 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1359 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1360 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1361 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1363 /* Mark the specified pixel as changed */
1364 VgaMarkForUpdate(i
, j
);
1367 else if (DoubleWidth
&& !DoubleHeight
)
1369 /* Now check if the resulting pixel data has changed */
1370 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1372 /* Yes, write the new value */
1373 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1374 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1376 /* Mark the specified pixel as changed */
1377 VgaMarkForUpdate(i
, j
);
1380 else if (!DoubleWidth
&& DoubleHeight
)
1382 /* Now check if the resulting pixel data has changed */
1383 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1385 /* Yes, write the new value */
1386 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1387 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1389 /* Mark the specified pixel as changed */
1390 VgaMarkForUpdate(i
, j
);
1393 else // if (!DoubleWidth && !DoubleHeight)
1395 /* Now check if the resulting pixel data has changed */
1396 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1398 /* Yes, write the new value */
1399 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1401 /* Mark the specified pixel as changed */
1402 VgaMarkForUpdate(i
, j
);
1407 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1409 /* Clear the high bit */
1410 Address
&= ~InterlaceHighBit
;
1413 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1415 /* Move to the next scanline */
1416 Address
+= ScanlineSize
;
1421 * Release the console framebuffer mutex
1422 * so that we allow for repainting.
1424 ReleaseMutex(ConsoleMutex
);
1430 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1434 * Technically, the horizontal panning and preset row count should
1435 * affect text mode too. However, it works on pixels and not characters,
1436 * so we can't support it currently.
1439 /* Loop through the scanlines */
1440 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1442 /* Loop through the characters */
1443 for (j
= 0; j
< CurrResolution
.X
; j
++)
1445 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1447 /* Plane 0 holds the character itself */
1448 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1450 /* Plane 1 holds the attribute */
1451 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1453 /* Now check if the resulting character data has changed */
1454 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1455 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1457 /* Yes, write the new value */
1458 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1460 /* Mark the specified cell as changed */
1461 VgaMarkForUpdate(i
, j
);
1465 /* Move to the next scanline */
1466 Address
+= ScanlineSize
;
1471 static VOID
VgaUpdateTextCursor(VOID
)
1474 CONSOLE_CURSOR_INFO CursorInfo
;
1476 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1477 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1478 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1480 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1481 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1482 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1483 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1485 /* Just return if we are not in text mode */
1486 if (ScreenMode
!= TEXT_MODE
) return;
1488 if (CursorStart
< CursorEnd
)
1490 /* Visible cursor */
1491 CursorInfo
.bVisible
= CursorVisible
;
1492 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1497 CursorInfo
.bVisible
= FALSE
;
1498 CursorInfo
.dwSize
= 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1501 /* Add the cursor skew to the location */
1502 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1504 /* Find the coordinates of the new position */
1505 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1506 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1508 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1510 /* Update the physical cursor */
1511 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1512 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1514 /* Reset the cursor changed flag */
1515 CursorChanged
= FALSE
;
1518 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1520 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1522 if (Port
!= VGA_DAC_MASK
) SvgaHdrCounter
= 0;
1527 return VgaMiscRegister
;
1529 case VGA_INSTAT0_READ
:
1530 return 0; // Not implemented
1532 case VGA_INSTAT1_READ_MONO
:
1533 case VGA_INSTAT1_READ_COLOR
:
1536 BOOLEAN Vsync
, Hsync
;
1537 ULONGLONG Cycles
= GetCycleCount();
1538 ULONG CyclesPerMicrosecond
= (ULONG
)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1539 ULONG Dots
= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & 1) ? 9 : 8;
1540 ULONG Clock
= VgaGetClockFrequency() / 1000000;
1541 ULONG HorizTotalDots
= ((ULONG
)VgaCrtcRegisters
[VGA_CRTC_HORZ_TOTAL_REG
] + 5) * Dots
;
1542 ULONG VblankStart
, VblankEnd
, HblankStart
, HblankEnd
;
1543 ULONG HblankDuration
, VblankDuration
;
1545 /* Calculate the vertical blanking duration in cycles */
1546 VblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_VERT_BLANKING_REG
] & 0x7F;
1547 VblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_VERT_BLANKING_REG
] & 0x7F;
1548 if (VblankEnd
< VblankStart
) VblankEnd
|= 0x80;
1549 VblankDuration
= ((VblankEnd
- VblankStart
) * HorizTotalDots
1550 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1552 /* Calculate the horizontal blanking duration in cycles */
1553 HblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_HORZ_BLANKING_REG
] & 0x1F;
1554 HblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_BLANKING_REG
] & 0x1F;
1555 if (HblankEnd
< HblankStart
) HblankEnd
|= 0x20;
1556 HblankDuration
= ((HblankEnd
- HblankStart
) * Dots
1557 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1559 Vsync
= (Cycles
- VerticalRetraceCycle
) < (ULONGLONG
)VblankDuration
;
1560 Hsync
= (Cycles
- HorizontalRetraceCycle
) < (ULONGLONG
)HblankDuration
;
1562 /* Reset the AC latch */
1565 /* Reverse the polarity, if needed */
1566 if (VgaMiscRegister
& VGA_MISC_VSYNCP
) Vsync
= !Vsync
;
1567 if (VgaMiscRegister
& VGA_MISC_HSYNCP
) Hsync
= !Hsync
;
1569 /* Set a flag if there is a vertical or horizontal retrace */
1570 if (Vsync
|| Hsync
) Result
|= VGA_STAT_DD
;
1572 /* Set an additional flag if there was a vertical retrace */
1573 if (Vsync
) Result
|= VGA_STAT_VRETRACE
;
1578 case VGA_FEATURE_READ
:
1579 return VgaFeatureRegister
;
1585 return VgaAcRegisters
[VgaAcIndex
];
1591 return VgaSeqRegisters
[VgaSeqIndex
];
1595 if (SvgaHdrCounter
== 4)
1598 return SvgaHiddenRegister
;
1607 case VGA_DAC_READ_INDEX
:
1608 /* This returns the read/write state */
1609 return (VgaDacReadWrite
? 0 : 3);
1611 case VGA_DAC_WRITE_INDEX
:
1616 /* Ignore reads in write mode */
1617 if (!VgaDacReadWrite
)
1619 BYTE Data
= VgaDacRegisters
[VgaDacIndex
* 3 + VgaDacLatchCounter
];
1620 VgaDacLatchCounter
++;
1622 if (VgaDacLatchCounter
== 3)
1624 /* Reset the latch counter and increment the palette index */
1625 VgaDacLatchCounter
= 0;
1627 VgaDacIndex
%= VGA_MAX_COLORS
;
1636 case VGA_CRTC_INDEX_MONO
:
1637 case VGA_CRTC_INDEX_COLOR
:
1638 return VgaCrtcIndex
;
1640 case VGA_CRTC_DATA_MONO
:
1641 case VGA_CRTC_DATA_COLOR
:
1642 return VgaCrtcRegisters
[VgaCrtcIndex
];
1648 return VgaGcRegisters
[VgaGcIndex
];
1651 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1658 static inline VOID
VgaWriteSequencer(BYTE Data
)
1660 /* Save the value */
1661 VgaSeqRegisters
[VgaSeqIndex
& VGA_SEQ_INDEX_MASK
] = Data
;
1663 /* Check the index */
1664 switch (VgaSeqIndex
& VGA_SEQ_INDEX_MASK
)
1666 case SVGA_SEQ_UNLOCK_REG
:
1668 if ((Data
& SVGA_SEQ_UNLOCK_MASK
) == SVGA_SEQ_UNLOCKED
)
1670 /* Unlock SVGA extensions */
1671 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_UNLOCKED
;
1675 /* Lock SVGA extensions */
1676 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
1684 static inline VOID
VgaWriteGc(BYTE Data
)
1686 /* Save the value */
1687 VgaGcRegisters
[VgaGcIndex
& VGA_GC_INDEX_MASK
] = Data
;
1689 /* Check the index */
1690 switch (VgaGcIndex
& VGA_GC_INDEX_MASK
)
1692 case VGA_GC_MISC_REG
:
1694 /* Remove any existing VGA memory hook */
1695 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1697 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1699 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1701 /* Register a memory hook */
1702 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1703 MemorySize
[MemoryMap
],
1708 /* The GC misc register decides if it's text or graphics mode */
1715 static inline VOID
VgaWriteCrtc(BYTE Data
)
1717 /* Save the value */
1718 VgaCrtcRegisters
[VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
] = Data
;
1720 /* Check the index */
1721 switch (VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
)
1723 case VGA_CRTC_END_HORZ_DISP_REG
:
1724 case VGA_CRTC_VERT_DISP_END_REG
:
1725 case VGA_CRTC_OVERFLOW_REG
:
1726 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1728 /* The video mode has changed */
1733 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1734 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1735 case VGA_CRTC_CURSOR_START_REG
:
1736 case VGA_CRTC_CURSOR_END_REG
:
1738 /* Set the cursor changed flag */
1739 CursorChanged
= TRUE
;
1745 static inline VOID
VgaWriteDac(BYTE Data
)
1750 /* Store the value in the latch */
1751 VgaDacLatch
[VgaDacLatchCounter
++] = Data
;
1752 if (VgaDacLatchCounter
< 3) return;
1754 /* Reset the latch counter */
1755 VgaDacLatchCounter
= 0;
1757 /* Set the DAC register values */
1758 VgaDacRegisters
[VgaDacIndex
* 3] = VgaDacLatch
[0];
1759 VgaDacRegisters
[VgaDacIndex
* 3 + 1] = VgaDacLatch
[1];
1760 VgaDacRegisters
[VgaDacIndex
* 3 + 2] = VgaDacLatch
[2];
1762 /* Fill the entry structure */
1763 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacLatch
[0]);
1764 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacLatch
[1]);
1765 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacLatch
[2]);
1768 /* Update the palette entry */
1769 SetPaletteEntries(PaletteHandle
, VgaDacIndex
, 1, &Entry
);
1771 /* Check which text palette entries are affected */
1772 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1774 if (VgaAcRegisters
[i
] == VgaDacIndex
)
1776 /* Update the text palette entry */
1777 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1781 /* Set the palette changed flag */
1782 PaletteChanged
= TRUE
;
1784 /* Update the index */
1786 VgaDacIndex
%= VGA_MAX_COLORS
;
1789 static inline VOID
VgaWriteAc(BYTE Data
)
1793 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1795 /* Save the value */
1796 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1798 if (VgaAcPalDisable
) return;
1800 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1801 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1803 /* Update the AC register */
1804 VgaAcRegisters
[VgaAcIndex
] = Data
;
1806 /* Fill the entry structure */
1807 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1808 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1809 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1812 /* Update the palette entry and set the palette change flag */
1813 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1814 PaletteChanged
= TRUE
;
1819 VgaAcRegisters
[VgaAcIndex
] = Data
;
1823 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1825 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1829 case VGA_MISC_WRITE
:
1831 VgaMiscRegister
= Data
;
1833 if (VgaMiscRegister
& 0x01)
1835 /* Color emulation */
1836 DPRINT1("Color emulation\n");
1838 /* Register the new I/O Ports */
1839 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1840 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1841 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1843 /* Unregister the old ones */
1844 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1845 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1846 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1850 /* Monochrome emulation */
1851 DPRINT1("Monochrome emulation\n");
1853 /* Register the new I/O Ports */
1854 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1855 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1856 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1858 /* Unregister the old ones */
1859 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1860 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1861 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1864 /* Remove any existing VGA memory hook */
1865 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1867 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1869 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1871 /* Register a memory hook */
1872 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1873 MemorySize
[MemoryMap
],
1881 case VGA_FEATURE_WRITE_MONO
:
1882 case VGA_FEATURE_WRITE_COLOR
:
1884 VgaFeatureRegister
= Data
;
1889 // case VGA_AC_WRITE:
1893 /* Change the index */
1894 BYTE Index
= Data
& 0x1F;
1895 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1898 * Change palette protection by checking for
1899 * the Palette Address Source bit.
1901 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1905 /* Write the data */
1909 /* Toggle the latch */
1910 VgaAcLatch
= !VgaAcLatch
;
1916 /* Set the sequencer index register */
1917 if ((Data
& 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1918 && (Data
& 0x1F) != VGA_SEQ_MAX_REG
)
1928 /* Call the sequencer function */
1929 VgaWriteSequencer(Data
);
1935 if (SvgaHdrCounter
== 4) SvgaHiddenRegister
= Data
;
1936 else VgaDacMask
= Data
;
1941 case VGA_DAC_READ_INDEX
:
1943 VgaDacReadWrite
= FALSE
;
1945 VgaDacLatchCounter
= 0;
1949 case VGA_DAC_WRITE_INDEX
:
1951 VgaDacReadWrite
= TRUE
;
1953 VgaDacLatchCounter
= 0;
1959 /* Ignore writes in read mode */
1960 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1964 case VGA_CRTC_INDEX_MONO
:
1965 case VGA_CRTC_INDEX_COLOR
:
1967 /* Set the CRTC index register */
1968 if (((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_MAX_UNLOCKED_REG
)
1969 && ((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_UNUSED0_REG
1970 || (Data
& VGA_CRTC_INDEX_MASK
) > SVGA_CRTC_UNUSED6_REG
)
1971 && (Data
& VGA_CRTC_INDEX_MASK
) != SVGA_CRTC_UNUSED7_REG
)
1973 VgaCrtcIndex
= Data
;
1979 case VGA_CRTC_DATA_MONO
:
1980 case VGA_CRTC_DATA_COLOR
:
1982 /* Call the CRTC function */
1989 /* Set the GC index register */
1990 if ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_MAX_UNLOCKED_REG
1991 && (Data
& VGA_GC_INDEX_MASK
) != SVGA_GC_UNUSED0_REG
1992 && ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_UNUSED1_REG
1993 || (Data
& VGA_GC_INDEX_MASK
) > SVGA_GC_UNUSED10_REG
))
2003 /* Call the GC function */
2009 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
2016 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
2018 HANDLE ConsoleBufferHandle
= NULL
;
2020 UNREFERENCED_PARAMETER(ElapsedTime
);
2022 /* Set the vertical retrace cycle */
2023 VerticalRetraceCycle
= GetCycleCount();
2025 /* If nothing has changed, just return */
2026 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
2029 /* Change the display mode */
2030 if (ModeChanged
) VgaChangeMode();
2032 /* Change the text cursor appearance */
2033 if (CursorChanged
) VgaUpdateTextCursor();
2037 /* Trigger a full update of the screen */
2039 UpdateRectangle
.Left
= 0;
2040 UpdateRectangle
.Top
= 0;
2041 UpdateRectangle
.Right
= CurrResolution
.X
;
2042 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
2044 PaletteChanged
= FALSE
;
2047 /* Update the contents of the framebuffer */
2048 VgaUpdateFramebuffer();
2050 /* Ignore if there's nothing to update */
2051 if (!NeedsUpdate
) return;
2053 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
2054 UpdateRectangle
.Left
,
2055 UpdateRectangle
.Top
,
2056 UpdateRectangle
.Right
,
2057 UpdateRectangle
.Bottom
);
2059 /* Check if we are in text or graphics mode */
2060 if (ScreenMode
== GRAPHICS_MODE
)
2063 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
2065 /* In DoubleVision mode, scale the update rectangle */
2068 UpdateRectangle
.Left
*= 2;
2069 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
2073 UpdateRectangle
.Top
*= 2;
2074 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
2080 ConsoleBufferHandle
= TextConsoleBuffer
;
2083 /* Redraw the screen */
2084 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
2086 /* Clear the update flag */
2087 NeedsUpdate
= FALSE
;
2090 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
2092 UNREFERENCED_PARAMETER(ElapsedTime
);
2095 HorizontalRetraceCycle
= GetCycleCount();
2098 /* PUBLIC FUNCTIONS ***********************************************************/
2100 COORD
VgaGetDisplayResolution(VOID
)
2103 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
2105 /* The low 8 bits are in the display registers */
2106 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
2107 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
2109 /* Set the top bits from the overflow register */
2110 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
2112 Resolution
.Y
|= 1 << 8;
2114 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
2116 Resolution
.Y
|= 1 << 9;
2119 /* Increase the values by 1 */
2123 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
2125 /* Multiply the horizontal resolution by the 9/8 dot mode */
2126 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
2129 /* The horizontal resolution is halved in 8-bit mode */
2130 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
2133 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
2135 /* Halve the vertical resolution */
2140 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
2141 Resolution
.Y
/= MaximumScanLine
;
2144 /* Return the resolution */
2148 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
2150 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
2151 if (Horizontal
) *Horizontal
= DoubleWidth
;
2152 if (Vertical
) *Vertical
= DoubleHeight
;
2156 VOID
VgaRefreshDisplay(VOID
)
2158 VgaVerticalRetrace(0);
2161 VOID FASTCALL
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2165 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2167 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2169 /* Ignore if video RAM access is disabled */
2170 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
2172 if (!(VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
))
2174 /* Loop through each byte */
2175 for (i
= 0; i
< Size
; i
++)
2177 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
2179 /* Copy the value to the buffer */
2180 BufPtr
[i
] = VgaMemory
[VideoAddress
];
2185 /* Loop through each byte */
2186 for (i
= 0; i
< Size
; i
++)
2190 /* This should always return a plane 0 address for read mode 1 */
2191 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
2193 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2195 /* Don't consider ignored banks */
2196 if (!(VgaGcRegisters
[VGA_GC_COLOR_IGNORE_REG
] & (1 << j
))) continue;
2198 if (VgaGcRegisters
[VGA_GC_COLOR_COMPARE_REG
] & (1 << j
))
2200 /* Comparing with 11111111 */
2201 Result
&= VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2205 /* Comparing with 00000000 */
2206 Result
&= ~(VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)]);
2210 /* Copy the value to the buffer */
2215 /* Load the latch registers */
2216 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
2217 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2218 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2219 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2222 BOOLEAN FASTCALL
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2226 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2228 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2230 /* Ignore if video RAM access is disabled */
2231 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
2233 /* Also ignore if write access to all planes is disabled */
2234 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
2236 /* Loop through each byte */
2237 for (i
= 0; i
< Size
; i
++)
2239 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
2241 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2243 /* Make sure the page is writeable */
2244 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
2246 /* Check if this is chain-4 mode */
2247 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
2249 if (((Address
+ i
) & 0x03) != j
)
2251 /* This plane will not be accessed */
2256 /* Check if this is odd-even mode */
2257 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
2259 if (((Address
+ i
) & 0x01) != (j
& 1))
2261 /* This plane will not be accessed */
2266 /* Copy the value to the VGA memory */
2267 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
2274 VOID
VgaClearMemory(VOID
)
2276 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
2279 VOID
VgaWriteTextModeFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
2282 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
2284 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
2286 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
2288 /* Write the character */
2289 for (j
= 0; j
< Height
; j
++)
2291 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
2294 /* Clear the unused part */
2295 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
2297 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
2302 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
2304 DPRINT1("Screen events not handled\n");
2307 BOOL
VgaAttachToConsole(VOID
)
2309 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2310 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2312 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2313 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2315 // VgaDetachFromConsoleInternal();
2318 * VgaAttachToConsoleInternal sets TextResolution to the
2319 * new resolution and updates ConsoleInfo.
2321 if (!VgaAttachToConsoleInternal(&TextResolution
))
2323 DisplayMessage(L
"An unexpected error occurred!\n");
2324 EmulatorTerminate();
2328 /* Restore the original screen buffer */
2329 VgaSetActiveScreenBuffer(ScreenBufferHandle
);
2330 ScreenBufferHandle
= NULL
;
2332 /* Restore the screen state */
2333 if (ScreenMode
== TEXT_MODE
)
2335 /* The text mode framebuffer was recreated */
2336 ConsoleFramebuffer
= TextFramebuffer
;
2340 /* The graphics mode framebuffer is unchanged */
2341 ConsoleFramebuffer
= OldConsoleFramebuffer
;
2343 OldConsoleFramebuffer
= NULL
;
2348 VOID
VgaDetachFromConsole(VOID
)
2352 VgaDetachFromConsoleInternal();
2354 /* Save the screen state */
2355 if (ScreenMode
== TEXT_MODE
)
2356 ScreenBufferHandle
= TextConsoleBuffer
;
2358 ScreenBufferHandle
= GraphicsConsoleBuffer
;
2360 /* Reset the active framebuffer */
2361 OldConsoleFramebuffer
= ConsoleFramebuffer
;
2362 ConsoleFramebuffer
= NULL
;
2364 /* Restore the old text-mode screen buffer */
2365 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2367 /* Restore the original console size */
2370 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2371 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2373 * See the following trick explanation in VgaAttachToConsoleInternal.
2375 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2376 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2377 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2379 /* Restore the original cursor shape */
2380 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2383 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2385 /* Save the default text-mode console output handle */
2386 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2387 TextConsoleBuffer
= TextHandle
;
2389 /* Save the original cursor and console screen buffer information */
2390 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2391 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2395 ConsoleInfo
= OrgConsoleBufferInfo
;
2397 /* Clear the SEQ, GC, CRTC and AC registers */
2398 RtlZeroMemory(VgaSeqRegisters
, sizeof(VgaSeqRegisters
));
2399 RtlZeroMemory(VgaGcRegisters
, sizeof(VgaGcRegisters
));
2400 RtlZeroMemory(VgaCrtcRegisters
, sizeof(VgaCrtcRegisters
));
2401 RtlZeroMemory(VgaAcRegisters
, sizeof(VgaAcRegisters
));
2403 /* Initialize the VGA palette and fail if it isn't successfully created */
2404 if (!VgaInitializePalette()) return FALSE
;
2405 /***/ VgaResetPalette(); /***/
2407 /* Switch to the text buffer, but do not enter into a text mode */
2408 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2410 /* Reset the sequencer */
2411 VgaResetSequencer();
2413 /* Clear the VGA memory */
2416 /* Register the I/O Ports */
2417 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2418 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2419 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2420 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2421 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2422 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2423 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2424 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2425 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2426 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2427 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2428 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2429 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2431 /* CGA ports for compatibility, unimplemented */
2432 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2433 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2435 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
2436 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
2438 /* Return success */
2442 VOID
VgaCleanup(VOID
)
2444 /* Do a final display refresh */
2445 VgaRefreshDisplay();
2447 DestroyHardwareTimer(VSyncTimer
);
2448 DestroyHardwareTimer(HSyncTimer
);
2450 /* Leave the current video mode */
2451 if (ScreenMode
== GRAPHICS_MODE
)
2452 VgaLeaveGraphicsMode();
2456 VgaDetachFromConsole();
2457 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2459 CloseHandle(AnotherEvent
);
2460 CloseHandle(EndEvent
);
2461 CloseHandle(StartEvent
);