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