[SHELL32_APITEST] Follow-up to #6796 (25e2f5f)
[reactos.git] / drivers / setup / blue / font.c
1 /*
2 * PROJECT: ReactOS Console Text-Mode Device Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Loading specific fonts into VGA.
5 * COPYRIGHT: Copyright 2008-2019 Aleksey Bragin (aleksey@reactos.org)
6 * Copyright 2008-2019 Colin Finck (mail@colinfinck.de)
7 * Copyright 2008-2019 Christoph von Wittich (christoph_vw@reactos.org)
8 */
9
10 /* INCLUDES ***************************************************************/
11
12 #include "blue.h"
13 #include <ndk/rtlfuncs.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 NTSTATUS ExtractFont(_In_ ULONG CodePage, _In_ PUCHAR FontBitField);
19 VOID OpenBitPlane(VOID);
20 VOID CloseBitPlane(VOID);
21 VOID LoadFont(_In_ PUCHAR Bitplane, _In_ PUCHAR FontBitfield);
22
23 /* FUNCTIONS ****************************************************************/
24
25 VOID
26 ScrLoadFontTable(
27 _In_ ULONG CodePage)
28 {
29 PHYSICAL_ADDRESS BaseAddress;
30 PUCHAR Bitplane;
31 PUCHAR FontBitfield = NULL;
32 NTSTATUS Status = STATUS_SUCCESS;
33
34 FontBitfield = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_BLUE);
35 if (FontBitfield == NULL)
36 {
37 DPRINT1("ExAllocatePoolWithTag failed\n");
38 return;
39 }
40
41 /* open bit plane for font table access */
42 OpenBitPlane();
43
44 /* get pointer to video memory */
45 BaseAddress.QuadPart = BITPLANE_BASE;
46 Bitplane = (PUCHAR)MmMapIoSpace(BaseAddress, 0xFFFF, MmNonCached);
47
48 Status = ExtractFont(CodePage, FontBitfield);
49 if (NT_SUCCESS(Status))
50 {
51 LoadFont(Bitplane, FontBitfield);
52 }
53 else
54 {
55 DPRINT1("ExtractFont failed with Status 0x%lx\n", Status);
56 }
57
58 MmUnmapIoSpace(Bitplane, 0xFFFF);
59 ExFreePoolWithTag(FontBitfield, TAG_BLUE);
60
61 /* close bit plane */
62 CloseBitPlane();
63 }
64
65 VOID
66 ScrSetFont(
67 _In_ PUCHAR FontBitfield)
68 {
69 PHYSICAL_ADDRESS BaseAddress;
70 PUCHAR Bitplane;
71
72 /* open bit plane for font table access */
73 OpenBitPlane();
74
75 /* get pointer to video memory */
76 BaseAddress.QuadPart = BITPLANE_BASE;
77 Bitplane = (PUCHAR)MmMapIoSpace(BaseAddress, 0xFFFF, MmNonCached);
78
79 LoadFont(Bitplane, FontBitfield);
80
81 MmUnmapIoSpace(Bitplane, 0xFFFF);
82
83 /* close bit plane */
84 CloseBitPlane();
85 }
86
87 /* PRIVATE FUNCTIONS *********************************************************/
88
89 NTSTATUS
90 ExtractFont(
91 _In_ ULONG CodePage,
92 _In_ PUCHAR FontBitField)
93 {
94 BOOLEAN bFoundFile = FALSE;
95 HANDLE Handle;
96 NTSTATUS Status;
97 CHAR FileName[20];
98 IO_STATUS_BLOCK IoStatusBlock;
99 OBJECT_ATTRIBUTES ObjectAttributes;
100 UNICODE_STRING LinkName;
101 UNICODE_STRING SourceName;
102 CFHEADER CabFileHeader;
103 CFFILE CabFile;
104 ULONG CabFileOffset = 0;
105 LARGE_INTEGER ByteOffset;
106 WCHAR SourceBuffer[MAX_PATH] = { L'\0' };
107 ULONG ReadCP;
108
109 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
110 return STATUS_INVALID_DEVICE_STATE;
111
112 RtlInitUnicodeString(&LinkName,
113 L"\\SystemRoot");
114
115 InitializeObjectAttributes(&ObjectAttributes,
116 &LinkName,
117 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
118 NULL,
119 NULL);
120
121 Status = ZwOpenSymbolicLinkObject(&Handle,
122 SYMBOLIC_LINK_ALL_ACCESS,
123 &ObjectAttributes);
124
125 if (!NT_SUCCESS(Status))
126 {
127 DPRINT1("ZwOpenSymbolicLinkObject failed with Status 0x%lx\n", Status);
128 return Status;
129 }
130
131 SourceName.Length = 0;
132 SourceName.MaximumLength = MAX_PATH * sizeof(WCHAR);
133 SourceName.Buffer = SourceBuffer;
134
135 Status = ZwQuerySymbolicLinkObject(Handle,
136 &SourceName,
137 NULL);
138 ZwClose(Handle);
139
140 if (!NT_SUCCESS(Status))
141 {
142 DPRINT1("ZwQuerySymbolicLinkObject failed with Status 0x%lx\n", Status);
143 return Status;
144 }
145
146 Status = RtlAppendUnicodeToString(&SourceName, L"\\vgafonts.cab");
147 if (!NT_SUCCESS(Status))
148 {
149 DPRINT1("RtlAppendUnicodeToString failed with Status 0x%lx\n", Status);
150 return Status;
151 }
152
153 InitializeObjectAttributes(&ObjectAttributes,
154 &SourceName,
155 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
156 NULL,
157 NULL);
158
159 Status = ZwCreateFile(&Handle,
160 GENERIC_READ,
161 &ObjectAttributes,
162 &IoStatusBlock,
163 NULL,
164 FILE_ATTRIBUTE_NORMAL,
165 0,
166 FILE_OPEN,
167 FILE_SYNCHRONOUS_IO_NONALERT,
168 NULL,
169 0);
170 if (!NT_SUCCESS(Status))
171 {
172 DPRINT1("Error: Cannot open vgafonts.cab (0x%lx)\n", Status);
173 return Status;
174 }
175
176 ByteOffset.QuadPart = 0;
177 Status = ZwReadFile(Handle,
178 NULL,
179 NULL,
180 NULL,
181 &IoStatusBlock,
182 &CabFileHeader,
183 sizeof(CabFileHeader),
184 &ByteOffset,
185 NULL);
186
187 if (!NT_SUCCESS(Status))
188 {
189 DPRINT1("Error: Cannot read from file (0x%lx)\n", Status);
190 goto Exit;
191 }
192
193 if (CabFileHeader.Signature != CAB_SIGNATURE)
194 {
195 DPRINT1("Invalid CAB signature: 0x%lx!\n", CabFileHeader.Signature);
196 Status = STATUS_UNSUCCESSFUL;
197 goto Exit;
198 }
199
200 // We have a valid CAB file!
201 // Read the file table now and decrement the file count on every file. When it's zero, we read the complete table.
202 ByteOffset.QuadPart = CabFileHeader.FileTableOffset;
203
204 while (CabFileHeader.FileCount)
205 {
206 Status = ZwReadFile(Handle,
207 NULL,
208 NULL,
209 NULL,
210 &IoStatusBlock,
211 &CabFile,
212 sizeof(CabFile),
213 &ByteOffset,
214 NULL);
215
216 if (NT_SUCCESS(Status))
217 {
218 ByteOffset.QuadPart += sizeof(CabFile);
219
220 // We assume here that the file name is max. 19 characters (+ 1 NULL character) long.
221 // This should be enough for our purpose.
222 Status = ZwReadFile(Handle,
223 NULL,
224 NULL,
225 NULL,
226 &IoStatusBlock,
227 FileName,
228 sizeof(FileName),
229 &ByteOffset,
230 NULL);
231
232 if (NT_SUCCESS(Status))
233 {
234 if (!bFoundFile)
235 {
236 Status = RtlCharToInteger(FileName, 0, &ReadCP);
237 if (NT_SUCCESS(Status) && ReadCP == CodePage)
238 {
239 // We got the correct file.
240 // Save the offset and loop through the rest of the file table to find the position, where the actual data starts.
241 CabFileOffset = CabFile.FileOffset;
242 bFoundFile = TRUE;
243 }
244 }
245
246 ByteOffset.QuadPart += strlen(FileName) + 1;
247 }
248 }
249
250 CabFileHeader.FileCount--;
251 }
252
253 // 8 = Size of a CFFOLDER structure (see cabman). As we don't need the values of that structure, just increase the offset here.
254 ByteOffset.QuadPart += 8;
255 ByteOffset.QuadPart += CabFileOffset;
256
257 // ByteOffset now contains the offset of the actual data, so we can read the RAW font
258 Status = ZwReadFile(Handle,
259 NULL,
260 NULL,
261 NULL,
262 &IoStatusBlock,
263 FontBitField,
264 2048,
265 &ByteOffset,
266 NULL);
267 if (!NT_SUCCESS(Status))
268 {
269 DPRINT1("ZwReadFile failed with Status 0x%lx\n", Status);
270 }
271
272 Exit:
273
274 ZwClose(Handle);
275 return Status;
276 }
277
278 /* Font-load specific funcs */
279 VOID
280 OpenBitPlane(VOID)
281 {
282 /* disable interrupts */
283 _disable();
284
285 /* sequence reg */
286 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x01);
287 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_ENABLE_WRT_PLANE); WRITE_PORT_UCHAR(SEQ_DATA, 0x04);
288 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_MEM_MODE); WRITE_PORT_UCHAR(SEQ_DATA, 0x07);
289 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
290
291 /* graphic reg */
292 WRITE_PORT_UCHAR(GCT_COMMAND, GCT_READ_PLANE); WRITE_PORT_UCHAR(GCT_DATA, 0x02);
293 WRITE_PORT_UCHAR(GCT_COMMAND, GCT_RW_MODES); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
294 WRITE_PORT_UCHAR(GCT_COMMAND, GCT_GRAPH_MODE); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
295
296 /* enable interrupts */
297 _enable();
298 }
299
300 VOID
301 CloseBitPlane(VOID)
302 {
303 /* disable interrupts */
304 _disable();
305
306 /* sequence reg */
307 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x01);
308 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_ENABLE_WRT_PLANE); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
309 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_MEM_MODE); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
310 WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
311
312 /* graphic reg */
313 WRITE_PORT_UCHAR(GCT_COMMAND, GCT_READ_PLANE); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
314 WRITE_PORT_UCHAR(GCT_COMMAND, GCT_RW_MODES); WRITE_PORT_UCHAR(GCT_DATA, 0x10);
315 WRITE_PORT_UCHAR(GCT_COMMAND, GCT_GRAPH_MODE); WRITE_PORT_UCHAR(GCT_DATA, 0x0e);
316
317 /* enable interrupts */
318 _enable();
319 }
320
321 VOID
322 LoadFont(
323 _In_ PUCHAR Bitplane,
324 _In_ PUCHAR FontBitfield)
325 {
326 UINT32 i, j;
327
328 for (i = 0; i < 256; i++)
329 {
330 for (j = 0; j < 8; j++)
331 {
332 *Bitplane = FontBitfield[i * 8 + j];
333 Bitplane++;
334 }
335
336 // padding
337 for (j = 8; j < 32; j++)
338 {
339 *Bitplane = 0;
340 Bitplane++;
341 }
342 }
343 }