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 * Console interface -- VGA-mode-agnostic
177 typedef struct _CHAR_CELL
181 } CHAR_CELL
, *PCHAR_CELL
;
182 C_ASSERT(sizeof(CHAR_CELL
) == 2);
184 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
185 // either TextFramebuffer or a valid
186 // graphics framebuffer.
187 static HPALETTE PaletteHandle
= NULL
;
189 static HANDLE StartEvent
= NULL
;
190 static HANDLE EndEvent
= NULL
;
191 static HANDLE AnotherEvent
= NULL
;
193 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
194 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
198 * Text mode -- we always keep a valid text mode framebuffer
199 * even if we are in graphics mode. This is needed in order to
200 * keep a consistent VGA state.
202 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
203 static COORD TextResolution
= {0};
204 static PCHAR_CELL TextFramebuffer
= NULL
;
205 static HANDLE TextConsoleBuffer
= NULL
;
208 static HANDLE GraphicsConsoleBuffer
= NULL
;
209 static HANDLE ConsoleMutex
= NULL
;
210 static BOOLEAN DoubleVision
= FALSE
;
215 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
217 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
219 static BYTE VgaMiscRegister
;
220 static BYTE VgaFeatureRegister
;
222 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
223 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
225 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
226 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
228 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
229 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
231 static BOOLEAN VgaAcLatch
= FALSE
;
232 static BOOLEAN VgaAcPalDisable
= TRUE
;
233 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
234 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
236 // static VGA_REGISTERS VgaRegisters;
238 static BYTE VgaDacMask
= 0xFF;
239 static WORD VgaDacIndex
= 0;
240 static BOOLEAN VgaDacReadWrite
= FALSE
;
241 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
243 static BOOLEAN InVerticalRetrace
= FALSE
;
244 static BOOLEAN InHorizontalRetrace
= FALSE
;
246 static BOOLEAN NeedsUpdate
= FALSE
;
247 static BOOLEAN ModeChanged
= FALSE
;
248 static BOOLEAN CursorMoved
= FALSE
;
249 static BOOLEAN PaletteChanged
= FALSE
;
256 } ScreenMode
= TEXT_MODE
;
258 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
260 /* RegisterConsoleVDM EMULATION ***********************************************/
262 #include <ntddvdeo.h>
266 (WINAPI
*pRegisterConsoleVDM
)
269 HANDLE EventHandle_1
,
270 HANDLE EventHandle_2
,
271 HANDLE EventHandle_3
,
273 PVOID returned_val_1
,
274 PVOID
*returned_val_2
,
275 PVOID lpUnknownBuffer
,
276 DWORD theUnknownBufferLength
,
277 COORD theVDMBufferSize
,
287 HANDLE EventHandle_1
,
288 HANDLE EventHandle_2
,
289 HANDLE EventHandle_3
,
291 PVOID returned_val_1
,
292 PVOID
*returned_val_2
,
293 PVOID lpUnknownBuffer
,
294 DWORD theUnknownBufferLength
,
295 COORD theVDMBufferSize
,
299 HMODULE hKernel32
= NULL
;
300 pRegisterConsoleVDM RegisterConsoleVDM
= NULL
;
304 * This private buffer, per-console, is used by
305 * RegisterConsoleVDM and InvalidateConsoleDIBits.
307 static COORD VDMBufferSize
= {0};
308 static PCHAR_CELL VDMBuffer
= NULL
;
310 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
311 // for the real RegisterConsoleVDM and
312 // InvalidateConsoleDIBits
316 __RegisterConsoleVDM(BOOL IsDosVDM_flag
,
317 HANDLE EventHandle_1
,
318 HANDLE EventHandle_2
,
319 HANDLE EventHandle_3
,
321 PVOID returned_val_1
,
322 PVOID
*returned_val_2
,
323 PVOID lpUnknownBuffer
,
324 DWORD theUnknownBufferLength
,
325 COORD theVDMBufferSize
,
328 UNREFERENCED_PARAMETER(EventHandle_3
);
329 UNREFERENCED_PARAMETER(Unused1
);
330 UNREFERENCED_PARAMETER(returned_val_1
);
331 UNREFERENCED_PARAMETER(returned_val_2
);
332 UNREFERENCED_PARAMETER(lpUnknownBuffer
);
333 UNREFERENCED_PARAMETER(theUnknownBufferLength
);
336 DPRINT1("__RegisterConsoleVDM(%d)\n", IsDosVDM_flag
);
338 if (lpVDMBuffer
== NULL
) return FALSE
;
342 // if (EventHandle_1 == NULL || EventHandle_2 == NULL) return FALSE;
343 if (VDMBuffer
!= NULL
) return FALSE
;
345 VDMBufferSize
= theVDMBufferSize
;
347 /* HACK: Cache -- to be removed in the real implementation */
348 CharBuff
= HeapAlloc(GetProcessHeap(),
350 theVDMBufferSize
.X
* theVDMBufferSize
.Y
351 * sizeof(CHAR_INFO
));
354 VDMBuffer
= HeapAlloc(GetProcessHeap(),
356 theVDMBufferSize
.X
* theVDMBufferSize
.Y
357 * sizeof(CHAR_CELL
));
358 *lpVDMBuffer
= (PCHAR
)VDMBuffer
;
359 return (VDMBuffer
!= NULL
);
363 /* HACK: Cache -- to be removed in the real implementation */
364 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
367 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
370 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
377 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
378 IN PSMALL_RECT lpRect
)
380 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
382 /* HACK: Write the cached data to the console */
384 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
389 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
391 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
393 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
394 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
398 WriteConsoleOutputA(hConsoleOutput
,
405 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
408 /* PRIVATE FUNCTIONS **********************************************************/
410 static inline DWORD
VgaGetAddressSize(VOID
);
411 static VOID
VgaUpdateTextCursor(VOID
);
413 static VOID
VgaUpdateCursorPosition(VOID
)
416 * Update the cursor position in the VGA registers.
418 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
419 ConsoleInfo
.dwCursorPosition
.X
;
421 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
422 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
424 VidBiosSyncCursorPosition();
425 VgaUpdateTextCursor();
428 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
432 PVIDEO_HARDWARE_STATE_HEADER State
;
435 DWORD AddressSize
, ScanlineSize
;
439 COORD Origin
= { 0, 0 };
441 ASSERT(TextFramebuffer
== NULL
);
443 TextResolution
= *Resolution
;
446 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
447 * in the two following APIs:
448 * SrvRegisterConsoleVDM (corresponding win32 API: RegisterConsoleVDM)
449 * SrvVDMConsoleOperation (corresponding Win32 API: )
450 * to check whether the current process is a VDM process, and fails otherwise with the
451 * error 0xC0000022 ().
453 * It is worth it to notice that also basesrv.dll does the same only for the
454 * BaseSrvIsFirstVDM API...
458 __RegisterConsoleVDM(1,
461 AnotherEvent
, // NULL,
463 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
464 (PVOID
*)&State
, // NULL,
468 (PCHAR
*)&TextFramebuffer
);
471 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
480 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
481 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
482 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
484 * Use this trick to effectively resize the console buffer and window,
486 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
487 * is smaller than the current console window size, and:
488 * - SetConsoleWindowInfo fails if the new console window size is larger
489 * than the current console screen buffer size.
491 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
492 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
493 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
494 /* Update the saved console information */
495 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
498 * Copy console data into VGA memory
502 AddressSize
= VgaGetAddressSize();
503 ConRect
.Left
= ConRect
.Top
= 0;
504 ConRect
.Right
= TextResolution
.X
;
505 ConRect
.Bottom
= TextResolution
.Y
;
506 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
508 /* Read the data from the console into the framebuffer... */
509 ReadConsoleOutputA(TextConsoleBuffer
,
515 /* ... and copy the framebuffer into the VGA memory */
517 /* Loop through the scanlines */
518 for (i
= 0; i
< TextResolution
.Y
; i
++)
520 /* Loop through the characters */
521 for (j
= 0; j
< TextResolution
.X
; j
++)
523 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
525 /* Store the character in plane 0 */
526 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
528 /* Store the attribute in plane 1 */
529 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
532 /* Move to the next scanline */
533 Address
+= ScanlineSize
;
536 VgaUpdateCursorPosition();
541 BOOL
VgaAttachToConsole(VOID
)
543 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
544 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
546 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
547 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
549 return VgaAttachToConsoleInternal(&TextResolution
);
552 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
556 COORD dummySize
= {0};
558 __RegisterConsoleVDM(0,
570 TextFramebuffer
= NULL
;
576 /* Restore the old screen buffer */
577 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
579 /* Restore the original console size */
582 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
583 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
585 * See the following trick explanation in VgaAttachToConsoleInternal.
587 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
588 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
589 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
591 /* Restore the original cursor shape */
592 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
596 static BOOL
IsConsoleHandle(HANDLE hHandle
)
600 /* Check whether the handle may be that of a console... */
601 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
605 * It may be. Perform another test... The idea comes from the
606 * MSDN description of the WriteConsole API:
608 * "WriteConsole fails if it is used with a standard handle
609 * that is redirected to a file. If an application processes
610 * multilingual output that can be redirected, determine whether
611 * the output handle is a console handle (one method is to call
612 * the GetConsoleMode function and check whether it succeeds).
613 * If the handle is a console handle, call WriteConsole. If the
614 * handle is not a console handle, the output is redirected and
615 * you should call WriteFile to perform the I/O."
617 return GetConsoleMode(hHandle
, &dwMode
);
620 static inline DWORD
VgaGetAddressSize(VOID
)
622 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
624 /* Double-word addressing */
625 return 4; // sizeof(DWORD)
627 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
629 /* Byte addressing */
630 return 1; // sizeof(BYTE)
634 /* Word addressing */
635 return 2; // sizeof(WORD)
639 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
641 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
644 /* Check for chain-4 and odd-even mode */
645 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
647 /* The lowest two bits are the plane number */
651 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
653 /* The LSB is the plane number */
659 /* Use the read mode */
660 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
663 /* Multiply the offset by the address size */
664 Offset
*= VgaGetAddressSize();
666 return Offset
+ Plane
* VGA_BANK_SIZE
;
669 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
671 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
673 /* Check for chain-4 and odd-even mode */
674 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
676 /* Shift the offset to the right by 2 */
679 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
681 /* Shift the offset to the right by 1 */
685 /* Multiply the offset by the address size */
686 Offset
*= VgaGetAddressSize();
688 /* Return the offset on plane 0 */
692 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
694 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
695 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
699 /* In write mode 1 just return the latch register */
700 return VgaLatchRegisters
[Plane
];
705 /* Write modes 0 and 3 rotate the data to the right first */
706 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
707 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
711 /* Write mode 2 expands the appropriate bit to all 8 bits */
712 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
718 * In write mode 0, the enable set/reset register decides if the
719 * set/reset bit should be expanded to all 8 bits.
721 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
723 /* Copy the bit from the set/reset register to all 8 bits */
724 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
730 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
731 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
733 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
734 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
735 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
739 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
742 /* Then we expand the bit in the set/reset field */
743 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
746 /* Bits cleared in the bitmask are replaced with latch register bits */
747 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
749 /* Return the byte */
753 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
755 /* Check if this is the first time the rectangle is updated */
758 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
759 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
762 /* Expand the rectangle to include the point */
763 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
764 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
765 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
766 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
768 /* Set the update request flag */
772 static VOID
VgaWriteSequencer(BYTE Data
)
774 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
777 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
780 static VOID
VgaWriteGc(BYTE Data
)
782 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
785 VgaGcRegisters
[VgaGcIndex
] = Data
;
787 /* Check the index */
790 case VGA_GC_MISC_REG
:
792 /* The GC misc register decides if it's text or graphics mode */
799 static VOID
VgaWriteCrtc(BYTE Data
)
801 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
804 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
806 /* Check the index */
807 switch (VgaCrtcIndex
)
809 case VGA_CRTC_END_HORZ_DISP_REG
:
810 case VGA_CRTC_VERT_DISP_END_REG
:
811 case VGA_CRTC_OVERFLOW_REG
:
813 /* The video mode has changed */
818 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
819 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
820 case VGA_CRTC_CURSOR_START_REG
:
821 case VGA_CRTC_CURSOR_END_REG
:
823 /* Set the cursor moved flag */
830 static VOID
VgaWriteDac(BYTE Data
)
836 VgaDacRegisters
[VgaDacIndex
] = Data
;
838 /* Find the palette index */
839 PaletteIndex
= VgaDacIndex
/ 3;
841 /* Fill the entry structure */
842 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
843 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
844 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
847 /* Update the palette entry and set the palette change flag */
848 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
849 PaletteChanged
= TRUE
;
851 /* Update the index */
853 VgaDacIndex
%= VGA_PALETTE_SIZE
;
856 static VOID
VgaWriteAc(BYTE Data
)
858 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
861 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
863 if (VgaAcPalDisable
) return;
865 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
866 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
868 /* Update the AC register and set the palette change flag */
869 VgaAcRegisters
[VgaAcIndex
] = Data
;
870 PaletteChanged
= TRUE
;
875 VgaAcRegisters
[VgaAcIndex
] = Data
;
879 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
883 /* Copy the colors of the default palette to the DAC and console palette */
884 for (i
= 0; i
< NumOfEntries
; i
++)
886 /* Set the palette entries */
887 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
888 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
889 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
890 Entries
[i
].peFlags
= 0;
892 /* Set the DAC registers */
893 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
894 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
895 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
899 static BOOLEAN
VgaInitializePalette(VOID
)
901 LPLOGPALETTE Palette
;
903 /* Allocate storage space for the palette */
904 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
907 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
908 if (Palette
== NULL
) return FALSE
;
910 /* Initialize the palette */
911 Palette
->palVersion
= 0x0300;
912 Palette
->palNumEntries
= VGA_MAX_COLORS
;
914 /* Restore the default palette */
915 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
917 /* Create the palette */
918 PaletteHandle
= CreatePalette(Palette
);
920 /* Free the palette */
921 HeapFree(GetProcessHeap(), 0, Palette
);
923 /* Fail if the palette wasn't successfully created... */
924 if (PaletteHandle
== NULL
) return FALSE
;
926 /* ... otherwise return success */
930 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
933 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
934 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
935 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
936 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
938 LONG Width
= Resolution
->X
;
939 LONG Height
= Resolution
->Y
;
941 /* Use DoubleVision mode if the resolution is too small */
942 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
950 DoubleVision
= FALSE
;
953 /* Fill the bitmap info header */
954 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
955 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
956 BitmapInfo
->bmiHeader
.biWidth
= Width
;
957 BitmapInfo
->bmiHeader
.biHeight
= Height
;
958 BitmapInfo
->bmiHeader
.biBitCount
= 8;
959 BitmapInfo
->bmiHeader
.biPlanes
= 1;
960 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
961 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
963 /* Fill the palette data */
964 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
966 /* Fill the console graphics buffer info */
967 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
968 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
969 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
971 /* Create the buffer */
972 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
973 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
975 CONSOLE_GRAPHICS_BUFFER
,
976 &GraphicsBufferInfo
);
977 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
979 /* Save the framebuffer address and mutex */
980 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
981 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
983 /* Clear the framebuffer */
984 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
986 /* Set the active buffer */
987 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
989 /* Set the graphics mode palette */
990 SetConsolePalette(GraphicsConsoleBuffer
,
994 /* Set the screen mode flag */
995 ScreenMode
= GRAPHICS_MODE
;
1000 static VOID
VgaLeaveGraphicsMode(VOID
)
1002 /* Release the console framebuffer mutex */
1003 ReleaseMutex(ConsoleMutex
);
1005 /* Switch back to the default console text buffer */
1006 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1008 /* Cleanup the video data */
1009 CloseHandle(ConsoleMutex
);
1010 ConsoleMutex
= NULL
;
1011 ConsoleFramebuffer
= NULL
;
1012 CloseHandle(GraphicsConsoleBuffer
);
1013 GraphicsConsoleBuffer
= NULL
;
1014 DoubleVision
= FALSE
;
1017 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1019 DPRINT1("VgaEnterTextMode\n");
1021 /* Switch to the text buffer */
1022 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1024 /* Adjust the text framebuffer if we changed the resolution */
1025 if (TextResolution
.X
!= Resolution
->X
||
1026 TextResolution
.Y
!= Resolution
->Y
)
1028 VgaDetachFromConsole(TRUE
);
1031 * VgaAttachToConsoleInternal sets TextResolution to the
1032 * new resolution and updates ConsoleInfo.
1034 if (!VgaAttachToConsoleInternal(Resolution
))
1036 DisplayMessage(L
"An unexpected error occurred!\n");
1037 EmulatorTerminate();
1041 else VgaUpdateCursorPosition();
1043 /* The active framebuffer is now the text framebuffer */
1044 ConsoleFramebuffer
= TextFramebuffer
;
1047 * Set the text mode palette.
1049 * WARNING: This call should fail on Windows (and therefore
1050 * we get the default palette and our external behaviour is
1051 * just like Windows' one), but it should success on ReactOS
1052 * (so that we get console palette changes even for text-mode
1053 * screen-buffers, which is a new feature on ReactOS).
1055 SetConsolePalette(TextConsoleBuffer
,
1057 SYSPAL_NOSTATIC256
);
1059 /* Set the screen mode flag */
1060 ScreenMode
= TEXT_MODE
;
1065 static VOID
VgaLeaveTextMode(VOID
)
1067 /* Reset the active framebuffer */
1068 ConsoleFramebuffer
= NULL
;
1071 static VOID
VgaChangeMode(VOID
)
1073 COORD Resolution
= VgaGetDisplayResolution();
1075 if (ScreenMode
== GRAPHICS_MODE
)
1077 /* Leave the current graphics mode */
1078 VgaLeaveGraphicsMode();
1082 /* Leave the current text mode */
1086 /* Check if the new mode is alphanumeric */
1087 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
1089 /* Enter new text mode */
1090 if (!VgaEnterTextMode(&Resolution
))
1092 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
1093 EmulatorTerminate();
1099 /* Enter graphics mode */
1100 if (!VgaEnterGraphicsMode(&Resolution
))
1102 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
1103 EmulatorTerminate();
1108 /* Trigger a full update of the screen */
1110 UpdateRectangle
.Left
= 0;
1111 UpdateRectangle
.Top
= 0;
1112 UpdateRectangle
.Right
= Resolution
.X
;
1113 UpdateRectangle
.Bottom
= Resolution
.Y
;
1115 /* Reset the mode change flag */
1116 ModeChanged
= FALSE
;
1119 static VOID
VgaUpdateFramebuffer(VOID
)
1122 COORD Resolution
= VgaGetDisplayResolution();
1123 DWORD AddressSize
= VgaGetAddressSize();
1124 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1125 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1126 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1129 * If console framebuffer is NULL, that means something went wrong
1130 * earlier and this is the final display refresh.
1132 if (ConsoleFramebuffer
== NULL
) return;
1134 /* Check if this is text mode or graphics mode */
1135 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1138 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1141 * Synchronize access to the graphics framebuffer
1142 * with the console framebuffer mutex.
1144 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1146 /* Loop through the scanlines */
1147 for (i
= 0; i
< Resolution
.Y
; i
++)
1149 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1151 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1153 /* Shift the high bit right by 1 in odd/even mode */
1154 InterlaceHighBit
>>= 1;
1157 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1159 /* Odd-numbered line in interlaced mode - set the high bit */
1160 Address
|= InterlaceHighBit
;
1163 /* Loop through the pixels */
1164 for (j
= 0; j
< Resolution
.X
; j
++)
1168 /* Check the shifting mode */
1169 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1171 /* 4 bits shifted from each plane */
1173 /* Check if this is 16 or 256 color mode */
1174 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1176 /* One byte per pixel */
1177 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1178 + (Address
+ (j
/ VGA_NUM_BANKS
))
1183 /* 4-bits per pixel */
1185 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1186 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1189 /* Check if we should use the highest 4 bits or lowest 4 */
1190 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1202 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1204 /* Check if this is 16 or 256 color mode */
1205 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1207 // TODO: NOT IMPLEMENTED
1208 DPRINT1("8-bit interleaved mode is not implemented!\n");
1213 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1214 * then 2 bits shifted from plane 1 and 3 for the next 4
1216 DWORD BankNumber
= (j
/ 4) % 2;
1217 DWORD Offset
= Address
+ (j
/ 8);
1218 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ Offset
* AddressSize
];
1219 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ Offset
* AddressSize
];
1221 /* Extract the two bits from each plane */
1222 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1223 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1225 /* Combine them into the pixel */
1226 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1231 /* 1 bit shifted from each plane */
1233 /* Check if this is 16 or 256 color mode */
1234 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1236 /* 8 bits per pixel, 2 on each plane */
1238 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1240 /* The data is on plane k, 4 pixels per byte */
1241 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1242 + (Address
+ (j
/ VGA_NUM_BANKS
))
1245 /* The mask of the first bit in the pair */
1246 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1248 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1249 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1251 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1252 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1257 /* 4 bits per pixel, 1 on each plane */
1259 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1261 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1262 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1265 /* If the bit on that plane is set, set it */
1266 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1271 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1274 * In 16 color mode, the value is an index to the AC registers
1275 * if external palette access is disabled, otherwise (in case
1276 * of palette loading) it is a blank pixel.
1278 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1282 /* Take into account DoubleVision mode when checking for pixel updates */
1285 /* Now check if the resulting pixel data has changed */
1286 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
1288 /* Yes, write the new value */
1289 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
1290 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
1291 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
1292 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1294 /* Mark the specified pixel as changed */
1295 VgaMarkForUpdate(i
, j
);
1300 /* Now check if the resulting pixel data has changed */
1301 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
1303 /* Yes, write the new value */
1304 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
1306 /* Mark the specified pixel as changed */
1307 VgaMarkForUpdate(i
, j
);
1312 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
&& (i
& 1))
1314 /* Clear the high bit */
1315 Address
&= ~InterlaceHighBit
;
1318 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1320 /* Move to the next scanline */
1321 Address
+= ScanlineSize
;
1326 * Release the console framebuffer mutex
1327 * so that we allow for repainting.
1329 ReleaseMutex(ConsoleMutex
);
1335 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1338 /* Loop through the scanlines */
1339 for (i
= 0; i
< Resolution
.Y
; i
++)
1341 /* Loop through the characters */
1342 for (j
= 0; j
< Resolution
.X
; j
++)
1344 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1346 /* Plane 0 holds the character itself */
1347 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1349 /* Plane 1 holds the attribute */
1350 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1352 /* Now check if the resulting character data has changed */
1353 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1354 (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1356 /* Yes, write the new value */
1357 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
1359 /* Mark the specified cell as changed */
1360 VgaMarkForUpdate(i
, j
);
1364 /* Move to the next scanline */
1365 Address
+= ScanlineSize
;
1370 static VOID
VgaUpdateTextCursor(VOID
)
1373 CONSOLE_CURSOR_INFO CursorInfo
;
1374 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
1375 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1376 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1377 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1378 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1379 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1381 /* Just return if we are not in text mode */
1382 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
1384 if (CursorStart
< CursorEnd
)
1386 /* Visible cursor */
1387 CursorInfo
.bVisible
= TRUE
;
1388 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1393 CursorInfo
.bVisible
= FALSE
;
1394 CursorInfo
.dwSize
= 0;
1397 /* Add the cursor skew to the location */
1398 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
1400 /* Find the coordinates of the new position */
1401 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1402 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1404 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1406 /* Update the physical cursor */
1407 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1408 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1410 /* Reset the cursor move flag */
1411 CursorMoved
= FALSE
;
1414 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1416 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1421 return VgaMiscRegister
;
1423 case VGA_INSTAT0_READ
:
1424 return 0; // Not implemented
1426 case VGA_INSTAT1_READ_MONO
:
1427 case VGA_INSTAT1_READ_COLOR
:
1431 /* Reset the AC latch */
1434 /* Set a flag if there is a vertical or horizontal retrace */
1435 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1437 /* Set an additional flag if there was a vertical retrace */
1438 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1440 /* Clear the flags */
1441 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1446 case VGA_FEATURE_READ
:
1447 return VgaFeatureRegister
;
1453 return VgaAcRegisters
[VgaAcIndex
];
1459 return VgaSeqRegisters
[VgaSeqIndex
];
1464 case VGA_DAC_READ_INDEX
:
1465 /* This returns the read/write state */
1466 return (VgaDacReadWrite
? 0 : 3);
1468 case VGA_DAC_WRITE_INDEX
:
1469 return (VgaDacIndex
/ 3);
1473 /* Ignore reads in write mode */
1474 if (!VgaDacReadWrite
)
1476 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1477 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1484 case VGA_CRTC_INDEX_MONO
:
1485 case VGA_CRTC_INDEX_COLOR
:
1486 return VgaCrtcIndex
;
1488 case VGA_CRTC_DATA_MONO
:
1489 case VGA_CRTC_DATA_COLOR
:
1490 return VgaCrtcRegisters
[VgaCrtcIndex
];
1496 return VgaGcRegisters
[VgaGcIndex
];
1499 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1506 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1508 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1512 case VGA_MISC_WRITE
:
1514 VgaMiscRegister
= Data
;
1516 if (VgaMiscRegister
& 0x01)
1518 /* Color emulation */
1519 DPRINT1("Color emulation\n");
1521 /* Register the new I/O Ports */
1522 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1523 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1524 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1526 /* Unregister the old ones */
1527 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1528 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1529 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1533 /* Monochrome emulation */
1534 DPRINT1("Monochrome emulation\n");
1536 /* Register the new I/O Ports */
1537 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1538 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1539 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1541 /* Unregister the old ones */
1542 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1543 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1544 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1547 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1551 case VGA_FEATURE_WRITE_MONO
:
1552 case VGA_FEATURE_WRITE_COLOR
:
1554 VgaFeatureRegister
= Data
;
1559 // case VGA_AC_WRITE:
1563 /* Change the index */
1564 BYTE Index
= Data
& 0x1F;
1565 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1568 * Change palette protection by checking for
1569 * the Palette Address Source bit.
1571 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1575 /* Write the data */
1579 /* Toggle the latch */
1580 VgaAcLatch
= !VgaAcLatch
;
1586 /* Set the sequencer index register */
1587 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1593 /* Call the sequencer function */
1594 VgaWriteSequencer(Data
);
1604 case VGA_DAC_READ_INDEX
:
1606 VgaDacReadWrite
= FALSE
;
1607 VgaDacIndex
= Data
* 3;
1611 case VGA_DAC_WRITE_INDEX
:
1613 VgaDacReadWrite
= TRUE
;
1614 VgaDacIndex
= Data
* 3;
1620 /* Ignore writes in read mode */
1621 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1625 case VGA_CRTC_INDEX_MONO
:
1626 case VGA_CRTC_INDEX_COLOR
:
1628 /* Set the CRTC index register */
1629 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1633 case VGA_CRTC_DATA_MONO
:
1634 case VGA_CRTC_DATA_COLOR
:
1636 /* Call the CRTC function */
1643 /* Set the GC index register */
1644 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1650 /* Call the GC function */
1656 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1661 /* PUBLIC FUNCTIONS ***********************************************************/
1663 DWORD
VgaGetVideoBaseAddress(VOID
)
1665 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1668 DWORD
VgaGetVideoLimitAddress(VOID
)
1670 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1673 COORD
VgaGetDisplayResolution(VOID
)
1676 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1678 /* The low 8 bits are in the display registers */
1679 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1680 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1682 /* Set the top bits from the overflow register */
1683 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1685 Resolution
.Y
|= 1 << 8;
1687 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1689 Resolution
.Y
|= 1 << 9;
1692 /* Increase the values by 1 */
1696 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1698 /* Multiply the horizontal resolution by the 9/8 dot mode */
1699 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1702 /* The horizontal resolution is halved in 8-bit mode */
1703 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1706 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1708 /* Halve the vertical resolution */
1713 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1714 Resolution
.Y
/= MaximumScanLine
;
1717 /* Return the resolution */
1721 VOID
VgaRefreshDisplay(VOID
)
1723 HANDLE ConsoleBufferHandle
= NULL
;
1726 /* Set the vertical retrace flag */
1727 InVerticalRetrace
= TRUE
;
1729 /* If nothing has changed, just return */
1730 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1733 /* Change the display mode */
1734 if (ModeChanged
) VgaChangeMode();
1736 /* Change the text cursor location */
1737 if (CursorMoved
) VgaUpdateTextCursor();
1739 /* Retrieve the current resolution */
1740 Resolution
= VgaGetDisplayResolution();
1744 /* Trigger a full update of the screen */
1746 UpdateRectangle
.Left
= 0;
1747 UpdateRectangle
.Top
= 0;
1748 UpdateRectangle
.Right
= Resolution
.X
;
1749 UpdateRectangle
.Bottom
= Resolution
.Y
;
1751 PaletteChanged
= FALSE
;
1754 /* Update the contents of the framebuffer */
1755 VgaUpdateFramebuffer();
1757 /* Ignore if there's nothing to update */
1758 if (!NeedsUpdate
) return;
1760 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1761 UpdateRectangle
.Left
,
1762 UpdateRectangle
.Top
,
1763 UpdateRectangle
.Right
,
1764 UpdateRectangle
.Bottom
);
1766 /* Check if this is text mode or graphics mode */
1767 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1770 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1772 /* In DoubleVision mode, scale the update rectangle */
1775 UpdateRectangle
.Left
*= 2;
1776 UpdateRectangle
.Top
*= 2;
1777 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1778 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1784 ConsoleBufferHandle
= TextConsoleBuffer
;
1787 /* Redraw the screen */
1788 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1790 /* Clear the update flag */
1791 NeedsUpdate
= FALSE
;
1794 VOID
VgaHorizontalRetrace(VOID
)
1797 InHorizontalRetrace
= TRUE
;
1800 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1805 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1807 /* Ignore if video RAM access is disabled */
1808 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1810 /* Loop through each byte */
1811 for (i
= 0; i
< Size
; i
++)
1813 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1815 /* Load the latch registers */
1816 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1817 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1818 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1819 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1821 /* Copy the value to the buffer */
1822 Buffer
[i
] = VgaMemory
[VideoAddress
];
1826 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1831 DPRINT("VgaWriteMemory: 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 /* Also ignore if write access to all planes is disabled */
1837 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1839 /* Loop through each byte */
1840 for (i
= 0; i
< Size
; i
++)
1842 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1844 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1846 /* Make sure the page is writeable */
1847 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1849 /* Check if this is chain-4 mode */
1850 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1852 if (((Address
+ i
) & 3) != j
)
1854 /* This plane will not be accessed */
1859 /* Check if this is odd-even mode */
1860 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1862 if (((Address
+ i
) & 1) != (j
& 1))
1864 /* This plane will not be accessed */
1869 /* Copy the value to the VGA memory */
1870 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1875 VOID
VgaClearMemory(VOID
)
1877 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1880 VOID
VgaResetPalette(VOID
)
1882 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1884 /* Restore the default palette */
1885 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1886 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1887 PaletteChanged
= TRUE
;
1890 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1892 /* Save the default text-mode console output handle */
1893 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
1894 TextConsoleBuffer
= TextHandle
;
1896 /* Save the original cursor and console screen buffer information */
1897 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
1898 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
1902 ConsoleInfo
= OrgConsoleBufferInfo
;
1904 /* Initialize the VGA palette and fail if it isn't successfully created */
1905 if (!VgaInitializePalette()) return FALSE
;
1906 /***/ VgaResetPalette(); /***/
1908 /* Switch to the text buffer */
1909 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1911 /* Clear the VGA memory */
1914 /* Register the I/O Ports */
1915 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1916 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1917 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1918 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1919 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1920 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1921 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1922 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1923 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1924 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1925 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1926 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1927 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1929 /* Return success */
1933 VOID
VgaCleanup(VOID
)
1935 if (ScreenMode
== GRAPHICS_MODE
)
1937 /* Leave the current graphics mode */
1938 VgaLeaveGraphicsMode();
1942 /* Leave the current text mode */
1946 VgaDetachFromConsole(FALSE
);
1948 CloseHandle(AnotherEvent
);
1949 CloseHandle(EndEvent
);
1950 CloseHandle(StartEvent
);
1953 RegisterConsoleVDM
= NULL
;
1954 FreeLibrary(hKernel32
);