Synchronize with trunk revision 59781.
[reactos.git] / drivers / sac / driver / conmgr.c
index b012cad..fda8547 100644 (file)
@@ -27,76 +27,10 @@ PSAC_CHANNEL SacChannel;
 ULONG ExecutePostConsumerCommand;
 PSAC_CHANNEL ExecutePostConsumerCommandData;
 
-/* FUNCTIONS *****************************************************************/
-
-VOID
-NTAPI
-ConMgrSerialPortConsumer(VOID)
-{
-    NTSTATUS Status;
-    CHAR Char;
-    SAC_DBG(0x2000, "SAC TimerDpcRoutine: Entering.\n"); //bug
-
-    /* Acquire the manager lock and make sure a channel is selected */
-    SacAcquireMutexLock();
-    ASSERT(CurrentChannel);
-
-    /* Read whatever came off the serial port */
-    for (Status = SerialBufferGetChar(&Char);
-         NT_SUCCESS(Status);
-         Status = SerialBufferGetChar(&Char))
-    {
-        /* If nothing came through, bail out */
-        if (Status == STATUS_NO_DATA_DETECTED) break;
-    }
+BOOLEAN InputInEscape, InputInEscTab, ConMgrLastCharWasCR;
+CHAR InputBuffer[80];
 
-    /* We're done, release the lock */
-    SacReleaseMutexLock();
-    SAC_DBG(0x2000, "SAC TimerDpcRoutine: Exiting.\n"); //bug
-}
-
-VOID
-NTAPI
-ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension)
-{
-    SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n");
-
-    /* Enter the main loop */
-    while (TRUE)
-    {
-        /* Wait for something to do */
-        KeWaitForSingleObject(&DeviceExtension->Event,
-                              Executive,
-                              KernelMode,
-                              FALSE,
-                              NULL);
-
-        /* Consume data off the serial port */
-        ConMgrSerialPortConsumer();
-        switch (ExecutePostConsumerCommand)
-        {
-            case 1:
-                /* A reboot was sent, do it  */
-                DoRebootCommand(FALSE);
-                break;
-
-            case 2:
-                /* A close was sent, do it */
-                ChanMgrCloseChannel(ExecutePostConsumerCommandData);
-                ChanMgrReleaseChannel(ExecutePostConsumerCommandData);
-                break;
-
-            case 3:
-                /* A shutdown was sent, do it */
-                DoRebootCommand(TRUE);
-                break;
-        }
-
-        /* Clear the serial port consumer state */
-        ExecutePostConsumerCommand = 0;
-        ExecutePostConsumerCommandData = NULL;
-    }
-}
+/* FUNCTIONS *****************************************************************/
 
 VOID
 NTAPI
@@ -235,7 +169,7 @@ ConMgrInitialize(VOID)
 
     /* Setup the attributes for the raw SAC channel */
     RtlZeroMemory(&SacChannelAttributes, sizeof(SacChannelAttributes));
-    SacChannelAttributes.ChannelType = Raw;
+    SacChannelAttributes.ChannelType = Raw; /* FIXME: Should be VtUtf8 */
 
     /* Get the right name for it */
     pcwch = GetMessage(SAC_CHANNEL_NAME);
