[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 the offset on plane 0 for read mode 1 */
648 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ) return Offset;
649 else return Offset + Plane * VGA_BANK_SIZE;
650 }
651
652 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
653 {
654 DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
655
656 /* Check for chain-4 and odd-even mode */
657 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
658 {
659 /* Clear the lowest two bits since they're used to select the bank */
660 Offset &= ~3;
661 }
662 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
663 {
664 /* Clear the lowest bit since it's used to select odd/even */
665 Offset &= ~1;
666 }
667
668 /* Return the offset on plane 0 */
669 return Offset;
670 }
671
672 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
673 {
674 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 0x03;
675 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
676
677 if (WriteMode == 1)
678 {
679 /* In write mode 1 just return the latch register */
680 return VgaLatchRegisters[Plane];
681 }
682
683 if (WriteMode != 2)
684 {
685 /* Write modes 0 and 3 rotate the data to the right first */
686 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 0x07;
687 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
688 }
689 else
690 {
691 /* Write mode 2 expands the appropriate bit to all 8 bits */
692 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
693 }
694
695 if (WriteMode == 0)
696 {
697 /*
698 * In write mode 0, the enable set/reset register decides if the
699 * set/reset bit should be expanded to all 8 bits.
700 */
701 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
702 {
703 /* Copy the bit from the set/reset register to all 8 bits */
704 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
705 }
706 }
707
708 if (WriteMode != 3)
709 {
710 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
711 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 0x03;
712
713 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
714 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
715 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
716 }
717 else
718 {
719 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
720 BitMask &= Data;
721
722 /* Then we expand the bit in the set/reset field */
723 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
724 }
725
726 /* Bits cleared in the bitmask are replaced with latch register bits */
727 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
728
729 /* Return the byte */
730 return Data;
731 }
732
733 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
734 {
735 /* Check if this is the first time the rectangle is updated */
736 if (!NeedsUpdate)
737 {
738 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
739 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
740 }
741
742 /* Expand the rectangle to include the point */
743 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
744 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
745 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
746 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
747
748 /* Set the update request flag */
749 NeedsUpdate = TRUE;
750 }
751
752 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
753 {
754 USHORT i;
755
756 /* Copy the colors of the default palette to the DAC and console palette */
757 for (i = 0; i < NumOfEntries; i++)
758 {
759 /* Set the palette entries */
760 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
761 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
762 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
763 Entries[i].peFlags = 0;
764
765 /* Set the DAC registers */
766 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
767 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
768 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
769 }
770 }
771
772 static BOOLEAN VgaInitializePalette(VOID)
773 {
774 INT i;
775 BOOLEAN Result = FALSE;
776 LPLOGPALETTE Palette, TextPalette;
777
778 /* Allocate storage space for the palettes */
779 Palette = RtlAllocateHeap(RtlGetProcessHeap(),
780 HEAP_ZERO_MEMORY,
781 sizeof(LOGPALETTE) +
782 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
783 TextPalette = RtlAllocateHeap(RtlGetProcessHeap(),
784 HEAP_ZERO_MEMORY,
785 sizeof(LOGPALETTE) +
786 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
787 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
788
789 /* Initialize the palettes */
790 Palette->palVersion = TextPalette->palVersion = 0x0300;
791 Palette->palNumEntries = VGA_MAX_COLORS;
792 TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1;
793
794 /* Restore the default graphics palette */
795 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
796
797 /* Set the default text palette */
798 for (i = 0; i < TextPalette->palNumEntries; i++)
799 {
800 /* Set the palette entries */
801 TextPalette->palPalEntry[i].peRed = GetRValue(ConsoleColors[i]);
802 TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]);
803 TextPalette->palPalEntry[i].peBlue = GetBValue(ConsoleColors[i]);
804 TextPalette->palPalEntry[i].peFlags = 0;
805 }
806
807 /* Create the palettes */
808 PaletteHandle = CreatePalette(Palette);
809 TextPaletteHandle = CreatePalette(TextPalette);
810
811 if (PaletteHandle != NULL && TextPaletteHandle != NULL)
812 {
813 /* The palettes have been created successfully */
814 Result = TRUE;
815 }
816
817 Cleanup:
818 /* Free the palettes */
819 if (Palette) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette);
820 if (TextPalette) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette);
821
822 if (!Result)
823 {
824 /* Something failed, delete the palettes */
825 if (PaletteHandle) DeleteObject(PaletteHandle);
826 if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
827 }
828
829 return Result;
830 }
831
832 static VOID VgaResetPalette(VOID)
833 {
834 PALETTEENTRY Entries[VGA_MAX_COLORS];
835
836 /* Restore the default palette */
837 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
838 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
839 PaletteChanged = TRUE;
840 }
841
842 static VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
843 {
844 /* Set the active buffer */
845 SetConsoleActiveScreenBuffer(ScreenBuffer);
846
847 /* Reinitialize the VDM menu */
848 DestroyVdmMenu();
849 CreateVdmMenu(ScreenBuffer);
850 }
851
852 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
853 {
854 DWORD i;
855 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
856 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
857 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
858 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
859
860 LONG Width = Resolution->X;
861 LONG Height = Resolution->Y;
862
863 /* Use DoubleVision mode if the resolution is too small */
864 DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
865 if (DoubleWidth) Width *= 2;
866 DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
867 if (DoubleHeight) Height *= 2;
868
869 /* Fill the bitmap info header */
870 RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
871 BitmapInfo->bmiHeader.biSize = sizeof(BitmapInfo->bmiHeader);
872 BitmapInfo->bmiHeader.biWidth = Width;
873 BitmapInfo->bmiHeader.biHeight = Height;
874 BitmapInfo->bmiHeader.biBitCount = 8;
875 BitmapInfo->bmiHeader.biPlanes = 1;
876 BitmapInfo->bmiHeader.biCompression = BI_RGB;
877 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
878
879 /* Fill the palette data */
880 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
881
882 /* Fill the console graphics buffer info */
883 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
884 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
885 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
886
887 /* Create the buffer */
888 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
889 FILE_SHARE_READ | FILE_SHARE_WRITE,
890 NULL,
891 CONSOLE_GRAPHICS_BUFFER,
892 &GraphicsBufferInfo);
893 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
894
895 /* Save the framebuffer address and mutex */
896 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
897 ConsoleMutex = GraphicsBufferInfo.hMutex;
898
899 /* Clear the framebuffer */
900 RtlZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
901
902 /* Set the active buffer */
903 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
904
905 /* Set the graphics mode palette */
906 SetConsolePalette(GraphicsConsoleBuffer,
907 PaletteHandle,
908 SYSPAL_NOSTATIC256);
909
910 /* Set the screen mode flag */
911 ScreenMode = GRAPHICS_MODE;
912
913 return TRUE;
914 }
915
916 static VOID VgaLeaveGraphicsMode(VOID)
917 {
918 /* Release the console framebuffer mutex */
919 ReleaseMutex(ConsoleMutex);
920
921 /* Switch back to the default console text buffer */
922 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
923
924 /* Cleanup the video data */
925 CloseHandle(ConsoleMutex);
926 ConsoleMutex = NULL;
927 ConsoleFramebuffer = NULL;
928 CloseHandle(GraphicsConsoleBuffer);
929 GraphicsConsoleBuffer = NULL;
930
931 DoubleWidth = FALSE;
932 DoubleHeight = FALSE;
933 }
934
935 static BOOL VgaEnterTextMode(PCOORD Resolution)
936 {
937 /* Switch to the text buffer */
938 VgaSetActiveScreenBuffer(TextConsoleBuffer);
939
940 /* Adjust the text framebuffer if we changed the resolution */
941 if (TextResolution.X != Resolution->X ||
942 TextResolution.Y != Resolution->Y)
943 {
944 VgaDetachFromConsole(TRUE);
945
946 /*
947 * VgaAttachToConsoleInternal sets TextResolution to the
948 * new resolution and updates ConsoleInfo.
949 */
950 if (!VgaAttachToConsoleInternal(Resolution))
951 {
952 DisplayMessage(L"An unexpected error occurred!\n");
953 EmulatorTerminate();
954 return FALSE;
955 }
956 }
957 else
958 {
959 VgaUpdateCursorPosition();
960 }
961
962 /* The active framebuffer is now the text framebuffer */
963 ConsoleFramebuffer = TextFramebuffer;
964
965 /*
966 * Set the text mode palette.
967 *
968 * WARNING: This call should fail on Windows (and therefore
969 * we get the default palette and our external behaviour is
970 * just like Windows' one), but it should success on ReactOS
971 * (so that we get console palette changes even for text-mode
972 * screen-buffers, which is a new feature on ReactOS).
973 */
974 SetConsolePalette(TextConsoleBuffer,
975 TextPaletteHandle,
976 SYSPAL_NOSTATIC256);
977
978 /* Set the screen mode flag */
979 ScreenMode = TEXT_MODE;
980
981 return TRUE;
982 }
983
984 static VOID VgaLeaveTextMode(VOID)
985 {
986 /* Reset the active framebuffer */
987 ConsoleFramebuffer = NULL;
988 }
989
990 static VOID VgaChangeMode(VOID)
991 {
992 COORD NewResolution = VgaGetDisplayResolution();
993 SCREEN_MODE NewScreenMode =
994 !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE
995 : GRAPHICS_MODE;
996
997 /*
998 * No need to switch to a different screen mode + resolution
999 * if the new ones are the same as the old ones.
1000 */
1001 if ((ScreenMode == NewScreenMode) &&
1002 (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y))
1003 {
1004 goto Quit;
1005 }
1006
1007 if (ScreenMode == GRAPHICS_MODE)
1008 {
1009 /* Leave the current graphics mode */
1010 VgaLeaveGraphicsMode();
1011 }
1012 else
1013 {
1014 /* Leave the current text mode */
1015 VgaLeaveTextMode();
1016 }
1017
1018 /* Update the current resolution */
1019 CurrResolution = NewResolution;
1020
1021 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1022
1023 /* Check if the new mode is alphanumeric */
1024 if (NewScreenMode == TEXT_MODE)
1025 {
1026 /* Enter new text mode */
1027 if (!VgaEnterTextMode(&CurrResolution))
1028 {
1029 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1030 EmulatorTerminate();
1031 return;
1032 }
1033 }
1034 else
1035 {
1036 /* Enter graphics mode */
1037 if (!VgaEnterGraphicsMode(&CurrResolution))
1038 {
1039 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1040 EmulatorTerminate();
1041 return;
1042 }
1043 }
1044
1045 Quit:
1046
1047 /* Trigger a full update of the screen */
1048 NeedsUpdate = TRUE;
1049 UpdateRectangle.Left = 0;
1050 UpdateRectangle.Top = 0;
1051 UpdateRectangle.Right = CurrResolution.X;
1052 UpdateRectangle.Bottom = CurrResolution.Y;
1053
1054 /* Reset the mode change flag */
1055 ModeChanged = FALSE;
1056 }
1057
1058 static VOID VgaUpdateFramebuffer(VOID)
1059 {
1060 SHORT i, j, k;
1061 DWORD AddressSize = VgaGetAddressSize();
1062 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1063 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
1064 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1065
1066 /*
1067 * If console framebuffer is NULL, that means something went wrong
1068 * earlier and this is the final display refresh.
1069 */
1070 if (ConsoleFramebuffer == NULL) return;
1071
1072 /* Check if we are in text or graphics mode */
1073 if (ScreenMode == GRAPHICS_MODE)
1074 {
1075 /* Graphics mode */
1076 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1077 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
1078
1079 /*
1080 * Synchronize access to the graphics framebuffer
1081 * with the console framebuffer mutex.
1082 */
1083 WaitForSingleObject(ConsoleMutex, INFINITE);
1084
1085 /* Shift the high bit right by 1 in odd/even mode */
1086 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1087 {
1088 InterlaceHighBit >>= 1;
1089 }
1090
1091 /* Loop through the scanlines */
1092 for (i = 0; i < CurrResolution.Y; i++)
1093 {
1094 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1095 {
1096 /* Odd-numbered line in interlaced mode - set the high bit */
1097 Address |= InterlaceHighBit;
1098 }
1099
1100 /* Loop through the pixels */
1101 for (j = 0; j < CurrResolution.X; j++)
1102 {
1103 BYTE PixelData = 0;
1104
1105 /* Check the shifting mode */
1106 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1107 {
1108 /* 4 bits shifted from each plane */
1109
1110 /* Check if this is 16 or 256 color mode */
1111 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1112 {
1113 /* One byte per pixel */
1114 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1115 + LOWORD((Address + (j / VGA_NUM_BANKS))
1116 * AddressSize)];
1117 }
1118 else
1119 {
1120 /* 4-bits per pixel */
1121
1122 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1123 + LOWORD((Address + (j / (VGA_NUM_BANKS * 2)))
1124 * AddressSize)];
1125
1126 /* Check if we should use the highest 4 bits or lowest 4 */
1127 if (((j / VGA_NUM_BANKS) % 2) == 0)
1128 {
1129 /* Highest 4 */
1130 PixelData >>= 4;
1131 }
1132 else
1133 {
1134 /* Lowest 4 */
1135 PixelData &= 0x0F;
1136 }
1137 }
1138 }
1139 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1140 {
1141 /* Check if this is 16 or 256 color mode */
1142 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1143 {
1144 // TODO: NOT IMPLEMENTED
1145 DPRINT1("8-bit interleaved mode is not implemented!\n");
1146 }
1147 else
1148 {
1149 /*
1150 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1151 * then 2 bits shifted from plane 1 and 3 for the next 4
1152 */
1153 DWORD BankNumber = (j / 4) % 2;
1154 DWORD Offset = Address + (j / 8);
1155 BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
1156 BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
1157
1158 /* Extract the two bits from each plane */
1159 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 0x03;
1160 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 0x03;
1161
1162 /* Combine them into the pixel */
1163 PixelData = LowPlaneData | (HighPlaneData << 2);
1164 }
1165 }
1166 else
1167 {
1168 /* 1 bit shifted from each plane */
1169
1170 /* Check if this is 16 or 256 color mode */
1171 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1172 {
1173 /* 8 bits per pixel, 2 on each plane */
1174
1175 for (k = 0; k < VGA_NUM_BANKS; k++)
1176 {
1177 /* The data is on plane k, 4 pixels per byte */
1178 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1179 + LOWORD((Address + (j / VGA_NUM_BANKS))
1180 * AddressSize)];
1181
1182 /* The mask of the first bit in the pair */
1183 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
1184
1185 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1186 if (PlaneData & BitMask) PixelData |= 1 << k;
1187
1188 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1189 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1190 }
1191 }
1192 else
1193 {
1194 /* 4 bits per pixel, 1 on each plane */
1195
1196 for (k = 0; k < VGA_NUM_BANKS; k++)
1197 {
1198 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1199 + LOWORD((Address + (j / (VGA_NUM_BANKS * 2)))
1200 * AddressSize)];
1201
1202 /* If the bit on that plane is set, set it */
1203 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
1204 }
1205 }
1206 }
1207
1208 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1209 {
1210 /*
1211 * In 16 color mode, the value is an index to the AC registers
1212 * if external palette access is disabled, otherwise (in case
1213 * of palette loading) it is a blank pixel.
1214 */
1215 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1216 : 0);
1217 }
1218
1219 /* Take into account DoubleVision mode when checking for pixel updates */
1220 if (DoubleWidth && DoubleHeight)
1221 {
1222 /* Now check if the resulting pixel data has changed */
1223 if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData)
1224 {
1225 /* Yes, write the new value */
1226 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] = PixelData;
1227 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1228 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2)] = PixelData;
1229 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1230
1231 /* Mark the specified pixel as changed */
1232 VgaMarkForUpdate(i, j);
1233 }
1234 }
1235 else if (DoubleWidth && !DoubleHeight)
1236 {
1237 /* Now check if the resulting pixel data has changed */
1238 if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData)
1239 {
1240 /* Yes, write the new value */
1241 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] = PixelData;
1242 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1243
1244 /* Mark the specified pixel as changed */
1245 VgaMarkForUpdate(i, j);
1246 }
1247 }
1248 else if (!DoubleWidth && DoubleHeight)
1249 {
1250 /* Now check if the resulting pixel data has changed */
1251 if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData)
1252 {
1253 /* Yes, write the new value */
1254 GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData;
1255 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData;
1256
1257 /* Mark the specified pixel as changed */
1258 VgaMarkForUpdate(i, j);
1259 }
1260 }
1261 else // if (!DoubleWidth && !DoubleHeight)
1262 {
1263 /* Now check if the resulting pixel data has changed */
1264 if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData)
1265 {
1266 /* Yes, write the new value */
1267 GraphicsBuffer[i * CurrResolution.X + j] = PixelData;
1268
1269 /* Mark the specified pixel as changed */
1270 VgaMarkForUpdate(i, j);
1271 }
1272 }
1273 }
1274
1275 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1276 {
1277 /* Clear the high bit */
1278 Address &= ~InterlaceHighBit;
1279 }
1280
1281 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1282 {
1283 /* Move to the next scanline */
1284 Address += ScanlineSize;
1285 }
1286 }
1287
1288 /*
1289 * Release the console framebuffer mutex
1290 * so that we allow for repainting.
1291 */
1292 ReleaseMutex(ConsoleMutex);
1293 }
1294 else
1295 {
1296 /* Text mode */
1297 DWORD CurrentAddr;
1298 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1299 CHAR_CELL CharInfo;
1300
1301 /* Loop through the scanlines */
1302 for (i = 0; i < CurrResolution.Y; i++)
1303 {
1304 /* Loop through the characters */
1305 for (j = 0; j < CurrResolution.X; j++)
1306 {
1307 CurrentAddr = LOWORD((Address + j) * AddressSize);
1308
1309 /* Plane 0 holds the character itself */
1310 CharInfo.Char = VgaMemory[CurrentAddr];
1311
1312 /* Plane 1 holds the attribute */
1313 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1314
1315 /* Now check if the resulting character data has changed */
1316 if ((CharBuffer[i * CurrResolution.X + j].Char != CharInfo.Char) ||
1317 (CharBuffer[i * CurrResolution.X + j].Attributes != CharInfo.Attributes))
1318 {
1319 /* Yes, write the new value */
1320 CharBuffer[i * CurrResolution.X + j] = CharInfo;
1321
1322 /* Mark the specified cell as changed */
1323 VgaMarkForUpdate(i, j);
1324 }
1325 }
1326
1327 /* Move to the next scanline */
1328 Address += ScanlineSize;
1329 }
1330 }
1331 }
1332
1333 static VOID VgaUpdateTextCursor(VOID)
1334 {
1335 COORD Position;
1336 CONSOLE_CURSOR_INFO CursorInfo;
1337
1338 BOOL CursorVisible = !(VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x20);
1339 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x1F;
1340 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1341
1342 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1343 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1344 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1345 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1346
1347 /* Just return if we are not in text mode */
1348 if (ScreenMode != TEXT_MODE) return;
1349
1350 if (CursorStart < CursorEnd)
1351 {
1352 /* Visible cursor */
1353 CursorInfo.bVisible = CursorVisible;
1354 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1355 }
1356 else
1357 {
1358 /* Hidden cursor */
1359 CursorInfo.bVisible = FALSE;
1360 CursorInfo.dwSize = 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1361 }
1362
1363 /* Add the cursor skew to the location */
1364 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
1365
1366 /* Find the coordinates of the new position */
1367 Position.X = (SHORT)(Location % ScanlineSize);
1368 Position.Y = (SHORT)(Location / ScanlineSize);
1369
1370 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position.X, Position.Y);
1371
1372 /* Update the physical cursor */
1373 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1374 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1375
1376 /* Reset the cursor changed flag */
1377 CursorChanged = FALSE;
1378 }
1379
1380 static BYTE WINAPI VgaReadPort(USHORT Port)
1381 {
1382 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1383
1384 switch (Port)
1385 {
1386 case VGA_MISC_READ:
1387 return VgaMiscRegister;
1388
1389 case VGA_INSTAT0_READ:
1390 return 0; // Not implemented
1391
1392 case VGA_INSTAT1_READ_MONO:
1393 case VGA_INSTAT1_READ_COLOR:
1394 {
1395 BYTE Result = 0;
1396
1397 /* Reset the AC latch */
1398 VgaAcLatch = FALSE;
1399
1400 /* Set a flag if there is a vertical or horizontal retrace */
1401 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1402
1403 /* Set an additional flag if there was a vertical retrace */
1404 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1405
1406 /* Clear the flags */
1407 InHorizontalRetrace = InVerticalRetrace = FALSE;
1408
1409 return Result;
1410 }
1411
1412 case VGA_FEATURE_READ:
1413 return VgaFeatureRegister;
1414
1415 case VGA_AC_INDEX:
1416 return VgaAcIndex;
1417
1418 case VGA_AC_READ:
1419 return VgaAcRegisters[VgaAcIndex];
1420
1421 case VGA_SEQ_INDEX:
1422 return VgaSeqIndex;
1423
1424 case VGA_SEQ_DATA:
1425 return VgaSeqRegisters[VgaSeqIndex];
1426
1427 case VGA_DAC_MASK:
1428 return VgaDacMask;
1429
1430 case VGA_DAC_READ_INDEX:
1431 /* This returns the read/write state */
1432 return (VgaDacReadWrite ? 0 : 3);
1433
1434 case VGA_DAC_WRITE_INDEX:
1435 return (VgaDacIndex / 3);
1436
1437 case VGA_DAC_DATA:
1438 {
1439 /* Ignore reads in write mode */
1440 if (!VgaDacReadWrite)
1441 {
1442 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1443 VgaDacIndex %= VGA_PALETTE_SIZE;
1444 return Data;
1445 }
1446
1447 break;
1448 }
1449
1450 case VGA_CRTC_INDEX_MONO:
1451 case VGA_CRTC_INDEX_COLOR:
1452 return VgaCrtcIndex;
1453
1454 case VGA_CRTC_DATA_MONO:
1455 case VGA_CRTC_DATA_COLOR:
1456 return VgaCrtcRegisters[VgaCrtcIndex];
1457
1458 case VGA_GC_INDEX:
1459 return VgaGcIndex;
1460
1461 case VGA_GC_DATA:
1462 return VgaGcRegisters[VgaGcIndex];
1463
1464 default:
1465 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1466 break;
1467 }
1468
1469 return 0;
1470 }
1471
1472 static inline VOID VgaWriteSequencer(BYTE Data)
1473 {
1474 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
1475
1476 /* Save the value */
1477 VgaSeqRegisters[VgaSeqIndex] = Data;
1478 }
1479
1480 static inline VOID VgaWriteGc(BYTE Data)
1481 {
1482 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
1483
1484 /* Save the value */
1485 VgaGcRegisters[VgaGcIndex] = Data;
1486
1487 /* Check the index */
1488 switch (VgaGcIndex)
1489 {
1490 case VGA_GC_MISC_REG:
1491 {
1492 /* The GC misc register decides if it's text or graphics mode */
1493 ModeChanged = TRUE;
1494 break;
1495 }
1496 }
1497 }
1498
1499 static inline VOID VgaWriteCrtc(BYTE Data)
1500 {
1501 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
1502
1503 /* Save the value */
1504 VgaCrtcRegisters[VgaCrtcIndex] = Data;
1505
1506 /* Check the index */
1507 switch (VgaCrtcIndex)
1508 {
1509 case VGA_CRTC_END_HORZ_DISP_REG:
1510 case VGA_CRTC_VERT_DISP_END_REG:
1511 case VGA_CRTC_OVERFLOW_REG:
1512 case VGA_CRTC_MAX_SCAN_LINE_REG:
1513 {
1514 /* The video mode has changed */
1515 ModeChanged = TRUE;
1516 break;
1517 }
1518
1519 case VGA_CRTC_CURSOR_LOC_LOW_REG:
1520 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
1521 case VGA_CRTC_CURSOR_START_REG:
1522 case VGA_CRTC_CURSOR_END_REG:
1523 {
1524 /* Set the cursor changed flag */
1525 CursorChanged = TRUE;
1526 break;
1527 }
1528 }
1529 }
1530
1531 static inline VOID VgaWriteDac(BYTE Data)
1532 {
1533 INT i, PaletteIndex;
1534 PALETTEENTRY Entry;
1535
1536 /* Set the value */
1537 VgaDacRegisters[VgaDacIndex] = Data;
1538
1539 /* Find the palette index */
1540 PaletteIndex = VgaDacIndex / 3;
1541
1542 /* Fill the entry structure */
1543 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
1544 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
1545 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
1546 Entry.peFlags = 0;
1547
1548 /* Update the palette entry */
1549 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
1550
1551 /* Check which text palette entries are affected */
1552 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1553 {
1554 if (VgaAcRegisters[i] == PaletteIndex)
1555 {
1556 /* Update the text palette entry */
1557 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
1558 }
1559 }
1560
1561 /* Set the palette changed flag */
1562 PaletteChanged = TRUE;
1563
1564 /* Update the index */
1565 VgaDacIndex++;
1566 VgaDacIndex %= VGA_PALETTE_SIZE;
1567 }
1568
1569 static inline VOID VgaWriteAc(BYTE Data)
1570 {
1571 PALETTEENTRY Entry;
1572
1573 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
1574
1575 /* Save the value */
1576 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
1577 {
1578 if (VgaAcPalDisable) return;
1579
1580 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1581 if (VgaAcRegisters[VgaAcIndex] != Data)
1582 {
1583 /* Update the AC register */
1584 VgaAcRegisters[VgaAcIndex] = Data;
1585
1586 /* Fill the entry structure */
1587 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]);
1588 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]);
1589 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]);
1590 Entry.peFlags = 0;
1591
1592 /* Update the palette entry and set the palette change flag */
1593 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
1594 PaletteChanged = TRUE;
1595 }
1596 }
1597 else
1598 {
1599 VgaAcRegisters[VgaAcIndex] = Data;
1600 }
1601 }
1602
1603 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1604 {
1605 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1606
1607 switch (Port)
1608 {
1609 case VGA_MISC_WRITE:
1610 {
1611 VgaMiscRegister = Data;
1612
1613 if (VgaMiscRegister & 0x01)
1614 {
1615 /* Color emulation */
1616 DPRINT1("Color emulation\n");
1617
1618 /* Register the new I/O Ports */
1619 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1620 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1621 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1622
1623 /* Unregister the old ones */
1624 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1625 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1626 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1627 }
1628 else
1629 {
1630 /* Monochrome emulation */
1631 DPRINT1("Monochrome emulation\n");
1632
1633 /* Register the new I/O Ports */
1634 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1635 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1636 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1637
1638 /* Unregister the old ones */
1639 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1640 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1641 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1642 }
1643
1644 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1645 break;
1646 }
1647
1648 case VGA_FEATURE_WRITE_MONO:
1649 case VGA_FEATURE_WRITE_COLOR:
1650 {
1651 VgaFeatureRegister = Data;
1652 break;
1653 }
1654
1655 case VGA_AC_INDEX:
1656 // case VGA_AC_WRITE:
1657 {
1658 if (!VgaAcLatch)
1659 {
1660 /* Change the index */
1661 BYTE Index = Data & 0x1F;
1662 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1663
1664 /*
1665 * Change palette protection by checking for
1666 * the Palette Address Source bit.
1667 */
1668 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1669 }
1670 else
1671 {
1672 /* Write the data */
1673 VgaWriteAc(Data);
1674 }
1675
1676 /* Toggle the latch */
1677 VgaAcLatch = !VgaAcLatch;
1678 break;
1679 }
1680
1681 case VGA_SEQ_INDEX:
1682 {
1683 /* Set the sequencer index register */
1684 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1685 break;
1686 }
1687
1688 case VGA_SEQ_DATA:
1689 {
1690 /* Call the sequencer function */
1691 VgaWriteSequencer(Data);
1692 break;
1693 }
1694
1695 case VGA_DAC_MASK:
1696 {
1697 VgaDacMask = Data;
1698 break;
1699 }
1700
1701 case VGA_DAC_READ_INDEX:
1702 {
1703 VgaDacReadWrite = FALSE;
1704 VgaDacIndex = Data * 3;
1705 break;
1706 }
1707
1708 case VGA_DAC_WRITE_INDEX:
1709 {
1710 VgaDacReadWrite = TRUE;
1711 VgaDacIndex = Data * 3;
1712 break;
1713 }
1714
1715 case VGA_DAC_DATA:
1716 {
1717 /* Ignore writes in read mode */
1718 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1719 break;
1720 }
1721
1722 case VGA_CRTC_INDEX_MONO:
1723 case VGA_CRTC_INDEX_COLOR:
1724 {
1725 /* Set the CRTC index register */
1726 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1727 break;
1728 }
1729
1730 case VGA_CRTC_DATA_MONO:
1731 case VGA_CRTC_DATA_COLOR:
1732 {
1733 /* Call the CRTC function */
1734 VgaWriteCrtc(Data);
1735 break;
1736 }
1737
1738 case VGA_GC_INDEX:
1739 {
1740 /* Set the GC index register */
1741 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1742 break;
1743 }
1744
1745 case VGA_GC_DATA:
1746 {
1747 /* Call the GC function */
1748 VgaWriteGc(Data);
1749 break;
1750 }
1751
1752 default:
1753 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data);
1754 break;
1755 }
1756 }
1757
1758 static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
1759 {
1760 HANDLE ConsoleBufferHandle = NULL;
1761
1762 UNREFERENCED_PARAMETER(ElapsedTime);
1763
1764 /* Set the vertical retrace flag */
1765 InVerticalRetrace = TRUE;
1766
1767 /* If nothing has changed, just return */
1768 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1769 // return;
1770
1771 /* Change the display mode */
1772 if (ModeChanged) VgaChangeMode();
1773
1774 /* Change the text cursor appearance */
1775 if (CursorChanged) VgaUpdateTextCursor();
1776
1777 if (PaletteChanged)
1778 {
1779 /* Trigger a full update of the screen */
1780 NeedsUpdate = TRUE;
1781 UpdateRectangle.Left = 0;
1782 UpdateRectangle.Top = 0;
1783 UpdateRectangle.Right = CurrResolution.X;
1784 UpdateRectangle.Bottom = CurrResolution.Y;
1785
1786 PaletteChanged = FALSE;
1787 }
1788
1789 /* Update the contents of the framebuffer */
1790 VgaUpdateFramebuffer();
1791
1792 /* Ignore if there's nothing to update */
1793 if (!NeedsUpdate) return;
1794
1795 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1796 UpdateRectangle.Left,
1797 UpdateRectangle.Top,
1798 UpdateRectangle.Right,
1799 UpdateRectangle.Bottom);
1800
1801 /* Check if we are in text or graphics mode */
1802 if (ScreenMode == GRAPHICS_MODE)
1803 {
1804 /* Graphics mode */
1805 ConsoleBufferHandle = GraphicsConsoleBuffer;
1806
1807 /* In DoubleVision mode, scale the update rectangle */
1808 if (DoubleWidth)
1809 {
1810 UpdateRectangle.Left *= 2;
1811 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1812 }
1813 if (DoubleHeight)
1814 {
1815 UpdateRectangle.Top *= 2;
1816 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1817 }
1818 }
1819 else
1820 {
1821 /* Text mode */
1822 ConsoleBufferHandle = TextConsoleBuffer;
1823 }
1824
1825 /* Redraw the screen */
1826 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1827
1828 /* Clear the update flag */
1829 NeedsUpdate = FALSE;
1830 }
1831
1832 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
1833 {
1834 UNREFERENCED_PARAMETER(ElapsedTime);
1835
1836 /* Set the flag */
1837 InHorizontalRetrace = TRUE;
1838 }
1839
1840 /* PUBLIC FUNCTIONS ***********************************************************/
1841
1842 COORD VgaGetDisplayResolution(VOID)
1843 {
1844 COORD Resolution;
1845 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1846
1847 /* The low 8 bits are in the display registers */
1848 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1849 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1850
1851 /* Set the top bits from the overflow register */
1852 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1853 {
1854 Resolution.Y |= 1 << 8;
1855 }
1856 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1857 {
1858 Resolution.Y |= 1 << 9;
1859 }
1860
1861 /* Increase the values by 1 */
1862 Resolution.X++;
1863 Resolution.Y++;
1864
1865 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1866 {
1867 /* Multiply the horizontal resolution by the 9/8 dot mode */
1868 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1869 ? 8 : 9;
1870
1871 /* The horizontal resolution is halved in 8-bit mode */
1872 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1873 }
1874
1875 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1876 {
1877 /* Halve the vertical resolution */
1878 Resolution.Y >>= 1;
1879 }
1880 else
1881 {
1882 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1883 Resolution.Y /= MaximumScanLine;
1884 }
1885
1886 /* Return the resolution */
1887 return Resolution;
1888 }
1889
1890 BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
1891 {
1892 if (GraphicsConsoleBuffer == NULL) return FALSE;
1893 if (Horizontal) *Horizontal = DoubleWidth;
1894 if (Vertical) *Vertical = DoubleHeight;
1895 return TRUE;
1896 }
1897
1898 VOID VgaRefreshDisplay(VOID)
1899 {
1900 VgaVerticalRetrace(0);
1901 }
1902
1903 VOID NTAPI VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
1904 {
1905 DWORD i, j;
1906 DWORD VideoAddress;
1907 PUCHAR BufPtr = (PUCHAR)Buffer;
1908
1909 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1910
1911 /* Ignore if video RAM access is disabled */
1912 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1913
1914 if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ))
1915 {
1916 /* Loop through each byte */
1917 for (i = 0; i < Size; i++)
1918 {
1919 VideoAddress = VgaTranslateReadAddress(Address + i);
1920
1921 /* Copy the value to the buffer */
1922 BufPtr[i] = VgaMemory[VideoAddress];
1923 }
1924 }
1925 else
1926 {
1927 /* Loop through each byte */
1928 for (i = 0; i < Size; i++)
1929 {
1930 BYTE Result = 0xFF;
1931
1932 /* This should always return a plane 0 address for read mode 1 */
1933 VideoAddress = VgaTranslateReadAddress(Address + i);
1934
1935 for (j = 0; j < VGA_NUM_BANKS; j++)
1936 {
1937 /* Don't consider ignored banks */
1938 if (!(VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & (1 << j))) continue;
1939
1940 if (VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & (1 << j))
1941 {
1942 /* Comparing with 11111111 */
1943 Result &= VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)];
1944 }
1945 else
1946 {
1947 /* Comparing with 00000000 */
1948 Result &= ~(VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)]);
1949 }
1950 }
1951
1952 /* Copy the value to the buffer */
1953 BufPtr[i] = Result;
1954 }
1955 }
1956
1957 /* Load the latch registers */
1958 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1959 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1960 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1961 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1962 }
1963
1964 BOOLEAN NTAPI VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
1965 {
1966 DWORD i, j;
1967 DWORD VideoAddress;
1968 PUCHAR BufPtr = (PUCHAR)Buffer;
1969
1970 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1971
1972 /* Ignore if video RAM access is disabled */
1973 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
1974
1975 /* Also ignore if write access to all planes is disabled */
1976 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
1977
1978 /* Loop through each byte */
1979 for (i = 0; i < Size; i++)
1980 {
1981 VideoAddress = VgaTranslateWriteAddress(Address + i);
1982
1983 for (j = 0; j < VGA_NUM_BANKS; j++)
1984 {
1985 /* Make sure the page is writeable */
1986 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1987
1988 /* Check if this is chain-4 mode */
1989 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1990 {
1991 if (((Address + i) & 0x03) != j)
1992 {
1993 /* This plane will not be accessed */
1994 continue;
1995 }
1996 }
1997
1998 /* Check if this is odd-even mode */
1999 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
2000 {
2001 if (((Address + i) & 0x01) != (j & 1))
2002 {
2003 /* This plane will not be accessed */
2004 continue;
2005 }
2006 }
2007
2008 /* Copy the value to the VGA memory */
2009 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j);
2010 }
2011 }
2012
2013 return TRUE;
2014 }
2015
2016 VOID VgaClearMemory(VOID)
2017 {
2018 RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
2019 }
2020
2021 VOID VgaWriteFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height)
2022 {
2023 UINT i, j;
2024 PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
2025
2026 ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
2027
2028 for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
2029 {
2030 /* Write the character */
2031 for (j = 0; j < Height; j++)
2032 {
2033 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
2034 }
2035
2036 /* Clear the unused part */
2037 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
2038 {
2039 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
2040 }
2041 }
2042 }
2043
2044 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
2045 {
2046 DPRINT1("Screen events not handled\n");
2047 }
2048
2049 BOOL VgaAttachToConsole(VOID)
2050 {
2051 //
2052 // FIXME: We should go back to the saved screen state
2053 //
2054 if (TextResolution.X == 0 || TextResolution.Y == 0)
2055 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2056
2057 if (TextResolution.X == 0) TextResolution.X = 80;
2058 if (TextResolution.Y == 0) TextResolution.Y = 25;
2059
2060 return VgaAttachToConsoleInternal(&TextResolution);
2061 }
2062
2063 VOID VgaDetachFromConsole(BOOL ChangingMode)
2064 {
2065 ULONG dummyLength;
2066 PVOID dummyPtr;
2067 COORD dummySize = {0};
2068
2069 //
2070 // FIXME: We should save the screen state
2071 //
2072
2073 __RegisterConsoleVDM(0,
2074 NULL,
2075 NULL,
2076 NULL,
2077 0,
2078 &dummyLength,
2079 &dummyPtr,
2080 NULL,
2081 0,
2082 dummySize,
2083 &dummyPtr);
2084
2085 TextFramebuffer = NULL;
2086
2087 if (!ChangingMode)
2088 {
2089 SMALL_RECT ConRect;
2090
2091 /* Restore the old screen buffer */
2092 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2093
2094 /* Restore the original console size */
2095 ConRect.Left = 0;
2096 ConRect.Top = 0;
2097 ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
2098 ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
2099 /*
2100 * See the following trick explanation in VgaAttachToConsoleInternal.
2101 */
2102 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
2103 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
2104 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
2105
2106 /* Restore the original cursor shape */
2107 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
2108 }
2109 }
2110
2111 BOOLEAN VgaInitialize(HANDLE TextHandle)
2112 {
2113 /* Save the default text-mode console output handle */
2114 if (!IsConsoleHandle(TextHandle)) return FALSE;
2115 TextConsoleBuffer = TextHandle;
2116
2117 /* Save the original cursor and console screen buffer information */
2118 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
2119 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
2120 {
2121 return FALSE;
2122 }
2123 ConsoleInfo = OrgConsoleBufferInfo;
2124
2125 /* Initialize the VGA palette and fail if it isn't successfully created */
2126 if (!VgaInitializePalette()) return FALSE;
2127 /***/ VgaResetPalette(); /***/
2128
2129 /* Switch to the text buffer */
2130 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2131
2132 /* Clear the VGA memory */
2133 VgaClearMemory();
2134
2135 /* Register the memory hook */
2136 MemInstallFastMemoryHook((PVOID)0xA0000, 0x20000, VgaReadMemory, VgaWriteMemory);
2137
2138 /* Register the I/O Ports */
2139 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
2140 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2141 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
2142 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
2143 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
2144 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
2145 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
2146 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
2147 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
2148 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
2149 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
2150 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
2151 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
2152
2153 /* CGA ports for compatibility, unimplemented */
2154 RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
2155 RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG
2156
2157 HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace);
2158 VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace);
2159
2160 /* Return success */
2161 return TRUE;
2162 }
2163
2164 VOID VgaCleanup(VOID)
2165 {
2166 DestroyHardwareTimer(VSyncTimer);
2167 DestroyHardwareTimer(HSyncTimer);
2168
2169 if (ScreenMode == GRAPHICS_MODE)
2170 {
2171 /* Leave the current graphics mode */
2172 VgaLeaveGraphicsMode();
2173 }
2174 else
2175 {
2176 /* Leave the current text mode */
2177 VgaLeaveTextMode();
2178 }
2179
2180 VgaDetachFromConsole(FALSE);
2181 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
2182
2183 CloseHandle(AnotherEvent);
2184 CloseHandle(EndEvent);
2185 CloseHandle(StartEvent);
2186 }
2187
2188 /* EOF */