[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 BOOL VgaAttachToConsole(PCOORD Resolution)
406 {
407 BOOL Success = FALSE;
408 ULONG Length = 0;
409 PVIDEO_HARDWARE_STATE_HEADER State;
410
411 ASSERT(TextFramebuffer == NULL);
412
413 // ResetEvent(AnotherEvent);
414
415 TextResolution = *Resolution;
416
417 /*
418 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
419 * in the two following APIs:
420 * SrvRegisterConsoleVDM (corresponding win32 API: RegisterConsoleVDM)
421 * SrvVDMConsoleOperation (corresponding Win32 API: )
422 * to check whether the current process is a VDM process, and fails otherwise with the
423 * error 0xC0000022 ().
424 *
425 * It is worth it to notice that also basesrv.dll does the same only for the
426 * BaseSrvIsFirstVDM API...
427 */
428
429 Success =
430 __RegisterConsoleVDM(1,
431 StartEvent,
432 EndEvent,
433 AnotherEvent, // NULL,
434 0,
435 &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
436 (PVOID*)&State, // NULL,
437 NULL,
438 0,
439 TextResolution,
440 (PCHAR*)&TextFramebuffer);
441 if (!Success)
442 {
443 DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
444 VdmRunning = FALSE;
445 }
446
447 return Success;
448 }
449
450 static VOID VgaDetachFromConsole(VOID)
451 {
452 ULONG dummyLength;
453 PVOID dummyPtr;
454 COORD dummySize = {0};
455
456 __RegisterConsoleVDM(0,
457 NULL,
458 NULL,
459 NULL,
460 0,
461 &dummyLength,
462 &dummyPtr,
463 NULL,
464 0,
465 dummySize,
466 (PCHAR*)&dummyPtr);
467
468 TextFramebuffer = NULL;
469 }
470
471 static BOOL IsConsoleHandle(HANDLE hHandle)
472 {
473 DWORD dwMode;
474
475 /* Check whether the handle may be that of a console... */
476 if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
477 return FALSE;
478
479 /*
480 * It may be. Perform another test... The idea comes from the
481 * MSDN description of the WriteConsole API:
482 *
483 * "WriteConsole fails if it is used with a standard handle
484 * that is redirected to a file. If an application processes
485 * multilingual output that can be redirected, determine whether
486 * the output handle is a console handle (one method is to call
487 * the GetConsoleMode function and check whether it succeeds).
488 * If the handle is a console handle, call WriteConsole. If the
489 * handle is not a console handle, the output is redirected and
490 * you should call WriteFile to perform the I/O."
491 */
492 return GetConsoleMode(hHandle, &dwMode);
493 }
494
495 static inline DWORD VgaGetAddressSize(VOID)
496 {
497 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
498 {
499 /* Double-word addressing */
500 return 4; // sizeof(DWORD)
501 }
502 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
503 {
504 /* Byte addressing */
505 return 1; // sizeof(BYTE)
506 }
507 else
508 {
509 /* Word addressing */
510 return 2; // sizeof(WORD)
511 }
512 }
513
514 static inline DWORD VgaTranslateReadAddress(DWORD Address)
515 {
516 DWORD Offset = Address - VgaGetVideoBaseAddress();
517 BYTE Plane;
518
519 /* Check for chain-4 and odd-even mode */
520 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
521 {
522 /* The lowest two bits are the plane number */
523 Plane = Offset & 3;
524 Offset >>= 2;
525 }
526 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
527 {
528 /* The LSB is the plane number */
529 Plane = Offset & 1;
530 Offset >>= 1;
531 }
532 else
533 {
534 /* Use the read mode */
535 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
536 }
537
538 /* Multiply the offset by the address size */
539 Offset *= VgaGetAddressSize();
540
541 return Offset + Plane * VGA_BANK_SIZE;
542 }
543
544 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
545 {
546 DWORD Offset = Address - VgaGetVideoBaseAddress();
547
548 /* Check for chain-4 and odd-even mode */
549 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
550 {
551 /* Shift the offset to the right by 2 */
552 Offset >>= 2;
553 }
554 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
555 {
556 /* Shift the offset to the right by 1 */
557 Offset >>= 1;
558 }
559
560 /* Multiply the offset by the address size */
561 Offset *= VgaGetAddressSize();
562
563 /* Return the offset on plane 0 */
564 return Offset;
565 }
566
567 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
568 {
569 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
570 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
571
572 if (WriteMode == 1)
573 {
574 /* In write mode 1 just return the latch register */
575 return VgaLatchRegisters[Plane];
576 }
577
578 if (WriteMode != 2)
579 {
580 /* Write modes 0 and 3 rotate the data to the right first */
581 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
582 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
583 }
584 else
585 {
586 /* Write mode 2 expands the appropriate bit to all 8 bits */
587 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
588 }
589
590 if (WriteMode == 0)
591 {
592 /*
593 * In write mode 0, the enable set/reset register decides if the
594 * set/reset bit should be expanded to all 8 bits.
595 */
596 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
597 {
598 /* Copy the bit from the set/reset register to all 8 bits */
599 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
600 }
601 }
602
603 if (WriteMode != 3)
604 {
605 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
606 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
607
608 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
609 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
610 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
611 }
612 else
613 {
614 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
615 BitMask &= Data;
616
617 /* Then we expand the bit in the set/reset field */
618 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
619 }
620
621 /* Bits cleared in the bitmask are replaced with latch register bits */
622 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
623
624 /* Return the byte */
625 return Data;
626 }
627
628 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
629 {
630 /* Check if this is the first time the rectangle is updated */
631 if (!NeedsUpdate)
632 {
633 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
634 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
635 }
636
637 /* Expand the rectangle to include the point */
638 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
639 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
640 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
641 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
642
643 /* Set the update request flag */
644 NeedsUpdate = TRUE;
645 }
646
647 static VOID VgaWriteSequencer(BYTE Data)
648 {
649 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
650
651 /* Save the value */
652 VgaSeqRegisters[VgaSeqIndex] = Data;
653 }
654
655 static VOID VgaWriteGc(BYTE Data)
656 {
657 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
658
659 /* Save the value */
660 VgaGcRegisters[VgaGcIndex] = Data;
661
662 /* Check the index */
663 switch (VgaGcIndex)
664 {
665 case VGA_GC_MISC_REG:
666 {
667 /* The GC misc register decides if it's text or graphics mode */
668 ModeChanged = TRUE;
669 break;
670 }
671 }
672 }
673
674 static VOID VgaWriteCrtc(BYTE Data)
675 {
676 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
677
678 /* Save the value */
679 VgaCrtcRegisters[VgaCrtcIndex] = Data;
680
681 /* Check the index */
682 switch (VgaCrtcIndex)
683 {
684 case VGA_CRTC_END_HORZ_DISP_REG:
685 case VGA_CRTC_VERT_DISP_END_REG:
686 case VGA_CRTC_OVERFLOW_REG:
687 {
688 /* The video mode has changed */
689 ModeChanged = TRUE;
690 break;
691 }
692
693 case VGA_CRTC_CURSOR_LOC_LOW_REG:
694 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
695 case VGA_CRTC_CURSOR_START_REG:
696 case VGA_CRTC_CURSOR_END_REG:
697 {
698 /* Set the cursor moved flag */
699 CursorMoved = TRUE;
700 break;
701 }
702 }
703 }
704
705 static VOID VgaWriteDac(BYTE Data)
706 {
707 INT PaletteIndex;
708 PALETTEENTRY Entry;
709
710 /* Set the value */
711 VgaDacRegisters[VgaDacIndex] = Data;
712
713 /* Find the palette index */
714 PaletteIndex = VgaDacIndex / 3;
715
716 /* Fill the entry structure */
717 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
718 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
719 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
720 Entry.peFlags = 0;
721
722 /* Update the palette entry and set the palette change flag */
723 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
724 PaletteChanged = TRUE;
725
726 /* Update the index */
727 VgaDacIndex++;
728 VgaDacIndex %= VGA_PALETTE_SIZE;
729 }
730
731 static VOID VgaWriteAc(BYTE Data)
732 {
733 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
734
735 /* Save the value */
736 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
737 {
738 if (VgaAcPalDisable) return;
739
740 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
741 if (VgaAcRegisters[VgaAcIndex] != Data)
742 {
743 /* Update the AC register and set the palette change flag */
744 VgaAcRegisters[VgaAcIndex] = Data;
745 PaletteChanged = TRUE;
746 }
747 }
748 else
749 {
750 VgaAcRegisters[VgaAcIndex] = Data;
751 }
752 }
753
754 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
755 {
756 USHORT i;
757
758 /* Copy the colors of the default palette to the DAC and console palette */
759 for (i = 0; i < NumOfEntries; i++)
760 {
761 /* Set the palette entries */
762 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
763 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
764 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
765 Entries[i].peFlags = 0;
766
767 /* Set the DAC registers */
768 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
769 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
770 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
771 }
772 }
773
774 static BOOLEAN VgaInitializePalette(VOID)
775 {
776 LPLOGPALETTE Palette;
777
778 /* Allocate storage space for the palette */
779 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
780 HEAP_ZERO_MEMORY,
781 sizeof(LOGPALETTE) +
782 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
783 if (Palette == NULL) return FALSE;
784
785 /* Initialize the palette */
786 Palette->palVersion = 0x0300;
787 Palette->palNumEntries = VGA_MAX_COLORS;
788
789 /* Restore the default palette */
790 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
791
792 /* Create the palette */
793 PaletteHandle = CreatePalette(Palette);
794
795 /* Free the palette */
796 HeapFree(GetProcessHeap(), 0, Palette);
797
798 /* Fail if the palette wasn't successfully created... */
799 if (PaletteHandle == NULL) return FALSE;
800
801 /* ... otherwise return success */
802 return TRUE;
803 }
804
805 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
806 {
807 DWORD i;
808 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
809 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
810 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
811 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
812
813 LONG Width = Resolution->X;
814 LONG Height = Resolution->Y;
815
816 /* Use DoubleVision mode if the resolution is too small */
817 if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
818 {
819 DoubleVision = TRUE;
820 Width *= 2;
821 Height *= 2;
822 }
823 else
824 {
825 DoubleVision = FALSE;
826 }
827
828 /* Fill the bitmap info header */
829 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
830 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
831 BitmapInfo->bmiHeader.biWidth = Width;
832 BitmapInfo->bmiHeader.biHeight = Height;
833 BitmapInfo->bmiHeader.biBitCount = 8;
834 BitmapInfo->bmiHeader.biPlanes = 1;
835 BitmapInfo->bmiHeader.biCompression = BI_RGB;
836 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
837
838 /* Fill the palette data */
839 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
840
841 /* Fill the console graphics buffer info */
842 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
843 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
844 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
845
846 /* Create the buffer */
847 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
848 FILE_SHARE_READ | FILE_SHARE_WRITE,
849 NULL,
850 CONSOLE_GRAPHICS_BUFFER,
851 &GraphicsBufferInfo);
852 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
853
854 /* Save the framebuffer address and mutex */
855 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
856 ConsoleMutex = GraphicsBufferInfo.hMutex;
857
858 /* Clear the framebuffer */
859 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
860
861 /* Set the active buffer */
862 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
863
864 /* Set the graphics mode palette */
865 SetConsolePalette(GraphicsConsoleBuffer,
866 PaletteHandle,
867 SYSPAL_NOSTATIC256);
868
869 /* Set the screen mode flag */
870 ScreenMode = GRAPHICS_MODE;
871
872 return TRUE;
873 }
874
875 static VOID VgaLeaveGraphicsMode(VOID)
876 {
877 /* Release the console framebuffer mutex */
878 ReleaseMutex(ConsoleMutex);
879
880 /* Switch back to the default console text buffer */
881 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
882
883 /* Cleanup the video data */
884 CloseHandle(ConsoleMutex);
885 ConsoleMutex = NULL;
886 ConsoleFramebuffer = NULL;
887 CloseHandle(GraphicsConsoleBuffer);
888 GraphicsConsoleBuffer = NULL;
889 DoubleVision = FALSE;
890 }
891
892 static BOOL VgaEnterTextMode(PCOORD Resolution)
893 {
894 SMALL_RECT ConRect;
895
896 /* Switch to the text buffer */
897 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
898
899 /* Resize the console */
900 ConRect.Left = 0; // ConsoleInfo.srWindow.Left;
901 ConRect.Top = ConsoleInfo.srWindow.Top;
902 ConRect.Right = ConRect.Left + Resolution->X - 1;
903 ConRect.Bottom = ConRect.Top + Resolution->Y - 1;
904 /*
905 * Use this trick to effectively resize the console buffer and window,
906 * because:
907 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
908 * is smaller than the current console window size, and:
909 * - SetConsoleWindowInfo fails if the new console window size is larger
910 * than the current console screen buffer size.
911 */
912 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
913 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
914 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
915 /* Update the saved console information */
916 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
917
918 /* Adjust the text framebuffer if we changed resolution */
919 if (TextResolution.X != Resolution->X ||
920 TextResolution.Y != Resolution->Y)
921 {
922 VgaDetachFromConsole();
923
924 /* VgaAttachToConsole sets TextResolution to the new resolution */
925 if (!VgaAttachToConsole(Resolution))
926 {
927 DisplayMessage(L"An unexpected error occurred!\n");
928 VdmRunning = FALSE;
929 return FALSE;
930 }
931 }
932
933 /* The active framebuffer is now the text framebuffer */
934 ConsoleFramebuffer = TextFramebuffer;
935
936 /*
937 * Set the text mode palette.
938 *
939 * WARNING: This call should fail on Windows (and therefore
940 * we get the default palette and our external behaviour is
941 * just like Windows' one), but it should success on ReactOS
942 * (so that we get console palette changes even for text-mode
943 * screen-buffers, which is a new feature on ReactOS).
944 */
945 SetConsolePalette(TextConsoleBuffer,
946 PaletteHandle,
947 SYSPAL_NOSTATIC256);
948
949 /* Set the screen mode flag */
950 ScreenMode = TEXT_MODE;
951
952 return TRUE;
953 }
954
955 static VOID VgaLeaveTextMode(VOID)
956 {
957 /* Reset the active framebuffer */
958 ConsoleFramebuffer = NULL;
959 }
960
961 static VOID VgaChangeMode(VOID)
962 {
963 COORD Resolution = VgaGetDisplayResolution();
964
965 if (ScreenMode == GRAPHICS_MODE)
966 {
967 /* Leave the current graphics mode */
968 VgaLeaveGraphicsMode();
969 }
970 else
971 {
972 /* Leave the current text mode */
973 VgaLeaveTextMode();
974 }
975
976 /* Check if the new mode is alphanumeric */
977 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
978 {
979 /* Enter new text mode */
980 if (!VgaEnterTextMode(&Resolution))
981 {
982 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
983 VdmRunning = FALSE;
984 return;
985 }
986 }
987 else
988 {
989 /* Enter graphics mode */
990 if (!VgaEnterGraphicsMode(&Resolution))
991 {
992 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
993 VdmRunning = FALSE;
994 return;
995 }
996 }
997
998 /* Trigger a full update of the screen */
999 NeedsUpdate = TRUE;
1000 UpdateRectangle.Left = 0;
1001 UpdateRectangle.Top = 0;
1002 UpdateRectangle.Right = Resolution.X;
1003 UpdateRectangle.Bottom = Resolution.Y;
1004
1005 /* Reset the mode change flag */
1006 ModeChanged = FALSE;
1007 }
1008
1009 static VOID VgaUpdateFramebuffer(VOID)
1010 {
1011 SHORT i, j, k;
1012 COORD Resolution = VgaGetDisplayResolution();
1013 DWORD AddressSize = VgaGetAddressSize();
1014 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1015 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
1016 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1017
1018 /*
1019 * If console framebuffer is NULL, that means something went wrong
1020 * earlier and this is the final display refresh.
1021 */
1022 if (ConsoleFramebuffer == NULL) return;
1023
1024 /* Check if this is text mode or graphics mode */
1025 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1026 {
1027 /* Graphics mode */
1028 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1029
1030 /*
1031 * Synchronize access to the graphics framebuffer
1032 * with the console framebuffer mutex.
1033 */
1034 WaitForSingleObject(ConsoleMutex, INFINITE);
1035
1036 /* Loop through the scanlines */
1037 for (i = 0; i < Resolution.Y; i++)
1038 {
1039 /* Loop through the pixels */
1040 for (j = 0; j < Resolution.X; j++)
1041 {
1042 BYTE PixelData = 0;
1043
1044 /* Check the shifting mode */
1045 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1046 {
1047 /* 4 bits shifted from each plane */
1048
1049 /* Check if this is 16 or 256 color mode */
1050 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1051 {
1052 /* One byte per pixel */
1053 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1054 + (Address + (j / VGA_NUM_BANKS))
1055 * AddressSize];
1056 }
1057 else
1058 {
1059 /* 4-bits per pixel */
1060
1061 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1062 + (Address + (j / (VGA_NUM_BANKS * 2)))
1063 * AddressSize];
1064
1065 /* Check if we should use the highest 4 bits or lowest 4 */
1066 if (((j / VGA_NUM_BANKS) % 2) == 0)
1067 {
1068 /* Highest 4 */
1069 PixelData >>= 4;
1070 }
1071 else
1072 {
1073 /* Lowest 4 */
1074 PixelData &= 0x0F;
1075 }
1076 }
1077 }
1078 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1079 {
1080 /* Check if this is 16 or 256 color mode */
1081 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1082 {
1083 // TODO: NOT IMPLEMENTED
1084 DPRINT1("8-bit interleaved mode is not implemented!\n");
1085 }
1086 else
1087 {
1088 /*
1089 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1090 * then 2 bits shifted from plane 1 and 3 for the next 4
1091 */
1092 BYTE LowPlaneData = VgaMemory[((j / 4) % 2) * VGA_BANK_SIZE
1093 + (Address + (j / 8)) * AddressSize];
1094 BYTE HighPlaneData = VgaMemory[(((j / 4) % 2) + 2) * VGA_BANK_SIZE
1095 + (Address + (j / 8)) * AddressSize];
1096
1097 /* Extract the two bits from each plane */
1098 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
1099 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
1100
1101 /* Combine them into the pixel */
1102 PixelData = LowPlaneData | (HighPlaneData << 2);
1103 }
1104 }
1105 else
1106 {
1107 /* 1 bit shifted from each plane */
1108
1109 /* Check if this is 16 or 256 color mode */
1110 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1111 {
1112 /* 8 bits per pixel, 2 on each plane */
1113
1114 for (k = 0; k < VGA_NUM_BANKS; k++)
1115 {
1116 /* The data is on plane k, 4 pixels per byte */
1117 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1118 + (Address + (j / VGA_NUM_BANKS))
1119 * AddressSize];
1120
1121 /* The mask of the first bit in the pair */
1122 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
1123
1124 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1125 if (PlaneData & BitMask) PixelData |= 1 << k;
1126
1127 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1128 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1129 }
1130 }
1131 else
1132 {
1133 /* 4 bits per pixel, 1 on each plane */
1134
1135 for (k = 0; k < VGA_NUM_BANKS; k++)
1136 {
1137 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1138 + (Address + (j / (VGA_NUM_BANKS * 2)))
1139 * AddressSize];
1140
1141 /* If the bit on that plane is set, set it */
1142 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
1143 }
1144 }
1145 }
1146
1147 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1148 {
1149 /*
1150 * In 16 color mode, the value is an index to the AC registers
1151 * if external palette access is disabled, otherwise (in case
1152 * of palette loading) it is a blank pixel.
1153 */
1154 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1155 : 0);
1156 }
1157
1158 /* Take into account DoubleVision mode when checking for pixel updates */
1159 if (DoubleVision)
1160 {
1161 /* Now check if the resulting pixel data has changed */
1162 if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
1163 {
1164 /* Yes, write the new value */
1165 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
1166 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
1167 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
1168 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
1169
1170 /* Mark the specified pixel as changed */
1171 VgaMarkForUpdate(i, j);
1172 }
1173 }
1174 else
1175 {
1176 /* Now check if the resulting pixel data has changed */
1177 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
1178 {
1179 /* Yes, write the new value */
1180 GraphicsBuffer[i * Resolution.X + j] = PixelData;
1181
1182 /* Mark the specified pixel as changed */
1183 VgaMarkForUpdate(i, j);
1184 }
1185 }
1186 }
1187
1188 /* Move to the next scanline */
1189 Address += ScanlineSize;
1190 }
1191
1192 /*
1193 * Release the console framebuffer mutex
1194 * so that we allow for repainting.
1195 */
1196 ReleaseMutex(ConsoleMutex);
1197 }
1198 else
1199 {
1200 /* Text mode */
1201 DWORD CurrentAddr;
1202 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1203 CHAR_CELL CharInfo;
1204
1205 /* Loop through the scanlines */
1206 for (i = 0; i < Resolution.Y; i++)
1207 {
1208 /* Loop through the characters */
1209 for (j = 0; j < Resolution.X; j++)
1210 {
1211 CurrentAddr = LOWORD((Address + j) * AddressSize);
1212
1213 /* Plane 0 holds the character itself */
1214 CharInfo.Char = VgaMemory[CurrentAddr];
1215
1216 /* Plane 1 holds the attribute */
1217 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1218
1219 /* Now check if the resulting character data has changed */
1220 if ((CharBuffer[i * Resolution.X + j].Char != CharInfo.Char)
1221 || (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
1222 {
1223 /* Yes, write the new value */
1224 CharBuffer[i * Resolution.X + j] = CharInfo;
1225
1226 /* Mark the specified cell as changed */
1227 VgaMarkForUpdate(i, j);
1228 }
1229 }
1230
1231 /* Move to the next scanline */
1232 Address += ScanlineSize;
1233 }
1234 }
1235 }
1236
1237 static VOID VgaUpdateTextCursor(VOID)
1238 {
1239 COORD Position;
1240 CONSOLE_CURSOR_INFO CursorInfo;
1241 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
1242 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1243 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1244 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1245 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1246 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1247
1248 /* Just return if we are not in text mode */
1249 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) return;
1250
1251 if (CursorStart < CursorEnd)
1252 {
1253 /* Visible cursor */
1254 CursorInfo.bVisible = TRUE;
1255 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1256 }
1257 else
1258 {
1259 /* No cursor */
1260 CursorInfo.bVisible = FALSE;
1261 CursorInfo.dwSize = 0;
1262 }
1263
1264 /* Add the cursor skew to the location */
1265 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
1266
1267 /* Find the coordinates of the new position */
1268 Position.X = (WORD)(Location % ScanlineSize);
1269 Position.Y = (WORD)(Location / ScanlineSize);
1270
1271 /* Update the physical cursor */
1272 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1273 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1274
1275 /* Reset the cursor move flag */
1276 CursorMoved = FALSE;
1277 }
1278
1279 static BYTE WINAPI VgaReadPort(ULONG Port)
1280 {
1281 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1282
1283 switch (Port)
1284 {
1285 case VGA_MISC_READ:
1286 return VgaMiscRegister;
1287
1288 case VGA_INSTAT0_READ:
1289 return 0; // Not implemented
1290
1291 case VGA_INSTAT1_READ_MONO:
1292 case VGA_INSTAT1_READ_COLOR:
1293 {
1294 BYTE Result = 0;
1295
1296 /* Reset the AC latch */
1297 VgaAcLatch = FALSE;
1298
1299 /* Set a flag if there is a vertical or horizontal retrace */
1300 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1301
1302 /* Set an additional flag if there was a vertical retrace */
1303 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1304
1305 /* Clear the flags */
1306 InHorizontalRetrace = InVerticalRetrace = FALSE;
1307
1308 return Result;
1309 }
1310
1311 case VGA_FEATURE_READ:
1312 return VgaFeatureRegister;
1313
1314 case VGA_AC_INDEX:
1315 return VgaAcIndex;
1316
1317 case VGA_AC_READ:
1318 return VgaAcRegisters[VgaAcIndex];
1319
1320 case VGA_SEQ_INDEX:
1321 return VgaSeqIndex;
1322
1323 case VGA_SEQ_DATA:
1324 return VgaSeqRegisters[VgaSeqIndex];
1325
1326 case VGA_DAC_MASK:
1327 return VgaDacMask;
1328
1329 case VGA_DAC_READ_INDEX:
1330 /* This returns the read/write state */
1331 return (VgaDacReadWrite ? 0 : 3);
1332
1333 case VGA_DAC_WRITE_INDEX:
1334 return (VgaDacIndex / 3);
1335
1336 case VGA_DAC_DATA:
1337 {
1338 /* Ignore reads in write mode */
1339 if (!VgaDacReadWrite)
1340 {
1341 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1342 VgaDacIndex %= VGA_PALETTE_SIZE;
1343 return Data;
1344 }
1345
1346 break;
1347 }
1348
1349 case VGA_CRTC_INDEX_MONO:
1350 case VGA_CRTC_INDEX_COLOR:
1351 return VgaCrtcIndex;
1352
1353 case VGA_CRTC_DATA_MONO:
1354 case VGA_CRTC_DATA_COLOR:
1355 return VgaCrtcRegisters[VgaCrtcIndex];
1356
1357 case VGA_GC_INDEX:
1358 return VgaGcIndex;
1359
1360 case VGA_GC_DATA:
1361 return VgaGcRegisters[VgaGcIndex];
1362
1363 default:
1364 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1365 break;
1366 }
1367
1368 return 0;
1369 }
1370
1371 static VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1372 {
1373 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1374
1375 switch (Port)
1376 {
1377 case VGA_MISC_WRITE:
1378 {
1379 VgaMiscRegister = Data;
1380
1381 if (VgaMiscRegister & 0x01)
1382 {
1383 /* Color emulation */
1384 DPRINT1("Color emulation\n");
1385
1386 /* Register the new I/O Ports */
1387 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1388 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1389 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1390
1391 /* Unregister the old ones */
1392 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1393 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1394 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1395 }
1396 else
1397 {
1398 /* Monochrome emulation */
1399 DPRINT1("Monochrome emulation\n");
1400
1401 /* Register the new I/O Ports */
1402 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1403 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1404 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1405
1406 /* Unregister the old ones */
1407 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1408 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1409 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1410 }
1411
1412 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1413 break;
1414 }
1415
1416 case VGA_FEATURE_WRITE_MONO:
1417 case VGA_FEATURE_WRITE_COLOR:
1418 {
1419 VgaFeatureRegister = Data;
1420 break;
1421 }
1422
1423 case VGA_AC_INDEX:
1424 // case VGA_AC_WRITE:
1425 {
1426 if (!VgaAcLatch)
1427 {
1428 /* Change the index */
1429 BYTE Index = Data & 0x1F;
1430 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1431
1432 /*
1433 * Change palette protection by checking for
1434 * the Palette Address Source bit.
1435 */
1436 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1437 }
1438 else
1439 {
1440 /* Write the data */
1441 VgaWriteAc(Data);
1442 }
1443
1444 /* Toggle the latch */
1445 VgaAcLatch = !VgaAcLatch;
1446 break;
1447 }
1448
1449 case VGA_SEQ_INDEX:
1450 {
1451 /* Set the sequencer index register */
1452 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1453 break;
1454 }
1455
1456 case VGA_SEQ_DATA:
1457 {
1458 /* Call the sequencer function */
1459 VgaWriteSequencer(Data);
1460 break;
1461 }
1462
1463 case VGA_DAC_MASK:
1464 {
1465 VgaDacMask = Data;
1466 break;
1467 }
1468
1469 case VGA_DAC_READ_INDEX:
1470 {
1471 VgaDacReadWrite = FALSE;
1472 VgaDacIndex = Data * 3;
1473 break;
1474 }
1475
1476 case VGA_DAC_WRITE_INDEX:
1477 {
1478 VgaDacReadWrite = TRUE;
1479 VgaDacIndex = Data * 3;
1480 break;
1481 }
1482
1483 case VGA_DAC_DATA:
1484 {
1485 /* Ignore writes in read mode */
1486 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1487 break;
1488 }
1489
1490 case VGA_CRTC_INDEX_MONO:
1491 case VGA_CRTC_INDEX_COLOR:
1492 {
1493 /* Set the CRTC index register */
1494 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1495 break;
1496 }
1497
1498 case VGA_CRTC_DATA_MONO:
1499 case VGA_CRTC_DATA_COLOR:
1500 {
1501 /* Call the CRTC function */
1502 VgaWriteCrtc(Data);
1503 break;
1504 }
1505
1506 case VGA_GC_INDEX:
1507 {
1508 /* Set the GC index register */
1509 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1510 break;
1511 }
1512
1513 case VGA_GC_DATA:
1514 {
1515 /* Call the GC function */
1516 VgaWriteGc(Data);
1517 break;
1518 }
1519
1520 default:
1521 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1522 break;
1523 }
1524 }
1525
1526 /* PUBLIC FUNCTIONS ***********************************************************/
1527
1528 DWORD VgaGetVideoBaseAddress(VOID)
1529 {
1530 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1531 }
1532
1533 DWORD VgaGetVideoLimitAddress(VOID)
1534 {
1535 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1536 }
1537
1538 COORD VgaGetDisplayResolution(VOID)
1539 {
1540 COORD Resolution;
1541 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1542
1543 /* The low 8 bits are in the display registers */
1544 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1545 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1546
1547 /* Set the top bits from the overflow register */
1548 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1549 {
1550 Resolution.Y |= 1 << 8;
1551 }
1552 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1553 {
1554 Resolution.Y |= 1 << 9;
1555 }
1556
1557 /* Increase the values by 1 */
1558 Resolution.X++;
1559 Resolution.Y++;
1560
1561 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1562 {
1563 /* Multiply the horizontal resolution by the 9/8 dot mode */
1564 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1565 ? 8 : 9;
1566
1567 /* The horizontal resolution is halved in 8-bit mode */
1568 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1569 }
1570
1571 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1572 {
1573 /* Halve the vertical resolution */
1574 Resolution.Y >>= 1;
1575 }
1576 else
1577 {
1578 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1579 Resolution.Y /= MaximumScanLine;
1580 }
1581
1582 /* Return the resolution */
1583 return Resolution;
1584 }
1585
1586 VOID VgaRefreshDisplay(VOID)
1587 {
1588 HANDLE ConsoleBufferHandle = NULL;
1589 COORD Resolution;
1590
1591 /* Set the vertical retrace flag */
1592 InVerticalRetrace = TRUE;
1593
1594 /* If nothing has changed, just return */
1595 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1596 // return;
1597
1598 /* Change the display mode */
1599 if (ModeChanged) VgaChangeMode();
1600
1601 /* Change the text cursor location */
1602 if (CursorMoved) VgaUpdateTextCursor();
1603
1604 /* Retrieve the current resolution */
1605 Resolution = VgaGetDisplayResolution();
1606
1607 if (PaletteChanged)
1608 {
1609 /* Trigger a full update of the screen */
1610 NeedsUpdate = TRUE;
1611 UpdateRectangle.Left = 0;
1612 UpdateRectangle.Top = 0;
1613 UpdateRectangle.Right = Resolution.X;
1614 UpdateRectangle.Bottom = Resolution.Y;
1615
1616 PaletteChanged = FALSE;
1617 }
1618
1619 /* Update the contents of the framebuffer */
1620 VgaUpdateFramebuffer();
1621
1622 /* Ignore if there's nothing to update */
1623 if (!NeedsUpdate) return;
1624
1625 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1626 UpdateRectangle.Left,
1627 UpdateRectangle.Top,
1628 UpdateRectangle.Right,
1629 UpdateRectangle.Bottom);
1630
1631 /* Check if this is text mode or graphics mode */
1632 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1633 {
1634 /* Graphics mode */
1635 ConsoleBufferHandle = GraphicsConsoleBuffer;
1636
1637 /* In DoubleVision mode, scale the update rectangle */
1638 if (DoubleVision)
1639 {
1640 UpdateRectangle.Left *= 2;
1641 UpdateRectangle.Top *= 2;
1642 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1643 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1644 }
1645 }
1646 else
1647 {
1648 /* Text mode */
1649 ConsoleBufferHandle = TextConsoleBuffer;
1650 }
1651
1652 /* Redraw the screen */
1653 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1654
1655 /* Clear the update flag */
1656 NeedsUpdate = FALSE;
1657 }
1658
1659 VOID VgaHorizontalRetrace(VOID)
1660 {
1661 /* Set the flag */
1662 InHorizontalRetrace = TRUE;
1663 }
1664
1665 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1666 {
1667 DWORD i;
1668 DWORD VideoAddress;
1669
1670 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1671
1672 /* Ignore if video RAM access is disabled */
1673 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1674
1675 /* Loop through each byte */
1676 for (i = 0; i < Size; i++)
1677 {
1678 VideoAddress = VgaTranslateReadAddress(Address + i);
1679
1680 /* Load the latch registers */
1681 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1682 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1683 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1684 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1685
1686 /* Copy the value to the buffer */
1687 Buffer[i] = VgaMemory[VideoAddress];
1688 }
1689 }
1690
1691 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1692 {
1693 DWORD i, j;
1694 DWORD VideoAddress;
1695
1696 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1697
1698 /* Ignore if video RAM access is disabled */
1699 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1700
1701 /* Also ignore if write access to all planes is disabled */
1702 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1703
1704 /* Loop through each byte */
1705 for (i = 0; i < Size; i++)
1706 {
1707 VideoAddress = VgaTranslateWriteAddress(Address + i);
1708
1709 for (j = 0; j < VGA_NUM_BANKS; j++)
1710 {
1711 /* Make sure the page is writeable */
1712 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1713
1714 /* Check if this is chain-4 mode */
1715 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1716 {
1717 if (((Address + i) & 3) != j)
1718 {
1719 /* This plane will not be accessed */
1720 continue;
1721 }
1722 }
1723
1724 /* Check if this is odd-even mode */
1725 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1726 {
1727 if (((Address + i) & 1) != (j & 1))
1728 {
1729 /* This plane will not be accessed */
1730 continue;
1731 }
1732 }
1733
1734 /* Copy the value to the VGA memory */
1735 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1736 }
1737 }
1738 }
1739
1740 VOID VgaClearMemory(VOID)
1741 {
1742 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1743 }
1744
1745 VOID VgaResetPalette(VOID)
1746 {
1747 PALETTEENTRY Entries[VGA_MAX_COLORS];
1748
1749 /* Restore the default palette */
1750 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1751 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1752 PaletteChanged = TRUE;
1753 }
1754
1755 BOOLEAN VgaInitialize(HANDLE TextHandle)
1756 {
1757 /* Save the default text-mode console output handle */
1758 if (!IsConsoleHandle(TextHandle)) return FALSE;
1759 TextConsoleBuffer = TextHandle;
1760
1761 /* Save the console information */
1762 if (!GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo))
1763 {
1764 return FALSE;
1765 }
1766
1767 /* Initialize the VGA palette and fail if it isn't successfully created */
1768 if (!VgaInitializePalette()) return FALSE;
1769 /***/ VgaResetPalette(); /***/
1770
1771 /* Switch to the text buffer */
1772 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1773
1774 /* Clear the VGA memory */
1775 VgaClearMemory();
1776
1777 /* Register the I/O Ports */
1778 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
1779 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1780 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
1781 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
1782 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
1783 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
1784 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
1785 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
1786 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
1787 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
1788 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
1789 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
1790 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
1791
1792 /* Return success */
1793 return TRUE;
1794 }
1795
1796 VOID VgaCleanup(VOID)
1797 {
1798 if (ScreenMode == GRAPHICS_MODE)
1799 {
1800 /* Leave the current graphics mode */
1801 VgaLeaveGraphicsMode();
1802 }
1803 else
1804 {
1805 /* Leave the current text mode */
1806 VgaLeaveTextMode();
1807 }
1808
1809 VgaDetachFromConsole();
1810
1811 CloseHandle(AnotherEvent);
1812 CloseHandle(EndEvent);
1813 CloseHandle(StartEvent);
1814
1815 #if 0
1816 RegisterConsoleVDM = NULL;
1817 FreeLibrary(hKernel32);
1818 #endif
1819 }
1820
1821 /* EOF */