@@ -504,6 +438,7 @@ ConMgrChannelOWrite(IN PSAC_CHANNEL Channel,
 
     /* Do the write with the lock held */
     SacAcquireMutexLock();
+    ASSERT(FALSE);
     Status = STATUS_NOT_IMPLEMENTED;// ChannelOWrite(Channel, WriteBuffer + 24, *(WriteBuffer + 20));
     SacReleaseMutexLock();
 
@@ -512,21 +447,441 @@ ConMgrChannelOWrite(IN PSAC_CHANNEL Channel,
     return Status;
 }
 
-NTSTATUS
+#define Shutdown    1
+#define Restart     3
+#define Nothing     0
+BOOLEAN GlobalPagingNeeded;
+
+VOID
 NTAPI
-ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel,
-                             IN NTSTATUS CloseStatus,
-                             OUT PWCHAR OutputBuffer)
+ConMgrProcessInputLine(VOID)
 {
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    BOOLEAN EnablePaging;
+    NTSTATUS Status;
+
+    SAC_DBG(4, "SAC Input Test: %s\n", InputBuffer);
+
+    if (!strncmp(InputBuffer, "t", 1))
+    {
+        DoTlistCommand();
+    }
+    else if (!strncmp(InputBuffer, "?", 1))
+    {
+        DoHelpCommand();
+    }
+    else if (!strncmp(InputBuffer, "help", 4))
+    {
+        DoHelpCommand();
+    }
+    else if (!strncmp(InputBuffer, "f", 1))
+    {
+        DoFullInfoCommand();
+    }
+    else if (!strncmp(InputBuffer, "p", 1))
+    {
+        DoPagingCommand();
+    }
+    else if (!strncmp(InputBuffer, "id", 2))
+    {
+        DoMachineInformationCommand();
+    }
+    else if (!strncmp(InputBuffer, "crashdump", 9))
+    {
+        DoCrashCommand();
+    }
+    else if (!strncmp(InputBuffer, "lock", 4))
+    {
+        DoLockCommand();
+    }
+    else if (!strncmp(InputBuffer, "shutdown", 8))
+    {
+        ExecutePostConsumerCommand = Shutdown;
+    }
+    else if (!strncmp(InputBuffer, "restart", 7))
+    {
+        ExecutePostConsumerCommand = Restart;
+    }
+    else if (!strncmp(InputBuffer, "d", 1))
+    {
+        EnablePaging = GlobalPagingNeeded;
+        Status = HeadlessDispatch(HeadlessCmdDisplayLog,
+                                  &EnablePaging,
+                                  sizeof(EnablePaging),
+                                  NULL,
+                                  0);
+        if (!NT_SUCCESS(Status)) SAC_DBG(4, "SAC Display Log failed.\n");
+    }
+    else if (!strncmp(InputBuffer, "cmd", 3))
+    {
+        if (CommandConsoleLaunchingEnabled)
+        {
+            DoCmdCommand(InputBuffer);
+        }
+        else
+        {
+            SacPutSimpleMessage(148);
+        }
+    }
+    else if (!(strncmp(InputBuffer, "ch", 2)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[2] == ' ')) ||
+              (strlen(InputBuffer) == 2)))
+    {
+        DoChannelCommand(InputBuffer);
+    }
+    else if (!(strncmp(InputBuffer, "k", 1)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
+              (strlen(InputBuffer) == 1)))
+    {
+        DoKillCommand(InputBuffer);
+    }
+    else if (!(strncmp(InputBuffer, "l", 1)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
+              (strlen(InputBuffer) == 1)))
+    {
+        DoLowerPriorityCommand(InputBuffer);
+    }
+    else if (!(strncmp(InputBuffer, "r", 1)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
+              (strlen(InputBuffer) == 1)))
+    {
+        DoRaisePriorityCommand(InputBuffer);
+    }
+    else if (!(strncmp(InputBuffer, "m", 1)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
+              (strlen(InputBuffer) == 1)))
+    {
+        DoLimitMemoryCommand(InputBuffer);
+    }
+    else if (!(strncmp(InputBuffer, "s", 1)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
+              (strlen(InputBuffer) == 1)))
+    {
+        DoSetTimeCommand(InputBuffer);
+    }
+    else if (!(strncmp(InputBuffer, "i", 1)) &&
+             (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
+              (strlen(InputBuffer) == 1)))
+    {
+        DoSetIpAddressCommand(InputBuffer);
+    }
+    else if ((InputBuffer[0] != '\n') && (InputBuffer[0] != ANSI_NULL))
+    {
+        SacPutSimpleMessage(105);
+    }
 }
 
 VOID
 NTAPI
