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 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 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 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 Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage; 120 121 Console->IsCJK = IsCJKCodePage(Console->OutputCodePage); 122 123 /* Initialize a new text-mode screen buffer with default settings */ 124 ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize; 125 ScreenBufferInfo.ViewSize = ConsoleInfo->ConsoleSize; 126 ScreenBufferInfo.ScreenAttrib = ConsoleInfo->ScreenAttrib; 127 ScreenBufferInfo.PopupAttrib = ConsoleInfo->PopupAttrib; 128 ScreenBufferInfo.CursorSize = ConsoleInfo->CursorSize; 129 ScreenBufferInfo.IsCursorVisible = TRUE; 130 131 InitializeListHead(&Console->BufferList); 132 Status = ConDrvCreateScreenBuffer(&NewBuffer, 133 Console, 134 NULL, 135 CONSOLE_TEXTMODE_BUFFER, 136 &ScreenBufferInfo); 137 if (!NT_SUCCESS(Status)) 138 { 139 DPRINT1("ConDrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status); 140 ConDrvDeinitInputBuffer(Console); 141 DeleteCriticalSection(&Console->Lock); 142 return Status; 143 } 144 /* Make the new screen buffer active */ 145 Console->ActiveBuffer = NewBuffer; 146 Console->ConsolePaused = FALSE; 147 148 DPRINT("Console initialized\n"); 149 150 /* The initialization is finished */ 151 DPRINT("Change state\n"); 152 Console->State = CONSOLE_RUNNING; 153 154 /* The caller now has a newly initialized console */ 155 return STATUS_SUCCESS; 156 } 157 158 NTSTATUS NTAPI 159 ConDrvAttachTerminal(IN PCONSOLE Console, 160 IN PTERMINAL Terminal) 161 { 162 NTSTATUS Status; 163 164 if (Console == NULL || Terminal == NULL) 165 return STATUS_INVALID_PARAMETER; 166 167 /* FIXME: Lock the console before ?? */ 168 169 /* 170 * Attach the terminal to the console. Use now the TermIFace of the console, 171 * and not the user-defined temporary Terminal pointer. 172 */ 173 Console->TermIFace = *Terminal; 174 Console->TermIFace.Console = Console; 175 176 /* Initialize the terminal AFTER having attached it to the console */ 177 DPRINT("Finish initialization of terminal\n"); 178 Status = Console->TermIFace.Vtbl->InitTerminal(&Console->TermIFace, Console); 179 if (!NT_SUCCESS(Status)) 180 { 181 DPRINT1("Terminal initialization failed, Status = 0x%08lx\n", Status); 182 183 /* We failed, detach the terminal from the console */ 184 Terminal->Console = NULL; // For the caller 185 ResetTerminal(Console); 186 return Status; 187 } 188 189 /* Copy buffer contents to screen */ 190 // Terminal.Draw(); 191 192 DPRINT("Terminal initialization done\n"); 193 return STATUS_SUCCESS; 194 } 195 196 NTSTATUS NTAPI 197 ConDrvDetachTerminal(IN PCONSOLE Console) 198 { 199 if (Console == NULL) return STATUS_INVALID_PARAMETER; 200 201 /* FIXME: Lock the console before ?? */ 202 203 /* Deinitialize the terminal BEFORE detaching it from the console */ 204 Console->TermIFace.Vtbl->DeinitTerminal(&Console->TermIFace/*, Console*/); 205 206 /* 207 * Detach the terminal from the console: 208 * reinitialize the terminal interface. 209 */ 210 ResetTerminal(Console); 211 212 DPRINT("Terminal unregistered\n"); 213 return STATUS_SUCCESS; 214 } 215 216 VOID NTAPI 217 ConDrvDeleteConsole(IN PCONSOLE Console) 218 { 219 DPRINT("ConDrvDeleteConsole(0x%p)\n", Console); 220 221 /* 222 * Forbid validation of any console by other threads 223 * during the deletion of this console. 224 */ 225 // ConDrvLockConsoleListExclusive(); 226 227 /* 228 * If the console is already being destroyed, i.e. not running 229 * or finishing to be initialized, just return. 230 */ 231 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE) && 232 !ConDrvValidateConsoleUnsafe(Console, CONSOLE_INITIALIZING, TRUE)) 233 { 234 return; 235 } 236 237 /* 238 * We are about to be destroyed. Signal it to other people 239 * so that they can terminate what they are doing, and that 240 * they cannot longer validate the console. 241 */ 242 Console->State = CONSOLE_TERMINATING; 243 244 /* 245 * Allow other threads to finish their job: basically, unlock 246 * all other calls to EnterCriticalSection(&Console->Lock); by 247 * ConDrvValidateConsoleUnsafe() functions so that they just see 248 * that we are not in CONSOLE_RUNNING state anymore, or unlock 249 * other concurrent calls to ConDrvDeleteConsole() so that they 250 * can see that we are in fact already deleting the console. 251 */ 252 LeaveCriticalSection(&Console->Lock); 253 254 /* Deregister the terminal */ 255 DPRINT("Deregister terminal\n"); 256 ConDrvDetachTerminal(Console); 257 DPRINT("Terminal deregistered\n"); 258 259 /*** 260 * Check that the console is in terminating state before continuing 261 * (the cleanup code must not change the state of the console... 262 * ...unless to cancel console deletion ?). 263 ***/ 264 265 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE)) 266 { 267 return; 268 } 269 270 /* We are now in destruction */ 271 Console->State = CONSOLE_IN_DESTRUCTION; 272 273 /* We really delete the console. Reset the count to be sure. */ 274 Console->ReferenceCount = 0; 275 276 /* Delete the last screen buffer */ 277 ConDrvDeleteScreenBuffer(Console->ActiveBuffer); 278 Console->ActiveBuffer = NULL; 279 if (!IsListEmpty(&Console->BufferList)) 280 { 281 /***ConDrvUnlockConsoleList();***/ 282 ASSERTMSG("BUGBUGBUG!! screen buffer list not empty\n", FALSE); 283 } 284 285 /* Deinitialize the input buffer */ 286 ConDrvDeinitInputBuffer(Console); 287 288 Console->ConsolePaused = FALSE; 289 290 DPRINT("ConDrvDeleteConsole - Unlocking\n"); 291 LeaveCriticalSection(&Console->Lock); 292 DPRINT("ConDrvDeleteConsole - Destroying lock\n"); 293 DeleteCriticalSection(&Console->Lock); 294 DPRINT("ConDrvDeleteConsole - Lock destroyed\n"); 295 296 DPRINT("ConDrvDeleteConsole - Console destroyed\n"); 297 } 298 299 300 /* PUBLIC DRIVER APIS *********************************************************/ 301 302 VOID NTAPI 303 ConDrvPause(PCONSOLE Console) 304 { 305 /* In case we are already paused, just exit... */ 306 if (Console->ConsolePaused) return; 307 308 /* ... otherwise set the flag */ 309 Console->ConsolePaused = TRUE; 310 } 311 312 VOID NTAPI 313 ConDrvUnpause(PCONSOLE Console) 314 { 315 /* In case we are already unpaused, just exit... */ 316 if (!Console->ConsolePaused) return; 317 318 /* ... otherwise reset the flag */ 319 Console->ConsolePaused = FALSE; 320 } 321 322 NTSTATUS NTAPI 323 ConDrvGetConsoleMode(IN PCONSOLE Console, 324 IN PCONSOLE_IO_OBJECT Object, 325 OUT PULONG ConsoleMode) 326 { 327 NTSTATUS Status = STATUS_SUCCESS; 328 329 if (Console == NULL || Object == NULL || ConsoleMode == NULL) 330 return STATUS_INVALID_PARAMETER; 331 332 /* Validity check */ 333 ASSERT(Console == Object->Console); 334 335 /*** FIXME: */ *ConsoleMode = 0; /***/ 336 337 if (INPUT_BUFFER == Object->Type) 338 { 339 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; 340 *ConsoleMode = InputBuffer->Mode; 341 } 342 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) 343 { 344 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; 345 *ConsoleMode = Buffer->Mode; 346 } 347 else 348 { 349 Status = STATUS_INVALID_HANDLE; 350 } 351 352 return Status; 353 } 354 355 NTSTATUS NTAPI 356 ConDrvSetConsoleMode(IN PCONSOLE Console, 357 IN PCONSOLE_IO_OBJECT Object, 358 IN ULONG ConsoleMode) 359 { 360 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \ 361 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \ 362 ENABLE_MOUSE_INPUT ) 363 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT ) 364 365 NTSTATUS Status = STATUS_SUCCESS; 366 367 if (Console == NULL || Object == NULL) 368 return STATUS_INVALID_PARAMETER; 369 370 /* Validity check */ 371 ASSERT(Console == Object->Console); 372 373 if (INPUT_BUFFER == Object->Type) 374 { 375 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; 376 377 /* Only the presence of valid mode flags is allowed */ 378 if (ConsoleMode & ~CONSOLE_VALID_INPUT_MODES) 379 { 380 Status = STATUS_INVALID_PARAMETER; 381 } 382 else 383 { 384 InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES); 385 } 386 } 387 else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) 388 { 389 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; 390 391 /* Only the presence of valid mode flags is allowed */ 392 if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES) 393 { 394 Status = STATUS_INVALID_PARAMETER; 395 } 396 else 397 { 398 Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES); 399 } 400 } 401 else 402 { 403 Status = STATUS_INVALID_HANDLE; 404 } 405 406 return Status; 407 } 408 409 NTSTATUS NTAPI 410 ConDrvGetConsoleCP(IN PCONSOLE Console, 411 OUT PUINT CodePage, 412 IN BOOLEAN OutputCP) 413 { 414 if (Console == NULL || CodePage == NULL) 415 return STATUS_INVALID_PARAMETER; 416 417 *CodePage = (OutputCP ? Console->OutputCodePage : Console->InputCodePage); 418 419 return STATUS_SUCCESS; 420 } 421 422 NTSTATUS NTAPI 423 ConDrvSetConsoleCP(IN PCONSOLE Console, 424 IN UINT CodePage, 425 IN BOOLEAN OutputCP) 426 { 427 if (Console == NULL || !IsValidCodePage(CodePage)) 428 return STATUS_INVALID_PARAMETER; 429 430 if (OutputCP) 431 { 432 Console->OutputCodePage = CodePage; 433 Console->IsCJK = IsCJKCodePage(CodePage); 434 } 435 else 436 { 437 Console->InputCodePage = CodePage; 438 } 439 440 return STATUS_SUCCESS; 441 } 442 443 /* EOF */ 444