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 static BOOL
IsConsoleHandle(HANDLE hHandle
)
545 /* Check whether the handle may be that of a console... */
546 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
550 * It may be. Perform another test... The idea comes from the
551 * MSDN description of the WriteConsole API:
553 * "WriteConsole fails if it is used with a standard handle
554 * that is redirected to a file. If an application processes
555 * multilingual output that can be redirected, determine whether
556 * the output handle is a console handle (one method is to call
557 * the GetConsoleMode function and check whether it succeeds).
558 * If the handle is a console handle, call WriteConsole. If the
559 * handle is not a console handle, the output is redirected and
560 * you should call WriteFile to perform the I/O."
562 return GetConsoleMode(hHandle
, &dwMode
);
565 static inline DWORD
VgaGetAddressSize(VOID
)
567 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
569 /* Double-word addressing */
570 return 4; // sizeof(DWORD)
572 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
574 /* Byte addressing */
575 return 1; // sizeof(BYTE)
579 /* Word addressing */
580 return 2; // sizeof(WORD)
584 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
586 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
589 /* Check for chain-4 and odd-even mode */
590 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
592 /* The lowest two bits are the plane number */
596 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
598 /* The LSB is the plane number */
604 /* Use the read mode */
605 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
608 /* Multiply the offset by the address size */
609 Offset
*= VgaGetAddressSize();
611 return Offset
+ Plane
* VGA_BANK_SIZE
;
614 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
616 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
618 /* Check for chain-4 and odd-even mode */
619 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
621 /* Shift the offset to the right by 2 */
624 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
626 /* Shift the offset to the right by 1 */
630 /* Multiply the offset by the address size */
631 Offset
*= VgaGetAddressSize();
633 /* Return the offset on plane 0 */
637 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
639 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
640 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
644 /* In write mode 1 just return the latch register */
645 return VgaLatchRegisters
[Plane
];
650 /* Write modes 0 and 3 rotate the data to the right first */
651 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
652 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
656 /* Write mode 2 expands the appropriate bit to all 8 bits */
657 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
663 * In write mode 0, the enable set/reset register decides if the
664 * set/reset bit should be expanded to all 8 bits.
666 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
668 /* Copy the bit from the set/reset register to all 8 bits */
669 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
675 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
676 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
678 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
679 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
680 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
684 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
687 /* Then we expand the bit in the set/reset field */
688 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
691 /* Bits cleared in the bitmask are replaced with latch register bits */
692 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
694 /* Return the byte */
698 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
700 /* Check if this is the first time the rectangle is updated */
703 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
704 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
707 /* Expand the rectangle to include the point */
708 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
709 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
710 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
711 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
713 /* Set the update request flag */
717 static VOID
VgaWriteSequencer(BYTE Data
)
719 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
722 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
725 static VOID
VgaWriteGc(BYTE Data
)
727 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
730 VgaGcRegisters
[VgaGcIndex
] = Data
;
732 /* Check the index */
735 case VGA_GC_MISC_REG
:
737 /* The GC misc register decides if it's text or graphics mode */
744 static VOID
VgaWriteCrtc(BYTE Data
)
746 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
749 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
751 /* Check the index */
752 switch (VgaCrtcIndex
)
754 case VGA_CRTC_END_HORZ_DISP_REG
:
755 case VGA_CRTC_VERT_DISP_END_REG
:
756 case VGA_CRTC_OVERFLOW_REG
:
758 /* The video mode has changed */
763 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
764 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
765 case VGA_CRTC_CURSOR_START_REG
:
766 case VGA_CRTC_CURSOR_END_REG
:
768 /* Set the cursor moved flag */
775 static VOID
VgaWriteDac(BYTE Data
)
781 VgaDacRegisters
[VgaDacIndex
] = Data
;
783 /* Find the palette index */
784 PaletteIndex
= VgaDacIndex
/ 3;
786 /* Fill the entry structure */
787 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
788 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
789 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
792 /* Update the palette entry and set the palette change flag */
793 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
794 PaletteChanged
= TRUE
;
796 /* Update the index */
798 VgaDacIndex
%= VGA_PALETTE_SIZE
;
801 static VOID
VgaWriteAc(BYTE Data
)
803 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
806 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
808 if (VgaAcPalDisable
) return;
810 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
811 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
813 /* Update the AC register and set the palette change flag */
814 VgaAcRegisters
[VgaAcIndex
] = Data
;
815 PaletteChanged
= TRUE
;
820 VgaAcRegisters
[VgaAcIndex
] = Data
;
824 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
828 /* Copy the colors of the default palette to the DAC and console palette */
829 for (i
= 0; i
< NumOfEntries
; i
++)
831 /* Set the palette entries */
832 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
833 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
834 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
835 Entries
[i
].peFlags
= 0;
837 /* Set the DAC registers */
838 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
839 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
840 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
844 static BOOLEAN
VgaInitializePalette(VOID
)
846 LPLOGPALETTE Palette
;
848 /* Allocate storage space for the palette */
849 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
852 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
853 if (Palette
== NULL
) return FALSE
;
855 /* Initialize the palette */
856 Palette
->palVersion
= 0x0300;
857 Palette
->palNumEntries
= VGA_MAX_COLORS
;
859 /* Restore the default palette */
860 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
862 /* Create the palette */
863 PaletteHandle
= CreatePalette(Palette
);
865 /* Free the palette */
866 HeapFree(GetProcessHeap(), 0, Palette
);
868 /* Fail if the palette wasn't successfully created... */
869 if (PaletteHandle
== NULL
) return FALSE
;
871 /* ... otherwise return success */
875 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
878 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
879 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
880 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
881 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
883 LONG Width
= Resolution
->X
;
884 LONG Height
= Resolution
->Y
;
886 /* Use DoubleVision mode if the resolution is too small */
887 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
895 DoubleVision
= FALSE
;
898 /* Fill the bitmap info header */
899 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
900 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
901 BitmapInfo
->bmiHeader
.biWidth
= Width
;
902 BitmapInfo
->bmiHeader
.biHeight
= Height
;
903 BitmapInfo
->bmiHeader
.biBitCount
= 8;
904 BitmapInfo
->bmiHeader
.biPlanes
= 1;
905 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
906 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
908 /* Fill the palette data */
909 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
911 /* Fill the console graphics buffer info */
912 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
913 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
914 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
916 /* Create the buffer */
917 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
918 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
920 CONSOLE_GRAPHICS_BUFFER
,
921 &GraphicsBufferInfo
);
922 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
924 /* Save the framebuffer address and mutex */
925 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
926 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
928 /* Clear the framebuffer */
929 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
931 /* Set the active buffer */
932 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
934 /* Set the graphics mode palette */
935 SetConsolePalette(GraphicsConsoleBuffer
,
939 /* Set the screen mode flag */
940 ScreenMode
= GRAPHICS_MODE
;
945 static VOID
VgaLeaveGraphicsMode(VOID
)
947 /* Release the console framebuffer mutex */
948 ReleaseMutex(ConsoleMutex
);
950 /* Switch back to the default console text buffer */
951 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
953 /* Cleanup the video data */
954 CloseHandle(ConsoleMutex
);
956 ConsoleFramebuffer
= NULL
;
957 CloseHandle(GraphicsConsoleBuffer
);
958 GraphicsConsoleBuffer
= NULL
;
959 DoubleVision
= FALSE
;
962 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
964 DPRINT1("VgaEnterTextMode\n");
966 /* Switch to the text buffer */
967 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
969 /* Adjust the text framebuffer if we changed the resolution */
970 if (TextResolution
.X
!= Resolution
->X
||
971 TextResolution
.Y
!= Resolution
->Y
)
973 VgaDetachFromConsole(TRUE
);
976 * VgaAttachToConsoleInternal sets TextResolution to the
977 * new resolution and updates ConsoleInfo.
979 if (!VgaAttachToConsoleInternal(Resolution
))
981 DisplayMessage(L
"An unexpected error occurred!\n");
988 VgaUpdateCursorPosition();
991 /* The active framebuffer is now the text framebuffer */
992 ConsoleFramebuffer
= TextFramebuffer
;
995 * Set the text mode palette.
997 * WARNING: This call should fail on Windows (and therefore
998 * we get the default palette and our external behaviour is
999 * just like Windows' one), but it should success on ReactOS
1000 * (so that we get console palette changes even for text-mode
1001 * screen-buffers, which is a new feature on ReactOS).
1003 SetConsolePalette(TextConsoleBuffer
,
1005 SYSPAL_NOSTATIC256
);
1007 /* Set the screen mode flag */
1008 ScreenMode
= TEXT_MODE
;
1013 static VOID
VgaLeaveTextMode(VOID
)
1015 /* Reset the active framebuffer */
1016 ConsoleFramebuffer
= NULL
;
1019 static VOID
VgaChangeMode(VOID
)
1021 COORD Resolution
= VgaGetDisplayResolution();
1023 if (ScreenMode
== GRAPHICS_MODE
)
1025 /* Leave the current graphics mode */
1026 VgaLeaveGraphicsMode();
1030 /* Leave the current text mode */
1034 /* Check if the new mode is alphanumeric */
1035 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
1037 /* Enter new text mode */
1038 if (!VgaEnterTextMode(&Resolution
))
1040 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
1041 EmulatorTerminate();
1047 /* Enter graphics mode */
1048 if (!VgaEnterGraphicsMode(&Resolution
))
1050 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
1051 EmulatorTerminate();
1056 /* Trigger a full update of the screen */
1058 UpdateRectangle
.Left
= 0;
1059 UpdateRectangle
.Top
= 0;
1060 UpdateRectangle
.Right
= Resolution
.X
;
1061 UpdateRectangle
.Bottom
= Resolution
.Y
;
1063 /* Reset the mode change flag */
1064 ModeChanged
= FALSE
;
1067 static VOID
VgaUpdateFramebuffer(VOID
)
1070 COORD Resolution
= VgaGetDisplayResolution();
1071 DWORD AddressSize
= VgaGetAddressSize();
1072 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1073 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1074 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1077 * If console framebuffer is NULL, that means something went wrong
1078 * earlier and this is the final display refresh.
1080 if (ConsoleFramebuffer
== NULL
) return;
1082 /* Check if this is text mode or graphics mode */
1083 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1086 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1087 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1090 * Synchronize access to the graphics framebuffer
1091 * with the console framebuffer mutex.
1093 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1095 /* Shift the high bit right by 1 in odd/even mode */
1096 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1098 InterlaceHighBit
>>= 1;
1101 /* Loop through the scanlines */
1102 for (i
= 0; i
< Resolution
.Y
; i
++)
1104 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1106 /* Odd-numbered line in interlaced mode - set the high bit */
1107 Address
|= InterlaceHighBit
;
1110 /* Loop through the pixels */
1111 for (j
= 0; j
< Resolution
.X
; j
++)
1115 /* Check the shifting mode */
1116 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1118 /* 4 bits shifted from each plane */
1120 /* Check if this is 16 or 256 color mode */
1121 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1123 /* One byte per pixel */
1124 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1125 + (Address
+ (j
/ VGA_NUM_BANKS
))
1130 /* 4-bits per pixel */
1132 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1133 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1136 /* Check if we should use the highest 4 bits or lowest 4 */
1137 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1149 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1151 /* Check if this is 16 or 256 color mode */
1152 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1154 // TODO: NOT IMPLEMENTED
1155 DPRINT1("8-bit interleaved mode is not implemented!\n");
1160 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1161 * then 2 bits shifted from plane 1 and 3 for the next 4
1163 DWORD BankNumber
= (j
/ 4) % 2;
1164 DWORD Offset
= Address
+ (j
/ 8);
1165 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ Offset
* AddressSize
];
1166 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ Offset
* AddressSize
];
1168 /* Extract the two bits from each plane */
1169 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1170 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1172 /* Combine them into the pixel */
1173 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1178 /* 1 bit shifted from each plane */
1180 /* Check if this is 16 or 256 color mode */
1181 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1183 /* 8 bits per pixel, 2 on each plane */
1185 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1187 /* The data is on plane k, 4 pixels per byte */
1188 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1189 + (Address
+ (j
/ VGA_NUM_BANKS
))
1192 /* The mask of the first bit in the pair */
1193 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1195 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1196 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1198 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1199 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1204 /* 4 bits per pixel, 1 on each plane */
1206 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1208 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1209 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1212 /* If the bit on that plane is set, set it */
1213 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1218 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1221 * In 16 color mode, the value is an index to the AC registers
1222 * if external palette access is disabled, otherwise (in case
1223 * of palette loading) it is a blank pixel.
1225 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1229 /* Take into account DoubleVision mode when checking for pixel updates */
1232 /* Now check if the resulting pixel data has changed */
1233 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
1235 /* Yes, write the new value */
1236 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
1237 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
1238 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
1239 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1241 /* Mark the specified pixel as changed */
1242 VgaMarkForUpdate(i
, j
);
1247 /* Now check if the resulting pixel data has changed */
1248 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
1250 /* Yes, write the new value */
1251 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
1253 /* Mark the specified pixel as changed */
1254 VgaMarkForUpdate(i
, j
);
1259 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1261 /* Clear the high bit */
1262 Address
&= ~InterlaceHighBit
;
1265 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1267 /* Move to the next scanline */
1268 Address
+= ScanlineSize
;
1273 * Release the console framebuffer mutex
1274 * so that we allow for repainting.
1276 ReleaseMutex(ConsoleMutex
);
1282 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1285 /* Loop through the scanlines */
1286 for (i
= 0; i
< Resolution
.Y
; i
++)
1288 /* Loop through the characters */
1289 for (j
= 0; j
< Resolution
.X
; j
++)
1291 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1293 /* Plane 0 holds the character itself */
1294 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1296 /* Plane 1 holds the attribute */
1297 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1299 /* Now check if the resulting character data has changed */
1300 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1301 (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1303 /* Yes, write the new value */
1304 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
1306 /* Mark the specified cell as changed */
1307 VgaMarkForUpdate(i
, j
);
1311 /* Move to the next scanline */
1312 Address
+= ScanlineSize
;
1317 static VOID
VgaUpdateTextCursor(VOID
)
1320 CONSOLE_CURSOR_INFO CursorInfo
;
1321 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
1322 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1323 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1324 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1325 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1326 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1328 /* Just return if we are not in text mode */
1329 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
1331 if (CursorStart
< CursorEnd
)
1333 /* Visible cursor */
1334 CursorInfo
.bVisible
= TRUE
;
1335 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1340 CursorInfo
.bVisible
= FALSE
;
1341 CursorInfo
.dwSize
= 0;
1344 /* Add the cursor skew to the location */
1345 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
1347 /* Find the coordinates of the new position */
1348 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1349 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1351 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1353 /* Update the physical cursor */
1354 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1355 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1357 /* Reset the cursor move flag */
1358 CursorMoved
= FALSE
;
1361 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1363 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1368 return VgaMiscRegister
;
1370 case VGA_INSTAT0_READ
:
1371 return 0; // Not implemented
1373 case VGA_INSTAT1_READ_MONO
:
1374 case VGA_INSTAT1_READ_COLOR
:
1378 /* Reset the AC latch */
1381 /* Set a flag if there is a vertical or horizontal retrace */
1382 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1384 /* Set an additional flag if there was a vertical retrace */
1385 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1387 /* Clear the flags */
1388 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1393 case VGA_FEATURE_READ
:
1394 return VgaFeatureRegister
;
1400 return VgaAcRegisters
[VgaAcIndex
];
1406 return VgaSeqRegisters
[VgaSeqIndex
];
1411 case VGA_DAC_READ_INDEX
:
1412 /* This returns the read/write state */
1413 return (VgaDacReadWrite
? 0 : 3);
1415 case VGA_DAC_WRITE_INDEX
:
1416 return (VgaDacIndex
/ 3);
1420 /* Ignore reads in write mode */
1421 if (!VgaDacReadWrite
)
1423 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1424 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1431 case VGA_CRTC_INDEX_MONO
:
1432 case VGA_CRTC_INDEX_COLOR
:
1433 return VgaCrtcIndex
;
1435 case VGA_CRTC_DATA_MONO
:
1436 case VGA_CRTC_DATA_COLOR
:
1437 return VgaCrtcRegisters
[VgaCrtcIndex
];
1443 return VgaGcRegisters
[VgaGcIndex
];
1446 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1453 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1455 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1459 case VGA_MISC_WRITE
:
1461 VgaMiscRegister
= Data
;
1463 if (VgaMiscRegister
& 0x01)
1465 /* Color emulation */
1466 DPRINT1("Color emulation\n");
1468 /* Register the new I/O Ports */
1469 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1470 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1471 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1473 /* Unregister the old ones */
1474 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1475 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1476 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1480 /* Monochrome emulation */
1481 DPRINT1("Monochrome emulation\n");
1483 /* Register the new I/O Ports */
1484 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1485 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1486 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1488 /* Unregister the old ones */
1489 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1490 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1491 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1494 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1498 case VGA_FEATURE_WRITE_MONO
:
1499 case VGA_FEATURE_WRITE_COLOR
:
1501 VgaFeatureRegister
= Data
;
1506 // case VGA_AC_WRITE:
1510 /* Change the index */
1511 BYTE Index
= Data
& 0x1F;
1512 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1515 * Change palette protection by checking for
1516 * the Palette Address Source bit.
1518 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1522 /* Write the data */
1526 /* Toggle the latch */
1527 VgaAcLatch
= !VgaAcLatch
;
1533 /* Set the sequencer index register */
1534 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1540 /* Call the sequencer function */
1541 VgaWriteSequencer(Data
);
1551 case VGA_DAC_READ_INDEX
:
1553 VgaDacReadWrite
= FALSE
;
1554 VgaDacIndex
= Data
* 3;
1558 case VGA_DAC_WRITE_INDEX
:
1560 VgaDacReadWrite
= TRUE
;
1561 VgaDacIndex
= Data
* 3;
1567 /* Ignore writes in read mode */
1568 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1572 case VGA_CRTC_INDEX_MONO
:
1573 case VGA_CRTC_INDEX_COLOR
:
1575 /* Set the CRTC index register */
1576 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1580 case VGA_CRTC_DATA_MONO
:
1581 case VGA_CRTC_DATA_COLOR
:
1583 /* Call the CRTC function */
1590 /* Set the GC index register */
1591 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1597 /* Call the GC function */
1603 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1608 /* PUBLIC FUNCTIONS ***********************************************************/
1610 DWORD
VgaGetVideoBaseAddress(VOID
)
1612 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1615 DWORD
VgaGetVideoLimitAddress(VOID
)
1617 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1620 COORD
VgaGetDisplayResolution(VOID
)
1623 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1625 /* The low 8 bits are in the display registers */
1626 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1627 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1629 /* Set the top bits from the overflow register */
1630 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1632 Resolution
.Y
|= 1 << 8;
1634 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1636 Resolution
.Y
|= 1 << 9;
1639 /* Increase the values by 1 */
1643 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1645 /* Multiply the horizontal resolution by the 9/8 dot mode */
1646 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1649 /* The horizontal resolution is halved in 8-bit mode */
1650 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1653 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1655 /* Halve the vertical resolution */
1660 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1661 Resolution
.Y
/= MaximumScanLine
;
1664 /* Return the resolution */
1668 VOID
VgaRefreshDisplay(VOID
)
1670 HANDLE ConsoleBufferHandle
= NULL
;
1673 /* Set the vertical retrace flag */
1674 InVerticalRetrace
= TRUE
;
1676 /* If nothing has changed, just return */
1677 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1680 /* Change the display mode */
1681 if (ModeChanged
) VgaChangeMode();
1683 /* Change the text cursor location */
1684 if (CursorMoved
) VgaUpdateTextCursor();
1686 /* Retrieve the current resolution */
1687 Resolution
= VgaGetDisplayResolution();
1691 /* Trigger a full update of the screen */
1693 UpdateRectangle
.Left
= 0;
1694 UpdateRectangle
.Top
= 0;
1695 UpdateRectangle
.Right
= Resolution
.X
;
1696 UpdateRectangle
.Bottom
= Resolution
.Y
;
1698 PaletteChanged
= FALSE
;
1701 /* Update the contents of the framebuffer */
1702 VgaUpdateFramebuffer();
1704 /* Ignore if there's nothing to update */
1705 if (!NeedsUpdate
) return;
1707 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1708 UpdateRectangle
.Left
,
1709 UpdateRectangle
.Top
,
1710 UpdateRectangle
.Right
,
1711 UpdateRectangle
.Bottom
);
1713 /* Check if this is text mode or graphics mode */
1714 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1717 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1719 /* In DoubleVision mode, scale the update rectangle */
1722 UpdateRectangle
.Left
*= 2;
1723 UpdateRectangle
.Top
*= 2;
1724 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1725 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1731 ConsoleBufferHandle
= TextConsoleBuffer
;
1734 /* Redraw the screen */
1735 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1737 /* Clear the update flag */
1738 NeedsUpdate
= FALSE
;
1741 VOID
VgaHorizontalRetrace(VOID
)
1744 InHorizontalRetrace
= TRUE
;
1747 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1752 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1754 /* Ignore if video RAM access is disabled */
1755 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1757 /* Loop through each byte */
1758 for (i
= 0; i
< Size
; i
++)
1760 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1762 /* Load the latch registers */
1763 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1764 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1765 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1766 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1768 /* Copy the value to the buffer */
1769 Buffer
[i
] = VgaMemory
[VideoAddress
];
1773 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1778 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1780 /* Ignore if video RAM access is disabled */
1781 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1783 /* Also ignore if write access to all planes is disabled */
1784 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1786 /* Loop through each byte */
1787 for (i
= 0; i
< Size
; i
++)
1789 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1791 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1793 /* Make sure the page is writeable */
1794 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1796 /* Check if this is chain-4 mode */
1797 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1799 if (((Address
+ i
) & 3) != j
)
1801 /* This plane will not be accessed */
1806 /* Check if this is odd-even mode */
1807 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1809 if (((Address
+ i
) & 1) != (j
& 1))
1811 /* This plane will not be accessed */
1816 /* Copy the value to the VGA memory */
1817 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1822 VOID
VgaClearMemory(VOID
)
1824 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1827 VOID
VgaResetPalette(VOID
)
1829 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1831 /* Restore the default palette */
1832 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1833 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1834 PaletteChanged
= TRUE
;
1840 BOOL
VgaAttachToConsole(VOID
)
1843 // FIXME: We should go back to the saved screen state
1845 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
1846 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1848 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
1849 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
1851 return VgaAttachToConsoleInternal(&TextResolution
);
1854 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
1858 COORD dummySize
= {0};
1861 // FIXME: We should save the screen state
1864 __RegisterConsoleVDM(0,
1876 TextFramebuffer
= NULL
;
1882 /* Restore the old screen buffer */
1883 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1885 /* Restore the original console size */
1888 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
1889 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
1891 * See the following trick explanation in VgaAttachToConsoleInternal.
1893 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1894 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
1895 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1897 /* Restore the original cursor shape */
1898 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
1902 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1904 /* Save the default text-mode console output handle */
1905 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
1906 TextConsoleBuffer
= TextHandle
;
1908 /* Save the original cursor and console screen buffer information */
1909 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
1910 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
1914 ConsoleInfo
= OrgConsoleBufferInfo
;
1916 /* Initialize the VGA palette and fail if it isn't successfully created */
1917 if (!VgaInitializePalette()) return FALSE
;
1918 /***/ VgaResetPalette(); /***/
1920 /* Switch to the text buffer */
1921 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1923 /* Clear the VGA memory */
1926 /* Register the I/O Ports */
1927 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1928 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1929 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1930 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1931 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1932 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1933 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1934 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1935 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1936 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1937 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1938 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1939 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1941 /* Return success */
1945 VOID
VgaCleanup(VOID
)
1947 if (ScreenMode
== GRAPHICS_MODE
)
1949 /* Leave the current graphics mode */
1950 VgaLeaveGraphicsMode();
1954 /* Leave the current text mode */
1958 VgaDetachFromConsole(FALSE
);
1960 CloseHandle(AnotherEvent
);
1961 CloseHandle(EndEvent
);
1962 CloseHandle(StartEvent
);
1965 RegisterConsoleVDM
= NULL
;
1966 FreeLibrary(hKernel32
);