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