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