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