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 { 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 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 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 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 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 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 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 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 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 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