1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Driver DLL
4  * FILE:            win32ss/user/winsrv/consrv/condrv/console.c
5  * PURPOSE:         Console Management Functions
6  * PROGRAMMERS:     G� van Geldorp
7  *                  Jeffrey Morlan
8  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9  *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
10  */
11 
12 /* INCLUDES *******************************************************************/
13 
14 #include <consrv.h>
15 #include <coninput.h>
16 #include "../../concfg/font.h"
17 
18 #define NDEBUG
19 #include <debug.h>
20 
21 /* CONSOLE VALIDATION FUNCTIONS ***********************************************/
22 
23 BOOLEAN NTAPI
ConDrvValidateConsoleState(IN PCONSOLE Console,IN CONSOLE_STATE ExpectedState)24 ConDrvValidateConsoleState(IN PCONSOLE Console,
25                            IN CONSOLE_STATE ExpectedState)
26 {
27     // if (!Console) return FALSE;
28 
29     /* The console must be locked */
30     // ASSERT(Console_locked);
31 
32     return (Console->State == ExpectedState);
33 }
34 
35 BOOLEAN NTAPI
ConDrvValidateConsoleUnsafe(IN PCONSOLE Console,IN CONSOLE_STATE ExpectedState,IN BOOLEAN LockConsole)36 ConDrvValidateConsoleUnsafe(IN PCONSOLE Console,
37                             IN CONSOLE_STATE ExpectedState,
38                             IN BOOLEAN LockConsole)
39 {
40     if (!Console) return FALSE;
41 
42     /*
43      * Lock the console to forbid possible console's state changes
44      * (which must be done when the console is already locked).
45      * If we don't want to lock it, it's because the lock is already
46      * held. So there must be no problems.
47      */
48     if (LockConsole) EnterCriticalSection(&Console->Lock);
49 
50     // ASSERT(Console_locked);
51 
52     /* Check whether the console's state is what we expect */
53     if (!ConDrvValidateConsoleState(Console, ExpectedState))
54     {
55         if (LockConsole) LeaveCriticalSection(&Console->Lock);
56         return FALSE;
57     }
58 
59     return TRUE;
60 }
61 
62 
63 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
64 
65 /* For resetting the terminal - defined in dummyterm.c */
66 VOID ResetTerminal(IN PCONSOLE Console);
67 
68 NTSTATUS NTAPI
ConDrvInitConsole(IN OUT PCONSOLE Console,IN PCONSOLE_INFO ConsoleInfo)69 ConDrvInitConsole(
70     IN OUT PCONSOLE Console,
71     IN PCONSOLE_INFO ConsoleInfo)
72 {
73     NTSTATUS Status;
74     // CONSOLE_INFO CapturedConsoleInfo;
75     TEXTMODE_BUFFER_INFO ScreenBufferInfo;
76     PCONSOLE_SCREEN_BUFFER NewBuffer;
77 
78     if (Console == NULL || ConsoleInfo == NULL)
79         return STATUS_INVALID_PARAMETER;
80 
81     /* Reset the console structure */
82     RtlZeroMemory(Console, sizeof(*Console));
83 
84     /*
85      * Set and fix the screen buffer size if needed.
86      * The rule is: ScreenBufferSize >= ConsoleSize
87      */
88     if (ConsoleInfo->ScreenBufferSize.X == 0) ConsoleInfo->ScreenBufferSize.X = 1;
89     if (ConsoleInfo->ScreenBufferSize.Y == 0) ConsoleInfo->ScreenBufferSize.Y = 1;
90     if (ConsoleInfo->ScreenBufferSize.X < ConsoleInfo->ConsoleSize.X)
91         ConsoleInfo->ScreenBufferSize.X = ConsoleInfo->ConsoleSize.X;
92     if (ConsoleInfo->ScreenBufferSize.Y < ConsoleInfo->ConsoleSize.Y)
93         ConsoleInfo->ScreenBufferSize.Y = ConsoleInfo->ConsoleSize.Y;
94 
95     /*
96      * Initialize the console
97      */
98     Console->State = CONSOLE_INITIALIZING;
99     Console->ReferenceCount = 0;
100     InitializeCriticalSection(&Console->Lock);
101 
102     /* Initialize the terminal interface */
103     ResetTerminal(Console);
104 
105     Console->ConsoleSize = ConsoleInfo->ConsoleSize;
106     Console->FixedSize   = FALSE; // Value by default; is reseted by the terminals if needed.
107 
108     /* Initialize the input buffer */
109     Status = ConDrvInitInputBuffer(Console, 0 /* ConsoleInfo->InputBufferSize */);
110     if (!NT_SUCCESS(Status))
111     {
112         DPRINT1("ConDrvInitInputBuffer: failed, Status = 0x%08lx\n", Status);
113         DeleteCriticalSection(&Console->Lock);
114         return Status;
115     }
116 
117     /* Set-up the code page */
118     if (IsValidCodePage(ConsoleInfo->CodePage))
119     {
120         CON_SET_OUTPUT_CP(Console, ConsoleInfo->CodePage);
121         Console->InputCodePage = ConsoleInfo->CodePage;
122     }
123 
124     /* Initialize a new text-mode screen buffer with default settings */
125     ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
126     ScreenBufferInfo.ViewSize         = ConsoleInfo->ConsoleSize;
127     ScreenBufferInfo.ScreenAttrib     = ConsoleInfo->ScreenAttrib;
128     ScreenBufferInfo.PopupAttrib      = ConsoleInfo->PopupAttrib;
129     ScreenBufferInfo.CursorSize       = ConsoleInfo->CursorSize;
130     ScreenBufferInfo.IsCursorVisible  = TRUE;
131 
132     InitializeListHead(&Console->BufferList);
133     Status = ConDrvCreateScreenBuffer(&NewBuffer,
134                                       Console,
135                                       NULL,
136                                       CONSOLE_TEXTMODE_BUFFER,
137                                       &ScreenBufferInfo);
138     if (!NT_SUCCESS(Status))
139     {
140         DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
141         ConDrvDeinitInputBuffer(Console);
142         DeleteCriticalSection(&Console->Lock);
143         return Status;
144     }
145     /* Make the new screen buffer active */
146     Console->ActiveBuffer = NewBuffer;
147     Console->ConsolePaused = FALSE;
148 
149     DPRINT("Console initialized\n");
150 
151     /* The initialization is finished */
152     DPRINT("Change state\n");
153     Console->State = CONSOLE_RUNNING;
154 
155     /* The caller now has a newly initialized console */
156     return STATUS_SUCCESS;
157 }
158 
159 NTSTATUS NTAPI
ConDrvAttachTerminal(IN PCONSOLE Console,IN PTERMINAL Terminal)160 ConDrvAttachTerminal(IN PCONSOLE Console,
161                      IN PTERMINAL Terminal)
162 {
163     NTSTATUS Status;
164 
165     if (Console == NULL || Terminal == NULL)
166         return STATUS_INVALID_PARAMETER;
167 
168     /* FIXME: Lock the console before ?? */
169 
170     /*
171      * Attach the terminal to the console. Use now the TermIFace of the console,
172      * and not the user-defined temporary Terminal pointer.
173      */
174     Console->TermIFace = *Terminal;
175     Console->TermIFace.Console = Console;
176 
177     /* Initialize the terminal AFTER having attached it to the console */
178     DPRINT("Finish initialization of terminal\n");
179     Status = Console->TermIFace.Vtbl->InitTerminal(&Console->TermIFace, Console);
180     if (!NT_SUCCESS(Status))
181     {
182         DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status);
183 
184         /* We failed, detach the terminal from the console */
185         Terminal->Console = NULL; // For the caller
186         ResetTerminal(Console);
187         return Status;
188     }
189 
190     /* Copy buffer contents to screen */
191     // Terminal.Draw();
192 
193     DPRINT("Terminal initialization done\n");
194     return STATUS_SUCCESS;
195 }
196 
197 NTSTATUS NTAPI
ConDrvDetachTerminal(IN PCONSOLE Console)198 ConDrvDetachTerminal(IN PCONSOLE Console)
199 {
200     if (Console == NULL) return STATUS_INVALID_PARAMETER;
201 
202     /* FIXME: Lock the console before ?? */
203 
204     /* Deinitialize the terminal BEFORE detaching it from the console */
205     Console->TermIFace.Vtbl->DeinitTerminal(&Console->TermIFace/*, Console*/);
206 
207     /*
208      * Detach the terminal from the console:
209      * reinitialize the terminal interface.
210      */
211     ResetTerminal(Console);
212 
213     DPRINT("Terminal unregistered\n");
214     return STATUS_SUCCESS;
215 }
216 
217 VOID NTAPI
ConDrvDeleteConsole(IN PCONSOLE Console)218 ConDrvDeleteConsole(IN PCONSOLE Console)
219 {
220     DPRINT("ConDrvDeleteConsole(0x%p)\n", Console);
221 
222     /*
223      * Forbid validation of any console by other threads
224      * during the deletion of this console.
225      */
226     // ConDrvLockConsoleListExclusive();
227 
228     /*
229      * If the console is already being destroyed, i.e. not running
230      * or finishing to be initialized, just return.
231      */
232     if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE) &&
233         !ConDrvValidateConsoleUnsafe(Console, CONSOLE_INITIALIZING, TRUE))
234     {
235         return;
236     }
237 
238     /*
239      * We are about to be destroyed. Signal it to other people
240      * so that they can terminate what they are doing, and that
241      * they cannot longer validate the console.
242      */
243     Console->State = CONSOLE_TERMINATING;
244 
245     /*
246      * Allow other threads to finish their job: basically, unlock
247      * all other calls to EnterCriticalSection(&Console->Lock); by
248      * ConDrvValidateConsoleUnsafe() functions so that they just see
249      * that we are not in CONSOLE_RUNNING state anymore, or unlock
250      * other concurrent calls to ConDrvDeleteConsole() so that they
251      * can see that we are in fact already deleting the console.
252      */
253     LeaveCriticalSection(&Console->Lock);
254 
255     /* Deregister the terminal */
256     DPRINT("Deregister terminal\n");
257     ConDrvDetachTerminal(Console);
258     DPRINT("Terminal deregistered\n");
259 
260     /***
261      * Check that the console is in terminating state before continuing
262      * (the cleanup code must not change the state of the console...
263      * ...unless to cancel console deletion ?).
264      ***/
265 
266     if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
267     {
268         return;
269     }
270 
271     /* We are now in destruction */
272     Console->State = CONSOLE_IN_DESTRUCTION;
273 
274     /* We really delete the console. Reset the count to be sure. */
275     Console->ReferenceCount = 0;
276 
277     /* Delete the last screen buffer */
278     ConDrvDeleteScreenBuffer(Console->ActiveBuffer);
279     Console->ActiveBuffer = NULL;
280     if (!IsListEmpty(&Console->BufferList))
281     {
282         /***ConDrvUnlockConsoleList();***/
283         ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE);
284     }
285 
286     /* Deinitialize the input buffer */
287     ConDrvDeinitInputBuffer(Console);
288 
289     Console->ConsolePaused = FALSE;
290 
291     DPRINT("ConDrvDeleteConsole - Unlocking\n");
292     LeaveCriticalSection(&Console->Lock);
293     DPRINT("ConDrvDeleteConsole - Destroying lock\n");
294     DeleteCriticalSection(&Console->Lock);
295     DPRINT("ConDrvDeleteConsole - Lock destroyed\n");
296 
297     DPRINT("ConDrvDeleteConsole - Console destroyed\n");
298 }
299 
300 
301 /* PUBLIC DRIVER APIS *********************************************************/
302 
303 VOID NTAPI
ConDrvPause(PCONSOLE Console)304 ConDrvPause(PCONSOLE Console)
305 {
306     /* In case we are already paused, just exit... */
307     if (Console->ConsolePaused) return;
308 
309     /* ... otherwise set the flag */
310     Console->ConsolePaused = TRUE;
311 }
312 
313 VOID NTAPI
ConDrvUnpause(PCONSOLE Console)314 ConDrvUnpause(PCONSOLE Console)
315 {
316     /* In case we are already unpaused, just exit... */
317     if (!Console->ConsolePaused) return;
318 
319     /* ... otherwise reset the flag */
320     Console->ConsolePaused = FALSE;
321 }
322 
323 NTSTATUS NTAPI
ConDrvGetConsoleMode(IN PCONSOLE Console,IN PCONSOLE_IO_OBJECT Object,OUT PULONG ConsoleMode)324 ConDrvGetConsoleMode(IN PCONSOLE Console,
325                      IN PCONSOLE_IO_OBJECT Object,
326                      OUT PULONG ConsoleMode)
327 {
328     NTSTATUS Status = STATUS_SUCCESS;
329 
330     if (Console == NULL || Object == NULL || ConsoleMode == NULL)
331         return STATUS_INVALID_PARAMETER;
332 
333     /* Validity check */
334     ASSERT(Console == Object->Console);
335 
336     /*** FIXME: */ *ConsoleMode = 0; /***/
337 
338     if (INPUT_BUFFER == Object->Type)
339     {
340         PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
341         *ConsoleMode = InputBuffer->Mode;
342     }
343     else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
344     {
345         PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
346         *ConsoleMode = Buffer->Mode;
347     }
348     else
349     {
350         Status = STATUS_INVALID_HANDLE;
351     }
352 
353     return Status;
354 }
355 
356 NTSTATUS NTAPI
ConDrvSetConsoleMode(IN PCONSOLE Console,IN PCONSOLE_IO_OBJECT Object,IN ULONG ConsoleMode)357 ConDrvSetConsoleMode(IN PCONSOLE Console,
358                      IN PCONSOLE_IO_OBJECT Object,
359                      IN ULONG ConsoleMode)
360 {
361 #define CONSOLE_VALID_INPUT_MODES   ( ENABLE_PROCESSED_INPUT  | ENABLE_LINE_INPUT   | \
362                                       ENABLE_ECHO_INPUT       | ENABLE_WINDOW_INPUT | \
363                                       ENABLE_MOUSE_INPUT )
364 #define CONSOLE_VALID_OUTPUT_MODES  ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
365 
366     NTSTATUS Status = STATUS_SUCCESS;
367 
368     if (Console == NULL || Object == NULL)
369         return STATUS_INVALID_PARAMETER;
370 
371     /* Validity check */
372     ASSERT(Console == Object->Console);
373 
374     if (INPUT_BUFFER == Object->Type)
375     {
376         PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
377 
378         /* Only the presence of valid mode flags is allowed */
379         if (ConsoleMode & ~CONSOLE_VALID_INPUT_MODES)
380         {
381             Status = STATUS_INVALID_PARAMETER;
382         }
383         else
384         {
385             InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
386         }
387     }
388     else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
389     {
390         PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
391 
392         /* Only the presence of valid mode flags is allowed */
393         if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
394         {
395             Status = STATUS_INVALID_PARAMETER;
396         }
397         else
398         {
399             Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
400         }
401     }
402     else
403     {
404         Status = STATUS_INVALID_HANDLE;
405     }
406 
407     return Status;
408 }
409 
410 NTSTATUS NTAPI
ConDrvGetConsoleCP(IN PCONSOLE Console,OUT PUINT CodePage,IN BOOLEAN OutputCP)411 ConDrvGetConsoleCP(IN PCONSOLE Console,
412                    OUT PUINT CodePage,
413                    IN BOOLEAN OutputCP)
414 {
415     if (Console == NULL || CodePage == NULL)
416         return STATUS_INVALID_PARAMETER;
417 
418     *CodePage = (OutputCP ? Console->OutputCodePage : Console->InputCodePage);
419 
420     return STATUS_SUCCESS;
421 }
422 
423 NTSTATUS NTAPI
ConDrvSetConsoleCP(IN PCONSOLE Console,IN UINT CodePage,IN BOOLEAN OutputCP)424 ConDrvSetConsoleCP(IN PCONSOLE Console,
425                    IN UINT CodePage,
426                    IN BOOLEAN OutputCP)
427 {
428     if (Console == NULL || !IsValidCodePage(CodePage))
429         return STATUS_INVALID_PARAMETER;
430 
431     if (OutputCP)
432     {
433         /* Request the terminal to change its code page support */
434         if (!TermSetCodePage(Console, CodePage))
435             return STATUS_UNSUCCESSFUL;
436 
437         /* All is fine, actually set the output code page */
438         CON_SET_OUTPUT_CP(Console, CodePage);
439         return STATUS_SUCCESS;
440     }
441     else
442     {
443         Console->InputCodePage = CodePage;
444         return STATUS_SUCCESS;
445     }
446 }
447 
448 /* EOF */
449