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 *******************************************************************/
18 /* PRIVATE VARIABLES **********************************************************/
20 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
21 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
23 #define USE_REACTOS_COLORS
24 // #define USE_DOSBOX_COLORS
26 #if defined(USE_REACTOS_COLORS)
29 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
31 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
32 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
33 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
34 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
35 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
36 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
37 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
38 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
39 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
40 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
41 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
42 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
43 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
44 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
45 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
46 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
47 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
48 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
49 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
50 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
51 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
52 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
53 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
54 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
55 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
56 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
57 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
58 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
59 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
60 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
61 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
62 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
63 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
64 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
65 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
66 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
67 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
68 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
69 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
70 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
71 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
72 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
73 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
74 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
75 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
76 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
77 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
78 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
79 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
80 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
81 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
82 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
83 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
84 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
85 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
86 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
87 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
88 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
89 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
90 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
91 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
92 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
93 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
94 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
97 #elif defined(USE_DOSBOX_COLORS)
100 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
102 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
103 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
104 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
105 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
106 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
107 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
108 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
109 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
110 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
111 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
112 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
113 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
114 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
115 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
116 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
117 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
119 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
120 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
121 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
122 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
123 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
124 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
125 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
126 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
127 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
128 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
129 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
130 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
131 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
132 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
133 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
134 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
136 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
137 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
138 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
139 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
140 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
141 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
142 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
143 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
144 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
145 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
146 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
147 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
148 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
149 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
150 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
151 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
153 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
154 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
155 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
156 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
157 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
158 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
159 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
160 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
161 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
162 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
163 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
164 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
165 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
166 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
167 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
168 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
174 * Console interface -- VGA-mode-agnostic
176 typedef struct _CHAR_CELL
180 } CHAR_CELL
, *PCHAR_CELL
;
181 C_ASSERT(sizeof(CHAR_CELL
) == 2);
183 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
184 // either TextFramebuffer or a valid
185 // graphics framebuffer.
186 static HPALETTE PaletteHandle
= NULL
;
188 static HANDLE StartEvent
= NULL
;
189 static HANDLE EndEvent
= NULL
;
190 static HANDLE AnotherEvent
= NULL
;
193 * Text mode -- we always keep a valid text mode framebuffer
194 * even if we are in graphics mode. This is needed in order to
195 * keep a consistent VGA state.
197 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
198 static COORD TextResolution
= {0};
199 static PCHAR_CELL TextFramebuffer
= NULL
;
200 static HANDLE TextConsoleBuffer
= NULL
;
203 static HANDLE GraphicsConsoleBuffer
= NULL
;
204 static HANDLE ConsoleMutex
= NULL
;
205 static BOOLEAN DoubleVision
= FALSE
;
210 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
212 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
214 static BYTE VgaMiscRegister
;
215 static BYTE VgaFeatureRegister
;
217 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
218 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
220 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
221 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
223 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
224 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
226 static BOOLEAN VgaAcLatch
= FALSE
;
227 static BOOLEAN VgaAcPalDisable
= TRUE
;
228 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
229 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
231 // static VGA_REGISTERS VgaRegisters;
233 static BYTE VgaDacMask
= 0xFF;
234 static WORD VgaDacIndex
= 0;
235 static BOOLEAN VgaDacReadWrite
= FALSE
;
236 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
238 static BOOLEAN InVerticalRetrace
= FALSE
;
239 static BOOLEAN InHorizontalRetrace
= FALSE
;
241 static BOOLEAN NeedsUpdate
= FALSE
;
242 static BOOLEAN ModeChanged
= FALSE
;
243 static BOOLEAN CursorMoved
= FALSE
;
244 static BOOLEAN PaletteChanged
= FALSE
;
251 } ScreenMode
= TEXT_MODE
;
253 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
255 /* RegisterConsoleVDM EMULATION ***********************************************/
257 #include <ntddvdeo.h>
261 (WINAPI
*pRegisterConsoleVDM
)
264 HANDLE EventHandle_1
,
265 HANDLE EventHandle_2
,
266 HANDLE EventHandle_3
,
268 PVOID returned_val_1
,
269 PVOID
*returned_val_2
,
270 PVOID lpUnknownBuffer
,
271 DWORD theUnknownBufferLength
,
272 COORD theVDMBufferSize
,
282 HANDLE EventHandle_1
,
283 HANDLE EventHandle_2
,
284 HANDLE EventHandle_3
,
286 PVOID returned_val_1
,
287 PVOID
*returned_val_2
,
288 PVOID lpUnknownBuffer
,
289 DWORD theUnknownBufferLength
,
290 COORD theVDMBufferSize
,
294 HMODULE hKernel32
= NULL
;
295 pRegisterConsoleVDM RegisterConsoleVDM
= NULL
;
299 * This private buffer, per-console, is used by
300 * RegisterConsoleVDM and InvalidateConsoleDIBits.
302 static COORD VDMBufferSize
= {0};
303 static PCHAR_CELL VDMBuffer
= NULL
;
305 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
306 // for the real RegisterConsoleVDM and
307 // InvalidateConsoleDIBits
311 __RegisterConsoleVDM(BOOL IsDosVDM_flag
,
312 HANDLE EventHandle_1
,
313 HANDLE EventHandle_2
,
314 HANDLE EventHandle_3
,
316 PVOID returned_val_1
,
317 PVOID
*returned_val_2
,
318 PVOID lpUnknownBuffer
,
319 DWORD theUnknownBufferLength
,
320 COORD theVDMBufferSize
,
323 UNREFERENCED_PARAMETER(EventHandle_3
);
324 UNREFERENCED_PARAMETER(Unused1
);
325 UNREFERENCED_PARAMETER(returned_val_1
);
326 UNREFERENCED_PARAMETER(returned_val_2
);
327 UNREFERENCED_PARAMETER(lpUnknownBuffer
);
328 UNREFERENCED_PARAMETER(theUnknownBufferLength
);
331 DPRINT1("__RegisterConsoleVDM(%d)\n", IsDosVDM_flag
);
333 if (lpVDMBuffer
== NULL
) return FALSE
;
337 // if (EventHandle_1 == NULL || EventHandle_2 == NULL) return FALSE;
338 if (VDMBuffer
!= NULL
) return FALSE
;
340 VDMBufferSize
= theVDMBufferSize
;
342 /* HACK: Cache -- to be removed in the real implementation */
343 CharBuff
= HeapAlloc(GetProcessHeap(),
345 theVDMBufferSize
.X
* theVDMBufferSize
.Y
346 * sizeof(CHAR_INFO
));
349 VDMBuffer
= HeapAlloc(GetProcessHeap(),
351 theVDMBufferSize
.X
* theVDMBufferSize
.Y
352 * sizeof(CHAR_CELL
));
353 *lpVDMBuffer
= (PCHAR
)VDMBuffer
;
354 return (VDMBuffer
!= NULL
);
358 /* HACK: Cache -- to be removed in the real implementation */
359 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
362 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
365 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
372 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
373 IN PSMALL_RECT lpRect
)
375 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
377 /* HACK: Write the cached data to the console */
379 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
384 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
386 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
388 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
389 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
393 WriteConsoleOutputA(hConsoleOutput
,
400 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
403 /* PRIVATE FUNCTIONS **********************************************************/
405 static inline DWORD
VgaGetAddressSize(VOID
);
407 static BOOL
VgaAttachToConsole(PCOORD Resolution
)
411 PVIDEO_HARDWARE_STATE_HEADER State
;
414 DWORD AddressSize
, ScanlineSize
;
417 SMALL_RECT ScreenRect
; // ConRect;
418 COORD Origin
= { 0, 0 };
420 ASSERT(TextFramebuffer
== NULL
);
422 // ResetEvent(AnotherEvent);
424 TextResolution
= *Resolution
;
427 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
428 * in the two following APIs:
429 * SrvRegisterConsoleVDM (corresponding win32 API: RegisterConsoleVDM)
430 * SrvVDMConsoleOperation (corresponding Win32 API: )
431 * to check whether the current process is a VDM process, and fails otherwise with the
432 * error 0xC0000022 ().
434 * It is worth it to notice that also basesrv.dll does the same only for the
435 * BaseSrvIsFirstVDM API...
439 __RegisterConsoleVDM(1,
442 AnotherEvent
, // NULL,
444 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
445 (PVOID
*)&State
, // NULL,
449 (PCHAR
*)&TextFramebuffer
);
452 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
457 /* Copy console data into VGA memory */
460 AddressSize
= VgaGetAddressSize();
461 ScreenRect
.Left
= ScreenRect
.Top
= 0;
462 ScreenRect
.Right
= TextResolution
.X
;
463 ScreenRect
.Bottom
= TextResolution
.Y
;
466 // ConRect.Top = ConsoleSize->Y - BufferSize.Y;
467 // ConRect.Right = ConRect.Left + BufferSize.X - 1;
468 // ConRect.Bottom = ConRect.Top + BufferSize.Y - 1;
470 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
472 /* Read the data from the console into the framebuffer... */
473 ReadConsoleOutputA(TextConsoleBuffer
,
477 &ScreenRect
); // &ConRect);
479 /* ... and copy the framebuffer into the VGA memory */
481 /* Loop through the scanlines */
482 for (i
= 0; i
< TextResolution
.Y
; i
++)
484 /* Loop through the characters */
485 for (j
= 0; j
< TextResolution
.X
; j
++)
487 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
489 /* Store the character in plane 0 */
490 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
492 /* Store the attribute in plane 1 */
493 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
496 /* Move to the next scanline */
497 Address
+= ScanlineSize
;
503 static VOID
VgaDetachFromConsole(VOID
)
507 COORD dummySize
= {0};
509 __RegisterConsoleVDM(0,
521 TextFramebuffer
= NULL
;
524 static BOOL
IsConsoleHandle(HANDLE hHandle
)
528 /* Check whether the handle may be that of a console... */
529 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
533 * It may be. Perform another test... The idea comes from the
534 * MSDN description of the WriteConsole API:
536 * "WriteConsole fails if it is used with a standard handle
537 * that is redirected to a file. If an application processes
538 * multilingual output that can be redirected, determine whether
539 * the output handle is a console handle (one method is to call
540 * the GetConsoleMode function and check whether it succeeds).
541 * If the handle is a console handle, call WriteConsole. If the
542 * handle is not a console handle, the output is redirected and
543 * you should call WriteFile to perform the I/O."
545 return GetConsoleMode(hHandle
, &dwMode
);
548 static inline DWORD
VgaGetAddressSize(VOID
)
550 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
552 /* Double-word addressing */
553 return 4; // sizeof(DWORD)
555 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
557 /* Byte addressing */
558 return 1; // sizeof(BYTE)
562 /* Word addressing */
563 return 2; // sizeof(WORD)
567 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
569 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
572 /* Check for chain-4 and odd-even mode */
573 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
575 /* The lowest two bits are the plane number */
579 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
581 /* The LSB is the plane number */
587 /* Use the read mode */
588 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
591 /* Multiply the offset by the address size */
592 Offset
*= VgaGetAddressSize();
594 return Offset
+ Plane
* VGA_BANK_SIZE
;
597 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
599 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
601 /* Check for chain-4 and odd-even mode */
602 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
604 /* Shift the offset to the right by 2 */
607 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
609 /* Shift the offset to the right by 1 */
613 /* Multiply the offset by the address size */
614 Offset
*= VgaGetAddressSize();
616 /* Return the offset on plane 0 */
620 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
622 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
623 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
627 /* In write mode 1 just return the latch register */
628 return VgaLatchRegisters
[Plane
];
633 /* Write modes 0 and 3 rotate the data to the right first */
634 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
635 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
639 /* Write mode 2 expands the appropriate bit to all 8 bits */
640 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
646 * In write mode 0, the enable set/reset register decides if the
647 * set/reset bit should be expanded to all 8 bits.
649 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
651 /* Copy the bit from the set/reset register to all 8 bits */
652 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
658 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
659 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
661 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
662 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
663 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
667 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
670 /* Then we expand the bit in the set/reset field */
671 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
674 /* Bits cleared in the bitmask are replaced with latch register bits */
675 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
677 /* Return the byte */
681 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
683 /* Check if this is the first time the rectangle is updated */
686 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
687 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
690 /* Expand the rectangle to include the point */
691 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
692 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
693 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
694 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
696 /* Set the update request flag */
700 static VOID
VgaWriteSequencer(BYTE Data
)
702 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
705 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
708 static VOID
VgaWriteGc(BYTE Data
)
710 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
713 VgaGcRegisters
[VgaGcIndex
] = Data
;
715 /* Check the index */
718 case VGA_GC_MISC_REG
:
720 /* The GC misc register decides if it's text or graphics mode */
727 static VOID
VgaWriteCrtc(BYTE Data
)
729 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
732 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
734 /* Check the index */
735 switch (VgaCrtcIndex
)
737 case VGA_CRTC_END_HORZ_DISP_REG
:
738 case VGA_CRTC_VERT_DISP_END_REG
:
739 case VGA_CRTC_OVERFLOW_REG
:
741 /* The video mode has changed */
746 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
747 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
748 case VGA_CRTC_CURSOR_START_REG
:
749 case VGA_CRTC_CURSOR_END_REG
:
751 /* Set the cursor moved flag */
758 static VOID
VgaWriteDac(BYTE Data
)
764 VgaDacRegisters
[VgaDacIndex
] = Data
;
766 /* Find the palette index */
767 PaletteIndex
= VgaDacIndex
/ 3;
769 /* Fill the entry structure */
770 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
771 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
772 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
775 /* Update the palette entry and set the palette change flag */
776 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
777 PaletteChanged
= TRUE
;
779 /* Update the index */
781 VgaDacIndex
%= VGA_PALETTE_SIZE
;
784 static VOID
VgaWriteAc(BYTE Data
)
786 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
789 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
791 if (VgaAcPalDisable
) return;
793 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
794 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
796 /* Update the AC register and set the palette change flag */
797 VgaAcRegisters
[VgaAcIndex
] = Data
;
798 PaletteChanged
= TRUE
;
803 VgaAcRegisters
[VgaAcIndex
] = Data
;
807 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
811 /* Copy the colors of the default palette to the DAC and console palette */
812 for (i
= 0; i
< NumOfEntries
; i
++)
814 /* Set the palette entries */
815 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
816 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
817 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
818 Entries
[i
].peFlags
= 0;
820 /* Set the DAC registers */
821 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
822 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
823 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
827 static BOOLEAN
VgaInitializePalette(VOID
)
829 LPLOGPALETTE Palette
;
831 /* Allocate storage space for the palette */
832 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
835 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
836 if (Palette
== NULL
) return FALSE
;
838 /* Initialize the palette */
839 Palette
->palVersion
= 0x0300;
840 Palette
->palNumEntries
= VGA_MAX_COLORS
;
842 /* Restore the default palette */
843 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
845 /* Create the palette */
846 PaletteHandle
= CreatePalette(Palette
);
848 /* Free the palette */
849 HeapFree(GetProcessHeap(), 0, Palette
);
851 /* Fail if the palette wasn't successfully created... */
852 if (PaletteHandle
== NULL
) return FALSE
;
854 /* ... otherwise return success */
858 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
861 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
862 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
863 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
864 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
866 LONG Width
= Resolution
->X
;
867 LONG Height
= Resolution
->Y
;
869 /* Use DoubleVision mode if the resolution is too small */
870 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
878 DoubleVision
= FALSE
;
881 /* Fill the bitmap info header */
882 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
883 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
884 BitmapInfo
->bmiHeader
.biWidth
= Width
;
885 BitmapInfo
->bmiHeader
.biHeight
= Height
;
886 BitmapInfo
->bmiHeader
.biBitCount
= 8;
887 BitmapInfo
->bmiHeader
.biPlanes
= 1;
888 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
889 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
891 /* Fill the palette data */
892 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
894 /* Fill the console graphics buffer info */
895 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
896 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
897 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
899 /* Create the buffer */
900 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
901 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
903 CONSOLE_GRAPHICS_BUFFER
,
904 &GraphicsBufferInfo
);
905 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
907 /* Save the framebuffer address and mutex */
908 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
909 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
911 /* Clear the framebuffer */
912 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
914 /* Set the active buffer */
915 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
917 /* Set the graphics mode palette */
918 SetConsolePalette(GraphicsConsoleBuffer
,
922 /* Set the screen mode flag */
923 ScreenMode
= GRAPHICS_MODE
;
928 static VOID
VgaLeaveGraphicsMode(VOID
)
930 /* Release the console framebuffer mutex */
931 ReleaseMutex(ConsoleMutex
);
933 /* Switch back to the default console text buffer */
934 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
936 /* Cleanup the video data */
937 CloseHandle(ConsoleMutex
);
939 ConsoleFramebuffer
= NULL
;
940 CloseHandle(GraphicsConsoleBuffer
);
941 GraphicsConsoleBuffer
= NULL
;
942 DoubleVision
= FALSE
;
945 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
949 DPRINT1("VgaEnterTextMode\n");
951 /* Switch to the text buffer */
952 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
954 /* Resize the console */
956 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
957 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
958 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
960 * Use this trick to effectively resize the console buffer and window,
962 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
963 * is smaller than the current console window size, and:
964 * - SetConsoleWindowInfo fails if the new console window size is larger
965 * than the current console screen buffer size.
967 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
968 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
969 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
970 /* Update the saved console information */
971 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
973 /* Adjust the text framebuffer if we changed resolution */
974 if (TextResolution
.X
!= Resolution
->X
||
975 TextResolution
.Y
!= Resolution
->Y
)
979 VgaDetachFromConsole();
981 /* VgaAttachToConsole sets TextResolution to the new resolution */
982 if (!VgaAttachToConsole(Resolution
))
984 DisplayMessage(L
"An unexpected error occurred!\n");
989 /* Update the cursor position in the registers */
990 Offset
= ConsoleInfo
.dwCursorPosition
.Y
* Resolution
->X
+
991 ConsoleInfo
.dwCursorPosition
.X
;
992 DPRINT1("X = %d ; Y = %d\n", ConsoleInfo
.dwCursorPosition
.X
, ConsoleInfo
.dwCursorPosition
.Y
);
993 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
994 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
998 /* The active framebuffer is now the text framebuffer */
999 ConsoleFramebuffer
= TextFramebuffer
;
1002 * Set the text mode palette.
1004 * WARNING: This call should fail on Windows (and therefore
1005 * we get the default palette and our external behaviour is
1006 * just like Windows' one), but it should success on ReactOS
1007 * (so that we get console palette changes even for text-mode
1008 * screen-buffers, which is a new feature on ReactOS).
1010 SetConsolePalette(TextConsoleBuffer
,
1012 SYSPAL_NOSTATIC256
);
1014 /* Set the screen mode flag */
1015 ScreenMode
= TEXT_MODE
;
1020 static VOID
VgaLeaveTextMode(VOID
)
1022 /* Reset the active framebuffer */
1023 ConsoleFramebuffer
= NULL
;
1026 static VOID
VgaChangeMode(VOID
)
1028 COORD Resolution
= VgaGetDisplayResolution();
1030 if (ScreenMode
== GRAPHICS_MODE
)
1032 /* Leave the current graphics mode */
1033 VgaLeaveGraphicsMode();
1037 /* Leave the current text mode */
1041 /* Check if the new mode is alphanumeric */
1042 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
1044 /* Enter new text mode */
1045 if (!VgaEnterTextMode(&Resolution
))
1047 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
1048 EmulatorTerminate();
1054 /* Enter graphics mode */
1055 if (!VgaEnterGraphicsMode(&Resolution
))
1057 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
1058 EmulatorTerminate();
1063 /* Trigger a full update of the screen */
1065 UpdateRectangle
.Left
= 0;
1066 UpdateRectangle
.Top
= 0;
1067 UpdateRectangle
.Right
= Resolution
.X
;
1068 UpdateRectangle
.Bottom
= Resolution
.Y
;
1070 /* Reset the mode change flag */
1071 ModeChanged
= FALSE
;
1074 static VOID
VgaUpdateFramebuffer(VOID
)
1077 COORD Resolution
= VgaGetDisplayResolution();
1078 DWORD AddressSize
= VgaGetAddressSize();
1079 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1080 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1081 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1084 * If console framebuffer is NULL, that means something went wrong
1085 * earlier and this is the final display refresh.
1087 if (ConsoleFramebuffer
== NULL
) return;
1089 /* Check if this is text mode or graphics mode */
1090 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1093 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1096 * Synchronize access to the graphics framebuffer
1097 * with the console framebuffer mutex.
1099 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1101 /* Loop through the scanlines */
1102 for (i
= 0; i
< Resolution
.Y
; i
++)
1104 /* Loop through the pixels */
1105 for (j
= 0; j
< Resolution
.X
; j
++)
1109 /* Check the shifting mode */
1110 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1112 /* 4 bits shifted from each plane */
1114 /* Check if this is 16 or 256 color mode */
1115 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1117 /* One byte per pixel */
1118 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1119 + (Address
+ (j
/ VGA_NUM_BANKS
))
1124 /* 4-bits per pixel */
1126 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1127 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1130 /* Check if we should use the highest 4 bits or lowest 4 */
1131 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1143 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1145 /* Check if this is 16 or 256 color mode */
1146 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1148 // TODO: NOT IMPLEMENTED
1149 DPRINT1("8-bit interleaved mode is not implemented!\n");
1154 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1155 * then 2 bits shifted from plane 1 and 3 for the next 4
1157 BYTE LowPlaneData
= VgaMemory
[((j
/ 4) % 2) * VGA_BANK_SIZE
1158 + (Address
+ (j
/ 8)) * AddressSize
];
1159 BYTE HighPlaneData
= VgaMemory
[(((j
/ 4) % 2) + 2) * VGA_BANK_SIZE
1160 + (Address
+ (j
/ 8)) * AddressSize
];
1162 /* Extract the two bits from each plane */
1163 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1164 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1166 /* Combine them into the pixel */
1167 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1172 /* 1 bit shifted from each plane */
1174 /* Check if this is 16 or 256 color mode */
1175 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1177 /* 8 bits per pixel, 2 on each plane */
1179 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1181 /* The data is on plane k, 4 pixels per byte */
1182 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1183 + (Address
+ (j
/ VGA_NUM_BANKS
))
1186 /* The mask of the first bit in the pair */
1187 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1189 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1190 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1192 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1193 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1198 /* 4 bits per pixel, 1 on each plane */
1200 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1202 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1203 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1206 /* If the bit on that plane is set, set it */
1207 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1212 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1215 * In 16 color mode, the value is an index to the AC registers
1216 * if external palette access is disabled, otherwise (in case
1217 * of palette loading) it is a blank pixel.
1219 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1223 /* Take into account DoubleVision mode when checking for pixel updates */
1226 /* Now check if the resulting pixel data has changed */
1227 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
1229 /* Yes, write the new value */
1230 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
1231 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
1232 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
1233 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1235 /* Mark the specified pixel as changed */
1236 VgaMarkForUpdate(i
, j
);
1241 /* Now check if the resulting pixel data has changed */
1242 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
1244 /* Yes, write the new value */
1245 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
1247 /* Mark the specified pixel as changed */
1248 VgaMarkForUpdate(i
, j
);
1253 /* Move to the next scanline */
1254 Address
+= ScanlineSize
;
1258 * Release the console framebuffer mutex
1259 * so that we allow for repainting.
1261 ReleaseMutex(ConsoleMutex
);
1267 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1270 /* Loop through the scanlines */
1271 for (i
= 0; i
< Resolution
.Y
; i
++)
1273 /* Loop through the characters */
1274 for (j
= 0; j
< Resolution
.X
; j
++)
1276 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1278 /* Plane 0 holds the character itself */
1279 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1281 /* Plane 1 holds the attribute */
1282 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1284 /* Now check if the resulting character data has changed */
1285 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1286 (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1288 /* Yes, write the new value */
1289 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
1291 /* Mark the specified cell as changed */
1292 VgaMarkForUpdate(i
, j
);
1296 /* Move to the next scanline */
1297 Address
+= ScanlineSize
;
1302 static VOID
VgaUpdateTextCursor(VOID
)
1305 CONSOLE_CURSOR_INFO CursorInfo
;
1306 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
1307 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1308 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1309 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1310 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1311 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1313 /* Just return if we are not in text mode */
1314 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
1316 if (CursorStart
< CursorEnd
)
1318 /* Visible cursor */
1319 CursorInfo
.bVisible
= TRUE
;
1320 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1325 CursorInfo
.bVisible
= FALSE
;
1326 CursorInfo
.dwSize
= 0;
1329 /* Add the cursor skew to the location */
1330 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
1332 /* Find the coordinates of the new position */
1333 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1334 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1336 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1338 /* Update the physical cursor */
1339 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1340 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1342 /* Reset the cursor move flag */
1343 CursorMoved
= FALSE
;
1346 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1348 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1353 return VgaMiscRegister
;
1355 case VGA_INSTAT0_READ
:
1356 return 0; // Not implemented
1358 case VGA_INSTAT1_READ_MONO
:
1359 case VGA_INSTAT1_READ_COLOR
:
1363 /* Reset the AC latch */
1366 /* Set a flag if there is a vertical or horizontal retrace */
1367 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1369 /* Set an additional flag if there was a vertical retrace */
1370 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1372 /* Clear the flags */
1373 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1378 case VGA_FEATURE_READ
:
1379 return VgaFeatureRegister
;
1385 return VgaAcRegisters
[VgaAcIndex
];
1391 return VgaSeqRegisters
[VgaSeqIndex
];
1396 case VGA_DAC_READ_INDEX
:
1397 /* This returns the read/write state */
1398 return (VgaDacReadWrite
? 0 : 3);
1400 case VGA_DAC_WRITE_INDEX
:
1401 return (VgaDacIndex
/ 3);
1405 /* Ignore reads in write mode */
1406 if (!VgaDacReadWrite
)
1408 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1409 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1416 case VGA_CRTC_INDEX_MONO
:
1417 case VGA_CRTC_INDEX_COLOR
:
1418 return VgaCrtcIndex
;
1420 case VGA_CRTC_DATA_MONO
:
1421 case VGA_CRTC_DATA_COLOR
:
1422 return VgaCrtcRegisters
[VgaCrtcIndex
];
1428 return VgaGcRegisters
[VgaGcIndex
];
1431 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1438 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1440 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1444 case VGA_MISC_WRITE
:
1446 VgaMiscRegister
= Data
;
1448 if (VgaMiscRegister
& 0x01)
1450 /* Color emulation */
1451 DPRINT1("Color emulation\n");
1453 /* Register the new I/O Ports */
1454 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1455 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1456 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1458 /* Unregister the old ones */
1459 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1460 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1461 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1465 /* Monochrome emulation */
1466 DPRINT1("Monochrome emulation\n");
1468 /* Register the new I/O Ports */
1469 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1470 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1471 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1473 /* Unregister the old ones */
1474 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1475 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1476 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1479 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1483 case VGA_FEATURE_WRITE_MONO
:
1484 case VGA_FEATURE_WRITE_COLOR
:
1486 VgaFeatureRegister
= Data
;
1491 // case VGA_AC_WRITE:
1495 /* Change the index */
1496 BYTE Index
= Data
& 0x1F;
1497 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1500 * Change palette protection by checking for
1501 * the Palette Address Source bit.
1503 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1507 /* Write the data */
1511 /* Toggle the latch */
1512 VgaAcLatch
= !VgaAcLatch
;
1518 /* Set the sequencer index register */
1519 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1525 /* Call the sequencer function */
1526 VgaWriteSequencer(Data
);
1536 case VGA_DAC_READ_INDEX
:
1538 VgaDacReadWrite
= FALSE
;
1539 VgaDacIndex
= Data
* 3;
1543 case VGA_DAC_WRITE_INDEX
:
1545 VgaDacReadWrite
= TRUE
;
1546 VgaDacIndex
= Data
* 3;
1552 /* Ignore writes in read mode */
1553 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1557 case VGA_CRTC_INDEX_MONO
:
1558 case VGA_CRTC_INDEX_COLOR
:
1560 /* Set the CRTC index register */
1561 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1565 case VGA_CRTC_DATA_MONO
:
1566 case VGA_CRTC_DATA_COLOR
:
1568 /* Call the CRTC function */
1575 /* Set the GC index register */
1576 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1582 /* Call the GC function */
1588 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1593 /* PUBLIC FUNCTIONS ***********************************************************/
1595 DWORD
VgaGetVideoBaseAddress(VOID
)
1597 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1600 DWORD
VgaGetVideoLimitAddress(VOID
)
1602 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1605 COORD
VgaGetDisplayResolution(VOID
)
1608 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1610 /* The low 8 bits are in the display registers */
1611 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1612 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1614 /* Set the top bits from the overflow register */
1615 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1617 Resolution
.Y
|= 1 << 8;
1619 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1621 Resolution
.Y
|= 1 << 9;
1624 /* Increase the values by 1 */
1628 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1630 /* Multiply the horizontal resolution by the 9/8 dot mode */
1631 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1634 /* The horizontal resolution is halved in 8-bit mode */
1635 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1638 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1640 /* Halve the vertical resolution */
1645 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1646 Resolution
.Y
/= MaximumScanLine
;
1649 /* Return the resolution */
1653 VOID
VgaRefreshDisplay(VOID
)
1655 HANDLE ConsoleBufferHandle
= NULL
;
1658 /* Set the vertical retrace flag */
1659 InVerticalRetrace
= TRUE
;
1661 /* If nothing has changed, just return */
1662 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1665 /* Change the display mode */
1666 if (ModeChanged
) VgaChangeMode();
1668 /* Change the text cursor location */
1669 if (CursorMoved
) VgaUpdateTextCursor();
1671 /* Retrieve the current resolution */
1672 Resolution
= VgaGetDisplayResolution();
1676 /* Trigger a full update of the screen */
1678 UpdateRectangle
.Left
= 0;
1679 UpdateRectangle
.Top
= 0;
1680 UpdateRectangle
.Right
= Resolution
.X
;
1681 UpdateRectangle
.Bottom
= Resolution
.Y
;
1683 PaletteChanged
= FALSE
;
1686 /* Update the contents of the framebuffer */
1687 VgaUpdateFramebuffer();
1689 /* Ignore if there's nothing to update */
1690 if (!NeedsUpdate
) return;
1692 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1693 UpdateRectangle
.Left
,
1694 UpdateRectangle
.Top
,
1695 UpdateRectangle
.Right
,
1696 UpdateRectangle
.Bottom
);
1698 /* Check if this is text mode or graphics mode */
1699 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1702 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1704 /* In DoubleVision mode, scale the update rectangle */
1707 UpdateRectangle
.Left
*= 2;
1708 UpdateRectangle
.Top
*= 2;
1709 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1710 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1716 ConsoleBufferHandle
= TextConsoleBuffer
;
1719 /* Redraw the screen */
1720 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1722 /* Clear the update flag */
1723 NeedsUpdate
= FALSE
;
1726 VOID
VgaHorizontalRetrace(VOID
)
1729 InHorizontalRetrace
= TRUE
;
1732 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1737 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1739 /* Ignore if video RAM access is disabled */
1740 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1742 /* Loop through each byte */
1743 for (i
= 0; i
< Size
; i
++)
1745 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1747 /* Load the latch registers */
1748 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1749 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1750 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1751 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1753 /* Copy the value to the buffer */
1754 Buffer
[i
] = VgaMemory
[VideoAddress
];
1758 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1763 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1765 /* Ignore if video RAM access is disabled */
1766 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1768 /* Also ignore if write access to all planes is disabled */
1769 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1771 /* Loop through each byte */
1772 for (i
= 0; i
< Size
; i
++)
1774 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1776 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1778 /* Make sure the page is writeable */
1779 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1781 /* Check if this is chain-4 mode */
1782 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1784 if (((Address
+ i
) & 3) != j
)
1786 /* This plane will not be accessed */
1791 /* Check if this is odd-even mode */
1792 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1794 if (((Address
+ i
) & 1) != (j
& 1))
1796 /* This plane will not be accessed */
1801 /* Copy the value to the VGA memory */
1802 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1807 VOID
VgaClearMemory(VOID
)
1809 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1812 VOID
VgaResetPalette(VOID
)
1814 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1816 /* Restore the default palette */
1817 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1818 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1819 PaletteChanged
= TRUE
;
1822 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1824 /* Save the default text-mode console output handle */
1825 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
1826 TextConsoleBuffer
= TextHandle
;
1828 /* Save the console information */
1829 if (!GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
))
1834 /* Initialize the VGA palette and fail if it isn't successfully created */
1835 if (!VgaInitializePalette()) return FALSE
;
1836 /***/ VgaResetPalette(); /***/
1838 /* Switch to the text buffer */
1839 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1841 /* Clear the VGA memory */
1844 /* Register the I/O Ports */
1845 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1846 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1847 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1848 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1849 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1850 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1851 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1852 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1853 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1854 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1855 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1856 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1857 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1859 /* Return success */
1863 VOID
VgaCleanup(VOID
)
1865 if (ScreenMode
== GRAPHICS_MODE
)
1867 /* Leave the current graphics mode */
1868 VgaLeaveGraphicsMode();
1872 /* Leave the current text mode */
1876 VgaDetachFromConsole();
1878 CloseHandle(AnotherEvent
);
1879 CloseHandle(EndEvent
);
1880 CloseHandle(StartEvent
);
1883 RegisterConsoleVDM
= NULL
;
1884 FreeLibrary(hKernel32
);