1 /* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/conmgr.c 5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "sacdrv.h" 12 13 #include <initguid.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 DEFINE_GUID(PRIMARY_SAC_CHANNEL_APPLICATION_GUID, 18 0x63D02270, 19 0x8AA4, 20 0x11D5, 21 0xBC, 0xCF, 0x80, 0x6D, 0x61, 0x72, 0x69, 0x6F); 22 23 LONG CurrentChannelRefCount; 24 KMUTEX CurrentChannelLock; 25 26 PSAC_CHANNEL CurrentChannel; 27 PSAC_CHANNEL SacChannel; 28 29 ULONG ExecutePostConsumerCommand; 30 PSAC_CHANNEL ExecutePostConsumerCommandData; 31 32 BOOLEAN InputInEscape, InputInEscTab, ConMgrLastCharWasCR; 33 CHAR InputBuffer[80]; 34 35 BOOLEAN GlobalPagingNeeded, GlobalDoThreads; 36 37 /* FUNCTIONS ******************************************************************/ 38 39 VOID 40 NTAPI 41 SacPutString(IN PWCHAR String) 42 { 43 NTSTATUS Status; 44 45 /* Write the string on the main SAC channel */ 46 Status = ChannelOWrite(SacChannel, 47 (PCHAR)String, 48 wcslen(String) * sizeof(WCHAR)); 49 if (!NT_SUCCESS(Status)) 50 { 51 SAC_DBG(SAC_DBG_INIT, "SAC XmlMgrSacPutString: OWrite failed\n"); 52 } 53 } 54 55 BOOLEAN 56 NTAPI 57 SacPutSimpleMessage(IN ULONG MessageIndex) 58 { 59 PWCHAR MessageBuffer; 60 BOOLEAN Result; 61 62 /* Get the message */ 63 MessageBuffer = GetMessage(MessageIndex); 64 if (MessageBuffer) 65 { 66 /* Output it */ 67 SacPutString(MessageBuffer); 68 Result = TRUE; 69 } 70 else 71 { 72 Result = FALSE; 73 } 74 75 /* All done */ 76 return Result; 77 } 78 79 NTSTATUS 80 NTAPI 81 ConMgrDisplayCurrentChannel(VOID) 82 { 83 NTSTATUS Status; 84 BOOLEAN HasRedraw; 85 86 /* Make sure the lock is held */ 87 SacAssertMutexLockHeld(); 88 89 /* Check if we can redraw */ 90 Status = ChannelHasRedrawEvent(CurrentChannel, &HasRedraw); 91 if (NT_SUCCESS(Status)) 92 { 93 /* Enable writes */ 94 _InterlockedExchange(&CurrentChannel->WriteEnabled, 1); 95 if (HasRedraw) 96 { 97 /* If we can redraw, set the event */ 98 ChannelSetRedrawEvent(CurrentChannel); 99 } 100 101 /* Flush the output */ 102 Status = ChannelOFlush(CurrentChannel); 103 } 104 105 /* All done, return the status */ 106 return Status; 107 } 108 109 NTSTATUS 110 NTAPI 111 ConMgrWriteData(IN PSAC_CHANNEL Channel, 112 IN PVOID Buffer, 113 IN ULONG BufferLength) 114 { 115 ULONG i; 116 NTSTATUS Status; 117 LARGE_INTEGER Interval; 118 119 /* Loop up to 32 times */ 120 for (i = 0; i < 32; i++) 121 { 122 /* Attempt sending the data */ 123 Status = HeadlessDispatch(HeadlessCmdPutData, Buffer, BufferLength, NULL, NULL); 124 if (Status != STATUS_UNSUCCESSFUL) break; 125 126 /* Sending the data on the port failed, wait a second... */ 127 Interval.HighPart = -1; 128 Interval.LowPart = -100000; 129 KeDelayExecutionThread(KernelMode, FALSE, &Interval); 130 } 131 132 /* After 32 attempts it should really have worked... */ 133 ASSERT(NT_SUCCESS(Status)); 134 return Status; 135 } 136 137 NTSTATUS 138 NTAPI 139 ConMgrFlushData(IN PSAC_CHANNEL Channel) 140 { 141 /* Nothing to do */ 142 return STATUS_SUCCESS; 143 } 144 145 BOOLEAN 146 NTAPI 147 ConMgrIsSacChannel(IN PSAC_CHANNEL Channel) 148 { 149 /* Check which channel is active */ 150 return Channel == SacChannel; 151 } 152 153 BOOLEAN 154 NTAPI 155 ConMgrIsWriteEnabled(IN PSAC_CHANNEL Channel) 156 { 157 /* If the current channel is active, allow writes */ 158 return ChannelIsEqual(Channel, &CurrentChannel->ChannelId); 159 } 160 161 NTSTATUS 162 NTAPI 163 ConMgrInitialize(VOID) 164 { 165 PWCHAR pcwch; 166 PSAC_CHANNEL FoundChannel; 167 SAC_CHANNEL_ATTRIBUTES SacChannelAttributes; 168 NTSTATUS Status; 169 170 /* Initialize the connection manager lock */ 171 SacInitializeMutexLock(); 172 SacAcquireMutexLock(); 173 174 /* Setup the attributes for the raw SAC channel */ 175 RtlZeroMemory(&SacChannelAttributes, sizeof(SacChannelAttributes)); 176 SacChannelAttributes.ChannelType = VtUtf8; 177 178 /* Get the right name for it */ 179 pcwch = GetMessage(SAC_CHANNEL_NAME); 180 ASSERT(pcwch); 181 wcsncpy(SacChannelAttributes.NameBuffer, pcwch, SAC_CHANNEL_NAME_SIZE); 182 SacChannelAttributes.NameBuffer[SAC_CHANNEL_NAME_SIZE] = ANSI_NULL; 183 184 /* Get the right description for it */ 185 pcwch = GetMessage(SAC_CHANNEL_DESCRIPTION); 186 ASSERT(pcwch); 187 wcsncpy(SacChannelAttributes.DescriptionBuffer, pcwch, SAC_CHANNEL_DESCRIPTION_SIZE); 188 SacChannelAttributes.DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = ANSI_NULL; 189 190 /* Set all the right flags */ 191 SacChannelAttributes.Flag = SAC_CHANNEL_FLAG_APPLICATION | SAC_CHANNEL_FLAG_INTERNAL; 192 SacChannelAttributes.CloseEvent = NULL; 193 SacChannelAttributes.HasNewDataEvent = NULL; 194 SacChannelAttributes.LockEvent = NULL; 195 SacChannelAttributes.RedrawEvent = NULL; 196 SacChannelAttributes.ChannelId = PRIMARY_SAC_CHANNEL_APPLICATION_GUID; 197 198 /* Now create it */ 199 Status = ChanMgrCreateChannel(&SacChannel, &SacChannelAttributes); 200 if (NT_SUCCESS(Status)) 201 { 202 /* Try to get it back */ 203 Status = ChanMgrGetByHandle(SacChannel->ChannelId, &FoundChannel); 204 if (NT_SUCCESS(Status)) 205 { 206 /* Set it as the current and SAC channel */ 207 SacChannel = CurrentChannel = FoundChannel; 208 209 /* Disable writes for now and clear the display */ 210 _InterlockedExchange(&FoundChannel->WriteEnabled, FALSE); 211 Status = HeadlessDispatch(HeadlessCmdClearDisplay, NULL, 0, NULL, NULL); 212 if (!NT_SUCCESS(Status)) 213 { 214 SAC_DBG(SAC_DBG_INIT, "SAC ConMgrInitialize: Failed dispatch\n"); 215 } 216 217 /* Display the initial prompt */ 218 SacPutSimpleMessage(SAC_NEWLINE); 219 SacPutSimpleMessage(SAC_INIT_STATUS); 220 SacPutSimpleMessage(SAC_NEWLINE); 221 SacPutSimpleMessage(SAC_PROMPT); 222 223 /* Display the current channel */ 224 ConMgrDisplayCurrentChannel(); 225 } 226 } 227 228 /* Release the channel lock */ 229 SacReleaseMutexLock(); 230 return STATUS_SUCCESS; 231 } 232 233 VOID 234 NTAPI 235 ConMgrEventMessage(IN PWCHAR EventMessage, 236 IN BOOLEAN LockHeld) 237 { 238 /* Acquire the current channel lock if needed */ 239 if (!LockHeld) SacAcquireMutexLock(); 240 241 /* Send out the event message */ 242 SacPutSimpleMessage(2); 243 SacPutString(EventMessage); 244 SacPutSimpleMessage(3); 245 246 /* Release the current channel lock if needed */ 247 if (!LockHeld) SacReleaseMutexLock(); 248 } 249 250 BOOLEAN 251 NTAPI 252 ConMgrSimpleEventMessage(IN ULONG MessageIndex, 253 IN BOOLEAN LockHeld) 254 { 255 PWCHAR MessageBuffer; 256 BOOLEAN Result; 257 258 /* Get the message to send out */ 259 MessageBuffer = GetMessage(MessageIndex); 260 if (MessageBuffer) 261 { 262 /* Send it */ 263 ConMgrEventMessage(MessageBuffer, LockHeld); 264 Result = TRUE; 265 } 266 else 267 { 268 /* It doesn't exist, fail */ 269 Result = FALSE; 270 } 271 272 /* Return if the message was sent or not */ 273 return Result; 274 } 275 276 NTSTATUS 277 NTAPI 278 ConMgrDisplayFastChannelSwitchingInterface(IN PSAC_CHANNEL Channel) 279 { 280 /* FIXME: TODO */ 281 ASSERT(FALSE); 282 return STATUS_NOT_IMPLEMENTED; 283 } 284 285 NTSTATUS 286 NTAPI 287 ConMgrSetCurrentChannel(IN PSAC_CHANNEL Channel) 288 { 289 NTSTATUS Status; 290 BOOLEAN HasRedrawEvent; 291 292 /* Make sure the lock is held */ 293 SacAssertMutexLockHeld(); 294 295 /* Check if we have a redraw event */ 296 Status = ChannelHasRedrawEvent(CurrentChannel, &HasRedrawEvent); 297 if (!NT_SUCCESS(Status)) return Status; 298 299 /* Clear it */ 300 if (HasRedrawEvent) ChannelClearRedrawEvent(CurrentChannel); 301 302 /* Disable writes on the current channel */ 303 _InterlockedExchange(&CurrentChannel->WriteEnabled, 0); 304 305 /* Release the current channel */ 306 Status = ChanMgrReleaseChannel(CurrentChannel); 307 if (!NT_SUCCESS(Status)) return Status; 308 309 /* Set the new channel and also disable writes on it */ 310 CurrentChannel = Channel; 311 _InterlockedExchange(&Channel->WriteEnabled, 0); 312 return STATUS_SUCCESS; 313 } 314 315 NTSTATUS 316 NTAPI 317 ConMgrResetCurrentChannel(IN BOOLEAN KeepChannel) 318 { 319 NTSTATUS Status; 320 PSAC_CHANNEL Channel; 321 322 /* Make sure the lock is held */ 323 SacAssertMutexLockHeld(); 324 325 /* Get the current SAC channel */ 326 Status = ChanMgrGetByHandle(SacChannel->ChannelId, &Channel); 327 if (NT_SUCCESS(Status)) 328 { 329 /* Set this as the current SAC channel*/ 330 SacChannel = Channel; 331 Status = ConMgrSetCurrentChannel(Channel); 332 if (NT_SUCCESS(Status)) 333 { 334 /* Check if the caller wants to switch or not */ 335 if (KeepChannel) 336 { 337 /* Nope, keep the same channel */ 338 Status = ConMgrDisplayCurrentChannel(); 339 } 340 else 341 { 342 /* Yep, show the switching interface */ 343 Status = ConMgrDisplayFastChannelSwitchingInterface(CurrentChannel); 344 } 345 } 346 } 347 348 /* All done */ 349 return Status; 350 } 351 352 NTSTATUS 353 NTAPI 354 ConMgrChannelClose(IN PSAC_CHANNEL Channel) 355 { 356 NTSTATUS Status = STATUS_SUCCESS; 357 358 /* Check if we're in the right channel */ 359 if (ConMgrIsWriteEnabled(Channel)) 360 { 361 /* Yep, reset it */ 362 Status = ConMgrResetCurrentChannel(FALSE); 363 ASSERT(NT_SUCCESS(Status)); 364 } 365 366 /* All done */ 367 return Status; 368 } 369 370 NTSTATUS 371 NTAPI 372 ConMgrShutdown(VOID) 373 { 374 NTSTATUS Status; 375 376 /* Check if we have a SAC channel */ 377 if (SacChannel) 378 { 379 /* Close it */ 380 Status = ChannelClose(SacChannel); 381 if (!NT_SUCCESS(Status)) 382 { 383 SAC_DBG(SAC_DBG_INIT, "SAC ConMgrShutdown: failed closing SAC channel.\n"); 384 } 385 386 /* No longer have one */ 387 SacChannel = NULL; 388 } 389 390 /* Check if we have a current channel */ 391 if (CurrentChannel) 392 { 393 /* Release it */ 394 Status = ChanMgrReleaseChannel(CurrentChannel); 395 if (!NT_SUCCESS(Status)) 396 { 397 SAC_DBG(SAC_DBG_INIT, "SAC ConMgrShutdown: failed releasing current channel\n"); 398 } 399 400 /* No longer have one */ 401 CurrentChannel = NULL; 402 } 403 404 /* All done */ 405 return STATUS_SUCCESS; 406 } 407 408 NTSTATUS 409 NTAPI 410 ConMgrAdvanceCurrentChannel(VOID) 411 { 412 NTSTATUS Status; 413 ULONG Index; 414 PSAC_CHANNEL Channel; 415 416 /* Should always be called with the lock held */ 417 SacAssertMutexLockHeld(); 418 419 /* Get the next active channel */ 420 Status = ChanMgrGetNextActiveChannel(CurrentChannel, &Index, &Channel); 421 if (NT_SUCCESS(Status)) 422 { 423 /* Set it as the new channel */ 424 Status = ConMgrSetCurrentChannel(Channel); 425 if (NT_SUCCESS(Status)) 426 { 427 /* Let the user switch to it */ 428 Status = ConMgrDisplayFastChannelSwitchingInterface(Channel); 429 } 430 } 431 432 /* All done */ 433 return Status; 434 } 435 436 NTSTATUS 437 NTAPI 438 ConMgrChannelOWrite(IN PSAC_CHANNEL Channel, 439 IN PVOID WriteBuffer) 440 { 441 NTSTATUS Status; 442 443 /* Do the write with the lock held */ 444 SacAcquireMutexLock(); 445 ASSERT(FALSE); 446 Status = STATUS_NOT_IMPLEMENTED;// ChannelOWrite(Channel, WriteBuffer + 24, *(WriteBuffer + 20)); 447 SacReleaseMutexLock(); 448 449 /* Return back to the caller */ 450 ASSERT(NT_SUCCESS(Status) || Status == STATUS_NOT_FOUND); 451 return Status; 452 } 453 454 VOID 455 NTAPI 456 ConMgrProcessInputLine(VOID) 457 { 458 BOOLEAN EnablePaging; 459 NTSTATUS Status; 460 461 SAC_DBG(SAC_DBG_INIT, "SAC Input Test: %s\n", InputBuffer); 462 463 if (!strncmp(InputBuffer, "t", 1)) 464 { 465 DoTlistCommand(); 466 } 467 else if (!strncmp(InputBuffer, "?", 1)) 468 { 469 DoHelpCommand(); 470 } 471 else if (!strncmp(InputBuffer, "help", 4)) 472 { 473 DoHelpCommand(); 474 } 475 else if (!strncmp(InputBuffer, "f", 1)) 476 { 477 DoFullInfoCommand(); 478 } 479 else if (!strncmp(InputBuffer, "p", 1)) 480 { 481 DoPagingCommand(); 482 } 483 else if (!strncmp(InputBuffer, "id", 2)) 484 { 485 DoMachineInformationCommand(); 486 } 487 else if (!strncmp(InputBuffer, "crashdump", 9)) 488 { 489 DoCrashCommand(); 490 } 491 else if (!strncmp(InputBuffer, "lock", 4)) 492 { 493 DoLockCommand(); 494 } 495 else if (!strncmp(InputBuffer, "shutdown", 8)) 496 { 497 ExecutePostConsumerCommand = Shutdown; 498 } 499 else if (!strncmp(InputBuffer, "restart", 7)) 500 { 501 ExecutePostConsumerCommand = Restart; 502 } 503 else if (!strncmp(InputBuffer, "d", 1)) 504 { 505 EnablePaging = GlobalPagingNeeded; 506 Status = HeadlessDispatch(HeadlessCmdDisplayLog, 507 &EnablePaging, 508 sizeof(EnablePaging), 509 NULL, 510 NULL); 511 if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "SAC Display Log failed.\n"); 512 } 513 else if (!strncmp(InputBuffer, "cmd", 3)) 514 { 515 if (CommandConsoleLaunchingEnabled) 516 { 517 DoCmdCommand(InputBuffer); 518 } 519 else 520 { 521 SacPutSimpleMessage(148); 522 } 523 } 524 else if (!(strncmp(InputBuffer, "ch", 2)) && 525 (((strlen(InputBuffer) > 1) && (InputBuffer[2] == ' ')) || 526 (strlen(InputBuffer) == 2))) 527 { 528 DoChannelCommand(InputBuffer); 529 } 530 else if (!(strncmp(InputBuffer, "k", 1)) && 531 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) || 532 (strlen(InputBuffer) == 1))) 533 { 534 DoKillCommand(InputBuffer); 535 } 536 else if (!(strncmp(InputBuffer, "l", 1)) && 537 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) || 538 (strlen(InputBuffer) == 1))) 539 { 540 DoLowerPriorityCommand(InputBuffer); 541 } 542 else if (!(strncmp(InputBuffer, "r", 1)) && 543 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) || 544 (strlen(InputBuffer) == 1))) 545 { 546 DoRaisePriorityCommand(InputBuffer); 547 } 548 else if (!(strncmp(InputBuffer, "m", 1)) && 549 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) || 550 (strlen(InputBuffer) == 1))) 551 { 552 DoLimitMemoryCommand(InputBuffer); 553 } 554 else if (!(strncmp(InputBuffer, "s", 1)) && 555 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) || 556 (strlen(InputBuffer) == 1))) 557 { 558 DoSetTimeCommand(InputBuffer); 559 } 560 else if (!(strncmp(InputBuffer, "i", 1)) && 561 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) || 562 (strlen(InputBuffer) == 1))) 563 { 564 DoSetIpAddressCommand(InputBuffer); 565 } 566 else if ((InputBuffer[0] != '\n') && (InputBuffer[0] != ANSI_NULL)) 567 { 568 SacPutSimpleMessage(SAC_UNKNOWN_COMMAND); 569 } 570 } 571 572 VOID 573 NTAPI 574 ConMgrSerialPortConsumer(VOID) 575 { 576 NTSTATUS Status; 577 CHAR Char; 578 WCHAR LastChar; 579 CHAR ReadBuffer[2]; 580 ULONG ReadBufferSize, i; 581 WCHAR StringBuffer[2]; 582 SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Entering.\n"); //bug 583 584 /* Acquire the manager lock and make sure a channel is selected */ 585 SacAcquireMutexLock(); 586 ASSERT(CurrentChannel); 587 588 /* Read whatever came off the serial port */ 589 for (Status = SerialBufferGetChar(&Char); 590 NT_SUCCESS(Status); 591 Status = SerialBufferGetChar(&Char)) 592 { 593 /* If nothing came through, bail out */ 594 if (Status == STATUS_NO_DATA_DETECTED) break; 595 596 /* Check if ESC was pressed */ 597 if (Char == '\x1B') 598 { 599 /* Was it already pressed? */ 600 if (!InputInEscape) 601 { 602 /* First time ESC is pressed! Remember and reset TAB state */ 603 InputInEscTab = FALSE; 604 InputInEscape = TRUE; 605 continue; 606 } 607 } 608 else if (Char == '\t') 609 { 610 /* TAB was pressed, is it following ESC (VT-100 sequence)? */ 611 if (InputInEscape) 612 { 613 /* Yes! This must be the only ESC-TAB we see in once moment */ 614 ASSERT(InputInEscTab == FALSE); 615 616 /* No longer treat us as being in ESC */ 617 InputInEscape = FALSE; 618 619 /* ESC-TAB is the sequence for changing channels */ 620 Status = ConMgrAdvanceCurrentChannel(); 621 if (!NT_SUCCESS(Status)) break; 622 623 /* Remember ESC-TAB was pressed */ 624 InputInEscTab = TRUE; 625 continue; 626 } 627 } 628 else if ((Char == '0') && (InputInEscTab)) 629 { 630 /* It this ESC-TAB-0? */ 631 ASSERT(InputInEscape == FALSE); 632 InputInEscTab = FALSE; 633 634 /* If writes are already enabled, don't do this */ 635 if (!CurrentChannel->WriteEnabled) 636 { 637 /* Reset the channel, this is our special sequence */ 638 Status = ConMgrResetCurrentChannel(FALSE); 639 if (!NT_SUCCESS(Status)) break; 640 } 641 642 continue; 643 } 644 else 645 { 646 /* This is ESC-TAB-something else */ 647 InputInEscTab = FALSE; 648 649 /* If writes are already enabled, don't do this */ 650 if (!CurrentChannel->WriteEnabled) 651 { 652 /* Display the current channel */ 653 InputInEscape = FALSE; 654 Status = ConMgrDisplayCurrentChannel(); 655 if (!NT_SUCCESS(Status)) break; 656 continue; 657 } 658 } 659 660 /* Check if an ESC-sequence was being typed into a command channel */ 661 if ((InputInEscape) && (CurrentChannel != SacChannel)) 662 { 663 /* Store the ESC in the current channel buffer */ 664 ReadBuffer[0] = '\x1B'; 665 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR)); 666 } 667 668 /* Check if we are no longer pressing ESC and exit the mode if so */ 669 if (Char != '\x1B') InputInEscape = FALSE; 670 671 /* Whatever was typed in, save it int eh current channel */ 672 ChannelIWrite(CurrentChannel, &Char, sizeof(Char)); 673 674 /* If this is a command channel, we're done, nothing to process */ 675 if (CurrentChannel != SacChannel) continue; 676 677 /* Check for line feed right after a carriage return */ 678 if ((ConMgrLastCharWasCR) && (Char == '\n')) 679 { 680 /* Ignore the line feed, but clear the carriage return */ 681 ChannelIReadLast(CurrentChannel); 682 ConMgrLastCharWasCR = 0; 683 continue; 684 } 685 686 /* Check if the user did a carriage return */ 687 ConMgrLastCharWasCR = (Char == '\n'); 688 689 /* If the user did an "ENTER", we need to run the command */ 690 if ((Char == '\n') || (Char == '\r')) 691 { 692 /* Echo back to the terminal */ 693 SacPutString(L"\r\n"); 694 695 DoLineParsing: 696 /* Inhibit the character (either CR or LF) */ 697 ChannelIReadLast(CurrentChannel); 698 699 /* NULL-terminate the channel's input buffer */ 700 ReadBuffer[0] = ANSI_NULL; 701 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR)); 702 703 /* Loop over every last character */ 704 do 705 { 706 /* Read every character in the channel, and strip whitespace */ 707 LastChar = ChannelIReadLast(CurrentChannel); 708 ReadBuffer[0] = (CHAR) LastChar; 709 } while ((!(LastChar) || 710 (LastChar == L' ') || 711 (LastChar == L'\t')) && 712 (ChannelIBufferLength(CurrentChannel))); 713 714 /* Write back into the channel the last character */ 715 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR)); 716 717 /* NULL-terminate the input buffer */ 718 ReadBuffer[0] = ANSI_NULL; 719 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR)); 720 721 /* Now loop over every first character */ 722 do 723 { 724 /* Read every character in the channel, and strip whitespace */ 725 ChannelIRead(CurrentChannel, 726 ReadBuffer, 727 sizeof(ReadBuffer), 728 &ReadBufferSize); 729 } while ((ReadBufferSize) && 730 ((ReadBuffer[0] == ' ') || (ReadBuffer[0] == '\t'))); 731 732 /* We read one more than we should, so treat that as our first one */ 733 InputBuffer[0] = ReadBuffer[0]; 734 i = 1; 735 736 /* And now loop reading all the others */ 737 do 738 { 739 /* Read each character -- there should be max 80 */ 740 ChannelIRead(CurrentChannel, 741 ReadBuffer, 742 sizeof(ReadBuffer), 743 &ReadBufferSize); 744 ASSERT(i < SAC_VTUTF8_COL_WIDTH); 745 InputBuffer[i++] = ReadBuffer[0]; 746 } while (ReadBufferSize); 747 748 /* Now go over the entire input stream */ 749 for (i = 0; InputBuffer[i]; i++) 750 { 751 /* Again it should be less than 80 characters */ 752 ASSERT(i < SAC_VTUTF8_COL_WIDTH); 753 754 /* And downbase each character */ 755 Char = InputBuffer[i]; 756 if ((Char >= 'A') && (Char <= 'Z')) InputBuffer[i] = Char + ' '; 757 } 758 759 /* Ok, at this point, no pending command should exist */ 760 ASSERT(ExecutePostConsumerCommand == Nothing); 761 762 /* Go and process the input, then show the prompt again */ 763 ConMgrProcessInputLine(); 764 SacPutSimpleMessage(SAC_PROMPT); 765 766 /* If the user typed a valid command, get out of here */ 767 if (ExecutePostConsumerCommand != Nothing) break; 768 769 /* Keep going */ 770 continue; 771 } 772 773 /* Check if the user typed backspace or delete */ 774 if ((Char == '\b') || (Char == '\x7F')) 775 { 776 /* Omit the last character, which should be the DEL/BS itself */ 777 if (ChannelIBufferLength(CurrentChannel)) 778 { 779 ChannelIReadLast(CurrentChannel); 780 } 781 782 /* Omit the before-last character, which is the one to delete */ 783 if (ChannelIBufferLength(CurrentChannel)) 784 { 785 /* Also send two backspaces back to the console */ 786 SacPutString(L"\b \b"); 787 ChannelIReadLast(CurrentChannel); 788 } 789 790 /* Keep going */ 791 continue; 792 } 793 794 /* If the user pressed CTRL-C at this point, treat it like ENTER */ 795 if (Char == '\x03') goto DoLineParsing; 796 797 /* Check if the user pressed TAB */ 798 if (Char == '\t') 799 { 800 /* Omit it, send a BELL, and keep going. We ignore TABs */ 801 ChannelIReadLast(CurrentChannel); 802 SacPutString(L"\a"); 803 continue; 804 } 805 806 /* Check if the user is getting close to the end of the screen */ 807 if (ChannelIBufferLength(CurrentChannel) == (SAC_VTUTF8_COL_WIDTH - 2)) 808 { 809 /* Delete the last character, replacing it with this one instead */ 810 swprintf(StringBuffer, L"\b%c", Char); 811 SacPutString(StringBuffer); 812 813 /* Omit the last two characters from the buffer */ 814 ChannelIReadLast(CurrentChannel); 815 ChannelIReadLast(CurrentChannel); 816 817 /* Write the last character that was just typed in */ 818 ReadBuffer[0] = Char; 819 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR)); 820 continue; 821 } 822 823 /* Nothing of interest happened, just write the character back */ 824 swprintf(StringBuffer, L"%c", Char); 825 SacPutString(StringBuffer); 826 } 827 828 /* We're done, release the lock */ 829 SacReleaseMutexLock(); 830 SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Exiting.\n"); //bug 831 } 832 833 VOID 834 NTAPI 835 ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension) 836 { 837 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n"); 838 839 /* Enter the main loop */ 840 while (TRUE) 841 { 842 /* Wait for something to do */ 843 KeWaitForSingleObject(&DeviceExtension->Event, 844 Executive, 845 KernelMode, 846 FALSE, 847 NULL); 848 849 /* Consume data off the serial port */ 850 ConMgrSerialPortConsumer(); 851 switch (ExecutePostConsumerCommand) 852 { 853 case Restart: 854 /* A reboot was sent, do it */ 855 DoRebootCommand(FALSE); 856 break; 857 858 case Close: 859 /* A close was sent, do it */ 860 ChanMgrCloseChannel(ExecutePostConsumerCommandData); 861 ChanMgrReleaseChannel(ExecutePostConsumerCommandData); 862 break; 863 864 case Shutdown: 865 /* A shutdown was sent, do it */ 866 DoRebootCommand(TRUE); 867 break; 868 } 869 870 /* Clear the serial port consumer state */ 871 ExecutePostConsumerCommand = Nothing; 872 ExecutePostConsumerCommandData = NULL; 873 } 874 } 875 876 NTSTATUS 877 NTAPI 878 ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel, 879 IN NTSTATUS CloseStatus, 880 OUT PWCHAR OutputBuffer) 881 { 882 ASSERT(FALSE); 883 return STATUS_NOT_IMPLEMENTED; 884 } 885 886 NTSTATUS 887 NTAPI 888 ConMgrHandleEvent(IN ULONG EventCode, 889 IN PSAC_CHANNEL Channel, 890 OUT PVOID Data) 891 { 892 ASSERT(FALSE); 893 return STATUS_NOT_IMPLEMENTED; 894 } 895