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 };
24 #define USE_REACTOS_COLORS
25 // #define USE_DOSBOX_COLORS
27 #if defined(USE_REACTOS_COLORS)
30 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
32 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
33 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
34 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
35 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
36 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
37 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
38 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
39 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
40 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
41 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
42 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
43 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
44 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
45 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
46 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
47 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
48 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
49 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
50 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
51 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
52 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
53 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
54 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
55 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
56 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
57 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
58 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
59 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
60 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
61 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
62 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
63 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
64 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
65 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
66 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
67 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
68 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
69 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
70 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
71 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
72 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
73 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
74 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
75 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
76 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
77 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
78 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
79 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
80 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
81 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
82 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
83 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
84 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
85 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
86 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
87 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
88 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
89 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
90 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
91 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
92 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
93 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
94 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
95 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
98 #elif defined(USE_DOSBOX_COLORS)
101 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
103 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
104 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
105 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
106 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
107 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
108 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
109 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
110 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
111 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
112 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
113 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
114 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
115 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
116 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
117 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
118 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
120 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
121 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
122 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
123 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
124 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
125 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
126 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
127 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
128 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
129 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
130 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
131 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
132 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
133 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
134 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
135 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
137 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
138 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
139 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
140 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
141 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
142 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
143 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
144 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
145 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
146 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
147 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
148 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
149 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
150 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
151 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
152 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
154 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
155 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
156 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
157 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
158 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
159 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
160 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
161 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
162 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
163 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
164 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
165 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
166 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
167 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
168 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
169 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
175 * Default 16-color palette for foreground and background
176 * (corresponding flags in comments).
177 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
179 static const COLORREF ConsoleColors
[16] =
181 RGB(0, 0, 0), // (Black)
182 RGB(0, 0, 128), // BLUE
183 RGB(0, 128, 0), // GREEN
184 RGB(0, 128, 128), // BLUE | GREEN
185 RGB(128, 0, 0), // RED
186 RGB(128, 0, 128), // BLUE | RED
187 RGB(128, 128, 0), // GREEN | RED
188 RGB(192, 192, 192), // BLUE | GREEN | RED
190 RGB(128, 128, 128), // (Grey) INTENSITY
191 RGB(0, 0, 255), // BLUE | INTENSITY
192 RGB(0, 255, 0), // GREEN | INTENSITY
193 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
194 RGB(255, 0, 0), // RED | INTENSITY
195 RGB(255, 0, 255), // BLUE | RED | INTENSITY
196 RGB(255, 255, 0), // GREEN | RED | INTENSITY
197 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
201 * Console interface -- VGA-mode-agnostic
203 typedef struct _CHAR_CELL
207 } CHAR_CELL
, *PCHAR_CELL
;
208 C_ASSERT(sizeof(CHAR_CELL
) == 2);
210 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
211 // either TextFramebuffer or a valid
212 // graphics framebuffer.
213 static HPALETTE TextPaletteHandle
= NULL
;
214 static HPALETTE PaletteHandle
= NULL
;
216 static HANDLE StartEvent
= NULL
;
217 static HANDLE EndEvent
= NULL
;
218 static HANDLE AnotherEvent
= NULL
;
220 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
221 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
225 * Text mode -- we always keep a valid text mode framebuffer
226 * even if we are in graphics mode. This is needed in order to
227 * keep a consistent VGA state.
229 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
230 static COORD TextResolution
= {0};
231 static PCHAR_CELL TextFramebuffer
= NULL
;
232 static HANDLE TextConsoleBuffer
= NULL
;
235 static HANDLE GraphicsConsoleBuffer
= NULL
;
236 static HANDLE ConsoleMutex
= NULL
;
237 static BOOLEAN DoubleVision
= FALSE
;
242 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
244 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
246 static BYTE VgaMiscRegister
;
247 static BYTE VgaFeatureRegister
;
249 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
250 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
252 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
253 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
255 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
256 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
258 static BOOLEAN VgaAcLatch
= FALSE
;
259 static BOOLEAN VgaAcPalDisable
= TRUE
;
260 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
261 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
263 // static VGA_REGISTERS VgaRegisters;
265 static BYTE VgaDacMask
= 0xFF;
266 static WORD VgaDacIndex
= 0;
267 static BOOLEAN VgaDacReadWrite
= FALSE
;
268 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
270 static BOOLEAN InVerticalRetrace
= FALSE
;
271 static BOOLEAN InHorizontalRetrace
= FALSE
;
273 static BOOLEAN NeedsUpdate
= FALSE
;
274 static BOOLEAN ModeChanged
= FALSE
;
275 static BOOLEAN CursorMoved
= FALSE
;
276 static BOOLEAN PaletteChanged
= FALSE
;
283 } ScreenMode
= TEXT_MODE
;
285 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
287 /* RegisterConsoleVDM EMULATION ***********************************************/
289 #include <ntddvdeo.h>
293 (WINAPI
*pRegisterConsoleVDM
)
296 HANDLE EventHandle_1
,
297 HANDLE EventHandle_2
,
298 HANDLE EventHandle_3
,
300 PVOID returned_val_1
,
301 PVOID
*returned_val_2
,
302 PVOID lpUnknownBuffer
,
303 DWORD theUnknownBufferLength
,
304 COORD theVDMBufferSize
,
314 HANDLE EventHandle_1
,
315 HANDLE EventHandle_2
,
316 HANDLE EventHandle_3
,
318 PVOID returned_val_1
,
319 PVOID
*returned_val_2
,
320 PVOID lpUnknownBuffer
,
321 DWORD theUnknownBufferLength
,
322 COORD theVDMBufferSize
,
326 HMODULE hKernel32
= NULL
;
327 pRegisterConsoleVDM RegisterConsoleVDM
= NULL
;
331 * This private buffer, per-console, is used by
332 * RegisterConsoleVDM and InvalidateConsoleDIBits.
334 static COORD VDMBufferSize
= {0};
335 static PCHAR_CELL VDMBuffer
= NULL
;
337 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
338 // for the real RegisterConsoleVDM and
339 // InvalidateConsoleDIBits
343 __RegisterConsoleVDM(BOOL IsDosVDM_flag
,
344 HANDLE EventHandle_1
,
345 HANDLE EventHandle_2
,
346 HANDLE EventHandle_3
,
348 PVOID returned_val_1
,
349 PVOID
*returned_val_2
,
350 PVOID lpUnknownBuffer
,
351 DWORD theUnknownBufferLength
,
352 COORD theVDMBufferSize
,
355 UNREFERENCED_PARAMETER(EventHandle_3
);
356 UNREFERENCED_PARAMETER(Unused1
);
357 UNREFERENCED_PARAMETER(returned_val_1
);
358 UNREFERENCED_PARAMETER(returned_val_2
);
359 UNREFERENCED_PARAMETER(lpUnknownBuffer
);
360 UNREFERENCED_PARAMETER(theUnknownBufferLength
);
363 DPRINT1("__RegisterConsoleVDM(%d)\n", IsDosVDM_flag
);
365 if (lpVDMBuffer
== NULL
) return FALSE
;
369 // if (EventHandle_1 == NULL || EventHandle_2 == NULL) return FALSE;
370 if (VDMBuffer
!= NULL
) return FALSE
;
372 VDMBufferSize
= theVDMBufferSize
;
374 /* HACK: Cache -- to be removed in the real implementation */
375 CharBuff
= HeapAlloc(GetProcessHeap(),
377 theVDMBufferSize
.X
* theVDMBufferSize
.Y
378 * sizeof(CHAR_INFO
));
381 VDMBuffer
= HeapAlloc(GetProcessHeap(),
383 theVDMBufferSize
.X
* theVDMBufferSize
.Y
384 * sizeof(CHAR_CELL
));
385 *lpVDMBuffer
= (PCHAR
)VDMBuffer
;
386 return (VDMBuffer
!= NULL
);
390 /* HACK: Cache -- to be removed in the real implementation */
391 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
394 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
397 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
404 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
405 IN PSMALL_RECT lpRect
)
407 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
409 /* HACK: Write the cached data to the console */
411 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
416 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
418 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
420 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
421 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
425 WriteConsoleOutputA(hConsoleOutput
,
432 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
435 /* PRIVATE FUNCTIONS **********************************************************/
437 static inline DWORD
VgaGetAddressSize(VOID
);
438 static VOID
VgaUpdateTextCursor(VOID
);
440 static VOID
VgaUpdateCursorPosition(VOID
)
443 * Update the cursor position in the VGA registers.
445 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
446 ConsoleInfo
.dwCursorPosition
.X
;
448 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
449 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
451 // VidBiosSyncCursorPosition();
452 VgaUpdateTextCursor();
455 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
459 PVIDEO_HARDWARE_STATE_HEADER State
;
462 DWORD AddressSize
, ScanlineSize
;
466 COORD Origin
= { 0, 0 };
468 ASSERT(TextFramebuffer
== NULL
);
470 TextResolution
= *Resolution
;
473 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
474 * in the two following APIs:
475 * SrvRegisterConsoleVDM (corresponding win32 API: RegisterConsoleVDM)
476 * SrvVDMConsoleOperation (corresponding Win32 API: )
477 * to check whether the current process is a VDM process, and fails otherwise with the
478 * error 0xC0000022 ().
480 * It is worth it to notice that also basesrv.dll does the same only for the
481 * BaseSrvIsFirstVDM API...
485 __RegisterConsoleVDM(1,
488 AnotherEvent
, // NULL,
490 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
491 (PVOID
*)&State
, // NULL,
495 (PCHAR
*)&TextFramebuffer
);
498 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
507 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
508 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
509 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
511 * Use this trick to effectively resize the console buffer and window,
513 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
514 * is smaller than the current console window size, and:
515 * - SetConsoleWindowInfo fails if the new console window size is larger
516 * than the current console screen buffer size.
518 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
519 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
520 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
521 /* Update the saved console information */
522 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
525 * Copy console data into VGA memory
529 AddressSize
= VgaGetAddressSize();
530 ConRect
.Left
= ConRect
.Top
= 0;
531 ConRect
.Right
= TextResolution
.X
;
532 ConRect
.Bottom
= TextResolution
.Y
;
533 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
535 /* Read the data from the console into the framebuffer... */
536 ReadConsoleOutputA(TextConsoleBuffer
,
542 /* ... and copy the framebuffer into the VGA memory */
544 /* Loop through the scanlines */
545 for (i
= 0; i
< TextResolution
.Y
; i
++)
547 /* Loop through the characters */
548 for (j
= 0; j
< TextResolution
.X
; j
++)
550 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
552 /* Store the character in plane 0 */
553 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
555 /* Store the attribute in plane 1 */
556 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
559 /* Move to the next scanline */
560 Address
+= ScanlineSize
;
563 VgaUpdateCursorPosition();
568 static BOOL
IsConsoleHandle(HANDLE hHandle
)
572 /* Check whether the handle may be that of a console... */
573 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
577 * It may be. Perform another test... The idea comes from the
578 * MSDN description of the WriteConsole API:
580 * "WriteConsole fails if it is used with a standard handle
581 * that is redirected to a file. If an application processes
582 * multilingual output that can be redirected, determine whether
583 * the output handle is a console handle (one method is to call
584 * the GetConsoleMode function and check whether it succeeds).
585 * If the handle is a console handle, call WriteConsole. If the
586 * handle is not a console handle, the output is redirected and
587 * you should call WriteFile to perform the I/O."
589 return GetConsoleMode(hHandle
, &dwMode
);
592 static inline DWORD
VgaGetAddressSize(VOID
)
594 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
596 /* Double-word addressing */
597 return 4; // sizeof(DWORD)
599 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
601 /* Byte addressing */
602 return 1; // sizeof(BYTE)
606 /* Word addressing */
607 return 2; // sizeof(WORD)
611 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
613 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
616 /* Check for chain-4 and odd-even mode */
617 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
619 /* The lowest two bits are the plane number */
623 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
625 /* The LSB is the plane number */
631 /* Use the read mode */
632 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
635 /* Multiply the offset by the address size */
636 Offset
*= VgaGetAddressSize();
638 return Offset
+ Plane
* VGA_BANK_SIZE
;
641 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
643 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
645 /* Check for chain-4 and odd-even mode */
646 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
648 /* Shift the offset to the right by 2 */
651 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
653 /* Shift the offset to the right by 1 */
657 /* Multiply the offset by the address size */
658 Offset
*= VgaGetAddressSize();
660 /* Return the offset on plane 0 */
664 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
666 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
667 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
671 /* In write mode 1 just return the latch register */
672 return VgaLatchRegisters
[Plane
];
677 /* Write modes 0 and 3 rotate the data to the right first */
678 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
679 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
683 /* Write mode 2 expands the appropriate bit to all 8 bits */
684 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
690 * In write mode 0, the enable set/reset register decides if the
691 * set/reset bit should be expanded to all 8 bits.
693 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
695 /* Copy the bit from the set/reset register to all 8 bits */
696 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
702 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
703 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
705 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
706 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
707 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
711 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
714 /* Then we expand the bit in the set/reset field */
715 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
718 /* Bits cleared in the bitmask are replaced with latch register bits */
719 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
721 /* Return the byte */
725 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
727 /* Check if this is the first time the rectangle is updated */
730 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
731 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
734 /* Expand the rectangle to include the point */
735 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
736 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
737 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
738 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
740 /* Set the update request flag */
744 static VOID
VgaWriteSequencer(BYTE Data
)
746 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
749 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
752 static VOID
VgaWriteGc(BYTE Data
)
754 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
757 VgaGcRegisters
[VgaGcIndex
] = Data
;
759 /* Check the index */
762 case VGA_GC_MISC_REG
:
764 /* The GC misc register decides if it's text or graphics mode */
771 static VOID
VgaWriteCrtc(BYTE Data
)
773 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
776 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
778 /* Check the index */
779 switch (VgaCrtcIndex
)
781 case VGA_CRTC_END_HORZ_DISP_REG
:
782 case VGA_CRTC_VERT_DISP_END_REG
:
783 case VGA_CRTC_OVERFLOW_REG
:
785 /* The video mode has changed */
790 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
791 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
792 case VGA_CRTC_CURSOR_START_REG
:
793 case VGA_CRTC_CURSOR_END_REG
:
795 /* Set the cursor moved flag */
802 static VOID
VgaWriteDac(BYTE Data
)
808 VgaDacRegisters
[VgaDacIndex
] = Data
;
810 /* Find the palette index */
811 PaletteIndex
= VgaDacIndex
/ 3;
813 /* Fill the entry structure */
814 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
815 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
816 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
819 /* Update the palette entry */
820 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
822 /* Check which text palette entries are affected */
823 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
825 if (VgaAcRegisters
[i
] == PaletteIndex
)
827 /* Update the text palette entry */
828 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
832 /* Set the palette changed flag */
833 PaletteChanged
= TRUE
;
835 /* Update the index */
837 VgaDacIndex
%= VGA_PALETTE_SIZE
;
840 static VOID
VgaWriteAc(BYTE Data
)
844 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
847 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
849 if (VgaAcPalDisable
) return;
851 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
852 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
854 /* Update the AC register */
855 VgaAcRegisters
[VgaAcIndex
] = Data
;
857 /* Fill the entry structure */
858 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
859 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
860 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
863 /* Update the palette entry and set the palette change flag */
864 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
865 PaletteChanged
= TRUE
;
870 VgaAcRegisters
[VgaAcIndex
] = Data
;
874 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
878 /* Copy the colors of the default palette to the DAC and console palette */
879 for (i
= 0; i
< NumOfEntries
; i
++)
881 /* Set the palette entries */
882 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
883 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
884 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
885 Entries
[i
].peFlags
= 0;
887 /* Set the DAC registers */
888 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
889 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
890 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
894 static BOOLEAN
VgaInitializePalette(VOID
)
897 BOOLEAN Result
= FALSE
;
898 LPLOGPALETTE Palette
, TextPalette
;
900 /* Allocate storage space for the palettes */
901 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
904 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
905 TextPalette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
908 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
909 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
911 /* Initialize the palettes */
912 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
913 Palette
->palNumEntries
= VGA_MAX_COLORS
;
914 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
916 /* Restore the default graphics palette */
917 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
919 /* Set the default text palette */
920 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
922 /* Set the palette entries */
923 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
924 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
925 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
926 TextPalette
->palPalEntry
[i
].peFlags
= 0;
929 /* Create the palettes */
930 PaletteHandle
= CreatePalette(Palette
);
931 TextPaletteHandle
= CreatePalette(TextPalette
);
933 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
935 /* The palettes have been created successfully */
940 /* Free the palettes */
941 if (Palette
) HeapFree(GetProcessHeap(), 0, Palette
);
942 if (TextPalette
) HeapFree(GetProcessHeap(), 0, TextPalette
);
946 /* Something failed, delete the palettes */
947 if (PaletteHandle
) DeleteObject(PaletteHandle
);
948 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
954 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
957 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
958 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
959 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
960 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
962 LONG Width
= Resolution
->X
;
963 LONG Height
= Resolution
->Y
;
965 /* Use DoubleVision mode if the resolution is too small */
966 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
974 DoubleVision
= FALSE
;
977 /* Fill the bitmap info header */
978 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
979 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
980 BitmapInfo
->bmiHeader
.biWidth
= Width
;
981 BitmapInfo
->bmiHeader
.biHeight
= Height
;
982 BitmapInfo
->bmiHeader
.biBitCount
= 8;
983 BitmapInfo
->bmiHeader
.biPlanes
= 1;
984 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
985 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
987 /* Fill the palette data */
988 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
990 /* Fill the console graphics buffer info */
991 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
992 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
993 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
995 /* Create the buffer */
996 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
997 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
999 CONSOLE_GRAPHICS_BUFFER
,
1000 &GraphicsBufferInfo
);
1001 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
1003 /* Save the framebuffer address and mutex */
1004 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
1005 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
1007 /* Clear the framebuffer */
1008 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
1010 /* Set the active buffer */
1011 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
1013 /* Set the graphics mode palette */
1014 SetConsolePalette(GraphicsConsoleBuffer
,
1016 SYSPAL_NOSTATIC256
);
1018 /* Set the screen mode flag */
1019 ScreenMode
= GRAPHICS_MODE
;
1024 static VOID
VgaLeaveGraphicsMode(VOID
)
1026 /* Release the console framebuffer mutex */
1027 ReleaseMutex(ConsoleMutex
);
1029 /* Switch back to the default console text buffer */
1030 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1032 /* Cleanup the video data */
1033 CloseHandle(ConsoleMutex
);
1034 ConsoleMutex
= NULL
;
1035 ConsoleFramebuffer
= NULL
;
1036 CloseHandle(GraphicsConsoleBuffer
);
1037 GraphicsConsoleBuffer
= NULL
;
1038 DoubleVision
= FALSE
;
1041 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1043 DPRINT1("VgaEnterTextMode\n");
1045 /* Switch to the text buffer */
1046 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1048 /* Adjust the text framebuffer if we changed the resolution */
1049 if (TextResolution
.X
!= Resolution
->X
||
1050 TextResolution
.Y
!= Resolution
->Y
)
1052 VgaDetachFromConsole(TRUE
);
1055 * VgaAttachToConsoleInternal sets TextResolution to the
1056 * new resolution and updates ConsoleInfo.
1058 if (!VgaAttachToConsoleInternal(Resolution
))
1060 DisplayMessage(L
"An unexpected error occurred!\n");
1061 EmulatorTerminate();
1067 VgaUpdateCursorPosition();
1070 /* The active framebuffer is now the text framebuffer */
1071 ConsoleFramebuffer
= TextFramebuffer
;
1074 * Set the text mode palette.
1076 * WARNING: This call should fail on Windows (and therefore
1077 * we get the default palette and our external behaviour is
1078 * just like Windows' one), but it should success on ReactOS
1079 * (so that we get console palette changes even for text-mode
1080 * screen-buffers, which is a new feature on ReactOS).
1082 SetConsolePalette(TextConsoleBuffer
,
1084 SYSPAL_NOSTATIC256
);
1086 /* Set the screen mode flag */
1087 ScreenMode
= TEXT_MODE
;
1092 static VOID
VgaLeaveTextMode(VOID
)
1094 /* Reset the active framebuffer */
1095 ConsoleFramebuffer
= NULL
;
1098 static VOID
VgaChangeMode(VOID
)
1100 COORD Resolution
= VgaGetDisplayResolution();
1102 if (ScreenMode
== GRAPHICS_MODE
)
1104 /* Leave the current graphics mode */
1105 VgaLeaveGraphicsMode();
1109 /* Leave the current text mode */
1113 /* Check if the new mode is alphanumeric */
1114 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
1116 /* Enter new text mode */
1117 if (!VgaEnterTextMode(&Resolution
))
1119 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
1120 EmulatorTerminate();
1126 /* Enter graphics mode */
1127 if (!VgaEnterGraphicsMode(&Resolution
))
1129 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
1130 EmulatorTerminate();
1135 /* Trigger a full update of the screen */
1137 UpdateRectangle
.Left
= 0;
1138 UpdateRectangle
.Top
= 0;
1139 UpdateRectangle
.Right
= Resolution
.X
;
1140 UpdateRectangle
.Bottom
= Resolution
.Y
;
1142 /* Reset the mode change flag */
1143 ModeChanged
= FALSE
;
1146 static VOID
VgaUpdateFramebuffer(VOID
)
1149 COORD Resolution
= VgaGetDisplayResolution();
1150 DWORD AddressSize
= VgaGetAddressSize();
1151 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1152 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1153 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1156 * If console framebuffer is NULL, that means something went wrong
1157 * earlier and this is the final display refresh.
1159 if (ConsoleFramebuffer
== NULL
) return;
1161 /* Check if this is text mode or graphics mode */
1162 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1165 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1166 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1169 * Synchronize access to the graphics framebuffer
1170 * with the console framebuffer mutex.
1172 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1174 /* Shift the high bit right by 1 in odd/even mode */
1175 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1177 InterlaceHighBit
>>= 1;
1180 /* Loop through the scanlines */
1181 for (i
= 0; i
< Resolution
.Y
; i
++)
1183 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1185 /* Odd-numbered line in interlaced mode - set the high bit */
1186 Address
|= InterlaceHighBit
;
1189 /* Loop through the pixels */
1190 for (j
= 0; j
< Resolution
.X
; j
++)
1194 /* Check the shifting mode */
1195 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1197 /* 4 bits shifted from each plane */
1199 /* Check if this is 16 or 256 color mode */
1200 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1202 /* One byte per pixel */
1203 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1204 + (Address
+ (j
/ VGA_NUM_BANKS
))
1209 /* 4-bits per pixel */
1211 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1212 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1215 /* Check if we should use the highest 4 bits or lowest 4 */
1216 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1228 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1230 /* Check if this is 16 or 256 color mode */
1231 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1233 // TODO: NOT IMPLEMENTED
1234 DPRINT1("8-bit interleaved mode is not implemented!\n");
1239 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1240 * then 2 bits shifted from plane 1 and 3 for the next 4
1242 DWORD BankNumber
= (j
/ 4) % 2;
1243 DWORD Offset
= Address
+ (j
/ 8);
1244 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ Offset
* AddressSize
];
1245 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ Offset
* AddressSize
];
1247 /* Extract the two bits from each plane */
1248 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1249 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1251 /* Combine them into the pixel */
1252 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1257 /* 1 bit shifted from each plane */
1259 /* Check if this is 16 or 256 color mode */
1260 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1262 /* 8 bits per pixel, 2 on each plane */
1264 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1266 /* The data is on plane k, 4 pixels per byte */
1267 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1268 + (Address
+ (j
/ VGA_NUM_BANKS
))
1271 /* The mask of the first bit in the pair */
1272 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1274 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1275 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1277 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1278 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1283 /* 4 bits per pixel, 1 on each plane */
1285 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1287 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1288 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1291 /* If the bit on that plane is set, set it */
1292 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1297 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1300 * In 16 color mode, the value is an index to the AC registers
1301 * if external palette access is disabled, otherwise (in case
1302 * of palette loading) it is a blank pixel.
1304 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1308 /* Take into account DoubleVision mode when checking for pixel updates */
1311 /* Now check if the resulting pixel data has changed */
1312 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
1314 /* Yes, write the new value */
1315 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
1316 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
1317 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
1318 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1320 /* Mark the specified pixel as changed */
1321 VgaMarkForUpdate(i
, j
);
1326 /* Now check if the resulting pixel data has changed */
1327 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
1329 /* Yes, write the new value */
1330 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
1332 /* Mark the specified pixel as changed */
1333 VgaMarkForUpdate(i
, j
);
1338 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1340 /* Clear the high bit */
1341 Address
&= ~InterlaceHighBit
;
1344 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1346 /* Move to the next scanline */
1347 Address
+= ScanlineSize
;
1352 * Release the console framebuffer mutex
1353 * so that we allow for repainting.
1355 ReleaseMutex(ConsoleMutex
);
1361 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1364 /* Loop through the scanlines */
1365 for (i
= 0; i
< Resolution
.Y
; i
++)
1367 /* Loop through the characters */
1368 for (j
= 0; j
< Resolution
.X
; j
++)
1370 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1372 /* Plane 0 holds the character itself */
1373 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1375 /* Plane 1 holds the attribute */
1376 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1378 /* Now check if the resulting character data has changed */
1379 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1380 (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1382 /* Yes, write the new value */
1383 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
1385 /* Mark the specified cell as changed */
1386 VgaMarkForUpdate(i
, j
);
1390 /* Move to the next scanline */
1391 Address
+= ScanlineSize
;
1396 static VOID
VgaUpdateTextCursor(VOID
)
1399 CONSOLE_CURSOR_INFO CursorInfo
;
1400 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
1401 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1402 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1403 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1404 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1405 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1407 /* Just return if we are not in text mode */
1408 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
1410 if (CursorStart
< CursorEnd
)
1412 /* Visible cursor */
1413 CursorInfo
.bVisible
= TRUE
;
1414 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1419 CursorInfo
.bVisible
= FALSE
;
1420 CursorInfo
.dwSize
= 0;
1423 /* Add the cursor skew to the location */
1424 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
1426 /* Find the coordinates of the new position */
1427 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1428 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1430 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1432 /* Update the physical cursor */
1433 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1434 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1436 /* Reset the cursor move flag */
1437 CursorMoved
= FALSE
;
1440 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1442 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1447 return VgaMiscRegister
;
1449 case VGA_INSTAT0_READ
:
1450 return 0; // Not implemented
1452 case VGA_INSTAT1_READ_MONO
:
1453 case VGA_INSTAT1_READ_COLOR
:
1457 /* Reset the AC latch */
1460 /* Set a flag if there is a vertical or horizontal retrace */
1461 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1463 /* Set an additional flag if there was a vertical retrace */
1464 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1466 /* Clear the flags */
1467 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1472 case VGA_FEATURE_READ
:
1473 return VgaFeatureRegister
;
1479 return VgaAcRegisters
[VgaAcIndex
];
1485 return VgaSeqRegisters
[VgaSeqIndex
];
1490 case VGA_DAC_READ_INDEX
:
1491 /* This returns the read/write state */
1492 return (VgaDacReadWrite
? 0 : 3);
1494 case VGA_DAC_WRITE_INDEX
:
1495 return (VgaDacIndex
/ 3);
1499 /* Ignore reads in write mode */
1500 if (!VgaDacReadWrite
)
1502 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1503 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1510 case VGA_CRTC_INDEX_MONO
:
1511 case VGA_CRTC_INDEX_COLOR
:
1512 return VgaCrtcIndex
;
1514 case VGA_CRTC_DATA_MONO
:
1515 case VGA_CRTC_DATA_COLOR
:
1516 return VgaCrtcRegisters
[VgaCrtcIndex
];
1522 return VgaGcRegisters
[VgaGcIndex
];
1525 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1532 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1534 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1538 case VGA_MISC_WRITE
:
1540 VgaMiscRegister
= Data
;
1542 if (VgaMiscRegister
& 0x01)
1544 /* Color emulation */
1545 DPRINT1("Color emulation\n");
1547 /* Register the new I/O Ports */
1548 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1549 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1550 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1552 /* Unregister the old ones */
1553 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1554 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1555 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1559 /* Monochrome emulation */
1560 DPRINT1("Monochrome emulation\n");
1562 /* Register the new I/O Ports */
1563 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1564 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1565 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1567 /* Unregister the old ones */
1568 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1569 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1570 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1573 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1577 case VGA_FEATURE_WRITE_MONO
:
1578 case VGA_FEATURE_WRITE_COLOR
:
1580 VgaFeatureRegister
= Data
;
1585 // case VGA_AC_WRITE:
1589 /* Change the index */
1590 BYTE Index
= Data
& 0x1F;
1591 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1594 * Change palette protection by checking for
1595 * the Palette Address Source bit.
1597 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1601 /* Write the data */
1605 /* Toggle the latch */
1606 VgaAcLatch
= !VgaAcLatch
;
1612 /* Set the sequencer index register */
1613 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1619 /* Call the sequencer function */
1620 VgaWriteSequencer(Data
);
1630 case VGA_DAC_READ_INDEX
:
1632 VgaDacReadWrite
= FALSE
;
1633 VgaDacIndex
= Data
* 3;
1637 case VGA_DAC_WRITE_INDEX
:
1639 VgaDacReadWrite
= TRUE
;
1640 VgaDacIndex
= Data
* 3;
1646 /* Ignore writes in read mode */
1647 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1651 case VGA_CRTC_INDEX_MONO
:
1652 case VGA_CRTC_INDEX_COLOR
:
1654 /* Set the CRTC index register */
1655 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1659 case VGA_CRTC_DATA_MONO
:
1660 case VGA_CRTC_DATA_COLOR
:
1662 /* Call the CRTC function */
1669 /* Set the GC index register */
1670 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1676 /* Call the GC function */
1682 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1687 /* PUBLIC FUNCTIONS ***********************************************************/
1689 DWORD
VgaGetVideoBaseAddress(VOID
)
1691 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1694 DWORD
VgaGetVideoLimitAddress(VOID
)
1696 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1699 COORD
VgaGetDisplayResolution(VOID
)
1702 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1704 /* The low 8 bits are in the display registers */
1705 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1706 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1708 /* Set the top bits from the overflow register */
1709 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1711 Resolution
.Y
|= 1 << 8;
1713 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1715 Resolution
.Y
|= 1 << 9;
1718 /* Increase the values by 1 */
1722 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1724 /* Multiply the horizontal resolution by the 9/8 dot mode */
1725 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1728 /* The horizontal resolution is halved in 8-bit mode */
1729 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1732 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1734 /* Halve the vertical resolution */
1739 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1740 Resolution
.Y
/= MaximumScanLine
;
1743 /* Return the resolution */
1747 VOID
VgaRefreshDisplay(VOID
)
1749 HANDLE ConsoleBufferHandle
= NULL
;
1752 /* Set the vertical retrace flag */
1753 InVerticalRetrace
= TRUE
;
1755 /* If nothing has changed, just return */
1756 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1759 /* Change the display mode */
1760 if (ModeChanged
) VgaChangeMode();
1762 /* Change the text cursor location */
1763 if (CursorMoved
) VgaUpdateTextCursor();
1765 /* Retrieve the current resolution */
1766 Resolution
= VgaGetDisplayResolution();
1770 /* Trigger a full update of the screen */
1772 UpdateRectangle
.Left
= 0;
1773 UpdateRectangle
.Top
= 0;
1774 UpdateRectangle
.Right
= Resolution
.X
;
1775 UpdateRectangle
.Bottom
= Resolution
.Y
;
1777 PaletteChanged
= FALSE
;
1780 /* Update the contents of the framebuffer */
1781 VgaUpdateFramebuffer();
1783 /* Ignore if there's nothing to update */
1784 if (!NeedsUpdate
) return;
1786 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1787 UpdateRectangle
.Left
,
1788 UpdateRectangle
.Top
,
1789 UpdateRectangle
.Right
,
1790 UpdateRectangle
.Bottom
);
1792 /* Check if this is text mode or graphics mode */
1793 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1796 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1798 /* In DoubleVision mode, scale the update rectangle */
1801 UpdateRectangle
.Left
*= 2;
1802 UpdateRectangle
.Top
*= 2;
1803 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1804 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1810 ConsoleBufferHandle
= TextConsoleBuffer
;
1813 /* Redraw the screen */
1814 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1816 /* Clear the update flag */
1817 NeedsUpdate
= FALSE
;
1820 VOID
VgaHorizontalRetrace(VOID
)
1823 InHorizontalRetrace
= TRUE
;
1826 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1831 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1833 /* Ignore if video RAM access is disabled */
1834 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1836 /* Loop through each byte */
1837 for (i
= 0; i
< Size
; i
++)
1839 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1841 /* Load the latch registers */
1842 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1843 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1844 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1845 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1847 /* Copy the value to the buffer */
1848 Buffer
[i
] = VgaMemory
[VideoAddress
];
1852 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1857 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1859 /* Ignore if video RAM access is disabled */
1860 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1862 /* Also ignore if write access to all planes is disabled */
1863 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1865 /* Loop through each byte */
1866 for (i
= 0; i
< Size
; i
++)
1868 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1870 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1872 /* Make sure the page is writeable */
1873 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1875 /* Check if this is chain-4 mode */
1876 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1878 if (((Address
+ i
) & 3) != j
)
1880 /* This plane will not be accessed */
1885 /* Check if this is odd-even mode */
1886 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1888 if (((Address
+ i
) & 1) != (j
& 1))
1890 /* This plane will not be accessed */
1895 /* Copy the value to the VGA memory */
1896 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1901 VOID
VgaClearMemory(VOID
)
1903 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1906 VOID
VgaResetPalette(VOID
)
1908 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1910 /* Restore the default palette */
1911 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1912 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1913 PaletteChanged
= TRUE
;
1919 BOOL
VgaAttachToConsole(VOID
)
1922 // FIXME: We should go back to the saved screen state
1924 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
1925 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1927 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
1928 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
1930 return VgaAttachToConsoleInternal(&TextResolution
);
1933 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
1937 COORD dummySize
= {0};
1940 // FIXME: We should save the screen state
1943 __RegisterConsoleVDM(0,
1955 TextFramebuffer
= NULL
;
1961 /* Restore the old screen buffer */
1962 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1964 /* Restore the original console size */
1967 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
1968 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
1970 * See the following trick explanation in VgaAttachToConsoleInternal.
1972 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1973 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
1974 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1976 /* Restore the original cursor shape */
1977 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
1981 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1983 /* Save the default text-mode console output handle */
1984 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
1985 TextConsoleBuffer
= TextHandle
;
1987 /* Save the original cursor and console screen buffer information */
1988 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
1989 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
1993 ConsoleInfo
= OrgConsoleBufferInfo
;
1995 /* Initialize the VGA palette and fail if it isn't successfully created */
1996 if (!VgaInitializePalette()) return FALSE
;
1997 /***/ VgaResetPalette(); /***/
1999 /* Switch to the text buffer */
2000 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
2002 /* Clear the VGA memory */
2005 /* Register the I/O Ports */
2006 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2007 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2008 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2009 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2010 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2011 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2012 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2013 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2014 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2015 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2016 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2017 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2018 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2020 /* Return success */
2024 VOID
VgaCleanup(VOID
)
2026 if (ScreenMode
== GRAPHICS_MODE
)
2028 /* Leave the current graphics mode */
2029 VgaLeaveGraphicsMode();
2033 /* Leave the current text mode */
2037 VgaDetachFromConsole(FALSE
);
2039 CloseHandle(AnotherEvent
);
2040 CloseHandle(EndEvent
);
2041 CloseHandle(StartEvent
);
2044 RegisterConsoleVDM
= NULL
;
2045 FreeLibrary(hKernel32
);