2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: consrv/condrv/console.c
5 * PURPOSE: Console Management Functions
6 * PROGRAMMERS: Gé van Geldorp
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
21 /* GLOBALS ********************************************************************/
23 static ULONG CurrentConsoleID
= 0;
25 /* Linked list of consoles */
26 static LIST_ENTRY ConsoleList
;
27 static RTL_RESOURCE ListLock
;
29 #define ConDrvLockConsoleListExclusive() \
30 RtlAcquireResourceExclusive(&ListLock, TRUE)
32 #define ConDrvLockConsoleListShared() \
33 RtlAcquireResourceShared(&ListLock, TRUE)
35 #define ConDrvUnlockConsoleList() \
36 RtlReleaseResource(&ListLock)
40 InsertConsole(IN PCONSOLE Console
)
44 /* All went right, so add the console to the list */
45 ConDrvLockConsoleListExclusive();
47 DPRINT("Insert in the list\n");
48 InsertTailList(&ConsoleList
, &Console
->ListEntry
);
50 // FIXME: Move this code to the caller function!!
51 /* Get a new console ID */
52 _InterlockedExchange((PLONG
)&Console
->ConsoleID
, CurrentConsoleID
);
53 _InterlockedIncrement((PLONG
)&CurrentConsoleID
);
55 /* Unlock the console list and return success */
56 ConDrvUnlockConsoleList();
57 return STATUS_SUCCESS
;
61 RemoveConsole(IN PCONSOLE Console
)
64 if (!Console
) return STATUS_INVALID_PARAMETER
;
66 /* Remove the console from the list */
67 ConDrvLockConsoleListExclusive();
69 RemoveEntryList(&Console
->ListEntry
);
71 /* Unlock the console list and return success */
72 ConDrvUnlockConsoleList();
73 return STATUS_SUCCESS
;
77 /* PRIVATE FUNCTIONS **********************************************************/
80 ConDrvPause(PCONSOLE Console
)
82 /* In case we already have a pause event, just exit... */
83 if (Console
->UnpauseEvent
) return;
85 /* ... otherwise create it */
86 NtCreateEvent(&Console
->UnpauseEvent
, EVENT_ALL_ACCESS
,
87 NULL
, NotificationEvent
, FALSE
);
91 ConDrvUnpause(PCONSOLE Console
)
93 /* In case we already freed the event, just exit... */
94 if (!Console
->UnpauseEvent
) return;
96 /* ... otherwise set and free it */
97 NtSetEvent(Console
->UnpauseEvent
, NULL
);
98 NtClose(Console
->UnpauseEvent
);
99 Console
->UnpauseEvent
= NULL
;
104 * Console accessibility check helpers
108 ConDrvValidateConsoleState(IN PCONSOLE Console
,
109 IN CONSOLE_STATE ExpectedState
)
111 // if (!Console) return FALSE;
113 /* The console must be locked */
114 // ASSERT(Console_locked);
116 return (Console
->State
== ExpectedState
);
120 ConDrvValidateConsoleUnsafe(IN PCONSOLE Console
,
121 IN CONSOLE_STATE ExpectedState
,
122 IN BOOLEAN LockConsole
)
124 if (!Console
) return FALSE
;
127 * Lock the console to forbid possible console's state changes
128 * (which must be done when the console is already locked).
129 * If we don't want to lock it, it's because the lock is already
130 * held. So there must be no problems.
132 if (LockConsole
) EnterCriticalSection(&Console
->Lock
);
134 // ASSERT(Console_locked);
136 /* Check whether the console's state is what we expect */
137 if (!ConDrvValidateConsoleState(Console
, ExpectedState
))
139 if (LockConsole
) LeaveCriticalSection(&Console
->Lock
);
147 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
150 ConDrvInitConsoleSupport(VOID
)
152 DPRINT("CONSRV: ConDrvInitConsoleSupport()\n");
154 /* Initialize the console list and its lock */
155 InitializeListHead(&ConsoleList
);
156 RtlInitializeResource(&ListLock
);
159 /* For resetting the terminal - defined in dummyterm.c */
160 VOID
ResetTerminal(IN PCONSOLE Console
);
163 ConDrvInitConsole(OUT PCONSOLE
* NewConsole
,
164 IN PCONSOLE_INFO ConsoleInfo
)
167 // CONSOLE_INFO CapturedConsoleInfo;
168 TEXTMODE_BUFFER_INFO ScreenBufferInfo
;
170 PCONSOLE_SCREEN_BUFFER NewBuffer
;
172 if (NewConsole
== NULL
|| ConsoleInfo
== NULL
)
173 return STATUS_INVALID_PARAMETER
;
178 * Allocate a new console
180 Console
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(*Console
));
183 DPRINT1("Not enough memory for console creation.\n");
184 return STATUS_NO_MEMORY
;
188 * Fix the screen buffer size if needed. The rule is:
189 * ScreenBufferSize >= ConsoleSize
191 if (ConsoleInfo
->ScreenBufferSize
.X
< ConsoleInfo
->ConsoleSize
.X
)
192 ConsoleInfo
->ScreenBufferSize
.X
= ConsoleInfo
->ConsoleSize
.X
;
193 if (ConsoleInfo
->ScreenBufferSize
.Y
< ConsoleInfo
->ConsoleSize
.Y
)
194 ConsoleInfo
->ScreenBufferSize
.Y
= ConsoleInfo
->ConsoleSize
.Y
;
197 * Initialize the console
199 Console
->State
= CONSOLE_INITIALIZING
;
200 Console
->ReferenceCount
= 0;
201 InitializeCriticalSection(&Console
->Lock
);
203 /* Initialize the terminal interface */
204 ResetTerminal(Console
);
206 Console
->ConsoleSize
= ConsoleInfo
->ConsoleSize
;
207 Console
->FixedSize
= FALSE
; // Value by default; is reseted by the terminals if needed.
209 /* Initialize the input buffer */
210 Status
= ConDrvInitInputBuffer(Console
, 0 /* ConsoleInfo->InputBufferSize */);
211 if (!NT_SUCCESS(Status
))
213 DPRINT1("ConDrvInitInputBuffer: failed, Status = 0x%08lx\n", Status
);
214 DeleteCriticalSection(&Console
->Lock
);
215 ConsoleFreeHeap(Console
);
219 /* Set-up the code page */
220 Console
->InputCodePage
= Console
->OutputCodePage
= ConsoleInfo
->CodePage
;
222 /* Initialize a new text-mode screen buffer with default settings */
223 ScreenBufferInfo
.ScreenBufferSize
= ConsoleInfo
->ScreenBufferSize
;
224 ScreenBufferInfo
.ScreenAttrib
= ConsoleInfo
->ScreenAttrib
;
225 ScreenBufferInfo
.PopupAttrib
= ConsoleInfo
->PopupAttrib
;
226 ScreenBufferInfo
.IsCursorVisible
= TRUE
;
227 ScreenBufferInfo
.CursorSize
= ConsoleInfo
->CursorSize
;
229 InitializeListHead(&Console
->BufferList
);
230 Status
= ConDrvCreateScreenBuffer(&NewBuffer
,
233 CONSOLE_TEXTMODE_BUFFER
,
235 if (!NT_SUCCESS(Status
))
237 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
238 ConDrvDeinitInputBuffer(Console
);
239 DeleteCriticalSection(&Console
->Lock
);
240 ConsoleFreeHeap(Console
);
243 /* Make the new screen buffer active */
244 Console
->ActiveBuffer
= NewBuffer
;
245 Console
->UnpauseEvent
= NULL
;
247 DPRINT("Console initialized\n");
249 /* All went right, so add the console to the list */
250 Status
= InsertConsole(Console
);
251 if (!NT_SUCCESS(Status
))
254 ConDrvDeleteConsole(Console
);
258 /* The initialization is finished */
259 DPRINT("Change state\n");
260 Console
->State
= CONSOLE_RUNNING
;
262 /* Return the newly created console to the caller and a success code too */
263 *NewConsole
= Console
;
264 return STATUS_SUCCESS
;
268 ConDrvAttachTerminal(IN PCONSOLE Console
,
269 IN PTERMINAL Terminal
)
273 if (Console
== NULL
|| Terminal
== NULL
)
274 return STATUS_INVALID_PARAMETER
;
276 /* FIXME: Lock the console before ?? */
279 * Attach the terminal to the console. Use now the TermIFace of the console,
280 * and not the user-defined temporary Terminal pointer.
282 Console
->TermIFace
= *Terminal
;
283 Console
->TermIFace
.Console
= Console
;
285 /* Initialize the terminal AFTER having attached it to the console */
286 DPRINT("Finish initialization of terminal\n");
287 Status
= Console
->TermIFace
.Vtbl
->InitTerminal(&Console
->TermIFace
, Console
);
288 if (!NT_SUCCESS(Status
))
290 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status
);
292 /* We failed, detach the terminal from the console */
293 Terminal
->Console
= NULL
; // For the caller
294 ResetTerminal(Console
);
298 /* Copy buffer contents to screen */
301 DPRINT("Terminal initialization done\n");
302 return STATUS_SUCCESS
;
306 ConDrvDetachTerminal(IN PCONSOLE Console
)
308 if (Console
== NULL
) return STATUS_INVALID_PARAMETER
;
310 /* FIXME: Lock the console before ?? */
312 /* Deinitialize the terminal BEFORE detaching it from the console */
313 Console
->TermIFace
.Vtbl
->DeinitTerminal(&Console
->TermIFace
/*, Console*/);
316 * Detach the terminal from the console:
317 * reinitialize the terminal interface.
319 ResetTerminal(Console
);
321 DPRINT("Terminal unregistered\n");
322 return STATUS_SUCCESS
;
326 ConDrvDeleteConsole(IN PCONSOLE Console
)
328 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console
);
331 * Forbid validation of any console by other threads
332 * during the deletion of this console.
334 ConDrvLockConsoleListExclusive();
337 * If the console is already being destroyed, i.e. not running
338 * or finishing to be initialized, just return.
340 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
) &&
341 !ConDrvValidateConsoleUnsafe(Console
, CONSOLE_INITIALIZING
, TRUE
))
343 /* Unlock the console list and return */
344 ConDrvUnlockConsoleList();
349 * We are about to be destroyed. Signal it to other people
350 * so that they can terminate what they are doing, and that
351 * they cannot longer validate the console.
353 Console
->State
= CONSOLE_TERMINATING
;
356 * Allow other threads to finish their job: basically, unlock
357 * all other calls to EnterCriticalSection(&Console->Lock); by
358 * ConDrvValidateConsoleUnsafe functions so that they just see
359 * that we are not in CONSOLE_RUNNING state anymore, or unlock
360 * other concurrent calls to ConDrvDeleteConsole so that they
361 * can see that we are in fact already deleting the console.
363 LeaveCriticalSection(&Console
->Lock
);
364 ConDrvUnlockConsoleList();
366 /* Deregister the terminal */
367 DPRINT("Deregister terminal\n");
368 ConDrvDetachTerminal(Console
);
369 DPRINT("Terminal deregistered\n");
372 * Check that the console is in terminating state before continuing
373 * (the cleanup code must not change the state of the console...
374 * ...unless to cancel console deletion ?).
377 ConDrvLockConsoleListExclusive();
379 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_TERMINATING
, TRUE
))
381 ConDrvUnlockConsoleList();
385 /* We are now in destruction */
386 Console
->State
= CONSOLE_IN_DESTRUCTION
;
388 /* We really delete the console. Reset the count to be sure. */
389 Console
->ReferenceCount
= 0;
391 /* Remove the console from the list */
392 RemoveConsole(Console
);
394 /* Delete the last screen buffer */
395 ConDrvDeleteScreenBuffer(Console
->ActiveBuffer
);
396 Console
->ActiveBuffer
= NULL
;
397 if (!IsListEmpty(&Console
->BufferList
))
399 /***ConDrvUnlockConsoleList();***/
400 ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE
);
403 /* Deinitialize the input buffer */
404 ConDrvDeinitInputBuffer(Console
);
406 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
408 DPRINT("ConDrvDeleteConsole - Unlocking\n");
409 LeaveCriticalSection(&Console
->Lock
);
410 DPRINT("ConDrvDeleteConsole - Destroying lock\n");
411 DeleteCriticalSection(&Console
->Lock
);
412 DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n");
414 ConsoleFreeHeap(Console
);
415 DPRINT("ConDrvDeleteConsole - Console destroyed\n");
417 /* Unlock the console list and return */
418 ConDrvUnlockConsoleList();
422 /* PUBLIC DRIVER APIS *********************************************************/
425 ConDrvGetConsoleMode(IN PCONSOLE Console
,
426 IN PCONSOLE_IO_OBJECT Object
,
427 OUT PULONG ConsoleMode
)
429 NTSTATUS Status
= STATUS_SUCCESS
;
431 if (Console
== NULL
|| Object
== NULL
|| ConsoleMode
== NULL
)
432 return STATUS_INVALID_PARAMETER
;
435 ASSERT(Console
== Object
->Console
);
437 /*** FIXME: */ *ConsoleMode
= 0; /***/
439 if (INPUT_BUFFER
== Object
->Type
)
441 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
442 *ConsoleMode
= InputBuffer
->Mode
;
444 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
446 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
447 *ConsoleMode
= Buffer
->Mode
;
451 Status
= STATUS_INVALID_HANDLE
;
458 ConDrvSetConsoleMode(IN PCONSOLE Console
,
459 IN PCONSOLE_IO_OBJECT Object
,
460 IN ULONG ConsoleMode
)
462 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
463 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
465 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
467 NTSTATUS Status
= STATUS_SUCCESS
;
469 if (Console
== NULL
|| Object
== NULL
)
470 return STATUS_INVALID_PARAMETER
;
473 ASSERT(Console
== Object
->Console
);
475 if (INPUT_BUFFER
== Object
->Type
)
477 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
479 /* Only the presence of valid mode flags is allowed */
480 if (ConsoleMode
& ~CONSOLE_VALID_INPUT_MODES
)
482 Status
= STATUS_INVALID_PARAMETER
;
486 InputBuffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_INPUT_MODES
);
489 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
491 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
493 /* Only the presence of valid mode flags is allowed */
494 if (ConsoleMode
& ~CONSOLE_VALID_OUTPUT_MODES
)
496 Status
= STATUS_INVALID_PARAMETER
;
500 Buffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_OUTPUT_MODES
);
505 Status
= STATUS_INVALID_HANDLE
;
512 ConDrvGetConsoleCP(IN PCONSOLE Console
,
516 if (Console
== NULL
|| CodePage
== NULL
)
517 return STATUS_INVALID_PARAMETER
;
519 *CodePage
= (OutputCP
? Console
->OutputCodePage
: Console
->InputCodePage
);
521 return STATUS_SUCCESS
;
525 ConDrvSetConsoleCP(IN PCONSOLE Console
,
529 if (Console
== NULL
|| !IsValidCodePage(CodePage
))
530 return STATUS_INVALID_PARAMETER
;
533 Console
->OutputCodePage
= CodePage
;
535 Console
->InputCodePage
= CodePage
;
537 return STATUS_SUCCESS
;