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