[NTVDM]
[reactos.git] / subsystems / ntvdm / 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 #include "bios.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 static HANDLE VgaSavedConsoleHandle = NULL;
175 static CONSOLE_SCREEN_BUFFER_INFO VgaSavedConsoleInfo;
176
177 static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE];
178 static LPVOID ConsoleFramebuffer = NULL;
179 static HANDLE TextConsoleBuffer = NULL;
180 static HANDLE GraphicsConsoleBuffer = NULL;
181 static HANDLE ConsoleMutex = NULL;
182 static HPALETTE PaletteHandle = NULL;
183 static BOOLEAN DoubleVision = FALSE;
184
185 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
186
187 static BYTE VgaMiscRegister;
188 static BYTE VgaFeatureRegister;
189
190 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
191 static BYTE VgaSeqRegisters[VGA_SEQ_MAX_REG];
192
193 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
194 static BYTE VgaCrtcRegisters[VGA_CRTC_MAX_REG];
195
196 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
197 static BYTE VgaGcRegisters[VGA_GC_MAX_REG];
198
199 static BOOLEAN VgaAcLatch = FALSE;
200 static BOOLEAN VgaAcPalDisable = TRUE;
201 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
202 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
203
204 // static VGA_REGISTERS VgaRegisters;
205
206 static BYTE VgaDacMask = 0xFF;
207 static WORD VgaDacIndex = 0;
208 static BOOLEAN VgaDacReadWrite = FALSE;
209 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
210
211 static BOOLEAN InVerticalRetrace = FALSE;
212 static BOOLEAN InHorizontalRetrace = FALSE;
213
214 static BOOLEAN NeedsUpdate = FALSE;
215 static BOOLEAN ModeChanged = TRUE;
216 static BOOLEAN CursorMoved = FALSE;
217 static BOOLEAN PaletteChanged = FALSE;
218
219 static
220 enum SCREEN_MODE
221 {
222 TEXT_MODE,
223 GRAPHICS_MODE
224 } ScreenMode = TEXT_MODE;
225
226 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
227
228 /* PRIVATE FUNCTIONS **********************************************************/
229
230 static inline DWORD VgaGetAddressSize(VOID)
231 {
232 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
233 {
234 /* Double-word addressing */
235 return 4; // sizeof(DWORD)
236 }
237
238 if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
239 {
240 /* Byte addressing */
241 return 1; // sizeof(BYTE)
242 }
243
244 /* Word addressing */
245 return 2; // sizeof(WORD)
246 }
247
248 static inline DWORD VgaTranslateReadAddress(DWORD Address)
249 {
250 DWORD Offset = Address - VgaGetVideoBaseAddress();
251 BYTE Plane;
252
253 /* Check for chain-4 and odd-even mode */
254 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
255 {
256 /* The lowest two bits are the plane number */
257 Plane = Offset & 3;
258 Offset >>= 2;
259 }
260 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
261 {
262 /* The LSB is the plane number */
263 Plane = Offset & 1;
264 Offset >>= 1;
265 }
266 else
267 {
268 /* Use the read mode */
269 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
270 }
271
272 /* Multiply the offset by the address size */
273 Offset *= VgaGetAddressSize();
274
275 return Offset + Plane * VGA_BANK_SIZE;
276 }
277
278 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
279 {
280 DWORD Offset = Address - VgaGetVideoBaseAddress();
281
282 /* Check for chain-4 and odd-even mode */
283 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
284 {
285 /* Shift the offset to the right by 2 */
286 Offset >>= 2;
287 }
288 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
289 {
290 /* Shift the offset to the right by 1 */
291 Offset >>= 1;
292 }
293
294 /* Multiply the offset by the address size */
295 Offset *= VgaGetAddressSize();
296
297 /* Return the offset on plane 0 */
298 return Offset;
299 }
300
301 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
302 {
303 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
304 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
305
306 if (WriteMode == 1)
307 {
308 /* In write mode 1 just return the latch register */
309 return VgaLatchRegisters[Plane];
310 }
311
312 if (WriteMode != 2)
313 {
314 /* Write modes 0 and 3 rotate the data to the right first */
315 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
316 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
317 }
318 else
319 {
320 /* Write mode 2 expands the appropriate bit to all 8 bits */
321 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
322 }
323
324 if (WriteMode == 0)
325 {
326 /*
327 * In write mode 0, the enable set/reset register decides if the
328 * set/reset bit should be expanded to all 8 bits.
329 */
330 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
331 {
332 /* Copy the bit from the set/reset register to all 8 bits */
333 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
334 }
335 }
336
337 if (WriteMode != 3)
338 {
339 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
340 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
341
342 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
343 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
344 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
345 }
346 else
347 {
348 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
349 BitMask &= Data;
350
351 /* Then we expand the bit in the set/reset field */
352 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
353 }
354
355 /* Bits cleared in the bitmask are replaced with latch register bits */
356 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
357
358 /* Return the byte */
359 return Data;
360 }
361
362 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
363 {
364 /* Check if this is the first time the rectangle is updated */
365 if (!NeedsUpdate)
366 {
367 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
368 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
369 }
370
371 /* Expand the rectangle to include the point */
372 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
373 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
374 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
375 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
376
377 /* Set the update request flag */
378 NeedsUpdate = TRUE;
379 }
380
381 static VOID VgaWriteSequencer(BYTE Data)
382 {
383 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
384
385 /* Save the value */
386 VgaSeqRegisters[VgaSeqIndex] = Data;
387 }
388
389 static VOID VgaWriteGc(BYTE Data)
390 {
391 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
392
393 /* Save the value */
394 VgaGcRegisters[VgaGcIndex] = Data;
395
396 /* Check the index */
397 switch (VgaGcIndex)
398 {
399 case VGA_GC_MISC_REG:
400 {
401 /* The GC misc register decides if it's text or graphics mode */
402 ModeChanged = TRUE;
403 break;
404 }
405 }
406 }
407
408 static VOID VgaWriteCrtc(BYTE Data)
409 {
410 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
411
412 /* Save the value */
413 VgaCrtcRegisters[VgaCrtcIndex] = Data;
414
415 /* Check the index */
416 switch (VgaCrtcIndex)
417 {
418 case VGA_CRTC_END_HORZ_DISP_REG:
419 case VGA_CRTC_VERT_DISP_END_REG:
420 case VGA_CRTC_OVERFLOW_REG:
421 {
422 /* The video mode has changed */
423 ModeChanged = TRUE;
424 break;
425 }
426
427 case VGA_CRTC_CURSOR_LOC_LOW_REG:
428 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
429 case VGA_CRTC_CURSOR_START_REG:
430 case VGA_CRTC_CURSOR_END_REG:
431 {
432 /* Set the cursor moved flag */
433 CursorMoved = TRUE;
434 break;
435 }
436 }
437 }
438
439 static VOID VgaWriteDac(BYTE Data)
440 {
441 INT PaletteIndex;
442 PALETTEENTRY Entry;
443
444 /* Set the value */
445 VgaDacRegisters[VgaDacIndex] = Data;
446
447 /* Find the palette index */
448 PaletteIndex = VgaDacIndex / 3;
449
450 /* Fill the entry structure */
451 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
452 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
453 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
454 Entry.peFlags = 0;
455
456 /* Update the palette entry and set the palette change flag */
457 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
458 PaletteChanged = TRUE;
459
460 /* Update the index */
461 VgaDacIndex++;
462 VgaDacIndex %= VGA_PALETTE_SIZE;
463 }
464
465 static VOID VgaWriteAc(BYTE Data)
466 {
467 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
468
469 /* Save the value */
470 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
471 {
472 if (VgaAcPalDisable) return;
473
474 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
475 if (VgaAcRegisters[VgaAcIndex] != Data)
476 {
477 /* Update the AC register and set the palette change flag */
478 VgaAcRegisters[VgaAcIndex] = Data;
479 PaletteChanged = TRUE;
480 }
481 }
482 else
483 {
484 VgaAcRegisters[VgaAcIndex] = Data;
485 }
486 }
487
488 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
489 {
490 USHORT i;
491
492 /* Copy the colors of the default palette to the DAC and console palette */
493 for (i = 0; i < NumOfEntries; i++)
494 {
495 /* Set the palette entries */
496 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
497 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
498 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
499 Entries[i].peFlags = 0;
500
501 /* Set the DAC registers */
502 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
503 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
504 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
505 }
506 }
507
508 static BOOLEAN VgaInitializePalette(VOID)
509 {
510 LPLOGPALETTE Palette;
511
512 /* Allocate storage space for the palette */
513 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
514 HEAP_ZERO_MEMORY,
515 sizeof(LOGPALETTE) +
516 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
517 if (Palette == NULL) return FALSE;
518
519 /* Initialize the palette */
520 Palette->palVersion = 0x0300;
521 Palette->palNumEntries = VGA_MAX_COLORS;
522
523 /* Restore the default palette */
524 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
525
526 /* Create the palette */
527 PaletteHandle = CreatePalette(Palette);
528
529 /* Free the palette */
530 HeapFree(GetProcessHeap(), 0, Palette);
531
532 /* Fail if the palette wasn't successfully created... */
533 if (PaletteHandle == NULL) return FALSE;
534
535 /* ... otherwise return success */
536 return TRUE;
537 }
538
539 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
540 {
541 DWORD i;
542 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
543 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
544 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
545 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
546
547 LONG Width = Resolution->X;
548 LONG Height = Resolution->Y;
549
550 /* Use DoubleVision mode if the resolution is too small */
551 if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
552 {
553 DoubleVision = TRUE;
554 Width *= 2;
555 Height *= 2;
556 }
557 else
558 {
559 DoubleVision = FALSE;
560 }
561
562 /* Fill the bitmap info header */
563 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
564 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
565 BitmapInfo->bmiHeader.biWidth = Width;
566 BitmapInfo->bmiHeader.biHeight = Height;
567 BitmapInfo->bmiHeader.biBitCount = 8;
568 BitmapInfo->bmiHeader.biPlanes = 1;
569 BitmapInfo->bmiHeader.biCompression = BI_RGB;
570 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
571
572 /* Fill the palette data */
573 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
574
575 /* Fill the console graphics buffer info */
576 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
577 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
578 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
579
580 /* Create the buffer */
581 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
582 FILE_SHARE_READ | FILE_SHARE_WRITE,
583 NULL,
584 CONSOLE_GRAPHICS_BUFFER,
585 &GraphicsBufferInfo);
586 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
587
588 /* Save the framebuffer address and mutex */
589 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
590 ConsoleMutex = GraphicsBufferInfo.hMutex;
591
592 /* Clear the framebuffer */
593 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
594
595 /* Set the active buffer */
596 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
597
598 /* Set the graphics mode palette */
599 SetConsolePalette(GraphicsConsoleBuffer,
600 PaletteHandle,
601 SYSPAL_NOSTATIC256);
602
603 /* Set the screen mode flag */
604 ScreenMode = GRAPHICS_MODE;
605
606 return TRUE;
607 }
608
609 static VOID VgaLeaveGraphicsMode(VOID)
610 {
611 /* Release the console framebuffer mutex */
612 ReleaseMutex(ConsoleMutex);
613
614 /* Switch back to the default console buffer */
615 // SetConsoleActiveScreenBuffer(VgaSavedConsoleHandle);
616
617 /* Cleanup the video data */
618 CloseHandle(ConsoleMutex);
619 ConsoleMutex = NULL;
620 CloseHandle(GraphicsConsoleBuffer);
621 GraphicsConsoleBuffer = NULL;
622 DoubleVision = FALSE;
623 }
624
625 static BOOL VgaEnterTextMode(PCOORD Resolution)
626 {
627 SMALL_RECT ConRect;
628
629 /* Switch to the text buffer */
630 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
631
632 /* Resize the console */
633 ConRect.Left = 0; // VgaSavedConsoleInfo.srWindow.Left;
634 ConRect.Top = VgaSavedConsoleInfo.srWindow.Top;
635 ConRect.Right = ConRect.Left + Resolution->X - 1;
636 ConRect.Bottom = ConRect.Top + Resolution->Y - 1;
637 /*
638 * Use this trick to effectively resize the console buffer and window,
639 * because:
640 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
641 * is smaller than the current console window size, and:
642 * - SetConsoleWindowInfo fails if the new console window size is larger
643 * than the current console screen buffer size.
644 */
645 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
646 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
647 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
648 /* Update the saved console information */
649 GetConsoleScreenBufferInfo(TextConsoleBuffer, &VgaSavedConsoleInfo);
650
651 /* Allocate a framebuffer */
652 ConsoleFramebuffer = HeapAlloc(GetProcessHeap(),
653 HEAP_ZERO_MEMORY,
654 Resolution->X * Resolution->Y
655 * sizeof(CHAR_INFO));
656 if (ConsoleFramebuffer == NULL)
657 {
658 DisplayMessage(L"An unexpected error occurred!\n");
659 VdmRunning = FALSE;
660 return FALSE;
661 }
662
663 /*
664 * Set the text mode palette.
665 *
666 * WARNING: This call should fail on Windows (and therefore
667 * we get the default palette and our external behaviour is
668 * just like Windows' one), but it should success on ReactOS
669 * (so that we get console palette changes even for text-mode
670 * screen-buffers, which is a new feature on ReactOS).
671 */
672 SetConsolePalette(TextConsoleBuffer,
673 PaletteHandle,
674 SYSPAL_NOSTATIC256);
675
676 /* Set the screen mode flag */
677 ScreenMode = TEXT_MODE;
678
679 return TRUE;
680 }
681
682 static VOID VgaLeaveTextMode(VOID)
683 {
684 /* Free the old framebuffer */
685 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer);
686 ConsoleFramebuffer = NULL;
687 }
688
689 static VOID VgaChangeMode(VOID)
690 {
691 COORD Resolution = VgaGetDisplayResolution();
692
693 /* Reset the mode change flag */
694 // ModeChanged = FALSE;
695
696 if (ScreenMode == GRAPHICS_MODE)
697 {
698 /* Leave the current graphics mode */
699 VgaLeaveGraphicsMode();
700 }
701 else
702 {
703 /* Leave the current text mode */
704 VgaLeaveTextMode();
705 }
706
707 /* Check if the new mode is alphanumeric */
708 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
709 {
710 /* Enter new text mode */
711 if (!VgaEnterTextMode(&Resolution))
712 {
713 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
714 VdmRunning = FALSE;
715 return;
716 }
717 }
718 else
719 {
720 /* Enter graphics mode */
721 if (!VgaEnterGraphicsMode(&Resolution))
722 {
723 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
724 VdmRunning = FALSE;
725 return;
726 }
727 }
728
729 /* Trigger a full update of the screen */
730 NeedsUpdate = TRUE;
731 UpdateRectangle.Left = 0;
732 UpdateRectangle.Top = 0;
733 UpdateRectangle.Right = Resolution.X;
734 UpdateRectangle.Bottom = Resolution.Y;
735
736 /* Reset the mode change flag */
737 ModeChanged = FALSE;
738 }
739
740 static VOID VgaUpdateFramebuffer(VOID)
741 {
742 INT i, j, k;
743 COORD Resolution = VgaGetDisplayResolution();
744 DWORD AddressSize = VgaGetAddressSize();
745 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
746 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
747 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
748
749 /*
750 * If console framebuffer is NULL, that means something went wrong
751 * earlier and this is the final display refresh.
752 */
753 if (ConsoleFramebuffer == NULL) return;
754
755 /* Check if this is text mode or graphics mode */
756 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
757 {
758 /* Graphics mode */
759 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
760
761 /*
762 * Synchronize access to the graphics framebuffer
763 * with the console framebuffer mutex.
764 */
765 WaitForSingleObject(ConsoleMutex, INFINITE);
766
767 /* Loop through the scanlines */
768 for (i = 0; i < Resolution.Y; i++)
769 {
770 /* Loop through the pixels */
771 for (j = 0; j < Resolution.X; j++)
772 {
773 BYTE PixelData = 0;
774
775 /* Check the shifting mode */
776 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
777 {
778 /* 4 bits shifted from each plane */
779
780 /* Check if this is 16 or 256 color mode */
781 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
782 {
783 /* One byte per pixel */
784 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
785 + (Address + (j / VGA_NUM_BANKS))
786 * AddressSize];
787 }
788 else
789 {
790 /* 4-bits per pixel */
791
792 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
793 + (Address + (j / (VGA_NUM_BANKS * 2)))
794 * AddressSize];
795
796 /* Check if we should use the highest 4 bits or lowest 4 */
797 if (((j / VGA_NUM_BANKS) % 2) == 0)
798 {
799 /* Highest 4 */
800 PixelData >>= 4;
801 }
802 else
803 {
804 /* Lowest 4 */
805 PixelData &= 0x0F;
806 }
807 }
808 }
809 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
810 {
811 /* Check if this is 16 or 256 color mode */
812 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
813 {
814 // TODO: NOT IMPLEMENTED
815 DPRINT1("8-bit interleaved mode is not implemented!\n");
816 }
817 else
818 {
819 /*
820 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
821 * then 2 bits shifted from plane 1 and 3 for the next 4
822 */
823 BYTE LowPlaneData = VgaMemory[((j / 4) % 2) * VGA_BANK_SIZE
824 + (Address + (j / 8)) * AddressSize];
825 BYTE HighPlaneData = VgaMemory[(((j / 4) % 2) + 2) * VGA_BANK_SIZE
826 + (Address + (j / 8)) * AddressSize];
827
828 /* Extract the two bits from each plane */
829 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
830 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
831
832 /* Combine them into the pixel */
833 PixelData = LowPlaneData | (HighPlaneData << 2);
834 }
835 }
836 else
837 {
838 /* 1 bit shifted from each plane */
839
840 /* Check if this is 16 or 256 color mode */
841 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
842 {
843 /* 8 bits per pixel, 2 on each plane */
844
845 for (k = 0; k < VGA_NUM_BANKS; k++)
846 {
847 /* The data is on plane k, 4 pixels per byte */
848 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
849 + (Address + (j / VGA_NUM_BANKS))
850 * AddressSize];
851
852 /* The mask of the first bit in the pair */
853 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
854
855 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
856 if (PlaneData & BitMask) PixelData |= 1 << k;
857
858 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
859 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
860 }
861 }
862 else
863 {
864 /* 4 bits per pixel, 1 on each plane */
865
866 for (k = 0; k < VGA_NUM_BANKS; k++)
867 {
868 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
869 + (Address + (j / (VGA_NUM_BANKS * 2)))
870 * AddressSize];
871
872 /* If the bit on that plane is set, set it */
873 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
874 }
875 }
876 }
877
878 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
879 {
880 /*
881 * In 16 color mode, the value is an index to the AC registers
882 * if external palette access is disabled, otherwise (in case
883 * of palette loading) it is a blank pixel.
884 */
885 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
886 : 0);
887 }
888
889 /* Take into account DoubleVision mode when checking for pixel updates */
890 if (DoubleVision)
891 {
892 /* Now check if the resulting pixel data has changed */
893 if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
894 {
895 /* Yes, write the new value */
896 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
897 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
898 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
899 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
900
901 /* Mark the specified pixel as changed */
902 VgaMarkForUpdate(i, j);
903 }
904 }
905 else
906 {
907 /* Now check if the resulting pixel data has changed */
908 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
909 {
910 /* Yes, write the new value */
911 GraphicsBuffer[i * Resolution.X + j] = PixelData;
912
913 /* Mark the specified pixel as changed */
914 VgaMarkForUpdate(i, j);
915 }
916 }
917 }
918
919 /* Move to the next scanline */
920 Address += ScanlineSize;
921 }
922
923 /*
924 * Release the console framebuffer mutex
925 * so that we allow for repainting.
926 */
927 ReleaseMutex(ConsoleMutex);
928 }
929 else
930 {
931 /* Text mode */
932 PCHAR_INFO CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
933
934 /* Loop through the scanlines */
935 for (i = 0; i < Resolution.Y; i++)
936 {
937 /* Loop through the characters */
938 for (j = 0; j < Resolution.X; j++)
939 {
940 DWORD CurrentAddr = LOWORD((Address + j) * AddressSize);
941 CHAR_INFO CharInfo;
942
943 /* Plane 0 holds the character itself */
944 CharInfo.Char.AsciiChar = VgaMemory[CurrentAddr];
945
946 /* Plane 1 holds the attribute */
947 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
948
949 /* Now check if the resulting character data has changed */
950 if ((CharBuffer[i * Resolution.X + j].Char.AsciiChar != CharInfo.Char.AsciiChar)
951 || (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
952 {
953 /* Yes, write the new value */
954 CharBuffer[i * Resolution.X + j] = CharInfo;
955
956 /* Mark the specified cell as changed */
957 VgaMarkForUpdate(i, j);
958 }
959 }
960
961 /* Move to the next scanline */
962 Address += ScanlineSize;
963 }
964 }
965 }
966
967 static VOID VgaUpdateTextCursor(VOID)
968 {
969 COORD Position;
970 CONSOLE_CURSOR_INFO CursorInfo;
971 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
972 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
973 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
974 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
975 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
976 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
977
978 /* Just return if we are not in text mode */
979 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) != 0) return;
980
981 if (CursorStart < CursorEnd)
982 {
983 /* Visible cursor */
984 CursorInfo.bVisible = TRUE;
985 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
986 }
987 else
988 {
989 /* No cursor */
990 CursorInfo.bVisible = FALSE;
991 CursorInfo.dwSize = 0;
992 }
993
994 /* Add the cursor skew to the location */
995 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
996
997 /* Find the coordinates of the new position */
998 Position.X = (WORD)(Location % ScanlineSize);
999 Position.Y = (WORD)(Location / ScanlineSize);
1000
1001 /* Update the physical cursor */
1002 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1003 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1004
1005 /* Reset the cursor move flag */
1006 CursorMoved = FALSE;
1007 }
1008
1009 /* PUBLIC FUNCTIONS ***********************************************************/
1010
1011 DWORD VgaGetVideoBaseAddress(VOID)
1012 {
1013 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1014 }
1015
1016 DWORD VgaGetVideoLimitAddress(VOID)
1017 {
1018 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1019 }
1020
1021 COORD VgaGetDisplayResolution(VOID)
1022 {
1023 COORD Resolution;
1024 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1025
1026 /* The low 8 bits are in the display registers */
1027 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1028 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1029
1030 /* Set the top bits from the overflow register */
1031 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1032 {
1033 Resolution.Y |= 1 << 8;
1034 }
1035 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1036 {
1037 Resolution.Y |= 1 << 9;
1038 }
1039
1040 /* Increase the values by 1 */
1041 Resolution.X++;
1042 Resolution.Y++;
1043
1044 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1045 {
1046 /* Multiply the horizontal resolution by the 9/8 dot mode */
1047 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1048 ? 8 : 9;
1049
1050 /* The horizontal resolution is halved in 8-bit mode */
1051 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1052 }
1053
1054 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1055 {
1056 /* Halve the vertical resolution */
1057 Resolution.Y >>= 1;
1058 }
1059 else
1060 {
1061 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1062 Resolution.Y /= MaximumScanLine;
1063 }
1064
1065 /* Return the resolution */
1066 return Resolution;
1067 }
1068
1069 VOID VgaRefreshDisplay(VOID)
1070 {
1071 HANDLE ConsoleBufferHandle = NULL;
1072 COORD Resolution;
1073
1074 /* Set the vertical retrace flag */
1075 InVerticalRetrace = TRUE;
1076
1077 /* If nothing has changed, just return */
1078 if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1079 return;
1080
1081 /* Retrieve the current resolution */
1082 Resolution = VgaGetDisplayResolution();
1083
1084 /* Change the display mode */
1085 if (ModeChanged) VgaChangeMode();
1086
1087 /* Change the text cursor location */
1088 if (CursorMoved) VgaUpdateTextCursor();
1089
1090 if (PaletteChanged)
1091 {
1092 /* Trigger a full update of the screen */
1093 NeedsUpdate = TRUE;
1094 UpdateRectangle.Left = 0;
1095 UpdateRectangle.Top = 0;
1096 UpdateRectangle.Right = Resolution.X;
1097 UpdateRectangle.Bottom = Resolution.Y;
1098
1099 PaletteChanged = FALSE;
1100 }
1101
1102 /* Update the contents of the framebuffer */
1103 VgaUpdateFramebuffer();
1104
1105 /* Ignore if there's nothing to update */
1106 if (!NeedsUpdate) return;
1107
1108 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1109 UpdateRectangle.Left,
1110 UpdateRectangle.Top,
1111 UpdateRectangle.Right,
1112 UpdateRectangle.Bottom);
1113
1114 /* Check if this is text mode or graphics mode */
1115 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1116 {
1117 /* Graphics mode */
1118 ConsoleBufferHandle = GraphicsConsoleBuffer;
1119 }
1120 else
1121 {
1122 /* Text mode */
1123 COORD Origin = { UpdateRectangle.Left, UpdateRectangle.Top };
1124 ConsoleBufferHandle = TextConsoleBuffer;
1125
1126 /* Write the data to the console */
1127 WriteConsoleOutputA(TextConsoleBuffer,
1128 (PCHAR_INFO)ConsoleFramebuffer,
1129 Resolution,
1130 Origin,
1131 &UpdateRectangle);
1132 }
1133
1134 /* In DoubleVision mode, scale the update rectangle */
1135 if (DoubleVision)
1136 {
1137 UpdateRectangle.Left *= 2;
1138 UpdateRectangle.Top *= 2;
1139 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1140 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1141 }
1142
1143 /* Redraw the screen */
1144 InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1145
1146 /* Clear the update flag */
1147 NeedsUpdate = FALSE;
1148 }
1149
1150 VOID VgaHorizontalRetrace(VOID)
1151 {
1152 /* Set the flag */
1153 InHorizontalRetrace = TRUE;
1154 }
1155
1156 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1157 {
1158 DWORD i;
1159 DWORD VideoAddress;
1160
1161 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1162
1163 /* Ignore if video RAM access is disabled */
1164 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1165
1166 /* Loop through each byte */
1167 for (i = 0; i < Size; i++)
1168 {
1169 VideoAddress = VgaTranslateReadAddress(Address + i);
1170
1171 /* Load the latch registers */
1172 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1173 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1174 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1175 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1176
1177 /* Copy the value to the buffer */
1178 Buffer[i] = VgaMemory[VideoAddress];
1179 }
1180 }
1181
1182 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1183 {
1184 DWORD i, j;
1185 DWORD VideoAddress;
1186
1187 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1188
1189 /* Ignore if video RAM access is disabled */
1190 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1191
1192 /* Also ignore if write access to all planes is disabled */
1193 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1194
1195 /* Loop through each byte */
1196 for (i = 0; i < Size; i++)
1197 {
1198 VideoAddress = VgaTranslateWriteAddress(Address + i);
1199
1200 for (j = 0; j < VGA_NUM_BANKS; j++)
1201 {
1202 /* Make sure the page is writeable */
1203 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1204
1205 /* Check if this is chain-4 mode */
1206 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1207 {
1208 if (((Address + i) & 3) != j)
1209 {
1210 /* This plane will not be accessed */
1211 continue;
1212 }
1213 }
1214
1215 /* Check if this is odd-even mode */
1216 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1217 {
1218 if (((Address + i) & 1) != (j & 1))
1219 {
1220 /* This plane will not be accessed */
1221 continue;
1222 }
1223 }
1224
1225 /* Copy the value to the VGA memory */
1226 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1227 }
1228 }
1229 }
1230
1231 BYTE WINAPI VgaReadPort(ULONG Port)
1232 {
1233 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1234
1235 switch (Port)
1236 {
1237 case VGA_MISC_READ:
1238 return VgaMiscRegister;
1239
1240 case VGA_INSTAT0_READ:
1241 return 0; // Not implemented
1242
1243 case VGA_INSTAT1_READ_MONO:
1244 case VGA_INSTAT1_READ_COLOR:
1245 {
1246 BYTE Result = 0;
1247
1248 /* Reset the AC latch */
1249 VgaAcLatch = FALSE;
1250
1251 /* Set a flag if there is a vertical or horizontal retrace */
1252 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1253
1254 /* Set an additional flag if there was a vertical retrace */
1255 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1256
1257 /* Clear the flags */
1258 InHorizontalRetrace = InVerticalRetrace = FALSE;
1259
1260 return Result;
1261 }
1262
1263 case VGA_FEATURE_READ:
1264 return VgaFeatureRegister;
1265
1266 case VGA_AC_INDEX:
1267 return VgaAcIndex;
1268
1269 case VGA_AC_READ:
1270 return VgaAcRegisters[VgaAcIndex];
1271
1272 case VGA_SEQ_INDEX:
1273 return VgaSeqIndex;
1274
1275 case VGA_SEQ_DATA:
1276 return VgaSeqRegisters[VgaSeqIndex];
1277
1278 case VGA_DAC_MASK:
1279 return VgaDacMask;
1280
1281 case VGA_DAC_READ_INDEX:
1282 /* This returns the read/write state */
1283 return (VgaDacReadWrite ? 0 : 3);
1284
1285 case VGA_DAC_WRITE_INDEX:
1286 return (VgaDacIndex / 3);
1287
1288 case VGA_DAC_DATA:
1289 {
1290 /* Ignore reads in write mode */
1291 if (!VgaDacReadWrite)
1292 {
1293 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1294 VgaDacIndex %= VGA_PALETTE_SIZE;
1295 return Data;
1296 }
1297
1298 break;
1299 }
1300
1301 case VGA_CRTC_INDEX_MONO:
1302 case VGA_CRTC_INDEX_COLOR:
1303 return VgaCrtcIndex;
1304
1305 case VGA_CRTC_DATA_MONO:
1306 case VGA_CRTC_DATA_COLOR:
1307 return VgaCrtcRegisters[VgaCrtcIndex];
1308
1309 case VGA_GC_INDEX:
1310 return VgaGcIndex;
1311
1312 case VGA_GC_DATA:
1313 return VgaGcRegisters[VgaGcIndex];
1314
1315 default:
1316 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1317 break;
1318 }
1319
1320 return 0;
1321 }
1322
1323 VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1324 {
1325 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1326
1327 switch (Port)
1328 {
1329 case VGA_MISC_WRITE:
1330 {
1331 VgaMiscRegister = Data;
1332
1333 if (VgaMiscRegister & 0x01)
1334 {
1335 /* Color emulation */
1336 DPRINT1("Color emulation\n");
1337
1338 /* Register the new I/O Ports */
1339 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1340 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1341 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1342
1343 /* Unregister the old ones */
1344 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1345 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1346 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1347 }
1348 else
1349 {
1350 /* Monochrome emulation */
1351 DPRINT1("Monochrome emulation\n");
1352
1353 /* Register the new I/O Ports */
1354 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1355 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1356 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1357
1358 /* Unregister the old ones */
1359 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1360 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1361 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1362 }
1363
1364 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1365 break;
1366 }
1367
1368 case VGA_FEATURE_WRITE_MONO:
1369 case VGA_FEATURE_WRITE_COLOR:
1370 {
1371 VgaFeatureRegister = Data;
1372 break;
1373 }
1374
1375 case VGA_AC_INDEX:
1376 // case VGA_AC_WRITE:
1377 {
1378 if (!VgaAcLatch)
1379 {
1380 /* Change the index */
1381 BYTE Index = Data & 0x1F;
1382 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1383
1384 /*
1385 * Change palette protection by checking for
1386 * the Palette Address Source bit.
1387 */
1388 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1389 }
1390 else
1391 {
1392 /* Write the data */
1393 VgaWriteAc(Data);
1394 }
1395
1396 /* Toggle the latch */
1397 VgaAcLatch = !VgaAcLatch;
1398 break;
1399 }
1400
1401 case VGA_SEQ_INDEX:
1402 {
1403 /* Set the sequencer index register */
1404 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1405 break;
1406 }
1407
1408 case VGA_SEQ_DATA:
1409 {
1410 /* Call the sequencer function */
1411 VgaWriteSequencer(Data);
1412 break;
1413 }
1414
1415 case VGA_DAC_MASK:
1416 {
1417 VgaDacMask = Data;
1418 break;
1419 }
1420
1421 case VGA_DAC_READ_INDEX:
1422 {
1423 VgaDacReadWrite = FALSE;
1424 VgaDacIndex = Data * 3;
1425 break;
1426 }
1427
1428 case VGA_DAC_WRITE_INDEX:
1429 {
1430 VgaDacReadWrite = TRUE;
1431 VgaDacIndex = Data * 3;
1432 break;
1433 }
1434
1435 case VGA_DAC_DATA:
1436 {
1437 /* Ignore writes in read mode */
1438 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1439 break;
1440 }
1441
1442 case VGA_CRTC_INDEX_MONO:
1443 case VGA_CRTC_INDEX_COLOR:
1444 {
1445 /* Set the CRTC index register */
1446 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1447 break;
1448 }
1449
1450 case VGA_CRTC_DATA_MONO:
1451 case VGA_CRTC_DATA_COLOR:
1452 {
1453 /* Call the CRTC function */
1454 VgaWriteCrtc(Data);
1455 break;
1456 }
1457
1458 case VGA_GC_INDEX:
1459 {
1460 /* Set the GC index register */
1461 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1462 break;
1463 }
1464
1465 case VGA_GC_DATA:
1466 {
1467 /* Call the GC function */
1468 VgaWriteGc(Data);
1469 break;
1470 }
1471
1472 default:
1473 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1474 break;
1475 }
1476 }
1477
1478 VOID VgaClearMemory(VOID)
1479 {
1480 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1481 }
1482
1483 VOID VgaResetPalette(VOID)
1484 {
1485 PALETTEENTRY Entries[VGA_MAX_COLORS];
1486
1487 /* Restore the default palette */
1488 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1489 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1490 PaletteChanged = TRUE;
1491 }
1492
1493 BOOLEAN VgaInitialize(HANDLE TextHandle)
1494 {
1495 INT i, j;
1496 COORD Resolution;
1497 DWORD AddressSize;
1498 DWORD ScanlineSize;
1499 COORD Origin = { 0, 0 };
1500 SMALL_RECT ScreenRect;
1501 PCHAR_INFO CharBuffer;
1502 DWORD Address = 0;
1503 DWORD CurrentAddr;
1504
1505 /* Save the console information */
1506 if (TextHandle == INVALID_HANDLE_VALUE) return FALSE;
1507 VgaSavedConsoleHandle = TextHandle;
1508 if (!GetConsoleScreenBufferInfo(VgaSavedConsoleHandle,
1509 &VgaSavedConsoleInfo))
1510 {
1511 return FALSE;
1512 }
1513
1514 /* Initialize the VGA palette and fail if it isn't successfully created */
1515 if (!VgaInitializePalette()) return FALSE;
1516 /***/ VgaResetPalette(); /***/
1517
1518 /* Save the default text-mode console output handle */
1519 TextConsoleBuffer = TextHandle;
1520
1521 /* Clear the VGA memory */
1522 VgaClearMemory();
1523
1524 /* Register the I/O Ports */
1525 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
1526 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1527 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
1528 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
1529 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
1530 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
1531 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
1532 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
1533 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
1534 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
1535 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
1536 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
1537 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
1538
1539 /* Set the default video mode */
1540 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
1541 VgaChangeMode();
1542
1543 /* Get the data */
1544 Resolution = VgaGetDisplayResolution();
1545 CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
1546 AddressSize = VgaGetAddressSize();
1547 ScreenRect.Left = ScreenRect.Top = 0;
1548 ScreenRect.Right = Resolution.X;
1549 ScreenRect.Bottom = Resolution.Y;
1550 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1551
1552 /* Read the data from the console into the framebuffer */
1553 ReadConsoleOutputA(TextConsoleBuffer,
1554 CharBuffer,
1555 Resolution,
1556 Origin,
1557 &ScreenRect);
1558
1559 /* Loop through the scanlines */
1560 for (i = 0; i < Resolution.Y; i++)
1561 {
1562 /* Loop through the characters */
1563 for (j = 0; j < Resolution.X; j++)
1564 {
1565 CurrentAddr = LOWORD((Address + j) * AddressSize);
1566
1567 /* Store the character in plane 0 */
1568 VgaMemory[CurrentAddr] = CharBuffer[i * Resolution.X + j].Char.AsciiChar;
1569
1570 /* Store the attribute in plane 1 */
1571 VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuffer[i * Resolution.X + j].Attributes;
1572 }
1573
1574 /* Move to the next scanline */
1575 Address += ScanlineSize;
1576 }
1577
1578 /* Return success */
1579 return TRUE;
1580 }
1581
1582 /* EOF */