2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
15 #include "../bios/vidbios.h"
19 /* PRIVATE VARIABLES **********************************************************/
21 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
25 * Activate this line if you want to use the real
26 * RegisterConsoleVDM API of ReactOS/Windows.
28 // #define USE_REAL_REGISTERCONSOLEVDM
30 #define USE_REACTOS_COLORS
31 // #define USE_DOSBOX_COLORS
33 #if defined(USE_REACTOS_COLORS)
36 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
38 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
39 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
40 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
41 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
42 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
43 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
44 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
45 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
46 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
47 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
48 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
49 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
50 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
51 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
52 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
53 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
54 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
55 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
56 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
57 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
58 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
59 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
60 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
61 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
62 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
63 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
64 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
65 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
66 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
67 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
68 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
69 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
70 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
71 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
72 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
73 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
74 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
75 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
76 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
77 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
78 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
79 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
80 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
81 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
82 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
83 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
84 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
85 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
86 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
87 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
88 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
89 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
90 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
91 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
92 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
93 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
94 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
95 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
96 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
97 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
98 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
99 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
100 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
104 #elif defined(USE_DOSBOX_COLORS)
107 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
109 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
110 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
111 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
112 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
113 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
114 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
115 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
116 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
117 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
118 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
119 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
120 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
121 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
122 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
123 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
124 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
126 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
127 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
128 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
129 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
130 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
131 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
132 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
133 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
134 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
135 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
136 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
137 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
138 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
139 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
140 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
141 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
143 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
144 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
145 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
146 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
147 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
148 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
149 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
150 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
151 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
152 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
153 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
154 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
155 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
156 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
157 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
158 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
160 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
161 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
162 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
163 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
164 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
165 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
166 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
167 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
168 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
169 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
170 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
171 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
172 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
173 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
174 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
181 * Default 16-color palette for foreground and background
182 * (corresponding flags in comments).
183 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
185 static const COLORREF ConsoleColors
[16] =
187 RGB(0, 0, 0), // (Black)
188 RGB(0, 0, 128), // BLUE
189 RGB(0, 128, 0), // GREEN
190 RGB(0, 128, 128), // BLUE | GREEN
191 RGB(128, 0, 0), // RED
192 RGB(128, 0, 128), // BLUE | RED
193 RGB(128, 128, 0), // GREEN | RED
194 RGB(192, 192, 192), // BLUE | GREEN | RED
196 RGB(128, 128, 128), // (Grey) INTENSITY
197 RGB(0, 0, 255), // BLUE | INTENSITY
198 RGB(0, 255, 0), // GREEN | INTENSITY
199 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
200 RGB(255, 0, 0), // RED | INTENSITY
201 RGB(255, 0, 255), // BLUE | RED | INTENSITY
202 RGB(255, 255, 0), // GREEN | RED | INTENSITY
203 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
207 * Console interface -- VGA-mode-agnostic
209 typedef struct _CHAR_CELL
213 } CHAR_CELL
, *PCHAR_CELL
;
214 C_ASSERT(sizeof(CHAR_CELL
) == 2);
216 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
217 // either TextFramebuffer or a valid
218 // graphics framebuffer.
219 static HPALETTE TextPaletteHandle
= NULL
;
220 static HPALETTE PaletteHandle
= NULL
;
222 static HANDLE StartEvent
= NULL
;
223 static HANDLE EndEvent
= NULL
;
224 static HANDLE AnotherEvent
= NULL
;
226 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
227 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
231 * Text mode -- we always keep a valid text mode framebuffer
232 * even if we are in graphics mode. This is needed in order to
233 * keep a consistent VGA state.
235 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
236 static COORD TextResolution
= {0};
237 static PCHAR_CELL TextFramebuffer
= NULL
;
238 static HANDLE TextConsoleBuffer
= NULL
;
241 static HANDLE GraphicsConsoleBuffer
= NULL
;
242 static HANDLE ConsoleMutex
= NULL
;
243 static BOOLEAN DoubleVision
= FALSE
;
248 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
250 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
252 static BYTE VgaMiscRegister
;
253 static BYTE VgaFeatureRegister
;
255 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
256 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
258 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
259 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
261 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
262 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
264 static BOOLEAN VgaAcLatch
= FALSE
;
265 static BOOLEAN VgaAcPalDisable
= TRUE
;
266 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
267 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
269 // static VGA_REGISTERS VgaRegisters;
271 static BYTE VgaDacMask
= 0xFF;
272 static WORD VgaDacIndex
= 0;
273 static BOOLEAN VgaDacReadWrite
= FALSE
;
274 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
276 static BOOLEAN InVerticalRetrace
= FALSE
;
277 static BOOLEAN InHorizontalRetrace
= FALSE
;
279 static BOOLEAN NeedsUpdate
= FALSE
;
280 static BOOLEAN ModeChanged
= FALSE
;
281 static BOOLEAN CursorMoved
= FALSE
;
282 static BOOLEAN PaletteChanged
= FALSE
;
289 } ScreenMode
= TEXT_MODE
;
291 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
293 /* RegisterConsoleVDM EMULATION ***********************************************/
295 #include <ntddvdeo.h>
297 #ifdef USE_REAL_REGISTERCONSOLEVDM
299 #define __RegisterConsoleVDM RegisterConsoleVDM
300 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
305 * This private buffer, per-console, is used by
306 * RegisterConsoleVDM and InvalidateConsoleDIBits.
308 static COORD VDMBufferSize
= {0};
309 static PCHAR_CELL VDMBuffer
= NULL
;
311 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
312 // for the real RegisterConsoleVDM and
313 // InvalidateConsoleDIBits
317 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
318 IN HANDLE hStartHardwareEvent
,
319 IN HANDLE hEndHardwareEvent
,
320 IN HANDLE hErrorHardwareEvent
,
321 IN DWORD dwUnusedVar
,
322 OUT LPDWORD lpVideoStateLength
,
323 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
324 IN PVOID lpUnusedBuffer
,
325 IN DWORD dwUnusedBufferLength
,
326 IN COORD dwVDMBufferSize
,
327 OUT PVOID
* lpVDMBuffer
)
329 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
330 UNREFERENCED_PARAMETER(dwUnusedVar
);
331 UNREFERENCED_PARAMETER(lpVideoStateLength
);
332 UNREFERENCED_PARAMETER(lpVideoState
);
333 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
334 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
337 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
339 if (lpVDMBuffer
== NULL
) return FALSE
;
341 if (dwRegisterFlags
!= 0)
343 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
344 if (VDMBuffer
!= NULL
) return FALSE
;
346 VDMBufferSize
= dwVDMBufferSize
;
348 /* HACK: Cache -- to be removed in the real implementation */
349 CharBuff
= HeapAlloc(GetProcessHeap(),
351 VDMBufferSize
.X
* VDMBufferSize
.Y
352 * sizeof(CHAR_INFO
));
355 VDMBuffer
= HeapAlloc(GetProcessHeap(),
357 VDMBufferSize
.X
* VDMBufferSize
.Y
358 * sizeof(CHAR_CELL
));
359 *lpVDMBuffer
= VDMBuffer
;
360 return (VDMBuffer
!= NULL
);
364 /* HACK: Cache -- to be removed in the real implementation */
365 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
368 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
371 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
378 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
379 IN PSMALL_RECT lpRect
)
381 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
383 /* HACK: Write the cached data to the console */
385 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
390 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
392 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
394 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
395 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
399 WriteConsoleOutputA(hConsoleOutput
,
406 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
411 /* PRIVATE FUNCTIONS **********************************************************/
413 static inline DWORD
VgaGetAddressSize(VOID
);
414 static VOID
VgaUpdateTextCursor(VOID
);
416 static VOID
VgaUpdateCursorPosition(VOID
)
419 * Update the cursor position in the VGA registers.
421 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
422 ConsoleInfo
.dwCursorPosition
.X
;
424 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
425 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
427 // VidBiosSyncCursorPosition();
428 VgaUpdateTextCursor();
431 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
435 PVIDEO_HARDWARE_STATE_HEADER State
;
437 #ifdef USE_REAL_REGISTERCONSOLEVDM
438 PCHAR_INFO CharBuff
= NULL
;
441 DWORD AddressSize
, ScanlineSize
;
445 COORD Origin
= { 0, 0 };
447 ASSERT(TextFramebuffer
== NULL
);
449 TextResolution
= *Resolution
;
452 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
453 * in the two following APIs:
454 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
455 * SrvVDMConsoleOperation (corresponding Win32 API: )
456 * to check whether the current process is a VDM process, and fails otherwise with the
457 * error 0xC0000022 ().
459 * It is worth it to notice that also basesrv.dll does the same only for the
460 * BaseSrvIsFirstVDM API...
464 __RegisterConsoleVDM(1,
467 AnotherEvent
, // NULL,
469 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
470 (PVOID
*)&State
, // NULL,
474 (PVOID
*)&TextFramebuffer
);
477 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
482 #ifdef USE_REAL_REGISTERCONSOLEVDM
483 CharBuff
= HeapAlloc(GetProcessHeap(),
485 TextResolution
.X
* TextResolution
.Y
486 * sizeof(CHAR_INFO
));
494 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
495 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
496 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
498 * Use this trick to effectively resize the console buffer and window,
500 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
501 * is smaller than the current console window size, and:
502 * - SetConsoleWindowInfo fails if the new console window size is larger
503 * than the current console screen buffer size.
505 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
506 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
507 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
508 /* Update the saved console information */
509 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
512 * Copy console data into VGA memory
516 AddressSize
= VgaGetAddressSize();
517 ConRect
.Left
= ConRect
.Top
= 0;
518 ConRect
.Right
= TextResolution
.X
;
519 ConRect
.Bottom
= TextResolution
.Y
;
520 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
522 /* Read the data from the console into the framebuffer... */
523 ReadConsoleOutputA(TextConsoleBuffer
,
529 /* ... and copy the framebuffer into the VGA memory */
531 /* Loop through the scanlines */
532 for (i
= 0; i
< TextResolution
.Y
; i
++)
534 /* Loop through the characters */
535 for (j
= 0; j
< TextResolution
.X
; j
++)
537 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
539 /* Store the character in plane 0 */
540 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
542 /* Store the attribute in plane 1 */
543 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
546 /* Move to the next scanline */
547 Address
+= ScanlineSize
;
550 #ifdef USE_REAL_REGISTERCONSOLEVDM
551 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
554 VgaUpdateCursorPosition();
559 static BOOL
IsConsoleHandle(HANDLE hHandle
)
563 /* Check whether the handle may be that of a console... */
564 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
568 * It may be. Perform another test... The idea comes from the
569 * MSDN description of the WriteConsole API:
571 * "WriteConsole fails if it is used with a standard handle
572 * that is redirected to a file. If an application processes
573 * multilingual output that can be redirected, determine whether
574 * the output handle is a console handle (one method is to call
575 * the GetConsoleMode function and check whether it succeeds).
576 * If the handle is a console handle, call WriteConsole. If the
577 * handle is not a console handle, the output is redirected and
578 * you should call WriteFile to perform the I/O."
580 return GetConsoleMode(hHandle
, &dwMode
);
583 static inline DWORD
VgaGetAddressSize(VOID
)
585 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
587 /* Double-word addressing */
588 return 4; // sizeof(DWORD)
590 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
592 /* Byte addressing */
593 return 1; // sizeof(BYTE)
597 /* Word addressing */
598 return 2; // sizeof(WORD)
602 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
604 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
607 /* Check for chain-4 and odd-even mode */
608 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
610 /* The lowest two bits are the plane number */
614 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
616 /* The LSB is the plane number */
622 /* Use the read mode */
623 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
626 /* Multiply the offset by the address size */
627 Offset
*= VgaGetAddressSize();
629 return Offset
+ Plane
* VGA_BANK_SIZE
;
632 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
634 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
636 /* Check for chain-4 and odd-even mode */
637 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
639 /* Shift the offset to the right by 2 */
642 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
644 /* Shift the offset to the right by 1 */
648 /* Multiply the offset by the address size */
649 Offset
*= VgaGetAddressSize();
651 /* Return the offset on plane 0 */
655 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
657 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
658 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
662 /* In write mode 1 just return the latch register */
663 return VgaLatchRegisters
[Plane
];
668 /* Write modes 0 and 3 rotate the data to the right first */
669 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
670 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
674 /* Write mode 2 expands the appropriate bit to all 8 bits */
675 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
681 * In write mode 0, the enable set/reset register decides if the
682 * set/reset bit should be expanded to all 8 bits.
684 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
686 /* Copy the bit from the set/reset register to all 8 bits */
687 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
693 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
694 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
696 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
697 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
698 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
702 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
705 /* Then we expand the bit in the set/reset field */
706 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
709 /* Bits cleared in the bitmask are replaced with latch register bits */
710 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
712 /* Return the byte */
716 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
718 /* Check if this is the first time the rectangle is updated */
721 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
722 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
725 /* Expand the rectangle to include the point */
726 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
727 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
728 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
729 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
731 /* Set the update request flag */
735 static VOID
VgaWriteSequencer(BYTE Data
)
737 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
740 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
743 static VOID
VgaWriteGc(BYTE Data
)
745 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
748 VgaGcRegisters
[VgaGcIndex
] = Data
;
750 /* Check the index */
753 case VGA_GC_MISC_REG
:
755 /* The GC misc register decides if it's text or graphics mode */
762 static VOID
VgaWriteCrtc(BYTE Data
)
764 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
767 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
769 /* Check the index */
770 switch (VgaCrtcIndex
)
772 case VGA_CRTC_END_HORZ_DISP_REG
:
773 case VGA_CRTC_VERT_DISP_END_REG
:
774 case VGA_CRTC_OVERFLOW_REG
:
776 /* The video mode has changed */
781 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
782 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
783 case VGA_CRTC_CURSOR_START_REG
:
784 case VGA_CRTC_CURSOR_END_REG
:
786 /* Set the cursor moved flag */
793 static VOID
VgaWriteDac(BYTE Data
)
799 VgaDacRegisters
[VgaDacIndex
] = Data
;
801 /* Find the palette index */
802 PaletteIndex
= VgaDacIndex
/ 3;
804 /* Fill the entry structure */
805 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
806 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
807 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
810 /* Update the palette entry */
811 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
813 /* Check which text palette entries are affected */
814 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
816 if (VgaAcRegisters
[i
] == PaletteIndex
)
818 /* Update the text palette entry */
819 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
823 /* Set the palette changed flag */
824 PaletteChanged
= TRUE
;
826 /* Update the index */
828 VgaDacIndex
%= VGA_PALETTE_SIZE
;
831 static VOID
VgaWriteAc(BYTE Data
)
835 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
838 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
840 if (VgaAcPalDisable
) return;
842 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
843 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
845 /* Update the AC register */
846 VgaAcRegisters
[VgaAcIndex
] = Data
;
848 /* Fill the entry structure */
849 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
850 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
851 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
854 /* Update the palette entry and set the palette change flag */
855 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
856 PaletteChanged
= TRUE
;
861 VgaAcRegisters
[VgaAcIndex
] = Data
;
865 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
869 /* Copy the colors of the default palette to the DAC and console palette */
870 for (i
= 0; i
< NumOfEntries
; i
++)
872 /* Set the palette entries */
873 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
874 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
875 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
876 Entries
[i
].peFlags
= 0;
878 /* Set the DAC registers */
879 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
880 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
881 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
885 static BOOLEAN
VgaInitializePalette(VOID
)
888 BOOLEAN Result
= FALSE
;
889 LPLOGPALETTE Palette
, TextPalette
;
891 /* Allocate storage space for the palettes */
892 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
895 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
896 TextPalette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
899 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
900 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
902 /* Initialize the palettes */
903 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
904 Palette
->palNumEntries
= VGA_MAX_COLORS
;
905 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
907 /* Restore the default graphics palette */
908 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
910 /* Set the default text palette */
911 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
913 /* Set the palette entries */
914 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
915 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
916 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
917 TextPalette
->palPalEntry
[i
].peFlags
= 0;
920 /* Create the palettes */
921 PaletteHandle
= CreatePalette(Palette
);
922 TextPaletteHandle
= CreatePalette(TextPalette
);
924 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
926 /* The palettes have been created successfully */
931 /* Free the palettes */
932 if (Palette
) HeapFree(GetProcessHeap(), 0, Palette
);
933 if (TextPalette
) HeapFree(GetProcessHeap(), 0, TextPalette
);
937 /* Something failed, delete the palettes */
938 if (PaletteHandle
) DeleteObject(PaletteHandle
);
939 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
945 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
947 /* Set the active buffer */
948 SetConsoleActiveScreenBuffer(ScreenBuffer
);
950 /* Reinitialize the VDM menu */
952 CreateVdmMenu(ScreenBuffer
);
955 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
958 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
959 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
960 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
961 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
963 LONG Width
= Resolution
->X
;
964 LONG Height
= Resolution
->Y
;
966 /* Use DoubleVision mode if the resolution is too small */
967 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
975 DoubleVision
= FALSE
;
978 /* Fill the bitmap info header */
979 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
980 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
981 BitmapInfo
->bmiHeader
.biWidth
= Width
;
982 BitmapInfo
->bmiHeader
.biHeight
= Height
;
983 BitmapInfo
->bmiHeader
.biBitCount
= 8;
984 BitmapInfo
->bmiHeader
.biPlanes
= 1;
985 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
986 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
988 /* Fill the palette data */
989 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
991 /* Fill the console graphics buffer info */
992 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
993 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
994 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
996 /* Create the buffer */
997 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
998 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1000 CONSOLE_GRAPHICS_BUFFER
,
1001 &GraphicsBufferInfo
);
1002 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
1004 /* Save the framebuffer address and mutex */
1005 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
1006 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
1008 /* Clear the framebuffer */
1009 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
1011 /* Set the active buffer */
1012 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
1014 /* Set the graphics mode palette */
1015 SetConsolePalette(GraphicsConsoleBuffer
,
1017 SYSPAL_NOSTATIC256
);
1019 /* Set the screen mode flag */
1020 ScreenMode
= GRAPHICS_MODE
;
1025 static VOID
VgaLeaveGraphicsMode(VOID
)
1027 /* Release the console framebuffer mutex */
1028 ReleaseMutex(ConsoleMutex
);
1030 /* Switch back to the default console text buffer */
1031 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1033 /* Cleanup the video data */
1034 CloseHandle(ConsoleMutex
);
1035 ConsoleMutex
= NULL
;
1036 ConsoleFramebuffer
= NULL
;
1037 CloseHandle(GraphicsConsoleBuffer
);
1038 GraphicsConsoleBuffer
= NULL
;
1039 DoubleVision
= FALSE
;
1042 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1044 DPRINT1("VgaEnterTextMode\n");
1046 /* Switch to the text buffer */
1047 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
1049 /* Adjust the text framebuffer if we changed the resolution */
1050 if (TextResolution
.X
!= Resolution
->X
||
1051 TextResolution
.Y
!= Resolution
->Y
)
1053 VgaDetachFromConsole(TRUE
);
1056 * VgaAttachToConsoleInternal sets TextResolution to the
1057 * new resolution and updates ConsoleInfo.
1059 if (!VgaAttachToConsoleInternal(Resolution
))
1061 DisplayMessage(L
"An unexpected error occurred!\n");
1062 EmulatorTerminate();
1068 VgaUpdateCursorPosition();
1071 /* The active framebuffer is now the text framebuffer */
1072 ConsoleFramebuffer
= TextFramebuffer
;
1075 * Set the text mode palette.
1077 * WARNING: This call should fail on Windows (and therefore
1078 * we get the default palette and our external behaviour is
1079 * just like Windows' one), but it should success on ReactOS
1080 * (so that we get console palette changes even for text-mode
1081 * screen-buffers, which is a new feature on ReactOS).
1083 SetConsolePalette(TextConsoleBuffer
,
1085 SYSPAL_NOSTATIC256
);
1087 /* Set the screen mode flag */
1088 ScreenMode
= TEXT_MODE
;
1093 static VOID
VgaLeaveTextMode(VOID
)
1095 /* Reset the active framebuffer */
1096 ConsoleFramebuffer
= NULL
;
1099 static VOID
VgaChangeMode(VOID
)
1101 COORD Resolution
= VgaGetDisplayResolution();
1103 if (ScreenMode
== GRAPHICS_MODE
)
1105 /* Leave the current graphics mode */
1106 VgaLeaveGraphicsMode();
1110 /* Leave the current text mode */
1114 /* Check if the new mode is alphanumeric */
1115 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
1117 /* Enter new text mode */
1118 if (!VgaEnterTextMode(&Resolution
))
1120 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1121 EmulatorTerminate();
1127 /* Enter graphics mode */
1128 if (!VgaEnterGraphicsMode(&Resolution
))
1130 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1131 EmulatorTerminate();
1136 /* Trigger a full update of the screen */
1138 UpdateRectangle
.Left
= 0;
1139 UpdateRectangle
.Top
= 0;
1140 UpdateRectangle
.Right
= Resolution
.X
;
1141 UpdateRectangle
.Bottom
= Resolution
.Y
;
1143 /* Reset the mode change flag */
1144 ModeChanged
= FALSE
;
1147 static VOID
VgaUpdateFramebuffer(VOID
)
1150 COORD Resolution
= VgaGetDisplayResolution();
1151 DWORD AddressSize
= VgaGetAddressSize();
1152 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1153 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1154 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1157 * If console framebuffer is NULL, that means something went wrong
1158 * earlier and this is the final display refresh.
1160 if (ConsoleFramebuffer
== NULL
) return;
1162 /* Check if this is text mode or graphics mode */
1163 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1166 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1167 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1170 * Synchronize access to the graphics framebuffer
1171 * with the console framebuffer mutex.
1173 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1175 /* Shift the high bit right by 1 in odd/even mode */
1176 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1178 InterlaceHighBit
>>= 1;
1181 /* Loop through the scanlines */
1182 for (i
= 0; i
< Resolution
.Y
; i
++)
1184 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1186 /* Odd-numbered line in interlaced mode - set the high bit */
1187 Address
|= InterlaceHighBit
;
1190 /* Loop through the pixels */
1191 for (j
= 0; j
< Resolution
.X
; j
++)
1195 /* Check the shifting mode */
1196 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1198 /* 4 bits shifted from each plane */
1200 /* Check if this is 16 or 256 color mode */
1201 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1203 /* One byte per pixel */
1204 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1205 + (Address
+ (j
/ VGA_NUM_BANKS
))
1210 /* 4-bits per pixel */
1212 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1213 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1216 /* Check if we should use the highest 4 bits or lowest 4 */
1217 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1229 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1231 /* Check if this is 16 or 256 color mode */
1232 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1234 // TODO: NOT IMPLEMENTED
1235 DPRINT1("8-bit interleaved mode is not implemented!\n");
1240 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1241 * then 2 bits shifted from plane 1 and 3 for the next 4
1243 DWORD BankNumber
= (j
/ 4) % 2;
1244 DWORD Offset
= Address
+ (j
/ 8);
1245 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ Offset
* AddressSize
];
1246 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ Offset
* AddressSize
];
1248 /* Extract the two bits from each plane */
1249 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1250 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1252 /* Combine them into the pixel */
1253 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1258 /* 1 bit shifted from each plane */
1260 /* Check if this is 16 or 256 color mode */
1261 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1263 /* 8 bits per pixel, 2 on each plane */
1265 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1267 /* The data is on plane k, 4 pixels per byte */
1268 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1269 + (Address
+ (j
/ VGA_NUM_BANKS
))
1272 /* The mask of the first bit in the pair */
1273 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1275 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1276 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1278 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1279 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1284 /* 4 bits per pixel, 1 on each plane */
1286 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1288 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1289 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1292 /* If the bit on that plane is set, set it */
1293 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1298 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1301 * In 16 color mode, the value is an index to the AC registers
1302 * if external palette access is disabled, otherwise (in case
1303 * of palette loading) it is a blank pixel.
1305 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1309 /* Take into account DoubleVision mode when checking for pixel updates */
1312 /* Now check if the resulting pixel data has changed */
1313 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
1315 /* Yes, write the new value */
1316 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
1317 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
1318 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
1319 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1321 /* Mark the specified pixel as changed */
1322 VgaMarkForUpdate(i
, j
);
1327 /* Now check if the resulting pixel data has changed */
1328 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
1330 /* Yes, write the new value */
1331 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
1333 /* Mark the specified pixel as changed */
1334 VgaMarkForUpdate(i
, j
);
1339 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1341 /* Clear the high bit */
1342 Address
&= ~InterlaceHighBit
;
1345 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1347 /* Move to the next scanline */
1348 Address
+= ScanlineSize
;
1353 * Release the console framebuffer mutex
1354 * so that we allow for repainting.
1356 ReleaseMutex(ConsoleMutex
);
1362 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1365 /* Loop through the scanlines */
1366 for (i
= 0; i
< Resolution
.Y
; i
++)
1368 /* Loop through the characters */
1369 for (j
= 0; j
< Resolution
.X
; j
++)
1371 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1373 /* Plane 0 holds the character itself */
1374 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1376 /* Plane 1 holds the attribute */
1377 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1379 /* Now check if the resulting character data has changed */
1380 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1381 (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1383 /* Yes, write the new value */
1384 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
1386 /* Mark the specified cell as changed */
1387 VgaMarkForUpdate(i
, j
);
1391 /* Move to the next scanline */
1392 Address
+= ScanlineSize
;
1397 static VOID
VgaUpdateTextCursor(VOID
)
1400 CONSOLE_CURSOR_INFO CursorInfo
;
1401 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
1402 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1403 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1404 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1405 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1406 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1408 /* Just return if we are not in text mode */
1409 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
1411 if (CursorStart
< CursorEnd
)
1413 /* Visible cursor */
1414 CursorInfo
.bVisible
= TRUE
;
1415 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1420 CursorInfo
.bVisible
= FALSE
;
1421 CursorInfo
.dwSize
= 0;
1424 /* Add the cursor skew to the location */
1425 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
1427 /* Find the coordinates of the new position */
1428 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1429 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1431 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1433 /* Update the physical cursor */
1434 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1435 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1437 /* Reset the cursor move flag */
1438 CursorMoved
= FALSE
;
1441 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1443 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1448 return VgaMiscRegister
;
1450 case VGA_INSTAT0_READ
:
1451 return 0; // Not implemented
1453 case VGA_INSTAT1_READ_MONO
:
1454 case VGA_INSTAT1_READ_COLOR
:
1458 /* Reset the AC latch */
1461 /* Set a flag if there is a vertical or horizontal retrace */
1462 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1464 /* Set an additional flag if there was a vertical retrace */
1465 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1467 /* Clear the flags */
1468 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1473 case VGA_FEATURE_READ
:
1474 return VgaFeatureRegister
;
1480 return VgaAcRegisters
[VgaAcIndex
];
1486 return VgaSeqRegisters
[VgaSeqIndex
];
1491 case VGA_DAC_READ_INDEX
:
1492 /* This returns the read/write state */
1493 return (VgaDacReadWrite
? 0 : 3);
1495 case VGA_DAC_WRITE_INDEX
:
1496 return (VgaDacIndex
/ 3);
1500 /* Ignore reads in write mode */
1501 if (!VgaDacReadWrite
)
1503 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1504 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1511 case VGA_CRTC_INDEX_MONO
:
1512 case VGA_CRTC_INDEX_COLOR
:
1513 return VgaCrtcIndex
;
1515 case VGA_CRTC_DATA_MONO
:
1516 case VGA_CRTC_DATA_COLOR
:
1517 return VgaCrtcRegisters
[VgaCrtcIndex
];
1523 return VgaGcRegisters
[VgaGcIndex
];
1526 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1533 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1535 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1539 case VGA_MISC_WRITE
:
1541 VgaMiscRegister
= Data
;
1543 if (VgaMiscRegister
& 0x01)
1545 /* Color emulation */
1546 DPRINT1("Color emulation\n");
1548 /* Register the new I/O Ports */
1549 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1550 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1551 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1553 /* Unregister the old ones */
1554 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1555 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1556 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1560 /* Monochrome emulation */
1561 DPRINT1("Monochrome emulation\n");
1563 /* Register the new I/O Ports */
1564 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1565 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1566 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1568 /* Unregister the old ones */
1569 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1570 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1571 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1574 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1578 case VGA_FEATURE_WRITE_MONO
:
1579 case VGA_FEATURE_WRITE_COLOR
:
1581 VgaFeatureRegister
= Data
;
1586 // case VGA_AC_WRITE:
1590 /* Change the index */
1591 BYTE Index
= Data
& 0x1F;
1592 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1595 * Change palette protection by checking for
1596 * the Palette Address Source bit.
1598 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1602 /* Write the data */
1606 /* Toggle the latch */
1607 VgaAcLatch
= !VgaAcLatch
;
1613 /* Set the sequencer index register */
1614 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1620 /* Call the sequencer function */
1621 VgaWriteSequencer(Data
);
1631 case VGA_DAC_READ_INDEX
:
1633 VgaDacReadWrite
= FALSE
;
1634 VgaDacIndex
= Data
* 3;
1638 case VGA_DAC_WRITE_INDEX
:
1640 VgaDacReadWrite
= TRUE
;
1641 VgaDacIndex
= Data
* 3;
1647 /* Ignore writes in read mode */
1648 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1652 case VGA_CRTC_INDEX_MONO
:
1653 case VGA_CRTC_INDEX_COLOR
:
1655 /* Set the CRTC index register */
1656 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1660 case VGA_CRTC_DATA_MONO
:
1661 case VGA_CRTC_DATA_COLOR
:
1663 /* Call the CRTC function */
1670 /* Set the GC index register */
1671 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1677 /* Call the GC function */
1683 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1688 /* PUBLIC FUNCTIONS ***********************************************************/
1690 DWORD
VgaGetVideoBaseAddress(VOID
)
1692 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1695 DWORD
VgaGetVideoLimitAddress(VOID
)
1697 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1700 COORD
VgaGetDisplayResolution(VOID
)
1703 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1705 /* The low 8 bits are in the display registers */
1706 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1707 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1709 /* Set the top bits from the overflow register */
1710 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1712 Resolution
.Y
|= 1 << 8;
1714 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1716 Resolution
.Y
|= 1 << 9;
1719 /* Increase the values by 1 */
1723 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1725 /* Multiply the horizontal resolution by the 9/8 dot mode */
1726 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1729 /* The horizontal resolution is halved in 8-bit mode */
1730 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1733 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1735 /* Halve the vertical resolution */
1740 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1741 Resolution
.Y
/= MaximumScanLine
;
1744 /* Return the resolution */
1748 VOID
VgaRefreshDisplay(VOID
)
1750 HANDLE ConsoleBufferHandle
= NULL
;
1753 /* Set the vertical retrace flag */
1754 InVerticalRetrace
= TRUE
;
1756 /* If nothing has changed, just return */
1757 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1760 /* Change the display mode */
1761 if (ModeChanged
) VgaChangeMode();
1763 /* Change the text cursor location */
1764 if (CursorMoved
) VgaUpdateTextCursor();
1766 /* Retrieve the current resolution */
1767 Resolution
= VgaGetDisplayResolution();
1771 /* Trigger a full update of the screen */
1773 UpdateRectangle
.Left
= 0;
1774 UpdateRectangle
.Top
= 0;
1775 UpdateRectangle
.Right
= Resolution
.X
;
1776 UpdateRectangle
.Bottom
= Resolution
.Y
;
1778 PaletteChanged
= FALSE
;
1781 /* Update the contents of the framebuffer */
1782 VgaUpdateFramebuffer();
1784 /* Ignore if there's nothing to update */
1785 if (!NeedsUpdate
) return;
1787 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1788 UpdateRectangle
.Left
,
1789 UpdateRectangle
.Top
,
1790 UpdateRectangle
.Right
,
1791 UpdateRectangle
.Bottom
);
1793 /* Check if this is text mode or graphics mode */
1794 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1797 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1799 /* In DoubleVision mode, scale the update rectangle */
1802 UpdateRectangle
.Left
*= 2;
1803 UpdateRectangle
.Top
*= 2;
1804 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1805 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1811 ConsoleBufferHandle
= TextConsoleBuffer
;
1814 /* Redraw the screen */
1815 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1817 /* Clear the update flag */
1818 NeedsUpdate
= FALSE
;
1821 VOID
VgaHorizontalRetrace(VOID
)
1824 InHorizontalRetrace
= TRUE
;
1827 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1832 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1834 /* Ignore if video RAM access is disabled */
1835 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1837 /* Loop through each byte */
1838 for (i
= 0; i
< Size
; i
++)
1840 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1842 /* Load the latch registers */
1843 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1844 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1845 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1846 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1848 /* Copy the value to the buffer */
1849 Buffer
[i
] = VgaMemory
[VideoAddress
];
1853 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1858 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1860 /* Ignore if video RAM access is disabled */
1861 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1863 /* Also ignore if write access to all planes is disabled */
1864 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1866 /* Loop through each byte */
1867 for (i
= 0; i
< Size
; i
++)
1869 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1871 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1873 /* Make sure the page is writeable */
1874 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1876 /* Check if this is chain-4 mode */
1877 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1879 if (((Address
+ i
) & 3) != j
)
1881 /* This plane will not be accessed */
1886 /* Check if this is odd-even mode */
1887 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1889 if (((Address
+ i
) & 1) != (j
& 1))
1891 /* This plane will not be accessed */
1896 /* Copy the value to the VGA memory */
1897 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1902 VOID
VgaClearMemory(VOID
)
1904 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1907 VOID
VgaResetPalette(VOID
)
1909 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1911 /* Restore the default palette */
1912 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1913 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1914 PaletteChanged
= TRUE
;
1917 VOID
VgaWriteFont(UINT FontNumber
, CONST UCHAR
*FontData
, UINT Height
)
1920 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1922 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
1924 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
1926 /* Write the character */
1927 for (j
= 0; j
< Height
; j
++)
1929 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
1932 /* Clear the unused part */
1933 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
1935 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
1940 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
1942 DPRINT1("Screen events not handled\n");
1945 BOOL
VgaAttachToConsole(VOID
)
1948 // FIXME: We should go back to the saved screen state
1950 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
1951 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1953 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
1954 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
1956 return VgaAttachToConsoleInternal(&TextResolution
);
1959 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
1963 COORD dummySize
= {0};
1966 // FIXME: We should save the screen state
1969 __RegisterConsoleVDM(0,
1981 TextFramebuffer
= NULL
;
1987 /* Restore the old screen buffer */
1988 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
1990 /* Restore the original console size */
1993 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
1994 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
1996 * See the following trick explanation in VgaAttachToConsoleInternal.
1998 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1999 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2000 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2002 /* Restore the original cursor shape */
2003 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2007 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2009 /* Save the default text-mode console output handle */
2010 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2011 TextConsoleBuffer
= TextHandle
;
2013 /* Save the original cursor and console screen buffer information */
2014 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2015 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2019 ConsoleInfo
= OrgConsoleBufferInfo
;
2021 /* Initialize the VGA palette and fail if it isn't successfully created */
2022 if (!VgaInitializePalette()) return FALSE
;
2023 /***/ VgaResetPalette(); /***/
2025 /* Switch to the text buffer */
2026 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2028 /* Clear the VGA memory */
2031 /* Register the I/O Ports */
2032 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2033 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2034 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2035 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2036 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2037 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2038 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2039 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2040 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2041 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2042 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2043 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2044 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2046 /* Return success */
2050 VOID
VgaCleanup(VOID
)
2052 if (ScreenMode
== GRAPHICS_MODE
)
2054 /* Leave the current graphics mode */
2055 VgaLeaveGraphicsMode();
2059 /* Leave the current text mode */
2063 VgaDetachFromConsole(FALSE
);
2065 CloseHandle(AnotherEvent
);
2066 CloseHandle(EndEvent
);
2067 CloseHandle(StartEvent
);