-ConMgrProcessInputLine(VOID)
+ConMgrSerialPortConsumer(VOID)
+{
+    NTSTATUS Status;
+    CHAR Char;
+    WCHAR LastChar;
+    CHAR ReadBuffer[2];
+    ULONG ReadBufferSize, i;
+    WCHAR StringBuffer[2];
+    SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Entering.\n"); //bug
+
+    /* Acquire the manager lock and make sure a channel is selected */
+    SacAcquireMutexLock();
+    ASSERT(CurrentChannel);
+
+    /* Read whatever came off the serial port */
+    for (Status = SerialBufferGetChar(&Char);
+         NT_SUCCESS(Status);
+         Status = SerialBufferGetChar(&Char))
+    {
+        /* If nothing came through, bail out */
+        if (Status == STATUS_NO_DATA_DETECTED) break;
+
+        /* Check if ESC was pressed */
+        if (Char == '\x1B')
+        {
+            /* Was it already pressed? */
+            if (!InputInEscape)
+            {
+                /* First time ESC is pressed! Remember and reset TAB state */
+                InputInEscTab = FALSE;
+                InputInEscape = TRUE;
+                continue;
+            }
+        }
+        else if (Char == '\t')
+        {
+            /* TAB was pressed, is it following ESC (VT-100 sequence)? */
+            if (InputInEscape)
+            {
+                /* Yes! This must be the only ESC-TAB we see in once moment */
+                ASSERT(InputInEscTab == FALSE);
+
+                /* No longer treat us as being in ESC */
+                InputInEscape = FALSE;
+
+                /* ESC-TAB is the sequence for changing channels */
+                Status = ConMgrAdvanceCurrentChannel();
+                if (!NT_SUCCESS(Status)) break;
+
+                /* Remember ESC-TAB was pressed */
+                InputInEscTab = TRUE;
+                continue;
+            }
+        }
+        else if ((Char == '0') && (InputInEscTab))
+        {
+            /* It this ESC-TAB-0? */
+            ASSERT(InputInEscape == FALSE);
+            InputInEscTab = FALSE;
+
+            /* If writes are already enabled, don't do this */
+            if (!CurrentChannel->WriteEnabled)
+            {
+                /* Reset the channel, this is our special sequence */
+                Status = ConMgrResetCurrentChannel(FALSE);
+                if (!NT_SUCCESS(Status)) break;
+            }
+
+            continue;
+        }
+        else
+        {
+            /* This is ESC-TAB-something else */
+            InputInEscTab = FALSE;
+
+            /* If writes are already enabled, don't do this */
+            if (!CurrentChannel->WriteEnabled)
+            {
+                /* Display the current channel */
+                InputInEscape = FALSE;
+                Status = ConMgrDisplayCurrentChannel();
+                if (!NT_SUCCESS(Status)) break;
+                continue;
+            }
+        }
+
+        /* Check if an ESC-sequence was being typed into a command channel */
+        if ((InputInEscape) && (CurrentChannel != SacChannel))
+        {
+            /* Store the ESC in the current channel buffer */
+            ReadBuffer[0] = '\x1B';
+            ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
+        }
+
+        /* Check if we are no longer pressing ESC and exit the mode if so */
+        if (Char != '\x1B') InputInEscape = FALSE;
+
+        /* Whatever was typed in, save it int eh current channel */
+        ChannelIWrite(CurrentChannel, &Char, sizeof(Char));
+
+        /* If this is a command channel, we're done, nothing to process */
+        if (CurrentChannel != SacChannel) continue;
+
+        /* Check for line feed right after a carriage return */
+        if ((ConMgrLastCharWasCR) && (Char == '\n'))
+        {
+            /* Ignore the line feed, but clear the carriage return */
+            ChannelIReadLast(CurrentChannel);
+            ConMgrLastCharWasCR = 0;
+            continue;
+        }
+
+        /* Check if the user did a carriage return */
+        ConMgrLastCharWasCR = (Char == '\n');
+
+        /* If the user did an "ENTER", we need to run the command */
+        if ((Char == '\n') || (Char == '\r'))
+        {
+            /* Echo back to the terminal */
+            SacPutString(L"\r\n");
+
+DoLineParsing:
+            /* Inhibit the character (either CR or LF) */
+            ChannelIReadLast(CurrentChannel);
+
+            /* NULL-terminate the channel's input buffer */
+            ReadBuffer[0] = ANSI_NULL;
+            ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
+
+            /* Loop over every last character */
+            do
+            {
+                /* Read every character in the channel, and strip whitespace */
+                LastChar = ChannelIReadLast(CurrentChannel);
+                ReadBuffer[0] = (CHAR) LastChar;
+            } while ((!(LastChar) ||
+                       (LastChar == L' ') ||
+                       (LastChar == L'\t')) &&
+                     (ChannelIBufferLength(CurrentChannel)));
+
+            /* Write back into the channel the last character */
+            ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
+
+            /* NULL-terminate the input buffer */
+            ReadBuffer[0] = ANSI_NULL;
+            ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
+
+            /* Now loop over every first character */
+            do
+            {
+                /* Read every character in the channel, and strip whitespace */
+                ChannelIRead(CurrentChannel,
+                             ReadBuffer,
+                             sizeof(CHAR), /* FIXME: Should be sizeof(ReadBuffer) */
+                             &ReadBufferSize);
+            } while ((ReadBufferSize) &&
+                     ((ReadBuffer[0] == ' ') || (ReadBuffer[0] == '\t')));
+
+            /* We read one more than we should, so treat that as our first one */
+            InputBuffer[0] = ReadBuffer[0];
+            i = 1;
+
+            /* And now loop reading all the others */
+            do
+            {
+                /* Read each character -- there should be max 80 */
+                ChannelIRead(CurrentChannel,
+                             ReadBuffer,
+                             sizeof(CHAR), /* FIXME: Should be sizeof(ReadBuffer) */
+                             &ReadBufferSize);
+                ASSERT(i < SAC_VTUTF8_COL_WIDTH);
+                InputBuffer[i++] = ReadBuffer[0];
+            } while (ReadBufferSize);
+
+            /* Now go over the entire input stream */
+            for (i = 0; InputBuffer[i]; i++)
+            {
+                /* Again it should be less than 80 characters */
+                ASSERT(i < SAC_VTUTF8_COL_WIDTH);
+
+                /* And downbase each character */
+                Char = InputBuffer[i];
+                if ((Char >= 'A') && (Char <= 'Z')) InputBuffer[i] = Char + ' ';
+            }
+
+            /* Ok, at this point, no pending command should exist */
+            ASSERT(ExecutePostConsumerCommand == Nothing);
+
+            /* Go and process the input, then show the prompt again */
+            ConMgrProcessInputLine();
+            SacPutSimpleMessage(SAC_PROMPT);
+
+            /* If the user typed a valid command, get out of here */
+            if (ExecutePostConsumerCommand != Nothing) break;
+
+            /* Keep going */
+            continue;
+        }
+
+        /* Check if the user typed backspace or delete */
+        if ((Char == '\b') || (Char == '\x7F'))
+        {
+            /* Omit the last character, which should be the DEL/BS itself */
+            if (ChannelIBufferLength(CurrentChannel))
+            {
+                ChannelIReadLast(CurrentChannel);
+            }
+
+            /* Omit the before-last character, which is the one to delete */
+            if (ChannelIBufferLength(CurrentChannel))
+            {
+                /* Also send two backspaces back to the console */
+                SacPutString(L"\b \b");
+                ChannelIReadLast(CurrentChannel);
+            }
+
+            /* Keep going */
+            continue;
+        }
+
+        /* If the user pressed CTRL-C at this point, treat it like ENTER */
+        if (Char == '\x03') goto DoLineParsing;
+
+        /* Check if the user pressed TAB */
+        if (Char == '\t')
+        {
+            /* Omit it, send a BELL, and keep going. We ignore TABs */
+            ChannelIReadLast(CurrentChannel);
+            SacPutString(L"\a");
+            continue;
+        }
+
+        /* Check if the user is getting close to the end of the screen */
+        if (ChannelIBufferLength(CurrentChannel) == (SAC_VTUTF8_COL_WIDTH - 2))
+        {
+            /* Delete the last character, replacing it with this one instead */
+            swprintf(StringBuffer, L"\b%c", Char);
+            SacPutString(StringBuffer);
+
+            /* Omit the last two characters from the buffer */
+            ChannelIReadLast(CurrentChannel);
+            ChannelIReadLast(CurrentChannel);
+
+            /* Write the last character that was just typed in */
+            ReadBuffer[0] = Char;
+            ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
+            continue;
+        }
+
+        /* Nothing of interest happened, just write the character back */
+        swprintf(StringBuffer, L"%c", Char);
+        SacPutString(StringBuffer);
+    }
+
+    /* We're done, release the lock */
+    SacReleaseMutexLock();
+    SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Exiting.\n"); //bug
+}
+
+VOID
+NTAPI
+ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension)
+{
+    SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n");
+
+    /* Enter the main loop */
+    while (TRUE)
+    {
+        /* Wait for something to do */
+        KeWaitForSingleObject(&DeviceExtension->Event,
+                              Executive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+
+        /* Consume data off the serial port */
+        ConMgrSerialPortConsumer();
+        switch (ExecutePostConsumerCommand)
+        {
+            case 1:
+                /* A reboot was sent, do it  */
+                DoRebootCommand(FALSE);
+                break;
+
+            case 2:
+                /* A close was sent, do it */
+                ChanMgrCloseChannel(ExecutePostConsumerCommandData);
+                ChanMgrReleaseChannel(ExecutePostConsumerCommandData);
+                break;
+
+            case 3:
+                /* A shutdown was sent, do it */
+                DoRebootCommand(TRUE);
+                break;
+        }
+
+        /* Clear the serial port consumer state */
+        ExecutePostConsumerCommand = 0;
+        ExecutePostConsumerCommandData = NULL;
+    }
+}
+
+NTSTATUS
+NTAPI
+ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel,
+                             IN NTSTATUS CloseStatus,
+                             OUT PWCHAR OutputBuffer)
 {
     ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 NTSTATUS