[NTVDM]: Fix the validity check of the hVdd handle in the port structure so that...
[reactos.git] / reactos / subsystems / ntvdm / hardware / vga.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: vga.c
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "emulator.h"
14 #include "vga.h"
15 #include "../bios/vidbios.h"
16
17 #include "io.h"
18
19 /* PRIVATE VARIABLES **********************************************************/
20
21 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
23
24 /*
25 * Activate this line if you want to use the real
26 * RegisterConsoleVDM API of ReactOS/Windows.
27 */
28 // #define USE_REAL_REGISTERCONSOLEVDM
29
30 #define USE_REACTOS_COLORS
31 // #define USE_DOSBOX_COLORS
32
33 #if defined(USE_REACTOS_COLORS)
34
35 // ReactOS colors
36 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
37 {
38 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
39 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
40 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
41 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
42 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
43 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
44 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
45 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
46 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
47 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
48 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
49 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
50 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
51 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
52 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
53 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
54 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
55 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
56 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
57 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
58 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
59 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
60 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
61 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
62 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
63 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
64 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
65 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
66 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
67 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
68 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
69 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
70 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
71 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
72 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
73 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
74 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
75 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
76 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
77 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
78 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
79 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
80 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
81 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
82 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
83 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
84 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
85 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
86 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
87 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
88 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
89 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
90 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
91 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
92 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
93 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
94 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
95 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
96 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
97 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
98 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
99 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
100 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
102 };
103
104 #elif defined(USE_DOSBOX_COLORS)
105
106 // DOSBox colors
107 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
108 {
109 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
110 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
111 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
112 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
113 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
114 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
115 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
116 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
117 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
118 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
119 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
120 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
121 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
122 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
123 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
124 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
125
126 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
127 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
128 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
129 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
130 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
131 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
132 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
133 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
134 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
135 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
136 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
137 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
138 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
139 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
140 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
141 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
142
143 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
144 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
145 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
146 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
147 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
148 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
149 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
150 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
151 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
152 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
153 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
154 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
155 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
156 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
157 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
158 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
159
160 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
161 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
162 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
163 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
164 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
165 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
166 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
167 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
168 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
169 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
170 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
171 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
172 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
173 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
174 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
176 };
177
178 #endif
179
180 /*
181 * Default 16-color palette for foreground and background
182 * (corresponding flags in comments).
183 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
184 */
185 static const COLORREF ConsoleColors[16] =
186 {
187 RGB(0, 0, 0), // (Black)
188 RGB(0, 0, 128), // BLUE
189 RGB(0, 128, 0), // GREEN
190 RGB(0, 128, 128), // BLUE | GREEN
191 RGB(128, 0, 0), // RED
192 RGB(128, 0, 128), // BLUE | RED
193 RGB(128, 128, 0), // GREEN | RED
194 RGB(192, 192, 192), // BLUE | GREEN | RED
195
196 RGB(128, 128, 128), // (Grey) INTENSITY
197 RGB(0, 0, 255), // BLUE | INTENSITY
198 RGB(0, 255, 0), // GREEN | INTENSITY
199 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
200 RGB(255, 0, 0), // RED | INTENSITY
201 RGB(255, 0, 255), // BLUE | RED | INTENSITY
202 RGB(255, 255, 0), // GREEN | RED | INTENSITY
203 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
204 };
205
206 /*
207 * Console interface -- VGA-mode-agnostic
208 */
209 typedef struct _CHAR_CELL
210 {
211 CHAR Char;
212 BYTE Attributes;
213 } CHAR_CELL, *PCHAR_CELL;
214 C_ASSERT(sizeof(CHAR_CELL) == 2);
215
216 static LPVOID ConsoleFramebuffer = NULL; // Active framebuffer, points to
217 // either TextFramebuffer or a valid
218 // graphics framebuffer.
219 static HPALETTE TextPaletteHandle = NULL;
220 static HPALETTE PaletteHandle = NULL;
221
222 static HANDLE StartEvent = NULL;
223 static HANDLE EndEvent = NULL;
224 static HANDLE AnotherEvent = NULL;
225
226 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
227 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
228
229
230 /*
231 * Text mode -- we always keep a valid text mode framebuffer
232 * even if we are in graphics mode. This is needed in order to
233 * keep a consistent VGA state.
234 */
235 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
236 static COORD TextResolution = {0};
237 static PCHAR_CELL TextFramebuffer = NULL;
238 static HANDLE TextConsoleBuffer = NULL;
239
240 /* Graphics mode */
241 static HANDLE GraphicsConsoleBuffer = NULL;
242 static HANDLE ConsoleMutex = NULL;
243 /* DoubleVision support */
244 static BOOLEAN DoubleWidth = FALSE;
245 static BOOLEAN DoubleHeight = FALSE;
246
247 /*
248 * VGA Hardware
249 */
250 static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE];
251
252 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
253
254 static BYTE VgaMiscRegister;
255 static BYTE VgaFeatureRegister;
256
257 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
258 static BYTE VgaSeqRegisters[VGA_SEQ_MAX_REG];
259
260 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
261 static BYTE VgaCrtcRegisters[VGA_CRTC_MAX_REG];
262
263 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
264 static BYTE VgaGcRegisters[VGA_GC_MAX_REG];
265
266 static BOOLEAN VgaAcLatch = FALSE;
267 static BOOLEAN VgaAcPalDisable = TRUE;
268 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
269 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
270
271 // static VGA_REGISTERS VgaRegisters;
272
273 static BYTE VgaDacMask = 0xFF;
274 static WORD VgaDacIndex = 0;
275 static BOOLEAN VgaDacReadWrite = FALSE;
276 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
277
278 static BOOLEAN InVerticalRetrace = FALSE;
279 static BOOLEAN InHorizontalRetrace = FALSE;
280
281 static BOOLEAN NeedsUpdate = FALSE;
282 static BOOLEAN ModeChanged = FALSE;
283 static BOOLEAN CursorMoved = FALSE;
284 static BOOLEAN PaletteChanged = FALSE;
285
286 static
287 enum SCREEN_MODE
288 {
289 TEXT_MODE,
290 GRAPHICS_MODE
291 } ScreenMode = TEXT_MODE;
292
293 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
294
295 /* RegisterConsoleVDM EMULATION ***********************************************/
296
297 #include <ntddvdeo.h>
298
299 #ifdef USE_REAL_REGISTERCONSOLEVDM
300
301 #define __RegisterConsoleVDM RegisterConsoleVDM
302 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
303
304 #else
305
306 /*
307 * This private buffer, per-console, is used by
308 * RegisterConsoleVDM and InvalidateConsoleDIBits.
309 */
310 static COORD VDMBufferSize = {0};
311 static PCHAR_CELL VDMBuffer = NULL;
312
313 static PCHAR_INFO CharBuff = NULL; // This is a hack, which is unneeded
314 // for the real RegisterConsoleVDM and
315 // InvalidateConsoleDIBits
316
317 BOOL
318 WINAPI
319 __RegisterConsoleVDM(IN DWORD dwRegisterFlags,
320 IN HANDLE hStartHardwareEvent,
321 IN HANDLE hEndHardwareEvent,
322 IN HANDLE hErrorHardwareEvent,
323 IN DWORD dwUnusedVar,
324 OUT LPDWORD lpVideoStateLength,
325 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
326 IN PVOID lpUnusedBuffer,
327 IN DWORD dwUnusedBufferLength,
328 IN COORD dwVDMBufferSize,
329 OUT PVOID* lpVDMBuffer)
330 {
331 UNREFERENCED_PARAMETER(hErrorHardwareEvent);
332 UNREFERENCED_PARAMETER(dwUnusedVar);
333 UNREFERENCED_PARAMETER(lpVideoStateLength);
334 UNREFERENCED_PARAMETER(lpVideoState);
335 UNREFERENCED_PARAMETER(lpUnusedBuffer);
336 UNREFERENCED_PARAMETER(dwUnusedBufferLength);
337
338 SetLastError(0);
339 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
340
341 if (lpVDMBuffer == NULL) return FALSE;
342
343 if (dwRegisterFlags != 0)
344 {
345 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
346 if (VDMBuffer != NULL) return FALSE;
347
348 VDMBufferSize = dwVDMBufferSize;
349
350 /* HACK: Cache -- to be removed in the real implementation */
351 CharBuff = HeapAlloc(GetProcessHeap(),
352 HEAP_ZERO_MEMORY,
353 VDMBufferSize.X * VDMBufferSize.Y
354 * sizeof(CHAR_INFO));
355 ASSERT(CharBuff);
356
357 VDMBuffer = HeapAlloc(GetProcessHeap(),
358 HEAP_ZERO_MEMORY,
359 VDMBufferSize.X * VDMBufferSize.Y
360 * sizeof(CHAR_CELL));
361 *lpVDMBuffer = VDMBuffer;
362 return (VDMBuffer != NULL);
363 }
364 else
365 {
366 /* HACK: Cache -- to be removed in the real implementation */
367 if (CharBuff) HeapFree(GetProcessHeap(), 0, CharBuff);
368 CharBuff = NULL;
369
370 if (VDMBuffer) HeapFree(GetProcessHeap(), 0, VDMBuffer);
371 VDMBuffer = NULL;
372
373 VDMBufferSize.X = VDMBufferSize.Y = 0;
374
375 return TRUE;
376 }
377 }
378
379 BOOL
380 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
381 IN PSMALL_RECT lpRect)
382 {
383 if ((hConsoleOutput == TextConsoleBuffer) && (VDMBuffer != NULL))
384 {
385 /* HACK: Write the cached data to the console */
386
387 COORD Origin = { lpRect->Left, lpRect->Top };
388 SHORT i, j;
389
390 ASSERT(CharBuff);
391
392 for (i = 0; i < VDMBufferSize.Y; i++)
393 {
394 for (j = 0; j < VDMBufferSize.X; j++)
395 {
396 CharBuff[i * VDMBufferSize.X + j].Char.AsciiChar = VDMBuffer[i * VDMBufferSize.X + j].Char;
397 CharBuff[i * VDMBufferSize.X + j].Attributes = VDMBuffer[i * VDMBufferSize.X + j].Attributes;
398 }
399 }
400
401 WriteConsoleOutputA(hConsoleOutput,
402 CharBuff,
403 VDMBufferSize,
404 Origin,
405 lpRect);
406 }
407
408 return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
409 }
410
411 #endif
412
413 /* PRIVATE FUNCTIONS **********************************************************/
414
415 static inline DWORD VgaGetAddressSize(VOID);
416 static VOID VgaUpdateTextCursor(VOID);
417
418 static VOID VgaUpdateCursorPosition(VOID)
419 {
420 /*
421 * Update the cursor position in the VGA registers.
422 */
423 WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X +
424 ConsoleInfo.dwCursorPosition.X;
425
426 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
427 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
428
429 // VidBiosSyncCursorPosition();
430 VgaUpdateTextCursor();
431 }
432
433 static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
434 {
435 BOOL Success;
436 ULONG Length = 0;
437 PVIDEO_HARDWARE_STATE_HEADER State;
438
439 #ifdef USE_REAL_REGISTERCONSOLEVDM
440 PCHAR_INFO CharBuff = NULL;
441 #endif
442 SHORT i, j;
443 DWORD AddressSize, ScanlineSize;
444 DWORD Address = 0;
445 DWORD CurrentAddr;
446 SMALL_RECT ConRect;
447 COORD Origin = { 0, 0 };
448
449 ASSERT(TextFramebuffer == NULL);
450
451 TextResolution = *Resolution;
452
453 /*
454 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
455 * in the two following APIs:
456 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
457 * SrvVDMConsoleOperation (corresponding Win32 API: )
458 * to check whether the current process is a VDM process, and fails otherwise with the
459 * error 0xC0000022 ().
460 *
461 * It is worth it to notice that also basesrv.dll does the same only for the
462 * BaseSrvIsFirstVDM API...
463 */
464
465 Success =
466 __RegisterConsoleVDM(1,
467 StartEvent,
468 EndEvent,
469 AnotherEvent, // NULL,
470 0,
471 &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
472 (PVOID*)&State, // NULL,
473 NULL,
474 0,
475 TextResolution,
476 (PVOID*)&TextFramebuffer);
477 if (!Success)
478 {
479 DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
480 EmulatorTerminate();
481 return FALSE;
482 }
483
484 #ifdef USE_REAL_REGISTERCONSOLEVDM
485 CharBuff = HeapAlloc(GetProcessHeap(),
486 HEAP_ZERO_MEMORY,
487 TextResolution.X * TextResolution.Y
488 * sizeof(CHAR_INFO));
489 ASSERT(CharBuff);
490 #endif
491
492 /*
493 * Resize the console
494 */
495 ConRect.Left = 0;
496 ConRect.Top = ConsoleInfo.srWindow.Top;
497 ConRect.Right = ConRect.Left + Resolution->X - 1;
498 ConRect.Bottom = ConRect.Top + Resolution->Y - 1;
499 /*
500 * Use this trick to effectively resize the console buffer and window,
501 * because:
502 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
503 * is smaller than the current console window size, and:
504 * - SetConsoleWindowInfo fails if the new console window size is larger
505 * than the current console screen buffer size.
506 */
507 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
508 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
509 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
510 /* Update the saved console information */
511 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
512
513 /*
514 * Copy console data into VGA memory
515 */
516
517 /* Get the data */
518 AddressSize = VgaGetAddressSize();
519 ConRect.Left = ConRect.Top = 0;
520 ConRect.Right = TextResolution.X;
521 ConRect.Bottom = TextResolution.Y;
522 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
523
524 /* Read the data from the console into the framebuffer... */
525 ReadConsoleOutputA(TextConsoleBuffer,
526 CharBuff,
527 TextResolution,
528 Origin,
529 &ConRect);
530
531 /* ... and copy the framebuffer into the VGA memory */
532
533 /* Loop through the scanlines */
534 for (i = 0; i < TextResolution.Y; i++)
535 {
536 /* Loop through the characters */
537 for (j = 0; j < TextResolution.X; j++)
538 {
539 CurrentAddr = LOWORD((Address + j) * AddressSize);
540
541 /* Store the character in plane 0 */
542 VgaMemory[CurrentAddr] = CharBuff[i * TextResolution.X + j].Char.AsciiChar;
543
544 /* Store the attribute in plane 1 */
545 VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes;
546 }
547
548 /* Move to the next scanline */
549 Address += ScanlineSize;
550 }
551
552 #ifdef USE_REAL_REGISTERCONSOLEVDM
553 if (CharBuff) HeapFree(GetProcessHeap(), 0, CharBuff);
554 #endif
555
556 VgaUpdateCursorPosition();
557
558 return TRUE;
559 }
560
561 static BOOL IsConsoleHandle(HANDLE hHandle)
562 {
563 DWORD dwMode;
564
565 /* Check whether the handle may be that of a console... */
566 if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
567 return FALSE;
568
569 /*
570 * It may be. Perform another test... The idea comes from the
571 * MSDN description of the WriteConsole API:
572 *
573 * "WriteConsole fails if it is used with a standard handle
574 * that is redirected to a file. If an application processes
575 * multilingual output that can be redirected, determine whether
576 * the output handle is a console handle (one method is to call
577 * the GetConsoleMode function and check whether it succeeds).
578 * If the handle is a console handle, call WriteConsole. If the
579 * handle is not a console handle, the output is redirected and
580 * you should call WriteFile to perform the I/O."
581 */
582 return GetConsoleMode(hHandle, &dwMode);
583 }
584
585 static inline DWORD VgaGetAddressSize(VOID)
586 {
587 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
588 {
589 /* Double-word addressing */
590 return 4; // sizeof(DWORD)
591 }
592 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
593 {
594 /* Byte addressing */
595 return 1; // sizeof(BYTE)
596 }
597 else
598 {
599 /* Word addressing */
600 return 2; // sizeof(WORD)
601 }
602 }
603
604 static inline DWORD VgaTranslateReadAddress(DWORD Address)
605 {
606 DWORD Offset = Address - VgaGetVideoBaseAddress();
607 BYTE Plane;
608
609 /* Check for chain-4 and odd-even mode */
610 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
611 {
612 /* The lowest two bits are the plane number */
613 Plane = Offset & 3;
614 Offset >>= 2;
615 }
616 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
617 {
618 /* The LSB is the plane number */
619 Plane = Offset & 1;
620 Offset >>= 1;
621 }
622 else
623 {
624 /* Use the read mode */
625 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
626 }
627
628 /* Multiply the offset by the address size */
629 Offset *= VgaGetAddressSize();
630
631 return Offset + Plane * VGA_BANK_SIZE;
632 }
633
634 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
635 {
636 DWORD Offset = Address - VgaGetVideoBaseAddress();
637
638 /* Check for chain-4 and odd-even mode */
639 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
640 {
641 /* Shift the offset to the right by 2 */
642 Offset >>= 2;
643 }
644 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
645 {
646 /* Shift the offset to the right by 1 */
647 Offset >>= 1;
648 }
649
650 /* Multiply the offset by the address size */
651 Offset *= VgaGetAddressSize();
652
653 /* Return the offset on plane 0 */
654 return Offset;
655 }
656
657 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
658 {
659 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
660 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
661
662 if (WriteMode == 1)
663 {
664 /* In write mode 1 just return the latch register */
665 return VgaLatchRegisters[Plane];
666 }
667
668 if (WriteMode != 2)
669 {
670 /* Write modes 0 and 3 rotate the data to the right first */
671 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
672 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
673 }
674 else
675 {
676 /* Write mode 2 expands the appropriate bit to all 8 bits */
677 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
678 }
679
680 if (WriteMode == 0)
681 {
682 /*
683 * In write mode 0, the enable set/reset register decides if the
684 * set/reset bit should be expanded to all 8 bits.
685 */
686 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
687 {
688 /* Copy the bit from the set/reset register to all 8 bits */
689 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
690 }
691 }
692
693 if (WriteMode != 3)
694 {
695 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
696 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
697
698 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
699 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
700 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
701 }
702 else
703 {
704 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
705 BitMask &= Data;
706
707 /* Then we expand the bit in the set/reset field */
708 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
709 }
710
711 /* Bits cleared in the bitmask are replaced with latch register bits */
712 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
713
714 /* Return the byte */
715 return Data;
716 }
717
718 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
719 {
720 /* Check if this is the first time the rectangle is updated */
721 if (!NeedsUpdate)
722 {
723 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
724 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
725 }
726
727 /* Expand the rectangle to include the point */
728 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
729 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
730 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
731 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
732
733 /* Set the update request flag */
734 NeedsUpdate = TRUE;
735 }
736
737 static VOID VgaWriteSequencer(BYTE Data)
738 {
739 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
740
741 /* Save the value */
742 VgaSeqRegisters[VgaSeqIndex] = Data;
743 }
744
745 static VOID VgaWriteGc(BYTE Data)
746 {
747 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
748
749 /* Save the value */
750 VgaGcRegisters[VgaGcIndex] = Data;
751
752 /* Check the index */
753 switch (VgaGcIndex)
754 {
755 case VGA_GC_MISC_REG:
756 {
757 /* The GC misc register decides if it's text or graphics mode */
758 ModeChanged = TRUE;
759 break;
760 }
761 }
762 }
763
764 static VOID VgaWriteCrtc(BYTE Data)
765 {
766 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
767
768 /* Save the value */
769 VgaCrtcRegisters[VgaCrtcIndex] = Data;
770
771 /* Check the index */
772 switch (VgaCrtcIndex)
773 {
774 case VGA_CRTC_END_HORZ_DISP_REG:
775 case VGA_CRTC_VERT_DISP_END_REG:
776 case VGA_CRTC_OVERFLOW_REG:
777 {
778 /* The video mode has changed */
779 ModeChanged = TRUE;
780 break;
781 }
782
783 case VGA_CRTC_CURSOR_LOC_LOW_REG:
784 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
785 case VGA_CRTC_CURSOR_START_REG:
786 case VGA_CRTC_CURSOR_END_REG:
787 {
788 /* Set the cursor moved flag */
789 CursorMoved = TRUE;
790 break;
791 }
792 }
793 }
794
795 static VOID VgaWriteDac(BYTE Data)
796 {
797 INT i, PaletteIndex;
798 PALETTEENTRY Entry;
799
800 /* Set the value */
801 VgaDacRegisters[VgaDacIndex] = Data;
802
803 /* Find the palette index */
804 PaletteIndex = VgaDacIndex / 3;
805
806 /* Fill the entry structure */
807 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
808 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
809 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
810 Entry.peFlags = 0;
811
812 /* Update the palette entry */
813 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
814
815 /* Check which text palette entries are affected */
816 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
817 {
818 if (VgaAcRegisters[i] == PaletteIndex)
819 {
820 /* Update the text palette entry */
821 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
822 }
823 }
824
825 /* Set the palette changed flag */
826 PaletteChanged = TRUE;
827
828 /* Update the index */
829 VgaDacIndex++;
830 VgaDacIndex %= VGA_PALETTE_SIZE;
831 }
832
833 static VOID VgaWriteAc(BYTE Data)
834 {
835 PALETTEENTRY Entry;
836
837 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
838
839 /* Save the value */
840 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
841 {
842 if (VgaAcPalDisable) return;
843
844 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
845 if (VgaAcRegisters[VgaAcIndex] != Data)
846 {
847 /* Update the AC register */
848 VgaAcRegisters[VgaAcIndex] = Data;
849
850 /* Fill the entry structure */
851 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]);
852 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]);
853 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]);
854 Entry.peFlags = 0;
855
856 /* Update the palette entry and set the palette change flag */
857 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
858 PaletteChanged = TRUE;
859 }
860 }
861 else
862 {
863 VgaAcRegisters[VgaAcIndex] = Data;
864 }
865 }
866
867 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
868 {
869 USHORT i;
870
871 /* Copy the colors of the default palette to the DAC and console palette */
872 for (i = 0; i < NumOfEntries; i++)
873 {
874 /* Set the palette entries */
875 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
876 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
877 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
878 Entries[i].peFlags = 0;
879
880 /* Set the DAC registers */
881 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
882 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
883 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
884 }
885 }
886
887 static BOOLEAN VgaInitializePalette(VOID)
888 {
889 INT i;
890 BOOLEAN Result = FALSE;
891 LPLOGPALETTE Palette, TextPalette;
892
893 /* Allocate storage space for the palettes */
894 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
895 HEAP_ZERO_MEMORY,
896 sizeof(LOGPALETTE) +
897 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
898 TextPalette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
899 HEAP_ZERO_MEMORY,
900 sizeof(LOGPALETTE) +
901 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
902 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
903
904 /* Initialize the palettes */
905 Palette->palVersion = TextPalette->palVersion = 0x0300;
906 Palette->palNumEntries = VGA_MAX_COLORS;
907 TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1;
908
909 /* Restore the default graphics palette */
910 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
911
912 /* Set the default text palette */
913 for (i = 0; i < TextPalette->palNumEntries; i++)
914 {
915 /* Set the palette entries */
916 TextPalette->palPalEntry[i].peRed = GetRValue(ConsoleColors[i]);
917 TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]);
918 TextPalette->palPalEntry[i].peBlue = GetBValue(ConsoleColors[i]);
919 TextPalette->palPalEntry[i].peFlags = 0;
920 }
921
922 /* Create the palettes */
923 PaletteHandle = CreatePalette(Palette);
924 TextPaletteHandle = CreatePalette(TextPalette);
925
926 if (PaletteHandle != NULL && TextPaletteHandle != NULL)
927 {
928 /* The palettes have been created successfully */
929 Result = TRUE;
930 }
931
932 Cleanup:
933 /* Free the palettes */
934 if (Palette) HeapFree(GetProcessHeap(), 0, Palette);
935 if (TextPalette) HeapFree(GetProcessHeap(), 0, TextPalette);
936
937 if (!Result)
938 {
939 /* Something failed, delete the palettes */
940 if (PaletteHandle) DeleteObject(PaletteHandle);
941 if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
942 }
943
944 return Result;
945 }
946
947 static VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
948 {
949 /* Set the active buffer */
950 SetConsoleActiveScreenBuffer(ScreenBuffer);
951
952 /* Reinitialize the VDM menu */
953 DestroyVdmMenu();
954 CreateVdmMenu(ScreenBuffer);
955 }
956
957 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
958 {
959 DWORD i;
960 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
961 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
962 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
963 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
964
965 LONG Width = Resolution->X;
966 LONG Height = Resolution->Y;
967
968 /* Use DoubleVision mode if the resolution is too small */
969 DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
970 if (DoubleWidth) Width *= 2;
971 DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
972 if (DoubleHeight) Height *= 2;
973
974 /* Fill the bitmap info header */
975 RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
976 BitmapInfo->bmiHeader.biSize = sizeof(BitmapInfo->bmiHeader);
977 BitmapInfo->bmiHeader.biWidth = Width;
978 BitmapInfo->bmiHeader.biHeight = Height;
979 BitmapInfo->bmiHeader.biBitCount = 8;
980 BitmapInfo->bmiHeader.biPlanes = 1;
981 BitmapInfo->bmiHeader.biCompression = BI_RGB;
982 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
983
984 /* Fill the palette data */
985 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
986
987 /* Fill the console graphics buffer info */
988 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
989 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
990 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
991
992 /* Create the buffer */
993 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
994 FILE_SHARE_READ | FILE_SHARE_WRITE,
995 NULL,
996 CONSOLE_GRAPHICS_BUFFER,
997 &GraphicsBufferInfo);
998 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
999
1000 /* Save the framebuffer address and mutex */
1001 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
1002 ConsoleMutex = GraphicsBufferInfo.hMutex;
1003
1004 /* Clear the framebuffer */
1005 RtlZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
1006
1007 /* Set the active buffer */
1008 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
1009
1010 /* Set the graphics mode palette */
1011 SetConsolePalette(GraphicsConsoleBuffer,
1012 PaletteHandle,
1013 SYSPAL_NOSTATIC256);
1014
1015 /* Set the screen mode flag */
1016 ScreenMode = GRAPHICS_MODE;
1017
1018 return TRUE;
1019 }
1020
1021 static VOID VgaLeaveGraphicsMode(VOID)
1022 {
1023 /* Release the console framebuffer mutex */
1024 ReleaseMutex(ConsoleMutex);
1025
1026 /* Switch back to the default console text buffer */
1027 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1028
1029 /* Cleanup the video data */
1030 CloseHandle(ConsoleMutex);
1031 ConsoleMutex = NULL;
1032 ConsoleFramebuffer = NULL;
1033 CloseHandle(GraphicsConsoleBuffer);
1034 GraphicsConsoleBuffer = NULL;
1035
1036 DoubleWidth = FALSE;
1037 DoubleHeight = FALSE;
1038 }
1039
1040 static BOOL VgaEnterTextMode(PCOORD Resolution)
1041 {
1042 DPRINT1("VgaEnterTextMode\n");
1043
1044 /* Switch to the text buffer */
1045 VgaSetActiveScreenBuffer(TextConsoleBuffer);
1046
1047 /* Adjust the text framebuffer if we changed the resolution */
1048 if (TextResolution.X != Resolution->X ||
1049 TextResolution.Y != Resolution->Y)
1050 {
1051 VgaDetachFromConsole(TRUE);
1052
1053 /*
1054 * VgaAttachToConsoleInternal sets TextResolution to the
1055 * new resolution and updates ConsoleInfo.
1056 */
1057 if (!VgaAttachToConsoleInternal(Resolution))
1058 {
1059 DisplayMessage(L"An unexpected error occurred!\n");
1060 EmulatorTerminate();
1061 return FALSE;
1062 }
1063 }
1064 else
1065 {
1066 VgaUpdateCursorPosition();
1067 }
1068
1069 /* The active framebuffer is now the text framebuffer */
1070 ConsoleFramebuffer = TextFramebuffer;
1071
1072 /*
1073 * Set the text mode palette.
1074 *
1075 * WARNING: This call should fail on Windows (and therefore
1076 * we get the default palette and our external behaviour is
1077 * just like Windows' one), but it should success on ReactOS
1078 * (so that we get console palette changes even for text-mode
1079 * screen-buffers, which is a new feature on ReactOS).
1080 */
1081 SetConsolePalette(TextConsoleBuffer,
1082 TextPaletteHandle,
1083 SYSPAL_NOSTATIC256);
1084
1085 /* Set the screen mode flag */
1086 ScreenMode = TEXT_MODE;
1087
1088 return TRUE;
1089 }
1090
1091 static VOID VgaLeaveTextMode(VOID)
1092 {
1093 /* Reset the active framebuffer */
1094 ConsoleFramebuffer = NULL;
1095 }
1096
1097 static VOID VgaChangeMode(VOID)
1098 {
1099 COORD Resolution = VgaGetDisplayResolution();
1100
1101 if (ScreenMode == GRAPHICS_MODE)
1102 {
1103 /* Leave the current graphics mode */
1104 VgaLeaveGraphicsMode();
1105 }
1106 else
1107 {
1108 /* Leave the current text mode */
1109 VgaLeaveTextMode();
1110 }
1111
1112 /* Check if the new mode is alphanumeric */
1113 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
1114 {
1115 /* Enter new text mode */
1116 if (!VgaEnterTextMode(&Resolution))
1117 {
1118 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1119 EmulatorTerminate();
1120 return;
1121 }
1122 }
1123 else
1124 {
1125 /* Enter graphics mode */
1126 if (!VgaEnterGraphicsMode(&Resolution))
1127 {
1128 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1129 EmulatorTerminate();
1130 return;
1131 }
1132 }
1133
1134 /* Trigger a full update of the screen */
1135 NeedsUpdate = TRUE;
1136 UpdateRectangle.Left = 0;
1137 UpdateRectangle.Top = 0;
1138 UpdateRectangle.Right = Resolution.X;
1139 UpdateRectangle.Bottom = Resolution.Y;
1140
1141 /* Reset the mode change flag */
1142 ModeChanged = FALSE;
1143 }
1144
1145 static VOID VgaUpdateFramebuffer(VOID)
1146 {
1147 SHORT i, j, k;
1148 COORD Resolution = VgaGetDisplayResolution();
1149 DWORD AddressSize = VgaGetAddressSize();
1150 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1151 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
1152 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1153
1154 /*
1155 * If console framebuffer is NULL, that means something went wrong
1156 * earlier and this is the final display refresh.
1157 */
1158 if (ConsoleFramebuffer == NULL) return;
1159
1160 /* Check if this is text mode or graphics mode */
1161 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1162 {
1163 /* Graphics mode */
1164 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1165 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
1166
1167 /*
1168 * Synchronize access to the graphics framebuffer
1169 * with the console framebuffer mutex.
1170 */
1171 WaitForSingleObject(ConsoleMutex, INFINITE);
1172
1173 /* Shift the high bit right by 1 in odd/even mode */
1174 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1175 {
1176 InterlaceHighBit >>= 1;
1177 }
1178
1179 /* Loop through the scanlines */
1180 for (i = 0; i < Resolution.Y; i++)
1181 {
1182 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1183 {
1184 /* Odd-numbered line in interlaced mode - set the high bit */
1185 Address |= InterlaceHighBit;
1186 }
1187
1188 /* Loop through the pixels */
1189 for (j = 0; j < Resolution.X; j++)
1190 {
1191 BYTE PixelData = 0;
1192
1193 /* Check the shifting mode */
1194 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1195 {
1196 /* 4 bits shifted from each plane */
1197
1198 /* Check if this is 16 or 256 color mode */
1199 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1200 {
1201 /* One byte per pixel */
1202 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1203 + (Address + (j / VGA_NUM_BANKS))
1204 * AddressSize];
1205 }
1206 else
1207 {
1208 /* 4-bits per pixel */
1209
1210 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1211 + (Address + (j / (VGA_NUM_BANKS * 2)))
1212 * AddressSize];
1213
1214 /* Check if we should use the highest 4 bits or lowest 4 */
1215 if (((j / VGA_NUM_BANKS) % 2) == 0)
1216 {
1217 /* Highest 4 */
1218 PixelData >>= 4;
1219 }
1220 else
1221 {
1222 /* Lowest 4 */
1223 PixelData &= 0x0F;
1224 }
1225 }
1226 }
1227 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1228 {
1229 /* Check if this is 16 or 256 color mode */
1230 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1231 {
1232 // TODO: NOT IMPLEMENTED
1233 DPRINT1("8-bit interleaved mode is not implemented!\n");
1234 }
1235 else
1236 {
1237 /*
1238 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1239 * then 2 bits shifted from plane 1 and 3 for the next 4
1240 */
1241 DWORD BankNumber = (j / 4) % 2;
1242 DWORD Offset = Address + (j / 8);
1243 BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + Offset * AddressSize];
1244 BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + Offset * AddressSize];
1245
1246 /* Extract the two bits from each plane */
1247 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
1248 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
1249
1250 /* Combine them into the pixel */
1251 PixelData = LowPlaneData | (HighPlaneData << 2);
1252 }
1253 }
1254 else
1255 {
1256 /* 1 bit shifted from each plane */
1257
1258 /* Check if this is 16 or 256 color mode */
1259 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1260 {
1261 /* 8 bits per pixel, 2 on each plane */
1262
1263 for (k = 0; k < VGA_NUM_BANKS; k++)
1264 {
1265 /* The data is on plane k, 4 pixels per byte */
1266 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1267 + (Address + (j / VGA_NUM_BANKS))
1268 * AddressSize];
1269
1270 /* The mask of the first bit in the pair */
1271 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
1272
1273 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1274 if (PlaneData & BitMask) PixelData |= 1 << k;
1275
1276 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1277 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1278 }
1279 }
1280 else
1281 {
1282 /* 4 bits per pixel, 1 on each plane */
1283
1284 for (k = 0; k < VGA_NUM_BANKS; k++)
1285 {
1286 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1287 + (Address + (j / (VGA_NUM_BANKS * 2)))
1288 * AddressSize];
1289
1290 /* If the bit on that plane is set, set it */
1291 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
1292 }
1293 }
1294 }
1295
1296 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1297 {
1298 /*
1299 * In 16 color mode, the value is an index to the AC registers
1300 * if external palette access is disabled, otherwise (in case
1301 * of palette loading) it is a blank pixel.
1302 */
1303 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1304 : 0);
1305 }
1306
1307 /* Take into account DoubleVision mode when checking for pixel updates */
1308 if (DoubleWidth && DoubleHeight)
1309 {
1310 /* Now check if the resulting pixel data has changed */
1311 if (GraphicsBuffer[(i * 2 * Resolution.X * 2) + (j * 2)] != PixelData)
1312 {
1313 /* Yes, write the new value */
1314 GraphicsBuffer[(i * 2 * Resolution.X * 2) + (j * 2)] = PixelData;
1315 GraphicsBuffer[(i * 2 * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
1316 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
1317 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
1318
1319 /* Mark the specified pixel as changed */
1320 VgaMarkForUpdate(i, j);
1321 }
1322 }
1323 else if (DoubleWidth && !DoubleHeight)
1324 {
1325 /* Now check if the resulting pixel data has changed */
1326 if (GraphicsBuffer[(i * Resolution.X * 2) + (j * 2)] != PixelData)
1327 {
1328 /* Yes, write the new value */
1329 GraphicsBuffer[(i * Resolution.X * 2) + (j * 2)] = PixelData;
1330 GraphicsBuffer[(i * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
1331
1332 /* Mark the specified pixel as changed */
1333 VgaMarkForUpdate(i, j);
1334 }
1335 }
1336 else if (!DoubleWidth && DoubleHeight)
1337 {
1338 /* Now check if the resulting pixel data has changed */
1339 if (GraphicsBuffer[(i * 2 * Resolution.X) + j] != PixelData)
1340 {
1341 /* Yes, write the new value */
1342 GraphicsBuffer[(i * 2 * Resolution.X) + j] = PixelData;
1343 GraphicsBuffer[((i * 2 + 1) * Resolution.X) + j] = PixelData;
1344
1345 /* Mark the specified pixel as changed */
1346 VgaMarkForUpdate(i, j);
1347 }
1348 }
1349 else // if (!DoubleWidth && !DoubleHeight)
1350 {
1351 /* Now check if the resulting pixel data has changed */
1352 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
1353 {
1354 /* Yes, write the new value */
1355 GraphicsBuffer[i * Resolution.X + j] = PixelData;
1356
1357 /* Mark the specified pixel as changed */
1358 VgaMarkForUpdate(i, j);
1359 }
1360 }
1361 }
1362
1363 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1364 {
1365 /* Clear the high bit */
1366 Address &= ~InterlaceHighBit;
1367 }
1368
1369 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1370 {
1371 /* Move to the next scanline */
1372 Address += ScanlineSize;
1373 }
1374 }
1375
1376 /*
1377 * Release the console framebuffer mutex
1378 * so that we allow for repainting.
1379 */
1380 ReleaseMutex(ConsoleMutex);
1381 }
1382 else
1383 {
1384 /* Text mode */
1385 DWORD CurrentAddr;
1386 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1387 CHAR_CELL CharInfo;
1388
1389 /* Loop through the scanlines */
1390 for (i = 0; i < Resolution.Y; i++)
1391 {
1392 /* Loop through the characters */
1393 for (j = 0; j < Resolution.X; j++)
1394 {
1395 CurrentAddr = LOWORD((Address + j) * AddressSize);
1396
1397 /* Plane 0 holds the character itself */
1398 CharInfo.Char = VgaMemory[CurrentAddr];
1399
1400 /* Plane 1 holds the attribute */
1401 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1402
1403 /* Now check if the resulting character data has changed */
1404 if ((CharBuffer[i * Resolution.X + j].Char != CharInfo.Char) ||
1405 (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
1406 {
1407 /* Yes, write the new value */
1408 CharBuffer[i * Resolution.X + j] = CharInfo;
1409
1410 /* Mark the specified cell as changed */
1411 VgaMarkForUpdate(i, j);
1412 }
1413 }
1414
1415 /* Move to the next scanline */
1416 Address += ScanlineSize;
1417 }
1418 }
1419 }
1420
1421 static VOID VgaUpdateTextCursor(VOID)
1422 {
1423 COORD Position;
1424 CONSOLE_CURSOR_INFO CursorInfo;
1425 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
1426 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1427 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1428 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1429 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1430 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1431
1432 /* Just return if we are not in text mode */
1433 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) return;
1434
1435 if (CursorStart < CursorEnd)
1436 {
1437 /* Visible cursor */
1438 CursorInfo.bVisible = TRUE;
1439 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1440 }
1441 else
1442 {
1443 /* No cursor */
1444 CursorInfo.bVisible = FALSE;
1445 CursorInfo.dwSize = 0;
1446 }
1447
1448 /* Add the cursor skew to the location */
1449 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
1450
1451 /* Find the coordinates of the new position */
1452 Position.X = (SHORT)(Location % ScanlineSize);
1453 Position.Y = (SHORT)(Location / ScanlineSize);
1454
1455 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position.X, Position.Y);
1456
1457 /* Update the physical cursor */
1458 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1459 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1460
1461 /* Reset the cursor move flag */
1462 CursorMoved = FALSE;
1463 }
1464
1465 static BYTE WINAPI VgaReadPort(USHORT Port)
1466 {
1467 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1468
1469 switch (Port)
1470 {
1471 case VGA_MISC_READ:
1472 return VgaMiscRegister;
1473
1474 case VGA_INSTAT0_READ:
1475 return 0; // Not implemented
1476
1477 case VGA_INSTAT1_READ_MONO:
1478 case VGA_INSTAT1_READ_COLOR:
1479 {
1480 BYTE Result = 0;
1481
1482 /* Reset the AC latch */
1483 VgaAcLatch = FALSE;
1484
1485 /* Set a flag if there is a vertical or horizontal retrace */
1486 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1487
1488 /* Set an additional flag if there was a vertical retrace */
1489 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1490
1491 /* Clear the flags */
1492 InHorizontalRetrace = InVerticalRetrace = FALSE;
1493
1494 return Result;
1495 }
1496
1497 case VGA_FEATURE_READ:
1498 return VgaFeatureRegister;
1499
1500 case VGA_AC_INDEX:
1501 return VgaAcIndex;
1502
1503 case VGA_AC_READ:
1504 return VgaAcRegisters[VgaAcIndex];
1505
1506 case VGA_SEQ_INDEX:
1507 return VgaSeqIndex;
1508
1509 case VGA_SEQ_DATA:
1510 return VgaSeqRegisters[VgaSeqIndex];
1511
1512 case VGA_DAC_MASK:
1513 return VgaDacMask;
1514
1515 case VGA_DAC_READ_INDEX:
1516 /* This returns the read/write state */
1517 return (VgaDacReadWrite ? 0 : 3);
1518
1519 case VGA_DAC_WRITE_INDEX:
1520 return (VgaDacIndex / 3);
1521
1522 case VGA_DAC_DATA:
1523 {
1524 /* Ignore reads in write mode */
1525 if (!VgaDacReadWrite)
1526 {
1527 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1528 VgaDacIndex %= VGA_PALETTE_SIZE;
1529 return Data;
1530 }
1531
1532 break;
1533 }
1534
1535 case VGA_CRTC_INDEX_MONO:
1536 case VGA_CRTC_INDEX_COLOR:
1537 return VgaCrtcIndex;
1538
1539 case VGA_CRTC_DATA_MONO:
1540 case VGA_CRTC_DATA_COLOR:
1541 return VgaCrtcRegisters[VgaCrtcIndex];
1542
1543 case VGA_GC_INDEX:
1544 return VgaGcIndex;
1545
1546 case VGA_GC_DATA:
1547 return VgaGcRegisters[VgaGcIndex];
1548
1549 default:
1550 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1551 break;
1552 }
1553
1554 return 0;
1555 }
1556
1557 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1558 {
1559 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1560
1561 switch (Port)
1562 {
1563 case VGA_MISC_WRITE:
1564 {
1565 VgaMiscRegister = Data;
1566
1567 if (VgaMiscRegister & 0x01)
1568 {
1569 /* Color emulation */
1570 DPRINT1("Color emulation\n");
1571
1572 /* Register the new I/O Ports */
1573 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1574 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1575 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1576
1577 /* Unregister the old ones */
1578 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1579 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1580 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1581 }
1582 else
1583 {
1584 /* Monochrome emulation */
1585 DPRINT1("Monochrome emulation\n");
1586
1587 /* Register the new I/O Ports */
1588 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1589 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1590 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1591
1592 /* Unregister the old ones */
1593 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1594 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1595 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1596 }
1597
1598 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1599 break;
1600 }
1601
1602 case VGA_FEATURE_WRITE_MONO:
1603 case VGA_FEATURE_WRITE_COLOR:
1604 {
1605 VgaFeatureRegister = Data;
1606 break;
1607 }
1608
1609 case VGA_AC_INDEX:
1610 // case VGA_AC_WRITE:
1611 {
1612 if (!VgaAcLatch)
1613 {
1614 /* Change the index */
1615 BYTE Index = Data & 0x1F;
1616 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1617
1618 /*
1619 * Change palette protection by checking for
1620 * the Palette Address Source bit.
1621 */
1622 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1623 }
1624 else
1625 {
1626 /* Write the data */
1627 VgaWriteAc(Data);
1628 }
1629
1630 /* Toggle the latch */
1631 VgaAcLatch = !VgaAcLatch;
1632 break;
1633 }
1634
1635 case VGA_SEQ_INDEX:
1636 {
1637 /* Set the sequencer index register */
1638 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1639 break;
1640 }
1641
1642 case VGA_SEQ_DATA:
1643 {
1644 /* Call the sequencer function */
1645 VgaWriteSequencer(Data);
1646 break;
1647 }
1648
1649 case VGA_DAC_MASK:
1650 {
1651 VgaDacMask = Data;
1652 break;
1653 }
1654
1655 case VGA_DAC_READ_INDEX:
1656 {
1657 VgaDacReadWrite = FALSE;
1658 VgaDacIndex = Data * 3;
1659 break;
1660 }
1661
1662 case VGA_DAC_WRITE_INDEX:
1663 {
1664 VgaDacReadWrite = TRUE;
1665 VgaDacIndex = Data * 3;
1666 break;
1667 }
1668
1669 case VGA_DAC_DATA:
1670 {
1671 /* Ignore writes in read mode */
1672 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1673 break;
1674 }
1675
1676 case VGA_CRTC_INDEX_MONO:
1677 case VGA_CRTC_INDEX_COLOR:
1678 {
1679 /* Set the CRTC index register */
1680 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1681 break;
1682 }
1683
1684 case VGA_CRTC_DATA_MONO:
1685 case VGA_CRTC_DATA_COLOR:
1686 {
1687 /* Call the CRTC function */
1688 VgaWriteCrtc(Data);
1689 break;
1690 }
1691
1692 case VGA_GC_INDEX:
1693 {
1694 /* Set the GC index register */
1695 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1696 break;
1697 }
1698
1699 case VGA_GC_DATA:
1700 {
1701 /* Call the GC function */
1702 VgaWriteGc(Data);
1703 break;
1704 }
1705
1706 default:
1707 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1708 break;
1709 }
1710 }
1711
1712 /* PUBLIC FUNCTIONS ***********************************************************/
1713
1714 DWORD VgaGetVideoBaseAddress(VOID)
1715 {
1716 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1717 }
1718
1719 DWORD VgaGetVideoLimitAddress(VOID)
1720 {
1721 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1722 }
1723
1724 COORD VgaGetDisplayResolution(VOID)
1725 {
1726 COORD Resolution;
1727 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1728
1729 /* The low 8 bits are in the display registers */
1730 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1731 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1732
1733 /* Set the top bits from the overflow register */
1734 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1735 {
1736 Resolution.Y |= 1 << 8;
1737 }
1738 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1739 {
1740 Resolution.Y |= 1 << 9;
1741 }
1742
1743 /* Increase the values by 1 */
1744 Resolution.X++;
1745 Resolution.Y++;
1746
1747 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1748 {
1749 /* Multiply the horizontal resolution by the 9/8 dot mode */
1750 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1751 ? 8 : 9;
1752
1753 /* The horizontal resolution is halved in 8-bit mode */
1754 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1755 }
1756
1757 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1758 {
1759 /* Halve the vertical resolution */
1760 Resolution.Y >>= 1;
1761 }
1762 else
1763 {
1764 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1765 Resolution.Y /= MaximumScanLine;
1766 }
1767
1768 /* Return the resolution */
1769 return Resolution;
1770 }
1771
1772 VOID VgaRefreshDisplay(VOID)
1773 {
1774 HANDLE ConsoleBufferHandle = NULL;
1775 COORD Resolution;
1776
1777 /* Set the vertical retrace flag */
1778 InVerticalRetrace = TRUE;
1779
1780 /* If nothing has changed, just return */
1781 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1782 // return;
1783
1784 /* Change the display mode */
1785 if (ModeChanged) VgaChangeMode();
1786
1787 /* Change the text cursor location */
1788 if (CursorMoved) VgaUpdateTextCursor();
1789
1790 /* Retrieve the current resolution */
1791 Resolution = VgaGetDisplayResolution();
1792
1793 if (PaletteChanged)
1794 {
1795 /* Trigger a full update of the screen */
1796 NeedsUpdate = TRUE;
1797 UpdateRectangle.Left = 0;
1798 UpdateRectangle.Top = 0;
1799 UpdateRectangle.Right = Resolution.X;
1800 UpdateRectangle.Bottom = Resolution.Y;
1801
1802 PaletteChanged = FALSE;
1803 }
1804
1805 /* Update the contents of the framebuffer */
1806 VgaUpdateFramebuffer();
1807
1808 /* Ignore if there's nothing to update */
1809 if (!NeedsUpdate) return;
1810
1811 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1812 UpdateRectangle.Left,
1813 UpdateRectangle.Top,
1814 UpdateRectangle.Right,
1815 UpdateRectangle.Bottom);
1816
1817 /* Check if this is text mode or graphics mode */
1818 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1819 {
1820 /* Graphics mode */
1821 ConsoleBufferHandle = GraphicsConsoleBuffer;
1822
1823 /* In DoubleVision mode, scale the update rectangle */
1824 if (DoubleWidth)
1825 {
1826 UpdateRectangle.Left *= 2;
1827 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1828 }
1829 if (DoubleHeight)
1830 {
1831 UpdateRectangle.Top *= 2;
1832 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1833 }
1834 }
1835 else
1836 {
1837 /* Text mode */
1838 ConsoleBufferHandle = TextConsoleBuffer;
1839 }
1840
1841 /* Redraw the screen */
1842 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1843
1844 /* Clear the update flag */
1845 NeedsUpdate = FALSE;
1846 }
1847
1848 VOID VgaHorizontalRetrace(VOID)
1849 {
1850 /* Set the flag */
1851 InHorizontalRetrace = TRUE;
1852 }
1853
1854 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1855 {
1856 DWORD i;
1857 DWORD VideoAddress;
1858
1859 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1860
1861 /* Ignore if video RAM access is disabled */
1862 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1863
1864 /* Loop through each byte */
1865 for (i = 0; i < Size; i++)
1866 {
1867 VideoAddress = VgaTranslateReadAddress(Address + i);
1868
1869 /* Load the latch registers */
1870 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1871 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1872 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1873 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1874
1875 /* Copy the value to the buffer */
1876 Buffer[i] = VgaMemory[VideoAddress];
1877 }
1878 }
1879
1880 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1881 {
1882 DWORD i, j;
1883 DWORD VideoAddress;
1884
1885 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1886
1887 /* Ignore if video RAM access is disabled */
1888 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1889
1890 /* Also ignore if write access to all planes is disabled */
1891 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1892
1893 /* Loop through each byte */
1894 for (i = 0; i < Size; i++)
1895 {
1896 VideoAddress = VgaTranslateWriteAddress(Address + i);
1897
1898 for (j = 0; j < VGA_NUM_BANKS; j++)
1899 {
1900 /* Make sure the page is writeable */
1901 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1902
1903 /* Check if this is chain-4 mode */
1904 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1905 {
1906 if (((Address + i) & 3) != j)
1907 {
1908 /* This plane will not be accessed */
1909 continue;
1910 }
1911 }
1912
1913 /* Check if this is odd-even mode */
1914 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1915 {
1916 if (((Address + i) & 1) != (j & 1))
1917 {
1918 /* This plane will not be accessed */
1919 continue;
1920 }
1921 }
1922
1923 /* Copy the value to the VGA memory */
1924 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1925 }
1926 }
1927 }
1928
1929 VOID VgaClearMemory(VOID)
1930 {
1931 RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
1932 }
1933
1934 VOID VgaResetPalette(VOID)
1935 {
1936 PALETTEENTRY Entries[VGA_MAX_COLORS];
1937
1938 /* Restore the default palette */
1939 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1940 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1941 PaletteChanged = TRUE;
1942 }
1943
1944 VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height)
1945 {
1946 UINT i, j;
1947 PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
1948
1949 ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
1950
1951 for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
1952 {
1953 /* Write the character */
1954 for (j = 0; j < Height; j++)
1955 {
1956 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
1957 }
1958
1959 /* Clear the unused part */
1960 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
1961 {
1962 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
1963 }
1964 }
1965 }
1966
1967 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
1968 {
1969 DPRINT1("Screen events not handled\n");
1970 }
1971
1972 BOOL VgaAttachToConsole(VOID)
1973 {
1974 //
1975 // FIXME: We should go back to the saved screen state
1976 //
1977 if (TextResolution.X == 0 || TextResolution.Y == 0)
1978 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1979
1980 if (TextResolution.X == 0) TextResolution.X = 80;
1981 if (TextResolution.Y == 0) TextResolution.Y = 25;
1982
1983 return VgaAttachToConsoleInternal(&TextResolution);
1984 }
1985
1986 VOID VgaDetachFromConsole(BOOL ChangingMode)
1987 {
1988 ULONG dummyLength;
1989 PVOID dummyPtr;
1990 COORD dummySize = {0};
1991
1992 //
1993 // FIXME: We should save the screen state
1994 //
1995
1996 __RegisterConsoleVDM(0,
1997 NULL,
1998 NULL,
1999 NULL,
2000 0,
2001 &dummyLength,
2002 &dummyPtr,
2003 NULL,
2004 0,
2005 dummySize,
2006 &dummyPtr);
2007
2008 TextFramebuffer = NULL;
2009
2010 if (!ChangingMode)
2011 {
2012 SMALL_RECT ConRect;
2013
2014 /* Restore the old screen buffer */
2015 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2016
2017 /* Restore the original console size */
2018 ConRect.Left = 0;
2019 ConRect.Top = 0;
2020 ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
2021 ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
2022 /*
2023 * See the following trick explanation in VgaAttachToConsoleInternal.
2024 */
2025 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
2026 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
2027 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
2028
2029 /* Restore the original cursor shape */
2030 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
2031 }
2032 }
2033
2034 BOOLEAN VgaInitialize(HANDLE TextHandle)
2035 {
2036 /* Save the default text-mode console output handle */
2037 if (!IsConsoleHandle(TextHandle)) return FALSE;
2038 TextConsoleBuffer = TextHandle;
2039
2040 /* Save the original cursor and console screen buffer information */
2041 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
2042 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
2043 {
2044 return FALSE;
2045 }
2046 ConsoleInfo = OrgConsoleBufferInfo;
2047
2048 /* Initialize the VGA palette and fail if it isn't successfully created */
2049 if (!VgaInitializePalette()) return FALSE;
2050 /***/ VgaResetPalette(); /***/
2051
2052 /* Switch to the text buffer */
2053 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2054
2055 /* Clear the VGA memory */
2056 VgaClearMemory();
2057
2058 /* Register the I/O Ports */
2059 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
2060 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2061 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
2062 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
2063 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
2064 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
2065 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
2066 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
2067 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
2068 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
2069 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
2070 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
2071 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
2072
2073 /* Return success */
2074 return TRUE;
2075 }
2076
2077 VOID VgaCleanup(VOID)
2078 {
2079 if (ScreenMode == GRAPHICS_MODE)
2080 {
2081 /* Leave the current graphics mode */
2082 VgaLeaveGraphicsMode();
2083 }
2084 else
2085 {
2086 /* Leave the current text mode */
2087 VgaLeaveTextMode();
2088 }
2089
2090 VgaDetachFromConsole(FALSE);
2091
2092 CloseHandle(AnotherEvent);
2093 CloseHandle(EndEvent);
2094 CloseHandle(StartEvent);
2095 }
2096
2097 /* EOF */