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